ldn-inbox-server 1.2.1 → 1.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.
@@ -2,6 +2,7 @@ LOG4JS=INFO
2
2
  LDN_SERVER_HOST=localhost
3
3
  LDN_SERVER_PORT=8000
4
4
  LDN_SERVER_INBOX_GLOB="^.*\.jsonld$"
5
+ LDN_SERVER_BASEURL=http://localhost:8000
5
6
  LDN_SERVER_INBOX_BATH_SIZE=5
6
7
  LDN_SERVER_INBOX_URL=inbox/
7
8
  LDN_SERVER_INBOX_PATH=./inbox
package/README.md CHANGED
@@ -45,14 +45,17 @@ npx ldn-inbox-server handle @outbox
45
45
  ## Environment
46
46
 
47
47
  - `LOG4JS` : log4js logging level
48
- - `LDN_SERVER_HOST` : default LDN inbox host
49
- - `LDN_SERVER_PORT` : default LDN inbox port
50
- - `LDN_SERVER_INBOX_URL` : default LDN inbox url (path)
51
- - `LDN_SERVER_INBOX_PATH` : default LDN inbox path
52
- - `LDN_SERVER_ERROR_PATH` : default LDN error path
53
- - `LDN_SERVER_OUTBOX_PATH` : default LDN outbox path
54
- - `LDN_SERVER_PUBLIC_PATH` : default public (HTML) path
55
- - `LDN_SERVER_JSON_SCHEMA` : default notification JSON validation schema
48
+ - `LDN_SERVER_HOST` : LDN inbox host
49
+ - `LDN_SERVER_PORT` : LDN inbox port
50
+ - `LDN_SERVER_INBOX_URL` : LDN inbox url (path)
51
+ - `LDN_SERVER_INBOX_PATH` : LDN inbox path
52
+ - `LDN_SERVER_ERROR_PATH` : LDN error path
53
+ - `LDN_SERVER_OUTBOX_PATH` : LDN outbox path
54
+ - `LDN_SERVER_PUBLIC_PATH` : public (HTML) path
55
+ - `LDN_SERVER_JSON_SCHEMA` : notification JSON validation schema
56
+ - `LDN_SERVER_BASEURL` : baseurl of the LDN inbox server
57
+ - `LDN_SERVER_INBOX_GLOB` : glob of files to process in inbox directory
58
+ - `LDN_SERVER_HAS_PUBLIC_INBOX` : if true, then public read access is allowed on inbox
56
59
 
57
60
  ## Extend
58
61
 
@@ -11,26 +11,30 @@ const PORT = process.env.LDN_SERVER_PORT ?? 8000;
11
11
  const INBOX_GLOB = process.env.LDN_SERVER_INBOX_GLOB ?? "^.*\\.jsonld$";
12
12
  const INBOX_BATCH_SIZE = process.env.LDN_SERVER_INBOX_BATH_SIZE ?? 5;
13
13
  const INBOX_URL = process.env.LDN_SERVER_INBOX_URL ?? 'inbox/';
14
+ const INBOX_BASE_URL = process.env.LDN_SERVER_BASEURL ?? 'http://localhost:8000';
14
15
  const PUBLIC_PATH = process.env.LDN_SERVER_PUBLIC_PATH ?? './public';
15
16
  const INBOX_PATH = process.env.LDN_SERVER_INBOX_PATH ?? './inbox';
16
17
  const ERROR_PATH = process.env.LDN_SERVER_ERROR_PATH ?? './error';
17
18
  const OUTBOX_PATH = process.env.LDN_SERVER_OUTBOX_PATH ?? './outbox';
18
19
  const JSON_SCHEMA_PATH = process.env.LDN_SERVER_JSON_SCHEMA ?? './config/notification_schema.json';
20
+ const HAS_PUBLIC = process.env.LDN_SERVER_HAS_PUBLIC_INBOX ?? 0;
19
21
 
20
22
  program
21
23
  .name('lnd-inbox-server')
22
- .version('1.2.1')
24
+ .version('1.2.2')
23
25
  .description('A demonstration Event Notifications Inbox server');
24
26
 
25
27
  program
26
28
  .command('start-server')
27
29
  .option('--host <host>','host',HOST)
28
30
  .option('--port <port>','port',PORT)
29
- .option('--url <url>','url',INBOX_URL)
31
+ .option('--url <path>','path',INBOX_URL)
32
+ .option('--base <url>','base url',INBOX_BASE_URL)
30
33
  .option('--inbox <inbox>','inbox',INBOX_PATH)
31
34
  .option('--public <public>','public',PUBLIC_PATH)
32
35
  .option('--schema <schema>','json schema',JSON_SCHEMA_PATH)
33
36
  .option('--registry <registry>','registry',null)
37
+ .option('--inbox-public','public readable inbox',HAS_PUBLIC)
34
38
  .action( (options) => {
35
39
  inbox_server(options);
36
40
  });
@@ -39,6 +43,7 @@ program
39
43
  .command('handler')
40
44
  .option('--inbox <inbox>','inbox',INBOX_PATH)
41
45
  .option('--outbox <outbox>','outbox',OUTBOX_PATH)
46
+ .option('--public <public>','public',PUBLIC_PATH)
42
47
  .option('--error <errbox>','errbox',ERROR_PATH)
43
48
  .option('--loop <seconds>', 'run in a loop',0)
44
49
  .option('--batch_size <num>','batch size to process',INBOX_BATCH_SIZE)
@@ -1,5 +1,7 @@
1
1
  const fs = require('fs');
2
2
 
3
+ // Demonstration of an inbox handler (don't use it the one in lib/handler.js
4
+ // is much more mature)
3
5
  async function handle({path,options}) {
4
6
  console.log(`handleInbox(${path},..)`);
5
7
  fs.readdir(path, (err,files) => {
@@ -0,0 +1,103 @@
1
+ const fs = require('fs');
2
+ const fsPath = require('path');
3
+ const lockfile = require('proper-lockfile');
4
+ const logger = require('../lib/util.js').getLogger();
5
+
6
+ const EVENT_DIR = 'events';
7
+ const EVENT_LOG = 'events.jsonld';
8
+
9
+ async function handle({path,options}) {
10
+ logger.info(`parsing notification ${path}`);
11
+
12
+ try {
13
+ const json = JSON.parse(fs.readFileSync(path, { encoding: 'utf-8'}));
14
+
15
+ const fileName = path.split('/').pop();
16
+ const logDir = fsPath.join(options['public'],EVENT_DIR,'log');
17
+
18
+ if (! fs.existsSync(logDir)) {
19
+ logger.info(`creating ${logDir}`);
20
+ fs.mkdirSync(logDir, { recursive : true });
21
+ }
22
+
23
+ const outboxFile = fsPath.join(logDir,fileName);
24
+
25
+ fs.writeFileSync(outboxFile, JSON.stringify(json));
26
+
27
+ // Updating metadata file
28
+ const metaFile = outboxFile + '.meta';
29
+
30
+ fs.writeFileSync(metaFile, JSON.stringify({
31
+ 'Content-Type': 'application/ld+json',
32
+ 'Last-Modified': nowISO()
33
+ },null,4));
34
+
35
+ await updateEventLog({path,options});
36
+
37
+ return { path,options, success: true };
38
+ }
39
+ catch(e) {
40
+ logger.error(`failed to process ${path}`);
41
+ logger.error(e);
42
+ return { path,options, success: false };
43
+ }
44
+ }
45
+
46
+ async function updateEventLog({path,options}) {
47
+ logger.info(`updating eventlog for ${path}`);
48
+
49
+ try {
50
+ const baseUrl = process.env.LDN_SERVER_BASEURL ?? "";
51
+ const fileName = path.split('/').pop();
52
+ const entry = `${baseUrl}/${EVENT_DIR}/log/${fileName}`;
53
+
54
+ const eventLog = fsPath.join(options['public'],EVENT_DIR,EVENT_LOG);
55
+
56
+ let json;
57
+
58
+ if (fs.existsSync(eventLog)) {
59
+ json = JSON.parse(fs.readFileSync(eventLog, { encoding: 'utf-8'}));
60
+ }
61
+ else {
62
+ json = {
63
+ "@context": "https://labs.eventnotifications.net/contexts/eventlog.jsonld",
64
+ "type": "EventLog",
65
+ "member": []
66
+ };
67
+ }
68
+
69
+ if (json['member'].findIndex( (e) => e === entry) >= 0) {
70
+ logger.info(`${entry} already in ${eventLog}`);
71
+ }
72
+ else {
73
+ logger.info(`updating ${eventLog}`);
74
+
75
+ json['member'].push(entry);
76
+
77
+ if (fs.existsSync(eventLog)) {
78
+ try {
79
+ const lock = await lockfile(eventLog, { retries: 10 });
80
+ fs.writeFileSync(eventLog,JSON.stringify(json,null,4));
81
+ lock(); // release
82
+ }
83
+ catch (e) {
84
+ logger.error(`failed to update ${eventLog}`);
85
+ }
86
+ }
87
+ else {
88
+ fs.writeFileSync(eventLog,JSON.stringify(json,null,4));
89
+ }
90
+ }
91
+
92
+ return true;
93
+ }
94
+ catch (e) {
95
+ return false;
96
+ }
97
+ }
98
+
99
+ function nowISO() {
100
+ return (new Date()).toUTCString();
101
+ }
102
+
103
+ module.exports = { handle };
package/lib/index.js CHANGED
@@ -14,11 +14,15 @@ const logger = getLogger();
14
14
 
15
15
  let INBOX_URL = 'inbox/';
16
16
  let INBOX_PATH = './inbox';
17
+ let INBOX_BASE_URL = 'http://localhost:8000';
18
+ let INBOX_PUBLIC_READABLE = 0;
17
19
  let JSON_SCHEMA = '';
18
20
 
19
21
  function inbox_server(options) {
20
22
  INBOX_URL = options['url'];
21
23
  INBOX_PATH = options['inbox'];
24
+ INBOX_BASE_URL = options['base'];
25
+ INBOX_PUBLIC_READABLE = options['inboxPublic'];
22
26
  JSON_SCHEMA = JSON.parse(fs.readFileSync(options['schema'], { encoding: 'utf-8'}));
23
27
  let registry = [{ path : `${INBOX_URL}.*` , do: doInbox }];
24
28
 
@@ -44,12 +48,113 @@ function inbox_server(options) {
44
48
  }
45
49
 
46
50
  function doInbox(req,res) {
47
- if (req.method !== 'POST') {
51
+ if (req.method === 'GET' && INBOX_PUBLIC_READABLE) {
52
+ doInboxGET(req,res);
53
+ }
54
+ if (req.method == 'HEAD' && INBOX_PUBLIC_READABLE) {
55
+ doInboxHEAD(req,res);
56
+ }
57
+ else if (req.method === 'POST') {
58
+ doInboxPOST(req,res);
59
+ }
60
+ else {
48
61
  logger.error(`tried method ${req.method} on inbox : forbidden`);
49
62
  res.writeHead(403);
50
63
  res.end('Forbidden');
51
64
  return;
52
65
  }
66
+ }
67
+
68
+ function doInboxGET(req,res) {
69
+ const pathItem = req.url.substring(INBOX_URL.length);
70
+
71
+ logger.debug(`doInboxGET (for ${pathItem})`);
72
+
73
+ if (pathItem === '/') {
74
+ doInboxGET_Index(req,res);
75
+ }
76
+ else if (pathItem.match(/^\/[a-z0-9]+\.jsonld$/)) {
77
+ doInboxGET_Read(req,res);
78
+ }
79
+ else {
80
+ res.writeHead(403);
81
+ res.end('Forbidden');
82
+ }
83
+ }
84
+
85
+ function doInboxHEAD(req,res) {
86
+ const pathItem = req.url.substring(INBOX_URL.length);
87
+
88
+ logger.debug(`doInboxHEAD (for ${pathItem})`);
89
+
90
+ if (pathItem === '/') {
91
+ res.setHeader('Content-Type','application/ld+json');
92
+ res.writeHead(200);
93
+ res.end();
94
+ return;
95
+ }
96
+
97
+ if (pathItem.match(/^\/[a-z0-9]+\.jsonld$/)) {
98
+ const id = pathItem.substring(1);
99
+ const result = getBody(id);
100
+
101
+ if (result) {
102
+ res.setHeader('Content-Type','application/ld+json');
103
+ res.writeHead(200);
104
+ res.end();
105
+ return;
106
+ }
107
+ else {
108
+ res.writeHead(403);
109
+ res.end('Forbidden');
110
+ }
111
+ }
112
+ else {
113
+ res.writeHead(403);
114
+ res.end('Forbidden');
115
+ return;
116
+ }
117
+ }
118
+
119
+ function doInboxGET_Index(req,res) {
120
+ const notifications = listInbox().map( (e) => {
121
+ return INBOX_BASE_URL + '/' + INBOX_URL + e;
122
+ });
123
+
124
+ const result = {
125
+ "@context": "http://www.w3.org/ns/ldp",
126
+ "@id": INBOX_BASE_URL + '/' + INBOX_URL,
127
+ "contains": notifications
128
+ };
129
+
130
+ res.writeHead(200);
131
+ res.end(JSON.stringify(result,null,2));
132
+ }
133
+
134
+ function doInboxGET_Read(req,res) {
135
+ const pathItem = req.url.substring(INBOX_URL.length);
136
+
137
+ const result = getBody(pathItem.substring(1));
138
+
139
+ if (result) {
140
+ res.setHeader('Content-Type','application/ld+json');
141
+ res.writeHead(200);
142
+ res.end(result);
143
+ }
144
+ else {
145
+ res.writeHead(403);
146
+ res.end('Forbidden');
147
+ }
148
+ }
149
+
150
+ function doInboxPOST(req,res) {
151
+ const pathItem = req.url.substring(INBOX_URL.length);
152
+
153
+ if (pathItem !== '/') {
154
+ req.writeHead(403);
155
+ res.end('Forbidden');
156
+ return;
157
+ }
53
158
 
54
159
  const headers = req.headers;
55
160
 
@@ -88,6 +193,35 @@ function doInbox(req,res) {
88
193
  });
89
194
  }
90
195
 
196
+ function listInbox() {
197
+ const glob = new RegExp("^.*\\.jsonld$");
198
+
199
+ logger.debug(`listInbox()`);
200
+
201
+ try {
202
+ const entries = fs.readdirSync(INBOX_PATH).filter( (file) => {
203
+ return file.match(glob);
204
+ });
205
+ return entries;
206
+ }
207
+ catch(e) {
208
+ logger.error(e);
209
+ return [];
210
+ }
211
+ }
212
+
213
+ function getBody(id) {
214
+ logger.debug(`getBody(${id})`);
215
+
216
+ try {
217
+ return fs.readFileSync(INBOX_PATH + '/' + id, {encoding : 'utf-8'});
218
+ }
219
+ catch(e) {
220
+ logger.error(e);
221
+ return null;
222
+ }
223
+ }
224
+
91
225
  function storeBody(data) {
92
226
  try {
93
227
  const id = md5(data);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ldn-inbox-server",
3
- "version": "1.2.1",
3
+ "version": "1.2.2",
4
4
  "description": "A demonstration Event Notifications Inbox server",
5
5
  "main": "lib/index.js",
6
6
  "author": "Patrick Hochstenbach <Patrick.Hochstenbach@UGent.be>",
@@ -10,6 +10,7 @@
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
12
  "handle-outbox": "npx ldn-inbox-server handler @outbox",
13
+ "handle-eventlog": "npx ldn-inbox-server handler @inbox -hn handler/eventlog_notification_handler.js",
13
14
  "clean": "rm error/* inbox/* outbox/*"
14
15
  },
15
16
  "bin": "./bin/ldn-inbox-server.js",
File without changes