@things-factory/integration-base 8.0.0-beta.1 → 8.0.0-beta.2
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/package.json +10 -10
- 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/headless-connector.ts +0 -341
- package/server/engine/connector/http-connector.ts +0 -65
- package/server/engine/connector/index.ts +0 -13
- 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 -11
- package/server/engine/pending-queue.ts +0 -97
- package/server/engine/resource-pool/headless-pool.ts +0 -136
- package/server/engine/resource-pool/index.ts +0 -1
- 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 -128
- package/server/engine/task/headless-scrap.ts +0 -83
- 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,97 +0,0 @@
|
|
1
|
-
const debug = require('debug')('things-factory:integration-base:pending-queue')
|
2
|
-
|
3
|
-
export type PendingObject = {
|
4
|
-
stuff
|
5
|
-
due
|
6
|
-
priority
|
7
|
-
tag
|
8
|
-
}
|
9
|
-
|
10
|
-
export class PendingQueue {
|
11
|
-
private _queue: PendingObject[] = []
|
12
|
-
private _changedCallback
|
13
|
-
|
14
|
-
constructor(changedCallback) {
|
15
|
-
this._changedCallback = changedCallback
|
16
|
-
}
|
17
|
-
|
18
|
-
get queue() {
|
19
|
-
return this._queue
|
20
|
-
}
|
21
|
-
|
22
|
-
get status() {
|
23
|
-
return {
|
24
|
-
total: this._queue.length
|
25
|
-
}
|
26
|
-
}
|
27
|
-
|
28
|
-
reset() {
|
29
|
-
this._queue = []
|
30
|
-
this._changedCallback(this._queue)
|
31
|
-
}
|
32
|
-
|
33
|
-
put({ delay, stuff, priority = 0, tag = '' }) {
|
34
|
-
const due = Date.now() + (Number(delay) || 0) * 1000
|
35
|
-
const insertBefore = this._queue.findIndex(pended => pended.due > due)
|
36
|
-
|
37
|
-
if (insertBefore == -1) {
|
38
|
-
this._queue.push({
|
39
|
-
due,
|
40
|
-
priority: Number(priority) || 0,
|
41
|
-
stuff,
|
42
|
-
tag: tag || ''
|
43
|
-
})
|
44
|
-
} else {
|
45
|
-
this._queue.splice(insertBefore, 0, {
|
46
|
-
due,
|
47
|
-
priority,
|
48
|
-
stuff,
|
49
|
-
tag
|
50
|
-
})
|
51
|
-
}
|
52
|
-
|
53
|
-
this._changedCallback(this._queue)
|
54
|
-
|
55
|
-
debug('put', this.status)
|
56
|
-
}
|
57
|
-
|
58
|
-
pick(tag = '') {
|
59
|
-
const due = Date.now()
|
60
|
-
|
61
|
-
var toppick
|
62
|
-
var index = -1
|
63
|
-
|
64
|
-
for (let i = 0; i < this._queue.length; i++) {
|
65
|
-
var pended = this._queue[i]
|
66
|
-
|
67
|
-
if (pended.due > due) {
|
68
|
-
break
|
69
|
-
}
|
70
|
-
|
71
|
-
if (pended.tag !== tag) {
|
72
|
-
continue
|
73
|
-
}
|
74
|
-
|
75
|
-
if (!toppick || toppick.priority < pended.priority) {
|
76
|
-
toppick = pended
|
77
|
-
index = i
|
78
|
-
}
|
79
|
-
}
|
80
|
-
|
81
|
-
if (index !== -1) {
|
82
|
-
this._queue.splice(index, 1)
|
83
|
-
this._changedCallback(this._queue)
|
84
|
-
}
|
85
|
-
|
86
|
-
toppick && debug('pick', toppick, this.status, due)
|
87
|
-
|
88
|
-
return toppick
|
89
|
-
}
|
90
|
-
|
91
|
-
cancel(stuff) {
|
92
|
-
const index = this._queue.findIndex(pended => pended.stuff === stuff)
|
93
|
-
index !== -1 && this._queue.splice(index, 1)
|
94
|
-
|
95
|
-
this._changedCallback(this._queue)
|
96
|
-
}
|
97
|
-
}
|
@@ -1,136 +0,0 @@
|
|
1
|
-
import * as genericPool from 'generic-pool'
|
2
|
-
import { config, logger } from '@things-factory/env'
|
3
|
-
|
4
|
-
try {
|
5
|
-
var puppeteer = require('puppeteer')
|
6
|
-
} catch (err) {
|
7
|
-
logger.error(err)
|
8
|
-
}
|
9
|
-
|
10
|
-
let headlessPool
|
11
|
-
|
12
|
-
export function getHeadlessPool() {
|
13
|
-
if (!headlessPool) {
|
14
|
-
headlessPool = createHeadlessPool({ min: 2, max: 20, acquireTimeoutMillis: 15000, testOnBorrow: true })
|
15
|
-
}
|
16
|
-
|
17
|
-
return headlessPool
|
18
|
-
}
|
19
|
-
|
20
|
-
function createHeadlessPool(options: genericPool.Options) {
|
21
|
-
return genericPool.createPool(
|
22
|
-
{
|
23
|
-
create() {
|
24
|
-
console.log('headless instance in headless-pool-integration about to create')
|
25
|
-
return initializeChromium()
|
26
|
-
},
|
27
|
-
validate(browser) {
|
28
|
-
return Promise.race([
|
29
|
-
new Promise(res => setTimeout(() => res(false), 1500)),
|
30
|
-
browser
|
31
|
-
//@ts-ignore
|
32
|
-
.version()
|
33
|
-
.then(() => true)
|
34
|
-
.catch(() => false)
|
35
|
-
])
|
36
|
-
},
|
37
|
-
destroy(browser) {
|
38
|
-
//@ts-ignore
|
39
|
-
return browser.close()
|
40
|
-
}
|
41
|
-
} as genericPool.Factory<any>,
|
42
|
-
options
|
43
|
-
)
|
44
|
-
}
|
45
|
-
|
46
|
-
async function destroyHeadlessPool() {
|
47
|
-
if (headlessPool) {
|
48
|
-
console.log('headless-pool-integration about to destroy')
|
49
|
-
|
50
|
-
try {
|
51
|
-
await Promise.race([
|
52
|
-
headlessPool.drain().then(() => headlessPool.clear()), // 정리 작업
|
53
|
-
new Promise(
|
54
|
-
(_, reject) => setTimeout(() => reject(new Error('Destroy timeout')), 5000) // 5초 타임아웃 설정
|
55
|
-
)
|
56
|
-
])
|
57
|
-
console.log('Headless pool destroyed')
|
58
|
-
} catch (err) {
|
59
|
-
logger.error('Failed to destroy headless pool:', err)
|
60
|
-
}
|
61
|
-
}
|
62
|
-
}
|
63
|
-
|
64
|
-
const CHROMIUM_PATH = config.get('CHROMIUM_PATH')
|
65
|
-
|
66
|
-
async function initializeChromium() {
|
67
|
-
try {
|
68
|
-
if (!puppeteer) {
|
69
|
-
return
|
70
|
-
}
|
71
|
-
|
72
|
-
const launchSetting = {
|
73
|
-
args: ['--hide-scrollbars', '--mute-audio', '--no-sandbox', '--use-gl=egl'],
|
74
|
-
headless: 'shell'
|
75
|
-
}
|
76
|
-
|
77
|
-
if (CHROMIUM_PATH) {
|
78
|
-
launchSetting['executablePath'] = CHROMIUM_PATH
|
79
|
-
}
|
80
|
-
|
81
|
-
const browser = await puppeteer.launch(launchSetting)
|
82
|
-
|
83
|
-
return browser
|
84
|
-
} catch (err) {
|
85
|
-
logger.error(err)
|
86
|
-
}
|
87
|
-
}
|
88
|
-
|
89
|
-
// Graceful shutdown logic
|
90
|
-
function setupProcessExitHandlers() {
|
91
|
-
let isCleaningUp = false // 중복 정리를 방지
|
92
|
-
|
93
|
-
const cleanup = async () => {
|
94
|
-
if (isCleaningUp) return // 이미 정리 중이면 무시
|
95
|
-
isCleaningUp = true
|
96
|
-
|
97
|
-
console.log('Application is shutting down. Cleaning up resources...')
|
98
|
-
try {
|
99
|
-
// Pool 정리 작업 실행
|
100
|
-
await destroyHeadlessPool()
|
101
|
-
} catch (err) {
|
102
|
-
logger.error('Error during cleanup:', err)
|
103
|
-
} finally {
|
104
|
-
console.log('Cleanup completed.')
|
105
|
-
}
|
106
|
-
}
|
107
|
-
|
108
|
-
const onExit = async (signal?: string) => {
|
109
|
-
console.log(`Received signal: ${signal || 'unknown'}`)
|
110
|
-
await cleanup()
|
111
|
-
|
112
|
-
// 다른 핸들러가 실행될 수 있도록 exit 호출을 지연
|
113
|
-
process.nextTick(() => process.exit(0)) // Tick 뒤에 종료
|
114
|
-
}
|
115
|
-
|
116
|
-
// Handle termination signals
|
117
|
-
process.once('SIGINT', () => onExit('SIGINT')) // Ctrl+C
|
118
|
-
process.once('SIGTERM', () => onExit('SIGTERM')) // Termination signal
|
119
|
-
|
120
|
-
// Handle uncaught exceptions
|
121
|
-
process.once('uncaughtException', async err => {
|
122
|
-
logger.error('Uncaught Exception:', err)
|
123
|
-
await cleanup()
|
124
|
-
process.nextTick(() => process.exit(1)) // Tick 뒤에 종료
|
125
|
-
})
|
126
|
-
|
127
|
-
// Handle unhandled promise rejections
|
128
|
-
process.once('unhandledRejection', async reason => {
|
129
|
-
logger.error('Unhandled Rejection:', reason)
|
130
|
-
await cleanup()
|
131
|
-
process.nextTick(() => process.exit(1)) // Tick 뒤에 종료
|
132
|
-
})
|
133
|
-
}
|
134
|
-
|
135
|
-
// Initialize process exit handlers
|
136
|
-
setupProcessExitHandlers()
|
@@ -1 +0,0 @@
|
|
1
|
-
export * from './headless-pool'
|
@@ -1,106 +0,0 @@
|
|
1
|
-
import { getRepository, GraphqlLocalClient, pubsub } from '@things-factory/shell'
|
2
|
-
|
3
|
-
import { Scenario } from '../service/scenario/scenario'
|
4
|
-
import { ScenarioInstance } from '../service/scenario-instance/scenario-instance-type'
|
5
|
-
|
6
|
-
import { PendingQueue } from './pending-queue'
|
7
|
-
|
8
|
-
const debug = require('debug')('things-factory:integration-base:scenario-engine')
|
9
|
-
|
10
|
-
export class ScenarioEngine {
|
11
|
-
private static scenarioInstances = {} // TODO impl. by WeakMap
|
12
|
-
private static pendingQueues = {}
|
13
|
-
|
14
|
-
public static getPendingQueue(domain) {
|
15
|
-
if (!ScenarioEngine.pendingQueues[domain.id]) {
|
16
|
-
ScenarioEngine.pendingQueues[domain.id] = new PendingQueue(queue => {
|
17
|
-
pubsub.publish('scenario-queue-state', {
|
18
|
-
scenarioQueueState: {
|
19
|
-
domain,
|
20
|
-
queue
|
21
|
-
}
|
22
|
-
})
|
23
|
-
})
|
24
|
-
}
|
25
|
-
|
26
|
-
return ScenarioEngine.pendingQueues[domain.id]
|
27
|
-
}
|
28
|
-
|
29
|
-
public static getScenarioInstance(domain, instanceName): ScenarioInstance {
|
30
|
-
return ScenarioEngine.scenarioInstances[domain.id]?.[instanceName]
|
31
|
-
}
|
32
|
-
|
33
|
-
public static getScenarioInstances(domain, scenarioName?): ScenarioInstance[] {
|
34
|
-
const instances: ScenarioInstance[] = Object.values(ScenarioEngine.scenarioInstances[domain.id] || {}) || []
|
35
|
-
return instances.filter(instance => !scenarioName || instance.scenarioName == scenarioName)
|
36
|
-
}
|
37
|
-
|
38
|
-
public static async load(instanceName, scenarioConfig, context?) {
|
39
|
-
const { domain: scenarioDomain } = scenarioConfig
|
40
|
-
const domain = context?.domain || scenarioDomain
|
41
|
-
|
42
|
-
debug('load', domain.subdomain, instanceName)
|
43
|
-
|
44
|
-
var scenarioInstances = ScenarioEngine.scenarioInstances[domain.id]
|
45
|
-
if (!scenarioInstances) {
|
46
|
-
scenarioInstances = ScenarioEngine.scenarioInstances[domain.id] = {}
|
47
|
-
}
|
48
|
-
|
49
|
-
var scenarioInstance = scenarioInstances[instanceName]
|
50
|
-
if (scenarioInstance) {
|
51
|
-
debug('load - duplicated', instanceName)
|
52
|
-
return scenarioInstance
|
53
|
-
}
|
54
|
-
|
55
|
-
var instance = new ScenarioInstance(instanceName, scenarioConfig, {
|
56
|
-
...context,
|
57
|
-
client: GraphqlLocalClient.client,
|
58
|
-
disposer: () => {
|
59
|
-
this.unload(domain, instanceName)
|
60
|
-
}
|
61
|
-
})
|
62
|
-
|
63
|
-
instance.start().catch(err => {
|
64
|
-
/* IMPORTANT. if you didn't catch exception here, system will be exit */
|
65
|
-
console.error(
|
66
|
-
`An exception occurred while executing the scenario instance named "${instanceName}" on the domain "${domain.name}"`,
|
67
|
-
err
|
68
|
-
)
|
69
|
-
})
|
70
|
-
|
71
|
-
scenarioInstances[instanceName] = instance
|
72
|
-
|
73
|
-
return instance
|
74
|
-
}
|
75
|
-
|
76
|
-
public static async unload(domain, instanceName) {
|
77
|
-
var scenarioInstances = ScenarioEngine.scenarioInstances[domain.id]
|
78
|
-
if (!scenarioInstances) {
|
79
|
-
return
|
80
|
-
}
|
81
|
-
|
82
|
-
var instance = scenarioInstances[instanceName]
|
83
|
-
if (!instance) {
|
84
|
-
return
|
85
|
-
}
|
86
|
-
|
87
|
-
delete scenarioInstances[instanceName]
|
88
|
-
|
89
|
-
instance.unload()
|
90
|
-
}
|
91
|
-
|
92
|
-
// will be deprecated soon
|
93
|
-
public static async loadAll() {
|
94
|
-
const SCENARIOS = await getRepository(Scenario).find({
|
95
|
-
where: { active: true },
|
96
|
-
relations: ['domain', 'steps']
|
97
|
-
})
|
98
|
-
|
99
|
-
debug(
|
100
|
-
'load-all',
|
101
|
-
SCENARIOS.map(scenario => `${scenario.domain.subdomain}: ${scenario.name}`)
|
102
|
-
)
|
103
|
-
|
104
|
-
SCENARIOS.forEach(scenario => ScenarioEngine.load(scenario.name, scenario))
|
105
|
-
}
|
106
|
-
}
|
@@ -1,73 +0,0 @@
|
|
1
|
-
import { access, deepClone } from '@things-factory/utils'
|
2
|
-
import { TaskRegistry } from '../task-registry'
|
3
|
-
import { substitute } from './utils/substitute'
|
4
|
-
import { ScenarioEngine } from '../scenario-engine'
|
5
|
-
import { InputStep } from '../../service/step/step-type'
|
6
|
-
import { Context } from '../types'
|
7
|
-
|
8
|
-
const debug = require('debug')('things-factory:integration-base:book-up-scenarios')
|
9
|
-
|
10
|
-
async function BookUpScenario(step: InputStep, { logger, data, domain }: Context) {
|
11
|
-
var {
|
12
|
-
params: { scenario, delay, priority, variables, tag }
|
13
|
-
} = step
|
14
|
-
|
15
|
-
const pendingQueue = ScenarioEngine.getPendingQueue(domain)
|
16
|
-
delay = Number(substitute(delay, data))
|
17
|
-
|
18
|
-
pendingQueue.put({
|
19
|
-
stuff: {
|
20
|
-
scenario,
|
21
|
-
variables: deepClone(access(variables, data))
|
22
|
-
},
|
23
|
-
delay,
|
24
|
-
priority: Number(priority) || 0,
|
25
|
-
tag: tag || ''
|
26
|
-
})
|
27
|
-
|
28
|
-
debug('pending', scenario, delay, tag, priority)
|
29
|
-
|
30
|
-
return {
|
31
|
-
data: pendingQueue.status
|
32
|
-
}
|
33
|
-
}
|
34
|
-
|
35
|
-
BookUpScenario.parameterSpec = [
|
36
|
-
{
|
37
|
-
type: 'entity-selector',
|
38
|
-
name: 'scenario',
|
39
|
-
label: 'scenario',
|
40
|
-
property: {
|
41
|
-
queryName: 'scenarios'
|
42
|
-
}
|
43
|
-
},
|
44
|
-
{
|
45
|
-
type: 'string',
|
46
|
-
name: 'delay',
|
47
|
-
label: 'delay',
|
48
|
-
placeHolder: 'seconds'
|
49
|
-
},
|
50
|
-
{
|
51
|
-
type: 'select',
|
52
|
-
name: 'priority',
|
53
|
-
label: 'priority',
|
54
|
-
property: {
|
55
|
-
options: ['', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
|
56
|
-
}
|
57
|
-
},
|
58
|
-
{
|
59
|
-
type: 'scenario-step-input',
|
60
|
-
name: 'variables',
|
61
|
-
label: 'variables'
|
62
|
-
},
|
63
|
-
{
|
64
|
-
type: 'string',
|
65
|
-
name: 'tag',
|
66
|
-
label: 'tag'
|
67
|
-
}
|
68
|
-
]
|
69
|
-
|
70
|
-
BookUpScenario.connectorFree = true
|
71
|
-
BookUpScenario.help = 'integration/task/book-up-scenario'
|
72
|
-
|
73
|
-
TaskRegistry.registerTaskHandler('book-up-scenario', BookUpScenario)
|
@@ -1,127 +0,0 @@
|
|
1
|
-
const fs = require('fs')
|
2
|
-
const { URL } = require('url')
|
3
|
-
const path = require('path')
|
4
|
-
const readline = require('readline')
|
5
|
-
const { Readable } = require('stream')
|
6
|
-
|
7
|
-
import { TaskRegistry } from '../task-registry'
|
8
|
-
|
9
|
-
import { InputStep } from '../../service/step/step-type'
|
10
|
-
import { Context } from '../types'
|
11
|
-
|
12
|
-
async function createReadStream(source) {
|
13
|
-
let stream
|
14
|
-
|
15
|
-
try {
|
16
|
-
const url = new URL(source)
|
17
|
-
const protocol = url.protocol.slice(0, -1) // Remove ':' from protocol
|
18
|
-
const filePath = url.pathname
|
19
|
-
|
20
|
-
switch (protocol) {
|
21
|
-
case 'file':
|
22
|
-
stream = fs.createReadStream(filePath)
|
23
|
-
break
|
24
|
-
case 'http':
|
25
|
-
case 'https':
|
26
|
-
const response = await fetch(source)
|
27
|
-
stream = Readable.from(await response.text())
|
28
|
-
// 아래의 경우는 문제 발생함. /attachment/:attachment로 테스트함 - 동일 서버에서 요청과 응답을 하는 상홍에서의 문제인가 ?
|
29
|
-
// TODO 스트림을 제대로 사용해야 서버의 자원 부담이 덜할텐데.
|
30
|
-
// TODO attachment 서비스가 authorization을 지원하는 상황에서는 인증에서 통과하지 못할 수도 있음.
|
31
|
-
// stream = response.body.getReader()
|
32
|
-
break
|
33
|
-
default:
|
34
|
-
stream = fs.createReadStream(path.resolve(source))
|
35
|
-
}
|
36
|
-
} catch (e) {
|
37
|
-
stream = fs.createReadStream(path.resolve(source))
|
38
|
-
}
|
39
|
-
|
40
|
-
return stream
|
41
|
-
}
|
42
|
-
|
43
|
-
async function CsvReadline(step: InputStep, context: Context) {
|
44
|
-
var {
|
45
|
-
params: { path }
|
46
|
-
} = step
|
47
|
-
|
48
|
-
var { logger, __csv_resources, closures } = context
|
49
|
-
|
50
|
-
if (!path) {
|
51
|
-
throw new Error('csv filepath should be given')
|
52
|
-
}
|
53
|
-
|
54
|
-
if (!__csv_resources) {
|
55
|
-
__csv_resources = context.__csv_resources = [] as ReadableStream[]
|
56
|
-
}
|
57
|
-
|
58
|
-
if (!__csv_resources[path]) {
|
59
|
-
let stream
|
60
|
-
|
61
|
-
try {
|
62
|
-
stream = await createReadStream(path)
|
63
|
-
} catch (e) {
|
64
|
-
throw new Error(e)
|
65
|
-
}
|
66
|
-
|
67
|
-
if (!stream) {
|
68
|
-
throw new Error('csv file loading failed')
|
69
|
-
}
|
70
|
-
|
71
|
-
const rl = readline.createInterface({
|
72
|
-
input: stream,
|
73
|
-
crlfDelay: Infinity
|
74
|
-
})
|
75
|
-
|
76
|
-
const iterator = rl[Symbol.asyncIterator]()
|
77
|
-
const { value: header } = await iterator.next()
|
78
|
-
|
79
|
-
__csv_resources[path] = {
|
80
|
-
stream,
|
81
|
-
iterator,
|
82
|
-
header: header ? header.split(',').map(h => h.replace(/"/g, '')) : []
|
83
|
-
}
|
84
|
-
|
85
|
-
closures.push(async () => {
|
86
|
-
try {
|
87
|
-
stream && (await stream.close())
|
88
|
-
logger.info(`csv file(${path}) is released before ending the scenario.`)
|
89
|
-
delete __csv_resources[path]
|
90
|
-
} catch (e) {
|
91
|
-
logger.error(e)
|
92
|
-
}
|
93
|
-
})
|
94
|
-
}
|
95
|
-
|
96
|
-
const { iterator, header } = __csv_resources[path]
|
97
|
-
|
98
|
-
const data = {} as { [key: string]: string }
|
99
|
-
const { value: line } = await iterator.next()
|
100
|
-
|
101
|
-
if (!line) {
|
102
|
-
return
|
103
|
-
}
|
104
|
-
|
105
|
-
const lineData = line.split(',')
|
106
|
-
|
107
|
-
for (let i = 0; i < header.length; i++) {
|
108
|
-
data[header[i]] = lineData[i]
|
109
|
-
}
|
110
|
-
|
111
|
-
return {
|
112
|
-
data
|
113
|
-
}
|
114
|
-
}
|
115
|
-
|
116
|
-
CsvReadline.parameterSpec = [
|
117
|
-
{
|
118
|
-
type: 'string',
|
119
|
-
name: 'path',
|
120
|
-
label: 'path'
|
121
|
-
}
|
122
|
-
]
|
123
|
-
|
124
|
-
CsvReadline.connectorFree = true
|
125
|
-
CsvReadline.help = 'integration/task/csv-readline'
|
126
|
-
|
127
|
-
TaskRegistry.registerTaskHandler('csv-readline', CsvReadline)
|
@@ -1,36 +0,0 @@
|
|
1
|
-
import { access } from '@things-factory/utils'
|
2
|
-
import { TaskRegistry } from '../task-registry'
|
3
|
-
|
4
|
-
import { InputStep } from '../../service/step/step-type'
|
5
|
-
import { Context } from '../types'
|
6
|
-
|
7
|
-
async function DataAccessor(step: InputStep, { logger, data }: Context) {
|
8
|
-
var {
|
9
|
-
params: { target, accessor }
|
10
|
-
} = step
|
11
|
-
|
12
|
-
const input = access(target, data)
|
13
|
-
const output = access(accessor, input)
|
14
|
-
|
15
|
-
return {
|
16
|
-
data: output
|
17
|
-
}
|
18
|
-
}
|
19
|
-
|
20
|
-
DataAccessor.parameterSpec = [
|
21
|
-
{
|
22
|
-
type: 'scenario-step-input',
|
23
|
-
name: 'target',
|
24
|
-
label: 'target'
|
25
|
-
},
|
26
|
-
{
|
27
|
-
type: 'data-accessor',
|
28
|
-
name: 'accessor',
|
29
|
-
label: 'accessor'
|
30
|
-
}
|
31
|
-
]
|
32
|
-
|
33
|
-
DataAccessor.connectorFree = true
|
34
|
-
DataAccessor.help = 'integration/task/data-accessor'
|
35
|
-
|
36
|
-
TaskRegistry.registerTaskHandler('data-accessor', DataAccessor)
|
@@ -1,47 +0,0 @@
|
|
1
|
-
import { access } from '@things-factory/utils'
|
2
|
-
import { TaskRegistry } from '../task-registry'
|
3
|
-
|
4
|
-
import { InputStep } from '../../service/step/step-type'
|
5
|
-
import { Context } from '../types'
|
6
|
-
|
7
|
-
function mapping(rule, input) {
|
8
|
-
if (Array.isArray(input)) {
|
9
|
-
return input.map(i => mapping(rule, i))
|
10
|
-
}
|
11
|
-
|
12
|
-
return Object.keys(rule).reduce((sum, key) => {
|
13
|
-
sum[key] = input[rule[key]]
|
14
|
-
return sum
|
15
|
-
}, {} as any)
|
16
|
-
}
|
17
|
-
|
18
|
-
async function DataMapper(step: InputStep, { logger, data }: Context) {
|
19
|
-
var {
|
20
|
-
params: { accessor, mappingRule }
|
21
|
-
} = step
|
22
|
-
|
23
|
-
const input = access(accessor, data)
|
24
|
-
const output = mapping(mappingRule || {}, input)
|
25
|
-
|
26
|
-
return {
|
27
|
-
data: output
|
28
|
-
}
|
29
|
-
}
|
30
|
-
|
31
|
-
DataMapper.parameterSpec = [
|
32
|
-
{
|
33
|
-
type: 'scenario-step-input',
|
34
|
-
name: 'accessor',
|
35
|
-
label: 'accessor'
|
36
|
-
},
|
37
|
-
{
|
38
|
-
type: 'key-values',
|
39
|
-
name: 'mappingRule',
|
40
|
-
label: 'mapping-rule'
|
41
|
-
}
|
42
|
-
]
|
43
|
-
|
44
|
-
DataMapper.connectorFree = true
|
45
|
-
DataMapper.help = 'integration/task/data-mapper'
|
46
|
-
|
47
|
-
TaskRegistry.registerTaskHandler('data-mapper', DataMapper)
|
@@ -1,56 +0,0 @@
|
|
1
|
-
import { ConnectionManager } from '../connection-manager'
|
2
|
-
import { TaskRegistry } from '../task-registry'
|
3
|
-
import { InputStep } from '../../service/step/step-type'
|
4
|
-
import { Context } from '../types'
|
5
|
-
import 'ses'
|
6
|
-
|
7
|
-
async function DatabaseQuery(step: InputStep, context: Context) {
|
8
|
-
var { domain, user, data, variables, lng } = context
|
9
|
-
var {
|
10
|
-
connection: connectionName,
|
11
|
-
params: { query }
|
12
|
-
} = step
|
13
|
-
|
14
|
-
var dbconnection = ConnectionManager.getConnectionInstanceByName(domain, connectionName)
|
15
|
-
|
16
|
-
const compartment = new Compartment({
|
17
|
-
domain,
|
18
|
-
user,
|
19
|
-
lng,
|
20
|
-
data,
|
21
|
-
variables,
|
22
|
-
console
|
23
|
-
})
|
24
|
-
|
25
|
-
let evalQuery
|
26
|
-
try {
|
27
|
-
evalQuery = compartment.evaluate('`' + query + '`')
|
28
|
-
} catch (err) {
|
29
|
-
throw new Error(`Failed to evaluate query: ${err.message}`)
|
30
|
-
}
|
31
|
-
|
32
|
-
var queryResult = await dbconnection.query(evalQuery, [])
|
33
|
-
|
34
|
-
return {
|
35
|
-
data: queryResult
|
36
|
-
}
|
37
|
-
}
|
38
|
-
|
39
|
-
DatabaseQuery.parameterSpec = [
|
40
|
-
{
|
41
|
-
type: 'textarea',
|
42
|
-
name: 'query',
|
43
|
-
label: 'query',
|
44
|
-
property: {
|
45
|
-
language: 'sql',
|
46
|
-
showLineNumbers: true
|
47
|
-
},
|
48
|
-
styles: {
|
49
|
-
flex: '1'
|
50
|
-
}
|
51
|
-
}
|
52
|
-
]
|
53
|
-
|
54
|
-
DatabaseQuery.help = 'integration/task/database-query'
|
55
|
-
|
56
|
-
TaskRegistry.registerTaskHandler('database-query', DatabaseQuery)
|
@@ -1,21 +0,0 @@
|
|
1
|
-
import { TaskRegistry } from '../task-registry'
|
2
|
-
import { ConnectionManager } from '../connection-manager'
|
3
|
-
|
4
|
-
import { InputStep } from '../../service/step/step-type'
|
5
|
-
import { Context } from '../types'
|
6
|
-
|
7
|
-
async function EchoReceive(step: InputStep, { logger, domain }: Context) {
|
8
|
-
var { connection: connectionName } = step
|
9
|
-
|
10
|
-
var connection = ConnectionManager.getConnectionInstanceByName(domain, connectionName)
|
11
|
-
|
12
|
-
var message = await connection.read()
|
13
|
-
|
14
|
-
return {
|
15
|
-
data: message.toString()
|
16
|
-
}
|
17
|
-
}
|
18
|
-
|
19
|
-
EchoReceive.parameterSpec = []
|
20
|
-
|
21
|
-
TaskRegistry.registerTaskHandler('echo-receive', EchoReceive)
|