From 1752e0b1e85a2b8ffa10b77f755ce5d80aa4f39b Mon Sep 17 00:00:00 2001 From: Youngsoo Choi Date: Sun, 29 Aug 2021 17:02:45 -0700 Subject: [PATCH] [DeviceHome] Upgrade to v1.0.8 - Send package ID to remote client - Don'y use hard-coded package ID - Update webclip icon on remote client when webclip is installed - Fix bugs for sending messages Change-Id: I8086ff1d13c046e5049904375655197f34832d4b Signed-off-by: Youngsoo Choi --- device_home/service/app_proxy.js | 2 +- device_home/service/app_router.js | 4 +- device_home/service/relay-server.js | 35 +++++---- device_home/service/service.js | 139 ++++++++++++++++++++---------------- 4 files changed, 103 insertions(+), 77 deletions(-) diff --git a/device_home/service/app_proxy.js b/device_home/service/app_proxy.js index a27fb27..1cd814c 100755 --- a/device_home/service/app_proxy.js +++ b/device_home/service/app_proxy.js @@ -66,7 +66,7 @@ module.exports = function (app, port) { appRouters.push({ path: path, name: name, - router: new AppRouter(app, path) + router: new AppRouter(app, path, appId, pkgId) }); } console.log('[GlobalWebServer] appProxy.post ', path, action); diff --git a/device_home/service/app_router.js b/device_home/service/app_router.js index 4aba0a3..b95b198 100755 --- a/device_home/service/app_router.js +++ b/device_home/service/app_router.js @@ -8,7 +8,7 @@ const platform_app_path = is_tv ? '/opt/usr/apps' : '/opt/usr/globalapps'; const platform_shared_path = '/shared/res/client'; class AppRouter { - constructor(app, app_path) { + constructor(app, app_path, appId, pkgId) { const appRouter = express.Router(); const client_path = path.join(platform_app_path, app_path, platform_shared_path); console.log(`${TAG} static client path : ${client_path}`); @@ -18,6 +18,8 @@ class AppRouter { console.log(`${TAG} req.baseUrl : ${req.baseUrl}`); const urlParam = require('./service').getUrlParam(); let urlObj = url.parse(urlParam, true).query; + urlObj.appId = appId; + urlObj.pkgId = pkgId; let url_format = { pathname: 'client.html', query: urlObj diff --git a/device_home/service/relay-server.js b/device_home/service/relay-server.js index f8ea8ad..3bd650d 100755 --- a/device_home/service/relay-server.js +++ b/device_home/service/relay-server.js @@ -10,6 +10,7 @@ const TAG_HOST = `${TAG}[Host]`; const TAG_CLIENT = `${TAG}[Client]`; const TO_ALL = 100; +let wsServer = undefined; let receiver = {}; let sender = {}; let remoteClients = {}; @@ -65,6 +66,8 @@ var OnReceived = function (msg) { return; } const id = msg.id; + const secure = msg.secure; + msg = JSON.stringify(msg); if (id === -1) { console.log(`${TAG_HOST}[OnReceived] Handle message only on relay server`); // Do what need to handle in relay server only @@ -75,14 +78,12 @@ var OnReceived = function (msg) { console.log(`${TAG_HOST}[OnReceived] Send message to all web sockets`); console.log(`${TAG_HOST}[OnReceived] remoteClients length : ${remoteClients[pkgId].length}`); for (let client of remoteClients[pkgId]) { - if (msg.secure) { - msg = encrypt(JSON.stringify(msg), client, pkgId, globalClientPublicKeys); + if (secure) { + msg = encrypt(msg, client, pkgId, globalClientPublicKeys); if (msg === false || msg === null) { console.log(`${TAG_HOST}[OnReceived] Failed to encrypt message!`); return; } - } else { - msg = JSON.stringify(msg); } console.log(`${TAG_HOST}[OnReceived] msg : ${msg}`); client.emit('d2d_message', msg); @@ -90,14 +91,12 @@ var OnReceived = function (msg) { } else { console.log(`${TAG_HOST}[OnReceived] Send message to a web socket #${id}`); if (id < remoteClients[pkgId].length) { - if (msg.secure) { - msg = encrypt(JSON.stringify(msg), remoteClients[pkgId][id], pkgId, globalClientPublicKeys); + if (secure) { + msg = encrypt(msg, remoteClients[pkgId][id], pkgId, globalClientPublicKeys); if (msg === false || msg === null) { console.log(`${TAG_HOST}[OnReceived] Failed to encrypt message!`); return; } - } else { - msg = JSON.stringify(msg); } console.log(`${TAG_HOST}[OnReceived] msg : ${msg}`); remoteClients[pkgId][id].emit('d2d_message', msg); @@ -252,13 +251,19 @@ var addConnection = function(wsServer, pkgId, sessionMiddleware, clientPublicKey } }); } -var RelayServer = function(httpserver, dataApps, sessionMiddleware, clientPublicKeys) { - const wsServer = io.listen(httpserver, { - log: true, - origins: '*:*' - }); - for (var j = 0; j < dataApps.length; j++) { - addConnection(wsServer, dataApps[j].d2dApp.pkgId, sessionMiddleware, clientPublicKeys); +var RelayServer = function(httpserver, dataApps, sessionMiddleware, clientPublicKeys, pkgId) { + if (wsServer === undefined) { + wsServer = io.listen(httpserver, { + log: true, + origins: '*:*' + }); + } + if (pkgId === undefined) { + for (var j = 0; j < dataApps.length; j++) { + addConnection(wsServer, dataApps[j].d2dApp.pkgId, sessionMiddleware, clientPublicKeys); + } + } else { + addConnection(wsServer, pkgId, sessionMiddleware, clientPublicKeys); } }; diff --git a/device_home/service/service.js b/device_home/service/service.js index 69b47ff..9997cb9 100755 --- a/device_home/service/service.js +++ b/device_home/service/service.js @@ -1,13 +1,13 @@ -"use strict"; +'use strict'; const express = require('express'); const http = require('http'); -const path = require("path"); +const path = require('path'); const relayServer = require('./relay-server.js'); const session = require('express-session'); const cookieParser = require('cookie-parser'); const EventEmitter = require('events'); -const XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest; +const XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; const crypto = require('crypto'); const { Security } = require('./security.js'); const JSEncryptLib = require('./jsencrypt'); @@ -59,10 +59,10 @@ function addD2Ddata(pkgId, appId, appName, iconPath) { let metaAppID = ''; let metaDataArray = tizen.application.getAppMetaData(appId); metaDataArray = metaDataArray.filter(function(metaData) { - if (metaData.key !== "d2dservice") + if (metaData.key !== 'd2dservice') return false; - if (metaData.value !== "enable") + if (metaData.value !== 'enable') metaAppID = metaData.value; return true; }); @@ -113,86 +113,105 @@ function promiseGetAppList() { }) } -function getWebclipsManifestByApp(app, callback) { - var fileHandle, - filePath = path.join(app.path, WEBCLIP_DIRECTORY, WEBCLIP_MANIFEST), - data, - skipMainDir = false; - - app.webclips = []; - console.log(`${TAG} webclip path : ${filePath}`); - try { - fileHandle = tizen.filesystem.openFile(filePath, "r"); - } catch (err) { - skipMainDir = true; - console.log(`${TAG} tizen.filesystem.openFile (error): ${filePath} ${err}`); - // check subdirectories - tizen.filesystem.listDirectory(path.join(app.path, WEBCLIP_DIRECTORY), function (dirs) { +function checkWebclipSubDirectories(app, data, callback) { + return new Promise(resolve => { + tizen.filesystem.listDirectory(path.join(app.path, WEBCLIP_DIRECTORY), function(dirs) { dirs.forEach(function (directory) { - filePath = path.join(app.path, WEBCLIP_DIRECTORY, directory, WEBCLIP_MANIFEST); - fileHandle = tizen.filesystem.openFile(filePath, "r"); + const filePath = path.join(app.path, WEBCLIP_DIRECTORY, directory, WEBCLIP_MANIFEST); + console.log(`${TAG} webclip path : ${filePath}`); + const fileHandle = tizen.filesystem.openFile(filePath, 'r'); if (fileHandle) { try { data = fileHandle.readString(); - data = data.replace(/\n/g, ""); + data = data.replace(/\n/g, ''); data = JSON.parse(data); app.webclips.push({ manifest: data, path: path.join(app.path, WEBCLIP_DIRECTORY, directory), }); - } catch (error) { - console.log("[GlobalWebServer] fileHandle.readString (error): ", error); + } catch (err) { + console.log(`${TAG} fileHandle.readString directory (error): ${err}`); } - fileHandle.close(); } }); - if (typeof callback === "function") { + if (typeof callback === 'function') { callback(); } + resolve(true); + }, function(err) { + console.log(`${TAG} ${err}`); + resolve(false); }); - } + }); +} - if (fileHandle && !skipMainDir) { - try { - data = fileHandle.readString(); - data = data.replace(/\n/g, ""); - data = JSON.parse(data); +function getWebclipManifestsByApp(app, callback) { + return new Promise(async resolve => { + const filePath = path.join(app.path, WEBCLIP_DIRECTORY, WEBCLIP_MANIFEST); + console.log(`${TAG} webclip path : ${filePath}`); + let data = ''; + let fileHandle = undefined; + let skipMainDir = false; + app.webclips = []; - app.webclips.push({ - manifest: data, - path: path.join(app.path, WEBCLIP_DIRECTORY) - }); + try { + fileHandle = tizen.filesystem.openFile(filePath, 'r'); } catch (err) { - console.log(`${TAG} fileHandle.readString (error): ${err}`); + skipMainDir = true; + console.log(`${TAG} No manifest in main directory : ${err}`); + // check subdirectories + console.log(`${TAG} Check subdirectories`); + await checkWebclipSubDirectories(app, data, callback); } - fileHandle.close(); - if (typeof callback === "function") { - callback(); + if (fileHandle && !skipMainDir) { + try { + data = fileHandle.readString(); + data = data.replace(/\n/g, ''); + data = JSON.parse(data); + + app.webclips.push({ + manifest: data, + path: path.join(app.path, WEBCLIP_DIRECTORY) + }); + } catch (err) { + console.log(`${TAG} fileHandle.readString (error): ${err}`); + } + fileHandle.close(); + + if (typeof callback === 'function') { + callback(); + } } - } + resolve(true); + }); } function getWebclipsManifest() { dataApps.forEach( - getWebclipsManifestByApp + getWebclipManifestsByApp ); } function setPackageInfoEventListener() { const packageEventCallback = { - oninstalled: function(packageInfo) { + oninstalled: async function(packageInfo) { console.log(`${TAG} The package ${packageInfo.name} is installed`); const app = addD2Ddata(packageInfo.id, packageInfo.appIds[0], packageInfo.name, packageInfo.iconPath); if (app.path !== undefined) { - getWebclipsManifestByApp(app, function () { - evtEmit.emit("updateapplist", "message", dataApps); + // only for webclip + await getWebclipManifestsByApp(app, function () { + console.log(`${TAG} Webclip has been updated`); }); + console.log(`${TAG} Emit app list`); + // for both companion and webclip + evtEmit.emit('updateapplist', 'message', dataApps); + relayServer(httpserver, dataApps, sessionMiddleware, clientPublicKeys, packageInfo.id); } else { - evtEmit.emit("updateapplist", "message", dataApps); + evtEmit.emit('updateapplist', 'message', dataApps); } }, onupdated: function(packageInfo) { @@ -201,7 +220,7 @@ function setPackageInfoEventListener() { onuninstalled: function(packageId) { console.log(`${TAG} The package ${packageId} is uninstalled`); removeD2Ddata(packageId); - evtEmit.emit("updateapplist", "message", dataApps); + evtEmit.emit('updateapplist', 'message', dataApps); } }; tizen.package.setPackageInfoEventListener(packageEventCallback); @@ -317,11 +336,11 @@ async function displayPincode(req) { // Generate RSA keys await security.awaitKeyPair(req); // Show pincode popup - webapis.postPlainNotification("Input Pincode: ", req.session.pincode, 10); + webapis.postPlainNotification('Input Pincode: ', req.session.pincode, 10); } function getIp(rawIp) { - return rawIp.slice(rawIp.lastIndexOf(":") + 1); + return rawIp.slice(rawIp.lastIndexOf(':') + 1); } var HTTPserverStart = function() { @@ -441,7 +460,7 @@ var HTTPserverStart = function() { console.log(`${TAG} get(/updateWebclip)`); const apps = getWebClipsList(); const result = { - type: "full", + type: 'full', data: { apps: apps } @@ -463,26 +482,26 @@ var HTTPserverStart = function() { urlParam = req.originalUrl; if (!DEMO_MODE) { - res.redirect("/pincode/pincode.html"); + res.redirect('/pincode/pincode.html'); } else { console.log(`${TAG} Set session ip and RSA keys in WT mode`); req.session.ip = getIp(req.socket.remoteAddress); await security.awaitKeyPair(req); if (req.query.roomId !== undefined) { // FIXME: Remove app logic here - res.render("client/invited.html"); + res.render('client/invited.html'); } else if (req.query.pageUrl !== undefined) { if (typeof webapis.mde !== 'undefined') webapis.mde.launchBrowserFromUrl(req.query.pageUrl); } else { // Device home - res.render("client/client.html"); + res.render('client/client.html'); } } }); app.get('/d2dIcon/*', (req, res) => { - let fullPath = req.originalUrl.replace("d2dIcon", platform_app_path); + let fullPath = req.originalUrl.replace('d2dIcon', platform_app_path); res.sendFile(fullPath); }); @@ -496,8 +515,8 @@ var HTTPserverStart = function() { 'Cache-Control': 'no-cache', 'Connection': 'keep-alive' }); - evtEmit.on("updateapplist", (event, data) => { - res.write("event: " + String(event) + "\n" + "data: " + JSON.stringify(data) + "\n\n"); + evtEmit.on('updateapplist', (event, data) => { + res.write('event: ' + String(event) + '\n' + 'data: ' + JSON.stringify(data) + '\n\n'); }); }); @@ -530,7 +549,7 @@ var HTTPserverStart = function() { app.post('/d2d', (req, res) => { if (req.session.ip !== undefined) { console.log(`${TAG} client.html`); - res.render("client/client.html"); + res.render('client/client.html'); } else { console.log(`${TAG} no client.html`); res.redirect(401, PUBLIC_DOMAIN); @@ -540,7 +559,7 @@ var HTTPserverStart = function() { // receive data or cmd to app on device app.post('/app', (req, res) => { res.send({ - result: "ok" + result: 'ok' }); }); @@ -597,7 +616,7 @@ module.exports.onStop = function() { console.log(`${TAG} Server Terminated`); } unsetPackageInfoEventListener(); - evtEmit.off("updateapplist"); + evtEmit.off('updateapplist'); console.log(`${TAG} onStop is called in DNS Resolver`); }; -- 2.7.4