@nocobase/server 1.5.0-beta.8 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/application.d.ts +2 -0
- package/lib/application.js +2 -0
- package/lib/gateway/index.js +43 -24
- package/lib/gateway/ws-server.d.ts +18 -2
- package/lib/gateway/ws-server.js +105 -27
- package/lib/middlewares/data-template.js +2 -2
- package/lib/plugin-manager/plugin-manager.d.ts +4 -4
- package/lib/plugin-manager/plugin-manager.js +27 -15
- package/lib/service-container.d.ts +5 -0
- package/lib/service-container.js +50 -0
- package/package.json +15 -15
package/lib/application.d.ts
CHANGED
|
@@ -31,6 +31,7 @@ import { Plugin } from './plugin';
|
|
|
31
31
|
import { InstallOptions, PluginManager } from './plugin-manager';
|
|
32
32
|
import { PubSubManager, PubSubManagerOptions } from './pub-sub-manager';
|
|
33
33
|
import { SyncMessageManager } from './sync-message-manager';
|
|
34
|
+
import { ServiceContainer } from './service-container';
|
|
34
35
|
import { AuditManager } from './audit-manager';
|
|
35
36
|
export type PluginType = string | typeof Plugin;
|
|
36
37
|
export type PluginConfiguration = PluginType | [PluginType, any];
|
|
@@ -169,6 +170,7 @@ export declare class Application<StateT = DefaultState, ContextT = DefaultContex
|
|
|
169
170
|
private _maintainingCommandStatus;
|
|
170
171
|
private _maintainingStatusBeforeCommand;
|
|
171
172
|
private _actionCommand;
|
|
173
|
+
container: ServiceContainer;
|
|
172
174
|
lockManager: LockManager;
|
|
173
175
|
constructor(options: ApplicationOptions);
|
|
174
176
|
private static staticCommands;
|
package/lib/application.js
CHANGED
|
@@ -76,6 +76,7 @@ var import_plugin_manager = require("./plugin-manager");
|
|
|
76
76
|
var import_pub_sub_manager = require("./pub-sub-manager");
|
|
77
77
|
var import_sync_message_manager = require("./sync-message-manager");
|
|
78
78
|
var import_package = __toESM(require("../package.json"));
|
|
79
|
+
var import_service_container = require("./service-container");
|
|
79
80
|
var import_available_action = require("./acl/available-action");
|
|
80
81
|
var import_audit_manager = require("./audit-manager");
|
|
81
82
|
const _Application = class _Application extends import_koa.default {
|
|
@@ -126,6 +127,7 @@ const _Application = class _Application extends import_koa.default {
|
|
|
126
127
|
_maintainingCommandStatus;
|
|
127
128
|
_maintainingStatusBeforeCommand;
|
|
128
129
|
_actionCommand;
|
|
130
|
+
container = new import_service_container.ServiceContainer();
|
|
129
131
|
lockManager;
|
|
130
132
|
static addCommand(callback) {
|
|
131
133
|
this.staticCommands.push(callback);
|
package/lib/gateway/index.js
CHANGED
|
@@ -63,7 +63,17 @@ var import_errors = require("./errors");
|
|
|
63
63
|
var import_ipc_socket_client = require("./ipc-socket-client");
|
|
64
64
|
var import_ipc_socket_server = require("./ipc-socket-server");
|
|
65
65
|
var import_ws_server = require("./ws-server");
|
|
66
|
+
var import_node_worker_threads = require("node:worker_threads");
|
|
67
|
+
var import_node_process = __toESM(require("node:process"));
|
|
66
68
|
const compress = (0, import_node_util.promisify)((0, import_compression.default)());
|
|
69
|
+
function getSocketPath() {
|
|
70
|
+
const { SOCKET_PATH } = import_node_process.default.env;
|
|
71
|
+
if ((0, import_path.isAbsolute)(SOCKET_PATH)) {
|
|
72
|
+
return SOCKET_PATH;
|
|
73
|
+
}
|
|
74
|
+
return (0, import_path.resolve)(import_node_process.default.cwd(), SOCKET_PATH);
|
|
75
|
+
}
|
|
76
|
+
__name(getSocketPath, "getSocketPath");
|
|
67
77
|
const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
68
78
|
/**
|
|
69
79
|
* use main app as default app to handle request
|
|
@@ -72,16 +82,14 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
|
72
82
|
server = null;
|
|
73
83
|
ipcSocketServer = null;
|
|
74
84
|
loggers = new import_utils.Registry();
|
|
75
|
-
port =
|
|
85
|
+
port = import_node_process.default.env.APP_PORT ? parseInt(import_node_process.default.env.APP_PORT) : null;
|
|
76
86
|
host = "0.0.0.0";
|
|
77
87
|
wsServer;
|
|
78
|
-
socketPath = (0, import_path.resolve)(
|
|
88
|
+
socketPath = (0, import_path.resolve)(import_node_process.default.cwd(), "storage", "gateway.sock");
|
|
79
89
|
constructor() {
|
|
80
90
|
super();
|
|
81
91
|
this.reset();
|
|
82
|
-
|
|
83
|
-
this.socketPath = (0, import_path.resolve)(process.cwd(), process.env.SOCKET_PATH);
|
|
84
|
-
}
|
|
92
|
+
this.socketPath = getSocketPath();
|
|
85
93
|
}
|
|
86
94
|
static getInstance(options = {}) {
|
|
87
95
|
if (!_Gateway.instance) {
|
|
@@ -90,7 +98,7 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
|
90
98
|
return _Gateway.instance;
|
|
91
99
|
}
|
|
92
100
|
static async getIPCSocketClient() {
|
|
93
|
-
const socketPath = (
|
|
101
|
+
const socketPath = getSocketPath();
|
|
94
102
|
try {
|
|
95
103
|
return await import_ipc_socket_client.IPCSocketClient.getConnection(socketPath);
|
|
96
104
|
} catch (error) {
|
|
@@ -166,7 +174,7 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
|
166
174
|
}
|
|
167
175
|
async requestHandler(req, res) {
|
|
168
176
|
const { pathname } = (0, import_url.parse)(req.url);
|
|
169
|
-
const { PLUGIN_STATICS_PATH, APP_PUBLIC_PATH } =
|
|
177
|
+
const { PLUGIN_STATICS_PATH, APP_PUBLIC_PATH } = import_node_process.default.env;
|
|
170
178
|
if (pathname.endsWith("/__umi/api/bundle-status")) {
|
|
171
179
|
res.statusCode = 200;
|
|
172
180
|
res.end("ok");
|
|
@@ -176,7 +184,7 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
|
176
184
|
req.url = req.url.substring(APP_PUBLIC_PATH.length - 1);
|
|
177
185
|
await compress(req, res);
|
|
178
186
|
return (0, import_serve_handler.default)(req, res, {
|
|
179
|
-
public: (0, import_path.resolve)(
|
|
187
|
+
public: (0, import_path.resolve)(import_node_process.default.cwd()),
|
|
180
188
|
directoryListing: false
|
|
181
189
|
});
|
|
182
190
|
}
|
|
@@ -195,15 +203,22 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
|
195
203
|
]
|
|
196
204
|
});
|
|
197
205
|
}
|
|
198
|
-
if (!pathname.startsWith(
|
|
206
|
+
if (!pathname.startsWith(import_node_process.default.env.API_BASE_PATH)) {
|
|
199
207
|
req.url = req.url.substring(APP_PUBLIC_PATH.length - 1);
|
|
200
208
|
await compress(req, res);
|
|
201
209
|
return (0, import_serve_handler.default)(req, res, {
|
|
202
|
-
public: `${
|
|
210
|
+
public: `${import_node_process.default.env.APP_PACKAGE_ROOT}/dist/client`,
|
|
203
211
|
rewrites: [{ source: "/**", destination: "/index.html" }]
|
|
204
212
|
});
|
|
205
213
|
}
|
|
206
|
-
|
|
214
|
+
let handleApp = "main";
|
|
215
|
+
try {
|
|
216
|
+
handleApp = await this.getRequestHandleAppName(req);
|
|
217
|
+
} catch (error) {
|
|
218
|
+
console.log(error);
|
|
219
|
+
this.responseErrorWithCode("APP_INITIALIZING", res, { appName: handleApp });
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
207
222
|
const hasApp = import_app_supervisor.AppSupervisor.getInstance().hasApp(handleApp);
|
|
208
223
|
if (!hasApp) {
|
|
209
224
|
void import_app_supervisor.AppSupervisor.getInstance().bootStrapApp(handleApp);
|
|
@@ -257,10 +272,10 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
|
257
272
|
}
|
|
258
273
|
/* istanbul ignore next -- @preserve */
|
|
259
274
|
async watch() {
|
|
260
|
-
if (!
|
|
275
|
+
if (!import_node_process.default.env.IS_DEV_CMD) {
|
|
261
276
|
return;
|
|
262
277
|
}
|
|
263
|
-
const file =
|
|
278
|
+
const file = import_node_process.default.env.WATCH_FILE;
|
|
264
279
|
if (!import_fs.default.existsSync(file)) {
|
|
265
280
|
await import_fs.default.promises.writeFile(file, `export const watchId = '${(0, import_utils.uid)()}';`, "utf-8");
|
|
266
281
|
}
|
|
@@ -273,8 +288,8 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
|
273
288
|
if (isStart) {
|
|
274
289
|
await this.watch();
|
|
275
290
|
const startOptions = this.getStartOptions();
|
|
276
|
-
const port = startOptions.port ||
|
|
277
|
-
const host = startOptions.host ||
|
|
291
|
+
const port = startOptions.port || import_node_process.default.env.APP_PORT || 13e3;
|
|
292
|
+
const host = startOptions.host || import_node_process.default.env.APP_HOST || "0.0.0.0";
|
|
278
293
|
this.start({
|
|
279
294
|
port,
|
|
280
295
|
host
|
|
@@ -282,7 +297,7 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
|
282
297
|
} else if (!this.isHelp()) {
|
|
283
298
|
ipcClient = await this.tryConnectToIPCServer();
|
|
284
299
|
if (ipcClient) {
|
|
285
|
-
const response = await ipcClient.write({ type: "passCliArgv", payload: { argv:
|
|
300
|
+
const response = await ipcClient.write({ type: "passCliArgv", payload: { argv: import_node_process.default.argv } });
|
|
286
301
|
ipcClient.close();
|
|
287
302
|
if (!["error", "not_found"].includes(response.type)) {
|
|
288
303
|
return;
|
|
@@ -293,15 +308,19 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
|
293
308
|
await (0, import_plugin_symlink.createStoragePluginsSymlink)();
|
|
294
309
|
}
|
|
295
310
|
const mainApp = import_app_supervisor.AppSupervisor.getInstance().bootMainApp(options.mainAppOptions);
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
from: "
|
|
299
|
-
}
|
|
311
|
+
let runArgs = [import_node_process.default.argv, { throwError: true, from: "node" }];
|
|
312
|
+
if (!import_node_worker_threads.isMainThread) {
|
|
313
|
+
runArgs = [import_node_worker_threads.workerData.argv, { throwError: true, from: "user" }];
|
|
314
|
+
}
|
|
315
|
+
mainApp.runAsCLI(...runArgs).then(async () => {
|
|
300
316
|
if (!isStart && !await mainApp.isStarted()) {
|
|
301
317
|
await mainApp.stop({ logging: false });
|
|
302
318
|
}
|
|
303
319
|
}).catch(async (e) => {
|
|
304
320
|
if (e.code !== "commander.helpDisplayed") {
|
|
321
|
+
if (!import_node_worker_threads.isMainThread) {
|
|
322
|
+
throw e;
|
|
323
|
+
}
|
|
305
324
|
mainApp.log.error(e);
|
|
306
325
|
}
|
|
307
326
|
if (!isStart && !await mainApp.isStarted()) {
|
|
@@ -310,16 +329,16 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
|
310
329
|
});
|
|
311
330
|
}
|
|
312
331
|
isStart() {
|
|
313
|
-
const argv =
|
|
332
|
+
const argv = import_node_process.default.argv;
|
|
314
333
|
return argv[2] === "start";
|
|
315
334
|
}
|
|
316
335
|
isHelp() {
|
|
317
|
-
const argv =
|
|
336
|
+
const argv = import_node_process.default.argv;
|
|
318
337
|
return argv[2] === "help";
|
|
319
338
|
}
|
|
320
339
|
getStartOptions() {
|
|
321
340
|
const program = new import_commander.Command();
|
|
322
|
-
program.allowUnknownOption().option("-s, --silent").option("-p, --port [post]").option("-h, --host [host]").option("--db-sync").parse(
|
|
341
|
+
program.allowUnknownOption().option("-s, --silent").option("-p, --port [post]").option("-h, --host [host]").option("--db-sync").parse(import_node_process.default.argv);
|
|
323
342
|
return program.opts();
|
|
324
343
|
}
|
|
325
344
|
start(options) {
|
|
@@ -344,7 +363,7 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
|
344
363
|
this.wsServer = new import_ws_server.WSServer();
|
|
345
364
|
this.server.on("upgrade", (request, socket, head) => {
|
|
346
365
|
const { pathname } = (0, import_url.parse)(request.url);
|
|
347
|
-
if (pathname ===
|
|
366
|
+
if (pathname === import_node_process.default.env.WS_PATH) {
|
|
348
367
|
this.wsServer.wss.handleUpgrade(request, socket, head, (ws) => {
|
|
349
368
|
this.wsServer.wss.emit("connection", ws, request);
|
|
350
369
|
});
|
|
@@ -7,29 +7,45 @@
|
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
9
|
/// <reference types="node" />
|
|
10
|
+
/// <reference types="node" />
|
|
10
11
|
import WebSocket from 'ws';
|
|
11
12
|
import { IncomingMessage } from 'http';
|
|
12
13
|
import { Logger } from '@nocobase/logger';
|
|
14
|
+
import EventEmitter from 'events';
|
|
13
15
|
declare class WebSocketWithId extends WebSocket {
|
|
14
16
|
id: string;
|
|
15
17
|
}
|
|
16
18
|
interface WebSocketClient {
|
|
17
19
|
ws: WebSocketWithId;
|
|
18
|
-
tags: string
|
|
20
|
+
tags: Set<string>;
|
|
19
21
|
url: string;
|
|
20
22
|
headers: any;
|
|
21
23
|
app?: string;
|
|
24
|
+
id: string;
|
|
22
25
|
}
|
|
23
|
-
export declare class WSServer {
|
|
26
|
+
export declare class WSServer extends EventEmitter {
|
|
24
27
|
wss: WebSocket.Server;
|
|
25
28
|
webSocketClients: Map<string, WebSocketClient>;
|
|
26
29
|
logger: Logger;
|
|
27
30
|
constructor();
|
|
31
|
+
bindAppWSEvents(app: any): void;
|
|
28
32
|
addNewConnection(ws: WebSocketWithId, request: IncomingMessage): WebSocketClient;
|
|
33
|
+
setClientTag(clientId: string, tagKey: string, tagValue: string): void;
|
|
34
|
+
removeClientTag(clientId: string, tagKey: string): void;
|
|
29
35
|
setClientApp(client: WebSocketClient): Promise<void>;
|
|
30
36
|
removeConnection(id: string): void;
|
|
31
37
|
sendMessageToConnection(client: WebSocketClient, sendMessage: object): void;
|
|
32
38
|
sendToConnectionsByTag(tagName: string, tagValue: string, sendMessage: object): void;
|
|
39
|
+
/**
|
|
40
|
+
* Send message to clients that match all the given tag conditions
|
|
41
|
+
* @param tags Array of tag conditions, each condition is an object with tagName and tagValue
|
|
42
|
+
* @param sendMessage Message to be sent
|
|
43
|
+
*/
|
|
44
|
+
sendToConnectionsByTags(tags: Array<{
|
|
45
|
+
tagName: string;
|
|
46
|
+
tagValue: string;
|
|
47
|
+
}>, sendMessage: object): void;
|
|
48
|
+
sendToClient(clientId: string, sendMessage: object): void;
|
|
33
49
|
loopThroughConnections(callback: (client: WebSocketClient) => void): void;
|
|
34
50
|
close(): void;
|
|
35
51
|
}
|
package/lib/gateway/ws-server.js
CHANGED
|
@@ -46,16 +46,18 @@ var import_nanoid = require("nanoid");
|
|
|
46
46
|
var import_app_supervisor = require("../app-supervisor");
|
|
47
47
|
var import_errors = require("./errors");
|
|
48
48
|
var import_lodash = __toESM(require("lodash"));
|
|
49
|
+
var import_events = __toESM(require("events"));
|
|
49
50
|
function getPayloadByErrorCode(code, options) {
|
|
50
51
|
const error = (0, import_errors.getErrorWithCode)(code);
|
|
51
52
|
return import_lodash.default.omit((0, import_errors.applyErrorWithArgs)(error, options), ["status", "maintaining"]);
|
|
52
53
|
}
|
|
53
54
|
__name(getPayloadByErrorCode, "getPayloadByErrorCode");
|
|
54
|
-
const _WSServer = class _WSServer {
|
|
55
|
+
const _WSServer = class _WSServer extends import_events.default {
|
|
55
56
|
wss;
|
|
56
57
|
webSocketClients = /* @__PURE__ */ new Map();
|
|
57
58
|
logger;
|
|
58
59
|
constructor() {
|
|
60
|
+
super();
|
|
59
61
|
this.wss = new import_ws.WebSocketServer({ noServer: true });
|
|
60
62
|
this.wss.on("connection", (ws, request) => {
|
|
61
63
|
const client = this.addNewConnection(ws, request);
|
|
@@ -66,6 +68,15 @@ const _WSServer = class _WSServer {
|
|
|
66
68
|
ws.on("close", () => {
|
|
67
69
|
this.removeConnection(ws.id);
|
|
68
70
|
});
|
|
71
|
+
ws.on("message", (message) => {
|
|
72
|
+
if (message.toString() === "ping") {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
this.emit("message", {
|
|
76
|
+
client,
|
|
77
|
+
message
|
|
78
|
+
});
|
|
79
|
+
});
|
|
69
80
|
});
|
|
70
81
|
import_gateway.Gateway.getInstance().on("appSelectorChanged", () => {
|
|
71
82
|
this.loopThroughConnections(async (client) => {
|
|
@@ -73,8 +84,12 @@ const _WSServer = class _WSServer {
|
|
|
73
84
|
url: client.url,
|
|
74
85
|
headers: client.headers
|
|
75
86
|
});
|
|
76
|
-
|
|
77
|
-
|
|
87
|
+
for (const tag of client.tags) {
|
|
88
|
+
if (tag.startsWith("app#")) {
|
|
89
|
+
client.tags.delete(tag);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
client.tags.add(`app#${handleAppName}`);
|
|
78
93
|
import_app_supervisor.AppSupervisor.getInstance().bootStrapApp(handleAppName);
|
|
79
94
|
});
|
|
80
95
|
});
|
|
@@ -118,19 +133,87 @@ const _WSServer = class _WSServer {
|
|
|
118
133
|
}
|
|
119
134
|
});
|
|
120
135
|
});
|
|
136
|
+
import_app_supervisor.AppSupervisor.getInstance().on("afterAppAdded", (app) => {
|
|
137
|
+
this.bindAppWSEvents(app);
|
|
138
|
+
});
|
|
139
|
+
this.on("message", async ({ client, message }) => {
|
|
140
|
+
const app = await import_app_supervisor.AppSupervisor.getInstance().getApp(client.app);
|
|
141
|
+
if (!app) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const parsedMessage = JSON.parse(message.toString());
|
|
145
|
+
if (!parsedMessage.type) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
const eventName = `ws:message:${parsedMessage.type}`;
|
|
149
|
+
app.emit(eventName, {
|
|
150
|
+
clientId: client.id,
|
|
151
|
+
tags: [...client.tags],
|
|
152
|
+
payload: parsedMessage.payload
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
bindAppWSEvents(app) {
|
|
157
|
+
if (app.listenerCount("ws:setTag") > 0) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
app.on("ws:setTag", ({ clientId, tagKey, tagValue }) => {
|
|
161
|
+
this.setClientTag(clientId, tagKey, tagValue);
|
|
162
|
+
});
|
|
163
|
+
app.on("ws:removeTag", ({ clientId, tagKey }) => {
|
|
164
|
+
this.removeClientTag(clientId, tagKey);
|
|
165
|
+
});
|
|
166
|
+
app.on("ws:sendToTag", ({ tagKey, tagValue, message }) => {
|
|
167
|
+
this.sendToConnectionsByTags(
|
|
168
|
+
[
|
|
169
|
+
{ tagName: tagKey, tagValue },
|
|
170
|
+
{ tagName: "app", tagValue: app.name }
|
|
171
|
+
],
|
|
172
|
+
message
|
|
173
|
+
);
|
|
174
|
+
});
|
|
175
|
+
app.on("ws:sendToClient", ({ clientId, message }) => {
|
|
176
|
+
this.sendToClient(clientId, message);
|
|
177
|
+
});
|
|
178
|
+
app.on("ws:sendToCurrentApp", ({ message }) => {
|
|
179
|
+
this.sendToConnectionsByTag("app", app.name, message);
|
|
180
|
+
});
|
|
181
|
+
app.on("ws:sendToTags", ({ tags, message }) => {
|
|
182
|
+
this.sendToConnectionsByTags(tags, message);
|
|
183
|
+
});
|
|
184
|
+
app.on("ws:authorized", ({ clientId, userId }) => {
|
|
185
|
+
this.sendToClient(clientId, { type: "authorized" });
|
|
186
|
+
});
|
|
121
187
|
}
|
|
122
188
|
addNewConnection(ws, request) {
|
|
123
189
|
const id = (0, import_nanoid.nanoid)();
|
|
124
190
|
ws.id = id;
|
|
125
191
|
this.webSocketClients.set(id, {
|
|
126
192
|
ws,
|
|
127
|
-
tags:
|
|
193
|
+
tags: /* @__PURE__ */ new Set(),
|
|
128
194
|
url: request.url,
|
|
129
|
-
headers: request.headers
|
|
195
|
+
headers: request.headers,
|
|
196
|
+
id
|
|
130
197
|
});
|
|
131
198
|
this.setClientApp(this.webSocketClients.get(id));
|
|
132
199
|
return this.webSocketClients.get(id);
|
|
133
200
|
}
|
|
201
|
+
setClientTag(clientId, tagKey, tagValue) {
|
|
202
|
+
const client = this.webSocketClients.get(clientId);
|
|
203
|
+
if (!client) {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
client.tags.add(`${tagKey}#${tagValue}`);
|
|
207
|
+
console.log(`client tags: ${Array.from(client.tags)}`);
|
|
208
|
+
}
|
|
209
|
+
removeClientTag(clientId, tagKey) {
|
|
210
|
+
const client = this.webSocketClients.get(clientId);
|
|
211
|
+
client.tags.forEach((tag) => {
|
|
212
|
+
if (tag.startsWith(tagKey)) {
|
|
213
|
+
client.tags.delete(tag);
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
}
|
|
134
217
|
async setClientApp(client) {
|
|
135
218
|
const req = {
|
|
136
219
|
url: client.url,
|
|
@@ -139,31 +222,11 @@ const _WSServer = class _WSServer {
|
|
|
139
222
|
const handleAppName = await import_gateway.Gateway.getInstance().getRequestHandleAppName(req);
|
|
140
223
|
client.app = handleAppName;
|
|
141
224
|
console.log(`client tags: app#${handleAppName}`);
|
|
142
|
-
client.tags.
|
|
225
|
+
client.tags.add(`app#${handleAppName}`);
|
|
143
226
|
const hasApp = import_app_supervisor.AppSupervisor.getInstance().hasApp(handleAppName);
|
|
144
227
|
if (!hasApp) {
|
|
145
228
|
import_app_supervisor.AppSupervisor.getInstance().bootStrapApp(handleAppName);
|
|
146
229
|
}
|
|
147
|
-
const appStatus = import_app_supervisor.AppSupervisor.getInstance().getAppStatus(handleAppName, "initializing");
|
|
148
|
-
if (appStatus === "not_found") {
|
|
149
|
-
this.sendMessageToConnection(client, {
|
|
150
|
-
type: "maintaining",
|
|
151
|
-
payload: getPayloadByErrorCode("APP_NOT_FOUND", { appName: handleAppName })
|
|
152
|
-
});
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
155
|
-
if (appStatus === "initializing") {
|
|
156
|
-
this.sendMessageToConnection(client, {
|
|
157
|
-
type: "maintaining",
|
|
158
|
-
payload: getPayloadByErrorCode("APP_INITIALIZING", { appName: handleAppName })
|
|
159
|
-
});
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
const app = await import_app_supervisor.AppSupervisor.getInstance().getApp(handleAppName);
|
|
163
|
-
this.sendMessageToConnection(client, {
|
|
164
|
-
type: "maintaining",
|
|
165
|
-
payload: getPayloadByErrorCode(appStatus, { app })
|
|
166
|
-
});
|
|
167
230
|
}
|
|
168
231
|
removeConnection(id) {
|
|
169
232
|
console.log(`client disconnected ${id}`);
|
|
@@ -173,12 +236,27 @@ const _WSServer = class _WSServer {
|
|
|
173
236
|
client.ws.send(JSON.stringify(sendMessage));
|
|
174
237
|
}
|
|
175
238
|
sendToConnectionsByTag(tagName, tagValue, sendMessage) {
|
|
239
|
+
this.sendToConnectionsByTags([{ tagName, tagValue }], sendMessage);
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Send message to clients that match all the given tag conditions
|
|
243
|
+
* @param tags Array of tag conditions, each condition is an object with tagName and tagValue
|
|
244
|
+
* @param sendMessage Message to be sent
|
|
245
|
+
*/
|
|
246
|
+
sendToConnectionsByTags(tags, sendMessage) {
|
|
176
247
|
this.loopThroughConnections((client) => {
|
|
177
|
-
|
|
248
|
+
const allTagsMatch = tags.every(({ tagName, tagValue }) => client.tags.has(`${tagName}#${tagValue}`));
|
|
249
|
+
if (allTagsMatch) {
|
|
178
250
|
this.sendMessageToConnection(client, sendMessage);
|
|
179
251
|
}
|
|
180
252
|
});
|
|
181
253
|
}
|
|
254
|
+
sendToClient(clientId, sendMessage) {
|
|
255
|
+
const client = this.webSocketClients.get(clientId);
|
|
256
|
+
if (client) {
|
|
257
|
+
this.sendMessageToConnection(client, sendMessage);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
182
260
|
loopThroughConnections(callback) {
|
|
183
261
|
this.webSocketClients.forEach((client) => {
|
|
184
262
|
callback(client);
|
|
@@ -36,7 +36,7 @@ async function dataTemplate(ctx, next) {
|
|
|
36
36
|
await next();
|
|
37
37
|
if (isTemplate && actionName === "get") {
|
|
38
38
|
ctx.body = traverseJSON(JSON.parse(JSON.stringify(ctx.body)), {
|
|
39
|
-
collection: ctx.
|
|
39
|
+
collection: ctx.getCurrentRepository().collection,
|
|
40
40
|
include: [...fields || [], ...appends || []]
|
|
41
41
|
});
|
|
42
42
|
}
|
|
@@ -101,7 +101,7 @@ const traverseJSON = /* @__PURE__ */ __name((data, options) => {
|
|
|
101
101
|
result[key] = data[key];
|
|
102
102
|
continue;
|
|
103
103
|
}
|
|
104
|
-
if (field.options.primaryKey && excludePk) {
|
|
104
|
+
if (field.options.primaryKey && excludePk && !collection.isMultiFilterTargetKey()) {
|
|
105
105
|
continue;
|
|
106
106
|
}
|
|
107
107
|
if (field.options.isForeignKey) {
|
|
@@ -67,7 +67,7 @@ export declare class PluginManager {
|
|
|
67
67
|
/**
|
|
68
68
|
* @internal
|
|
69
69
|
*/
|
|
70
|
-
static getPackageName(name: string): Promise<
|
|
70
|
+
static getPackageName(name: string): Promise<any>;
|
|
71
71
|
/**
|
|
72
72
|
* @internal
|
|
73
73
|
*/
|
|
@@ -75,7 +75,7 @@ export declare class PluginManager {
|
|
|
75
75
|
/**
|
|
76
76
|
* @internal
|
|
77
77
|
*/
|
|
78
|
-
static findPackage(name: string): Promise<
|
|
78
|
+
static findPackage(name: string): Promise<any>;
|
|
79
79
|
/**
|
|
80
80
|
* @internal
|
|
81
81
|
*/
|
|
@@ -89,9 +89,9 @@ export declare class PluginManager {
|
|
|
89
89
|
addPreset(plugin: string | typeof Plugin, options?: any): void;
|
|
90
90
|
getPlugins(): Map<typeof Plugin, Plugin<any>>;
|
|
91
91
|
getAliases(): IterableIterator<string>;
|
|
92
|
-
get(name: string | typeof Plugin):
|
|
92
|
+
get<T extends Plugin>(name: string | typeof Plugin | (new () => T)): T;
|
|
93
93
|
has(name: string | typeof Plugin): boolean;
|
|
94
|
-
del(name:
|
|
94
|
+
del(name: any): void;
|
|
95
95
|
create(pluginName: string, options?: {
|
|
96
96
|
forceRecreate?: boolean;
|
|
97
97
|
}): Promise<void>;
|
|
@@ -139,15 +139,12 @@ const _PluginManager = class _PluginManager {
|
|
|
139
139
|
* @internal
|
|
140
140
|
*/
|
|
141
141
|
static async getPackageName(name) {
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
if (exists) {
|
|
147
|
-
return `${prefix}${name}`;
|
|
148
|
-
}
|
|
142
|
+
const { packageName } = await this.parseName(name);
|
|
143
|
+
const packageFile = (0, import_path.resolve)(process.env.NODE_MODULES_PATH, packageName, "package.json");
|
|
144
|
+
if (!await import_fs_extra.default.exists(packageFile)) {
|
|
145
|
+
return null;
|
|
149
146
|
}
|
|
150
|
-
|
|
147
|
+
return packageName;
|
|
151
148
|
}
|
|
152
149
|
/**
|
|
153
150
|
* @internal
|
|
@@ -312,7 +309,9 @@ const _PluginManager = class _PluginManager {
|
|
|
312
309
|
try {
|
|
313
310
|
if (typeof plugin === "string" && options.name && !options.packageName) {
|
|
314
311
|
const packageName = await _PluginManager.getPackageName(options.name);
|
|
315
|
-
|
|
312
|
+
if (packageName) {
|
|
313
|
+
options["packageName"] = packageName;
|
|
314
|
+
}
|
|
316
315
|
}
|
|
317
316
|
if (options.packageName) {
|
|
318
317
|
const packageJson = await _PluginManager.getPackageJson(options.packageName);
|
|
@@ -320,12 +319,14 @@ const _PluginManager = class _PluginManager {
|
|
|
320
319
|
options["version"] = packageJson.version;
|
|
321
320
|
}
|
|
322
321
|
} catch (error) {
|
|
322
|
+
this.app.log.error(error);
|
|
323
323
|
console.error(error);
|
|
324
324
|
}
|
|
325
|
-
this.app.log.trace(`
|
|
325
|
+
this.app.log.trace(`adding plugin [${options.name}]`, {
|
|
326
326
|
method: "add",
|
|
327
327
|
submodule: "plugin-manager",
|
|
328
|
-
name: options.name
|
|
328
|
+
name: options.name,
|
|
329
|
+
options
|
|
329
330
|
});
|
|
330
331
|
let P;
|
|
331
332
|
try {
|
|
@@ -343,6 +344,12 @@ const _PluginManager = class _PluginManager {
|
|
|
343
344
|
this.pluginAliases.set(options.packageName, instance);
|
|
344
345
|
}
|
|
345
346
|
await instance.afterAdd();
|
|
347
|
+
this.app.log.trace(`added plugin [${options.name}]`, {
|
|
348
|
+
method: "add",
|
|
349
|
+
submodule: "plugin-manager",
|
|
350
|
+
name: instance.name,
|
|
351
|
+
options: instance.options
|
|
352
|
+
});
|
|
346
353
|
}
|
|
347
354
|
/**
|
|
348
355
|
* @internal
|
|
@@ -364,15 +371,20 @@ const _PluginManager = class _PluginManager {
|
|
|
364
371
|
const packageNames = items.map((item) => item.packageName);
|
|
365
372
|
const source = [];
|
|
366
373
|
for (const packageName of packageNames) {
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
374
|
+
try {
|
|
375
|
+
const dirname = await (0, import_utils2.getPluginBasePath)(packageName);
|
|
376
|
+
const directory = (0, import_path.join)(dirname, "server/commands/*." + ((0, import_path.basename)(dirname) === "src" ? "{ts,js}" : "js"));
|
|
377
|
+
source.push(directory.replaceAll(import_path.sep, "/"));
|
|
378
|
+
} catch (error) {
|
|
379
|
+
this.app.log.error(error);
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
370
382
|
}
|
|
371
383
|
for (const plugin of this.options.plugins || []) {
|
|
372
384
|
if (typeof plugin === "string") {
|
|
373
385
|
const { packageName } = await _PluginManager.parseName(plugin);
|
|
374
386
|
const dirname = await (0, import_utils2.getPluginBasePath)(packageName);
|
|
375
|
-
const directory = (0, import_path.join)(dirname, "server/commands/*." + ((0, import_path.basename)(dirname) === "src" ? "ts" : "js"));
|
|
387
|
+
const directory = (0, import_path.join)(dirname, "server/commands/*." + ((0, import_path.basename)(dirname) === "src" ? "{ts,js}" : "js"));
|
|
376
388
|
source.push(directory.replaceAll(import_path.sep, "/"));
|
|
377
389
|
}
|
|
378
390
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
var __defProp = Object.defineProperty;
|
|
11
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
12
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
13
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
14
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
15
|
+
var __export = (target, all) => {
|
|
16
|
+
for (var name in all)
|
|
17
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
18
|
+
};
|
|
19
|
+
var __copyProps = (to, from, except, desc) => {
|
|
20
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
21
|
+
for (let key of __getOwnPropNames(from))
|
|
22
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
23
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
24
|
+
}
|
|
25
|
+
return to;
|
|
26
|
+
};
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
var service_container_exports = {};
|
|
29
|
+
__export(service_container_exports, {
|
|
30
|
+
ServiceContainer: () => ServiceContainer
|
|
31
|
+
});
|
|
32
|
+
module.exports = __toCommonJS(service_container_exports);
|
|
33
|
+
const _ServiceContainer = class _ServiceContainer {
|
|
34
|
+
services = /* @__PURE__ */ new Map();
|
|
35
|
+
register(name, service) {
|
|
36
|
+
if (typeof service === "function") {
|
|
37
|
+
service = service();
|
|
38
|
+
}
|
|
39
|
+
this.services.set(name, service);
|
|
40
|
+
}
|
|
41
|
+
get(name) {
|
|
42
|
+
return this.services.get(name);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
__name(_ServiceContainer, "ServiceContainer");
|
|
46
|
+
let ServiceContainer = _ServiceContainer;
|
|
47
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
48
|
+
0 && (module.exports = {
|
|
49
|
+
ServiceContainer
|
|
50
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nocobase/server",
|
|
3
|
-
"version": "1.5.0
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"main": "lib/index.js",
|
|
5
5
|
"types": "./lib/index.d.ts",
|
|
6
6
|
"license": "AGPL-3.0",
|
|
@@ -10,19 +10,19 @@
|
|
|
10
10
|
"@koa/cors": "^3.1.0",
|
|
11
11
|
"@koa/multer": "^3.0.2",
|
|
12
12
|
"@koa/router": "^9.4.0",
|
|
13
|
-
"@nocobase/acl": "1.5.0
|
|
14
|
-
"@nocobase/actions": "1.5.0
|
|
15
|
-
"@nocobase/auth": "1.5.0
|
|
16
|
-
"@nocobase/cache": "1.5.0
|
|
17
|
-
"@nocobase/data-source-manager": "1.5.0
|
|
18
|
-
"@nocobase/database": "1.5.0
|
|
19
|
-
"@nocobase/evaluators": "1.5.0
|
|
20
|
-
"@nocobase/lock-manager": "1.5.0
|
|
21
|
-
"@nocobase/logger": "1.5.0
|
|
22
|
-
"@nocobase/resourcer": "1.5.0
|
|
23
|
-
"@nocobase/sdk": "1.5.0
|
|
24
|
-
"@nocobase/telemetry": "1.5.0
|
|
25
|
-
"@nocobase/utils": "1.5.0
|
|
13
|
+
"@nocobase/acl": "1.5.0",
|
|
14
|
+
"@nocobase/actions": "1.5.0",
|
|
15
|
+
"@nocobase/auth": "1.5.0",
|
|
16
|
+
"@nocobase/cache": "1.5.0",
|
|
17
|
+
"@nocobase/data-source-manager": "1.5.0",
|
|
18
|
+
"@nocobase/database": "1.5.0",
|
|
19
|
+
"@nocobase/evaluators": "1.5.0",
|
|
20
|
+
"@nocobase/lock-manager": "1.5.0",
|
|
21
|
+
"@nocobase/logger": "1.5.0",
|
|
22
|
+
"@nocobase/resourcer": "1.5.0",
|
|
23
|
+
"@nocobase/sdk": "1.5.0",
|
|
24
|
+
"@nocobase/telemetry": "1.5.0",
|
|
25
|
+
"@nocobase/utils": "1.5.0",
|
|
26
26
|
"@types/decompress": "4.2.7",
|
|
27
27
|
"@types/ini": "^1.3.31",
|
|
28
28
|
"@types/koa-send": "^4.1.3",
|
|
@@ -56,5 +56,5 @@
|
|
|
56
56
|
"@types/serve-handler": "^6.1.1",
|
|
57
57
|
"@types/ws": "^8.5.5"
|
|
58
58
|
},
|
|
59
|
-
"gitHead": "
|
|
59
|
+
"gitHead": "1eae52e1fc837e9b1c6b63fc31bda7945b6101e9"
|
|
60
60
|
}
|