import DataChannel from "./networking/DataChannel.js"; import Signaler from "./networking/Signaler.js"; /** * @typedef {{action:"join",name:string}} MessageToServer */ /** * @typedef {"yup"|"nope"|{action:"updatePlayerList",update:{type:"set",players:string[]}|{type:"add",player:string}}} MessageToClient */ /** * A local server. Handles all the important game logic, and communicates with clients via DataChannels. */ export default class SkribblServer { /** * Starts a new SkribblServer. */ constructor(){ this._readyPromise = (async()=>{ /** @type {{name:string,dataChannel:DataChannel<MessageToClient,MessageToServer>}[]} */ this._clients = []; this._id = await Signaler.host(dataChannel=>{ this.connect(DataChannel.from(dataChannel,JSON.stringify,JSON.parse)); }); /** @type {[DataChannel<MessageToServer,MessageToClient>,DataChannel<MessageToClient,MessageToServer>]} */ let [endpointA,endpointB] = DataChannel.createPair(); this._dataChannel = endpointA; this.connect(endpointB); })(); } /** * Waits until the server is ready. */ async waitUntilReady(){ return this._readyPromise; } /** * A dataChannel talking to this server like any other client. * @readonly */ get dataChannel(){ return this._dataChannel; } /** * The ID others can use to connect to this server. * @readonly */ get id(){ return this._id; } /** * Returns the full url others can use to connect to this server. * @readonly */ get url(){ return document.location.host+document.location.pathname+"#"+this._id; } /** * Adds an incoming connection as a client. * @param {DataChannel<MessageToClient,MessageToServer>} dataChannel */ connect(dataChannel){ (async()=>{ let message = await dataChannel.next(); console.log("message: ",message); if (message.action==="join"){ let name = message.name; if (name.length<30&&name.length>=1){ dataChannel.send("yup"); this._clients.forEach(({dataChannel})=>{ dataChannel.send({action:"updatePlayerList",update:{type:"add",player:name}}); }); this._clients.push({name,dataChannel}); dataChannel.send({action:"updatePlayerList",update:{type:"set",players:this._clients.map(({name})=>name)}}); }else{ dataChannel.send("nope"); dataChannel.close(); } }else{ dataChannel.send("nope"); dataChannel.close(); } })(); } }