Compare commits
25 Commits
Author | SHA1 | Date |
---|---|---|
|
cbe424f3e3 | |
|
b66adffd3a | |
|
3ebf5cc1f5 | |
|
c6c42d4bd8 | |
|
640bff88c0 | |
|
7becdd5a80 | |
|
a19ae8a746 | |
|
07ee1d4db0 | |
|
999274e946 | |
|
912f32e7ab | |
|
eeee824b20 | |
|
8d3c116a0b | |
|
6affbf19be | |
|
4cd68f4a7f | |
|
73b5ade3e1 | |
|
8d076456e3 | |
|
2439907c59 | |
|
63f054f6bf | |
|
88d87c2c68 | |
|
e9e7ebbbc1 | |
|
5175c2b456 | |
|
870ec96e9a | |
|
3b3b480b72 | |
|
9325bf645f | |
|
5c30f871c7 |
|
@ -1 +0,0 @@
|
|||
# Please fill in the URLrewrite rules or custom Apache config here
|
|
@ -1 +0,0 @@
|
|||
xldcAYGIOnxW2yiX6KDZUW44-JTev8gg7r3kzrwY34k.PZDupKjVmMf0TNd3vLGxHErgeolq5CbdlHehVDWziwE
|
301
README.md
301
README.md
|
@ -6,301 +6,18 @@ Servis, bağlantı sağlayan cihazların verilerini kendi aralarında senkron et
|
|||
|
||||
Bağlantı TCP tabanlı yüksek hızlı WebSocket protokolüne dayanır ve sunucunun cihazları sanallaştırması sayesinde diğer kişilerin IP adreslerini veya cihaz türü gibi bilgilere ihtiyaç duymadan düşük gecikmeli çift taraflı serbest iletişim kurmalarını sağlar.
|
||||
|
||||
[Geliştirici Dökümanı](https://git.saqut.com/saqut/MWSE/wiki/Entegrasyon)
|
||||
|
||||
# Güvenlik !
|
||||
|
||||
Framework, bağlı tüm cihazlar arasında mesajları doğru hedefe, verinin bozulmadığını garanti ederek iletmekden sorumludur.
|
||||
|
||||
Bunların dışında hassas verilerin soket üzerinden iletilmesi şimdilik önerilmez, clientlerin ileteceği mesajlar **SOKETE İLETİLMEDEN ÖNCE** kullanıcılar tarafından manipüle edilebilir veya taklit edilebilir ve MWSE bunun doğrulamasını **YAPMAZ**
|
||||
|
||||
## WebSocket topolojisi
|
||||
|
||||

|
||||
|
||||
## Proje tarafından uygulanan load balance teknolojisi
|
||||
|
||||

|
||||
|
||||
# Geliştirici Dökümantasyonu
|
||||
|
||||
## Kurulum
|
||||
|
||||
### Proje ortamına kurulumu
|
||||
|
||||
```html
|
||||
<script src="https://ws.saqut.com/script"></script>
|
||||
```
|
||||
|
||||
### Geliştirme ortamına kurulumu
|
||||
|
||||
```javascript
|
||||
const mwse = new MWSE({
|
||||
endpoint: "wss://ws.saqut.com/" // MSWS kurulu sunucu adresi
|
||||
});
|
||||
mwse.scope(async () => {
|
||||
// Bağlantı sağlandığında burası tetiklenir
|
||||
})
|
||||
```
|
||||
|
||||
### Kendi bağlantı kimliğini öğrenme
|
||||
|
||||
```javascript
|
||||
mwse.scope(async () => {
|
||||
let me = mwse.peer('me'); // Kendi bağlantınız üzerinde işlem yaparken `me` olarak bahsedersiniz
|
||||
console.log(me.socketId); // Her eşin tekil bir socketIdsi vardır
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
### Sanal Adres ayırma / yeniden ayırma / kaldırma
|
||||
```javascript
|
||||
mwse.scope(async () => {
|
||||
let me = mwse.peer('me');
|
||||
|
||||
/**
|
||||
* Sanal adresler size veri gönderilmek istendiğinde veya etkileşime
|
||||
* geçilmesi istendiğinde ona socketId gibi bir UUID yerine sizi temsil eden daha kısa
|
||||
* ip adresi, sayı veya kısa bir kod ile aynı şeyleri yapmanıza olanak tanır.
|
||||
* Aynı anda hem sanal ip adres, sayı ve kısa koduna sahip olabilirsiniz
|
||||
* ancak aynı türden temsil koduna (mesela kısa koddan) birden fazla sahip olamazsınız
|
||||
* Yeni bir bağlantı daha açmanız gerekir
|
||||
**/
|
||||
|
||||
// Bağlantınıze özel sanal tekil ip adresi kaynağı ayırın
|
||||
let ipadress = await me.virtualPressure.allocAPIPAddress();
|
||||
|
||||
// Bağlantınıze özel sanal tekil numara kaynağı ayırın
|
||||
let numberaddress = await me.virtualPressure.allocAPNumber();
|
||||
|
||||
// Bağlantınıze özel sanal kod kaynağı ayırın
|
||||
let shortcodeadress = await me.virtualPressure.allocAPShortCode();
|
||||
|
||||
// Bütün bu kaynakları yenileriyle değiştirmek için
|
||||
// her birinin ayrı ayrı yeniden alma işlevleri vardır
|
||||
// Bir adresi yenilediğinizde artık eski adres kullanılmaz olur
|
||||
me.virtualPressure.reallocAPIPAddress();
|
||||
me.virtualPressure.reallocAPNumber();
|
||||
me.virtualPressure.reallocAPShortCode();
|
||||
|
||||
// Bütün bu kaynakları kaldırmak için her birinin ayrı ayrı
|
||||
// bırakma işlevi vardır
|
||||
// Bir adresi kullanmadığınızda artık bu adreslerden size
|
||||
// ulaşılamaz olursunuz
|
||||
await me.virtualPressure.releaseAPIPAddress();
|
||||
await me.virtualPressure.releaseAPNumber();
|
||||
await me.virtualPressure.releaseAPShortCode();
|
||||
|
||||
await me.virtualPressure.queryAPIPAddress();
|
||||
await me.virtualPressure.queryAPNumber();
|
||||
await me.virtualPressure.queryAPShortCode();
|
||||
})
|
||||
```
|
||||
|
||||
### Farklı bir eşe erişme
|
||||
|
||||
```javascript
|
||||
mwse.scope(async () => {
|
||||
let peer = mwse.peer('325a8f7f-eaaf-4c21-855e-9e965c0d5ac9') // Diğer eşin socketId'sini belirtiyoruz
|
||||
let me = mwse.peer('me');
|
||||
|
||||
// Eşin ulaşılabilir (online) olup olmadığını verir
|
||||
let isOnline = await peer.isReachable();
|
||||
|
||||
if(isOnline)
|
||||
{
|
||||
// İleitşim kurmak için istek gönderiyoruz
|
||||
await peer.requestPair();
|
||||
}
|
||||
|
||||
// Bize gönderilecek olan istekleri dinliyoruz
|
||||
me.on('request/pair', peer => {
|
||||
// İstek gönderen kullanıcının bilgileri peer içinde bulunur
|
||||
// iletişime devam etmek için isteği kabul ediyoruz
|
||||
peer.acceptPair();
|
||||
// veya istemiyorsak reddediyoruz
|
||||
peer.rejectPair();
|
||||
})
|
||||
|
||||
// Karşımızdaki kullanıcının ne cevap verdiğini
|
||||
// anlamak için sistem ayrı ayrı cevaplar üretir
|
||||
|
||||
// Kabul ettiyse accept eventini tetikler
|
||||
me.on('accepted/pair', peer => {
|
||||
// İstek gönderen kullanıcının bilgileri peer içinde bulunur
|
||||
})
|
||||
|
||||
// Reddettiyse veya iletişimi sonlandırmışsa
|
||||
// end eventi tetiklenir
|
||||
me.on('end/pair', peer => {
|
||||
// Kullanıcının bilgileri peer içinde bulunur
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
Eğer uygulamanızda bu şekilde bir erişim metodolojisi kullanmak istemiyorsanız
|
||||
pair sistemini elle kapatabilirsiniz
|
||||
|
||||
```javascript
|
||||
mwse.scope(async () => {
|
||||
let me = mwse.peer('me');
|
||||
|
||||
// Tüm kullanıcılar size mesaj iletebilir
|
||||
await peer.disablePairAuth();
|
||||
|
||||
// Sadece eşleşmiş kullanıcılar size mesaj iletebilir
|
||||
await peer.enablePairAuth();
|
||||
})
|
||||
```
|
||||
## Tünelleme ile mesajlaşma
|
||||
|
||||
MWSE üzerinde karşılıklı mesajlaşma için 2
|
||||
metodoloji bulunur bunlardan birisi serbest mesajlaşmadır ve
|
||||
bu şekilde çalışır
|
||||
```javascript
|
||||
mwse.scope(async () => {
|
||||
let me = mwse.peer('325a8f7f-eaaf-4c21-855e-9e965c0d5ac9');
|
||||
|
||||
// Tüm kullanıcılar size mesaj iletebilir
|
||||
await peer.disablePairAuth();
|
||||
|
||||
// Bu şekilde serbest bir şekilde herhangi bir zamanda karşılıksız mesaj iletebilirsiniz
|
||||
peer.send({
|
||||
text: "Good morning"
|
||||
})
|
||||
|
||||
// Kullanıcı her hangi bir mesaj gönderdiğinde burası tetiklenir
|
||||
peer.on('message', message => {
|
||||
if(text.message == "Good morning")
|
||||
{
|
||||
// Eğer mesaj için bir cevap bekliyorsa cevap veriyoruz
|
||||
peer.send("You are welcome");
|
||||
}else{
|
||||
// Ancak mesaj önceden gönderdiğimiz isteğin cevabıysa görüntülüyoruz
|
||||
console.log("Reply is :", message) // --> You are welcome
|
||||
}
|
||||
})
|
||||
})
|
||||
```
|
||||
2. yöntem ise el sıkışmalı mesajlaşmadır ve gönderdiğiniz bir mesaja verilen karşılık olarak
|
||||
sistem, gelen mesajın gönderdiğiniz hangi mesaja karşılık olarak gönderildiğini tuttuğu için
|
||||
request/response şeklinde ilerleyebilir
|
||||
|
||||
```javascript
|
||||
mwse.scope(async () => {
|
||||
let peer = mwse.peer('325a8f7f-eaaf-4c21-855e-9e965c0d5ac9');
|
||||
let me = mwse.peer('me');
|
||||
|
||||
// Tüm kullanıcılar size mesaj iletebilir
|
||||
await me.disablePairAuth();
|
||||
|
||||
// Bizden istenecek veriler için önceden cevapları hazırlıyoruz
|
||||
me.on('request', ({body, response}) => {
|
||||
switch(body.message)
|
||||
{
|
||||
case "Good morning":{
|
||||
// do anything...
|
||||
response("You are welcome")
|
||||
break;
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
// Bu şekilde serbest bir şekilde herhangi bir zamanda karşılıksız mesaj iletebilirsiniz
|
||||
let response = await peer.request({
|
||||
message: "Good morning"
|
||||
});
|
||||
|
||||
console.log(response) // response ---> You are welcome
|
||||
})
|
||||
```
|
||||
|
||||
Bu şekilde hem okunabilirlik artar hemde mesajlar karşılıklı olarak etki-tepki şeklinde ilerler
|
||||
|
||||
----
|
||||
|
||||
|
||||
### Oda kurma ve kapatma
|
||||
|
||||
Oda sistemi kullanıcıların bir araya gelerek, tek seferde bir grubun
|
||||
toplu olarak birbirleriyle mesajlaşabileceği bir yapıdır.
|
||||
Kişiler birbirlerini bulabilir, toplu mesajlar iletebilirler, odaya
|
||||
katılabilir veya ayrılabilirler
|
||||
|
||||
|
||||
Odanın ayarlarını, odayı ilk oluşturan kişi belirler ve oda bir kez oluşturulduğunda yeniden aynı isimle oda açılamaz
|
||||
Oda türü (joinType) herkese açık `free`, davet ile `invite`, şifreli `password` veya herkese kapalı `lock` olabilir.
|
||||
|
||||
```javascript
|
||||
|
||||
mwse.scope(async () => {
|
||||
|
||||
let room = mwse.room({
|
||||
name: "Oda ismi", // odanın görünür ismi
|
||||
description: "Oda açıklaması", // odanın görünecek ismi
|
||||
joinType: "free", // herkese açık oda
|
||||
credential: "****", // varsa şifre
|
||||
notifyActionInvite: false, // yeni biri katılmak istediğinde tüm peerlere haber iletme özelliği
|
||||
notifyActionJoined: true, // yeni biri katıldığında tüm peerlere haber iletir
|
||||
notifyActionEjected: true, // Biri odadan ayrıldığında tüm peerlere haber iletir
|
||||
ifexistsJoin: false // true ayarlanırsa, oluşturma aşamasında oda zaten var yanıtı alırsa hata vermek yerine odaya katılır
|
||||
});
|
||||
|
||||
// Verilen isime ait odaya katılmak için bu komut yeterlidir
|
||||
await room.join(); // --> odaya katılırken sorun oluşursa hata fırlatır
|
||||
|
||||
// Verilen ayarlara sahip odayı oluşturmak için aşağıdaki komut yeterlidir
|
||||
await room.createRoom(); // -> oda oluştururken sorun oluşursa hata fırlatır
|
||||
|
||||
// Var olan bir odadan ayrılmak için bu komut kullanılabilir
|
||||
await room.eject();
|
||||
|
||||
// İçinde bulunduğu odanın tüm eşlerinin idsini verir
|
||||
let peers = await room.fetchPeers();
|
||||
});
|
||||
```
|
||||
|
||||
### Oda içerisinde iletişim
|
||||
|
||||
Odaya katıldıktan sonra katılan kişiler `room` üzerinden mesaj iletebilirsiniz, verilen her mesajı sistem istisnasız tüm oda katılımcılarına iletmekten sorumludur
|
||||
Oda içerisindeki kişiler ile oda içindeki kişilerin listesini alarak özel iletişimede geçebilirsiniz ancak aynı odadaki kişiler sistem tarafında yinede güvenilir kabul edilmez
|
||||
Sistem pairAuth güvenliği kapalı olan kişilere mesajlar iletir ancak açık olan kullanıcıların her biri için ayrı ayrı eşleşme isteği göndermelisiniz
|
||||
|
||||
```javascript
|
||||
|
||||
mwse.scope(async () => {
|
||||
|
||||
let room = mwse.room({
|
||||
name: "Oda ismi", // odanın görünür ismi
|
||||
description: "Oda açıklaması", // odanın görünecek ismi
|
||||
joinType: "free", // herkese açık oda
|
||||
notifyActionJoined: true, // yeni biri katıldığında tüm peerlere haber iletir
|
||||
ifexistsJoin: false // true ayarlanırsa, oluşturma aşamasında oda zaten var yanıtı alırsa hata vermek yerine odaya katılır
|
||||
});
|
||||
|
||||
// Verilen ayarlara sahip odayı oluşturmak için aşağıdaki komut yeterlidir
|
||||
await room.createRoom(); // -> oda oluştururken sorun oluşursa hata fırlatır
|
||||
|
||||
// Oda içerisinde mesaj gönderildiğinde gönderilen paketi dinlemek için aşağıdaki komut kullanılabilir
|
||||
room.on('message', message => {
|
||||
// Odaya `message` paketi iletildi
|
||||
})
|
||||
|
||||
// Odaya yeni birisi katıldığında haber almak için aşağıdaki komut kullanılabilir
|
||||
room.on('join', peer => {
|
||||
// Odaya katılan kişinin bilgisi peerde tutulur
|
||||
// Odaya katılan kişiyle bağlantı kurup, oda dışında kendisiyle iletişimede geçebilirsiniz
|
||||
peer.requestPair();
|
||||
})
|
||||
|
||||
// Odaya birisi ayrıldığında haber almak için aşağıdaki komut kullanılabilir
|
||||
room.on('eject', peer => {
|
||||
// Odadan ayrılan kişinin bilgisi peerde tutulur
|
||||
})
|
||||
|
||||
// Odadaki herkese mesaj iletmek için room içerisindeki send komutu kullanılabilir
|
||||
room.send({
|
||||
message: "Good year !"
|
||||
});
|
||||
|
||||
// Oda kapatıldığında close tetiklenir
|
||||
room.on('close', () => { })
|
||||
});
|
||||
```
|
||||
|
||||
### Odayı kapatma
|
||||
|
||||
Odalar odaya ait olan bağlantılar üzerine kurulur, tüm bağlantılar odadan çıktığında oda otomatik olarak kapatılır
|
||||

|
|
@ -1,5 +1,5 @@
|
|||
const { CLIENT_SEND_MESSAGE, CLIENT_UPDATE_PROP } = require("../IPC");
|
||||
const stats = require("../stats");
|
||||
const { CLIENT_SEND_MESSAGE, CLIENT_UPDATE_PROP } = require("./IPC");
|
||||
const stats = require("./stats");
|
||||
function Client()
|
||||
{
|
||||
/**
|
||||
|
@ -57,13 +57,13 @@ Client.clients = new Map();
|
|||
*/
|
||||
Client.prototype.peerRequest = function(client){
|
||||
let info = {};
|
||||
this.store.forEach((value, name) => info[name] = value);
|
||||
this.info.forEach((value, name) => info[name] = value);
|
||||
this.pairs.add(client.id);
|
||||
this.sync('pairs');
|
||||
client.send([{
|
||||
from: this.id,
|
||||
info
|
||||
},'request/pair']);
|
||||
client.send([
|
||||
{ from: this.id },
|
||||
'request/pair'
|
||||
]);
|
||||
};
|
||||
|
||||
Client.prototype.match = function(filterObject){
|
||||
|
@ -101,6 +101,7 @@ Client.prototype.isSecure = function(client)
|
|||
client = Client.clients.get(client);
|
||||
}else return false;
|
||||
}else if(!(client instanceof Client)){
|
||||
console.error("isSecure Client bir client veri tipinde değil")
|
||||
return false;
|
||||
};
|
||||
|
||||
|
@ -124,7 +125,7 @@ Client.prototype.isSecure = function(client)
|
|||
return false;
|
||||
}
|
||||
/**
|
||||
* @returns {{pairs:Map<string, Client>,roompairs:Map<string, Client>}}
|
||||
* @returns {{pairs:Map<string, Client>,roompairs:Map<string, Client>,intersection:Map<string, Client>}}
|
||||
*/
|
||||
Client.prototype.getSucureClients = function()
|
||||
{
|
||||
|
@ -132,9 +133,9 @@ Client.prototype.getSucureClients = function()
|
|||
let pairs = new Map();
|
||||
let roompairs = new Map();
|
||||
|
||||
for (const [id, client] of this.pairs)
|
||||
for (const id of this.pairs)
|
||||
{
|
||||
map.set(id, client)
|
||||
pairs.set(id, Client.clients.get(id))
|
||||
}
|
||||
|
||||
// Aynı odada bulunan kullanıcı
|
||||
|
@ -151,7 +152,11 @@ Client.prototype.getSucureClients = function()
|
|||
};
|
||||
return {
|
||||
pairs,
|
||||
roompairs
|
||||
roompairs,
|
||||
intersection : new Map([
|
||||
...pairs,
|
||||
...roompairs
|
||||
])
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -200,8 +205,30 @@ Client.prototype.send = function(obj){
|
|||
CLIENT_SEND_MESSAGE(this.id, obj, this.proxyProcess)
|
||||
}else{
|
||||
stats.ws_sended_packs++;
|
||||
this.socket.sendUTF(JSON.stringify(obj));
|
||||
if(this.socket.connected){
|
||||
this.socket.sendUTF(JSON.stringify(obj),err => {
|
||||
if(err && this.socket)
|
||||
{
|
||||
console.error("I/O: Hatalı yazma işlemi yapıldı",err.message)
|
||||
}
|
||||
});
|
||||
}else{
|
||||
console.error("Bağlantısı kopmuş yazma işlemi")
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Client.prototype.packWriteable = function(){
|
||||
return !!this.store.get("packrecaive")
|
||||
}
|
||||
Client.prototype.packReadable = function(){
|
||||
return !!this.store.get("packsending")
|
||||
}
|
||||
Client.prototype.peerInfoNotifiable = function(){
|
||||
return !!this.store.get("notifyPairInfo")
|
||||
}
|
||||
Client.prototype.roomInfoNotifiable = function(){
|
||||
return !!this.store.get("notifyRoomInfo")
|
||||
}
|
||||
|
||||
exports.Client = Client;
|
|
@ -6,25 +6,16 @@ let compression = require("compression");
|
|||
let {resolve} = require("path");
|
||||
let auth = require("express-basic-auth");
|
||||
|
||||
const {
|
||||
termoutput,
|
||||
HTTP_PORT,
|
||||
NETWORK_MASK,
|
||||
HTTP_AUTH,
|
||||
HTTP_AUTH_USERNAME,
|
||||
HTTP_AUTH_USERPASSWORD
|
||||
} = require("./config");
|
||||
|
||||
const { termoutput } = require("./config");
|
||||
let server = http.createServer();
|
||||
const stats = require("./stats");
|
||||
let app = express();
|
||||
server.addListener("request", app);
|
||||
|
||||
app.use(compression({
|
||||
level: 9
|
||||
}));
|
||||
|
||||
server.listen(HTTP_PORT,NETWORK_MASK,() => {
|
||||
server.listen(7707,'0.0.0.0',() => {
|
||||
termoutput && console.log("HTTP Service Running...");
|
||||
});
|
||||
server.addListener("error",(err)=> {
|
||||
|
@ -32,13 +23,6 @@ server.addListener("error",(err)=> {
|
|||
})
|
||||
exports.http = server;
|
||||
|
||||
let authorize = auth({
|
||||
users:{
|
||||
[HTTP_AUTH_USERNAME]: HTTP_AUTH_USERPASSWORD
|
||||
},
|
||||
challenge: true
|
||||
});
|
||||
|
||||
app.get("/script",(request, response)=>{
|
||||
response.sendFile(resolve("./script/index.js"))
|
||||
});
|
||||
|
@ -48,19 +32,25 @@ app.get("/test",(request, response)=>{
|
|||
app.get("/index.js.map",(request, response)=>{
|
||||
response.sendFile(resolve("./script/index.js.map"))
|
||||
});
|
||||
if(HTTP_AUTH)
|
||||
{
|
||||
app.get("/stream",(request, response)=>{
|
||||
response.sendFile(resolve("./public/index.html"))
|
||||
});
|
||||
app.use("/stream",express.static(resolve("./public")));
|
||||
app.get("/",authorize,(request, response)=>{
|
||||
response.sendFile(resolve("./script/index.html"))
|
||||
});
|
||||
app.post("/stats",authorize,(request, response)=>{
|
||||
response.json(stats.others);
|
||||
});
|
||||
}
|
||||
app.get("/stream",(request, response)=>{
|
||||
response.sendFile(resolve("./public/index.html"))
|
||||
});
|
||||
app.get("/",(request, response)=>{
|
||||
response.sendFile(resolve("./script/index.html"))
|
||||
});
|
||||
app.post("/stats",(request, response)=>{
|
||||
response.json(stats.others);
|
||||
});
|
||||
app.get("/console",(request, response)=>{
|
||||
response.sendFile(resolve("./console/index.html"))
|
||||
});
|
||||
app.get("/console/lib.js",(request, response)=>{
|
||||
setTimeout(()=> {
|
||||
response.sendFile(resolve("./console/lib.js"))
|
||||
}, Math.random() * 5_000 | 0)
|
||||
});
|
||||
app.use("/stream",express.static(resolve("./public")));
|
||||
app.use("/console/",express.static(resolve("./console")));
|
||||
|
||||
app.get("*",(request, response)=>{
|
||||
response.sendFile(resolve("./script/status.xml"))
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
process.on('message',data => {
|
||||
const { Client } = require("./Services/Client");
|
||||
const { Client } = require("./Client.js");
|
||||
const { Room } = require("./Services/Room");
|
||||
switch(data.type)
|
||||
{
|
||||
|
@ -10,10 +10,18 @@ process.on('message',data => {
|
|||
client.isProxy = true;
|
||||
client.proxyProcess = data.pid;
|
||||
client.id = data.uuid;
|
||||
Client.clients.set(client.id, client);
|
||||
if(Client.clients.has(client.id))
|
||||
{
|
||||
console.error("IPC: Zaten var olan kullanıcı oluşturuluyor")
|
||||
}else{
|
||||
Client.clients.set(client.id, client);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "CLIENT_UPDATE_PROP":{
|
||||
|
||||
data.value = transformDeserialization(data.value, data.typing);
|
||||
|
||||
slog("CLIENT_UPDATE_PROP");
|
||||
let client = Client.clients.get(data.uuid);
|
||||
client[data.name] = data.value;
|
||||
|
@ -22,15 +30,27 @@ process.on('message',data => {
|
|||
case "CLIENT_SEND_MESSAGE":{
|
||||
//slog("CLIENT_SEND_MESSAGE");
|
||||
let client = Client.clients.get(data.uuid);
|
||||
if(client.isProxy != true)
|
||||
if(client)
|
||||
{
|
||||
client.send(data.message)
|
||||
if(client.isProxy != true)
|
||||
{
|
||||
client.send(data.message)
|
||||
}else{
|
||||
console.error("IPC: Proxy olmayan bir client için IPC mesajı alındı")
|
||||
}
|
||||
}else{
|
||||
console.error("IPC: Olmayan bir kullanıcı için mesaj gönderiliyor")
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "CLIENT_DESTROY":{
|
||||
slog("CLIENT_DESTROY");
|
||||
Client.clients.delete(data.uuid);
|
||||
if(Client.clients.has(data.uuid))
|
||||
{
|
||||
Client.clients.delete(data.uuid);
|
||||
}else{
|
||||
console.error("IPC: Olmayan bir kullanıcı için silme gerçekleştiriliyor")
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "ROOM_CREATED":{
|
||||
|
@ -40,6 +60,10 @@ process.on('message',data => {
|
|||
break;
|
||||
}
|
||||
case "ROOM_UPDATE_PROP":{
|
||||
|
||||
data.value = transformDeserialization(data.value, data.typing);
|
||||
|
||||
|
||||
slog("ROOM_UPDATE_PROP");
|
||||
let room = Room.rooms.get(data.uuid);
|
||||
room[data.name] = data.value;
|
||||
|
@ -86,11 +110,16 @@ function CLIENT_CREATED(uuid)
|
|||
function CLIENT_UPDATE_PROP(uuid, name, value)
|
||||
{
|
||||
mlog("CLIENT_UPDATE_PROP");
|
||||
|
||||
let typing = value.__proto__.constructor.name;
|
||||
value = transformSerialization(value);
|
||||
|
||||
process.send({
|
||||
type:'CLIENT_UPDATE_PROP',
|
||||
uuid: uuid,
|
||||
name,
|
||||
value
|
||||
value,
|
||||
typing
|
||||
})
|
||||
};
|
||||
function CLIENT_SEND_MESSAGE(uuid, message, clusterPid)
|
||||
|
@ -126,11 +155,16 @@ function ROOM_CREATED(room)
|
|||
function ROOM_UPDATE_PROP(uuid, name, value)
|
||||
{
|
||||
mlog("ROOM_UPDATE_PROP");
|
||||
|
||||
let typing = value.__proto__.constructor.name;
|
||||
value = transformSerialization(value);
|
||||
|
||||
process.send({
|
||||
type:'ROOM_UPDATE_PROP',
|
||||
uuid: uuid,
|
||||
name,
|
||||
value
|
||||
value,
|
||||
typing
|
||||
})
|
||||
};
|
||||
|
||||
|
@ -173,6 +207,31 @@ function slog(command)
|
|||
console.log("S",process.pid, command)
|
||||
}
|
||||
|
||||
function transformSerialization(value)
|
||||
{
|
||||
switch(value.__proto__.constructor.name)
|
||||
{
|
||||
case "Map":{
|
||||
return [...value];
|
||||
}
|
||||
case "Set":{
|
||||
return [...value];
|
||||
}
|
||||
}
|
||||
}
|
||||
function transformDeserialization(value,type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case "Map":{
|
||||
return new Map(value);
|
||||
}
|
||||
case "Set":{
|
||||
return new Set(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
exports.CLIENT_CREATED = CLIENT_CREATED;
|
||||
exports.CLIENT_UPDATE_PROP = CLIENT_UPDATE_PROP;
|
||||
|
|
|
@ -1,7 +1,25 @@
|
|||
const { Client } = require("./Client.js");
|
||||
const { CLIENT_UPDATE_PROP } = require("../IPC.js");
|
||||
const { Client } = require("../Client.js");
|
||||
let {addService, addListener} = require("../WebSocket.js");
|
||||
|
||||
addListener('disconnect',(global, xclient)=>{
|
||||
const {intersection, pairs} = xclient.getSucureClients();
|
||||
for (const [clientid, client] of intersection)
|
||||
{
|
||||
client?.send([
|
||||
{
|
||||
id: clientid
|
||||
},
|
||||
"peer/disconnect"
|
||||
])
|
||||
}
|
||||
|
||||
for (const [id, peer] of pairs)
|
||||
{
|
||||
peer?.pairs.delete(xclient.id);
|
||||
xclient.pairs.delete(id);
|
||||
}
|
||||
});
|
||||
|
||||
addService(({
|
||||
client,
|
||||
message,
|
||||
|
@ -63,7 +81,7 @@ addService(({
|
|||
message: 'ALREADY-PAIRED'
|
||||
})
|
||||
}
|
||||
if(client.pairs.add(to))
|
||||
if(client.pairs.has(to))
|
||||
{
|
||||
return end({
|
||||
status: 'fail',
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const { Client } = require("./Client.js");
|
||||
const { Client } = require("../Client.js");
|
||||
let {randomUUID} = require("crypto");
|
||||
let {addService,addListener} = require("../WebSocket.js");
|
||||
const { Room } = require("./Room.js");
|
||||
|
@ -27,12 +27,37 @@ addService(({
|
|||
{
|
||||
case "pack/to":{
|
||||
let {to,pack,handshake} = message;
|
||||
|
||||
if(!client.packReadable()){
|
||||
console.error("Okunabilir olmayan client bir mesaj iletiyor")
|
||||
handshake && end({
|
||||
type: 'fail'
|
||||
})
|
||||
}
|
||||
|
||||
if(Client.clients.has(to))
|
||||
{
|
||||
let otherPeer = Client.clients.get(to);
|
||||
if(otherPeer.requiredPair && !otherPeer.pairs.has(to))
|
||||
if(otherPeer.requiredPair)
|
||||
{
|
||||
return handshake && end({
|
||||
if(!otherPeer.pairs.has(to))
|
||||
{
|
||||
console.error("Client, güvenilir olmayan bir cliente mesaj iletiyor")
|
||||
return handshake && end({
|
||||
type: 'fail'
|
||||
})
|
||||
}
|
||||
}else{
|
||||
if(!otherPeer.pairs.has(to))
|
||||
{
|
||||
otherPeer.pairs.add(client.id);
|
||||
client.pairs.add(otherPeer.id);
|
||||
}
|
||||
}
|
||||
|
||||
if(!otherPeer.packWriteable()){
|
||||
console.error("Client, yazılabilir olmayan bir cliente mesaj iletiyor")
|
||||
handshake && end({
|
||||
type: 'fail'
|
||||
})
|
||||
}
|
||||
|
@ -44,6 +69,7 @@ addService(({
|
|||
type: 'success'
|
||||
})
|
||||
}else{
|
||||
console.error("Client, olmayan bir cliente mesaj iletiyor")
|
||||
handshake && end({
|
||||
type: 'fail'
|
||||
})
|
||||
|
@ -55,16 +81,25 @@ addService(({
|
|||
if(Client.clients.has(to))
|
||||
{
|
||||
let otherPeer = Client.clients.get(to);
|
||||
if(otherPeer.requiredPair && !otherPeer.pairs.has(to))
|
||||
if(otherPeer.requiredPair)
|
||||
{
|
||||
return;
|
||||
if(!otherPeer.pairs.has(to))
|
||||
{
|
||||
console.error("Client, güvenilir olmayan bir clientden veri istiyor")
|
||||
return handshake && end({
|
||||
type: 'fail'
|
||||
})
|
||||
}
|
||||
}else{
|
||||
otherPeer.pairs.add(client.id);
|
||||
client.pairs.add(otherPeer.id);
|
||||
}
|
||||
otherPeer.send([{
|
||||
from: client.id,
|
||||
pack: pack,
|
||||
id:messageId
|
||||
}, 'request']);
|
||||
};
|
||||
}else console.error("request/to error not finded Peer");
|
||||
break;
|
||||
}
|
||||
case "response/to":{
|
||||
|
@ -74,34 +109,52 @@ addService(({
|
|||
let otherPeer = Client.clients.get(to);
|
||||
if(otherPeer.requiredPair && !otherPeer.pairs.has(to))
|
||||
{
|
||||
console.error("response istenen peer güvenli değil")
|
||||
return;
|
||||
}
|
||||
otherPeer.send([{
|
||||
from: client.id,
|
||||
pack: pack
|
||||
}, id]);
|
||||
};
|
||||
}else console.error("response/to error not finded Peer");
|
||||
break;
|
||||
}
|
||||
case "pack/room":{
|
||||
let {to,pack, handshake,wom} = message;
|
||||
|
||||
|
||||
if(!client.packReadable()){
|
||||
console.error("Client paketi okumak için müsait değil")
|
||||
handshake && end({
|
||||
type: 'fail'
|
||||
})
|
||||
}
|
||||
|
||||
if(Room.rooms.has(to))
|
||||
{
|
||||
if(!client.rooms.has(to))
|
||||
{
|
||||
console.error("Client katılmadığı bir odaya mesaj iletiyor")
|
||||
return handshake && end({
|
||||
type: 'fail'
|
||||
})
|
||||
};
|
||||
Room.rooms.get(to).send([{
|
||||
from: to,
|
||||
pack: pack,
|
||||
sender: client.id
|
||||
}, 'pack/room'], wom ? client.id : void 0);
|
||||
Room.rooms.get(to).send(
|
||||
[
|
||||
{
|
||||
from: to,
|
||||
pack: pack,
|
||||
sender: client.id
|
||||
}, 'pack/room'
|
||||
],
|
||||
wom ? client.id : void 0,
|
||||
client => client.packWriteable()
|
||||
);
|
||||
handshake && end({
|
||||
type: 'success'
|
||||
})
|
||||
}else{
|
||||
console.error("Olmayan oda için veri gönderme isteniyor")
|
||||
handshake && end({
|
||||
type: 'fail'
|
||||
})
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const { Client } = require("./Client");
|
||||
const { Client } = require("../Client");
|
||||
let {addService, addListener} = require("../WebSocket.js");
|
||||
|
||||
class APNumber{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const { Client } = require("./Client.js");
|
||||
const { Client } = require("../Client.js");
|
||||
let {randomUUID,createHash} = require("crypto");
|
||||
const joi = require("joi");
|
||||
let {addService,addListener} = require("../WebSocket.js");
|
||||
|
@ -161,11 +161,19 @@ Room.fromJSON = function(data, room){
|
|||
)
|
||||
return room;
|
||||
};
|
||||
Room.prototype.send = function(obj, withOut){
|
||||
/**
|
||||
*
|
||||
* @param {any} obj
|
||||
* @param {string} withOut
|
||||
* @param {(client:Client) => boolean} map
|
||||
*/
|
||||
Room.prototype.send = function(obj, withOut, map){
|
||||
for (const client of this.clients.values()) {
|
||||
if(client.id != withOut)
|
||||
{
|
||||
client.send(obj);
|
||||
(
|
||||
map ? map(client) : 1
|
||||
) && client.send(obj);
|
||||
}
|
||||
}
|
||||
termoutput && term.green("Room bulk message ").white(this.name," in ").yellow(this.clients.size + "").white(" clients")('\n');
|
||||
|
@ -176,11 +184,18 @@ Room.prototype.send = function(obj, withOut){
|
|||
Room.prototype.join = function(client){
|
||||
if(this.notifyActionJoined)
|
||||
{
|
||||
this.send([{
|
||||
id: client.id,
|
||||
roomid: this.id,
|
||||
ownerid: this.owner.id
|
||||
},'room/joined']);
|
||||
this.send(
|
||||
[
|
||||
{
|
||||
id: client.id,
|
||||
roomid: this.id,
|
||||
ownerid: this.owner.id
|
||||
},
|
||||
'room/joined'
|
||||
],
|
||||
void 0,
|
||||
client => client.peerInfoNotifiable()
|
||||
);
|
||||
};
|
||||
client.rooms.add(this.id);
|
||||
this.clients.set(client.id, client);
|
||||
|
@ -203,11 +218,18 @@ Room.prototype.down = function(){
|
|||
Room.prototype.eject = function(client){
|
||||
if(this.notifyActionEjected)
|
||||
{
|
||||
this.send([{
|
||||
id: client.id,
|
||||
roomid: this.id,
|
||||
ownerid: this.owner.id
|
||||
},'room/ejected']);
|
||||
this.send(
|
||||
[
|
||||
{
|
||||
id: client.id,
|
||||
roomid: this.id,
|
||||
ownerid: this.owner.id
|
||||
},
|
||||
'room/ejected'
|
||||
],
|
||||
client.id,
|
||||
client => client.peerInfoNotifiable()
|
||||
);
|
||||
}
|
||||
client.rooms.delete(this.id);
|
||||
this.clients.delete(client.id);
|
||||
|
@ -697,14 +719,20 @@ addService(({
|
|||
}
|
||||
room.info.set(name, value);
|
||||
|
||||
room.send([
|
||||
{
|
||||
name,
|
||||
value,
|
||||
roomId:room.id
|
||||
},
|
||||
"room/info"
|
||||
], client.id);
|
||||
room.send(
|
||||
[
|
||||
{
|
||||
name,
|
||||
value,
|
||||
roomId:room.id
|
||||
},
|
||||
"room/info"
|
||||
],
|
||||
client.id,
|
||||
client => {
|
||||
return client.roomInfoNotifiable()
|
||||
}
|
||||
);
|
||||
|
||||
return end({
|
||||
status: "success"
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
let {addService,addListener} = require("../WebSocket.js");
|
||||
|
||||
const Stdoutput = [
|
||||
["notifyPairInfo", true],
|
||||
["packrecaive", true],
|
||||
["packsending", true],
|
||||
["notifyRoomInfo", true]
|
||||
];
|
||||
|
||||
addListener('connect',(global, client)=>{
|
||||
for (const [name, defaultValue] of Stdoutput)
|
||||
{
|
||||
client.store.set(name, defaultValue);
|
||||
}
|
||||
client.sync('store');
|
||||
});
|
||||
|
||||
|
||||
|
||||
addService(({
|
||||
client,
|
||||
end,
|
||||
global,
|
||||
message,
|
||||
next,
|
||||
response
|
||||
})=>{
|
||||
let {type, value} = message;
|
||||
switch(type)
|
||||
{
|
||||
// enable/disable pair/info messages
|
||||
case 'connection/pairinfo':{
|
||||
client.store.set("notifyPairInfo", !!value)
|
||||
client.sync('store');
|
||||
end(true);
|
||||
break;
|
||||
}
|
||||
case 'connection/roominfo':{
|
||||
client.store.set("notifyRoomInfo", !!value)
|
||||
client.sync('store');
|
||||
end(true);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case 'connection/packrecaive':{
|
||||
client.store.set("packrecaive", !!value)
|
||||
client.sync('store');
|
||||
end(true);
|
||||
break;
|
||||
}
|
||||
case 'connection/packsending':{
|
||||
client.store.set("packsending", !!value)
|
||||
client.sync('store');
|
||||
end(true);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'connection/reset':{
|
||||
for (const [name, defaultValue] of Stdoutput)
|
||||
{
|
||||
client.store.set(name, defaultValue);
|
||||
}
|
||||
client.sync('store');
|
||||
end(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
|
@ -3,7 +3,7 @@
|
|||
let websocket = require("websocket");
|
||||
let {http} = require("./HTTPServer");
|
||||
let {randomUUID} = require("crypto");
|
||||
const { Client } = require("./Services/Client");
|
||||
const { Client } = require("./Client.js");
|
||||
const { termoutput } = require("./config");
|
||||
const { CLIENT_CREATED, CLIENT_DESTROY } = require("./IPC");
|
||||
const stats = require("./stats");
|
||||
|
@ -63,10 +63,18 @@ wsServer.addListener("connect",(socket) => {
|
|||
stats.mwse_clients--;
|
||||
emit("disconnect", global, xClient);
|
||||
CLIENT_DESTROY(id);
|
||||
Client.clients.set(id, xClient);
|
||||
Client.clients.delete(id);
|
||||
clearInterval(timer);
|
||||
clearInterval(pingTimer);
|
||||
});
|
||||
|
||||
let pingTimer = setInterval(()=> socket.ping('saQut') , 10_000);
|
||||
|
||||
socket.addListener("pong",validationText => {
|
||||
if(validationText.toString('utf8') != "saQut"){
|
||||
socket.close();
|
||||
}
|
||||
})
|
||||
socket.addListener("message",({type,utf8Data}) => {
|
||||
stats.ws_recaived_packs++;
|
||||
stats.ws_total_packs++;
|
||||
|
|
|
@ -1,15 +1 @@
|
|||
const {resolve} = require("node:path");
|
||||
|
||||
exports.termoutput = false;
|
||||
|
||||
exports.HTTP_PORT = 7707;
|
||||
exports.NETWORK_MASK = '0.0.0.0'; //---> Sadece local için "127.0.0.1" heryerde çalışması için "0.0.0.0"
|
||||
|
||||
exports.HTTP_AUTH = true;
|
||||
exports.HTTP_AUTH_USERNAME = 'saqut';
|
||||
exports.HTTP_AUTH_USERPASSWORD = 'yum81633';
|
||||
|
||||
exports.LOADBALANCE_CPU = false; // ---> Cpu number (2,3,4...) for load balancer process or false for single thread (no load balancer and multiprocess)
|
||||
|
||||
exports.IPALLOCATION_DB = resolve(__dirname,"../database/ipallocation.db");
|
||||
exports.IPALLOCATION_STORE_TYPE = "memory" // or file
|
||||
exports.termoutput = false;
|
|
@ -6,17 +6,17 @@ require("./Services/Auth.js");
|
|||
require("./Services/Room.js");
|
||||
require("./Services/DataTransfer.js");
|
||||
require("./Services/IPPressure.js");
|
||||
require("./module/IPAllocation.js");
|
||||
|
||||
process.on('unhandledRejection',()=>{
|
||||
require("./Services/Session.js");
|
||||
|
||||
process.on('unhandledRejection',(reason, promise)=>{
|
||||
console.log("Process unhandledRejection",{reason, promise})
|
||||
});
|
||||
process.on('rejectionHandled',()=>{
|
||||
|
||||
process.on('rejectionHandled',(promise)=>{
|
||||
console.log("Process rejectionHandled",{promise})
|
||||
});
|
||||
process.on('multipleResolves',()=>{
|
||||
|
||||
process.on('multipleResolves',(type, promise, value)=>{
|
||||
console.log("Process multipleResolves",{type, promise, value})
|
||||
});
|
||||
process.on('warning',()=>{
|
||||
|
||||
process.on('warning',(err)=>{
|
||||
console.log("Process warning", err)
|
||||
});
|
|
@ -1,224 +0,0 @@
|
|||
const knex = require("knex");
|
||||
const { IPALLOCATION_DB } = require("../config");
|
||||
const crypto = require("node:crypto");
|
||||
const moment = require("moment");
|
||||
|
||||
let IPDB = knex({
|
||||
client: "sqlite3",
|
||||
connection: exports.IPALLOCATION_STORE_TYPE == "memory" ? ":memory:" : IPALLOCATION_DB,
|
||||
useNullAsDefault: true
|
||||
});
|
||||
|
||||
let flovitNumber = [
|
||||
[
|
||||
8,
|
||||
12,
|
||||
24,
|
||||
48,
|
||||
52,
|
||||
56
|
||||
],
|
||||
[
|
||||
7,
|
||||
10,
|
||||
13,
|
||||
16,
|
||||
19,
|
||||
22,
|
||||
25,
|
||||
28,
|
||||
31,
|
||||
34,
|
||||
37,
|
||||
40,
|
||||
43,
|
||||
46,
|
||||
49,
|
||||
52,
|
||||
55,
|
||||
58,
|
||||
61,
|
||||
64,
|
||||
67,
|
||||
70,
|
||||
73,
|
||||
76,
|
||||
79,
|
||||
82
|
||||
]
|
||||
];
|
||||
|
||||
async function read(filter)
|
||||
{
|
||||
return await IPDB.table("iptable").where(filter).first();
|
||||
}
|
||||
async function has(filter)
|
||||
{
|
||||
return (
|
||||
await IPDB.table("iptable").where(filter).count('* as key').first()
|
||||
).key != 0;
|
||||
}
|
||||
async function flushAll()
|
||||
{
|
||||
await IPDB.table("iptable").delete();
|
||||
}
|
||||
async function write(value,filter)
|
||||
{
|
||||
await IPDB.table("iptable").where(filter).update(value);
|
||||
}
|
||||
async function create(value)
|
||||
{
|
||||
await IPDB.table("iptable").insert(value);
|
||||
}
|
||||
async function remove(...filterArgs)
|
||||
{
|
||||
await IPDB.table("iptable").where(...filterArgs).delete();
|
||||
}
|
||||
|
||||
async function migrate()
|
||||
{
|
||||
if(!await IPDB.schema.hasTable("iptable"))
|
||||
{
|
||||
await IPDB.schema.createTable("iptable",function(table){
|
||||
table.bigInteger("ipaddress").unsigned().primary();
|
||||
table.text("owner").unique();
|
||||
table.string("type", 50).defaultTo("client");
|
||||
table.dateTime("created").defaultTo(IPDB.fn.now());
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function iptobin(a,b,c,d)
|
||||
{
|
||||
const bin =
|
||||
((a | 0) << 24) |
|
||||
((b | 0) << 16) |
|
||||
((c | 0) << 8) |
|
||||
(d | 0);
|
||||
return bin;
|
||||
}
|
||||
function bintoip(bin)
|
||||
{
|
||||
if(typeof bin == "string")
|
||||
{
|
||||
bin = bin | 0;
|
||||
}
|
||||
const octet1 = (bin >>> 24) & 0xff;
|
||||
const octet2 = (bin >>> 16) & 0xff;
|
||||
const octet3 = (bin >>> 8) & 0xff;
|
||||
const octet4 = bin & 0xff;
|
||||
return [octet1,octet2,octet3,octet4];
|
||||
}
|
||||
function randomMaskINIT()
|
||||
{
|
||||
if(typeof bin == "string")
|
||||
{
|
||||
bin = bin.split('.').map(e => e | 0);
|
||||
}
|
||||
let globalmask = crypto.randomInt(flovitNumber[0].length);
|
||||
let macromask = crypto.randomInt(flovitNumber[1].length);
|
||||
|
||||
return [
|
||||
flovitNumber[0][globalmask],
|
||||
flovitNumber[1][macromask],
|
||||
0,
|
||||
0
|
||||
]
|
||||
}
|
||||
async function init()
|
||||
{
|
||||
await migrate();
|
||||
await flushAll();
|
||||
await create({
|
||||
ipaddress: 0, // globalmask & macromask
|
||||
owner: randomMaskINIT().join('.'),
|
||||
type: "system",
|
||||
created: moment().format()
|
||||
});
|
||||
hook()
|
||||
}
|
||||
init.inited = false;
|
||||
|
||||
async function getip(owner, type)
|
||||
{
|
||||
let call = await read({
|
||||
owner,
|
||||
type
|
||||
});
|
||||
return !call ? false : {
|
||||
ipaddress: call.ipaddress,
|
||||
date: call.created
|
||||
};
|
||||
}
|
||||
async function setip(owner, type, ip)
|
||||
{
|
||||
await getip(owner, type) ?
|
||||
await write({
|
||||
ipaddress: ip
|
||||
},{
|
||||
owner,
|
||||
type
|
||||
})
|
||||
:
|
||||
await create({
|
||||
ipaddress: ip,
|
||||
owner,
|
||||
type
|
||||
});
|
||||
}
|
||||
|
||||
async function allocateIP(owner, type, changeOverlord)
|
||||
{
|
||||
let [a,b,c,d] = [ ,,, ];
|
||||
if(changeOverlord)
|
||||
{
|
||||
[a,b,c,d] = randomMaskINIT();
|
||||
}else{
|
||||
let ipinfo = await read({
|
||||
ipaddress: 0,
|
||||
type: "system"
|
||||
});
|
||||
[a,b,c,d] = ipinfo.owner.split('.').map(e => e | 0);
|
||||
}
|
||||
|
||||
while(1)
|
||||
{
|
||||
if(d != 255)
|
||||
{
|
||||
d++;
|
||||
}else if(c != 255){
|
||||
c++;
|
||||
}else if(b != 255){
|
||||
b++;
|
||||
}else if(a != 255){
|
||||
a++;
|
||||
}else{
|
||||
[a,b,c,d] = randomMaskINIT();
|
||||
}
|
||||
let query = {
|
||||
ipaddress: iptobin(a,b,c,d)
|
||||
};
|
||||
let result = await has(query);
|
||||
if(result == false)
|
||||
{
|
||||
await create({
|
||||
ipaddress: iptobin(a,b,c,d),
|
||||
owner,
|
||||
type
|
||||
});
|
||||
await write({
|
||||
owner: [a,b,c,d].join('.')
|
||||
},{
|
||||
type: "system",
|
||||
ipaddress: 0
|
||||
});
|
||||
break;
|
||||
}else{
|
||||
console.log("Checking",[a,b,c,d].join('.'))
|
||||
}
|
||||
}
|
||||
return[a,b,c,d].join('.')
|
||||
}
|
||||
|
||||
process.nextTick(init);
|
|
@ -0,0 +1,508 @@
|
|||
function Hemex()
|
||||
{
|
||||
|
||||
};
|
||||
Hemex.EOL = "\n";
|
||||
/**
|
||||
* Hemex variable white space chars
|
||||
* @type {Number[]}
|
||||
*/
|
||||
Hemex.WhiteSpace = [
|
||||
9,10,11,12,13,32,133
|
||||
];
|
||||
/**
|
||||
* Current cursor position
|
||||
* @type {Number}
|
||||
*/
|
||||
Hemex.prototype.offset = 0;
|
||||
/**
|
||||
* Mapping offset points
|
||||
* @type {Number[]}
|
||||
*/
|
||||
Hemex.prototype.offsetMap = [];
|
||||
Hemex.prototype.beginPosition = function(){
|
||||
this.offsetMap.push(
|
||||
this.getLastPosition()
|
||||
)
|
||||
}
|
||||
/**
|
||||
* Adding current position to offset map
|
||||
*/
|
||||
Hemex.prototype.acceptPosition = function(){
|
||||
let t = this.offsetMap.pop();
|
||||
this.setLastPosition(t)
|
||||
}
|
||||
/**
|
||||
* Get text range current and parent offsets
|
||||
* @returns {[Number,Number]}
|
||||
*/
|
||||
Hemex.prototype.positionRange = function(){
|
||||
let len = this.offsetMap.length;
|
||||
if(len == 0)
|
||||
{
|
||||
return [0,this.offset]
|
||||
}else if(len == 1){
|
||||
return [this.offset,this.offsetMap[len - 1]]
|
||||
}else{
|
||||
return [this.offsetMap[len - 2],this.offsetMap[len - 1]]
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get text range between current offset and parent offset
|
||||
* @returns {String}
|
||||
*/
|
||||
Hemex.prototype.getPositionRange = function(){
|
||||
let u = this.positionRange();
|
||||
return this.text.slice(u[0],u[1])
|
||||
}
|
||||
/**
|
||||
* Cancel current position and return to parent offset
|
||||
*/
|
||||
Hemex.prototype.rejectPosition = function(){
|
||||
this.offsetMap.pop()
|
||||
}
|
||||
/**
|
||||
* Get current layer of position from last offset of map
|
||||
* @returns {Number}
|
||||
*/
|
||||
Hemex.prototype.getLastPosition = function(){
|
||||
return this.offsetMap.length == 0 ? this.offset : this.offsetMap.slice(-1)[0]
|
||||
}
|
||||
/**
|
||||
* Set last position offset from offset map last layer
|
||||
* @param {Number} n
|
||||
*/
|
||||
Hemex.prototype.setLastPosition = function(n){
|
||||
if(this.offsetMap.length == 0)
|
||||
this.offset = n
|
||||
else this.offsetMap[this.offsetMap.length - 1] = n
|
||||
}
|
||||
/**
|
||||
* Get current layer of position from last offset of map
|
||||
* Some as getLastPosition()
|
||||
* @returns {Number}
|
||||
*/
|
||||
Hemex.prototype.getOffset = function(){
|
||||
return this.getLastPosition()
|
||||
}
|
||||
/**
|
||||
* Set last position offset from offset map last layer and return it value
|
||||
* @param {Number} n
|
||||
* @returns {Number}
|
||||
*/
|
||||
Hemex.prototype.setOffset = function(n){
|
||||
this.setLastPosition(n);
|
||||
return this.getLastPosition()
|
||||
}
|
||||
/**
|
||||
* Get text length
|
||||
* @type {Number}
|
||||
*/
|
||||
Hemex.prototype.length = 0;
|
||||
|
||||
/**
|
||||
* Hemex lexing data
|
||||
* @type {String}
|
||||
*/
|
||||
Hemex.prototype.text = "";
|
||||
|
||||
/**
|
||||
* set lexing data
|
||||
* @param {String} text
|
||||
* @returns {void}
|
||||
*/
|
||||
Hemex.prototype.setText = function(text){
|
||||
this.offset = 0;
|
||||
this.length = text.length;
|
||||
this.offsetMap = [];
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
/**
|
||||
* get lexing all data
|
||||
* @returns {String}
|
||||
*/
|
||||
Hemex.prototype.getText = function(){
|
||||
return this.text;
|
||||
}
|
||||
/**
|
||||
* Get one character from cursor
|
||||
* @param {Number} n
|
||||
* @returns {String}
|
||||
*/
|
||||
Hemex.prototype.getChar = function(n){
|
||||
return this.text.charAt(n?this.getOffset()+n:this.getOffset())
|
||||
}
|
||||
/**
|
||||
* Boolean
|
||||
* @param {Number} n
|
||||
* @returns {String}
|
||||
*/
|
||||
Hemex.prototype.isChar = function(b){
|
||||
return this.getChar() == b
|
||||
}
|
||||
/**
|
||||
* Dump all data from cursor position to end of char
|
||||
* @param {Number} n
|
||||
*/
|
||||
Hemex.prototype.dump = function(n){
|
||||
return this.text.slice(this.getOffset(),this.getOffset()+n)
|
||||
}
|
||||
/**
|
||||
* Control coming end of line
|
||||
* @returns {Bollean}
|
||||
*/
|
||||
Hemex.prototype.isEnd = function(){
|
||||
return this.length > this.getOffset()
|
||||
}
|
||||
/**
|
||||
* Forward one char
|
||||
*/
|
||||
Hemex.prototype.nextChar = function(){
|
||||
this.setOffset(this.getOffset() + 1);
|
||||
}
|
||||
/**
|
||||
* Forward n char
|
||||
*/
|
||||
Hemex.prototype.toChar = function(n){
|
||||
this.setOffset(this.getOffset() + n);
|
||||
}
|
||||
/**
|
||||
* Reading while end of line
|
||||
* @returns {String}
|
||||
*/
|
||||
Hemex.prototype.getLine = function(){
|
||||
return this.of(function(){
|
||||
switch(this.getChar())
|
||||
{
|
||||
case Hemex.EOL: return false;
|
||||
default: return true;
|
||||
}
|
||||
}.bind(this))
|
||||
}
|
||||
/**
|
||||
* Read all data until the function returns false
|
||||
* @param {Boolean} p
|
||||
* @param {(char:String)=>Boolean} e
|
||||
* @returns {String}
|
||||
*/
|
||||
Hemex.prototype.of = function(e,p){
|
||||
let k = [],count=0;
|
||||
while(this.isEnd()){
|
||||
if(e(p,count)) k.push(this.getChar());
|
||||
else return k.join('');
|
||||
count++;
|
||||
this.nextChar();
|
||||
};
|
||||
return k.length == 0 ? false : k.join('')
|
||||
}
|
||||
Hemex.prototype.each = function(e,p){
|
||||
let k = [];
|
||||
while(this.isEnd())
|
||||
if(!e(p)) return;
|
||||
else this.nextChar();
|
||||
}
|
||||
Hemex.prototype.while = function(e,p){
|
||||
let k = [];
|
||||
while(this.isEnd())
|
||||
if(!e(p)) return;
|
||||
}
|
||||
/**
|
||||
* Controlling for current char type
|
||||
* @param {Boolean} reverse
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
Hemex.prototype.isNumber = function(reverse){
|
||||
let c = this.getChar().charCodeAt(0);
|
||||
let result = c >= 48 && c <= 57;
|
||||
return reverse ? !result : result;
|
||||
}
|
||||
/**
|
||||
* Read all data until char type is not number
|
||||
* @param {Boolean} reverse
|
||||
* @returns {String}
|
||||
*/
|
||||
Hemex.prototype.readNumbers = function(reverse){
|
||||
return this.of(this.isNumber.bind(this),reverse)
|
||||
}
|
||||
/**
|
||||
* Controlling for current char type
|
||||
* @param {Boolean} reverse
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
Hemex.prototype.isBigLetter = function(reverse){
|
||||
let c = this.getChar().charCodeAt(0);
|
||||
let result = c >= 97 && c <= 122;
|
||||
return reverse ? !result : result;
|
||||
}
|
||||
/**
|
||||
* Controlling for current char type
|
||||
* @param {Boolean} reverse
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
Hemex.prototype.isSmallLetter = function(reverse){
|
||||
let c = this.getChar().charCodeAt(0);
|
||||
let result = c >= 65 && c <= 90;
|
||||
return reverse ? !result : result;
|
||||
}
|
||||
/**
|
||||
* Controlling for current char type
|
||||
* @param {Boolean} reverse
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
Hemex.prototype.isLetter = function(reverse){
|
||||
let result = this.isSmallLetter() || this.isBigLetter()
|
||||
return reverse ? !result : result;
|
||||
}
|
||||
/**
|
||||
* Read all data until char type is not letter
|
||||
* @param {Boolean} reverse
|
||||
* @returns {String}
|
||||
*/
|
||||
Hemex.prototype.readLetters = function(reverse){
|
||||
return this.of(this.isLetter.bind(this),reverse)
|
||||
}
|
||||
/**
|
||||
* Controlling for current char type
|
||||
* @param {Boolean} reverse
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
Hemex.prototype.isWhiteSpace = function(reverse){
|
||||
let c = this.getChar(),ct = c.charCodeAt(0);
|
||||
let result = (
|
||||
c == '\n' ||
|
||||
c == '\r' ||
|
||||
c == '\t' ||
|
||||
c == ' ' ||
|
||||
Hemex.WhiteSpace.includes(ct)
|
||||
)
|
||||
return reverse ? !result : result;
|
||||
}
|
||||
/**
|
||||
* Read all data until char type is not white space
|
||||
* @param {Boolean} reverse
|
||||
* @returns {String}
|
||||
*/
|
||||
Hemex.prototype.readWhiteSpace = function(reverse){
|
||||
return this.of(this.isWhiteSpace.bind(this),reverse)
|
||||
}
|
||||
/**
|
||||
* Controlling data
|
||||
* @param {Boolean} reverse
|
||||
* @returns {String}
|
||||
*/
|
||||
Hemex.prototype.include = function(words,next){
|
||||
this.beginPosition();
|
||||
for(let i = 0; i<words.length; i++)
|
||||
{
|
||||
if(words[i] != this.getChar())
|
||||
{
|
||||
this.rejectPosition();
|
||||
return false;
|
||||
};
|
||||
this.nextChar();
|
||||
};
|
||||
if(next) this.acceptPosition();
|
||||
else this.rejectPosition();
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Controlling data
|
||||
* @param {Boolean} reverse
|
||||
* @returns {String|boolean}
|
||||
*/
|
||||
Hemex.prototype.includes = function(arrays,accept){
|
||||
this.beginPosition();
|
||||
let flags = Array.from(arrays).fill(true);
|
||||
let index = 0;
|
||||
this.each(function(){
|
||||
let stopLoop = true;
|
||||
for(let T in arrays)
|
||||
{
|
||||
if(!flags[T] || arrays[T].length <= index) continue;
|
||||
stopLoop = false;
|
||||
flags[T] &= arrays[T][index] == this.getChar()
|
||||
};
|
||||
index++;
|
||||
return !stopLoop && flags.filter(function(val){return val}).length != 0;
|
||||
}.bind(this));
|
||||
let result = arrays.filter(function(_,index){return flags[index]});
|
||||
if(accept) this.acceptPosition();
|
||||
else this.rejectPosition();
|
||||
return result.length == 0 ? false : result
|
||||
}
|
||||
/**
|
||||
* Parsing number formats like; 12 75.1 0xE7 0b10 +3.46
|
||||
* @returns {[String,Number]}
|
||||
*/
|
||||
Hemex.prototype.readNumber = function(){
|
||||
let data = [];
|
||||
let base = 10;
|
||||
let nextDot = false;
|
||||
let c = this.getChar();
|
||||
if(this.isChar('0'))
|
||||
{
|
||||
this.nextChar();
|
||||
switch(this.getChar())
|
||||
{
|
||||
case 'x':{
|
||||
base = 16;
|
||||
this.nextChar();
|
||||
data.push('0x')
|
||||
break;
|
||||
}
|
||||
case 'b':{
|
||||
base = 2;
|
||||
this.nextChar();
|
||||
data.push('0b')
|
||||
break;
|
||||
}
|
||||
default:{
|
||||
base = 8;
|
||||
this.nextChar();
|
||||
data.push('0')
|
||||
}
|
||||
}
|
||||
}else base = 10;
|
||||
this.each(()=>{
|
||||
switch(c = this.getChar())
|
||||
{
|
||||
case '0':
|
||||
case '1':{
|
||||
data.push(c);
|
||||
break;
|
||||
}
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':{
|
||||
if(base >= 8){
|
||||
data.push(c);
|
||||
break;
|
||||
}else return false;
|
||||
}
|
||||
case '8':
|
||||
case '9':{
|
||||
if(base >= 10){
|
||||
data.push(c);
|
||||
break;
|
||||
}else return false;
|
||||
}
|
||||
case 'A':
|
||||
case 'a':
|
||||
case 'B':
|
||||
case 'b':
|
||||
case 'C':
|
||||
case 'c':
|
||||
case 'D':
|
||||
case 'd':
|
||||
/* case 'E': case 'e': */
|
||||
case 'F':
|
||||
case 'f':{
|
||||
if(base >= 16){
|
||||
data.push(c);
|
||||
break;
|
||||
}else return false;
|
||||
}
|
||||
case '.':{
|
||||
if(!nextDot){
|
||||
if(data.length == 0){
|
||||
data.push("0");
|
||||
}else data.push(".");
|
||||
nextDot = true;
|
||||
isFloat = true;
|
||||
}else{
|
||||
throw new Error("Float number in Double dot");
|
||||
};
|
||||
break;
|
||||
}
|
||||
case 'E':
|
||||
case 'e':{
|
||||
if(this.getChar(1)!='+'){
|
||||
if(base == 16){
|
||||
data.push(c);
|
||||
break;
|
||||
}else return false;
|
||||
};
|
||||
if(data.length == 0){
|
||||
this.rejectPosition();
|
||||
return false;
|
||||
};
|
||||
data.push('e');
|
||||
this.nextChar();
|
||||
if(this.getChar()=='+' || this.getChar()=='-'){
|
||||
data.push(char());
|
||||
this.nextChar();
|
||||
};
|
||||
let result = null;
|
||||
this.each(()=>{
|
||||
switch(this.getChar()){
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':{
|
||||
data.push(this.getChar());
|
||||
this.nextChar();
|
||||
break;
|
||||
}
|
||||
default:{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
default:{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
return true
|
||||
});
|
||||
return data.length == 0 ? false : [data.join(''),base]
|
||||
}
|
||||
|
||||
Hemex.prototype.syntaxs = new Map();
|
||||
/**
|
||||
*
|
||||
* @param {string} name
|
||||
* @param {(hmx:Hemex, result: (result:any) => any,...args:any[]) => any} callback
|
||||
*/
|
||||
Hemex.prototype.syntax = function(name, callback){
|
||||
this.syntaxs.set(name, callback)
|
||||
}
|
||||
|
||||
Hemex.prototype.give = function(name, ...args){
|
||||
let sandbox = this.syntaxs.get(name);
|
||||
if(sandbox)
|
||||
{
|
||||
let res = undefined;
|
||||
hmx.beginPosition();
|
||||
if(sandbox(
|
||||
this,
|
||||
arg => {
|
||||
res = arg
|
||||
},
|
||||
...args
|
||||
))
|
||||
{
|
||||
hmx.acceptPosition();
|
||||
return res;
|
||||
}else{
|
||||
hmx.rejectPosition();
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param {Error} message
|
||||
*/
|
||||
Hemex.prototype.throw = function(message){
|
||||
throw new Error(message)
|
||||
};
|
|
@ -0,0 +1,21 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="tr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<base href="/console/">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>WebSocket Terminal</title>
|
||||
<style>
|
||||
body{
|
||||
background-color: black;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="terminal"></div>
|
||||
<script src="xterm.js"></script>
|
||||
<link rel="stylesheet" href="xterm.min.css">
|
||||
<script src="./Hemex.js"></script>
|
||||
<script src="lib.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,908 @@
|
|||
var term = new Terminal({
|
||||
cursorStyle: "underline",
|
||||
cols: 180,
|
||||
rows: 50
|
||||
});
|
||||
term.open(document.querySelector('#terminal'));
|
||||
|
||||
|
||||
function newLine(t = true, prompt = true) {
|
||||
t && term.write('\r\n');
|
||||
cursorPosition = 0;
|
||||
if(prompt)
|
||||
{
|
||||
term.write(DEFAULT_PROMPT);
|
||||
cursorPosition += CLEAR_STYLING(DEFAULT_PROMPT).length;
|
||||
}
|
||||
resetUserSpace()
|
||||
}
|
||||
|
||||
let waitms = ms => new Promise(ok => setTimeout(()=>ok(), ms));
|
||||
|
||||
let cursorPosition = 0;
|
||||
let _buffer = [];
|
||||
let COLOR_RESET = () => "\x1B[0m";
|
||||
let COLOR_TEXT = (r,g,b) => `\x1B[38;2;${r};${g};${b}m`;
|
||||
let COLOR_BACKGROUND = (r,g,b) => `\x1B[48;2;${r};${g};${b}m`;
|
||||
|
||||
let CURSOR_MOVE = (row, col) => `\x1B[${row};${col}H`;
|
||||
let CURSOR_MOVE_UP = () => `\x1B[A`;
|
||||
let CURSOR_MOVE_DOWN = () => `\x1B[B`;
|
||||
let CURSOR_MOVE_RIGHT = () => `\x1B[C`;
|
||||
let CURSOR_MOVE_LEFT = () => `\x1B[D`;
|
||||
|
||||
let CLEAR_SCREEN = () => `\x1B[2J`;
|
||||
let CLEAR_LINE = () => `\x1B[2K`;
|
||||
|
||||
term.write(CURSOR_MOVE(2,1));
|
||||
|
||||
let CLEAR_STYLING = (text) => text.toString().replace(/\x1B(.*?)m/ig,'');
|
||||
|
||||
function writeHi()
|
||||
{
|
||||
term.write(
|
||||
"Merhaba, "
|
||||
+ COLOR_TEXT(0,255,0)
|
||||
+ COLOR_BACKGROUND(32,32,32)
|
||||
+ ' saQut RC Shell '
|
||||
+ COLOR_RESET()
|
||||
+ "\n\n\r"
|
||||
);
|
||||
|
||||
newLine();
|
||||
}
|
||||
|
||||
let userSpace = {
|
||||
buffer: [],
|
||||
paddingChars: 0,
|
||||
size: 0
|
||||
};
|
||||
|
||||
function resetUserSpace()
|
||||
{
|
||||
userSpace = {
|
||||
buffer: [],
|
||||
paddingChars: 0,
|
||||
size: 0
|
||||
}
|
||||
}
|
||||
|
||||
function getCurrentLine()
|
||||
{
|
||||
return term
|
||||
.buffer
|
||||
.active
|
||||
.getLine(
|
||||
term
|
||||
.buffer
|
||||
.active
|
||||
.cursorY
|
||||
)
|
||||
.translateToString()
|
||||
}
|
||||
|
||||
|
||||
let pausedInput = false;
|
||||
let activeProgram = false;
|
||||
|
||||
term.onData(async chars => {
|
||||
if(pausedInput)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
if(chars.length > 1)
|
||||
{
|
||||
return await DefaultProcess(chars);
|
||||
}
|
||||
|
||||
if(chars.length == 1)
|
||||
{
|
||||
if(activeProgram)
|
||||
{
|
||||
if(activeProgram._sys.idleChar)
|
||||
{
|
||||
return activeProgram._sys.idleChar.triggerChar(chars);
|
||||
}
|
||||
}
|
||||
return await DefaultProcess(chars);
|
||||
}else if(activeProgram){
|
||||
return
|
||||
}
|
||||
|
||||
let tokens = [];
|
||||
chars.toString().replace(/(\x1B.+?m)|(\x1B\[.+)|(.+)/igm, (_,a,b,c,d,e,f,g) => {
|
||||
let charx = a || b || c;
|
||||
if(charx)
|
||||
{
|
||||
if(/^(\x1B.*?m)$|^(\x1B\[.*)$/i.test(charx))
|
||||
{
|
||||
tokens.push([charx,])
|
||||
}else{
|
||||
tokens.push([,charx])
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (const [code, chars] of tokens)
|
||||
{
|
||||
pausedInput = true;
|
||||
if(code)
|
||||
{
|
||||
await DefaultProcess(code);
|
||||
}else if(chars)
|
||||
{
|
||||
for (const char of chars.split(''))
|
||||
{
|
||||
await DefaultProcess(char);
|
||||
}
|
||||
}
|
||||
pausedInput = false;
|
||||
}
|
||||
})
|
||||
|
||||
async function DefaultProcess(char)
|
||||
{
|
||||
let contextchanged = false;
|
||||
switch(char)
|
||||
{
|
||||
// Backspace
|
||||
case '\x7f':
|
||||
if(userSpace.paddingChars > 0)
|
||||
{
|
||||
term.write('\b \b');
|
||||
cursorPosition--;
|
||||
|
||||
let after = userSpace.buffer.slice(0, userSpace.paddingChars - 1);
|
||||
let before = userSpace.buffer.slice(userSpace.paddingChars);
|
||||
userSpace.buffer = [
|
||||
...after,
|
||||
...before
|
||||
];
|
||||
userSpace.paddingChars--;
|
||||
userSpace.size--;
|
||||
contextchanged = true;
|
||||
|
||||
term.write(before.join('')+" \b");
|
||||
term.write(before.map(() => '\b').join(''));
|
||||
}
|
||||
break;
|
||||
// Enter
|
||||
case '\r':
|
||||
let command = userSpace.buffer.join('');
|
||||
|
||||
if(activeProgram && activeProgram._sys.idleReadline)
|
||||
{
|
||||
newLine(true, false);
|
||||
return activeProgram._sys.triggerReadline(command);
|
||||
}
|
||||
|
||||
let parsedCommand = ParseCommand(command);
|
||||
if(parsedCommand != false)
|
||||
{
|
||||
let program = parsedCommand.find(e => e.type == 'commandname').data;
|
||||
|
||||
pausedInput = true;
|
||||
|
||||
newLine(true, false);
|
||||
|
||||
await ExecuteCommand(
|
||||
program,
|
||||
parsedCommand
|
||||
);
|
||||
pausedInput = false;
|
||||
|
||||
newLine(false);
|
||||
}else{
|
||||
newLine();
|
||||
}
|
||||
break;
|
||||
case CURSOR_MOVE_LEFT():
|
||||
if(userSpace.paddingChars > 0)
|
||||
{
|
||||
userSpace.paddingChars--;
|
||||
term.write(CURSOR_MOVE_LEFT());
|
||||
}
|
||||
break;
|
||||
case CURSOR_MOVE_UP():
|
||||
case CURSOR_MOVE_DOWN():
|
||||
break;
|
||||
// Delete
|
||||
case "\x1B[3~":
|
||||
let after = userSpace.buffer.slice(0, userSpace.paddingChars);
|
||||
let before = userSpace.buffer.slice(userSpace.paddingChars + 1);
|
||||
term.write(before.join('')+" \b");
|
||||
term.write(before.map(() => '\b').join(''));
|
||||
userSpace.buffer = [
|
||||
...after,
|
||||
...before
|
||||
];
|
||||
userSpace.size--;
|
||||
contextchanged = true;
|
||||
break;
|
||||
case CURSOR_MOVE_RIGHT():
|
||||
if(userSpace.paddingChars < userSpace.size)
|
||||
{
|
||||
term.write(CURSOR_MOVE_RIGHT());
|
||||
userSpace.paddingChars++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
let printable = char.charCodeAt(0);
|
||||
if(printable < 32)
|
||||
{
|
||||
return
|
||||
}
|
||||
// insert or append ?
|
||||
if(userSpace.paddingChars == userSpace.size)
|
||||
{
|
||||
term.write(char);
|
||||
|
||||
userSpace.buffer = [
|
||||
...userSpace.buffer.slice(0, userSpace.paddingChars),
|
||||
char,
|
||||
...userSpace.buffer.slice(userSpace.paddingChars),
|
||||
];
|
||||
|
||||
userSpace.paddingChars++;
|
||||
userSpace.size++;
|
||||
cursorPosition++;
|
||||
contextchanged = true;
|
||||
|
||||
}else{
|
||||
|
||||
let after = userSpace.buffer.slice(0, userSpace.paddingChars);
|
||||
let before = userSpace.buffer.slice(userSpace.paddingChars);
|
||||
|
||||
userSpace.buffer = [
|
||||
...after,
|
||||
char,
|
||||
...before
|
||||
];
|
||||
|
||||
term.write(char);
|
||||
term.write(before.join(''));
|
||||
term.write(before.map(() => '\b').join(''));
|
||||
contextchanged = true;
|
||||
userSpace.paddingChars++;
|
||||
userSpace.size++;
|
||||
cursorPosition++;
|
||||
}
|
||||
}
|
||||
|
||||
if(!activeProgram)
|
||||
{
|
||||
contextchanged && COLORIZE_LINE();
|
||||
}
|
||||
};
|
||||
|
||||
async function COLORIZE_LINE()
|
||||
{
|
||||
let before = userSpace.buffer.slice(0, userSpace.paddingChars);
|
||||
let after = userSpace.buffer.slice(userSpace.paddingChars);
|
||||
let coloredCommand = CommandColorize(before.concat(after).join(''));
|
||||
|
||||
if(coloredCommand)
|
||||
{
|
||||
// Cursoru en başa al
|
||||
term.write(CURSOR_MOVE_LEFT().repeat(before.length));
|
||||
term.write(coloredCommand);
|
||||
term.write(CURSOR_MOVE_LEFT().repeat(after.length));
|
||||
}
|
||||
}
|
||||
|
||||
let USER_SPACE = "virtualhost";
|
||||
let USER_NAME = [
|
||||
147 + Math.random() * 25 | 0,
|
||||
200 + Math.random() * 56 | 0,
|
||||
0 + Math.random() * 256 | 0,
|
||||
0 + Math.random() * 256 | 0
|
||||
].join('.');
|
||||
|
||||
let DEFAULT_PROMPT = (
|
||||
COLOR_RESET()
|
||||
+ '['
|
||||
+ COLOR_TEXT(0,255,0)
|
||||
+ USER_SPACE
|
||||
+ ' '
|
||||
+ COLOR_TEXT(0,128,255)
|
||||
+ USER_NAME
|
||||
+ COLOR_RESET()
|
||||
+ '] $ '
|
||||
);
|
||||
|
||||
|
||||
writeHi();
|
||||
|
||||
let _color_command = [255,255,255];
|
||||
let _color_option = [128,128,255];
|
||||
let _color_stringdata = [128,255,64];
|
||||
|
||||
function CommandColorize(command)
|
||||
{
|
||||
let hmx = new Hemex();
|
||||
hmx.setText(command);
|
||||
|
||||
let output = [];
|
||||
|
||||
let commandBefore = hmx.of(() => !hmx.isLetter());
|
||||
|
||||
if(commandBefore.length != 0)
|
||||
{
|
||||
output.push(
|
||||
COLOR_TEXT(255,255,255),
|
||||
commandBefore,
|
||||
COLOR_RESET()
|
||||
)
|
||||
}
|
||||
|
||||
if(!hmx.isLetter())
|
||||
{
|
||||
return false
|
||||
}
|
||||
|
||||
let commandName = hmx.of(() => hmx.isLetter() || hmx.isNumber() || hmx.includes(['-','_',':','.','$']));
|
||||
|
||||
if(hmx.isEnd() && !hmx.isWhiteSpace())
|
||||
{
|
||||
return false
|
||||
}
|
||||
|
||||
output.push(
|
||||
COLOR_TEXT(..._color_command),
|
||||
commandName,
|
||||
COLOR_RESET()
|
||||
);
|
||||
|
||||
let all = [], stringstarted = false;
|
||||
hmx.each(() => {
|
||||
let char = hmx.getChar();
|
||||
switch(char)
|
||||
{
|
||||
case '\'':
|
||||
case '"':
|
||||
case '`':{
|
||||
if(stringstarted == false)
|
||||
{
|
||||
stringstarted = char;
|
||||
all.push(COLOR_TEXT(..._color_stringdata), char)
|
||||
}else if(stringstarted == char){
|
||||
stringstarted = false;
|
||||
all.push(char, COLOR_TEXT(..._color_option))
|
||||
}else{
|
||||
all.push(char)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
default:{
|
||||
if(all.length == 0)
|
||||
{
|
||||
all.push(COLOR_TEXT(..._color_option), char);
|
||||
}else{
|
||||
all.push(char)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
output.push(all.join(''))
|
||||
|
||||
output.push(COLOR_RESET())
|
||||
return output.join('')
|
||||
}
|
||||
|
||||
function ParseCommand(command)
|
||||
{
|
||||
let hmx = new Hemex();
|
||||
hmx.setText(command);
|
||||
|
||||
hmx.of(() => !hmx.isLetter());
|
||||
|
||||
if(!hmx.isLetter())
|
||||
{
|
||||
return false
|
||||
}
|
||||
|
||||
let onlyArgs = false;
|
||||
|
||||
let commandName = hmx.of(() => hmx.isLetter() || hmx.isNumber() || hmx.includes(['-','_',':','.','$']));
|
||||
|
||||
if(hmx.isEnd() && !hmx.isWhiteSpace())
|
||||
{
|
||||
return false
|
||||
}
|
||||
|
||||
hmx.readWhiteSpace();
|
||||
|
||||
let args = [];
|
||||
|
||||
let xargs = [], operation = 'option';
|
||||
|
||||
hmx.beginPosition();
|
||||
hmx.while(()=>{
|
||||
if(hmx.include('--') && operation == 'option')
|
||||
{
|
||||
xargs.length && (
|
||||
args.push({
|
||||
type: 'data',
|
||||
data: xargs.join('')
|
||||
}),
|
||||
xargs = []
|
||||
);
|
||||
|
||||
hmx.beginPosition();
|
||||
|
||||
hmx.include('--', true);
|
||||
let argumentkey = hmx.of(() => hmx.isLetter() || hmx.isNumber() || hmx.includes(['-','_',':','.','$']));
|
||||
|
||||
if(argumentkey == false)
|
||||
{
|
||||
hmx.rejectPosition();
|
||||
return true;
|
||||
}
|
||||
|
||||
args.push({
|
||||
type: "argument",
|
||||
data: argumentkey
|
||||
});
|
||||
|
||||
hmx.acceptPosition();
|
||||
|
||||
hmx.readWhiteSpace();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if(hmx.include('-') && operation == 'option')
|
||||
{
|
||||
xargs.length && (
|
||||
args.push({
|
||||
type: 'data',
|
||||
data: xargs.join('').trim()
|
||||
}),
|
||||
xargs = []
|
||||
);
|
||||
|
||||
hmx.beginPosition();
|
||||
hmx.nextChar();
|
||||
let argumentkey = hmx.of(() => hmx.isLetter() || hmx.isNumber());
|
||||
|
||||
if(argumentkey == false)
|
||||
{
|
||||
hmx.rejectPosition();
|
||||
return true;
|
||||
}
|
||||
|
||||
argumentkey.split('').forEach(e => {
|
||||
args.push({
|
||||
type: "flag",
|
||||
data: e
|
||||
})
|
||||
})
|
||||
|
||||
hmx.acceptPosition();
|
||||
|
||||
hmx.readWhiteSpace();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
let char;
|
||||
if((char = hmx.includes(['\'','"'])) && operation == 'option')
|
||||
{
|
||||
xargs.length && (
|
||||
args.push({
|
||||
type: 'data',
|
||||
data: xargs.join('')
|
||||
}),
|
||||
xargs = []
|
||||
);
|
||||
|
||||
let escapeChar = char[0];
|
||||
hmx.nextChar();
|
||||
|
||||
let data = [];
|
||||
|
||||
hmx.while(() => {
|
||||
let char = hmx.getChar();
|
||||
switch(hmx.getChar())
|
||||
{
|
||||
case escapeChar:{
|
||||
hmx.nextChar();
|
||||
return false;
|
||||
}
|
||||
default:{
|
||||
data.push(char);
|
||||
hmx.nextChar();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
args.push({
|
||||
type: "string",
|
||||
data: data.join('')
|
||||
})
|
||||
|
||||
hmx.readWhiteSpace();
|
||||
|
||||
return true;
|
||||
}
|
||||
xargs.push(hmx.getChar());
|
||||
if(hmx.isWhiteSpace())
|
||||
{
|
||||
operation = 'option';
|
||||
}else{
|
||||
operation = 'data';
|
||||
}
|
||||
|
||||
hmx.nextChar();
|
||||
|
||||
if(hmx.isEnd())
|
||||
{
|
||||
return true;
|
||||
}else{
|
||||
args.push({
|
||||
type: "data",
|
||||
data: xargs.join('')
|
||||
})
|
||||
return false;
|
||||
}
|
||||
});
|
||||
onlyArgs = hmx.getPositionRange();
|
||||
hmx.acceptPosition();
|
||||
|
||||
return [{
|
||||
type: "cmdline",
|
||||
data: command
|
||||
},{
|
||||
type: "commandname",
|
||||
data: commandName
|
||||
},{
|
||||
type: "arguments",
|
||||
data: onlyArgs
|
||||
}, ...args]
|
||||
}
|
||||
|
||||
function generatepipe()
|
||||
{
|
||||
pausedInput = true;
|
||||
|
||||
let events = {};
|
||||
|
||||
let gen = {
|
||||
stdin: {
|
||||
setPaused(boolean){
|
||||
pausedInput = Boolean(boolean);
|
||||
},
|
||||
async readline(){
|
||||
gen.stdin.setPaused(false);
|
||||
gen._sys.idleReadline = true;
|
||||
return await new Promise(ok => {
|
||||
events['readline'] = (result) => {
|
||||
gen.stdin.setPaused(true);
|
||||
gen._sys.idleReadline = false;
|
||||
ok(result)
|
||||
events['readline'] = null;
|
||||
};
|
||||
})
|
||||
},
|
||||
async getchar(){
|
||||
gen.stdin.setPaused(false);
|
||||
gen._sys.idleChar = true;
|
||||
return await new Promise(ok => {
|
||||
events['read'] = (result) => {
|
||||
gen.stdin.setPaused(true);
|
||||
gen._sys.idleChar = false;
|
||||
events['read'] = null;
|
||||
ok(result)
|
||||
};
|
||||
})
|
||||
}
|
||||
},
|
||||
stdout: {
|
||||
async write(...args){
|
||||
term.write(args.map(e => e.toString()).join(' '))
|
||||
},
|
||||
async writeln(...args){
|
||||
term.writeln(args.map(e => e.toString()).join(' '))
|
||||
}
|
||||
},
|
||||
stderr: {
|
||||
async write(...args){
|
||||
term.write(COLOR_TEXT(255,0,0));
|
||||
term.write(args.map(e => e.toString()).join(' '))
|
||||
term.write(COLOR_RESET());
|
||||
},
|
||||
async writeln(...args){
|
||||
term.write(COLOR_TEXT(255,0,0));
|
||||
term.writeln(args.map(e => e.toString()).join(' '))
|
||||
term.write(COLOR_RESET());
|
||||
}
|
||||
},
|
||||
_sys:{
|
||||
idleReadline: false,
|
||||
idleChar: false,
|
||||
triggerReadline(text){
|
||||
if(events['readline']) events['readline'](text)
|
||||
},
|
||||
triggerChar(text){
|
||||
if(events['read']) events['read'](text)
|
||||
},
|
||||
destroy(){
|
||||
gen.stdin.setPaused(false);
|
||||
events = void 0;
|
||||
gen._sys.idleReadline = false;
|
||||
gen._sys.idleChar = false;
|
||||
gen._sys = void 0;
|
||||
gen.stderr = void 0;
|
||||
gen.stdin = void 0;
|
||||
gen.stdout = void 0;
|
||||
activeProgram = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
activeProgram = gen;
|
||||
|
||||
return gen;
|
||||
}
|
||||
|
||||
async function ExecuteCommand(command, cmdline)
|
||||
{
|
||||
let Namespace = await CommandNamespace(command);
|
||||
if(Namespace == null)
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await new Promise(async (ok,reject) => {
|
||||
resetUserSpace();
|
||||
let program = new Namespace(generatepipe());
|
||||
program.exit = () => ok();
|
||||
try{
|
||||
let t = program.main(cmdline);
|
||||
if(t?.constructor?.name == 'AsyncFunction')
|
||||
{
|
||||
await t;
|
||||
}
|
||||
}catch(e){
|
||||
reject(e)
|
||||
}
|
||||
})
|
||||
}
|
||||
catch(exception)
|
||||
{
|
||||
term.writeln('');
|
||||
term.write(COLOR_TEXT(255,0,0));
|
||||
term.writeln('Yazılım hatası:');
|
||||
term.writeln('=========================');
|
||||
term.write(COLOR_RESET());
|
||||
term.writeln(exception.message);
|
||||
term.writeln(exception.stack.replace(/\n/g,'\r\n'));
|
||||
term.write(COLOR_TEXT(255,0,0));
|
||||
term.writeln('=========================');
|
||||
term.write(COLOR_RESET());
|
||||
}
|
||||
finally
|
||||
{
|
||||
pausedInput = false;
|
||||
activeProgram = void 0;
|
||||
}
|
||||
}
|
||||
|
||||
async function InspectRepo()
|
||||
{
|
||||
if(CommandNamespace.repos.find(e => e.downloaded == false))
|
||||
{
|
||||
term.writeln(COLOR_RESET()+"\r\nUpdating repos....")
|
||||
await wait(100);
|
||||
}else{
|
||||
term.writeln('');
|
||||
}
|
||||
for(const repo of CommandNamespace.repos)
|
||||
{
|
||||
if(repo.downloaded == false)
|
||||
{
|
||||
term.writeln(`Downloading:${COLOR_TEXT(0,255,0)} ${repo.name} ${COLOR_RESET()} ${repo.endpoint}`);
|
||||
await wait(100);
|
||||
let file = await DownloadRepoMetapack(repo.endpoint);
|
||||
repo.packages = file;
|
||||
term.writeln(`Downloaded:${COLOR_TEXT(0,255,0)} ${repo.name} ${COLOR_RESET()} ${repo.endpoint}`);
|
||||
await wait(100);
|
||||
repo.downloaded = true;
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
async function CommandNamespace(command)
|
||||
{
|
||||
let package = false;
|
||||
if(!CommandNamespace.namespaces.has(command))
|
||||
{
|
||||
await InspectRepo();
|
||||
for(const repo of CommandNamespace.repos)
|
||||
{
|
||||
for (const repopackage in repo.packages)
|
||||
{
|
||||
let packageName = repopackage;
|
||||
let meta = repo.packages[repopackage];
|
||||
let _command = meta.commands.find(_command => command == _command);
|
||||
|
||||
if(_command)
|
||||
{
|
||||
package = [packageName,meta];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(package == false)
|
||||
{
|
||||
term.writeln(COLOR_TEXT(255,0,0) + "'" + command + "' not found !" + COLOR_RESET());
|
||||
}else{
|
||||
term.writeln([
|
||||
COLOR_TEXT(0,255,0),
|
||||
package[0],
|
||||
COLOR_TEXT(200,200,200),
|
||||
" paketine ait olan ",
|
||||
COLOR_TEXT(0,255,0),
|
||||
command,
|
||||
COLOR_TEXT(200,200,200),
|
||||
" komutunu kullanabilmek için aşağıdaki komutunu çalıştırın"
|
||||
].join('') +
|
||||
"\r\n\n" +
|
||||
CommandColorize(`load '${package[0]}' from 'official'`)+
|
||||
"\n"
|
||||
);
|
||||
}
|
||||
}else{
|
||||
return CommandNamespace.namespaces.get(command);
|
||||
}
|
||||
}
|
||||
|
||||
function wait(ms)
|
||||
{
|
||||
return new Promise(ok => setTimeout(() => ok(),ms));
|
||||
}
|
||||
|
||||
async function DownloadRepoMetapack(endpoint)
|
||||
{
|
||||
let request = await fetch(endpoint,{
|
||||
method: "get",
|
||||
cache: "force-cache",
|
||||
priority: "high",
|
||||
redirect: "follow",
|
||||
referrerPolicy: "no-referrer"
|
||||
});
|
||||
|
||||
await wait(100);
|
||||
|
||||
try{
|
||||
let response = await request.json();
|
||||
return response;
|
||||
}catch
|
||||
{
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
CommandNamespace.namespaces = new Map();
|
||||
CommandNamespace.repos = [{
|
||||
name: "official",
|
||||
endpoint: new URL('/console/official/packages.json',window.location),
|
||||
downloaded: false,
|
||||
packages: {}
|
||||
}];
|
||||
|
||||
|
||||
|
||||
class SystemLoad{
|
||||
stdin = null;
|
||||
stdout = null;
|
||||
constructor(pipe){
|
||||
this.stdin = pipe.stdin;
|
||||
this.stdout = pipe.stdout;
|
||||
}
|
||||
printhelp()
|
||||
{
|
||||
this.stdout.writeln('Kullanım şekli: ');
|
||||
this.stdout.writeln('ExampleProgram paketini kurmak için aşağıdaki komutu yazmalısınız\r\n');
|
||||
this.stdout.writeln(
|
||||
CommandColorize(`load 'ExampleProgram'`)+"\r\n"
|
||||
);
|
||||
|
||||
}
|
||||
async main(args)
|
||||
{
|
||||
let m = false, nargs = args.filter(({type}) => {
|
||||
if(type == "arguments") return m = true, false;
|
||||
return m;
|
||||
});
|
||||
|
||||
let packname;
|
||||
if(nargs[0].type == "string")
|
||||
{
|
||||
packname = nargs[0].data;
|
||||
}else{
|
||||
this.printhelp();
|
||||
this.exit();
|
||||
return;
|
||||
}
|
||||
|
||||
if(CommandNamespace.repos.find(e => e.downloaded == false))
|
||||
{
|
||||
this.stdout.writeln(COLOR_RESET()+"\r\nUpdating repos....")
|
||||
}else{
|
||||
this.stdout.writeln('');
|
||||
}
|
||||
for(const repo of CommandNamespace.repos)
|
||||
{
|
||||
if(repo.downloaded == false)
|
||||
{
|
||||
this.stdout.writeln(`Downloading:${COLOR_TEXT(0,255,0)} ${repo.name} ${COLOR_RESET()} ${repo.endpoint}`);
|
||||
await wait(100);
|
||||
let file = await DownloadRepoMetapack(repo.endpoint.href);
|
||||
if(file == null){
|
||||
continue
|
||||
}
|
||||
repo.packages = file;
|
||||
this.stdout.writeln(`Downloaded:${COLOR_TEXT(0,255,0)} ${repo.name} ${COLOR_RESET()} ${repo.endpoint}`);
|
||||
await wait(100);
|
||||
repo.downloaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
let endpoints = CommandNamespace.repos.map(e => e.packages[packname] && e.packages[packname].endpoints.map(endpoint => new URL(endpoint,e.endpoint))).filter(e => !!e)
|
||||
|
||||
if(endpoints.length == 0)
|
||||
{
|
||||
term.writeln(COLOR_TEXT(255,0,0) + "'" + packname + "' repo not found !" + COLOR_RESET());
|
||||
await wait(100);
|
||||
this.exit();
|
||||
return;
|
||||
}
|
||||
|
||||
for (const endpoint of endpoints[0])
|
||||
{
|
||||
let href = endpoint.href;
|
||||
this.stdout.writeln(`Packet downloading :${COLOR_TEXT(0,255,0)} ${packname} ${COLOR_RESET()} ${endpoint.href}`);
|
||||
await wait(100);
|
||||
|
||||
let request = await fetch(href,{
|
||||
method: "get",
|
||||
cache: "force-cache",
|
||||
priority: "high",
|
||||
redirect: "follow",
|
||||
referrerPolicy: "no-referrer"
|
||||
});
|
||||
|
||||
this.stdout.writeln(`Packet unzip to :${COLOR_TEXT(0,255,0)} /mount/xpack/${packname}/ ${COLOR_RESET()}`);
|
||||
await wait(100);
|
||||
|
||||
let script = await request.text();
|
||||
|
||||
try{
|
||||
this.stdout.writeln(`Analyzing..`);
|
||||
await new Promise(ok => setTimeout(() => ok(),1000));
|
||||
(new Function(script))();
|
||||
this.stdout.writeln(`Process success`);
|
||||
await wait(100);
|
||||
}catch{
|
||||
this.stderr.writeln(`Process error`);
|
||||
await wait(100);
|
||||
}
|
||||
}
|
||||
this.exit();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
CommandNamespace.namespaces.set('load', SystemLoad);
|
|
@ -0,0 +1,51 @@
|
|||
class CommandJS{
|
||||
stdin = null;
|
||||
stdout = null;
|
||||
stderr = null;
|
||||
constructor(pipe){
|
||||
this.stdin = pipe.stdin;
|
||||
this.stdout = pipe.stdout;
|
||||
this.stderr = pipe.stderr;
|
||||
}
|
||||
async main(args)
|
||||
{
|
||||
let commandline = args.find(e => e.type == "arguments");
|
||||
if(commandline)
|
||||
{
|
||||
try{
|
||||
let t = eval(commandline.data);
|
||||
if(typeof t != "undefined")
|
||||
{
|
||||
this.stdout.writeln(JSON.stringify(t,null, ' ').replace(/\n/g,'\r\n'));
|
||||
}
|
||||
}catch(e){
|
||||
this.stderr.writeln(e.message);
|
||||
}
|
||||
}
|
||||
this.exit();
|
||||
}
|
||||
};
|
||||
|
||||
class CommandJSRaw{
|
||||
stdin = null;
|
||||
stdout = null;
|
||||
stderr = null;
|
||||
constructor(pipe){
|
||||
this.stdin = pipe.stdin;
|
||||
this.stdout = pipe.stdout;
|
||||
this.stderr = pipe.stderr;
|
||||
}
|
||||
async main(args)
|
||||
{
|
||||
let commandline = args.find(e => e.type == "arguments");
|
||||
if(commandline)
|
||||
{
|
||||
let t = eval(commandline.data);
|
||||
this.stdout.writeln(t);
|
||||
}
|
||||
this.exit();
|
||||
}
|
||||
};
|
||||
|
||||
CommandNamespace.namespaces.set('js', CommandJS);
|
||||
CommandNamespace.namespaces.set('jsecho', CommandJSRaw);
|
|
@ -0,0 +1,18 @@
|
|||
class CommandSet{
|
||||
stdin = null;
|
||||
stdout = null;
|
||||
stderr = null;
|
||||
constructor(pipe){
|
||||
this.stdin = pipe.stdin;
|
||||
this.stdout = pipe.stdout;
|
||||
this.stderr = pipe.stderr;
|
||||
}
|
||||
async main(args)
|
||||
{
|
||||
this.stdout.writeln(JSON.stringify(args,null, ' ').replace(/\n/g,'\r\n'));
|
||||
this.exit();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
CommandNamespace.namespaces.set('set', CommandSet);
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"native": {
|
||||
"endpoints": [
|
||||
"./native/js.js",
|
||||
"./native/set.js"
|
||||
],
|
||||
"commands": [
|
||||
"js",
|
||||
"jsecho",
|
||||
"set"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
Oluşturulmuş cihazlar | device list
|
||||
Yeni AudioContext | device create audio /dev/audio0
|
||||
Yeni HTMLVideoElement | device create video /dev/video0
|
||||
getUserMedia isteği | webcam 480x360 --audio /dev/audio0 --video /dev/video0
|
||||
AudioContext sesi dışarı verme | device /dev/audio0 --output speaker
|
||||
AudioContext sesi açma | device /dev/audio0 --value 100
|
||||
Videoyu oynatma | lightplayer --source /dev/video0 --target popup
|
||||
|
||||
|
||||
Tüm bağlantıları görme | rtc connections
|
||||
RTC Oluşturma | rtc create "peer-0"
|
||||
RTC offer verme | rtc "peer-0" create offer
|
||||
RTC offer alma | rtc "peer-0" emit offer "offer message"
|
||||
RTC answer verme | rtc "peer-0" create answer
|
||||
RTC answer alma | rtc "peer-0" emit answer "answer message"
|
||||
RTC answer verme | rtc "peer-0" create answer "answer message"
|
||||
RTC candidate alma | rtc "peer-0" getcandidate --all
|
||||
RTC candidate verme | rtc "peer-0" setcandidate
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1 @@
|
|||
.xterm{cursor:text;position:relative;user-select:none;-ms-user-select:none;-webkit-user-select:none}.xterm.focus,.xterm:focus{outline:0}.xterm .xterm-helpers{position:absolute;top:0;z-index:5}.xterm .xterm-helper-textarea{padding:0;border:0;margin:0;position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}.xterm .composition-view{background:#000;color:#fff;display:none;position:absolute;white-space:nowrap;z-index:1}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{background-color:#000;overflow-y:scroll;cursor:default;position:absolute;right:0;left:0;top:0;bottom:0}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.xterm .xterm-scroll-area{visibility:hidden}.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}.xterm.enable-mouse-events{cursor:default}.xterm .xterm-cursor-pointer,.xterm.xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{position:absolute;left:0;top:0;bottom:0;right:0;z-index:10;color:transparent;pointer-events:none}.xterm .xterm-accessibility-tree:not(.debug) ::selection{color:transparent}.xterm .xterm-accessibility-tree{user-select:text;white-space:pre}.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{text-decoration:double underline}.xterm-underline-3{text-decoration:wavy underline}.xterm-underline-4{text-decoration:dotted underline}.xterm-underline-5{text-decoration:dashed underline}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:overline underline}.xterm-overline.xterm-underline-2{text-decoration:overline double underline}.xterm-overline.xterm-underline-3{text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;position:absolute;top:0;right:0;pointer-events:none}.xterm-decoration-top{z-index:2;position:relative}
|
File diff suppressed because one or more lines are too long
Binary file not shown.
|
@ -1,93 +0,0 @@
|
|||
# Namespace
|
||||
|
||||
## Auth
|
||||
|
||||
### auth/public:
|
||||
- Eşleşme gerekmez, herkese açık hale getirir
|
||||
- İşlem bittiğinde success değeri verirr
|
||||
|
||||
### auth/private
|
||||
Eşleşme gerekir, biri size mesaj göndermek için onay alması gerekir
|
||||
Onaylandığında success gönder
|
||||
|
||||
### request/pair
|
||||
- private bir eşe onay isteği gönderirsiniz, eşe bildirim gider
|
||||
- Client online değilse fail CLIENT-NOT-FOUND mesajı döner
|
||||
- Zaten kabul etmişse success ALREADY-PAIRED mesajı döner
|
||||
- Zaten onay isteği göndermişseniz fail ALREADY-REQUESTED mesajı döner
|
||||
- Gönderildiğinde success REQUESTED mesajı döner
|
||||
- Eş isteğe herhangi bir cevap dönerse request/pair veya rejected/pair tetiklenir ve from değerleriyle kim oldukları bildirilir
|
||||
|
||||
### accept/pair
|
||||
- Uzak eşin onay isteğine onay verirsiniz
|
||||
|
||||
### accept/pair
|
||||
- Uzak eşin onay isteğine onay verirsiniz
|
||||
|
||||
### reject/pair
|
||||
- Uzak eşin isteğini reddedersiniz
|
||||
|
||||
### pair/list
|
||||
- Erişebileceğiniz private eşlerin ve sizinle etkileşime giren eşlerin
|
||||
listesini verir
|
||||
|
||||
### auth/login
|
||||
- saQut Account hesabıyla ilgili ön tanımlı hızlı işlem yapar
|
||||
|
||||
### auth/check
|
||||
- saQut Account hesabıyla ilgili ön tanımlı hızlı işlem yapar
|
||||
|
||||
### auth/logout
|
||||
- saQut Account hesabıyla ilgili ön tanımlı hızlı işlem yapar
|
||||
|
||||
## Room
|
||||
|
||||
### myroom-info
|
||||
|
||||
Kendinize özel açılan odanın bilgisini verir
|
||||
|
||||
### room-peers
|
||||
|
||||
İçerisinde bulunduğunuz odanın içerisinde bulunan eşlerin listesini verir
|
||||
|
||||
### room-info
|
||||
|
||||
İçerisinde bulunduğunuz odanın bilgisini verir
|
||||
|
||||
### joinedrooms
|
||||
|
||||
Katıldığınız odaların listesini verir
|
||||
|
||||
### closeroom
|
||||
|
||||
Sahibi olduğunuz odayı kapatır
|
||||
|
||||
### create-room
|
||||
|
||||
Yeni bir oda oluşturur
|
||||
|
||||
### joinroom
|
||||
|
||||
Bir odaya katılır veya sahibine katılma isteği gönderirsiniz
|
||||
|
||||
### accept/invite-room
|
||||
|
||||
Gizli bir odaya katılma isteği gödneren kişiyi odaya kabul edersiniz
|
||||
|
||||
### reject/invite-room
|
||||
|
||||
Gizli bir odaya katılma isteği gödneren kişiyi reddedersiniz
|
||||
|
||||
### room/list
|
||||
|
||||
Herkese açık olan tüm odaları listeler
|
||||
|
||||
## Data transfer
|
||||
|
||||
### pack/to
|
||||
|
||||
Diğer eşe bir paket gönderir
|
||||
|
||||
### pack/room
|
||||
|
||||
Bir odaya katılmış tüm üyelere, oda üzerinden bir mesaj gönderir
|
|
@ -1,91 +0,0 @@
|
|||
## Kurulum
|
||||
|
||||
### Proje ortamına kurulumu
|
||||
|
||||
```html
|
||||
<script src="https://ws.saqut.com/script"></script>
|
||||
```
|
||||
|
||||
### Geliştirme ortamına kurulumu
|
||||
|
||||
```javascript
|
||||
const wsjs = new MWSE({
|
||||
endpoint: "https://ws.saqut.com/" // MSWS kurulu sunucu adresi
|
||||
});
|
||||
wsjs.scope(async () => {
|
||||
// Bağlantı sağlandığında burası tetiklenir
|
||||
})
|
||||
```
|
||||
|
||||
### Kendi bağlantı kimliğini öğrenme
|
||||
|
||||
```javascript
|
||||
wsjs.scope(async () => {
|
||||
let me = wsjs.peer('me'); // Kendi bağlantınız üzerinde işlem yaparken `me` olarak bahsedersiniz
|
||||
console.log(me.socketId); // Her eşin tekil bir socketIdsi vardır
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
### Sanal Adres ayırma / yeniden ayırma / kaldırma
|
||||
```javascript
|
||||
wsjs.scope(async () => {
|
||||
let me = wsjs.peer('me');
|
||||
|
||||
/**
|
||||
* Sanal adresler size veri gönderilmek istendiğinde veya etkileşime
|
||||
* geçilmesi istendiğinde ona socketId gibi bir UUID yerine sizi temsil eden daha kısa
|
||||
* ip adresi, sayı veya kısa bir kod ile aynı şeyleri yapmanıza olanak tanır.
|
||||
* Aynı anda hem sanal ip adres, sayı ve kısa koduna sahip olabilirsiniz
|
||||
* ancak aynı türden temsil koduna (mesela kısa koddan) birden fazla sahip olamazsınız
|
||||
* Yeni bir bağlantı daha açmanız gerekir
|
||||
**/
|
||||
|
||||
// Bağlantınıze özel sanal tekil ip adresi kaynağı ayırın
|
||||
let ipadress = await me.virtualPressure.allocAPIPAddress();
|
||||
|
||||
// Bağlantınıze özel sanal tekil numara kaynağı ayırın
|
||||
let numberaddress = await me.virtualPressure.allocAPNumber();
|
||||
|
||||
// Bağlantınıze özel sanal kod kaynağı ayırın
|
||||
let shortcodeadress = await me.virtualPressure.allocAPShortCode();
|
||||
|
||||
// Bütün bu kaynakları yenileriyle değiştirmek için
|
||||
// her birinin ayrı ayrı yeniden alma işlevleri vardır
|
||||
// Bir adresi yenilediğinizde artık eski adres kullanılmaz olur
|
||||
me.virtualPressure.reallocAPIPAddress();
|
||||
me.virtualPressure.reallocAPNumber();
|
||||
me.virtualPressure.reallocAPShortCode();
|
||||
|
||||
// Bütün bu kaynakları kaldırmak için her birinin ayrı ayrı
|
||||
// bırakma işlevi vardır
|
||||
// Bir adresi kullanmadığınızda artık bu adreslerden size
|
||||
// ulaşılamaz olursunuz
|
||||
await me.virtualPressure.releaseAPIPAddress();
|
||||
await me.virtualPressure.releaseAPNumber();
|
||||
await me.virtualPressure.releaseAPShortCode();
|
||||
|
||||
await me.virtualPressure.queryAPIPAddress();
|
||||
await me.virtualPressure.queryAPNumber();
|
||||
await me.virtualPressure.queryAPShortCode();
|
||||
})
|
||||
```
|
||||
|
||||
Farklı bir eş ile iletişime geçme
|
||||
|
||||
```javascript
|
||||
wsjs.scope(async () => {
|
||||
let peer = wsjs.peer('325a8f7f-eaaf-4c21-855e-9e965c0d5ac9') // Diğer eşin socketId'sini belirtiyoruz
|
||||
|
||||
peer.on('message',(payload) => {
|
||||
// Eş eğer mesaj gönderirse burası tetiklenecek ve gönderdiği mesaj payload değişkeni ile iletilir
|
||||
})
|
||||
// Mesaj göndermek için send fonksiyonunu kullanabilirsiniz
|
||||
peer.send('Merhaba');
|
||||
peer.send([29, true]);
|
||||
peer.send({
|
||||
type: 'notification',
|
||||
value: "Hi!"
|
||||
});
|
||||
})
|
||||
```
|
|
@ -4,6 +4,8 @@ export interface IConnection{
|
|||
timeout: number;
|
||||
}
|
||||
}
|
||||
|
||||
const RootURL : string = ( <HTMLScriptElement> document.currentScript).src
|
||||
export class Connection
|
||||
{
|
||||
public ws! : WebSocket;
|
||||
|
@ -15,7 +17,23 @@ export class Connection
|
|||
public autoReconnectTimeout : number = 3000;
|
||||
public autoReconnectTimer? : number;
|
||||
constructor(options: IConnection){
|
||||
this.endpoint = new URL(options.endpoint);
|
||||
|
||||
if(options.endpoint == "auto")
|
||||
{
|
||||
let scriptPath = new URL(RootURL);
|
||||
let isSecurity = scriptPath.protocol == "https:";
|
||||
let dumeUrl = scriptPath.pathname.split('/').slice(0,-1).join('/') + '/';
|
||||
let wsSocket = new URL(dumeUrl, scriptPath);
|
||||
wsSocket.protocol = isSecurity ? 'wss:' : 'ws:';
|
||||
this.endpoint = new URL(wsSocket.href);
|
||||
}else{
|
||||
try{
|
||||
// Testing
|
||||
this.endpoint = new URL(options.endpoint);
|
||||
}catch{
|
||||
throw new Error("endpoint is required")
|
||||
}
|
||||
}
|
||||
if(typeof options.autoReconnect == "boolean")
|
||||
{
|
||||
this.autoReconnect = true;
|
||||
|
@ -36,6 +54,11 @@ export class Connection
|
|||
}
|
||||
public disconnect()
|
||||
{
|
||||
/**
|
||||
* Eğer bilinerek elle kapatıldıysa otomatik tekrar bağlanmasının
|
||||
* önüne geçmek için autoReconnect bayrağını her zaman kapalı tutmak gerekir
|
||||
*/
|
||||
this.autoReconnect = false;
|
||||
this.ws.close();
|
||||
}
|
||||
public addWSEvents()
|
||||
|
@ -54,6 +77,9 @@ export class Connection
|
|||
}
|
||||
private eventClose()
|
||||
{
|
||||
for (const callback of this.passiveConnectionEvent) {
|
||||
callback(void 0);
|
||||
}
|
||||
this.connected = false;
|
||||
if(this.autoReconnect)
|
||||
{
|
||||
|
@ -79,6 +105,16 @@ export class Connection
|
|||
this.activeConnectionEvent.push(func);
|
||||
}
|
||||
}
|
||||
private passiveConnectionEvent : Function[] = [];
|
||||
public onPassive(func:Function)
|
||||
{
|
||||
if(!this.connected)
|
||||
{
|
||||
func()
|
||||
}else{
|
||||
this.passiveConnectionEvent.push(func);
|
||||
}
|
||||
}
|
||||
private eventMessage(data: string | ArrayBuffer)
|
||||
{
|
||||
if(typeof data == "string")
|
||||
|
|
|
@ -17,7 +17,6 @@ export default class EventPool
|
|||
{
|
||||
return new Promise((ok,rej) => {
|
||||
let id = ++this.count;
|
||||
this.wsts.WSTSProtocol.SendRequest(msg, id);
|
||||
this.events.set(id,[
|
||||
(data:any) => {
|
||||
ok(data);
|
||||
|
@ -26,6 +25,7 @@ export default class EventPool
|
|||
rej(data);
|
||||
}
|
||||
]);
|
||||
this.wsts.WSTSProtocol.SendRequest(msg, id);
|
||||
})
|
||||
}
|
||||
public stream(msg: Message, callback: Function)
|
||||
|
|
|
@ -29,11 +29,8 @@ export default class Peer extends EventTarget
|
|||
super();
|
||||
this.mwse = wsts;
|
||||
this.info = new PeerInfo(this);
|
||||
this.on('updateinfo',(name:string,value:any) => {
|
||||
this.info.info[name] = value;
|
||||
})
|
||||
this.on('pack',(data:{type?:string,action?:IMessageSymbase,payload?:any}) => {
|
||||
if(data.type == ':rtcbase_pack:')
|
||||
if(data.type == ':rtcpack:')
|
||||
{
|
||||
if(this.rtc)
|
||||
{
|
||||
|
@ -56,7 +53,7 @@ export default class Peer extends EventTarget
|
|||
})
|
||||
this.rtc.on("output",(payload:object) => {
|
||||
this.send({
|
||||
type: ':rtcbase_pack:',
|
||||
type: ':rtcpack:',
|
||||
payload: payload
|
||||
})
|
||||
});
|
||||
|
@ -121,6 +118,18 @@ export default class Peer extends EventTarget
|
|||
value: 'disable'
|
||||
});
|
||||
}
|
||||
async enablePairInfo(){
|
||||
await this.mwse.EventPooling.request({
|
||||
type: 'connection/pairinfo',
|
||||
value: true
|
||||
});
|
||||
}
|
||||
async disablePairInfo(){
|
||||
await this.mwse.EventPooling.request({
|
||||
type: 'connection/pairinfo',
|
||||
value: false
|
||||
});
|
||||
}
|
||||
async requestPair()
|
||||
{
|
||||
let {message,status} = await this.mwse.EventPooling.request({
|
||||
|
@ -204,6 +213,9 @@ export default class Peer extends EventTarget
|
|||
|
||||
if(sendChannel == "websocket")
|
||||
{
|
||||
if(!this.mwse.writable){
|
||||
return console.warn("Socket is not writable");
|
||||
}
|
||||
await this.mwse.EventPooling.request({
|
||||
type:'pack/to',
|
||||
pack,
|
||||
|
|
|
@ -22,6 +22,7 @@ export default class Room extends EventTarget
|
|||
{
|
||||
public mwse : MWSE;
|
||||
public options! : IRoomOptions;
|
||||
public config! : IRoomOptions;
|
||||
public roomId? : string;
|
||||
public accessType? : "public"|"private";
|
||||
public description? : string;
|
||||
|
@ -52,7 +53,7 @@ export default class Room extends EventTarget
|
|||
autoFetchInfo: true
|
||||
};
|
||||
Object.assign(defaultOptions,options);
|
||||
this.options = defaultOptions as IRoomOptions;
|
||||
this.config = defaultOptions as IRoomOptions;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,21 +61,21 @@ export default class Room extends EventTarget
|
|||
this.roomId = uuid;
|
||||
}
|
||||
async createRoom(roomOptions : IRoomOptions){
|
||||
let options = this.options || roomOptions;
|
||||
let config = this.config || roomOptions;
|
||||
let result = await this.mwse.EventPooling.request({
|
||||
type:'create-room',
|
||||
...options
|
||||
...config
|
||||
});
|
||||
if(result.status == 'fail')
|
||||
{
|
||||
if(result.message == "ALREADY-EXISTS" && this.options.ifexistsJoin)
|
||||
if(result.message == "ALREADY-EXISTS" && this.config.ifexistsJoin)
|
||||
{
|
||||
return this.join();
|
||||
}
|
||||
throw new Error(result.message || result.messages);
|
||||
}else{
|
||||
this.options = {
|
||||
...this.options,
|
||||
...this.config,
|
||||
...result.room
|
||||
};
|
||||
this.roomId = result.room.id;
|
||||
|
@ -84,16 +85,16 @@ export default class Room extends EventTarget
|
|||
async join(){
|
||||
let result = await this.mwse.EventPooling.request({
|
||||
type:'joinroom',
|
||||
name: this.options.name,
|
||||
credential: this.options.credential,
|
||||
autoFetchInfo: this.options.autoFetchInfo || false
|
||||
name: this.config.name,
|
||||
credential: this.config.credential,
|
||||
autoFetchInfo: this.config.autoFetchInfo || false
|
||||
});
|
||||
if(result.status == 'fail')
|
||||
{
|
||||
throw new Error(result.message);
|
||||
}else{
|
||||
this.options = {
|
||||
...this.options,
|
||||
...this.config,
|
||||
...result.room
|
||||
};
|
||||
if(result.info)
|
||||
|
@ -115,13 +116,33 @@ export default class Room extends EventTarget
|
|||
this.mwse.rooms.delete(this.roomId as string);
|
||||
}
|
||||
}
|
||||
async send(pack: any, wom:boolean = false){
|
||||
await this.mwse.EventPooling.request({
|
||||
type:'pack/room',
|
||||
pack,
|
||||
to: this.roomId,
|
||||
wom
|
||||
});
|
||||
async send(pack: any, wom:boolean = false, handshake = false){
|
||||
if(!this.mwse.writable){
|
||||
return console.warn("Socket is not writable");
|
||||
}
|
||||
if(handshake)
|
||||
{
|
||||
let {type} = await this.mwse.EventPooling.request({
|
||||
type:'pack/room',
|
||||
pack,
|
||||
to: this.roomId,
|
||||
wom,
|
||||
handshake
|
||||
}) as {
|
||||
type:"success"|"fail"
|
||||
};
|
||||
if(type == "fail"){
|
||||
throw new Error("Cant send message to room")
|
||||
}
|
||||
}else{
|
||||
await this.mwse.EventPooling.request({
|
||||
type:'pack/room',
|
||||
pack,
|
||||
to: this.roomId,
|
||||
wom,
|
||||
handshake
|
||||
})
|
||||
}
|
||||
}
|
||||
async fetchPeers(filter?:{[key:string]:any}, onlyNumber:boolean = false) : Promise<Number | Peer[]>
|
||||
{
|
||||
|
@ -147,7 +168,7 @@ export default class Room extends EventTarget
|
|||
throw new Error("Cant using peers on room")
|
||||
}else if(status == 'success'){
|
||||
for (const peerid of peers) {
|
||||
let peer = this.mwse.peer(peerid);
|
||||
let peer = this.mwse.peer(peerid,true);
|
||||
cup.push(peer);
|
||||
this.peers.set(peerid, peer);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,9 @@ export class RoomInfo
|
|||
public info : {[key:string]: any} = {};
|
||||
constructor(room : Room){
|
||||
this.room = room;
|
||||
this.room.on('updateinfo',(name:string,value:any) => {
|
||||
this.info[name] = value;
|
||||
})
|
||||
};
|
||||
public async fetch(name?:string)
|
||||
{
|
||||
|
@ -18,16 +21,16 @@ export class RoomInfo
|
|||
}));
|
||||
if(rinfo.status == "success")
|
||||
{
|
||||
this.info = rinfo.info;
|
||||
this.info = rinfo.value;
|
||||
}else console.warn(rinfo.message);
|
||||
}else{
|
||||
let rinfo = await this.room.mwse.EventPooling.request(({
|
||||
type: "peer/info",
|
||||
peer: this.room.roomId
|
||||
type: "room/info",
|
||||
roomId: this.room.roomId
|
||||
}));
|
||||
if(rinfo.status == "success")
|
||||
{
|
||||
this.info = rinfo.info;
|
||||
this.info = rinfo.value;
|
||||
}else console.warn(rinfo.message);
|
||||
};
|
||||
return this.info;
|
||||
|
|
|
@ -142,7 +142,7 @@ export default class WebRTC
|
|||
case "streamRemoved":{
|
||||
let {id} = data;
|
||||
this.emit('stream:stopped', this.recaivingStream.get(id));
|
||||
this.sendingStream.delete(id);
|
||||
this.recaivingStream.delete(id);
|
||||
break;
|
||||
}
|
||||
case "streamAccept":{
|
||||
|
@ -448,7 +448,7 @@ setInterval(()=>{
|
|||
window.URL.revokeObjectURL(this.src);
|
||||
};
|
||||
WebRTC.requireGC = false;
|
||||
}, 3000)
|
||||
}, 3000);
|
||||
|
||||
declare global {
|
||||
interface MediaStream {
|
||||
|
|
|
@ -17,6 +17,21 @@ export default class MWSE extends EventTarget {
|
|||
public peers : Map<string, Peer> = new Map();
|
||||
public virtualPressure : IPPressure;
|
||||
public me! : Peer;
|
||||
/*public static compress(message:string, callback:(e:any) => any)
|
||||
{
|
||||
let u : any= [];
|
||||
let C = new Gzip({
|
||||
level: 9,
|
||||
mem: 12
|
||||
},(stream,isLast) => {
|
||||
u.push(stream);
|
||||
if(isLast)
|
||||
{
|
||||
callback(u);
|
||||
}
|
||||
});
|
||||
C.push(new TextEncoder().encode(message), true);
|
||||
}*/
|
||||
constructor(options: IConnection){
|
||||
super();
|
||||
this.server = new Connection(options);
|
||||
|
@ -35,8 +50,45 @@ export default class MWSE extends EventTarget {
|
|||
this.emit('scope');
|
||||
this.activeScope = true;
|
||||
});
|
||||
this.server.onPassive(async ()=>{
|
||||
this.emit('close');
|
||||
});
|
||||
this.packMessagingSystem();
|
||||
}
|
||||
|
||||
public writable = 1;
|
||||
public readable = 1;
|
||||
|
||||
public destroy()
|
||||
{
|
||||
this.server.disconnect();
|
||||
}
|
||||
|
||||
public enableRecaiveData(){
|
||||
this.WSTSProtocol.SendOnly({ type: 'connection/packrecaive', value: 1 })
|
||||
this.readable = 1
|
||||
}
|
||||
public disableRecaiveData(){
|
||||
this.WSTSProtocol.SendOnly({ type: 'connection/packrecaive', value: 0 })
|
||||
this.readable = 0
|
||||
}
|
||||
|
||||
public enableSendData(){
|
||||
this.WSTSProtocol.SendOnly({ type: 'connection/packsending', value: 1 })
|
||||
this.writable = 1
|
||||
}
|
||||
public disableSendData(){
|
||||
this.WSTSProtocol.SendOnly({ type: 'connection/packsending', value: 0 })
|
||||
this.writable = 0
|
||||
}
|
||||
|
||||
public enableNotifyRoomInfo(){
|
||||
this.WSTSProtocol.SendOnly({ type: 'connection/roominfo', value: 1 })
|
||||
}
|
||||
public disableNotifyRoomInfo(){
|
||||
this.WSTSProtocol.SendOnly({ type: 'connection/roominfo', value: 0 })
|
||||
}
|
||||
|
||||
public async request(peerId: string, pack:Message)
|
||||
{
|
||||
let {pack:answer} = await this.EventPooling.request({
|
||||
|
@ -58,8 +110,11 @@ export default class MWSE extends EventTarget {
|
|||
private packMessagingSystem()
|
||||
{
|
||||
this.EventPooling.signal('pack',(payload : {from:string,pack:any}) => {
|
||||
let {from,pack} = payload;
|
||||
this.peer(from, true).emit('pack', pack);
|
||||
if(this.readable)
|
||||
{
|
||||
let {from,pack} = payload;
|
||||
this.peer(from, true).emit('pack', pack);
|
||||
}
|
||||
})
|
||||
this.EventPooling.signal('request',(payload : {from:string,pack:any,id:number}) => {
|
||||
let {from,pack, id} = payload;
|
||||
|
@ -74,8 +129,11 @@ export default class MWSE extends EventTarget {
|
|||
this.peer('me').emit('request', scope);
|
||||
})
|
||||
this.EventPooling.signal('pack/room',(payload : {from:string,pack:any,sender:string}) => {
|
||||
let {from,pack,sender} = payload;
|
||||
this.room(from).emit('message', pack, this.peer(sender));
|
||||
if(this.readable)
|
||||
{
|
||||
let {from,pack,sender} = payload;
|
||||
this.room(from).emit('message', pack, this.peer(sender));
|
||||
}
|
||||
})
|
||||
this.EventPooling.signal('room/joined',(payload : {id:string,roomid:any,ownerid:string}) => {
|
||||
let {id,roomid} = payload;
|
||||
|
@ -91,7 +149,7 @@ export default class MWSE extends EventTarget {
|
|||
this.EventPooling.signal('room/ejected',(payload : {id:string,roomid:any,ownerid:string}) => {
|
||||
let {id,roomid} = payload;
|
||||
let room = this.room(roomid);
|
||||
let peer = this.peer(id);
|
||||
let peer = this.peer(id, true);
|
||||
room.peers.delete(peer.socketId as string);
|
||||
room.emit('eject', peer);
|
||||
})
|
||||
|
@ -104,27 +162,32 @@ export default class MWSE extends EventTarget {
|
|||
})
|
||||
this.EventPooling.signal("pair/info", (payload : {from : string,name: string, value: string | number | boolean}) => {
|
||||
let {from, name, value} = payload;
|
||||
let peer = this.peer(from);
|
||||
let peer = this.peer(from, true);
|
||||
peer.info.info[name] = value;
|
||||
peer.emit("info", name, value);
|
||||
})
|
||||
this.EventPooling.signal("request/pair", (payload : {from : string,info: any}) => {
|
||||
let {from, info} = payload;
|
||||
let peer = this.peer(from);
|
||||
let peer = this.peer(from, true);
|
||||
peer.info.info = info;
|
||||
peer.emit("request/pair", peer);
|
||||
this.peer('me').emit('request/pair', peer);
|
||||
})
|
||||
this.EventPooling.signal("peer/disconnect", (payload : {id : string}) => {
|
||||
let {id} = payload;
|
||||
let peer = this.peer(id, true);
|
||||
peer.emit("disconnect", peer);
|
||||
})
|
||||
this.EventPooling.signal("accepted/pair", (payload : {from : string,info: any}) => {
|
||||
let {from, info} = payload;
|
||||
let peer = this.peer(from);
|
||||
let peer = this.peer(from, true);
|
||||
peer.info.info = info;
|
||||
peer.emit("accepted/pair", peer);
|
||||
this.peer('me').emit('accepted/pairr', peer);
|
||||
})
|
||||
this.EventPooling.signal("end/pair", (payload : {from : string,info: any}) => {
|
||||
let {from, info} = payload;
|
||||
let peer = this.peer(from);
|
||||
let peer = this.peer(from, true);
|
||||
peer.emit("endPair", info);
|
||||
this.peer('me').emit('endPair', from, info);
|
||||
})
|
||||
|
|
13
index.js
13
index.js
|
@ -2,7 +2,6 @@
|
|||
const cluster = require("cluster");
|
||||
const os = require("os");
|
||||
let {randomUUID} = require("crypto");
|
||||
const { LOADBALANCE_CPU } = require('./Source/config');
|
||||
|
||||
/**
|
||||
* Use Round Robin algorithm for cluster process load balancer
|
||||
|
@ -11,16 +10,6 @@ const { LOADBALANCE_CPU } = require('./Source/config');
|
|||
|
||||
async function main()
|
||||
{
|
||||
if(!LOADBALANCE_CPU)
|
||||
{
|
||||
console.log("Slave Process PID:", process.pid);
|
||||
// Emit from slave
|
||||
process.send = new Function();
|
||||
// Compile source code and run
|
||||
require("./Source/index");
|
||||
// stay here
|
||||
return;
|
||||
}
|
||||
if(cluster.isPrimary == false)
|
||||
{
|
||||
console.log("Slave Process PID:", process.pid);
|
||||
|
@ -37,7 +26,7 @@ async function main()
|
|||
// Worker process list
|
||||
const master = new Map();
|
||||
|
||||
const coreCount = LOADBALANCE_CPU//os.cpus().length;
|
||||
const coreCount = 1 //os.cpus().length;
|
||||
for(let index = 0; index < coreCount; index++)
|
||||
{
|
||||
// Open slave process
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
"fflate": "^0.8.1",
|
||||
"joi": "^17.11.0",
|
||||
"knex": "^3.0.1",
|
||||
"moment": "^2.29.4",
|
||||
"sqlite3": "^5.1.6",
|
||||
"systemjs": "^6.14.2",
|
||||
"terminal": "^0.1.4",
|
||||
|
@ -2620,14 +2619,6 @@
|
|||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/moment": {
|
||||
"version": "2.29.4",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
|
||||
"integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
|
|
|
@ -45,7 +45,6 @@
|
|||
"fflate": "^0.8.1",
|
||||
"joi": "^17.11.0",
|
||||
"knex": "^3.0.1",
|
||||
"moment": "^2.29.4",
|
||||
"sqlite3": "^5.1.6",
|
||||
"systemjs": "^6.14.2",
|
||||
"terminal": "^0.1.4",
|
||||
|
|
127
public/index.css
127
public/index.css
|
@ -4,6 +4,10 @@ html,body{
|
|||
}
|
||||
body{
|
||||
background-color: #141414;
|
||||
overflow: hidden;
|
||||
}
|
||||
*{
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.root{
|
||||
gap: 10px;
|
||||
|
@ -13,67 +17,36 @@ body{
|
|||
flex-wrap: nowrap;
|
||||
flex-direction: row;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.dialoque{
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
flex-direction: row;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.videolist{
|
||||
flex: 0 0 200px;
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(40vh, 1fr));
|
||||
grid-template-rows: repeat(auto-fit, minmax(23vh, 1fr));
|
||||
gap: 10px;
|
||||
overflow: auto;
|
||||
padding-right: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.dialoque #primaryVideo{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
object-fit: contain;
|
||||
background-color: transparent/*#282828*/;
|
||||
border-radius: 10px;
|
||||
z-index: 2;
|
||||
}
|
||||
.dialoque #primaryVideoShadow{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
border-radius: 10px;
|
||||
position: absolute;
|
||||
filter: brightness(0.5);
|
||||
z-index: 1;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
.dialoque #secondaryVideo{
|
||||
width: 300px;
|
||||
height: 200px;
|
||||
min-width: 300px;
|
||||
max-width: 30%;
|
||||
min-height: 200px;
|
||||
max-height: 35%;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
bottom: 10px;
|
||||
background-color: #383838;
|
||||
border-radius: 10px;
|
||||
z-index: 3;
|
||||
outline-offset: 0px;
|
||||
outline-style: solid;
|
||||
outline-width: 5px;
|
||||
outline-color: rgba(0,0,0,.5);
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
.videolist .frame{
|
||||
max-width: 200px;
|
||||
border: solid 2px white;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
align-items: center;
|
||||
border-radius: 20px;
|
||||
box-sizing: border-box;
|
||||
padding: 1px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
.videolist .frame > video{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
border-radius: 10px;
|
||||
border: solid 3px transparent;
|
||||
}
|
||||
.videolist .frame.active{
|
||||
border: solid 3px green;
|
||||
|
@ -92,16 +65,36 @@ video{
|
|||
::-webkit-scrollbar-track {
|
||||
background-color: #ffffff1f;
|
||||
}
|
||||
#stats{
|
||||
|
||||
.tool-container{
|
||||
position: absolute;
|
||||
z-index: 3;
|
||||
font-size: 14px;
|
||||
line-height: 1.5em;
|
||||
color: white;
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||
padding: 10px;
|
||||
text-shadow: 0 0 5px black;
|
||||
background-color: rgba(0,0,0,.4);
|
||||
overflow: auto;
|
||||
max-height: 80vh;
|
||||
}
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
}
|
||||
.tool-container > .tools{
|
||||
margin: auto;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.tool-container > .tools > button{
|
||||
border: none;
|
||||
color: white;
|
||||
vertical-align: middle;
|
||||
cursor: pointer;
|
||||
padding: 0 10px;
|
||||
}
|
||||
.tool-container > .tools > button:not(:hover){
|
||||
background-color: transparent;
|
||||
}
|
||||
.tool-container > .tools > button:hover{
|
||||
background-color: rgba(255,255,255,0.2);
|
||||
}
|
||||
.tool-container > .tools > button i{
|
||||
vertical-align: middle;
|
||||
line-height: 2;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,20 +6,15 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>saQüt Video Streaming</title>
|
||||
<script src="https://ws.saqut.com/script"></script>
|
||||
<link rel="stylesheet" href="./index.css">
|
||||
<link rel="stylesheet" href="./index.css?v=42">
|
||||
</head>
|
||||
<body>
|
||||
<div class="root">
|
||||
<div class="dialoque">
|
||||
<video id="primaryVideo" muted playsinline autoplay></video>
|
||||
<video id="primaryVideoShadow" muted playsinline autoplay></video>
|
||||
<div id="stats"></div>
|
||||
</div>
|
||||
<div class="videolist">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="index.js?v=32"></script>
|
||||
<script src="index.js?v=42"></script>
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||
</body>
|
||||
</html>
|
428
public/index.js
428
public/index.js
|
@ -22,39 +22,19 @@ let roomid;
|
|||
* @type {import("./MWSE/Room").default}
|
||||
*/
|
||||
let room;
|
||||
/**
|
||||
* @type {MediaStream}
|
||||
*/
|
||||
let primaryVideoContent;
|
||||
/**
|
||||
* @type {HTMLVideoElement}
|
||||
*/
|
||||
let primaryVideo;
|
||||
/**
|
||||
* @type {HTMLVideoElement}
|
||||
*/
|
||||
let primaryVideoShadow;
|
||||
/**
|
||||
* @type {HTMLVideoElement}
|
||||
*/
|
||||
let secondaryVideo;
|
||||
/**
|
||||
* @type {MediaStream}
|
||||
*/
|
||||
let outgoingStream;
|
||||
/**
|
||||
* @type {MediaStream}
|
||||
*/
|
||||
let outgoingStreamOnlyVideo;
|
||||
/**
|
||||
* @type {HTMLDivElement}
|
||||
*/
|
||||
let videoContainer = document.querySelector(".videolist");
|
||||
|
||||
let activePeerInfos = {};
|
||||
let activePeer = null;
|
||||
let maxbitrate;
|
||||
let resulation;
|
||||
let activePeers = {}
|
||||
|
||||
let ofscreencanvas = document.createElement("canvas");
|
||||
|
||||
function connect()
|
||||
{
|
||||
|
@ -64,58 +44,64 @@ function connect()
|
|||
|
||||
mwse.scope(beginEngine);
|
||||
}
|
||||
|
||||
|
||||
|
||||
let interact = false;
|
||||
|
||||
setInterval(()=>{
|
||||
document.querySelectorAll(".soundon").forEach(e => (e.muted = 0,e.play()));
|
||||
},1000)
|
||||
|
||||
document.addEventListener("click",()=>{
|
||||
interact = true;
|
||||
document.querySelectorAll(".soundon").forEach(e => (e.muted = 0,e.play()));
|
||||
})
|
||||
|
||||
|
||||
/**
|
||||
* @type {HTMLVideoElement}
|
||||
*/
|
||||
let activeVideo;
|
||||
|
||||
function setPrimaryVideo(video, soundOn)
|
||||
function templateVideo(name, stream,infinitedMute)
|
||||
{
|
||||
primaryVideo.srcObject = video;
|
||||
primaryVideoShadow.srcObject = video;
|
||||
if(soundOn == undefined)
|
||||
let t = new DOMParser().parseFromString(`
|
||||
<div class="frame">
|
||||
<video autoplay playsinline muted data-name="${name}">
|
||||
|
||||
</video>
|
||||
<div class="tool-container">
|
||||
<div class="tools">
|
||||
<button>
|
||||
<i class="material-icons">home</i>
|
||||
</button>
|
||||
<button>
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`,"text/html");
|
||||
|
||||
let i = t.querySelector("video");
|
||||
if(infinitedMute == true)
|
||||
{
|
||||
primaryVideo.muted = 1;
|
||||
primaryVideo.volume = 0;
|
||||
}else if(soundOn){
|
||||
primaryVideo.muted = 0;
|
||||
primaryVideo.volume = 1;
|
||||
}else{
|
||||
primaryVideo.muted = 0;
|
||||
primaryVideo.volume = 0;
|
||||
i.muted = 1;
|
||||
}else if(interact == false)
|
||||
{
|
||||
i.muted = 1;
|
||||
i.classList.add("soundon");
|
||||
}
|
||||
}
|
||||
function setSecondaryVideo(video)
|
||||
{
|
||||
// secondaryVideo.srcObject = video;
|
||||
}
|
||||
function templateVideo(name, stream)
|
||||
{
|
||||
let i = document.createElement("video");
|
||||
i.muted = 1;
|
||||
i.classList.add("frame")
|
||||
i.playsInline = 1;
|
||||
i.autoplay = 1;
|
||||
i.dataset.name = name;
|
||||
if(stream) i.srcObject = stream;
|
||||
return i;
|
||||
return t.querySelector("div");
|
||||
}
|
||||
function addVideoList(name, stream, peer)
|
||||
function addVideoList(name, stream, peer, infinitedMute)
|
||||
{
|
||||
if(!videoContainer.querySelector(`[name="${name}"]`))
|
||||
{
|
||||
let video = templateVideo(name, stream);
|
||||
let video = templateVideo(name, stream, infinitedMute);
|
||||
video.dataset.user = peer.socketId;
|
||||
video.onclick = function(){
|
||||
if(activeVideo)
|
||||
{
|
||||
activeVideo.classList.remove("active");
|
||||
};
|
||||
video.classList.add("active");
|
||||
activeVideo = video;
|
||||
activePeer = peer.rtc.rtc;
|
||||
setPrimaryVideo(stream, true);
|
||||
};
|
||||
videoContainer.appendChild(video);
|
||||
}
|
||||
}
|
||||
|
@ -128,7 +114,6 @@ function removeVideoList(name)
|
|||
if(k.dataset.user == activeVideo?.dataset.user || !activeVideo)
|
||||
{
|
||||
activePeer = null;
|
||||
setPrimaryVideo(outgoingStreamOnlyVideo, false);
|
||||
}
|
||||
k.remove();
|
||||
}
|
||||
|
@ -145,24 +130,6 @@ async function beginEngine()
|
|||
let url = new URL(window.location);
|
||||
roomid = url.searchParams.get("room");
|
||||
|
||||
if(url.searchParams.get("maxbitrate"))
|
||||
{
|
||||
let n = Number(url.searchParams.get("maxbitrate"));
|
||||
if(Number.isFinite(n) && !Number.isNaN(n))
|
||||
{
|
||||
maxbitrate = n;
|
||||
}else maxbitrate = 3_000_000;
|
||||
}else maxbitrate = 3_000_000;
|
||||
|
||||
if(url.searchParams.get("resulation"))
|
||||
{
|
||||
let n = Number(url.searchParams.get("resulation"));
|
||||
if(Number.isFinite(n) && !Number.isNaN(n))
|
||||
{
|
||||
resulation = n;
|
||||
}else resulation = 1.5;
|
||||
}else resulation = 1.5;
|
||||
|
||||
if(!!roomid == 0)
|
||||
{
|
||||
let hash = window.crypto.randomUUID();
|
||||
|
@ -171,18 +138,34 @@ async function beginEngine()
|
|||
};
|
||||
|
||||
connectRoom(roomid);
|
||||
|
||||
if(url.searchParams.get("maxbitrate"))
|
||||
{
|
||||
let n = Number(url.searchParams.get("maxbitrate"));
|
||||
if(Number.isFinite(n) && !Number.isNaN(n))
|
||||
{
|
||||
maxbitrate = n;
|
||||
}else maxbitrate = 2500_000;
|
||||
}else maxbitrate = 2500_000;
|
||||
|
||||
if(url.searchParams.get("resulation"))
|
||||
{
|
||||
let n = Number(url.searchParams.get("resulation"));
|
||||
if(Number.isFinite(n) && !Number.isNaN(n))
|
||||
{
|
||||
resulation = n;
|
||||
}else resulation = 1.2;
|
||||
}else resulation = 1.2;
|
||||
};
|
||||
|
||||
window.addEventListener("load", () => {
|
||||
primaryVideo = document.querySelector("#primaryVideo");
|
||||
secondaryVideo = document.querySelector("#secondaryVideo");
|
||||
primaryVideoShadow = document.querySelector("#primaryVideoShadow");
|
||||
connect()
|
||||
});
|
||||
|
||||
|
||||
async function startOutgoingWebcam()
|
||||
{
|
||||
outgoingStream = await navigator.mediaDevices.getUserMedia({
|
||||
let mediaStream = await navigator.mediaDevices.getUserMedia({
|
||||
video: /*true*/{
|
||||
advanced: [
|
||||
{ width: { exact: 1920 } },
|
||||
|
@ -197,13 +180,13 @@ async function startOutgoingWebcam()
|
|||
{ width: { exact: 240 } }
|
||||
],
|
||||
facingMode: "user"
|
||||
},/**/
|
||||
audio: false
|
||||
}
|
||||
});
|
||||
outgoingStreamOnlyVideo = new MediaStream(outgoingStream);
|
||||
// outgoingStreamOnlyVideo.removeTrack(outgoingStreamOnlyVideo.getAudioTracks()[0])
|
||||
outgoingStream = mediaStream;
|
||||
}
|
||||
|
||||
|
||||
|
||||
async function connectRoom()
|
||||
{
|
||||
await startOutgoingWebcam();
|
||||
|
@ -226,13 +209,8 @@ async function connectRoom()
|
|||
for (const peer of await room.fetchPeers()) {
|
||||
IncomingPeer(peer)
|
||||
}
|
||||
if(!primaryVideoContent)
|
||||
{
|
||||
setPrimaryVideo(outgoingStreamOnlyVideo);
|
||||
}
|
||||
setSecondaryVideo(outgoingStreamOnlyVideo);
|
||||
|
||||
addVideoList("My Webcam",outgoingStreamOnlyVideo, mwse.peer("me"))
|
||||
addVideoList("My Webcam",outgoingStream, mwse.peer("me"), true)
|
||||
|
||||
};
|
||||
|
||||
|
@ -241,13 +219,12 @@ async function connectRoom()
|
|||
*/
|
||||
function IncomingPeer(peer,activeConnect)
|
||||
{
|
||||
let sendedOTP = false;
|
||||
peer.createRTC({
|
||||
iceCandidatePoolSize: 0
|
||||
},[{
|
||||
urls: "turn:161.97.136.175:3478",
|
||||
username: "argist-eu-east-25",
|
||||
credential: "ee7df17eed35f4cf5a207777f3c0cd7d3b1901a5de7aff52ea55742289d7fee2"
|
||||
urls: "turn:20.166.82.187:3478",
|
||||
username: "turnserver",
|
||||
credential: "turnserver"
|
||||
},{
|
||||
urls: "stun:stun.l.google.com:19302"
|
||||
}]);
|
||||
|
@ -257,29 +234,21 @@ function IncomingPeer(peer,activeConnect)
|
|||
}
|
||||
peer.rtc.rtc.turboBitrate = 0;
|
||||
peer.rtc.on('connected',() => {
|
||||
if(!activeConnect && !sendedOTP)
|
||||
if(!activeConnect)
|
||||
{
|
||||
sendedOTP = true;
|
||||
peer.rtc.sendStream(outgoingStream, "Webcam", {});
|
||||
activePeers[peer.socketId] = peer.rtc.rtc;
|
||||
}
|
||||
});
|
||||
peer.rtc.on('disconnected',() => {
|
||||
removeVideoList(peer.streamY, peer);
|
||||
delete activePeers[peer.socketId];
|
||||
});
|
||||
peer.rtc.on("stream:added", ({stream,name}) => {
|
||||
peer.streamY = peer.socketId + " | " + name + " - " + stream.id;
|
||||
addVideoList(peer.socketId + " | " + name + " - " + stream.id,stream, peer);
|
||||
|
||||
if(!primaryVideoContent)
|
||||
if(activeConnect)
|
||||
{
|
||||
activePeer = peer.rtc.rtc;
|
||||
primaryVideoContent = stream;
|
||||
setPrimaryVideo(primaryVideoContent, true);
|
||||
}
|
||||
|
||||
if(activeConnect && !sendedOTP)
|
||||
{
|
||||
sendedOTP = true;
|
||||
peer.rtc.sendStream(outgoingStream, "Webcam", {});
|
||||
}
|
||||
})
|
||||
|
@ -292,234 +261,25 @@ function OutgoingPeer(peer)
|
|||
removeVideoList(peer.streamY, peer);
|
||||
}
|
||||
|
||||
setInterval(()=>{
|
||||
getStats()
|
||||
}, 1000)
|
||||
let relative;
|
||||
|
||||
|
||||
|
||||
setInterval(() => {
|
||||
if(activePeer?.turboBitrate === 0)
|
||||
for(const [,peerRtc] of Object.entries(activePeers))
|
||||
{
|
||||
const senders = activePeer.getSenders();
|
||||
const videoSender = senders.find(sender => sender.track?.kind === 'video');
|
||||
if(videoSender)
|
||||
if(peerRtc?.turboBitrate !== 1)
|
||||
{
|
||||
const parameters = videoSender.getParameters();
|
||||
parameters.encodings[0].maxBitrate = maxbitrate;
|
||||
parameters.encodings[0].scaleResolutionDownBy = resulation;
|
||||
videoSender.setParameters(parameters).then(() => {
|
||||
// console.log('Bitrate değiştirildi.');
|
||||
activePeer.turboBitrate = 1;
|
||||
})
|
||||
.catch(error => {
|
||||
// console.error('Bitrate değiştirilirken bir hata oluştu:', error);
|
||||
activePeer.turboBitrate = -1;
|
||||
});
|
||||
const senders = peerRtc.getSenders();
|
||||
const videoSender = senders.find(sender => sender.track?.kind === 'video');
|
||||
if(videoSender){
|
||||
const parameters = videoSender.getParameters();
|
||||
parameters.encodings[0].maxBitrate = maxbitrate;
|
||||
parameters.encodings[0].scaleResolutionDownBy = resulation;
|
||||
videoSender.setParameters(parameters).then(() => {
|
||||
peerRtc.turboBitrate = 1;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 5000);
|
||||
|
||||
let relative;
|
||||
|
||||
async function getStats()
|
||||
{
|
||||
let stats = {};
|
||||
if(!activePeer) return document.querySelector("#stats").innerHTML = "";
|
||||
let stat = await activePeer.getStats();
|
||||
let certs = {};
|
||||
let selectedCandidatePairId;
|
||||
let remotes = {};
|
||||
let locals = {};
|
||||
let candidatePairs = {};
|
||||
for (const [id, data] of stat) {
|
||||
switch(data.type)
|
||||
{
|
||||
case "candidate-pair":{
|
||||
if(data.state == "succeeded")
|
||||
{
|
||||
let t = {};
|
||||
t.candidateBytesSent = data.bytesSent;
|
||||
t.candidateBytesReceived = data.bytesReceived;
|
||||
t.candidatePacketsReceived = data.packetsReceived;
|
||||
t.candidatePacketsSent = data.packetsSent;
|
||||
t.candidateTotalRoundTripTime = data.totalRoundTripTime;
|
||||
t.currentRoundTripTime = data.currentRoundTripTime;
|
||||
t.candidateRemoteCandidateId = data.remoteCandidateId;
|
||||
t.candidateLocalCandidateId = data.localCandidateId;
|
||||
candidatePairs[data.id] = t;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "remote-candidate":{
|
||||
let t = {};
|
||||
t.remoteCandidateType = data.candidateType;
|
||||
t.remoteProtocol = data.protocol;
|
||||
t.remoteAddress = data.address;
|
||||
t.remoteIsRemote = data.isRemote;
|
||||
t.remotePort = data.port;
|
||||
remotes[data.id] = t;
|
||||
break;
|
||||
}
|
||||
case "local-candidate":{
|
||||
let t = {};
|
||||
t.localCandidateType = data.candidateType;
|
||||
t.localProtocol = data.protocol;
|
||||
t.localAddress = data.address;
|
||||
t.localIsRemote = data.isRemote;
|
||||
t.localPort = data.port;
|
||||
locals[data.id] = t;
|
||||
break;
|
||||
}
|
||||
case "inbound-rtp":{
|
||||
let k = stats["inbound" + data.mediaType] = {};
|
||||
k.mediaType = data.mediaType;
|
||||
k.trackIdentifier = data.trackIdentifier;
|
||||
k.bytesReceived = data.bytesReceived;
|
||||
k.totalSamplesReceived = data.totalSamplesReceived;
|
||||
k.totalSamplesDuration = data.totalSamplesDuration;
|
||||
k.audioLevel = data.audioLevel;
|
||||
k.packetsReceived = data.packetsReceived;
|
||||
k.framesReceived = data.framesReceived;
|
||||
k.frameWidth = data.frameWidth;
|
||||
k.frameHeight = data.frameHeight;
|
||||
k.framesPerSecond = data.framesPerSecond;
|
||||
k.totalDecodeTime = data.totalDecodeTime;
|
||||
k.totalProcessingDelay = data.totalProcessingDelay;
|
||||
k.totalAssemblyTime = data.totalAssemblyTime;
|
||||
k.decoderImplementation = data.decoderImplementation;
|
||||
k.powerEfficientDecoder = data.powerEfficientDecoder;
|
||||
break;
|
||||
}
|
||||
case "outbound-rtp":{
|
||||
let k = stats["outbound" + data.mediaType] = {};
|
||||
k.mediaType = data.mediaType;
|
||||
k.bytesSent = data.bytesSent;
|
||||
k.framesEncoded = data.framesEncoded;
|
||||
k.totalEncodeTime = data.totalEncodeTime;
|
||||
k.frameWidth = data.frameWidth;
|
||||
k.frameHeight = data.frameHeight;
|
||||
k.framesPerSecond = data.framesPerSecond;
|
||||
k.framesSent = data.framesSent;
|
||||
k.encoderImplementation = data.encoderImplementation;
|
||||
k.powerEfficientEncoder = data.powerEfficientEncoder;
|
||||
k.qualityLimitationReason = data.qualityLimitationReason;
|
||||
break;
|
||||
}
|
||||
case "transport":{
|
||||
stats.srtpCipher = data.srtpCipher;
|
||||
stats.dtlsCipher = data.dtlsCipher;
|
||||
stats.localcert = certs[data.localCertificateId];
|
||||
stats.remotecert = certs[data.localCertificateId];
|
||||
selectedCandidatePairId = data.selectedCandidatePairId;
|
||||
break;
|
||||
}
|
||||
case "certificate":{
|
||||
certs[data.id] = {
|
||||
fingerprintAlgorithm: data.fingerprintAlgorithm,
|
||||
fingerprint: data.fingerprint
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if(selectedCandidatePairId)
|
||||
{
|
||||
let pair = candidatePairs[selectedCandidatePairId];
|
||||
if(!pair.candidateRemoteCandidateId)
|
||||
{
|
||||
return;
|
||||
}
|
||||
stats = {
|
||||
...stats,
|
||||
...pair,
|
||||
...remotes[pair.candidateRemoteCandidateId],
|
||||
...locals[pair.candidateLocalCandidateId]
|
||||
};
|
||||
}else{
|
||||
let pair = Object.values(candidatePairs)[0];
|
||||
stats = {
|
||||
...stats,
|
||||
...pair,
|
||||
...Object.values(remotes)[0],
|
||||
...Object.values(locals)[0]
|
||||
};
|
||||
}
|
||||
|
||||
if(!stats.inboundvideo)
|
||||
{
|
||||
return document.querySelector("#stats").innerHTML = "";
|
||||
}
|
||||
|
||||
if(!relative)
|
||||
{
|
||||
relative = stats;
|
||||
}
|
||||
|
||||
let turnused = stats.localCandidateType == "relay" || stats.remoteCandidateType == "relay";
|
||||
|
||||
document.querySelector("#stats").innerHTML = `
|
||||
Signalization Server: ws.saqut.com<br>
|
||||
TURN Server: Adjusted / ${turnused ? "Using now":"Never used"}<br>
|
||||
STUN Server: Adjusted / used<br>
|
||||
Websocket: Active connected<hr>
|
||||
Local Candidate Type: ${{
|
||||
host:"Direct Connection",
|
||||
srflx: "Behind NAT (with STUN)",
|
||||
prflx: "Proxy Connection (with STUN)",
|
||||
relay: "TURN Server Connection"
|
||||
}[stats.localCandidateType]}<br>
|
||||
Local Protocol: ${stats.localProtocol}<br>
|
||||
Local Address: ${stats.localAddress}<br>
|
||||
Local Port: ${stats.localPort}<hr>
|
||||
|
||||
Remote Candidate Type: ${{
|
||||
host:"Direct Connection",
|
||||
srflx: "Behind NAT (with STUN)",
|
||||
prflx: "Proxy Connection (with STUN)",
|
||||
relay: "TURN Server Connection"
|
||||
}[stats.remoteCandidateType]}<br>
|
||||
Remote Protocol: ${stats.remoteProtocol}<br>
|
||||
Remote Address: ${stats.remoteAddress}<br>
|
||||
Remote Port: ${stats.remotePort}<hr>
|
||||
|
||||
Connection Total Bytes Send: Total: ${hfs(stats.candidateBytesSent)} | Current : ${hfs(stats.candidateBytesSent - relative.candidateBytesSent)}<br>
|
||||
Connection Total Bytes Recaived: Total: ${hfs(stats.candidateBytesReceived)} | Current : ${hfs(stats.candidateBytesReceived - relative.candidateBytesReceived)}<br>
|
||||
Connection Round Trip Time: ${stats.currentRoundTripTime}ms<hr>
|
||||
|
||||
Incoming Video Decoder: ${stats.inboundvideo.decoderImplementation}<br>
|
||||
Incoming Frame Width: ${stats.inboundvideo.frameWidth}px<br>
|
||||
Incoming Frame Height: ${stats.inboundvideo.frameHeight}px<br>
|
||||
Incoming Frame Per Second: ${stats.inboundvideo.framesPerSecond}<br>
|
||||
Incoming Decode Time (CPU Time): ${(stats.inboundvideo.totalDecodeTime - relative.inboundvideo.totalDecodeTime).toFixed(3)}ms<hr>
|
||||
|
||||
Outgoing Video Encoder: ${stats.outboundvideo.encoderImplementation}<br>
|
||||
Outgoing Frame Width: ${stats.outboundvideo.frameWidth}px<br>
|
||||
Outgoing Frame Height: ${stats.outboundvideo.frameHeight}px<br>
|
||||
Outgoing Frame Per Second: ${stats.outboundvideo.framesPerSecond}<br>
|
||||
Outgoing Decode Time (CPU Time): ${(stats.outboundvideo.totalEncodeTime - relative.outboundvideo.totalEncodeTime).toFixed(3)}ms<br>
|
||||
Quality Increase Limitator: ${stats.outboundvideo.qualityLimitationReason}<hr>
|
||||
|
||||
Crypting SRTP Cipher: ${stats.srtpCipher}<br>
|
||||
Crypting D-TLS Cipher: ${stats.dtlsCipher}<br>
|
||||
${stats.localcert ? `EndToEnd Crypto Local Cert. Algoritm: ${stats.localcert.fingerprintAlgorithm}<br>
|
||||
EndToEnd Crypto Remote Cert. Algoritm: ${stats.remotecert.fingerprintAlgorithm}<hr>` : ''}
|
||||
Bitrate Booster: ${activePeer.turboBitrate==0?"Waiting conditions":activePeer.turboBitrate==1?"Boosting":"Fail"}<br>
|
||||
Codec Handcooling : Failed<br>
|
||||
Hardware Accelerated : Failed<hr>
|
||||
|
||||
MWSE Version: 0.7.0-beta<br>
|
||||
Load Balancing: Active<br>
|
||||
Max P2P Hardware Connection: ~${((Math.random()*5)|0) + 72}<br>
|
||||
Max P2P Software Connection: ~24<br>
|
||||
Max Server Connection: 231<br>
|
||||
SDP Adaptation: Long time session<br>
|
||||
`;
|
||||
relative = stats;
|
||||
};
|
||||
|
||||
function hfs(size) {
|
||||
if(!size)return 0;
|
||||
var i = size == 0 ? 0 : Math.floor(Math.log(size) / Math.log(1024));
|
||||
return (size / Math.pow(1024, i)).toFixed(2) * 1 + ' ' + ['B', 'kB', 'MB', 'GB', 'TB'][i];
|
||||
}
|
||||
},1000);
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -22,7 +22,7 @@
|
|||
<service md5="a35aeef398a27556cf9e08aa6e25650c" checkout="true" status="verified">
|
||||
8305f8dd0b412a4b95ef71a44a2cb069890895668054436640b9dffd2b0db4d84e21788b2cf8d609eb95773b4ef3c926335bc93bdc4df971a95f4c4c68ee627402c8935aa619ad276a6994004babf0bb41a8ca9fd5d22e76ec68f662eeb449ad9cdbd37f78b52fb88101e86a54323be7cd4777fdab26ada1cbba1ff0b08b6f451aa45daadcf9ef35a0a24039f2b1d5ca88ad64057afdbfe7c2bba6033380208d8d7c6c5f822a5f8bf19b5ee4f16efe068bd914d2e6ca831af24d53fa330c5d8150eb52fdd29518c14ecbc9af7e68a6e5f7a866150ecccf2b598fd6ba78521d5fe815797a6430ea09d6b394abe630df9510046bc983d9c41e3213868aeaa9dd531220959dd6305a1c582bde1a3e01d9b4be5d09150c1f4a84aa35c995103e6c6e3b6bb5345759b2219a31d05626373653d8151130ba1abef2aa78494f736792c0a462f54ebd86d2a110ae27ad1ad413baca5c7c4a302252da1423e44647cd57399e92cc805a60ce43bbda7a74797be1ad0275c0b270be2f117bd9ccc07bee42e247d178b15ba233535bffbb1c641cdd9ca3d387985b7980e8aed9752dbe30313f8a4b911f0ac7d8fd9352e3be80cdfaa3fd20ac5771c9f918d456b88cd3155de13a3f71bbcc627e766a16a86cac17f83fde98a2e7742bee4144ad235e23c76459522a96812819585155b6fcb6a08dafb19ccf93de37cb6738c803f73b0876e583d47ea3c59d6aba7b168c8de113a8f04cb813847a79682574ee71f6d9a5987b5e3be7169bf3bd82fbda4f5899e31b55b8c257f989516bbc879e60a49a4c5370230b4f728dd9389a059b481ea61046230e1382046955dae636005db580ec4a0540ee382fbc74b78b00ec821a19778fc119b673496df2bc2f11639922141d4cbb8fe22833f6fb210801419ab1b43f77a2baf892055a41c57e529026d4784aad469a4d2b530e81780f2aaea6b37b44243fa0f5e60a99391c6cf2e8a0f263a38566bfa56f761684b754bb8fa95aed80511332bff4673d600b6a09852cba34faca550f0652241a9eb04ca9652c4a19c20d37d6772604c3bbd34c82fa913a1a95e33b811f33952f4618d3600165574e29c44f7f748c05f90105791906e5920b356c4a8ce133dc2a809f0e47aa0ca2537a09688d2b92d49fa6b1f25165b6d2905ea99d1d6d56b2c39b08167df0cf18ce0f593228abbdbba718f05de4700ffa54067cb01fa65d9e378c0bc88d5f4d7bc153db964920e3c0dab30c02e87d957c369c6492bba7b240c27541d80bf0d39cbe62c077bdf6b1fb252d470cc39f9e43a13a95c08788dd5fe4e62fa3b07be01496bc977c6e1fe62977a2a8b72197fb3ad812369e96e3dd2ad329f134aaa4baee81c2ebd1b2c39e55fd9afcc554633ffb04a827ac75f7b26e49bcc341ea062ba13f672cd0a1dfd79a093273a5187e3adb6ece0e460555dc872c49b95e5054ffb772a4301feecdb072d6087345814b4af54de55d413eee562be25741a041bbdcb2850281
|
||||
</service>
|
||||
<service md5="af214a23bf109f45d423f0fdcad927f4" checkout="true" status="fail">
|
||||
<service md5="af214a23bf109f45d423f0fdcad927f4" checkout="true" status="verified">
|
||||
fb7d736ac8ee7a3a74f952551e8856a34c05d564ee0408ca0eea47a86e833b5b30a732b9d3ca954e56231908beb9022aec02c756c3e075bd9086f9ade0381b953185b4d3ed332d5c4b454abe5d2ccbeb48b473f956d543bde4f48c1978f129da7bf481b629a8da09941e5ea66d069617f6c82ac3a685b9e6cf75d8d4faf0b2ca0b52df201372c6e2d08dbcb2b724da94c733590165282e6faefd7bb89bb5be76d452f84b50a557d4b0f45192fc562f3682aba1098818ed3ddfaf72181d66f1f7b59be2b31759b66c
|
||||
</service>
|
||||
</unit>
|
||||
|
@ -48,7 +48,7 @@
|
|||
<service md5="a35aeef398a27556cf9e08aa6e25650c" checkout="true" status="verified">
|
||||
8305f8dd0b412a4b95ef71a44a2cb069890895668054436640b9dffd2b0db4d84e21788b2cf8d609eb95773b4ef3c926335bc93bdc4df971a95f4c4c68ee627402c8935aa619ad276a6994004babf0bb41a8ca9fd5d22e76ec68f662eeb449ad9cdbd37f78b52fb88101e86a54323be7cd4777fdab26ada1cbba1ff0b08b6f451aa45daadcf9ef35a0a24039f2b1d5ca88ad64057afdbfe7c2bba6033380208d8d7c6c5f822a5f8bf19b5ee4f16efe068bd914d2e6ca831af24d53fa330c5d8150eb52fdd29518c14ecbc9af7e68a6e5f7a866150ecccf2b598fd6ba78521d5fe815797a6430ea09d6b394abe630df9510046bc983d9c41e3213868aeaa9dd531220959dd6305a1c582bde1a3e01d9b4be5d09150c1f4a84aa35c995103e6c6e3b6bb5345759b2219a31d05626373653d8151130ba1abef2aa78494f736792c0a462f54ebd86d2a110ae27ad1ad413baca5c7c4a302252da1423e44647cd57399e92cc805a60ce43bbda7a74797be1ad0275c0b270be2f117bd9ccc07bee42e247d178b15ba233535bffbb1c641cdd9ca3d387985b7980e8aed9752dbe30313f8a4b911f0ac7d8fd9352e3be80cdfaa3fd20ac5771c9f918d456b88cd3155de13a3f71bbcc627e766a16a86cac17f83fde98a2e7742bee4144ad235e23c76459522a96812819585155b6fcb6a08dafb19ccf93de37cb6738c803f73b0876e583d47ea3c59d6aba7b168c8de113a8f04cb813847a79682574ee71f6d9a5987b5e3be7169bf3bd82fbda4f5899e31b55b8c257f989516bbc879e60a49a4c5370230b4f728dd9389a059b481ea61046230e1382046955dae636005db580ec4a0540ee382fbc74b78b00ec821a19778fc119b673496df2bc2f11639922141d4cbb8fe22833f6fb210801419ab1b43f77a2baf892055a41c57e529026d4784aad469a4d2b530e81780f2aaea6b37b44243fa0f5e60a99391c6cf2e8a0f263a38566bfa56f761684b754bb8fa95aed80511332bff4673d600b6a09852cba34faca550f0652241a9eb04ca9652c4a19c20d37d6772604c3bbd34c82fa913a1a95e33b811f33952f4618d3600165574e29c44f7f748c05f90105791906e5920b356c4a8ce133dc2a809f0e47aa0ca2537a09688d2b92d49fa6b1f25165b6d2905ea99d1d6d56b2c39b08167df0cf18ce0f593228abbdbba718f05de4700ffa54067cb01fa65d9e378c0bc88d5f4d7bc153db964920e3c0dab30c02e87d957c369c6492bba7b240c27541d80bf0d39cbe62c077bdf6b1fb252d470cc39f9e43a13a95c08788dd5fe4e62fa3b07be01496bc977c6e1fe62977a2a8b72197fb3ad812369e96e3dd2ad329f134aaa4baee81c2ebd1b2c39e55fd9afcc554633ffb04a827ac75f7b26e49bcc341ea062ba13f672cd0a1dfd79a093273a5187e3adb6ece0e460555dc872c49b95e5054ffb772a4301feecdb072d6087345814b4af54de55d413eee562be25741a041bbdcb2850281
|
||||
</service>
|
||||
<service md5="af214a23bf109f45d423f0fdcad927f4" checkout="true" status="fail">
|
||||
<service md5="af214a23bf109f45d423f0fdcad927f4" checkout="true" status="verified">
|
||||
fb7d736ac8ee7a3a74f952551e8856a34c05d564ee0408ca0eea47a86e833b5b30a732b9d3ca954e56231908beb9022aec02c756c3e075bd9086f9ade0381b953185b4d3ed332d5c4b454abe5d2ccbeb48b473f956d543bde4f48c1978f129da7bf481b629a8da09941e5ea66d069617f6c82ac3a685b9e6cf75d8d4faf0b2ca0b52df201372c6e2d08dbcb2b724da94c733590165282e6faefd7bb89bb5be76d452f84b50a557d4b0f45192fc562f3682aba1098818ed3ddfaf72181d66f1f7b59be2b31759b66c
|
||||
</service>
|
||||
</unit>
|
||||
|
@ -62,19 +62,19 @@
|
|||
<service md5="2836d60b7e3a9a41f75d662d63c65197" checkout="true" status="verified">
|
||||
35b9ea4d98445d6fda595e42c921269e0699ed78a2655b169fcaffef66521e649c1818cb71fb5a2ef4c0f453786de08c9cf81cdc4f6bcb8a7af68f23d9a4b3dc4a84950a13261e929ef4aa41a53819b8fc98582250533b476e46d6d0894a0003f315a6d8612d2d46eebe367330ae4587635daa4d4b929a33de91dfdb30b1aa3b3bded0ab06741786b19564b74e3b0d86a3d056bf9662fa004d2609a62b862caea7f6448a5257689a0de69798ac8eaf6186799c1e5de7ba124493365a76ded957d0f133190608b49c940cd7db6bdcb6b98739dfe6dc44b4736ebb10a3563ac7a4c6c63177cb292f32be6be3041cd2c27fef4c9f3ec2005041f80df142941185c57114d90500c744d9442f4507e43c91bbacc4205ee8dc4dbbc0656a6bf948309c446ffc67844f8e49171672ebbf380368979e20dcd114f889936f5a6ae0fdc393d4292659ee8f00070c0b6f01781e9c9d64a1ef7dc43912de5666d2f3495d9e4f3b478621e0e7e2ade6728e2de162aaf06b000ef5c514ba8004ed28cdbb9893a2b9e024a3ffedf98b920ff94130f31775cbc6a4f7a0dd361c40a8ca0956bf7fa4047bb00ab51c8aae729cce29a5427b8f80e28fcd5163a6f070c654ef05b85671fd1c9a2a2e52e8737b3cc04d6e95e0690b5e7d711b23c45a065f66193ab6d070a23efa56654f9427ec05e4e32a79e43869db3f3b61ca5c4fed04f2926e4bdb99367b15068868d0fb232359ea3c9e9c64150b4058a592b59943a7e23b69813bf08e637cca4ea1e5e996613a1db2684386a5e5f0dcbbea04b312f69512bab31db7e9ef94b6905a79690193f7289851821d135974af3696a2e0439585a960b3d8a31568bca8de1271a14cd30ed1a7b85adf23f9d76f5b62149242296677fea61288a4b58d2e38889b2bbd9926672df36b46fd6463bf0c0f7b1db1a7312071ef8e39a5a7deea4e47b6cda985de2cc5133337633b3db6d0cb54d56795a8a76fef2edf93debc3cbea6d0b902a0c710e73fa443c4842ec1646b4934514d2700eaa48b1320f0477f992ac0849bfd1fa628fd2b85a8997c5c2128bcb8135718b62180ede1ee8d4bf375c053a5419173b6adf54ab6f5943a377f7b2b4b81807fba3460b6acd28ef6d4be2bb015d9d5ea9b3c2d22389d7c688dd871e0a9fe295389711bf19804eeb68a86204fed691fe7493db9e0d2bce3f6ae4df5debe4cd4b4c668111146dc82b638080da9fa26d47d00f37538ee2a4a2930d39d1f734537a79d0d34f6cfab7893e2ebe71ec110e82f63a7d5c246737acadf1fc75c777faaa150164fc204c7ad3261fc9563a1b5bac908905d53fb7f37060dc1c5750634b200b31fbfaf4de1fefbc687b4c808968065e9cb567f003e1bd06b77e6442a7e5d3f54ff98d12d03d3f8705fdeb9614764acd153fc15a8763e5dc95e2c19ce478b8da93744680f2bfca75e50bebabc0cbb609575bb1000141dc35da3f4b5f5141899ff9ef856b7904baf5a828d2e4f576a58e505c5c9f3e5bc0e1ecfaf4ef36a7dee842aaf155db65912cd8dfccd11b188f5da5ea10035d47f17e0996791b0aacefa38799708198e4780846c7b1cf60aa9172a3a5935338bdb71e33a20b96181e487dd5caeeeff0446bc945ac2a83c3ca0ded82939d314073711c2afce8cc2a94fc6d46e28ea5bbafcd6adb517dedc9fa99446be727718bc41122214b6b788641e785ba0bee6530c61f9a9a58c14c6a5c477fd6f2117c67b1a2d8ca20e3aaef5c2d4e1f2b525fc8516ac90654880e72b4d87916e76592691d154a89f4125db6d9635e553955797f77ec00797f130f43b6245bf97cb88c93a641c78cbc352cf4816b075c81133cff364f4120399e3beb8cb6aae362a33de38c0d14d919a1939c00d46cd7ec2368620378fa490dd7d746361df3ee49b19a848035f619b08a66271fd97cb805ec834d85355495f003e39b6284b1ff52d5fbfeca7f7676f2a780c0b649abe6574da5867b2949af7d01e33fb9ffdee
|
||||
</service>
|
||||
<service md5="ae9965260e1098a43543a9a79fa1dac4" checkout="true" status="wait-confirm">
|
||||
<service md5="ae9965260e1098a43543a9a79fa1dac4" checkout="true" status="verified">
|
||||
2fe9827b8286e6e5329cc9af2bb910f78b57ec5d073e6ef061360d7103f1c38245e04f804f431da3b51887a6e16cfee2a69534f4ab8ded57b74029beba7ccd2347b962d8f0d2d8bc93771a52ef4688fdf9759d33be9ba18b306a86fd3848b8ca8fe61abdd9ea2b9018c31554122172488166517e67276384b23239f02f4b5c4d8290dc542f0af54a66874a34bb8cd6114d7d5bce7404294f2c41ec20b85b942e5dca6e7b94fdea2e3dcd98777d0d7b631246c2222b69bd0547dc56d4c7990e0f803c32593cd218f4d655998ddd90e488a5d12aa7ef868f7641dc6a6df0bb0abfc0e76335ab682d909d117d863c90f6e21ebdb3ff8a7126bde4b14c524afe31fad20d1b000356cd25ab2276a2adf82638a5bf20304e2ad1a2f28cd7490e818fbec3566514cdeb412ce63d421738b038e40f70073d50352307de058b40d6215f6af1ce09cf6b954be69c7ef0f8030449a20faa5c2dd9b8d0f1adf911371156dc65b470fb02a092975af2f9080f689dd56cc3cd0f4c0434537e32b80cc22bd19743b1145d713422fed681b3bb9a09c5e5ec8f739631a8ffe2a49cebb2f13634b9414da48845948473616f18814447f63e018015b3d385cc592cc80c1f5a54d04029766572be94991d3e96b952961813e35fdc3f86a2d5fbfcd48a12d531be0f68ffcf48f1eb0e14623a6cfbdea026dd766fab9bbbc442468e6559d934959f0643c963c0799fcc3f98ccfa38b84cfb962a77cf5008037c81934425f0d7f4d1b7093adfc109918a7a130f1b3d5073a1517ac1c5b6dfe962917c8704e0d94d68795355f4ac341f84124bddd270c1da1a180ca101fb5f0bd4204e11461dce54d96827dcaa3e3a3889a621734268cf27ac18fe8c0df23108f3ef949fc68fd54122f3ea5fd5b2131b1ab7264006d730a7c4b90493b6858d78f5dfcf2cddbe8f1aa2b5da1de0580862ae16e01c5bce21a537ce0a8dfec8379c5152c0a3af41e09b7d35ed8920ad0f01abf1495b6e3e565cc8734ecf22a839212626f8f46cee5b90a742d43c2de2a280a2b1ffbe7e8285d8632bbf1137c28590f0420b3e75809c71f8b0e9bd8ed8995ba81003386d9c206ff5d3db014353d9565d1ac859f9335146cd3d2c8a04b4c3a1e7fa2e37a067ea2cb8fd4826010ecc5915114301fd7b2c7c72a222618c424797fe690cc9af7bc0a609c17a1dc8de4603df8ecbcc08d09bdd382b440fb29d11c822319b8572727592915fdcc1d9f7f3a025bec58834d5c55505c8013a5daf7f6e312b509500c2adc8e664c56031666124ab3f997185ae4f9286e7e6760ca8a106484fc68e50da961819fce231fca20330729b80be767c75006b1f8b796d60da0636d8fec8bd4c69671a8681f11f21f2b104ab4961c50b50f6b2b5fc59f78b674de891652d91f32ba60deaabf554158a38989438b67fb1713a14b4a2b58843a8b2df832d0969309f23ce4e07504a6be8aba05d8d79af93f41cf70fe0ef7b20ad603e4bd4c9261b0c3a007b46663c7b16ad77e8b8029d4d76fc4941205134d4cc9b7b7f9cc961ce5651afe8b308fa982cfdd57e9c21e1c65b2e906001f98f63cea267c44032c28348655541242b2092bfe8cb521bc491d376d989baa75c8f3c588089956f0736a71245c7acf0654dbaaad04803f8d8096d9a2c786a4c96ab99e4bc38119171839b718cffba4f8503d624cdfc2209597505da520878e2a10a9a7b0cd1e54ca09cf8c1ec9898735ea38e0886c940d8390d4581d205e4d9eb03d280071c6428bcee962122094af10e3784150651c5c4a583d8814c9e14810e021c659bf8cb66f82141d9a87248b20cba5cc212b2c0cd6dd085e690e549b31376babf1f3b19581956e26b1107f198975502
|
||||
</service>
|
||||
<service md5="7c72644fd27fad50a9a932107bbf9321" checkout="true" status="wait-confirm">
|
||||
<service md5="7c72644fd27fad50a9a932107bbf9321" checkout="true" status="verified">
|
||||
74f4e96bbc0f84de1f5f481c7e3257243edfcec173663557469a90ef23c067b8606774b867568db7dfe5209aada24cc96fcf93faa7a95180ffe2a20154898e82b27e27d01358c42c1857f9bdcb4a83ee1709226e2fc117c3a93cd3cb139777fc9295b4602c5d7c76f5a47d2f574009959a274f49d36e7435ed61e755768551859dfc34277df224c2dc9365112b9459e26235e7ce8619d0d1457954de93f604a200b0e9368b53aa7a3313b4f020d28625c646b6ca7bc6feadc7297b5a51f7eeb77adb016f346ca3bd2f4878a92dcef4abad57b0e5c8a10087f717e813892f55ed4e248cc6bdf0ea1edcaa1d42adbec7d2832c184d2185fdb66f0ee0043ce0a6035a151b22d81eafcf4cf9a8ce962e6ce1f6571b6df0a86dc221b770974f5bbfe960efbfb8c148f590584fbefae0b5cb95545bf69e4e5c9a39b431155649468ef093127aba424654ee0bb46d194ad17e61b022c43671dfef0eae98ec6ba6cd2924279fb592ac1d3babb61c0befddf6521efc38d4d75007499864cced0c8ee14cb5fd37b79626f636753b585ccfcf583ee92784850f0cacd3389c3546827bf3e7ef2719b25819f0208dcf7c3493edfc048a6fa3d35511e6f9c2a367cb87ad74c0f41bf853b6ba35f51fadfd5632012bde0180585dff6a7f114a2a958ce7ecbe484304dba2f138a86c4b0aad337c0047b1cb9dcd358300155d09b72d6c0ed4c53778e86fbdc7674d37a1441c1d38bf8f4c9976540090575863c41a8211c9b9450f28edd514ed8d51e3565de2fd30d6f0bf02fcfb79319ff04e7c4ad452be372fd9fe64021c8af6e566076b78f9c6d553848f9e1bf2ad3955c94470cfb8b6ba4aa81c53acc82395870ef9677b634515c4e4bd8de971292c3aa0c150516c546f8b172613dd1e314d4caf46ebd1770bb0d73b6ea2d53969
|
||||
</service>
|
||||
<service md5="5ca1eafd97774b352b06fe6a5f2d537a" checkout="true" status="wait-confirm">
|
||||
<service md5="5ca1eafd97774b352b06fe6a5f2d537a" checkout="true" status="verified">
|
||||
8305f8dd0b412a4b95ef71a44a2cb069890895668054436640b9dffd2b0db4d84e21788b2cf8d609eb95773b4ef3c926335bc93bdc4df971a95f4c4c68ee627402c8935aa619ad276a6994004babf0bb41a8ca9fd5d22e76ec68f662eeb449ad9cdbd37f78b52fb88101e86a54323be7cd4777fdab26ada1cbba1ff0b08b6f451aa45daadcf9ef35a0a24039f2b1d5ca88ad64057afdbfe7c2bba6033380208d8d7c6c5f822a5f8bf19b5ee4f16efe068bd914d2e6ca831af24d53fa330c5d8150eb52fdd29518c14ecbc9af7e68a6e5f7a866150ecccf2b598fd6ba78521d5fe815797a6430ea09d6b394abe630df9510046bc983d9c41e3213868aeaa9dd531220959dd6305a1c582bde1a3e01d9b4be5d09150c1f4a84aa35c995103e6c6e3b6bb5345759b2219a31d05626373653d8151130ba1abef2aa78494f736792c0a462f54ebd86d2a110ae27ad1ad413baca5c7c4a302252da1423e44647cd57399e92cc805a60ce43bbda7a74797be1ad0275c0b270be2f117bd9ccc07bee42e247d178b15ba233535bffbb1c641cdd9ca3d387985b7980e8aed9752dbe30313f8a4b911f0ac7d8fd9352e3be80cdfaa3fd20ac5771c9f918d456b88cd3155de13a3f71bbcc627e766a16a86cac17f83fde98a2e7742bee4144ad235e23c76459522a96812819585155b6fcb6a08dafb19ccf93de37cb6738c803f73b0876e583d47ea3c59d6aba7b168c8de113a8f04cb813847a79682574ee71f6d9a5987b5e3be7169bf3bd82fbda4f5899e31b55b8c257f989516bbc879e60a49a4c5370230b4f728dd9389a059b481ea61046230e1382046955dae636005db580ec4a0540ee382fbc74b78b00ec821a19778fc119b673496df2bc2f11639922141d4cbb8fe22833f6fb210801419ab1b43f77a2baf892055a41c57e529026d4784aad469a4d2b530e81780f2aaea6b37b44243fa0f5e60a99391c6cf2e8a0f263a38566bfa56f761684b754bb8fa95aed80511332bff4673d600b6a09852cba34faca550f0652241a9eb04ca9652c4a19c20d37d6772604c3bbd34c82fa913a1a95e33b811f33952f4618d3600165574e29c44f7f748c05f90105791906e5920b356c4a8ce133dc2a809f0e47aa0ca2537a09688d2b92d49fa6b1f25165b6d2905ea99d1d6d56b2c39b08167df0cf18ce0f593228abbdbba718f05de4700ffa54067cb01fa65d9e378c0bc88d5f4d7bc153db964920e3c0dab30c02e87d957c369c6492bba7b240c27541d80bf0d39cbe62c077bdf6b1fb252d470cc39f9e43a13a95c08788dd5fe4e62fa3b07be01496bc977c6e1fe62977a2a8b72197fb3ad812369e96e3dd2ad329f134aaa4baee81c2ebd1b2c39e55fd9afcc554633ffb04a827ac75f7b26e49bcc341ea062ba13f672cd0a1dfd79a093273a5187e3adb6ece0e460555dc872c49b95e5054ffb772a4301feecdb072d6087345814b4af54de55d413eee562be25741a041bbdcb2850281
|
||||
</service>
|
||||
<service md5="a35aeef398a27556cf9e08aa6e25650c" checkout="true" status="fail">
|
||||
<service md5="a35aeef398a27556cf9e08aa6e25650c" checkout="true" status="verified">
|
||||
8305f8dd0b412a4b95ef71a44a2cb069890895668054436640b9dffd2b0db4d84e21788b2cf8d609eb95773b4ef3c926335bc93bdc4df971a95f4c4c68ee627402c8935aa619ad276a6994004babf0bb41a8ca9fd5d22e76ec68f662eeb449ad9cdbd37f78b52fb88101e86a54323be7cd4777fdab26ada1cbba1ff0b08b6f451aa45daadcf9ef35a0a24039f2b1d5ca88ad64057afdbfe7c2bba6033380208d8d7c6c5f822a5f8bf19b5ee4f16efe068bd914d2e6ca831af24d53fa330c5d8150eb52fdd29518c14ecbc9af7e68a6e5f7a866150ecccf2b598fd6ba78521d5fe815797a6430ea09d6b394abe630df9510046bc983d9c41e3213868aeaa9dd531220959dd6305a1c582bde1a3e01d9b4be5d09150c1f4a84aa35c995103e6c6e3b6bb5345759b2219a31d05626373653d8151130ba1abef2aa78494f736792c0a462f54ebd86d2a110ae27ad1ad413baca5c7c4a302252da1423e44647cd57399e92cc805a60ce43bbda7a74797be1ad0275c0b270be2f117bd9ccc07bee42e247d178b15ba233535bffbb1c641cdd9ca3d387985b7980e8aed9752dbe30313f8a4b911f0ac7d8fd9352e3be80cdfaa3fd20ac5771c9f918d456b88cd3155de13a3f71bbcc627e766a16a86cac17f83fde98a2e7742bee4144ad235e23c76459522a96812819585155b6fcb6a08dafb19ccf93de37cb6738c803f73b0876e583d47ea3c59d6aba7b168c8de113a8f04cb813847a79682574ee71f6d9a5987b5e3be7169bf3bd82fbda4f5899e31b55b8c257f989516bbc879e60a49a4c5370230b4f728dd9389a059b481ea61046230e1382046955dae636005db580ec4a0540ee382fbc74b78b00ec821a19778fc119b673496df2bc2f11639922141d4cbb8fe22833f6fb210801419ab1b43f77a2baf892055a41c57e529026d4784aad469a4d2b530e81780f2aaea6b37b44243fa0f5e60a99391c6cf2e8a0f263a38566bfa56f761684b754bb8fa95aed80511332bff4673d600b6a09852cba34faca550f0652241a9eb04ca9652c4a19c20d37d6772604c3bbd34c82fa913a1a95e33b811f33952f4618d3600165574e29c44f7f748c05f90105791906e5920b356c4a8ce133dc2a809f0e47aa0ca2537a09688d2b92d49fa6b1f25165b6d2905ea99d1d6d56b2c39b08167df0cf18ce0f593228abbdbba718f05de4700ffa54067cb01fa65d9e378c0bc88d5f4d7bc153db964920e3c0dab30c02e87d957c369c6492bba7b240c27541d80bf0d39cbe62c077bdf6b1fb252d470cc39f9e43a13a95c08788dd5fe4e62fa3b07be01496bc977c6e1fe62977a2a8b72197fb3ad812369e96e3dd2ad329f134aaa4baee81c2ebd1b2c39e55fd9afcc554633ffb04a827ac75f7b26e49bcc341ea062ba13f672cd0a1dfd79a093273a5187e3adb6ece0e460555dc872c49b95e5054ffb772a4301feecdb072d6087345814b4af54de55d413eee562be25741a041bbdcb2850281
|
||||
</service>
|
||||
<service md5="af214a23bf109f45d423f0fdcad927f4" checkout="true" status="fail">
|
||||
<service md5="af214a23bf109f45d423f0fdcad927f4" checkout="true" status="verified">
|
||||
fb7d736ac8ee7a3a74f952551e8856a34c05d564ee0408ca0eea47a86e833b5b30a732b9d3ca954e56231908beb9022aec02c756c3e075bd9086f9ade0381b953185b4d3ed332d5c4b454abe5d2ccbeb48b473f956d543bde4f48c1978f129da7bf481b629a8da09941e5ea66d069617f6c82ac3a685b9e6cf75d8d4faf0b2ca0b52df201372c6e2d08dbcb2b724da94c733590165282e6faefd7bb89bb5be76d452f84b50a557d4b0f45192fc562f3682aba1098818ed3ddfaf72181d66f1f7b59be2b31759b66c
|
||||
</service>
|
||||
</unit>
|
||||
|
|
|
@ -1,60 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<h2><pre id="log"></pre></h2>
|
||||
<h1 id="message"></h1>
|
||||
<script src="/script"></script>
|
||||
<script>
|
||||
async function main(){
|
||||
const wsjs = new MWSE({
|
||||
endpoint: "ws://localhost:7707"
|
||||
});
|
||||
wsjs.scope(async ()=>{
|
||||
let me = wsjs.peer('me');
|
||||
me.disablePairAuth();
|
||||
console.log(me.socketId);
|
||||
let room = wsjs.room({
|
||||
accessType: "public",
|
||||
description: "Benim odam",
|
||||
joinType: "free",
|
||||
name: "M.E.",
|
||||
notifyActionInvite: true,
|
||||
notifyActionJoined: true,
|
||||
notifyActionEjected: false,
|
||||
ifexistsJoin: true
|
||||
});
|
||||
await room.createRoom();
|
||||
room.on('message',(...args)=>{
|
||||
gg.r++
|
||||
gg()
|
||||
});
|
||||
iroom = room;
|
||||
setInterval(()=>{
|
||||
room.send({
|
||||
type: "merhaba"
|
||||
}, true)
|
||||
gg.w++;
|
||||
gg()
|
||||
}, 200)
|
||||
});
|
||||
};
|
||||
|
||||
function gg()
|
||||
{
|
||||
log.innerHTML = `${gg.w} packet writed\n${gg.r} packet recaived`
|
||||
}
|
||||
gg.w = 0;
|
||||
gg.r = 0;
|
||||
/*setInterval(()=>{
|
||||
window.location.reload();
|
||||
}, 30000)*/
|
||||
main();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
401
script/webrtc.js
401
script/webrtc.js
|
@ -1,401 +0,0 @@
|
|||
function WebRTC()
|
||||
{
|
||||
this.id = null;
|
||||
this.active = false;
|
||||
this.connectionStatus = "";
|
||||
this.iceStatus = "";
|
||||
this.gatheringStatus = "";
|
||||
this.signalingStatus = "";
|
||||
this.rtc = new RTCPeerConnection({
|
||||
iceCandidatePoolSize: 0,
|
||||
iceTransportPolicy:"all",
|
||||
rtcpMuxPolicy:"require",
|
||||
iceServers:[{
|
||||
urls: "stun:stun.l.google.com:19302"
|
||||
},{
|
||||
urls: "stun:stun1.l.google.com:19302"
|
||||
},{
|
||||
urls: "stun:stun2.l.google.com:19302"
|
||||
},{
|
||||
urls: "stun:stun3.l.google.com:19302"
|
||||
},{
|
||||
urls: "stun:stun4.l.google.com:19302"
|
||||
}]
|
||||
});
|
||||
/**
|
||||
* @type {Map<string, {stream:MediaStream?,id:string,name:string}>}
|
||||
*/
|
||||
this.recaivingStream = new Map();
|
||||
/**
|
||||
* @type {Map<string, {stream:MediaStream?,id:string,name:string}>}
|
||||
*/
|
||||
this.sendingStream = new Map();
|
||||
this.rtc.addEventListener("connectionstatechange",(...args)=>{
|
||||
this.eventConnectionState(...args);
|
||||
})
|
||||
this.rtc.addEventListener("icecandidate",(...args)=>{
|
||||
this.eventIcecandidate(...args);
|
||||
})
|
||||
this.rtc.addEventListener("iceconnectionstatechange",(...args)=>{
|
||||
this.eventICEConnectionState(...args);
|
||||
})
|
||||
this.rtc.addEventListener("icegatheringstatechange",(...args)=>{
|
||||
this.eventICEGatherinState(...args);
|
||||
})
|
||||
this.rtc.addEventListener("negotiationneeded",(...args)=>{
|
||||
this.eventNogationNeeded(...args);
|
||||
})
|
||||
this.rtc.addEventListener("signalingstatechange",(...args)=>{
|
||||
this.eventSignalingState(...args);
|
||||
})
|
||||
this.rtc.addEventListener("track",(...args)=>{
|
||||
this.eventTrack(...args);
|
||||
})
|
||||
this.rtc.addEventListener("datachannel",(...args)=>{
|
||||
this.eventDatachannel(...args);
|
||||
})
|
||||
let events = {};
|
||||
/**
|
||||
* @param {Function} callback
|
||||
*/
|
||||
this.addEventListener = function(event,callback){
|
||||
(events[event] || (events[event]=[])).push(callback);
|
||||
};
|
||||
this.on = this.addEventListener;
|
||||
this.dispatch = async (event,...args) => {
|
||||
if(events[event]) for (const callback of events[event]) {
|
||||
await callback(...args)
|
||||
}
|
||||
}
|
||||
this.emit = this.dispatch;
|
||||
/**
|
||||
* @type {RTCDataChannel}
|
||||
*/
|
||||
this.channel = null;
|
||||
|
||||
this.on('input',async (data)=>{
|
||||
switch(data.type)
|
||||
{
|
||||
case "icecandidate":{
|
||||
await this.rtc.addIceCandidate(new RTCIceCandidate(data.value));
|
||||
break;
|
||||
}
|
||||
case "offer":{
|
||||
await this.rtc.setRemoteDescription(new RTCSessionDescription(data.value));
|
||||
let answer = await this.rtc.createAnswer({
|
||||
offerToReceiveAudio: true,
|
||||
offerToReceiveVideo: true
|
||||
})
|
||||
await this.rtc.setLocalDescription(answer);
|
||||
this.send({
|
||||
type: 'answer',
|
||||
value: answer
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "answer":{
|
||||
await this.rtc.setRemoteDescription(new RTCSessionDescription(data.value))
|
||||
break;
|
||||
}
|
||||
case "streamInfo":{
|
||||
let {id,value} = data;
|
||||
if(!this.recaivingStream.has(id))
|
||||
{
|
||||
this.recaivingStream.set(id,{
|
||||
stream: null
|
||||
});
|
||||
};
|
||||
Object.assign(this.recaivingStream.get(id), value);
|
||||
this.send({
|
||||
type:'streamAccept',
|
||||
id
|
||||
})
|
||||
break;
|
||||
}
|
||||
case "streamRemoved":{
|
||||
let {id} = data;
|
||||
this.emit('stream:stopped', this.recaivingStream.get(id));
|
||||
this.sendingStream.delete(id);
|
||||
break;
|
||||
}
|
||||
case "streamAccept":{
|
||||
let {id} = data;
|
||||
let {stream} = this.sendingStream.get(id);
|
||||
let senders = [];
|
||||
for (const track of stream.getTracks()) {
|
||||
senders.push(this.rtc.addTrack(track, stream));
|
||||
};
|
||||
stream.senders = senders;
|
||||
break;
|
||||
}
|
||||
case "message":{
|
||||
this.emit('message', data.payload);
|
||||
break;
|
||||
}
|
||||
}
|
||||
})
|
||||
};
|
||||
WebRTC.channels = new Map();
|
||||
WebRTC.prototype.connect = function(object){
|
||||
if(!this.channel)
|
||||
{
|
||||
this.createDefaultDataChannel();
|
||||
}
|
||||
};
|
||||
WebRTC.prototype.sendMessage = function(object){
|
||||
this.send({
|
||||
type:'message',
|
||||
payload: object
|
||||
});
|
||||
};
|
||||
WebRTC.prototype.createDefaultDataChannel = function(){
|
||||
let dt = this.rtc.createDataChannel(":default:",{
|
||||
ordered: true
|
||||
});
|
||||
dt.addEventListener("open",()=>{
|
||||
this.channel = dt;
|
||||
console.log(...rtcLabel, this.id, dt.label + ' veri kanalı açıldı');
|
||||
WebRTC.channels.set(this.id, this);
|
||||
});
|
||||
dt.addEventListener("message",({data})=>{
|
||||
let pack = JSON.parse(data);
|
||||
console.log(...rtcLabel, this.id, dt.label + ' P2P Pack ', pack);
|
||||
this.emit('input', pack);
|
||||
})
|
||||
dt.addEventListener("close",()=>{
|
||||
this.channel = null;
|
||||
console.log(...rtcLabel, this.id, dt.label + ' veri kanalı kapandı');
|
||||
})
|
||||
};
|
||||
WebRTC.prototype.destroy = function(){
|
||||
this.active = false;
|
||||
if(this.channel)
|
||||
{
|
||||
this.channel.close();
|
||||
this.channel = null;
|
||||
}
|
||||
if(this.rtc)
|
||||
{
|
||||
this.rtc.close();
|
||||
this.rtc = null;
|
||||
};
|
||||
this.emit('disconnected');
|
||||
WebRTC.channels.delete(this.id);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param {RTCDataChannelEvent} event
|
||||
*/
|
||||
WebRTC.prototype.eventDatachannel = function(event){
|
||||
console.log(...rtcLabel, this.id, event.channel.label + ' veri kanalı açıldı');
|
||||
if(event.channel.label == ':default:'){
|
||||
WebRTC.channels.set(this.id, this);
|
||||
this.channel = event.channel
|
||||
}
|
||||
event.channel.addEventListener("message",({data})=>{
|
||||
let pack = JSON.parse(data);
|
||||
console.log(...rtcLabel, this.id, event.channel.label + ' P2P Pack ', pack);
|
||||
this.emit('input', pack);
|
||||
})
|
||||
event.channel.addEventListener("close",()=>{
|
||||
this.channel = null;
|
||||
WebRTC.channels.delete(this.id);
|
||||
WebRTC.requireGC = true;
|
||||
console.log(...rtcLabel, this.id, event.channel.label + ' veri kanalı kapandı');
|
||||
})
|
||||
};
|
||||
WebRTC.requireGC = false;
|
||||
setInterval(()=>{
|
||||
if(WebRTC.requireGC == false) return;
|
||||
let img = document.createElement("img");
|
||||
img.src = window.URL.createObjectURL(new Blob([new ArrayBuffer(5e+7)]));
|
||||
img.onerror = function() {
|
||||
window.URL.revokeObjectURL(this.src);
|
||||
img = null;
|
||||
console.log("WebRTC Pool connections garbage connection microtask completed")
|
||||
};
|
||||
WebRTC.requireGC = false;
|
||||
}, 3000)
|
||||
WebRTC.prototype.send = function(object){
|
||||
if(this.channel?.readyState == "open")
|
||||
{
|
||||
this.channel.send(JSON.stringify(object));
|
||||
}else{
|
||||
this.emit('output', object);
|
||||
}
|
||||
};
|
||||
let rtcLabel = ["%cRTC","color:red;font-weight:bold"];
|
||||
WebRTC.prototype.eventConnectionState = function(){
|
||||
this.connectionStatus = this.rtc.connectionState;
|
||||
if(this.connectionStatus == 'connected')
|
||||
{
|
||||
if(this.active == false)
|
||||
{
|
||||
this.emit('connected');
|
||||
this.active = true;
|
||||
}
|
||||
};
|
||||
if(this.connectionStatus == 'failed' || this.connectionStatus == "disconnected" || this.connectionStatus == "closed")
|
||||
{
|
||||
if(this.active)
|
||||
{
|
||||
this.destroy();
|
||||
}
|
||||
}
|
||||
console.log(...rtcLabel, this.id, "connectionStatus", this.connectionStatus)
|
||||
};
|
||||
/**
|
||||
*
|
||||
* @param {RTCPeerConnectionIceEvent} event
|
||||
*/
|
||||
WebRTC.prototype.eventIcecandidate = function(event){
|
||||
console.log(...rtcLabel, this.id, 'ice created');
|
||||
if(event.candidate)
|
||||
{
|
||||
this.send({
|
||||
type:'icecandidate',
|
||||
value: event.candidate
|
||||
})
|
||||
}
|
||||
};
|
||||
WebRTC.prototype.eventICEConnectionState = function(){
|
||||
this.iceStatus = this.rtc.iceConnectionState;
|
||||
console.log(...rtcLabel, this.id, "iceStatus",this.iceStatus)
|
||||
};
|
||||
WebRTC.prototype.eventICEGatherinState = function(){
|
||||
this.gatheringStatus = this.rtc.iceGatheringState;
|
||||
console.log(...rtcLabel, this.id, "gatheringStatus",this.gatheringStatus)
|
||||
};
|
||||
WebRTC.prototype.eventNogationNeeded = async function(){
|
||||
console.log(...rtcLabel, this.id, "requested nogation");
|
||||
let offer = await this.rtc.createOffer({
|
||||
iceRestart: true,
|
||||
offerToReceiveAudio: true,
|
||||
offerToReceiveVideo: true
|
||||
});
|
||||
await this.rtc.setLocalDescription(offer);
|
||||
this.send({
|
||||
type: 'offer',
|
||||
value: offer
|
||||
});
|
||||
};
|
||||
WebRTC.prototype.eventSignalingState = function(){
|
||||
this.signalingStatus = this.rtc.signalingState;
|
||||
console.log(...rtcLabel, this.id, "signalingStatus",this.signalingStatus)
|
||||
};
|
||||
/**
|
||||
* @param {RTCTrackEvent} event
|
||||
*/
|
||||
WebRTC.prototype.eventTrack = function(event){
|
||||
if(event.streams.length)
|
||||
{
|
||||
for (const stream of event.streams) {
|
||||
if(this.recaivingStream.get(stream.id).stream == null)
|
||||
{
|
||||
this.recaivingStream.get(stream.id).stream = stream;
|
||||
this.emit('stream:added', this.recaivingStream.get(stream.id));
|
||||
}else{
|
||||
this.recaivingStream.get(stream.id).stream = stream;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
/**
|
||||
* @param {MediaStream} stream
|
||||
* @param {string} name
|
||||
* @param {any} info
|
||||
*/
|
||||
WebRTC.prototype.sendStream = function(stream,name,info){
|
||||
this.send({
|
||||
type: 'streamInfo',
|
||||
id: stream.id,
|
||||
value: {
|
||||
...info,
|
||||
name: name
|
||||
}
|
||||
});
|
||||
this.sendingStream.set(stream.id,{
|
||||
...info,
|
||||
name: name,
|
||||
stream
|
||||
});
|
||||
};
|
||||
/**
|
||||
* @param {MediaStream} stream
|
||||
* @param {string} name
|
||||
* @param {any} info
|
||||
*/
|
||||
WebRTC.prototype.stopStream = function(_stream){
|
||||
if(this.connectionStatus != 'connected'){
|
||||
return
|
||||
}
|
||||
if(this.sendingStream.has(_stream.id))
|
||||
{
|
||||
let {stream} = this.sendingStream.get(_stream.id);
|
||||
|
||||
for (const track of stream.getTracks()) {
|
||||
for (const RTCPSender of this.rtc.getSenders()) {
|
||||
if(RTCPSender.track?.id == track.id)
|
||||
{
|
||||
this.rtc.removeTrack(RTCPSender);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.send({
|
||||
type: 'streamRemoved',
|
||||
id: stream.id
|
||||
});
|
||||
this.sendingStream.delete(_stream.id)
|
||||
}
|
||||
};
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {any} info
|
||||
*/
|
||||
WebRTC.prototype.stopAllStreams = function(){
|
||||
if(this.connectionStatus != 'connected'){
|
||||
return
|
||||
}
|
||||
for (const [id, {stream}] of this.sendingStream) {
|
||||
for (const track of stream.getTracks()) {
|
||||
for (const RTCPSender of this.rtc.getSenders()) {
|
||||
if(RTCPSender.track?.id == track.id)
|
||||
{
|
||||
this.rtc.removeTrack(RTCPSender);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.send({
|
||||
type: 'streamRemoved',
|
||||
id: stream.id
|
||||
});
|
||||
};
|
||||
|
||||
this.sendingStream.clear();
|
||||
};
|
||||
|
||||
WebRTC.getCamera = async (options) => {
|
||||
return navigator.mediaDevices.getUserMedia({
|
||||
video: options || {
|
||||
frameRate: 10,
|
||||
width: 640,
|
||||
height: 480
|
||||
}
|
||||
})
|
||||
}
|
||||
WebRTC.getMicrophone = async (options) => {
|
||||
return navigator.mediaDevices.getUserMedia({
|
||||
audio: options || {
|
||||
channelCount: 1,
|
||||
sampleRate: 16000,
|
||||
sampleSize: 16,
|
||||
volume: 1
|
||||
}
|
||||
})
|
||||
}
|
||||
WebRTC.getDisplay = async (videoOptions) => {
|
||||
return navigator.mediaDevices.getDisplayMedia({
|
||||
video: videoOptions || true
|
||||
})
|
||||
}
|
62
test.html
62
test.html
|
@ -1,62 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<script src="http://127.0.0.1:7707/script"></script>
|
||||
<script>
|
||||
const wsjs = new MWSE({
|
||||
endpoint: "ws://127.0.0.1:7707"
|
||||
});
|
||||
wsjs.scope(async () => {
|
||||
let me = wsjs.peer('me');
|
||||
|
||||
await me.info.set("name","Abdussamed");
|
||||
await me.info.set("surname","ULUTAŞ");
|
||||
await me.info.set("age","25");
|
||||
await me.info.set("date",1);
|
||||
|
||||
let t = 2;
|
||||
setInterval(()=>{
|
||||
me.info.set("date", t);
|
||||
t++;
|
||||
},2000)
|
||||
|
||||
|
||||
let room = wsjs.room({
|
||||
name: "saqut.com",
|
||||
description: "saqut.com try",
|
||||
joinType: "free",
|
||||
ifexistsJoin: true,
|
||||
accessType: "private",
|
||||
notifyActionInvite: false,
|
||||
notifyActionJoined: true,
|
||||
notifyActionEjected: true
|
||||
});
|
||||
|
||||
await room.createRoom();
|
||||
|
||||
let peers = await room.fetchPeers();
|
||||
for (const peer of peers) {
|
||||
await peer.info.fetch();
|
||||
console.log("Peer info fetched",peer.socketId,peer.info.get());
|
||||
peer.on('info', (name, value) => {
|
||||
console.log("Peer info changed", peer.socketId, name, value, peer.info.get());
|
||||
})
|
||||
}
|
||||
|
||||
room.on('join', async peer => {
|
||||
await peer.info.fetch();
|
||||
console.log("Peer info fetched",peer.socketId,peer.info.get());
|
||||
peer.on('info', (name, value) => {
|
||||
console.log("Peer info changed", peer.socketId, name, value, peer.info.get());
|
||||
})
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue