<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no">
<title>My Device App</title>
- <link href="lib/tau/mobile/theme/default/tau.min.css" rel="stylesheet" />
- <link rel="stylesheet" href="css/style.css" />
- <script data-build-remove="false" src="lib/tau/mobile/js/tau.min.js"></script>
- <script src="js/app.js" type="module"></script>
- <script src="js/invited.js" type="module"></script>
+ <link href="client/lib/tau/mobile/theme/default/tau.min.css" rel="stylesheet" />
+ <link rel="stylesheet" href="client/css/style.css" />
+ <script data-build-remove="false" src="client/lib/tau/mobile/js/tau.min.js"></script>
+ <script src="client/js/app.js" type="module"></script>
+ <script src="client/js/invited.js" type="module"></script>
</head>
<body>
+const TAG = '[DeviceHome][pincode]';
const serverPort = 9000;
const serverURL = window.location.protocol + '//' + window.location.hostname;
}
dots[input.length - 1].className += ' active';
if (input.length >= 4) {
+ console.log(`${TAG} input: ${input}`);
sendPinCode(input);
setTimeout(function () {
});
}
-function sendPinCode(data) {
+async function sendPinCode(data) {
var encrypt = new JSEncrypt();
encrypt.setPublicKey(publicKey);
var xhr = new XMLHttpRequest();
}
};
xhr.open('POST', serverURL + ':' + serverPort + '/pincode/pinCodeToServer');
- xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
- xhr.send(encrypt.encrypt(data));
+ xhr.setRequestHeader("Content-Type", "application/json");
+ var data = encrypt.encrypt(data);
+ console.log(`${TAG} data: ${data}`);
+ xhr.send(JSON.stringify({ pincode: data.toString("utf8") }));
}
function generatePinCodeNumber() {
</head>
<body>
- <form id="loginForm" action="/d2d" method="post"></form>
+ <form id="loginForm" action="/d2d" method="post">
<div id="pin">
<div class="dots">
<div class="dot"></div>
-var express = require('express');
+const express = require('express');
+const url = require('url');
const AppRouter = require('./app_router');
var appRouters = [];
var path = null;
if (isRunning && currentD2DAppId === appId) {
callback();
} else {
- var appControl = new tizen.ApplicationControl(
+ const urlParam = require('./service').getUrlParam();
+ const urlObj = url.parse(urlParam, true).query;
+ const appControl = new tizen.ApplicationControl(
"http://tizen.org/appcontrol/operation/default", null, null, null,
[new tizen.ApplicationControlData(
"http://tizen.org/appcontrol/data/launch_port", [port]
+ ),
+ new tizen.ApplicationControlData(
+ "http://tizen.org/appcontrol/data/url_parameter", [JSON.stringify(urlObj)]
)]
);
-var express = require('express');
+const express = require('express');
+const url = require('url');
+const TAG = '[App Router]'
class AppRouter {
constructor(app, path) {
- var appRouter = express.Router();
+ let appRouter = express.Router();
appRouter.use(express.static(__dirname + '/../../../../' + path + '/shared/res/client'));
appRouter.get('/', (req, res) => {
- console.log("[GlobalWebServer] appRouter.get(/) ", req.baseUrl);
- var roomData = require('./service').getUrlParam();
- console.log("[GlobalWebServer] appRouter.get(/) roomData : ", roomData);
-
- // [WT] Chatting App
- if (path === 'NAe4rftRic') {
- if (roomData.indexOf('roomId') != -1) {
- res.redirect('chat.html');
- }
- else {
- res.redirect('client.html');
- }
- }
- else {
- res.redirect('client.html');
- }
+ console.log(`${TAG} req.baseUrl : ${req.baseUrl}`);
+ const urlParam = require('./service').getUrlParam();
+ let urlObj = url.parse(urlParam, true).query;
+ let url_format = {
+ pathname: 'client.html',
+ query: urlObj
+ };
+ console.log(`${TAG} #################################`);
+ console.log(`${TAG} url_format : ${JSON.stringify(url_format)}`);
+ console.log(`${TAG} #################################`);
+ res.redirect(url.format(url_format));
});
return appRouter;
}
"use strict";
var WebSocketServer = require('ws').Server;
-const serviceWsClientIp = "1";
+const localClientIp = "1";
+const TAG = '[D2D Relay Server]'
const TO_ALL = 100;
-let wsClients = [];
-let serviceWs = [];
+let remoteClients = [];
+let localClients = [];
+let localClientsMessageQueue = [];
var RelayServer = function(httpserver, options) {
var wsServer = new WebSocketServer({ server : httpserver });
const ip = rawIp.slice(rawIp.lastIndexOf(":") + 1);
const pkgId = req.url.slice(1); // get the substring after '/' from req.url
- if (serviceWs[pkgId] === undefined) {
- serviceWs[pkgId] = null;
- }
- if (wsClients[pkgId] === undefined) {
- wsClients[pkgId] = [];
- }
- if (ip === serviceWsClientIp || ip === '127.0.0.1') {
+ if (remoteClients[pkgId] === undefined)
+ remoteClients[pkgId] = [];
+
+ if (ip === localClientIp || ip === '127.0.0.1') {
console.log("connected from local");
- serviceWs[pkgId] = ws;
- if (!wsClients[pkgId].length) {
+ const TAG_LOCAL = `${TAG}[Local Client]`;
+ localClients[pkgId] = ws;
+ if (!remoteClients[pkgId].length) {
console.log("connected : no client-clients");
}
+ if (localClientsMessageQueue[pkgId] !== undefined) {
+ for (let msg of localClientsMessageQueue[pkgId]) {
+ console.log(`${TAG_LOCAL}[message] #################################`);
+ console.log(`${TAG_LOCAL}[message] send pending msg : ${msg}`);
+ console.log(`${TAG_LOCAL}[message] #################################`);
+ ws.send(msg);
+ }
+ }
console.log("relay-service: ws", ws);
ws.on('message', function(msg) {
- console.log("msg[" + msg + "]");
- const res_msg = 'Success to send : ' + msg;
+ console.log(`${TAG_LOCAL}[message] #################################`);
+ console.log(`${TAG_LOCAL}[message] msg : ${msg}`);
+ console.log(`${TAG_LOCAL}[message] #################################`);
let myPkgId = null;
- for (let key in serviceWs) {
- if (serviceWs[key] === ws) {
+ for (let key in localClients) {
+ if (localClients[key] === ws) {
myPkgId = key;
break;
}
// Do what need to handle in relay server only
return;
}
- if (!wsClients[myPkgId].length)
+ if (!remoteClients[myPkgId].length)
return;
if (id == TO_ALL) {
- for (let client of wsClients[myPkgId])
+ for (let client of remoteClients[myPkgId])
client.send(msg);
} else {
- if (id < wsClients[myPkgId].length)
- wsClients[myPkgId][id].send(msg);
+ if (id < remoteClients[myPkgId].length)
+ remoteClients[myPkgId][id].send(msg);
+ }
+ });
+ ws.on('close', function(msg) {
+ console.log(`${TAG_LOCAL}[close] #################################`);
+ console.log(`${TAG_LOCAL}[close] msg : ${msg}`);
+ console.log(`${TAG_LOCAL}[close] #################################`);
+ let myPkgId = null;
+ for (let key in localClients) {
+ if (localClients[key] === ws) {
+ myPkgId = key;
+ break;
+ }
+ }
+ // remote local client
+ delete localClients[myPkgId];
+
+ console.log(`${TAG_LOCAL}[close] remoteClients[${myPkgId}] : ${remoteClients[myPkgId]}`);
+ for (let remoteClient of remoteClients[myPkgId]) {
+ console.log(`${TAG}[close local client] sent local_client_disconnect`);
+ remoteClient.send(JSON.stringify({
+ type: "local_client_disconnect",
+ data: {
+ totalcount: localClients.length,
+ id: 0
+ },
+ id: -1
+ }));
}
});
} else {
console.log("connected from", ip);
- if (wsClients[pkgId].indexOf(ws) == -1) {
- wsClients[pkgId].push(ws);
- let index = wsClients[pkgId].length - 1;
+ const TAG_REMOTE = `${TAG}[Remote Client]`;
+ if (remoteClients[pkgId].indexOf(ws) == -1) {
+ remoteClients[pkgId].push(ws);
+ let index = remoteClients[pkgId].length - 1;
let res = JSON.stringify({type: "id", data: index, id: -1});
ws.send(res);
- if (serviceWs[pkgId] === null)
+ console.log(`${TAG_REMOTE}[connection] localClients.length : ${localClients.length}`);
+ if (localClients[pkgId] === undefined || localClients.length === 0)
console.log("connected : no server-client")
else {
- serviceWs[pkgId].send(JSON.stringify({type: "new_client", data: index, id: -1}));
+ localClients[pkgId].send(JSON.stringify({type: "new_client", data: index, id: -1}));
}
}
ws.on('message', function(msg) {
- console.log("msg[" + msg + "]");
- const res_msg = 'Success to send : ' + msg;
+ console.log(`${TAG_REMOTE}[message] #################################`);
+ console.log(`${TAG_REMOTE}[message] msg : ${msg}`);
+ console.log(`${TAG_REMOTE}[message] #################################`);
let myPkgId = null;
- for (let key in wsClients) {
- if (wsClients[key].indexOf(ws) != -1) {
+ for (let key in remoteClients) {
+ if (remoteClients[key].indexOf(ws) != -1) {
myPkgId = key;
break;
}
}
- if (serviceWs[myPkgId])
- serviceWs[myPkgId].send(msg);
+ if (localClients[myPkgId]) {
+ localClients[myPkgId].send(msg);
+ } else {
+ console.log(`${TAG_REMOTE}[message] #################################`);
+ console.log(`${TAG_REMOTE}[message] localClient is not ready`);
+ console.log(`${TAG_REMOTE}[message] #################################`);
+ if (localClientsMessageQueue[myPkgId] === undefined)
+ localClientsMessageQueue[myPkgId] = [];
+ localClientsMessageQueue[myPkgId].push(msg);
+ console.log(`${TAG_REMOTE}[message] localClient is not ready : ${localClientsMessageQueue[myPkgId]}`);
+ }
});
ws.on('close', function(msg) {
+ console.log(`${TAG_REMOTE}[close] #################################`);
+ console.log(`${TAG_REMOTE}[close] msg : ${msg}`);
+ console.log(`${TAG_REMOTE}[close] #################################`);
let myPkgId = null;
- for (let key in wsClients) {
- if (wsClients[key].indexOf(ws) != -1) {
+ for (let key in remoteClients) {
+ if (remoteClients[key].indexOf(ws) != -1) {
myPkgId = key;
break;
}
}
-
- let index = wsClients[myPkgId].indexOf(ws);
- wsClients[myPkgId].splice(index, 1);
- serviceWs[myPkgId].send(JSON.stringify({type: "client_disconnect", data: {totalcount: wsClients[myPkgId].length, id: index}, id: -1}));
+ // remote remote client
+ let index = remoteClients[myPkgId].indexOf(ws);
+ delete remoteClients[myPkgId][index];
+ remoteClients[myPkgId].splice(index, 1);
+ console.log(`${TAG}[close remote client] localClients[${myPkgId}] : ${localClients[myPkgId]}`);
+ if (localClients[myPkgId] !== undefined) {
+ console.log(`${TAG}[close remote client] sent remote_client_disconnect`);
+ localClients[myPkgId].send(JSON.stringify({
+ type: "remote_client_disconnect",
+ data: {
+ totalcount: remoteClients[myPkgId].length,
+ id: index
+ },
+ id: -1
+ }));
+ }
});
}
});
--- /dev/null
+const crypto = require("crypto");
+const { generateKeyPair } = require("crypto");
+
+const TAG = '[DeviceHome][security.js]';
+
+module.exports.Security = class Security {
+ constructor() {
+ this.privateKey = '';
+ this.publicKey = '';
+ }
+
+ getKeyPairPromise(pincode) {
+ console.log(`${TAG} getKeyPairPromise`);
+ return new Promise((resolve, reject) => {
+ console.log(`${TAG} Generating key will take some time..`);
+ generateKeyPair("rsa", {
+ modulusLength: 1024,
+ publicKeyEncoding: {
+ type: "spki",
+ format: "pem"
+ },
+ privateKeyEncoding: {
+ type: "pkcs1",
+ format: "pem",
+ // TODO: Enable ciper and passphrase
+ //cipher: "aes-256-cbc",
+ //passphrase: pincode
+ }
+ }, (err, publicKey, privateKey) => {
+ // Handle errors and use the generated key pair.
+ resolve({
+ publicKey: publicKey,
+ privateKey: privateKey
+ });
+ });
+ });
+ }
+
+ awaitKeyPair(pincode) {
+ return this.getKeyPairPromise(pincode).then(r => {
+ this.privateKey = r.privateKey;
+ this.publicKey = r.publicKey;
+ console.log(`${TAG}[awaitKeyPair] RSA keys are generated`);
+ }).catch(err => {
+ console.log(`${TAG} Error : ${err}`);
+ });
+ }
+
+ // TODO: Use following APIs instead of JSEncryptLib
+ decryptWithPrivateKey(encryptedString, pincode) {
+ const key = crypto.createPrivateKey({
+ key: this.privateKey,
+ format: "pem",
+ passphrase: pincode
+ });
+ const encrypted = crypto.privateDecrypt(key, Buffer.from(encryptedString, "base64"));
+ const decryptedString = encrypted.toString("utf8");
+ return decryptedString;
+ }
+
+ encryptWithPrivateKey(plain, pincode) {
+ const keyp = crypto.createPrivateKey({
+ key: this.privateKey,
+ format: "pem",
+ passphrase: pincode
+ });
+ const encrypted = crypto.privateEncrypt(keyp, Buffer.from(plain));
+ const encryptedString = encrypted.toString("base64");
+ return encryptedString;
+ }
+
+ decryptWithPublicKey(encryptedString) {
+ const decrypted = crypto.publicDecrypt(this.publicKey, Buffer.from(encryptedString, "base64"));
+ const decryptedString = decrypted.toString("utf8");
+ return decryptedString;
+ }
+
+ encryptWithPublicKey(plain) {
+ const encrypted = crypto.publicEncrypt(this.publicKey, Buffer.from(plain));
+ const encryptedString = encrypted.toString("base64");
+ return encryptedString;
+ }
+
+ getPrivateKey() {
+ console.log(`${TAG} getPrivateKey`);
+ return this.privateKey;
+ }
+
+ getPublicKey() {
+ console.log(`${TAG} getPublicKey`);
+ return this.publicKey;
+ }
+}
const relayServer = require('./relay-server.js');
const session = require('express-session');
const EventEmitter = require('events');
-const WebSocket = require('ws');
const XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
const crypto = require('crypto');
+const { Security } = require('./security.js');
-const PUBLIC_DOMAIN = 'http://mydevice.ga';
-const TAG = '[D2D Server]'
+const PUBLIC_DOMAIN = 'http://219.254.222.198';
+const TAG = '[DeviceHome][service.js]'
const TIZEN_WEB_APP_SHARED_RESOURCES = 'shared/res/';
const WEBCLIP_DIRECTORY = 'webclip';
const WEBCLIP_MANIFEST = 'manifest.json';
'127.0.0.1',
'192.168.250.250'
]
+const security = new Security();
var apps = [];
var dataApps = [];
var clientRouter = express.Router();
-var httpserver, evtEmit, d2dService;
+var httpserver, evtEmit;
var platform_app_path = '/opt/usr/globalapps';
var serverAppId = '';
var urlParam = '';
// Watch together doesn't use pincode just for demo.
var MODE_WT = false;
-// manage private key.
-var pvkeyHandle = tizen.filesystem.openFile(path.resolve(__dirname, 'private.key'), 'r');
-var privateKey = pvkeyHandle.readString();
-
-// manage public key.
-var pbkeyHandle = tizen.filesystem.openFile(path.resolve(__dirname, 'public.key'), 'r');
-var publicKey = pbkeyHandle.readString();
-
function addD2Ddata(appPkgID, appAppID, appName, iconPath) {
let metaDataArray = tizen.application.getAppMetaData(appAppID),
app = null,
metaAppID = '';
- metaDataArray = metaDataArray.filter(function (metaData) {
+ metaDataArray = metaDataArray.filter(function(metaData) {
if (metaData.key === "d2dservice") {
if (metaData.value !== "enable") {
metaAppID = metaData.value;
}
return false;
});
- metaDataArray.forEach(function () {
+ metaDataArray.forEach(function() {
let appPath = path.join(platform_app_path, appPkgID, TIZEN_WEB_APP_SHARED_RESOURCES);
app = {
function getAppList() {
if (tizen.application) {
try {
- tizen.application.getAppsInfo(function (applications) {
+ tizen.application.getAppsInfo(function(applications) {
apps = applications;
setData();
getWebclipsManifest();
function setPackageInfoEventListener() {
var packageEventCallback = {
- oninstalled: function (packageInfo) {
+ oninstalled: function(packageInfo) {
console.log(`${TAG} The package ${packageInfo.name} is installed`);
let app = addD2Ddata(packageInfo.id, packageInfo.appIds[0], packageInfo.name, packageInfo.iconPath);
- getWebclipsManifestByApp(app);
+ if (app !== null)
+ getWebclipsManifestByApp(app);
evtEmit.emit("updateapplist", "message", dataApps);
},
- onupdated: function (packageInfo) {
+ onupdated: function(packageInfo) {
console.log(`${TAG} The package ${packageInfo.name} is updated`);
},
- onuninstalled: function (packageId) {
+ onuninstalled: function(packageId) {
console.log(`${TAG} The package ${packageId} is uninstalled`);
removeD2Ddata(packageId);
evtEmit.emit("updateapplist", "message", dataApps);
var result = [];
var webclips = [];
- dataApps.forEach(function (app) {
+ dataApps.forEach(function(app) {
webclips = [];
if (app.webclip && app.webclip.manifest) {
webclips.push({
device_name: device_name,
device_ip: device_ip
};
- xhr.onreadystatechange = function () {
+ xhr.onreadystatechange = function() {
if (xhr.readyState === xhr.DONE) {
console.log(`${TAG} xhr text: ${xhr.responseText}`);
if (xhr.status === 200 || xhr.status === 201) {
function comparePincode(req, res, encrypted) {
console.log(`${TAG} comparePincode`);
+ console.log(`${TAG} encrypted : ${encrypted}`);
// Decrypt pincode using private key
var decrypt = new JSEncryptLib.JSEncrypt();
- decrypt.setPrivateKey(privateKey);
+ decrypt.setPrivateKey(security.getPrivateKey());
var decrypted = decrypt.decrypt(encrypted);
-
- console.log('[WT] input pincode : ' + pincode);
- console.log('[WT] decrypted : ' + decrypted);
+ console.log(`${TAG} decrypted : ${decrypted}`);
let pincode_passed = decrypted === pincode ? true : false;
console.log(`${TAG} pincode result : ${pincode_passed}`);
webapis.postPlainNotification("PIN Code", pinNumber, 10);
}
-var HTTPserverStart = function () {
+var HTTPserverStart = function() {
evtEmit = new EventEmitter();
var app = express();
app.engine('html', require('ejs').renderFile);
},
}));
- var sessionChecker = function (req, res, next) {
+ var sessionChecker = function(req, res, next) {
console.log(`${TAG} url : ${req.url}`);
+ console.log(`${TAG} session : ${JSON.stringify(req.session)}`);
const rawIp = req.socket.remoteAddress;
const ip = rawIp.slice(rawIp.lastIndexOf(":") + 1);
// The pincode page and local connections are allowed without session.
if (req.session.pincode === undefined &&
- !req.url.includes('/?id=') &&
+ !req.url.includes('id=') &&
!req.url.includes('/pincode/') &&
!non_ip_list.includes(ip)) {
- console.log(`${TAG} session : ${JSON.stringify(req.session)}`);
+ console.log(`${TAG} Not valid access`);
res.redirect(401, PUBLIC_DOMAIN);
+ } else {
+ next();
}
- next();
};
if (!MODE_WT)
g.baseDir = __dirname.split(serverAppId)[0];
console.log(`${TAG} g.baseDir: ${g.baseDir}`);
- clientRouter.get('/webclip/*', function (req, res) {
+ clientRouter.get('/webclip/*', function(req, res) {
let file = req.originalUrl.replace('/client/webclip/', '').replace(/\?.+$/, '');
let webclipName = '';
console.log(`${TAG} webclip name: ${webclipName}`);
// find appId by webclip name
- let app = dataApps.filter(function (app) {
+ let app = dataApps.filter(function(app) {
return !!app.webclip && app.webclip.manifest.name === webclipName;
})[0];
if (app) {
appId = app.d2dApp.appPkgID;;
}
+ console.log(`${TAG} root : ${platform_app_path}/${appId}/${TIZEN_WEB_APP_SHARED_RESOURCES}/${WEBCLIP_DIRECTORY}`);
let options = {
root: path.join(platform_app_path, appId, TIZEN_WEB_APP_SHARED_RESOURCES, WEBCLIP_DIRECTORY)
};
// remove weblip name from path
file = file.replace(webclipName + '/', '');
- res.sendFile(file, options, function (err) {
+ res.sendFile(file, options, function(err) {
if (err) {
console.log(`${TAG} err: ${err}`);
res.send("err", err);
});
});
- clientRouter.get('/updateWebclip', function (req, res) {
+ clientRouter.get('/updateWebclip', function(req, res) {
console.log(`${TAG} get(/updateWebclip)`);
var apps = getWebClipsList();
var result = {
res.send(result);
});
- clientRouter.get('/*', function (req, res) {
+ clientRouter.get('/*', function(req, res) {
let file = req.originalUrl.replace('/client/', '').replace(/\?.+$/, '');
let pkgId = webapis.getPackageId();
let fullPath = require('path').join(g.baseDir, pkgId, '/res/wgt/client', file);
res.sendFile(fullPath);
});
- app.get('/', function (req, res) {
+ app.get('/', function(req, res) {
console.log(`${TAG} URL parameter : ${req.originalUrl}`);
urlParam = req.originalUrl;
if (!MODE_WT) {
- // Getnerate pincode
- const crypto = require('crypto');
- var byteData = crypto.randomBytes(256);
- pincode = parseInt(byteData.toString('hex').substr(0, 8), 16).toString().substr(0, 4);
- webapis.postPlainNotification("PIN Code", pincode, 10);
res.redirect("/pincode/pincode.html");
} else {
if (req.query.roomId !== undefined) {
- res.redirect("/client/invited.html");
+ // FIXME: Remove app logic here
+ res.render("client/invited.html");
} else {
+ // Device home
res.render("client/client.html");
}
}
});
});
- app.get('/pincode/publicKey', (req, res) => {
- // Send public key
- res.send(publicKey);
+ app.get('/pincode/publicKey', async (req, res) => {
+ // Getnerate pincode
+ var byteData = crypto.randomBytes(256);
+ pincode = parseInt(byteData.toString('hex').substr(0, 8), 16).toString().substr(0, 4);
+ // Getnerate RSA keys
+ await security.awaitKeyPair();
+ // Show pincode popup
+ webapis.postPlainNotification("Input Pincode: ", pincode, 10);
+
+ const key = security.getPublicKey();
+ console.log(`${TAG} Send public key`);
+ res.send(key);
});
- app.post('/pincode/pinCodeToServer', (req, res) => {
- console.log(`${TAG} pinCodeToServer`);
+ app.post('/pincode/pinCodeToServer', express.json(), (req, res) => {
var revData = JSON.stringify(req.body);
var resultData = revData.replace(/"/g, "").replace(/{/g, "").replace(/}/g, "").replace(/:/g, "").replace(/[\s]/g, "+");
// Verify encrypted pincode
+ resultData = req.body['pincode'];
+ console.log(`${TAG} pinCodeToServer resultData : ${resultData}`);
comparePincode(req, res, resultData);
});
generatePinCodeNumber();
});
- app.get('/getRoomId', (req, res) => {
- res.send(urlParam);
- });
-
// receive data or cmd to app on device
app.post('/app', (req, res) => {
res.send({
});
httpserver = http.createServer(app);
- httpserver.listen(g.port, function () {
+ httpserver.listen(g.port, function() {
var interfaces = require('os').networkInterfaces();
for (var devName in interfaces) {
if (interfaces.hasOwnProperty(devName)) {
relayServer(httpserver);
};
-module.exports.getUrlParam = function () {
+module.exports.getUrlParam = function() {
console.log(`${TAG} getUrlParam is called`);
return urlParam;
};
-module.exports.onStart = function () {
+module.exports.onStart = function() {
getAppList();
HTTPserverStart();
setPackageInfoEventListener();
console.log(`${TAG} onStart is called in DNS Resolver`);
};
-module.exports.onStop = function () {
+module.exports.onStop = function() {
if (httpserver) {
httpserver.close();
console.log(`${TAG} Server Terminated`);