@things-factory/integration-base 7.0.1-beta.18 → 7.0.1-beta.19
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/controllers/scenario-controller.d.ts +2 -2
- package/dist-server/controllers/scenario-controller.js +8 -2
- package/dist-server/controllers/scenario-controller.js.map +1 -1
- package/dist-server/engine/types.d.ts +2 -2
- package/dist-server/engine/types.js.map +1 -1
- package/dist-server/restful/unstable/run-scenario.js +0 -1
- package/dist-server/restful/unstable/run-scenario.js.map +1 -1
- package/dist-server/service/scenario/scenario-type.d.ts +2 -0
- package/dist-server/service/scenario/scenario-type.js +8 -0
- package/dist-server/service/scenario/scenario-type.js.map +1 -1
- package/dist-server/service/scenario/scenario.d.ts +1 -0
- package/dist-server/service/scenario/scenario.js +5 -0
- package/dist-server/service/scenario/scenario.js.map +1 -1
- package/dist-server/service/scenario-instance/scenario-instance-mutation.d.ts +2 -2
- package/dist-server/service/scenario-instance/scenario-instance-mutation.js +1 -1
- package/dist-server/service/scenario-instance/scenario-instance-mutation.js.map +1 -1
- package/dist-server/service/scenario-instance/scenario-instance-query.d.ts +1 -7
- package/dist-server/service/scenario-instance/scenario-instance-query.js +0 -64
- package/dist-server/service/scenario-instance/scenario-instance-query.js.map +1 -1
- package/dist-server/service/scenario-instance/scenario-instance-type.d.ts +35 -11
- package/dist-server/service/scenario-instance/scenario-instance-type.js +100 -14
- package/dist-server/service/scenario-instance/scenario-instance-type.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -2
- package/server/controllers/scenario-controller.ts +55 -19
- package/server/engine/types.ts +2 -2
- package/server/restful/unstable/run-scenario.ts +0 -1
- package/server/service/scenario/scenario-type.ts +6 -0
- package/server/service/scenario/scenario.ts +4 -0
- package/server/service/scenario-instance/scenario-instance-mutation.ts +7 -4
- package/server/service/scenario-instance/scenario-instance-query.ts +0 -29
- package/server/service/scenario-instance/scenario-instance-type.ts +87 -9
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@things-factory/integration-base",
|
3
|
-
"version": "7.0.1-beta.
|
3
|
+
"version": "7.0.1-beta.19",
|
4
4
|
"main": "dist-server/index.js",
|
5
5
|
"browser": "client/index.js",
|
6
6
|
"things-factory": true,
|
@@ -29,6 +29,7 @@
|
|
29
29
|
"@operato/moment-timezone-es": "^2.0.0-beta.0",
|
30
30
|
"@things-factory/api": "^7.0.1-beta.18",
|
31
31
|
"@things-factory/auth-base": "^7.0.1-beta.18",
|
32
|
+
"@things-factory/cache-service": "^7.0.1-beta.19",
|
32
33
|
"@things-factory/env": "^7.0.1-beta.18",
|
33
34
|
"@things-factory/oauth2-client": "^7.0.1-beta.18",
|
34
35
|
"@things-factory/scheduler-client": "^7.0.1-beta.18",
|
@@ -43,5 +44,5 @@
|
|
43
44
|
"readline": "^1.3.0",
|
44
45
|
"vm2": "^3.9.11"
|
45
46
|
},
|
46
|
-
"gitHead": "
|
47
|
+
"gitHead": "bc939e291a4489432fb0fa0707e9c7594517ce94"
|
47
48
|
}
|
@@ -1,14 +1,22 @@
|
|
1
1
|
import { getRepository, Domain, GraphqlLocalClient } from '@things-factory/shell'
|
2
|
-
import { PrivilegeObject, checkPermission } from '@things-factory/auth-base'
|
2
|
+
import { PrivilegeObject, User, checkPermission } from '@things-factory/auth-base'
|
3
|
+
import { cacheService } from '@things-factory/cache-service'
|
3
4
|
|
4
5
|
import { ScenarioEngine } from '../engine/scenario-engine'
|
5
6
|
import { Scenario } from '../service/scenario/scenario'
|
6
|
-
import {
|
7
|
+
import {
|
8
|
+
ScenarioInstance,
|
9
|
+
ScenarioInstanceRunResult,
|
10
|
+
ScenarioInstanceStatus
|
11
|
+
} from '../service/scenario-instance/scenario-instance-type'
|
7
12
|
import { Step } from '../service/step/step-type'
|
8
13
|
|
9
14
|
const debug = require('debug')('things-factory:integration-base:controller:run-scenario')
|
10
15
|
|
11
|
-
async function findScenario(
|
16
|
+
async function findScenario(
|
17
|
+
scenarioName: string,
|
18
|
+
domain: Domain
|
19
|
+
): Promise<{ id: string; name: string; steps: Step[]; domain: Domain; privilege?: PrivilegeObject; ttl?: number }> {
|
12
20
|
var repository = getRepository(Scenario)
|
13
21
|
|
14
22
|
var scenario = await repository.findOne({
|
@@ -26,7 +34,12 @@ async function findScenario(scenarioName: string, domain: Domain): Promise<{ nam
|
|
26
34
|
return scenario as any
|
27
35
|
}
|
28
36
|
|
29
|
-
export async function runScenario(
|
37
|
+
export async function runScenario(
|
38
|
+
instanceName: string,
|
39
|
+
scenarioName: string,
|
40
|
+
variables: any,
|
41
|
+
context: ResolverContext
|
42
|
+
): Promise<ScenarioInstanceRunResult> {
|
30
43
|
const { domain, user, lng, unsafeIP, prohibitedPrivileges } = context.state
|
31
44
|
|
32
45
|
debug('runScenario', scenarioName, instanceName, variables)
|
@@ -44,11 +57,22 @@ export async function runScenario(instanceName: string, scenarioName: string, va
|
|
44
57
|
if (!(await checkPermission(scenario.privilege, user, domain, unsafeIP, prohibitedPrivileges))) {
|
45
58
|
const { category, privilege } = scenario.privilege || {}
|
46
59
|
|
47
|
-
console.error(
|
60
|
+
console.error(
|
61
|
+
`Unauthorized! ${category && privilege ? category + ':' + privilege + ' privilege' : 'ownership granted'} required`
|
62
|
+
)
|
63
|
+
|
64
|
+
throw new Error(
|
65
|
+
context.t('error.scenario run unauthorized', {
|
66
|
+
scenario: scenarioName
|
67
|
+
})
|
68
|
+
)
|
69
|
+
}
|
48
70
|
|
49
|
-
|
50
|
-
|
51
|
-
|
71
|
+
if (scenario.ttl > 0) {
|
72
|
+
const cachedValue = await cacheService.getFromCache(scenario.id, variables || {})
|
73
|
+
if (cachedValue) {
|
74
|
+
return cachedValue.value
|
75
|
+
}
|
52
76
|
}
|
53
77
|
|
54
78
|
/* 시나리오 인스턴스를 생성한다. */
|
@@ -62,19 +86,24 @@ export async function runScenario(instanceName: string, scenarioName: string, va
|
|
62
86
|
})
|
63
87
|
|
64
88
|
try {
|
65
|
-
await instance.run()
|
66
|
-
} catch(err) {
|
89
|
+
return await instance.run()
|
90
|
+
} catch (err) {
|
67
91
|
console.error(err)
|
68
92
|
|
69
|
-
throw new Error(
|
70
|
-
scenario
|
71
|
-
|
93
|
+
throw new Error(
|
94
|
+
context.t('error.scenario run error', {
|
95
|
+
scenario: scenarioName
|
96
|
+
})
|
97
|
+
)
|
72
98
|
}
|
73
|
-
|
74
|
-
return instance
|
75
99
|
}
|
76
100
|
|
77
|
-
export async function startScenario(
|
101
|
+
export async function startScenario(
|
102
|
+
instanceName: string,
|
103
|
+
scenarioName: string,
|
104
|
+
variables: any,
|
105
|
+
context: ResolverContext
|
106
|
+
): Promise<ScenarioInstance> {
|
78
107
|
const { domain, user, lng, unsafeIP, prohibitedPrivileges } = context.state
|
79
108
|
|
80
109
|
debug('startScenario', instanceName, scenarioName, variables)
|
@@ -91,14 +120,19 @@ export async function startScenario(instanceName: string, scenarioName: string,
|
|
91
120
|
|
92
121
|
if (!(await checkPermission(scenario.privilege, user, domain, unsafeIP, prohibitedPrivileges))) {
|
93
122
|
const { category, privilege } = scenario.privilege || {}
|
94
|
-
throw new Error(
|
123
|
+
throw new Error(
|
124
|
+
`Unauthorized! ${category && privilege ? category + ':' + privilege + ' privilege' : 'ownership granted'} required`
|
125
|
+
)
|
95
126
|
}
|
96
127
|
|
97
128
|
instanceName = instanceName || scenarioName
|
98
129
|
return await ScenarioEngine.load(instanceName, scenario, { domain, user, lng, variables })
|
99
130
|
}
|
100
131
|
|
101
|
-
export async function stopScenario(
|
132
|
+
export async function stopScenario(
|
133
|
+
instanceName: string,
|
134
|
+
context: ResolverContext
|
135
|
+
): Promise<ScenarioInstance | undefined> {
|
102
136
|
const { domain, user, unsafeIP, prohibitedPrivileges } = context.state
|
103
137
|
|
104
138
|
debug('stopScenario', instanceName)
|
@@ -120,7 +154,9 @@ export async function stopScenario(instanceName: string, context: ResolverContex
|
|
120
154
|
|
121
155
|
if (!(await checkPermission(scenario.privilege, user, domain, unsafeIP, prohibitedPrivileges))) {
|
122
156
|
const { category, privilege } = scenario.privilege || {}
|
123
|
-
throw new Error(
|
157
|
+
throw new Error(
|
158
|
+
`Unauthorized! ${category && privilege ? category + ':' + privilege + ' privilege' : 'ownership granted'} required`
|
159
|
+
)
|
124
160
|
}
|
125
161
|
|
126
162
|
await ScenarioEngine.unload(domain, instanceName)
|
package/server/engine/types.ts
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import { Connection, PropertySpec, ScenarioInstanceStatus, Step } from '../service'
|
1
|
+
import { Connection, PropertySpec, ScenarioInstance, ScenarioInstanceStatus, Step } from '../service'
|
2
2
|
import { Domain } from '@things-factory/shell'
|
3
3
|
import { User } from '@things-factory/auth-base'
|
4
4
|
|
@@ -76,7 +76,7 @@ export type Context = {
|
|
76
76
|
/**
|
77
77
|
* Root object, can be used for various purposes.
|
78
78
|
*/
|
79
|
-
root
|
79
|
+
root?: ScenarioInstance
|
80
80
|
|
81
81
|
/**
|
82
82
|
* Array of function closures.
|
@@ -22,6 +22,9 @@ export class NewScenario {
|
|
22
22
|
@Field({ nullable: true })
|
23
23
|
timezone?: string
|
24
24
|
|
25
|
+
@Field({ nullable: true })
|
26
|
+
ttl?: number
|
27
|
+
|
25
28
|
@Field({ nullable: true })
|
26
29
|
active?: boolean
|
27
30
|
|
@@ -49,6 +52,9 @@ export class ScenarioPatch {
|
|
49
52
|
@Field({ nullable: true })
|
50
53
|
timezone?: string
|
51
54
|
|
55
|
+
@Field({ nullable: true })
|
56
|
+
ttl?: number
|
57
|
+
|
52
58
|
@Field({ nullable: true })
|
53
59
|
active?: boolean
|
54
60
|
|
@@ -64,6 +64,10 @@ export class Scenario {
|
|
64
64
|
@Field({ nullable: true })
|
65
65
|
timezone?: string
|
66
66
|
|
67
|
+
@Column({ nullable: true })
|
68
|
+
@Field({ nullable: true })
|
69
|
+
ttl?: number
|
70
|
+
|
67
71
|
@OneToMany(type => Step, step => step.scenario)
|
68
72
|
@Field(type => [Step], { nullable: true })
|
69
73
|
steps?: Step[]
|
@@ -2,7 +2,7 @@ import { Arg, Ctx, Mutation, Resolver } from 'type-graphql'
|
|
2
2
|
|
3
3
|
import { ScalarObject } from '@things-factory/shell'
|
4
4
|
|
5
|
-
import { ScenarioInstance } from './scenario-instance-type'
|
5
|
+
import { ScenarioInstance, ScenarioInstanceRunResult } from './scenario-instance-type'
|
6
6
|
|
7
7
|
import {
|
8
8
|
runScenario as controllerRunScenario,
|
@@ -12,7 +12,7 @@ import {
|
|
12
12
|
|
13
13
|
@Resolver(ScenarioInstance)
|
14
14
|
export class ScenarioInstanceMutation {
|
15
|
-
@Mutation(returns =>
|
15
|
+
@Mutation(returns => ScenarioInstanceRunResult, {
|
16
16
|
description: 'To run new scenario instance and will return the result after the scenario stop.'
|
17
17
|
})
|
18
18
|
async runScenario(
|
@@ -20,7 +20,7 @@ export class ScenarioInstanceMutation {
|
|
20
20
|
@Arg('scenarioName') scenarioName: string,
|
21
21
|
@Arg('variables', type => ScalarObject, { nullable: true }) variables: any,
|
22
22
|
@Ctx() context: ResolverContext
|
23
|
-
): Promise<
|
23
|
+
): Promise<ScenarioInstanceRunResult> {
|
24
24
|
return await controllerRunScenario(instanceName, scenarioName, variables, context)
|
25
25
|
}
|
26
26
|
|
@@ -35,7 +35,10 @@ export class ScenarioInstanceMutation {
|
|
35
35
|
}
|
36
36
|
|
37
37
|
@Mutation(returns => ScenarioInstance, { nullable: true, description: 'To start new scenario instance' })
|
38
|
-
async stopScenario(
|
38
|
+
async stopScenario(
|
39
|
+
@Arg('instanceName', { nullable: true }) instanceName: string,
|
40
|
+
@Ctx() context: ResolverContext
|
41
|
+
): Promise<ScenarioInstance | undefined> {
|
39
42
|
return await controllerStopScenario(instanceName, context)
|
40
43
|
}
|
41
44
|
}
|
@@ -39,33 +39,4 @@ export class ScenarioInstanceQuery {
|
|
39
39
|
total: items.length
|
40
40
|
}
|
41
41
|
}
|
42
|
-
|
43
|
-
@FieldResolver(type => ScenarioInstance)
|
44
|
-
async root(@Root() scenarioInstance: ScenarioInstance): Promise<ScenarioInstance> {
|
45
|
-
return scenarioInstance.context?.root as ScenarioInstance
|
46
|
-
}
|
47
|
-
|
48
|
-
@FieldResolver(type => ScenarioInstanceStatus)
|
49
|
-
async state(@Root() scenarioInstance: ScenarioInstance): Promise<ScenarioInstanceStatus> {
|
50
|
-
return scenarioInstance.context?.state
|
51
|
-
}
|
52
|
-
|
53
|
-
@FieldResolver(type => ScenarioInstanceProgress)
|
54
|
-
progress(@Root() scenarioInstance: ScenarioInstance): ScenarioInstanceProgress {
|
55
|
-
return scenarioInstance.calcProgress()
|
56
|
-
}
|
57
|
-
@FieldResolver(type => ScalarObject)
|
58
|
-
async variables(@Root() scenarioInstance: ScenarioInstance): Promise<Object> {
|
59
|
-
return scenarioInstance.context?.variables
|
60
|
-
}
|
61
|
-
|
62
|
-
@FieldResolver(type => ScalarObject)
|
63
|
-
async data(@Root() scenarioInstance: ScenarioInstance): Promise<Object> {
|
64
|
-
return scenarioInstance.context?.data
|
65
|
-
}
|
66
|
-
|
67
|
-
@FieldResolver()
|
68
|
-
async timestamp(@Root() scenarioInstance: ScenarioInstance): Promise<Date> {
|
69
|
-
return new Date()
|
70
|
-
}
|
71
42
|
}
|
@@ -7,6 +7,7 @@ import util from 'util'
|
|
7
7
|
import { createLogger, format, transports } from 'winston'
|
8
8
|
|
9
9
|
import { Domain, pubsub, PubSubLogTransport, ScalarObject } from '@things-factory/shell'
|
10
|
+
import { cacheService } from '@things-factory/cache-service'
|
10
11
|
import { User } from '@things-factory/auth-base'
|
11
12
|
import { sleep } from '@things-factory/utils'
|
12
13
|
|
@@ -87,6 +88,33 @@ export class ScenarioInstanceState {
|
|
87
88
|
public timestamp: Date
|
88
89
|
}
|
89
90
|
|
91
|
+
@ObjectType()
|
92
|
+
export class ScenarioInstanceRunResult {
|
93
|
+
@Field({ nullable: true })
|
94
|
+
public scenarioName: string
|
95
|
+
|
96
|
+
@Field({ nullable: true })
|
97
|
+
public instanceName: string
|
98
|
+
|
99
|
+
@Field(type => ScalarObject, { nullable: true })
|
100
|
+
public variables: any
|
101
|
+
|
102
|
+
@Field(type => ScalarObject, { nullable: true })
|
103
|
+
public data: any
|
104
|
+
|
105
|
+
@Field(type => ScalarObject, { nullable: true })
|
106
|
+
public result: any
|
107
|
+
|
108
|
+
@Field({ nullable: true })
|
109
|
+
public timestamp: Date
|
110
|
+
|
111
|
+
@Field({ nullable: true })
|
112
|
+
public message: string
|
113
|
+
|
114
|
+
@Field({ nullable: true })
|
115
|
+
public state: ScenarioInstanceStatus
|
116
|
+
}
|
117
|
+
|
90
118
|
@ObjectType()
|
91
119
|
export class ScenarioInstance {
|
92
120
|
private subScenarioInstances: ScenarioInstance[] = [] // TODO Imple by WeakSet
|
@@ -106,29 +134,43 @@ export class ScenarioInstance {
|
|
106
134
|
public instanceName: string
|
107
135
|
|
108
136
|
@Field({ nullable: true })
|
109
|
-
root: ScenarioInstance
|
137
|
+
get root(): ScenarioInstance {
|
138
|
+
return this.context?.root
|
139
|
+
}
|
110
140
|
|
111
141
|
@Field({ nullable: true })
|
112
|
-
state: ScenarioInstanceStatus
|
142
|
+
get state(): ScenarioInstanceStatus {
|
143
|
+
return this.context?.state
|
144
|
+
}
|
113
145
|
|
114
146
|
@Field(type => ScenarioInstanceProgress, { nullable: true })
|
115
|
-
progress: ScenarioInstanceProgress
|
147
|
+
get progress(): ScenarioInstanceProgress {
|
148
|
+
return this.calcProgress()
|
149
|
+
}
|
116
150
|
|
117
151
|
@Field(type => ScalarObject, { nullable: true })
|
118
|
-
variables: any
|
152
|
+
get variables(): any {
|
153
|
+
return this.context?.variables
|
154
|
+
}
|
119
155
|
|
120
156
|
@Field(type => ScalarObject, { nullable: true })
|
121
|
-
data: any
|
157
|
+
get data(): any {
|
158
|
+
return this.context?.data
|
159
|
+
}
|
122
160
|
|
123
161
|
@Field(type => ScalarObject, { nullable: true })
|
124
162
|
result: any
|
125
163
|
|
126
164
|
@Field({ nullable: true })
|
127
|
-
timestamp: Date
|
165
|
+
get timestamp(): Date {
|
166
|
+
return new Date()
|
167
|
+
}
|
128
168
|
|
129
169
|
@Field({ nullable: true })
|
130
170
|
public message: string
|
131
171
|
|
172
|
+
private scenarioId: string
|
173
|
+
private scenarioTtl: number
|
132
174
|
private steps: Step[]
|
133
175
|
private rounds: number = 0
|
134
176
|
|
@@ -154,10 +196,22 @@ export class ScenarioInstance {
|
|
154
196
|
}
|
155
197
|
}
|
156
198
|
|
157
|
-
constructor(
|
199
|
+
constructor(
|
200
|
+
instanceName,
|
201
|
+
{
|
202
|
+
id: scenarioId,
|
203
|
+
ttl: scenarioTtl,
|
204
|
+
name: scenarioName,
|
205
|
+
steps,
|
206
|
+
domain: scenarioDomain
|
207
|
+
}: { id: string; ttl?: number; name: string; steps: Step[]; domain: Domain },
|
208
|
+
context?
|
209
|
+
) {
|
158
210
|
var { domain, user, lng, unsafeIP, prohibitedPrivileges } = context || {}
|
159
211
|
domain ||= scenarioDomain
|
160
212
|
|
213
|
+
this.scenarioId = scenarioId
|
214
|
+
this.scenarioTtl = scenarioTtl
|
161
215
|
this.instanceName = instanceName
|
162
216
|
this.scenarioName = scenarioName
|
163
217
|
this.steps = orderBy(steps || [], step => step.sequence)
|
@@ -269,7 +323,10 @@ export class ScenarioInstance {
|
|
269
323
|
this.context.logger.error(ex.message ? ex.message : ex)
|
270
324
|
|
271
325
|
debug('failed to run ', `[ Domain: ${domain.name}, Scenario: ${scenarioName} ]\n`, ex)
|
272
|
-
this.setState(
|
326
|
+
this.setState(
|
327
|
+
ScenarioInstanceStatus.HALTED,
|
328
|
+
typeof message == 'object' ? JSON.stringify(message, null, 2) : message
|
329
|
+
)
|
273
330
|
|
274
331
|
throw ex
|
275
332
|
}
|
@@ -280,6 +337,26 @@ export class ScenarioInstance {
|
|
280
337
|
sum[step.name] = this.context.data[step.name]
|
281
338
|
return sum
|
282
339
|
}, {})
|
340
|
+
|
341
|
+
const { scenarioId, scenarioTtl, variables, message, scenarioName, instanceName, result } = this
|
342
|
+
const obj = {
|
343
|
+
scenarioName,
|
344
|
+
instanceName,
|
345
|
+
variables,
|
346
|
+
data: this.data,
|
347
|
+
result,
|
348
|
+
timestamp: new Date(),
|
349
|
+
message,
|
350
|
+
state: ScenarioInstanceStatus.STOPPED /* redundent, no meaning */
|
351
|
+
}
|
352
|
+
|
353
|
+
if (this.scenarioTtl && this.scenarioId) {
|
354
|
+
setTimeout(() => {
|
355
|
+
cacheService.setInCache(scenarioId, variables || {}, obj, scenarioTtl)
|
356
|
+
})
|
357
|
+
}
|
358
|
+
|
359
|
+
return obj
|
283
360
|
}
|
284
361
|
|
285
362
|
async loadSubscenario(step, scenarioConfig, context) {
|
@@ -442,7 +519,8 @@ export class ScenarioInstance {
|
|
442
519
|
}
|
443
520
|
step.params = step.params || {}
|
444
521
|
|
445
|
-
const connection =
|
522
|
+
const connection =
|
523
|
+
step.connection && ConnectionManager.getConnectionInstanceEntityByName(this.domain, step.connection)
|
446
524
|
|
447
525
|
if (!connection || !connection.edgeId) {
|
448
526
|
var handler = TaskRegistry.getTaskHandler(step.task)
|