verteilen-core 1.0.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/LICENSE +21 -0
- package/README.md +2 -0
- package/bun.lock +730 -0
- package/index.ts +1 -0
- package/jest.config.js +8 -0
- package/package.json +42 -0
- package/src/client/analysis.ts +377 -0
- package/src/client/client.ts +230 -0
- package/src/client/cluster.ts +125 -0
- package/src/client/execute.ts +210 -0
- package/src/client/http.ts +45 -0
- package/src/client/javascript.ts +535 -0
- package/src/client/job_execute.ts +216 -0
- package/src/client/job_parameter.ts +41 -0
- package/src/client/os.ts +210 -0
- package/src/client/parameter.ts +58 -0
- package/src/client/resource.ts +121 -0
- package/src/client/shell.ts +147 -0
- package/src/interface/base.ts +82 -0
- package/src/interface/bus.ts +144 -0
- package/src/interface/enum.ts +181 -0
- package/src/interface/execute.ts +47 -0
- package/src/interface/record.ts +131 -0
- package/src/interface/server.ts +91 -0
- package/src/interface/struct.ts +292 -0
- package/src/interface/table.ts +34 -0
- package/src/interface/ui.ts +35 -0
- package/src/interface.ts +50 -0
- package/src/lan/en.json +395 -0
- package/src/lan/zh_TW.json +395 -0
- package/src/plugins/i18n.ts +20 -0
- package/src/script/console_manager.ts +135 -0
- package/src/script/console_server_manager.ts +46 -0
- package/src/script/execute/base.ts +309 -0
- package/src/script/execute/feedback.ts +212 -0
- package/src/script/execute/region_job.ts +14 -0
- package/src/script/execute/region_project.ts +23 -0
- package/src/script/execute/region_subtask.ts +14 -0
- package/src/script/execute/region_task.ts +23 -0
- package/src/script/execute/runner.ts +339 -0
- package/src/script/execute/util_parser.ts +175 -0
- package/src/script/execute_manager.ts +348 -0
- package/src/script/socket_manager.ts +329 -0
- package/src/script/webhook_manager.ts +6 -0
- package/src/script/webhook_server_manager.ts +102 -0
- package/src/util/server/console_handle.ts +248 -0
- package/src/util/server/log_handle.ts +194 -0
- package/test/TEST.ts +63 -0
- package/test/client/execute.test.ts +54 -0
- package/test/client/javascript.test.ts +78 -0
- package/test/client/server.test.ts +26 -0
- package/test/client/task.test.ts +136 -0
- package/test/script/parser.test.ts +110 -0
- package/test/script/socket.test.ts +27 -0
- package/tsconfig.json +15 -0
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
// ========================
|
|
2
|
+
//
|
|
3
|
+
// Share Codebase
|
|
4
|
+
//
|
|
5
|
+
// ========================
|
|
6
|
+
import { v6 as uuid6 } from 'uuid';
|
|
7
|
+
import { CronJobState, DataType, ExecuteProxy, ExecuteState, Header, Job, JobCategory, JobType, JobType2, Libraries, Messager, Parameter, Project, Record, Task, WebsocketPack, WorkState } from "../../interface";
|
|
8
|
+
import { WebsocketManager } from "../socket_manager";
|
|
9
|
+
import { Util_Parser } from './util_parser';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The base class of task scheduler, contain some basic funcationality
|
|
13
|
+
*/
|
|
14
|
+
export class ExecuteManager_Base {
|
|
15
|
+
/**
|
|
16
|
+
* The task scheduler UUID
|
|
17
|
+
*/
|
|
18
|
+
uuid: string
|
|
19
|
+
name: string
|
|
20
|
+
/**
|
|
21
|
+
* Register record\
|
|
22
|
+
* This record holds the project data you want to process
|
|
23
|
+
*/
|
|
24
|
+
record: Record
|
|
25
|
+
/**
|
|
26
|
+
* Current select task\
|
|
27
|
+
* If it's undefined, it means:
|
|
28
|
+
* * It's finish the current task
|
|
29
|
+
* * It has not start processing yet
|
|
30
|
+
*/
|
|
31
|
+
current_t:Task | undefined = undefined
|
|
32
|
+
/**
|
|
33
|
+
* Current select project\
|
|
34
|
+
* If it's undefined, it means:
|
|
35
|
+
* * It's finish the current project
|
|
36
|
+
* * It has not start processing yet
|
|
37
|
+
*/
|
|
38
|
+
current_p:Project | undefined = undefined
|
|
39
|
+
/**
|
|
40
|
+
* The list of projects you want to process\
|
|
41
|
+
* Each project UUID should be unique by now\
|
|
42
|
+
* Prevent findIndex error, When there is repeat project source
|
|
43
|
+
*/
|
|
44
|
+
current_projects:Array<Project> = []
|
|
45
|
+
/**
|
|
46
|
+
* The connection nodes list
|
|
47
|
+
*/
|
|
48
|
+
current_nodes:Array<WebsocketPack> = []
|
|
49
|
+
/**
|
|
50
|
+
* Cron job type execute record
|
|
51
|
+
*/
|
|
52
|
+
current_cron:Array<CronJobState> = []
|
|
53
|
+
/**
|
|
54
|
+
* Single job type execute record
|
|
55
|
+
*/
|
|
56
|
+
current_job:Array<WorkState> = []
|
|
57
|
+
/**
|
|
58
|
+
* Current execute task use multithread setting
|
|
59
|
+
*/
|
|
60
|
+
current_multithread = 1
|
|
61
|
+
current_task_count = -1
|
|
62
|
+
/**
|
|
63
|
+
* * NONE: Not yet start
|
|
64
|
+
* * RUNNING: In the processing stage
|
|
65
|
+
* * FINISH: Everything is finish processing
|
|
66
|
+
*/
|
|
67
|
+
state:ExecuteState = ExecuteState.NONE
|
|
68
|
+
/**
|
|
69
|
+
* * NONE: Not yet start
|
|
70
|
+
* * RUNNING: In the processing stage
|
|
71
|
+
* * FINISH: Everything is finish processing
|
|
72
|
+
*/
|
|
73
|
+
t_state:ExecuteState = ExecuteState.NONE
|
|
74
|
+
jobstack = 0
|
|
75
|
+
first = false
|
|
76
|
+
libs:Libraries | undefined = undefined
|
|
77
|
+
proxy:ExecuteProxy | undefined = undefined
|
|
78
|
+
localPara: Parameter | undefined = undefined
|
|
79
|
+
|
|
80
|
+
websocket_manager:WebsocketManager
|
|
81
|
+
messager_log:Messager
|
|
82
|
+
|
|
83
|
+
constructor(_name:string, _websocket_manager:WebsocketManager, _messager_log:Messager, _record:Record) {
|
|
84
|
+
this.name = _name
|
|
85
|
+
this.uuid = uuid6()
|
|
86
|
+
this.record = _record
|
|
87
|
+
this.websocket_manager = _websocket_manager
|
|
88
|
+
this.messager_log = _messager_log
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* This will let nodes update the parameter and lib
|
|
93
|
+
* @param target
|
|
94
|
+
*/
|
|
95
|
+
protected sync_local_para = (target:Parameter) => {
|
|
96
|
+
this.current_nodes.forEach(x => this.sync_para(target, x))
|
|
97
|
+
this.proxy?.updateParameter(target)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
//#region Helper
|
|
101
|
+
protected sync_para = (target:Parameter, source:WebsocketPack) => {
|
|
102
|
+
const h:Header = {
|
|
103
|
+
name: 'set_parameter',
|
|
104
|
+
channel: this.uuid,
|
|
105
|
+
data: target
|
|
106
|
+
}
|
|
107
|
+
const h2:Header = {
|
|
108
|
+
name: 'set_libs',
|
|
109
|
+
channel: this.uuid,
|
|
110
|
+
data: this.libs
|
|
111
|
+
}
|
|
112
|
+
source.websocket.send(JSON.stringify(h))
|
|
113
|
+
source.websocket.send(JSON.stringify(h2))
|
|
114
|
+
}
|
|
115
|
+
protected release = (source:WebsocketPack) => {
|
|
116
|
+
const h:Header = {
|
|
117
|
+
name: 'release',
|
|
118
|
+
channel: this.uuid,
|
|
119
|
+
data: 0
|
|
120
|
+
}
|
|
121
|
+
source.websocket.send(JSON.stringify(h))
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Check all the cronjob is finish or not
|
|
125
|
+
*/
|
|
126
|
+
protected check_all_cron_end = () => {
|
|
127
|
+
return this.current_cron.filter(x => !this.check_cron_end(x)).length == 0
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Check input cronjob is finish or not
|
|
131
|
+
* @param cron target cronjob instance
|
|
132
|
+
*/
|
|
133
|
+
protected check_cron_end = (cron:CronJobState) => {
|
|
134
|
+
return cron.work.filter(x => x.state == ExecuteState.RUNNING || x.state == ExecuteState.NONE).length == 0
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Check current single is finish or not
|
|
138
|
+
*/
|
|
139
|
+
protected check_single_end = () => {
|
|
140
|
+
if(this.current_t == undefined) return false
|
|
141
|
+
return this.current_job.length == this.current_t.jobs.length &&
|
|
142
|
+
this.current_job.filter(y => y.state == ExecuteState.RUNNING || y.state == ExecuteState.NONE).length == 0
|
|
143
|
+
}
|
|
144
|
+
//#endregion
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
//#region Utility
|
|
148
|
+
/**
|
|
149
|
+
* Project format checking
|
|
150
|
+
* @param projects
|
|
151
|
+
* @returns
|
|
152
|
+
*/
|
|
153
|
+
protected validation = (projects:Array<Project>):boolean => {
|
|
154
|
+
if (this.websocket_manager.targets.length == 0) {
|
|
155
|
+
this.messager_log(`[Execute State] The execute node does not exists`)
|
|
156
|
+
return false
|
|
157
|
+
}
|
|
158
|
+
projects.forEach(x => {
|
|
159
|
+
x.task.forEach(t => {
|
|
160
|
+
if(t.cronjob){
|
|
161
|
+
const index = x.parameter?.containers.findIndex(x => x.name == t.cronjobKey && x.type == DataType.Number) ?? -1
|
|
162
|
+
if(index == -1){
|
|
163
|
+
this.messager_log(`[Execute:CronJob] Project ${x.title} (${x.uuid}), Task ${t.title} (${t.uuid}), Has unknoed parameter: \"${t.cronjobKey}\"`)
|
|
164
|
+
this.messager_log(`[Execute:CronJob] Cron task registerd key not found`)
|
|
165
|
+
return false
|
|
166
|
+
}
|
|
167
|
+
else if (x.parameter?.containers[index].value == 0){
|
|
168
|
+
this.messager_log(`[Execute:CronJob] Project ${x.title} (${x.uuid}), Task ${t.title} (${t.uuid}), Has unknoed parameter: \"${t.cronjobKey}\"`)
|
|
169
|
+
this.messager_log(`[Execute:CronJob] Cron task value must bigger than 0`)
|
|
170
|
+
return false
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
if(t.cronjob && t.multi){
|
|
174
|
+
const index = x.parameter?.containers.findIndex(x => x.name == t.multiKey && x.type == DataType.Number) ?? -1
|
|
175
|
+
if(index == -1){
|
|
176
|
+
this.messager_log(`[Execute:Multi] Project ${x.title} (${x.uuid}), Task ${t.title} (${t.uuid}), Has unknoed parameter: \"${t.multiKey}\"`)
|
|
177
|
+
this.messager_log(`[Execute:Multi] Cron task registerd key not found`)
|
|
178
|
+
return false
|
|
179
|
+
}
|
|
180
|
+
else if (x.parameter?.containers[index].value == 0){
|
|
181
|
+
this.messager_log(`[Execute:Multi] Project ${x.title} (${x.uuid}), Task ${t.title} (${t.uuid}), Has unknoed parameter: \"${t.multiKey}\"`)
|
|
182
|
+
this.messager_log(`[Execute:Multi] Cron task value must bigger than 0`)
|
|
183
|
+
return false
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
})
|
|
187
|
+
})
|
|
188
|
+
return true
|
|
189
|
+
}
|
|
190
|
+
protected filter_lib = (projects:Array<Project>, lib:Libraries):Libraries => {
|
|
191
|
+
const r:Libraries = { libs: [] }
|
|
192
|
+
projects.forEach(x => {
|
|
193
|
+
x.task.forEach(y => {
|
|
194
|
+
y.jobs.forEach(z => {
|
|
195
|
+
let code = -1
|
|
196
|
+
if((z.category == JobCategory.Execution && z.type == JobType.JAVASCRIPT) || (z.category == JobCategory.Condition && z.type == JobType2.JAVASCRIPT)) code = 0
|
|
197
|
+
if(code == -1) return
|
|
198
|
+
z.string_args.forEach(s1 => {
|
|
199
|
+
const target = lib.libs.find(l => l.name == s1)
|
|
200
|
+
if(target != undefined) r.libs.push(target)
|
|
201
|
+
})
|
|
202
|
+
})
|
|
203
|
+
})
|
|
204
|
+
})
|
|
205
|
+
return JSON.parse(JSON.stringify(r))
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Get the multi-core setting\
|
|
209
|
+
* Find in the parameter setting
|
|
210
|
+
* @param key The multi-core-key
|
|
211
|
+
* @returns
|
|
212
|
+
*/
|
|
213
|
+
protected get_task_multi_count = (t:Task):number => {
|
|
214
|
+
const r = this.get_number(t.multiKey)
|
|
215
|
+
return r == -1 ? 1 : r
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Get the task's cronjob count
|
|
219
|
+
*/
|
|
220
|
+
public get_task_state_count(t:Task){
|
|
221
|
+
if(t.setupjob) return this.current_nodes.length
|
|
222
|
+
if (t.cronjob) return this.get_number(t.cronjobKey)
|
|
223
|
+
else return 1
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Find the number in the parameter, this include the expression phrasing
|
|
228
|
+
* @param key The name key
|
|
229
|
+
* @param p Project instance
|
|
230
|
+
* @returns The value, if key cannot be found, it will return -1
|
|
231
|
+
*/
|
|
232
|
+
protected get_number(key:string){
|
|
233
|
+
return ExecuteManager_Base.get_number_global(key, this.localPara)
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
static get_number_global(key:string, localPara:Parameter | undefined){
|
|
237
|
+
const e = ExecuteManager_Base.parameter_update(localPara!)
|
|
238
|
+
const a = e.replacePara(`%{${key}}%`)
|
|
239
|
+
return Number(a)
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Remove dups item in the list
|
|
244
|
+
* @param arr
|
|
245
|
+
* @returns
|
|
246
|
+
*/
|
|
247
|
+
protected removeDups = (arr: any[]): any[] => {
|
|
248
|
+
return [...new Set(arr)];
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Filter out the idle and connection open nodes
|
|
253
|
+
* @returns All idle and open connection nodes
|
|
254
|
+
*/
|
|
255
|
+
protected get_idle = ():Array<WebsocketPack> => {
|
|
256
|
+
return this.current_nodes.filter(x => this.check_socket_state(x) != ExecuteState.RUNNING && x.websocket.readyState == 1)
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Filter out the connection open nodes
|
|
260
|
+
* @returns All open connection nodes
|
|
261
|
+
*/
|
|
262
|
+
protected get_idle_open = ():Array<WebsocketPack> => {
|
|
263
|
+
return this.current_nodes.filter(x => x.websocket.readyState == 1)
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
protected check_socket_state = (target:WebsocketPack) => {
|
|
267
|
+
return target.current_job.length == 0 ? ExecuteState.NONE : ExecuteState.RUNNING
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
static string_args_transform = (task:Task, job:Job, messager_log:Messager, localPara:Parameter, n:number) => {
|
|
271
|
+
let e = ExecuteManager_Base.parameter_update(localPara, n)
|
|
272
|
+
e = ExecuteManager_Base.property_update(task, e)
|
|
273
|
+
|
|
274
|
+
for(let i = 0; i < job.string_args.length; i++){
|
|
275
|
+
const b = job.string_args[i]
|
|
276
|
+
if(b == null || b == undefined || b.length == 0) continue
|
|
277
|
+
if(job.category == JobCategory.Execution && job.type == JobType.CREATE_FILE && i == 1) continue
|
|
278
|
+
job.string_args[i] = e.replacePara(job.string_args[i])
|
|
279
|
+
//messager_log(`String replace: "${b}" -> "${job.string_args[i]}"`)
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
static property_update = (task:Task, e:Util_Parser) => {
|
|
284
|
+
for(let j = 0; j < task.properties.length; j++){
|
|
285
|
+
const target = task.properties[j];
|
|
286
|
+
const times = target.deep ? target.deep : 1
|
|
287
|
+
let act:any = target.expression
|
|
288
|
+
for(let k = 0; k < times; k++){
|
|
289
|
+
act = e.replacePara(`%{${act}}%`)
|
|
290
|
+
}
|
|
291
|
+
e.paras.push({ key: task.properties[j].name, value: act})
|
|
292
|
+
}
|
|
293
|
+
return e
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
static parameter_update = (localPara:Parameter, n?:number) => {
|
|
297
|
+
const e = new Util_Parser([...Util_Parser.to_keyvalue(localPara)])
|
|
298
|
+
if(n != undefined){
|
|
299
|
+
e.paras.push({ key: 'ck', value: n.toString() })
|
|
300
|
+
}
|
|
301
|
+
localPara.containers.forEach((c, index) => {
|
|
302
|
+
if(c.type != DataType.Expression) return
|
|
303
|
+
c.value = e.replacePara(`%{${c.meta}}%`)
|
|
304
|
+
e.paras.find(p => p.key == c.name)!.value = c.value
|
|
305
|
+
})
|
|
306
|
+
return e
|
|
307
|
+
}
|
|
308
|
+
//#endregion
|
|
309
|
+
}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
// ========================
|
|
2
|
+
//
|
|
3
|
+
// Share Codebase
|
|
4
|
+
//
|
|
5
|
+
// ========================
|
|
6
|
+
import { BusAnalysis, CronJobState, DataType, ExecuteState, FeedBack, Header, Setter, Single, WebsocketPack, WorkState } from "../../interface"
|
|
7
|
+
import { ExecuteManager_Base } from "./base"
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Recevied the information from the nodes\
|
|
11
|
+
* This include job feedback and error feedback and pong and other stuff
|
|
12
|
+
*/
|
|
13
|
+
export class ExecuteManager_Feedback extends ExecuteManager_Base{
|
|
14
|
+
/**
|
|
15
|
+
* The analysis method for decoding the information where the nodes is sending
|
|
16
|
+
* @param d Package info
|
|
17
|
+
*/
|
|
18
|
+
Analysis = (d:BusAnalysis) => {
|
|
19
|
+
const targetn = this.current_nodes.find(x => x.uuid == d.c?.uuid)
|
|
20
|
+
if(targetn == undefined) {
|
|
21
|
+
this.messager_log("Not inside")
|
|
22
|
+
return
|
|
23
|
+
}
|
|
24
|
+
const typeMap:{ [key:string]:Function } = {
|
|
25
|
+
'feedback_message': this.feedback_message,
|
|
26
|
+
'feedback_job': this.feedback_job,
|
|
27
|
+
'feedback_string': this.feedback_string,
|
|
28
|
+
'feedback_boolean': this.feedback_boolean,
|
|
29
|
+
'feedback_number': this.feedback_number,
|
|
30
|
+
'feedback_object': this.feedback_object,
|
|
31
|
+
}
|
|
32
|
+
if(typeMap.hasOwnProperty(d.name)){
|
|
33
|
+
const castingFunc = typeMap[d.h.name]
|
|
34
|
+
castingFunc(d.h.data, targetn, d.h.meta)
|
|
35
|
+
}else{
|
|
36
|
+
this.messager_log(`[Source Data Analysis] Decode failed, Unknowed header, name: ${d.name}, meta: ${d.h.meta}`)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
//#region Feedback
|
|
41
|
+
/**
|
|
42
|
+
* Print information, sended by the node worker
|
|
43
|
+
* @param data feedback data, any type
|
|
44
|
+
* @param source The node target
|
|
45
|
+
*/
|
|
46
|
+
private feedback_message = (data:Single, source:WebsocketPack | undefined, meta:string | undefined) => {
|
|
47
|
+
if(source == undefined) {
|
|
48
|
+
this.messager_log("[Server Feedback Warn] source is none")
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
if(this.state == ExecuteState.NONE) {
|
|
52
|
+
this.messager_log("[Server Feedback Warn] state is none, should not received feedback")
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
this.messager_log(`[Execute] Single Received data: ${data.data}, cron length: ${this.current_cron.length}`)
|
|
56
|
+
let index = 0
|
|
57
|
+
if(this.current_cron.length > 0 && meta != undefined){
|
|
58
|
+
const r = this.GetCronAndWork(meta, source)
|
|
59
|
+
const cron:CronJobState | undefined = r[0]
|
|
60
|
+
const work:WorkState | undefined = r[1]
|
|
61
|
+
if(cron != undefined && work != undefined){
|
|
62
|
+
index = cron.id
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const d:FeedBack = {
|
|
66
|
+
node_uuid: source.uuid,
|
|
67
|
+
index: index,
|
|
68
|
+
job_uuid: '',
|
|
69
|
+
runtime_uuid: '',
|
|
70
|
+
meta: 0,
|
|
71
|
+
message: data.data
|
|
72
|
+
}
|
|
73
|
+
this.proxy?.feedbackMessage(d)
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* The job has been finish executing, sended by the node worker
|
|
77
|
+
* @param data feedback data
|
|
78
|
+
* @param source The node target
|
|
79
|
+
*/
|
|
80
|
+
private feedback_job = (data:FeedBack, source:WebsocketPack | undefined) => {
|
|
81
|
+
if(source == undefined) return
|
|
82
|
+
if(this.state == ExecuteState.NONE) return
|
|
83
|
+
this.jobstack = Math.max(this.jobstack - 1, 0)
|
|
84
|
+
if(this.current_t == undefined) {
|
|
85
|
+
console.error("Cannot feedback when task is null")
|
|
86
|
+
return
|
|
87
|
+
}
|
|
88
|
+
this.messager_log(`[Execute] Job Feedback: ${data.job_uuid} ${data.runtime_uuid} ${data.message} ${data.meta}`)
|
|
89
|
+
// If it's a single type work
|
|
90
|
+
|
|
91
|
+
if(this.current_job.length > 0){
|
|
92
|
+
const work = this.current_job.find(x => x.uuid == source.uuid && x.state == ExecuteState.RUNNING)
|
|
93
|
+
if(work == undefined) {
|
|
94
|
+
console.error("Cannot find the feedback container, work", work)
|
|
95
|
+
return
|
|
96
|
+
}
|
|
97
|
+
data.index = 0
|
|
98
|
+
this.proxy?.executeJobFinish([work.job, 0, source.uuid, data.meta])
|
|
99
|
+
work.state = data.meta == 0 ? ExecuteState.FINISH : ExecuteState.ERROR
|
|
100
|
+
if(this.check_single_end()){
|
|
101
|
+
this.proxy?.executeSubtaskFinish([this.current_t!, 0, source.uuid])
|
|
102
|
+
this.messager_log(`[Execute] Subtask finish: ${this.current_t!.uuid}`)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// If it's a cronjob type work
|
|
106
|
+
else if(this.current_cron.length > 0){
|
|
107
|
+
const r = this.GetCronAndWork(data.runtime_uuid, source)
|
|
108
|
+
const cron:CronJobState | undefined = r[0]
|
|
109
|
+
const work:WorkState | undefined = r[1]
|
|
110
|
+
if(cron == undefined || work == undefined) {
|
|
111
|
+
console.error("Cannot find the feedback container, cron or work", data.runtime_uuid, cron, work)
|
|
112
|
+
console.error("Full current cron instance", this.current_cron)
|
|
113
|
+
return
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
this.proxy?.executeJobFinish([work.job, cron.id, source.uuid, data.meta])
|
|
117
|
+
data.index = cron.id
|
|
118
|
+
work.state = data.meta == 0 ? ExecuteState.FINISH : ExecuteState.ERROR
|
|
119
|
+
if(this.check_cron_end(cron)){
|
|
120
|
+
this.proxy?.executeSubtaskFinish([this.current_t, cron.id, cron.uuid ])
|
|
121
|
+
this.messager_log(`[Execute] Subtask finish: ${this.current_t!.uuid}`)
|
|
122
|
+
cron.uuid = ''
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// Reset the state of the node
|
|
126
|
+
const index = source.current_job.findIndex(x => x == data.runtime_uuid)
|
|
127
|
+
if(index == -1){
|
|
128
|
+
this.messager_log(`[Execute] Cannot find runtime uuid: ${data.runtime_uuid} in websocket pack source: ${source.uuid}`)
|
|
129
|
+
}else{
|
|
130
|
+
source.current_job.splice(index, 1)
|
|
131
|
+
}
|
|
132
|
+
data.node_uuid = source.uuid
|
|
133
|
+
this.proxy?.feedbackMessage(data)
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* When one of the node decide to change the parameter of string value
|
|
137
|
+
* @param data The assigner
|
|
138
|
+
*/
|
|
139
|
+
private feedback_string = (data:Setter) => {
|
|
140
|
+
if(this.current_p == undefined) return
|
|
141
|
+
const index = this.localPara!.containers.findIndex(x => x.name == data.key && x.type == DataType.String)
|
|
142
|
+
if(index != -1) this.localPara!.containers[index].value = data.value
|
|
143
|
+
else this.localPara!.containers.push({ name: data.key, value: data.value, type: DataType.String, hidden: true, runtimeOnly: true })
|
|
144
|
+
this.messager_log(`[String Feedback] ${data.key} = ${data.value}`)
|
|
145
|
+
// Sync to other
|
|
146
|
+
const d:Header = { name: 'set_parameter', data: this.localPara!}
|
|
147
|
+
this.current_nodes.forEach(x => x.websocket.send(JSON.stringify(d)))
|
|
148
|
+
this.proxy?.updateParameter(this.localPara!)
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* When one of the node decide to change the parameter of number value
|
|
152
|
+
* @param data The assigner
|
|
153
|
+
*/
|
|
154
|
+
private feedback_number = (data:Setter) => {
|
|
155
|
+
if(this.current_p == undefined) return
|
|
156
|
+
const index = this.localPara!.containers.findIndex(x => x.name == data.key && x.type == DataType.Number)
|
|
157
|
+
if(index != -1) this.localPara!.containers[index].value = data.value
|
|
158
|
+
else this.localPara!.containers.push({ name: data.key, value: data.value, type: DataType.Number, hidden: true, runtimeOnly: true })
|
|
159
|
+
this.messager_log(`[Number Feedback] ${data.key} = ${data.value}`)
|
|
160
|
+
// Sync to other
|
|
161
|
+
const d:Header = { name: 'set_parameter', data: this.localPara!}
|
|
162
|
+
this.current_nodes.forEach(x => x.websocket.send(JSON.stringify(d)))
|
|
163
|
+
this.proxy?.updateParameter(this.localPara!)
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* When one of the node decide to change the parameter of object value
|
|
167
|
+
* @param data The assigner
|
|
168
|
+
*/
|
|
169
|
+
private feedback_object = (data:Setter) => {
|
|
170
|
+
if(this.current_p == undefined) return
|
|
171
|
+
const index = this.localPara!.containers.findIndex(x => x.name == data.key && x.type == DataType.Object)
|
|
172
|
+
if(index != -1) this.localPara!.containers[index].value = data.value
|
|
173
|
+
else this.localPara!.containers.push({ name: data.key, value: data.value, type: DataType.Object, hidden: true, runtimeOnly: true })
|
|
174
|
+
this.messager_log(`[Object Feedback] ${data.key}`)
|
|
175
|
+
// Sync to other
|
|
176
|
+
const d:Header = { name: 'set_parameter', data: this.localPara!}
|
|
177
|
+
this.current_nodes.forEach(x => x.websocket.send(JSON.stringify(d)))
|
|
178
|
+
this.proxy?.updateParameter(this.localPara!)
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* When one of the node decide to change the parameter of boolean value
|
|
182
|
+
* @param data The assigner
|
|
183
|
+
*/
|
|
184
|
+
private feedback_boolean = (data:Setter) => {
|
|
185
|
+
if(this.current_p == undefined) return
|
|
186
|
+
const index = this.localPara!.containers.findIndex(x => x.name == data.key && x.type == DataType.Boolean)
|
|
187
|
+
if(index != -1) this.localPara!.containers[index].value = data.value
|
|
188
|
+
else this.localPara!.containers.push({ name: data.key, value: data.value, type: DataType.Boolean, hidden: true, runtimeOnly: true })
|
|
189
|
+
this.messager_log(`[Boolean Feedback] ${data.key} = ${data.value}`)
|
|
190
|
+
// Sync to other
|
|
191
|
+
const d:Header = { name: 'set_parameter', data: this.localPara!}
|
|
192
|
+
this.current_nodes.forEach(x => x.websocket.send(JSON.stringify(d)))
|
|
193
|
+
this.proxy?.updateParameter(this.localPara!)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
private GetCronAndWork = (runtime:string, source:WebsocketPack):[CronJobState | undefined, WorkState | undefined] => {
|
|
197
|
+
let cron:CronJobState | undefined = undefined
|
|
198
|
+
let work:WorkState | undefined = undefined
|
|
199
|
+
const crons = this.current_cron.filter(x => x.uuid == source.uuid)
|
|
200
|
+
for(let i = 0; i < crons.length; i++){
|
|
201
|
+
const c = crons[i]
|
|
202
|
+
const a = c.work.find(x => x.runtime == runtime)
|
|
203
|
+
if(a != undefined) {
|
|
204
|
+
cron = c
|
|
205
|
+
work = a
|
|
206
|
+
break
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return [cron, work]
|
|
210
|
+
}
|
|
211
|
+
//#endregion
|
|
212
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// ========================
|
|
2
|
+
//
|
|
3
|
+
// Share Codebase
|
|
4
|
+
//
|
|
5
|
+
// ========================
|
|
6
|
+
import { ExecuteManager } from "../execute_manager"
|
|
7
|
+
|
|
8
|
+
export class Region_Job {
|
|
9
|
+
target:ExecuteManager
|
|
10
|
+
|
|
11
|
+
constructor(_target:ExecuteManager){
|
|
12
|
+
this.target = _target
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// ========================
|
|
2
|
+
//
|
|
3
|
+
// Share Codebase
|
|
4
|
+
//
|
|
5
|
+
// ========================
|
|
6
|
+
import { ExecuteState, Project } from "../../interface"
|
|
7
|
+
import { ExecuteManager } from "../execute_manager"
|
|
8
|
+
import { Region_Task } from "./region_task"
|
|
9
|
+
|
|
10
|
+
export class Region_Project {
|
|
11
|
+
target:ExecuteManager
|
|
12
|
+
state: ExecuteState
|
|
13
|
+
project: Project
|
|
14
|
+
task: Region_Task | undefined
|
|
15
|
+
constructor(_target:ExecuteManager, _project:Project){
|
|
16
|
+
this.project = _project
|
|
17
|
+
this.target = _target
|
|
18
|
+
this.state = _project.task.length > 0 ? ExecuteState.NONE : ExecuteState.SKIP
|
|
19
|
+
if(_project.task.length > 0){
|
|
20
|
+
this.task = new Region_Task(_target, _project.task[0])
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// ========================
|
|
2
|
+
//
|
|
3
|
+
// Share Codebase
|
|
4
|
+
//
|
|
5
|
+
// ========================
|
|
6
|
+
import { ExecuteManager } from "../execute_manager"
|
|
7
|
+
|
|
8
|
+
export class Region_Subtask {
|
|
9
|
+
target:ExecuteManager
|
|
10
|
+
|
|
11
|
+
constructor(_target:ExecuteManager){
|
|
12
|
+
this.target = _target
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// ========================
|
|
2
|
+
//
|
|
3
|
+
// Share Codebase
|
|
4
|
+
//
|
|
5
|
+
// ========================
|
|
6
|
+
import { ExecuteState, Task } from "../../interface";
|
|
7
|
+
import { ExecuteManager } from "../execute_manager";
|
|
8
|
+
import { Region_Subtask } from "./region_subtask";
|
|
9
|
+
|
|
10
|
+
export class Region_Task {
|
|
11
|
+
target:ExecuteManager
|
|
12
|
+
state: ExecuteState
|
|
13
|
+
task: Task
|
|
14
|
+
subtask: Region_Subtask | undefined
|
|
15
|
+
constructor(_target:ExecuteManager, _task:Task){
|
|
16
|
+
this.task = _task
|
|
17
|
+
this.target = _target
|
|
18
|
+
this.state = _task.jobs.length > 0 ? ExecuteState.NONE : ExecuteState.SKIP
|
|
19
|
+
if(_task.jobs.length > 0){
|
|
20
|
+
this.subtask = new Region_Subtask(_target)
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|