Skip to main content
File
import { Client } from "./client.ts";import { EventHandler } from "./eventhandler.ts";import { Packet } from "./packet.ts";import type { WebSocket } from "./deps.ts";import type { HTTPOptions, HTTPSOptions} from "./deps.ts";import { serve, Server as DenoServer, serveTLS, ServerRequest } from "https://deno.land/std@0.95.0/http/server.ts";import { serveFile } from "./deps.ts";import { acceptWebSocket, isWebSocketCloseEvent } from "./deps.ts";
/** * Class that handles WebSocket messages. * Uses Client objects and an EventHandler object * to send messages to Clients.*/export class Sono { public server: DenoServer | null = null; public hostname = 'localhost'; public clients: {[key: string]: Client} = {}; public channelsList: {[key: string]: Record<string, Client>} = {'home': {}}; public eventHandler: EventHandler;
/** * Constructor creates a new instance of the Event, * binds handleWs to this and returns a Sono instance. */ constructor() { this.eventHandler = new EventHandler(); this.handleWs = this.handleWs.bind(this); }
/** * Start server listening on passed-in port number. * @param {number} port - Port that Sono.server listens to. */ listen(port: number): DenoServer { const options: HTTPOptions = {port}; this.server = serve(options); this.awaitRequests(this.server); return this.server; }

/** * Adding a channel to channelsList object * @param { name } - name of channel */ channel(name: string, callback: () => void) :void { this.channelsList[name] = {}; // console.log(this.channelsList) callback(); return; }
/** * awaitRequests handles requests to server and returns undefined * @param { DenoServer } - Sono.server from which requests are sent from */ async awaitRequests(server: DenoServer):Promise<void> { // iterate over async request objects to server for await(const req of server) { this.handler(req); } }
/** * Handler method handles request to server * and serves files or upgrades connection to websocket * @param { ServerRequest } - request object from a client */ async handler(req: ServerRequest) { //serve index html console.log(req, 'request') if (req.method === "GET" && req.url === "/") { const path = `${Deno.cwd()}/webRTC/assets/index.html` const content = await serveFile(req, path); req.respond(content) } // upgrade to websocket connection else if (req.method === "GET" && req.url === "/ws") { const { conn, w:bufWriter, r:bufReader, headers } = req; acceptWebSocket({conn, bufWriter, bufReader, headers}) .then(this.handleWs) .catch(err => console.log(err, 'err')) } // request to favicon is skipped else if (req.url === "/favicon.ico") { // continue } else { const path = `${Deno.cwd()}/webRTC/assets${req.url}`; const content = await serveFile(req, path); req.respond(content) } }
/** * handleWS method handles a socket connection * Instantiants a new client * Events of socket are looped thru and dealt with accordingly * @param { WebSocket } - WebSocket connection from a client */ async handleWs (socket: WebSocket):Promise<void> { // create new client, add to clients object, add client to home channel // console.log(socket, 'im here') const client = new Client(socket, Object.keys(this.clients).length); this.clients[client.id] = client; this.channelsList['home'][client.id] = client;
for await(const message of socket){ // if client sends close websocket event, delete client if (isWebSocketCloseEvent(message) || typeof message !== 'string'){ delete this.channelsList[client.channel][client.id]; delete this.clients[client.id] break; } const data: Packet = JSON.parse(message) // const grab = data.payload.message;
// depending on data.protocol, invoke an eventHandler method switch(data.protocol) { case 'message': console.log('case message', this.clients) this.eventHandler.handleMessage(data, client, this.channelsList); break; case 'broadcast': this.eventHandler.broadcast(data, client, this.channelsList) break; case 'changeChannel': this.channelsList = this.eventHandler.changeChannel(data, client, this.channelsList); console.log('case channel', this.channelsList); break; case 'directmessage': this.eventHandler.directMessage(data, client, this.clients); break; case 'grab': this.eventHandler.grab(data, client, this.clients, this.channelsList); break; default: console.log('default hit', data) } } }}