@rdfc/js-runner 0.2.0 → 0.2.2
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/README.md +10 -12
- package/bin/bundle.mjs +32933 -0
- package/dist/args.d.ts +4 -0
- package/dist/args.js +47 -0
- package/dist/connectors/file.d.ts +15 -0
- package/dist/connectors/file.js +89 -0
- package/dist/connectors/http.d.ts +14 -0
- package/dist/connectors/http.js +81 -0
- package/dist/connectors/kafka.d.ts +48 -0
- package/dist/connectors/kafka.js +66 -0
- package/dist/connectors/ws.d.ts +10 -0
- package/dist/connectors/ws.js +69 -0
- package/dist/connectors.d.ts +52 -0
- package/dist/connectors.js +136 -0
- package/dist/index.cjs +655 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +73 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/util.d.ts +43 -0
- package/dist/util.js +75 -0
- package/package.json +24 -23
package/dist/args.d.ts
ADDED
package/dist/args.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import commandLineArgs from "command-line-args";
|
|
2
|
+
import commandLineUsage from "command-line-usage";
|
|
3
|
+
const optionDefinitions = [
|
|
4
|
+
{ name: 'input', type: String, defaultOption: true, summary: "Specify what input file to start up" },
|
|
5
|
+
{ name: 'help', alias: 'h', type: Boolean, description: "Display this help message" },
|
|
6
|
+
];
|
|
7
|
+
const sections = [
|
|
8
|
+
{
|
|
9
|
+
header: "Js-runner",
|
|
10
|
+
content: "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!"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
header: "Synopsis",
|
|
14
|
+
content: "$ js-runner <input>"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
header: "Command List",
|
|
18
|
+
content: [{ name: "input", summary: "Specify what input file to start up" }],
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
optionList: [optionDefinitions[1]]
|
|
22
|
+
}
|
|
23
|
+
];
|
|
24
|
+
function validArgs(args) {
|
|
25
|
+
if (!args.input)
|
|
26
|
+
return false;
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
function printUsage() {
|
|
30
|
+
const usage = commandLineUsage(sections);
|
|
31
|
+
console.log(usage);
|
|
32
|
+
process.exit(0);
|
|
33
|
+
}
|
|
34
|
+
export function getArgs() {
|
|
35
|
+
let args;
|
|
36
|
+
try {
|
|
37
|
+
args = commandLineArgs(optionDefinitions);
|
|
38
|
+
}
|
|
39
|
+
catch (e) {
|
|
40
|
+
console.error(e);
|
|
41
|
+
printUsage();
|
|
42
|
+
}
|
|
43
|
+
if (args.help || !validArgs(args)) {
|
|
44
|
+
printUsage();
|
|
45
|
+
}
|
|
46
|
+
return args;
|
|
47
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ReaderConstructor, WriterConstructor } from "../connectors.js";
|
|
2
|
+
export interface FileReaderConfig {
|
|
3
|
+
path: string;
|
|
4
|
+
onReplace: boolean;
|
|
5
|
+
readFirstContent?: boolean;
|
|
6
|
+
encoding?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface FileWriterConfig {
|
|
9
|
+
path: string;
|
|
10
|
+
onReplace: boolean;
|
|
11
|
+
readFirstContent?: boolean;
|
|
12
|
+
encoding?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare const startFileStreamReader: ReaderConstructor<FileReaderConfig>;
|
|
15
|
+
export declare const startFileStreamWriter: WriterConstructor<FileWriterConfig>;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { createReadStream, openSync } from "fs";
|
|
2
|
+
import { appendFile, readFile, stat, writeFile } from "fs/promises";
|
|
3
|
+
import { isAbsolute } from "path";
|
|
4
|
+
import { watch } from "node:fs";
|
|
5
|
+
import { SimpleStream, } from "../connectors.js";
|
|
6
|
+
async function getFileSize(path) {
|
|
7
|
+
return (await stat(path)).size;
|
|
8
|
+
}
|
|
9
|
+
function readPart(path, start, end, encoding) {
|
|
10
|
+
return new Promise((res) => {
|
|
11
|
+
const stream = createReadStream(path, { encoding, start, end });
|
|
12
|
+
let buffer = "";
|
|
13
|
+
stream.on("data", (chunk) => {
|
|
14
|
+
buffer += chunk;
|
|
15
|
+
});
|
|
16
|
+
stream.on("close", () => res(buffer));
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
function debounce(func, timeout = 100) {
|
|
20
|
+
let timer;
|
|
21
|
+
return (...args) => {
|
|
22
|
+
clearTimeout(timer);
|
|
23
|
+
timer = setTimeout(() => {
|
|
24
|
+
func(...args);
|
|
25
|
+
}, timeout);
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export const startFileStreamReader = (config) => {
|
|
29
|
+
const path = isAbsolute(config.path)
|
|
30
|
+
? config.path
|
|
31
|
+
: `${process.cwd()}/${config.path}`;
|
|
32
|
+
openSync(path, "a+");
|
|
33
|
+
const encoding = config.encoding || "utf-8";
|
|
34
|
+
const reader = new SimpleStream();
|
|
35
|
+
const init = async () => {
|
|
36
|
+
let currentPos = await getFileSize(path);
|
|
37
|
+
const watcher = watch(path, { encoding: "utf-8" });
|
|
38
|
+
watcher.on("change", debounce(async () => {
|
|
39
|
+
try {
|
|
40
|
+
let content;
|
|
41
|
+
if (config.onReplace) {
|
|
42
|
+
content = await readFile(path, { encoding });
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
const newSize = await getFileSize(path);
|
|
46
|
+
if (newSize <= currentPos) {
|
|
47
|
+
currentPos = newSize;
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
content = await readPart(path, currentPos, newSize, encoding);
|
|
51
|
+
currentPos = newSize;
|
|
52
|
+
}
|
|
53
|
+
await reader.push(content);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
if (error.code === "ENOENT") {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
}));
|
|
62
|
+
if (config.onReplace && config.readFirstContent) {
|
|
63
|
+
const content = await readFile(path, { encoding });
|
|
64
|
+
await reader.push(content);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
return { reader, init };
|
|
68
|
+
};
|
|
69
|
+
export const startFileStreamWriter = (config) => {
|
|
70
|
+
const path = isAbsolute(config.path)
|
|
71
|
+
? config.path
|
|
72
|
+
: `${process.cwd()}/${config.path}`;
|
|
73
|
+
const encoding = config.encoding || "utf-8";
|
|
74
|
+
const init = async () => {
|
|
75
|
+
if (!config.onReplace) {
|
|
76
|
+
await writeFile(path, "", { encoding });
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
const push = async (item) => {
|
|
80
|
+
if (config.onReplace) {
|
|
81
|
+
await writeFile(path, item, { encoding });
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
await appendFile(path, item, { encoding });
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
const end = async () => { };
|
|
88
|
+
return { writer: { push, end }, init };
|
|
89
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ReaderConstructor, WriterConstructor } from "../connectors.js";
|
|
2
|
+
export interface HttpReaderConfig {
|
|
3
|
+
endpoint: string;
|
|
4
|
+
port: number;
|
|
5
|
+
binary: boolean;
|
|
6
|
+
waitHandled?: boolean;
|
|
7
|
+
responseCode?: number;
|
|
8
|
+
}
|
|
9
|
+
export declare const startHttpStreamReader: ReaderConstructor<HttpReaderConfig>;
|
|
10
|
+
export interface HttpWriterConfig {
|
|
11
|
+
endpoint: string;
|
|
12
|
+
method: string;
|
|
13
|
+
}
|
|
14
|
+
export declare const startHttpStreamWriter: WriterConstructor<HttpWriterConfig>;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import * as http from "http";
|
|
2
|
+
import { createServer } from "http";
|
|
3
|
+
import { SimpleStream, } from "../connectors.js";
|
|
4
|
+
function streamToString(stream, binary) {
|
|
5
|
+
const datas = [];
|
|
6
|
+
return new Promise((res) => {
|
|
7
|
+
stream.on("data", (data) => {
|
|
8
|
+
datas.push(data);
|
|
9
|
+
});
|
|
10
|
+
stream.on("end", () => {
|
|
11
|
+
const streamData = Buffer.concat(datas);
|
|
12
|
+
res(binary ? streamData : streamData.toString());
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
export const startHttpStreamReader = (config) => {
|
|
17
|
+
let server;
|
|
18
|
+
const stream = new SimpleStream(() => new Promise((res) => {
|
|
19
|
+
if (server !== undefined) {
|
|
20
|
+
server.close(() => {
|
|
21
|
+
res();
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
res();
|
|
26
|
+
}
|
|
27
|
+
}));
|
|
28
|
+
const requestListener = async function (req, res) {
|
|
29
|
+
try {
|
|
30
|
+
const content = await streamToString(req, config.binary);
|
|
31
|
+
const promise = stream.push(content).catch((error) => {
|
|
32
|
+
throw error;
|
|
33
|
+
});
|
|
34
|
+
if (config.waitHandled) {
|
|
35
|
+
await promise;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
console.error("Failed", error);
|
|
40
|
+
}
|
|
41
|
+
res.writeHead(config.responseCode || 200);
|
|
42
|
+
res.end("OK");
|
|
43
|
+
};
|
|
44
|
+
server = createServer(requestListener);
|
|
45
|
+
const init = () => {
|
|
46
|
+
return new Promise((res) => {
|
|
47
|
+
const cb = () => res(undefined);
|
|
48
|
+
if (server) {
|
|
49
|
+
server.listen(config.port, config.endpoint, cb);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
cb();
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
return { reader: stream, init };
|
|
57
|
+
};
|
|
58
|
+
export const startHttpStreamWriter = (config) => {
|
|
59
|
+
const requestConfig = new URL(config.endpoint);
|
|
60
|
+
const push = async (item) => {
|
|
61
|
+
await new Promise(async (resolve) => {
|
|
62
|
+
const options = {
|
|
63
|
+
hostname: requestConfig.hostname,
|
|
64
|
+
path: requestConfig.path,
|
|
65
|
+
method: config.method,
|
|
66
|
+
port: requestConfig.port,
|
|
67
|
+
};
|
|
68
|
+
const cb = (response) => {
|
|
69
|
+
response.on("data", () => { });
|
|
70
|
+
response.on("end", () => {
|
|
71
|
+
resolve(null);
|
|
72
|
+
});
|
|
73
|
+
};
|
|
74
|
+
const req = http.request(options, cb);
|
|
75
|
+
await new Promise((res) => req.write(item, res));
|
|
76
|
+
await new Promise((res) => req.end(res));
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
const end = async () => { };
|
|
80
|
+
return { writer: { push, end }, init: async () => { } };
|
|
81
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { ProducerConfig } from "kafkajs";
|
|
2
|
+
import { ReaderConstructor, WriterConstructor } from "../connectors.js";
|
|
3
|
+
export interface SASLOptions {
|
|
4
|
+
mechanism: "plain";
|
|
5
|
+
username: string;
|
|
6
|
+
password: string;
|
|
7
|
+
}
|
|
8
|
+
export interface BrokerConfig {
|
|
9
|
+
hosts: string[];
|
|
10
|
+
ssl?: boolean;
|
|
11
|
+
sasl?: SASLOptions;
|
|
12
|
+
}
|
|
13
|
+
export interface ConsumerConfig {
|
|
14
|
+
groupId: string;
|
|
15
|
+
metadataMaxAge?: number;
|
|
16
|
+
sessionTimeout?: number;
|
|
17
|
+
rebalanceTimeout?: number;
|
|
18
|
+
heartbeatInterval?: number;
|
|
19
|
+
maxBytesPerPartition?: number;
|
|
20
|
+
minBytes?: number;
|
|
21
|
+
maxBytes?: number;
|
|
22
|
+
maxWaitTimeInMs?: number;
|
|
23
|
+
allowAutoTopicCreation?: boolean;
|
|
24
|
+
maxInFlightRequests?: number;
|
|
25
|
+
readUncommitted?: boolean;
|
|
26
|
+
rackId?: string;
|
|
27
|
+
}
|
|
28
|
+
export interface CSTopic {
|
|
29
|
+
topic: string;
|
|
30
|
+
fromBeginning?: boolean;
|
|
31
|
+
}
|
|
32
|
+
export interface KafkaReaderConfig {
|
|
33
|
+
topic: {
|
|
34
|
+
name: string;
|
|
35
|
+
fromBeginning?: boolean;
|
|
36
|
+
};
|
|
37
|
+
consumer: ConsumerConfig;
|
|
38
|
+
broker: string | BrokerConfig;
|
|
39
|
+
}
|
|
40
|
+
export declare const startKafkaStreamReader: ReaderConstructor<KafkaReaderConfig>;
|
|
41
|
+
export interface KafkaWriterConfig {
|
|
42
|
+
topic: {
|
|
43
|
+
name: string;
|
|
44
|
+
};
|
|
45
|
+
producer: ProducerConfig;
|
|
46
|
+
broker: BrokerConfig | string;
|
|
47
|
+
}
|
|
48
|
+
export declare const startKafkaStreamWriter: WriterConstructor<KafkaWriterConfig>;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { Kafka } from "kafkajs";
|
|
3
|
+
import { SimpleStream, } from "../connectors.js";
|
|
4
|
+
export const startKafkaStreamReader = (config) => {
|
|
5
|
+
const brokerConfig = {};
|
|
6
|
+
if (typeof config.broker === "string" || config.broker instanceof String) {
|
|
7
|
+
Object.assign(brokerConfig, JSON.parse(readFileSync(config.broker, "utf-8")));
|
|
8
|
+
}
|
|
9
|
+
else {
|
|
10
|
+
Object.assign(brokerConfig, config.broker);
|
|
11
|
+
}
|
|
12
|
+
if (brokerConfig && brokerConfig.hosts) {
|
|
13
|
+
brokerConfig.brokers = brokerConfig.hosts;
|
|
14
|
+
}
|
|
15
|
+
const kafka = new Kafka(brokerConfig);
|
|
16
|
+
const consumer = kafka.consumer(config.consumer);
|
|
17
|
+
const stream = new SimpleStream(async () => {
|
|
18
|
+
await consumer.disconnect();
|
|
19
|
+
await consumer.stop();
|
|
20
|
+
});
|
|
21
|
+
const init = async () => {
|
|
22
|
+
await consumer.connect();
|
|
23
|
+
await consumer.subscribe({
|
|
24
|
+
topic: config.topic.name,
|
|
25
|
+
fromBeginning: config.topic.fromBeginning,
|
|
26
|
+
});
|
|
27
|
+
consumer
|
|
28
|
+
.run({
|
|
29
|
+
async eachMessage({ topic, message, }) {
|
|
30
|
+
if (topic === config.topic.name) {
|
|
31
|
+
const element = message.value?.toString() ?? "";
|
|
32
|
+
stream.push(element).catch((error) => {
|
|
33
|
+
throw error;
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
})
|
|
38
|
+
.catch((error) => {
|
|
39
|
+
throw error;
|
|
40
|
+
});
|
|
41
|
+
};
|
|
42
|
+
return { reader: stream, init };
|
|
43
|
+
};
|
|
44
|
+
export const startKafkaStreamWriter = (config) => {
|
|
45
|
+
const topic = config.topic.name;
|
|
46
|
+
const brokerConfig = {};
|
|
47
|
+
if (typeof config.broker === "string" || config.broker instanceof String) {
|
|
48
|
+
Object.assign(brokerConfig, JSON.parse(readFileSync(config.broker, "utf-8")));
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
Object.assign(brokerConfig, config.broker);
|
|
52
|
+
}
|
|
53
|
+
if (brokerConfig && brokerConfig.hosts) {
|
|
54
|
+
brokerConfig.brokers = brokerConfig.hosts;
|
|
55
|
+
}
|
|
56
|
+
const kafka = new Kafka(brokerConfig);
|
|
57
|
+
const producer = kafka.producer(config.producer);
|
|
58
|
+
const init = () => producer.connect();
|
|
59
|
+
const push = async (item) => {
|
|
60
|
+
await producer.send({ topic, messages: [{ value: item }] });
|
|
61
|
+
};
|
|
62
|
+
const end = async () => {
|
|
63
|
+
await producer.disconnect();
|
|
64
|
+
};
|
|
65
|
+
return { writer: { push, end }, init };
|
|
66
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ReaderConstructor, WriterConstructor } from "../connectors.js";
|
|
2
|
+
export interface WsWriterConfig {
|
|
3
|
+
url: string;
|
|
4
|
+
}
|
|
5
|
+
export interface WsReaderConfig {
|
|
6
|
+
host: string;
|
|
7
|
+
port: number;
|
|
8
|
+
}
|
|
9
|
+
export declare const startWsStreamReader: ReaderConstructor<WsReaderConfig>;
|
|
10
|
+
export declare const startWsStreamWriter: WriterConstructor<WsWriterConfig>;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { SimpleStream, } from "../connectors.js";
|
|
2
|
+
import { WebSocket } from "ws";
|
|
3
|
+
import { WebSocketServer } from "ws";
|
|
4
|
+
function _connectWs(url, res) {
|
|
5
|
+
const ws = new WebSocket(url, {});
|
|
6
|
+
ws.on("error", () => {
|
|
7
|
+
setTimeout(() => _connectWs(url, res), 300);
|
|
8
|
+
});
|
|
9
|
+
ws.on("ping", () => ws.pong());
|
|
10
|
+
ws.on("open", () => {
|
|
11
|
+
res(ws);
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
function connectWs(url) {
|
|
15
|
+
return new Promise((res) => _connectWs(url, res));
|
|
16
|
+
}
|
|
17
|
+
export const startWsStreamReader = (config) => {
|
|
18
|
+
const server = new WebSocketServer(config);
|
|
19
|
+
server.on("error", (error) => {
|
|
20
|
+
console.error("Ws server error:");
|
|
21
|
+
console.error(error);
|
|
22
|
+
});
|
|
23
|
+
const connections = [];
|
|
24
|
+
const interval = setInterval(() => {
|
|
25
|
+
connections.forEach((instance, i) => {
|
|
26
|
+
if (!instance) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
if (!instance.alive) {
|
|
30
|
+
instance.socket.terminate();
|
|
31
|
+
delete connections[i];
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
instance.socket.ping();
|
|
35
|
+
instance.alive = false;
|
|
36
|
+
});
|
|
37
|
+
}, 30_000);
|
|
38
|
+
const reader = new SimpleStream(() => new Promise((res) => {
|
|
39
|
+
clearInterval(interval);
|
|
40
|
+
server.close(() => res());
|
|
41
|
+
}));
|
|
42
|
+
server.on("connection", (ws) => {
|
|
43
|
+
const instance = { socket: ws, alive: true };
|
|
44
|
+
connections.push(instance);
|
|
45
|
+
ws.on("message", async (msg) => {
|
|
46
|
+
reader.push(msg.toString()).catch((error) => {
|
|
47
|
+
throw error;
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
ws.on("pong", () => {
|
|
51
|
+
instance.alive = true;
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
return { reader, init: async () => { } };
|
|
55
|
+
};
|
|
56
|
+
export const startWsStreamWriter = (config) => {
|
|
57
|
+
let ws;
|
|
58
|
+
const init = async () => {
|
|
59
|
+
ws = await connectWs(config.url);
|
|
60
|
+
ws.on("open", () => console.log("open"));
|
|
61
|
+
};
|
|
62
|
+
const push = async (item) => {
|
|
63
|
+
ws.send(item);
|
|
64
|
+
};
|
|
65
|
+
const end = async () => {
|
|
66
|
+
ws.close();
|
|
67
|
+
};
|
|
68
|
+
return { writer: { push, end }, init };
|
|
69
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { NamedNode, Term } from "@rdfjs/types";
|
|
2
|
+
export * from "./connectors/file.js";
|
|
3
|
+
export * from "./connectors/ws.js";
|
|
4
|
+
export * from "./connectors/kafka.js";
|
|
5
|
+
export * from "./connectors/http.js";
|
|
6
|
+
export declare const Conn: import("@treecg/types").Namespace<("FileReaderChannel" | "FileWriterChannel" | "HttpReaderChannel" | "HttpWriterChannel" | "KafkaReaderChannel" | "KafkaWriterChannel" | "WsReaderChannel" | "WsWriterChannel" | "WriterChannel" | "ReaderChannel")[], NamedNode<string>, string>;
|
|
7
|
+
export interface Config<T> {
|
|
8
|
+
id: Term;
|
|
9
|
+
ty: NamedNode;
|
|
10
|
+
config: T;
|
|
11
|
+
}
|
|
12
|
+
export type ReaderConstructor<C> = (config: C) => {
|
|
13
|
+
reader: Stream<string | Buffer>;
|
|
14
|
+
init: () => Promise<void>;
|
|
15
|
+
};
|
|
16
|
+
export type WriterConstructor<C> = (config: C) => {
|
|
17
|
+
writer: Writer<string | Buffer>;
|
|
18
|
+
init: () => Promise<void>;
|
|
19
|
+
};
|
|
20
|
+
export declare const JsOntology: import("@treecg/types").Namespace<("JsProcess" | "JsChannel" | "JsReaderChannel" | "JsWriterChannel")[], NamedNode<string>, string>;
|
|
21
|
+
export declare class ChannelFactory {
|
|
22
|
+
private inits;
|
|
23
|
+
private jsChannelsNamedNodes;
|
|
24
|
+
private jsChannelsBlankNodes;
|
|
25
|
+
createReader(config: Config<any>): Stream<string | Buffer>;
|
|
26
|
+
createWriter(config: Config<any>): Writer<string | Buffer>;
|
|
27
|
+
init(): Promise<void>;
|
|
28
|
+
}
|
|
29
|
+
export interface Writer<T> {
|
|
30
|
+
push(item: T): Promise<void>;
|
|
31
|
+
end(): Promise<void>;
|
|
32
|
+
}
|
|
33
|
+
export interface Stream<T> {
|
|
34
|
+
lastElement?: T;
|
|
35
|
+
end(): Promise<void>;
|
|
36
|
+
data(listener: (t: T) => PromiseLike<void> | void): this;
|
|
37
|
+
on(event: "data", listener: (t: T) => PromiseLike<void> | void): this;
|
|
38
|
+
on(event: "end", listener: () => PromiseLike<void> | void): this;
|
|
39
|
+
}
|
|
40
|
+
export type Handler<T> = (item: T) => Promise<void> | void;
|
|
41
|
+
export declare class SimpleStream<T> implements Stream<T> {
|
|
42
|
+
private readonly dataHandlers;
|
|
43
|
+
private readonly endHandlers;
|
|
44
|
+
readonly disconnect: () => Promise<void>;
|
|
45
|
+
lastElement?: T | undefined;
|
|
46
|
+
constructor(onDisconnect?: () => Promise<void>);
|
|
47
|
+
data(listener: Handler<T>): this;
|
|
48
|
+
push(data: T): Promise<void>;
|
|
49
|
+
end(): Promise<void>;
|
|
50
|
+
on(event: "data", listener: Handler<T>): this;
|
|
51
|
+
on(event: "end", listener: Handler<void>): this;
|
|
52
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { createTermNamespace } from "@treecg/types";
|
|
2
|
+
import { startFileStreamReader, startFileStreamWriter, } from "./connectors/file.js";
|
|
3
|
+
export * from "./connectors/file.js";
|
|
4
|
+
import { startWsStreamReader, startWsStreamWriter, } from "./connectors/ws.js";
|
|
5
|
+
export * from "./connectors/ws.js";
|
|
6
|
+
import { startKafkaStreamReader, startKafkaStreamWriter, } from "./connectors/kafka.js";
|
|
7
|
+
export * from "./connectors/kafka.js";
|
|
8
|
+
import { startHttpStreamReader, startHttpStreamWriter, } from "./connectors/http.js";
|
|
9
|
+
import { LOG } from "./util.js";
|
|
10
|
+
export * from "./connectors/http.js";
|
|
11
|
+
export const Conn = createTermNamespace("https://w3id.org/conn#", "FileReaderChannel", "FileWriterChannel", "HttpReaderChannel", "HttpWriterChannel", "KafkaReaderChannel", "KafkaWriterChannel", "WsReaderChannel", "WsWriterChannel", "WriterChannel", "ReaderChannel");
|
|
12
|
+
export const JsOntology = createTermNamespace("https://w3id.org/conn/js#", "JsProcess", "JsChannel", "JsReaderChannel", "JsWriterChannel");
|
|
13
|
+
export class ChannelFactory {
|
|
14
|
+
inits = [];
|
|
15
|
+
jsChannelsNamedNodes = {};
|
|
16
|
+
jsChannelsBlankNodes = {};
|
|
17
|
+
createReader(config) {
|
|
18
|
+
LOG.channel("Creating reader %s: a %s", config.id.value, config.ty.value);
|
|
19
|
+
if (config.ty.equals(Conn.FileReaderChannel)) {
|
|
20
|
+
const { reader, init } = startFileStreamReader(config.config);
|
|
21
|
+
this.inits.push(init);
|
|
22
|
+
return reader;
|
|
23
|
+
}
|
|
24
|
+
if (config.ty.equals(Conn.WsReaderChannel)) {
|
|
25
|
+
const { reader, init } = startWsStreamReader(config.config);
|
|
26
|
+
this.inits.push(init);
|
|
27
|
+
return reader;
|
|
28
|
+
}
|
|
29
|
+
if (config.ty.equals(Conn.KafkaReaderChannel)) {
|
|
30
|
+
const { reader, init } = startKafkaStreamReader(config.config);
|
|
31
|
+
this.inits.push(init);
|
|
32
|
+
return reader;
|
|
33
|
+
}
|
|
34
|
+
if (config.ty.equals(Conn.HttpReaderChannel)) {
|
|
35
|
+
const { reader, init } = startHttpStreamReader(config.config);
|
|
36
|
+
this.inits.push(init);
|
|
37
|
+
return reader;
|
|
38
|
+
}
|
|
39
|
+
if (config.ty.equals(JsOntology.JsReaderChannel)) {
|
|
40
|
+
const c = config.config;
|
|
41
|
+
if (c.channel) {
|
|
42
|
+
const id = c.channel.id.value;
|
|
43
|
+
if (c.channel.id.termType === "NamedNode") {
|
|
44
|
+
if (!this.jsChannelsNamedNodes[id]) {
|
|
45
|
+
this.jsChannelsNamedNodes[id] = new SimpleStream();
|
|
46
|
+
}
|
|
47
|
+
return this.jsChannelsNamedNodes[id];
|
|
48
|
+
}
|
|
49
|
+
if (c.channel.id.termType === "BlankNode") {
|
|
50
|
+
if (!this.jsChannelsBlankNodes[id]) {
|
|
51
|
+
this.jsChannelsBlankNodes[id] = new SimpleStream();
|
|
52
|
+
}
|
|
53
|
+
return this.jsChannelsBlankNodes[id];
|
|
54
|
+
}
|
|
55
|
+
throw "Should have found a thing";
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
throw "Unknown reader channel " + config.ty.value;
|
|
59
|
+
}
|
|
60
|
+
createWriter(config) {
|
|
61
|
+
LOG.channel("Creating writer %s: a %s", config.id.value, config.ty.value);
|
|
62
|
+
if (config.ty.equals(Conn.FileWriterChannel)) {
|
|
63
|
+
const { writer, init } = startFileStreamWriter(config.config);
|
|
64
|
+
this.inits.push(init);
|
|
65
|
+
return writer;
|
|
66
|
+
}
|
|
67
|
+
if (config.ty.equals(Conn.WsWriterChannel)) {
|
|
68
|
+
const { writer, init } = startWsStreamWriter(config.config);
|
|
69
|
+
this.inits.push(init);
|
|
70
|
+
return writer;
|
|
71
|
+
}
|
|
72
|
+
if (config.ty.equals(Conn.KafkaWriterChannel)) {
|
|
73
|
+
const { writer, init } = startKafkaStreamWriter(config.config);
|
|
74
|
+
this.inits.push(init);
|
|
75
|
+
return writer;
|
|
76
|
+
}
|
|
77
|
+
if (config.ty.equals(Conn.HttpWriterChannel)) {
|
|
78
|
+
const { writer, init } = startHttpStreamWriter(config.config);
|
|
79
|
+
this.inits.push(init);
|
|
80
|
+
return writer;
|
|
81
|
+
}
|
|
82
|
+
if (config.ty.equals(JsOntology.JsWriterChannel)) {
|
|
83
|
+
const c = config.config;
|
|
84
|
+
if (c.channel) {
|
|
85
|
+
const id = c.channel.id.value;
|
|
86
|
+
if (c.channel.id.termType === "NamedNode") {
|
|
87
|
+
if (!this.jsChannelsNamedNodes[id]) {
|
|
88
|
+
this.jsChannelsNamedNodes[id] = new SimpleStream();
|
|
89
|
+
}
|
|
90
|
+
return this.jsChannelsNamedNodes[id];
|
|
91
|
+
}
|
|
92
|
+
if (c.channel.id.termType === "BlankNode") {
|
|
93
|
+
if (!this.jsChannelsBlankNodes[id]) {
|
|
94
|
+
this.jsChannelsBlankNodes[id] = new SimpleStream();
|
|
95
|
+
}
|
|
96
|
+
return this.jsChannelsBlankNodes[id];
|
|
97
|
+
}
|
|
98
|
+
throw "Should have found a thing";
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
throw "Unknown writer channel " + config.ty.value;
|
|
102
|
+
}
|
|
103
|
+
async init() {
|
|
104
|
+
await Promise.all(this.inits.map((x) => x()));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
export class SimpleStream {
|
|
108
|
+
dataHandlers = [];
|
|
109
|
+
endHandlers = [];
|
|
110
|
+
disconnect;
|
|
111
|
+
lastElement;
|
|
112
|
+
constructor(onDisconnect) {
|
|
113
|
+
this.disconnect = onDisconnect || (async () => { });
|
|
114
|
+
}
|
|
115
|
+
data(listener) {
|
|
116
|
+
this.dataHandlers.push(listener);
|
|
117
|
+
return this;
|
|
118
|
+
}
|
|
119
|
+
async push(data) {
|
|
120
|
+
this.lastElement = data;
|
|
121
|
+
await Promise.all(this.dataHandlers.map((handler) => handler(data)));
|
|
122
|
+
}
|
|
123
|
+
async end() {
|
|
124
|
+
await this.disconnect();
|
|
125
|
+
await Promise.all(this.endHandlers.map((handler) => handler()));
|
|
126
|
+
}
|
|
127
|
+
on(event, listener) {
|
|
128
|
+
if (event === "data") {
|
|
129
|
+
this.dataHandlers.push(listener);
|
|
130
|
+
}
|
|
131
|
+
if (event === "end") {
|
|
132
|
+
this.endHandlers.push(listener);
|
|
133
|
+
}
|
|
134
|
+
return this;
|
|
135
|
+
}
|
|
136
|
+
}
|