This commit is contained in:
abdussamedulutas 2026-04-23 23:10:05 +03:00
parent 1b02eb1bce
commit c623016841
41 changed files with 1229 additions and 5877 deletions

62
Source/EventEmitter.js Normal file
View File

@ -0,0 +1,62 @@
"use strict";
const events = new Map();
function on(event, callback) {
if (!events.has(event)) {
events.set(event, []);
}
events.get(event).push(callback);
}
function emit(event, ...args) {
if (events.has(event)) {
for (const callback of events.get(event)) {
try {
callback(...args);
} catch (error) {
console.error(`Event error [${event}]:`, error);
}
}
}
}
function once(event, callback) {
const wrapper = (...args) => {
off(event, wrapper);
callback(...args);
};
on(event, wrapper);
}
function off(event, callback) {
if (events.has(event)) {
const callbacks = events.get(event);
const index = callbacks.indexOf(callback);
if (index > -1) {
callbacks.splice(index, 1);
}
}
}
function removeAllListeners(event) {
if (event) {
events.delete(event);
} else {
events.clear();
}
}
function listenerCount(event) {
return events.has(event) ? events.get(event).length : 0;
}
module.exports = {
on,
emit,
once,
off,
removeAllListeners,
listenerCount,
events
};

View File

@ -4,48 +4,40 @@ let http = require("http");
let express = require("express");
let compression = require("compression");
let {resolve} = require("path");
let auth = require("express-basic-auth");
const { termoutput } = require("./config");
let server = http.createServer();
let app = express();
server.addListener("request", app);
app.use(compression({
level: 9
}));
server.listen(7707,'0.0.0.0',() => {
let app = express();
app.use(compression({ level: 9 }));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
let server = http.createServer(app);
server.listen(7707, '0.0.0.0', () => {
termoutput && console.log("HTTP Service Running...");
});
server.addListener("error",(err)=> {
console.err(err)
})
server.on("error", (err) => {
console.error(err);
});
exports.http = server;
app.get("/script",(request, response)=>{
response.sendFile(resolve("./script/index.js"))
});
app.get("/test",(request, response)=>{
response.sendFile(resolve("./script/test.html"))
});
app.get("/index.js.map",(request, response)=>{
response.sendFile(resolve("./script/index.js.map"))
});
app.get("/stream",(request, response)=>{
response.sendFile(resolve("./public/index.html"))
});
app.get("/",(request, response)=>{
response.sendFile(resolve("./script/index.html"))
});
app.get("/console",(request, response)=>{
response.sendFile(resolve("./console/index.html"))
});
app.get("/console/lib.js",(request, response)=>{
response.sendFile(resolve("./console/lib.js"))
});
app.use("/stream",express.static(resolve("./public")));
app.use("/console/",express.static(resolve("./console")));
const apiRouter = require("./api");
app.use("/api", apiRouter);
app.get("*",(request, response)=>{
response.sendFile(resolve("./script/status.xml"))
});
app.get("/script", (req, res) => {
res.sendFile(resolve("./script/index.js"));
});
app.use(express.static(resolve("./public")));
app.use("/script", express.static(resolve("./script")));
app.get("/", (req, res) => {
res.sendFile(resolve("./script/index.js"));
});
app.get("*", (req, res) => {
res.sendFile(resolve("./script/status.xml"));
});

54
Source/MessageRouter.js Normal file
View File

@ -0,0 +1,54 @@
"use strict";
const handlers = new Map();
function register(type, handler) {
handlers.set(type, handler);
}
function handle(client, message) {
const { type } = message;
if (!type) {
return { status: 'fail', message: 'MISSING_TYPE' };
}
const handler = handlers.get(type);
if (!handler) {
return { status: 'fail', message: 'UNKNOWN_TYPE' };
}
try {
const result = handler(client, message);
return result;
} catch (error) {
console.error(`Handler error [${type}]:`, error);
return { status: 'fail', message: 'HANDLER_ERROR', error: error.message };
}
}
function unregister(type) {
handlers.delete(type);
}
function clear() {
handlers.clear();
}
function hasHandler(type) {
return handlers.has(type);
}
function listHandlers() {
return [...handlers.keys()];
}
module.exports = {
register,
handle,
unregister,
clear,
hasHandler,
listHandlers
};

View File

@ -1,232 +1,175 @@
const { Client } = require("../Client.js");
let {addService, addListener} = require("../WebSocket.js");
"use strict";
addListener('disconnect',(global, xclient)=>{
const {intersection, pairs} = xclient.getSucureClients();
for (const [clientid, client] of intersection)
{
client?.send([
{
id: xclient.id
},
"peer/disconnect"
])
const { Client } = require("../Client.js");
const { on, emit, register } = require("../WebSocket");
on('disconnect', (xclient) => {
const { intersection, pairs } = xclient.getSucureClients();
for (const [clientid, client] of intersection) {
client?.send([{ id: xclient.id }, "peer/disconnect"]);
}
for (const [id, peer] of pairs)
{
for (const [id, peer] of pairs) {
peer?.pairs.delete(xclient.id);
xclient.pairs.delete(id);
}
});
addService(({
client,
message,
end,
next
})=>{
let {type,to,value,name} = message;
switch(type)
{
case "auth/pair-system":{
if(value == 'everybody')
{
client.requiredPair = true;
end({status:"success"});
client.sync('requiredPair');
}
if(value == 'disable')
{
client.requiredPair = false;
end({status:"success"});
client.sync('requiredPair');
//CLIENT_UPDATE_PROP(client.id, 'requiredPair', client.requiredPair);
}
break;
}
case "my/socketid":{
end(client.id);
break;
}
case 'auth/public':{
client.requiredPair = false;
client.sync('requiredPair');
return end({
value: 'success',
mode: 'public'
})
}
case 'auth/private':{
client.requiredPair = true;
client.sync('requiredPair');
return end({
value: 'success',
mode: 'private'
})
}
case 'request/pair':{
if(Client.clients.has(to)){
return end({
status: 'fail',
message: 'CLIENT-NOT-FOUND'
})
};
let pairclient = Client.clients.get(to);
if(pairclient.pairs.has(client.id))
{
return end({
status: 'success',
message: 'ALREADY-PAIRED'
})
}
if(client.pairs.has(to))
{
return end({
status: 'fail',
message: 'ALREADY-REQUESTED'
})
};
end({
status: 'success',
message: 'REQUESTED'
})
client.peerRequest(pairclient);
break;
}
case 'accept/pair':{
if(Client.clients.has(to)){
return end({
status: 'fail',
message: 'CLIENT-NOT-FOUND'
})
};
let pairclient = Client.clients.get(to);
if(pairclient.pairs.has(client.id))
{
return end({
status: 'success',
message: 'ALREADY-PAIRED'
})
}
if(!client.pairs.has(to))
{
return end({
status: 'fail',
message: 'NOT-REQUESTED-PAIR'
})
}
client.acceptPeerRequest(pairclient);
break;
}
case 'reject/pair':{
if(Client.clients.has(to)){
return end({
status: 'fail',
message: 'CLIENT-NOT-FOUND'
})
};
let pairclient = Client.clients.get(to);
if(pairclient.pairs.has(client.id))
{
return end({
status: 'success',
message: 'ALREADY-PAIRED'
})
}
if(!client.pairs.has(to))
{
return end({
status: 'fail',
message: 'NOT-REQUESTED-PAIR'
})
}
client.rejectPeerRequest(pairclient);
break;
}
case 'end/pair':{
if(Client.clients.has(to)){
return end({
status: 'fail',
message: 'CLIENT-NOT-FOUND'
})
};
let pairclient = Client.clients.get(to);
if(!pairclient.pairs.has(client.id))
{
return end({
status: 'success',
message: 'NOT-PAIRED'
})
}
client.rejectPeerRequest(pairclient);
break;
}
case 'pair/list':{
end({
type:'pair/list',
value: client.pairList()
})
break;
}
case 'is/reachable':{
if(Client.clients.has(to))
{
let otherPeer = Client.clients.get(to);
if(otherPeer.requiredPair && !otherPeer.pairs.has(to))
{
end(false);
}else{
end(true);
}
}else{
end(false);
}
break;
}
case 'auth/info':{
client.info.set(name, value);
let clients = client.getSucureClients();
for (const [,spair] of clients.pairs)
{
spair.send([{
from: client.id,
name,
value
},"pair/info"]);
};
for (const [,spair] of clients.roompairs)
{
spair.send([{
from: client.id,
name,
value
},"pair/info"]);
};
return end({
status: 'success'
});
}
case 'peer/info':{
if(client.isSecure(message.peer))
{
let info = {};
let peer = Client.clients.get(message.peer);
peer.info.forEach((value, name) => info[name] = value);
return end({
status: "success",
info
});
}else{
return end({
status: "fail",
message: "unaccessible user"
});
}
}
default:{
next();
}
register('auth/pair-system', (client, msg) => {
if (msg.value == 'everybody') {
client.requiredPair = true;
return { status: 'success' };
}
});
if (msg.value == 'disable') {
client.requiredPair = false;
return { status: 'success' };
}
return { status: 'fail', message: 'INVALID_VALUE' };
});
register('my/socketid', (client, msg) => {
return client.id;
});
register('auth/public', (client, msg) => {
client.requiredPair = false;
return { value: 'success', mode: 'public' };
});
register('auth/private', (client, msg) => {
client.requiredPair = true;
return { value: 'success', mode: 'private' };
});
register('request/pair', (client, msg) => {
const { to } = msg;
if (!Client.clients.has(to)) {
return { status: 'fail', message: 'CLIENT_NOT_FOUND' };
}
const pairclient = Client.clients.get(to);
if (pairclient.pairs.has(client.id)) {
return { status: 'success', message: 'ALREADY-PAIRED' };
}
if (client.pairs.has(to)) {
return { status: 'fail', message: 'ALREADY-REQUESTED' };
}
client.peerRequest(pairclient);
return { status: 'success', message: 'REQUESTED' };
});
register('accept/pair', (client, msg) => {
const { to } = msg;
if (!Client.clients.has(to)) {
return { status: 'fail', message: 'CLIENT_NOT_FOUND' };
}
const pairclient = Client.clients.get(to);
if (pairclient.pairs.has(client.id)) {
return { status: 'success', message: 'ALREADY-PAIRED' };
}
if (!client.pairs.has(to)) {
return { status: 'fail', message: 'NOT_REQUESTED_PAIR' };
}
client.acceptPeerRequest(pairclient);
return { status: 'success' };
});
register('reject/pair', (client, msg) => {
const { to } = msg;
if (!Client.clients.has(to)) {
return { status: 'fail', message: 'CLIENT_NOT_FOUND' };
}
const pairclient = Client.clients.get(to);
if (pairclient.pairs.has(client.id)) {
return { status: 'success', message: 'ALREADY-PAIRED' };
}
if (!client.pairs.has(to)) {
return { status: 'fail', message: 'NOT_REQUESTED_PAIR' };
}
client.rejectPeerRequest(pairclient);
return { status: 'success' };
});
register('end/pair', (client, msg) => {
const { to } = msg;
if (!Client.clients.has(to)) {
return { status: 'fail', message: 'CLIENT_NOT_FOUND' };
}
const pairclient = Client.clients.get(to);
if (!pairclient.pairs.has(client.id)) {
return { status: 'success', message: 'NOT_PAIRED' };
}
client.rejectPeerRequest(pairclient);
return { status: 'success' };
});
register('pair/list', (client, msg) => {
return { type: 'pair/list', value: client.pairList() };
});
register('is/reachable', (client, msg) => {
const { to } = msg;
if (!Client.clients.has(to)) {
return false;
}
const otherPeer = Client.clients.get(to);
if (otherPeer.requiredPair && !otherPeer.pairs.has(to)) {
return false;
}
return true;
});
register('auth/info', (client, msg) => {
const { name, value } = msg;
client.info.set(name, value);
const clients = client.getSucureClients();
for (const [, spair] of clients.pairs) {
spair.send([{ from: client.id, name, value }, "pair/info"]);
}
for (const [, spair] of clients.roompairs) {
spair.send([{ from: client.id, name, value }, "pair/info"]);
}
return { status: 'success' };
});
register('peer/info', (client, msg) => {
const { peer } = msg;
if (!client.isSecure(peer)) {
return { status: "fail", message: "unaccessible user" };
}
const peerClient = Client.clients.get(peer);
const info = {};
peerClient.info.forEach((value, name) => { info[name] = value; });
return { status: "success", info };
});

View File

@ -1,168 +1,101 @@
"use strict";
const { Client } = require("../Client.js");
let {randomUUID} = require("crypto");
let {addService,addListener} = require("../WebSocket.js");
const { Room } = require("./Room.js");
const { register } = require("../WebSocket");
const { Room } = require("./Room");
/*
Peer to peer veri aktarımı
register('pack/to', (client, msg) => {
const { to, pack, handshake } = msg;
- Kişiden kişiye direkt veri aktarımı
- Kişiler arası tünelleme / Kişiler arası özel protokol
- Oda katılımcıları içerisinde veri aktarımı
- Oda katılımcıları arasında belli kişilere veri aktarımı
if (!client.packReadable()) {
return handshake ? { type: 'fail' } : undefined;
}
*/
if (!Client.clients.has(to)) {
return handshake ? { type: 'fail' } : undefined;
}
addService(({
client,
end,
global,
message,
next,
response,
messageId
}) => {
let {type} = message;
switch(type)
{
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)
{
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'
})
}
otherPeer.send([{
from: client.id,
pack: pack
}, 'pack']);
handshake && end({
type: 'success'
})
}else{
console.error("Client, olmayan bir cliente mesaj iletiyor")
handshake && end({
type: 'fail'
})
}
break;
const otherPeer = Client.clients.get(to);
if (otherPeer.requiredPair) {
if (!otherPeer.pairs.has(to)) {
return handshake ? { type: 'fail' } : undefined;
}
case "request/to":{
let {to,pack} = message;
if(Client.clients.has(to))
{
let otherPeer = Client.clients.get(to);
if(otherPeer.requiredPair)
{
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;
} else {
if (!otherPeer.pairs.has(to)) {
otherPeer.pairs.add(client.id);
client.pairs.add(otherPeer.id);
}
case "response/to":{
let {to,pack, id} = message;
if(Client.clients.has(to))
{
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 (!otherPeer.packWriteable()) {
return handshake ? { type: 'fail' } : undefined;
}
if(!client.packReadable()){
console.error("Client paketi okumak için müsait değil")
handshake && end({
type: 'fail'
})
}
otherPeer.send([{ from: client.id, pack }, 'pack']);
return handshake ? { type: 'success' } : undefined;
});
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,
client => client.packWriteable()
);
handshake && end({
type: 'success'
})
}else{
console.error("Olmayan oda için veri gönderme isteniyor")
handshake && end({
type: 'fail'
})
}
break;
register('request/to', (client, msg) => {
const { to, pack } = msg;
if (!Client.clients.has(to)) {
return;
}
const otherPeer = Client.clients.get(to);
if (otherPeer.requiredPair) {
if (!otherPeer.pairs.has(to)) {
return;
}
default:{
next();
}
};
});
} else {
otherPeer.pairs.add(client.id);
client.pairs.add(otherPeer.id);
}
otherPeer.send([{ from: client.id, pack }, 'request']);
});
register('response/to', (client, msg) => {
const { to, pack, id } = msg;
if (!Client.clients.has(to)) {
return;
}
const otherPeer = Client.clients.get(to);
if (otherPeer.requiredPair && !otherPeer.pairs.has(to)) {
return;
}
otherPeer.send([{ from: client.id, pack }, id]);
});
register('pack/room', (client, msg) => {
const { to, pack, handshake, wom } = msg;
if (!client.packReadable()) {
return handshake ? { type: 'fail' } : undefined;
}
if (!Room.rooms.has(to)) {
return handshake ? { type: 'fail' } : undefined;
}
if (!client.rooms.has(to)) {
return handshake ? { type: 'fail' } : undefined;
}
const room = Room.rooms.get(to);
room.send(
[{ from: to, pack, sender: client.id }, 'pack/room'],
wom ? client.id : undefined,
c => c.packWriteable()
);
return handshake ? { type: 'success' } : undefined;
});

View File

@ -1,394 +1,269 @@
const { Client } = require("../Client");
let {addService, addListener} = require("../WebSocket.js");
"use strict";
class APNumber{
/**
* @type {Map<Number, Client>}
*/
const { Client } = require("../Client");
const { on, register } = require("../WebSocket");
class APNumber {
static busyNumbers = new Map();
/**
* @type {number}
* @param {Client} client
*/
static lock(client)
{
static lock(client) {
let c = 24;
while(true){
if(!APNumber.busyNumbers.has(c))
{
APNumber.busyNumbers.set(c,client);
while (true) {
if (!APNumber.busyNumbers.has(c)) {
APNumber.busyNumbers.set(c, client);
process.send({
type: 'AP_NUMBER/LOCK',
uuid: client.id,
value: c
})
});
return c;
}
c++;
}
}
/**
* @param {number} num
*/
static release(num)
{
static release(num) {
process.send({
type: 'AP_NUMBER/RELEASE',
uuid: APNumber.busyNumbers.get(num).id,
value: num
})
});
APNumber.busyNumbers.delete(num);
}
static whois(num){
static whois(num) {
return APNumber.busyNumbers.get(num)?.id;
}
}
class APShortCode{
/**
* @type {Map<string, Client>}
*/
class APShortCode {
static busyCodes = new Map();
/**
*
* @param {Client} client
* @returns
*/
static lock(client){
static lock(client) {
let firstLetter = new ShortCodeLetter();
let secondLetter = new ShortCodeLetter();
let thirdLetter = new ShortCodeLetter();
while(1)
{
let code = [firstLetter.code,secondLetter.code,thirdLetter.code].join('');
if(APShortCode.busyCodes.has(code) == false)
{
while (1) {
let code = [firstLetter.code, secondLetter.code, thirdLetter.code].join('');
if (!APShortCode.busyCodes.has(code)) {
APShortCode.busyCodes.set(code, client);
process.send({
type: 'AP_SHORTCODE/LOCK',
uuid: APShortCode.busyCodes.get(code).id,
value: code
})
});
return code;
}
if(!thirdLetter.end())
{
thirdLetter.next()
}else{
thirdLetter.reset()
if(!secondLetter.end())
{
if (!thirdLetter.end()) {
thirdLetter.next();
} else {
thirdLetter.reset();
if (!secondLetter.end()) {
secondLetter.next();
}else{
} else {
secondLetter.reset();
if(!firstLetter.end())
{
if (!firstLetter.end()) {
firstLetter.next();
}else{
} else {
break;
}
}
}
}
}
static release(code){
if(APShortCode.busyCodes.has(code))
{
static release(code) {
if (APShortCode.busyCodes.has(code)) {
process.send({
type: 'AP_SHORTCODE/RELEASE',
uuid: APShortCode.busyCodes.get(code).id,
value: code
})
});
APShortCode.busyCodes.delete(code);
}
}
static whois(num){
static whois(num) {
return APShortCode.busyCodes.get(num)?.id;
}
};
class ShortCodeLetter{
chars = 'ABCDEFGHIKLMNOPRSTVXYZ'.split('');
now = 0;
code = 'A';
next(){
this.now++
this.code = this.chars.at(this.now);
return this.code;
}
reset(){
this.now = 0;
this.code = 'A';
}
end(){
return !this.chars.at(this.now + 1)
}
}
class APIPAddress{
/**
* @type {Map<[number,number,number,number], Client>}
*/
class ShortCodeLetter {
chars = 'ABCDEFGHIKLMNOPRSTVXYZ'.split('');
now = 0;
code = 'A';
next() {
this.now++;
this.code = this.chars.at(this.now);
return this.code;
}
reset() {
this.now = 0;
this.code = 'A';
}
end() {
return !this.chars.at(this.now + 1);
}
}
class APIPAddress {
static busyIP = new Map();
/**
* @param {Client} client
*/
static lock(client){
let A = 10;
let B = 0;
let C = 0;
let D = 1;
while(1)
{
let code = [A,B,C,D].join('.');
if(APIPAddress.busyIP.has(code) == false)
{
static lock(client) {
let A = 10, B = 0, C = 0, D = 1;
while (1) {
let code = [A, B, C, D].join('.');
if (!APIPAddress.busyIP.has(code)) {
APIPAddress.busyIP.set(code, client);
process.send({
type: 'AP_IPADDRESS/LOCK',
uuid: APIPAddress.busyIP.get(code).id,
value: code
})
});
return code;
}
if(D != 255)
{
D++;
continue;
}else{
D = 0;
}
if(C != 255)
{
C++;
continue;
}else{
C = 0;
}
if(B != 255)
{
B++;
continue;
}else{
B = 0;
}
if(A != 255)
{
A++;
continue;
}else{
A = 0;
}
if (D != 255) { D++; continue; }
D = 0;
if (C != 255) { C++; continue; }
C = 0;
if (B != 255) { B++; continue; }
B = 0;
if (A != 255) { A++; continue; }
return;
}
}
static release(code){
if(APIPAddress.busyIP.has(code))
{
static release(code) {
if (APIPAddress.busyIP.has(code)) {
process.send({
type: 'AP_IPADDRESS/RELEASE',
uuid: APIPAddress.busyIP.get(code).id,
value: code
})
});
APIPAddress.busyIP.delete(code);
}
}
static whois(num){
static whois(num) {
return APIPAddress.busyIP.get(num)?.id;
}
};
}
exports.APNumber = APNumber;
exports.APShortCode = APShortCode;
exports.APIPAddress = APIPAddress;
addService(({
client,
message,
end,
next
})=>{
let {type,whois} = message;
switch(type)
{
case "alloc/APIPAddress":{
if(client.APIPAddress) {
end({
status : "success",
ip : client.APIPAddress
})
};
let value = APIPAddress.lock(client);
client.APIPAddress = value;
client.sync('APIPAddress');
end({
status : "success",
ip : value
})
break;
}
case "alloc/APNumber":{
if(client.APNumber) {
end({
status : "success",
number : client.APNumber
})
};
let value = APNumber.lock(client);
client.APNumber = value;
client.sync('APNumber');
end({
status : "success",
number : value
})
break;
}
case "alloc/APShortCode":{
if(client.APShortCode) {
end({
status : "success",
code : client.APShortCode
})
};
let value = APShortCode.lock(client);
client.APShortCode = value;
client.sync('APShortCode');
end({
status : "success",
code : value
})
break;
}
case "realloc/APIPAddress":{
if(client.APIPAddress == 0){
return end({
status : "fail"
})
}
APIPAddress.release(client.APIPAddress);
let value = APIPAddress.lock(client);
client.sync('APIPAddress');
end({
status : "success",
ip : value
})
break;
}
case "realloc/APNumber":{
if(client.APNumber == 0){
return end({
status : "fail"
})
}
APNumber.release(client.APNumber);
let value = APNumber.lock(client);
client.sync('APNumber');
end({
status : "success",
number : value
})
break;
}
case "realloc/APShortCode":{
if(client.APShortCode == 0){
return end({
status : "fail"
})
}
APShortCode.release(client.APShortCode);
let value = APShortCode.lock(client);
client.sync('APShortCode');
end({
status : "success",
code : value
})
break;
}
case "release/APIPAddress":{
APIPAddress.release(client.APIPAddress);
client.APIPAddress = void 0;
client.sync('APShortCode');
end({
status : "success"
})
break;
}
case "release/APNumber":{
APNumber.release(client.APNumber);
client.APNumber = void 0;
client.sync('APIPAddress');
end({
status : "success"
})
break;
}
case "release/APShortCode":{
APShortCode.release(client.APShortCode);
client.APShortCode = void 0;
client.sync('APIPAddress');
end({
status : "success"
})
break;
}
case "whois/APIPAddress":{
let socketId = APIPAddress.whois(whois);
if(socketId)
{
end({
status : "success",
socket : socketId
})
}else{
end({
status : "fail"
})
}
break;
}
case "whois/APNumber":{
let socketId = APNumber.whois(whois);
if(socketId)
{
end({
status : "success",
socket : socketId
})
}else{
end({
status : "fail"
})
}
break;
}
case "whois/APShortCode":{
let socketId = APShortCode.whois(whois);
if(socketId)
{
end({
status : "success",
socket : socketId
})
}else{
end({
status : "fail"
})
}
break;
}
register('alloc/APIPAddress', (client, msg) => {
if (client.APIPAddress) {
return { status: 'success', ip: client.APIPAddress };
}
})
let value = APIPAddress.lock(client);
client.APIPAddress = value;
return { status: 'success', ip: value };
});
addListener('disconnect',(global, client)=>{
if(client.APIPAddress != 0)
{
register('alloc/APNumber', (client, msg) => {
if (client.APNumber) {
return { status: 'success', number: client.APNumber };
}
let value = APNumber.lock(client);
client.APNumber = value;
return { status: 'success', number: value };
});
register('alloc/APShortCode', (client, msg) => {
if (client.APShortCode) {
return { status: 'success', code: client.APShortCode };
}
let value = APShortCode.lock(client);
client.APShortCode = value;
return { status: 'success', code: value };
});
register('realloc/APIPAddress', (client, msg) => {
if (client.APIPAddress == 0) {
return { status: 'fail' };
}
APIPAddress.release(client.APIPAddress);
let value = APIPAddress.lock(client);
return { status: 'success', ip: value };
});
register('realloc/APNumber', (client, msg) => {
if (client.APNumber == 0) {
return { status: 'fail' };
}
APNumber.release(client.APNumber);
let value = APNumber.lock(client);
return { status: 'success', number: value };
});
register('realloc/APShortCode', (client, msg) => {
if (client.APShortCode == 0) {
return { status: 'fail' };
}
APShortCode.release(client.APShortCode);
let value = APShortCode.lock(client);
return { status: 'success', code: value };
});
register('release/APIPAddress', (client, msg) => {
APIPAddress.release(client.APIPAddress);
client.APIPAddress = undefined;
return { status: 'success' };
});
register('release/APNumber', (client, msg) => {
APNumber.release(client.APNumber);
client.APNumber = undefined;
return { status: 'success' };
});
register('release/APShortCode', (client, msg) => {
APShortCode.release(client.APShortCode);
client.APShortCode = undefined;
return { status: 'success' };
});
register('whois/APIPAddress', (client, msg) => {
let socketId = APIPAddress.whois(msg.whois);
if (socketId) {
return { status: 'success', socket: socketId };
}
return { status: 'fail' };
});
register('whois/APNumber', (client, msg) => {
let socketId = APNumber.whois(msg.whois);
if (socketId) {
return { status: 'success', socket: socketId };
}
return { status: 'fail' };
});
register('whois/APShortCode', (client, msg) => {
let socketId = APShortCode.whois(msg.whois);
if (socketId) {
return { status: 'success', socket: socketId };
}
return { status: 'fail' };
});
on('disconnect', (client) => {
if (client.APIPAddress != 0) {
APIPAddress.release(client.APIPAddress);
}
if(client.APNumber != 0)
{
if (client.APNumber != 0) {
APNumber.release(client.APNumber);
}
if(client.APShortCode != 0)
{
if (client.APShortCode != 0) {
APShortCode.release(client.APShortCode);
}
});
});

View File

@ -1,12 +1,11 @@
const { Client } = require("../Client.js");
let {randomUUID,createHash} = require("crypto");
let { randomUUID, createHash } = require("crypto");
const joi = require("joi");
let {addService,addListener} = require("../WebSocket.js");
const { on, register } = require("../WebSocket");
const { termoutput } = require("../config.js");
let term = require("terminal-kit").terminal;
function Sha256(update)
{
function Sha256(update) {
return createHash("sha256").update(update).digest("hex");
};
@ -233,7 +232,7 @@ Room.prototype.eject = function(client){
*/
Room.rooms = new Map();
addListener('connect',(global, client)=>{
on('connect', (client) => {
let room = new Room();
room.accessType = "private";
room.joinType = "notify";
@ -245,10 +244,12 @@ addListener('connect',(global, client)=>{
room.join(client);
});
addListener('disconnect',(global, client)=>{
Room.rooms.get(client.id).eject(client);
on('disconnect', (client) => {
const room = Room.rooms.get(client.id);
if (room) room.eject(client);
for (const roomId of client.rooms) {
Room.rooms.get(roomId).eject(client);
const r = Room.rooms.get(roomId);
if (r) r.eject(client);
}
});
@ -267,466 +268,282 @@ let CreateRoomVerify = joi.object({
autoFetchInfo: joi.boolean().optional(),
});
addService(({
client,
end,
global,
message,
next,
response
})=>{
let {type} = message;
switch(type)
{
case 'myroom-info':{
let room = Room.rooms.get(client.id);
end({
status: "success",
room: room.toJSON()
})
break;
}
case 'room-peers':{
let {roomId,filter} = message;
if(Room.rooms.has(roomId))
{
let filteredPeers = Room.rooms.get(roomId).filterPeers(filter || {});
end({
status: 'success',
peers: filteredPeers.map(i => i.id)
});
}else{
end({
status: 'fail'
})
}
break;
}
case 'room/peer-count':{
let {roomId,filter} = message;
if(Room.rooms.has(roomId))
{
let filteredPeers = Room.rooms.get(roomId).filterPeers(filter || {});
end({
status: 'success',
count: filteredPeers.length
});
}else{
end({
status: 'fail'
})
}
break;
}
case 'room-info':{
let {name} = message;
for (const [roomId,{name:RoomName}] of Room.rooms) {
if(name == RoomName)
{
return end({
status : "success",
room : Room.rooms.get(roomId).toJSON()
})
}
};
end({
status : "fail",
message : "NOT-FOUND-ROOM"
})
break;
}
case 'joinedrooms':{
let data = [
...client.rooms
].map(e => {
return Room.rooms.get(e).toJSON()
});
end(data)
break;
}
case 'closeroom':{
let {roomId} = message;
if(Room.rooms.has(roomId))
{
let room = Room.rooms.get(roomId);
if(room.owner === client.id)
{
room.down();
end({
status: 'success'
});
}else{
end({
status: 'fail'
});
}
}else{
end({
status: 'fail'
})
}
break;
}
case 'create-room':{
let {error} = CreateRoomVerify.validate(message);
if(error)
{
return end({
status: 'fail',
messages: error.message
})
}else{
let {name} = message;
for (const [,{name:RoomName}] of Room.rooms) {
if(name == RoomName)
{
return end({
status : "fail",
message : "ALREADY-EXISTS"
})
}
}
let room = new Room();
room.accessType = message.accessType;
room.notifyActionInvite = message.notifyActionInvite;
room.notifyActionJoined = message.notifyActionJoined;
room.notifyActionEjected = message.notifyActionEjected;
room.joinType = message.joinType;
room.description = message.description;
room.name = message.name;
room.owner = client;
if(message.credential)
{
room.credential = Sha256(message.credential + "");
}
room.publish();
room.join(client);
end({
status: "success",
room: room.toJSON()
});
}
break;
}
case 'joinroom':{
let {name,autoFetchInfo} = message;
let roomId;
for (const [_roomId,{name:RoomName}] of Room.rooms) {
if(name == RoomName)
{
roomId = _roomId
break;
}
}
let isRoom = Room.rooms.has(roomId);
if(isRoom)
{
let room = Room.rooms.get(roomId);
if(room.joinType == "lock")
{
return end({
status : "fail",
message : "LOCKED-ROOM"
})
}else if(room.joinType == "password")
{
if(room.credential == Sha256(message.credential + ""))
{
let info = {};
if(autoFetchInfo)
{
info.info = room.getInfo();
};
room.join(client);
return end({
status : "success",
room: room.toJSON()
})
}else return end({
status : "fail",
message : "WRONG-PASSWORD",
area: "credential"
})
}else if(room.joinType == "free"){
let info = {};
if(autoFetchInfo)
{
info.info = room.getInfo();
};
room.join(client);
return end({
status : "success",
room: room.toJSON(),
...info
})
}else if(room.joinType == "invite"){
room.waitingInvited.add(client.id);
if(room.notifyActionInvite)
{
room.send([{
id: client.id
},"room/invite"]);
}else{
room.owner.send([{
id: client.id
},"room/invite"]);
}
};
}else{
return end({
status : "fail",
message : "NOT-FOUND-ROOM"
})
}
break;
}
case 'ejectroom':{
let {roomId} = message;
let isRoom = Room.rooms.has(roomId);
if(isRoom)
{
let room = Room.rooms.get(roomId);
if(room.clients.has(client.id))
{
room.eject(client)
return end({
status : "success"
})
}else{
return end({
status : "fail",
message : "ALREADY-ROOM-OUT"
})
}
}else{
return end({
status : "fail",
message : "NOT-FOUND-ROOM"
})
}
break;
}
case 'accept/invite-room':{
let {roomId, clientId} = message;
// Odanın varlığının kontrolü
if(!Room.rooms.has(roomId))
{
end({
status : "fail",
message : "NOT-FOUND-ROOM"
})
};
let room = Room.rooms.get(roomId);
// erişim kontrolü
if(!client.rooms.has(room.id))
{
return end({
status : "fail",
message : "FORBIDDEN-INVITE-ACTIONS"
})
}
// Odaya katılma şeklinin doğruluğu
if(room.joinType == 'invite')
{
return end({
status : "fail",
message : "INVALID-DATA"
})
};
// Odaya katılma talebinin doğruluğu
if(!room.waitingInvited.includes(clientId))
{
return end({
status : "fail",
message : "NO-WAITING-INVITED"
})
};
// Odaya katılan kişinin varlığı
if(!Client.clients.has(clientId))
{
return end({
status : "fail",
message : "NO-CLIENT"
})
};
// Odaya kişiyi kabul etme
let JoinClient = Client.clients.get(clientId)
room.join(JoinClient);
JoinClient.send([{
status:"accepted"
},'room/invite/status']);
return end({
status : "success"
});
}
case 'reject/invite-room':{
let {roomId, clientId} = message;
// Odanın varlığının kontrolü
if(!Room.rooms.has(roomId))
{
end({
status : "fail",
message : "NOT-FOUND-ROOM"
})
};
let room = Room.rooms.get(roomId);
// erişim kontrolü
if(!client.rooms.has(room.id))
{
return end({
status : "fail",
message : "FORBIDDEN-INVITE-ACTIONS"
})
}
// Odaya katılma şeklinin doğruluğu
if(room.joinType == 'invite')
{
return end({
status : "fail",
message : "INVALID-DATA"
})
};
// Odaya katılma talebinin doğruluğu
if(!room.waitingInvited.includes(clientId))
{
return end({
status : "fail",
message : "NO-WAITING-INVITED"
})
};
// Odaya katılan kişinin varlığı
if(!Client.clients.has(clientId))
{
return end({
status : "fail",
message : "NO-CLIENT"
})
};
// Odaya davet edilen kişiyi reddetme
let JoinClient = Client.clients.get(clientId)
room.waitingInvited = room.waitingInvited.filter(e => e != clientId);
room.send([{id:clientId,roomId:room.id},'room/invite/status'])
JoinClient.send([{
status:"rejected"
},'room/invite/status']);
return end({
status : "success"
});
}
case 'room/list':{
let rooms = [];
for (const [id, {accessType,name,joinType,description}] of Room.rooms)
{
if(accessType == "public")
{
rooms.push({
name,
joinType,
description,
id
})
}
}
end({
type:'public/rooms',
rooms
});
}
case 'room/info':{
let {roomId,name} = message;
// Odanın varlığının kontrolü
if(!Room.rooms.has(roomId))
{
end({
status : "fail",
message : "NOT-FOUND-ROOM"
})
};
let room = Room.rooms.get(roomId);
// erişim kontrolü
if(!client.rooms.has(room.id))
{
return end({
status : "fail",
message : "NO-jıoned-ROOM"
})
}
if(name)
{
return end({
status: "success",
value: room.info.get(name)
});
}else{
return end({
status: "success",
value: room.getInfo()
});
}
}
case 'room/setinfo':{
let {roomId,name,value} = message;
// Odanın varlığının kontrolü
if(!Room.rooms.has(roomId))
{
return end({
status : "fail",
message : "NOT-FOUND-ROOM"
})
};
let room = Room.rooms.get(roomId);
// erişim kontrolü
if(!client.rooms.has(room.id))
{
return end({
status : "fail",
message : "NO-JOINED-ROOM"
})
}
room.info.set(name, value);
room.send(
[
{
name,
value,
roomId:room.id
},
"room/info"
],
client.id,
client => {
return client.roomInfoNotifiable()
}
);
return end({
status: "success"
});
}
default:{
next();
}
}
register('myroom-info', (client, msg) => {
let room = Room.rooms.get(client.id);
return { status: "success", room: room.toJSON() };
});
register('room-peers', (client, msg) => {
const { roomId, filter } = msg;
if (!Room.rooms.has(roomId)) {
return { status: 'fail' };
}
const filteredPeers = Room.rooms.get(roomId).filterPeers(filter || {});
return { status: 'success', peers: filteredPeers.map(i => i.id) };
});
exports.Room = Room;
register('room/peer-count', (client, msg) => {
const { roomId, filter } = msg;
if (!Room.rooms.has(roomId)) {
return { status: 'fail' };
}
const filteredPeers = Room.rooms.get(roomId).filterPeers(filter || {});
return { status: 'success', count: filteredPeers.length };
});
register('room-info', (client, msg) => {
const { name } = msg;
for (const [roomId, room] of Room.rooms) {
if (name == room.name) {
return { status: "success", room: room.toJSON() };
}
}
return { status: "fail", message: "NOT-FOUND-ROOM" };
});
register('joinedrooms', (client, msg) => {
return [...client.rooms].map(e => Room.rooms.get(e).toJSON());
});
register('closeroom', (client, msg) => {
const { roomId } = msg;
if (!Room.rooms.has(roomId)) {
return { status: 'fail' };
}
const room = Room.rooms.get(roomId);
if (room.owner === client.id) {
room.down();
return { status: 'success' };
}
return { status: 'fail' };
});
register('create-room', (client, msg) => {
const { error } = CreateRoomValidate.validate(msg);
if (error) {
return { status: 'fail', messages: error.message };
}
const { name } = msg;
for (const [, room] of Room.rooms) {
if (name == room.name) {
return { status: "fail", message: "ALREADY-EXISTS" };
}
}
let room = new Room();
room.accessType = msg.accessType;
room.notifyActionInvite = msg.notifyActionInvite;
room.notifyActionJoined = msg.notifyActionJoined;
room.notifyActionEjected = msg.notifyActionEjected;
room.joinType = msg.joinType;
room.description = msg.description;
room.name = msg.name;
room.owner = client;
if (msg.credential) {
room.credential = Sha256(msg.credential + "");
}
room.publish();
room.join(client);
return { status: "success", room: room.toJSON() };
});
register('joinroom', (client, msg) => {
const { name, autoFetchInfo } = msg;
let roomId;
for (const [_roomId, room] of Room.rooms) {
if (name == room.name) {
roomId = _roomId;
break;
}
}
if (!Room.rooms.has(roomId)) {
return { status: "fail", message: "NOT-FOUND-ROOM" };
}
const room = Room.rooms.get(roomId);
if (room.joinType == "lock") {
return { status: "fail", message: "LOCKED-ROOM" };
}
if (room.joinType == "password") {
if (room.credential == Sha256(msg.credential + "")) {
let info = {};
if (autoFetchInfo) {
info.info = room.getInfo();
}
room.join(client);
return { status: "success", room: room.toJSON(), ...info };
}
return { status: "fail", message: "WRONG-PASSWORD", area: "credential" };
}
if (room.joinType == "free") {
let info = {};
if (autoFetchInfo) {
info.info = room.getInfo();
}
room.join(client);
return { status: "success", room: room.toJSON(), ...info };
}
if (room.joinType == "invite") {
room.waitingInvited.add(client.id);
if (room.notifyActionInvite) {
room.send([{ id: client.id }, "room/invite"]);
} else {
room.owner.send([{ id: client.id }, "room/invite"]);
}
}
return { status: "fail", message: "NOT-FOUND-ROOM" };
});
register('ejectroom', (client, msg) => {
const { roomId } = msg;
if (!Room.rooms.has(roomId)) {
return { status: "fail", message: "NOT-FOUND-ROOM" };
}
const room = Room.rooms.get(roomId);
if (!room.clients.has(client.id)) {
return { status: "fail", message: "ALREADY-ROOM-OUT" };
}
room.eject(client);
return { status: "success" };
});
register('accept/invite-room', (client, msg) => {
const { roomId, clientId } = msg;
if (!Room.rooms.has(roomId)) {
return { status: "fail", message: "NOT-FOUND-ROOM" };
}
const room = Room.rooms.get(roomId);
if (!client.rooms.has(room.id)) {
return { status: "fail", message: "FORBIDDEN-INVITE-ACTIONS" };
}
if (room.joinType == 'invite') {
return { status: "fail", message: "INVALID-DATA" };
}
if (!room.waitingInvited.includes(clientId)) {
return { status: "fail", message: "NO-WAITING-INVITED" };
}
if (!Client.clients.has(clientId)) {
return { status: "fail", message: "NO-CLIENT" };
}
const JoinClient = Client.clients.get(clientId);
room.join(JoinClient);
JoinClient.send([{ status: "accepted" }, 'room/invite/status']);
return { status: "success" };
});
register('reject/invite-room', (client, msg) => {
const { roomId, clientId } = msg;
if (!Room.rooms.has(roomId)) {
return { status: "fail", message: "NOT-FOUND-ROOM" };
}
const room = Room.rooms.get(roomId);
if (!client.rooms.has(room.id)) {
return { status: "fail", message: "FORBIDDEN-INVITE-ACTIONS" };
}
if (room.joinType == 'invite') {
return { status: "fail", message: "INVALID-DATA" };
}
if (!room.waitingInvited.includes(clientId)) {
return { status: "fail", message: "NO-WAITING-INVITED" };
}
if (!Client.clients.has(clientId)) {
return { status: "fail", message: "NO-CLIENT" };
}
const JoinClient = Client.clients.get(clientId);
room.waitingInvited = room.waitingInvited.filter(e => e != clientId);
room.send([{ id: clientId, roomId: room.id }, 'room/invite/status']);
JoinClient.send([{ status: "rejected" }, 'room/invite/status']);
return { status: "success" };
});
register('room/list', (client, msg) => {
const rooms = [];
for (const [id, room] of Room.rooms) {
if (room.accessType == "public") {
rooms.push({
name: room.name,
joinType: room.joinType,
description: room.description,
id
});
}
}
return { type: 'public/rooms', rooms };
});
register('room/info', (client, msg) => {
const { roomId, name } = msg;
if (!Room.rooms.has(roomId)) {
return { status: "fail", message: "NOT-FOUND-ROOM" };
}
const room = Room.rooms.get(roomId);
if (!client.rooms.has(room.id)) {
return { status: "fail", message: "NO-JOINED-ROOM" };
}
if (name) {
return { status: "success", value: room.info.get(name) };
}
return { status: "success", value: room.getInfo() };
});
register('room/setinfo', (client, msg) => {
const { roomId, name, value } = msg;
if (!Room.rooms.has(roomId)) {
return { status: "fail", message: "NOT-FOUND-ROOM" };
}
const room = Room.rooms.get(roomId);
if (!client.rooms.has(room.id)) {
return { status: "fail", message: "NO-JOINED-ROOM" };
}
room.info.set(name, value);
room.send(
[{ name, value, roomId: room.id }, "room/info"],
client.id,
c => c.roomInfoNotifiable()
);
return { status: "success" };
});
exports.Room = Room;

View File

@ -1,69 +1,43 @@
let {addService,addListener} = require("../WebSocket.js");
"use strict";
const Stdoutput = [
["notifyPairInfo", true],
["packrecaive", true],
["packsending", true],
["notifyRoomInfo", true]
];
const { on, emit, register } = require("../WebSocket");
addListener('connect',(global, client)=>{
for (const [name, defaultValue] of Stdoutput)
{
client.store.set(name, defaultValue);
const defaults = {
notifyPairInfo: true,
packrecaive: true,
packsending: true,
notifyRoomInfo: true
};
on('connect', (client) => {
for (const [name, value] of Object.entries(defaults)) {
client.store.set(name, value);
}
client.sync('store');
});
register('connection/pairinfo', (client, msg) => {
client.store.set("notifyPairInfo", !!msg.value);
return { status: 'success' };
});
register('connection/roominfo', (client, msg) => {
client.store.set("notifyRoomInfo", !!msg.value);
return { status: 'success' };
});
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;
}
register('connection/packrecaive', (client, msg) => {
client.store.set("packrecaive", !!msg.value);
return { status: 'success' };
});
register('connection/packsending', (client, msg) => {
client.store.set("packsending", !!msg.value);
return { status: 'success' };
});
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;
}
register('connection/reset', (client, msg) => {
for (const [name, value] of Object.entries(defaults)) {
client.store.set(name, value);
}
});
return { status: 'success' };
});

View File

@ -1,8 +1,7 @@
let {addListener} = require("../WebSocket.js");
"use strict";
addListener('connect',(global, client)=>{
client.send([{
type: 'id',
value: client.id
},'id'])
});
const { on } = require("../WebSocket");
on('connect', (client) => {
client.send([{ type: 'id', value: client.id }, 'id']);
});

View File

@ -1,147 +1,94 @@
"use strict";
let websocket = require("websocket");
let {http} = require("./HTTPServer");
let http = null;
let wsServer = null;
let {randomUUID} = require("crypto");
const { Client } = require("./Client.js");
const { termoutput } = require("./config");
termoutput && console.log("Web Socket Protocol is ready");
const EventEmitter = require("./EventEmitter");
const MessageRouter = require("./MessageRouter");
http.addListener("upgrade",() => {
termoutput && console.log("HTTP Upgrading to WebSocket");
})
let wsServer = new websocket.server({
httpServer: http,
autoAcceptConnections: true
});
/*
process.send({
core: "writestat",
writeBytes:0,
readBytes:0,
totalBytes:0,
recaivedPacket:0,
sendedPacket:0,
totalPacket:0
})*/
let global = new Map();
let clients = new Map();
wsServer.addListener("connect",(socket) => {
let xClient = new Client();
let id = randomUUID();
socket.id = id;
xClient.id = id;
xClient.socket = socket;
xClient.created_at = new Date();
Client.clients.set(id, xClient);
clients.set(id, xClient);
emit("connect", global, xClient);
let pingTimer = setInterval(()=> socket.ping('saQut') , 10_000);
function init(server) {
http = server;
socket.addListener("pong",validationText => {
if(validationText.toString('utf8') != "saQut"){
socket.close();
}
})
socket.addListener("message",({type,utf8Data}) => {
if(type == "utf8")
{
let json;
try{
json = JSON.parse(utf8Data);
emit('services', global, xClient, json);
let [payload, id, action] = json;
if(typeof id === "string")
{
action = id;
id = void 0;
};
emitService(global, xClient, id, payload, action);
}catch{
emit("messageError", global, xClient, utf8Data);
}
}
termoutput && console.log("Web Socket Protocol is ready");
http.addListener("upgrade", () => {
termoutput && console.log("HTTP Upgrading to WebSocket");
});
socket.addListener("close",()=>{
emit("disconnect", global, xClient);
Client.clients.delete(id);
clearInterval(pingTimer);
wsServer = new websocket.server({
httpServer: http,
autoAcceptConnections: true
});
});
/**
* @type {Map<string, Function[]>}
*/
let events = new Map();
/**
* @type {Map<string, Function[]>}
*/
let services = []
/**
*
* @param {string} event
* @param {(global:Map<string, any>, client:Client, data:any) => any} func
*/
exports.addListener = (event, func) => {
if(!events.has(event))
{
events.set(event,[]);
};
events.get(event).push(func);
};
/**
*
* @param {string} event
* @param {(data:{global:Map<string, any>, client:Client, message:any,response:Function,end:Function,next:Function}) => any} func
*/
exports.addService = (func) => {
services.push(func);
};
function emit(event,...args)
{
if(events.has(event))
{
for (const callback of events.get(event)) {
callback(...args);
}
};
};
/**
*
* @param {Map} global
* @param {Client} local
* @param {number} id
* @param {{[key:string]:any}} payload
* @param {"R"|"S"} action [R]EQUEST flag or [S]TREAM flag
*/
async function emitService(global, client, id, payload, action)
{
let willContinue = false;
for (const callback of services) {
await callback({
message: payload,
action,
client,
global,
messageId: id,
response:(obj)=>{
id != undefined && client.send([obj, id, 'C']) // continue ([C]ONTINUE flag)
},
end:(obj)=>{
id != undefined && client.send([obj, id, 'E']) // stopped data stream (this channel) ([E]ND flag)
},
next:function(){
willContinue = true;
wsServer.addListener("connect", (socket) => {
let client = new Client();
let id = randomUUID();
socket.id = id;
client.id = id;
client.socket = socket;
client.created_at = new Date();
Client.clients.set(id, client);
EventEmitter.emit('connect', client);
let pingTimer = setInterval(() => socket.ping('saQut'), 10_000);
socket.addListener("pong", (validationText) => {
if (validationText.toString('utf8') != "saQut") {
socket.close();
}
});
if(willContinue === false) break;
}
};
exports.websocket = wsServer;
socket.addListener("message", ({ type, utf8Data }) => {
if (type == "utf8") {
try {
const json = JSON.parse(utf8Data);
const [message, id, action] = json;
let response;
if (typeof id === 'number' || typeof id === 'string') {
response = MessageRouter.handle(client, message);
if (action === 'R') {
client.send([response, id, 'E']);
} else if (action === 'S') {
client.send([response, id, 'C']);
}
} else {
const result = MessageRouter.handle(client, message);
if (result && result.broadcast) {
EventEmitter.emit('broadcast', result.broadcast, client);
}
}
} catch (error) {
EventEmitter.emit('messageError', client, utf8Data);
}
}
});
socket.addListener("close", () => {
EventEmitter.emit('disconnect', client);
Client.clients.delete(id);
clearInterval(pingTimer);
});
});
}
const on = EventEmitter.on;
const emit = EventEmitter.emit;
const off = EventEmitter.off;
const register = MessageRouter.register;
const handle = MessageRouter.handle;
exports.init = init;
exports.on = on;
exports.emit = emit;
exports.off = off;
exports.register = register;
exports.handle = handle;

235
Source/api.js Normal file
View File

@ -0,0 +1,235 @@
"use strict";
const express = require("express");
const router = express.Router();
const { Client } = require("./Client");
const { Room } = require("./Services/Room");
const apiKeys = new Map();
const webhooks = new Map();
function auth(req, res, next) {
const key = req.headers['x-api-key'];
if (!key) {
return res.status(401).json({ status: 'fail', message: 'API_KEY_REQUIRED' });
}
if (!apiKeys.has(key)) {
return res.status(401).json({ status: 'fail', message: 'INVALID_API_KEY' });
}
req.server = apiKeys.get(key);
next();
}
router.post('/auth/key', (req, res) => {
const { domain } = req.body;
if (!domain) {
return res.json({ status: 'fail', message: 'DOMAIN_REQUIRED' });
}
const key = require("crypto").randomUUID();
apiKeys.set(key, { domain, key });
res.json({ status: 'success', key });
});
router.post('/client/:id/send', auth, (req, res) => {
const { id } = req.params;
const { pack } = req.body;
const client = Client.clients.get(id);
if (!client) {
return res.json({ status: 'fail', message: 'CLIENT_NOT_FOUND' });
}
if (!pack) {
return res.json({ status: 'fail', message: 'PACK_REQUIRED' });
}
const fromServer = req.server;
client.send([{ from: 'server', fromServer, pack }, 'server/pack']);
res.json({ status: 'success' });
});
router.post('/room/:id/send', auth, (req, res) => {
const { id } = req.params;
const { pack, wom } = req.body;
const room = Room.rooms.get(id);
if (!room) {
return res.json({ status: 'fail', message: 'ROOM_NOT_FOUND' });
}
if (!pack) {
return res.json({ status: 'fail', message: 'PACK_REQUIRED' });
}
const fromServer = req.server;
room.send(
[{ from: 'server', fromServer, pack, roomId: id }, 'server/pack/room'],
wom ? undefined : 'server',
() => true
);
res.json({ status: 'success' });
});
router.post('/room/create', auth, (req, res) => {
const { name, accessType, joinType, description, credential } = req.body;
if (!name) {
return res.json({ status: 'fail', message: 'NAME_REQUIRED' });
}
for (const [, room] of Room.rooms) {
if (room.name === name) {
return res.json({ status: 'fail', message: 'ROOM_ALREADY_EXISTS' });
}
}
const room = new Room();
room.name = name;
room.accessType = accessType || 'public';
room.joinType = joinType || 'free';
room.description = description || '';
room.owner = { id: 'server', isServer: true };
if (credential) {
const { createHash } = require("crypto");
room.credential = createHash("sha256").update(credential).digest("hex");
}
room.publish();
res.json({ status: 'success', room: room.toJSON() });
});
router.post('/room/:id/join', auth, (req, res) => {
const { id } = req.params;
const { credential } = req.body;
const room = Room.rooms.get(id);
if (!room) {
return res.json({ status: 'fail', message: 'ROOM_NOT_FOUND' });
}
if (room.joinType === 'lock') {
return res.json({ status: 'fail', message: 'ROOM_LOCKED' });
}
if (room.joinType === 'password') {
const { createHash } = require("crypto");
const hash = createHash(credential || '').digest("hex");
if (room.credential !== hash) {
return res.json({ status: 'fail', message: 'WRONG_PASSWORD' });
}
}
const fakeClient = {
id: 'server-joined',
isServer: true,
rooms: new Set(),
send: (msg) => {
const fromServer = req.server;
room.send([{ from: 'server', fromServer, ...msg[0] }, msg[1]], 'server');
}
};
room.join(fakeClient);
res.json({ status: 'success', room: room.toJSON() });
});
router.delete('/room/:id/leave', auth, (req, res) => {
const { id } = req.params;
const room = Room.rooms.get(id);
if (!room) {
return res.json({ status: 'fail', message: 'ROOM_NOT_FOUND' });
}
const fakeClient = { id: 'server-joined', isServer: true };
room.eject(fakeClient);
res.json({ status: 'success' });
});
router.get('/room/:id', (req, res) => {
const { id } = req.params;
const room = Room.rooms.get(id);
if (!room) {
return res.json({ status: 'fail', message: 'ROOM_NOT_FOUND' });
}
res.json({ status: 'success', room: room.toJSON() });
});
router.get('/rooms', (req, res) => {
const rooms = [];
for (const [id, room] of Room.rooms) {
rooms.push({
id,
name: room.name,
accessType: room.accessType,
joinType: room.joinType,
description: room.description,
clientCount: room.clients.size
});
}
res.json({ status: 'success', rooms });
});
router.get('/clients', (req, res) => {
const clients = [];
for (const [id, client] of Client.clients) {
clients.push({
id,
rooms: [...client.rooms],
pairs: [...client.pairs]
});
}
res.json({ status: 'success', clients });
});
router.post('/webhook', auth, (req, res) => {
const { url, events } = req.body;
if (!url) {
return res.json({ status: 'fail', message: 'URL_REQUIRED' });
}
const server = req.server;
webhooks.set(server.domain, { url, events: events || ['server/pack', 'server/pack/room'] });
res.json({ status: 'success' });
});
function triggerWebhook(event, data) {
for (const [, webhook] of webhooks) {
if (webhook.events.includes(event)) {
fetch(webhook.url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ event, data })
}).catch(console.error);
}
}
}
module.exports = router;
module.exports.triggerWebhook = triggerWebhook;

View File

@ -1,5 +1,9 @@
require("./HTTPServer.js");
require("./WebSocket.js");
const { http } = require("./HTTPServer");
const WebSocket = require("./WebSocket");
WebSocket.init(http);
require("./Services/YourID.js");
require("./Services/Auth.js");
@ -19,4 +23,4 @@ process.on('multipleResolves',(type, promise, value)=>{
});
process.on('warning',(err)=>{
console.log("Process warning", err)
});
});

View File

@ -1,508 +0,0 @@
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)
};

View File

@ -1,21 +0,0 @@
<!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>

View File

@ -1,920 +0,0 @@
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(' '))
},
COLOR_RESET,
COLOR_TEXT,
COLOR_BACKGROUND,
CURSOR_MOVE,
CURSOR_MOVE_UP,
CURSOR_MOVE_DOWN,
CURSOR_MOVE_RIGHT,
CURSOR_MOVE_LEFT,
CLEAR_SCREEN,
CLEAR_LINE,
CLEAR_STYLING
},
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(error){
debugger;
this.stderr.writeln(`Process error`);
await wait(100);
}
}
this.exit();
}
};
CommandNamespace.namespaces.set('load', SystemLoad);

View File

@ -1,51 +0,0 @@
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);

View File

@ -1,18 +0,0 @@
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);

View File

@ -1,23 +0,0 @@
{
"native": {
"endpoints": [
"./native/js.js",
"./native/set.js"
],
"commands": [
"js",
"jsecho",
"set"
]
},
"rtc": {
"endpoints": [
"./rtc/mwse-socket.js",
"./rtc/mwse-close.js"
],
"commands": [
"mwse-socket",
"mwse-close"
]
}
}

View File

@ -1,18 +0,0 @@
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

View File

@ -1,44 +0,0 @@
class MWSECloser{
stdin = null;
stdout = null;
stderr = null;
endpoint = null;
static mwse = null;
constructor(pipe){
this.stdin = pipe.stdin;
this.stdout = pipe.stdout;
this.stderr = pipe.stderr;
}
greenText(text){
this.stdout.writeln(`${this.stdout.COLOR_TEXT(0,255,0)}${text}${this.stdout.COLOR_RESET()}`);
}
redText(text){
this.stdout.writeln(`${this.stdout.COLOR_TEXT(255,0,0)}${text}${this.stdout.COLOR_RESET()}`);
}
async main(args)
{
let mwseConnector = CommandNamespace.namespaces.get('mwse-socket');
if(mwseConnector == null){
this.stderr.writeln(`mwse-socket yok`);
return this.exit();
}
if(mwseConnector.mwse == null){
this.stderr.writeln(`ık bir soket bulunamadı`);
return this.exit();
}
if(mwseConnector.mwse.server?.disconnect == null){
this.stderr.writeln(`MWSE bağlayıcısında hata oluştu`);
return this.exit();
}
mwseConnector.mwse.server.disconnect();
this.greenText("MWSE socketi başarılı bir şekilde kapatıldı");
this.redText(`\n\n${mwseConnector.mwse.server.endpoint.host} sunucusuyla MWSE bağlantısı kesildi\n\n`);
return this.exit();
}
};
CommandNamespace.namespaces.set('mwse-close', MWSECloser);

View File

@ -1,93 +0,0 @@
class MWSECloser{
stdin = null;
stdout = null;
stderr = null;
endpoint = null;
static mwse = null;
constructor(pipe){
this.stdin = pipe.stdin;
this.stdout = pipe.stdout;
this.stderr = pipe.stderr;
}
greenText(text){
this.stdout.writeln(`${this.stdout.COLOR_TEXT(0,255,0)}${text}${this.stdout.COLOR_RESET()}`);
}
async main(args)
{
this.stdout.write("Endpoint: ");
let answer = await this.stdin.readline();
let url;
try{
url = new URL(answer)
}catch{
this.stderr.writeln('Bilinmeyen path yapısı');
return this.exit();
};
this.greenText('Path doğrulandı');
if(url.protocol.toLowerCase() != 'wss:' && url.protocol.toLowerCase() != 'ws:'){
this.stderr.writeln('Bilinmeyen protokol');
return this.exit();
}
this.greenText('Şema doğrulandı');
this.endpoint = url;
try{
await this.scriptImport();
}catch{
this.stderr.writeln('MWSE bağlayıcısı indirilemedi');
return this.exit();
};
this.greenText(`${url.host} üzerinden bağlanılıyor : ${url.href}`);
let mwse;
try{
mwse = new MWSE({
endpoint: url.href
});
await new Promise(ok => {
mwse.scope(async ()=>{
this.greenText(`\n\nMWSE üzerinden ${url.host} makinesine bağlısınız\n\n`);
ok();
})
});
MWSECloser.mwse = mwse;
}catch{
this.stderr.writeln(`${url.host} makinesine bağlanırken bir sorun oluştu`);
return this.exit();
}finally{
this.exit();
}
}
async scriptImport()
{
let t = new URL("script",this.endpoint);
if(t.protocol == 'wss:'){
t.protocol = 'https:';
}else{
t.protocol = 'http:';
}
let script = document.createElement("script");
await new Promise((ok,rej) => {
script.onload = () => ok();
script.onerror = () => rej();
script.setAttribute("src",t.href);
document.head.appendChild(script);
});
if(window.MWSE === void 0){
this.stderr.writeln('MWSE bağlayıcısı indirilemedi');
return this.exit();
}
}
};
CommandNamespace.namespaces.set('mwse-socket', MWSECloser);

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
.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

View File

@ -1,25 +0,0 @@
import "./studio/window.js";
import { InputDevicesWindow } from "./studio/InputDevices.js";
import { Rooms } from "./studio/Rooms.js";
let mwse = new MWSE({
endpoint: "ws://localhost:7707"
});
mwse.scope(beginEngine);
async function beginEngine()
{
let me = await mwse.virtualPressure.allocAPIPAddress();
$(".network-id").text(me);
}
window.openInputDevicesWindow = () => {
InputDevicesWindow.toggle();
InputDevicesWindow.bringToFront();
};
window.openRoomsWindow = () => {
Rooms.toggle();
Rooms.bringToFront();
};

View File

@ -1,179 +0,0 @@
html,body{
margin: 0;
height: 100%;
}
body{
background-color: #141414;
overflow: hidden;
font-family: system-ui;
}
*{
box-sizing: border-box;
}
.root{
gap: 10px;
padding: 10px;
height: 100%;
display: flex;
flex-wrap: nowrap;
flex-direction: column;
box-sizing: border-box;
overflow: hidden;
}
.videolist{
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;
justify-content: center;
align-items: center;
overflow: hidden;
}
.videolist .frame{
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;
}
.videolist .frame.active{
border: solid 3px green;
box-shadow: 0px 0px 20px -10px green;
}
video{
image-rendering: pixelated;
}
::-webkit-scrollbar {
width: 6px;
}
::-webkit-scrollbar-thumb {
background: white;
border-radius: 10px;
}
::-webkit-scrollbar-track {
background-color: #ffffff1f;
}
.tool-container{
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
display: flex;
flex-direction: column;
}
.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;
}
.tool-container > .namer{
flex: 0 0 auto;
background-color: rgba(0, 0, 0, 0.5);
border-radius: 10px;
overflow: hidden;
color: white;
display: flex;
flex-direction: row;
gap: 10px;
line-height: 2;
margin: 10px;
width: max-content;
padding: 0 10px;
.avatar {
display: flex;
& > *{
margin: auto;
}
}
}
.tool-container > .progress{
margin-top: auto;
margin-bottom: 10px;
width: 250px;
margin-left: auto;
margin-right: auto;
height: 5px;
border-radius: 5px;
background-color: white;
overflow: auto;
& .progress-box {
height: 5px;
width: 50%;
background-color: red;
transition: width 0.05s linear;
}
}
.controllist{
display: flex;
flex-direction: row;
flex-wrap: nowrap;
gap: 12px;
flex: 1 1 auto;
}
.ctrl-btn {
width: 48px;
height: 48px;
border: 1px solid #ccc;
border-radius: 8px;
background: #fff;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: background 0.2s, border-color 0.2s;
}
.ctrl-btn:hover {
background: #f0f0f0;
border-color: #999;
}
.ctrl-btn .material-icons {
font-size: 26px;
}
.logo{
object-fit: contain;
max-height: 50px;
width: 100%;
background-color: white;
border-radius: 10px;
}

View File

@ -1,48 +0,0 @@
<!DOCTYPE html>
<html lang="tr">
<head>
<base href="/stream/">
<meta charset="UTF-8">
<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?v=42">
</head>
<body>
<div class="root">
<div class="videolist">
</div>
<div style="display:flex;flex-direction: row;">
<div class="controllist">
<div style="flex:0 0 300px">
<img src="https://app.argist.com/img/argist-logo-yan.png" class="logo">
</div>
<div style="flex: 1 1 auto"></div>
<button class="ctrl-btn mic-on" title="Mikrofon Aç">
<span class="material-icons">mic</span>
</button>
<button class="ctrl-btn mic-off" title="Mikrofon Kapat" style="display:none">
<span class="material-icons">mic_off</span>
</button>
<button class="ctrl-btn cam-on" title="Kamera Aç" style="display:none">
<span class="material-icons">videocam</span>
</button>
<button class="ctrl-btn cam-off" title="Kamera Kapat">
<span class="material-icons">videocam_off</span>
</button>
<button class="ctrl-btn share-on" title="Ekran Paylaş">
<span class="material-icons">screen_share</span>
</button>
<button class="ctrl-btn share-off" title="Ekran Paylaşmayı Durdur" style="display:none">
<span class="material-icons">stop_screen_share</span>
</button>
<div style="flex: 1 1 auto"></div>
<div style="flex:0 0 300px"></div>
</div>
</div>
</div>
<script src="./index.js?v=42"></script>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</body>
</html>

View File

@ -1,352 +0,0 @@
const url = new URL(window.location);
/**
* @type {import("./MWSE/index").default}
*/
let mwse;
/**
* @type {string}
*/
let mySocketId;
/**
* @type {string}
*/
let myIPAddress;
/**
* @type {string}
*/
let myNumber;
/**
* @type {string}
*/
let roomid;
/**
* @type {import("./MWSE/Room").default}
*/
let room;
/**
* @type {MediaStream}
*/
let outgoingStream;
/**
* @type {HTMLDivElement}
*/
let videoContainer = document.querySelector(".videolist");
let amaxb;
let vmaxb;
let rate;
let resulation;
let activePeers = {}
let ofscreencanvas = document.createElement("canvas");
function connect()
{
mwse = new MWSE({
endpoint: "wss://ws.saqut.com"
});
mwse.scope(beginEngine);
}
let peername = url.searchParams.get("user");
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 templateVideo(name, stream,infinitedMute, peername)
{
let t = new DOMParser().parseFromString(`
<div class="frame" data-name="${name}">
<video autoplay playsinline muted>
</video>
<div class="tool-container">
<div class="namer">
<div class="avatar">
<i class="material-icons">account_circle</i>
</div>
<div class="name">
${peername ?? "User"}
</div>
</div>
<div class="tools">
</div>
<div class="progress">
<div class="progress-box">
</div>
</div>
</div>
</div>
`,"text/html");
let i = t.querySelector("video");
if(infinitedMute == true)
{
i.muted = 1;
}else if(interact == false)
{
i.muted = 1;
i.classList.add("soundon");
}
if(stream){
i.srcObject = stream;
bindAudioLevel(stream, t.querySelector(".progress-box"));
}
return t.querySelector("div");
}
function addVideoList(name, stream, peer, infinitedMute, name)
{
if(!videoContainer.querySelector(`[name="${name}"]`))
{
let video = templateVideo(name, stream, infinitedMute, name);
video.dataset.user = peer.socketId;
videoContainer.appendChild(video);
}
}
function removeVideoList(name)
{
if(videoContainer.querySelector(`[data-user="${name}"]`))
{
let k = videoContainer.querySelector(`[data-user="${name}"]`);
k.remove();
}
}
async function beginEngine()
{
let me = mwse.peer("me");
me.disablePairAuth();
mySocketId = me.socketId;
myIPAddress = await mwse.virtualPressure.allocAPIPAddress();
myNumber = await mwse.virtualPressure.allocAPNumber();
roomid = url.searchParams.get("room");
user = url.searchParams.get("user") ?? "User";
vmaxb = url.searchParams.get("vmaxb") ?? 32_0000
amaxb = url.searchParams.get("amaxb") ?? 2500000
resulation = url.searchParams.get("resulation") ?? 1
rate = url.searchParams.get("rate") ?? 10
if(!!roomid == 0)
{
let hash = window.crypto.randomUUID();
url.searchParams.set("room", hash);
url.searchParams.set("vmaxb", vmaxb);
url.searchParams.set("amaxb", amaxb);
url.searchParams.set("resulation", resulation);
url.searchParams.set("rate", rate);
url.searchParams.set("user", user);
window.location = url.href;
};
connectRoom(roomid);
};
window.addEventListener("load", () => {
connect()
});
async function startOutgoingWebcam()
{
let mediaStream = await navigator.mediaDevices.getUserMedia({
video: /*true*/{
advanced: [
{ width: { exact: 1920 } },
{ width: { exact: 1600 } },
{ width: { exact: 1366 } },
{ width: { exact: 1280 } },
{ width: { exact: 1024 } },
{ width: { exact: 900 } },
{ width: { exact: 800 } },
{ width: { exact: 640 } },
{ width: { exact: 320 } },
{ width: { exact: 240 } }
],
facingMode: "user"
},
audio: true
});
outgoingStream = mediaStream;
}
async function connectRoom()
{
await startOutgoingWebcam();
room = mwse.room({
name: roomid,
joinType: "free",
accessType: "private",
description: "Private free joined room",
ifexistsJoin: true,
notifyActionEjected: true,
notifyActionInvite: false,
notifyActionJoined: true
});
await mwse.peer('me').info.set("name", peername);
await room.createRoom();
room.on("join", peer => IncomingPeer(peer, true));
room.on("eject", peer => OutgoingPeer(peer));
for (const peer of await room.fetchPeers()) {
IncomingPeer(peer)
}
addVideoList("My Webcam",outgoingStream, mwse.peer("me"), true, peername);
};
/**
* @param {import("./MWSE/Peer").default} peer
*/
async function IncomingPeer(peer,activeConnect)
{
await peer.info.fetch();
peer.createRTC({
iceCandidatePoolSize: 0
},[{
urls: "turn:20.166.82.187:3478",
username: "turnserver",
credential: "turnserver"
},{
urls: "stun:stun.l.google.com:19302"
}]);
if(peer.rtc.isPolite())
{
peer.rtc.connect();
}
peer.rtc.rtc.turboBitrate = 0;
peer.rtc.on('connected',() => {
if(peer.rtc.isPolite())
{
peer.rtc.sendStream(outgoingStream, "Webcam", {});
activePeers[peer.socketId] = peer;
}
});
peer.rtc.on('disconnected',() => {
removeVideoList(peer.socketId, peer);
delete activePeers[peer.socketId];
});
peer.rtc.on("stream:added", ({stream,name}) => {
addVideoList(
peer.socketId,
stream,
peer,
void 0,
peer.info.get("name")
);
if(peer.rtc.isPolite() == false)
{
peer.rtc.sendStream(outgoingStream, "Webcam", {});
activePeers[peer.socketId] = peer;
}
})
}
/**
* @param {import("./MWSE/Peer").default} peer
*/
function OutgoingPeer(peer)
{
removeVideoList(peer.socketId, peer);
delete activePeers[peer.socketId];
}
let relative;
setInterval(() => {
for(const [,peer] of Object.entries(activePeers))
{
let peerRtc = peer.rtc.rtc;
const senders = peerRtc.getSenders();
if(peerRtc.vturboBitrate !== 1)
{
const videoSender = senders.find(sender => sender.track?.kind === 'video');
if(videoSender){
const parameters = videoSender.getParameters();
parameters.encodings[0].maxBitrate = vmaxb;
parameters.encodings[0].scaleResolutionDownBy = resulation;
parameters.encodings[0].maxFramerate = rate;
videoSender.setParameters(parameters).then(() => {
peerRtc.vturboBitrate = 1;
});
}
}
if(peerRtc.aturboBitrate !== 1)
{
const audioSender = senders.find(sender => sender.track?.kind === 'audio');
if(audioSender){
const parameters = audioSender.getParameters();
parameters.encodings[0].maxBitrate = amaxb;
audioSender.setParameters(parameters).then(() => {
peerRtc.aturboBitrate = 1;
});
}
}
}
},1000);
function bindAudioLevel(stream, element, options = {}) {
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
const source = audioCtx.createMediaStreamSource(stream);
const analyser = audioCtx.createAnalyser();
analyser.fftSize = 512;
analyser.smoothingTimeConstant = 0.1;
const dataArray = new Uint8Array(analyser.frequencyBinCount);
source.connect(analyser);
const track = stream.getAudioTracks()[0];
const bufferLength = analyser.frequencyBinCount;
function update()
{
if (track.readyState === 'ended' || !track.enabled) {
source.disconnect();
analyser.disconnect();
audioCtx.close();
return;
}
analyser.getByteFrequencyData(dataArray);
// Ortalama ses seviyesi hesapla
let sum = 0;
for (let i = 0; i < bufferLength; i++) {
sum += dataArray[i];
}
const avg = sum / bufferLength;
// Ortalama değeri % olarak hesapla (0-255 arası değer)
const volumePercent = Math.min(100, (avg / 255) * 100);
element.style.width = `${volumePercent * 2}%`;
requestAnimationFrame(update);
}
requestAnimationFrame(update);
}

View File

@ -1,175 +0,0 @@
/**
* =================================================================
* LİSANS BİLDİRİMİ -LGPL - LGPL-AU-EK
* =================================================================
* * Yazar (Original Author): Abdussamed ulutaş
* * İzinler (Permissions):
* ---------------------
* Bu kod, ticari veya kişisel amaçlarla serbestçe OKUNABILIR,
* KOPYALANABILIR, ÇOĞALTILABILIR, DEĞIŞTIRILEBILIR ve KULLANILABILIR.
* * * Koşul (Zorunlu Atıf Şartı - Attribution Requirement):
* ---------------------------------------------------
* Bu yazılımın temelindeki ANA ALGORITMA tamamen ve özgün bir şekilde değiştirilmediği sürece,
* "author by Abdussamed ulutaş" ifadesi kodun içerisinde MUTLAKA KORUNMALIDIR.
* * NOT: Algoritmanın temel mantığı korunarak yapılan küçük değişiklikler,
* optimizasyonlar veya arayüz entegrasyonları, bu atıf ifadesinin kaldırılması için yeterli sayılmaz.
* * * Sorumluluk Reddi (Disclaimer):
* ----------------------------
* Bu yazılım "olduğu gibi" (as-is) sağlanmıştır. Yazar, yazılımın kullanımından
* kaynaklanacak hiçbir zarardan sorumlu değildir.
* * =================================================================
*/
// Aşağıdaki satır, atıf şartını yerine getiren zorunlu ifadedir ve kodun içinde kalmalıdır:
//
// author by Abdussamed ulutaş
//
// =================================================================
/*
- Tüm dizinler herkese görünecek
- Dizinler ve dosyalar arayüzden tekrarlanamayacak
- Dosya ve klasör isimler aynı isimde olabilir
- Kimse bir başkasının dosyasını ve klasörünü silemez
- Yeni bir kişi bağlandığında dizin listesi eşitleniyor olacak
- Bağlanılan kişi ayrıldığında ona ait olan tüm dosya/dizin sistemi silinecek
*/
function é(rule)
{
if(é.element == null)
{
/** @type {HTMLStyleElement} */
é.element = document.createElement("style");
document.head.appendChild(é.element);
/** @type {CSSStyleSheet} */
é.sheet = é.element.sheet;
}
é.sheet.insertRule(rule);
}
é`html,body{
background-color: black;
height: 100%;
font-size: 14px;
> * {
box-sizing:border-box;
}
}`;
é`body{
display: flex;
flex-direction: row;
flex-wrap: nowrap;
padding: 20px;
overflow: hidden;
}`;
é`@keyframes color-transition {
0% {
color: #c8c8c8;
}
50% {
color: #757575;
}
100% {
color: #c8c8c8;
}
}`;
/// UI
// <span class="material-icons">
const UIM = new class UI {
constructor(){
this.setup();
}
setup(){
this.setupOutContainer();
this.setupDirentContainer();
}
/** @type {JQuery} */
container = null;
setupOutContainer(){
this.container = $("<div>");
this.container.addClass("dip-fev");
é`.dip-fev{
width: 100%;
height: 100%;
background-color: rgba(255,255,255,0.2);
position: relative;
border-radius: 5px;
border: solid 1px rgba(255,255,255,0.1);
display: flex;
overflow: auto;
flex-direction: column;
flex-wrap: nowrap;
}`;
document.body.append(this.container.get(0));
}
/** @type {JQuery} */
direntbezier = null;
setupDirentContainer(){
this.direntbezier = $("<div>");
this.direntbezier.addClass("dip-bezier");
é`.dip-bezier{
flex: 0 0 auto;
background-color: rgba(255,255,255,0.2);
display: flex;
flex-direction: row;
flex-wrap: nowrap;
padding: 5px;
& > .dip-bezier-icon{
padding: 3px;
animation: color-transition 1s ease-in-out infinite;
}
& > .dip-bezier-disk{
color: white;
padding: 3px;
}
& > .dip-bezier-object{
color: white;
padding: 3px 2px;
cursor: pointer;
border-radius: 3px;
&:hover{
background-color: rgba(255,255,255,0.05);
}
}
& > .dip-bezier-splitter{
margin: 5px 2px;
width: 1px;
background-color: rgba(0,0,0,0.1);
}
}`;
this.container.append(this.direntbezier);
this.setupBezier("Diskim",["Resimler","Yakalamalar","Benim yakalamalarım"]);
}
setupBezier(disk, folders){
let icon = $("<span>");
icon.addClass("dip-bezier-icon material-symbols-outlined");
icon.text("bigtop_updates");
this.direntbezier.append(icon);
let section = $("<div>");
section.addClass("dip-bezier-disk");
section.html(disk + " ://");
this.direntbezier.append(section);
folders.map((element, index, array) => {
let section = $("<div>");
section.addClass("dip-bezier-object");
section.text(element);
this.direntbezier.append(section);
if(index < array.length - 1)
{
let sectionPadding = $("<div>");
sectionPadding.addClass("dip-bezier-splitter");
this.direntbezier.append(sectionPadding);
}
});
}
}

View File

@ -1,27 +0,0 @@
/**
* =================================================================
* LİSANS BİLDİRİMİ - LGPL - LGPL-AU-EK
* =================================================================
* * Yazar (Original Author): Abdussamed ulutaş
* * İzinler (Permissions):
* ---------------------
* Bu kod, ticari veya kişisel amaçlarla serbestçe OKUNABILIR,
* KOPYALANABILIR, ÇOĞALTILABILIR, DEĞIŞTIRILEBILIR ve KULLANILABILIR.
* * * Koşul (Zorunlu Atıf Şartı - Attribution Requirement):
* ---------------------------------------------------
* Bu yazılımın temelindeki ANA ALGORITMA tamamen ve özgün bir şekilde değiştirilmediği sürece,
* "author by Abdussamed ulutaş" ifadesi kodun içerisinde MUTLAKA KORUNMALIDIR.
* * NOT: Algoritmanın temel mantığı korunarak yapılan küçük değişiklikler,
* optimizasyonlar veya arayüz entegrasyonları, bu atıf ifadesinin kaldırılması için yeterli sayılmaz.
* * * Sorumluluk Reddi (Disclaimer):
* ----------------------------
* Bu yazılım "olduğu gibi" (as-is) sağlanmıştır. Yazar, yazılımın kullanımından
* kaynaklanacak hiçbir zarardan sorumlu değildir.
* * =================================================================
*/
// Aşağıdaki satır, atıf şartını yerine getiren zorunlu ifadedir ve kodun içinde kalmalıdır:
//
// author by Abdussamed ulutaş
//
// =================================================================

View File

@ -1,86 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MWSE UI 24.3 Studio</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.7/css/bootstrap.min.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined" />
</head>
<body>
<div class="container" style="max-width: 1200px;padding-top: 125px">
<h2 class="text-center">
MWSE UI 24.3
</h2>
<h1 class="text-center mb-5 mt-3 text-bold fw-bold">
<span>Ağ Adresiniz</span>
<span class="text-danger network-id">
#.#.#.#
</span>
</h1>
</div>
<div style="position:fixed;left:0;right:0;bottom:0;background-color: rgba(0,0,0,.1);display: flex;flex-direction: row;gap: 5px">
<span class="bg-white d-inline-block m-1">
<button class="btn btn-outline-primary" onclick="openInputDevicesWindow()">
Giriş Aygıtları
</button>
</span>
<!--span class="bg-white d-inline-block m-1">
<button class="btn btn-outline-primary" onclick="openOutputDevicesWindow()">
Çıkış Aygıtları
</button>
</span-->
<span class="bg-white d-inline-block m-1">
<button class="btn btn-outline-primary" onclick="openRoomsWindow()">
Odalar
</button>
</span>
<span class="bg-white d-inline-block m-1">
<button class="btn btn-outline-primary" onclick="openPeersWindow()">
Cihazlar
</button>
</span>
</div>
<script src="https://ws.saqut.com/script"></script>
<script src="./core.js" type="module"></script>
<style>
html,body{
margin: 0;
height: 100%;
background-image: url(./studio/background.jpg);
background-position: center center;
background-repeat: no-repeat;
background-size: cover;
}
*{
box-sizing: border-box;
}
* {
scrollbar-width: thin;
scrollbar-color: #7a7a7a #1e1e1e;
}
*::-webkit-scrollbar {
width: 8px;
height: 8px;
}
*::-webkit-scrollbar-track {
background: #1e1e1e;
}
*::-webkit-scrollbar-thumb {
background-color: #7a7a7a;
border-radius: 8px;
}
*::-webkit-scrollbar-thumb:hover {
background-color: #aaaaaa;
}
</style>
</body>
</html>

View File

@ -1,398 +0,0 @@
import DWindow from "./window.js";
import { AddCell, FilterCell, memory, RemoveCell } from "./sdb.js";
export const InputDevicesWindow = new class InputDevicesWindow extends DWindow{
constructor(){
super();
this.initContent();
this.headtext.text("Giriş Aygıtları");
this.hide();
this.panel.css("min-width","640px");
this.panel.css("min-height","250px");
this.panel.css("width","max-content");
this.initEvent();
}
/**
* @type {JQuery<HTMLElement>}
*/
table = null;
initContent(){
this.table = $(`
<table class="table table-sm table-bordered table-striped text-nowrap">
<thead>
<tr>
<th>Cihaz Türü</th>
<th>Sağlanan Kanallar</th>
<th>Akış ID</th>
<th></th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td colspan="4">
<button class="btn btn-success w-100 newdevice">
Yeni Giriş Cihazı Ekle
</button>
</td>
</tr>
</tfoot>
</table>
`);
this.updateDevices();
this.content.append(this.table);
}
initEvent(){
this.content.find(".newdevice").on('click', this.generateDevice.bind(this));
this.addEventListener("close",()=>{
this.hide();
})
}
updateDevices(){
let tbody = this.table.find("tbody");
tbody.text('');
for (const cell of FilterCell("rawstream", () => true))
{
let tr = $(`
<tr class="text-nowrap">
<td>${cell.source}</td>
<td>${cell.kind}</td>
<td>${cell.payload.id}</td>
<td>
<button class="btn btn-outline-primary action-view">Görüntüle</button>
<button class="btn btn-outline-danger action-close">Kapat</button>
</td>
</tr>
`);
tr.attr("data-declare", cell.payload.id);
cell.addEventListener("stop",() => tr.remove());
tbody.append(tr);
}
tbody.find(".action-view").on('click', e => this.viewSource($(e.target)));
tbody.find(".action-close").on('click', e => this.closeSource($(e.target)));
}
closeSource(btn){
let streamid = btn.closest("tr").attr("data-declare");
for (const brain of FilterCell("rawstream",e => e.payload.id == streamid)) {
brain.stop();
}
}
viewSource(btn){
let streamid = btn.closest("tr").attr("data-declare");
/**
* @type {MediaStream}
*/
let p = null;
for (const rawstream of FilterCell("rawstream",e => e.payload.id == streamid)) {
p = rawstream.payload;
}
let modal = new ViewSourceDialog(p.getTracks()[0]);
modal.enableDialog(this);
modal.bringToFront();
}
generateDevice(){
let modal = new AddDeviceDialog();
modal.enableDialog(this);
modal.bringToFront();
modal.addEventListener("stream:added",()=>{
this.updateDevices();
});
}
}
class StreamRecord extends EventTarget {
lockedby = 0;
stop(){
this.payload.getTracks().forEach(e => e.stop());
this.dispatchEvent(new Event("stop"));
}
isLocked(){
return this.lockedby != 0;
}
lock(){
this.lockedby++;
}
unlock(){
this.lockedby--;
}
}
class AddDeviceDialog extends DWindow {
constructor(){
super();
this.initContent();
this.headtext.text("Aygıt Ekleme Sihirbazı");
this.addEventListener('close',()=>{
this.disableDialog();
this.exit();
})
}
initContent(){
let table = $(`
<div style="display:flex;flex-direction:column;gap:5px">
<button class="btn btn-success w-100 action-sdcam">
SD Kamara Ekle
</button>
<button class="btn btn-success w-100 action-hdcam">
HD Kamara Ekle
</button>
<button class="btn btn-success w-100 action-mic">
Mikrofon Ekle
</button>
<button class="btn btn-success w-100 action-displaycam">
Ekran Görüntüsü Ekle
</button>
</div>
`);
table.find(".action-sdcam").on("click",this.sdcam.bind(this));
table.find(".action-hdcam").on("click",this.hdcam.bind(this));
table.find(".action-mic").on("click",this.mic.bind(this));
table.find(".action-displaycam").on("click",this.displaycam.bind(this));
this.content.append(table);
}
async sdcam(){
let stream = await navigator.mediaDevices.getUserMedia({
video: {
advanced: [
{ width: { exact: 640 } },
{ width: { exact: 320 } },
{ width: { exact: 240 } }
],
facingMode: "user"
}
});
AddCell("rawstream", new class extends StreamRecord {
source = "Kamera";
kind = "Görüntü";
payload = stream;
constructor(){
super();
this.onEnded(() => {
this.dispatchEvent(new Event("stop"));
})
this.addEventListener("stop",() => {
RemoveCell("rawstream",cell => {
return cell.payload.id == stream.id
})
})
}
onEnded(event){
/** @type {MediaStreamTrack} */
let track;
stream.getVideoTracks().forEach(e => track = e);
if(track)
{
track.addEventListener("ended",event);
}
}
});
this.dispatchEvent(new Event("stream:added"));
this.disableDialog();
this.exit();
}
async hdcam(){
let stream = await navigator.mediaDevices.getUserMedia({
video: {
advanced: [
{ width: { exact: 1920 } },
{ width: { exact: 1600 } },
{ width: { exact: 1366 } },
{ width: { exact: 1280 } },
{ width: { exact: 1024 } },
{ width: { exact: 900 } },
{ width: { exact: 800 } },
{ width: { exact: 640 } },
{ width: { exact: 320 } },
{ width: { exact: 240 } }
],
facingMode: "user"
}
});
AddCell("rawstream", new class extends StreamRecord {
source = "Kamera";
kind = "Görüntü";
payload = stream;
constructor(){
super();
this.onEnded(() => {
this.dispatchEvent(new Event("stop"));
})
this.addEventListener("stop",() => {
RemoveCell("rawstream",cell => {
return cell.payload.id == stream.id
})
})
}
onEnded(event){
/** @type {MediaStreamTrack} */
let track;
stream.getVideoTracks().forEach(e => track = e);
if(track)
{
track.addEventListener("ended",event);
}
}
});
this.dispatchEvent(new Event("stream:added"));
this.disableDialog();
this.exit();
}
async mic(){
let stream = await navigator.mediaDevices.getUserMedia({
audio: true
});
AddCell("rawstream", new class extends StreamRecord {
source = "Kamera";
kind = "Ses";
payload = stream;
constructor(){
super();
this.onEnded(() => {
this.dispatchEvent(new Event("stop"));
})
this.addEventListener("stop",() => {
RemoveCell("rawstream",cell => {
return cell.payload.id == stream.id
})
})
}
onEnded(event){
/** @type {MediaStreamTrack} */
let track;
stream.getAudioTracks().forEach(e => track = e);
if(track)
{
track.addEventListener("ended",event);
}
}
});
this.dispatchEvent(new Event("stream:added"));
this.disableDialog();
this.exit();
}
async displaycam(){
let stream = await navigator.mediaDevices.getDisplayMedia({
video: true
});
AddCell("rawstream", new class extends StreamRecord{
source = "Ekran";
kind = "Görüntü";
payload = stream;
constructor(){
super();
this.onEnded(() => {
this.dispatchEvent(new Event("stop"));
})
this.addEventListener("stop",() => {
RemoveCell("rawstream",cell => {
return cell.payload.id == stream.id
})
})
}
onEnded(event){
/** @type {MediaStreamTrack} */
let track;
stream.getTracks().forEach(e => track = e);
if(track)
{
track.addEventListener("ended",event);
}
}
});
this.dispatchEvent(new Event("stream:added"));
this.disableDialog();
this.exit();
}
}
class ViewSourceDialog extends DWindow {
/**
* @type {MediaStreamTrack}
*/
track = null;
extra = {};
constructor(track){
super();
this.headtext.text("Giriş Kaynağı Görüntüleme");
this.addEventListener('close',()=>{
this.disableDialog();
this.exit();
})
this.track = track;
this.initContent();
}
initContent(){
if(this.track.kind == "video")
{
this.initVideoContent();
}else{
this.initAudioContent();
}
this.table = $(`<table class="table">
<tbody>
<tr>
<td>Track ID</td>
<td>${this.track.id}</td>
</tr>
<tr>
<td>Data Type</td>
<td>${this.track.kind}</td>
</tr>
<tr>
<td>Status</td>
<td>${this.track.enabled ? "Active" : "Passive"}</td>
</tr>
<tr>
<td>Track Label</td>
<td>${this.track.label}</td>
</tr>
</tbody>
</table>`);
this.content.append(this.table);
}
initVideoContent(){
let player = $(`<video
style="height: 450px"
controls
/>`);
let stream = new MediaStream();
stream.addTrack(this.track);
player.on('canplay', e => e.target.play());
player.get(0).srcObject = stream;
this.content.append(player);
player.on('play', e => {
this.table.find("tbody").append(`
<tr>
<td>Video Width</td>
<td>${e.target.videoWidth}px</td>
</tr>
`);
this.table.find("tbody").append(`
<tr>
<td>Video Height</td>
<td>${e.target.videoHeight}px</td>
</tr>
`);
});
}
initAudioContent(){
let player = $(`<audio
style="width: 500px"
controls
/>`);
let stream = new MediaStream();
stream.addTrack(this.track);
player.get(0).srcObject = stream;
player.on('canplay', e => e.target.play());
this.content.append(player);
}
}

View File

@ -1,65 +0,0 @@
import DWindow from "./window.js";
import { AddCell, FilterCell, memory, RemoveCell } from "./sdb.js";
export const Rooms = new class Rooms extends DWindow{
constructor(){
super();
this.emptyConnect();
this.headtext.text("MWSE Ağları");
this.hide();
this.panel.css("min-width","640px");
this.addEventListener("close",()=>{
this.hide();
})
}
emptyConnect(){
this.content.append($(`
<h4 class="text-white text-center">MWSE Ağları</h4>
`),$(`
<h6 class="text-white text-center">Herhangi bir ağa bağlı değilsiniz</h6>
`));
this.content.append($(`
<h3 class="text-white text-center" style="margin-top: 50px">
Oluştur
</h3>
`));
let createinput = $(`
<input type="text" class="form-control" placeholder="Oluşturulacak Oda Adı" style="line-height:2;font-size: 2em">
`);
let createbutton = $(`
<button class="btn btn-lg btn-success d-block m-auto mt-3">Oluştur</button>
`);
this.content.append(createinput,createbutton);
this.content.append($(`
<h3 class="text-white text-center" style="margin-top: 50px">
Ağa Katıl
</h3>
`));
let joininput = $(`
<input type="text" class="form-control" placeholder="Katılacak Oda Adı" style="line-height:2;font-size: 2em">
`);
let joinbutton = $(`
<button class="btn btn-lg btn-success d-block m-auto mt-3">Katıl</button>
`);
this.content.append(joininput,joinbutton);
this.content.append($(`
<span class="text-white" style="margin-top: 50px;max-width:100%;font-size: 0.9em;line-height: 1;display: block;text-shadow: 0px 0px 4px black;">
Aynı ağdaki kullanıcılar birbirini görecek ve akışlarını paylaşabilecektir.
Verilerinizi, bilgilerinizi ve akışlarınızı paylaşmakta tamamen özgürsünüz.
Sistem tamamen deneysel teknoloji araştırma ve geliştirme üzerine kuruludur.
Sistem kullanılarak yapılan tüm iyi ve kötü amaçlı eylemlerden kullanıcı sorumludur.
</span>
`));
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 660 KiB

View File

@ -1,162 +0,0 @@
const style = document.createElement("style");
document.head.appendChild(style);
export default class CSSOM {
/** @type {Map<string, CSSOM>} */
static rules = new Map();
/** @type {Map<string, CSSRuleList>} */
static cRules = new Map();
/**
* @returns {CSSOM}
*/
static get(name){
return CSSOM.rules.get(name);
}
/** @returns {CSSRule} */
static findRule(selector){
for (let ruleIndex = 0; ruleIndex < style.sheet.cssRules.length; ruleIndex++)
{
let rule = style.sheet.cssRules.item(ruleIndex);
if(rule.selectorText == selector)
{
return rule;
}
}
}
/** @returns {CSSRule} */
static removeRule(selector){
for (let ruleIndex = 0; ruleIndex < style.sheet.cssRules.length; ruleIndex++)
{
let rule = style.sheet.cssRules.item(ruleIndex);
if(rule.selectorText == selector)
{
style.sheet.deleteRule(ruleIndex);
}
}
}
static css(selector, values){
let rule;
if(!(rule = CSSOM.findRule(selector)))
{
let no = style.sheet.insertRule(`${selector}{}`);
rule = style.sheet.cssRules[no];
}
for(let [stylename, stylevalue] of Object.entries(values))
{
let name = stylename;
let value = typeof stylevalue == "string" ? stylevalue.split('!')[0] : stylevalue;
let priority = typeof stylevalue == "string" ? (stylevalue.split('!')[1] == "important" ? "important" : void 0) : void 0;
name = name.replace(/([A-Z])/g,(_,$1) => '-' + $1.toLowerCase());
rule.style.setProperty(name, value, priority);
}
}
static generate(idd = null, css = null){
let id = idd || CSSOM.generateCode();
let t = new CSSOM(id);
CSSOM.rules.set(t.id,t);
css && t.css(css);
return t;
}
static generateCode(){
let mine;
do{
mine = Math.random().toString(36).slice(2,6);
}while(CSSOM.rules.has(mine));
return "i" + mine;
}
id = "";
/** @type {{[key:string]: CSSRuleList}} */
rule_t = {};
constructor(id){
this.id = id;
}
toString(){
return this.id;
}
css(name, value, prefix = 'owner'){
let rule;
if(!this.rule_t[prefix])
{
let rulename = `.${this.id}` + (prefix == "owner" ? "" : prefix);
let no = style.sheet.insertRule(`${rulename}{}`);
this.rule_t[prefix] = style.sheet.cssRules[no];
};
rule = this.rule_t[prefix];
if(value === undefined && typeof name == "string")
{
return rule.style.getPropertyValue(name);
}
if(value === null)
{
rule.style.removeProperty(name, value);
}else{
if(typeof name == "object")
{
for(let [stylename, stylevalue] of Object.entries(name))
{
let name = stylename;
let value = typeof stylevalue == "string" ? stylevalue.split('!')[0] : stylevalue;
let priority = typeof stylevalue == "string" ? (stylevalue.split('!')[1] == "important" ? "!important" : void 0) : stylevalue;
if(name.indexOf('-') == -1)
{
rule.style[name] = value + (priority || "");
}else{
rule.style.setProperty(name, value, priority);
}
}
}else{
rule.style.setProperty(name, value);
}
}
return this;
}
}
$.fn.cssom = function(obj, prefix){
if(prefix === void 0 || (typeof obj == "object" && typeof prefix == "string"))
{
let cssom;
if(this.attr("data-cssom"))
{
let name = this.attr("data-cssom");
cssom = CSSOM.get(name)
}else{
cssom = CSSOM.generate();
this.addClass(cssom.id);
this.attr("data-cssom", cssom.id);
}
cssom.css(obj,void 0,prefix);
}else{
if(obj.indexOf(":") == -1){
this.addClass(obj);
CSSOM.css("." + obj, prefix);
}else{
let [_class,_psudio] = obj.split(":");
this.addClass(_class);
CSSOM.css("." + _class + ":" + _psudio, prefix);
}
}
return this;
};
window.debugCssom = function(){
for (let ruleIndex = 0; ruleIndex < style.sheet.cssRules.length; ruleIndex++)
{
let rule = style.sheet.cssRules.item(ruleIndex);
console.log(rule.cssText)
}
};
window.cssom = CSSOM;
/*
*/

View File

@ -1,44 +0,0 @@
/**
* @ typedef {Object} BirthData
* @ property {Date} birthDate
*/
/**
* @typedef {Object} BrainCell
* @property {string} type
* @property {Object} data
*/
/**
* @type {BrainCell[]}
*/
export let memory = [];
export function AddCell(name, data)
{
memory.push({
type: name,
data
});
};
/**
* @param {string} type
* @param {(BrainCell) => boolean} filterQuery
*/
export function RemoveCell(type, filterQuery)
{
memory = memory.filter(e => !(
e.type == type && filterQuery(e.data)
));
};
/**
* @param {string} type
* @param {(BrainCell) => boolean} filterQuery
*/
export function FilterCell(type, filterQuery)
{
return memory.filter(e =>
e.type == type && filterQuery(e.data)
).map(e => e.data);
};
window.memoryDump = () => memory;

View File

@ -1,293 +0,0 @@
export default class DWindow extends EventTarget {
static allWindows = []; // açık pencereler
static zCounter = 1; // global sayaç
static normalizeThreshold = 9999; // yeniden sıfırlama eşiği
/** @type {JQuery<HTMLElement>} */ panel = null;
/** @type {JQuery<HTMLElement>} */ title = null;
/** @type {JQuery<HTMLElement>} */ content = null;
/** @type {JQuery<HTMLElement>} */ headtext = null;
constructor() {
super();
this.initpanel();
this.enableFocus();
DWindow.allWindows.push(this);
this.bringToFront();
requestAnimationFrame(()=>{
this.enableDragging();
this.enableResize();
})
}
activeDragging = true;
activeResizing = true;
initpanel() {
this.panel = $(`<div></div>`).css({
width: 450,
//height: 500,
position: "fixed",
left: (Math.random() * 300 | 0) + 100,
top: (Math.random() * 100 | 0) + 100,
boxShadow: "black 0px 0px 20px -10px",
borderRadius: "10px",
backgroundColor: "#3333335b",
backdropFilter: "blur(3px)",
border: "solid 1px #a2a2a2",
display: "flex",
flexDirection: "column",
outlineOffset: "-5px",
//overflow: "hidden",
userSelect: "none",
minWidth: "max-content",
minHeight: "max-content"
});
$("body").append(this.panel);
this.title = $(`<div></div>`).css({
display: "flex",
flex: "0 0 auto",
flexDirection: "row",
lineHeight: "2em",
backgroundColor: "#333333",
color: "white",
paddingLeft: "10px",
cursor: "move",
borderTopLeftRadius: "10px",
borderTopRightRadius: "10px",
});
this.content = $(`<div></div>`).css({
flex: "1 1 auto",
overflow: "auto",
borderBottomRightRadius: "10px",
borderBottomLeftRadius: "10px",
padding: "20px"
});
this.panel.append(this.title, this.content);
this.initTitle();
}
initTitle() {
this.headtext = $("<div>Başlıksız pencere</div>");
const divider = $("<div style='flex:1 1 auto'></div>");
this.exitbtn = $("<div><span class='btn btn-sm material-symbols-outlined text-white'>close</span></div>");
this.exitbtn.on('click',()=>{
this.dispatchEvent(new Event("close"));
})
this.title.append(
this.headtext,
divider,
this.exitbtn
);
}
enableDragging() {
let isDragging = false;
let startX, startY, startLeft, startTop;
this.title.on("mousedown", (e) => {
if(this.activeDragging == false){
return;
}
let isInput = $(e.target).closest("button, input, select, textarea,.btn");
if (isInput.length) return;
e.preventDefault();
isDragging = true;
startX = e.pageX;
startY = e.pageY;
startLeft = parseFloat(this.panel.css("left"));
startTop = parseFloat(this.panel.css("top"));
$("body").css("user-select", "none");
this.dispatchEvent(new Event("dragging"));
this.panel.css("box-shadow","black 0px 0px 40px -20px");
this.panel.css("backdrop-filter","blur(10px)");
});
$(document).on("mousemove", (e) => {
if (!isDragging) return;
const dx = e.pageX - startX;
const dy = e.pageY - startY;
this.panel.css({
left: startLeft + dx,
top: startTop + dy,
});
});
$(document).on("mouseup", () => {
if (isDragging) {
isDragging = false;
this.panel.css("box-shadow","black 0px 0px 20px -10px");
this.panel.css("backdrop-filter","blur(3px)");
$("body").css("user-select", "auto");
this.dispatchEvent(new Event("draggingend"));
}
});
}
enableResize() {
const offset = 5; // panelin dışından 5px alan
let resizing = false;
let resizeDir = "";
let startX, startY, startW, startH, startL, startT;
const minW = 200, minH = 150;
// overlay divleri oluştur
const handles = {};
const names = ["n","s","e","w","ne","nw","se","sw"];
names.forEach(n => {
handles[n] = $('<div></div>').css({
position: "absolute",
zIndex: 1000,
background: "transparent",
cursor: n + "-resize",
transition: "all 0.5s all",
outlineOffset: "3px"
}).appendTo(this.panel);
});
// boyut ve pozisyonlarını ayarla
const updateHandles = () => {
const w = this.panel.outerWidth();
const h = this.panel.outerHeight();
// kenarlar
handles.n.css({ top: -offset, left: 0, width: w, height: offset*2 });
handles.s.css({ bottom: -offset, left: 0, width: w, height: offset*2 });
handles.w.css({ top: 0, left: -offset, width: offset*2, height: h });
handles.e.css({ top: 0, right: -offset, width: offset*2, height: h });
// köşeler
handles.nw.css({ top: -offset, left: -offset, width: offset*2, height: offset*2 });
handles.ne.css({ top: -offset, right: -offset, width: offset*2, height: offset*2 });
handles.sw.css({ bottom: -offset, left: -offset, width: offset*2, height: offset*2 });
handles.se.css({ bottom: -offset, right: -offset, width: offset*2, height: offset*2 });
};
updateHandles();
$(window).on("resize", updateHandles);
let activeDir = null;
// resize eventleri
names.forEach(dir => {
handles[dir].on("mousedown", (e) => {
if(this.activeResizing == false){
return;
}
activeDir = e.target;
e.preventDefault();
e.stopPropagation();
resizing = true;
resizeDir = dir;
startX = e.pageX;
startY = e.pageY;
startW = this.panel.outerWidth();
startH = this.panel.outerHeight();
startL = parseFloat(this.panel.css("left"));
startT = parseFloat(this.panel.css("top"));
this.dispatchEvent(new Event("resizing"));
$("body").css("user-select","none");
});
});
$(document).on("mousemove", (e) => {
if (!resizing) return;
const dx = e.pageX - startX;
const dy = e.pageY - startY;
let newW = startW;
let newH = startH;
let newL = startL;
let newT = startT;
if (resizeDir.includes("e")) newW = Math.max(minW, startW + dx);
if (resizeDir.includes("w")) { newW = Math.max(minW, startW - dx); newL = startL + (startW - newW); }
if (resizeDir.includes("s")) newH = Math.max(minH, startH + dy);
if (resizeDir.includes("n")) { newH = Math.max(minH, startH - dy); newT = startT + (startH - newH); }
this.panel.css({ width: newW, height: newH, left: newL, top: newT });
updateHandles();
$(activeDir).css("outline", "solid 2px #00ff00");
});
$(document).on("mouseup", () => {
if (resizing) {
resizing = false;
$("body").css("user-select","auto");
$(activeDir).css("outline", "solid 0px #00ff00");
this.dispatchEvent(new Event("resizingend"));
}
});
}
enableFocus() {
this.panel.on("mousedown", () => {
this.bringToFront();
});
}
bringToFront() {
if (DWindow.zCounter > DWindow.normalizeThreshold) {
DWindow.normalizeZ();
}
DWindow.zCounter++;
this.panel.css("z-index", DWindow.zCounter);
}
showing = true;
show(){
this.dispatchEvent(new Event("show"));
this.panel.show();
this.showing = true;
}
hide(){
this.dispatchEvent(new Event("hide"));
this.panel.hide();
this.showing = false;
}
toggle(){
this.showing ? this.hide() : this.show();
}
exit(){
this.dispatchEvent(new Event("exit"));
this.panel.remove();
}
/** @type {DWindow} */
parent = null;
/** @param {DWindow} parent */
enableDialog(parent){
this.parent = parent;
this.parent.activeDragging = false;
this.parent.activeResizing = false;
this.parent.panel.css('pointer-events',"none");
this.parent.panel.css('filter',"grayscale(1)");
let [{
left: parentL,
top: parentT,
width: parentW,
height: parentH
}] = this.parent.panel[0].getClientRects();
let [{
width: childW,
height: childH
}] = this.panel[0].getClientRects();
let newLeft = parentL + (parentW - childW) / 2;
let newTop = parentT + (parentH - childH) / 2;
debugger;
newLeft = Math.max(newLeft, 20);
newTop = Math.max(newTop, 20);
newLeft = Math.min(newLeft, screen.availWidth - 100);
newTop = Math.min(newTop, screen.availHeight - 100);
Object.assign(this.panel[0].style, {
left: `${Math.round(newLeft)}px`,
top: `${Math.round(newTop)}px`
});
}
/** @param {DWindow} parent */
disableDialog(){
this.parent.activeDragging = true;
this.parent.activeResizing = true;
this.parent.panel.css('pointer-events',"all");
this.parent.panel.css('filter',"initial");
}
}

View File

@ -1,32 +0,0 @@
let mwse = new MWSE({
endpoint: "ws://localhost:7707"
});
mwse.scope(beginEngine);
async function beginEngine()
{
room = mwse.room({
name: "Naber",
joinType: "free",
accessType: "private",
description: "Private free joined room",
ifexistsJoin: false,
notifyActionEjected: false,
notifyActionInvite: false,
notifyActionJoined: false
});
try{
await room.createRoom();
let time = 0;
setInterval(()=>{
room.info.set("set time",time);
time++;
},1000);
}catch{
await room.join();
}
room.on('updateinfo',(name, value) => {
console.log("read",name,value)
})
}

View File

@ -1,16 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dosya Transfer Sistem</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.7/css/bootstrap.min.css">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined" />
</head>
<body>
<script src="https://ws.saqut.com/script"></script>
<script src="m.h.2.8.8.js"></script>
</body>
</html>

View File

@ -1,166 +0,0 @@
<!doctype html>
<html lang="tr">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>jQuery ile Resizable Kutu</title>
<style>
body { font-family: Arial, Helvetica, sans-serif; height:100vh; margin:0; display:flex; align-items:center; justify-content:center; background:#f2f2f2; }
.stage { width:90vw; height:80vh; border:1px solid #ccc; position:relative; background:#fff; }
.box {
position:absolute;
left:50px; top:50px;
width:300px; height:200px;
background:#e8f0ff;
border:1px solid #5b8cff;
box-sizing:border-box;
user-select:none;
}
/* küçücük tutamaklar (handles) */
.handle {
position:absolute;
width:12px; height:12px;
background:#5b8cff;
border-radius:2px;
margin:-6px 0 0 -6px; /* merkezler */
cursor:default;
}
.handle.n { top:0; left:50%; cursor:n-resize; }
.handle.s { bottom:0; left:50%; cursor:s-resize; }
.handle.e { right:0; top:50%; cursor:e-resize; }
.handle.w { left:0; top:50%; cursor:w-resize; }
.handle.ne { right:0; top:0; cursor:ne-resize; }
.handle.nw { left:0; top:0; cursor:nw-resize; }
.handle.se { right:0; bottom:0; cursor:se-resize; }
.handle.sw { left:0; bottom:0; cursor:sw-resize; }
/* bilgi satırı (isteğe bağlı) */
.info { position:absolute; left:6px; bottom:6px; font-size:12px; color:#333; background:rgba(255,255,255,0.8); padding:4px 6px; border-radius:4px; }
</style>
</head>
<body>
<div class="stage">
<div class="box" id="resizable">
<div class="handle n" data-dir="n"></div>
<div class="handle s" data-dir="s"></div>
<div class="handle e" data-dir="e"></div>
<div class="handle w" data-dir="w"></div>
<div class="handle ne" data-dir="ne"></div>
<div class="handle nw" data-dir="nw"></div>
<div class="handle se" data-dir="se"></div>
<div class="handle sw" data-dir="sw"></div>
<div class="info" id="info"></div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script>
$(function(){
var $doc = $(document);
var $box = $('#resizable');
var dragging = false;
var dir = null;
var start = {}; // {mouseX, mouseY, left, top, width, height}
var minW = 60, minH = 40;
function updateInfo(){
var w = Math.round($box.width()), h = Math.round($box.height());
$('#info').text(w + ' x ' + h);
}
updateInfo();
$box.on('mousedown', '.handle', function(e){
e.preventDefault();
dragging = true;
dir = $(this).data('dir');
var offset = $box.position();
start = {
mouseX: e.pageX,
mouseY: e.pageY,
left: offset.left,
top: offset.top,
width: $box.outerWidth(),
height: $box.outerHeight()
};
// disable text selection while dragging
$('body').css('user-select','none');
});
$doc.on('mousemove', function(e){
if(!dragging) return;
e.preventDefault();
var dx = e.pageX - start.mouseX;
var dy = e.pageY - start.mouseY;
var newLeft = start.left;
var newTop = start.top;
var newW = start.width;
var newH = start.height;
// handle horizontal changes
if(dir.indexOf('e') !== -1){
newW = Math.max(minW, start.width + dx);
}
if(dir.indexOf('w') !== -1){
newW = Math.max(minW, start.width - dx);
newLeft = start.left + (start.width - newW);
}
// handle vertical changes
if(dir.indexOf('s') !== -1){
newH = Math.max(minH, start.height + dy);
}
if(dir.indexOf('n') !== -1){
newH = Math.max(minH, start.height - dy);
newTop = start.top + (start.height - newH);
}
// apply
$box.css({ left: newLeft + 'px', top: newTop + 'px', width: newW + 'px', height: newH + 'px' });
updateInfo();
});
$doc.on('mouseup mouseleave', function(){
if(dragging){
dragging = false;
dir = null;
$('body').css('user-select','auto');
}
});
// optional: allow dragging the whole box when clicking inside (but not on handles)
var draggingBox = false, dragBoxStart = {};
$box.on('mousedown', function(e){
if($(e.target).hasClass('handle')) return;
e.preventDefault();
draggingBox = true;
dragBoxStart = { mouseX: e.pageX, mouseY: e.pageY, left: $box.position().left, top: $box.position().top };
$('body').css('user-select','none');
});
$doc.on('mousemove', function(e){
if(!draggingBox) return;
var nx = dragBoxStart.left + (e.pageX - dragBoxStart.mouseX);
var ny = dragBoxStart.top + (e.pageY - dragBoxStart.mouseY);
$box.css({ left: nx + 'px', top: ny + 'px' });
});
$doc.on('mouseup', function(){
if(draggingBox){
draggingBox = false;
$('body').css('user-select','auto');
}
});
// keyboard nudges (isteğe bağlı)
$doc.on('keydown', function(e){
e.preventDefault();
if(!e.altKey) return; // alt ile etkinleştir
var pos = $box.position();
if(e.key === 'ArrowLeft') $box.css('left', pos.left - 1);
if(e.key === 'ArrowRight') $box.css('left', pos.left + 1);
if(e.key === 'ArrowUp') $box.css('top', pos.top - 1);
if(e.key === 'ArrowDown') $box.css('top', pos.top + 1);
});
});
</script>
</body>
</html>

View File

@ -1,714 +0,0 @@
<!DOCTYPE html>
<html lang="tr">
<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>Network meter</title>
</head>
<body style="background-color: #333333;">
<div id="container">
<div class="speed-container">
</div>
</div>
<style>
html,body,#container{
height: 100%;
margin: 0;
}
#container{
display: flex;
flex-direction: column;
}
.speed-container{
display: flex;
flex-direction: row;
max-width: 1200px;
flex-wrap: wrap;
margin: auto;
}
.speed-container > div{
flex: 1 1 25%;
max-width: 100%;
overflow: auto;
margin-bottom: 50px;
}
.speed-container > div canvas{
max-width: 100%;
overflow: auto;
}
.speed-container > div .text{
display: flex;
color: white;
vertical-align: middle;
}
.speed-container > div .mwse{
display: flex;
justify-content: space-evenly;
color: white;
text-align: center;
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
}
.speed-container > div .text > .text1{
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
font-size: 2em;
text-align: center;
vertical-align: middle;
flex: 1;
display: flex;
justify-content: center;
}
.speed-container > div .text > .text2{
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
font-size: 2em;
text-align: center;
vertical-align: middle;
flex: 1;
display: flex;
justify-content: center;
}
.speed-container > div .text1::after{
content:' FLOW';
font-size: 0.4em;
margin: auto 0 auto 5px;
}
.speed-container > div .text2::after{
content:' PRESSURE';
font-size: 0.4em;
margin: auto 0 auto 5px;
}
</style>
<script>
function CreateMeter()
{
var iCurrentSpeed = 0,
iTargetSpeed = 0,
bDecrement = null,
job = null;
function degToRad(angle) {
// Degrees to radians
return ((angle * Math.PI) / 180);
}
function radToDeg(angle) {
// Radians to degree
return ((angle * 180) / Math.PI);
}
function drawLine(options, line) {
// Draw a line using the line object passed in
options.ctx.beginPath();
// Set attributes of open
options.ctx.globalAlpha = line.alpha;
options.ctx.lineWidth = line.lineWidth;
options.ctx.fillStyle = line.fillStyle;
options.ctx.strokeStyle = line.fillStyle;
options.ctx.moveTo(line.from.X,
line.from.Y);
// Plot the line
options.ctx.lineTo(
line.to.X,
line.to.Y
);
options.ctx.stroke();
}
function createLine(fromX, fromY, toX, toY, fillStyle, lineWidth, alpha) {
// Create a line object using Javascript object notation
return {
from: {
X: fromX,
Y: fromY
},
to: {
X: toX,
Y: toY
},
fillStyle: fillStyle,
lineWidth: lineWidth,
alpha: alpha
};
}
function drawOuterMetallicArc(options) {
/* Draw the metallic border of the speedometer
* Outer grey area
*/
options.ctx.beginPath();
// Nice shade of grey
options.ctx.fillStyle = "rgb(127,127,127)";
// Draw the outer circle
options.ctx.arc(options.center.X,
options.center.Y,
options.radius,
0,
Math.PI,
true);
// Fill the last object
options.ctx.fill();
/* */
}
function drawInnerMetallicArc(options) {
/* Draw the metallic border of the speedometer
* Inner white area
*/
options.ctx.beginPath();
// White
options.ctx.fillStyle = "rgb(255,255,255)";
// Outer circle (subtle edge in the grey)
options.ctx.arc(options.center.X,
options.center.Y,
(options.radius / 100) * 90,
0,
Math.PI,
true);
options.ctx.fill();
/* */
}
function drawMetallicArc(options) {
/* Draw the metallic border of the speedometer
* by drawing two semi-circles, one over lapping
* the other with a bot of alpha transparency
*/
drawOuterMetallicArc(options);
drawInnerMetallicArc(options);
}
function drawBackground(options) {
/* Black background with alphs transparency to
* blend the edges of the metallic edge and
* black background
*/
var i = 0;
options.ctx.globalAlpha = 0.2;
options.ctx.fillStyle = "rgb(0,0,0)";
// Draw semi-transparent circles
for (i = 170; i < 180; i++) {
options.ctx.beginPath();
options.ctx.arc(options.center.X,
options.center.Y,
i,
0,
Math.PI,
true);
options.ctx.fill();
}
}
function applyDefaultContextSettings(options) {
/* Helper function to revert to gauges
* default settings
*/
options.ctx.lineWidth = 2;
options.ctx.globalAlpha = 0.5;
options.ctx.strokeStyle = "rgb(255, 255, 255)";
options.ctx.fillStyle = 'rgb(255,255,255)';
}
function drawSmallTickMarks(options) {
/* The small tick marks against the coloured
* arc drawn every 5 mph from 10 degrees to
* 170 degrees.
*/
var tickvalue = options.levelRadius - 8,
iTick = 0,
gaugeOptions = options.gaugeOptions,
iTickRad = 0,
onArchX,
onArchY,
innerTickX,
innerTickY,
fromX,
fromY,
line,
toX,
toY;
applyDefaultContextSettings(options);
// Tick every 20 degrees (small ticks)
for (iTick = 10; iTick < 180; iTick += 10) {
iTickRad = degToRad(iTick);
/* Calculate the X and Y of both ends of the
* line I need to draw at angle represented at Tick.
* The aim is to draw the a line starting on the
* coloured arc and continueing towards the outer edge
* in the direction from the center of the gauge.
*/
onArchX = gaugeOptions.radius - (Math.cos(iTickRad) * tickvalue);
onArchY = gaugeOptions.radius - (Math.sin(iTickRad) * tickvalue);
innerTickX = gaugeOptions.radius - (Math.cos(iTickRad) * gaugeOptions.radius);
innerTickY = gaugeOptions.radius - (Math.sin(iTickRad) * gaugeOptions.radius);
fromX = (options.center.X - gaugeOptions.radius) + onArchX;
fromY = (gaugeOptions.center.Y - gaugeOptions.radius) + onArchY;
toX = (options.center.X - gaugeOptions.radius) + innerTickX;
toY = (gaugeOptions.center.Y - gaugeOptions.radius) + innerTickY;
// Create a line expressed in JSON
line = createLine(fromX, fromY, toX, toY, "rgb(127,127,127)", 3, 0.6);
// Draw the line
drawLine(options, line);
}
}
function drawLargeTickMarks(options) {
/* The large tick marks against the coloured
* arc drawn every 10 mph from 10 degrees to
* 170 degrees.
*/
var tickvalue = options.levelRadius - 8,
iTick = 0,
gaugeOptions = options.gaugeOptions,
iTickRad = 0,
innerTickY,
innerTickX,
onArchX,
onArchY,
fromX,
fromY,
toX,
toY,
line;
applyDefaultContextSettings(options);
tickvalue = options.levelRadius - 2;
// 10 units (major ticks)
for (iTick = 20; iTick < 180; iTick += 20) {
iTickRad = degToRad(iTick);
/* Calculate the X and Y of both ends of the
* line I need to draw at angle represented at Tick.
* The aim is to draw the a line starting on the
* coloured arc and continueing towards the outer edge
* in the direction from the center of the gauge.
*/
onArchX = gaugeOptions.radius - (Math.cos(iTickRad) * tickvalue);
onArchY = gaugeOptions.radius - (Math.sin(iTickRad) * tickvalue);
innerTickX = gaugeOptions.radius - (Math.cos(iTickRad) * gaugeOptions.radius);
innerTickY = gaugeOptions.radius - (Math.sin(iTickRad) * gaugeOptions.radius);
fromX = (options.center.X - gaugeOptions.radius) + onArchX;
fromY = (gaugeOptions.center.Y - gaugeOptions.radius) + onArchY;
toX = (options.center.X - gaugeOptions.radius) + innerTickX;
toY = (gaugeOptions.center.Y - gaugeOptions.radius) + innerTickY;
// Create a line expressed in JSON
line = createLine(fromX, fromY, toX, toY, "rgb(127,127,127)", 3, 0.6);
// Draw the line
drawLine(options, line);
}
}
function drawTicks(options) {
/* Two tick in the coloured arc!
* Small ticks every 5
* Large ticks every 10
*/
drawSmallTickMarks(options);
drawLargeTickMarks(options);
}
function drawTextMarkers(options) {
/* The text labels marks above the coloured
* arc drawn every 10 mph from 10 degrees to
* 170 degrees.
*/
var innerTickX = 0,
innerTickY = 0,
iTick = 0,
gaugeOptions = options.gaugeOptions,
iTickToPrint = 00;
applyDefaultContextSettings(options);
// Font styling
options.ctx.font = 'italic 10px sans-serif';
options.ctx.textBaseline = 'top';
options.ctx.beginPath();
// Tick every 20 (small ticks)
for (iTick = 10; iTick < 160; iTick += 20) {
innerTickX = gaugeOptions.radius - (Math.cos(degToRad(iTick)) * gaugeOptions.radius);
innerTickY = gaugeOptions.radius - (Math.sin(degToRad(iTick)) * gaugeOptions.radius);
// Some cludging to center the values (TODO: Improve)
if (iTick <= 10) {
options.ctx.fillText(iTickToPrint, (options.center.X - gaugeOptions.radius - 12) + innerTickX,
(gaugeOptions.center.Y - gaugeOptions.radius - 12) + innerTickY + 5);
} else if (iTick < 50) {
options.ctx.fillText(iTickToPrint, (options.center.X - gaugeOptions.radius - 12) + innerTickX - 5,
(gaugeOptions.center.Y - gaugeOptions.radius - 12) + innerTickY + 5);
} else if (iTick < 90) {
options.ctx.fillText(iTickToPrint, (options.center.X - gaugeOptions.radius - 12) + innerTickX,
(gaugeOptions.center.Y - gaugeOptions.radius - 12) + innerTickY);
} else if (iTick === 90) {
options.ctx.fillText(iTickToPrint, (options.center.X - gaugeOptions.radius - 12) + innerTickX + 4,
(gaugeOptions.center.Y - gaugeOptions.radius - 12) + innerTickY);
} else if (iTick < 145) {
options.ctx.fillText(iTickToPrint, (options.center.X - gaugeOptions.radius - 12) + innerTickX + 10,
(gaugeOptions.center.Y - gaugeOptions.radius - 12) + innerTickY);
} else {
options.ctx.fillText(iTickToPrint, (options.center.X - gaugeOptions.radius - 12) + innerTickX + 15,
(gaugeOptions.center.Y - gaugeOptions.radius - 12) + innerTickY + 5);
}
// MPH increase by 10 every 20 degrees
//iTickToPrint += Math.round(2160 / 9);
iTickToPrint += 30;
}
options.ctx.stroke();
}
function drawSpeedometerPart(options, alphaValue, strokeStyle, startPos) {
/* Draw part of the arc that represents
* the colour speedometer arc
*/
options.ctx.beginPath();
options.ctx.globalAlpha = alphaValue;
options.ctx.lineWidth = 5;
options.ctx.strokeStyle = strokeStyle;
options.ctx.arc(options.center.X,
options.center.Y,
options.levelRadius,
Math.PI + (Math.PI / 360 * startPos),
0 - (Math.PI / 360 * 10),
false);
options.ctx.stroke();
}
function drawSpeedometerColourArc(options) {
/* Draws the colour arc. Three different colours
* used here; thus, same arc drawn 3 times with
* different colours.
* TODO: Gradient possible?
*/
drawSpeedometerPart(options, 1.0, "rgb(255,255,255)", 10);
drawSpeedometerPart(options, 0.9, "rgb(0,255,0)", 80);
drawSpeedometerPart(options, 0.9, "rgb(255,128,0)", 250);
drawSpeedometerPart(options, 0.9, "rgb(255,0,0)", 300);
}
function drawNeedleDial(options, alphaValue, strokeStyle, fillStyle) {
/* Draws the metallic dial that covers the base of the
* needle.
*/
var i = 0;
options.ctx.globalAlpha = alphaValue;
options.ctx.lineWidth = 3;
options.ctx.strokeStyle = strokeStyle;
options.ctx.fillStyle = fillStyle;
// Draw several transparent circles with alpha
for (i = 0; i < 30; i++) {
options.ctx.beginPath();
options.ctx.arc(options.center.X,
options.center.Y,
i,
0,
Math.PI,
true);
options.ctx.fill();
options.ctx.stroke();
}
}
function drawNeedle(options) {
/* Draw the needle in a nice read colour at the
* angle that represents the options.speed value.
*/
var iSpeedAsAngle = convertSpeedToAngle(options),
iSpeedAsAngleRad = degToRad(iSpeedAsAngle),
gaugeOptions = options.gaugeOptions,
innerTickX = gaugeOptions.radius - (Math.cos(iSpeedAsAngleRad) * 20),
innerTickY = gaugeOptions.radius - (Math.sin(iSpeedAsAngleRad) * 20),
fromX = (options.center.X - gaugeOptions.radius) + innerTickX,
fromY = (gaugeOptions.center.Y - gaugeOptions.radius) + innerTickY,
endNeedleX = gaugeOptions.radius - (Math.cos(iSpeedAsAngleRad) * gaugeOptions.radius),
endNeedleY = gaugeOptions.radius - (Math.sin(iSpeedAsAngleRad) * gaugeOptions.radius),
toX = (options.center.X - gaugeOptions.radius) + endNeedleX,
toY = (gaugeOptions.center.Y - gaugeOptions.radius) + endNeedleY,
line = createLine(fromX, fromY, toX, toY, "rgb(255, 0, 0)", 5, 0.6);
drawLine(options, line);
// Two circle to draw the dial at the base (give its a nice effect?)
drawNeedleDial(options, 0.6, "rgb(127, 127, 127)", "rgb(255,255,255)");
drawNeedleDial(options, 0.2, "rgb(127, 127, 127)", "rgb(127,127,127)");
}
function buildOptionsAsJSON(canvas, iSpeed) {
/* Setting for the speedometer
* Alter these to modify its look and feel
*/
var centerX = 210,
centerY = 210,
radius = 150,
outerRadius = 200;
// Create a speedometer object using Javascript object notation
return {
ctx: canvas.getContext('2d'),
speed: iSpeed,
center: {
X: centerX,
Y: centerY
},
levelRadius: radius - 10,
gaugeOptions: {
center: {
X: centerX,
Y: centerY
},
radius: radius
},
radius: outerRadius
};
}
function clearCanvas(options) {
options.ctx.clearRect(0, 0, 800, 600);
applyDefaultContextSettings(options);
}
function draw() {
/* Main entry point for drawing the speedometer
* If canvas is not support alert the user.
*/
var canvas = createCanvas.value,
options = null;
// Canvas good?
if (canvas !== null && canvas.getContext) {
options = buildOptionsAsJSON(canvas, iCurrentSpeed);
// Clear canvas
clearCanvas(options);
// Draw the metallic styled edge
drawMetallicArc(options);
// Draw thw background
drawBackground(options);
// Draw tick marks
drawTicks(options);
// Draw labels on markers
drawTextMarkers(options);
// Draw speeometer colour arc
drawSpeedometerColourArc(options);
// Draw the needle and base
drawNeedle(options);
} else {
alert("Canvas not supported by your browser!");
};
if(iTargetSpeed == iCurrentSpeed) {
cancelAnimationFrame(job);
return;
} else if(iTargetSpeed < iCurrentSpeed) {
bDecrement = true;
} else if(iTargetSpeed > iCurrentSpeed) {
bDecrement = false;
}
console.log(iTargetSpeed,bDecrement)
if(bDecrement) {
iCurrentSpeed = iCurrentSpeed - 1;
} else {
iCurrentSpeed = iCurrentSpeed + 1;
}
job = requestAnimationFrame(draw);
};
function createCanvas()
{
let container = document.createElement("div");
container.classList.add("boxmodel")
let canvas = document.createElement("canvas");
let text = document.createElement("div");
let text1 = document.createElement("div");
let text2 = document.createElement("div");
text.classList.add("text")
text1.classList.add("text1")
text2.classList.add("text2")
let mwse = document.createElement("div");
let text3 = document.createElement("span");
let text4 = document.createElement("span");
mwse.classList.add("mwse")
text3.classList.add("text3")
text4.classList.add("text4")
text.append(text1);
text.append(text2);
mwse.append(text3);
mwse.append(text4);
canvas.setAttribute("width", "440px");
canvas.setAttribute("height", "220px");
container.append(canvas);
container.append(text);
container.append(mwse);
createCanvas.value = canvas;
createCanvas.container = container;
createCanvas.ps = text1;
createCanvas.pw = text2;
createCanvas.rooms = text3;
createCanvas.clients = text4;
return container;
};
function update(value, pressure, rooms, clients)
{
iTargetSpeed = value;
createCanvas.ps.innerText = value;
createCanvas.pw.innerText = pressure + '%';
createCanvas.rooms.innerText = rooms;
createCanvas.clients.innerText = clients;
draw()
}
function convertSpeedToAngle(options) {
/* Helper function to convert a speed to the
* equivelant angle.
*/
let m = 150;
let value = (m/10) + Math.min(
Math.max(
options.speed,
0
),
240
);
iSpeedAsAngle = (
(100 / m) * value
);
// Ensure the angle is within range
if (iSpeedAsAngle > 180) {
iSpeedAsAngle = iSpeedAsAngle - 180;
} else if (iSpeedAsAngle < 0) {
iSpeedAsAngle = iSpeedAsAngle + 180;
}
return iSpeedAsAngle;
}
return {
createCanvas,
update
}
}
/*
let elem = document.querySelector(".speed-container");
for(let e = 0; e < 8; e++)
{
let meter = CreateMeter();
let container = meter.createCanvas();
elem.appendChild(container);
meter.update(54,25)
}
*/
let elem = document.querySelector(".speed-container");
let meters = new Map();
async function reloadData()
{
while(1)
{
await fetchData();
await new Promise(ok => {
setTimeout(() => ok(), 3000)
})
}
};
let isFirst = true;
async function fetchData()
{
let response = await fetch("/stats",{
method: "post",
credentials: "same-origin",
cache: "no-cache",
mode:"no-cors"
}).then(e => e.json());
for (const {
ws_total_packs,
core,
mwse_rooms,
mwse_clients
} of response) {
if(!meters.has(core))
{
let meter = CreateMeter();
let container = meter.createCanvas();
elem.appendChild(container);
meters.set(core, meter)
};
let _meter = meters.get(core);
_meter.update(
ws_total_packs,
ws_total_packs < 30 ? 0 : ws_total_packs < 60 ? 1 : ws_total_packs < 90 ? 2 : 3,
"RM: "+mwse_rooms,
"CL: "+mwse_clients
);
}
}
reloadData();
</script>
</body>
</html>