@things-factory/integration-base 8.0.0 → 9.0.0-beta.3
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/dist-server/engine/connector/headless-connector.d.ts +23 -0
- package/dist-server/engine/connector/headless-connector.js +357 -0
- package/dist-server/engine/connector/headless-connector.js.map +1 -0
- package/dist-server/engine/connector/http-connector.js +1 -1
- package/dist-server/engine/connector/http-connector.js.map +1 -1
- package/dist-server/engine/connector/index.d.ts +1 -0
- package/dist-server/engine/connector/index.js +1 -0
- package/dist-server/engine/connector/index.js.map +1 -1
- package/dist-server/engine/index.d.ts +1 -0
- package/dist-server/engine/index.js +1 -0
- package/dist-server/engine/index.js.map +1 -1
- package/dist-server/engine/resource-pool/headless-pool.d.ts +1 -0
- package/dist-server/engine/resource-pool/headless-pool.js +62 -0
- package/dist-server/engine/resource-pool/headless-pool.js.map +1 -0
- package/dist-server/engine/resource-pool/index.d.ts +1 -0
- package/dist-server/engine/resource-pool/index.js +5 -0
- package/dist-server/engine/resource-pool/index.js.map +1 -0
- package/dist-server/engine/task/headless-post.js +19 -33
- package/dist-server/engine/task/headless-post.js.map +1 -1
- package/dist-server/engine/task/headless-scrap.js +20 -13
- package/dist-server/engine/task/headless-scrap.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +12 -11
- package/translations/en.json +12 -4
- package/translations/ja.json +12 -4
- package/translations/ko.json +12 -4
- package/translations/ms.json +12 -4
- package/translations/zh.json +12 -4
- package/server/controllers/index.ts +0 -2
- package/server/controllers/publish-data.ts +0 -29
- package/server/controllers/scenario-controller.ts +0 -156
- package/server/engine/analyzer/analyze-integration.ts +0 -115
- package/server/engine/connection-manager.ts +0 -239
- package/server/engine/connector/echo-back-connector.ts +0 -51
- package/server/engine/connector/echo-back-server.ts +0 -72
- package/server/engine/connector/graphql-connector.ts +0 -126
- package/server/engine/connector/http-connector.ts +0 -65
- package/server/engine/connector/index.ts +0 -12
- package/server/engine/connector/mqtt-connector.ts +0 -78
- package/server/engine/connector/mssql-connector.ts +0 -152
- package/server/engine/connector/mysql-connector.ts +0 -94
- package/server/engine/connector/operato-connector.ts +0 -264
- package/server/engine/connector/oracle-connector.ts +0 -218
- package/server/engine/connector/postgresql-connector.ts +0 -152
- package/server/engine/connector/proxy-connector.ts +0 -53
- package/server/engine/connector/socket-server.ts +0 -86
- package/server/engine/connector/sqlite-connector.ts +0 -69
- package/server/engine/edge-client.ts +0 -45
- package/server/engine/index.ts +0 -10
- package/server/engine/pending-queue.ts +0 -97
- package/server/engine/scenario-engine.ts +0 -106
- package/server/engine/task/book-up-scenario.ts +0 -73
- package/server/engine/task/csv-readline.ts +0 -127
- package/server/engine/task/data-accessor.ts +0 -36
- package/server/engine/task/data-mapper.ts +0 -47
- package/server/engine/task/database-query.ts +0 -56
- package/server/engine/task/echo-receive.ts +0 -21
- package/server/engine/task/echo-send.ts +0 -32
- package/server/engine/task/empty-check.ts +0 -38
- package/server/engine/task/end.ts +0 -18
- package/server/engine/task/floating-point.ts +0 -71
- package/server/engine/task/goto.ts +0 -27
- package/server/engine/task/graphql-mutate.ts +0 -79
- package/server/engine/task/graphql-query.ts +0 -78
- package/server/engine/task/headless-post.ts +0 -147
- package/server/engine/task/headless-scrap.ts +0 -80
- package/server/engine/task/http-get.ts +0 -117
- package/server/engine/task/http-post.ts +0 -148
- package/server/engine/task/index.ts +0 -45
- package/server/engine/task/jsonata.ts +0 -45
- package/server/engine/task/local-graphql-mutate.ts +0 -100
- package/server/engine/task/local-graphql-query.ts +0 -100
- package/server/engine/task/log.ts +0 -78
- package/server/engine/task/mqtt-publish.ts +0 -45
- package/server/engine/task/mqtt-subscribe.ts +0 -139
- package/server/engine/task/mssql-procedure.ts +0 -128
- package/server/engine/task/oracle-procedure.ts +0 -124
- package/server/engine/task/pick-pending-scenario.ts +0 -80
- package/server/engine/task/publish.ts +0 -40
- package/server/engine/task/random.ts +0 -53
- package/server/engine/task/reset-pending-queue.ts +0 -17
- package/server/engine/task/script.ts +0 -63
- package/server/engine/task/set-domain.ts +0 -37
- package/server/engine/task/sleep.ts +0 -34
- package/server/engine/task/socket-listener.ts +0 -96
- package/server/engine/task/state-group-read.ts +0 -69
- package/server/engine/task/state-read.ts +0 -56
- package/server/engine/task/state-write.ts +0 -65
- package/server/engine/task/stop-scenario.ts +0 -44
- package/server/engine/task/sub-scenario.ts +0 -57
- package/server/engine/task/switch-goto.ts +0 -43
- package/server/engine/task/switch-range-goto.ts +0 -53
- package/server/engine/task/switch-range-scenario.ts +0 -79
- package/server/engine/task/switch-range-set.ts +0 -48
- package/server/engine/task/switch-scenario.ts +0 -67
- package/server/engine/task/switch-set.ts +0 -37
- package/server/engine/task/throw.ts +0 -27
- package/server/engine/task/utils/headless-pool-for-scenario.ts +0 -71
- package/server/engine/task/utils/substitute.ts +0 -44
- package/server/engine/task/variables.ts +0 -17
- package/server/engine/task-registry.ts +0 -23
- package/server/engine/types.ts +0 -114
- package/server/index.ts +0 -20
- package/server/migrations/index.ts +0 -9
- package/server/restful/index.ts +0 -1
- package/server/restful/unstable/index.ts +0 -7
- package/server/restful/unstable/run-scenario.ts +0 -51
- package/server/restful/unstable/scenario-instance.ts +0 -52
- package/server/restful/unstable/scenario-instances.ts +0 -80
- package/server/restful/unstable/scenario.ts +0 -41
- package/server/restful/unstable/scenarios.ts +0 -69
- package/server/restful/unstable/start-scenario.ts +0 -33
- package/server/restful/unstable/stop-scenario.ts +0 -30
- package/server/routers/scenario-schedule-callback-router.ts +0 -69
- package/server/routers/scenario-view-router.ts +0 -46
- package/server/routes.ts +0 -30
- package/server/service/analysis/analysis-query.ts +0 -13
- package/server/service/analysis/index.ts +0 -3
- package/server/service/connection/connection-mutation.ts +0 -190
- package/server/service/connection/connection-query.ts +0 -87
- package/server/service/connection/connection-subscription.ts +0 -104
- package/server/service/connection/connection-type.ts +0 -288
- package/server/service/connection/index.ts +0 -7
- package/server/service/connector/connector-query.ts +0 -62
- package/server/service/connector/connector-type.ts +0 -29
- package/server/service/connector/index.ts +0 -4
- package/server/service/index.ts +0 -52
- package/server/service/payload-log/index.ts +0 -7
- package/server/service/payload-log/payload-log-mutation.ts +0 -151
- package/server/service/payload-log/payload-log-query.ts +0 -49
- package/server/service/payload-log/payload-log-type.ts +0 -36
- package/server/service/payload-log/payload-log.ts +0 -100
- package/server/service/property-spec.ts +0 -24
- package/server/service/scenario/index.ts +0 -6
- package/server/service/scenario/scenario-mutation.ts +0 -396
- package/server/service/scenario/scenario-query.ts +0 -109
- package/server/service/scenario/scenario-type.ts +0 -78
- package/server/service/scenario/scenario.ts +0 -124
- package/server/service/scenario-flow/scenario-flow.ts +0 -17
- package/server/service/scenario-instance/index.ts +0 -6
- package/server/service/scenario-instance/scenario-instance-mutation.ts +0 -44
- package/server/service/scenario-instance/scenario-instance-query.ts +0 -42
- package/server/service/scenario-instance/scenario-instance-subscription.ts +0 -118
- package/server/service/scenario-instance/scenario-instance-type.ts +0 -563
- package/server/service/scenario-queue/index.ts +0 -4
- package/server/service/scenario-queue/scenario-queue-subscription.ts +0 -55
- package/server/service/scenario-queue/scenario-queue-type.ts +0 -27
- package/server/service/state-register/data-resolver.ts +0 -56
- package/server/service/state-register/index.ts +0 -8
- package/server/service/state-register/state-register-mutation.ts +0 -166
- package/server/service/state-register/state-register-query.ts +0 -80
- package/server/service/state-register/state-register-type.ts +0 -80
- package/server/service/state-register/state-register.ts +0 -113
- package/server/service/step/index.ts +0 -6
- package/server/service/step/step-mutation.ts +0 -52
- package/server/service/step/step-query.ts +0 -55
- package/server/service/step/step-type.ts +0 -215
- package/server/service/task-type/index.ts +0 -4
- package/server/service/task-type/task-type-query.ts +0 -95
- package/server/service/task-type/task-type-type.ts +0 -29
@@ -1,563 +0,0 @@
|
|
1
|
-
import 'winston-daily-rotate-file'
|
2
|
-
|
3
|
-
import orderBy from 'lodash/orderBy'
|
4
|
-
import moment from 'moment-timezone'
|
5
|
-
import { Field, Int, ObjectType, registerEnumType } from 'type-graphql'
|
6
|
-
import util from 'util'
|
7
|
-
import { createLogger, format, transports } from 'winston'
|
8
|
-
|
9
|
-
import { Domain, pubsub, PubSubLogTransport, ScalarObject } from '@things-factory/shell'
|
10
|
-
import { cacheService } from '@things-factory/cache-service'
|
11
|
-
import { User } from '@things-factory/auth-base'
|
12
|
-
import { sleep } from '@things-factory/utils'
|
13
|
-
|
14
|
-
import { publishData } from '../../controllers/publish-data'
|
15
|
-
import { ConnectionManager } from '../../engine/connection-manager'
|
16
|
-
import { TaskRegistry } from '../../engine'
|
17
|
-
import { Context } from '../../engine/types'
|
18
|
-
import { Step } from '../step/step-type'
|
19
|
-
import { handler as edgeHandler } from '../../engine/edge-client'
|
20
|
-
|
21
|
-
const debug = require('debug')('things-factory:integration-base:scenario-instance')
|
22
|
-
const { combine, errors, splat, printf } = format
|
23
|
-
|
24
|
-
const LOGFORMAT = printf(({ level, message, timestamp, stack }) => {
|
25
|
-
return `${timestamp} ${level}: ${stack || message}`
|
26
|
-
})
|
27
|
-
|
28
|
-
function getSystemTimeZone() {
|
29
|
-
try {
|
30
|
-
const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone
|
31
|
-
if (!timeZone) {
|
32
|
-
throw new Error('Unable to resolve timeZone')
|
33
|
-
}
|
34
|
-
return timeZone
|
35
|
-
} catch (e) {
|
36
|
-
console.warn('Failed to get system timeZone, falling back to UTC.', e)
|
37
|
-
return 'UTC'
|
38
|
-
}
|
39
|
-
}
|
40
|
-
|
41
|
-
const SYSTEM_TZ = getSystemTimeZone()
|
42
|
-
const systemTimestamp = format((info, opts: { tz?: string }) => {
|
43
|
-
if (opts.tz) info.timestamp = moment().tz(opts.tz).format()
|
44
|
-
return info
|
45
|
-
})
|
46
|
-
|
47
|
-
export enum ScenarioInstanceStatus {
|
48
|
-
READY = 'READY',
|
49
|
-
STARTED = 'STARTED',
|
50
|
-
STOPPED = 'STOPPED',
|
51
|
-
HALTED = 'HALTED',
|
52
|
-
UNLOADED = 'UNLOADED'
|
53
|
-
}
|
54
|
-
|
55
|
-
registerEnumType(ScenarioInstanceStatus, {
|
56
|
-
name: 'ScenarioInstanceStatus',
|
57
|
-
description: 'state enumeration of a scenario-instance'
|
58
|
-
})
|
59
|
-
|
60
|
-
@ObjectType()
|
61
|
-
export class ScenarioInstanceProgress {
|
62
|
-
@Field(type => Int)
|
63
|
-
rounds: number
|
64
|
-
|
65
|
-
@Field(type => Int)
|
66
|
-
rate: number
|
67
|
-
|
68
|
-
@Field(type => Int)
|
69
|
-
steps: number
|
70
|
-
|
71
|
-
@Field(type => Int)
|
72
|
-
step: number
|
73
|
-
}
|
74
|
-
|
75
|
-
@ObjectType()
|
76
|
-
export class ScenarioInstanceState {
|
77
|
-
@Field({ nullable: true })
|
78
|
-
public domain: Domain
|
79
|
-
|
80
|
-
@Field({ nullable: true })
|
81
|
-
public instanceName: string
|
82
|
-
|
83
|
-
@Field({ nullable: true })
|
84
|
-
public scenarioName: string
|
85
|
-
|
86
|
-
@Field(type => ScenarioInstanceStatus, { nullable: true })
|
87
|
-
public state: ScenarioInstanceStatus
|
88
|
-
|
89
|
-
@Field(type => ScalarObject, { nullable: true })
|
90
|
-
public variables: any
|
91
|
-
|
92
|
-
@Field(type => ScalarObject, { nullable: true })
|
93
|
-
public data: any
|
94
|
-
|
95
|
-
@Field(type => ScenarioInstanceProgress, { nullable: true })
|
96
|
-
public progress: ScenarioInstanceProgress
|
97
|
-
|
98
|
-
@Field({ nullable: true })
|
99
|
-
public message: string
|
100
|
-
|
101
|
-
@Field({ nullable: true })
|
102
|
-
public timestamp: Date
|
103
|
-
}
|
104
|
-
|
105
|
-
@ObjectType()
|
106
|
-
export class ScenarioInstanceRunResult {
|
107
|
-
@Field({ nullable: true })
|
108
|
-
public scenarioName: string
|
109
|
-
|
110
|
-
@Field({ nullable: true })
|
111
|
-
public instanceName: string
|
112
|
-
|
113
|
-
@Field(type => ScalarObject, { nullable: true })
|
114
|
-
public variables: any
|
115
|
-
|
116
|
-
@Field(type => ScalarObject, { nullable: true })
|
117
|
-
public data: any
|
118
|
-
|
119
|
-
@Field(type => ScalarObject, { nullable: true })
|
120
|
-
public result: any
|
121
|
-
|
122
|
-
@Field({ nullable: true })
|
123
|
-
public timestamp: Date
|
124
|
-
|
125
|
-
@Field({ nullable: true })
|
126
|
-
public message: string
|
127
|
-
|
128
|
-
@Field({ nullable: true })
|
129
|
-
public state: ScenarioInstanceStatus
|
130
|
-
}
|
131
|
-
|
132
|
-
@ObjectType()
|
133
|
-
export class ScenarioInstance {
|
134
|
-
private subScenarioInstances: ScenarioInstance[] = [] // TODO Imple by WeakSet
|
135
|
-
|
136
|
-
public context: Context
|
137
|
-
|
138
|
-
@Field({ nullable: true })
|
139
|
-
public domain: Domain
|
140
|
-
|
141
|
-
@Field({ nullable: true })
|
142
|
-
public user: User
|
143
|
-
|
144
|
-
@Field({ nullable: true })
|
145
|
-
public scenarioName: string
|
146
|
-
|
147
|
-
@Field({ nullable: true })
|
148
|
-
public instanceName: string
|
149
|
-
|
150
|
-
@Field({ nullable: true })
|
151
|
-
get root(): ScenarioInstance {
|
152
|
-
return this.context?.root
|
153
|
-
}
|
154
|
-
|
155
|
-
@Field({ nullable: true })
|
156
|
-
get state(): ScenarioInstanceStatus {
|
157
|
-
return this.context?.state
|
158
|
-
}
|
159
|
-
|
160
|
-
@Field(type => ScenarioInstanceProgress, { nullable: true })
|
161
|
-
get progress(): ScenarioInstanceProgress {
|
162
|
-
return this.calcProgress()
|
163
|
-
}
|
164
|
-
|
165
|
-
@Field(type => ScalarObject, { nullable: true })
|
166
|
-
get variables(): any {
|
167
|
-
return this.context?.variables
|
168
|
-
}
|
169
|
-
|
170
|
-
@Field(type => ScalarObject, { nullable: true })
|
171
|
-
get data(): any {
|
172
|
-
return this.context?.data
|
173
|
-
}
|
174
|
-
|
175
|
-
@Field(type => ScalarObject, { nullable: true })
|
176
|
-
result: any
|
177
|
-
|
178
|
-
@Field({ nullable: true })
|
179
|
-
get timestamp(): Date {
|
180
|
-
return new Date()
|
181
|
-
}
|
182
|
-
|
183
|
-
@Field({ nullable: true })
|
184
|
-
public message: string
|
185
|
-
|
186
|
-
private scenarioId: string
|
187
|
-
private scenarioTtl: number
|
188
|
-
private steps: Step[]
|
189
|
-
private rounds: number = 0
|
190
|
-
|
191
|
-
private lastStep: number = -1
|
192
|
-
private nextStep: number = -1
|
193
|
-
private disposer: any
|
194
|
-
public addSubScenarioInstance(instance: ScenarioInstance): ScenarioInstance[] {
|
195
|
-
this.subScenarioInstances.push(instance)
|
196
|
-
return this.subScenarioInstances
|
197
|
-
}
|
198
|
-
|
199
|
-
public getSubScenarioInstances(): ScenarioInstance[] {
|
200
|
-
return this.subScenarioInstances
|
201
|
-
}
|
202
|
-
|
203
|
-
public async stopSubScenarios() {
|
204
|
-
var subScenarioInstances = this.getSubScenarioInstances()
|
205
|
-
|
206
|
-
var subInstance = subScenarioInstances.pop()
|
207
|
-
while (subInstance) {
|
208
|
-
await subInstance.dispose()
|
209
|
-
subInstance = subScenarioInstances.pop()
|
210
|
-
}
|
211
|
-
}
|
212
|
-
|
213
|
-
constructor(
|
214
|
-
instanceName,
|
215
|
-
{
|
216
|
-
id: scenarioId,
|
217
|
-
ttl: scenarioTtl,
|
218
|
-
name: scenarioName,
|
219
|
-
steps,
|
220
|
-
domain: scenarioDomain
|
221
|
-
}: { id: string; ttl?: number; name: string; steps: Step[]; domain: Domain },
|
222
|
-
context?
|
223
|
-
) {
|
224
|
-
var { domain, user, lng, unsafeIP, prohibitedPrivileges } = context || {}
|
225
|
-
domain ||= scenarioDomain
|
226
|
-
|
227
|
-
this.scenarioId = scenarioId
|
228
|
-
this.scenarioTtl = scenarioTtl
|
229
|
-
this.instanceName = instanceName
|
230
|
-
this.scenarioName = scenarioName
|
231
|
-
this.steps = orderBy(steps || [], step => step.sequence)
|
232
|
-
this.domain = domain
|
233
|
-
this.user = user
|
234
|
-
this.disposer = context?.disposer
|
235
|
-
|
236
|
-
this.context = {
|
237
|
-
domain,
|
238
|
-
user,
|
239
|
-
lng,
|
240
|
-
unsafeIP,
|
241
|
-
prohibitedPrivileges,
|
242
|
-
logger:
|
243
|
-
context?.logger ||
|
244
|
-
createLogger({
|
245
|
-
format: combine(errors({ stack: true }), systemTimestamp({ tz: SYSTEM_TZ }), splat(), LOGFORMAT),
|
246
|
-
transports: [
|
247
|
-
new (transports as any).DailyRotateFile({
|
248
|
-
filename: `logs/${domain.subdomain}/scenario-${scenarioName}-%DATE%.log`,
|
249
|
-
datePattern: 'YYYY-MM-DD-HH',
|
250
|
-
zippedArchive: false,
|
251
|
-
maxSize: '5m',
|
252
|
-
maxFiles: '14d',
|
253
|
-
level: 'info'
|
254
|
-
}),
|
255
|
-
new PubSubLogTransport({
|
256
|
-
topic: 'scenario-instance-log',
|
257
|
-
source: { domain, scenarioName, instanceName }
|
258
|
-
})
|
259
|
-
]
|
260
|
-
}),
|
261
|
-
publish: context?.publish || this.publishData.bind(this),
|
262
|
-
load: context?.load || this.loadSubscenario.bind(this),
|
263
|
-
data: context?.data || {},
|
264
|
-
variables: context?.variables || {},
|
265
|
-
client: context?.client,
|
266
|
-
state: ScenarioInstanceStatus.STOPPED,
|
267
|
-
root: context?.root || this,
|
268
|
-
closures: [],
|
269
|
-
checkState(state = ScenarioInstanceStatus.STARTED) {
|
270
|
-
return this.state == state
|
271
|
-
}
|
272
|
-
}
|
273
|
-
|
274
|
-
this.setState(ScenarioInstanceStatus.READY)
|
275
|
-
}
|
276
|
-
|
277
|
-
async run() {
|
278
|
-
var state = this.getState()
|
279
|
-
if (state == ScenarioInstanceStatus.STARTED || this.steps.length == 0) {
|
280
|
-
return
|
281
|
-
}
|
282
|
-
|
283
|
-
this.setState(ScenarioInstanceStatus.STARTED)
|
284
|
-
var context = this.context
|
285
|
-
|
286
|
-
try {
|
287
|
-
while (this.getState() == ScenarioInstanceStatus.STARTED) {
|
288
|
-
if (this.nextStep == -1) {
|
289
|
-
this.setNextStep(0)
|
290
|
-
}
|
291
|
-
|
292
|
-
if (this.nextStep == 0) {
|
293
|
-
this.rounds++
|
294
|
-
this.context.logger.info(`Start ${this.rounds} Rounds #######`)
|
295
|
-
}
|
296
|
-
|
297
|
-
var step = this.steps[this.nextStep]
|
298
|
-
var next, data
|
299
|
-
|
300
|
-
if (!step.skip) {
|
301
|
-
// @ts-ignore: Initializer provides no value for this binding element and the binding element has no default value.
|
302
|
-
var { next, state: stepState, data } = (await this.process(step, context)) || {}
|
303
|
-
context.data[step.name] = data
|
304
|
-
} else {
|
305
|
-
next = ''
|
306
|
-
stepState = undefined
|
307
|
-
}
|
308
|
-
|
309
|
-
this.publishState()
|
310
|
-
|
311
|
-
await sleep(1)
|
312
|
-
|
313
|
-
if (next) {
|
314
|
-
this.setNextStep(
|
315
|
-
this.steps.findIndex(step => {
|
316
|
-
return step.name == next
|
317
|
-
})
|
318
|
-
)
|
319
|
-
if (this.nextStep == -1) {
|
320
|
-
throw 'Not Found Next Step'
|
321
|
-
}
|
322
|
-
} else if (this.nextStep == this.steps.length - 1) {
|
323
|
-
this.setState(ScenarioInstanceStatus.STOPPED)
|
324
|
-
} else {
|
325
|
-
this.setNextStep(this.nextStep + 1)
|
326
|
-
}
|
327
|
-
|
328
|
-
/* last step 에 의해서 시나리오 state를 변경할 수 있도록 함. */
|
329
|
-
if (stepState !== undefined) {
|
330
|
-
this.setState(stepState)
|
331
|
-
}
|
332
|
-
}
|
333
|
-
} catch (ex) {
|
334
|
-
const message = ex.stack ? ex.stack : ex
|
335
|
-
const { scenarioName, domain } = this
|
336
|
-
|
337
|
-
this.context.logger.error(ex)
|
338
|
-
|
339
|
-
debug('failed to run ', `[ Domain: ${domain.name}, Scenario: ${scenarioName} ]\n`, ex)
|
340
|
-
this.setState(
|
341
|
-
ScenarioInstanceStatus.HALTED,
|
342
|
-
typeof message == 'object' ? JSON.stringify(message, null, 2) : message
|
343
|
-
)
|
344
|
-
|
345
|
-
throw ex
|
346
|
-
}
|
347
|
-
|
348
|
-
this.result = this.steps
|
349
|
-
.filter(step => !!step.result)
|
350
|
-
.reduce((sum, step) => {
|
351
|
-
sum[step.name] = this.context.data[step.name]
|
352
|
-
return sum
|
353
|
-
}, {})
|
354
|
-
|
355
|
-
const { scenarioId, scenarioTtl, variables, message, scenarioName, instanceName, result, domain } = this
|
356
|
-
const obj = {
|
357
|
-
scenarioName,
|
358
|
-
instanceName,
|
359
|
-
variables,
|
360
|
-
data: this.data,
|
361
|
-
result,
|
362
|
-
timestamp: new Date(),
|
363
|
-
message,
|
364
|
-
state: ScenarioInstanceStatus.STOPPED /* redundent, no meaning */
|
365
|
-
}
|
366
|
-
|
367
|
-
if (this.scenarioTtl && this.scenarioId) {
|
368
|
-
setTimeout(() => {
|
369
|
-
cacheService.setInCache(scenarioId, { domain: domain.id, variables: variables || {} }, obj, scenarioTtl)
|
370
|
-
})
|
371
|
-
}
|
372
|
-
|
373
|
-
return obj
|
374
|
-
}
|
375
|
-
|
376
|
-
async loadSubscenario(step, scenarioConfig, context) {
|
377
|
-
var { name: stepName, params } = step
|
378
|
-
var { preventErrorPropagation } = params || {}
|
379
|
-
|
380
|
-
debug('load-subscenario', this.instanceName, stepName, scenarioConfig.name)
|
381
|
-
|
382
|
-
context.data[stepName] = {}
|
383
|
-
|
384
|
-
let subContext = {
|
385
|
-
...context,
|
386
|
-
data: context.data[stepName],
|
387
|
-
closures: [],
|
388
|
-
state: ScenarioInstanceStatus.READY
|
389
|
-
}
|
390
|
-
|
391
|
-
if (!scenarioConfig.domain) {
|
392
|
-
scenarioConfig.domain = context.domain
|
393
|
-
}
|
394
|
-
|
395
|
-
var subScenarioInstance = new ScenarioInstance(`${this.instanceName}$${stepName}`, scenarioConfig, subContext)
|
396
|
-
this.addSubScenarioInstance(subScenarioInstance)
|
397
|
-
await subScenarioInstance.run()
|
398
|
-
|
399
|
-
if (!preventErrorPropagation && subScenarioInstance.getState() == ScenarioInstanceStatus.HALTED) {
|
400
|
-
throw new Error(`Sub-scenario[${this.instanceName}$${stepName}] is halted.`)
|
401
|
-
}
|
402
|
-
|
403
|
-
return subContext
|
404
|
-
}
|
405
|
-
|
406
|
-
publishData(tag, data) {
|
407
|
-
publishData(tag, data, this.context)
|
408
|
-
}
|
409
|
-
|
410
|
-
publishState() {
|
411
|
-
const {
|
412
|
-
instanceName,
|
413
|
-
scenarioName,
|
414
|
-
steps,
|
415
|
-
domain,
|
416
|
-
message,
|
417
|
-
context: { data, variables, state }
|
418
|
-
} = this
|
419
|
-
|
420
|
-
pubsub.publish('scenario-instance-state', {
|
421
|
-
scenarioInstanceState: {
|
422
|
-
domain,
|
423
|
-
instanceName,
|
424
|
-
scenarioName,
|
425
|
-
state,
|
426
|
-
variables,
|
427
|
-
progress: this.calcProgress(),
|
428
|
-
data,
|
429
|
-
message,
|
430
|
-
timestamp: new Date()
|
431
|
-
}
|
432
|
-
})
|
433
|
-
|
434
|
-
this.context.logger.info(this.message)
|
435
|
-
}
|
436
|
-
|
437
|
-
calcProgress(): ScenarioInstanceProgress {
|
438
|
-
var steps = this.steps.length
|
439
|
-
var step = Math.max(this.lastStep, 0)
|
440
|
-
|
441
|
-
return {
|
442
|
-
rounds: this.rounds,
|
443
|
-
rate: steps ? Math.round(100 * (step / steps)) : 0,
|
444
|
-
steps,
|
445
|
-
step
|
446
|
-
}
|
447
|
-
}
|
448
|
-
|
449
|
-
setNextStep(step) {
|
450
|
-
this.lastStep = this.nextStep + 1
|
451
|
-
this.nextStep = step
|
452
|
-
}
|
453
|
-
|
454
|
-
getState(): ScenarioInstanceStatus {
|
455
|
-
return this.context.state
|
456
|
-
}
|
457
|
-
|
458
|
-
setState(state, message?) {
|
459
|
-
if (this.context.state == state) {
|
460
|
-
return
|
461
|
-
}
|
462
|
-
|
463
|
-
this.message = `${this.instanceName}:[state changed] ${ScenarioInstanceStatus[this.getState()]} => ${ScenarioInstanceStatus[state]}${
|
464
|
-
message ? ' caused by ' + util.inspect(message, false, 2, true) : ''
|
465
|
-
}`
|
466
|
-
|
467
|
-
this.context.state = state
|
468
|
-
|
469
|
-
if (state == ScenarioInstanceStatus.STOPPED || state == ScenarioInstanceStatus.HALTED) {
|
470
|
-
this.setNextStep(-1)
|
471
|
-
this.setState(ScenarioInstanceStatus.UNLOADED)
|
472
|
-
} else if (state == ScenarioInstanceStatus.UNLOADED) {
|
473
|
-
this.setNextStep(-1)
|
474
|
-
this.dispose()
|
475
|
-
}
|
476
|
-
|
477
|
-
this.publishState()
|
478
|
-
}
|
479
|
-
|
480
|
-
async start() {
|
481
|
-
await this.run()
|
482
|
-
}
|
483
|
-
|
484
|
-
stop() {
|
485
|
-
if (this.getState() !== ScenarioInstanceStatus.HALTED) {
|
486
|
-
this.setState(ScenarioInstanceStatus.STOPPED)
|
487
|
-
}
|
488
|
-
}
|
489
|
-
|
490
|
-
unload() {
|
491
|
-
this.setState(ScenarioInstanceStatus.UNLOADED)
|
492
|
-
}
|
493
|
-
|
494
|
-
async dispose() {
|
495
|
-
await this.stopSubScenarios()
|
496
|
-
|
497
|
-
this.unload()
|
498
|
-
|
499
|
-
var closure = this.context?.closures?.pop()
|
500
|
-
while (closure) {
|
501
|
-
closure.call(this)
|
502
|
-
closure = this.context?.closures?.pop()
|
503
|
-
}
|
504
|
-
|
505
|
-
if (this.disposer) {
|
506
|
-
await this.disposer.call(this)
|
507
|
-
}
|
508
|
-
|
509
|
-
// {{ CHECKPOINT 본 인스턴스를 위해서 생성된 logger를 닫는다. 사용을 완료하고 닫기위해서 지연해서 수행한다.
|
510
|
-
if (this.context?.logger) {
|
511
|
-
setTimeout(() => {
|
512
|
-
this.context.logger.close()
|
513
|
-
}, 300)
|
514
|
-
}
|
515
|
-
// }}
|
516
|
-
}
|
517
|
-
|
518
|
-
async process(step, context): Promise<{ next: string; state: ScenarioInstanceStatus; data: object }> {
|
519
|
-
this.context.logger.info(`Step '${step.name}'(${step.id}) started.`)
|
520
|
-
|
521
|
-
step = {
|
522
|
-
...step
|
523
|
-
} // copy step
|
524
|
-
|
525
|
-
try {
|
526
|
-
step.params = JSON.parse(step.params)
|
527
|
-
} catch (ex) {
|
528
|
-
this.context.logger.error(`params(${step.params}) parsing error. params must be a JSON.`, ex)
|
529
|
-
}
|
530
|
-
step.params = step.params || {}
|
531
|
-
|
532
|
-
const connection =
|
533
|
-
step.connection && ConnectionManager.getConnectionInstanceEntityByName(this.domain, step.connection)
|
534
|
-
|
535
|
-
if (!connection || !connection.edgeId) {
|
536
|
-
var handler = TaskRegistry.getTaskHandler(step.task)
|
537
|
-
if (!handler) {
|
538
|
-
throw new Error(`no task handler for step '${step.name}'(${step.id})`)
|
539
|
-
}
|
540
|
-
|
541
|
-
var retval: any = await handler(step, context)
|
542
|
-
} else {
|
543
|
-
var retval: any = await edgeHandler(step, context)
|
544
|
-
}
|
545
|
-
|
546
|
-
if (step.log) {
|
547
|
-
var { data } = retval || {}
|
548
|
-
this.context.logger.info(`returns ${typeof data == 'string' ? data : JSON.stringify(data, null, 2)}`)
|
549
|
-
}
|
550
|
-
|
551
|
-
this.context.logger.info(`Step done.`)
|
552
|
-
return retval
|
553
|
-
}
|
554
|
-
}
|
555
|
-
|
556
|
-
@ObjectType()
|
557
|
-
export class ScenarioInstanceList {
|
558
|
-
@Field(type => [ScenarioInstance])
|
559
|
-
items: ScenarioInstance[]
|
560
|
-
|
561
|
-
@Field(type => Int)
|
562
|
-
total: number
|
563
|
-
}
|
@@ -1,55 +0,0 @@
|
|
1
|
-
import { Resolver, Subscription, Root, Arg } from 'type-graphql'
|
2
|
-
import { ScenarioQueueState } from './scenario-queue-type'
|
3
|
-
import { pubsub } from '@things-factory/shell'
|
4
|
-
import { filter, pipe } from 'graphql-yoga'
|
5
|
-
import { ScenarioEngine } from '../../engine'
|
6
|
-
|
7
|
-
const debug = require('debug')('things-factory:integration:connection-subscription')
|
8
|
-
|
9
|
-
@Resolver()
|
10
|
-
export class ScenarioQueueSubscription {
|
11
|
-
@Subscription({
|
12
|
-
subscribe: ({ args, context, info }) => {
|
13
|
-
const { domain, user } = context.state
|
14
|
-
const subdomain = domain?.subdomain
|
15
|
-
|
16
|
-
debug('subscribe', subdomain)
|
17
|
-
|
18
|
-
if (!domain) {
|
19
|
-
throw new Error('domain required.')
|
20
|
-
}
|
21
|
-
|
22
|
-
if (!user.domains?.find(d => d.subdomain === subdomain) && !process.superUserGranted(domain, user)) {
|
23
|
-
throw new Error(`domain(${subdomain}) is not working for user(${user.email}).`)
|
24
|
-
}
|
25
|
-
|
26
|
-
process.nextTick(async () => {
|
27
|
-
var queue = ScenarioEngine.getPendingQueue(domain)
|
28
|
-
if (queue) {
|
29
|
-
pubsub.publish('scenario-queue-state', {
|
30
|
-
scenarioQueueState: {
|
31
|
-
domain,
|
32
|
-
queue: queue.queue
|
33
|
-
}
|
34
|
-
})
|
35
|
-
}
|
36
|
-
})
|
37
|
-
|
38
|
-
return pipe(
|
39
|
-
pubsub.subscribe('scenario-queue-state'),
|
40
|
-
filter((payload: { scenarioQueueState: ScenarioQueueState }) => {
|
41
|
-
const { domain: pdomain } = payload.scenarioQueueState
|
42
|
-
|
43
|
-
if (pdomain?.subdomain !== subdomain) {
|
44
|
-
return false
|
45
|
-
}
|
46
|
-
|
47
|
-
return true
|
48
|
-
})
|
49
|
-
)
|
50
|
-
}
|
51
|
-
})
|
52
|
-
scenarioQueueState(@Root() payload: { scenarioQueueState: ScenarioQueueState }): ScenarioQueueState {
|
53
|
-
return payload.scenarioQueueState
|
54
|
-
}
|
55
|
-
}
|
@@ -1,27 +0,0 @@
|
|
1
|
-
import { Field, Int, ObjectType } from 'type-graphql'
|
2
|
-
|
3
|
-
import { Domain, ScalarObject } from '@things-factory/shell'
|
4
|
-
|
5
|
-
@ObjectType()
|
6
|
-
export class PendingObject {
|
7
|
-
@Field(type => ScalarObject)
|
8
|
-
stuff: any
|
9
|
-
|
10
|
-
@Field()
|
11
|
-
due: string
|
12
|
-
|
13
|
-
@Field(type => Int)
|
14
|
-
priority: number
|
15
|
-
|
16
|
-
@Field({ nullable: true })
|
17
|
-
tag: String
|
18
|
-
}
|
19
|
-
|
20
|
-
@ObjectType()
|
21
|
-
export class ScenarioQueueState {
|
22
|
-
@Field()
|
23
|
-
domain: Domain
|
24
|
-
|
25
|
-
@Field(type => [PendingObject])
|
26
|
-
queue: PendingObject[]
|
27
|
-
}
|
@@ -1,56 +0,0 @@
|
|
1
|
-
import { filter, pipe } from 'graphql-yoga'
|
2
|
-
import { Arg, Resolver, Root, Subscription } from 'type-graphql'
|
3
|
-
|
4
|
-
import { pubsub, Data, getRepository } from '@things-factory/shell'
|
5
|
-
import { StateRegister } from './state-register'
|
6
|
-
|
7
|
-
/* 이 Resolver는 @things-factory/shell에서 등록한 DataResolver를 Overide 한 것이다. */
|
8
|
-
@Resolver()
|
9
|
-
export class DataResolver {
|
10
|
-
@Subscription({
|
11
|
-
subscribe: ({ args, context, info }) => {
|
12
|
-
const { domain, user } = context.state
|
13
|
-
const { tag } = args
|
14
|
-
const subdomain = domain?.subdomain
|
15
|
-
|
16
|
-
if (!domain || !tag) {
|
17
|
-
throw new Error('domain and tag required')
|
18
|
-
}
|
19
|
-
|
20
|
-
//@ts-ignore
|
21
|
-
if (!user.domains?.find(d => d.subdomain === subdomain) && !process.superUserGranted(domain, user)) {
|
22
|
-
throw new Error(`domain(${subdomain}) is not working for user(${user.email}).`)
|
23
|
-
}
|
24
|
-
|
25
|
-
process.nextTick(async () => {
|
26
|
-
/* state-register에 등록된 태그라면, 현재 상태값을 publish 한다. */
|
27
|
-
const { domain } = context.state
|
28
|
-
|
29
|
-
const state = await getRepository(StateRegister).findOne({
|
30
|
-
where: { domain: { id: domain.id }, name: tag }
|
31
|
-
})
|
32
|
-
|
33
|
-
if (state) {
|
34
|
-
pubsub.publish('data', {
|
35
|
-
data: {
|
36
|
-
domain,
|
37
|
-
tag,
|
38
|
-
data: state.state
|
39
|
-
}
|
40
|
-
})
|
41
|
-
}
|
42
|
-
})
|
43
|
-
|
44
|
-
return pipe(
|
45
|
-
pubsub.subscribe('data'),
|
46
|
-
filter((payload: { data: Data }) => {
|
47
|
-
const { domain: pdomain, tag: ptag, data } = payload.data
|
48
|
-
return tag === ptag && subdomain === pdomain?.subdomain
|
49
|
-
})
|
50
|
-
)
|
51
|
-
}
|
52
|
-
})
|
53
|
-
data(@Root() payload: { data: Data }, @Arg('tag') tag: string): Data {
|
54
|
-
return payload.data
|
55
|
-
}
|
56
|
-
}
|
@@ -1,8 +0,0 @@
|
|
1
|
-
import { StateRegister } from './state-register'
|
2
|
-
import { StateRegisterQuery } from './state-register-query'
|
3
|
-
import { StateRegisterMutation } from './state-register-mutation'
|
4
|
-
import { DataResolver } from './data-resolver'
|
5
|
-
|
6
|
-
export const entities = [StateRegister]
|
7
|
-
export const resolvers = [StateRegisterQuery, StateRegisterMutation, DataResolver]
|
8
|
-
export const subscribers = []
|