// routes
const prodStatus = require('./routes/' + ver + '/status');
-const prodEvents = require('./routes/' + ver + '/events');
+const prodEvents = require('./routes/' + ver + '/events').router;
const prodControl = require('./routes/' + ver + '/control');
const prodNotification = require('./routes/' + ver + '/notification');
const testStatus = require('./routes/' + ver + '/test/status');
// api-docs
app.use('/' + ver + '/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument));
-/*
-app.use((err, req, res, next) => {
-log.error(err);
- res.status(err.status).json({
- message: err.message,
- errors: err.errors,
- });
-});
-*/
-
module.exports = app;
--- /dev/null
+const MongoClient = require('mongodb').MongoClient;
+const log = require('./logger')(__filename.slice(__dirname.length + 1));
+const url = 'mongodb://localhost:27017';
+const name = 'garnod';
+var db = null;
+
+const msg = {
+ ok: 'ok',
+ dbError: 'dbError',
+ keyMismatch: 'keyMismatch'
+};
+
+function connect() {
+ // connect to mongodb/mydb once, auto_reconnect is set by default
+ if (db === null) {
+ MongoClient.connect(url, function(err, connection) {
+ if (err) {
+ log.error('Connection to database failed', JSON.stringify(err));
+ } else {
+ log.info('Connection to database opened');
+ db = connection;
+ // handle irreversible connection lost
+ db.on('close', function() {
+ log.error('Connection to DB permanently lost');
+ process.exit(1);
+ });
+ }
+ });
+ }
+}
+
+// connect to DB immediately
+connect();
+
+function setSettings(data, callback) {
+ // resolve API key
+ new Promise((resolve, reject) => {
+ var keys = db.db(name).collection('keys');
+ log.debug('Search for API key, area', data.area);
+ keys.findOne({ area: data.area }, {}, (err, res) => {
+ if (err) {
+ log.error('Error on searching for API key', JSON.stringify(err));
+ return reject(msg.dbError);
+ }
+ if (res === null) {
+ log.warn('No such key area found in DB');
+ return reject(msg.dbError);
+ }
+ if (res.key !== data.key) {
+ log.info('API key doesn\'t match');
+ return reject(msg.keyMismatch);
+ }
+ log.debug('API key is valid');
+ resolve(msg.ok);
+ })
+ })
+ .catch (err => {
+ log.error('Error on searching for API key', JSON.stringify(err));
+ return callback(err, null);
+ })
+
+ // save settings
+ .then(res => {
+ return new Promise((resolve, reject) => {
+ var settings = db.db(name).collection('settings');
+ log.debug('Update settings:', JSON.stringify(data.settings));
+ settings.updateOne({ _id: 1 }, { $set: data.settings }, { upsert: true }, (err, res) => {
+ if (err) {
+ log.error('Error on updating settings', JSON.stringify(err));
+ return reject(msg.dbError);
+ }
+ log.debug('Update settings done');
+ resolve(msg.ok);
+ });
+ });
+ })
+ .catch (err => {
+ log.error('Error on updating settings', JSON.stringify(err));
+ return callback(err, null);
+ })
+
+ // return result
+ .then(res => {
+ return callback(null, res);
+ });
+}
+
+function setNotification(data, callback) {
+ // resolve API key
+ new Promise((resolve, reject) => {
+ var keys = db.db(name).collection('keys');
+ log.debug('Search for API key, area', data.area);
+ keys.findOne({ area: data.area }, {}, (err, res) => {
+ if (err) {
+ log.error('Error on searching for API key', JSON.stringify(err));
+ return reject(msg.dbError);
+ }
+ if (res === null) {
+ log.warn('No such key area found in DB');
+ return reject(msg.dbError);
+ }
+ if (res.key !== data.key) {
+ log.info('API key doesn\'t match');
+ return reject(msg.keyMismatch);
+ }
+ log.debug('API key is valid');
+ resolve(msg.ok);
+ })
+ })
+ .catch (err => {
+ log.error('Error on searching for API key', JSON.stringify(err));
+ return callback(err, null);
+ })
+
+ // save notification data
+ .then(res => {
+ return new Promise((resolve, reject) => {
+ var settings = db.db(name).collection('notifications');
+ log.debug('Update notifications:', JSON.stringify(data.notification));
+ settings.updateOne({ _id: 1 }, { $set: data.notification }, { upsert: true }, (err, res) => {
+ if (err) {
+ log.error('Error on updating notification', JSON.stringify(err));
+ return reject(msg.dbError);
+ }
+ log.debug('Update notification done');
+ resolve(msg.ok);
+ });
+ });
+ })
+ .catch (err => {
+ log.error('Error on updating notification', JSON.stringify(err));
+ return callback(err, null);
+ })
+
+ // return result
+ .then(res => {
+ return callback(null, res);
+ });
+}
+
+function getSettings(data, callback) {
+ // resolve API key
+ new Promise((resolve, reject) => {
+ var keys = db.db(name).collection('keys');
+ log.debug('Search for API key, area', data.area);
+ keys.findOne({ area: data.area }, {}, (err, res) => {
+ if (err) {
+ log.error('Error on searching for API key', JSON.stringify(err));
+ return reject(msg.dbError);
+ }
+ if (res === null) {
+ log.warn('No such key area found in DB');
+ return reject(msg.dbError);
+ }
+ if (res.key !== data.key) {
+ log.info('API key doesn\'t match');
+ return reject(msg.keyMismatch);
+ }
+ log.debug('API key is valid');
+ resolve(msg.ok);
+ })
+ })
+ .catch (err => {
+ log.error('Error on searching for API key', JSON.stringify(err));
+ return callback(err, null);
+ })
+
+ // get settings
+ .then(res => {
+ return new Promise((resolve, reject) => {
+ var settings = db.db(name).collection('settings');
+ log.debug('Search for settings object');
+ settings.findOne({ _id: 1 }, {}, (err, res) => {
+ if (err) {
+ log.error('Error on getting settings', JSON.stringify(err));
+ return reject(msg.dbError);
+ }
+ log.debug('Get settings done:', JSON.stringify(res));
+ resolve(res);
+ });
+ });
+ })
+ .catch (err => {
+ log.error('Error on getting settings', err);
+ return callback(err, null);
+ })
+
+ // return result
+ .then(res => {
+ return callback(null, res);
+ });
+}
+
+function getNotification(data, callback) {
+ // resolve API key
+ new Promise((resolve, reject) => {
+ var keys = db.db(name).collection('keys');
+ log.debug('Search for API key, area', data.area);
+ keys.findOne({ area: data.area }, {}, (err, res) => {
+ if (err) {
+ log.error('Error on searching for API key', JSON.stringify(err));
+ return reject(msg.dbError);
+ }
+ if (res === null) {
+ log.warn('No such key area found in DB');
+ return reject(msg.dbError);
+ }
+ if (res.key !== data.key) {
+ log.info('API key doesn\'t match');
+ return reject(msg.keyMismatch);
+ }
+ log.debug('API key is valid');
+ resolve(msg.ok);
+ })
+ })
+ .catch (err => {
+ log.error('Error on searching for API key', JSON.stringify(err));
+ return callback(err, null);
+ })
+
+ // get notification
+ .then(res => {
+ return new Promise((resolve, reject) => {
+ var settings = db.db(name).collection('notifications');
+ log.debug('Search for notification object');
+ settings.findOne({ _id: 1 }, {}, (err, res) => {
+ if (err) {
+ log.error('Error on getting notification', JSON.stringify(err));
+ return reject(msg.dbError);
+ }
+ log.debug('Get notification done:', JSON.stringify(res));
+ resolve(res);
+ });
+ });
+ })
+ .catch (err => {
+ log.error('Error on getting notification', JSON.stringify(err));
+ return callback(err, null);
+ })
+
+ // return result
+ .then(res => {
+ return callback(null, res);
+ });
+}
+
+module.exports = {
+ msg,
+ setSettings,
+ getSettings,
+ setNotification,
+ getNotification
+}
+++ /dev/null
-const MongoClient = require('mongodb').MongoClient;
-const log = require('./logger')(__filename.slice(__dirname.length + 1));
-const url = 'mongodb://localhost:27017';
-const name = 'garnod';
-var db = null;
-
-const msg = {
- ok: 'ok',
- dbError: 'dbError',
- keyMismatch: 'keyMismatch'
-};
-
-function connect() {
- // connect to mongodb/mydb once, auto_reconnect is set by default
- if (db === null) {
- MongoClient.connect(url, function(err, connection) {
- if (err) {
- log.error('Connection to database failed', JSON.stringify(err));
- } else {
- log.info('Connection to database opened');
- db = connection;
- // handle irreversible connection lost
- db.on('close', function() {
- log.error('Connection to DB permanently lost');
- process.exit(1);
- });
- }
- });
- }
-}
-
-// connect to DB immediately
-connect();
-
-function setSettings(data, callback) {
- // resolve API key
- new Promise((resolve, reject) => {
- var keys = db.db(name).collection('keys');
- log.debug('Search for API key, area', data.area);
- keys.findOne({ area: data.area }, {}, (err, res) => {
- if (err) {
- log.error('Error on searching for API key', JSON.stringify(err));
- return reject(msg.dbError);
- }
- if (res === null) {
- log.warn('No such key area found in DB');
- return reject(msg.dbError);
- }
- if (res.key !== data.key) {
- log.info('API key doesn\'t match');
- return reject(msg.keyMismatch);
- }
- log.debug('API key is valid');
- resolve(msg.ok);
- })
- })
- .catch (err => {
- log.error('Error on searching for API key', JSON.stringify(err));
- return callback(err, null);
- })
-
- // save settings
- .then(res => {
- return new Promise((resolve, reject) => {
- var settings = db.db(name).collection('settings');
- log.debug('Update settings:', JSON.stringify(data.settings));
- settings.updateOne({ _id: 1 }, { $set: data.settings }, { upsert: true }, (err, res) => {
- if (err) {
- log.error('Error on updating settings', JSON.stringify(err));
- return reject(msg.dbError);
- }
- log.debug('Update settings done');
- resolve(msg.ok);
- });
- });
- })
- .catch (err => {
- log.error('Error on updating settings', JSON.stringify(err));
- return callback(err, null);
- })
-
- // return result
- .then(res => {
- return callback(null, res);
- });
-}
-
-function setNotification(data, callback) {
- // resolve API key
- new Promise((resolve, reject) => {
- var keys = db.db(name).collection('keys');
- log.debug('Search for API key, area', data.area);
- keys.findOne({ area: data.area }, {}, (err, res) => {
- if (err) {
- log.error('Error on searching for API key', JSON.stringify(err));
- return reject(msg.dbError);
- }
- if (res === null) {
- log.warn('No such key area found in DB');
- return reject(msg.dbError);
- }
- if (res.key !== data.key) {
- log.info('API key doesn\'t match');
- return reject(msg.keyMismatch);
- }
- log.debug('API key is valid');
- resolve(msg.ok);
- })
- })
- .catch (err => {
- log.error('Error on searching for API key', JSON.stringify(err));
- return callback(err, null);
- })
-
- // save notification data
- .then(res => {
- return new Promise((resolve, reject) => {
- var settings = db.db(name).collection('notifications');
- log.debug('Update notifications:', JSON.stringify(data.notification));
- settings.updateOne({ _id: 1 }, { $set: data.notification }, { upsert: true }, (err, res) => {
- if (err) {
- log.error('Error on updating notification', JSON.stringify(err));
- return reject(msg.dbError);
- }
- log.debug('Update notification done');
- resolve(msg.ok);
- });
- });
- })
- .catch (err => {
- log.error('Error on updating notification', JSON.stringify(err));
- return callback(err, null);
- })
-
- // return result
- .then(res => {
- return callback(null, res);
- });
-}
-
-function getSettings(data, callback) {
- // resolve API key
- new Promise((resolve, reject) => {
- var keys = db.db(name).collection('keys');
- log.debug('Search for API key, area', data.area);
- keys.findOne({ area: data.area }, {}, (err, res) => {
- if (err) {
- log.error('Error on searching for API key', JSON.stringify(err));
- return reject(msg.dbError);
- }
- if (res === null) {
- log.warn('No such key area found in DB');
- return reject(msg.dbError);
- }
- if (res.key !== data.key) {
- log.info('API key doesn\'t match');
- return reject(msg.keyMismatch);
- }
- log.debug('API key is valid');
- resolve(msg.ok);
- })
- })
- .catch (err => {
- log.error('Error on searching for API key', JSON.stringify(err));
- return callback(err, null);
- })
-
- // get settings
- .then(res => {
- return new Promise((resolve, reject) => {
- var settings = db.db(name).collection('settings');
- log.debug('Search for settings object');
- settings.findOne({ _id: 1 }, {}, (err, res) => {
- if (err) {
- log.error('Error on getting settings', JSON.stringify(err));
- return reject(msg.dbError);
- }
- log.debug('Get settings done:', JSON.stringify(res));
- resolve(res);
- });
- });
- })
- .catch (err => {
- log.error('Error on getting settings', err);
- return callback(err, null);
- })
-
- // return result
- .then(res => {
- return callback(null, res);
- });
-}
-
-function getNotification(data, callback) {
- // resolve API key
- new Promise((resolve, reject) => {
- var keys = db.db(name).collection('keys');
- log.debug('Search for API key, area', data.area);
- keys.findOne({ area: data.area }, {}, (err, res) => {
- if (err) {
- log.error('Error on searching for API key', JSON.stringify(err));
- return reject(msg.dbError);
- }
- if (res === null) {
- log.warn('No such key area found in DB');
- return reject(msg.dbError);
- }
- if (res.key !== data.key) {
- log.info('API key doesn\'t match');
- return reject(msg.keyMismatch);
- }
- log.debug('API key is valid');
- resolve(msg.ok);
- })
- })
- .catch (err => {
- log.error('Error on searching for API key', JSON.stringify(err));
- return callback(err, null);
- })
-
- // get notification
- .then(res => {
- return new Promise((resolve, reject) => {
- var settings = db.db(name).collection('notifications');
- log.debug('Search for notification object');
- settings.findOne({ _id: 1 }, {}, (err, res) => {
- if (err) {
- log.error('Error on getting notification', JSON.stringify(err));
- return reject(msg.dbError);
- }
- log.debug('Get notification done:', JSON.stringify(res));
- resolve(res);
- });
- });
- })
- .catch (err => {
- log.error('Error on getting notification', JSON.stringify(err));
- return callback(err, null);
- })
-
- // return result
- .then(res => {
- return callback(null, res);
- });
-}
-
-module.exports = {
- msg,
- setSettings,
- getSettings,
- setNotification,
- getNotification
-}
--- /dev/null
+const rpio = require('rpio');
+const log = require('./logger')(__filename.slice(__dirname.length + 1));
+
+const RELAIS = 16; // GPIO 23
+const REED = 11; // GPIO 17
+const UNKNOWN = 2;
+const DELAY = 10;
+var reedState;
+var controlCallback = null;
+var notificationCallback = null;
+var apiKey = null;
+var timer = null;
+
+function init() {
+ rpio.open(RELAIS, rpio.OUTPUT);
+ rpio.write(RELAIS, rpio.LOW);
+ rpio.open(REED, rpio.INPUT);
+
+ reedState = readDebounced(REED);
+}
+
+init();
+
+function trigger() {
+ rpio.write(RELAIS, rpio.HIGH);
+ rpio.msleep(500);
+ rpio.write(RELAIS, rpio.LOW);
+
+ log.debug('relais triggered');
+}
+
+function readDebounced(pin) {
+ const state = rpio.read(pin);
+
+ rpio.msleep(1000);
+
+ if (state != rpio.read(pin)) {
+ log.debug('state unknown');
+ return UNKNOWN;
+ } else {
+ log.debug('state :', state);
+ return state;
+ }
+}
+
+function pollcb(pin)
+{
+ const state = readDebounced(pin);
+
+ if (state != UNKNOWN && reedState != UNKNOWN) {
+ if (state != reedState) {
+ log.debug('reed state changed, now:', state);
+
+ if (controlCallback != null) {
+ // handle callbacks
+ if (state == rpio.LOW) {
+ controlCallback('closed');
+ controlCallback = null;
+ } else {
+ controlCallback('open');
+ controlCallback = null;
+ }
+ }
+
+ // evaluate state
+ evaluation(state);
+ }
+ reedState = state;
+ }
+}
+
+rpio.poll(REED, pollcb);
+
+function register(callback) {
+ controlCallback = callback;
+}
+
+function read() {
+ const state = readDebounced(REED);
+
+ switch (state) {
+ case rpio.LOW:
+ return 'closed'
+ break;
+ case rpio.HIGH:
+ return 'open'
+ break;
+ case rpio.LOW:
+ default:
+ return 'unknown'
+ break;
+ }
+}
+
+function subscribe(callback, key) {
+ notificationCallback = callback;
+ apiKey = key;
+}
+
+function evaluation(state) {
+ if (notificationCallback != null) {
+ if (state == rpio.HIGH) {
+ timer = setTimeout(notificationCallback, DELAY * 1000, apiKey);
+ log.debug('Open door evaluation started');
+ } else {
+ clearTimeout(timer);
+ timer = null;
+ log.debug('Open door evaluation stopped');
+ }
+ }
+}
+
+module.exports = {
+ trigger,
+ register,
+ read,
+ subscribe,
+}
{
"name": "garnod",
- "version": "0.0.0",
+ "version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"safe-buffer": "5.1.2"
}
},
+ "bindings": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
+ "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
+ "requires": {
+ "file-uri-to-path": "1.0.0"
+ }
+ },
"bn.js": {
"version": "4.11.8",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
+ "cors": {
+ "version": "2.8.5",
+ "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
+ "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
+ "requires": {
+ "object-assign": "^4",
+ "vary": "^1"
+ }
+ },
"currently-unhandled": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
"resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz",
"integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A="
},
+ "file-uri-to-path": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
+ "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="
+ },
"finalhandler": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
+ "nan": {
+ "version": "2.14.0",
+ "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
+ "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg=="
+ },
"negotiator": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
"validate-npm-package-license": "^3.0.1"
}
},
+ "object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
+ },
"on-finished": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz",
"integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c="
},
+ "rpio": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/rpio/-/rpio-2.1.1.tgz",
+ "integrity": "sha512-0Pluzy3s77JXxpUVE3zs25TAYIjYb3q1yOJVkK6taH/idzDohZH6whqp5owgYeawxs767nc8y9TdbAv0Q1xL7w==",
+ "requires": {
+ "bindings": "~1.5.0",
+ "nan": "~2.14.0"
+ }
+ },
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"license": "GPL-2.0-or-later",
"dependencies": {
"cookie-parser": "~1.4.4",
+ "cors": "^2.8.5",
"dateformat": "1.0.11",
"debug": "~2.6.9",
"express": "~4.16.1",
"mongodb": "^2.2.36",
"morgan": "~1.9.1",
"query-string": "^6.8.3",
+ "rpio": "^2.1.1",
"swagger-ui-express": "^4.1.2",
"web-push": "^3.4.1",
"winston": "1.1.2",
-var express = require('express');
-var router = express.Router();
+const express = require('express');
+const log = require('./../../lib/logger')(__filename.slice(__dirname.length + 1));
+const qStr = require('query-string');
+const router = express.Router();
+const db = require('./../../lib/db');
+const ev = require('./events');
+const gpio = require('./../../lib/gpio');
-/* GET */
-router.get('/', function(req, res, next) {
- res.status(500).send;
+const events = ev.events;
+var timer = null;
+
+/* Disables caching in client */
+function nocache(req, res, next) {
+ res.header('Cache-Control', 'private, no-cache, no-store, must-revalidate');
+ res.header('Expires', '-1');
+ res.header('Pragma', 'no-cache');
+ next();
+}
+
+/* POST /vN/control */
+router.post('/', nocache, function(req, res, next) {
+ // check header
+ if (typeof req.header('X-API-Key') === 'undefined') {
+ log.info('API key not set in request header');
+ res.status(401).send();
+ return;
+ } else {
+ log.debug('API key set in request header');
+ }
+
+ // check query parameter
+ if (typeof req.query.command != 'undefined') {
+ if (typeof req.query.command == 'string') {
+ switch (req.query.command) {
+ case 'move':
+ break;
+ default:
+ log.info('Value of command query parameter unknown');
+ res.status(400).send();
+ return;
+ }
+ }
+ }
+
+ // read settings
+ db.getSettings({
+ area: 'prod',
+ key: req.header('X-API-Key')
+ }, (err, data) => {
+ if (err) {
+ switch (err) {
+ case db.msg.dbError:
+ log.info('Server error response');
+ res.status(500).send();
+ break;
+ case db.msg.keyMismatch:
+ log.info('Unauthorized access');
+ res.status(401).send();
+ break;
+ default:
+ log.error('Error result unexpected');
+ res.status(500).send();
+ break;
+ }
+ } else {
+ // register callback
+ gpio.register(onStateChanged);
+ gpio.trigger();
+ log.debug('Door closing triggered and state change event subscribed');
+ // send response
+ res.status(200).send();
+ }
+ });
});
+function onStateChanged(state) {
+ events.emit('stateChanged', state);
+}
+
module.exports = router;
-var express = require('express');
-var router = express.Router();
+const express = require('express');
+const log = require('./../../lib/logger')(__filename.slice(__dirname.length + 1));
+const qStr = require('query-string');
+const router = express.Router();
+const db = require('./../../lib/db');
+const EventEmitter = require('events');
+const fs = require('fs');
-/* GET */
-router.get('/', function(req, res, next) {
- res.status(500).send;
+const events = new EventEmitter();
+var response = null;
+var request = null;
+var timer = null;
+const delayMin = -1;
+const delayMax = 300;
+
+function nocache(req, res, next) {
+ res.header('Cache-Control', 'private, no-cache, no-store, must-revalidate');
+ res.header('Expires', '-1');
+ res.header('Pragma', 'no-cache');
+ next();
+}
+
+/* GET /vN/events */
+router.get('/', nocache, function(req, res, next) {
+ // check header
+ if (typeof req.header('X-API-Key') === 'undefined') {
+ log.info('API key not set in request header');
+ res.status(401).send();
+ return;
+ } else {
+ log.debug('API key set in request header');
+ }
+
+ // TODO: dequeue?
+
+ // check query parameter
+ var timeout = 30;
+ if (typeof req.query.timeout != 'undefined') {
+ var delay = parseInt(req.query.timeout);
+ if (!isNaN(delay)) {
+ if (delay < delayMin || delay > delayMax) {
+ log.info('Value of timeout query parameter not in range');
+ res.status(400).send();
+ return;
+ } else {
+ timeout = delay;
+ }
+ }
+ }
+
+ // schedule resonse on timeout
+ response = res;
+ request = req;
+ if (timer === null && timeout !== delayMin) {
+ timer = setTimeout(processTimeout, timeout * 1000);
+ log.debug('Response timeout scheduled');
+ } else {
+ log.todo('not implemented');
+ }
});
-module.exports = router;
+events.on('stateChanged', (state) => {
+ log.debug('Event ready for sending');
+ if (timer !== null) {
+ clearTimeout(timer);
+ timer = null;
+ }
+
+ // read settings
+ log.debug('Got state:', state);
+ var image = true;
+ if (request !== null) {
+ if (typeof request.query.image != 'undefined') {
+ if (request.query.image === 'false') {
+ image = false;
+ }
+ }
+ request = null;
+ }
+
+ // TODO: enqueue?
+
+ // response
+ if (response !== null) {
+ var content = {
+ 'state': state
+ };
+ if (image) {
+ var file = null;
+ switch (state) {
+ case 'open':
+ file = fs.readFileSync(__dirname + '/../../public/images/open.jpg', 'base64');
+ break;
+ case 'closed':
+ file = fs.readFileSync(__dirname + '/../../public/images/closed.jpg', 'base64');
+ break;
+ default:
+ log.error('Unexpected status from state');
+ response.status(500).send();
+ return;
+ }
+ content['image'] = file;
+ }
+ response.json(content);
+ response = null;
+ }
+});
+
+function processTimeout() {
+ log.debug('Timeout, no events');
+ clearTimeout(timer);
+ timer = null;
+ response.status(304).end('');
+ response = null;
+}
+
+module.exports = {
+ router,
+ events
+}
-var express = require('express');
-var router = express.Router();
+const express = require('express');
+const log = require('./../../lib/logger')(__filename.slice(__dirname.length + 1));
+const qStr = require('query-string');
+const router = express.Router();
+const db = require('./../../lib/db');
+const gpio = require('./../../lib/gpio');
+const fs = require('fs');
+const webpush = require('web-push');
-/* GET */
-router.get('/', function(req, res, next) {
- res.status(500).send;
+/* Disables caching in client */
+function nocache(req, res, next) {
+ res.header('Cache-Control', 'private, no-cache, no-store, must-revalidate');
+ res.header('Expires', '-1');
+ res.header('Pragma', 'no-cache');
+ next();
+}
+
+/* POST /vN/notification */
+router.post('/', nocache, function(req, res, next) {
+ // check header
+ if (typeof req.header('X-API-Key') === 'undefined') {
+ log.info('API key not set in request header');
+ res.status(401).send();
+ return;
+ } else {
+ log.debug('API key set in request header');
+ }
+
+ // check body
+ if (typeof req.body != 'object') {
+ log.info('Request body is not JSON');
+ res.status(400).send();
+ return;
+ } else{
+ // check endpoint
+ if (typeof req.body.endpoint != 'string' ) {
+ log.info('Type of endpoint in content invalid');
+ res.status(400).send();
+ return;
+ }
+
+ // check expirationTime
+ if (req.body.expirationTime !== null) {
+ if (typeof req.body.expirationTime != 'string' ) {
+ log.info('Type of expirationTime in content invalid');
+ res.status(400).send();
+ return;
+ }
+ }
+
+ // check keys
+ if (typeof req.body.keys == 'object' ) {
+ if (typeof req.body.keys.p256dh != 'string' ) {
+ log.info('Type of keys.p256dh in content invalid');
+ res.status(400).send();
+ return;
+ }
+ if (typeof req.body.keys.auth != 'string' ) {
+ log.info('Type of keys.auth in content invalid');
+ res.status(400).send();
+ return;
+ }
+ }
+
+ // save to DB
+ db.setNotification({
+ area: 'prod',
+ key: req.header('X-API-Key'),
+ notification: req.body
+ }, (err, data) => {
+ if (err) {
+ switch (err) {
+ case db.msg.dbError:
+ log.info('Server error response');
+ res.status(500).send();
+ break;
+ case db.msg.keyMismatch:
+ log.info('Unauthorized access');
+ res.status(401).send();
+ break;
+ default:
+ log.error('Error result unexpected');
+ res.status(500).send();
+ break;
+ }
+ } else {
+ // subscribe notification
+ gpio.subscribe(onDoorOpen, req.header('X-API-Key'));
+ log.debug('Open door event subscribed');
+ res.status(200).send();
+ }
+ });
+ }
});
+function onDoorOpen(key) {
+ // get settings
+ db.getNotification({
+ area: 'prod',
+ key: key
+ }, (err, data) => {
+ if (err) {
+ switch (err) {
+ case db.msg.dbError:
+ log.info('Server error response');
+ res.status(500).send();
+ break;
+ case db.msg.keyMismatch:
+ log.info('Unauthorized access');
+ res.status(401).send();
+ break;
+ default:
+ log.error('Error result unexpected');
+ res.status(500).send();
+ break;
+ }
+ } else {
+ executeNotification(data);
+ }
+ });
+}
+
+function executeNotification(notification) {
+ const pushSubscription = {
+ endpoint: notification.endpoint,
+ keys: {
+ auth: notification.keys.auth,
+ p256dh: notification.keys.p256dh
+ }
+ };
+
+ const options = {
+ gcmAPIKey: 'AAAAUtHuYco:APA91bEBTxCRGaez9_glljXAlit3PY5HMwhLSqWYMC1j-jFSp6'
+ + 'nvnNqjI42jAVFApQbM0oyAOQjCUilIovB76cwTFxyZTP96wm9n09XwiMRXJjhwiJX1hO3'
+ + '2mBB2zwK6X-w7epE1V67K',
+ vapidDetails: {
+ subject: 'mailto:ebelcrom@gmail.com',
+ publicKey: 'BLDSdGasI5sLks30brbIWvlLMFqzoxxkOs7aW_E9PDBzIO_mDs6-tvtb2U0-'
+ + 'BVFDafNd58DJgoXxdK5711FF29c',
+ privateKey: '_AFTIegzYV_l_5RYwzOCc22cpYcMUmpkA8bLbrlNq9I'
+ },
+ headers: {
+ 'Urgency': 'high'
+ },
+ contentEncoding: 'aes128gcm'
+ };
+
+ const icon = 'data:image/png;base64,' +
+ fs.readFileSync(__dirname + '/../../public/images/icon.png', 'base64');
+ const payload = {
+ message: 'The garage door is open!',
+ icon: icon
+ };
+ log.debug('Paylod length:', JSON.stringify(payload).length);
+
+ const details = webpush.generateRequestDetails(pushSubscription, JSON.stringify(payload), options);
+ log.debug('Request details:', JSON.stringify(details));
+
+ webpush.sendNotification(pushSubscription, JSON.stringify(payload), options)
+ .then(data => {
+ if (data) {
+ log.info('sent, data:', JSON.stringify(data));
+ }
+ })
+ .catch(err => {
+ log.info('sent, err:', JSON.stringify(err));
+ });
+}
+
module.exports = router;
-var express = require('express');
-var router = express.Router();
+const express = require('express');
+const log = require('./../../lib/logger')(__filename.slice(__dirname.length + 1));
+const qStr = require('query-string');
+const router = express.Router();
+const db = require('./../../lib/db');
+const fs = require('fs');
+const gpio = require('./../../lib/gpio');
-/* GET */
-router.get('/', function(req, res, next) {
- res.status(500).send;
+/* Disables caching in client */
+function nocache(req, res, next) {
+ res.header('Cache-Control', 'private, no-cache, no-store, must-revalidate');
+ res.header('Expires', '-1');
+ res.header('Pragma', 'no-cache');
+ next();
+}
+
+/* GET /vN/status */
+router.get('/', nocache, function(req, res, next) {
+ // check header
+ if (typeof req.header('X-API-Key') === 'undefined') {
+ log.info('API key not set in request header');
+ res.status(401).send();
+ return;
+ } else {
+ log.debug('API key set in request header');
+ }
+
+ // check query parameter
+ var image = true;
+ if (typeof req.query.image != 'undefined') {
+ if (req.query.image === 'false') {
+ image = false;
+ }
+ }
+
+ // read settings
+ db.getSettings({
+ area: 'prod',
+ key: req.header('X-API-Key')
+ }, (err, data) => {
+ if (err) {
+ switch (err) {
+ case db.msg.dbError:
+ log.info('Server error response');
+ res.status(500).send();
+ break;
+ case db.msg.keyMismatch:
+ log.info('Unauthorized access');
+ res.status(401).send();
+ break;
+ default:
+ log.error('Error result unexpected');
+ res.status(500).send();
+ break;
+ }
+ } else {
+ // response
+ const state = gpio.read();
+
+ var content = {
+ 'state': state
+ };
+ if (image) {
+ var file = null;
+ switch (state) {
+ case 'open':
+ file = fs.readFileSync(__dirname + '/../../public/images/open.jpg', 'base64');
+ break;
+ case 'closed':
+ file = fs.readFileSync(__dirname + '/../../public/images/closed.jpg', 'base64');
+ break;
+ default:
+ log.error('Unexpected status from settings');
+ res.status(500).send();
+ return;
+ }
+ content['image'] = file;
+ }
+ res.json(content);
+ }
+ });
});
module.exports = router;
const log = require('./../../../lib/logger')(__filename.slice(__dirname.length + 1));
const qStr = require('query-string');
const router = express.Router();
-const dblib = require('./../../../lib/dblib');
+const db = require('./../../../lib/db');
const ev = require('./events');
const events = ev.events;
function move(req, res, next) {
// get settings
- dblib.getSettings({
+ db.getSettings({
area: 'test',
key: req.header('X-API-Key-Test')
}, (err, data) => {
if (err) {
switch (err) {
- case dblib.msg.dbError:
+ case db.msg.dbError:
log.info('Server error response');
res.status(500).send();
break;
- case dblib.msg.keyMismatch:
+ case db.msg.keyMismatch:
log.info('Unauthorized access');
res.status(401).send();
break;
const log = require('./../../../lib/logger')(__filename.slice(__dirname.length + 1));
const qStr = require('query-string');
const router = express.Router();
-const dblib = require('./../../../lib/dblib');
+const db = require('./../../../lib/db');
const EventEmitter = require('events');
const fs = require('fs');
const log = require('./../../../lib/logger')(__filename.slice(__dirname.length + 1));
const qStr = require('query-string');
const router = express.Router();
-const dblib = require('./../../../lib/dblib');
+const db = require('./../../../lib/db');
-/* Disables caching in client */
+/* Disables caching in client */
function nocache(req, res, next) {
res.header('Cache-Control', 'private, no-cache, no-store, must-revalidate');
res.header('Expires', '-1');
next();
}
-/* POST /vN/test/notification */
+/* POST /vN/notification */
router.post('/', nocache, function(req, res, next) {
// check header
if (typeof req.header('X-API-Key-Test') === 'undefined') {
}
// save to DB
- dblib.setNotification({
+ db.setNotification({
area: 'test',
key: req.header('X-API-Key-Test'),
notification: req.body
}, (err, data) => {
if (err) {
switch (err) {
- case dblib.msg.dbError:
+ case db.msg.dbError:
log.info('Server error response');
res.status(500).send();
break;
- case dblib.msg.keyMismatch:
+ case db.msg.keyMismatch:
log.info('Unauthorized access');
res.status(401).send();
break;
const log = require('./../../../lib/logger')(__filename.slice(__dirname.length + 1));
const qStr = require('query-string');
const router = express.Router();
-const dblib = require('./../../../lib/dblib');
+const db = require('./../../../lib/db');
const fs = require('fs');
const webpush = require('web-push');
}
// save to DB
- dblib.setSettings({
+ db.setSettings({
area: 'test',
key: req.header('X-API-Key-Test'),
settings: settings
}, (err, data) => {
if (err) {
switch (err) {
- case dblib.msg.dbError:
+ case db.msg.dbError:
log.info('Server error response');
res.status(500).send();
break;
- case dblib.msg.keyMismatch:
+ case db.msg.keyMismatch:
log.info('Unauthorized access');
res.status(401).send();
break;
function notify(req, res, next, delay) {
// get settings
- dblib.getNotification({
+ db.getNotification({
area: 'test',
key: req.header('X-API-Key-Test')
}, (err, data) => {
if (err) {
switch (err) {
- case dblib.msg.dbError:
+ case db.msg.dbError:
log.info('Server error response');
res.status(500).send();
break;
- case dblib.msg.keyMismatch:
+ case db.msg.keyMismatch:
log.info('Unauthorized access');
res.status(401).send();
break;
clearTimeout(timer);
timer = null;
- // web push
- webpush.setGCMAPIKey('AAAAUtHuYco:APA91bEBTxCRGaez9_glljXAlit3PY5HMwhLSqWYMC1j-jFSp6nvnNqj' +
- 'I42jAVFApQbM0oyAOQjCUilIovB76cwTFxyZTP96wm9n09XwiMRXJjhwiJX1hO32mBB2zwK6X-w7epE1V67K');
- webpush.setVapidDetails(
- 'mailto:ebelcrom@gmail.com',
- 'BLDSdGasI5sLks30brbIWvlLMFqzoxxkOs7aW_E9PDBzIO_mDs6-tvtb2U0-BVFDafNd58DJgoXxdK5711FF29c',
- '_AFTIegzYV_l_5RYwzOCc22cpYcMUmpkA8bLbrlNq9I'
- );
-
- log.debug('Notification data:', JSON.stringify(notification))
const pushSubscription = {
endpoint: notification.endpoint,
keys: {
}
};
+ const options = {
+ gcmAPIKey: 'AAAAUtHuYco:APA91bEBTxCRGaez9_glljXAlit3PY5HMwhLSqWYMC1j-jFSp6'
+ + 'nvnNqjI42jAVFApQbM0oyAOQjCUilIovB76cwTFxyZTP96wm9n09XwiMRXJjhwiJX1hO3'
+ + '2mBB2zwK6X-w7epE1V67K',
+ vapidDetails: {
+ subject: 'mailto:ebelcrom@gmail.com',
+ publicKey: 'BLDSdGasI5sLks30brbIWvlLMFqzoxxkOs7aW_E9PDBzIO_mDs6-tvtb2U0-'
+ + 'BVFDafNd58DJgoXxdK5711FF29c',
+ privateKey: '_AFTIegzYV_l_5RYwzOCc22cpYcMUmpkA8bLbrlNq9I'
+ },
+ headers: {
+ 'Urgency': 'high'
+ },
+ contentEncoding: 'aes128gcm'
+ };
+
const icon = 'data:image/png;base64,' +
fs.readFileSync(__dirname + '/../../../public/images/icon.png', 'base64');
const payload = {
};
log.debug('Paylod length:', JSON.stringify(payload).length);
- webpush.sendNotification(pushSubscription, JSON.stringify(payload))
+ const details = webpush.generateRequestDetails(pushSubscription, JSON.stringify(payload), options);
+ log.debug('Request details:', JSON.stringify(details));
+
+ webpush.sendNotification(pushSubscription, JSON.stringify(payload), options)
.then(data => {
if (data) {
log.info('sent, data:', JSON.stringify(data));
const log = require('./../../../lib/logger')(__filename.slice(__dirname.length + 1));
const qStr = require('query-string');
const router = express.Router();
-const dblib = require('./../../../lib/dblib');
+const db = require('./../../../lib/db');
const fs = require('fs');
-/* Disables caching in client */
+/* Disables caching in client */
function nocache(req, res, next) {
res.header('Cache-Control', 'private, no-cache, no-store, must-revalidate');
res.header('Expires', '-1');
}
// read settings
- dblib.getSettings({
+ db.getSettings({
area: 'test',
key: req.header('X-API-Key-Test')
}, (err, data) => {
if (err) {
switch (err) {
- case dblib.msg.dbError:
+ case db.msg.dbError:
log.info('Server error response');
res.status(500).send();
break;
- case dblib.msg.keyMismatch:
+ case db.msg.keyMismatch:
log.info('Unauthorized access');
res.status(401).send();
break;