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.
Files changed (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +2 -0
  3. package/bun.lock +730 -0
  4. package/index.ts +1 -0
  5. package/jest.config.js +8 -0
  6. package/package.json +42 -0
  7. package/src/client/analysis.ts +377 -0
  8. package/src/client/client.ts +230 -0
  9. package/src/client/cluster.ts +125 -0
  10. package/src/client/execute.ts +210 -0
  11. package/src/client/http.ts +45 -0
  12. package/src/client/javascript.ts +535 -0
  13. package/src/client/job_execute.ts +216 -0
  14. package/src/client/job_parameter.ts +41 -0
  15. package/src/client/os.ts +210 -0
  16. package/src/client/parameter.ts +58 -0
  17. package/src/client/resource.ts +121 -0
  18. package/src/client/shell.ts +147 -0
  19. package/src/interface/base.ts +82 -0
  20. package/src/interface/bus.ts +144 -0
  21. package/src/interface/enum.ts +181 -0
  22. package/src/interface/execute.ts +47 -0
  23. package/src/interface/record.ts +131 -0
  24. package/src/interface/server.ts +91 -0
  25. package/src/interface/struct.ts +292 -0
  26. package/src/interface/table.ts +34 -0
  27. package/src/interface/ui.ts +35 -0
  28. package/src/interface.ts +50 -0
  29. package/src/lan/en.json +395 -0
  30. package/src/lan/zh_TW.json +395 -0
  31. package/src/plugins/i18n.ts +20 -0
  32. package/src/script/console_manager.ts +135 -0
  33. package/src/script/console_server_manager.ts +46 -0
  34. package/src/script/execute/base.ts +309 -0
  35. package/src/script/execute/feedback.ts +212 -0
  36. package/src/script/execute/region_job.ts +14 -0
  37. package/src/script/execute/region_project.ts +23 -0
  38. package/src/script/execute/region_subtask.ts +14 -0
  39. package/src/script/execute/region_task.ts +23 -0
  40. package/src/script/execute/runner.ts +339 -0
  41. package/src/script/execute/util_parser.ts +175 -0
  42. package/src/script/execute_manager.ts +348 -0
  43. package/src/script/socket_manager.ts +329 -0
  44. package/src/script/webhook_manager.ts +6 -0
  45. package/src/script/webhook_server_manager.ts +102 -0
  46. package/src/util/server/console_handle.ts +248 -0
  47. package/src/util/server/log_handle.ts +194 -0
  48. package/test/TEST.ts +63 -0
  49. package/test/client/execute.test.ts +54 -0
  50. package/test/client/javascript.test.ts +78 -0
  51. package/test/client/server.test.ts +26 -0
  52. package/test/client/task.test.ts +136 -0
  53. package/test/script/parser.test.ts +110 -0
  54. package/test/script/socket.test.ts +27 -0
  55. 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
+ }