Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/src/packages/project/servers/hub/tcp-server.ts
Views: 687
/*1* This file is part of CoCalc: Copyright © 2023 Sagemath, Inc.2* License: MS-RSL – see LICENSE.md for details3*/45/* Create the TCP server that communicates with hubs */67import { writeFile } from "node:fs/promises";8import { createServer } from "node:net";9import * as uuid from "uuid";1011import enableMessagingProtocol, {12CoCalcSocket,13} from "@cocalc/backend/tcp/enable-messaging-protocol";14import { unlockSocket } from "@cocalc/backend/tcp/locked-socket";15import { hubPortFile } from "@cocalc/project/data";16import { getOptions } from "@cocalc/project/init-program";17import { getSecretToken } from "@cocalc/project/servers/secret-token";18import { once } from "@cocalc/util/async-utils";19import handleMessage from "./handle-message";20import { getClient } from "@cocalc/project/client";2122import { getLogger } from "@cocalc/project/logger";23const winston = getLogger("hub-tcp-server");2425export default async function init(): Promise<void> {26const secretToken = getSecretToken(); // could throw if not initialized yet27if (!secretToken || secretToken.length < 16) {28// being extra careful since security29throw Error("secret token must be defined and at least 16 characters");30return;31}3233winston.info("starting tcp server: project <--> hub...");34const server = createServer(handleConnection);35const options = getOptions();36server.listen(options.hubPort, options.hostname);37await once(server, "listening");38const address = server.address();39if (address == null || typeof address == "string") {40// null = failed; string doesn't happen since that's for unix domain41// sockets, which we aren't using.42// This is probably impossible, but it makes typescript happier.43throw Error("failed to assign a port");44}45const { port } = address;46winston.info(`hub tcp_server listening ${options.hostname}:${port}`);47await writeFile(hubPortFile, `${port}`);48}4950async function handleConnection(socket: CoCalcSocket) {51winston.info(`*new* connection from ${socket.remoteAddress}`);52socket.on("error", (err) => {53winston.error(`socket '${socket.remoteAddress}' error - ${err}`);54});55socket.on("close", () => {56winston.info(`*closed* connection from ${socket.remoteAddress}`);57});5859try {60await unlockSocket(socket, getSecretToken());61} catch (err) {62winston.error(63"failed to unlock socket -- ignoring any future messages and closing connection"64);65socket.destroy(new Error("invalid secret token"));66return;67}6869socket.id = uuid.v4();70socket.heartbeat = new Date(); // obviously working now71enableMessagingProtocol(socket);7273socket.on("mesg", (type, mesg) => {74getClient().active_socket(socket); // record that this socket is active now.75if (type === "json") {76// non-JSON types are handled elsewhere, e.g., for sending binary data.77// I'm not sure that any other message types are actually used though.78// winston.debug("received json mesg", mesg);79handleMessage(socket, mesg);80}81});82}838485