egg
Version:
A web application framework for Node.js
130 lines (129 loc) • 4.16 kB
JavaScript
import { BaseMessenger } from "./base.js";
import { debuglog } from "node:util";
import workerThreads from "node:worker_threads";
import { sendmessage } from "sendmessage";
//#region src/lib/core/messenger/ipc.ts
const debug = debuglog("egg/lib/core/messenger/ipc");
/**
* Communication between app worker and agent worker by IPC channel
*/
var Messenger = class extends BaseMessenger {
pid;
opids = [];
constructor(egg) {
super(egg);
this.pid = String(process.pid);
this.on("egg-pids", (workerIds) => {
debug("[%s:%s] got egg-pids %j", this.egg.type, this.pid, workerIds);
this.opids = workerIds.map((workerId) => String(workerId));
});
this.onMessage = this.onMessage.bind(this);
process.on("message", this.onMessage);
if (!workerThreads.isMainThread) workerThreads.parentPort.on("message", this.onMessage);
}
/**
* Send message to all agent and app
* @param {String} action - message key
* @param {Object} data - message value
* @return {Messenger} this
*/
broadcast(action, data) {
debug("[%s:%s] broadcast %s with %j", this.egg.type, this.pid, action, data);
this.send(action, data, "app");
this.send(action, data, "agent");
return this;
}
/**
* send message to the specified process
* @param {String} workerId - the workerId of the receiver
* @param {String} action - message key
* @param {Object} data - message value
* @return {Messenger} this
*/
sendTo(workerId, action, data) {
debug("[%s:%s] send %s with %j to workerId:%s", this.egg.type, this.pid, action, data, workerId);
const message = {
action,
data,
/**
* @deprecated Keep compatible, please use receiverWorkerId instead
*/
receiverPid: String(workerId),
receiverWorkerId: String(workerId)
};
this.#sendMessage(message);
return this;
}
/**
* send message to one app worker by random
* - if it's running in agent, it will send to one of app workers
* - if it's running in app, it will send to agent
* @param {String} action - message key
* @param {Object} data - message value
* @return {Messenger} this
*/
sendRandom(action, data) {
if (this.opids.length === 0) {
debug("[%s:%s] no pids, ignore sendRandom %s with %j", this.egg.type, this.pid, action, data);
return this;
}
const index = Math.floor(Math.random() * this.opids.length);
const workerId = this.opids[index];
this.sendTo(workerId, action, data);
return this;
}
/**
* send message to app
* @param {String} action - message key
* @param {Object} data - message value
* @return {Messenger} this
*/
sendToApp(action, data) {
debug("[%s:%s] send %s with %j to all app", this.egg.type, this.pid, action, data);
this.send(action, data, "app");
return this;
}
/**
* send message to agent
* @param {String} action - message key
* @param {Object} data - message value
* @return {Messenger} this
*/
sendToAgent(action, data) {
debug("[%s:%s] send %s with %j to all agent", this.egg.type, this.pid, action, data);
this.send(action, data, "agent");
return this;
}
/**
* @param {String} action - message key
* @param {Object} data - message value
* @param {String} to - let master know how to send message
* @return {Messenger} this
*/
send(action, data, to) {
debug("send message %s with %j to %s", action, data, to);
this.#sendMessage({
action,
data,
to
});
return this;
}
#sendMessage(message) {
debug("[%s:%s] send message %j, mode: %s", this.egg.type, this.pid, message, this.egg.options.mode);
sendmessage(process, message);
}
onMessage(message) {
if (typeof message?.action === "string") {
debug("[%s:%s] got message %s with %j, receiverWorkerId: %s", this.egg.type, this.pid, message.action, message.data, message.receiverWorkerId ?? message.receiverPid);
this.emit(message.action, message.data);
} else if (message?.type === "Buffer") debug("[%s:%s] got an invalid message: %s", this.egg.type, this.pid, Buffer.from(message.data));
else debug("[%s:%s] got an invalid message %j", this.egg.type, this.pid, message);
}
close() {
process.removeListener("message", this.onMessage);
this.removeAllListeners();
}
};
//#endregion
export { Messenger };