@things-factory/integration-base 8.0.89 → 8.0.92
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/operato-connector.js +17 -6
- package/dist-server/engine/connector/operato-connector.js.map +1 -1
- package/dist-server/engine/connector/socket-server.js +12 -2
- package/dist-server/engine/connector/socket-server.js.map +1 -1
- package/dist-server/engine/task/socket-listener.js +27 -9
- package/dist-server/engine/task/socket-listener.js.map +1 -1
- package/dist-server/service/index.d.ts +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/server/engine/connector/operato-connector.ts +19 -5
- package/server/engine/connector/socket-server.ts +16 -2
- package/server/engine/task/socket-listener.ts +28 -9
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@things-factory/integration-base",
|
|
3
|
-
"version": "8.0.
|
|
3
|
+
"version": "8.0.92",
|
|
4
4
|
"main": "dist-server/index.js",
|
|
5
5
|
"browser": "client/index.js",
|
|
6
6
|
"things-factory": true,
|
|
@@ -44,5 +44,5 @@
|
|
|
44
44
|
"readline": "^1.3.0",
|
|
45
45
|
"ses": "^1.5.0"
|
|
46
46
|
},
|
|
47
|
-
"gitHead": "
|
|
47
|
+
"gitHead": "7f6ea0914d9117e9fe4ca3fff64a8a0faedb616f"
|
|
48
48
|
}
|
|
@@ -130,9 +130,10 @@ export class OperatoConnector implements Connector {
|
|
|
130
130
|
})
|
|
131
131
|
|
|
132
132
|
const subscriptions: SubscriberData[] = []
|
|
133
|
-
Object.keys(subscriptionHandlers).
|
|
134
|
-
if (!tag || !subscriptionHandlers[tag]) return
|
|
133
|
+
const tags = Object.keys(subscriptionHandlers).filter(tag => tag && subscriptionHandlers[tag])
|
|
135
134
|
|
|
135
|
+
/* 시나리오 조회 및 subscription 등록을 순차적으로 처리 */
|
|
136
|
+
for (const tag of tags) {
|
|
136
137
|
const scenarioName = subscriptionHandlers[tag]
|
|
137
138
|
|
|
138
139
|
// fetch a scenario
|
|
@@ -143,6 +144,14 @@ export class OperatoConnector implements Connector {
|
|
|
143
144
|
relations: ['steps', 'domain']
|
|
144
145
|
})
|
|
145
146
|
|
|
147
|
+
/* 시나리오가 DB에 없으면 경고 로그를 남기고 건너뜀 */
|
|
148
|
+
if (!selectedScenario) {
|
|
149
|
+
ConnectionManager.logger.warn(
|
|
150
|
+
`(${connection.name}) scenario not found for tag "${tag}" (scenarioName: "${scenarioName}") - skipping subscription`
|
|
151
|
+
)
|
|
152
|
+
continue
|
|
153
|
+
}
|
|
154
|
+
|
|
146
155
|
const subscription = client.subscribe({
|
|
147
156
|
query: gql`
|
|
148
157
|
subscription {
|
|
@@ -156,8 +165,13 @@ export class OperatoConnector implements Connector {
|
|
|
156
165
|
|
|
157
166
|
const subscriptionObserver = subscription.subscribe({
|
|
158
167
|
next: async data => {
|
|
159
|
-
|
|
160
|
-
|
|
168
|
+
/* subscription 수신 시 에러가 발생해도 프로세스가 죽지 않도록 catch 처리 */
|
|
169
|
+
try {
|
|
170
|
+
debug('received pubsub msg.:', data?.data)
|
|
171
|
+
await this.runScenario(subscriptions, data?.data?.data)
|
|
172
|
+
} catch (e) {
|
|
173
|
+
ConnectionManager.logger.error(`(${connection.name}:${tag}) runScenario failed`, e)
|
|
174
|
+
}
|
|
161
175
|
},
|
|
162
176
|
error: error => {
|
|
163
177
|
ConnectionManager.logger.error(`(${connection.name}:${connection.endpoint}) subscription error`, error)
|
|
@@ -177,7 +191,7 @@ export class OperatoConnector implements Connector {
|
|
|
177
191
|
subscriptionObserver
|
|
178
192
|
})
|
|
179
193
|
ConnectionManager.logger.info(`(${tag}:${scenarioName}) subscription closed flag: ${subscriptionObserver.closed}`)
|
|
180
|
-
}
|
|
194
|
+
}
|
|
181
195
|
|
|
182
196
|
client['subscriptions'] = subscriptions
|
|
183
197
|
ConnectionManager.addConnectionInstance(connection, client)
|
|
@@ -16,23 +16,37 @@ export class SocketServer implements Connector {
|
|
|
16
16
|
async connect(config: InputConnection): Promise<void> {
|
|
17
17
|
var em = new EventEmitter()
|
|
18
18
|
var [host = '0.0.0.0', port = 8124] = config.endpoint.split(':')
|
|
19
|
+
var clientIPs = new Set<string>()
|
|
19
20
|
return new Promise((resolve, reject) => {
|
|
20
21
|
var server = net.createServer(tcp => {
|
|
22
|
+
const remoteIP = `${tcp.remoteAddress}:${tcp.remotePort}`
|
|
23
|
+
clientIPs.add(remoteIP)
|
|
21
24
|
ConnectionManager.logger.info('Client connection: ')
|
|
22
25
|
ConnectionManager.logger.info(' local = %s:%s', tcp.localAddress, tcp.localPort)
|
|
23
26
|
ConnectionManager.logger.info(' remote = %s:%s', tcp.remoteAddress, tcp.remotePort)
|
|
27
|
+
console.log(
|
|
28
|
+
`[socket-server] ${config.name} clients: ${clientIPs.size}\n${[...clientIPs].sort().map(ip => ` - ${ip}`).join('\n')}`
|
|
29
|
+
)
|
|
24
30
|
tcp.on('data', (data: any) => {
|
|
25
31
|
em['__tcp__'] = tcp
|
|
26
32
|
var message = data.toString()
|
|
27
33
|
message = message.replace('SB#', '')
|
|
28
34
|
message = message.replace(/(\r\n|\n|\r)/gm, '')
|
|
29
|
-
|
|
35
|
+
// IP 정보를 함께 전달한다
|
|
36
|
+
em.emit('socket-message-arrive', message, tcp.remoteAddress)
|
|
30
37
|
ConnectionManager.logger.info(`socket ${message}`)
|
|
31
38
|
tcp.write('ok')
|
|
32
39
|
})
|
|
33
40
|
|
|
34
|
-
tcp.on('
|
|
41
|
+
tcp.on('close', hadError => {
|
|
35
42
|
ConnectionManager.logger.info('Client disconnected')
|
|
43
|
+
if (hadError) {
|
|
44
|
+
ConnectionManager.logger.info('Client disconnected with error: ' + hadError)
|
|
45
|
+
}
|
|
46
|
+
clientIPs.delete(remoteIP)
|
|
47
|
+
console.log(
|
|
48
|
+
`[socket-server] ${config.name} clients: ${clientIPs.size}\n${[...clientIPs].sort().map(ip => ` - ${ip}`).join('\n')}`
|
|
49
|
+
)
|
|
36
50
|
})
|
|
37
51
|
|
|
38
52
|
tcp.on('error', ex => {
|
|
@@ -4,18 +4,29 @@ import { ConnectionManager } from '../connection-manager'
|
|
|
4
4
|
import { InputStep } from '../../service/step/step-type'
|
|
5
5
|
import { Context } from '../types'
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
const WITH_IP_FORMATS = ['string-with-ip', 'json-with-ip']
|
|
8
|
+
|
|
9
|
+
function convertDataFormat(data: string, format: string, ip?: string) {
|
|
10
|
+
let converted: any
|
|
8
11
|
try {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
const baseFormat = format.replace('-with-ip', '')
|
|
13
|
+
if (baseFormat == 'json') {
|
|
14
|
+
converted = JSON.parse(data)
|
|
15
|
+
} else if (baseFormat == 'csv') {
|
|
16
|
+
converted = data.split(',')
|
|
17
|
+
} else {
|
|
18
|
+
converted = data
|
|
13
19
|
}
|
|
14
20
|
} catch (e) {
|
|
15
|
-
|
|
21
|
+
converted = data.toString()
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// IP 포함 포맷이면 { data, ip } 형태로 반환한다
|
|
25
|
+
if (WITH_IP_FORMATS.includes(format) && ip) {
|
|
26
|
+
return { data: converted, ip }
|
|
16
27
|
}
|
|
17
28
|
|
|
18
|
-
return
|
|
29
|
+
return converted
|
|
19
30
|
}
|
|
20
31
|
|
|
21
32
|
async function SocketListener(step: InputStep, context: Context) {
|
|
@@ -54,9 +65,9 @@ async function SocketListener(step: InputStep, context: Context) {
|
|
|
54
65
|
}
|
|
55
66
|
}
|
|
56
67
|
|
|
57
|
-
await connection.addListener('socket-message-arrive', async message => {
|
|
68
|
+
await connection.addListener('socket-message-arrive', async (message: string, ip: string) => {
|
|
58
69
|
logger.info(message.toString())
|
|
59
|
-
MESSAGES.push(convertDataFormat(message.toString(), dataFormat))
|
|
70
|
+
MESSAGES.push(convertDataFormat(message.toString(), dataFormat, ip))
|
|
60
71
|
})
|
|
61
72
|
} catch (e) {
|
|
62
73
|
logger.error(e)
|
|
@@ -88,6 +99,14 @@ SocketListener.parameterSpec = [
|
|
|
88
99
|
{
|
|
89
100
|
display: 'String',
|
|
90
101
|
value: 'string'
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
display: 'String with IP',
|
|
105
|
+
value: 'string-with-ip'
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
display: 'JSON with IP',
|
|
109
|
+
value: 'json-with-ip'
|
|
91
110
|
}
|
|
92
111
|
]
|
|
93
112
|
}
|