@operato/scene-integration 0.0.5
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/@types/global/index.d.ts +1 -0
- package/CHANGELOG.md +17 -0
- package/LICENSE +21 -0
- package/README.md +105 -0
- package/assets/icon-camera-stream.png +0 -0
- package/assets/icon-connection-control.png +0 -0
- package/assets/icon-connection-state-subscription.png +0 -0
- package/assets/icon-data-subscription.png +0 -0
- package/assets/icon-integration.png +0 -0
- package/assets/icon-scenario-control.png +0 -0
- package/assets/icon-scenario-instance-subscription.png +0 -0
- package/assets/icon-scenario-queue-subscription.png +0 -0
- package/assets/icon-scenario-run.png +0 -0
- package/assets/icon-scenario-start.png +0 -0
- package/assets/icon-scenario-stop.png +0 -0
- package/assets/no-image.png +0 -0
- package/assets/symbol-connection-control.png +0 -0
- package/assets/symbol-connection-state-subscription.png +0 -0
- package/assets/symbol-data-subscription.png +0 -0
- package/assets/symbol-integration.png +0 -0
- package/assets/symbol-scenario-control.png +0 -0
- package/assets/symbol-scenario-instance-subscription.png +0 -0
- package/assets/symbol-scenario-queue-subscription.png +0 -0
- package/assets/symbol-scenario-run.png +0 -0
- package/assets/symbol-scenario-start.png +0 -0
- package/assets/symbol-scenario-stop.png +0 -0
- package/helps/scene/component/connection-control.ko.md +15 -0
- package/helps/scene/component/connection-control.md +15 -0
- package/helps/scene/component/connection-control.zh.md +16 -0
- package/helps/scene/component/connection-state-subscription.ko.md +17 -0
- package/helps/scene/component/connection-state-subscription.md +17 -0
- package/helps/scene/component/connection-state-subscription.zh.md +18 -0
- package/helps/scene/component/data-subscription.ko.md +10 -0
- package/helps/scene/component/data-subscription.md +10 -0
- package/helps/scene/component/data-subscription.zh.md +10 -0
- package/helps/scene/component/scenario-control.ko.md +4 -0
- package/helps/scene/component/scenario-control.md +4 -0
- package/helps/scene/component/scenario-control.zh.md +4 -0
- package/helps/scene/component/scenario-instance-subscription.ko.md +23 -0
- package/helps/scene/component/scenario-instance-subscription.md +24 -0
- package/helps/scene/component/scenario-instance-subscription.zh.md +23 -0
- package/helps/scene/component/scenario-queue-subscription.ko.md +27 -0
- package/helps/scene/component/scenario-queue-subscription.md +27 -0
- package/helps/scene/component/scenario-run.ko.md +27 -0
- package/helps/scene/component/scenario-run.md +27 -0
- package/helps/scene/component/scenario-run.zh.md +27 -0
- package/helps/scene/component/scenario-start.ko.md +16 -0
- package/helps/scene/component/scenario-start.md +16 -0
- package/helps/scene/component/scenario-start.zh.md +16 -0
- package/helps/scene/component/scenario-stop.ko.md +12 -0
- package/helps/scene/component/scenario-stop.md +12 -0
- package/helps/scene/component/scenario-stop.zh.md +12 -0
- package/package.json +64 -0
- package/src/connection-control.ts +163 -0
- package/src/connection-state-subscription.ts +113 -0
- package/src/data-subscription.ts +103 -0
- package/src/editors/index.js +1 -0
- package/src/index.ts +21 -0
- package/src/origin-client.ts +136 -0
- package/src/scenario-control.ts +163 -0
- package/src/scenario-instance-subscription.ts +133 -0
- package/src/scenario-queue-subscription.ts +91 -0
- package/src/scenario-run.ts +157 -0
- package/src/scenario-start.ts +155 -0
- package/src/scenario-stop.ts +143 -0
- package/templates/connection-control.js +17 -0
- package/templates/connection-state-subscription.js +17 -0
- package/templates/data-subscription.js +17 -0
- package/templates/index.js +21 -0
- package/templates/scenario-control.js +18 -0
- package/templates/scenario-instance-subscription.js +17 -0
- package/templates/scenario-queue-subscription.js +17 -0
- package/templates/scenario-run.js +17 -0
- package/templates/scenario-start.js +17 -0
- package/templates/scenario-stop.js +17 -0
- package/things-scene.config.js +7 -0
- package/translations/en.json +9 -0
- package/translations/ko.json +9 -0
- package/translations/ms.json +9 -0
- package/translations/zh.json +9 -0
- package/tsconfig.json +23 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# scenario stop
|
|
2
|
+
|
|
3
|
+
- 시나리오를 종료시킨다.
|
|
4
|
+
- 현재 실행중인 동일한 이름(instance name)의 시나리오 인스턴스를 찾아서 종료한다. 주어진 이름의 인스턴스가 없으면, 아무런 동작이 일어나지 않는다.
|
|
5
|
+
- value : 아무런 값이 주어져도 되며, 데이터 바인딩에 의해서 value값이 설정될 때 컴포넌트가 동작한다.
|
|
6
|
+
|
|
7
|
+
## properties
|
|
8
|
+
- instance name : (선택값) 이 이름으로 존재하는 시나리오 인스턴스를 종료시킨다. 이 값을 설정하지 않으면, scenario name 속성값을 사용한다. 이 값을 설정하지 않으면, scenario name 속성 값을 시나리오 인스턴스 이름으로 한다.
|
|
9
|
+
- scenario name : (선택값) instance name 과 scenario name 둘 중 하나는 입력되어야 한다.
|
|
10
|
+
|
|
11
|
+
## data
|
|
12
|
+
- scenario-stop 으로 종료된 scenario instance 의 상태값 : 'STOPPED' | 'HALTED'
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# scenario stop
|
|
2
|
+
|
|
3
|
+
- End the scenario.
|
|
4
|
+
- Finds the currently running scenario instance with the same name and terminates it. If there is no instance of the given name, nothing happens.
|
|
5
|
+
- value: Any value can be given, and the component operates when the value is set by data binding.
|
|
6
|
+
|
|
7
|
+
## properties
|
|
8
|
+
- instance name: (optional value) Terminates the scenario instance that exists under this name. If this value is not set, the scenario name property value is used. If this value is not set, the scenario name property value is used as the scenario instance name.
|
|
9
|
+
- scenario name: (optional value) Either of the instance name and the scenario name must be entered.
|
|
10
|
+
|
|
11
|
+
## data
|
|
12
|
+
- Status value of the scenario instance terminated with scenario-stop : 'STOPPED' | 'HALTED'
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# scenario stop
|
|
2
|
+
|
|
3
|
+
- 结束方案。
|
|
4
|
+
- 查找具有相同名称的当前正在运行的方案实例并终止它。 如果没有给定名称的实例,则什么也不会发生。
|
|
5
|
+
- value:可以指定任何值,并且通过数据绑定设置该值时,组件将运行。
|
|
6
|
+
|
|
7
|
+
## properties
|
|
8
|
+
- instance name :(可选值)终止以该名称存在的方案实例。 如果未设置此值,则使用方案名称属性值。 如果未设置此值,那么方案名称属性值将用作方案实例名称。
|
|
9
|
+
- 方案名称:(可选)必须输入实例名称和方案名称。
|
|
10
|
+
|
|
11
|
+
## data
|
|
12
|
+
- 方案停止时方案实例的状态值: 'STOPPED' | 'HALTED'
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@operato/scene-integration",
|
|
3
|
+
"description": "Things factory integration component for things-scene",
|
|
4
|
+
"version": "0.0.5",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "heartyoh",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"module": "dist/index.js",
|
|
9
|
+
"things-scene": true,
|
|
10
|
+
"publishConfig": {
|
|
11
|
+
"access": "public",
|
|
12
|
+
"@operato:registry": "https://registry.npmjs.org"
|
|
13
|
+
},
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/things-scene/operato-scene.git",
|
|
17
|
+
"directory": "packages/integration"
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"serve": "tsc && things-factory-dev",
|
|
21
|
+
"start": "tsc && concurrently -k -r \"tsc --watch --preserveWatchOutput\" \"wds\"",
|
|
22
|
+
"build": "tsc",
|
|
23
|
+
"prepublish": "tsc",
|
|
24
|
+
"lint": "eslint --ext .ts,.html . --ignore-path .gitignore && prettier \"**/*.ts\" --check --ignore-path .gitignore",
|
|
25
|
+
"format": "eslint --ext .ts,.html . --fix --ignore-path .gitignore && prettier \"**/*.ts\" --write --ignore-path .gitignore",
|
|
26
|
+
"migration": "things-factory-migration"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@apollo/client": "^3.4.17",
|
|
30
|
+
"graphql-tag": "^2.12.6",
|
|
31
|
+
"subscriptions-transport-ws": "^0.11.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@hatiolab/prettier-config": "^1.0.0",
|
|
35
|
+
"@hatiolab/things-scene": "^2.7.16",
|
|
36
|
+
"@operato/board": "^0.2.27",
|
|
37
|
+
"@things-factory/builder": "^4.0.6",
|
|
38
|
+
"@things-factory/operato-board": "^4.0.6",
|
|
39
|
+
"@typescript-eslint/eslint-plugin": "^4.33.0",
|
|
40
|
+
"@typescript-eslint/parser": "^4.33.0",
|
|
41
|
+
"@web/dev-server": "^0.1.28",
|
|
42
|
+
"concurrently": "^5.3.0",
|
|
43
|
+
"eslint": "^7.32.0",
|
|
44
|
+
"eslint-config-prettier": "^8.3.0",
|
|
45
|
+
"husky": "^4.3.8",
|
|
46
|
+
"lint-staged": "^10.5.4",
|
|
47
|
+
"prettier": "^2.4.1",
|
|
48
|
+
"tslib": "^2.3.1",
|
|
49
|
+
"typescript": "^4.5.2"
|
|
50
|
+
},
|
|
51
|
+
"prettier": "@hatiolab/prettier-config",
|
|
52
|
+
"husky": {
|
|
53
|
+
"hooks": {
|
|
54
|
+
"pre-commit": "lint-staged"
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"lint-staged": {
|
|
58
|
+
"*.ts": [
|
|
59
|
+
"eslint --fix",
|
|
60
|
+
"prettier --write"
|
|
61
|
+
]
|
|
62
|
+
},
|
|
63
|
+
"gitHead": "d3717e3284d88dc2831fbcf4ddbce827e2cc2940"
|
|
64
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import gql from 'graphql-tag'
|
|
2
|
+
|
|
3
|
+
import { Component, RectPath, Shape } from '@hatiolab/things-scene'
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
* Copyright © HatioLab Inc. All rights reserved.
|
|
7
|
+
*/
|
|
8
|
+
import COMPONENT_IMAGE from '../assets/symbol-connection-control.png'
|
|
9
|
+
import { getClient } from './origin-client'
|
|
10
|
+
|
|
11
|
+
const NATURE = {
|
|
12
|
+
mutable: false,
|
|
13
|
+
resizable: true,
|
|
14
|
+
rotatable: true,
|
|
15
|
+
properties: [
|
|
16
|
+
{
|
|
17
|
+
type: 'select',
|
|
18
|
+
label: 'connection-name',
|
|
19
|
+
name: 'connectionName',
|
|
20
|
+
property: {
|
|
21
|
+
options: async () => {
|
|
22
|
+
var response = await getClient().query({
|
|
23
|
+
query: gql`
|
|
24
|
+
query {
|
|
25
|
+
connections {
|
|
26
|
+
items {
|
|
27
|
+
name
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
`
|
|
32
|
+
})
|
|
33
|
+
if (response.errors) {
|
|
34
|
+
return ['']
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return [''].concat(response.data.connections.items.map((item: any) => item.name))
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
type: 'select',
|
|
43
|
+
label: 'control-type',
|
|
44
|
+
name: 'controlType',
|
|
45
|
+
property: {
|
|
46
|
+
options: [
|
|
47
|
+
{
|
|
48
|
+
display: '',
|
|
49
|
+
value: ''
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
display: 'connect',
|
|
53
|
+
value: 'connect'
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
display: 'disconnect',
|
|
57
|
+
value: 'disconnect'
|
|
58
|
+
}
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
],
|
|
63
|
+
'value-property': 'controlType',
|
|
64
|
+
help: 'scene/component/connection-control'
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export default class ConnectionControl extends RectPath(Shape) {
|
|
68
|
+
static _image: HTMLImageElement
|
|
69
|
+
|
|
70
|
+
static get image() {
|
|
71
|
+
if (!ConnectionControl._image) {
|
|
72
|
+
ConnectionControl._image = new Image()
|
|
73
|
+
ConnectionControl._image.src = COMPONENT_IMAGE
|
|
74
|
+
}
|
|
75
|
+
return ConnectionControl._image
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
private _client: any
|
|
79
|
+
|
|
80
|
+
render(context: CanvasRenderingContext2D) {
|
|
81
|
+
var { left, top, width, height } = this.bounds
|
|
82
|
+
context.beginPath()
|
|
83
|
+
this.drawImage(context, ConnectionControl.image, left, top, width, height)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
ready() {
|
|
87
|
+
super.ready()
|
|
88
|
+
this._init()
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
_init() {
|
|
92
|
+
if (!this.app.isViewMode) return
|
|
93
|
+
|
|
94
|
+
this._client = getClient()
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
dispose() {
|
|
98
|
+
super.dispose()
|
|
99
|
+
|
|
100
|
+
try {
|
|
101
|
+
if (this._client) {
|
|
102
|
+
this._client.stop()
|
|
103
|
+
}
|
|
104
|
+
} catch (e) {
|
|
105
|
+
console.error(e)
|
|
106
|
+
}
|
|
107
|
+
delete this._client
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
get nature() {
|
|
111
|
+
return NATURE
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
get client() {
|
|
115
|
+
return this._client
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
get controlType() {
|
|
119
|
+
return this.getState('controlType')
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
set controlType(controlType: string) {
|
|
123
|
+
this.setState('controlType', controlType)
|
|
124
|
+
this.controlConnect()
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async controlConnect() {
|
|
128
|
+
let { controlType, connectionName } = this.state
|
|
129
|
+
|
|
130
|
+
if (!connectionName || !this.app.isViewMode) return
|
|
131
|
+
|
|
132
|
+
switch (controlType) {
|
|
133
|
+
case 'connect':
|
|
134
|
+
case true:
|
|
135
|
+
case 1:
|
|
136
|
+
controlType = 'connect'
|
|
137
|
+
break
|
|
138
|
+
default:
|
|
139
|
+
controlType = 'disconnect'
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
var client = this._client
|
|
143
|
+
var query = ''
|
|
144
|
+
|
|
145
|
+
query = `mutation{
|
|
146
|
+
${controlType}Connection(name: "${connectionName}") {
|
|
147
|
+
status
|
|
148
|
+
}
|
|
149
|
+
}`
|
|
150
|
+
|
|
151
|
+
if (client) {
|
|
152
|
+
var response = await client.query({
|
|
153
|
+
query: gql`
|
|
154
|
+
${query}
|
|
155
|
+
`
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
this.data = response
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
Component.register('connection-control', ConnectionControl)
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright © HatioLab Inc. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import gql from 'graphql-tag'
|
|
6
|
+
|
|
7
|
+
import { Component, DataSource, RectPath, Shape } from '@hatiolab/things-scene'
|
|
8
|
+
|
|
9
|
+
import COMPONENT_IMAGE from '../assets/symbol-connection-state-subscription.png'
|
|
10
|
+
import { getClient, subscribe } from './origin-client'
|
|
11
|
+
|
|
12
|
+
const NATURE = {
|
|
13
|
+
mutable: false,
|
|
14
|
+
resizable: true,
|
|
15
|
+
rotatable: true,
|
|
16
|
+
properties: [
|
|
17
|
+
{
|
|
18
|
+
type: 'select',
|
|
19
|
+
label: 'connection-name',
|
|
20
|
+
name: 'connectionName',
|
|
21
|
+
property: {
|
|
22
|
+
options: async () => {
|
|
23
|
+
var response = await getClient().query({
|
|
24
|
+
query: gql`
|
|
25
|
+
query {
|
|
26
|
+
connections {
|
|
27
|
+
items {
|
|
28
|
+
name
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
`
|
|
33
|
+
})
|
|
34
|
+
if (response.errors) {
|
|
35
|
+
return ['']
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return [''].concat(response.data.connections.items.map((item: any) => item.name))
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
help: 'scene/component/connection-state-subscription'
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export default class ConnectionStateSubscription extends DataSource(RectPath(Shape)) {
|
|
47
|
+
static _image: HTMLImageElement
|
|
48
|
+
static get image() {
|
|
49
|
+
if (!ConnectionStateSubscription._image) {
|
|
50
|
+
ConnectionStateSubscription._image = new Image()
|
|
51
|
+
ConnectionStateSubscription._image.src = COMPONENT_IMAGE
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return ConnectionStateSubscription._image
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
private subscription?: {
|
|
58
|
+
unsubscribe(): void
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
dispose() {
|
|
62
|
+
super.dispose()
|
|
63
|
+
|
|
64
|
+
this.subscription?.unsubscribe()
|
|
65
|
+
delete this.subscription
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
render(context: CanvasRenderingContext2D) {
|
|
69
|
+
var { left, top, width, height } = this.bounds
|
|
70
|
+
|
|
71
|
+
context.beginPath()
|
|
72
|
+
this.drawImage(context, ConnectionStateSubscription.image, left, top, width, height)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
ready() {
|
|
76
|
+
if (!this.app.isViewMode) return
|
|
77
|
+
this._initConnectionStateSubscription()
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
get nature() {
|
|
81
|
+
return NATURE
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
_initConnectionStateSubscription() {
|
|
85
|
+
if (!this.app.isViewMode) return
|
|
86
|
+
this.startSubscribe()
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async startSubscribe() {
|
|
90
|
+
var { connectionName } = this.state
|
|
91
|
+
|
|
92
|
+
this.subscription = await subscribe(
|
|
93
|
+
{
|
|
94
|
+
query: gql`subscription {
|
|
95
|
+
connectionState(name: "${connectionName}") {
|
|
96
|
+
name
|
|
97
|
+
state
|
|
98
|
+
timestamp
|
|
99
|
+
}
|
|
100
|
+
}`
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
next: async ({ data }: { data: any }) => {
|
|
104
|
+
if (data) {
|
|
105
|
+
this.data = data.connectionState
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
Component.register('connection-state-subscription', ConnectionStateSubscription)
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright © HatioLab Inc. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import gql from 'graphql-tag'
|
|
6
|
+
|
|
7
|
+
import { Component, DataSource, RectPath, Shape } from '@hatiolab/things-scene'
|
|
8
|
+
|
|
9
|
+
import COMPONENT_IMAGE from '../assets/symbol-data-subscription.png'
|
|
10
|
+
import { subscribe } from './origin-client'
|
|
11
|
+
|
|
12
|
+
const NATURE = {
|
|
13
|
+
mutable: false,
|
|
14
|
+
resizable: true,
|
|
15
|
+
rotatable: true,
|
|
16
|
+
properties: [
|
|
17
|
+
{
|
|
18
|
+
type: 'string',
|
|
19
|
+
label: 'tag',
|
|
20
|
+
name: 'tag'
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
'value-property': 'tag',
|
|
24
|
+
help: 'scene/component/data-subscription'
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export default class DataSubscription extends DataSource(RectPath(Shape)) {
|
|
28
|
+
static _image: HTMLImageElement
|
|
29
|
+
static get image() {
|
|
30
|
+
if (!DataSubscription._image) {
|
|
31
|
+
DataSubscription._image = new Image()
|
|
32
|
+
DataSubscription._image.src = COMPONENT_IMAGE
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return DataSubscription._image
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
private subscription?: {
|
|
39
|
+
unsubscribe(): void
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
dispose() {
|
|
43
|
+
this.subscription?.unsubscribe()
|
|
44
|
+
delete this.subscription
|
|
45
|
+
|
|
46
|
+
super.dispose()
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
render(context: CanvasRenderingContext2D) {
|
|
50
|
+
var { left, top, width, height } = this.bounds
|
|
51
|
+
|
|
52
|
+
context.beginPath()
|
|
53
|
+
this.drawImage(context, DataSubscription.image, left, top, width, height)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
ready() {
|
|
57
|
+
this._initDataSubscription()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
get nature() {
|
|
61
|
+
return NATURE
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
get tag() {
|
|
65
|
+
return this.state.tag
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
set tag(tag) {
|
|
69
|
+
this.setState('tag', tag)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
_initDataSubscription() {
|
|
73
|
+
if (!this.app.isViewMode) return
|
|
74
|
+
|
|
75
|
+
this.startSubscribe()
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async startSubscribe() {
|
|
79
|
+
var { tag } = this.state
|
|
80
|
+
|
|
81
|
+
this.subscription = await subscribe(
|
|
82
|
+
{
|
|
83
|
+
query: gql`
|
|
84
|
+
subscription {
|
|
85
|
+
data(tag: "${tag}") {
|
|
86
|
+
tag
|
|
87
|
+
data
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
`
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
next: async ({ data }: { data: any }) => {
|
|
94
|
+
if (data) {
|
|
95
|
+
this.data = data.data.data
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
Component.register('data-subscription', DataSubscription)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default [];
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import DataSubscription from './data-subscription'
|
|
2
|
+
import ScenarioControl from './scenario-control'
|
|
3
|
+
import ScenarioRun from './scenario-run'
|
|
4
|
+
import ScenarioStart from './scenario-start'
|
|
5
|
+
import ScenarioStop from './scenario-stop'
|
|
6
|
+
import ScenarioInstanceSubscription from './scenario-instance-subscription'
|
|
7
|
+
import ScenarioQueueSubscription from './scenario-queue-subscription'
|
|
8
|
+
import ConnectionStateSubscription from './connection-state-subscription'
|
|
9
|
+
import ConnectionControl from './connection-control'
|
|
10
|
+
|
|
11
|
+
export default [
|
|
12
|
+
DataSubscription,
|
|
13
|
+
ScenarioControl,
|
|
14
|
+
ScenarioRun,
|
|
15
|
+
ScenarioStart,
|
|
16
|
+
ScenarioStop,
|
|
17
|
+
ScenarioInstanceSubscription,
|
|
18
|
+
ScenarioQueueSubscription,
|
|
19
|
+
ConnectionStateSubscription,
|
|
20
|
+
ConnectionControl
|
|
21
|
+
]
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { ApolloClient, HttpLink, InMemoryCache, from } from '@apollo/client/core'
|
|
2
|
+
import { ErrorResponse, onError } from '@apollo/client/link/error'
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
* Copyright © HatioLab Inc. All rights reserved.
|
|
6
|
+
*/
|
|
7
|
+
import { DefaultOptions } from '@apollo/client'
|
|
8
|
+
import { SubscriptionClient } from 'subscriptions-transport-ws'
|
|
9
|
+
|
|
10
|
+
const defaultOptions: DefaultOptions = {
|
|
11
|
+
watchQuery: {
|
|
12
|
+
fetchPolicy: 'no-cache',
|
|
13
|
+
errorPolicy: 'ignore'
|
|
14
|
+
},
|
|
15
|
+
query: {
|
|
16
|
+
fetchPolicy: 'no-cache', //'network-only'
|
|
17
|
+
errorPolicy: 'all'
|
|
18
|
+
},
|
|
19
|
+
mutate: {
|
|
20
|
+
errorPolicy: 'all'
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const ERROR_HANDLER = ({ graphQLErrors, networkError }: ErrorResponse) => {
|
|
25
|
+
if (graphQLErrors) {
|
|
26
|
+
document.dispatchEvent(
|
|
27
|
+
new CustomEvent('notify', {
|
|
28
|
+
detail: {
|
|
29
|
+
level: 'error',
|
|
30
|
+
message: graphQLErrors[0].message,
|
|
31
|
+
ex: graphQLErrors
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (networkError) {
|
|
38
|
+
const code = (networkError as any).statusCode || ''
|
|
39
|
+
const message = `[Response-${code}]: ${networkError.message}`
|
|
40
|
+
|
|
41
|
+
document.dispatchEvent(
|
|
42
|
+
new CustomEvent('notify', {
|
|
43
|
+
detail: {
|
|
44
|
+
level: 'error',
|
|
45
|
+
message,
|
|
46
|
+
ex: networkError
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
var client: ApolloClient<any>
|
|
54
|
+
|
|
55
|
+
export function getClient() {
|
|
56
|
+
if (!client) {
|
|
57
|
+
var cache = new InMemoryCache()
|
|
58
|
+
client = new ApolloClient({
|
|
59
|
+
defaultOptions,
|
|
60
|
+
cache,
|
|
61
|
+
link: from([
|
|
62
|
+
onError(ERROR_HANDLER),
|
|
63
|
+
new HttpLink({
|
|
64
|
+
uri: '/graphql',
|
|
65
|
+
credentials: 'include'
|
|
66
|
+
})
|
|
67
|
+
])
|
|
68
|
+
})
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return client
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/* SubscriptionClient */
|
|
75
|
+
var subscriptionClient: Promise<SubscriptionClient> | null
|
|
76
|
+
|
|
77
|
+
const getSubscriptionClient = async () => {
|
|
78
|
+
if (!subscriptionClient) {
|
|
79
|
+
subscriptionClient = new Promise((resolve, reject) => {
|
|
80
|
+
var client = new SubscriptionClient(location.origin.replace(/^http/, 'ws') + '/subscriptions', {
|
|
81
|
+
reconnect: true,
|
|
82
|
+
connectionParams: {
|
|
83
|
+
headers: {
|
|
84
|
+
/*
|
|
85
|
+
특정 도메인의 데이타만 받고자 하는 경우에, referer 정보를 제공해서 서버에서 서브도메인 정보를 취득하도록 한다.
|
|
86
|
+
referer: location.href
|
|
87
|
+
또는, 이미 서브도메인 정보를 알고 있다면,
|
|
88
|
+
'x-things-factory-domain': '[subdomain]'
|
|
89
|
+
을 보낼 수 있다.
|
|
90
|
+
관련 정보를 보내지 않는다면, 사용자가 권한을 가진 모든 도메인의 데이타를 수신하게 된다.
|
|
91
|
+
*/
|
|
92
|
+
referer: location.href
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
client.onError(err => {
|
|
98
|
+
//readyState === 3 인 경우 url을 잘 못 입력했거나, 서버에 문제가 있는 경우이므로 reconnect = false로 변경한다.
|
|
99
|
+
if (client.status === 3) {
|
|
100
|
+
// client.reconnect = false // reconnect is private property
|
|
101
|
+
client.close(true)
|
|
102
|
+
}
|
|
103
|
+
reject(err)
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
client.onConnected(() => {
|
|
107
|
+
resolve(client)
|
|
108
|
+
})
|
|
109
|
+
})
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return await subscriptionClient
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
var subscriptions: (() => void)[] = []
|
|
116
|
+
|
|
117
|
+
export const subscribe = async (request: any, subscribe: any) => {
|
|
118
|
+
var client = await getSubscriptionClient()
|
|
119
|
+
var { unsubscribe } = client.request(request).subscribe(subscribe)
|
|
120
|
+
|
|
121
|
+
subscriptions.push(unsubscribe)
|
|
122
|
+
|
|
123
|
+
return {
|
|
124
|
+
unsubscribe() {
|
|
125
|
+
subscriptions.splice(subscriptions.indexOf(unsubscribe), 1)
|
|
126
|
+
unsubscribe()
|
|
127
|
+
|
|
128
|
+
if (subscriptions.length == 0) {
|
|
129
|
+
client.unsubscribeAll()
|
|
130
|
+
client.close(true)
|
|
131
|
+
|
|
132
|
+
subscriptionClient = null
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|