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,102 @@
1
+ import * as path from 'path';
2
+ import * as ws from 'ws'
3
+ import * as pem from 'pem'
4
+ import * as https from 'https'
5
+ import * as os from 'os'
6
+ import { DATA_FOLDER, Header, Messager, Messager_log, WebHookPORT } from '../interface'
7
+ import { check } from 'tcp-port-used'
8
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs'
9
+
10
+ export class WebhookServerManager {
11
+
12
+ private httpss:https.Server<any> | undefined = undefined
13
+ private server:ws.Server | undefined = undefined
14
+ private sources:Array<WebSocket> = []
15
+ private messager:Messager
16
+ private messager_log:Messager_log
17
+
18
+ constructor(_messager:Messager, _messager_log:Messager_log) {
19
+ this.messager = _messager
20
+ this.messager_log = _messager_log
21
+ }
22
+
23
+ Init = async () => {
24
+ let port_result = WebHookPORT
25
+ let canbeuse = false
26
+
27
+ while(!canbeuse){
28
+ await check(port_result).then(x => {
29
+ canbeuse = !x
30
+ }).catch(err => {
31
+ canbeuse = true
32
+ })
33
+ if(!canbeuse) port_result += 1
34
+ }
35
+
36
+ const pems = await this.get_pem()
37
+ this.httpss = https.createServer({ key: pems[0], cert: pems[1], minVersion: 'TLSv1.2', maxVersion: 'TLSv1.3' }, (req, res) => {
38
+ res.writeHead(200)
39
+ res.end('HTTPS server is running');
40
+ })
41
+ this.httpss.addListener('upgrade', (req, res, head) => console.log('UPGRADE:', req.url))
42
+ this.server = new ws.Server({server: this.httpss})
43
+ this.server.on('listening', () => {
44
+ this.messager_log('[Server] Listen PORT: ' + port_result.toString())
45
+ })
46
+ this.server.on('error', (err) => {
47
+ this.messager_log(`[Server] Error ${err.name}\n\t${err.message}\n\t${err.stack}`)
48
+ })
49
+ this.server.on('close', () => {
50
+ this.messager_log('[Server] Close !')
51
+ this.Release()
52
+ })
53
+ this.server.on('connection', (ws, request) => {
54
+ this.messager_log(`[Server] New Connection detected, ${ws.url}`)
55
+ ws.on('close', (code, reason) => {
56
+ this.messager_log(`[Source] Close ${code} ${reason}`)
57
+ })
58
+ ws.on('error', (err) => {
59
+ this.messager_log(`[Source] Error ${err.name}\n\t${err.message}\n\t${err.stack}`)
60
+ })
61
+ ws.on('open', () => {
62
+ this.messager_log(`[Source] New source is connected, URL: ${ws?.url}`)
63
+ })
64
+ ws.on('message', (data, isBinery) => {
65
+ const h:Header | undefined = JSON.parse(data.toString());
66
+ })
67
+ })
68
+ this.httpss.listen(port_result, () => {
69
+ this.messager_log('[Server] Select Port: ' + port_result.toString())
70
+ })
71
+ }
72
+
73
+ Destroy = () => {
74
+ if(this.server == undefined) return
75
+ this.server.close((err) => {
76
+ this.messager_log(`[Client] Close error ${err}`)
77
+ })
78
+ this.Release()
79
+ }
80
+
81
+ Release = () => {
82
+
83
+ }
84
+
85
+ private get_pem = ():Promise<[string, string]> => {
86
+ return new Promise<[string, string]>((resolve) => {
87
+ const pemFolder = path.join(os.homedir(), DATA_FOLDER, 'pem')
88
+ if(!existsSync(pemFolder)) mkdirSync(pemFolder)
89
+ const clientKey = path.join(pemFolder, "cluster_clientkey.pem")
90
+ const certificate = path.join(pemFolder, "cluster_certificate.pem")
91
+ if(!existsSync(clientKey) || !existsSync(certificate)){
92
+ pem.createCertificate({selfSigned: true}, (err, keys) => {
93
+ writeFileSync(clientKey, keys.clientKey, { encoding: 'utf8' })
94
+ writeFileSync(certificate, keys.certificate, { encoding: 'utf8' })
95
+ resolve([keys.clientKey, keys.certificate])
96
+ })
97
+ }else{
98
+ resolve([readFileSync(clientKey, 'utf8').toString(), readFileSync(certificate, 'utf8').toString()])
99
+ }
100
+ })
101
+ }
102
+ }
@@ -0,0 +1,248 @@
1
+ import { ConditionResult, ExecutePair, ExecuteProxy, ExecuteRecordTask, ExecuteState, FeedBack, Job, JobCategory, MESSAGE_LIMIT, Parameter, Project, Record, Task } from "../../interface"
2
+
3
+ export class Util_Server_Console {
4
+
5
+ receivedPack = (model:ExecutePair, record:Record) => {
6
+ const pass = model.manager!.Register()
7
+ if(pass == -1){
8
+ model.record!.running = false
9
+ model.record!.stop = true
10
+ return false
11
+ }
12
+ model.record!.projects = record.projects
13
+ model.record!.nodes = record.nodes
14
+ model.record!.project_state = model.record!.projects.map(x => {
15
+ return {
16
+ uuid: x.uuid,
17
+ state: ExecuteState.NONE
18
+ }
19
+ })
20
+ model.record!.project_index = pass
21
+ model.record!.project = record.projects[pass].uuid
22
+ model.record!.task_index = 0
23
+ model.record!.task_state = model.record!.projects[0].task.map(x => {
24
+ return {
25
+ uuid: x.uuid,
26
+ state: ExecuteState.NONE
27
+ }
28
+ })
29
+ model.record!.task_state[0].state = ExecuteState.RUNNING
30
+ model.record!.task_detail = []
31
+ const task = model.record!.projects[model.record!.project_index]?.task[model.record!.task_index]
32
+ const count = task.cronjob ? (task?.jobs.length ?? 0) : 1
33
+ for(let i = 0; i < count; i++){
34
+ model.record!.task_detail.push({
35
+ index: i,
36
+ node: "",
37
+ message: [],
38
+ state: ExecuteState.NONE
39
+ })
40
+ }
41
+ model.manager!.Update()
42
+ return true
43
+ }
44
+ }
45
+
46
+ export class Util_Server_Console_Proxy {
47
+ model:ExecutePair
48
+
49
+ constructor(_model:ExecutePair){
50
+ this.model = _model
51
+ }
52
+
53
+ public get execute_proxy() : ExecuteProxy {
54
+ const d:ExecuteProxy = {
55
+ executeProjectStart: (data:[Project, number]):void => { this.execute_project_start(data) },
56
+ executeProjectFinish: (data:[Project, number]):void => { this.execute_project_finish(data) },
57
+ executeTaskStart: (data:[Task, number]):void => { this.execute_task_start(data) },
58
+ executeTaskFinish: (data:Task):void => { this.execute_task_finish(data) },
59
+ executeSubtaskStart: (data:[Task, number, string]):void => { this.execute_subtask_start(data) },
60
+ executeSubtaskUpdate: (data:[Task, number, string, ExecuteState]):void => { this.execute_subtask_update(data) },
61
+ executeSubtaskFinish: (data:[Task, number, string]):void => { this.execute_subtask_end(data) },
62
+ executeJobStart: (data:[Job, number, string]):void => { this.execute_job_start(data) },
63
+ executeJobFinish: (data:[Job, number, string, number]):void => { this.execute_job_finish(data) },
64
+ feedbackMessage: (data:FeedBack):void => { this.feedback_message(data) },
65
+ updateParameter: (data:Parameter):void => { this.update_runtime_parameter(data) }
66
+ }
67
+ return d
68
+ }
69
+
70
+ execute_project_start = (d:[Project, number]) => {
71
+ const index = d[1]
72
+ if(index == -1) return
73
+ this.model.record!.project = d[0].uuid
74
+ this.model.record!.project_index = index
75
+ this.model.record!.project_state[index].state = ExecuteState.RUNNING
76
+ this.model.record!.task_state = this.model.record!.projects[index].task.map(x => {
77
+ return {
78
+ uuid: x.uuid,
79
+ state: ExecuteState.NONE
80
+ }
81
+ })
82
+ this.model.record!.task_detail = []
83
+ const task = this.model.record!.projects[this.model.record!.project_index]?.task[this.model.record!.task_index]
84
+ const count = task.cronjob ? (task?.jobs.length ?? 0) : 1
85
+ for(let i = 0; i < count; i++){
86
+ this.model.record!.task_detail.push({
87
+ index: i,
88
+ node: "",
89
+ message: [],
90
+ state: ExecuteState.NONE
91
+ })
92
+ }
93
+ console.log("project start: ", this.model.record!.projects.length, index)
94
+ }
95
+
96
+ execute_project_finish = (d:[Project, number]) => {
97
+ if(this.model.record!.process_type >= 1) {
98
+ this.model.record!.running = false
99
+ this.model.record!.stop = true
100
+ }
101
+ const index = d[1]
102
+ const size = this.model.record!.projects.length
103
+ if(index == -1) return
104
+ this.model.record!.project = ""
105
+ this.model.record!.project_state[index].state = ExecuteState.FINISH
106
+ this.model.record!.para = undefined
107
+ console.log("project finish: ", this.model.record!.projects.length, index)
108
+
109
+ if(index == size - 1){
110
+ this.model.record!.command.push(['clean'])
111
+ }
112
+ }
113
+
114
+ execute_task_start = (d:[Task, number]) => {
115
+ if (this.model.record!.project_index == -1) return
116
+ const index = this.model.record!.projects[this.model.record!.project_index].task.findIndex(x => x.uuid == d[0].uuid)
117
+ if(index == -1) return
118
+ this.model.record!.useCron = d[0].cronjob
119
+ this.model.record!.task = d[0].uuid
120
+ this.model.record!.task_index = index
121
+ this.model.record!.task_state[index].state = ExecuteState.RUNNING
122
+ for(let i = 0; i < index; i++) this.model.record!.task_state[i].state = ExecuteState.FINISH
123
+ for(let i = index + 1; i < this.model.record!.task_state.length; i++) this.model.record!.task_state[i].state = ExecuteState.NONE
124
+ this.model.record!.task_detail = []
125
+ const p = this.model.record!.projects[this.model.record!.project_index]
126
+ const t = p.task[this.model.record!.task_index]
127
+ const count = this.model.manager!.get_task_state_count(t)
128
+ for(let i = 0; i < count; i++){
129
+ this.model.record!.task_detail.push({
130
+ index: i,
131
+ node: "",
132
+ message: [],
133
+ state: ExecuteState.NONE
134
+ })
135
+ }
136
+ }
137
+
138
+ execute_task_finish = (d:Task) => {
139
+ if(this.model.record!.process_type == 2) {
140
+ this.model.record!.running = false
141
+ this.model.record!.stop = true
142
+ }
143
+ if (this.model.record!.project_index == -1) return
144
+ const index = this.model.record!.projects[this.model.record!.project_index].task.findIndex(x => x.uuid == d.uuid)
145
+ if(index == -1) return
146
+ this.model.record!.useCron = false
147
+ this.model.record!.task = ""
148
+ this.model.record!.task_state[index].state = ExecuteState.FINISH
149
+ if(index + 1 < this.model.record!.task_state.length - 1){
150
+ this.model.record!.task_state[index + 1].state = ExecuteState.RUNNING
151
+ }
152
+ }
153
+
154
+ execute_subtask_start = (d:[Task, number, string]) => {
155
+ try{
156
+ this.model.record!.task_detail[d[1]].node = d[2] ?? ''
157
+ this.model.record!.task_detail[d[1]].state = ExecuteState.RUNNING
158
+ }catch(error:any) {
159
+ console.error(`execute_subtask_start`, error.message)
160
+ }
161
+ }
162
+
163
+ execute_subtask_update = (d:[Task, number, string, ExecuteState]) => {
164
+ if(this.model.record!.task_detail.length > d[1]){
165
+ this.model.record!.task_detail[d[1]].node = d[2]
166
+ this.model.record!.task_detail[d[1]].state = d[3]
167
+ }else{
168
+ console.error(`subtask_start ${d[1]} is out of range: ${this.model.record!.task_detail.length}`)
169
+ }
170
+ }
171
+
172
+ execute_subtask_end = (d:[Task, number, string]) => {
173
+ try{
174
+ this.model.record!.task_detail[d[1]].state = ExecuteState.FINISH
175
+ }catch(error:any) {
176
+ console.error(`execute_subtask_end`, error.message)
177
+ }
178
+ }
179
+
180
+ execute_job_start = (d:[Job, number, string]) => {
181
+ if (this.model.record!.project_index == -1) return
182
+ if(!this.model.record!.useCron){
183
+ this.model.record!.task_detail[0].node = d[2]
184
+ }
185
+ }
186
+
187
+ execute_job_finish = (d:[Job, number, string, number]) => {
188
+ if (d[3] == 1){
189
+ const task = this.model.record!.projects[this.model.record!.project_index].task[this.model.record!.task_index]
190
+ const index = task.jobs.findIndex(x => x.uuid == d[0].uuid)
191
+ if(index != -1 && task.jobs[index].category == JobCategory.Condition){
192
+ const cr:ConditionResult = task.jobs[index].number_args[0] as ConditionResult
193
+ if(cr == ConditionResult.None) return
194
+
195
+ this.model.record!.command.push(['stop'])
196
+ let timer:any
197
+ timer = setInterval(() => {
198
+ if(this.model.record!.running == false){
199
+ clearInterval(timer)
200
+ const state = (cr == ConditionResult.ThrowTask || cr == ConditionResult.ThrowProject) ? ExecuteState.ERROR : ExecuteState.SKIP
201
+ const target: ExecuteRecordTask | undefined = this.model.record!.task_detail[d[1]]
202
+ if(target != undefined) {
203
+ target.state = state
204
+ }
205
+ if (cr == ConditionResult.Pause) return
206
+ if (cr == ConditionResult.SkipProject || cr == ConditionResult.ThrowProject){
207
+ this.model.record!.command.push(['skip', 0, state])
208
+ if(this.model.record!.project.length > 0){
209
+ if(this.model.record!.process_type == 0){
210
+ this.model.record!.command.push(['execute', this.model.record!.process_type])
211
+ }
212
+ }
213
+ }
214
+ else if (cr == ConditionResult.SkipTask || cr == ConditionResult.ThrowTask){
215
+ this.model.record!.command.push(['skip', 1, state])
216
+ if(this.model.record!.project.length > 0){
217
+ if(this.model.record!.process_type == 0){
218
+ this.model.record!.command.push(['execute', this.model.record!.process_type])
219
+ }
220
+ }
221
+ }
222
+ }
223
+ }, 1000);
224
+ }
225
+ }
226
+ //model.value![1].task_detail[index].node = ""
227
+ }
228
+
229
+ feedback_message = (d:FeedBack) => {
230
+ if(d.index == undefined || d.index == -1) return
231
+ const container = this.model.record!.task_detail[d.index]
232
+ if(container != undefined){
233
+ container.message.push(d.message)
234
+ if(container.message.length > MESSAGE_LIMIT){
235
+ container.message.shift()
236
+ }
237
+ }
238
+ }
239
+
240
+ /**
241
+ * When parameter getting change by the process steps\
242
+ * This get called
243
+ * @param d The whole container for the parameters
244
+ */
245
+ update_runtime_parameter = (d:Parameter, ) => {
246
+ this.model.record!.para = d
247
+ }
248
+ }
@@ -0,0 +1,194 @@
1
+ import { v6 as uuid6 } from 'uuid'
2
+ import { ConditionResult, ExecutePair, ExecuteProxy, ExecuteRecordTask, ExecuteState, ExecutionLog, FeedBack, Job, JobCategory, Log, Parameter, Preference, Project, Task } from "../../interface"
3
+ import * as fs from 'fs'
4
+
5
+ export class Util_Server_Log_Proxy {
6
+ model:ExecutePair
7
+ logs:Log
8
+ preference:Preference
9
+
10
+ private task_index:number = 0
11
+ private uuid:string = ''
12
+ private get target_log ():ExecutionLog | undefined {
13
+ return this.logs.logs.find(x => x.uuid == this.uuid)!
14
+ }
15
+
16
+ constructor(_model:ExecutePair, _log:Log, _preference:Preference){
17
+ this.model = _model
18
+ this.logs = _log
19
+ this.preference = _preference
20
+ }
21
+
22
+ public get execute_proxy() : ExecuteProxy {
23
+ const d:ExecuteProxy = {
24
+ executeProjectStart: (data:[Project, number]):void => { this.execute_project_start(data) },
25
+ executeProjectFinish: (data:[Project, number]):void => { this.execute_project_finish(data) },
26
+ executeTaskStart: (data:[Task, number]):void => { this.execute_task_start(data) },
27
+ executeTaskFinish: (data:Task):void => { this.execute_task_finish(data) },
28
+ executeSubtaskStart: (data:[Task, number, string]):void => { this.execute_subtask_start(data) },
29
+ executeSubtaskUpdate: (data:[Task, number, string, ExecuteState]):void => { this.execute_subtask_update(data) },
30
+ executeSubtaskFinish: (data:[Task, number, string]):void => { this.execute_subtask_end(data) },
31
+ executeJobStart: (data:[Job, number, string]):void => { this.execute_job_start(data) },
32
+ executeJobFinish: (data:[Job, number, string, number]):void => { this.execute_job_finish(data) },
33
+ feedbackMessage: (data:FeedBack):void => { this.feedback_message(data) },
34
+ updateParameter: (data:Parameter):void => { this.update_runtime_parameter(data) }
35
+ }
36
+ return d
37
+ }
38
+
39
+ execute_project_start = async (d:[Project, number]) => {
40
+ const target = this.model.record!.projects[this.model.record!.project_index]
41
+ const title = await this.getnewname(target.title)
42
+ this.uuid = uuid6()
43
+ const newlog:ExecutionLog = {
44
+ uuid: this.uuid,
45
+ filename: title,
46
+ dirty: true,
47
+ output: this.preference.log,
48
+ project: target,
49
+ state: ExecuteState.RUNNING,
50
+ start_timer: Date.now(),
51
+ parameter: d[0].parameter!,
52
+ end_timer: 0,
53
+ logs: target.task.map(x => {
54
+ return {
55
+ start_timer: 0,
56
+ end_timer: 0,
57
+ task_state: {
58
+ uuid: x.uuid,
59
+ state: ExecuteState.NONE
60
+ },
61
+ task_detail: []
62
+ }
63
+ })
64
+ }
65
+ this.logs.logs = [newlog].concat(this.logs.logs)
66
+ }
67
+
68
+ execute_project_finish = (d:[Project, number]) => {
69
+ if(this.target_log == undefined) return
70
+ this.target_log!.state = ExecuteState.FINISH
71
+ this.target_log!.end_timer = Date.now()
72
+ this.target_log!.dirty = true
73
+ }
74
+
75
+ execute_task_start = (d:[Task, number]) => {
76
+ if(this.target_log == undefined) return
77
+ const index = this.target_log!.project.task.findIndex(x => x.uuid == d[0].uuid)
78
+ if(index == -1) return
79
+ this.task_index = index
80
+ this.target_log!.logs[this.task_index].task_detail = []
81
+
82
+ const p = this.model.record!.projects[this.model.record!.project_index]
83
+ const t = p.task[this.task_index]
84
+ const count = this.model.manager!.get_task_state_count(t)
85
+
86
+ for(let i = 0; i < count; i++){
87
+ this.target_log!.logs[this.task_index].task_detail.push({
88
+ index: i,
89
+ node: "",
90
+ message: [],
91
+ state: ExecuteState.NONE
92
+ })
93
+ }
94
+
95
+ if(this.target_log!.logs.length > this.task_index){
96
+ this.target_log!.logs[this.task_index].task_state.state = ExecuteState.RUNNING
97
+ this.target_log!.logs[this.task_index].start_timer = Date.now()
98
+ this.target_log!.dirty = true
99
+ }
100
+ }
101
+
102
+ execute_task_finish = (d:Task) => {
103
+ if(this.target_log == undefined) return
104
+ if(this.target_log!.logs.length > this.task_index){
105
+ this.target_log!.logs[this.task_index].task_state.state = ExecuteState.FINISH
106
+ this.target_log!.logs[this.task_index].end_timer = Date.now()
107
+ this.target_log!.dirty = true
108
+ }
109
+ }
110
+
111
+ execute_subtask_start = (d:[Task, number, string]) => {
112
+ if(this.target_log == undefined) return
113
+ if(this.target_log!.logs[this.task_index].task_detail.length > d[1]){
114
+ this.target_log!.logs[this.task_index].task_detail[d[1]].state = ExecuteState.RUNNING
115
+ this.target_log!.dirty = true
116
+ }
117
+ }
118
+
119
+ execute_subtask_update = (d:[Task, number, string, ExecuteState]) => {
120
+ if(this.target_log == undefined) return
121
+ if(this.target_log!.logs[this.task_index].task_detail.length > d[1]){
122
+ this.target_log!.logs[this.task_index].task_detail[d[1]].state = d[3]
123
+ this.target_log!.dirty = true
124
+ }
125
+ }
126
+
127
+ execute_subtask_end = (d:[Task, number, string]) => {
128
+ if(this.target_log == undefined) return
129
+ if(this.target_log!.logs[this.task_index].task_detail.length > d[1]){
130
+ this.target_log!.logs[this.task_index].task_detail[d[1]].state = ExecuteState.FINISH
131
+ this.target_log!.dirty = true
132
+ }
133
+ }
134
+
135
+ execute_job_start = (d:[Job, number, string]) => {
136
+
137
+ }
138
+
139
+ execute_job_finish = (d:[Job, number, string, number]) => {
140
+ if(this.target_log == undefined) return
141
+ if (d[3] == 1){
142
+ const currentLog = this.target_log!
143
+ const task = currentLog.project.task[this.task_index]
144
+ const index = task.jobs.findIndex(x => x.uuid == d[0].uuid)
145
+ if(index != -1 && task.jobs[index].category == JobCategory.Condition){
146
+ const cr:ConditionResult = task.jobs[index].number_args[0] as ConditionResult
147
+ if(cr == ConditionResult.None) return
148
+ const state = (cr == ConditionResult.ThrowTask || cr == ConditionResult.ThrowProject) ? ExecuteState.ERROR : ExecuteState.SKIP
149
+ const target: ExecuteRecordTask | undefined = this.model.record!.task_detail[d[1]]
150
+ if(target != undefined) {
151
+ target.state = state
152
+ }
153
+
154
+ currentLog.logs[this.task_index].task_state.state = state
155
+ if (cr == ConditionResult.Pause) return
156
+ if (cr == ConditionResult.SkipProject || cr == ConditionResult.ThrowProject){
157
+ currentLog.state = state
158
+ }
159
+ }
160
+ }
161
+ }
162
+
163
+ feedback_message = (d:FeedBack) => {
164
+ if(this.target_log == undefined) return
165
+ if(d.index == undefined || d.index == -1) return
166
+ if(this.target_log == undefined) return
167
+ if(this.target_log!.logs[this.task_index].task_detail.length > d.index){
168
+ this.target_log!.logs[this.task_index].task_detail[d.index].message.push(d.message)
169
+ this.target_log!.dirty = true
170
+ }else{
171
+ console.warn("Try access message by index but failed: ", d)
172
+ }
173
+ }
174
+
175
+ update_runtime_parameter = (d:Parameter) => {
176
+ if(this.target_log != undefined) {
177
+ this.target_log!.parameter = d
178
+ this.target_log!.dirty = true
179
+ }
180
+ }
181
+
182
+ getnewname = async (name:string) => {
183
+ const root = "data/log"
184
+ let count = 0
185
+ let filename = name
186
+ let p = `${root}/${filename}`
187
+ while(fs.existsSync(p + ".json")){
188
+ count = count + 1
189
+ filename = `${name} ${count}`
190
+ p = `${root}/${filename}`
191
+ }
192
+ return filename
193
+ }
194
+ }
package/test/TEST.ts ADDED
@@ -0,0 +1,63 @@
1
+ import * as pem from 'pem'
2
+ import * as https from 'https'
3
+ import * as ws from 'ws'
4
+
5
+ let h:https.Server<any> | undefined = undefined
6
+ let w:ws.Server | undefined = undefined
7
+
8
+ async function get_pem ():Promise<[string, string]> {
9
+ return new Promise<[string, string]>(resolve => {
10
+ pem.createCertificate({ days: 1, selfSigned: true }, (err, keys) => {
11
+ resolve([keys.clientKey, keys.certificate])
12
+ })
13
+ })
14
+ }
15
+
16
+
17
+ async function start_server() {
18
+ const pems = await get_pem()
19
+ h = https.createServer({ key: pems[0], cert: pems[1], minVersion: 'TLSv1.2', maxVersion: 'TLSv1.3' }, (req, res) => {
20
+ res.writeHead(200)
21
+ res.end('HTTPS server is running');
22
+ })
23
+ h.addListener('upgrade', (req, res, head) => console.log('UPGRADE:', req.url))
24
+ w = new ws.Server({ server: h })
25
+ w.on('listening', (socket) => {
26
+ console.log("Listen Event")
27
+ })
28
+ w.on('error', (err) => {
29
+ console.log("Error Event")
30
+ })
31
+ w.on('connection', (socket) => {
32
+ socket.on('message', (data) => {
33
+ console.log("Recevied Data: ", data.toString())
34
+ })
35
+ })
36
+ h.listen(10000, () => {
37
+ console.log("Listen to 10000")
38
+ })
39
+ }
40
+
41
+
42
+ async function start_client() {
43
+ return new Promise((resolve) => {
44
+ const cli = new ws.WebSocket("wss://127.0.0.1:10000", { agent: new https.Agent(), rejectUnauthorized: false })
45
+ cli.on('error', (err) => {
46
+ console.log("Socket Error: ", err)
47
+ })
48
+ setTimeout(() => {
49
+ cli.send("Hello World")
50
+ cli.close()
51
+ resolve(undefined)
52
+ }, 1000);
53
+ })
54
+ }
55
+
56
+ async function main() {
57
+ await start_server()
58
+ await start_client()
59
+ //w?.close()
60
+ //h?.close()
61
+ }
62
+
63
+ main()
@@ -0,0 +1,54 @@
1
+ import { ClientJobExecute } from "../../src/client/job_execute"
2
+ import { Job, JobCategory, JobType2 } from "../../src/interface"
3
+
4
+
5
+ describe("Client Execute Test", () => {
6
+ let execute:ClientJobExecute | undefined = undefined
7
+ let job:Job | undefined = undefined
8
+ afterAll(() => {
9
+ execute = undefined
10
+ })
11
+
12
+ test("Testing condition (OS when path not exist)", async () => {
13
+ job = {
14
+ index: 0,
15
+ uuid: "UUID",
16
+ runtime_uuid: "Runtime",
17
+ category: JobCategory.Condition,
18
+ type: JobType2.CHECK_PATH,
19
+ script: "",
20
+ string_args: ["Not Exist"],
21
+ number_args: [],
22
+ boolean_args: []
23
+ }
24
+ execute = new ClientJobExecute(
25
+ (str) => console.log(str),
26
+ (str) => console.log(str),
27
+ job!,
28
+ undefined,
29
+ { plugins: [] },
30
+ )
31
+ await expect(execute.execute()).rejects.toBeDefined()
32
+ })
33
+ test("Testing condition (OS when path exist)", async () => {
34
+ job = {
35
+ index: 0,
36
+ uuid: "UUID",
37
+ runtime_uuid: "Runtime",
38
+ category: JobCategory.Condition,
39
+ type: JobType2.CHECK_PATH,
40
+ script: "",
41
+ string_args: [process.cwd()],
42
+ number_args: [],
43
+ boolean_args: []
44
+ }
45
+ execute = new ClientJobExecute(
46
+ (str) => console.log(str),
47
+ (str) => console.log(str),
48
+ job!,
49
+ undefined,
50
+ { plugins: [] }
51
+ )
52
+ await expect(execute.execute()).resolves.toBeDefined()
53
+ })
54
+ })