Skip to content
Snippets Groups Projects
SkribblServer.js 2.35 KiB
Newer Older
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._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}});
					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();
			}
		})();