@things-factory/edge-client 8.0.0-beta.1 → 8.0.0-beta.4
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 +6 -6
- package/server/controllers/connect-connections.ts +0 -6
- package/server/controllers/disconnect-connections.ts +0 -6
- package/server/controllers/index.ts +0 -2
- package/server/controllers/run-task.ts +0 -33
- package/server/controllers/sync-connections.ts +0 -6
- package/server/engine/connector/edge-connector.ts +0 -45
- package/server/engine/index.ts +0 -1
- package/server/index.ts +0 -17
- package/server/service/appliance/edge-client-mutation.ts +0 -18
- package/server/service/appliance/edge-client-subscription.ts +0 -241
- package/server/service/appliance/edge-client-type.ts +0 -46
- package/server/service/appliance/index.ts +0 -6
- package/server/service/index.ts +0 -21
- package/server/tsconfig.json +0 -10
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@things-factory/edge-client",
|
|
3
|
-
"version": "8.0.0-beta.
|
|
3
|
+
"version": "8.0.0-beta.4",
|
|
4
4
|
"main": "dist-server/index.js",
|
|
5
5
|
"things-factory": true,
|
|
6
6
|
"license": "MIT",
|
|
@@ -22,10 +22,10 @@
|
|
|
22
22
|
"clean": "npm run clean:server"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@things-factory/auth-base": "^8.0.0-beta.
|
|
26
|
-
"@things-factory/integration-base": "^8.0.0-beta.
|
|
27
|
-
"@things-factory/lock-client": "^8.0.0-beta.
|
|
28
|
-
"@things-factory/shell": "^8.0.0-beta.
|
|
25
|
+
"@things-factory/auth-base": "^8.0.0-beta.4",
|
|
26
|
+
"@things-factory/integration-base": "^8.0.0-beta.4",
|
|
27
|
+
"@things-factory/lock-client": "^8.0.0-beta.4",
|
|
28
|
+
"@things-factory/shell": "^8.0.0-beta.4"
|
|
29
29
|
},
|
|
30
|
-
"gitHead": "
|
|
30
|
+
"gitHead": "d83d12ed4ba07177dff1dac26e37be347d156b43"
|
|
31
31
|
}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { pubsub } from '@things-factory/shell'
|
|
2
|
-
import { Connection } from '@things-factory/integration-base'
|
|
3
|
-
|
|
4
|
-
export async function connectConnections(connections: Connection[], context: ResolverContext): Promise<any> {
|
|
5
|
-
pubsub.publish('connect-connections', connections)
|
|
6
|
-
}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { pubsub } from '@things-factory/shell'
|
|
2
|
-
import { Connection } from '@things-factory/integration-base'
|
|
3
|
-
|
|
4
|
-
export async function disconnectConnections(connections: Connection[], context: ResolverContext): Promise<any> {
|
|
5
|
-
pubsub.publish('disconnect-connections', connections)
|
|
6
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { pubsub } from '@things-factory/shell'
|
|
2
|
-
import { Context, Step, TaskHandler } from '@things-factory/integration-base'
|
|
3
|
-
import { requestLock, tryLock } from '@things-factory/lock-client'
|
|
4
|
-
|
|
5
|
-
export const runTask: TaskHandler = async (step: Step, scenarioContext: Context) => {
|
|
6
|
-
const { logger }: { logger: any } = scenarioContext
|
|
7
|
-
|
|
8
|
-
try {
|
|
9
|
-
const id = await requestLock()
|
|
10
|
-
|
|
11
|
-
pubsub.publish('run-task', {
|
|
12
|
-
id,
|
|
13
|
-
step,
|
|
14
|
-
context: scenarioContext
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
const result = await tryLock({ id })
|
|
18
|
-
const { out, logs, error } = result || {}
|
|
19
|
-
|
|
20
|
-
if (logger.transports?.length > 0) {
|
|
21
|
-
/* 강제로 시나리오 인스턴스가 종료된 경우에는 logger도 닫힌 상태가 된다. 이 경우에는 transports가 설정되지 않게된다. */
|
|
22
|
-
logs && logs.map(log => logger.log(log))
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
if (error) {
|
|
26
|
-
throw new Error(error)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
return out
|
|
30
|
-
} catch (err) {
|
|
31
|
-
throw new Error(err)
|
|
32
|
-
}
|
|
33
|
-
}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { pubsub } from '@things-factory/shell'
|
|
2
|
-
import { Connection } from '@things-factory/integration-base'
|
|
3
|
-
|
|
4
|
-
export async function syncConnections(connections: Connection[], context: ResolverContext): Promise<any> {
|
|
5
|
-
pubsub.publish('sync-connections', connections)
|
|
6
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { Connector, ConnectionManager, InputConnection } from '@things-factory/integration-base'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* This connector only serves the role of a tag specifying that a particular step of the task will be performed on the Edge Server,
|
|
5
|
-
* and therefore, contains no special logic.
|
|
6
|
-
*/
|
|
7
|
-
export class EdgeConnector implements Connector {
|
|
8
|
-
async ready(connectionConfigs: InputConnection[]) {
|
|
9
|
-
await Promise.all(connectionConfigs.map(this.connect.bind(this)))
|
|
10
|
-
|
|
11
|
-
ConnectionManager.logger.info('edge-connector connections are ready')
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
async connect(connection: InputConnection) {
|
|
15
|
-
const edge = {}
|
|
16
|
-
|
|
17
|
-
ConnectionManager.addConnectionInstance(connection, edge)
|
|
18
|
-
|
|
19
|
-
ConnectionManager.logger.info(`edge-connector connection(${connection.name}:${connection.endpoint}) is connected`)
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
async disconnect(connection: InputConnection) {
|
|
23
|
-
ConnectionManager.removeConnectionInstance(connection)
|
|
24
|
-
|
|
25
|
-
ConnectionManager.logger.info(`edge-connector connection(${connection.name}) is disconnected`)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
get parameterSpec() {
|
|
29
|
-
return []
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
get taskPrefixes() {
|
|
33
|
-
return [] // intentionally empty
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
get help() {
|
|
37
|
-
return 'integration/connector/edge-connector'
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
get description() {
|
|
41
|
-
return 'Operato Edge Connector'
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
ConnectionManager.registerConnector('edge-connector', new EdgeConnector())
|
package/server/engine/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import './connector/edge-connector'
|
package/server/index.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
export * from './service'
|
|
2
|
-
|
|
3
|
-
import { setEdgeClient } from '@things-factory/integration-base'
|
|
4
|
-
import { runTask } from './controllers/run-task'
|
|
5
|
-
import { syncConnections } from './controllers/sync-connections'
|
|
6
|
-
import { connectConnections } from './controllers/connect-connections'
|
|
7
|
-
import { disconnectConnections } from './controllers/disconnect-connections'
|
|
8
|
-
import './engine' // for registering edge-connector
|
|
9
|
-
|
|
10
|
-
process.on('bootstrap-module-start' as any, async ({ app, config, client }: any) => {
|
|
11
|
-
setEdgeClient({
|
|
12
|
-
handler: runTask,
|
|
13
|
-
syncConnections,
|
|
14
|
-
connectConnections,
|
|
15
|
-
disconnectConnections
|
|
16
|
-
})
|
|
17
|
-
})
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { Resolver, Mutation, Arg, Ctx, Directive } from 'type-graphql'
|
|
2
|
-
|
|
3
|
-
import { Appliance } from '@things-factory/auth-base'
|
|
4
|
-
import { releaseLock } from '@things-factory/lock-client'
|
|
5
|
-
|
|
6
|
-
import { RunTaskCallbackInput } from './edge-client-type'
|
|
7
|
-
|
|
8
|
-
@Resolver(Appliance)
|
|
9
|
-
export class EdgeClientMutation {
|
|
10
|
-
@Mutation(returns => Boolean, { description: 'To receive the result of runTask' })
|
|
11
|
-
async runTaskCallback(@Arg('result', type => RunTaskCallbackInput) result: RunTaskCallbackInput, @Ctx() context: ResolverContext): Promise<boolean> {
|
|
12
|
-
const { id, out, logs, error } = result
|
|
13
|
-
|
|
14
|
-
await releaseLock({ id, payload: { out, logs, error } })
|
|
15
|
-
|
|
16
|
-
return true
|
|
17
|
-
}
|
|
18
|
-
}
|
|
@@ -1,241 +0,0 @@
|
|
|
1
|
-
import { filter, pipe } from 'graphql-yoga'
|
|
2
|
-
import { Resolver, Subscription, Root, Arg } from 'type-graphql'
|
|
3
|
-
|
|
4
|
-
import { pubsub, getRepository, Domain } from '@things-factory/shell'
|
|
5
|
-
import { Appliance, User } from '@things-factory/auth-base'
|
|
6
|
-
import { ConnectionManager, Connection, Step } from '@things-factory/integration-base'
|
|
7
|
-
|
|
8
|
-
import { EdgeContext, RunTaskPayload } from './edge-client-type'
|
|
9
|
-
|
|
10
|
-
@Resolver(Appliance)
|
|
11
|
-
export class EdgeClientSubscription {
|
|
12
|
-
@Subscription(type => [Connection], {
|
|
13
|
-
subscribe: async ({ args, context, info }) => {
|
|
14
|
-
const { domain, user }: { domain: Domain; user: User } = context.state
|
|
15
|
-
const subdomain = domain?.subdomain
|
|
16
|
-
|
|
17
|
-
if (!domain) {
|
|
18
|
-
throw new Error('domain required')
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
if (!user.domains?.find(d => d.subdomain === subdomain) && !process.superUserGranted(domain, user)) {
|
|
22
|
-
throw new Error(`domain(${subdomain}) is not working for user(${user.email}).`)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const appliance =
|
|
26
|
-
user.reference &&
|
|
27
|
-
(await getRepository(Appliance).findOne({
|
|
28
|
-
where: {
|
|
29
|
-
id: user.reference
|
|
30
|
-
}
|
|
31
|
-
}))
|
|
32
|
-
|
|
33
|
-
if (!appliance) {
|
|
34
|
-
throw new Error('Appliance not found')
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
process.nextTick(async () => {
|
|
38
|
-
const connections = Object.values(ConnectionManager.getConnectionInstanceEntities(domain)).filter(
|
|
39
|
-
({ edgeId }) => edgeId == appliance.id
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
if (connections.length > 0) {
|
|
43
|
-
pubsub.publish('sync-connections', connections)
|
|
44
|
-
}
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
return pipe(
|
|
48
|
-
pubsub.subscribe('sync-connections'),
|
|
49
|
-
filter(async (payload: Connection[]) => {
|
|
50
|
-
const connections = payload
|
|
51
|
-
const { edgeId } = connections[0]
|
|
52
|
-
|
|
53
|
-
if (connections.find(connection => connection.domain?.subdomain !== subdomain)) {
|
|
54
|
-
return false
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (!edgeId || appliance?.id !== edgeId) {
|
|
58
|
-
return false
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return true
|
|
62
|
-
})
|
|
63
|
-
)
|
|
64
|
-
}
|
|
65
|
-
})
|
|
66
|
-
syncConnections(@Root() payload: Connection[]): Connection[] {
|
|
67
|
-
return payload.map(connection => {
|
|
68
|
-
return {
|
|
69
|
-
...connection,
|
|
70
|
-
params: JSON.stringify(connection.params)
|
|
71
|
-
}
|
|
72
|
-
}) as any
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
@Subscription(type => [Connection], {
|
|
76
|
-
subscribe: async ({ args, context, info }) => {
|
|
77
|
-
const { domain, user }: { domain: Domain; user: User } = context.state
|
|
78
|
-
const subdomain = domain?.subdomain
|
|
79
|
-
|
|
80
|
-
if (!domain) {
|
|
81
|
-
throw new Error('domain required')
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (!user.domains?.find(d => d.subdomain === subdomain) && !process.superUserGranted(domain, user)) {
|
|
85
|
-
throw new Error(`domain(${subdomain}) is not working for user(${user.email}).`)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const appliance =
|
|
89
|
-
user.reference &&
|
|
90
|
-
(await getRepository(Appliance).findOne({
|
|
91
|
-
where: {
|
|
92
|
-
id: user.reference
|
|
93
|
-
}
|
|
94
|
-
}))
|
|
95
|
-
|
|
96
|
-
if (!appliance) {
|
|
97
|
-
throw new Error('Appliance not found')
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
return pipe(
|
|
101
|
-
pubsub.subscribe('connect-connections'),
|
|
102
|
-
filter(async (payload: Connection[]) => {
|
|
103
|
-
const connections = payload
|
|
104
|
-
const { edgeId } = connections[0]
|
|
105
|
-
|
|
106
|
-
if (connections.find(connection => connection.domain?.subdomain !== subdomain)) {
|
|
107
|
-
return false
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
if (!edgeId || appliance?.id !== edgeId) {
|
|
111
|
-
return false
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return true
|
|
115
|
-
})
|
|
116
|
-
)
|
|
117
|
-
}
|
|
118
|
-
})
|
|
119
|
-
connectConnections(@Root() payload: Connection[]): Connection[] {
|
|
120
|
-
return payload.map(connection => {
|
|
121
|
-
return {
|
|
122
|
-
...connection,
|
|
123
|
-
params: JSON.stringify(connection.params)
|
|
124
|
-
}
|
|
125
|
-
}) as any
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
@Subscription(type => [Connection], {
|
|
129
|
-
subscribe: async ({ args, context, info }) => {
|
|
130
|
-
const { domain, user }: { domain: Domain; user: User } = context.state
|
|
131
|
-
const subdomain = domain?.subdomain
|
|
132
|
-
|
|
133
|
-
if (!domain) {
|
|
134
|
-
throw new Error('domain required')
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
if (!user.domains?.find(d => d.subdomain === subdomain) && !process.superUserGranted(domain, user)) {
|
|
138
|
-
throw new Error(`domain(${subdomain}) is not working for user(${user.email}).`)
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const appliance =
|
|
142
|
-
user.reference &&
|
|
143
|
-
(await getRepository(Appliance).findOne({
|
|
144
|
-
where: {
|
|
145
|
-
id: user.reference
|
|
146
|
-
}
|
|
147
|
-
}))
|
|
148
|
-
|
|
149
|
-
if (!appliance) {
|
|
150
|
-
throw new Error('Appliance not found')
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
return pipe(
|
|
154
|
-
pubsub.subscribe('disconnect-connections'),
|
|
155
|
-
filter(async (payload: Connection[]) => {
|
|
156
|
-
const connections = payload
|
|
157
|
-
const { edgeId } = connections[0]
|
|
158
|
-
|
|
159
|
-
if (connections.find(connection => connection.domain?.subdomain !== subdomain)) {
|
|
160
|
-
return false
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
if (!edgeId || appliance?.id !== edgeId) {
|
|
164
|
-
return false
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
return true
|
|
168
|
-
})
|
|
169
|
-
)
|
|
170
|
-
}
|
|
171
|
-
})
|
|
172
|
-
disconnectConnections(@Root() payload: Connection[]): Connection[] {
|
|
173
|
-
return payload.map(connection => {
|
|
174
|
-
return {
|
|
175
|
-
...connection,
|
|
176
|
-
params: JSON.stringify(connection.params)
|
|
177
|
-
}
|
|
178
|
-
}) as any
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
@Subscription({
|
|
182
|
-
subscribe: async ({ args, context, info }) => {
|
|
183
|
-
const { domain, user }: { domain: Domain; user: User } = context.state
|
|
184
|
-
|
|
185
|
-
const subdomain = domain?.subdomain
|
|
186
|
-
if (!domain) {
|
|
187
|
-
throw new Error('domain required')
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
if (!user.domains?.find(d => d.subdomain === subdomain) && !process.superUserGranted(domain, user)) {
|
|
191
|
-
throw new Error(`domain(${subdomain}) is not working for user(${user.email}).`)
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
const appliance =
|
|
195
|
-
user.reference &&
|
|
196
|
-
(await getRepository(Appliance).findOne({
|
|
197
|
-
where: {
|
|
198
|
-
id: user.reference
|
|
199
|
-
}
|
|
200
|
-
}))
|
|
201
|
-
|
|
202
|
-
if (!appliance) {
|
|
203
|
-
throw new Error('Appliance not found')
|
|
204
|
-
}
|
|
205
|
-
return pipe(
|
|
206
|
-
pubsub.subscribe('run-task'),
|
|
207
|
-
filter(async (payload: { id: string; step: Step; context: EdgeContext }) => {
|
|
208
|
-
const { domainId, connection } = payload.step
|
|
209
|
-
|
|
210
|
-
if (domainId !== domain.id) {
|
|
211
|
-
return false
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
const { edgeId } = connection && ConnectionManager.getConnectionInstanceEntityByName(domain, connection)
|
|
215
|
-
|
|
216
|
-
if (!edgeId || appliance?.id !== edgeId) {
|
|
217
|
-
return false
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
return true
|
|
221
|
-
})
|
|
222
|
-
)
|
|
223
|
-
}
|
|
224
|
-
})
|
|
225
|
-
runTask(@Root() payload: RunTaskPayload): RunTaskPayload {
|
|
226
|
-
const { id, step, context } = payload
|
|
227
|
-
const { name, task, description, connection, params } = step
|
|
228
|
-
|
|
229
|
-
return {
|
|
230
|
-
id, // requestId
|
|
231
|
-
step: {
|
|
232
|
-
name,
|
|
233
|
-
task,
|
|
234
|
-
description,
|
|
235
|
-
connection,
|
|
236
|
-
params: JSON.stringify(params)
|
|
237
|
-
},
|
|
238
|
-
context
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { InputType, ObjectType, Field } from 'type-graphql'
|
|
2
|
-
|
|
3
|
-
import { Domain, ScalarObject } from '@things-factory/shell'
|
|
4
|
-
import { Step } from '@things-factory/integration-base'
|
|
5
|
-
|
|
6
|
-
@ObjectType()
|
|
7
|
-
export class EdgeContext {
|
|
8
|
-
@Field(type => Domain, { nullable: true })
|
|
9
|
-
domain: any
|
|
10
|
-
|
|
11
|
-
@Field(type => ScalarObject, { nullable: true })
|
|
12
|
-
data: any
|
|
13
|
-
|
|
14
|
-
@Field(type => ScalarObject, { nullable: true })
|
|
15
|
-
variables: any
|
|
16
|
-
|
|
17
|
-
@Field({ nullable: true })
|
|
18
|
-
lng: string
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
@ObjectType()
|
|
22
|
-
export class RunTaskPayload {
|
|
23
|
-
@Field()
|
|
24
|
-
id: string
|
|
25
|
-
|
|
26
|
-
@Field()
|
|
27
|
-
step: Step
|
|
28
|
-
|
|
29
|
-
@Field()
|
|
30
|
-
context: EdgeContext
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
@InputType()
|
|
34
|
-
export class RunTaskCallbackInput {
|
|
35
|
-
@Field({ nullable: true })
|
|
36
|
-
id: string
|
|
37
|
-
|
|
38
|
-
@Field(type => ScalarObject, { nullable: true })
|
|
39
|
-
out: any
|
|
40
|
-
|
|
41
|
-
@Field(type => ScalarObject, { nullable: true })
|
|
42
|
-
logs: any
|
|
43
|
-
|
|
44
|
-
@Field(type => ScalarObject, { nullable: true })
|
|
45
|
-
error: any
|
|
46
|
-
}
|
package/server/service/index.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/* EXPORT ENTITY TYPES */
|
|
2
|
-
|
|
3
|
-
/* IMPORT ENTITIES AND RESOLVERS */
|
|
4
|
-
import { entities as EdgeClientEntities, resolvers as EdgeClientResolvers, subscribers as EdgeClientSubscribers } from './appliance'
|
|
5
|
-
|
|
6
|
-
export const entities = [
|
|
7
|
-
/* ENTITIES */
|
|
8
|
-
...EdgeClientEntities
|
|
9
|
-
]
|
|
10
|
-
|
|
11
|
-
export const subscribers = [
|
|
12
|
-
/* SUBSCRIBERS */
|
|
13
|
-
...EdgeClientSubscribers
|
|
14
|
-
]
|
|
15
|
-
|
|
16
|
-
export const schema = {
|
|
17
|
-
resolverClasses: [
|
|
18
|
-
/* RESOLVER CLASSES */
|
|
19
|
-
...EdgeClientResolvers
|
|
20
|
-
]
|
|
21
|
-
}
|