@rdfc/js-runner 1.0.0 → 2.0.0-alpha.10
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/.husky/pre-commit +6 -0
- package/.idea/LNKD.tech Editor.xml +194 -0
- package/.idea/codeStyles/Project.xml +52 -0
- package/.idea/codeStyles/codeStyleConfig.xml +5 -0
- package/.idea/inspectionProfiles/Project_Default.xml +6 -0
- package/.idea/js-runner.iml +12 -0
- package/.idea/modules.xml +8 -0
- package/.idea/vcs.xml +6 -0
- package/.prettierrc +4 -0
- package/README.md +3 -38
- package/__tests__/channels.test.ts +96 -0
- package/bin/runner.js +8 -0
- package/dist/args.d.ts +3 -3
- package/dist/args.js +50 -51
- package/dist/connectors/file.d.ts +11 -11
- package/dist/connectors/file.js +79 -79
- package/dist/connectors/http.d.ts +10 -10
- package/dist/connectors/http.js +76 -76
- package/dist/connectors/kafka.d.ts +36 -36
- package/dist/connectors/kafka.js +66 -62
- package/dist/connectors/ws.d.ts +6 -6
- package/dist/connectors/ws.js +66 -63
- package/dist/connectors.d.ts +61 -42
- package/dist/connectors.js +155 -132
- package/dist/index.cjs +650 -595
- package/dist/index.d.ts +40 -31
- package/dist/index.js +72 -63
- package/dist/util.d.ts +63 -35
- package/dist/util.js +80 -63
- package/eslint.config.mjs +21 -0
- package/examples/echo/package-lock.json +80 -0
- package/examples/echo/package.json +18 -0
- package/examples/echo/pipeline.ttl +48 -0
- package/examples/echo/processors.ttl +82 -0
- package/examples/echo/src/processors.ts +74 -0
- package/examples/echo/tsconfig.json +114 -0
- package/index.ttl +71 -0
- package/jest.config.js +2 -0
- package/lib/client.d.ts +1 -0
- package/lib/client.js +43 -0
- package/lib/convertor.d.ts +9 -0
- package/lib/convertor.js +51 -0
- package/lib/index.d.ts +7 -0
- package/lib/index.js +8 -0
- package/lib/jsonld.d.ts +17 -0
- package/lib/jsonld.js +135 -0
- package/lib/logger.d.ts +17 -0
- package/lib/logger.js +49 -0
- package/lib/processor.d.ts +19 -0
- package/lib/processor.js +13 -0
- package/lib/reader.d.ts +30 -0
- package/lib/reader.js +101 -0
- package/lib/reexports.d.ts +3 -0
- package/lib/reexports.js +4 -0
- package/lib/runner.d.ts +26 -0
- package/lib/runner.js +121 -0
- package/lib/testUtils.d.ts +24 -0
- package/lib/testUtils.js +150 -0
- package/lib/tsconfig.tsbuildinfo +1 -0
- package/lib/util_processors.d.ts +11 -0
- package/lib/util_processors.js +13 -0
- package/lib/writer.d.ts +26 -0
- package/lib/writer.js +57 -0
- package/package.json +49 -51
- package/src/client.ts +52 -0
- package/src/convertor.ts +59 -0
- package/src/index.ts +8 -0
- package/src/jsonld.ts +220 -0
- package/src/logger.ts +64 -0
- package/src/processor.ts +39 -0
- package/src/reader.ts +142 -0
- package/src/reexports.ts +6 -0
- package/src/runner.ts +197 -0
- package/src/testUtils.ts +196 -0
- package/src/util_processors.ts +20 -0
- package/src/writer.ts +90 -0
- package/tsconfig.json +33 -0
- package/vite.config.ts +10 -0
- package/LICENSE +0 -21
- package/bin/js-runner.js +0 -4
- package/channels/file.ttl +0 -37
- package/channels/http.ttl +0 -59
- package/channels/kafka.ttl +0 -98
- package/channels/ws.ttl +0 -33
- package/ontology.ttl +0 -169
- package/processor/echo.ttl +0 -38
- package/processor/resc.ttl +0 -34
- package/processor/send.ttl +0 -40
- package/processor/test.js +0 -35
package/dist/index.cjs
CHANGED
|
@@ -1,677 +1,732 @@
|
|
|
1
|
-
'use strict'
|
|
1
|
+
'use strict'
|
|
2
2
|
|
|
3
|
-
var n3 = require('n3')
|
|
4
|
-
var commandLineArgs = require('command-line-args')
|
|
5
|
-
var commandLineUsage = require('command-line-usage')
|
|
6
|
-
var fs = require('fs')
|
|
7
|
-
var http = require('http')
|
|
8
|
-
var https = require('https')
|
|
9
|
-
var types = require('@treecg/types')
|
|
10
|
-
var debug = require('debug')
|
|
11
|
-
var path = require('path')
|
|
12
|
-
var promises = require('fs/promises')
|
|
13
|
-
var node_fs = require('node:fs')
|
|
14
|
-
var ws = require('ws')
|
|
15
|
-
var kafkajs = require('kafkajs')
|
|
16
|
-
var rdfLens = require('rdf-lens')
|
|
3
|
+
var n3 = require('n3')
|
|
4
|
+
var commandLineArgs = require('command-line-args')
|
|
5
|
+
var commandLineUsage = require('command-line-usage')
|
|
6
|
+
var fs = require('fs')
|
|
7
|
+
var http = require('http')
|
|
8
|
+
var https = require('https')
|
|
9
|
+
var types = require('@treecg/types')
|
|
10
|
+
var debug = require('debug')
|
|
11
|
+
var path = require('path')
|
|
12
|
+
var promises = require('fs/promises')
|
|
13
|
+
var node_fs = require('node:fs')
|
|
14
|
+
var ws = require('ws')
|
|
15
|
+
var kafkajs = require('kafkajs')
|
|
16
|
+
var rdfLens = require('rdf-lens')
|
|
17
17
|
|
|
18
18
|
function _interopNamespaceDefault(e) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
19
|
+
var n = Object.create(null)
|
|
20
|
+
if (e) {
|
|
21
|
+
Object.keys(e).forEach(function (k) {
|
|
22
|
+
if (k !== 'default') {
|
|
23
|
+
var d = Object.getOwnPropertyDescriptor(e, k)
|
|
24
|
+
Object.defineProperty(
|
|
25
|
+
n,
|
|
26
|
+
k,
|
|
27
|
+
d.get
|
|
28
|
+
? d
|
|
29
|
+
: {
|
|
30
|
+
enumerable: true,
|
|
31
|
+
get: function () {
|
|
32
|
+
return e[k]
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
}
|
|
39
|
+
n.default = e
|
|
40
|
+
return Object.freeze(n)
|
|
33
41
|
}
|
|
34
42
|
|
|
35
|
-
var http__namespace = /*#__PURE__*/_interopNamespaceDefault(http)
|
|
43
|
+
var http__namespace = /*#__PURE__*/ _interopNamespaceDefault(http)
|
|
36
44
|
|
|
37
45
|
const optionDefinitions = [
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
]
|
|
46
|
+
{
|
|
47
|
+
name: 'input',
|
|
48
|
+
type: String,
|
|
49
|
+
defaultOption: true,
|
|
50
|
+
summary: 'Specify what input file to start up',
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: 'help',
|
|
54
|
+
alias: 'h',
|
|
55
|
+
type: Boolean,
|
|
56
|
+
description: 'Display this help message',
|
|
57
|
+
},
|
|
58
|
+
]
|
|
51
59
|
const sections = [
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
60
|
+
{
|
|
61
|
+
header: 'Js-runner',
|
|
62
|
+
content:
|
|
63
|
+
'JS-runner is part of the {italic connector architecture}. Starting from an input file start up all JsProcessors that are defined. Please do not use blank nodes, skolemize your data somewhere else!',
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
header: 'Synopsis',
|
|
67
|
+
content: '$ js-runner <input>',
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
header: 'Command List',
|
|
71
|
+
content: [
|
|
72
|
+
{ name: 'input', summary: 'Specify what input file to start up' },
|
|
73
|
+
],
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
optionList: [optionDefinitions[1]],
|
|
77
|
+
},
|
|
78
|
+
]
|
|
70
79
|
function validArgs(args) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
return true;
|
|
80
|
+
if (!args.input) return false
|
|
81
|
+
return true
|
|
74
82
|
}
|
|
75
83
|
function printUsage() {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
84
|
+
const usage = commandLineUsage(sections)
|
|
85
|
+
console.log(usage)
|
|
86
|
+
process.exit(0)
|
|
79
87
|
}
|
|
80
88
|
function getArgs() {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
return args;
|
|
89
|
+
let args
|
|
90
|
+
try {
|
|
91
|
+
args = commandLineArgs(optionDefinitions)
|
|
92
|
+
} catch (e) {
|
|
93
|
+
console.error(e)
|
|
94
|
+
printUsage()
|
|
95
|
+
}
|
|
96
|
+
if (args.help || !validArgs(args)) {
|
|
97
|
+
printUsage()
|
|
98
|
+
}
|
|
99
|
+
return args
|
|
93
100
|
}
|
|
94
101
|
|
|
95
102
|
const LOG = (function () {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
})()
|
|
103
|
+
const main = debug('js-runner')
|
|
104
|
+
const channel = main.extend('channel')
|
|
105
|
+
const util = main.extend('util')
|
|
106
|
+
return { main, channel, util }
|
|
107
|
+
})()
|
|
101
108
|
function toArray(stream) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
+
const output = []
|
|
110
|
+
return new Promise((res, rej) => {
|
|
111
|
+
stream.on('data', (x) => output.push(x))
|
|
112
|
+
stream.on('end', () => res(output))
|
|
113
|
+
stream.on('close', () => res(output))
|
|
114
|
+
stream.on('error', rej)
|
|
115
|
+
})
|
|
109
116
|
}
|
|
110
|
-
const OWL = types.createUriAndTermNamespace(
|
|
111
|
-
|
|
112
|
-
|
|
117
|
+
const OWL = types.createUriAndTermNamespace(
|
|
118
|
+
'http://www.w3.org/2002/07/owl#',
|
|
119
|
+
'imports',
|
|
120
|
+
)
|
|
121
|
+
types.createUriAndTermNamespace(
|
|
122
|
+
'https://w3id.org/conn#',
|
|
123
|
+
'install',
|
|
124
|
+
'build',
|
|
125
|
+
'GitInstall',
|
|
126
|
+
'LocalInstall',
|
|
127
|
+
'url',
|
|
128
|
+
'procFile',
|
|
129
|
+
'path',
|
|
130
|
+
'EnvVariable',
|
|
131
|
+
'envKey',
|
|
132
|
+
'envDefault',
|
|
133
|
+
)
|
|
134
|
+
const { namedNode, literal } = n3.DataFactory
|
|
113
135
|
async function get_readstream(location) {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
return fs.createReadStream(location);
|
|
126
|
-
}
|
|
136
|
+
if (location.startsWith('https')) {
|
|
137
|
+
return new Promise((res) => {
|
|
138
|
+
https.get(location, res)
|
|
139
|
+
})
|
|
140
|
+
} else if (location.startsWith('http')) {
|
|
141
|
+
return new Promise((res) => {
|
|
142
|
+
http.get(location, res)
|
|
143
|
+
})
|
|
144
|
+
} else {
|
|
145
|
+
return fs.createReadStream(location)
|
|
146
|
+
}
|
|
127
147
|
}
|
|
128
148
|
async function load_quads(location, baseIRI) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
}
|
|
149
|
+
try {
|
|
150
|
+
LOG.util('Loading quads %s', location)
|
|
151
|
+
const parser = new n3.StreamParser({ baseIRI: baseIRI || location })
|
|
152
|
+
const rdfStream = await get_readstream(location)
|
|
153
|
+
rdfStream.pipe(parser)
|
|
154
|
+
const quads = await toArray(parser)
|
|
155
|
+
return quads
|
|
156
|
+
} catch (ex) {
|
|
157
|
+
console.error('Failed to load_quads', location, baseIRI)
|
|
158
|
+
console.error(ex)
|
|
159
|
+
return []
|
|
160
|
+
}
|
|
142
161
|
}
|
|
143
162
|
function load_memory_quads(value, baseIRI) {
|
|
144
|
-
|
|
145
|
-
|
|
163
|
+
const parser = new n3.Parser({ baseIRI })
|
|
164
|
+
return parser.parse(value)
|
|
146
165
|
}
|
|
147
|
-
const loaded = new Set()
|
|
166
|
+
const loaded = new Set()
|
|
148
167
|
async function load_store(location, store, recursive = true) {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
168
|
+
if (loaded.has(location)) return
|
|
169
|
+
loaded.add(location)
|
|
170
|
+
const quads =
|
|
171
|
+
location.type === 'remote'
|
|
172
|
+
? await load_quads(location.location)
|
|
173
|
+
: load_memory_quads(location.value, location.baseIRI)
|
|
174
|
+
store.addQuads(quads)
|
|
175
|
+
if (recursive) {
|
|
176
|
+
const loc =
|
|
177
|
+
location.type === 'remote' ? location.location : location.baseIRI
|
|
178
|
+
const other_imports = store.getObjects(
|
|
179
|
+
namedNode(loc),
|
|
180
|
+
OWL.terms.imports,
|
|
181
|
+
null,
|
|
182
|
+
)
|
|
183
|
+
for (const other of other_imports) {
|
|
184
|
+
await load_store({ location: other.value, type: 'remote' }, store, true)
|
|
162
185
|
}
|
|
186
|
+
}
|
|
163
187
|
}
|
|
164
188
|
|
|
165
189
|
async function getFileSize(path) {
|
|
166
|
-
|
|
190
|
+
return (await promises.stat(path)).size
|
|
167
191
|
}
|
|
168
192
|
function readPart(path, start, end, encoding) {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
193
|
+
return new Promise((res) => {
|
|
194
|
+
const stream = fs.createReadStream(path, { encoding, start, end })
|
|
195
|
+
let buffer = ''
|
|
196
|
+
stream.on('data', (chunk) => {
|
|
197
|
+
buffer += chunk
|
|
198
|
+
})
|
|
199
|
+
stream.on('close', () => res(buffer))
|
|
200
|
+
})
|
|
177
201
|
}
|
|
178
202
|
function debounce(func, timeout = 100) {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
203
|
+
let timer
|
|
204
|
+
return (...args) => {
|
|
205
|
+
clearTimeout(timer)
|
|
206
|
+
timer = setTimeout(() => {
|
|
207
|
+
func(...args)
|
|
208
|
+
}, timeout)
|
|
209
|
+
}
|
|
186
210
|
}
|
|
187
211
|
const startFileStreamReader = (config) => {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
content = await readPart(path$1, currentPos, newSize, encoding);
|
|
210
|
-
currentPos = newSize;
|
|
211
|
-
}
|
|
212
|
-
await reader.push(content);
|
|
213
|
-
}
|
|
214
|
-
catch (error) {
|
|
215
|
-
if (error.code === "ENOENT") {
|
|
216
|
-
return;
|
|
217
|
-
}
|
|
218
|
-
throw error;
|
|
212
|
+
const path$1 = path.isAbsolute(config.path)
|
|
213
|
+
? config.path
|
|
214
|
+
: `${process.cwd()}/${config.path}`
|
|
215
|
+
fs.openSync(path$1, 'a+')
|
|
216
|
+
const encoding = config.encoding || 'utf-8'
|
|
217
|
+
const reader = new SimpleStream()
|
|
218
|
+
const init = async () => {
|
|
219
|
+
let currentPos = await getFileSize(path$1)
|
|
220
|
+
const watcher = node_fs.watch(path$1, { encoding: 'utf-8' })
|
|
221
|
+
watcher.on(
|
|
222
|
+
'change',
|
|
223
|
+
debounce(async () => {
|
|
224
|
+
try {
|
|
225
|
+
let content
|
|
226
|
+
if (config.onReplace) {
|
|
227
|
+
content = await promises.readFile(path$1, { encoding })
|
|
228
|
+
} else {
|
|
229
|
+
const newSize = await getFileSize(path$1)
|
|
230
|
+
if (newSize <= currentPos) {
|
|
231
|
+
currentPos = newSize
|
|
232
|
+
return
|
|
219
233
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
234
|
+
content = await readPart(path$1, currentPos, newSize, encoding)
|
|
235
|
+
currentPos = newSize
|
|
236
|
+
}
|
|
237
|
+
await reader.push(content)
|
|
238
|
+
} catch (error) {
|
|
239
|
+
if (error.code === 'ENOENT') {
|
|
240
|
+
return
|
|
241
|
+
}
|
|
242
|
+
throw error
|
|
224
243
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
244
|
+
}),
|
|
245
|
+
)
|
|
246
|
+
if (config.onReplace && config.readFirstContent) {
|
|
247
|
+
const content = await promises.readFile(path$1, { encoding })
|
|
248
|
+
await reader.push(content)
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
return { reader, init }
|
|
252
|
+
}
|
|
228
253
|
const startFileStreamWriter = (config) => {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
};
|
|
254
|
+
const path$1 = path.isAbsolute(config.path)
|
|
255
|
+
? config.path
|
|
256
|
+
: `${process.cwd()}/${config.path}`
|
|
257
|
+
const encoding = config.encoding || 'utf-8'
|
|
258
|
+
const writer = new SimpleStream()
|
|
259
|
+
const init = async () => {
|
|
260
|
+
if (!config.onReplace) {
|
|
261
|
+
await promises.writeFile(path$1, '', { encoding })
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
writer.push = async (item) => {
|
|
265
|
+
if (config.onReplace) {
|
|
266
|
+
await promises.writeFile(path$1, item, { encoding })
|
|
267
|
+
} else {
|
|
268
|
+
await promises.appendFile(path$1, item, { encoding })
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return { writer, init }
|
|
272
|
+
}
|
|
249
273
|
|
|
250
274
|
function _connectWs(url, res) {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
275
|
+
const ws$1 = new ws.WebSocket(url, {})
|
|
276
|
+
ws$1.on('error', () => {
|
|
277
|
+
setTimeout(() => _connectWs(url, res), 300)
|
|
278
|
+
})
|
|
279
|
+
ws$1.on('ping', () => ws$1.pong())
|
|
280
|
+
ws$1.on('open', () => {
|
|
281
|
+
res(ws$1)
|
|
282
|
+
})
|
|
259
283
|
}
|
|
260
284
|
function connectWs(url) {
|
|
261
|
-
|
|
285
|
+
return new Promise((res) => _connectWs(url, res))
|
|
262
286
|
}
|
|
263
287
|
const startWsStreamReader = (config) => {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
}
|
|
288
|
+
const server = new ws.WebSocketServer(config)
|
|
289
|
+
server.on('error', (error) => {
|
|
290
|
+
console.error('Ws server error:')
|
|
291
|
+
console.error(error)
|
|
292
|
+
})
|
|
293
|
+
const connections = []
|
|
294
|
+
const interval = setInterval(() => {
|
|
295
|
+
connections.forEach((instance, i) => {
|
|
296
|
+
if (!instance) {
|
|
297
|
+
return
|
|
298
|
+
}
|
|
299
|
+
if (!instance.alive) {
|
|
300
|
+
instance.socket.terminate()
|
|
301
|
+
delete connections[i]
|
|
302
|
+
return
|
|
303
|
+
}
|
|
304
|
+
instance.socket.ping()
|
|
305
|
+
instance.alive = false
|
|
306
|
+
})
|
|
307
|
+
}, 30_000)
|
|
308
|
+
const reader = new SimpleStream(
|
|
309
|
+
() =>
|
|
310
|
+
new Promise((res) => {
|
|
311
|
+
clearInterval(interval)
|
|
312
|
+
server.close(() => res())
|
|
313
|
+
}),
|
|
314
|
+
)
|
|
315
|
+
server.on('connection', (ws) => {
|
|
316
|
+
const instance = { socket: ws, alive: true }
|
|
317
|
+
connections.push(instance)
|
|
318
|
+
ws.on('message', async (msg) => {
|
|
319
|
+
reader.push(msg.toString()).catch((error) => {
|
|
320
|
+
throw error
|
|
321
|
+
})
|
|
322
|
+
})
|
|
323
|
+
ws.on('pong', () => {
|
|
324
|
+
instance.alive = true
|
|
325
|
+
})
|
|
326
|
+
})
|
|
327
|
+
return { reader, init: async () => {} }
|
|
328
|
+
}
|
|
302
329
|
const startWsStreamWriter = (config) => {
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
}
|
|
330
|
+
let ws
|
|
331
|
+
const init = async () => {
|
|
332
|
+
ws = await connectWs(config.url)
|
|
333
|
+
ws.on('open', () => console.log('open'))
|
|
334
|
+
}
|
|
335
|
+
const writer = new SimpleStream(async () => {
|
|
336
|
+
ws.close()
|
|
337
|
+
})
|
|
338
|
+
writer.push = async (item) => {
|
|
339
|
+
ws.send(item)
|
|
340
|
+
}
|
|
341
|
+
return { writer, init }
|
|
342
|
+
}
|
|
316
343
|
|
|
317
344
|
const startKafkaStreamReader = (config) => {
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
}
|
|
345
|
+
const brokerConfig = {}
|
|
346
|
+
if (typeof config.broker === 'string' || config.broker instanceof String) {
|
|
347
|
+
Object.assign(
|
|
348
|
+
brokerConfig,
|
|
349
|
+
JSON.parse(node_fs.readFileSync(config.broker, 'utf-8')),
|
|
350
|
+
)
|
|
351
|
+
} else {
|
|
352
|
+
Object.assign(brokerConfig, config.broker)
|
|
353
|
+
}
|
|
354
|
+
if (brokerConfig && brokerConfig.hosts) {
|
|
355
|
+
brokerConfig.brokers = brokerConfig.hosts
|
|
356
|
+
}
|
|
357
|
+
const kafka = new kafkajs.Kafka(brokerConfig)
|
|
358
|
+
const consumer = kafka.consumer(config.consumer)
|
|
359
|
+
const stream = new SimpleStream(async () => {
|
|
360
|
+
await consumer.disconnect()
|
|
361
|
+
await consumer.stop()
|
|
362
|
+
})
|
|
363
|
+
const init = async () => {
|
|
364
|
+
await consumer.connect()
|
|
365
|
+
await consumer.subscribe({
|
|
366
|
+
topic: config.topic.name,
|
|
367
|
+
fromBeginning: config.topic.fromBeginning,
|
|
368
|
+
})
|
|
369
|
+
consumer
|
|
370
|
+
.run({
|
|
371
|
+
async eachMessage({ topic, message }) {
|
|
372
|
+
if (topic === config.topic.name) {
|
|
373
|
+
const element = message.value?.toString() ?? ''
|
|
374
|
+
stream.push(element).catch((error) => {
|
|
375
|
+
throw error
|
|
376
|
+
})
|
|
377
|
+
}
|
|
378
|
+
},
|
|
379
|
+
})
|
|
380
|
+
.catch((error) => {
|
|
381
|
+
throw error
|
|
382
|
+
})
|
|
383
|
+
}
|
|
384
|
+
return { reader: stream, init }
|
|
385
|
+
}
|
|
357
386
|
const startKafkaStreamWriter = (config) => {
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
}
|
|
387
|
+
const topic = config.topic.name
|
|
388
|
+
const brokerConfig = {}
|
|
389
|
+
if (typeof config.broker === 'string' || config.broker instanceof String) {
|
|
390
|
+
Object.assign(
|
|
391
|
+
brokerConfig,
|
|
392
|
+
JSON.parse(node_fs.readFileSync(config.broker, 'utf-8')),
|
|
393
|
+
)
|
|
394
|
+
} else {
|
|
395
|
+
Object.assign(brokerConfig, config.broker)
|
|
396
|
+
}
|
|
397
|
+
if (brokerConfig && brokerConfig.hosts) {
|
|
398
|
+
brokerConfig.brokers = brokerConfig.hosts
|
|
399
|
+
}
|
|
400
|
+
const kafka = new kafkajs.Kafka(brokerConfig)
|
|
401
|
+
const producer = kafka.producer(config.producer)
|
|
402
|
+
const writer = new SimpleStream(async () => {
|
|
403
|
+
await producer.disconnect()
|
|
404
|
+
})
|
|
405
|
+
const init = () => producer.connect()
|
|
406
|
+
writer.push = async (item) => {
|
|
407
|
+
await producer.send({ topic, messages: [{ value: item }] })
|
|
408
|
+
}
|
|
409
|
+
return { writer, init }
|
|
410
|
+
}
|
|
380
411
|
|
|
381
412
|
function streamToString(stream, binary) {
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
413
|
+
const datas = []
|
|
414
|
+
return new Promise((res) => {
|
|
415
|
+
stream.on('data', (data) => {
|
|
416
|
+
datas.push(data)
|
|
417
|
+
})
|
|
418
|
+
stream.on('end', () => {
|
|
419
|
+
const streamData = Buffer.concat(datas)
|
|
420
|
+
res(binary ? streamData : streamData.toString())
|
|
421
|
+
})
|
|
422
|
+
})
|
|
392
423
|
}
|
|
393
424
|
const startHttpStreamReader = (config) => {
|
|
394
|
-
|
|
395
|
-
|
|
425
|
+
let server = undefined
|
|
426
|
+
const stream = new SimpleStream(
|
|
427
|
+
() =>
|
|
428
|
+
new Promise((res) => {
|
|
396
429
|
if (server !== undefined) {
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
430
|
+
server.close(() => {
|
|
431
|
+
res()
|
|
432
|
+
})
|
|
433
|
+
} else {
|
|
434
|
+
res()
|
|
400
435
|
}
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
});
|
|
432
|
-
};
|
|
433
|
-
return { reader: stream, init };
|
|
434
|
-
};
|
|
436
|
+
}),
|
|
437
|
+
)
|
|
438
|
+
const requestListener = async function (req, res) {
|
|
439
|
+
try {
|
|
440
|
+
const content = await streamToString(req, config.binary)
|
|
441
|
+
const promise = stream.push(content).catch((error) => {
|
|
442
|
+
throw error
|
|
443
|
+
})
|
|
444
|
+
if (config.waitHandled) {
|
|
445
|
+
await promise
|
|
446
|
+
}
|
|
447
|
+
} catch (error) {
|
|
448
|
+
console.error('Failed', error)
|
|
449
|
+
}
|
|
450
|
+
res.writeHead(config.responseCode || 200)
|
|
451
|
+
res.end('OK')
|
|
452
|
+
}
|
|
453
|
+
server = http.createServer(requestListener)
|
|
454
|
+
const init = () => {
|
|
455
|
+
return new Promise((res) => {
|
|
456
|
+
const cb = () => res(undefined)
|
|
457
|
+
if (server) {
|
|
458
|
+
server.listen(config.port, config.endpoint, cb)
|
|
459
|
+
} else {
|
|
460
|
+
cb()
|
|
461
|
+
}
|
|
462
|
+
})
|
|
463
|
+
}
|
|
464
|
+
return { reader: stream, init }
|
|
465
|
+
}
|
|
435
466
|
const startHttpStreamWriter = (config) => {
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
}
|
|
467
|
+
const requestConfig = new URL(config.endpoint)
|
|
468
|
+
const writer = new SimpleStream()
|
|
469
|
+
writer.push = async (item) => {
|
|
470
|
+
await new Promise((resolve) => {
|
|
471
|
+
const options = {
|
|
472
|
+
hostname: requestConfig.hostname,
|
|
473
|
+
path: requestConfig.path,
|
|
474
|
+
method: config.method,
|
|
475
|
+
port: requestConfig.port,
|
|
476
|
+
}
|
|
477
|
+
const cb = (response) => {
|
|
478
|
+
response.on('data', () => {})
|
|
479
|
+
response.on('end', () => {
|
|
480
|
+
resolve(null)
|
|
481
|
+
})
|
|
482
|
+
}
|
|
483
|
+
const req = http__namespace.request(options, cb)
|
|
484
|
+
req.write(item, () => {
|
|
485
|
+
req.end()
|
|
486
|
+
})
|
|
487
|
+
})
|
|
488
|
+
}
|
|
489
|
+
return { writer, init: async () => {} }
|
|
490
|
+
}
|
|
460
491
|
|
|
461
|
-
const Conn = types.createTermNamespace(
|
|
462
|
-
|
|
492
|
+
const Conn = types.createTermNamespace(
|
|
493
|
+
'https://w3id.org/conn#',
|
|
494
|
+
'FileReaderChannel',
|
|
495
|
+
'FileWriterChannel',
|
|
496
|
+
'HttpReaderChannel',
|
|
497
|
+
'HttpWriterChannel',
|
|
498
|
+
'KafkaReaderChannel',
|
|
499
|
+
'KafkaWriterChannel',
|
|
500
|
+
'WsReaderChannel',
|
|
501
|
+
'WsWriterChannel',
|
|
502
|
+
'WriterChannel',
|
|
503
|
+
'ReaderChannel',
|
|
504
|
+
)
|
|
505
|
+
const JsOntology = types.createTermNamespace(
|
|
506
|
+
'https://w3id.org/conn/js#',
|
|
507
|
+
'JsProcess',
|
|
508
|
+
'JsChannel',
|
|
509
|
+
'JsReaderChannel',
|
|
510
|
+
'JsWriterChannel',
|
|
511
|
+
)
|
|
463
512
|
class ChannelFactory {
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
}
|
|
474
|
-
if (config.ty.equals(Conn.WsReaderChannel)) {
|
|
475
|
-
const { reader, init } = startWsStreamReader(config.config);
|
|
476
|
-
this.inits.push(init);
|
|
477
|
-
return reader;
|
|
478
|
-
}
|
|
479
|
-
if (config.ty.equals(Conn.KafkaReaderChannel)) {
|
|
480
|
-
const { reader, init } = startKafkaStreamReader(config.config);
|
|
481
|
-
this.inits.push(init);
|
|
482
|
-
return reader;
|
|
483
|
-
}
|
|
484
|
-
if (config.ty.equals(Conn.HttpReaderChannel)) {
|
|
485
|
-
const { reader, init } = startHttpStreamReader(config.config);
|
|
486
|
-
this.inits.push(init);
|
|
487
|
-
return reader;
|
|
488
|
-
}
|
|
489
|
-
if (config.ty.equals(JsOntology.JsReaderChannel)) {
|
|
490
|
-
const c = config.config;
|
|
491
|
-
if (c.channel) {
|
|
492
|
-
const id = c.channel.id.value;
|
|
493
|
-
if (c.channel.id.termType === "NamedNode") {
|
|
494
|
-
if (!this.jsChannelsNamedNodes[id]) {
|
|
495
|
-
this.jsChannelsNamedNodes[id] =
|
|
496
|
-
new SimpleStream();
|
|
497
|
-
}
|
|
498
|
-
return this.jsChannelsNamedNodes[id];
|
|
499
|
-
}
|
|
500
|
-
if (c.channel.id.termType === "BlankNode") {
|
|
501
|
-
if (!this.jsChannelsBlankNodes[id]) {
|
|
502
|
-
this.jsChannelsBlankNodes[id] =
|
|
503
|
-
new SimpleStream();
|
|
504
|
-
}
|
|
505
|
-
return this.jsChannelsBlankNodes[id];
|
|
506
|
-
}
|
|
507
|
-
throw "Should have found a thing";
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
throw "Unknown reader channel " + config.ty.value;
|
|
513
|
+
inits = []
|
|
514
|
+
jsChannelsNamedNodes = {}
|
|
515
|
+
jsChannelsBlankNodes = {}
|
|
516
|
+
createReader(config) {
|
|
517
|
+
LOG.channel('Creating reader %s: a %s', config.id.value, config.ty.value)
|
|
518
|
+
if (config.ty.equals(Conn.FileReaderChannel)) {
|
|
519
|
+
const { reader, init } = startFileStreamReader(config.config)
|
|
520
|
+
this.inits.push(init)
|
|
521
|
+
return reader
|
|
511
522
|
}
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
523
|
+
if (config.ty.equals(Conn.WsReaderChannel)) {
|
|
524
|
+
const { reader, init } = startWsStreamReader(config.config)
|
|
525
|
+
this.inits.push(init)
|
|
526
|
+
return reader
|
|
527
|
+
}
|
|
528
|
+
if (config.ty.equals(Conn.KafkaReaderChannel)) {
|
|
529
|
+
const { reader, init } = startKafkaStreamReader(config.config)
|
|
530
|
+
this.inits.push(init)
|
|
531
|
+
return reader
|
|
532
|
+
}
|
|
533
|
+
if (config.ty.equals(Conn.HttpReaderChannel)) {
|
|
534
|
+
const { reader, init } = startHttpStreamReader(config.config)
|
|
535
|
+
this.inits.push(init)
|
|
536
|
+
return reader
|
|
537
|
+
}
|
|
538
|
+
if (config.ty.equals(JsOntology.JsReaderChannel)) {
|
|
539
|
+
const c = config.config
|
|
540
|
+
if (c.channel) {
|
|
541
|
+
const id = c.channel.id.value
|
|
542
|
+
if (c.channel.id.termType === 'NamedNode') {
|
|
543
|
+
if (!this.jsChannelsNamedNodes[id]) {
|
|
544
|
+
this.jsChannelsNamedNodes[id] = new SimpleStream()
|
|
545
|
+
}
|
|
546
|
+
return this.jsChannelsNamedNodes[id]
|
|
533
547
|
}
|
|
534
|
-
if (
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
if (!this.jsChannelsNamedNodes[id]) {
|
|
540
|
-
this.jsChannelsNamedNodes[id] =
|
|
541
|
-
new SimpleStream();
|
|
542
|
-
}
|
|
543
|
-
return this.jsChannelsNamedNodes[id];
|
|
544
|
-
}
|
|
545
|
-
if (c.channel.id.termType === "BlankNode") {
|
|
546
|
-
if (!this.jsChannelsBlankNodes[id]) {
|
|
547
|
-
this.jsChannelsBlankNodes[id] =
|
|
548
|
-
new SimpleStream();
|
|
549
|
-
}
|
|
550
|
-
return this.jsChannelsBlankNodes[id];
|
|
551
|
-
}
|
|
552
|
-
throw "Should have found a thing";
|
|
553
|
-
}
|
|
548
|
+
if (c.channel.id.termType === 'BlankNode') {
|
|
549
|
+
if (!this.jsChannelsBlankNodes[id]) {
|
|
550
|
+
this.jsChannelsBlankNodes[id] = new SimpleStream()
|
|
551
|
+
}
|
|
552
|
+
return this.jsChannelsBlankNodes[id]
|
|
554
553
|
}
|
|
555
|
-
throw
|
|
554
|
+
throw 'Should have found a thing'
|
|
555
|
+
}
|
|
556
556
|
}
|
|
557
|
-
|
|
558
|
-
|
|
557
|
+
throw 'Unknown reader channel ' + config.ty.value
|
|
558
|
+
}
|
|
559
|
+
createWriter(config) {
|
|
560
|
+
LOG.channel('Creating writer %s: a %s', config.id.value, config.ty.value)
|
|
561
|
+
if (config.ty.equals(Conn.FileWriterChannel)) {
|
|
562
|
+
const { writer, init } = startFileStreamWriter(config.config)
|
|
563
|
+
this.inits.push(init)
|
|
564
|
+
return writer
|
|
559
565
|
}
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
disconnect;
|
|
565
|
-
lastElement;
|
|
566
|
-
ended = false;
|
|
567
|
-
constructor(onDisconnect) {
|
|
568
|
-
this.disconnect = onDisconnect || (async () => { });
|
|
566
|
+
if (config.ty.equals(Conn.WsWriterChannel)) {
|
|
567
|
+
const { writer, init } = startWsStreamWriter(config.config)
|
|
568
|
+
this.inits.push(init)
|
|
569
|
+
return writer
|
|
569
570
|
}
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
async push(data) {
|
|
575
|
-
if (this.ended) {
|
|
576
|
-
throw new Error("Trying to push to a stream that has ended!");
|
|
577
|
-
}
|
|
578
|
-
this.lastElement = data;
|
|
579
|
-
await Promise.all(this.dataHandlers.map((handler) => handler(data)));
|
|
571
|
+
if (config.ty.equals(Conn.KafkaWriterChannel)) {
|
|
572
|
+
const { writer, init } = startKafkaStreamWriter(config.config)
|
|
573
|
+
this.inits.push(init)
|
|
574
|
+
return writer
|
|
580
575
|
}
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
576
|
+
if (config.ty.equals(Conn.HttpWriterChannel)) {
|
|
577
|
+
const { writer, init } = startHttpStreamWriter(config.config)
|
|
578
|
+
this.inits.push(init)
|
|
579
|
+
return writer
|
|
585
580
|
}
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
581
|
+
if (config.ty.equals(JsOntology.JsWriterChannel)) {
|
|
582
|
+
const c = config.config
|
|
583
|
+
if (c.channel) {
|
|
584
|
+
const id = c.channel.id.value
|
|
585
|
+
if (c.channel.id.termType === 'NamedNode') {
|
|
586
|
+
if (!this.jsChannelsNamedNodes[id]) {
|
|
587
|
+
this.jsChannelsNamedNodes[id] = new SimpleStream()
|
|
588
|
+
}
|
|
589
|
+
return this.jsChannelsNamedNodes[id]
|
|
589
590
|
}
|
|
590
|
-
if (
|
|
591
|
-
|
|
591
|
+
if (c.channel.id.termType === 'BlankNode') {
|
|
592
|
+
if (!this.jsChannelsBlankNodes[id]) {
|
|
593
|
+
this.jsChannelsBlankNodes[id] = new SimpleStream()
|
|
594
|
+
}
|
|
595
|
+
return this.jsChannelsBlankNodes[id]
|
|
592
596
|
}
|
|
593
|
-
|
|
597
|
+
throw 'Should have found a thing'
|
|
598
|
+
}
|
|
594
599
|
}
|
|
600
|
+
throw 'Unknown writer channel ' + config.ty.value
|
|
601
|
+
}
|
|
602
|
+
async init() {
|
|
603
|
+
await Promise.all(this.inits.map((x) => x()))
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
class SimpleStream {
|
|
607
|
+
dataHandlers = []
|
|
608
|
+
endHandlers = []
|
|
609
|
+
disconnect
|
|
610
|
+
lastElement
|
|
611
|
+
ended = false
|
|
612
|
+
constructor(onDisconnect) {
|
|
613
|
+
this.disconnect = onDisconnect || (async () => {})
|
|
614
|
+
}
|
|
615
|
+
data(listener) {
|
|
616
|
+
this.dataHandlers.push(listener)
|
|
617
|
+
return this
|
|
618
|
+
}
|
|
619
|
+
async push(data) {
|
|
620
|
+
if (this.ended) {
|
|
621
|
+
throw new Error('Trying to push to a stream that has ended!')
|
|
622
|
+
}
|
|
623
|
+
this.lastElement = data
|
|
624
|
+
await Promise.all(this.dataHandlers.map((handler) => handler(data)))
|
|
625
|
+
}
|
|
626
|
+
async end() {
|
|
627
|
+
await this.disconnect()
|
|
628
|
+
await Promise.all(this.endHandlers.map((handler) => handler()))
|
|
629
|
+
this.ended = true
|
|
630
|
+
}
|
|
631
|
+
on(event, listener) {
|
|
632
|
+
if (event === 'data') {
|
|
633
|
+
this.dataHandlers.push(listener)
|
|
634
|
+
}
|
|
635
|
+
if (event === 'end') {
|
|
636
|
+
this.endHandlers.push(listener)
|
|
637
|
+
}
|
|
638
|
+
return this
|
|
639
|
+
}
|
|
595
640
|
}
|
|
596
641
|
|
|
597
642
|
function safeJoin(a, b) {
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
643
|
+
if (b.startsWith('/')) {
|
|
644
|
+
return b
|
|
645
|
+
}
|
|
646
|
+
return path.join(a, b)
|
|
602
647
|
}
|
|
603
648
|
async function extractProcessors(source, apply) {
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
.
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
649
|
+
const store = new n3.Store()
|
|
650
|
+
await load_store(source, store)
|
|
651
|
+
const quads = store.getQuads(null, null, null, null)
|
|
652
|
+
const config = rdfLens.extractShapes(quads, apply)
|
|
653
|
+
const subjects = quads
|
|
654
|
+
.filter(
|
|
655
|
+
(x) =>
|
|
656
|
+
x.predicate.equals(types.RDF.terms.type) &&
|
|
657
|
+
x.object.equals(JsOntology.JsProcess),
|
|
658
|
+
)
|
|
659
|
+
.map((x) => x.subject)
|
|
660
|
+
const processorLens = config.lenses[JsOntology.JsProcess.value]
|
|
661
|
+
const processors = subjects.map((id) => processorLens.execute({ id, quads }))
|
|
662
|
+
return { processors, quads, shapes: config }
|
|
615
663
|
}
|
|
616
664
|
function extractSteps(proc, quads, config) {
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
665
|
+
const out = []
|
|
666
|
+
const subjects = quads
|
|
667
|
+
.filter(
|
|
668
|
+
(x) =>
|
|
669
|
+
x.predicate.equals(types.RDF.terms.type) && x.object.equals(proc.ty),
|
|
670
|
+
)
|
|
671
|
+
.map((x) => x.subject)
|
|
672
|
+
const processorLens = config.lenses[proc.ty.value]
|
|
673
|
+
const fields = proc.mapping.parameters
|
|
674
|
+
for (const id of subjects) {
|
|
675
|
+
const obj = processorLens.execute({ id, quads })
|
|
676
|
+
const functionArgs = new Array(fields.length)
|
|
677
|
+
for (const field of fields) {
|
|
678
|
+
functionArgs[field.position] = obj[field.parameter]
|
|
630
679
|
}
|
|
631
|
-
|
|
680
|
+
out.push(functionArgs)
|
|
681
|
+
}
|
|
682
|
+
return out
|
|
632
683
|
}
|
|
633
684
|
async function jsRunner() {
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
685
|
+
const args = getArgs()
|
|
686
|
+
const cwd = process.cwd()
|
|
687
|
+
const source = {
|
|
688
|
+
location: safeJoin(cwd, args.input).replaceAll('\\', '/'),
|
|
689
|
+
type: 'remote',
|
|
690
|
+
}
|
|
691
|
+
const factory = new ChannelFactory()
|
|
692
|
+
const apply = {}
|
|
693
|
+
apply[Conn.ReaderChannel.value] = factory.createReader.bind(factory)
|
|
694
|
+
apply[Conn.WriterChannel.value] = factory.createWriter.bind(factory)
|
|
695
|
+
const {
|
|
696
|
+
processors,
|
|
697
|
+
quads,
|
|
698
|
+
shapes: config,
|
|
699
|
+
} = await extractProcessors(source, apply)
|
|
700
|
+
LOG.main('Found %d processors', processors.length)
|
|
701
|
+
const starts = []
|
|
702
|
+
for (const proc of processors) {
|
|
703
|
+
const argss = extractSteps(proc, quads, config)
|
|
704
|
+
const jsProgram = await import('file://' + proc.file)
|
|
705
|
+
process.chdir(proc.location)
|
|
706
|
+
for (const args of argss) {
|
|
707
|
+
starts.push(await jsProgram[proc.func](...args))
|
|
654
708
|
}
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
709
|
+
}
|
|
710
|
+
await factory.init()
|
|
711
|
+
for (const s of starts) {
|
|
712
|
+
if (s && typeof s === 'function') {
|
|
713
|
+
s()
|
|
660
714
|
}
|
|
715
|
+
}
|
|
661
716
|
}
|
|
662
717
|
|
|
663
|
-
exports.ChannelFactory = ChannelFactory
|
|
664
|
-
exports.Conn = Conn
|
|
665
|
-
exports.JsOntology = JsOntology
|
|
666
|
-
exports.SimpleStream = SimpleStream
|
|
667
|
-
exports.extractProcessors = extractProcessors
|
|
668
|
-
exports.extractSteps = extractSteps
|
|
669
|
-
exports.jsRunner = jsRunner
|
|
670
|
-
exports.startFileStreamReader = startFileStreamReader
|
|
671
|
-
exports.startFileStreamWriter = startFileStreamWriter
|
|
672
|
-
exports.startHttpStreamReader = startHttpStreamReader
|
|
673
|
-
exports.startHttpStreamWriter = startHttpStreamWriter
|
|
674
|
-
exports.startKafkaStreamReader = startKafkaStreamReader
|
|
675
|
-
exports.startKafkaStreamWriter = startKafkaStreamWriter
|
|
676
|
-
exports.startWsStreamReader = startWsStreamReader
|
|
677
|
-
exports.startWsStreamWriter = startWsStreamWriter
|
|
718
|
+
exports.ChannelFactory = ChannelFactory
|
|
719
|
+
exports.Conn = Conn
|
|
720
|
+
exports.JsOntology = JsOntology
|
|
721
|
+
exports.SimpleStream = SimpleStream
|
|
722
|
+
exports.extractProcessors = extractProcessors
|
|
723
|
+
exports.extractSteps = extractSteps
|
|
724
|
+
exports.jsRunner = jsRunner
|
|
725
|
+
exports.startFileStreamReader = startFileStreamReader
|
|
726
|
+
exports.startFileStreamWriter = startFileStreamWriter
|
|
727
|
+
exports.startHttpStreamReader = startHttpStreamReader
|
|
728
|
+
exports.startHttpStreamWriter = startHttpStreamWriter
|
|
729
|
+
exports.startKafkaStreamReader = startKafkaStreamReader
|
|
730
|
+
exports.startKafkaStreamWriter = startKafkaStreamWriter
|
|
731
|
+
exports.startWsStreamReader = startWsStreamReader
|
|
732
|
+
exports.startWsStreamWriter = startWsStreamWriter
|