Revision
This commit is contained in:
parent
1b02eb1bce
commit
c623016841
|
|
@ -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
|
||||
};
|
||||
|
|
@ -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"));
|
||||
});
|
||||
|
|
@ -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
|
||||
};
|
||||
|
|
@ -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 };
|
||||
});
|
||||
|
|
@ -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;
|
||||
const otherPeer = Client.clients.get(to);
|
||||
|
||||
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;
|
||||
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']);
|
||||
|
||||
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;
|
||||
}
|
||||
default:{
|
||||
next();
|
||||
}
|
||||
};
|
||||
return handshake ? { type: 'success' } : undefined;
|
||||
});
|
||||
|
||||
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;
|
||||
}
|
||||
} 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;
|
||||
});
|
||||
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
|
@ -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) };
|
||||
});
|
||||
|
||||
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;
|
||||
|
|
@ -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);
|
||||
}
|
||||
client.sync('store');
|
||||
});
|
||||
const defaults = {
|
||||
notifyPairInfo: true,
|
||||
packrecaive: true,
|
||||
packsending: true,
|
||||
notifyRoomInfo: true
|
||||
};
|
||||
|
||||
|
||||
|
||||
addService(({
|
||||
client,
|
||||
end,
|
||||
global,
|
||||
message,
|
||||
next,
|
||||
response
|
||||
})=>{
|
||||
let {type, value} = message;
|
||||
switch(type)
|
||||
{
|
||||
// enable/disable pair/info messages
|
||||
case 'connection/pairinfo':{
|
||||
client.store.set("notifyPairInfo", !!value)
|
||||
client.sync('store');
|
||||
end(true);
|
||||
break;
|
||||
}
|
||||
case 'connection/roominfo':{
|
||||
client.store.set("notifyRoomInfo", !!value)
|
||||
client.sync('store');
|
||||
end(true);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case 'connection/packrecaive':{
|
||||
client.store.set("packrecaive", !!value)
|
||||
client.sync('store');
|
||||
end(true);
|
||||
break;
|
||||
}
|
||||
case 'connection/packsending':{
|
||||
client.store.set("packsending", !!value)
|
||||
client.sync('store');
|
||||
end(true);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'connection/reset':{
|
||||
for (const [name, defaultValue] of Stdoutput)
|
||||
{
|
||||
client.store.set(name, defaultValue);
|
||||
}
|
||||
client.sync('store');
|
||||
end(true);
|
||||
break;
|
||||
}
|
||||
on('connect', (client) => {
|
||||
for (const [name, value] of Object.entries(defaults)) {
|
||||
client.store.set(name, value);
|
||||
}
|
||||
});
|
||||
|
||||
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' };
|
||||
});
|
||||
|
||||
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' };
|
||||
});
|
||||
|
||||
register('connection/reset', (client, msg) => {
|
||||
for (const [name, value] of Object.entries(defaults)) {
|
||||
client.store.set(name, value);
|
||||
}
|
||||
return { status: 'success' };
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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']);
|
||||
});
|
||||
|
|
@ -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");
|
||||
})
|
||||
function init(server) {
|
||||
http = server;
|
||||
|
||||
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
|
||||
})*/
|
||||
termoutput && console.log("Web Socket Protocol is ready");
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -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");
|
||||
|
|
|
|||
508
console/Hemex.js
508
console/Hemex.js
|
|
@ -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)
|
||||
};
|
||||
|
|
@ -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>
|
||||
920
console/lib.js
920
console/lib.js
|
|
@ -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);
|
||||
|
|
@ -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);
|
||||
|
|
@ -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);
|
||||
|
|
@ -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"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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(`Açı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);
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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();
|
||||
};
|
||||
179
public/index.css
179
public/index.css
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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>
|
||||
352
public/index.js
352
public/index.js
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -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ş
|
||||
//
|
||||
// =================================================================
|
||||
|
|
@ -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>
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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">
|
||||
Ağ 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 |
|
|
@ -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;
|
||||
/*
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
|
@ -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;
|
||||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
Loading…
Reference in New Issue