diff --git a/Source/Client.js b/Source/Client.js index 12e36f5..3ef4999 100644 --- a/Source/Client.js +++ b/Source/Client.js @@ -16,6 +16,10 @@ function Client() this.store = new Map(); this.rooms = new Set(); }; +/** + * @type {Map} + */ +Client.clients = new Map(); Client.prototype.send = function(obj){ this.socket.sendUTF(JSON.stringify(obj)); diff --git a/Source/Services/DataTransfer.js b/Source/Services/DataTransfer.js new file mode 100644 index 0000000..da11c25 --- /dev/null +++ b/Source/Services/DataTransfer.js @@ -0,0 +1,74 @@ +const { Client } = require("../Client.js"); +let {randomUUID} = require("crypto"); +let {addService,addListener} = require("../WebSocket.js"); +const { Room } = require("./Room.js"); +let term = require("terminal-kit").terminal; + +/* +Peer to peer veri aktarımı + +- 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ı + +*/ + +addService(({ + client, + end, + global, + message, + next, + response +}) => { + let {type} = message; + switch(type) + { + case "pack/to":{ + let {to,pack} = message; + if(Client.clients.has(to)) + { + Client.clients.get(to).send([{ + from: client.id, + pack: pack + }, 'pack']); + end({ + type: 'success' + }) + }else{ + end({ + type: 'fail' + }) + } + break; + } + case "pack/room":{ + let {to,pack} = message; + if(Room.rooms.has(to)) + { + if(!client.rooms.has(to)) + { + return end({ + type: 'fail' + }) + }; + Room.rooms.get(to).send([{ + from: client.id, + pack: pack + }, 'pack']); + end({ + type: 'success' + }) + }else{ + end({ + type: 'fail' + }) + } + break; + } + default:{ + next(); + } + }; +}); \ No newline at end of file diff --git a/Source/Services/Room.js b/Source/Services/Room.js index 7711814..302398b 100644 --- a/Source/Services/Room.js +++ b/Source/Services/Room.js @@ -1,9 +1,14 @@ const { Client } = require("../Client.js"); -let {randomUUID} = require("crypto"); +let {randomUUID,createHash} = require("crypto"); const joi = require("joi"); let {addService,addListener} = require("../WebSocket.js"); let term = require("terminal-kit").terminal; +function Sha256(update) +{ + return createHash("sha256").update(update).digest("hex"); +}; + function Room() { /** @@ -53,7 +58,7 @@ function Room() /** * @type {string} */ - this.password = null; + this.credential = null; /** * @type {string[]} */ @@ -103,7 +108,6 @@ Room.prototype.join = function(client){ Room.prototype.down = function(){ term.red("Room is downed ").red(this.name," in ").yellow(this.clients.size + "").red(" clients")('\n'); this.send([{ - id: client.id, roomid: this.id, ownerid: this.owner.id },'room/closed']); @@ -123,6 +127,13 @@ Room.prototype.eject = function(client){ } client.rooms.delete(this.id); this.clients.delete(client.id); + + if(this.clients.size == 0) + { + this.down(); + term.red("Client Room closed ").red(this.name," at 0 clients")('\n'); + } + term.red("Client Room ejected ").red(this.name," in ").yellow(this.clients.size + "").red(" clients")('\n'); }; @@ -159,7 +170,8 @@ let CreateRoomVerify = joi.object({ notifyActionEjected: joi.boolean().required(), joinType: joi.string().pattern(/^free$|^invite$|^password$|^lock$/).required(), description: joi.string().required(), - name: joi.string().required() + name: joi.string().required(), + credential: joi.string().optional() }); addService(({ @@ -175,7 +187,27 @@ addService(({ { case 'myroom-info':{ let room = Room.rooms.get(client.id); - end(room.toJSON()) + end({ + status: "success", + room: room.toJSON() + }) + break; + } + case 'room-peers':{ + let {roomId} = message; + if(Room.rooms.has(roomId)) + { + end({ + status: 'success', + peers: [ + ...Room.rooms.get(roomId).clients.values() + ].map(i => i.id) + }); + }else{ + end({ + status: 'fail' + }) + } break; } case 'room-info':{ @@ -189,7 +221,7 @@ addService(({ }) } }; - return end({ + end({ status : "fail", message : "NOT-FOUND-ROOM" }) @@ -204,6 +236,29 @@ addService(({ 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) @@ -232,6 +287,10 @@ addService(({ room.description = message.description; room.name = message.name; room.owner = client; + if(message.credential) + { + room.credential = Sha256(message.credential + ""); + } room.join(client); room.publish(); end({ @@ -263,17 +322,24 @@ addService(({ }) }else if(room.joinType == "password") { - if(room.password == message.credential) + if(room.credential == Sha256(message.credential + "")) { room.join(client); - return end({status : "success"}) + return end({ + status : "success", + room: room.toJSON() + }) }else return end({ status : "fail", - message : "WRONG-PASSWORD" + message : "WRONG-PASSWORD", + area: "credential" }) }else if(room.joinType == "free"){ room.join(client); - return end({status : "success"}) + return end({ + status : "success", + room: room.toJSON() + }) }else if(room.joinType == "invite"){ room.waitingInvited.add(client.id); if(room.notifyActionInvite) @@ -295,6 +361,9 @@ addService(({ } break; } + default:{ + next(); + } } }); diff --git a/Source/WebSocket.js b/Source/WebSocket.js index 9170026..5f6c1c6 100644 --- a/Source/WebSocket.js +++ b/Source/WebSocket.js @@ -20,18 +20,19 @@ let global = new Map(); let clients = new Map(); wsServer.addListener("connect",(socket) => { - let local = new Client(); + let xClient = new Client(); let id = randomUUID(); socket.id = id; - local.id = id; - local.socket = socket; - local.created_at = new Date(); - clients.set(id, local); + xClient.id = id; + xClient.socket = socket; + xClient.created_at = new Date(); + Client.clients.set(id, xClient); + clients.set(id, xClient); - emit("connect", global, local); + emit("connect", global, xClient); socket.addListener("close",()=>{ - emit("disconnect", global, local); - clients.delete(id); + emit("disconnect", global, xClient); + Client.clients.set(id, xClient); }); socket.addListener("message",({type,utf8Data}) => { if(type == "utf8") @@ -39,15 +40,15 @@ wsServer.addListener("connect",(socket) => { let json; try{ json = JSON.parse(utf8Data); - emit('services', global, local, json); + emit('services', global, xClient, json); let [payload, id, action] = json; if(typeof id === "string") { action = id; } - emitService(global, local, id, payload, action); + emitService(global, xClient, id, payload, action); }catch{ - emit("messageError", global, local, utf8Data); + emit("messageError", global, xClient, utf8Data); } } }); @@ -96,7 +97,7 @@ function emit(event,...args) * @param {Client} local * @param {number} id * @param {{[key:string]:any}} payload - * @param {"R"|"S"} action + * @param {"R"|"S"} action [R]EQUEST flag or [S]TREAM flag */ async function emitService(global, client, id, payload, action) { @@ -108,10 +109,10 @@ async function emitService(global, client, id, payload, action) client, global, response:(obj)=>{ - client.send([obj, id, 'C']) // continue + client.send([obj, id, 'C']) // continue ([C]ONTINUE flag) }, end:(obj)=>{ - client.send([obj, id, 'E']) // stopped data stream (this channel) + client.send([obj, id, 'E']) // stopped data stream (this channel) ([E]ND flag) }, next:function(){ willContinue = true; diff --git a/Source/index.js b/Source/index.js index da92496..0d4b10d 100644 --- a/Source/index.js +++ b/Source/index.js @@ -3,4 +3,5 @@ require("./WebSocket.js"); require("./Services/YourID.js"); require("./Services/Auth.js"); -require("./Services/Room.js"); \ No newline at end of file +require("./Services/Room.js"); +require("./Services/DataTransfer.js"); \ No newline at end of file diff --git a/test.html b/test.html index 8b6eca8..d3defee 100644 --- a/test.html +++ b/test.html @@ -16,18 +16,39 @@ console.log("Connected ws") let roomInfo = await ws.roomInfo("MY-ROOM"); console.log("Room Info", roomInfo) + + let type = ""; + if(roomInfo.status == 'fail' && roomInfo.message == "NOT-FOUND-ROOM") { - let secretRoom = await ws.createRoom({ + type = "owner"; + roomInfo = await ws.createRoom({ name: "MY-ROOM", description: "Gizli Odam", - joinType: "free" + joinType: "password", + credential: "123456Kc" }); - console.log("CreateRoom",secretRoom); + + + setInterval(()=>{ + ws.sendPackToRoom( roomInfo.room.id,"Merhaba"); + }, 5000); + }else{ - let joinedRoom = await ws.joinRoom("MY-ROOM"); - console.log("JoinRoom",joinedRoom); - } + roomInfo = await ws.joinRoom({name:"MY-ROOM",credential:"123456Kc"}); + + setInterval(()=>{ + ws.sendPackToPeer( roomInfo.room.owner,"Merhaba Yönetici"); + }, 5000); + + type = "member"; + }; + + + console.log("Oda bilgisi: ",roomInfo); + let Peers = await ws.getRoomPeers( roomInfo.room.id); + + console.log("Odadaki eşlerin bilgisi: ",Peers) console.log(await ws.getJoinedRooms()); @@ -35,6 +56,9 @@ ws.signal('id',(data)=>{ console.log("Your id is ", data.value) }); + ws.signal('pack',(pack)=>{ + console.log("Recaived Package :", pack) + }); ws.signal("room/joined",(joinStatus)=>{ console.log("Room joined", joinStatus) }); diff --git a/wsjs.js b/wsjs.js index 6424690..7f67d46 100644 --- a/wsjs.js +++ b/wsjs.js @@ -31,11 +31,11 @@ WSJS.prototype.messageEvent = function({data}){ this.requests.get(id)(payload, action); switch(action) { - case 'E':{ + case 'E':{ // [E]ND flag this.requests.delete(id); break; } - case 'S': + case 'S': // [S]TREAM flag default:{ break; } @@ -114,6 +114,7 @@ WSJS.prototype.sendRaw = function(obj){ this.ws.send(JSON.stringify(obj)) }; } +/* WSJS.prototype.checkAuth = async function(username, password){ return false; let {value:isAuth} = await this.request({ @@ -121,67 +122,70 @@ WSJS.prototype.checkAuth = async function(username, password){ }); return isAuth; }; +*/ WSJS.prototype.authWith = async function(username, password){ - if(!await this.checkAuth()) - { - await this.request({ - type: 'auth/login', - username, - password - }); - } + await this.request({ + type: 'auth/login', + username, + password + }); }; WSJS.prototype.fetchMyRoomInfo = async function(){ - if(!await this.checkAuth()) - { - return await this.request({ - type: 'myroom-info' - }); - } + return await this.request({ + type: 'myroom-info' + }); }; WSJS.prototype.createRoom = async function(options){ - if(!await this.checkAuth()) - { - let result = await this.request({ - type: 'create-room', - accessType: options.accessType || "public", - notifyActionInvite:options.notifyActionInvite || true, - notifyActionJoined: options.notifyActionJoined || true, - notifyActionEjected: options.notifyActionEjected || true, - joinType: options.joinType || "free", - description: options.description || "No Description", - name: options.name || "No" - - }); - return result; - } + let result = await this.request({ + type: 'create-room', + accessType: options.accessType || "private", + notifyActionInvite: options.notifyActionInvite === undefined ? true : options.notifyActionInvite, + notifyActionJoined: options.notifyActionJoined === undefined ? true : options.notifyActionJoined, + notifyActionEjected: options.notifyActionEjected === undefined ? true : options.notifyActionEjected, + joinType: options.joinType || "free", + description: options.description || "No Description", + name: options.name || "No", + credential: options.credential || undefined + }); + return result; }; WSJS.prototype.roomInfo = async function(name){ - if(!await this.checkAuth()) - { - let result = await this.request({ - type: 'room-info', - name - }); - return result; - } + let result = await this.request({ + type: 'room-info', + name + }); + return result; }; -WSJS.prototype.joinRoom = async function(name){ - if(!await this.checkAuth()) - { - let result = await this.request({ - type: 'joinroom', - name - }); - return result; - } +WSJS.prototype.joinRoom = async function(options){ + let result = await this.request({ + ...options, + type: 'joinroom' + }); + return result; }; WSJS.prototype.joinedRooms = new Map(); WSJS.prototype.getJoinedRooms = async function(){ - if(!await this.checkAuth()) - { - return await this.request({ - type: 'joinedrooms' - }); - } + return await this.request({ + type: 'joinedrooms' + }); +}; +WSJS.prototype.getRoomPeers = async function(id){ + return await this.request({ + type: 'room-peers', + roomId: id + }); +}; +WSJS.prototype.sendPackToPeer = async function(roomId, pack){ + return await this.request({ + type: 'pack/to', + to: roomId, + pack + }); +}; +WSJS.prototype.sendPackToRoom = async function(roomId, pack){ + return await this.request({ + type: 'pack/room', + to: roomId, + pack + }); }; \ No newline at end of file