ldn-inbox-server 1.2.2 → 1.3.0
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/.env-example +4 -1
- package/README.md +13 -2
- package/bin/ldn-inbox-server.js +11 -4
- package/config/inbox_config.json +10 -0
- package/config/outbox_config.json +10 -0
- package/handler/demo_inbox_handler.js +6 -2
- package/handler/demo_notification_handler.js +12 -8
- package/handler/eventlog_notification_handler.js +16 -5
- package/handler/multi_notification_handler.js +57 -0
- package/lib/handler.js +1 -0
- package/lib/index.js +3 -3
- package/lib/util.js +12 -1
- package/package.json +6 -4
- /package/{lib/sendNotificationHandler.js → handler/send_notification_handler.js} +0 -0
package/.env-example
CHANGED
|
@@ -9,4 +9,7 @@ LDN_SERVER_INBOX_PATH=./inbox
|
|
|
9
9
|
LDN_SERVER_ERROR_PATH=./error
|
|
10
10
|
LDN_SERVER_OUTBOX_PATH=./outbox
|
|
11
11
|
LDN_SERVER_PUBLIC_PATH=./public
|
|
12
|
-
LDN_SERVER_JSON_SCHEMA=./config/notification_schema.json
|
|
12
|
+
LDN_SERVER_JSON_SCHEMA=./config/notification_schema.json
|
|
13
|
+
LDN_SERVER_INBOX_CONFIG=./config/inbox_config.json
|
|
14
|
+
LDN_SERVER_OUTBOX_CONFIG=./config/outbox_config.json
|
|
15
|
+
LDN_SERVER_HAS_PUBLIC_INBOX=0
|
package/README.md
CHANGED
|
@@ -39,7 +39,7 @@ npx ldn-inbox-server handle @inbox -hn ./handler/demo_notification_handler.js
|
|
|
39
39
|
Send the notifications in the outbox:
|
|
40
40
|
|
|
41
41
|
```
|
|
42
|
-
npx ldn-inbox-server handle @outbox
|
|
42
|
+
npx ldn-inbox-server handle @outbox -hn ./handler/send_notification_handler.js
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
## Environment
|
|
@@ -74,7 +74,14 @@ main();
|
|
|
74
74
|
|
|
75
75
|
async function main() {
|
|
76
76
|
await handle_inbox('./inbox', {
|
|
77
|
-
'
|
|
77
|
+
'inbox': './inbox',
|
|
78
|
+
'outbox': './outbox',
|
|
79
|
+
'public': './public',
|
|
80
|
+
'error': './error',
|
|
81
|
+
'batch_size': 5,
|
|
82
|
+
'glob': '^.*\\.jsonld$',
|
|
83
|
+
'config': './config/inbox_config.json',
|
|
84
|
+
'notification_handler': 'handler/demo_notification_handler.js'
|
|
78
85
|
});
|
|
79
86
|
}
|
|
80
87
|
```
|
|
@@ -102,6 +109,10 @@ A handler can be started on any directory. E.g. a workflow might be:
|
|
|
102
109
|
- processed LDN messages will end up in the "outbox" box
|
|
103
110
|
- invalid processing will be saved into the "error" box
|
|
104
111
|
|
|
112
|
+
## Multi handler
|
|
113
|
+
|
|
114
|
+
A `handler/multi_notification_handler.js` is available to start multiple handler for each notification messages. The handlers to start are specified in a configuraton file that can be passed via the `config` parameter of an `handle_inbox`. In the commmand line tool `bin/ldn-inbox-server` the default location of such config file is `config/inbox_config.json` when processing an `@inbox`, and `config/outbox_config.json` when processing an `@outbox`.
|
|
115
|
+
|
|
105
116
|
## See also
|
|
106
117
|
|
|
107
118
|
- [mellon-server](https://www.npmjs.com/package/mellon-server)
|
package/bin/ldn-inbox-server.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const fs = require('fs');
|
|
4
4
|
const { program } = require('commander');
|
|
5
5
|
const { inbox_server } = require('../lib/index');
|
|
6
|
-
const { handle_inbox
|
|
6
|
+
const { handle_inbox } = require('../lib/handler');
|
|
7
7
|
require('dotenv').config();
|
|
8
8
|
|
|
9
9
|
const HOST = process.env.LDN_SERVER_HOST ?? 'localhost';
|
|
@@ -17,6 +17,8 @@ const INBOX_PATH = process.env.LDN_SERVER_INBOX_PATH ?? './inbox';
|
|
|
17
17
|
const ERROR_PATH = process.env.LDN_SERVER_ERROR_PATH ?? './error';
|
|
18
18
|
const OUTBOX_PATH = process.env.LDN_SERVER_OUTBOX_PATH ?? './outbox';
|
|
19
19
|
const JSON_SCHEMA_PATH = process.env.LDN_SERVER_JSON_SCHEMA ?? './config/notification_schema.json';
|
|
20
|
+
const INBOX_CONFIG = process.env.LDN_SERVER_INBOX_CONFIG;
|
|
21
|
+
const OUTBOX_CONFIG = process.env.LDN_SERVER_OUTBOX_CONFIG;
|
|
20
22
|
const HAS_PUBLIC = process.env.LDN_SERVER_HAS_PUBLIC_INBOX ?? 0;
|
|
21
23
|
|
|
22
24
|
program
|
|
@@ -48,6 +50,7 @@ program
|
|
|
48
50
|
.option('--loop <seconds>', 'run in a loop',0)
|
|
49
51
|
.option('--batch_size <num>','batch size to process',INBOX_BATCH_SIZE)
|
|
50
52
|
.option('--glob <glob>','files to process in inbox',INBOX_GLOB)
|
|
53
|
+
.option('--config <path>','config file for handlers')
|
|
51
54
|
.option('-hi,--inbox_handler <handler>','inbox handler')
|
|
52
55
|
.option('-hn,--notification_handler <handler>','notification handler')
|
|
53
56
|
.argument('<box>','box to process')
|
|
@@ -55,11 +58,15 @@ program
|
|
|
55
58
|
switch (box) {
|
|
56
59
|
case '@inbox':
|
|
57
60
|
box = INBOX_PATH;
|
|
61
|
+
if (!options['config'] && fs.existsSync(INBOX_CONFIG)) {
|
|
62
|
+
options['config'] = INBOX_CONFIG
|
|
63
|
+
}
|
|
58
64
|
break;
|
|
59
65
|
case '@outbox':
|
|
60
66
|
box = OUTBOX_PATH;
|
|
61
|
-
options['
|
|
62
|
-
|
|
67
|
+
if (!options['config'] && fs.existsSync(OUTBOX_CONFIG)) {
|
|
68
|
+
options['config'] = OUTBOX_CONFIG
|
|
69
|
+
}
|
|
63
70
|
break;
|
|
64
71
|
}
|
|
65
72
|
if (options['loop']) {
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Demonstration of an alternatve inbox handler
|
|
5
|
+
* (don't use it the one in lib/handler.js is much more mature)
|
|
6
|
+
* To use it set it via the `--hi` option of `bin/ldn-inbox-server.js`, or
|
|
7
|
+
* the `inbox_handler` option of the `handle_inbox` function.
|
|
8
|
+
*/
|
|
5
9
|
async function handle({path,options}) {
|
|
6
10
|
console.log(`handleInbox(${path},..)`);
|
|
7
11
|
fs.readdir(path, (err,files) => {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
|
+
const md5 = require('md5');
|
|
2
3
|
const logger = require('../lib/util.js').getLogger();
|
|
3
4
|
|
|
4
5
|
async function handle({path,options}) {
|
|
@@ -7,17 +8,13 @@ async function handle({path,options}) {
|
|
|
7
8
|
try {
|
|
8
9
|
const json = JSON.parse(fs.readFileSync(path, { encoding: 'utf-8'}));
|
|
9
10
|
|
|
10
|
-
const outboxFile = options['outbox'] + '/' + path.split('/').pop();
|
|
11
|
-
|
|
12
11
|
const id = json['id'];
|
|
13
12
|
const object = json['object'];
|
|
14
13
|
const actor_id = json['actor']['id'];
|
|
15
14
|
const actor_type = json['actor']['type'];
|
|
16
15
|
const actor_inbox = json['actor']['inbox'];
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
fs.writeFileSync(outboxFile, JSON.stringify({
|
|
17
|
+
const data = JSON.stringify({
|
|
21
18
|
type: 'Accept',
|
|
22
19
|
actor: {
|
|
23
20
|
id: 'http://my.server' ,
|
|
@@ -32,13 +29,20 @@ async function handle({path,options}) {
|
|
|
32
29
|
type: actor_type ,
|
|
33
30
|
inbox: actor_inbox
|
|
34
31
|
}
|
|
35
|
-
},null,
|
|
36
|
-
|
|
32
|
+
},null,4);
|
|
33
|
+
|
|
34
|
+
const outboxFile = options['outbox'] + '/' + md5(data) + '.jsonld';
|
|
35
|
+
|
|
36
|
+
logger.info(`storing Accept to ${outboxFile}`);
|
|
37
|
+
|
|
38
|
+
fs.writeFileSync(outboxFile,data);
|
|
39
|
+
|
|
40
|
+
return { path, options, success: true };
|
|
37
41
|
}
|
|
38
42
|
catch(e) {
|
|
39
43
|
logger.error(`failed to process ${path}`);
|
|
40
44
|
logger.debug(e);
|
|
41
|
-
return { path,options, success: false };
|
|
45
|
+
return { path, options, success: false };
|
|
42
46
|
}
|
|
43
47
|
}
|
|
44
48
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
|
+
const md5 = require('md5');
|
|
2
3
|
const fsPath = require('path');
|
|
3
4
|
const lockfile = require('proper-lockfile');
|
|
4
5
|
const logger = require('../lib/util.js').getLogger();
|
|
@@ -10,7 +11,7 @@ async function handle({path,options}) {
|
|
|
10
11
|
logger.info(`parsing notification ${path}`);
|
|
11
12
|
|
|
12
13
|
try {
|
|
13
|
-
const json =
|
|
14
|
+
const json = fs.readFileSync(path, { encoding: 'utf-8'});
|
|
14
15
|
|
|
15
16
|
const fileName = path.split('/').pop();
|
|
16
17
|
const logDir = fsPath.join(options['public'],EVENT_DIR,'log');
|
|
@@ -22,7 +23,7 @@ async function handle({path,options}) {
|
|
|
22
23
|
|
|
23
24
|
const outboxFile = fsPath.join(logDir,fileName);
|
|
24
25
|
|
|
25
|
-
fs.writeFileSync(outboxFile,
|
|
26
|
+
fs.writeFileSync(outboxFile, json);
|
|
26
27
|
|
|
27
28
|
// Updating metadata file
|
|
28
29
|
const metaFile = outboxFile + '.meta';
|
|
@@ -34,12 +35,12 @@ async function handle({path,options}) {
|
|
|
34
35
|
|
|
35
36
|
await updateEventLog({path,options});
|
|
36
37
|
|
|
37
|
-
return { path,options, success: true };
|
|
38
|
+
return { path, options, success: true };
|
|
38
39
|
}
|
|
39
40
|
catch(e) {
|
|
40
41
|
logger.error(`failed to process ${path}`);
|
|
41
42
|
logger.error(e);
|
|
42
|
-
return { path,options, success: false };
|
|
43
|
+
return { path, options, success: false };
|
|
43
44
|
}
|
|
44
45
|
}
|
|
45
46
|
|
|
@@ -47,6 +48,9 @@ async function updateEventLog({path,options}) {
|
|
|
47
48
|
logger.info(`updating eventlog for ${path}`);
|
|
48
49
|
|
|
49
50
|
try {
|
|
51
|
+
const notification = fs.readFileSync(path, { encoding: 'utf-8'});
|
|
52
|
+
const notification_checksum = md5(notification);
|
|
53
|
+
|
|
50
54
|
const baseUrl = process.env.LDN_SERVER_BASEURL ?? "";
|
|
51
55
|
const fileName = path.split('/').pop();
|
|
52
56
|
const entry = `${baseUrl}/${EVENT_DIR}/log/${fileName}`;
|
|
@@ -72,7 +76,14 @@ async function updateEventLog({path,options}) {
|
|
|
72
76
|
else {
|
|
73
77
|
logger.info(`updating ${eventLog}`);
|
|
74
78
|
|
|
75
|
-
json['member'].push(
|
|
79
|
+
json['member'].push({
|
|
80
|
+
"id": entry ,
|
|
81
|
+
"checksum": {
|
|
82
|
+
"type": "Checksum",
|
|
83
|
+
"algorithm": "spdx:checksumAlgorithm_md5",
|
|
84
|
+
"checksumValue": notification_checksum
|
|
85
|
+
}
|
|
86
|
+
});
|
|
76
87
|
|
|
77
88
|
if (fs.existsSync(eventLog)) {
|
|
78
89
|
try {
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
const { dynamic_handler , parseAsJSON } = require('../lib/util');
|
|
2
|
+
const logger = require('../lib/util.js').getLogger();
|
|
3
|
+
|
|
4
|
+
async function handle({path,options}) {
|
|
5
|
+
let success = false;
|
|
6
|
+
|
|
7
|
+
const config = parseAsJSON(options['config']);
|
|
8
|
+
|
|
9
|
+
if (! config) {
|
|
10
|
+
logger.error('no configuration found for multi_notification_handler');
|
|
11
|
+
return { path, options, success: false };
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const handlers = config['notification_handler']?.['multi']?.['handlers'];
|
|
15
|
+
|
|
16
|
+
if (! handlers) {
|
|
17
|
+
logger.error('no notification_handler.multi.handlers key in configuration file');
|
|
18
|
+
return { path, options, success: false };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
logger.info(`starting multi handler`);
|
|
23
|
+
|
|
24
|
+
for (let i = 0 ; i < handlers.length ; i++) {
|
|
25
|
+
logger.info(`starting ${handlers[i]}`);
|
|
26
|
+
|
|
27
|
+
const handler = dynamic_handler(handlers[i],null);
|
|
28
|
+
|
|
29
|
+
if (! handler) {
|
|
30
|
+
throw new Error(`failed to load ${handlers[i]}`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const result = await handler({path,options});
|
|
34
|
+
|
|
35
|
+
if (result['success']) {
|
|
36
|
+
logger.info(`finished ${handlers[i]}`);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
throw new Error(`Eek! ${handlers[i]} failed`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
success = true;
|
|
44
|
+
}
|
|
45
|
+
catch (e) {
|
|
46
|
+
logger.error(`failed to process ${path}`);
|
|
47
|
+
logger.error(e);
|
|
48
|
+
|
|
49
|
+
success = false;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
logger.info(`finished multi handler`);
|
|
53
|
+
|
|
54
|
+
return { path, options, success: success };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
module.exports = { handle };
|
package/lib/handler.js
CHANGED
|
@@ -17,6 +17,7 @@ async function defaultInboxHandler({path,options}) {
|
|
|
17
17
|
|
|
18
18
|
const worker = options['notification_handler'] ?? fsPath.resolve(__dirname,'..','lib','notification.js');
|
|
19
19
|
|
|
20
|
+
// Run the notifications using a node.js worker pool
|
|
20
21
|
const pool = new piscina({
|
|
21
22
|
filename: worker,
|
|
22
23
|
maxQueue: queue_size
|
package/lib/index.js
CHANGED
|
@@ -42,16 +42,17 @@ function inbox_server(options) {
|
|
|
42
42
|
start_server({
|
|
43
43
|
host: options['host'],
|
|
44
44
|
port: options['port'],
|
|
45
|
+
base: options['base'],
|
|
45
46
|
public: options['public'],
|
|
46
47
|
registry: registry
|
|
47
48
|
});
|
|
48
49
|
}
|
|
49
50
|
|
|
50
51
|
function doInbox(req,res) {
|
|
51
|
-
if (req.method === 'GET' && INBOX_PUBLIC_READABLE) {
|
|
52
|
+
if (req.method === 'GET' && INBOX_PUBLIC_READABLE == 1) {
|
|
52
53
|
doInboxGET(req,res);
|
|
53
54
|
}
|
|
54
|
-
if (req.method == 'HEAD' && INBOX_PUBLIC_READABLE) {
|
|
55
|
+
else if (req.method == 'HEAD' && INBOX_PUBLIC_READABLE == 1) {
|
|
55
56
|
doInboxHEAD(req,res);
|
|
56
57
|
}
|
|
57
58
|
else if (req.method === 'POST') {
|
|
@@ -61,7 +62,6 @@ function doInbox(req,res) {
|
|
|
61
62
|
logger.error(`tried method ${req.method} on inbox : forbidden`);
|
|
62
63
|
res.writeHead(403);
|
|
63
64
|
res.end('Forbidden');
|
|
64
|
-
return;
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
|
package/lib/util.js
CHANGED
|
@@ -125,11 +125,22 @@ function dynamic_handler(handler,fallback) {
|
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
+
function parseAsJSON(path) {
|
|
129
|
+
try {
|
|
130
|
+
return JSON.parse(fs.readFileSync(path, { encoding: 'utf-8'}));
|
|
131
|
+
}
|
|
132
|
+
catch (e) {
|
|
133
|
+
logger.error(`failed to parse ${path}`);
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
128
138
|
module.exports = {
|
|
129
139
|
getLogger ,
|
|
130
140
|
backOff_fetch ,
|
|
131
141
|
fetchOriginal ,
|
|
132
142
|
moveTo ,
|
|
133
143
|
sendNotification ,
|
|
134
|
-
dynamic_handler
|
|
144
|
+
dynamic_handler ,
|
|
145
|
+
parseAsJSON
|
|
135
146
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ldn-inbox-server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "A demonstration Event Notifications Inbox server",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"author": "Patrick Hochstenbach <Patrick.Hochstenbach@UGent.be>",
|
|
@@ -9,9 +9,11 @@
|
|
|
9
9
|
"server": "npx ldn-inbox-server start-server",
|
|
10
10
|
"demo-post": "curl -X POST -H 'Content-Type: application/ld+json' --data-binary '@examples/offer.jsonld' http://localhost:8000/inbox/",
|
|
11
11
|
"handle-inbox": "npx ldn-inbox-server handler @inbox -hn ./handler/demo_notification_handler.js",
|
|
12
|
-
"handle-outbox": "npx ldn-inbox-server handler @outbox",
|
|
12
|
+
"handle-outbox": "npx ldn-inbox-server handler @outbox -hn ./handler/send_notification_handler.js",
|
|
13
13
|
"handle-eventlog": "npx ldn-inbox-server handler @inbox -hn handler/eventlog_notification_handler.js",
|
|
14
|
-
"
|
|
14
|
+
"handle-inbox-multi": "npx ldn-inbox-server handler @inbox -hn ./handler/multi_notification_handler.js",
|
|
15
|
+
"handle-outbox-multi": "npx ldn-inbox-server handler @outbox -hn ./handler/multi_notification_handler.js",
|
|
16
|
+
"clean": "rm error/* inbox/* outbox/* public/events/* public/events/log/*"
|
|
15
17
|
},
|
|
16
18
|
"bin": "./bin/ldn-inbox-server.js",
|
|
17
19
|
"keywords": [
|
|
@@ -25,7 +27,7 @@
|
|
|
25
27
|
"exponential-backoff": "^3.1.1",
|
|
26
28
|
"jsonschema": "^1.4.1",
|
|
27
29
|
"md5": "^2.3.0",
|
|
28
|
-
"mellon-server": "^1.0.
|
|
30
|
+
"mellon-server": "^1.0.8",
|
|
29
31
|
"node-fetch": "1.7.3",
|
|
30
32
|
"piscina": "^4.4.0",
|
|
31
33
|
"proper-lockfile": "^4.1.2",
|
|
File without changes
|