@nocobase/server 2.0.0-alpha.5 → 2.0.0-alpha.50
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/acl/available-action.js +1 -1
- package/lib/aes-encryptor.js +4 -0
- package/lib/app-command.d.ts +1 -0
- package/lib/app-command.js +3 -0
- package/lib/app-supervisor.d.ts +7 -2
- package/lib/app-supervisor.js +54 -15
- package/lib/application.d.ts +4 -6
- package/lib/application.js +19 -11
- package/lib/commands/pm.js +11 -0
- package/lib/commands/start.js +1 -1
- package/lib/event-queue.js +7 -3
- package/lib/gateway/errors.js +10 -5
- package/lib/gateway/index.d.ts +8 -0
- package/lib/gateway/index.js +26 -2
- package/lib/index.d.ts +1 -1
- package/lib/index.js +3 -3
- package/lib/locale/locale.js +1 -1
- package/lib/locale/resource.js +6 -9
- package/lib/main-data-source.d.ts +11 -0
- package/lib/main-data-source.js +128 -0
- package/lib/middlewares/data-template.js +1 -6
- package/lib/middlewares/parse-variables.js +4 -0
- package/lib/plugin-manager/options/resource.js +48 -25
- package/lib/plugin-manager/plugin-manager.d.ts +1 -0
- package/lib/plugin-manager/plugin-manager.js +36 -1
- package/lib/pub-sub-manager/pub-sub-manager.d.ts +1 -1
- package/lib/pub-sub-manager/pub-sub-manager.js +8 -8
- package/package.json +17 -16
- package/lib/background-job-manager.d.ts +0 -40
- package/lib/background-job-manager.js +0 -111
package/lib/aes-encryptor.js
CHANGED
|
@@ -109,6 +109,10 @@ const _AesEncryptor = class _AesEncryptor {
|
|
|
109
109
|
return appKeyPath;
|
|
110
110
|
}
|
|
111
111
|
static async create(app) {
|
|
112
|
+
if (process.env.APP_AES_SECRET_KEY) {
|
|
113
|
+
const key2 = Buffer.from(process.env.APP_AES_SECRET_KEY, "hex");
|
|
114
|
+
return new _AesEncryptor(key2);
|
|
115
|
+
}
|
|
112
116
|
const KEY_PATH = process.env.APP_AES_SECRET_KEY_PATH;
|
|
113
117
|
const keyPath = KEY_PATH ? (0, import_path.resolve)(process.cwd(), KEY_PATH) : await this.getKeyPath(app.name);
|
|
114
118
|
const key = await _AesEncryptor.getOrGenerateKey(keyPath);
|
package/lib/app-command.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export declare class AppCommand extends Command {
|
|
|
14
14
|
auth(): this;
|
|
15
15
|
preload(): this;
|
|
16
16
|
hasCommand(name: string): boolean;
|
|
17
|
+
findCommand(name: string): any;
|
|
17
18
|
isHandleByIPCServer(): boolean;
|
|
18
19
|
createCommand(name?: string): AppCommand;
|
|
19
20
|
parseHandleByIPCServer(argv: any, parseOptions?: any): Boolean;
|
package/lib/app-command.js
CHANGED
|
@@ -51,6 +51,9 @@ const _AppCommand = class _AppCommand extends import_commander.Command {
|
|
|
51
51
|
const names = this.commands.map((c) => c.name());
|
|
52
52
|
return names.includes(name);
|
|
53
53
|
}
|
|
54
|
+
findCommand(name) {
|
|
55
|
+
return this._findCommand(name);
|
|
56
|
+
}
|
|
54
57
|
isHandleByIPCServer() {
|
|
55
58
|
return this._handleByIPCServer;
|
|
56
59
|
}
|
package/lib/app-supervisor.d.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
/// <reference types="node" />
|
|
10
10
|
import { AsyncEmitter } from '@nocobase/utils';
|
|
11
|
+
import { Mutex } from 'async-mutex';
|
|
11
12
|
import { EventEmitter } from 'events';
|
|
12
13
|
import Application, { ApplicationOptions } from './application';
|
|
13
14
|
type BootOptions = {
|
|
@@ -16,9 +17,10 @@ type BootOptions = {
|
|
|
16
17
|
appSupervisor: AppSupervisor;
|
|
17
18
|
};
|
|
18
19
|
type AppBootstrapper = (bootOptions: BootOptions) => Promise<void>;
|
|
19
|
-
type AppStatus = 'initializing' | 'initialized' | 'running' | 'commanding' | 'stopped' | 'error' | 'not_found';
|
|
20
|
+
export type AppStatus = 'preparing' | 'initializing' | 'initialized' | 'running' | 'commanding' | 'stopped' | 'error' | 'not_found';
|
|
20
21
|
export declare class AppSupervisor extends EventEmitter implements AsyncEmitter {
|
|
21
22
|
private static instance;
|
|
23
|
+
private bootstrapQueue;
|
|
22
24
|
runningMode: 'single' | 'multiple';
|
|
23
25
|
singleAppName: string | null;
|
|
24
26
|
emitAsync: (event: string | symbol, ...args: any[]) => Promise<boolean>;
|
|
@@ -48,7 +50,8 @@ export declare class AppSupervisor extends EventEmitter implements AsyncEmitter
|
|
|
48
50
|
reset(): Promise<void>;
|
|
49
51
|
destroy(): Promise<void>;
|
|
50
52
|
setAppStatus(appName: string, status: AppStatus, options?: {}): void;
|
|
51
|
-
getMutexOfApp(appName: string):
|
|
53
|
+
getMutexOfApp(appName: string): Mutex;
|
|
54
|
+
private _bootStrapApp;
|
|
52
55
|
bootStrapApp(appName: string, options?: {}): Promise<void>;
|
|
53
56
|
getApp(appName: string, options?: {
|
|
54
57
|
withOutBootStrap?: boolean;
|
|
@@ -61,6 +64,8 @@ export declare class AppSupervisor extends EventEmitter implements AsyncEmitter
|
|
|
61
64
|
touchApp(appName: string): void;
|
|
62
65
|
addApp(app: Application): Application<import("./application").DefaultState, import("./application").DefaultContext>;
|
|
63
66
|
getAppsNames(): Promise<string[]>;
|
|
67
|
+
startApp(appName: string): Promise<void>;
|
|
68
|
+
stopApp(appName: string): Promise<void>;
|
|
64
69
|
removeApp(appName: string): Promise<void>;
|
|
65
70
|
subApps(): Application<import("./application").DefaultState, import("./application").DefaultContext>[];
|
|
66
71
|
on(eventName: string | symbol, listener: (...args: any[]) => void): this;
|
package/lib/app-supervisor.js
CHANGED
|
@@ -47,7 +47,9 @@ var import_async_mutex = require("async-mutex");
|
|
|
47
47
|
var import_events = require("events");
|
|
48
48
|
var import_application = __toESM(require("./application"));
|
|
49
49
|
var import_handler = require("./errors/handler");
|
|
50
|
+
var import_p_queue = __toESM(require("p-queue"));
|
|
50
51
|
const _AppSupervisor = class _AppSupervisor extends import_events.EventEmitter {
|
|
52
|
+
bootstrapQueue;
|
|
51
53
|
runningMode = "multiple";
|
|
52
54
|
singleAppName = null;
|
|
53
55
|
apps = {};
|
|
@@ -64,6 +66,12 @@ const _AppSupervisor = class _AppSupervisor extends import_events.EventEmitter {
|
|
|
64
66
|
this.runningMode = "single";
|
|
65
67
|
this.singleAppName = process.env.STARTUP_SUBAPP;
|
|
66
68
|
}
|
|
69
|
+
this.bootstrapQueue = new import_p_queue.default({
|
|
70
|
+
concurrency: process.env.SUBAPP_BOOTSTRAP_CONCURRENCY ? parseInt(process.env.SUBAPP_BOOTSTRAP_CONCURRENCY) : Infinity,
|
|
71
|
+
intervalCap: process.env.SUBAPP_BOOTSTRAP_INTERVAL_CAP ? parseInt(process.env.SUBAPP_BOOTSTRAP_INTERVAL_CAP) : Infinity,
|
|
72
|
+
interval: process.env.SUBAPP_BOOTSTRAP_INTERVAL ? parseInt(process.env.SUBAPP_BOOTSTRAP_INTERVAL) : 0,
|
|
73
|
+
timeout: 1 * 60 * 1e3
|
|
74
|
+
});
|
|
67
75
|
}
|
|
68
76
|
static getInstance() {
|
|
69
77
|
if (!_AppSupervisor.instance) {
|
|
@@ -113,24 +121,42 @@ const _AppSupervisor = class _AppSupervisor extends import_events.EventEmitter {
|
|
|
113
121
|
}
|
|
114
122
|
return this.appMutexes[appName];
|
|
115
123
|
}
|
|
124
|
+
async _bootStrapApp(appName, options = {}) {
|
|
125
|
+
this.setAppStatus(appName, "initializing");
|
|
126
|
+
if (this.appBootstrapper) {
|
|
127
|
+
await this.appBootstrapper({
|
|
128
|
+
appSupervisor: this,
|
|
129
|
+
appName,
|
|
130
|
+
options
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
if (!this.hasApp(appName)) {
|
|
134
|
+
this.setAppStatus(appName, "not_found");
|
|
135
|
+
} else if (!this.getAppStatus(appName) || this.getAppStatus(appName) === "initializing") {
|
|
136
|
+
this.setAppStatus(appName, "initialized");
|
|
137
|
+
}
|
|
138
|
+
}
|
|
116
139
|
async bootStrapApp(appName, options = {}) {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
if (this.
|
|
121
|
-
|
|
122
|
-
appSupervisor: this,
|
|
123
|
-
appName,
|
|
124
|
-
options
|
|
125
|
-
});
|
|
140
|
+
const mutex = this.getMutexOfApp(appName);
|
|
141
|
+
try {
|
|
142
|
+
await (0, import_async_mutex.tryAcquire)(mutex).runExclusive(async () => {
|
|
143
|
+
if (this.hasApp(appName) && this.getAppStatus(appName) !== "preparing") {
|
|
144
|
+
return;
|
|
126
145
|
}
|
|
127
|
-
if (
|
|
128
|
-
this.
|
|
129
|
-
} else if (!this.getAppStatus(appName) || this.getAppStatus(appName) == "initializing") {
|
|
130
|
-
this.setAppStatus(appName, "initialized");
|
|
146
|
+
if (appName === "main") {
|
|
147
|
+
return this._bootStrapApp(appName, options);
|
|
131
148
|
}
|
|
149
|
+
this.setAppStatus(appName, "preparing");
|
|
150
|
+
await this.bootstrapQueue.add(async () => {
|
|
151
|
+
await this._bootStrapApp(appName, options);
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
} catch (e) {
|
|
155
|
+
console.log(e);
|
|
156
|
+
if (e === import_async_mutex.E_ALREADY_LOCKED) {
|
|
157
|
+
return;
|
|
132
158
|
}
|
|
133
|
-
}
|
|
159
|
+
}
|
|
134
160
|
}
|
|
135
161
|
async getApp(appName, options = {}) {
|
|
136
162
|
if (!options.withOutBootStrap) {
|
|
@@ -170,7 +196,7 @@ const _AppSupervisor = class _AppSupervisor extends import_events.EventEmitter {
|
|
|
170
196
|
this.apps[app.name] = app;
|
|
171
197
|
this.emit("afterAppAdded", app);
|
|
172
198
|
if (!this.getAppStatus(app.name) || this.getAppStatus(app.name) == "not_found") {
|
|
173
|
-
this.setAppStatus(app.name, "
|
|
199
|
+
this.setAppStatus(app.name, "preparing");
|
|
174
200
|
}
|
|
175
201
|
return app;
|
|
176
202
|
}
|
|
@@ -179,12 +205,25 @@ const _AppSupervisor = class _AppSupervisor extends import_events.EventEmitter {
|
|
|
179
205
|
const apps = Object.values(this.apps);
|
|
180
206
|
return apps.map((app) => app.name);
|
|
181
207
|
}
|
|
208
|
+
async startApp(appName) {
|
|
209
|
+
const appInstance = await _AppSupervisor.getInstance().getApp(appName);
|
|
210
|
+
await appInstance.runCommand("start", "--quickstart");
|
|
211
|
+
}
|
|
212
|
+
async stopApp(appName) {
|
|
213
|
+
if (!this.apps[appName]) {
|
|
214
|
+
console.log(`app ${appName} not exists`);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
await this.apps[appName].runCommand("stop");
|
|
218
|
+
this.apps[appName] = null;
|
|
219
|
+
}
|
|
182
220
|
async removeApp(appName) {
|
|
183
221
|
if (!this.apps[appName]) {
|
|
184
222
|
console.log(`app ${appName} not exists`);
|
|
185
223
|
return;
|
|
186
224
|
}
|
|
187
225
|
await this.apps[appName].runCommand("destroy");
|
|
226
|
+
this.apps[appName] = null;
|
|
188
227
|
}
|
|
189
228
|
subApps() {
|
|
190
229
|
return Object.values(this.apps).filter((app) => app.name !== "main");
|
package/lib/application.d.ts
CHANGED
|
@@ -34,10 +34,9 @@ import { SyncMessageManager } from './sync-message-manager';
|
|
|
34
34
|
import AesEncryptor from './aes-encryptor';
|
|
35
35
|
import { AuditManager } from './audit-manager';
|
|
36
36
|
import { Environment } from './environment';
|
|
37
|
-
import { ServiceContainer } from './service-container';
|
|
38
37
|
import { EventQueue, EventQueueOptions } from './event-queue';
|
|
39
|
-
import { BackgroundJobManager, BackgroundJobManagerOptions } from './background-job-manager';
|
|
40
38
|
import { RedisConfig, RedisConnectionManager } from './redis-connection-manager';
|
|
39
|
+
import { ServiceContainer } from './service-container';
|
|
41
40
|
import { WorkerIdAllocator } from './worker-id-allocator';
|
|
42
41
|
export type PluginType = string | typeof Plugin;
|
|
43
42
|
export type PluginConfiguration = PluginType | [PluginType, any];
|
|
@@ -89,7 +88,6 @@ export interface ApplicationOptions {
|
|
|
89
88
|
auditManager?: AuditManager;
|
|
90
89
|
lockManager?: LockManagerOptions;
|
|
91
90
|
eventQueue?: EventQueueOptions;
|
|
92
|
-
backgroundJobManager?: BackgroundJobManagerOptions;
|
|
93
91
|
/**
|
|
94
92
|
* @internal
|
|
95
93
|
*/
|
|
@@ -190,9 +188,9 @@ export declare class Application<StateT = DefaultState, ContextT = DefaultContex
|
|
|
190
188
|
container: ServiceContainer;
|
|
191
189
|
lockManager: LockManager;
|
|
192
190
|
eventQueue: EventQueue;
|
|
193
|
-
backgroundJobManager: BackgroundJobManager;
|
|
194
191
|
constructor(options: ApplicationOptions);
|
|
195
192
|
private static staticCommands;
|
|
193
|
+
static registerStaticCommand(callback: (app: Application) => void): void;
|
|
196
194
|
static addCommand(callback: (app: Application) => void): void;
|
|
197
195
|
private _sqlLogger;
|
|
198
196
|
get instanceId(): number;
|
|
@@ -219,7 +217,7 @@ export declare class Application<StateT = DefaultState, ContextT = DefaultContex
|
|
|
219
217
|
get environment(): Environment;
|
|
220
218
|
protected _cronJobManager: CronJobManager;
|
|
221
219
|
get cronJobManager(): CronJobManager;
|
|
222
|
-
get mainDataSource(): SequelizeDataSource
|
|
220
|
+
get mainDataSource(): SequelizeDataSource<import("@nocobase/data-source-manager").DatabaseIntrospector>;
|
|
223
221
|
get db(): Database;
|
|
224
222
|
get resourceManager(): import("@nocobase/resourcer").ResourceManager;
|
|
225
223
|
/**
|
|
@@ -283,7 +281,7 @@ export declare class Application<StateT = DefaultState, ContextT = DefaultContex
|
|
|
283
281
|
setMaintainingMessage(message: string): void;
|
|
284
282
|
/**
|
|
285
283
|
* This method is deprecated and should not be used.
|
|
286
|
-
* Use {@link #this.
|
|
284
|
+
* Use {@link #this.getPackageVersion} instead.
|
|
287
285
|
* @deprecated
|
|
288
286
|
*/
|
|
289
287
|
getVersion(): string;
|
package/lib/application.js
CHANGED
|
@@ -50,8 +50,8 @@ var import_database = __toESM(require("@nocobase/database"));
|
|
|
50
50
|
var import_logger = require("@nocobase/logger");
|
|
51
51
|
var import_telemetry = require("@nocobase/telemetry");
|
|
52
52
|
var import_lock_manager = require("@nocobase/lock-manager");
|
|
53
|
-
var import_utils = require("@nocobase/utils");
|
|
54
53
|
var import_snowflake_id = require("@nocobase/snowflake-id");
|
|
54
|
+
var import_utils = require("@nocobase/utils");
|
|
55
55
|
var import_crypto = require("crypto");
|
|
56
56
|
var import_glob = __toESM(require("glob"));
|
|
57
57
|
var import_koa = __toESM(require("koa"));
|
|
@@ -81,12 +81,11 @@ var import_available_action = require("./acl/available-action");
|
|
|
81
81
|
var import_aes_encryptor = __toESM(require("./aes-encryptor"));
|
|
82
82
|
var import_audit_manager = require("./audit-manager");
|
|
83
83
|
var import_environment = require("./environment");
|
|
84
|
-
var import_service_container = require("./service-container");
|
|
85
84
|
var import_event_queue = require("./event-queue");
|
|
86
|
-
var import_background_job_manager = require("./background-job-manager");
|
|
87
85
|
var import_redis_connection_manager = require("./redis-connection-manager");
|
|
88
|
-
var
|
|
86
|
+
var import_service_container = require("./service-container");
|
|
89
87
|
var import_snowflake_id_field = require("./snowflake-id-field");
|
|
88
|
+
var import_worker_id_allocator = require("./worker-id-allocator");
|
|
90
89
|
const _Application = class _Application extends import_koa.default {
|
|
91
90
|
constructor(options) {
|
|
92
91
|
super();
|
|
@@ -142,7 +141,9 @@ const _Application = class _Application extends import_koa.default {
|
|
|
142
141
|
container = new import_service_container.ServiceContainer();
|
|
143
142
|
lockManager;
|
|
144
143
|
eventQueue;
|
|
145
|
-
|
|
144
|
+
static registerStaticCommand(callback) {
|
|
145
|
+
this.staticCommands.push(callback);
|
|
146
|
+
}
|
|
146
147
|
static addCommand(callback) {
|
|
147
148
|
this.staticCommands.push(callback);
|
|
148
149
|
}
|
|
@@ -336,7 +337,7 @@ const _Application = class _Application extends import_koa.default {
|
|
|
336
337
|
}
|
|
337
338
|
/**
|
|
338
339
|
* This method is deprecated and should not be used.
|
|
339
|
-
* Use {@link #this.
|
|
340
|
+
* Use {@link #this.getPackageVersion} instead.
|
|
340
341
|
* @deprecated
|
|
341
342
|
*/
|
|
342
343
|
getVersion() {
|
|
@@ -777,6 +778,12 @@ const _Application = class _Application extends import_koa.default {
|
|
|
777
778
|
}
|
|
778
779
|
async upgrade(options = {}) {
|
|
779
780
|
this.log.info("upgrading...");
|
|
781
|
+
const pkgVersion = this.getPackageVersion();
|
|
782
|
+
const appVersion = await this.version.get();
|
|
783
|
+
if (process.env.SKIP_SAME_VERSION_UPGRADE === "true" && pkgVersion === appVersion) {
|
|
784
|
+
this.log.info(`app is already the latest version (${appVersion})`);
|
|
785
|
+
return;
|
|
786
|
+
}
|
|
780
787
|
await this.reInit();
|
|
781
788
|
const migrator1 = await this.loadCoreMigrations();
|
|
782
789
|
await migrator1.beforeLoad.up();
|
|
@@ -800,7 +807,9 @@ const _Application = class _Application extends import_koa.default {
|
|
|
800
807
|
await migrator3.afterLoad.up();
|
|
801
808
|
await this.pm.repository.updateVersions();
|
|
802
809
|
await this.version.update();
|
|
803
|
-
|
|
810
|
+
if (!options.quickstart) {
|
|
811
|
+
await this.emitAsync("afterUpgrade", this, options);
|
|
812
|
+
}
|
|
804
813
|
await this.restart();
|
|
805
814
|
}
|
|
806
815
|
toJSON() {
|
|
@@ -911,7 +920,6 @@ const _Application = class _Application extends import_koa.default {
|
|
|
911
920
|
this.pubSubManager = (0, import_pub_sub_manager.createPubSubManager)(this, options.pubSubManager);
|
|
912
921
|
this.syncMessageManager = new import_sync_message_manager.SyncMessageManager(this, options.syncMessageManager);
|
|
913
922
|
this.eventQueue = new import_event_queue.EventQueue(this, options.eventQueue);
|
|
914
|
-
this.backgroundJobManager = new import_background_job_manager.BackgroundJobManager(this, options.backgroundJobManager);
|
|
915
923
|
this.lockManager = new import_lock_manager.LockManager({
|
|
916
924
|
defaultAdapter: process.env.LOCK_ADAPTER_DEFAULT,
|
|
917
925
|
...options.lockManager
|
|
@@ -927,8 +935,8 @@ const _Application = class _Application extends import_koa.default {
|
|
|
927
935
|
plugins: plugins || []
|
|
928
936
|
});
|
|
929
937
|
this._telemetry = new import_telemetry.Telemetry({
|
|
930
|
-
|
|
931
|
-
version: this.
|
|
938
|
+
appName: this.name,
|
|
939
|
+
version: this.getPackageVersion(),
|
|
932
940
|
...options.telemetry
|
|
933
941
|
});
|
|
934
942
|
this._authManager = new import_auth.AuthManager({
|
|
@@ -948,7 +956,7 @@ const _Application = class _Application extends import_koa.default {
|
|
|
948
956
|
}
|
|
949
957
|
}
|
|
950
958
|
});
|
|
951
|
-
this._dataSourceManager.use(this._authManager.middleware(), { tag: "auth" });
|
|
959
|
+
this._dataSourceManager.use(this._authManager.middleware(), { tag: "auth", before: "default" });
|
|
952
960
|
this._dataSourceManager.use(import_validate_filter_params.default, { tag: "validate-filter-params", before: ["auth"] });
|
|
953
961
|
this._dataSourceManager.use(import_middlewares.parseVariables, {
|
|
954
962
|
group: "parseVariables",
|
package/lib/commands/pm.js
CHANGED
|
@@ -38,6 +38,17 @@ var pm_default = /* @__PURE__ */ __name((app) => {
|
|
|
38
38
|
pm.command("create").argument("plugin").option("--force-recreate").action(async (plugin, options) => {
|
|
39
39
|
await app.pm.create(plugin, options);
|
|
40
40
|
});
|
|
41
|
+
pm.command("pull").arguments("<packageNames...>").option("--registry [registry]").option("--auth-token [authToken]").option("--version [version]").action(async (packageNames, options, cli) => {
|
|
42
|
+
try {
|
|
43
|
+
let name = packageNames;
|
|
44
|
+
if (Array.isArray(packageNames) && packageNames.length === 1) {
|
|
45
|
+
name = packageNames[0];
|
|
46
|
+
}
|
|
47
|
+
await app.pm.pull(name, { ...options });
|
|
48
|
+
} catch (error) {
|
|
49
|
+
throw new import_plugin_command_error.PluginCommandError(`Failed to pull plugin`, { cause: error });
|
|
50
|
+
}
|
|
51
|
+
});
|
|
41
52
|
pm.command("add").ipc().preload().arguments("<packageNames...>").option("--registry [registry]").option("--auth-token [authToken]").option("--version [version]").action(async (packageNames, options, cli) => {
|
|
42
53
|
try {
|
|
43
54
|
let name = packageNames;
|
package/lib/commands/start.js
CHANGED
package/lib/event-queue.js
CHANGED
|
@@ -300,13 +300,13 @@ const _EventQueue = class _EventQueue {
|
|
|
300
300
|
return this.adapter.isConnected();
|
|
301
301
|
}
|
|
302
302
|
async connect() {
|
|
303
|
-
if (!this.adapter) {
|
|
304
|
-
throw new Error("no adapter set, cannot connect");
|
|
305
|
-
}
|
|
306
303
|
if (!this.app.serving()) {
|
|
307
304
|
this.app.logger.warn("app is not serving, will not connect to event queue");
|
|
308
305
|
return;
|
|
309
306
|
}
|
|
307
|
+
if (!this.adapter) {
|
|
308
|
+
throw new Error("no adapter set, cannot connect");
|
|
309
|
+
}
|
|
310
310
|
await this.adapter.connect();
|
|
311
311
|
this.app.logger.debug(`connected to adapter, using memory? ${this.adapter instanceof MemoryEventQueueAdapter}`);
|
|
312
312
|
for (const [channel, event] of this.events.entries()) {
|
|
@@ -342,6 +342,10 @@ const _EventQueue = class _EventQueue {
|
|
|
342
342
|
}
|
|
343
343
|
}
|
|
344
344
|
async publish(channel, message, options = {}) {
|
|
345
|
+
if (!this.app.serving()) {
|
|
346
|
+
this.app.logger.warn("app is not serving, will not publish message to event queue");
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
345
349
|
if (!this.adapter) {
|
|
346
350
|
throw new Error("no adapter set, cannot publish");
|
|
347
351
|
}
|
package/lib/gateway/errors.js
CHANGED
|
@@ -53,7 +53,7 @@ const errors = {
|
|
|
53
53
|
APP_ERROR: {
|
|
54
54
|
status: 503,
|
|
55
55
|
message: /* @__PURE__ */ __name(({ app }) => {
|
|
56
|
-
const error = import_app_supervisor.AppSupervisor.getInstance().appErrors[app.name];
|
|
56
|
+
const error = import_app_supervisor.AppSupervisor.getInstance().appErrors[app == null ? void 0 : app.name];
|
|
57
57
|
if (!error) {
|
|
58
58
|
return "";
|
|
59
59
|
}
|
|
@@ -64,12 +64,17 @@ const errors = {
|
|
|
64
64
|
return message;
|
|
65
65
|
}, "message"),
|
|
66
66
|
code: /* @__PURE__ */ __name(({ app }) => {
|
|
67
|
-
const error = import_app_supervisor.AppSupervisor.getInstance().appErrors[app.name];
|
|
67
|
+
const error = import_app_supervisor.AppSupervisor.getInstance().appErrors[app == null ? void 0 : app.name];
|
|
68
68
|
return error["code"] || "APP_ERROR";
|
|
69
69
|
}, "code"),
|
|
70
70
|
command: /* @__PURE__ */ __name(({ app }) => app.getMaintaining().command, "command"),
|
|
71
71
|
maintaining: true
|
|
72
72
|
},
|
|
73
|
+
APP_PREPARING: {
|
|
74
|
+
status: 503,
|
|
75
|
+
message: /* @__PURE__ */ __name(({ appName }) => `application ${appName} is preparing, please wait patiently`, "message"),
|
|
76
|
+
maintaining: true
|
|
77
|
+
},
|
|
73
78
|
APP_STARTING: {
|
|
74
79
|
status: 503,
|
|
75
80
|
message: /* @__PURE__ */ __name(({ app }) => app.maintainingMessage, "message"),
|
|
@@ -77,12 +82,12 @@ const errors = {
|
|
|
77
82
|
},
|
|
78
83
|
APP_STOPPED: {
|
|
79
84
|
status: 503,
|
|
80
|
-
message: /* @__PURE__ */ __name(({ app }) => `application ${app.name} is stopped`, "message"),
|
|
85
|
+
message: /* @__PURE__ */ __name(({ app }) => `application ${app == null ? void 0 : app.name} is stopped`, "message"),
|
|
81
86
|
maintaining: true
|
|
82
87
|
},
|
|
83
88
|
APP_INITIALIZED: {
|
|
84
89
|
status: 503,
|
|
85
|
-
message: /* @__PURE__ */ __name(({ app }) => `application ${app.name} is initialized,
|
|
90
|
+
message: /* @__PURE__ */ __name(({ app }) => `application ${app == null ? void 0 : app.name} is initialized, please refresh the page`, "message"),
|
|
86
91
|
maintaining: true
|
|
87
92
|
},
|
|
88
93
|
APP_INITIALIZING: {
|
|
@@ -111,7 +116,7 @@ const errors = {
|
|
|
111
116
|
APP_RUNNING: {
|
|
112
117
|
status: 200,
|
|
113
118
|
maintaining: false,
|
|
114
|
-
message: /* @__PURE__ */ __name(({ message, app }) => message || `application ${app.name} is running`, "message")
|
|
119
|
+
message: /* @__PURE__ */ __name(({ message, app }) => message || `application ${app == null ? void 0 : app.name} is running`, "message")
|
|
115
120
|
},
|
|
116
121
|
UNKNOWN_ERROR: {
|
|
117
122
|
status: 500,
|
package/lib/gateway/index.d.ts
CHANGED
|
@@ -23,6 +23,12 @@ export interface IncomingRequest {
|
|
|
23
23
|
url: string;
|
|
24
24
|
headers: any;
|
|
25
25
|
}
|
|
26
|
+
export interface GatewayRequestContext {
|
|
27
|
+
req: IncomingMessage;
|
|
28
|
+
res: ServerResponse;
|
|
29
|
+
appName: string;
|
|
30
|
+
}
|
|
31
|
+
type GatewayMiddleware = (ctx: GatewayRequestContext, next: () => Promise<void>) => Promise<void> | void;
|
|
26
32
|
export type AppSelector = (req: IncomingRequest) => string | Promise<string>;
|
|
27
33
|
export type AppSelectorMiddleware = (ctx: AppSelectorMiddlewareContext, next: () => Promise<void>) => void;
|
|
28
34
|
interface StartHttpServerOptions {
|
|
@@ -39,6 +45,7 @@ export interface AppSelectorMiddlewareContext {
|
|
|
39
45
|
}
|
|
40
46
|
export declare class Gateway extends EventEmitter {
|
|
41
47
|
private static instance;
|
|
48
|
+
middlewares: Toposort<GatewayMiddleware>;
|
|
42
49
|
/**
|
|
43
50
|
* use main app as default app to handle request
|
|
44
51
|
*/
|
|
@@ -54,6 +61,7 @@ export declare class Gateway extends EventEmitter {
|
|
|
54
61
|
private onTerminate;
|
|
55
62
|
private constructor();
|
|
56
63
|
static getInstance(options?: any): Gateway;
|
|
64
|
+
use(middleware: GatewayMiddleware, options?: ToposortOptions): void;
|
|
57
65
|
static getIPCSocketClient(): Promise<false | IPCSocketClient>;
|
|
58
66
|
destroy(): void;
|
|
59
67
|
reset(): void;
|
package/lib/gateway/index.js
CHANGED
|
@@ -75,6 +75,7 @@ function getSocketPath() {
|
|
|
75
75
|
}
|
|
76
76
|
__name(getSocketPath, "getSocketPath");
|
|
77
77
|
const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
78
|
+
middlewares;
|
|
78
79
|
/**
|
|
79
80
|
* use main app as default app to handle request
|
|
80
81
|
*/
|
|
@@ -124,6 +125,9 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
|
124
125
|
}
|
|
125
126
|
return _Gateway.instance;
|
|
126
127
|
}
|
|
128
|
+
use(middleware, options) {
|
|
129
|
+
this.middlewares.add(middleware, options);
|
|
130
|
+
}
|
|
127
131
|
static async getIPCSocketClient() {
|
|
128
132
|
const socketPath = getSocketPath();
|
|
129
133
|
try {
|
|
@@ -139,6 +143,7 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
|
139
143
|
_Gateway.instance = null;
|
|
140
144
|
}
|
|
141
145
|
reset() {
|
|
146
|
+
this.middlewares = new import_utils.Toposort();
|
|
142
147
|
this.selectorMiddlewares = new import_utils.Toposort();
|
|
143
148
|
this.addAppSelectorMiddleware(
|
|
144
149
|
async (ctx, next) => {
|
|
@@ -202,7 +207,15 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
|
202
207
|
res.end(JSON.stringify({ error }));
|
|
203
208
|
}
|
|
204
209
|
responseErrorWithCode(code, res, options) {
|
|
210
|
+
const log = this.getLogger(options.appName, res);
|
|
205
211
|
const error = (0, import_errors.applyErrorWithArgs)((0, import_errors.getErrorWithCode)(code), options);
|
|
212
|
+
log.error(error.message, {
|
|
213
|
+
method: "responseErrorWithCode",
|
|
214
|
+
code,
|
|
215
|
+
error,
|
|
216
|
+
statusCode: res.statusCode,
|
|
217
|
+
appName: options.appName
|
|
218
|
+
});
|
|
206
219
|
this.responseError(res, error);
|
|
207
220
|
}
|
|
208
221
|
async requestHandler(req, res) {
|
|
@@ -256,11 +269,15 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
|
256
269
|
if (!hasApp) {
|
|
257
270
|
void import_app_supervisor.AppSupervisor.getInstance().bootStrapApp(handleApp);
|
|
258
271
|
}
|
|
259
|
-
let appStatus = import_app_supervisor.AppSupervisor.getInstance().getAppStatus(handleApp, "
|
|
272
|
+
let appStatus = import_app_supervisor.AppSupervisor.getInstance().getAppStatus(handleApp, "preparing");
|
|
260
273
|
if (appStatus === "not_found") {
|
|
261
274
|
this.responseErrorWithCode("APP_NOT_FOUND", res, { appName: handleApp });
|
|
262
275
|
return;
|
|
263
276
|
}
|
|
277
|
+
if (appStatus === "preparing") {
|
|
278
|
+
this.responseErrorWithCode("APP_PREPARING", res, { appName: handleApp });
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
264
281
|
if (appStatus === "initializing") {
|
|
265
282
|
this.responseErrorWithCode("APP_INITIALIZING", res, { appName: handleApp });
|
|
266
283
|
return;
|
|
@@ -283,7 +300,14 @@ const _Gateway = class _Gateway extends import_events.EventEmitter {
|
|
|
283
300
|
if (handleApp !== "main") {
|
|
284
301
|
import_app_supervisor.AppSupervisor.getInstance().touchApp(handleApp);
|
|
285
302
|
}
|
|
286
|
-
|
|
303
|
+
const ctx = { req, res, appName: handleApp };
|
|
304
|
+
const fn = (0, import_koa_compose.default)([
|
|
305
|
+
...this.middlewares.nodes,
|
|
306
|
+
async (_ctx) => {
|
|
307
|
+
await app.callback()(req, res);
|
|
308
|
+
}
|
|
309
|
+
]);
|
|
310
|
+
await fn(ctx);
|
|
287
311
|
}
|
|
288
312
|
getAppSelectorMiddlewares() {
|
|
289
313
|
return this.selectorMiddlewares;
|
package/lib/index.d.ts
CHANGED
|
@@ -19,9 +19,9 @@ export * from './plugin';
|
|
|
19
19
|
export * from './plugin-manager';
|
|
20
20
|
export * from './pub-sub-manager';
|
|
21
21
|
export * from './event-queue';
|
|
22
|
-
export * from './background-job-manager';
|
|
23
22
|
export * from './worker-id-allocator';
|
|
24
23
|
export * from './redis-connection-manager';
|
|
24
|
+
export * from './main-data-source';
|
|
25
25
|
export declare const OFFICIAL_PLUGIN_PREFIX = "@nocobase/plugin-";
|
|
26
26
|
export { appendToBuiltInPlugins, findAllPlugins, findBuiltInPlugins, findLocalPlugins, packageNameTrim, } from './plugin-manager/findPackageNames';
|
|
27
27
|
export { runPluginStaticImports } from './run-plugin-static-imports';
|
package/lib/index.js
CHANGED
|
@@ -61,9 +61,9 @@ __reExport(src_exports, require("./plugin"), module.exports);
|
|
|
61
61
|
__reExport(src_exports, require("./plugin-manager"), module.exports);
|
|
62
62
|
__reExport(src_exports, require("./pub-sub-manager"), module.exports);
|
|
63
63
|
__reExport(src_exports, require("./event-queue"), module.exports);
|
|
64
|
-
__reExport(src_exports, require("./background-job-manager"), module.exports);
|
|
65
64
|
__reExport(src_exports, require("./worker-id-allocator"), module.exports);
|
|
66
65
|
__reExport(src_exports, require("./redis-connection-manager"), module.exports);
|
|
66
|
+
__reExport(src_exports, require("./main-data-source"), module.exports);
|
|
67
67
|
var import_findPackageNames = require("./plugin-manager/findPackageNames");
|
|
68
68
|
var import_run_plugin_static_imports = require("./run-plugin-static-imports");
|
|
69
69
|
const OFFICIAL_PLUGIN_PREFIX = "@nocobase/plugin-";
|
|
@@ -88,7 +88,7 @@ const OFFICIAL_PLUGIN_PREFIX = "@nocobase/plugin-";
|
|
|
88
88
|
...require("./plugin-manager"),
|
|
89
89
|
...require("./pub-sub-manager"),
|
|
90
90
|
...require("./event-queue"),
|
|
91
|
-
...require("./background-job-manager"),
|
|
92
91
|
...require("./worker-id-allocator"),
|
|
93
|
-
...require("./redis-connection-manager")
|
|
92
|
+
...require("./redis-connection-manager"),
|
|
93
|
+
...require("./main-data-source")
|
|
94
94
|
});
|
package/lib/locale/locale.js
CHANGED
|
@@ -138,7 +138,7 @@ const _Locale = class _Locale {
|
|
|
138
138
|
if (!packageName) {
|
|
139
139
|
continue;
|
|
140
140
|
}
|
|
141
|
-
const res = (0, import_resource.getResource)(packageName, lang);
|
|
141
|
+
const res = await (0, import_resource.getResource)(packageName, lang);
|
|
142
142
|
if (res) {
|
|
143
143
|
resources[packageName] = { ...res };
|
|
144
144
|
if (packageName.includes(import__.OFFICIAL_PLUGIN_PREFIX)) {
|
package/lib/locale/resource.js
CHANGED
|
@@ -40,7 +40,7 @@ __export(resource_exports, {
|
|
|
40
40
|
getResource: () => getResource
|
|
41
41
|
});
|
|
42
42
|
module.exports = __toCommonJS(resource_exports);
|
|
43
|
-
var
|
|
43
|
+
var import_promises = __toESM(require("fs/promises"));
|
|
44
44
|
const arr2obj = /* @__PURE__ */ __name((items) => {
|
|
45
45
|
const obj = {};
|
|
46
46
|
for (const item of items) {
|
|
@@ -48,7 +48,7 @@ const arr2obj = /* @__PURE__ */ __name((items) => {
|
|
|
48
48
|
}
|
|
49
49
|
return obj;
|
|
50
50
|
}, "arr2obj");
|
|
51
|
-
const getResource = /* @__PURE__ */ __name((packageName, lang, isPlugin = true) => {
|
|
51
|
+
const getResource = /* @__PURE__ */ __name(async (packageName, lang, isPlugin = true) => {
|
|
52
52
|
const resources = [];
|
|
53
53
|
const prefixes = [isPlugin ? "dist" : "lib"];
|
|
54
54
|
if (process.env.APP_ENV !== "production") {
|
|
@@ -70,13 +70,10 @@ const getResource = /* @__PURE__ */ __name((packageName, lang, isPlugin = true)
|
|
|
70
70
|
}
|
|
71
71
|
for (const prefix of prefixes) {
|
|
72
72
|
try {
|
|
73
|
-
const file = `${packageName}/${prefix}/locale/${lang}`;
|
|
73
|
+
const file = `${packageName}/${prefix}/locale/${lang}.json`;
|
|
74
74
|
const f = require.resolve(file);
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
78
|
-
const resource = (0, import_utils.requireModule)(file);
|
|
79
|
-
resources.push(resource);
|
|
75
|
+
const resource = await import_promises.default.readFile(f, "utf8");
|
|
76
|
+
resources.push(JSON.parse(resource));
|
|
80
77
|
} catch (error) {
|
|
81
78
|
}
|
|
82
79
|
if (resources.length) {
|
|
@@ -84,7 +81,7 @@ const getResource = /* @__PURE__ */ __name((packageName, lang, isPlugin = true)
|
|
|
84
81
|
}
|
|
85
82
|
}
|
|
86
83
|
if (resources.length === 0 && lang.replace("-", "_") !== lang) {
|
|
87
|
-
return getResource(packageName, lang.replace("-", "_"));
|
|
84
|
+
return await getResource(packageName, lang.replace("-", "_"));
|
|
88
85
|
}
|
|
89
86
|
return arr2obj(resources);
|
|
90
87
|
}, "getResource");
|
|
@@ -6,7 +6,18 @@
|
|
|
6
6
|
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
|
+
import { Context } from '@nocobase/actions';
|
|
9
10
|
import { DataSourceOptions, SequelizeDataSource } from '@nocobase/data-source-manager';
|
|
11
|
+
type MainDataSourceStatus = 'loaded' | 'loading';
|
|
10
12
|
export declare class MainDataSource extends SequelizeDataSource {
|
|
13
|
+
status: MainDataSourceStatus;
|
|
11
14
|
init(options?: DataSourceOptions): void;
|
|
15
|
+
readTables(): Promise<{
|
|
16
|
+
name: string;
|
|
17
|
+
}[]>;
|
|
18
|
+
private tables2Collections;
|
|
19
|
+
loadTables(ctx: Context, tables: string[]): Promise<void>;
|
|
20
|
+
private getLoadedCollections;
|
|
21
|
+
syncFieldsFromDatabase(ctx: any, collectionNames?: string[]): Promise<void>;
|
|
12
22
|
}
|
|
23
|
+
export {};
|
package/lib/main-data-source.js
CHANGED
|
@@ -32,6 +32,7 @@ __export(main_data_source_exports, {
|
|
|
32
32
|
module.exports = __toCommonJS(main_data_source_exports);
|
|
33
33
|
var import_data_source_manager = require("@nocobase/data-source-manager");
|
|
34
34
|
const _MainDataSource = class _MainDataSource extends import_data_source_manager.SequelizeDataSource {
|
|
35
|
+
status = "loaded";
|
|
35
36
|
init(options = {}) {
|
|
36
37
|
const { acl, resourceManager, database } = options;
|
|
37
38
|
this.acl = acl;
|
|
@@ -48,6 +49,133 @@ const _MainDataSource = class _MainDataSource extends import_data_source_manager
|
|
|
48
49
|
this.resourceManager.use(this.acl.middleware(), { group: "acl", after: "auth" });
|
|
49
50
|
}
|
|
50
51
|
}
|
|
52
|
+
async readTables() {
|
|
53
|
+
const allTables = await this.introspector.getTableList();
|
|
54
|
+
const existsCollections = this.collectionManager.db.collections;
|
|
55
|
+
const existsTables = Array.from(existsCollections.values()).map(
|
|
56
|
+
(collection) => collection.model.tableName
|
|
57
|
+
);
|
|
58
|
+
const diffTables = allTables.filter((table) => !existsTables.includes(table));
|
|
59
|
+
return diffTables.map((name) => ({ name }));
|
|
60
|
+
}
|
|
61
|
+
async tables2Collections(tableNames) {
|
|
62
|
+
const db = this.collectionManager.db;
|
|
63
|
+
const results = await Promise.all(
|
|
64
|
+
tableNames.map(async (tableName) => {
|
|
65
|
+
let tableInfo;
|
|
66
|
+
if (typeof tableName === "string") {
|
|
67
|
+
tableInfo = { tableName };
|
|
68
|
+
if (db.options.schema) {
|
|
69
|
+
tableInfo.schema = db.options.schema;
|
|
70
|
+
}
|
|
71
|
+
} else {
|
|
72
|
+
tableInfo = tableName;
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
return await this.introspector.getCollection({ tableInfo });
|
|
76
|
+
} catch (e) {
|
|
77
|
+
if (e.message.includes("No description found for")) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
throw e;
|
|
81
|
+
}
|
|
82
|
+
})
|
|
83
|
+
);
|
|
84
|
+
return results.filter(Boolean);
|
|
85
|
+
}
|
|
86
|
+
async loadTables(ctx, tables) {
|
|
87
|
+
const repo = this.collectionManager.db.getRepository("collections");
|
|
88
|
+
const existsCollections = this.collectionManager.db.collections;
|
|
89
|
+
const existsTables = Array.from(existsCollections.values()).map(
|
|
90
|
+
(collection) => collection.model.tableName
|
|
91
|
+
);
|
|
92
|
+
const toAddTables = tables.filter((table) => !existsTables.includes(table));
|
|
93
|
+
if (toAddTables.length) {
|
|
94
|
+
try {
|
|
95
|
+
this.status = "loading";
|
|
96
|
+
const results = await this.tables2Collections(toAddTables);
|
|
97
|
+
const values = results.map((result) => ({
|
|
98
|
+
...result,
|
|
99
|
+
underscored: false
|
|
100
|
+
}));
|
|
101
|
+
await repo.create({ values, context: ctx });
|
|
102
|
+
} catch (e) {
|
|
103
|
+
throw e;
|
|
104
|
+
} finally {
|
|
105
|
+
this.status = "loaded";
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
async getLoadedCollections(filter) {
|
|
110
|
+
const db = this.collectionManager.db;
|
|
111
|
+
const loadedCollections = await db.getRepository("collections").find({
|
|
112
|
+
appends: ["fields"],
|
|
113
|
+
filter: {
|
|
114
|
+
hidden: false,
|
|
115
|
+
...filter
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
const collections = loadedCollections.filter((collection) => {
|
|
119
|
+
var _a;
|
|
120
|
+
return ((_a = collection.options) == null ? void 0 : _a.from) !== "db2cm";
|
|
121
|
+
});
|
|
122
|
+
const loadedData = {};
|
|
123
|
+
for (const collection of collections) {
|
|
124
|
+
const c = db.getCollection(collection.name);
|
|
125
|
+
loadedData[c.tableName()] = {
|
|
126
|
+
...collection.toJSON(),
|
|
127
|
+
fields: collection.fields.map((field) => {
|
|
128
|
+
const f = c.getField(field.name);
|
|
129
|
+
return {
|
|
130
|
+
columnName: f == null ? void 0 : f.columnName(),
|
|
131
|
+
...field.toJSON()
|
|
132
|
+
};
|
|
133
|
+
})
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
return loadedData;
|
|
137
|
+
}
|
|
138
|
+
async syncFieldsFromDatabase(ctx, collectionNames) {
|
|
139
|
+
let filter = {};
|
|
140
|
+
if (collectionNames == null ? void 0 : collectionNames.length) {
|
|
141
|
+
filter = {
|
|
142
|
+
name: collectionNames
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
const db = this.collectionManager.db;
|
|
146
|
+
const loadedCollections = await this.getLoadedCollections(filter);
|
|
147
|
+
const tableNames = Object.values(loadedCollections).map(({ name }) => {
|
|
148
|
+
const collection = db.getCollection(name);
|
|
149
|
+
return collection.getTableNameWithSchema();
|
|
150
|
+
});
|
|
151
|
+
let collections = [];
|
|
152
|
+
try {
|
|
153
|
+
collections = await this.tables2Collections(tableNames);
|
|
154
|
+
} catch (err) {
|
|
155
|
+
ctx.log.error(err);
|
|
156
|
+
}
|
|
157
|
+
const toLoadCollections = this.mergeWithLoadedCollections(collections, loadedCollections);
|
|
158
|
+
for (const values of toLoadCollections) {
|
|
159
|
+
const existsFields = loadedCollections[values.tableName].fields;
|
|
160
|
+
const deletedFields = existsFields.filter((field) => !values.fields.find((f) => f.name === field.name));
|
|
161
|
+
await db.sequelize.transaction(async (transaction) => {
|
|
162
|
+
for (const field of deletedFields) {
|
|
163
|
+
await db.getRepository("fields").destroy({
|
|
164
|
+
filterByTk: field.key,
|
|
165
|
+
context: ctx,
|
|
166
|
+
transaction
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
await db.getRepository("collections").update({
|
|
170
|
+
filterByTk: values.name,
|
|
171
|
+
values,
|
|
172
|
+
updateAssociationValues: ["fields"],
|
|
173
|
+
context: ctx,
|
|
174
|
+
transaction
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
51
179
|
};
|
|
52
180
|
__name(_MainDataSource, "MainDataSource");
|
|
53
181
|
let MainDataSource = _MainDataSource;
|
|
@@ -126,12 +126,7 @@ const traverseJSON = /* @__PURE__ */ __name((data, options) => {
|
|
|
126
126
|
include: subInclude
|
|
127
127
|
});
|
|
128
128
|
} else if (field.type === "belongsTo") {
|
|
129
|
-
result[key] =
|
|
130
|
-
collection: collection.db.getCollection(field.target),
|
|
131
|
-
// exclude: [field.foreignKey],
|
|
132
|
-
include: subInclude,
|
|
133
|
-
excludePk: false
|
|
134
|
-
});
|
|
129
|
+
result[key] = data[key];
|
|
135
130
|
} else if (field.type === "belongsToMany") {
|
|
136
131
|
result[key] = traverseBelongsToMany(data[key], {
|
|
137
132
|
collection: collection.db.getCollection(field.target),
|
|
@@ -64,6 +64,7 @@ async function parseVariables(ctx, next) {
|
|
|
64
64
|
if (!filter) {
|
|
65
65
|
return next();
|
|
66
66
|
}
|
|
67
|
+
const state = JSON.parse(JSON.stringify(ctx.state));
|
|
67
68
|
ctx.action.params.filter = await (0, import_utils.parseFilter)(filter, {
|
|
68
69
|
timezone: ctx.get("x-timezone"),
|
|
69
70
|
now: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -73,6 +74,9 @@ async function parseVariables(ctx, next) {
|
|
|
73
74
|
return ctx.db.getFieldByPath(`${resourceName}.${fieldPath}`);
|
|
74
75
|
}, "getField"),
|
|
75
76
|
vars: {
|
|
77
|
+
ctx: {
|
|
78
|
+
state
|
|
79
|
+
},
|
|
76
80
|
// @deprecated
|
|
77
81
|
$system: {
|
|
78
82
|
now: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -13,6 +13,8 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
13
13
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
14
14
|
var __getProtoOf = Object.getPrototypeOf;
|
|
15
15
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
16
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
17
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
16
18
|
var __export = (target, all) => {
|
|
17
19
|
for (var name in all)
|
|
18
20
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -34,6 +36,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
34
36
|
mod
|
|
35
37
|
));
|
|
36
38
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
39
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
37
40
|
var resource_exports = {};
|
|
38
41
|
__export(resource_exports, {
|
|
39
42
|
default: () => resource_default
|
|
@@ -43,6 +46,33 @@ var import_utils = require("@nocobase/utils");
|
|
|
43
46
|
var import_fs = __toESM(require("fs"));
|
|
44
47
|
var import_fs_extra = __toESM(require("fs-extra"));
|
|
45
48
|
var import_path = __toESM(require("path"));
|
|
49
|
+
const _PackageUrls = class _PackageUrls {
|
|
50
|
+
static async get(packageName, version) {
|
|
51
|
+
if (!this.items[packageName]) {
|
|
52
|
+
this.items[packageName] = await this.fetch(packageName, version);
|
|
53
|
+
}
|
|
54
|
+
return this.items[packageName];
|
|
55
|
+
}
|
|
56
|
+
static async fetch(packageName, version) {
|
|
57
|
+
const PLUGIN_CLIENT_ENTRY_FILE = "dist/client/index.js";
|
|
58
|
+
const pkgPath = import_path.default.resolve(process.env.NODE_MODULES_PATH, packageName);
|
|
59
|
+
const r = await import_fs_extra.default.exists(pkgPath);
|
|
60
|
+
if (r) {
|
|
61
|
+
let t = "";
|
|
62
|
+
const dist = import_path.default.resolve(pkgPath, PLUGIN_CLIENT_ENTRY_FILE);
|
|
63
|
+
const distExists = await import_fs_extra.default.exists(dist);
|
|
64
|
+
if (distExists) {
|
|
65
|
+
const fsState = await import_fs_extra.default.stat(distExists ? dist : pkgPath);
|
|
66
|
+
t = `&t=${fsState.mtime.getTime()}`;
|
|
67
|
+
}
|
|
68
|
+
const url = `${process.env.APP_SERVER_BASE_URL}${process.env.PLUGIN_STATICS_PATH}${packageName}/${PLUGIN_CLIENT_ENTRY_FILE}?version=${version}${t}`;
|
|
69
|
+
return url;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
__name(_PackageUrls, "PackageUrls");
|
|
74
|
+
__publicField(_PackageUrls, "items", {});
|
|
75
|
+
let PackageUrls = _PackageUrls;
|
|
46
76
|
var resource_default = {
|
|
47
77
|
name: "pm",
|
|
48
78
|
actions: {
|
|
@@ -152,33 +182,26 @@ var resource_default = {
|
|
|
152
182
|
await next();
|
|
153
183
|
},
|
|
154
184
|
async listEnabled(ctx, next) {
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
if (distExists) {
|
|
171
|
-
const fsState = await import_fs_extra.default.stat(distExists ? dist : pkgPath);
|
|
172
|
-
t = `&t=${fsState.mtime.getTime()}`;
|
|
185
|
+
const toArr = /* @__PURE__ */ __name(async () => {
|
|
186
|
+
const pm = ctx.db.getRepository("applicationPlugins");
|
|
187
|
+
const items = await pm.find({
|
|
188
|
+
filter: {
|
|
189
|
+
enabled: true
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
const arr = [];
|
|
193
|
+
for (const item of items) {
|
|
194
|
+
const url = await PackageUrls.get(item.packageName, item.version);
|
|
195
|
+
if (url) {
|
|
196
|
+
arr.push({
|
|
197
|
+
...item.toJSON(),
|
|
198
|
+
url
|
|
199
|
+
});
|
|
173
200
|
}
|
|
174
|
-
const url = `${process.env.APP_SERVER_BASE_URL}${process.env.PLUGIN_STATICS_PATH}${item.packageName}/${PLUGIN_CLIENT_ENTRY_FILE}?version=${item.version}${t}`;
|
|
175
|
-
arr.push({
|
|
176
|
-
...item.toJSON(),
|
|
177
|
-
url
|
|
178
|
-
});
|
|
179
201
|
}
|
|
180
|
-
|
|
181
|
-
|
|
202
|
+
return arr;
|
|
203
|
+
}, "toArr");
|
|
204
|
+
ctx.body = await toArr();
|
|
182
205
|
await next();
|
|
183
206
|
},
|
|
184
207
|
async get(ctx, next) {
|
|
@@ -90,7 +90,7 @@ const _PluginManager = class _PluginManager {
|
|
|
90
90
|
namespace: "core/pm",
|
|
91
91
|
directory: (0, import_path.resolve)(__dirname, "../migrations")
|
|
92
92
|
});
|
|
93
|
-
this.app.
|
|
93
|
+
this.app.resourceManager.use(import_middleware.uploadMiddleware, { tag: "upload", after: "acl" });
|
|
94
94
|
}
|
|
95
95
|
/**
|
|
96
96
|
* @internal
|
|
@@ -718,6 +718,41 @@ const _PluginManager = class _PluginManager {
|
|
|
718
718
|
await removeDir();
|
|
719
719
|
}
|
|
720
720
|
}
|
|
721
|
+
async pull(urlOrName, options, emitStartedEvent = true) {
|
|
722
|
+
if (Array.isArray(urlOrName)) {
|
|
723
|
+
for (const packageName of urlOrName) {
|
|
724
|
+
await this.addViaCLI(packageName, import_lodash.default.omit(options, "name"), false);
|
|
725
|
+
}
|
|
726
|
+
return;
|
|
727
|
+
}
|
|
728
|
+
if ((0, import_utils.isURL)(urlOrName)) {
|
|
729
|
+
await this.addByCompressedFileUrl(
|
|
730
|
+
{
|
|
731
|
+
...options,
|
|
732
|
+
compressedFileUrl: urlOrName
|
|
733
|
+
},
|
|
734
|
+
emitStartedEvent
|
|
735
|
+
);
|
|
736
|
+
} else if (await import_fs_extra.default.exists(urlOrName)) {
|
|
737
|
+
await this.addByCompressedFileUrl(
|
|
738
|
+
{
|
|
739
|
+
...options,
|
|
740
|
+
compressedFileUrl: urlOrName
|
|
741
|
+
},
|
|
742
|
+
emitStartedEvent
|
|
743
|
+
);
|
|
744
|
+
} else if (options == null ? void 0 : options.registry) {
|
|
745
|
+
const { name, packageName } = await _PluginManager.parseName(urlOrName);
|
|
746
|
+
options["name"] = name;
|
|
747
|
+
await this.addByNpm(
|
|
748
|
+
{
|
|
749
|
+
...options,
|
|
750
|
+
packageName
|
|
751
|
+
},
|
|
752
|
+
emitStartedEvent
|
|
753
|
+
);
|
|
754
|
+
}
|
|
755
|
+
}
|
|
721
756
|
/**
|
|
722
757
|
* @internal
|
|
723
758
|
*/
|
|
@@ -17,8 +17,8 @@ export declare class PubSubManager {
|
|
|
17
17
|
protected adapter: IPubSubAdapter;
|
|
18
18
|
protected handlerManager: HandlerManager;
|
|
19
19
|
constructor(app: Application, options?: PubSubManagerOptions);
|
|
20
|
-
get channelPrefix(): string;
|
|
21
20
|
setAdapter(adapter: IPubSubAdapter): void;
|
|
21
|
+
getFullChannel(channel: string): string;
|
|
22
22
|
isConnected(): Promise<boolean>;
|
|
23
23
|
connect(): Promise<void>;
|
|
24
24
|
close(): Promise<any>;
|
|
@@ -55,13 +55,13 @@ const _PubSubManager = class _PubSubManager {
|
|
|
55
55
|
publisherId;
|
|
56
56
|
adapter;
|
|
57
57
|
handlerManager;
|
|
58
|
-
get channelPrefix() {
|
|
59
|
-
var _a;
|
|
60
|
-
return ((_a = this.options) == null ? void 0 : _a.channelPrefix) ? `${this.options.channelPrefix}.` : "";
|
|
61
|
-
}
|
|
62
58
|
setAdapter(adapter) {
|
|
63
59
|
this.adapter = adapter;
|
|
64
60
|
}
|
|
61
|
+
getFullChannel(channel) {
|
|
62
|
+
var _a;
|
|
63
|
+
return [this.app.name, (_a = this.options) == null ? void 0 : _a.channelPrefix, channel].filter(Boolean).join(".");
|
|
64
|
+
}
|
|
65
65
|
async isConnected() {
|
|
66
66
|
if (this.adapter) {
|
|
67
67
|
return this.adapter.isConnected();
|
|
@@ -79,7 +79,7 @@ const _PubSubManager = class _PubSubManager {
|
|
|
79
79
|
await this.adapter.connect();
|
|
80
80
|
await this.handlerManager.each(async (channel, headler) => {
|
|
81
81
|
this.app.logger.debug(`[PubSubManager] subscribe ${channel} added before connected`);
|
|
82
|
-
await this.adapter.subscribe(
|
|
82
|
+
await this.adapter.subscribe(this.getFullChannel(channel), headler);
|
|
83
83
|
});
|
|
84
84
|
}
|
|
85
85
|
async close() {
|
|
@@ -93,7 +93,7 @@ const _PubSubManager = class _PubSubManager {
|
|
|
93
93
|
const handler = this.handlerManager.set(channel, callback, options);
|
|
94
94
|
if (await this.isConnected()) {
|
|
95
95
|
this.app.logger.debug(`[PubSubManager] subscribe ${channel} added after connected`);
|
|
96
|
-
await this.adapter.subscribe(
|
|
96
|
+
await this.adapter.subscribe(this.getFullChannel(channel), handler);
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
99
|
async unsubscribe(channel, callback) {
|
|
@@ -101,7 +101,7 @@ const _PubSubManager = class _PubSubManager {
|
|
|
101
101
|
if (!this.adapter || !handler) {
|
|
102
102
|
return;
|
|
103
103
|
}
|
|
104
|
-
return this.adapter.unsubscribe(
|
|
104
|
+
return this.adapter.unsubscribe(this.getFullChannel(channel), handler);
|
|
105
105
|
}
|
|
106
106
|
async publish(channel, message, options) {
|
|
107
107
|
var _a;
|
|
@@ -116,7 +116,7 @@ const _PubSubManager = class _PubSubManager {
|
|
|
116
116
|
...options,
|
|
117
117
|
message
|
|
118
118
|
});
|
|
119
|
-
await this.adapter.publish(
|
|
119
|
+
await this.adapter.publish(this.getFullChannel(channel), wrappedMessage);
|
|
120
120
|
this.app.logger.trace(`[PubSubManager] published message to channel ${channel}`);
|
|
121
121
|
}
|
|
122
122
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nocobase/server",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.50",
|
|
4
4
|
"main": "lib/index.js",
|
|
5
5
|
"types": "./lib/index.d.ts",
|
|
6
6
|
"license": "AGPL-3.0",
|
|
@@ -10,20 +10,20 @@
|
|
|
10
10
|
"@koa/cors": "^5.0.0",
|
|
11
11
|
"@koa/multer": "^3.1.0",
|
|
12
12
|
"@koa/router": "^13.1.0",
|
|
13
|
-
"@nocobase/acl": "2.0.0-alpha.
|
|
14
|
-
"@nocobase/actions": "2.0.0-alpha.
|
|
15
|
-
"@nocobase/auth": "2.0.0-alpha.
|
|
16
|
-
"@nocobase/cache": "2.0.0-alpha.
|
|
17
|
-
"@nocobase/data-source-manager": "2.0.0-alpha.
|
|
18
|
-
"@nocobase/database": "2.0.0-alpha.
|
|
19
|
-
"@nocobase/evaluators": "2.0.0-alpha.
|
|
20
|
-
"@nocobase/lock-manager": "2.0.0-alpha.
|
|
21
|
-
"@nocobase/logger": "2.0.0-alpha.
|
|
22
|
-
"@nocobase/resourcer": "2.0.0-alpha.
|
|
23
|
-
"@nocobase/sdk": "2.0.0-alpha.
|
|
24
|
-
"@nocobase/snowflake-id": "2.0.0-alpha.
|
|
25
|
-
"@nocobase/telemetry": "2.0.0-alpha.
|
|
26
|
-
"@nocobase/utils": "2.0.0-alpha.
|
|
13
|
+
"@nocobase/acl": "2.0.0-alpha.50",
|
|
14
|
+
"@nocobase/actions": "2.0.0-alpha.50",
|
|
15
|
+
"@nocobase/auth": "2.0.0-alpha.50",
|
|
16
|
+
"@nocobase/cache": "2.0.0-alpha.50",
|
|
17
|
+
"@nocobase/data-source-manager": "2.0.0-alpha.50",
|
|
18
|
+
"@nocobase/database": "2.0.0-alpha.50",
|
|
19
|
+
"@nocobase/evaluators": "2.0.0-alpha.50",
|
|
20
|
+
"@nocobase/lock-manager": "2.0.0-alpha.50",
|
|
21
|
+
"@nocobase/logger": "2.0.0-alpha.50",
|
|
22
|
+
"@nocobase/resourcer": "2.0.0-alpha.50",
|
|
23
|
+
"@nocobase/sdk": "2.0.0-alpha.50",
|
|
24
|
+
"@nocobase/snowflake-id": "2.0.0-alpha.50",
|
|
25
|
+
"@nocobase/telemetry": "2.0.0-alpha.50",
|
|
26
|
+
"@nocobase/utils": "2.0.0-alpha.50",
|
|
27
27
|
"@types/decompress": "4.2.7",
|
|
28
28
|
"@types/ini": "^1.3.31",
|
|
29
29
|
"@types/koa-send": "^4.1.3",
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
"lodash": "^4.17.21",
|
|
50
50
|
"multer": "^1.4.5-lts.2",
|
|
51
51
|
"nanoid": "^3.3.11",
|
|
52
|
+
"p-queue": "^6.6.2",
|
|
52
53
|
"semver": "^7.7.1",
|
|
53
54
|
"serve-handler": "^6.1.6",
|
|
54
55
|
"ws": "^8.13.0",
|
|
@@ -59,5 +60,5 @@
|
|
|
59
60
|
"@types/serve-handler": "^6.1.1",
|
|
60
61
|
"@types/ws": "^8.5.5"
|
|
61
62
|
},
|
|
62
|
-
"gitHead": "
|
|
63
|
+
"gitHead": "a6eb64abf3632e116ad0b295a7f410270a1059d1"
|
|
63
64
|
}
|
|
@@ -1,40 +0,0 @@
|
|
|
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
|
-
import Application from './application';
|
|
10
|
-
import { QueueEventOptions, QueueMessageOptions } from './event-queue';
|
|
11
|
-
export interface BackgroundJobManagerOptions {
|
|
12
|
-
channel?: string;
|
|
13
|
-
}
|
|
14
|
-
type BackgroundJobEventOptions = Pick<QueueEventOptions, 'process' | 'idle'>;
|
|
15
|
-
declare class BackgroundJobManager {
|
|
16
|
-
private app;
|
|
17
|
-
private options;
|
|
18
|
-
static DEFAULT_CHANNEL: string;
|
|
19
|
-
private subscriptions;
|
|
20
|
-
private processing;
|
|
21
|
-
private get channel();
|
|
22
|
-
private onAfterStart;
|
|
23
|
-
private onBeforeStop;
|
|
24
|
-
private process;
|
|
25
|
-
constructor(app: Application, options?: BackgroundJobManagerOptions);
|
|
26
|
-
private get idle();
|
|
27
|
-
/**
|
|
28
|
-
* 订阅指定主题的任务处理器
|
|
29
|
-
* @param options 订阅选项
|
|
30
|
-
*/
|
|
31
|
-
subscribe(topic: string, options: BackgroundJobEventOptions): void;
|
|
32
|
-
/**
|
|
33
|
-
* 取消订阅指定主题
|
|
34
|
-
* @param topic 主题名称
|
|
35
|
-
*/
|
|
36
|
-
unsubscribe(topic: string): void;
|
|
37
|
-
publish(topic: string, payload: any, options?: QueueMessageOptions): Promise<void>;
|
|
38
|
-
}
|
|
39
|
-
export { BackgroundJobManager };
|
|
40
|
-
export default BackgroundJobManager;
|
|
@@ -1,111 +0,0 @@
|
|
|
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 __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
15
|
-
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
16
|
-
var __export = (target, all) => {
|
|
17
|
-
for (var name in all)
|
|
18
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
19
|
-
};
|
|
20
|
-
var __copyProps = (to, from, except, desc) => {
|
|
21
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
22
|
-
for (let key of __getOwnPropNames(from))
|
|
23
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
24
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
25
|
-
}
|
|
26
|
-
return to;
|
|
27
|
-
};
|
|
28
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
-
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
30
|
-
var background_job_manager_exports = {};
|
|
31
|
-
__export(background_job_manager_exports, {
|
|
32
|
-
BackgroundJobManager: () => BackgroundJobManager,
|
|
33
|
-
default: () => background_job_manager_default
|
|
34
|
-
});
|
|
35
|
-
module.exports = __toCommonJS(background_job_manager_exports);
|
|
36
|
-
const _BackgroundJobManager = class _BackgroundJobManager {
|
|
37
|
-
constructor(app, options = {}) {
|
|
38
|
-
this.app = app;
|
|
39
|
-
this.options = options;
|
|
40
|
-
this.app.on("afterStart", this.onAfterStart);
|
|
41
|
-
this.app.on("beforeStop", this.onBeforeStop);
|
|
42
|
-
}
|
|
43
|
-
subscriptions = /* @__PURE__ */ new Map();
|
|
44
|
-
// topic -> handler
|
|
45
|
-
processing = null;
|
|
46
|
-
get channel() {
|
|
47
|
-
return this.options.channel ?? _BackgroundJobManager.DEFAULT_CHANNEL;
|
|
48
|
-
}
|
|
49
|
-
onAfterStart = /* @__PURE__ */ __name(() => {
|
|
50
|
-
this.app.eventQueue.subscribe(this.channel, {
|
|
51
|
-
idle: /* @__PURE__ */ __name(() => this.idle, "idle"),
|
|
52
|
-
process: this.process
|
|
53
|
-
});
|
|
54
|
-
}, "onAfterStart");
|
|
55
|
-
onBeforeStop = /* @__PURE__ */ __name(() => {
|
|
56
|
-
this.app.eventQueue.unsubscribe(this.channel);
|
|
57
|
-
}, "onBeforeStop");
|
|
58
|
-
process = /* @__PURE__ */ __name(async ({ topic, payload }, options) => {
|
|
59
|
-
const event = this.subscriptions.get(topic);
|
|
60
|
-
if (!event) {
|
|
61
|
-
this.app.logger.warn(`No handler found for topic: ${topic}, event skipped.`);
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
this.processing = event.process(payload, options);
|
|
65
|
-
try {
|
|
66
|
-
await this.processing;
|
|
67
|
-
this.app.logger.debug(`Completed background job ${topic}:${options.id}`);
|
|
68
|
-
} catch (error) {
|
|
69
|
-
this.app.logger.error(`Failed to process background job ${topic}:${options.id}`, error);
|
|
70
|
-
throw error;
|
|
71
|
-
} finally {
|
|
72
|
-
this.processing = null;
|
|
73
|
-
}
|
|
74
|
-
}, "process");
|
|
75
|
-
get idle() {
|
|
76
|
-
return !this.processing && [...this.subscriptions.values()].every((event) => event.idle());
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* 订阅指定主题的任务处理器
|
|
80
|
-
* @param options 订阅选项
|
|
81
|
-
*/
|
|
82
|
-
subscribe(topic, options) {
|
|
83
|
-
if (this.subscriptions.has(topic)) {
|
|
84
|
-
this.app.logger.warn(`Topic "${topic}" already has a handler, skip...`);
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
this.subscriptions.set(topic, options);
|
|
88
|
-
this.app.logger.debug(`Subscribed to background job topic: ${topic}`);
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* 取消订阅指定主题
|
|
92
|
-
* @param topic 主题名称
|
|
93
|
-
*/
|
|
94
|
-
unsubscribe(topic) {
|
|
95
|
-
if (this.subscriptions.has(topic)) {
|
|
96
|
-
this.subscriptions.delete(topic);
|
|
97
|
-
this.app.logger.debug(`Unsubscribed from background job topic: ${topic}`);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
async publish(topic, payload, options) {
|
|
101
|
-
await this.app.eventQueue.publish(this.channel, { topic, payload }, options);
|
|
102
|
-
}
|
|
103
|
-
};
|
|
104
|
-
__name(_BackgroundJobManager, "BackgroundJobManager");
|
|
105
|
-
__publicField(_BackgroundJobManager, "DEFAULT_CHANNEL", "background-jobs");
|
|
106
|
-
let BackgroundJobManager = _BackgroundJobManager;
|
|
107
|
-
var background_job_manager_default = BackgroundJobManager;
|
|
108
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
109
|
-
0 && (module.exports = {
|
|
110
|
-
BackgroundJobManager
|
|
111
|
-
});
|