ldn-inbox-server 1.3.2 → 1.4.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/README.md CHANGED
@@ -119,7 +119,7 @@ A handler that creates for an incoming notification an `Accept` notification in
119
119
 
120
120
  A handler that updates an event log with the incoming notification.
121
121
 
122
- Requires a configuration file with property `notification_handler.eventlog`:
122
+ Requires configuration properties:
123
123
 
124
124
  - `log`: the path to the event log (starting from the `public` directory)
125
125
  - `dir`: the path to a container to store the events (starting from the `public` directory)
@@ -127,6 +127,25 @@ Requires a configuration file with property `notification_handler.eventlog`:
127
127
  The `log` and `dir` path may contain a `@artifact(:strip)?@` directive to fill in the
128
128
  path of the current artifact. The `:strip` filter is used to strip an artifact path of a file extension. E.g. `path/artifact.html` becomes `path/artifact` when using a `:strip`.
129
129
 
130
+ ### Json Path handler
131
+
132
+ A handler that accepts a notifiction when it matches one or more JSON paths
133
+
134
+ Requires configuration properties:
135
+
136
+ - anyOf : an array of json path matchers, the combination should be interpreted as a logical `OR`.
137
+ - every json path matcher is an array of single matchers, the combination should be interpered as a logical `AND`.
138
+
139
+ A single matcher needs two properties:
140
+
141
+ - path : a json path
142
+ - value : a value
143
+
144
+ The json path matches when one of:
145
+
146
+ - On the json path an array is found and the value is included in the array
147
+ - On the json path a string or number is found and the value is equal to this string or number
148
+
130
149
  ### Multi handler
131
150
 
132
151
  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`.
@@ -135,19 +154,37 @@ A `handler/multi_notification_handler.js` is available to start multiple handler
135
154
 
136
155
  A handler to `Offer` an event log to a memento server.
137
156
 
138
- Requires a configuration file with property `notification_handler.offer_memento`:
157
+ Requires configuration properties:
139
158
 
140
159
  - `actor`: the LDN+AS2 `actor` to use in a notification
141
160
  - `target`: the LDN+AS2 `target` to use in a notification
142
161
 
143
- ### Send handler
162
+ ### Send notification handler
144
163
 
145
- A hanlder to send notification that live in the `@outbox` via the LDN protocol to the LDN `target`.
164
+ A handler to send notification that live in the `@outbox` via the LDN protocol to the LDN `target`.
146
165
 
147
- ### Valid artifact
166
+ ### Type handler
167
+
168
+ A handler that accepts any notification with a type that matches one of the `anyOf` types.
169
+
170
+ ### Valid artifact handler
148
171
 
149
172
  A handler that validates the incoming notification and checks if the `object` or `context` contains an artifact that is part of the `public` resources. See 'Artifact support' below.
150
173
 
174
+ Generates the following options keys:
175
+
176
+ - artifact.id : the URL of the artifact
177
+ - artifact.path : the local path to the artifact
178
+
179
+ ### Valid event log handler
180
+
181
+ A hander that validates the incoming notification and checks if the `object` or `context` contains an event log that is part of the `public` resources.
182
+
183
+ Generates the following options keys:
184
+
185
+ - eventlog.id : the URL of the event log
186
+ - eventlog.path : the local path of the event log
187
+
151
188
  ## Artifact support
152
189
 
153
190
  This code base contains Event Notifications support for Data Node artifacts. See the examples
@@ -69,15 +69,7 @@ program
69
69
  }
70
70
  break;
71
71
  }
72
- if (options['loop']) {
73
- while(1) {
74
- await handle_inbox(box,options);
75
- await new Promise(resolve => setTimeout(resolve, options['loop']*1000));
76
- }
77
- }
78
- else {
79
- await handle_inbox(box,options);
80
- }
72
+ await handle_inbox(box,options);
81
73
  });
82
74
 
83
- program.parse();
75
+ program.parse();
@@ -16,9 +16,24 @@ program
16
16
  .argument('<url>','notification')
17
17
  .argument('<file>','notification')
18
18
  .action( async(url,file) => {
19
- const to = url === '@me' ? `${INBOX_BASE_URL}/${INBOX_URL}` : url;
20
19
  const json = JSON.parse(fs.readFileSync(file, { encoding: 'utf-8'}));
21
- await sendNotification(to,json);
20
+
21
+ let to = url;
22
+
23
+ if (to === '@me') {
24
+ to = `${INBOX_BASE_URL}/${INBOX_URL}`;
25
+ }
26
+ else if (to === '@target') {
27
+ to = json['target']['inbox'];
28
+ }
29
+
30
+ if (!to) {
31
+ logger.error('no "to" inbox found');
32
+ }
33
+ else {
34
+ logger.info(`sending notification to ${to}`);
35
+ await sendNotification(to,json);
36
+ }
22
37
  });
23
38
 
24
39
  program.parse();
@@ -1,31 +1,50 @@
1
1
  {
2
2
  "notification_handler": {
3
- "eventlog": {
4
- "log": "@artifact:strip@.jsonld",
5
- "dir": "@artifact:strip@"
6
- },
7
3
  "multi": {
8
4
  "handlers": [
9
- "handler/type_filter_notification_handler.js",
10
- "handler/valid_artifact_notification_handler.js" ,
11
- "handler/eventlog_notification_handler.js",
12
- "handler/offer_memento_notification_handler.js"
5
+ [
6
+ {
7
+ "id": "handler/notification_handler/jsonpath_filter.js",
8
+ "anyOf": [
9
+ [
10
+ { "path": "$.type" , "value": "Offer" }
11
+ ]
12
+ ]
13
+ },
14
+ "handler/notification_handler/valid_artifact.js" ,
15
+ {
16
+ "id": "handler/notification_handler/eventlog.js",
17
+ "log": "@artifact:strip@.jsonld",
18
+ "dir": "@artifact:strip@"
19
+ },
20
+ {
21
+ "id": "handler/notification_handler/offer_memento.js",
22
+ "actor": {
23
+ "id": "http://localhost:8000/profile/card#me" ,
24
+ "inbox": "http://localhost:8000/inbox/" ,
25
+ "type": "Service"
26
+ },
27
+ "target": {
28
+ "id": "http://localhost:8001/profile/card#me" ,
29
+ "inbox": "http://localhost:8001/inbox/" ,
30
+ "type": "Service"
31
+ }
32
+ }
33
+ ] ,
34
+ [
35
+ {
36
+ "id": "handler/notification_handler/jsonpath_filter.js",
37
+ "anyOf": [
38
+ [
39
+ { "path": "$.type" , "value": "Announce" } ,
40
+ { "path": "$.actor.id", "value": "https://labs.eventnotifications.net/service/m/profile/card.ttl" }
41
+ ]
42
+ ]
43
+ } ,
44
+ "handler/notification_handler/valid_eventlog.js",
45
+ "handler/notification_handler/add_timemap_link.js"
46
+ ]
13
47
  ]
14
- },
15
- "offer_memento": {
16
- "actor": {
17
- "id": "http://localhost:8000/profile/card#me" ,
18
- "inbox": "http://localhost:8000/inbox/" ,
19
- "type": "Service"
20
- },
21
- "target": {
22
- "id": "http://localhost:8001/profile/card#me" ,
23
- "inbox": "http://localhost:8001/inbox/" ,
24
- "type": "Service"
25
- }
26
- },
27
- "type_filter": {
28
- "anyOf": [ "Offer" ]
29
48
  }
30
49
  }
31
50
  }
@@ -1,14 +1,15 @@
1
1
  {
2
2
  "notification_handler": {
3
- "eventlog": {
4
- "log": "@artifact:strip@.jsonld",
5
- "dir": "@artifact:strip@"
6
- },
7
3
  "multi": {
8
4
  "handlers": [
9
- "handler/valid_artifact_notification_handler.js" ,
10
- "handler/send_notification_handler.js",
11
- "handler/eventlog_notification_handler.js"
5
+ [
6
+ "handler/notification_handler/send_notification.js",
7
+ {
8
+ "id": "handler/eventlog_notification_handler.js",
9
+ "log": "@artifact:strip@.jsonld",
10
+ "dir": "@artifact:strip@"
11
+ }
12
+ ]
12
13
  ]
13
14
  }
14
15
  }
@@ -0,0 +1,16 @@
1
+ module.exports = {
2
+ apps : [
3
+ {
4
+ name : "ldn-inbox-server",
5
+ script : "./bin/ldn-inbox-server.js start-server"
6
+ } ,
7
+ {
8
+ name : "ldn-inbox-inbox",
9
+ script : "LOG4JS=info ./bin/ldn-inbox-server.js handler @inbox --loop 20 -hn ./handler/notification_handler/multi.js"
10
+ } ,
11
+ {
12
+ name : "ldn-inbox-outbox",
13
+ script : "LOG4JS=info ./bin/ldn-inbox-server.js handler @outbox --loop 20 -hn ./handler/notification_handler/multi.js"
14
+ }
15
+ ]
16
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "@context": [
3
+ "https://www.w3.org/ns/activitystreams",
4
+ {
5
+ "ietf": "https://www.iana.org/"
6
+ }
7
+ ],
8
+ "type": "Announce",
9
+ "actor": {
10
+ "id": "https://labs.eventnotifications.net/service/m/profile/card.ttl",
11
+ "inbox": "https://labs.eventnotifications.net/service/m/inbox/",
12
+ "type": "Service"
13
+ },
14
+ "context": "http://localhost:8000/artifacts/artifact1.jsonld",
15
+ "inReplyTo": "urn:uuid:6E5FAF88-A7F1-47A4-B087-77345EBFF495",
16
+ "object": {
17
+ "id": "https://labs.eventnotifications.net/service/m/map/http://localhost:8000/artifacts/artifact1.jsonld",
18
+ "type": "Document",
19
+ "ietf:original": "http://localhost:8000/artifacts/artifact1.jsonld",
20
+ "ietf:memento": "https://labs.eventnotifications.net/service/m/memento/http://localhost:8000/artifacts/artifact1.jsonld/6c7f984b0702a16b6b9661ea7dca2db48fa8086d"
21
+ },
22
+ "target": {
23
+ "id": "http://193.190.80.48:56633/service/r/profile/card#me",
24
+ "type": "Service",
25
+ "inbox": "http://193.190.80.48:56633/service/r/inbox/"
26
+ }
27
+ }
@@ -6,7 +6,7 @@ const fs = require('fs');
6
6
  * To use it set it via the `--hi` option of `bin/ldn-inbox-server.js`, or
7
7
  * the `inbox_handler` option of the `handle_inbox` function.
8
8
  */
9
- async function handle({path,options}) {
9
+ async function handle({path,options,config}) {
10
10
  console.log(`handleInbox(${path},..)`);
11
11
  fs.readdir(path, (err,files) => {
12
12
  files.forEach( (file) => {
@@ -1,14 +1,14 @@
1
1
  const fs = require('fs');
2
2
  const md5 = require('md5');
3
- const { parseAsJSON } = require('../lib/util');
4
- const logger = require('../lib/util.js').getLogger();
3
+ const { parseAsJSON } = require('../../lib/util.js');
4
+ const logger = require('../../lib/util.js').getLogger();
5
5
 
6
6
  /**
7
7
  * Demonstration notification handler, that creates an 'Accept'
8
8
  * notification for each incoming notification message and stores
9
9
  * it in the outbox container.
10
10
  */
11
- async function handle({path,options}) {
11
+ async function handle({path,options,config}) {
12
12
  logger.info(`parsing notification ${path}`);
13
13
 
14
14
  try {
@@ -47,7 +47,7 @@ async function handle({path,options}) {
47
47
  }
48
48
  catch(e) {
49
49
  logger.error(`failed to process ${path}`);
50
- logger.debug(e);
50
+ logger.error(e);
51
51
  return { path, options, success: false };
52
52
  }
53
53
  }
@@ -0,0 +1,51 @@
1
+ const fs = require('fs');
2
+ const jp = require('jsonpath');
3
+ const { parseAsJSON } = require('../../lib/util.js');
4
+ const logger = require('../../lib/util.js').getLogger();
5
+
6
+ /**
7
+ * Demonstration event log handler
8
+ */
9
+ async function handle({path,options,config}) {
10
+ logger.info(`parsing notification ${path}`);
11
+
12
+ const eventlog = options['eventlog'];
13
+
14
+ if (!eventlog) {
15
+ logger.error(`no eventlog option available (do you run valid_eventlog first?)`);
16
+ return { path, options, success: false };
17
+ }
18
+
19
+ try {
20
+ const json = parseAsJSON(path);
21
+
22
+ const meta = parseAsJSON(`${eventlog['path']}.meta`);
23
+
24
+ const timemap = jp.query(json,'$.object.id');
25
+ const relation = `<${timemap}> ; rel="timemap"`;
26
+
27
+ let links = meta['Link'] || [];
28
+
29
+ if (links.includes(relation)) {
30
+ // Do nothing
31
+ }
32
+ else {
33
+ links.push(`<${timemap}> ; rel="timemap"`);
34
+ }
35
+
36
+ meta['Link'] = links;
37
+
38
+ logger.info(`Writing ${meta['Link']} to ${eventlog['path']}.meta`);
39
+
40
+ fs.writeFileSync(`${eventlog['path']}.meta`,JSON.stringify(meta,null,4));
41
+
42
+ return { path, options, success: true };
43
+ }
44
+ catch(e) {
45
+ logger.error(`failed to process ${path}`);
46
+ logger.error(e);
47
+ return { path, options, success: false };
48
+ }
49
+ }
50
+
51
+ module.exports = { handle };
@@ -1,26 +1,20 @@
1
1
  const fs = require('fs');
2
2
  const md5 = require('md5');
3
- const fsPath = require('path');
4
3
  const lockfile = require('proper-lockfile');
5
- const { parseAsJSON } = require('../lib/util');
6
- const logger = require('../lib/util.js').getLogger();
4
+ const logger = require('../../lib/util.js').getLogger();
7
5
 
8
6
  /**
9
7
  * Demonstration event log handler
10
8
  */
11
- async function handle({path,options}) {
9
+ async function handle({path,options,config}) {
12
10
  logger.info(`parsing notification ${path}`);
13
11
 
14
- const config = parseAsJSON(options['config']);
15
-
16
12
  if (! config) {
17
13
  logger.error('no configuration found for eventlog_notification_handler');
18
14
  return { path, options, success: false };
19
15
  }
20
16
 
21
- const thisConfig = config['notification_handler']?.['eventlog'];
22
-
23
- if (! thisConfig || !thisConfig['log'] || !thisConfig['dir']) {
17
+ if (!config['log'] || !config['dir']) {
24
18
  logger.error('no log/dir entry for notification_handler.eventlog configuration');
25
19
  return { path, options, success: false };
26
20
  }
@@ -30,8 +24,8 @@ async function handle({path,options}) {
30
24
  `http://${options['host']}:${options['port']}` :
31
25
  'http://localhost:8000';
32
26
 
33
- let eventLog = thisConfig['log'];
34
- let eventDir = thisConfig['dir'];
27
+ let eventLog = config['log'];
28
+ let eventDir = config['dir'];
35
29
 
36
30
  let artifactPath = undefined;
37
31
 
@@ -0,0 +1,84 @@
1
+ const jp = require('jsonpath');
2
+ const { parseAsJSON } = require('../../lib/util.js');
3
+ const logger = require('../../lib/util.js').getLogger();
4
+
5
+ /**
6
+ * Demonstration notification handler, that checks if the notification
7
+ * matches a configurable list
8
+ */
9
+ async function handle({path,options,config}) {
10
+ logger.info(`parsing notification ${path}`);
11
+
12
+ if (! config) {
13
+ logger.error('no configuration found for eventlog_notification_handler');
14
+ return { path, options, success: false };
15
+ }
16
+
17
+ if (! (config['anyOf'] && Array.isArray(config['anyOf']))) {
18
+ logger.error('no anyOf entry in notification_handler.type_filer should be an array');
19
+ return { path, options, success: false };
20
+ }
21
+
22
+ try {
23
+ const anyOf = config['anyOf'];
24
+ const json = parseAsJSON(path);
25
+
26
+ let isOk = false;
27
+
28
+ for (let i = 0 ; i < anyOf.length ; i++) {
29
+ let matchCount = 0;
30
+ for (let j = 0 ; j < anyOf[i].length ; j++) {
31
+ const anyPart = anyOf[i][j];
32
+ const path = anyPart['path'];
33
+ const value = anyPart['value'];
34
+
35
+ const jsonValue = jp.query(json,path);
36
+
37
+ if (jsonValue !== null || jsonValue !== undefined) {
38
+ if (Array.isArray(jsonValue)) {
39
+ if (jsonValue.includes(value)) {
40
+ // Yup ..
41
+ logger.info(`found ${path} includes ${value} `)
42
+ matchCount++;
43
+ }
44
+ else {
45
+ // Nope ..
46
+ }
47
+ }
48
+ else if (typeof jsonValue === 'string' || typeof jsonValue === 'number') {
49
+ if (jsonValue === value) {
50
+ // Yup ..
51
+ logger.info(`found ${path} === ${value} `)
52
+ matchCount++
53
+ }
54
+ else {
55
+ // Nope ..
56
+ }
57
+ }
58
+ else {
59
+ // Nope ..
60
+ }
61
+ }
62
+ }
63
+ if (matchCount == anyOf[i].length) {
64
+ isOk = true;
65
+ break;
66
+ }
67
+ }
68
+
69
+ if (isOk) {
70
+ return { path, options, success: true };
71
+ }
72
+ else {
73
+ logger.error(`notification does not pass jsonpath_filter check`);
74
+ return { path, options, success: false };
75
+ }
76
+ }
77
+ catch(e) {
78
+ logger.error(`failed to process ${path}`);
79
+ logger.error(e);
80
+ return { path, options, success: false };
81
+ }
82
+ }
83
+
84
+ module.exports = { handle };
@@ -0,0 +1,96 @@
1
+ const { dynamic_handler , parseAsJSON } = require('../../lib/util.js');
2
+ const logger = require('../../lib/util.js').getLogger();
3
+
4
+ /**
5
+ * Demonstration notification handler that start multiple notification handlers.
6
+ * Requires a config file that specifies which handlers to start.
7
+ */
8
+ async function handle({path,options}) {
9
+ let success = false;
10
+
11
+ const config = parseAsJSON(options['config']);
12
+
13
+ if (! config) {
14
+ logger.error('no configuration found for multi_notification_handler');
15
+ return { path, options, success: false };
16
+ }
17
+
18
+ const handlers = config['notification_handler']?.['multi']?.['handlers'];
19
+
20
+ if (! handlers) {
21
+ logger.error('no notification_handler.multi.handlers key in configuration file');
22
+ return { path, options, success: false };
23
+ }
24
+
25
+ logger.info(`starting multi handler`);
26
+
27
+ let workflow_success = 0;
28
+ let workflow_errors = 0;
29
+
30
+ for (let i = 0 ; i < handlers.length ; i++) {
31
+ const workflow = handlers[i];
32
+
33
+ let thisWorkflow = true;
34
+
35
+ try {
36
+ for (let j = 0 ; j < workflow.length ; j++) {
37
+ let step = undefined;
38
+ let config = undefined;
39
+
40
+ if (typeof workflow[j] === 'string' || workflow[j] instanceof String) {
41
+ step = workflow[j];
42
+ config = {};
43
+ }
44
+ else {
45
+ step = workflow[j]['id'];
46
+ delete workflow[j]['id'];
47
+ config = workflow[j];
48
+ }
49
+
50
+ logger.info(`workflow[${i}] : starting ${step}`);
51
+
52
+ const handler = dynamic_handler(step,null);
53
+
54
+ if (! handler) {
55
+ throw new Error(`failed to load ${step}`);
56
+ }
57
+
58
+ const result = await handler({path,options,config});
59
+
60
+ if (result['success']) {
61
+ logger.info(`workflow[${i}] : finished ${step}`);
62
+ }
63
+ else {
64
+ logger.error(`workflow[${i}] : failed ${step}`);
65
+ thisWorkflow = false;
66
+ break;
67
+ }
68
+ }
69
+ }
70
+ catch (e) {
71
+ logger.error(`failed to process ${path}`);
72
+ logger.error(e);
73
+ thisWorkflow = false;
74
+ }
75
+
76
+ if (thisWorkflow) {
77
+ workflow_success++;
78
+ }
79
+ else {
80
+ workflow_errors++;
81
+ }
82
+ }
83
+
84
+ if (handlers.length > 0 && workflow_success > 0) {
85
+ success = true;
86
+ }
87
+ else {
88
+ success = false;
89
+ }
90
+
91
+ logger.info(`finished multi handler`);
92
+
93
+ return { path, options, success: success };
94
+ }
95
+
96
+ module.exports = { handle };
@@ -1,26 +1,21 @@
1
1
  const fs = require('fs');
2
2
  const md5 = require('md5');
3
- const { parseAsJSON } = require('../lib/util.js');
4
- const logger = require('../lib/util.js').getLogger();
3
+ const logger = require('../../lib/util.js').getLogger();
5
4
 
6
5
  /**
7
6
  * Demonstration notification handler, that creates an 'Offer'
8
7
  * notification for each incoming notificaation to request the
9
8
  * archivation of the event log.
10
9
  */
11
- async function handle({path,options}) {
10
+ async function handle({path,options,config}) {
12
11
  logger.info(`parsing notification ${path}`);
13
12
 
14
- const config = parseAsJSON(options['config']);
15
-
16
13
  if (! config) {
17
14
  logger.error('no configuration found for offer_memento_notification_handler');
18
15
  return { path, options, success: false };
19
16
  }
20
17
 
21
- const thisConfig = config['notification_handler']?.['offer_memento'];
22
-
23
- if (! thisConfig || !thisConfig['actor'] || !thisConfig['target']) {
18
+ if (!config['actor'] || !config['target']) {
24
19
  logger.error('no actor/target entry for notification_handler.eventlog configuration');
25
20
  return { path, options, success: false };
26
21
  }
@@ -42,12 +37,12 @@ async function handle({path,options}) {
42
37
  {"schema": "https://schema.org/"}
43
38
  ],
44
39
  type: 'Offer',
45
- actor: thisConfig['actor'],
40
+ actor: config['actor'],
46
41
  object: {
47
42
  id: options['eventlog']['id'],
48
43
  type: [ "Document", "schema:Dataset" ]
49
44
  },
50
- target: thisConfig['target']
45
+ target: config['target']
51
46
  },null,4);
52
47
 
53
48
  const outboxFile = options['outbox'] + '/' + md5(data) + '.jsonld';
@@ -60,7 +55,7 @@ async function handle({path,options}) {
60
55
  }
61
56
  catch(e) {
62
57
  logger.error(`failed to process ${path}`);
63
- logger.debug(e);
58
+ logger.error(e);
64
59
  return { path, options, success: false };
65
60
  }
66
61
  }
@@ -1,11 +1,11 @@
1
- const logger = require('../lib/util.js').getLogger();
2
- const { sendNotification , parseAsJSON } = require('../lib/util.js');
1
+ const logger = require('../../lib/util.js').getLogger();
2
+ const { sendNotification , parseAsJSON } = require('../../lib/util.js');
3
3
 
4
4
  /**
5
5
  * Demonstration notification handler that sends a notification to a
6
6
  * target inbox.
7
7
  */
8
- async function handle({path,options}) {
8
+ async function handle({path,options,config}) {
9
9
  try {
10
10
  const data = parseAsJSON(path);
11
11
  const type = data['type'];
@@ -1,29 +1,19 @@
1
- const fs = require('fs');
2
- const { parseAsJSON } = require('../lib/util');
3
- const logger = require('../lib/util.js').getLogger();
1
+ const { parseAsJSON } = require('../../lib/util.js');
2
+ const logger = require('../../lib/util.js').getLogger();
4
3
 
5
4
  /**
6
5
  * Demonstration notification handler, that checks if the notification
7
6
  * matches a configurable list
8
7
  */
9
- async function handle({path,options}) {
8
+ async function handle({path,options,config}) {
10
9
  logger.info(`parsing notification ${path}`);
11
10
 
12
- const config = parseAsJSON(options['config']);
13
-
14
11
  if (! config) {
15
12
  logger.error('no configuration found for eventlog_notification_handler');
16
13
  return { path, options, success: false };
17
14
  }
18
15
 
19
- const thisConfig = config['notification_handler']?.['type_filter'];
20
-
21
- if (! thisConfig) {
22
- logger.error('no notification_handler.type_filer configuration');
23
- return { path, options, success: false };
24
- }
25
-
26
- if (! (thisConfig['anyOf'] && Array.isArray(thisConfig['anyOf']))) {
16
+ if (! (config['anyOf'] && Array.isArray(config['anyOf']))) {
27
17
  logger.error('no anyOf entry in notification_handler.type_filer should be an array');
28
18
  return { path, options, success: false };
29
19
  }
@@ -38,7 +28,7 @@ async function handle({path,options}) {
38
28
  let isOk = true ;
39
29
 
40
30
  for (let i = 0 ; i < typeArray.length ; i++) {
41
- if (thisConfig['anyOf'].includes(typeArray[i])) {
31
+ if (config['anyOf'].includes(typeArray[i])) {
42
32
  // We are ok
43
33
  }
44
34
  else {
@@ -57,7 +47,7 @@ async function handle({path,options}) {
57
47
  }
58
48
  catch(e) {
59
49
  logger.error(`failed to process ${path}`);
60
- logger.debug(e);
50
+ logger.error(e);
61
51
  return { path, options, success: false };
62
52
  }
63
53
  }
@@ -1,11 +1,11 @@
1
- const { ldPropertyAsId , parseArtifact, parseAsJSON } = require('../lib/util.js');
2
- const logger = require('../lib/util.js').getLogger();
1
+ const { ldPropertyAsId , parseArtifact, parseAsJSON } = require('../../lib/util.js');
2
+ const logger = require('../../lib/util.js').getLogger();
3
3
 
4
4
  /**
5
5
  * Demonstration notification handler, that checks if the notification
6
6
  * message contains an artifact that is known to the data node
7
7
  */
8
- async function handle({path,options}) {
8
+ async function handle({path,options,config}) {
9
9
  logger.info(`parsing notification ${path}`);
10
10
 
11
11
  try {
@@ -47,7 +47,7 @@ async function handle({path,options}) {
47
47
  }
48
48
  catch(e) {
49
49
  logger.error(`failed to process ${path}`);
50
- logger.debug(e);
50
+ logger.error(e);
51
51
  return { path, options, success: false };
52
52
  }
53
53
  }
@@ -0,0 +1,52 @@
1
+ const { ldPropertyAsId , parseEventLog, parseAsJSON } = require('../../lib/util.js');
2
+ const logger = require('../../lib/util.js').getLogger();
3
+
4
+ /**
5
+ * Demonstration notification handler, that checks if the notification
6
+ * message contains an artifact that is known to the data node
7
+ */
8
+ async function handle({path,options,config}) {
9
+ logger.info(`parsing notification ${path}`);
10
+
11
+ try {
12
+ const json = parseAsJSON(path);
13
+
14
+ let eventlog = undefined;
15
+
16
+ if (ldPropertyAsId(json['context'])) {
17
+ eventlog = ldPropertyAsId(json['context']);
18
+ }
19
+ else {
20
+ logger.error(`failed to find valid context or object`);
21
+ return { path, options, success: false };
22
+ }
23
+
24
+ if (! eventlog) {
25
+ logger.error(`failed to find eventlog`);
26
+ return { path, options, success: false };
27
+ }
28
+
29
+ const eventLogPath = parseEventLog(eventlog,options);
30
+
31
+ if (eventLogPath) {
32
+ // Storing the eventlog path to the options.
33
+ // Maybe bad practice..but it is a workflow attribute like in Nifi :P
34
+ options['eventlog'] = {
35
+ 'id': eventlog ,
36
+ 'path': eventLogPath
37
+ };
38
+ return { path, options, success: true };
39
+ }
40
+ else {
41
+ logger.error(`artifact ${artifact} is not known here...`);
42
+ return { path, options, success: false };
43
+ }
44
+ }
45
+ catch(e) {
46
+ logger.error(`failed to process ${path}`);
47
+ logger.error(e);
48
+ return { path, options, success: false };
49
+ }
50
+ }
51
+
52
+ module.exports = { handle };
package/lib/handler.js CHANGED
@@ -23,35 +23,45 @@ async function defaultInboxHandler({path,options}) {
23
23
  maxQueue: queue_size
24
24
  });
25
25
 
26
- try {
27
- const [prms,locks] = await inboxProcessor(pool,path,options);
28
- const results = await Promise.all(prms);
29
-
30
- for (let i = 0 ; i < results.length ; i++) {
31
- const result = results[i];
32
- const success = result['success'];
33
- const notification = result['path'];
34
-
35
- if (success) {
36
- logger.info(`processing ${notification} is a success`);
37
- if (fs.existsSync(notification)) {
38
- logger.debug(`removing ${notification}`);
39
- fs.unlinkSync(result['path']);
26
+ const loopWait = options['loop'] || 0;
27
+
28
+ do {
29
+ try {
30
+ const [prms,locks] = await inboxProcessor(pool,path,options);
31
+ const results = await Promise.all(prms);
32
+
33
+ for (let i = 0 ; i < results.length ; i++) {
34
+ const result = results[i];
35
+ const success = result['success'];
36
+ const notification = result['path'];
37
+
38
+ if (success) {
39
+ logger.info(`processing ${notification} is a success`);
40
+ if (fs.existsSync(notification)) {
41
+ logger.debug(`removing ${notification}`);
42
+ fs.unlinkSync(result['path']);
43
+ }
40
44
  }
45
+ else {
46
+ logger.warn(`processing ${notification} is a failure`);
47
+ logger.debug(`moving ${notification} to ${options['error']}`);
48
+ moveTo(notification,options['error']);
49
+ }
50
+
51
+ // release lock
52
+ if (locks[i]) locks[i]();
41
53
  }
42
- else {
43
- logger.warn(`processing ${notification} is a failure`);
44
- logger.debug(`moving ${notification} to ${options['error']}`);
45
- moveTo(notification,options['error']);
46
- }
54
+ }
55
+ catch (e) {
56
+ logger.error(e);
57
+ }
47
58
 
48
- // release lock
49
- if (locks[i]) locks[i]();
59
+ if (loopWait) {
60
+ logger.debug(`sleep ${loopWait} secs...`);
61
+ await new Promise(resolve => setTimeout(resolve, loopWait*1000));
50
62
  }
51
63
  }
52
- catch (e) {
53
- logger.error(e);
54
- }
64
+ while (loopWait > 0);
55
65
  }
56
66
 
57
67
  async function inboxProcessor(pool,path,options) {
package/lib/util.js CHANGED
@@ -156,6 +156,40 @@ function ldPropertyAsId(object_or_string) {
156
156
 
157
157
  function parseArtifact(url,options) {
158
158
  logger.debug(`isArtifact(${url})?`);
159
+
160
+ const resource = parseLocalResource(url,options);
161
+
162
+ if (resource === null) {
163
+ return null;
164
+ }
165
+
166
+ const { filePath , metaPath , json} = resource;
167
+
168
+ if (json['X-Artifact']) {
169
+ return filePath;
170
+ }
171
+ else {
172
+ return null;
173
+ }
174
+ }
175
+
176
+ function parseEventLog(url,options) {
177
+ logger.debug(`isEventLog(${url})?`);
178
+
179
+ const resource = parseLocalResource(url,options);
180
+
181
+ if (resource === null) {
182
+ return null;
183
+ }
184
+
185
+ const { filePath , metaPath , json} = resource;
186
+
187
+ return filePath;
188
+ }
189
+
190
+ function parseLocalResource(url,options) {
191
+ logger.debug(`isLocalResource(${url})?`);
192
+
159
193
  const base = options['base'] ? options['base'] :
160
194
  options['host'] && options['port'] ?
161
195
  `http://${options['host']}:${options['port']}` :
@@ -163,9 +197,9 @@ function parseArtifact(url,options) {
163
197
 
164
198
  const public = options['public'];
165
199
 
166
- const filePath = url.substring(base.length + 1);
200
+ const filePath = `${public}/` + url.substring(base.length + 1);
167
201
 
168
- const metaPath = `${public}/${filePath}.meta`;
202
+ const metaPath = `${filePath}.meta`;
169
203
 
170
204
  logger.debug(`searching ${metaPath}`);
171
205
 
@@ -181,12 +215,7 @@ function parseArtifact(url,options) {
181
215
  return null;
182
216
  }
183
217
 
184
- if (json['X-Artifact']) {
185
- return `${public}/${filePath}`;
186
- }
187
- else {
188
- return null;
189
- }
218
+ return { filePath, metaPath, json };
190
219
  }
191
220
 
192
221
  module.exports = {
@@ -198,5 +227,7 @@ module.exports = {
198
227
  dynamic_handler ,
199
228
  parseAsJSON ,
200
229
  parseArtifact ,
230
+ parseEventLog ,
231
+ parseLocalResource ,
201
232
  ldPropertyAsId
202
233
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ldn-inbox-server",
3
- "version": "1.3.2",
3
+ "version": "1.4.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>",
@@ -8,11 +8,11 @@
8
8
  "scripts": {
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
- "handle-inbox": "npx ldn-inbox-server handler @inbox -hn ./handler/accept_notification_handler.js",
12
- "handle-outbox": "npx ldn-inbox-server handler @outbox -hn ./handler/send_notification_handler.js",
13
- "handle-eventlog": "npx ldn-inbox-server handler @inbox -hn handler/eventlog_notification_handler.js",
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",
11
+ "handle-inbox": "npx ldn-inbox-server handler @inbox -hn ./handler/notification_handler/accept.js",
12
+ "handle-outbox": "npx ldn-inbox-server handler @outbox -hn ./handler/notification_handler/send_notification.js",
13
+ "handle-eventlog": "npx ldn-inbox-server handler @inbox -hn handler/notification_handler/eventlog.js",
14
+ "handle-inbox-multi": "npx ldn-inbox-server handler @inbox -hn ./handler/notification_handler/multi.js",
15
+ "handle-outbox-multi": "npx ldn-inbox-server handler @outbox -hn ./handler/notification_handler/multi.js",
16
16
  "clean": "rm -rf error/* inbox/* outbox/* public/events/* public/events/log/* public/artifacts/artifact1 public/artifacts/artifact2 public/artifacts/*.jsonld*"
17
17
  },
18
18
  "bin": "./bin/ldn-inbox-server.js",
@@ -25,6 +25,7 @@
25
25
  "commander": "^12.0.0",
26
26
  "dotenv": "^16.4.5",
27
27
  "exponential-backoff": "^3.1.1",
28
+ "jsonpath": "^1.1.1",
28
29
  "jsonschema": "^1.4.1",
29
30
  "md5": "^2.3.0",
30
31
  "mellon-server": "^1.0.8",
@@ -1,61 +0,0 @@
1
- const { dynamic_handler , parseAsJSON } = require('../lib/util');
2
- const logger = require('../lib/util.js').getLogger();
3
-
4
- /**
5
- * Demonstration notification handler that start multiple notification handlers.
6
- * Requires a config file that specifies which handlers to start.
7
- */
8
- async function handle({path,options}) {
9
- let success = false;
10
-
11
- const config = parseAsJSON(options['config']);
12
-
13
- if (! config) {
14
- logger.error('no configuration found for multi_notification_handler');
15
- return { path, options, success: false };
16
- }
17
-
18
- const handlers = config['notification_handler']?.['multi']?.['handlers'];
19
-
20
- if (! handlers) {
21
- logger.error('no notification_handler.multi.handlers key in configuration file');
22
- return { path, options, success: false };
23
- }
24
-
25
- try {
26
- logger.info(`starting multi handler`);
27
-
28
- for (let i = 0 ; i < handlers.length ; i++) {
29
- logger.info(`starting ${handlers[i]}`);
30
-
31
- const handler = dynamic_handler(handlers[i],null);
32
-
33
- if (! handler) {
34
- throw new Error(`failed to load ${handlers[i]}`);
35
- }
36
-
37
- const result = await handler({path,options});
38
-
39
- if (result['success']) {
40
- logger.info(`finished ${handlers[i]}`);
41
- }
42
- else {
43
- throw new Error(`Eek! ${handlers[i]} failed`);
44
- }
45
- }
46
-
47
- success = true;
48
- }
49
- catch (e) {
50
- logger.error(`failed to process ${path}`);
51
- logger.error(e);
52
-
53
- success = false;
54
- }
55
-
56
- logger.info(`finished multi handler`);
57
-
58
- return { path, options, success: success };
59
- }
60
-
61
- module.exports = { handle };