@nocobase/plugin-async-task-manager 1.5.0-beta.20
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/LICENSE.txt +159 -0
- package/README.md +1 -0
- package/client.d.ts +2 -0
- package/client.js +1 -0
- package/dist/client/AsyncTaskManagerProvider.d.ts +4 -0
- package/dist/client/TaskResultRendererManager.d.ts +6 -0
- package/dist/client/components/AsyncTasks.d.ts +3 -0
- package/dist/client/index.d.ts +7 -0
- package/dist/client/index.js +10 -0
- package/dist/client/locale.d.ts +2 -0
- package/dist/externalVersion.js +19 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +48 -0
- package/dist/locale/en-US.json +5 -0
- package/dist/locale/zh-CN.json +45 -0
- package/dist/node_modules/uuid/AUTHORS +5 -0
- package/dist/node_modules/uuid/bin/uuid +65 -0
- package/dist/node_modules/uuid/index.js +1 -0
- package/dist/node_modules/uuid/lib/bytesToUuid.js +26 -0
- package/dist/node_modules/uuid/lib/md5-browser.js +216 -0
- package/dist/node_modules/uuid/lib/md5.js +25 -0
- package/dist/node_modules/uuid/lib/rng-browser.js +34 -0
- package/dist/node_modules/uuid/lib/rng.js +8 -0
- package/dist/node_modules/uuid/lib/sha1-browser.js +89 -0
- package/dist/node_modules/uuid/lib/sha1.js +25 -0
- package/dist/node_modules/uuid/lib/v35.js +57 -0
- package/dist/node_modules/uuid/package.json +1 -0
- package/dist/node_modules/uuid/v1.js +109 -0
- package/dist/node_modules/uuid/v3.js +4 -0
- package/dist/node_modules/uuid/v4.js +29 -0
- package/dist/node_modules/uuid/v5.js +3 -0
- package/dist/server/base-task-manager.d.ts +23 -0
- package/dist/server/base-task-manager.js +135 -0
- package/dist/server/command-task-type.d.ts +8 -0
- package/dist/server/command-task-type.js +121 -0
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.js +50 -0
- package/dist/server/interfaces/async-task-manager.d.ts +58 -0
- package/dist/server/interfaces/async-task-manager.js +41 -0
- package/dist/server/interfaces/task.d.ts +37 -0
- package/dist/server/interfaces/task.js +24 -0
- package/dist/server/plugin.d.ts +7 -0
- package/dist/server/plugin.js +163 -0
- package/dist/server/resourcers/async-tasks.d.ts +8 -0
- package/dist/server/resourcers/async-tasks.js +73 -0
- package/dist/server/static-import.d.ts +1 -0
- package/dist/server/static-import.js +39 -0
- package/dist/server/task-type.d.ts +93 -0
- package/dist/server/task-type.js +197 -0
- package/package.json +16 -0
- package/server.d.ts +2 -0
- package/server.js +1 -0
|
@@ -0,0 +1,135 @@
|
|
|
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 __export = (target, all) => {
|
|
15
|
+
for (var name in all)
|
|
16
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
17
|
+
};
|
|
18
|
+
var __copyProps = (to, from, except, desc) => {
|
|
19
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
20
|
+
for (let key of __getOwnPropNames(from))
|
|
21
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
22
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
23
|
+
}
|
|
24
|
+
return to;
|
|
25
|
+
};
|
|
26
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
27
|
+
var base_task_manager_exports = {};
|
|
28
|
+
__export(base_task_manager_exports, {
|
|
29
|
+
BaseTaskManager: () => BaseTaskManager
|
|
30
|
+
});
|
|
31
|
+
module.exports = __toCommonJS(base_task_manager_exports);
|
|
32
|
+
var import_events = require("events");
|
|
33
|
+
class BaseTaskManager extends import_events.EventEmitter {
|
|
34
|
+
taskTypes = /* @__PURE__ */ new Map();
|
|
35
|
+
tasks = /* @__PURE__ */ new Map();
|
|
36
|
+
// Clean up completed tasks after 30 minutes by default
|
|
37
|
+
cleanupDelay = 30 * 60 * 1e3;
|
|
38
|
+
logger;
|
|
39
|
+
app;
|
|
40
|
+
setLogger(logger) {
|
|
41
|
+
this.logger = logger;
|
|
42
|
+
}
|
|
43
|
+
setApp(app) {
|
|
44
|
+
this.app = app;
|
|
45
|
+
}
|
|
46
|
+
scheduleCleanup(taskId) {
|
|
47
|
+
setTimeout(() => {
|
|
48
|
+
this.tasks.delete(taskId);
|
|
49
|
+
this.logger.debug(`Task ${taskId} cleaned up after ${this.cleanupDelay}ms`);
|
|
50
|
+
}, this.cleanupDelay);
|
|
51
|
+
}
|
|
52
|
+
constructor() {
|
|
53
|
+
super();
|
|
54
|
+
}
|
|
55
|
+
async cancelTask(taskId) {
|
|
56
|
+
const task = this.tasks.get(taskId);
|
|
57
|
+
if (!task) {
|
|
58
|
+
this.logger.warn(`Attempted to cancel non-existent task ${taskId}`);
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
this.logger.info(`Cancelling task ${taskId}, type: ${task.constructor.name}, tags: ${JSON.stringify(task.tags)}`);
|
|
62
|
+
return task.cancel();
|
|
63
|
+
}
|
|
64
|
+
createTask(options) {
|
|
65
|
+
const taskType = this.taskTypes.get(options.type);
|
|
66
|
+
if (!taskType) {
|
|
67
|
+
this.logger.error(`Task type not found: ${options.type}, params: ${JSON.stringify(options.params)}`);
|
|
68
|
+
throw new Error(`Task type ${options.type} not found`);
|
|
69
|
+
}
|
|
70
|
+
this.logger.info(
|
|
71
|
+
`Creating task of type: ${options.type}, params: ${JSON.stringify(options.params)}, tags: ${JSON.stringify(
|
|
72
|
+
options.tags
|
|
73
|
+
)}`
|
|
74
|
+
);
|
|
75
|
+
const task = new taskType(options.params, options.tags);
|
|
76
|
+
task.title = options.title;
|
|
77
|
+
task.setLogger(this.logger);
|
|
78
|
+
task.setApp(this.app);
|
|
79
|
+
task.setContext(options.context);
|
|
80
|
+
this.tasks.set(task.taskId, task);
|
|
81
|
+
this.logger.info(
|
|
82
|
+
`Created new task ${task.taskId} of type ${options.type}, params: ${JSON.stringify(
|
|
83
|
+
options.params
|
|
84
|
+
)}, tags: ${JSON.stringify(options.tags)}, title: ${task.title}`
|
|
85
|
+
);
|
|
86
|
+
this.emit("taskCreated", { task });
|
|
87
|
+
task.on("progress", (progress) => {
|
|
88
|
+
this.logger.debug(`Task ${task.taskId} progress: ${progress}`);
|
|
89
|
+
this.emit("taskProgress", { task, progress });
|
|
90
|
+
});
|
|
91
|
+
task.on("statusChange", (status) => {
|
|
92
|
+
if (["success", "failed"].includes(status.type)) {
|
|
93
|
+
this.scheduleCleanup(task.taskId);
|
|
94
|
+
} else if (status.type === "cancelled") {
|
|
95
|
+
this.tasks.delete(task.taskId);
|
|
96
|
+
}
|
|
97
|
+
this.emit("taskStatusChange", { task, status });
|
|
98
|
+
});
|
|
99
|
+
return task;
|
|
100
|
+
}
|
|
101
|
+
getTask(taskId) {
|
|
102
|
+
const task = this.tasks.get(taskId);
|
|
103
|
+
if (!task) {
|
|
104
|
+
this.logger.debug(`Task not found: ${taskId}`);
|
|
105
|
+
return void 0;
|
|
106
|
+
}
|
|
107
|
+
this.logger.debug(`Retrieved task ${taskId}, type: ${task.constructor.name}, status: ${task.status.type}`);
|
|
108
|
+
return task;
|
|
109
|
+
}
|
|
110
|
+
async getTaskStatus(taskId) {
|
|
111
|
+
const task = this.tasks.get(taskId);
|
|
112
|
+
if (!task) {
|
|
113
|
+
this.logger.warn(`Attempted to get status of non-existent task ${taskId}`);
|
|
114
|
+
throw new Error(`Task ${taskId} not found`);
|
|
115
|
+
}
|
|
116
|
+
this.logger.debug(`Getting status for task ${taskId}, current status: ${task.status.type}`);
|
|
117
|
+
return task.status;
|
|
118
|
+
}
|
|
119
|
+
registerTaskType(taskType) {
|
|
120
|
+
this.logger.info(`Registering task type: ${taskType.type}`);
|
|
121
|
+
this.taskTypes.set(taskType.type, taskType);
|
|
122
|
+
}
|
|
123
|
+
async getTasksByTag(tagKey, tagValue) {
|
|
124
|
+
this.logger.debug(`Getting tasks by tag - key: ${tagKey}, value: ${tagValue}`);
|
|
125
|
+
const tasks = Array.from(this.tasks.values()).filter((task) => {
|
|
126
|
+
return task.tags[tagKey] == tagValue;
|
|
127
|
+
});
|
|
128
|
+
this.logger.debug(`Found ${tasks.length} tasks with tag ${tagKey}=${tagValue}`);
|
|
129
|
+
return tasks;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
133
|
+
0 && (module.exports = {
|
|
134
|
+
BaseTaskManager
|
|
135
|
+
});
|
|
@@ -0,0 +1,121 @@
|
|
|
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 __create = Object.create;
|
|
11
|
+
var __defProp = Object.defineProperty;
|
|
12
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
13
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
14
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
15
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
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 __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
29
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
30
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
31
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
32
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
33
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
34
|
+
mod
|
|
35
|
+
));
|
|
36
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
37
|
+
var command_task_type_exports = {};
|
|
38
|
+
__export(command_task_type_exports, {
|
|
39
|
+
CommandTaskType: () => CommandTaskType
|
|
40
|
+
});
|
|
41
|
+
module.exports = __toCommonJS(command_task_type_exports);
|
|
42
|
+
var import_async_task_manager = require("./interfaces/async-task-manager");
|
|
43
|
+
var import_node_process = __toESM(require("node:process"));
|
|
44
|
+
var import_worker_threads = require("worker_threads");
|
|
45
|
+
var import_path = __toESM(require("path"));
|
|
46
|
+
var import_task_type = require("./task-type");
|
|
47
|
+
class CommandTaskType extends import_task_type.TaskType {
|
|
48
|
+
static type = "command";
|
|
49
|
+
workerThread;
|
|
50
|
+
async execute() {
|
|
51
|
+
var _a;
|
|
52
|
+
const { argv } = this.options;
|
|
53
|
+
const isDev = (((_a = import_node_process.default.argv[1]) == null ? void 0 : _a.endsWith(".ts")) || import_node_process.default.argv[1].includes("tinypool")) ?? false;
|
|
54
|
+
const appRoot = import_node_process.default.env.APP_PACKAGE_ROOT || "packages/core/app";
|
|
55
|
+
const workerPath = import_path.default.resolve(import_node_process.default.cwd(), appRoot, isDev ? "src/index.ts" : "lib/index.js");
|
|
56
|
+
const workerPromise = new Promise((resolve, reject) => {
|
|
57
|
+
var _a2, _b;
|
|
58
|
+
try {
|
|
59
|
+
(_a2 = this.logger) == null ? void 0 : _a2.info(
|
|
60
|
+
`Creating worker for task ${this.taskId} - path: ${workerPath}, argv: ${JSON.stringify(
|
|
61
|
+
argv
|
|
62
|
+
)}, isDev: ${isDev}`
|
|
63
|
+
);
|
|
64
|
+
const worker = new import_worker_threads.Worker(workerPath, {
|
|
65
|
+
execArgv: isDev ? ["--require", "tsx/cjs"] : [],
|
|
66
|
+
workerData: {
|
|
67
|
+
argv
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
this.workerThread = worker;
|
|
71
|
+
(_b = this.logger) == null ? void 0 : _b.debug(`Worker created successfully for task ${this.taskId}`);
|
|
72
|
+
let isCancelling = false;
|
|
73
|
+
this.abortController.signal.addEventListener("abort", () => {
|
|
74
|
+
var _a3;
|
|
75
|
+
isCancelling = true;
|
|
76
|
+
(_a3 = this.logger) == null ? void 0 : _a3.info(`Terminating worker for task ${this.taskId} due to cancellation`);
|
|
77
|
+
worker.terminate();
|
|
78
|
+
});
|
|
79
|
+
worker.on("message", (message) => {
|
|
80
|
+
var _a3, _b2;
|
|
81
|
+
(_a3 = this.logger) == null ? void 0 : _a3.debug(`Worker message received for task ${this.taskId} - type: ${message.type}`);
|
|
82
|
+
if (message.type === "progress") {
|
|
83
|
+
this.reportProgress(message.payload);
|
|
84
|
+
}
|
|
85
|
+
if (message.type === "success") {
|
|
86
|
+
(_b2 = this.logger) == null ? void 0 : _b2.info(
|
|
87
|
+
`Worker completed successfully for task ${this.taskId} with payload: ${JSON.stringify(message.payload)}`
|
|
88
|
+
);
|
|
89
|
+
resolve(message.payload);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
worker.on("error", (error) => {
|
|
93
|
+
var _a3;
|
|
94
|
+
(_a3 = this.logger) == null ? void 0 : _a3.error(`Worker error for task ${this.taskId}`, error);
|
|
95
|
+
reject(error);
|
|
96
|
+
});
|
|
97
|
+
worker.on("exit", (code) => {
|
|
98
|
+
var _a3;
|
|
99
|
+
(_a3 = this.logger) == null ? void 0 : _a3.info(`Worker exited for task ${this.taskId} with code ${code}`);
|
|
100
|
+
if (isCancelling) {
|
|
101
|
+
reject(new import_async_task_manager.CancelError());
|
|
102
|
+
} else if (code !== 0) {
|
|
103
|
+
reject(new Error(`Worker stopped with exit code ${code}`));
|
|
104
|
+
} else {
|
|
105
|
+
resolve(code);
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
worker.on("messageerror", (error) => {
|
|
109
|
+
reject(error);
|
|
110
|
+
});
|
|
111
|
+
} catch (error) {
|
|
112
|
+
reject(error);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
return workerPromise;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
119
|
+
0 && (module.exports = {
|
|
120
|
+
CommandTaskType
|
|
121
|
+
});
|
|
@@ -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 __create = Object.create;
|
|
11
|
+
var __defProp = Object.defineProperty;
|
|
12
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
13
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
14
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
15
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
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 __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
29
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
30
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
31
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
32
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
33
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
34
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
35
|
+
mod
|
|
36
|
+
));
|
|
37
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
38
|
+
var server_exports = {};
|
|
39
|
+
__export(server_exports, {
|
|
40
|
+
default: () => import_plugin.default
|
|
41
|
+
});
|
|
42
|
+
module.exports = __toCommonJS(server_exports);
|
|
43
|
+
__reExport(server_exports, require("./interfaces/async-task-manager"), module.exports);
|
|
44
|
+
__reExport(server_exports, require("./static-import"), module.exports);
|
|
45
|
+
var import_plugin = __toESM(require("./plugin"));
|
|
46
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
47
|
+
0 && (module.exports = {
|
|
48
|
+
...require("./interfaces/async-task-manager"),
|
|
49
|
+
...require("./static-import")
|
|
50
|
+
});
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { Logger } from '@nocobase/logger';
|
|
3
|
+
import { ITask, TaskConstructor } from './task';
|
|
4
|
+
import { Application } from '@nocobase/server';
|
|
5
|
+
import { EventEmitter } from 'events';
|
|
6
|
+
export type TaskOptions = any;
|
|
7
|
+
export interface CreateTaskOptions {
|
|
8
|
+
type: string;
|
|
9
|
+
params: TaskOptions;
|
|
10
|
+
tags?: Record<string, string>;
|
|
11
|
+
title?: {
|
|
12
|
+
actionType: string;
|
|
13
|
+
collection: string;
|
|
14
|
+
dataSource: string;
|
|
15
|
+
};
|
|
16
|
+
context?: any;
|
|
17
|
+
}
|
|
18
|
+
export type TaskId = string;
|
|
19
|
+
export type TaskStatus = PendingStatus | SuccessStatus<any> | RunningStatus | FailedStatus | CancelledStatus;
|
|
20
|
+
export type ProgressIndicator = 'spinner' | 'progress' | 'success' | 'error';
|
|
21
|
+
export interface PendingStatus {
|
|
22
|
+
type: 'pending';
|
|
23
|
+
indicator?: 'spinner';
|
|
24
|
+
}
|
|
25
|
+
export interface SuccessStatus<T = any> {
|
|
26
|
+
type: 'success';
|
|
27
|
+
indicator?: 'success';
|
|
28
|
+
resultType?: 'file' | 'data';
|
|
29
|
+
payload?: T;
|
|
30
|
+
}
|
|
31
|
+
export interface RunningStatus {
|
|
32
|
+
type: 'running';
|
|
33
|
+
indicator: 'progress';
|
|
34
|
+
}
|
|
35
|
+
export interface FailedStatus {
|
|
36
|
+
type: 'failed';
|
|
37
|
+
indicator?: 'error';
|
|
38
|
+
errors: Array<{
|
|
39
|
+
message: string;
|
|
40
|
+
code?: number;
|
|
41
|
+
}>;
|
|
42
|
+
}
|
|
43
|
+
export interface CancelledStatus {
|
|
44
|
+
type: 'cancelled';
|
|
45
|
+
}
|
|
46
|
+
export interface AsyncTasksManager extends EventEmitter {
|
|
47
|
+
setLogger(logger: Logger): void;
|
|
48
|
+
setApp(app: Application): void;
|
|
49
|
+
registerTaskType(taskType: TaskConstructor): void;
|
|
50
|
+
createTask<T>(options: CreateTaskOptions): ITask;
|
|
51
|
+
getTasksByTag(tagKey: string, tagValue: string): Promise<ITask[]>;
|
|
52
|
+
cancelTask(taskId: TaskId): Promise<boolean>;
|
|
53
|
+
getTaskStatus(taskId: TaskId): Promise<TaskStatus>;
|
|
54
|
+
getTask(taskId: TaskId): ITask | undefined;
|
|
55
|
+
}
|
|
56
|
+
export declare class CancelError extends Error {
|
|
57
|
+
constructor(message?: string);
|
|
58
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
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 __export = (target, all) => {
|
|
15
|
+
for (var name in all)
|
|
16
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
17
|
+
};
|
|
18
|
+
var __copyProps = (to, from, except, desc) => {
|
|
19
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
20
|
+
for (let key of __getOwnPropNames(from))
|
|
21
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
22
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
23
|
+
}
|
|
24
|
+
return to;
|
|
25
|
+
};
|
|
26
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
27
|
+
var async_task_manager_exports = {};
|
|
28
|
+
__export(async_task_manager_exports, {
|
|
29
|
+
CancelError: () => CancelError
|
|
30
|
+
});
|
|
31
|
+
module.exports = __toCommonJS(async_task_manager_exports);
|
|
32
|
+
class CancelError extends Error {
|
|
33
|
+
constructor(message = "Task cancelled") {
|
|
34
|
+
super(message);
|
|
35
|
+
this.name = "CancelError";
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
39
|
+
0 && (module.exports = {
|
|
40
|
+
CancelError
|
|
41
|
+
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { Logger } from '@nocobase/logger';
|
|
3
|
+
import { TaskStatus } from './async-task-manager';
|
|
4
|
+
import { EventEmitter } from 'events';
|
|
5
|
+
import { Application } from '@nocobase/server';
|
|
6
|
+
export interface ITask extends EventEmitter {
|
|
7
|
+
taskId: string;
|
|
8
|
+
status: TaskStatus;
|
|
9
|
+
progress: {
|
|
10
|
+
total: number;
|
|
11
|
+
current: number;
|
|
12
|
+
};
|
|
13
|
+
startedAt: Date;
|
|
14
|
+
fulfilledAt: Date;
|
|
15
|
+
tags: Record<string, string>;
|
|
16
|
+
createdAt: Date;
|
|
17
|
+
title?: any;
|
|
18
|
+
isCancelled: boolean;
|
|
19
|
+
context?: any;
|
|
20
|
+
setLogger(logger: Logger): void;
|
|
21
|
+
setApp(app: Application): void;
|
|
22
|
+
setContext(context: any): void;
|
|
23
|
+
cancel(): Promise<boolean>;
|
|
24
|
+
execute(): Promise<any>;
|
|
25
|
+
reportProgress(progress: {
|
|
26
|
+
total: number;
|
|
27
|
+
current: number;
|
|
28
|
+
}): void;
|
|
29
|
+
run(): Promise<void>;
|
|
30
|
+
toJSON(options?: {
|
|
31
|
+
raw?: boolean;
|
|
32
|
+
}): any;
|
|
33
|
+
}
|
|
34
|
+
export interface TaskConstructor {
|
|
35
|
+
type: string;
|
|
36
|
+
new (options: any, tags?: Record<string, string>): ITask;
|
|
37
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
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 __copyProps = (to, from, except, desc) => {
|
|
15
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
16
|
+
for (let key of __getOwnPropNames(from))
|
|
17
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
18
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
19
|
+
}
|
|
20
|
+
return to;
|
|
21
|
+
};
|
|
22
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
23
|
+
var task_exports = {};
|
|
24
|
+
module.exports = __toCommonJS(task_exports);
|
|
@@ -0,0 +1,163 @@
|
|
|
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 __create = Object.create;
|
|
11
|
+
var __defProp = Object.defineProperty;
|
|
12
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
13
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
14
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
15
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
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 __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
29
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
30
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
31
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
32
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
33
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
34
|
+
mod
|
|
35
|
+
));
|
|
36
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
37
|
+
var plugin_exports = {};
|
|
38
|
+
__export(plugin_exports, {
|
|
39
|
+
PluginAsyncExportServer: () => PluginAsyncExportServer,
|
|
40
|
+
default: () => plugin_default
|
|
41
|
+
});
|
|
42
|
+
module.exports = __toCommonJS(plugin_exports);
|
|
43
|
+
var import_server = require("@nocobase/server");
|
|
44
|
+
var import_base_task_manager = require("./base-task-manager");
|
|
45
|
+
var import_command_task_type = require("./command-task-type");
|
|
46
|
+
var import_async_tasks = __toESM(require("./resourcers/async-tasks"));
|
|
47
|
+
class PluginAsyncExportServer extends import_server.Plugin {
|
|
48
|
+
async afterAdd() {
|
|
49
|
+
}
|
|
50
|
+
async beforeLoad() {
|
|
51
|
+
this.app.container.register("AsyncTaskManager", () => {
|
|
52
|
+
const manager = new import_base_task_manager.BaseTaskManager();
|
|
53
|
+
manager.setLogger(this.app.logger);
|
|
54
|
+
manager.setApp(this.app);
|
|
55
|
+
return manager;
|
|
56
|
+
});
|
|
57
|
+
this.app.container.get("AsyncTaskManager").registerTaskType(import_command_task_type.CommandTaskType);
|
|
58
|
+
this.app.acl.allow("asyncTasks", ["get", "fetchFile"], "loggedIn");
|
|
59
|
+
}
|
|
60
|
+
async load() {
|
|
61
|
+
this.app.resourceManager.define(import_async_tasks.default);
|
|
62
|
+
const asyncTaskManager = this.app.container.get("AsyncTaskManager");
|
|
63
|
+
this.app.on(`ws:message:request:async-tasks:list`, async (message) => {
|
|
64
|
+
const { tags } = message;
|
|
65
|
+
this.app.logger.info(`Received request for async tasks with tags: ${JSON.stringify(tags)}`);
|
|
66
|
+
const userTag = tags == null ? void 0 : tags.find((tag) => tag.startsWith("userId#"));
|
|
67
|
+
const userId = userTag ? userTag.split("#")[1] : null;
|
|
68
|
+
if (userId) {
|
|
69
|
+
this.app.logger.info(`Fetching tasks for userId: ${userId}`);
|
|
70
|
+
const tasks = await asyncTaskManager.getTasksByTag("userId", userId);
|
|
71
|
+
this.app.logger.info(`Found ${tasks.length} tasks for userId: ${userId}`);
|
|
72
|
+
this.app.emit("ws:sendToTag", {
|
|
73
|
+
tagKey: "userId",
|
|
74
|
+
tagValue: userId,
|
|
75
|
+
message: {
|
|
76
|
+
type: "async-tasks",
|
|
77
|
+
payload: tasks.map((task) => task.toJSON())
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
} else {
|
|
81
|
+
this.app.logger.warn(`No userId found in message tags: ${JSON.stringify(tags)}`);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
asyncTaskManager.on("taskCreated", ({ task }) => {
|
|
85
|
+
const userId = task.tags["userId"];
|
|
86
|
+
if (userId) {
|
|
87
|
+
this.app.emit("ws:sendToTag", {
|
|
88
|
+
tagKey: "userId",
|
|
89
|
+
tagValue: userId,
|
|
90
|
+
message: {
|
|
91
|
+
type: "async-tasks:created",
|
|
92
|
+
payload: task.toJSON()
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
asyncTaskManager.on("taskProgress", ({ task, progress }) => {
|
|
98
|
+
const userId = task.tags["userId"];
|
|
99
|
+
if (userId) {
|
|
100
|
+
this.app.emit("ws:sendToTag", {
|
|
101
|
+
tagKey: "userId",
|
|
102
|
+
tagValue: userId,
|
|
103
|
+
message: {
|
|
104
|
+
type: "async-tasks:progress",
|
|
105
|
+
payload: {
|
|
106
|
+
taskId: task.taskId,
|
|
107
|
+
progress
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
asyncTaskManager.on("taskStatusChange", ({ task, status }) => {
|
|
114
|
+
const userId = task.tags["userId"];
|
|
115
|
+
if (userId) {
|
|
116
|
+
this.app.emit("ws:sendToTag", {
|
|
117
|
+
tagKey: "userId",
|
|
118
|
+
tagValue: userId,
|
|
119
|
+
message: {
|
|
120
|
+
type: "async-tasks:status",
|
|
121
|
+
payload: {
|
|
122
|
+
taskId: task.taskId,
|
|
123
|
+
status: task.toJSON().status
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
asyncTaskManager.on("taskStatusChange", ({ status }) => {
|
|
130
|
+
if (status.type === "success") {
|
|
131
|
+
this.app.emit("workflow:dispatch");
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
this.app.on("ws:message:request:async-tasks:cancel", async (message) => {
|
|
135
|
+
const { payload, tags } = message;
|
|
136
|
+
const { taskId } = payload;
|
|
137
|
+
const userTag = tags == null ? void 0 : tags.find((tag) => tag.startsWith("userId#"));
|
|
138
|
+
const userId = userTag ? userTag.split("#")[1] : null;
|
|
139
|
+
if (userId) {
|
|
140
|
+
const task = asyncTaskManager.getTask(taskId);
|
|
141
|
+
if (task.tags["userId"] != userId) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const cancelled = await asyncTaskManager.cancelTask(taskId);
|
|
145
|
+
if (cancelled) {
|
|
146
|
+
this.app.emit("ws:sendToTag", {
|
|
147
|
+
tagKey: "userId",
|
|
148
|
+
tagValue: userId,
|
|
149
|
+
message: {
|
|
150
|
+
type: "async-tasks:cancelled",
|
|
151
|
+
payload: { taskId }
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
var plugin_default = PluginAsyncExportServer;
|
|
160
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
161
|
+
0 && (module.exports = {
|
|
162
|
+
PluginAsyncExportServer
|
|
163
|
+
});
|