ldn-inbox-server
Version:
A demonstration Event Notifications Inbox server
297 lines (193 loc) • 9.38 kB
Markdown
# ldn-inbox-server
An experimental [LDN](https://www.w3.org/TR/ldn/) inbox server for [Event Notification](https://www.eventnotifications.net) messages.
## Install
```
yarn add ldn-inbox-server
```
## Example
Create required directories
```
mkdir config inbox public
```
Start the server:
```
npx ldn-inbox-server start-server --port 8000
```
Send a demonstration Event Notifications message:
```
curl -X POST -H 'Content-Type: application/ld+json' --data-binary '@examples/offer.jsonld' http://localhost:8000/inbox/
```
Start an inbox handler with a demo handler (that creates an `Accept` message in the `./outbox`).
```
npx ldn-inbox-server handler @inbox -hn ./handler/accept_notification_handler.js
```
Start an outbox handler that send the notifications that are available outbox:
```
npx ldn-inbox-server handler @outbox -hn ./handler/send_notification_handler.js
```
## Environment
- `LOG4JS` : log4js logging level
- `LDN_SERVER_HOST` : LDN inbox host
- `LDN_SERVER_PORT` : LDN inbox port
- `LDN_SERVER_INBOX_URL` : LDN inbox url (path)
- `LDN_SERVER_INBOX_PATH` : LDN inbox path
- `LDN_SERVER_ERROR_PATH` : LDN error path
- `LDN_SERVER_OUTBOX_PATH` : LDN outbox path
- `LDN_SERVER_PUBLIC_PATH` : public (HTML) path
- `LDN_SERVER_JSON_SCHEMA` : notification JSON validation schema
- `LDN_SERVER_BASEURL` : baseurl of the LDN inbox server
- `LDN_SERVER_INBOX_GLOB` : glob of files to process in inbox directory
- `LDN_SERVER_HAS_PUBLIC_INBOX` : if true, then public read access is allowed on the inbox
- `LDN_SERVER_HAS_WRITABLE_INBOX` : if true, then public write access is allowed on the inbox
- `LDN_SERVER_LOCKDIR` : directory to store optional lock files for handler
## Multiple inboxes
Instead of a single inbox, multiple inboxes can be configured by adding a JSON configuration file to the installation. The JSON file should contain a `registry` entry with contains an array of inbox configuration. An example:
```
{
"registry": [
{ "path": "inbox/.*" ,
"with": {
"url": "inbox/",
"inbox": "./inbox",
"inboxPublic": 1,
"inboxWritable": 1,
"schema": "./config/schema1.json"
}},
{ "path": "inbox2/.*" ,
"with": {
"url": "inbox2/",
"inbox": "./inbox2",
"inboxPublic": 1,
"inboxWritable": 0,
"schema": "./config/schema2.json"
}}
]
}
```
## Extend
Server extensions are possible by providing custom inbox and notification handlers. E.g.
```
npx ldn-inbox-server handler @inbox -hn handler/my_handler.js
```
Or, in JavaScript:
```
const { handle_inbox } = require('ldn-inbox-handler');
main();
async function main() {
await handle_inbox('./inbox', {
'inbox': './inbox',
'outbox': './outbox',
'public': './public',
'error': './error',
'batch_size': 5,
'glob': '^.*\\.jsonld$',
'config': './config/inbox_config.json',
'notification_handler': 'handler/my_handler.js'
});
}
```
with `my_handler.js` :
```
async function handle({path,options}) {
//...
return { path, options, success: true };
}
module.exports = { handle };
```
## Hints
A handler can be started on any directory. E.g. a workflow might be:
- have an "inbox" handler to validate incoming LDN messages
- valid LDN messages will be saved into the "accepted" box
- invalid LDN messages will be saved into the "error" box
- have an "accepted" handler to process valid LDN messages
- processed LDN messages will end up in the "outbox" box
- invalid processing will be saved into the "error" box
## Handlers
### Accept handler
A handler that creates for an incoming notification an `Accept` notification in the `@outbox`.
### Eventlog handler
A handler that updates an event log with the incoming notification.
Requires configuration properties:
- `log`: the path to the event log (starting from the `public` directory)
- `dir`: the path to a container to store the events (starting from the `public` directory)
The `log` and `dir` path may contain a `@artifact(:strip)?@` directive to fill in the
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`.
### Json Path handler
A handler that accepts a notifiction when it matches one or more JSON paths
Requires configuration properties:
- anyOf : an array of json path matchers, the combination should be interpreted as a logical `OR`.
- every json path matcher is an array of single matchers, the combination should be interpered as a logical `AND`.
A single matcher needs two properties:
- path : a json path
- value : a value
The json path matches when one of:
- On the json path an array is found and the value is included in the array
- On the json path a string or number is found and the value is equal to this string or number
### Multi handler
A `handler/multi_notification_handler.js` is available to start multiple handler for each notification messages. The handlers to start are specified in a configuration file that can be passed via the `config` parameter of an `handle_inbox`. For 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`.
The multi handler requires a configuration file with properties `notification_handler.multi.handlers` which is an array of array. Each outer array defines a workflow: a list of handlers that should be executed sequentially on a notification until one handler returns a `success=false` response or the last handler returns a `success=true` response, or a handler returns `break=true` (which will skip all other steps in a workflow). The multi handler is successful when at least one workflow could be completed with success.
Each handler is defined by a hash containing as `id` property the path to the handler and optionally other property keys that will be passed to the handlers in the `config` section.
Optionally when a `fallback` handler is defined as option it will be attempted when a handler in a sequence returns a `false` response.
### On Error handler
A handler that sets the `fallback` for a workflow sequence.
### Offer memento handler
A handler to `Offer` an event log to a memento server.
Requires configuration properties:
- `actor`: the LDN+AS2 `actor` to use in a notification
- `target`: the LDN+AS2 `target` to use in a notification
### Send notification handler
A handler to send notification that live in the `@outbox` via the LDN protocol to the LDN `target`.
If the environoment `DEMO_MODE=NO_NOTIFICATIONS` is set, no real notifications will be sent.
### Type handler
A handler that accepts any notification with a type that matches one of the `anyOf` types.
### Valid artifact handler
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.
Generates the following options keys:
- artifact.id : the URL of the artifact
- artifact.path : the local path to the artifact
### Valid event log handler
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.
Generates the following options keys:
- eventlog.id : the URL of the event log
- eventlog.path : the local path of the event log
## Artifact support
This code base contains Event Notifications support for Data Node artifacts. See the examples
in `public/artifacts-example`. Move this directory tp `public/artifacts` to get a running example.
- Each artifact requires at least a `.meta` file with the `X-Artifact` header set to `true` to be recognized by the software as an artifact
- Each artifact should update the `Link-Template` header in the `.meta` file
- The config files in `config/inbox_config.json` and `config/outbox_config.json` define the location of the possible event logs for the artifact
## API
### getLogger()
Returns a LOG4JS logger instance.
### fetchOriginal(url)
Resolve the url and return the textual body.
### backOff_fetch(url,options)
Return the result of `fetch(url,options)` (tries many times untill the server responds).
### sendNotification(url,payload,options)
Send to `url` the payload uptionally a `fetch` can be provided in the options.
### moveTo(oldPath, newPath)
Move a file from an oldPath to a newPath .
### parseAsJSON(path)
Parse the path into a JSON document (or return null when failed).
### generateId()
Generate a uuid URN.
### generatePublished()
Generate a ISO8601 date time string.
### parseConfig(path)
Parse a path containing `.json` | `.jsonld` | `.json5` | `.yaml` | `.yml` into a
JavaScript object.
## Docker
Pull
```
docker pull hochstenbach/ldn-inbox-server:v0.0.1
```
```
docker run -p 8000:8000 hochstenbach/ldn-inbox-server:v0.0.1
```
Post a notification:
```
curl -X POST -H 'Content-Type: application/ld+json' --data-binary '@examples/offer.jsonld' http://localhost:8000/inbox/
```
Check the inbox: http://localhost:8000/inbox/
## See also
- [mellon-server](https://www.npmjs.com/package/mellon-server)