UNPKG

@cocalc/project

Version:
75 lines (66 loc) 2.77 kB
/* Create the TCP server that communicates with hubs */ import { createServer } from "net"; import { writeFile } from "fs"; import { callback } from "awaiting"; import { once } from "@cocalc/util/async-utils"; import { getLogger } from "@cocalc/project/logger"; import { hubPortFile } from "@cocalc/project/data"; const { unlock_socket } = require("@cocalc/backend/misc_node"); import enableMessagingProtocol from "@cocalc/backend/tcp/enable-messaging-protocol"; import { options } from "@cocalc/project/init-program"; import { secretToken } from "@cocalc/project/servers/secret-token"; const client = require("@cocalc/project/client"); import * as uuid from "uuid"; import handleMessage from "./handle-message"; const winston = getLogger("hub-tcp-server"); export default async function init(): Promise<void> { if (!secretToken || secretToken.length < 16) { // being extra careful since security throw Error("secret token must be defined and at least 16 characters"); return; } winston.info("starting tcp server: project <--> hub..."); const server = createServer(handleConnection); server.listen(options.hubPort, options.hostname); await once(server, "listening"); const address = server.address(); if (address == null || typeof address == "string") { // null = failed; string doesn't happen since that's for unix domain // sockets, which we aren't using. // This is probably impossible, but it makes typescript happier. throw Error("failed to assign a port"); } const { port } = address; winston.info(`hub tcp_server listening ${options.hostname}:${port}`); await callback(writeFile, hubPortFile, `${port}`); } async function handleConnection(socket) { winston.info(`*new* connection from ${socket.remoteAddress}`); socket.on("error", (err) => { winston.error(`socket '${socket.remoteAddress}' error - ${err}`); }); socket.on("close", () => { winston.info(`*closed* connection from ${socket.remoteAddress}`); }); try { await callback(unlock_socket, socket, secretToken); } catch (err) { winston.error( "failed to unlock socket -- ignoring any future messages and closing connection" ); socket.destroy("invalid secret token"); return; } socket.id = uuid.v4(); socket.heartbeat = new Date(); // obviously working now enableMessagingProtocol(socket); socket.on("mesg", (type, mesg) => { client.client?.active_socket(socket); // record that this socket is active now. if (type === "json") { // non-JSON types are handled elsewhere, e.g., for sending binary data. // I'm not sure that any other message types are actually used though. // winston.debug("received json mesg", mesg); handleMessage(socket, mesg); } }); }