@cocalc/project
Version:
CoCalc: project daemon
130 lines (113 loc) • 4.15 kB
text/typescript
/*
Handle a general message from the hub. These are the generic message,
as opposed to the messages specific to "client" functionality such as
database queries.
*/
import { getLogger } from "@cocalc/project/logger";
import { Message } from "./types";
import * as message from "@cocalc/util/message";
import handleNamedServer from "@cocalc/project/named-servers";
const { exec_shell_code } = require("@cocalc/project/exec_shell_code");
// Reading and writing files to/from project and sending over socket
const {
read_file_from_project,
write_file_to_project,
} = require("@cocalc/project/read_write_files");
const { print_to_pdf } = require("@cocalc/project/print_to_pdf");
import processKill from "@cocalc/backend/misc/process-kill";
const { handle_save_blob_message } = require("@cocalc/project/blobs");
const client = require("@cocalc/project/client");
import { version } from "@cocalc/util/smc-version";
import writeTextFileToProject from "./write-text-file-to-project";
const winston = getLogger("handle-message-from-hub");
export default function handleMessage(socket, mesg: Message) {
winston.debug("received a message", {
event: mesg.event,
id: mesg.id,
"...": "...",
});
// We can't just log this in general, since it can be big.
// So only uncomment this for low level debugging, unfortunately.
// winston.debug("received ", mesg);
if (client.client?.handle_mesg(mesg, socket)) {
return;
}
switch (mesg.event) {
case "heartbeat":
winston.debug(`received heartbeat on socket '${socket.id}'`);
// Update the last hearbeat timestamp, so we know socket is working.
socket.heartbeat = new Date();
return;
case "ping":
// ping message is used only for debugging purposes.
socket.write_mesg("json", message.pong({ id: mesg.id }));
return;
case "named_server_port":
handleNamedServer(socket, mesg);
return;
case "project_exec":
// this is no longer used by web browser clients; however it *is* used by the HTTP api served
// by the hub to api key users, so do NOT remove it!
// The web browser clients use the websocket api,
exec_shell_code(socket, mesg);
return;
case "read_file_from_project":
read_file_from_project(socket, mesg);
return;
case "write_file_to_project":
write_file_to_project(socket, mesg);
return;
case "write_text_file_to_project":
writeTextFileToProject(socket, mesg);
return;
case "print_to_pdf":
print_to_pdf(socket, mesg);
return;
case "send_signal":
if (
mesg.pid &&
(mesg.signal == 2 || mesg.signal == 3 || mesg.signal == 9)
) {
processKill(mesg.pid, mesg.signal);
} else {
if (mesg.id) {
socket.write_mesg(
"json",
message.error({
id: mesg.id,
error: "invalid pid or signal (must be 2,3,9)",
})
);
}
return;
}
if (mesg.id != null) {
// send back confirmation that a signal was sent
socket.write_mesg("json", message.signal_sent({ id: mesg.id }));
}
return;
case "save_blob":
handle_save_blob_message(mesg);
return;
case "error":
winston.error(`ERROR from hub: ${mesg.error}`);
return;
case "hello":
// No action -- this is used by the hub to send an initial control message that has no effect, so that
// we know this socket will be used for control messages.
winston.info(`hello from hub -- sending back our version = ${version}`);
socket.write_mesg("json", message.version({ version }));
return;
default:
if (mesg.id != null) {
// only respond with error if there is an id -- otherwise response has no meaning to hub.
const err = message.error({
id: mesg.id,
error: `Project does not implement handling mesg with event='${mesg.event}'`,
});
socket.write_mesg("json", err);
} else {
winston.debug(`Dropping unknown message with event='${mesg.event}'`);
}
}
}