2015-11-06 11:05:32 +00:00
|
|
|
'use strict';
|
|
|
|
|
2016-04-09 23:14:00 +00:00
|
|
|
module.exports.create = function (webserver, xconfx, state) {
|
|
|
|
console.log('DEBUG create worker');
|
|
|
|
|
2015-11-12 11:14:59 +00:00
|
|
|
if (!state) {
|
|
|
|
state = {};
|
|
|
|
}
|
|
|
|
|
|
|
|
var PromiseA = state.Promise || require('bluebird');
|
|
|
|
var memstore;
|
|
|
|
var sqlstores = {};
|
|
|
|
var systemFactory = require('sqlite3-cluster/client').createClientFactory({
|
2016-04-09 23:14:00 +00:00
|
|
|
dirname: xconfx.varpath
|
|
|
|
, prefix: 'com.daplie.walnut.'
|
2015-11-12 11:14:59 +00:00
|
|
|
//, dbname: 'config'
|
|
|
|
, suffix: ''
|
|
|
|
, ext: '.sqlite3'
|
2016-04-09 23:14:00 +00:00
|
|
|
, sock: xconfx.sqlite3Sock
|
|
|
|
, ipcKey: xconfx.ipcKey
|
2015-11-12 11:14:59 +00:00
|
|
|
});
|
2016-04-09 23:14:00 +00:00
|
|
|
/*
|
2015-11-12 11:14:59 +00:00
|
|
|
var clientFactory = require('sqlite3-cluster/client').createClientFactory({
|
|
|
|
algorithm: 'aes'
|
|
|
|
, bits: 128
|
|
|
|
, mode: 'cbc'
|
2016-04-09 23:14:00 +00:00
|
|
|
, dirname: xconfx.varpath // TODO conf
|
|
|
|
, prefix: 'com.daplie.walnut.'
|
2015-11-12 11:14:59 +00:00
|
|
|
//, dbname: 'cluster'
|
|
|
|
, suffix: ''
|
|
|
|
, ext: '.sqlcipher'
|
2016-04-09 23:14:00 +00:00
|
|
|
, sock: xconfx.sqlite3Sock
|
|
|
|
, ipcKey: xconfx.ipcKey
|
2015-11-12 11:14:59 +00:00
|
|
|
});
|
2015-11-06 11:05:32 +00:00
|
|
|
*/
|
2016-04-09 23:14:00 +00:00
|
|
|
var cstore = require('cluster-store');
|
2015-11-06 11:05:32 +00:00
|
|
|
|
2015-11-12 11:14:59 +00:00
|
|
|
return PromiseA.all([
|
2015-11-18 11:44:22 +00:00
|
|
|
// TODO security on memstore
|
|
|
|
// TODO memstoreFactory.create
|
2015-11-12 11:14:59 +00:00
|
|
|
cstore.create({
|
2016-04-09 23:14:00 +00:00
|
|
|
sock: xconfx.memstoreSock
|
|
|
|
, connect: xconfx.memstoreSock
|
2015-11-12 11:14:59 +00:00
|
|
|
// TODO implement
|
2016-04-09 23:14:00 +00:00
|
|
|
, key: xconfx.ipcKey
|
2015-11-12 11:14:59 +00:00
|
|
|
}).then(function (_memstore) {
|
2016-04-09 23:14:00 +00:00
|
|
|
memstore = PromiseA.promisifyAll(_memstore);
|
2015-11-12 11:14:59 +00:00
|
|
|
return memstore;
|
|
|
|
})
|
|
|
|
// TODO mark a device as lost, stolen, missing in DNS records
|
|
|
|
// (and in turn allow other devices to lock it, turn on location reporting, etc)
|
|
|
|
, systemFactory.create({
|
|
|
|
init: true
|
|
|
|
, dbname: 'config'
|
|
|
|
})
|
|
|
|
]).then(function (args) {
|
|
|
|
memstore = args[0];
|
|
|
|
sqlstores.config = args[1];
|
|
|
|
|
2016-04-09 23:14:00 +00:00
|
|
|
var wrap = require('masterquest-sqlite3');
|
|
|
|
var dir = [
|
|
|
|
{ tablename: 'com_daplie_walnut_config'
|
|
|
|
, idname: 'id'
|
|
|
|
, unique: [ 'id' ]
|
|
|
|
, indices: [ 'createdAt', 'updatedAt' ]
|
|
|
|
}
|
|
|
|
, { tablename: 'com_daplie_walnut_redirects'
|
|
|
|
, idname: 'id' // blog.example.com:sample.net/blog
|
|
|
|
, unique: [ 'id' ]
|
|
|
|
, indices: [ 'createdAt', 'updatedAt' ]
|
|
|
|
}
|
|
|
|
];
|
2017-05-05 05:09:56 +00:00
|
|
|
console.log('config directive', dir);
|
2015-11-14 04:25:12 +00:00
|
|
|
|
2016-04-09 23:14:00 +00:00
|
|
|
function scopeMemstore(expId) {
|
|
|
|
var scope = expId + '|';
|
|
|
|
return {
|
|
|
|
getAsync: function (id) {
|
2017-05-05 05:09:56 +00:00
|
|
|
id = id.replace(/\|/, );
|
2016-04-09 23:14:00 +00:00
|
|
|
return memstore.getAsync(scope + id);
|
|
|
|
}
|
|
|
|
, setAsync: function (id, data) {
|
|
|
|
return memstore.setAsync(scope + id, data);
|
|
|
|
}
|
|
|
|
, touchAsync: function (id, data) {
|
|
|
|
return memstore.touchAsync(scope + id, data);
|
|
|
|
}
|
|
|
|
, destroyAsync: function (id) {
|
|
|
|
return memstore.destroyAsync(scope + id);
|
|
|
|
}
|
2015-11-14 04:25:12 +00:00
|
|
|
|
2016-04-09 23:14:00 +00:00
|
|
|
// helpers
|
|
|
|
, allAsync: function () {
|
2016-06-07 14:49:26 +00:00
|
|
|
return memstore.allAsync().then(function (db) {
|
2016-04-09 23:14:00 +00:00
|
|
|
return Object.keys(db).filter(function (key) {
|
|
|
|
return 0 === key.indexOf(scope);
|
|
|
|
}).map(function (key) {
|
|
|
|
return db[key];
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
, lengthAsync: function () {
|
2016-06-07 14:49:26 +00:00
|
|
|
return memstore.allAsync().then(function (db) {
|
2016-04-09 23:14:00 +00:00
|
|
|
return Object.keys(db).filter(function (key) {
|
|
|
|
return 0 === key.indexOf(scope);
|
|
|
|
}).length;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
, clearAsync: function () {
|
2016-06-07 14:49:26 +00:00
|
|
|
return memstore.allAsync().then(function (db) {
|
2016-04-09 23:14:00 +00:00
|
|
|
return Object.keys(db).filter(function (key) {
|
|
|
|
return 0 === key.indexOf(scope);
|
|
|
|
}).map(function (key) {
|
|
|
|
return memstore.destroyAsync(key);
|
|
|
|
});
|
|
|
|
}).then(function () {
|
|
|
|
return null;
|
|
|
|
});
|
2015-11-14 04:25:12 +00:00
|
|
|
}
|
2016-04-09 23:14:00 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
return wrap.wrap(sqlstores.config, dir).then(function (models) {
|
|
|
|
return models.ComDaplieWalnutConfig.find(null, { limit: 100 }).then(function (results) {
|
|
|
|
return models.ComDaplieWalnutConfig.find(null, { limit: 10000 }).then(function (redirects) {
|
|
|
|
var express = require('express-lazy');
|
|
|
|
var app = express();
|
|
|
|
var recase = require('connect-recase')({
|
|
|
|
// TODO allow explicit and or default flag
|
|
|
|
explicit: false
|
|
|
|
, default: 'snake'
|
|
|
|
, prefixes: ['/api']
|
|
|
|
// TODO allow exclude
|
|
|
|
//, exclusions: [config.oauthPrefix]
|
|
|
|
, exceptions: {}
|
|
|
|
//, cancelParam: 'camel'
|
|
|
|
});
|
|
|
|
var bootstrapApp;
|
|
|
|
var mainApp;
|
|
|
|
var apiDeps = {
|
|
|
|
models: models
|
|
|
|
// TODO don't let packages use this directly
|
|
|
|
, Promise: PromiseA
|
|
|
|
};
|
|
|
|
var apiFactories = {
|
|
|
|
memstoreFactory: { create: scopeMemstore }
|
|
|
|
, systemSqlFactory: systemFactory
|
|
|
|
};
|
|
|
|
|
2016-06-07 14:49:26 +00:00
|
|
|
var hostsmap = {};
|
2016-04-09 23:14:00 +00:00
|
|
|
function log(req, res, next) {
|
2016-06-07 14:49:26 +00:00
|
|
|
var hostname = (req.hostname || req.headers.host || '').split(':').shift();
|
|
|
|
console.log('[worker/log]', req.method, hostname, req.url);
|
|
|
|
if (hostname && !hostsmap[hostname]) {
|
|
|
|
hostsmap[hostname] = true;
|
|
|
|
require('fs').writeFile(
|
|
|
|
require('path').join(__dirname, '..', '..', 'var', 'hostnames', hostname)
|
|
|
|
, hostname, function () {});
|
|
|
|
}
|
2016-04-09 23:14:00 +00:00
|
|
|
next();
|
|
|
|
}
|
|
|
|
|
|
|
|
function setupMain() {
|
|
|
|
mainApp = express();
|
|
|
|
require('./main').create(mainApp, xconfx, apiFactories, apiDeps).then(function () {
|
|
|
|
// TODO process.send({});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!bootstrapApp) {
|
|
|
|
bootstrapApp = express();
|
|
|
|
require('./bootstrap').create(bootstrapApp, xconfx, models).then(function () {
|
|
|
|
// TODO process.send({});
|
|
|
|
setupMain();
|
|
|
|
});
|
|
|
|
}
|
2015-11-14 04:25:12 +00:00
|
|
|
|
2016-04-09 23:14:00 +00:00
|
|
|
process.on('message', function (data) {
|
|
|
|
if ('com.daplie.walnut.bootstrap' === data.type) {
|
|
|
|
setupMain();
|
|
|
|
}
|
|
|
|
});
|
2015-11-14 04:25:12 +00:00
|
|
|
|
2016-04-09 23:14:00 +00:00
|
|
|
app.disable('x-powered-by');
|
|
|
|
app.use('/', log);
|
|
|
|
app.use('/api', require('body-parser').json({
|
2015-11-14 04:25:12 +00:00
|
|
|
strict: true // only objects and arrays
|
|
|
|
, inflate: true
|
|
|
|
// limited to due performance issues with JSON.parse and JSON.stringify
|
|
|
|
// http://josh.zeigler.us/technology/web-development/how-big-is-too-big-for-json/
|
|
|
|
//, limit: 128 * 1024
|
|
|
|
, limit: 1.5 * 1024 * 1024
|
|
|
|
, reviver: undefined
|
|
|
|
, type: 'json'
|
|
|
|
, verify: undefined
|
2016-04-09 23:14:00 +00:00
|
|
|
}));
|
|
|
|
app.use('/api', recase);
|
|
|
|
|
2017-05-05 05:09:56 +00:00
|
|
|
app.set('trust proxy', ['loopback', 'linklocal', 'uniquelocal']);
|
2016-04-09 23:14:00 +00:00
|
|
|
app.use('/', function (req, res) {
|
2017-05-05 05:09:56 +00:00
|
|
|
if (!(req.encrypted || req.secure)) {
|
2016-04-09 23:14:00 +00:00
|
|
|
// did not come from https
|
|
|
|
if (/\.(appcache|manifest)\b/.test(req.url)) {
|
|
|
|
require('./unbrick-appcache').unbrick(req, res);
|
|
|
|
return;
|
|
|
|
}
|
2017-05-05 05:09:56 +00:00
|
|
|
res.end("Connection is not encrypted. That's no bueno or, as we say in Hungarian, nem szabad!");
|
2016-04-09 23:14:00 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO check https://letsencrypt.status.io to see if https certification is not available
|
|
|
|
|
|
|
|
if (mainApp) {
|
|
|
|
mainApp(req, res);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
bootstrapApp(req, res);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return app;
|
2015-11-19 07:42:20 +00:00
|
|
|
});
|
2015-11-12 11:14:59 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2015-11-06 11:05:32 +00:00
|
|
|
};
|