@things-factory/integration-base 7.0.0-alpha.9 → 7.0.1-alpha.1
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/connection-manager.js +37 -6
- package/dist-server/engine/connection-manager.js.map +1 -1
- package/dist-server/engine/connector/graphql-connector.js +6 -6
- package/dist-server/engine/connector/graphql-connector.js.map +1 -1
- package/dist-server/engine/connector/operato-connector.js +19 -22
- package/dist-server/engine/connector/operato-connector.js.map +1 -1
- package/dist-server/engine/connector/proxy-connector.js +44 -0
- package/dist-server/engine/connector/proxy-connector.js.map +1 -0
- package/dist-server/engine/edge-client.js +38 -0
- package/dist-server/engine/edge-client.js.map +1 -0
- package/dist-server/engine/index.js +1 -0
- package/dist-server/engine/index.js.map +1 -1
- package/dist-server/engine/task/script.js +1 -0
- package/dist-server/engine/task/script.js.map +1 -1
- package/dist-server/engine/types.js.map +1 -1
- package/dist-server/service/connection/connection-mutation.js +4 -8
- package/dist-server/service/connection/connection-mutation.js.map +1 -1
- package/dist-server/service/connection/connection-query.js +17 -14
- package/dist-server/service/connection/connection-query.js.map +1 -1
- package/dist-server/service/connection/connection-subscription.js +1 -1
- package/dist-server/service/connection/connection-subscription.js.map +1 -1
- package/dist-server/service/connection/connection-type.js +32 -8
- package/dist-server/service/connection/connection-type.js.map +1 -1
- package/dist-server/service/scenario-instance/scenario-instance-type.js +12 -4
- package/dist-server/service/scenario-instance/scenario-instance-type.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/helps/integration/concept/script-internal-variables.ja.md +21 -1
- package/helps/integration/concept/script-internal-variables.ko.md +17 -0
- package/helps/integration/concept/script-internal-variables.md +18 -0
- package/helps/integration/concept/script-internal-variables.ms.md +19 -1
- package/helps/integration/concept/script-internal-variables.zh.md +18 -0
- package/helps/integration/task/script.ja.md +1 -1
- package/helps/integration/task/script.ko.md +1 -1
- package/helps/integration/task/script.md +1 -1
- package/helps/integration/task/script.ms.md +1 -1
- package/helps/integration/task/script.zh.md +1 -1
- package/package.json +10 -10
- package/server/engine/connection-manager.ts +49 -7
- package/server/engine/connector/graphql-connector.ts +8 -10
- package/server/engine/connector/operato-connector.ts +22 -32
- package/server/engine/connector/proxy-connector.ts +53 -0
- package/server/engine/edge-client.ts +45 -0
- package/server/engine/index.ts +1 -0
- package/server/engine/task/script.ts +1 -0
- package/server/engine/types.ts +45 -46
- package/server/service/connection/connection-mutation.ts +9 -29
- package/server/service/connection/connection-query.ts +13 -12
- package/server/service/connection/connection-subscription.ts +1 -1
- package/server/service/connection/connection-type.ts +53 -41
- package/server/service/scenario-instance/scenario-instance-type.ts +13 -5
@@ -17,8 +17,28 @@
|
|
17
17
|
- email: ユーザーの電子メール
|
18
18
|
- userType: ユーザータイプ
|
19
19
|
|
20
|
-
- lng: シナリオを開始するユーザーのブラウザで使用されている言語(例:en-US、ko-KR など)。
|
20
|
+
- lng: シナリオを開始するユーザーのブラウザで使用されている言語(例:en-US、ko-KR など)。
|
21
|
+
|
22
|
+
- ユーザーのブラウザを介さないリクエストを処理する場合、この組み込み変数は提供されない場合があります。
|
21
23
|
|
22
24
|
- variables: シナリオ呼び出し時に呼び出し元から受け取るオブジェクト。
|
23
25
|
|
24
26
|
- data: シナリオの実行中に生成された各ステップの結果データ。
|
27
|
+
|
28
|
+
- logger (only for script):スクリプト内で必要に応じてログを残すことができる
|
29
|
+
- ログレベル:info, warn, error
|
30
|
+
|
31
|
+
```javascript
|
32
|
+
// 組み込み変数と変数の使用例
|
33
|
+
const username = user ? user.name : '不明なユーザー'
|
34
|
+
const companyName = domain ? domain.name : '不明な会社'
|
35
|
+
|
36
|
+
// info レベルのログを残す例(組み込み変数と変数を使用)
|
37
|
+
logger.info(`ユーザー '${username}' が '${companyName}' からシステムにアクセスしました。`)
|
38
|
+
|
39
|
+
// warn レベルのログを残す例(組み込み変数と変数を使用)
|
40
|
+
logger.warn(`ユーザー '${username}' が許可されていない操作を試みました。`)
|
41
|
+
|
42
|
+
// error レベルのログを残す例(組み込み変数と変数を使用)
|
43
|
+
logger.error(`ユーザー '${username}' のデータ処理中にエラーが発生しました。`)
|
44
|
+
```
|
@@ -16,3 +16,20 @@
|
|
16
16
|
- 사용자 브라우저를 통하지 않은 요청을 처리할 때에는 이 내장변수가 제공되지 않을 수 있다.
|
17
17
|
- variables : 시나리오 호출 시점에 호출자로부터 전달받은 오브젝트
|
18
18
|
- data: 시나리오 실행과정에 생성된 각 스텝의 결과 데이타
|
19
|
+
- logger: 스크립트 내에서 필요시 로그를 남길 수 있도록 제공된다
|
20
|
+
- log levels : info, warn, error
|
21
|
+
|
22
|
+
```javascript
|
23
|
+
// 내장 변수와 변수 사용 예시
|
24
|
+
const username = user ? user.name : 'Unknown User'
|
25
|
+
const companyName = domain ? domain.name : 'Unknown Company'
|
26
|
+
|
27
|
+
// info 레벨의 로그를 남기는 예시 (내장 변수 및 변수 사용)
|
28
|
+
logger.info(`User '${username}' from '${companyName}' accessed the system.`)
|
29
|
+
|
30
|
+
// warn 레벨의 로그를 남기는 예시 (내장 변수 및 변수 사용)
|
31
|
+
logger.warn(`User '${username}' attempted an unauthorized action.`)
|
32
|
+
|
33
|
+
// error 레벨의 로그를 남기는 예시 (내장 변수 및 변수 사용)
|
34
|
+
logger.error(`An error occurred while processing data for user '${username}'.`)
|
35
|
+
```
|
@@ -22,3 +22,21 @@ In script-type task properties (Script, SQL, GraphQL Query/Mutation, Log, etc.),
|
|
22
22
|
- variables: An object received from the caller at the time of scenario invocation.
|
23
23
|
|
24
24
|
- data: Results data generated for each step during scenario execution.
|
25
|
+
|
26
|
+
- logger (only for script): Provided to leave logs as needed within the script
|
27
|
+
- log levels: info, warn, error
|
28
|
+
|
29
|
+
```javascript
|
30
|
+
// Example of using built-in variables and variables
|
31
|
+
const username = user ? user.name : 'Unknown User'
|
32
|
+
const companyName = domain ? domain.name : 'Unknown Company'
|
33
|
+
|
34
|
+
// Example of leaving a log at the info level (using built-in variables and variables)
|
35
|
+
logger.info(`User '${username}' from '${companyName}' accessed the system.`)
|
36
|
+
|
37
|
+
// Example of leaving a log at the warn level (using built-in variables and variables)
|
38
|
+
logger.warn(`User '${username}' attempted an unauthorized action.`)
|
39
|
+
|
40
|
+
// Example of leaving a log at the error level (using built-in variables and variables)
|
41
|
+
logger.error(`An error occurred while processing data for user '${username}'.`)
|
42
|
+
```
|
@@ -17,4 +17,22 @@ Dalam sifat tugas jenis skrip (Skrip, SQL, Pertanyaan/Mutasi GraphQL, Log, dsb.)
|
|
17
17
|
- email: E-mel pengguna
|
18
18
|
- userType: Jenis pengguna
|
19
19
|
|
20
|
-
- lng: Bahasa yang digunakan oleh pelayar pengguna ketika memulakan senario (contohnya, en-US, ko
|
20
|
+
- lng: Bahasa yang digunakan oleh pelayar pengguna ketika memulakan senario (contohnya, en-US, ko-KR)
|
21
|
+
|
22
|
+
- logger (only for script): menyediakan kemampuan untuk meninggalkan log apabila diperlukan dalam skrip
|
23
|
+
- tahap log: info, warn, error
|
24
|
+
|
25
|
+
```javascript
|
26
|
+
// contoh penggunaan variable bawaan dan variable
|
27
|
+
const username = user ? user.name : 'Pengguna Tidak Diketahui'
|
28
|
+
const companyName = domain ? domain.name : 'Syarikat Tidak Diketahui'
|
29
|
+
|
30
|
+
// contoh meninggalkan log tahap info (menggunakan variable bawaan dan variable)
|
31
|
+
logger.info(`Pengguna '${username}' dari '${companyName}' mengakses sistem.`)
|
32
|
+
|
33
|
+
// contoh meninggalkan log tahap warn (menggunakan variable bawaan dan variable)
|
34
|
+
logger.warn(`Pengguna '${username}' mencuba tindakan yang tidak dibenarkan.`)
|
35
|
+
|
36
|
+
// contoh meninggalkan log tahap error (menggunakan variable bawaan dan variable)
|
37
|
+
logger.error(`Terjadi kesalahan semasa memproses data untuk pengguna '${username}'.`)
|
38
|
+
```
|
@@ -22,3 +22,21 @@
|
|
22
22
|
- variables: 在方案调用时从调用者那里接收的对象
|
23
23
|
|
24
24
|
- data: 在方案执行过程中生成的每个步骤的结果数据
|
25
|
+
|
26
|
+
- logger(only for script):在脚本中需要时可以留下日志
|
27
|
+
- 日志级别:info, warn, error
|
28
|
+
|
29
|
+
```javascript
|
30
|
+
// 内置变量和变量使用示例
|
31
|
+
const username = user ? user.name : '未知用户'
|
32
|
+
const companyName = domain ? domain.name : '未知公司'
|
33
|
+
|
34
|
+
// 记录 info 级别日志的示例(使用内置变量和变量)
|
35
|
+
logger.info(`用户 '${username}' 从 '${companyName}' 访问了系统。`)
|
36
|
+
|
37
|
+
// 记录 warn 级别日志的示例(使用内置变量和变量)
|
38
|
+
logger.warn(`用户 '${username}' 尝试了未授权的操作。`)
|
39
|
+
|
40
|
+
// 记录 error 级别日志的示例(使用内置变量和变量)
|
41
|
+
logger.error(`处理用户 '${username}' 的数据时发生错误。`)
|
42
|
+
```
|
@@ -6,7 +6,7 @@
|
|
6
6
|
|
7
7
|
- script
|
8
8
|
- JavaScript 構文で記述します。
|
9
|
-
- グローバルオブジェクトは、対応する[シナリオコンテキスト](../concept/scenario-context.md)からのデータと変数を含むシンプルなオブジェクトです。つまり、スクリプト内では、シナリオの[スクリプト内蔵変数](../concept/script-internal-variables.md)から特別な修飾子なしで、または`this
|
9
|
+
- グローバルオブジェクトは、対応する[シナリオコンテキスト](../concept/scenario-context.md)からのデータと変数を含むシンプルなオブジェクトです。つまり、スクリプト内では、シナリオの[スクリプト内蔵変数](../concept/script-internal-variables.md)から特別な修飾子なしで、または`this`アクセサを介して data, variables, domain, user, lng, logger 変数を使用できます。
|
10
10
|
- タスクの実行結果は`return`構文を介して返されます。
|
11
11
|
- スクリプト内のグ
|
12
12
|
|
@@ -6,7 +6,7 @@ Javascript Syntax로 작성된 script를 실행하여 그 결과를 리턴하는
|
|
6
6
|
|
7
7
|
- script
|
8
8
|
- javascript systax로 작성한다.
|
9
|
-
- global 오브젝트는 해당된 [Scenario Context](../concept/scenario-context.md)중 data 와 variables 를 가진 단순한 오브젝트이다. 즉, 스크립트 내에서 해당된 시나리오의 [스크립트 내장변수](../concept/script-internal-variables.md)인 data, variables, domain, user, lng 변수를 특별한 수식자없이 또는 this 접근자를 통해서 사용할 수 있다.
|
9
|
+
- global 오브젝트는 해당된 [Scenario Context](../concept/scenario-context.md)중 data 와 variables 를 가진 단순한 오브젝트이다. 즉, 스크립트 내에서 해당된 시나리오의 [스크립트 내장변수](../concept/script-internal-variables.md)인 data, variables, domain, user, lng, logger 변수를 특별한 수식자없이 또는 this 접근자를 통해서 사용할 수 있다.
|
10
10
|
- 태스크의 수행 결과는 return 신택스를 통해서 반환된다.
|
11
11
|
- script 내에서는 global 오브젝트가 data와 variables 등 [스크립트 내장변수](../concept/script-internal-variables.md)로 한정되므로, 대부분의 시스템 관련된 기능은 사용할 수 없는 sandbox 환경이라고 이해하고, 단순한 연산정도의 기능을 구현하는 것을 권장한다.
|
12
12
|
- [Node Sandbox](https://medium.com/@devnullnor/a-secure-node-sandbox-f23b9fc9f2b0)
|
@@ -6,7 +6,7 @@ This is a task that executes a script written in JavaScript syntax and returns t
|
|
6
6
|
|
7
7
|
- script
|
8
8
|
- Write in JavaScript syntax.
|
9
|
-
- The global object is a simple object that contains data and variables from the corresponding [Scenario Context](../concept/scenario-context.md). In other words, within the script, you can use the data, variables, domain, user, and lng variables from the scenario's [Script Built-in Variables](../concept/script-internal-variables.md) without any special modifiers or through the `this` accessor.
|
9
|
+
- The global object is a simple object that contains data and variables from the corresponding [Scenario Context](../concept/scenario-context.md). In other words, within the script, you can use the data, variables, domain, user, logger and lng variables from the scenario's [Script Built-in Variables](../concept/script-internal-variables.md) without any special modifiers or through the `this` accessor.
|
10
10
|
- The task's execution result is returned through the `return` syntax.
|
11
11
|
- Since the global object within the script is limited to data and variables, as well as other [Script Built-in Variables](../concept/script-internal-variables.md), consider it a sandbox environment where most system-related functionalities are unavailable. It's recommended to implement simple operations.
|
12
12
|
- [Node Sandbox](https://medium.com/@devnullnor/a-secure-node-sandbox-f23b9fc9f2b0)
|
@@ -6,7 +6,7 @@ Ini adalah tugas yang menjalankan skrip yang ditulis dalam sintaks JavaScript da
|
|
6
6
|
|
7
7
|
- skrip
|
8
8
|
- Ditulis dalam sintaks JavaScript.
|
9
|
-
- Objek global adalah objek sederhana yang mengandungi data dan pembolehubah dari [Konteks Senario](../concept/scenario-context.md) yang berkaitan. Dengan kata lain, dalam skrip ini, anda boleh menggunakan data,
|
9
|
+
- Objek global adalah objek sederhana yang mengandungi data dan pembolehubah dari [Konteks Senario](../concept/scenario-context.md) yang berkaitan. Dengan kata lain, dalam skrip ini, anda boleh menggunakan data, variables, domain, user, lng, logger dari [Pembolehubah Terbina Dalam Skrip](../concept/script-internal-variables.md) senario tanpa modifier khas atau melalui aksesori `this`.
|
10
10
|
- Hasil pelaksanaan tugas dikembalikan melalui sintaks `return`.
|
11
11
|
- Oleh kerana objek global dalam skrip terhad kepada data dan pembolehubah, serta Pembolehubah Terbina Dalam Skrip yang lain, pertimbangkan ia sebagai persekitaran sandbox di mana kebanyakan fungsi berkaitan sistem tidak tersedia. Disarankan untuk melaksanakan operasi yang ringkas.
|
12
12
|
- [Node Sandbox](https://medium.com/@devnullnor/a-secure-node-sandbox-f23b9fc9f2b0)
|
@@ -6,7 +6,7 @@
|
|
6
6
|
|
7
7
|
- 脚本
|
8
8
|
- 以 JavaScript 语法编写。
|
9
|
-
- 全局对象是一个简单的对象,包含来自相应[场景上下文](../concept/scenario-context.md)的数据和变量。换句话说,在脚本内部,您可以使用来自场景的[脚本内置变量](../concept/script-internal-variables.md)(例如 data、variables、domain、user 和 lng 变量)而无需任何特殊修饰符,或者通过`this`访问器。
|
9
|
+
- 全局对象是一个简单的对象,包含来自相应[场景上下文](../concept/scenario-context.md)的数据和变量。换句话说,在脚本内部,您可以使用来自场景的[脚本内置变量](../concept/script-internal-variables.md)(例如 data、variables、domain、user, logger 和 lng 变量)而无需任何特殊修饰符,或者通过`this`访问器。
|
10
10
|
- 任务的执行结果通过`return`语法返回。
|
11
11
|
- 由于脚本内的全局对象仅限于数据和变量以及其他[脚本内置变量](../concept/script-internal-variables.md),请将其视为一个沙盒环境,在该环境中大多数与系统相关的功能不可用。建议实现简单的操作。
|
12
12
|
- [Node Sandbox](https://medium.com/@devnullnor/a-secure-node-sandbox-f23b9fc9f2b0)
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@things-factory/integration-base",
|
3
|
-
"version": "7.0.
|
3
|
+
"version": "7.0.1-alpha.1",
|
4
4
|
"main": "dist-server/index.js",
|
5
5
|
"browser": "client/index.js",
|
6
6
|
"things-factory": true,
|
@@ -26,13 +26,13 @@
|
|
26
26
|
},
|
27
27
|
"dependencies": {
|
28
28
|
"@apollo/client": "^3.6.9",
|
29
|
-
"@things-factory/api": "^7.0.
|
30
|
-
"@things-factory/auth-base": "^7.0.
|
31
|
-
"@things-factory/env": "^7.0.
|
32
|
-
"@things-factory/oauth2-client": "^7.0.
|
33
|
-
"@things-factory/scheduler-client": "^7.0.
|
34
|
-
"@things-factory/shell": "^7.0.
|
35
|
-
"@things-factory/utils": "^7.0.
|
29
|
+
"@things-factory/api": "^7.0.1-alpha.1",
|
30
|
+
"@things-factory/auth-base": "^7.0.1-alpha.1",
|
31
|
+
"@things-factory/env": "^7.0.1-alpha.0",
|
32
|
+
"@things-factory/oauth2-client": "^7.0.1-alpha.1",
|
33
|
+
"@things-factory/scheduler-client": "^7.0.1-alpha.1",
|
34
|
+
"@things-factory/shell": "^7.0.1-alpha.1",
|
35
|
+
"@things-factory/utils": "^7.0.1-alpha.0",
|
36
36
|
"async-mqtt": "^2.5.0",
|
37
37
|
"chance": "^1.1.11",
|
38
38
|
"cross-fetch": "^3.0.4",
|
@@ -41,7 +41,7 @@
|
|
41
41
|
"node-fetch": "^2.6.0",
|
42
42
|
"promise-socket": "^7.0.0",
|
43
43
|
"readline": "^1.3.0",
|
44
|
-
"vm2": "3.9.11"
|
44
|
+
"vm2": "^3.9.11"
|
45
45
|
},
|
46
|
-
"gitHead": "
|
46
|
+
"gitHead": "6cc9a9da9059f32f8c2968c57831c1d353a2ec97"
|
47
47
|
}
|
@@ -5,6 +5,7 @@ import { Domain, getRepository, pubsub, PubSubLogTransport } from '@things-facto
|
|
5
5
|
|
6
6
|
import { Connection, ConnectionStatus } from '../service'
|
7
7
|
import { Connector } from './types'
|
8
|
+
import { ProxyConnector } from './connector/proxy-connector'
|
8
9
|
|
9
10
|
const { combine, timestamp, splat, printf } = format
|
10
11
|
const debug = require('debug')('things-factory:integration-base:connections')
|
@@ -17,7 +18,8 @@ const systemTimestamp = format((info, opts) => {
|
|
17
18
|
|
18
19
|
export class ConnectionManager {
|
19
20
|
private static connectors: { [propName: string]: Connector } = {}
|
20
|
-
private static connections = {}
|
21
|
+
private static connections: { [domainId: string]: { [name: string]: any } } = {}
|
22
|
+
private static entities = {}
|
21
23
|
private static logFormat = printf(({ level, message, timestamp }) => {
|
22
24
|
return `${timestamp} ${level}: ${message}`
|
23
25
|
})
|
@@ -43,7 +45,7 @@ export class ConnectionManager {
|
|
43
45
|
const CONNECTIONS = (
|
44
46
|
await getRepository(Connection).find({
|
45
47
|
where: { active: true },
|
46
|
-
relations: ['domain', 'creator', 'updater']
|
48
|
+
relations: ['domain', 'edge', 'creator', 'updater']
|
47
49
|
})
|
48
50
|
).map(connection => {
|
49
51
|
var params = {}
|
@@ -63,12 +65,21 @@ export class ConnectionManager {
|
|
63
65
|
ConnectionManager.logger.info('Initializing ConnectionManager...')
|
64
66
|
|
65
67
|
return await Promise.all(
|
66
|
-
Object.keys(ConnectionManager.connectors).map(type => {
|
67
|
-
|
68
|
+
[...Object.keys(ConnectionManager.connectors), 'proxy-connector'].map(type => {
|
69
|
+
const connector = 'proxy-connector' ? ProxyConnector.instance : ConnectionManager.getConnector(type)
|
70
|
+
|
68
71
|
ConnectionManager.logger.info(`Connector '${type}' started to ready`)
|
69
72
|
|
70
73
|
return connector
|
71
|
-
.ready(
|
74
|
+
.ready(
|
75
|
+
CONNECTIONS.filter(connection => {
|
76
|
+
if (type == 'proxy-connector') {
|
77
|
+
return !!connection.edge
|
78
|
+
} else {
|
79
|
+
return !connection.edge && connection.type == type
|
80
|
+
}
|
81
|
+
}) as any
|
82
|
+
)
|
72
83
|
.catch(error => {
|
73
84
|
ConnectionManager.logger.error(error.message)
|
74
85
|
})
|
@@ -103,6 +114,14 @@ export class ConnectionManager {
|
|
103
114
|
delete ConnectionManager.connectors[type]
|
104
115
|
}
|
105
116
|
|
117
|
+
static getConnections() {
|
118
|
+
return ConnectionManager.connections
|
119
|
+
}
|
120
|
+
|
121
|
+
static getEntities() {
|
122
|
+
return ConnectionManager.entities
|
123
|
+
}
|
124
|
+
|
106
125
|
static getConnectionInstance(connection: Connection): any {
|
107
126
|
const { domain, name } = connection
|
108
127
|
return ConnectionManager.connections[domain.id]?.[name]
|
@@ -119,6 +138,11 @@ export class ConnectionManager {
|
|
119
138
|
return connection
|
120
139
|
}
|
121
140
|
|
141
|
+
static getConnectionInstanceEntityByName(domain: Domain, name: string): any {
|
142
|
+
const entities = ConnectionManager.entities[domain.id]
|
143
|
+
return entities?.[name]
|
144
|
+
}
|
145
|
+
|
122
146
|
static getConnectionInstances(domain: Domain): { [connectionName: string]: any } {
|
123
147
|
const connections = ConnectionManager.connections[domain.id]
|
124
148
|
|
@@ -127,6 +151,14 @@ export class ConnectionManager {
|
|
127
151
|
}
|
128
152
|
}
|
129
153
|
|
154
|
+
static getConnectionInstanceEntities(domain: Domain): { [connectionName: string]: any } {
|
155
|
+
const connections = ConnectionManager.entities[domain.id]
|
156
|
+
|
157
|
+
return {
|
158
|
+
...connections
|
159
|
+
}
|
160
|
+
}
|
161
|
+
|
130
162
|
static addConnectionInstance(connection: Connection, instance: any) {
|
131
163
|
const { domain, name } = connection
|
132
164
|
|
@@ -135,7 +167,13 @@ export class ConnectionManager {
|
|
135
167
|
connections = ConnectionManager.connections[domain.id] = {}
|
136
168
|
}
|
137
169
|
|
170
|
+
var entities = ConnectionManager.entities[domain.id]
|
171
|
+
if (!entities) {
|
172
|
+
entities = ConnectionManager.entities[domain.id] = {}
|
173
|
+
}
|
174
|
+
|
138
175
|
connections[name] = instance
|
176
|
+
entities[name] = connection
|
139
177
|
|
140
178
|
ConnectionManager.publishState(connection, ConnectionStatus.CONNECTED)
|
141
179
|
debug('add-connection', domain.subdomain, name)
|
@@ -144,6 +182,8 @@ export class ConnectionManager {
|
|
144
182
|
static removeConnectionInstance(connection: Connection): any {
|
145
183
|
const { domain, name } = connection
|
146
184
|
var connections = ConnectionManager.connections[domain.id]
|
185
|
+
var entities = ConnectionManager.entities[domain.id]
|
186
|
+
|
147
187
|
var instance = connections?.[name]
|
148
188
|
|
149
189
|
if (!connections || !instance) {
|
@@ -152,6 +192,7 @@ export class ConnectionManager {
|
|
152
192
|
}
|
153
193
|
|
154
194
|
delete connections[name]
|
195
|
+
delete entities[name]
|
155
196
|
|
156
197
|
ConnectionManager.publishState(connection, ConnectionStatus.DISCONNECTED)
|
157
198
|
debug('remove-connection', `'${name}' connection is removed from domain '${domain.subdomain}'`)
|
@@ -159,8 +200,8 @@ export class ConnectionManager {
|
|
159
200
|
return instance
|
160
201
|
}
|
161
202
|
|
162
|
-
static publishState(connection: Connection, state) {
|
163
|
-
const { domain, id, name, description, type } = connection
|
203
|
+
private static async publishState(connection: Connection, state) {
|
204
|
+
const { domain, id, name, description, type, edge } = connection
|
164
205
|
|
165
206
|
pubsub.publish('connection-state', {
|
166
207
|
connectionState: {
|
@@ -169,6 +210,7 @@ export class ConnectionManager {
|
|
169
210
|
name,
|
170
211
|
description,
|
171
212
|
type,
|
213
|
+
edge,
|
172
214
|
state,
|
173
215
|
timestamp: new Date()
|
174
216
|
}
|
@@ -23,10 +23,6 @@ const defaultOptions: any = {
|
|
23
23
|
}
|
24
24
|
}
|
25
25
|
|
26
|
-
const cache = new InMemoryCache({
|
27
|
-
addTypename: false
|
28
|
-
})
|
29
|
-
|
30
26
|
export class GraphqlConnector implements Connector {
|
31
27
|
async ready(connectionConfigs: InputConnection[]) {
|
32
28
|
await Promise.all(connectionConfigs.map(this.connect.bind(this)))
|
@@ -35,12 +31,12 @@ export class GraphqlConnector implements Connector {
|
|
35
31
|
}
|
36
32
|
|
37
33
|
async connect(connection: InputConnection) {
|
38
|
-
|
34
|
+
const {
|
39
35
|
endpoint: uri,
|
40
36
|
params: { authClient }
|
41
37
|
} = connection
|
42
38
|
|
43
|
-
|
39
|
+
const ERROR_HANDLER: any = ({ graphQLErrors, networkError }) => {
|
44
40
|
if (graphQLErrors)
|
45
41
|
graphQLErrors.map(({ message, locations, path }) => {
|
46
42
|
ConnectionManager.logger.error(`[GraphQL error] Message: ${message}, Location: ${locations}, Path: ${path}`)
|
@@ -65,6 +61,10 @@ export class GraphqlConnector implements Connector {
|
|
65
61
|
return forward(operation)
|
66
62
|
})
|
67
63
|
|
64
|
+
const cache = new InMemoryCache({
|
65
|
+
addTypename: false
|
66
|
+
})
|
67
|
+
|
68
68
|
ConnectionManager.addConnectionInstance(
|
69
69
|
connection,
|
70
70
|
new ApolloClient({
|
@@ -81,13 +81,11 @@ export class GraphqlConnector implements Connector {
|
|
81
81
|
})
|
82
82
|
)
|
83
83
|
|
84
|
-
ConnectionManager.logger.info(
|
85
|
-
`graphql-connector connection(${connection.name}:${connection.endpoint}) is connected`
|
86
|
-
)
|
84
|
+
ConnectionManager.logger.info(`graphql-connector connection(${connection.name}:${connection.endpoint}) is connected`)
|
87
85
|
}
|
88
86
|
|
89
87
|
async disconnect(connection: InputConnection) {
|
90
|
-
|
88
|
+
const client = ConnectionManager.getConnectionInstance(connection)
|
91
89
|
client.stop()
|
92
90
|
ConnectionManager.removeConnectionInstance(connection)
|
93
91
|
|
@@ -3,7 +3,6 @@ import 'cross-fetch/polyfill'
|
|
3
3
|
import { ApolloClient, InMemoryCache, createHttpLink, split } from '@apollo/client/core'
|
4
4
|
import { setContext } from '@apollo/client/link/context'
|
5
5
|
|
6
|
-
// for subscription
|
7
6
|
import WebSocket from 'ws'
|
8
7
|
import { createClient } from 'graphql-ws'
|
9
8
|
import { GraphQLWsLink } from '@apollo/client/link/subscriptions'
|
@@ -20,7 +19,7 @@ import { ScenarioInstance } from '../../service/scenario-instance/scenario-insta
|
|
20
19
|
import { getRepository, GraphqlLocalClient, Domain } from '@things-factory/shell'
|
21
20
|
import { User, checkPermission } from '@things-factory/auth-base'
|
22
21
|
|
23
|
-
const debug = require('debug')('things-factory:integration-base:operato-connector
|
22
|
+
const debug = require('debug')('things-factory:integration-base:operato-connector')
|
24
23
|
|
25
24
|
const defaultOptions: any = {
|
26
25
|
watchQuery: {
|
@@ -36,10 +35,6 @@ const defaultOptions: any = {
|
|
36
35
|
}
|
37
36
|
}
|
38
37
|
|
39
|
-
const cache = new InMemoryCache({
|
40
|
-
addTypename: false
|
41
|
-
})
|
42
|
-
|
43
38
|
export const GRAPHQL_URI = '/graphql'
|
44
39
|
export const SUBSCRIPTION_URI = GRAPHQL_URI
|
45
40
|
|
@@ -48,7 +43,6 @@ interface SubscriberData {
|
|
48
43
|
scenario: any
|
49
44
|
subscriptionObserver: any
|
50
45
|
}
|
51
|
-
;``
|
52
46
|
|
53
47
|
export class OperatoConnector implements Connector {
|
54
48
|
private context: any
|
@@ -56,11 +50,11 @@ export class OperatoConnector implements Connector {
|
|
56
50
|
async ready(connectionConfigs: InputConnection[]) {
|
57
51
|
await Promise.all(connectionConfigs.map(this.connect.bind(this)))
|
58
52
|
|
59
|
-
ConnectionManager.logger.info('
|
53
|
+
ConnectionManager.logger.info('operato-connector connections are ready')
|
60
54
|
}
|
61
55
|
|
62
56
|
async connect(connection: InputConnection) {
|
63
|
-
|
57
|
+
const {
|
64
58
|
endpoint: uri,
|
65
59
|
params: { authKey, domain, subscriptionHandlers = {} }
|
66
60
|
} = connection
|
@@ -69,7 +63,7 @@ export class OperatoConnector implements Connector {
|
|
69
63
|
throw new Error('some connection paramter missing.')
|
70
64
|
}
|
71
65
|
|
72
|
-
|
66
|
+
const domainOwner = await getRepository(User).findOne({
|
73
67
|
where: {
|
74
68
|
id: connection.domain.owner
|
75
69
|
}
|
@@ -125,20 +119,24 @@ export class OperatoConnector implements Connector {
|
|
125
119
|
}).concat(httpLink)
|
126
120
|
)
|
127
121
|
|
128
|
-
|
122
|
+
const cache = new InMemoryCache({
|
123
|
+
addTypename: false
|
124
|
+
})
|
125
|
+
|
126
|
+
const client = new ApolloClient({
|
129
127
|
defaultOptions,
|
130
128
|
cache,
|
131
129
|
link: splitLink
|
132
130
|
})
|
133
131
|
|
134
|
-
|
132
|
+
const subscriptions: SubscriberData[] = []
|
135
133
|
Object.keys(subscriptionHandlers).forEach(async tag => {
|
136
134
|
if (!tag || !subscriptionHandlers[tag]) return
|
137
135
|
|
138
|
-
|
136
|
+
const scenarioName = subscriptionHandlers[tag]
|
139
137
|
|
140
138
|
// fetch a scenario
|
141
|
-
|
139
|
+
const selectedScenario = await getRepository(Scenario).findOne({
|
142
140
|
where: {
|
143
141
|
name: scenarioName
|
144
142
|
},
|
@@ -156,7 +154,7 @@ export class OperatoConnector implements Connector {
|
|
156
154
|
`
|
157
155
|
})
|
158
156
|
|
159
|
-
|
157
|
+
const subscriptionObserver = subscription.subscribe({
|
160
158
|
next: async data => {
|
161
159
|
debug('received pubsub msg.:', data?.data)
|
162
160
|
await this.runScenario(subscriptions, data?.data?.data)
|
@@ -169,9 +167,7 @@ export class OperatoConnector implements Connector {
|
|
169
167
|
}
|
170
168
|
})
|
171
169
|
|
172
|
-
ConnectionManager.logger.info(
|
173
|
-
`(${connection.name}:${connection.endpoint}) subscription closed flag: ${subscriptionObserver.closed}`
|
174
|
-
)
|
170
|
+
ConnectionManager.logger.info(`(${connection.name}:${connection.endpoint}) subscription closed flag: ${subscriptionObserver.closed}`)
|
175
171
|
|
176
172
|
subscriptions.push({
|
177
173
|
tag,
|
@@ -184,19 +180,17 @@ export class OperatoConnector implements Connector {
|
|
184
180
|
client['subscriptions'] = subscriptions
|
185
181
|
ConnectionManager.addConnectionInstance(connection, client)
|
186
182
|
|
187
|
-
ConnectionManager.logger.info(
|
188
|
-
`graphql-connector connection(${connection.name}:${connection.endpoint}) is connected`
|
189
|
-
)
|
183
|
+
ConnectionManager.logger.info(`operato-connector connection(${connection.name}:${connection.endpoint}) is connected`)
|
190
184
|
}
|
191
185
|
|
192
186
|
async disconnect(connection: InputConnection) {
|
193
|
-
|
194
|
-
|
187
|
+
const client = ConnectionManager.getConnectionInstance(connection)
|
188
|
+
const subscriptions: SubscriberData[] = client['subscriptions']
|
195
189
|
subscriptions.forEach(subscription => subscription.subscriptionObserver.unsubscribe())
|
196
190
|
client.stop()
|
197
191
|
ConnectionManager.removeConnectionInstance(connection)
|
198
192
|
|
199
|
-
ConnectionManager.logger.info(`
|
193
|
+
ConnectionManager.logger.info(`operato-connector connection(${connection.name}) is disconnected`)
|
200
194
|
}
|
201
195
|
|
202
196
|
async runScenario(subscriptions: SubscriberData[], variables: any): Promise<ScenarioInstance> {
|
@@ -207,23 +201,19 @@ export class OperatoConnector implements Connector {
|
|
207
201
|
throw new Error(`tag is invalid - ${tag}`)
|
208
202
|
}
|
209
203
|
|
210
|
-
|
204
|
+
const scenario = subscriptions.find(subscription => subscription.tag === tag)?.scenario
|
211
205
|
if (!scenario) {
|
212
206
|
throw new Error(`scenario is not found - ${tag}`)
|
213
207
|
}
|
214
208
|
|
215
209
|
if (!(await checkPermission(scenario.privilege, user, domain, unsafeIP, prohibitedPrivileges))) {
|
216
210
|
const { category, privilege } = scenario.privilege || {}
|
217
|
-
throw new Error(
|
218
|
-
`Unauthorized! ${
|
219
|
-
category && privilege ? category + ':' + privilege + ' privilege' : 'ownership granted'
|
220
|
-
} required`
|
221
|
-
)
|
211
|
+
throw new Error(`Unauthorized! ${category && privilege ? category + ':' + privilege + ' privilege' : 'ownership granted'} required`)
|
222
212
|
}
|
223
213
|
|
224
214
|
/* create a scenario instance */
|
225
|
-
|
226
|
-
|
215
|
+
const instanceName = scenario.name + '-' + String(Date.now())
|
216
|
+
const instance = new ScenarioInstance(instanceName, scenario, {
|
227
217
|
user,
|
228
218
|
domain,
|
229
219
|
variables,
|
@@ -0,0 +1,53 @@
|
|
1
|
+
import { ConnectionManager } from '../connection-manager'
|
2
|
+
import { Connector } from '../types'
|
3
|
+
import { InputConnection } from '../../service/connection/connection-type'
|
4
|
+
import { connectConnections, disconnectConnections } from '../edge-client'
|
5
|
+
|
6
|
+
/**
|
7
|
+
* This connector is a proxy connector installed on the edge server to manage connections from the host.
|
8
|
+
* It interacts with connections established on the edge server and provides synchronization functionality.
|
9
|
+
*/
|
10
|
+
export class ProxyConnector implements Connector {
|
11
|
+
public static instance = new ProxyConnector()
|
12
|
+
|
13
|
+
async ready(connectionConfigs: InputConnection[]) {
|
14
|
+
await Promise.all(connectionConfigs.map(this.connect.bind(this)))
|
15
|
+
|
16
|
+
ConnectionManager.logger.info('proxy-connector connections are ready')
|
17
|
+
}
|
18
|
+
|
19
|
+
async connect(connection: InputConnection) {
|
20
|
+
// TODO 원래 커넥션과 에지설정을 참고하여, 에지 서버로 CONNECT/DISCONNECT 명령을 보낸다.
|
21
|
+
const proxy = {
|
22
|
+
disconnect: async () => {
|
23
|
+
ConnectionManager.logger.info('[proxy-connector] trying disconnect')
|
24
|
+
await disconnectConnections([connection])
|
25
|
+
}
|
26
|
+
}
|
27
|
+
|
28
|
+
await connectConnections([connection])
|
29
|
+
|
30
|
+
ConnectionManager.addConnectionInstance(connection, proxy)
|
31
|
+
|
32
|
+
ConnectionManager.logger.info(`proxy-connector connection(${connection.name}:${connection.endpoint}) is connected`)
|
33
|
+
}
|
34
|
+
|
35
|
+
async disconnect(connection: InputConnection) {
|
36
|
+
const proxy = ConnectionManager.removeConnectionInstance(connection)
|
37
|
+
await proxy.disconnect()
|
38
|
+
|
39
|
+
ConnectionManager.logger.info(`proxy-connector connection(${connection.name}) is disconnected`)
|
40
|
+
}
|
41
|
+
|
42
|
+
get parameterSpec() {
|
43
|
+
return []
|
44
|
+
}
|
45
|
+
|
46
|
+
get taskPrefixes() {
|
47
|
+
return []
|
48
|
+
}
|
49
|
+
|
50
|
+
get description() {
|
51
|
+
return 'Operato Proxy Connector'
|
52
|
+
}
|
53
|
+
}
|