ldn-inbox-server
Version:
A demonstration Event Notifications Inbox server
189 lines (156 loc) • 6.18 kB
JavaScript
const fs = require('fs');
const md5 = require('md5');
const lockfile = require('proper-lockfile');
const logger = require('../../lib/util.js').getLogger();
/**
* Demonstration event log handler
*/
async function handle({path,options,config,notification}) {
if (! config) {
logger.error('no configuration found for eventlog_notification_handler');
return { path, options, success: false };
}
if (!config['log'] || !config['dir']) {
logger.error('no log/dir entry for notification_handler.eventlog configuration');
return { path, options, success: false };
}
const base = options['base'] ? options['base'] :
options['host'] && options['port'] ?
`http://${options['host']}:${options['port']}` :
'http://localhost:8000';
let eventLog = config['log'];
let eventDir = config['dir'];
let artifactPath = undefined;
if (options['artifact']) {
artifactPath = options['artifact']['id'].substring(base.length+1);
logger.info(artifactPath);
}
if (eventLog.match(/@artifact(:[a-zA-Z]+)?@/)) {
if (options['artifact']) {
if (eventLog.match(/@artifact:strip@/)) {
eventLog = eventLog.replaceAll(/@artifact(:[a-zA-Z]+)?@/g,artifactPath.replaceAll(/\.\w+$/g,''));
}
else {
eventLog = eventLog.replaceAll(/@artifact(:[a-zA-Z]+)?@/g,artifactPath);
}
}
else {
logger.error(`requested to parse ${eventLog} but no artifact information available`);
return { path, options, success: false };
}
}
if (eventDir.match(/@artifact(:[a-zA-Z]+)?@/)) {
if (options['artifact']) {
if (eventDir.match(/@artifact:strip@/)) {
eventDir = eventDir.replaceAll(/@artifact(:[a-zA-Z]+)?@/g,artifactPath.replaceAll(/\.\w+$/g,''));
}
else {
eventDir = eventDir.replaceAll(/@artifact(:[a-zA-Z]+)?@/g,artifactPath);
}
}
else {
logger.error(`requested to parse ${eventDir} but no artifact information available`);
return { path, options, success: false };
}
}
try {
const json = fs.readFileSync(path, { encoding: 'utf-8' });
const fileName = path.split('/').pop();
if (! fs.existsSync(`${options['public']}/${eventDir}`)) {
logger.info(`creating ${options['public']}/${eventDir}`);
fs.mkdirSync(`${options['public']}/${eventDir}`, { recursive : true });
}
const eventFile = `${options['public']}/${eventDir}/${fileName}`;
fs.writeFileSync(eventFile, json);
// Updating metadata file
const metaFile = `${options['public']}/${eventLog}.meta`;
fs.writeFileSync(metaFile, JSON.stringify({
'Content-Type': 'application/ld+json',
'Last-Modified': nowISO(),
'Access-Control-Allow-Origin': '*',
'Access-Control-Expose-Headers': 'Link, Link-Template'
},null,4));
const eventMetaFile = `${eventFile}.meta`;
fs.writeFileSync(eventMetaFile, JSON.stringify({
'Content-Type': 'application/ld+json',
'Last-Modified': nowISO(),
'Access-Control-Allow-Origin': '*',
'Access-Control-Expose-Headers': 'Link, Link-Template'
},null,4));
// Store the path in the options .. yeah yeah we know ugly but it works for now
const eventPath = `${eventDir}/${fileName}`;
const eventId = `${base}/${eventPath}`;
const eventLogId = `${base}/${eventLog}`;
options['eventlog'] = {
'id': eventLogId ,
'file': `${options['public']}/${eventLog}` ,
'dir': `${options['public']}/${eventDir}` ,
'item': {
'id' : eventId ,
'file' : eventFile
}
};
await updateEventLog({path,options});
return { path, options, success: true };
}
catch(e) {
logger.error(`failed to process ${path}`);
logger.error(e);
return { path, options, success: false };
}
}
async function updateEventLog({path,options}) {
logger.info(`updating eventlog for ${path}`);
try {
const notification = fs.readFileSync(path, { encoding: 'utf-8'});
const notification_checksum = md5(notification);
const entry = options['eventlog']['item']['id'];
const eventLog = options['eventlog']['file'];
let json;
if (fs.existsSync(eventLog)) {
json = JSON.parse(fs.readFileSync(eventLog, { encoding: 'utf-8'}));
}
else {
json = {
"@context": "https://labs.eventnotifications.net/contexts/eventlog.jsonld",
"type": "EventLog",
"member": []
};
}
if (json['member'].findIndex( (e) => e['id'] === entry) >= 0) {
logger.info(`${entry} already in ${eventLog}`);
}
else {
logger.info(`updating ${eventLog}`);
json['member'].push({
"id": entry ,
"checksum": {
"type": "Checksum",
"algorithm": "spdx:checksumAlgorithm_md5",
"checksumValue": notification_checksum
}
});
if (fs.existsSync(eventLog)) {
try {
const lock = await lockfile(eventLog, { retries: 10 });
fs.writeFileSync(eventLog,JSON.stringify(json,null,4));
lock(); // release
}
catch (e) {
logger.error(`failed to update ${eventLog}`);
}
}
else {
fs.writeFileSync(eventLog,JSON.stringify(json,null,4));
}
}
return true;
}
catch (e) {
return false;
}
}
function nowISO() {
return (new Date()).toUTCString();
}
module.exports = { handle };