// // Copyright © 2020, 2021 Anticrm Platform Contributors. // Copyright © 2021 Hardcore Engineering Inc. // // Licensed under the Eclipse Public License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. You may // obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // // See the License for the specific language governing permissions and // limitations under the License. // import { readRequest, serialize, Response } from '@anticrm/platform' import { createServer, IncomingMessage } from 'http' import WebSocket, { Server } from 'ws' import { decode } from 'jwt-simple' /** * @internal */ export interface _Token { workspace: string } async function handleRequest (service: S, ws: WebSocket, msg: string): Promise { const request = readRequest(msg) const f = (service as any)[request.method] const result = await f.apply(null, request.params) ws.send(serialize({ id: request.id, result })) } /** * @public */ // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface Session {} /** * @public */ export interface JsonRpcServer { broadcast: (from: Session, resp: Response) => void } /** * @public * @param sessionFactory - * @param port - * @param host - */ export function start (sessionFactory: (server: JsonRpcServer) => Session, port: number, host?: string): void { // console.log('starting server on port ' + port + '...') // console.log('host: ' + host) const sessions: [Session, WebSocket][] = [] const jsonServer: JsonRpcServer = { broadcast (from: Session, resp: Response<[]>) { const msg = serialize(resp) for (const session of sessions) { if (session[0] !== from) { session[1].send(msg) } } } } const wss = new Server({ noServer: true }) // eslint-disable-next-line @typescript-eslint/no-misused-promises wss.on('connection', (ws: WebSocket, request: any, token: _Token) => { const service = sessionFactory(jsonServer) sessions.push([service, ws]) // eslint-disable-next-line @typescript-eslint/no-misused-promises ws.on('message', async (msg: string) => await handleRequest(service, ws, msg)) }) const server = createServer() server.on('upgrade', (request: IncomingMessage, socket, head: Buffer) => { const token = request.url?.substring(1) // remove leading '/' try { const payload = decode(token ?? '', 'secret', false) wss.handleUpgrade(request, socket, head, ws => wss.emit('connection', ws, request, payload)) } catch (err) { socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n') socket.destroy() } }) server.listen(port, host) }