From 5edb76ef347e9e5da1e0cb4f0f769e23b4c6cb24 Mon Sep 17 00:00:00 2001 From: Roxanne Skelly Date: Fri, 14 Sep 2018 11:35:20 -0700 Subject: [PATCH 01/38] Checkpoint Tray Notifier --- .../resources/tray-menu-notification.png | Bin 0 -> 319 bytes server-console/src/main.js | 229 +++++++++------ server-console/src/modules/hf-app.js | 71 +++++ .../src/modules/hf-notifications.js | 263 ++++++++++++++++++ server-console/src/modules/hf-process.js | 18 ++ 5 files changed, 493 insertions(+), 88 deletions(-) create mode 100644 server-console/resources/tray-menu-notification.png create mode 100644 server-console/src/modules/hf-app.js create mode 100644 server-console/src/modules/hf-notifications.js diff --git a/server-console/resources/tray-menu-notification.png b/server-console/resources/tray-menu-notification.png new file mode 100644 index 0000000000000000000000000000000000000000..569ee95d7ed77761062251173dda4a02f2d40e75 GIT binary patch literal 319 zcmV-F0l@x=P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0MtoDK~yMHElxXb z0x=MMV=b^qp`Zb}h%0abD3YFn2Bm?9bJ5UofK)jG1!+?tBsPgiw%}`QuP0ASMtYv{ zypJvTFP%&k`(F-RHJgydyyVJ5heO5b3KS6tgtApDsJy+3=*w8~{c|Tu1lkM^H0GTa z#6Lf2a9k3`2NZN$5gaJmCkfXtfg4eS}R@*jg3nv`Z2I{s5>wVTi4c RNGSjS002ovPDHLkV1gtFc~bxY literal 0 HcmV?d00001 diff --git a/server-console/src/main.js b/server-console/src/main.js index 92ebdbf36c..0fd2659fe9 100644 --- a/server-console/src/main.js +++ b/server-console/src/main.js @@ -29,58 +29,31 @@ const updater = require('./modules/hf-updater.js'); const Config = require('./modules/config').Config; const hfprocess = require('./modules/hf-process.js'); + +global.log = require('electron-log'); + const Process = hfprocess.Process; const ACMonitorProcess = hfprocess.ACMonitorProcess; const ProcessStates = hfprocess.ProcessStates; const ProcessGroup = hfprocess.ProcessGroup; const ProcessGroupStates = hfprocess.ProcessGroupStates; +const hfApp = require('./modules/hf-app.js'); +const GetBuildInfo = hfApp.getBuildInfo; +const StartInterface = hfApp.startInterface; + const osType = os.type(); const appIcon = path.join(__dirname, '../resources/console.png'); +const menuNotificationIcon = path.join(__dirname, '../resources/tray-menu-notification.png'); + const DELETE_LOG_FILES_OLDER_THAN_X_SECONDS = 60 * 60 * 24 * 7; // 7 Days const LOG_FILE_REGEX = /(domain-server|ac-monitor|ac)-.*-std(out|err).txt/; const HOME_CONTENT_URL = "http://cdn.highfidelity.com/content-sets/home-tutorial-RC40.tar.gz"; -function getBuildInfo() { - var buildInfoPath = null; - - if (osType == 'Windows_NT') { - buildInfoPath = path.join(path.dirname(process.execPath), 'build-info.json'); - } else if (osType == 'Darwin') { - var contentPath = ".app/Contents/"; - var contentEndIndex = __dirname.indexOf(contentPath); - - if (contentEndIndex != -1) { - // this is an app bundle - var appPath = __dirname.substring(0, contentEndIndex) + ".app"; - buildInfoPath = path.join(appPath, "/Contents/Resources/build-info.json"); - } - } - - const DEFAULT_BUILD_INFO = { - releaseType: "", - buildIdentifier: "dev", - buildNumber: "0", - stableBuild: "0", - organization: "High Fidelity - dev", - appUserModelId: "com.highfidelity.sandbox-dev" - }; - var buildInfo = DEFAULT_BUILD_INFO; - - if (buildInfoPath) { - try { - buildInfo = JSON.parse(fs.readFileSync(buildInfoPath)); - } catch (e) { - buildInfo = DEFAULT_BUILD_INFO; - } - } - - return buildInfo; -} -const buildInfo = getBuildInfo(); +const buildInfo = GetBuildInfo(); function getRootHifiDataDirectory(local) { var organization = buildInfo.organization; @@ -114,7 +87,6 @@ const UPDATER_LOCK_FILENAME = ".updating"; const UPDATER_LOCK_FULL_PATH = getRootHifiDataDirectory() + "/" + UPDATER_LOCK_FILENAME; // Configure log -global.log = require('electron-log'); const oldLogFile = path.join(getApplicationDataDirectory(), '/log.txt'); const logFile = path.join(getApplicationDataDirectory(true), '/log.txt'); if (oldLogFile != logFile && fs.existsSync(oldLogFile)) { @@ -149,15 +121,23 @@ const configPath = path.join(getApplicationDataDirectory(), 'config.json'); var userConfig = new Config(); userConfig.load(configPath); - const ipcMain = electron.ipcMain; + +function isServerInstalled() { + return interfacePath && userConfig.get("serverInstalled", true); +} + +function isInterfaceInstalled() { + return dsPath && acPath && userConfig.get("interfaceInstalled", true); +} + var isShuttingDown = false; function shutdown() { log.debug("Normal shutdown (isShuttingDown: " + isShuttingDown + ")"); if (!isShuttingDown) { // if the home server is running, show a prompt before quit to ask if the user is sure - if (homeServer.state == ProcessGroupStates.STARTED) { + if (isServerInstalled() && homeServer.state == ProcessGroupStates.STARTED) { log.debug("Showing shutdown dialog."); dialog.showMessageBox({ type: 'question', @@ -184,6 +164,9 @@ function shutdownCallback(idx) { if (idx == 0 && !isShuttingDown) { isShuttingDown = true; + log.debug("Stop tray polling."); + trayNotifications.stopPolling(); + log.debug("Saving user config"); userConfig.save(configPath); @@ -191,31 +174,37 @@ function shutdownCallback(idx) { log.debug("Closing log window"); logWindow.close(); } - if (homeServer) { - log.debug("Stoping home server"); - homeServer.stop(); - } - updateTrayMenu(homeServer.state); + if(isServerInstalled()) { + if (homeServer) { + log.debug("Stoping home server"); + homeServer.stop(); - if (homeServer.state == ProcessGroupStates.STOPPED) { - // if the home server is already down, take down the server console now - log.debug("Quitting."); - app.exit(0); - } else { - // if the home server is still running, wait until we get a state change or timeout - // before quitting the app - log.debug("Server still shutting down. Waiting"); - var timeoutID = setTimeout(function() { - app.exit(0); - }, 5000); - homeServer.on('state-update', function(processGroup) { - if (processGroup.state == ProcessGroupStates.STOPPED) { - clearTimeout(timeoutID); + updateTrayMenu(homeServer.state); + + if (homeServer.state == ProcessGroupStates.STOPPED) { + // if the home server is already down, take down the server console now log.debug("Quitting."); app.exit(0); + } else { + // if the home server is still running, wait until we get a state change or timeout + // before quitting the app + log.debug("Server still shutting down. Waiting"); + var timeoutID = setTimeout(function() { + app.exit(0); + }, 5000); + homeServer.on('state-update', function(processGroup) { + if (processGroup.state == ProcessGroupStates.STOPPED) { + clearTimeout(timeoutID); + log.debug("Quitting."); + app.exit(0); + } + }); } - }); + } + } + else { + app.exit(0); } } } @@ -351,20 +340,6 @@ function openLogDirectory() { app.on('window-all-closed', function() { }); -function startInterface(url) { - var argArray = []; - - // check if we have a url parameter to include - if (url) { - argArray = ["--url", url]; - } - - // create a new Interface instance - Interface makes sure only one is running at a time - var pInterface = new Process('interface', interfacePath, argArray); - pInterface.detached = true; - pInterface.start(); -} - var tray = null; global.homeServer = null; global.domainServer = null; @@ -372,6 +347,18 @@ global.acMonitor = null; global.userConfig = userConfig; global.openLogDirectory = openLogDirectory; +const hfNotifications = require('./modules/hf-notifications.js'); +const HifiNotifications = hfNotifications.HifiNotifications; +const HifiNotificationType = hfNotifications.NotificationType; + +var pendingNotifications = {} +function notificationCallback(notificationType) { + pendingNotifications[notificationType] = true; + updateTrayMenu(homeServer ? homeServer.state : ProcessGroupStates.STOPPED); +} + +var trayNotifications = new HifiNotifications(userConfig, notificationCallback); + var LogWindow = function(ac, ds) { this.ac = ac; this.ds = ds; @@ -407,7 +394,7 @@ LogWindow.prototype = { function visitSandboxClicked() { if (interfacePath) { - startInterface('hifi://localhost'); + StartInterface('hifi://localhost'); } else { // show an error to say that we can't go home without an interface instance dialog.showErrorBox("Client Not Found", binaryMissingMessage("High Fidelity client", "Interface", false)); @@ -425,6 +412,47 @@ var labels = { label: 'Version - ' + buildInfo.buildIdentifier, enabled: false }, + enableNotifications: { + label: 'Enable Notifications', + type: 'checkbox', + checked: true, + click: function() { + trayNotifications.enable(!trayNotifications.enabled(), notificationCallback); + updateTrayMenu(homeServer ? homeServer.state : ProcessGroupStates.STOPPED); + } + }, + goto: { + label: 'Goto', + click: function() { + StartInterface(""); + pendingNotifications[HifiNotificationType.GOTO] = false; + updateTrayMenu(homeServer ? homeServer.state : ProcessGroupStates.STOPPED); + } + }, + people: { + label: 'People', + click: function() { + StartInterface(""); + pendingNotifications[HifiNotificationType.PEOPLE] = false; + updateTrayMenu(homeServer ? homeServer.state : ProcessGroupStates.STOPPED); + } + }, + wallet: { + label: 'Wallet', + click: function() { + StartInterface(""); + pendingNotifications[HifiNotificationType.WALLET] = false; + updateTrayMenu(homeServer ? homeServer.state : ProcessGroupStates.STOPPED); + } + }, + marketplace: { + label: 'Marketplace', + click: function() { + StartInterface(""); + pendingNotifications[HifiNotificationType.MARKETPLACE] = false; + updateTrayMenu(homeServer ? homeServer.state : ProcessGroupStates.STOPPED); + } + }, restart: { label: 'Start Server', click: function() { @@ -489,16 +517,30 @@ function buildMenuArray(serverState) { if (isShuttingDown) { menuArray.push(labels.shuttingDown); } else { - menuArray.push(labels.serverState); - menuArray.push(labels.version); - menuArray.push(separator); - menuArray.push(labels.goHome); - menuArray.push(separator); - menuArray.push(labels.restart); - menuArray.push(labels.stopServer); - menuArray.push(labels.settings); - menuArray.push(labels.viewLogs); - menuArray.push(separator); + if(isServerInstalled()) { + menuArray.push(labels.serverState); + menuArray.push(labels.version); + menuArray.push(separator); + } + if(isInterfaceInstalled()) { + menuArray.push(labels.enableNotifications); + menuArray.push(labels.goto); + menuArray.push(labels.people); + menuArray.push(labels.wallet); + menuArray.push(labels.marketplace); + menuArray.push(separator); + } + if(isServerInstalled() && isInterfaceInstalled()) { + menuArray.push(labels.goHome); + menuArray.push(separator); + } + if(isServerInstalled()) { + menuArray.push(labels.restart); + menuArray.push(labels.stopServer); + menuArray.push(labels.settings); + menuArray.push(labels.viewLogs); + menuArray.push(separator); + } menuArray.push(labels.share); menuArray.push(separator); menuArray.push(labels.quit); @@ -528,6 +570,17 @@ function updateLabels(serverState) { labels.restart.label = "Restart Server"; labels.restart.enabled = false; } + + labels.enableNotifications.checked = trayNotifications.enabled(); + labels.people.visible = trayNotifications.enabled(); + labels.goto.visible = trayNotifications.enabled(); + labels.wallet.visible = trayNotifications.enabled(); + labels.marketplace.visible = trayNotifications.enabled(); + labels.goto.icon = pendingNotifications[HifiNotificationType.GOTO] ? menuNotificationIcon : null; + labels.people.icon = pendingNotifications[HifiNotificationType.PEOPLE] ? menuNotificationIcon : null; + labels.wallet.icon = pendingNotifications[HifiNotificationType.WALLET] ? menuNotificationIcon : null; + labels.marketplace.icon = pendingNotifications[HifiNotificationType.MARKETPLACE] ? menuNotificationIcon : null; + } function updateTrayMenu(serverState) { @@ -807,7 +860,7 @@ function onContentLoaded() { deleteOldFiles(logPath, DELETE_LOG_FILES_OLDER_THAN_X_SECONDS, LOG_FILE_REGEX); - if (dsPath && acPath) { + if (isServerInstalled()) { var dsArguments = ['--get-temp-name', '--parent-pid', process.pid]; domainServer = new Process('domain-server', dsPath, dsArguments, logPath); @@ -838,7 +891,7 @@ function onContentLoaded() { // If we were launched with the launchInterface option, then we need to launch interface now if (argv.launchInterface) { log.debug("Interface launch requested... argv.launchInterface:", argv.launchInterface); - startInterface(); + StartInterface(); } // If we were launched with the shutdownWith option, then we need to shutdown when that process (pid) @@ -869,7 +922,7 @@ app.on('ready', function() { // Create tray icon tray = new Tray(trayIcons[ProcessGroupStates.STOPPED]); - tray.setToolTip('High Fidelity Sandbox'); + tray.setToolTip('High Fidelity'); tray.on('click', function() { tray.popUpContextMenu(tray.menu); diff --git a/server-console/src/modules/hf-app.js b/server-console/src/modules/hf-app.js new file mode 100644 index 0000000000..28b97f582a --- /dev/null +++ b/server-console/src/modules/hf-app.js @@ -0,0 +1,71 @@ +const fs = require('fs'); +const extend = require('extend'); +const Config = require('./config').Config +const os = require('os'); +const pathFinder = require('./path-finder'); +const path = require('path'); +const argv = require('yargs').argv; +const hfprocess = require('./hf-process'); +const Process = hfprocess.Process; + +const binaryType = argv.binaryType; +const osType = os.type(); + +exports.getBuildInfo = function() { + var buildInfoPath = null; + + if (osType == 'Windows_NT') { + buildInfoPath = path.join(path.dirname(process.execPath), 'build-info.json'); + } else if (osType == 'Darwin') { + var contentPath = ".app/Contents/"; + var contentEndIndex = __dirname.indexOf(contentPath); + + if (contentEndIndex != -1) { + // this is an app bundle + var appPath = __dirname.substring(0, contentEndIndex) + ".app"; + buildInfoPath = path.join(appPath, "/Contents/Resources/build-info.json"); + } + } + + const DEFAULT_BUILD_INFO = { + releaseType: "", + buildIdentifier: "dev", + buildNumber: "0", + stableBuild: "0", + organization: "High Fidelity - dev", + appUserModelId: "com.highfidelity.sandbox-dev" + }; + var buildInfo = DEFAULT_BUILD_INFO; + + if (buildInfoPath) { + try { + buildInfo = JSON.parse(fs.readFileSync(buildInfoPath)); + } catch (e) { + buildInfo = DEFAULT_BUILD_INFO; + } + } + + return buildInfo; +} + +const buildInfo = exports.getBuildInfo(); +const interfacePath = pathFinder.discoveredPath("Interface", binaryType, buildInfo.releaseType); + +exports.startInterface = function(url) { + var argArray = []; + + // check if we have a url parameter to include + if (url) { + argArray = ["--url", url]; + } + console.log("Starting with " + url); + // create a new Interface instance - Interface makes sure only one is running at a time + var pInterface = new Process('Interface', interfacePath, argArray); + pInterface.detached = true; + pInterface.start(); +} + +exports.isInterfaceRunning = function(done) { + var pInterface = new Process('interface', 'interface.exe'); + return pInterface.isRunning(done); +} diff --git a/server-console/src/modules/hf-notifications.js b/server-console/src/modules/hf-notifications.js new file mode 100644 index 0000000000..06be365208 --- /dev/null +++ b/server-console/src/modules/hf-notifications.js @@ -0,0 +1,263 @@ +const request = require('request'); +const notifier = require('node-notifier'); +const os = require('os'); +const process = require('process'); +const hfApp = require('./hf-app'); +const path = require('path'); + +const notificationIcon = path.join(__dirname, '../../resources/console-notification.png'); +const NOTIFICATION_POLL_TIME_MS = 15 * 1000; +const METAVERSE_SERVER_URL= process.env.HIFI_METAVERSE_URL ? process.env.HIFI_METAVERSE_URL : 'https://highfidelity.com' +const STORIES_URL= '/api/v1/user_stories'; +const USERS_URL= '/api/v1/users'; +const ECONOMIC_ACTIVITY_URL= '/api/v1/commerce/history'; +const UPDATES_URL= '/api/v1/commerce/available_updates'; + + +const StartInterface=hfApp.startInterface; +const IsInterfaceRunning=hfApp.isInterfaceRunning; + +const NotificationType = { + GOTO: 'goto', + PEOPLE: 'people', + WALLET: 'wallet', + MARKETPLACE: 'marketplace' +}; + +function HifiNotification(notificationType, notificationData) { + this.type = notificationType; + this.data = notificationData; +} + +HifiNotification.prototype = { + show: function() { + switch(this.type) { + case NotificationType.GOTO: + var text = this.data.username + " " + this.data.action_string + " in " + this.data.place_name; + notifier.notify({ + notificationType: this.type, + icon: notificationIcon, + title: text, + message: "Click to goto " + this.data.place_name, + wait: true, + url: "hifi://" + this.data.place_name + this.data.path + }); + break; + + case NotificationType.PEOPLE: + var text = this.data.username + " has logged in."; + notifier.notify({ + notificationType: this.type, + icon: notificationIcon, + title: text, + message: "Click to join them in " + this.data.location.root.name, + wait: true, + url: "hifi://" + this.data.location.root.name + this.data.location.path + }); + break; + + case NotificationType.WALLET: + var text = "Economic activity."; + notifier.notify({ + notificationType: this.type, + icon: notificationIcon, + title: text, + message: "Click to open your wallet", + wait: true, + app: "Wallet" + }); + break; + + case NotificationType.MARKETPLACE: + var text = "One of your marketplace items has an update."; + notifier.notify({ + notificationType: this.type, + icon: notificationIcon, + title: text, + message: "Click to start the marketplace app", + wait: true, + app: "Marketplace" + }); + break; + } + } +} + +function HifiNotifications(config, callback) { + this.config = config; + this.callback = callback; + this.since = new Date(this.config.get("notifySince", "1970-01-01T00:00:00.000Z")); + this.enable(this.enabled()); + notifier.on('click', function(notifierObject, options) { + console.log(options); + StartInterface(options.url); + }); +} + +HifiNotifications.prototype = { + enable: function(enabled) { + this.config.set("enableTrayNotifications", enabled); + if(enabled) { + var _this = this; + this.pollTimer = setInterval(function() { + var _since = _this.since; + _this.since = new Date(); + IsInterfaceRunning(function(running) { + if(running) { + return; + } + _this.pollForStories(_since, _this.callback); + _this.pollForConnections(_since, _this.callback); + _this.pollForEconomicActivity(_since, _this.callback); + _this.pollForMarketplaceUpdates(_since, _this.callback); + }); + }, + NOTIFICATION_POLL_TIME_MS); + } + else if(this.pollTimer) { + clearInterval(this.pollTimer); + } + }, + enabled: function() { + return this.config.get("enableTrayNotifications", true); + }, + stopPolling: function() { + this.config.set("notifySince", this.since.toISOString()); + if(this.pollTimer) { + clearInterval(this.pollTimer); + } + }, + pollForStories: function(since, callback) { + var _this = this; + var actions = 'announcement'; + var options = [ + 'now=' + new Date().toISOString(), + 'since=' + since.toISOString(), + 'include_actions=announcement', + 'restriction=open,hifi', + 'require_online=true' + ]; + console.log("Polling for stories"); + var url = METAVERSE_SERVER_URL + STORIES_URL + '?' + options.join('&'); + request({ + uri: url + }, function (error, data) { + if (error || !data.body) { + console.log("Error: unable to get " + url); + return; + } + var content = JSON.parse(data.body); + if(!content || content.status != 'success') { + console.log("Error: unable to get " + url); + return; + } + content.user_stories.forEach(function(story) { + var updated_at = new Date(story.updated_at); + if (updated_at < since) { + return; + } + callback(NotificationType.GOTO); + var notification = new HifiNotification(NotificationType.GOTO, story); + notification.show(); + }); + }); + }, + pollForConnections: function(since, callback) { + var _this = this; + var options = [ + 'filter=connections', + 'since=' + since.toISOString(), + 'status=online' + ]; + console.log("Polling for connections"); + var url = METAVERSE_SERVER_URL + USERS_URL + '?' + options.join('&'); + request({ + uri: url + }, function (error, data) { + if (error || !data.body) { + console.log("Error: unable to get " + url); + return; + } + var content = JSON.parse(data.body); + if(!content || content.status != 'success') { + console.log("Error: unable to get " + url); + return; + } + console.log(content.data); + content.data.users.forEach(function(user) { + if(user.online) { + callback(NotificationType.PEOPLE); + var notification = new HifiNotification(NotificationType.PEOPLE, user); + notification.show(); + } + }); + }); + }, + pollForEconomicActivity: function(since, callback) { + var _this = this; + var options = [ + 'filter=connections', + 'since=' + since.toISOString(), + 'status=online' + ]; + console.log("Polling for economic activity"); + var url = METAVERSE_SERVER_URL + ECONOMIC_ACTIVITY_URL + '?' + options.join('&'); + request.post({ + uri: url + }, function (error, data) { + if (error || !data.body) { + console.log("Error " + error + ": unable to post " + url); + console.log(data); + return; + } + var content = JSON.parse(data.body); + if(!content || content.status != 'success') { + console.log(data.body); + console.log("Error " + content.status + ": unable to post " + url); + return; + } + console.log(content.data); + content.data.users.forEach(function(user) { + if(user.online) { + callback(NotificationType.PEOPLE); + var notification = new HifiNotification(NotificationType.PEOPLE, user); + notification.show(); + } + }); + }); + }, + pollForMarketplaceUpdates: function(since, callback) { + var _this = this; + var options = [ + 'filter=connections', + 'since=' + since.toISOString(), + 'status=online' + ]; + console.log("Polling for marketplace update"); + var url = METAVERSE_SERVER_URL + UPDATES_URL + '?' + options.join('&'); + request.put({ + uri: url + }, function (error, data) { + if (error || !data.body) { + console.log("Error " + error + ": unable to put " + url); + return; + } + var content = JSON.parse(data.body); + if(!content || content.status != 'success') { + console.log(data.body); + console.log("Error " + content.status + ": unable to put " + url); + return; + } + content.data.users.forEach(function(user) { + if(user.online) { + callback(NotificationType.PEOPLE); + var notification = new HifiNotification(NotificationType.PEOPLE, user); + notification.show(); + } + }); + }); + } +}; + +exports.HifiNotifications = HifiNotifications; +exports.NotificationType = NotificationType; \ No newline at end of file diff --git a/server-console/src/modules/hf-process.js b/server-console/src/modules/hf-process.js index 797ee38a0d..7fbc9a894e 100644 --- a/server-console/src/modules/hf-process.js +++ b/server-console/src/modules/hf-process.js @@ -259,6 +259,24 @@ Process.prototype = extend(Process.prototype, { }; return logs; }, + isRunning: function(done) { + var _command = this.command; + if (os.type == 'Windows_NT') { + childProcess.exec('tasklist /FO CSV', function(err, stdout, stderr) { + var running = false; + stdout.split("\n").forEach(function(line) { + var exeData = line.split(","); + var executable = exeData[0].replace(/\"/g, "").toLowerCase(); + if(executable == _command) { + running = true; + } + }); + done(running); + }); + } else if (os.type == 'Darwin') { + console.log("TODO IsRunning Darwin"); + } + }, // Events onChildStartError: function(error) { From 555432dd49cf70b31c11f3a0791e0cde2b715a8b Mon Sep 17 00:00:00 2001 From: Roxanne Skelly Date: Fri, 14 Sep 2018 14:13:26 -0700 Subject: [PATCH 02/38] Blank js file to force build (and prep for appinfo parsing) --- server-console/src/modules/hf-appinfo.js | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 server-console/src/modules/hf-appinfo.js diff --git a/server-console/src/modules/hf-appinfo.js b/server-console/src/modules/hf-appinfo.js new file mode 100644 index 0000000000..9fac0ca61c --- /dev/null +++ b/server-console/src/modules/hf-appinfo.js @@ -0,0 +1,10 @@ +'use strict' + +const request = require('request'); +const extend = require('extend'); +const util = require('util'); +const events = require('events'); +const childProcess = require('child_process'); +const fs = require('fs-extra'); +const os = require('os'); +const path = require('path'); From 1e8ae1a2940a53e867fc8d4bbadf8daca9b7f0da Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 15 Sep 2018 16:36:55 -0700 Subject: [PATCH 03/38] fix scaling of worn shape entities --- libraries/entities-renderer/src/RenderableShapeEntityItem.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index 71e3a0ff27..5003e36e86 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -97,10 +97,10 @@ void ShapeEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce withWriteLock([&] { auto entity = getEntity(); _position = entity->getWorldPosition(); - _dimensions = entity->getScaledDimensions(); + _dimensions = entity->getUnscaledDimensions(); // get unscaled to avoid scaling twice _orientation = entity->getWorldOrientation(); updateModelTransformAndBound(); - _renderTransform = getModelTransform(); + _renderTransform = getModelTransform(); // contains parent scale, if this entity scales with its parent if (_shape == entity::Sphere) { _renderTransform.postScale(SPHERE_ENTITY_SCALE); } From a97f9eb79aeccf423517c099d12f3c4daf319cb8 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 18 Sep 2018 12:28:03 -0700 Subject: [PATCH 04/38] Logic for Wallet notifications; some bugfixes --- scripts/modules/appUi.js | 18 +++-- scripts/modules/request.js | 4 +- scripts/system/commerce/wallet.js | 106 +++++++++++++++++++++++++++++- scripts/system/pal.js | 22 ++++--- 4 files changed, 131 insertions(+), 19 deletions(-) diff --git a/scripts/modules/appUi.js b/scripts/modules/appUi.js index dab377911b..98f6dad1f9 100644 --- a/scripts/modules/appUi.js +++ b/scripts/modules/appUi.js @@ -155,8 +155,8 @@ function AppUi(properties) { return; } - // User is "appearing offline" - if (GlobalServices.findableBy === "none") { + // User is "appearing offline", or is offline, or the app is open + if (GlobalServices.findableBy === "none" || Account.username === "" || that.isOpen) { that.notificationPollTimeout = Script.setTimeout(that.notificationPoll, that.notificationPollTimeoutMs); return; } @@ -164,7 +164,10 @@ function AppUi(properties) { var url = METAVERSE_BASE + that.notificationPollEndpoint; if (that.notificationPollCaresAboutSince) { - url = url + "&since=" + (new Date().getTime()); + var settingsKey = "notifications/" + that.buttonName + "/lastSince"; + var timestamp = Settings.getValue(settingsKey, new Date().getTime()); + url = url + "&since=" + timestamp; + Settings.setValue(settingsKey, timestamp); } console.debug(that.buttonName, 'polling for notifications at endpoint', url); @@ -203,7 +206,8 @@ function AppUi(properties) { // This won't do anything if there isn't a notification endpoint set that.notificationPoll(); - function availabilityChanged() { + function restartNotificationPoll() { + that.notificationInitialCallbackMade = false; if (that.notificationPollTimeout) { Script.clearTimeout(that.notificationPollTimeout); that.notificationPollTimeout = false; @@ -303,7 +307,8 @@ function AppUi(properties) { } : that.ignore; that.onScriptEnding = function onScriptEnding() { // Close if necessary, clean up any remaining handlers, and remove the button. - GlobalServices.findableByChanged.disconnect(availabilityChanged); + GlobalServices.myUsernameChanged.disconnect(restartNotificationPoll); + GlobalServices.findableByChanged.disconnect(restartNotificationPoll); if (that.isOpen) { that.close(); } @@ -323,6 +328,7 @@ function AppUi(properties) { that.tablet.screenChanged.connect(that.onScreenChanged); that.button.clicked.connect(that.onClicked); Script.scriptEnding.connect(that.onScriptEnding); - GlobalServices.findableByChanged.connect(availabilityChanged); + GlobalServices.findableByChanged.connect(restartNotificationPoll); + GlobalServices.myUsernameChanged.connect(restartNotificationPoll); } module.exports = AppUi; diff --git a/scripts/modules/request.js b/scripts/modules/request.js index 3516554567..d0037f9b43 100644 --- a/scripts/modules/request.js +++ b/scripts/modules/request.js @@ -19,7 +19,7 @@ module.exports = { // ------------------------------------------------------------------ request: function (options, callback) { // cb(error, responseOfCorrectContentType) of url. A subset of npm request. - var httpRequest = new XMLHttpRequest(), key; + var httpRequest = new XMLHttpRequest(), key; // QT bug: apparently doesn't handle onload. Workaround using readyState. httpRequest.onreadystatechange = function () { var READY_STATE_DONE = 4; @@ -72,7 +72,7 @@ module.exports = { } httpRequest.open(options.method, options.uri, true); httpRequest.send(options.body || null); - } + } }; // =========================================================================================== diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js index 993ea30c2e..26b8f95bd5 100644 --- a/scripts/system/commerce/wallet.js +++ b/scripts/system/commerce/wallet.js @@ -491,12 +491,110 @@ function walletOpened() { Controller.mouseMoveEvent.connect(handleMouseMoveEvent); triggerMapping.enable(); triggerPressMapping.enable(); + ui.messagesWaiting(false); } function walletClosed() { off(); } +function notificationDataProcessPage(data) { + return data.data.history; +} + +var shouldShowDot = false; +function notificationPollCallback(historyArray) { + var i; + var someoneElsePurchasedArray = []; + var proofIssuedArray = []; + var moneyReceivedArray = []; + var giftReceivedArray = []; + for (i = 0; i < historyArray.length; i++) { + var currentHistoryTxn = historyArray[i]; + + if (currentHistoryTxn.sent_certs <= 0 && + currentHistoryTxn.received_certs <= 0) { + // This is an HFC transfer. + if (currentHistoryTxn.received_money > 0) { + if (currentHistoryTxn.sender_name === "marketplace") { + someoneElsePurchasedArray.push(currentHistoryTxn); + } else { + moneyReceivedArray.push(currentHistoryTxn); + } + } + } else if (currentHistoryTxn.sent_money <= 0 && + currentHistoryTxn.received_money <= 0 && + currentHistoryTxn.received_certs > 0) { + // This is a non-HFC asset transfer. + if (currentHistoryTxn.sender_name === "marketplace") { + proofIssuedArray.push(currentHistoryTxn); + } else { + giftReceivedArray.push(currentHistoryTxn); + } + } + } + + if (!ui.isOpen) { + shouldShowDot = shouldShowDot || + (someoneElsePurchasedArray.length > 0) || + (proofIssuedArray.length > 0) || + (moneyReceivedArray.length > 0) || + (giftReceivedArray.length > 0); + ui.messagesWaiting(shouldShowDot); + + var notificationCount = someoneElsePurchasedArray.length + + proofIssuedArray.length + + moneyReceivedArray.length + + giftReceivedArray.length; + + if (notificationCount > 0) { + var message; + if (!ui.notificationInitialCallbackMade) { + message = "You have " + notificationCount + " unread wallet " + + "notification" + (notificationCount === 1 ? "" : "s") + "! Open WALLET to see all activity."; + ui.notificationDisplayBanner(message); + } else { + var currentItemName, senderName; + for (i = 0; i < someoneElsePurchasedArray.length; i++) { + currentItemName = (someoneElsePurchasedArray[i].message).match('(.*)')[1]; + message = "Someone purchased your item \"" + currentItemName + "\" from the Marketplace! " + + "Open WALLET to see all activity."; + ui.notificationDisplayBanner(message); + } + for (i = 0; i < proofIssuedArray.length; i++) { + currentItemName = (proofIssuedArray[i].message).match('(.*)')[1]; + message = "You have been issued a proof for your Marketplace item \"" + currentItemName + "\"! " + + "Open WALLET to see all activity."; + ui.notificationDisplayBanner(message); + } + for (i = 0; i < moneyReceivedArray.length; i++) { + senderName = moneyReceivedArray[i].sender_name; + if (senderName === "") { + senderName = "Someone"; + } + message = senderName + " sent you " + moneyReceivedArray[i].received_money + " HFC! " + + "Open WALLET to see all activity."; + ui.notificationDisplayBanner(message); + } + for (i = 0; i < giftReceivedArray.length; i++) { + senderName = giftReceivedArray[i].sender_name; + if (senderName === "") { + senderName = "Someone"; + } + message = senderName + " sent you a gift! " + + "Open WALLET to see all activity."; + ui.notificationDisplayBanner(message); + } + } + } + } +} + +function isReturnedDataEmpty(data) { + var historyArray = data.data.history; + return historyArray.length === 0; +} + // // Manage the connection between the button and the window. // @@ -510,7 +608,13 @@ function startup() { home: WALLET_QML_SOURCE, onOpened: walletOpened, onClosed: walletClosed, - onMessage: fromQml + onMessage: fromQml, + notificationPollEndpoint: "/api/v1/notifications?source=commerce-history&per_page=10", + notificationPollTimeoutMs: 60000, + notificationDataProcessPage: notificationDataProcessPage, + notificationPollCallback: notificationPollCallback, + notificationPollStopPaginatingConditionMet: isReturnedDataEmpty, + notificationPollCaresAboutSince: true }); GlobalServices.myUsernameChanged.connect(onUsernameChanged); } diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 1be5b44786..38359fbab9 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -874,16 +874,18 @@ function notificationPollCallback(connectionsArray) { shouldShowDot: shouldShowDot }); - var message; - if (!ui.notificationInitialCallbackMade) { - message = newlyOnlineConnectionsArray.length + " of your connections " + - (newlyOnlineConnectionsArray.length === 1 ? "is" : "are") + " online. Open PEOPLE to join them!"; - ui.notificationDisplayBanner(message); - } else { - for (i = 0; i < newlyOnlineConnectionsArray.length; i++) { - message = newlyOnlineConnectionsArray[i].username + " is available in " + - newlyOnlineConnectionsArray[i].location.root.name + ". Open PEOPLE to join them!"; + if (newlyOnlineConnectionsArray.length > 0) { + var message; + if (!ui.notificationInitialCallbackMade) { + message = newlyOnlineConnectionsArray.length + " of your connections " + + (newlyOnlineConnectionsArray.length === 1 ? "is" : "are") + " online! Open PEOPLE to join them."; ui.notificationDisplayBanner(message); + } else { + for (i = 0; i < newlyOnlineConnectionsArray.length; i++) { + message = newlyOnlineConnectionsArray[i].username + " is available in " + + newlyOnlineConnectionsArray[i].location.root.name + "! Open PEOPLE to join them."; + ui.notificationDisplayBanner(message); + } } } } @@ -902,7 +904,7 @@ function startup() { onOpened: palOpened, onClosed: off, onMessage: fromQml, - notificationPollEndpoint: "/api/v1/users?filter=connections&per_page=10", + notificationPollEndpoint: "/api/v1/notifications?source=users&filter=connections&per_page=10", notificationPollTimeoutMs: 60000, notificationDataProcessPage: notificationDataProcessPage, notificationPollCallback: notificationPollCallback, From 04b44d05942d3247ccf5f6eaf523432ec64e7e29 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 18 Sep 2018 12:38:33 -0700 Subject: [PATCH 05/38] Fix small since bug --- scripts/modules/appUi.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/modules/appUi.js b/scripts/modules/appUi.js index 98f6dad1f9..b8e5cc45f9 100644 --- a/scripts/modules/appUi.js +++ b/scripts/modules/appUi.js @@ -165,9 +165,10 @@ function AppUi(properties) { if (that.notificationPollCaresAboutSince) { var settingsKey = "notifications/" + that.buttonName + "/lastSince"; - var timestamp = Settings.getValue(settingsKey, new Date().getTime()); - url = url + "&since=" + timestamp; - Settings.setValue(settingsKey, timestamp); + var currentTimestamp = new Date().getTime(); + var settingsTimestamp = Settings.getValue(settingsKey, currentTimestamp); + url = url + "&since=" + settingsTimestamp; + Settings.setValue(settingsKey, currentTimestamp); } console.debug(that.buttonName, 'polling for notifications at endpoint', url); From 55a0f77697bb66190b8b8086df14ddb24ad27716 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 18 Sep 2018 14:45:14 -0700 Subject: [PATCH 06/38] Notifications for MARKET --- .../qml/hifi/commerce/wallet/WalletHome.qml | 8 ---- scripts/modules/appUi.js | 10 ++-- scripts/system/commerce/wallet.js | 3 -- scripts/system/marketplaces/marketplaces.js | 46 +++++++++++++++++-- 4 files changed, 47 insertions(+), 20 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml index 50208793fe..627da1d43f 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml @@ -45,14 +45,6 @@ Item { onHistoryResult : { transactionHistoryModel.handlePage(null, result); } - - onAvailableUpdatesResult: { - if (result.status !== 'success') { - console.log("Failed to get Available Updates", result.data.message); - } else { - sendToScript({method: 'wallet_availableUpdatesReceived', numUpdates: result.data.updates.length }); - } - } } Connections { diff --git a/scripts/modules/appUi.js b/scripts/modules/appUi.js index b8e5cc45f9..c7f6cc5f39 100644 --- a/scripts/modules/appUi.js +++ b/scripts/modules/appUi.js @@ -163,13 +163,13 @@ function AppUi(properties) { var url = METAVERSE_BASE + that.notificationPollEndpoint; + var settingsKey = "notifications/" + that.buttonName + "/lastPoll"; + var currentTimestamp = new Date().getTime(); + var lastPollTimestamp = Settings.getValue(settingsKey, currentTimestamp); if (that.notificationPollCaresAboutSince) { - var settingsKey = "notifications/" + that.buttonName + "/lastSince"; - var currentTimestamp = new Date().getTime(); - var settingsTimestamp = Settings.getValue(settingsKey, currentTimestamp); - url = url + "&since=" + settingsTimestamp; - Settings.setValue(settingsKey, currentTimestamp); + url = url + "&since=" + lastPollTimestamp; } + Settings.setValue(settingsKey, currentTimestamp); console.debug(that.buttonName, 'polling for notifications at endpoint', url); diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js index 26b8f95bd5..a896bd4071 100644 --- a/scripts/system/commerce/wallet.js +++ b/scripts/system/commerce/wallet.js @@ -474,9 +474,6 @@ function fromQml(message) { Window.location = "hifi://BankOfHighFidelity"; } break; - case 'wallet_availableUpdatesReceived': - // NOP - break; case 'http.request': // Handled elsewhere, don't log. break; diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index 13ad1f6b69..1bb0713f50 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -908,10 +908,9 @@ var onQmlMessageReceived = function onQmlMessageReceived(message) { removeOverlays(); } break; - case 'wallet_availableUpdatesReceived': case 'purchases_availableUpdatesReceived': - userHasUpdates = message.numUpdates > 0; - ui.messagesWaiting(userHasUpdates); + shouldShowDot = message.numUpdates > 0; + ui.messagesWaiting(shouldShowDot); break; case 'purchases_updateWearables': var currentlyWornWearables = []; @@ -1030,6 +1029,39 @@ var onTabletScreenChanged = function onTabletScreenChanged(type, url) { "\nNew screen URL: " + url + "\nCurrent app open status: " + ui.isOpen + "\n"); }; +function notificationDataProcessPage(data) { + return data.data.updates; +} + +var shouldShowDot = false; +function notificationPollCallback(updatesArray) { + shouldShowDot = shouldShowDot || updatesArray.length > 0; + ui.messagesWaiting(shouldShowDot); + + if (updatesArray.length > 0) { + var message; + if (!ui.notificationInitialCallbackMade) { + message = updatesArray.length + " of your purchased items have updates available! " + + "Open MARKET to update."; + ui.notificationDisplayBanner(message); + + ui.notificationPollCaresAboutSince = true; + } else { + for (var i = 0; i < updatesArray.length; i++) { + message = "There's an update available for your version of \"" + + updatesArray[i].marketplace_item_name + "\"!" + + "Open MARKET to update."; + ui.notificationDisplayBanner(message); + } + } + } +} + +function isReturnedDataEmpty(data) { + var historyArray = data.data.updates; + return historyArray.length === 0; +} + // // Manage the connection between the button and the window. // @@ -1044,7 +1076,13 @@ function startup() { inject: MARKETPLACES_INJECT_SCRIPT_URL, home: MARKETPLACE_URL_INITIAL, onScreenChanged: onTabletScreenChanged, - onMessage: onQmlMessageReceived + onMessage: onQmlMessageReceived, + notificationPollEndpoint: "/api/v1/notifications?source=commerce-available_updates&per_page=10", + notificationPollTimeoutMs: 60000, + notificationDataProcessPage: notificationDataProcessPage, + notificationPollCallback: notificationPollCallback, + notificationPollStopPaginatingConditionMet: isReturnedDataEmpty, + notificationPollCaresAboutSince: false // Changes to true after first poll }); ContextOverlay.contextOverlayClicked.connect(openInspectionCertificateQML); Entities.canWriteAssetsChanged.connect(onCanWriteAssetsChanged); From 498716470641908c61e39bb0ca52583d282a8002 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 18 Sep 2018 15:30:43 -0700 Subject: [PATCH 07/38] Notifications for GOTO (using a cool algorithm) --- scripts/system/commerce/wallet.js | 9 +- scripts/system/tablet-goto.js | 193 +++++++++++++++--------------- 2 files changed, 99 insertions(+), 103 deletions(-) diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js index a896bd4071..2f3f5c109d 100644 --- a/scripts/system/commerce/wallet.js +++ b/scripts/system/commerce/wallet.js @@ -532,17 +532,12 @@ function notificationPollCallback(historyArray) { } if (!ui.isOpen) { - shouldShowDot = shouldShowDot || - (someoneElsePurchasedArray.length > 0) || - (proofIssuedArray.length > 0) || - (moneyReceivedArray.length > 0) || - (giftReceivedArray.length > 0); - ui.messagesWaiting(shouldShowDot); - var notificationCount = someoneElsePurchasedArray.length + proofIssuedArray.length + moneyReceivedArray.length + giftReceivedArray.length; + shouldShowDot = shouldShowDot || notificationCount > 0; + ui.messagesWaiting(shouldShowDot); if (notificationCount > 0) { var message; diff --git a/scripts/system/tablet-goto.js b/scripts/system/tablet-goto.js index 804f838d04..26099828dc 100644 --- a/scripts/system/tablet-goto.js +++ b/scripts/system/tablet-goto.js @@ -15,118 +15,119 @@ // (function () { // BEGIN LOCAL_SCOPE -var request = Script.require('request').request; var AppUi = Script.require('appUi'); -var DEBUG = false; -function debug() { - if (!DEBUG) { - return; - } - print('tablet-goto.js:', [].map.call(arguments, JSON.stringify)); -} - -var stories = {}, pingPong = false; -function expire(id) { - var options = { - uri: Account.metaverseServerURL + '/api/v1/user_stories/' + id, - method: 'PUT', - json: true, - body: {expire: "true"} - }; - request(options, function (error, response) { - debug('expired story', options, 'error:', error, 'response:', response); - if (error || (response.status !== 'success')) { - print("ERROR expiring story: ", error || response.status); - } - }); -} -var PER_PAGE_DEBUG = 10; -var PER_PAGE_NORMAL = 100; -function pollForAnnouncements() { - // We could bail now if !Account.isLoggedIn(), but what if we someday have system-wide announcments? - var actions = 'announcement'; - var count = DEBUG ? PER_PAGE_DEBUG : PER_PAGE_NORMAL; - var options = [ - 'now=' + new Date().toISOString(), - 'include_actions=' + actions, - 'restriction=' + (Account.isLoggedIn() ? 'open,hifi' : 'open'), - 'require_online=true', - 'protocol=' + encodeURIComponent(Window.protocolSignature()), - 'per_page=' + count - ]; - var url = Account.metaverseServerURL + '/api/v1/user_stories?' + options.join('&'); - request({ - uri: url - }, function (error, data) { - debug(url, error, data); - if (error || (data.status !== 'success')) { - print("Error: unable to get", url, error || data.status); - return; - } - var didNotify = false, key; - pingPong = !pingPong; - data.user_stories.forEach(function (story) { - var stored = stories[story.id], storedOrNew = stored || story; - debug('story exists:', !!stored, storedOrNew); - if ((storedOrNew.username === Account.username) && (storedOrNew.place_name !== location.placename)) { - if (storedOrNew.audience === 'for_connections') { // Only expire if we haven't already done so. - expire(story.id); - } - return; // before marking - } - storedOrNew.pingPong = pingPong; - if (stored) { // already seen - return; - } - stories[story.id] = story; - var message = story.username + " " + story.action_string + " in " + - story.place_name + ". Open GOTO to join them."; - Window.displayAnnouncement(message); - didNotify = true; - }); - for (key in stories) { // Any story we were tracking that was not marked, has expired. - if (stories[key].pingPong !== pingPong) { - debug('removing story', key); - delete stories[key]; - } - } - if (didNotify) { - ui.messagesWaiting(true); - if (HMD.isHandControllerAvailable()) { - var STRENGTH = 1.0, DURATION_MS = 60, HAND = 2; // both hands - Controller.triggerHapticPulse(STRENGTH, DURATION_MS, HAND); - } - } else if (!Object.keys(stories).length) { // If there's nothing being tracked, then any messageWaiting has expired. - ui.messagesWaiting(false); - } - }); -} -var MS_PER_SEC = 1000; -var DEBUG_POLL_TIME_SEC = 10; -var NORMAL_POLL_TIME_SEC = 60; -var ANNOUNCEMENTS_POLL_TIME_MS = (DEBUG ? DEBUG_POLL_TIME_SEC : NORMAL_POLL_TIME_SEC) * MS_PER_SEC; -var pollTimer = Script.setInterval(pollForAnnouncements, ANNOUNCEMENTS_POLL_TIME_MS); function gotoOpened() { ui.messagesWaiting(false); } +function notificationDataProcessPage(data) { + return data.user_stories; +} + +var shouldShowDot = false; +var pingPong = false; +var storedAnnouncements = {}; +var storedFeaturedStories = {}; +function notificationPollCallback(userStoriesArray) { + // + // START logic for keeping track of new info + // + pingPong = !pingPong; + var totalCountedStories = 0; + userStoriesArray.forEach(function (story) { + if (story.audience !== "for_connections" && + story.audience !== "for_feed") { + return; + } else { + totalCountedStories++; + } + + var stored = storedAnnouncements[story.id] || storedFeaturedStories[story.id]; + var storedOrNew = stored || story; + storedOrNew.pingPong = pingPong; + if (stored) { + return; + } + + if (story.audience === "for_connections") { + storedAnnouncements[story.id] = story; + } else if (story.audience === "for_feed") { + storedFeaturedStories[story.id] = story; + } + }); + var key; + for (key in storedAnnouncements) { + if (storedAnnouncements[key].pingPong !== pingPong) { + delete storedAnnouncements[key]; + } + } + for (key in storedFeaturedStories) { + if (storedFeaturedStories[key].pingPong !== pingPong) { + delete storedFeaturedStories[key]; + } + } + // + // END logic for keeping track of new info + // + + var notificationCount = Object.keys(storedAnnouncements).length + + Object.keys(storedFeaturedStories).length; + shouldShowDot = totalCountedStories > 0 || (notificationCount > 0 && shouldShowDot); + ui.messagesWaiting(shouldShowDot && !ui.isOpen); + + if (notificationCount > 0 && !ui.isOpen) { + var message; + if (!ui.notificationInitialCallbackMade) { + message = "You have " + userStoriesArray.length + "event invitations pending! " + + "Open GOTO to see them."; + ui.notificationDisplayBanner(message); + } else { + for (key in storedAnnouncements) { + message = storedAnnouncements[key].username + " says something is happening in " + + storedAnnouncements[key].place_name + "! Open GOTO to join them."; + ui.notificationDisplayBanner(message); + } + for (key in storedFeaturedStories) { + message = storedFeaturedStories[key].username + " has invited you to an event in " + + storedFeaturedStories[key].place_name + "! Open GOTO to join them."; + ui.notificationDisplayBanner(message); + } + } + } +} + +function isReturnedDataEmpty(data) { + var storiesArray = data.user_stories; + return storiesArray.length === 0; +} + var ui; var GOTO_QML_SOURCE = "hifi/tablet/TabletAddressDialog.qml"; var BUTTON_NAME = "GOTO"; function startup() { + var options = [ + 'include_actions=announcement', + 'restriction=open,hifi', + 'require_online=true', + 'protocol=' + encodeURIComponent(Window.protocolSignature()), + 'per_page=10' + ]; + var endpoint = '/api/v1/notifications?source=user_stories?' + options.join('&'); + ui = new AppUi({ buttonName: BUTTON_NAME, sortOrder: 8, onOpened: gotoOpened, - home: GOTO_QML_SOURCE + home: GOTO_QML_SOURCE, + notificationPollEndpoint: endpoint, + notificationPollTimeoutMs: 60000, + notificationDataProcessPage: notificationDataProcessPage, + notificationPollCallback: notificationPollCallback, + notificationPollStopPaginatingConditionMet: isReturnedDataEmpty, + notificationPollCaresAboutSince: true }); } -function shutdown() { - Script.clearInterval(pollTimer); -} - startup(); -Script.scriptEnding.connect(shutdown); }()); // END LOCAL_SCOPE From 9db11aeda77be5368e2f13cacf1e32bebfcb0bc7 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 18 Sep 2018 16:35:53 -0700 Subject: [PATCH 08/38] Bugfixes and new algo for PAL notifs --- scripts/system/pal.js | 77 +++++++++++++++-------------------- scripts/system/tablet-goto.js | 36 ++++++++-------- 2 files changed, 50 insertions(+), 63 deletions(-) diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 38359fbab9..355ed0a504 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -823,46 +823,42 @@ function notificationDataProcessPage(data) { } var shouldShowDot = false; -var storedOnlineUsersArray = []; +var pingPong = false; +var storedOnlineUsers = {}; function notificationPollCallback(connectionsArray) { // // START logic for handling online/offline user changes // - var i, j; - var newlyOnlineConnectionsArray = []; - for (i = 0; i < connectionsArray.length; i++) { - var currentUser = connectionsArray[i]; + pingPong = !pingPong; + var newOnlineUsers = 0; + var message; - if (connectionsArray[i].online) { - var indexOfStoredOnlineUser = -1; - for (j = 0; j < storedOnlineUsersArray.length; j++) { - if (currentUser.username === storedOnlineUsersArray[j].username) { - indexOfStoredOnlineUser = j; - break; - } - } - // If the user record isn't already presesnt inside `storedOnlineUsersArray`... - if (indexOfStoredOnlineUser < 0) { - storedOnlineUsersArray.push(currentUser); - newlyOnlineConnectionsArray.push(currentUser); - } - } else { - var indexOfOfflineUser = -1; - for (j = 0; j < storedOnlineUsersArray.length; j++) { - if (currentUser.username === storedOnlineUsersArray[j].username) { - indexOfOfflineUser = j; - break; - } - } - if (indexOfOfflineUser >= 0) { - storedOnlineUsersArray.splice(indexOfOfflineUser); + connectionsArray.forEach(function (user) { + var stored = storedOnlineUsers[user.username]; + var storedOrNew = stored || user; + storedOrNew.pingPong = pingPong; + if (stored) { + return; + } + + if (user.online) { + newOnlineUsers++; + storedOnlineUsers[user.username] = user; + + if (!ui.isOpen && ui.notificationInitialCallbackMade) { + message = user.username + " is available in " + + user.location.root.name + "! Open PEOPLE to join them."; + ui.notificationDisplayBanner(message); } } + }); + var key; + for (key in storedOnlineUsers) { + if (storedOnlineUsers[key].pingPong !== pingPong) { + delete storedOnlineUsers[key]; + } } - // If there's new data, the light should turn on. - // If the light is already on and you have connections online, the light should stay on. - // In all other cases, the light should turn off or stay off. - shouldShowDot = newlyOnlineConnectionsArray.length > 0 || (storedOnlineUsersArray.length > 0 && shouldShowDot); + shouldShowDot = newOnlineUsers > 0 || (Object.keys(storedOnlineUsers).length > 0 && shouldShowDot); // // END logic for handling online/offline user changes // @@ -874,19 +870,10 @@ function notificationPollCallback(connectionsArray) { shouldShowDot: shouldShowDot }); - if (newlyOnlineConnectionsArray.length > 0) { - var message; - if (!ui.notificationInitialCallbackMade) { - message = newlyOnlineConnectionsArray.length + " of your connections " + - (newlyOnlineConnectionsArray.length === 1 ? "is" : "are") + " online! Open PEOPLE to join them."; - ui.notificationDisplayBanner(message); - } else { - for (i = 0; i < newlyOnlineConnectionsArray.length; i++) { - message = newlyOnlineConnectionsArray[i].username + " is available in " + - newlyOnlineConnectionsArray[i].location.root.name + "! Open PEOPLE to join them."; - ui.notificationDisplayBanner(message); - } - } + if (newOnlineUsers > 0 && !ui.notificationInitialCallbackMade) { + message = newOnlineUsers + " of your connections " + + (newOnlineUsers === 1 ? "is" : "are") + " online! Open PEOPLE to join them."; + ui.notificationDisplayBanner(message); } } } diff --git a/scripts/system/tablet-goto.js b/scripts/system/tablet-goto.js index 26099828dc..972b9d9841 100644 --- a/scripts/system/tablet-goto.js +++ b/scripts/system/tablet-goto.js @@ -29,12 +29,14 @@ var shouldShowDot = false; var pingPong = false; var storedAnnouncements = {}; var storedFeaturedStories = {}; +var message; function notificationPollCallback(userStoriesArray) { // // START logic for keeping track of new info // pingPong = !pingPong; var totalCountedStories = 0; + var shouldNotifyIndividually = !ui.isOpen && ui.notificationInitialCallbackMade; userStoriesArray.forEach(function (story) { if (story.audience !== "for_connections" && story.audience !== "for_feed") { @@ -52,8 +54,20 @@ function notificationPollCallback(userStoriesArray) { if (story.audience === "for_connections") { storedAnnouncements[story.id] = story; + + if (shouldNotifyIndividually) { + message = storedAnnouncements[key].username + " says something is happening in " + + storedAnnouncements[key].place_name + "! Open GOTO to join them."; + ui.notificationDisplayBanner(message); + } } else if (story.audience === "for_feed") { storedFeaturedStories[story.id] = story; + + if (shouldNotifyIndividually) { + message = storedFeaturedStories[key].username + " has invited you to an event in " + + storedFeaturedStories[key].place_name + "! Open GOTO to join them."; + ui.notificationDisplayBanner(message); + } } }); var key; @@ -76,24 +90,10 @@ function notificationPollCallback(userStoriesArray) { shouldShowDot = totalCountedStories > 0 || (notificationCount > 0 && shouldShowDot); ui.messagesWaiting(shouldShowDot && !ui.isOpen); - if (notificationCount > 0 && !ui.isOpen) { - var message; - if (!ui.notificationInitialCallbackMade) { - message = "You have " + userStoriesArray.length + "event invitations pending! " + - "Open GOTO to see them."; - ui.notificationDisplayBanner(message); - } else { - for (key in storedAnnouncements) { - message = storedAnnouncements[key].username + " says something is happening in " + - storedAnnouncements[key].place_name + "! Open GOTO to join them."; - ui.notificationDisplayBanner(message); - } - for (key in storedFeaturedStories) { - message = storedFeaturedStories[key].username + " has invited you to an event in " + - storedFeaturedStories[key].place_name + "! Open GOTO to join them."; - ui.notificationDisplayBanner(message); - } - } + if (notificationCount > 0 && !ui.isOpen && !ui.notificationInitialCallbackMade) { + message = "You have " + notificationCount + "event invitations pending! " + + "Open GOTO to see them."; + ui.notificationDisplayBanner(message); } } From f70ecdad1698468c87f09b58f47127347c09316d Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 18 Sep 2018 17:00:53 -0700 Subject: [PATCH 09/38] Small bugfix --- scripts/system/tablet-goto.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/scripts/system/tablet-goto.js b/scripts/system/tablet-goto.js index 972b9d9841..63bc8431e8 100644 --- a/scripts/system/tablet-goto.js +++ b/scripts/system/tablet-goto.js @@ -35,14 +35,12 @@ function notificationPollCallback(userStoriesArray) { // START logic for keeping track of new info // pingPong = !pingPong; - var totalCountedStories = 0; + var totalNewStories = 0; var shouldNotifyIndividually = !ui.isOpen && ui.notificationInitialCallbackMade; userStoriesArray.forEach(function (story) { if (story.audience !== "for_connections" && story.audience !== "for_feed") { return; - } else { - totalCountedStories++; } var stored = storedAnnouncements[story.id] || storedFeaturedStories[story.id]; @@ -52,6 +50,8 @@ function notificationPollCallback(userStoriesArray) { return; } + totalNewStories++; + if (story.audience === "for_connections") { storedAnnouncements[story.id] = story; @@ -85,13 +85,13 @@ function notificationPollCallback(userStoriesArray) { // END logic for keeping track of new info // - var notificationCount = Object.keys(storedAnnouncements).length + + var totalStories = Object.keys(storedAnnouncements).length + Object.keys(storedFeaturedStories).length; - shouldShowDot = totalCountedStories > 0 || (notificationCount > 0 && shouldShowDot); + shouldShowDot = totalNewStories > 0 || (totalStories > 0 && shouldShowDot); ui.messagesWaiting(shouldShowDot && !ui.isOpen); - if (notificationCount > 0 && !ui.isOpen && !ui.notificationInitialCallbackMade) { - message = "You have " + notificationCount + "event invitations pending! " + + if (totalStories > 0 && !ui.isOpen && !ui.notificationInitialCallbackMade) { + message = "You have " + totalStories + "event invitations pending! " + "Open GOTO to see them."; ui.notificationDisplayBanner(message); } From 46c8083fb994abec215a2cb933d8a2276801bf6c Mon Sep 17 00:00:00 2001 From: David Back Date: Wed, 19 Sep 2018 10:13:15 -0700 Subject: [PATCH 10/38] only call selectEntity one time per trigger --- .../controllerModules/inEditMode.js | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/scripts/system/controllers/controllerModules/inEditMode.js b/scripts/system/controllers/controllerModules/inEditMode.js index 2bdd89f141..9f25a1b37c 100644 --- a/scripts/system/controllers/controllerModules/inEditMode.js +++ b/scripts/system/controllers/controllerModules/inEditMode.js @@ -73,21 +73,22 @@ Script.include("/~/system/libraries/utils.js"); method: "clearSelection", hand: hand })); + } else { + if (this.selectedTarget.type === Picks.INTERSECTED_ENTITY) { + Messages.sendLocalMessage("entityToolUpdates", JSON.stringify({ + method: "selectEntity", + entityID: this.selectedTarget.objectID, + hand: hand + })); + } else if (this.selectedTarget.type === Picks.INTERSECTED_OVERLAY) { + Messages.sendLocalMessage("entityToolUpdates", JSON.stringify({ + method: "selectOverlay", + overlayID: this.selectedTarget.objectID, + hand: hand + })); + } } } - if (this.selectedTarget.type === Picks.INTERSECTED_ENTITY) { - Messages.sendLocalMessage("entityToolUpdates", JSON.stringify({ - method: "selectEntity", - entityID: this.selectedTarget.objectID, - hand: hand - })); - } else if (this.selectedTarget.type === Picks.INTERSECTED_OVERLAY) { - Messages.sendLocalMessage("entityToolUpdates", JSON.stringify({ - method: "selectOverlay", - overlayID: this.selectedTarget.objectID, - hand: hand - })); - } this.triggerClicked = true; } From 144771b77b28918d544e2bb5bf13f2d8c73b803f Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 19 Sep 2018 11:35:17 -0700 Subject: [PATCH 11/38] Request JSON from server --- scripts/modules/appUi.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/modules/appUi.js b/scripts/modules/appUi.js index c7f6cc5f39..10c3ed023c 100644 --- a/scripts/modules/appUi.js +++ b/scripts/modules/appUi.js @@ -197,11 +197,11 @@ function AppUi(properties) { } else { concatenatedServerResponse = concatenatedServerResponse.concat(that.notificationDataProcessPage(response)); currentDataPageToRetrieve++; - request({ uri: (url + "&page=" + currentDataPageToRetrieve) }, requestCallback); + request({ json: true, uri: (url + "&page=" + currentDataPageToRetrieve) }, requestCallback); } } - request({ uri: url }, requestCallback); + request({ json: true, uri: url }, requestCallback); }; // This won't do anything if there isn't a notification endpoint set From d5f756c79dd3b266f80e0b6e585de809698692e7 Mon Sep 17 00:00:00 2001 From: Roxanne Skelly Date: Wed, 19 Sep 2018 12:40:15 -0700 Subject: [PATCH 12/38] Tray Notifier Checkpoint * Add app launch * Add authentication for auth-related calls * Refactor notifications code --- interface/src/Application.cpp | 11 +- interface/src/commerce/QmlCommerce.cpp | 12 +- interface/src/commerce/QmlCommerce.h | 1 + interface/src/main.cpp | 2 +- .../networking/src/NetworkingConstants.h | 1 + server-console/src/main.js | 42 +-- server-console/src/modules/hf-acctinfo.js | 135 +++++++++ server-console/src/modules/hf-app.js | 33 +++ server-console/src/modules/hf-appinfo.js | 10 - .../src/modules/hf-notifications.js | 272 +++++++++--------- 10 files changed, 341 insertions(+), 178 deletions(-) create mode 100644 server-console/src/modules/hf-acctinfo.js delete mode 100644 server-console/src/modules/hf-appinfo.js diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 46cebc1661..26c244a9d3 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3427,7 +3427,13 @@ void Application::handleSandboxStatus(QNetworkReply* reply) { int urlIndex = arguments().indexOf(HIFI_URL_COMMAND_LINE_KEY); QString addressLookupString; if (urlIndex != -1) { - addressLookupString = arguments().value(urlIndex + 1); + QUrl url(arguments().value(urlIndex + 1)); + if (url.scheme() == URL_SCHEME_HIFIAPP) { + QmlCommerce commerce; + commerce.openSystemApp(url.path()); + } else { + addressLookupString = arguments().value(urlIndex + 1); + } } static const QString SENT_TO_PREVIOUS_LOCATION = "previous_location"; @@ -7674,6 +7680,9 @@ void Application::openUrl(const QUrl& url) const { if (!url.isEmpty()) { if (url.scheme() == URL_SCHEME_HIFI) { DependencyManager::get()->handleLookupString(url.toString()); + } else if (url.scheme() == URL_SCHEME_HIFIAPP) { + QmlCommerce commerce; + commerce.openSystemApp(url.path()); } else { // address manager did not handle - ask QDesktopServices to handle QDesktopServices::openUrl(url); diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp index 06da18148f..e1f9f63bfb 100644 --- a/interface/src/commerce/QmlCommerce.cpp +++ b/interface/src/commerce/QmlCommerce.cpp @@ -47,6 +47,16 @@ QmlCommerce::QmlCommerce() { _appsPath = PathUtils::getAppDataPath() + "Apps/"; } +void QmlCommerce::openSystemApp(const QString& appPath) { + + QUrl appUrl = PathUtils::qmlUrl(appPath); + + auto tablet = dynamic_cast( + DependencyManager::get()->getTablet("com.highfidelity.interface.tablet.system")); + tablet->loadQMLSource(appUrl); +} + + void QmlCommerce::getWalletStatus() { auto wallet = DependencyManager::get(); wallet->getWalletStatus(); @@ -353,7 +363,7 @@ bool QmlCommerce::openApp(const QString& itemHref) { // Read from the file to know what .html or .qml document to open QFile appFile(_appsPath + "/" + appHref.fileName()); if (!appFile.open(QIODevice::ReadOnly)) { - qCDebug(commerce) << "Couldn't open local .app.json file."; + qCDebug(commerce) << "Couldn't open local .app.json file:" << _appsPath << "/" << appHref.fileName(); return false; } QJsonDocument appFileJsonDocument = QJsonDocument::fromJson(appFile.readAll()); diff --git a/interface/src/commerce/QmlCommerce.h b/interface/src/commerce/QmlCommerce.h index 79d8e82e71..bee30e1b62 100644 --- a/interface/src/commerce/QmlCommerce.h +++ b/interface/src/commerce/QmlCommerce.h @@ -24,6 +24,7 @@ class QmlCommerce : public QObject { public: QmlCommerce(); + void openSystemApp(const QString& appPath); signals: void walletStatusResult(uint walletStatus); diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 3e3c9da148..d9396ae4d1 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -176,7 +176,7 @@ int main(int argc, const char* argv[]) { if (socket.waitForConnected(LOCAL_SERVER_TIMEOUT_MS)) { if (parser.isSet(urlOption)) { QUrl url = QUrl(parser.value(urlOption)); - if (url.isValid() && url.scheme() == URL_SCHEME_HIFI) { + if (url.isValid() && (url.scheme() == URL_SCHEME_HIFI || url.scheme() == URL_SCHEME_HIFIAPP)) { qDebug() << "Writing URL to local socket"; socket.write(url.toString().toUtf8()); if (!socket.waitForBytesWritten(5000)) { diff --git a/libraries/networking/src/NetworkingConstants.h b/libraries/networking/src/NetworkingConstants.h index 31ff6da873..839e269fd4 100644 --- a/libraries/networking/src/NetworkingConstants.h +++ b/libraries/networking/src/NetworkingConstants.h @@ -32,6 +32,7 @@ namespace NetworkingConstants { const QString URL_SCHEME_ABOUT = "about"; const QString URL_SCHEME_HIFI = "hifi"; +const QString URL_SCHEME_HIFIAPP = "hifiapp"; const QString URL_SCHEME_QRC = "qrc"; const QString URL_SCHEME_FILE = "file"; const QString URL_SCHEME_HTTP = "http"; diff --git a/server-console/src/main.js b/server-console/src/main.js index 0fd2659fe9..876f1fddaa 100644 --- a/server-console/src/main.js +++ b/server-console/src/main.js @@ -41,6 +41,11 @@ const ProcessGroupStates = hfprocess.ProcessGroupStates; const hfApp = require('./modules/hf-app.js'); const GetBuildInfo = hfApp.getBuildInfo; const StartInterface = hfApp.startInterface; +const getRootHifiDataDirectory = hfApp.getRootHifiDataDirectory; +const getDomainServerClientResourcesDirectory = hfApp.getDomainServerClientResourcesDirectory; +const getAssignmentClientResourcesDirectory = hfApp.getAssignmentClientResourcesDirectory; +const getApplicationDataDirectory = hfApp.getApplicationDataDirectory; + const osType = os.type(); @@ -55,32 +60,7 @@ const HOME_CONTENT_URL = "http://cdn.highfidelity.com/content-sets/home-tutorial const buildInfo = GetBuildInfo(); -function getRootHifiDataDirectory(local) { - var organization = buildInfo.organization; - if (osType == 'Windows_NT') { - if (local) { - return path.resolve(osHomeDir(), 'AppData/Local', organization); - } else { - return path.resolve(osHomeDir(), 'AppData/Roaming', organization); - } - } else if (osType == 'Darwin') { - return path.resolve(osHomeDir(), 'Library/Application Support', organization); - } else { - return path.resolve(osHomeDir(), '.local/share/', organization); - } -} -function getDomainServerClientResourcesDirectory() { - return path.join(getRootHifiDataDirectory(), '/domain-server'); -} - -function getAssignmentClientResourcesDirectory() { - return path.join(getRootHifiDataDirectory(), '/assignment-client'); -} - -function getApplicationDataDirectory(local) { - return path.join(getRootHifiDataDirectory(local), '/Server Console'); -} // Update lock filepath const UPDATER_LOCK_FILENAME = ".updating"; @@ -352,8 +332,8 @@ const HifiNotifications = hfNotifications.HifiNotifications; const HifiNotificationType = hfNotifications.NotificationType; var pendingNotifications = {} -function notificationCallback(notificationType) { - pendingNotifications[notificationType] = true; +function notificationCallback(notificationType, pending = true) { + pendingNotifications[notificationType] = pending; updateTrayMenu(homeServer ? homeServer.state : ProcessGroupStates.STOPPED); } @@ -424,7 +404,7 @@ var labels = { goto: { label: 'Goto', click: function() { - StartInterface(""); + StartInterface("hifiapp:hifi/tablet/TabletAddressDialog.qml"); pendingNotifications[HifiNotificationType.GOTO] = false; updateTrayMenu(homeServer ? homeServer.state : ProcessGroupStates.STOPPED); } @@ -432,7 +412,7 @@ var labels = { people: { label: 'People', click: function() { - StartInterface(""); + StartInterface("hifiapp:hifi/Pal.qml"); pendingNotifications[HifiNotificationType.PEOPLE] = false; updateTrayMenu(homeServer ? homeServer.state : ProcessGroupStates.STOPPED); } @@ -440,7 +420,7 @@ var labels = { wallet: { label: 'Wallet', click: function() { - StartInterface(""); + StartInterface("hifiapp:hifi/commerce/wallet/Wallet.qml"); pendingNotifications[HifiNotificationType.WALLET] = false; updateTrayMenu(homeServer ? homeServer.state : ProcessGroupStates.STOPPED); } @@ -448,7 +428,7 @@ var labels = { marketplace: { label: 'Marketplace', click: function() { - StartInterface(""); + StartInterface("hifiapp:hifi/commerce/purchases/Purchases.qml"); pendingNotifications[HifiNotificationType.MARKETPLACE] = false; updateTrayMenu(homeServer ? homeServer.state : ProcessGroupStates.STOPPED); } diff --git a/server-console/src/modules/hf-acctinfo.js b/server-console/src/modules/hf-acctinfo.js new file mode 100644 index 0000000000..5e0c9f7f65 --- /dev/null +++ b/server-console/src/modules/hf-acctinfo.js @@ -0,0 +1,135 @@ +'use strict' + +const request = require('request'); +const extend = require('extend'); +const util = require('util'); +const events = require('events'); +const childProcess = require('child_process'); +const fs = require('fs-extra'); +const os = require('os'); +const path = require('path'); + +const hfApp = require('./hf-app.js'); +const getInterfaceDataDirectory = hfApp.getInterfaceDataDirectory; + + +const VariantTypes = { + USER_TYPE: 1024 +} + +function AccountInfo() { + + var accountInfoPath = path.join(getInterfaceDataDirectory(), '/AccountInfo.bin'); + this.rawData = null; + this.parseOffset = 0; + try { + this.rawData = fs.readFileSync(accountInfoPath); + + this.data = this._parseMap(); + + } catch(e) { + console.log(e); + log.debug("AccountInfo file not found: " + accountInfoPath); + } +} + +AccountInfo.prototype = { + + accessToken: function(metaverseUrl) { + return this.data[metaverseUrl]["accessToken"]["token"]; + }, + _parseUInt32: function () { + if (!this.rawData || (this.rawData.length - this.parseOffset < 4)) { + throw "Expected uint32"; + } + var result = this.rawData.readUInt32BE(this.parseOffset); + this.parseOffset += 4; + return result; + }, + _parseMap: function() { + var result = {}; + var n = this._parseUInt32(); + for(var i = 0; i < n; i++) { + var key = this._parseQString(); + result[key] = this._parseVariant(); + } + return result; + }, + _parseVariant: function() { + var varType = this._parseUInt32(); + var isNull = this.rawData[this.parseOffset++]; + + switch(varType) { + case VariantTypes.USER_TYPE: + //user type + var userTypeName = this._parseByteArray().toString('ascii').slice(0,-1); + if(userTypeName == "DataServerAccountInfo") { + return this._parseDataServerAccountInfo(); + } + else { + throw "Unknown custom type " + userTypeName; + } + break; + } + }, + _parseByteArray: function() { + var length = this._parseUInt32(); + if (length == 0xffffffff) { + return null; + } + var result = this.rawData.slice(this.parseOffset, this.parseOffset+length); + this.parseOffset += length; + return result; + + }, + _parseQString: function() { + if (!this.rawData || (this.rawData.length <= this.parseOffset)) { + throw "Expected QString"; + } + // length in bytes; + var length = this._parseUInt32(); + if(length == 0xFFFFFFFF) { + return null; + } + + if(this.rawData.length - this.parseOffset < length) { + throw "Insufficient buffer length for QString parsing"; + } + + // Convert from BE UTF16 to LE + var resultBuffer = this.rawData.slice(this.parseOffset, this.parseOffset+length); + resultBuffer.swap16(); + var result = resultBuffer.toString('utf16le'); + this.parseOffset += length; + return result; + }, + _parseDataServerAccountInfo: function() { + return { + accessToken: this._parseOAuthAccessToken(), + username: this._parseQString(), + xmppPassword: this._parseQString(), + discourseApiKey: this._parseQString(), + walletId: this._parseUUID(), + privateKey: this._parseByteArray(), + domainId: this._parseUUID(), + tempDomainId: this._parseUUID(), + tempDomainApiKey: this._parseQString() + + } + }, + _parseOAuthAccessToken: function() { + return { + token: this._parseQString(), + timestampHigh: this._parseUInt32(), + timestampLow: this._parseUInt32(), + tokenType: this._parseQString(), + refreshToken: this._parseQString() + } + }, + _parseUUID: function() { + this.parseOffset += 16; + return null; + } +} + +exports.AccountInfo = AccountInfo; \ No newline at end of file diff --git a/server-console/src/modules/hf-app.js b/server-console/src/modules/hf-app.js index 28b97f582a..625715b392 100644 --- a/server-console/src/modules/hf-app.js +++ b/server-console/src/modules/hf-app.js @@ -6,6 +6,7 @@ const pathFinder = require('./path-finder'); const path = require('path'); const argv = require('yargs').argv; const hfprocess = require('./hf-process'); +const osHomeDir = require('os-homedir'); const Process = hfprocess.Process; const binaryType = argv.binaryType; @@ -69,3 +70,35 @@ exports.isInterfaceRunning = function(done) { var pInterface = new Process('interface', 'interface.exe'); return pInterface.isRunning(done); } + + +exports.getRootHifiDataDirectory = function(local) { + var organization = buildInfo.organization; + if (osType == 'Windows_NT') { + if (local) { + return path.resolve(osHomeDir(), 'AppData/Local', organization); + } else { + return path.resolve(osHomeDir(), 'AppData/Roaming', organization); + } + } else if (osType == 'Darwin') { + return path.resolve(osHomeDir(), 'Library/Application Support', organization); + } else { + return path.resolve(osHomeDir(), '.local/share/', organization); + } +} + +exports.getDomainServerClientResourcesDirectory = function() { + return path.join(exports.getRootHifiDataDirectory(), '/domain-server'); +} + +exports.getAssignmentClientResourcesDirectory = function() { + return path.join(exports.getRootHifiDataDirectory(), '/assignment-client'); +} + +exports.getApplicationDataDirectory = function(local) { + return path.join(exports.getRootHifiDataDirectory(local), '/Server Console'); +} + +exports.getInterfaceDataDirectory = function(local) { + return path.join(exports.getRootHifiDataDirectory(local), '/Interface'); +} \ No newline at end of file diff --git a/server-console/src/modules/hf-appinfo.js b/server-console/src/modules/hf-appinfo.js deleted file mode 100644 index 9fac0ca61c..0000000000 --- a/server-console/src/modules/hf-appinfo.js +++ /dev/null @@ -1,10 +0,0 @@ -'use strict' - -const request = require('request'); -const extend = require('extend'); -const util = require('util'); -const events = require('events'); -const childProcess = require('child_process'); -const fs = require('fs-extra'); -const os = require('os'); -const path = require('path'); diff --git a/server-console/src/modules/hf-notifications.js b/server-console/src/modules/hf-notifications.js index 06be365208..785ecc4ec0 100644 --- a/server-console/src/modules/hf-notifications.js +++ b/server-console/src/modules/hf-notifications.js @@ -4,14 +4,18 @@ const os = require('os'); const process = require('process'); const hfApp = require('./hf-app'); const path = require('path'); +const AccountInfo = require('./hf-acctinfo').AccountInfo; +const GetBuildInfo = hfApp.getBuildInfo; +const buildInfo = GetBuildInfo(); const notificationIcon = path.join(__dirname, '../../resources/console-notification.png'); const NOTIFICATION_POLL_TIME_MS = 15 * 1000; -const METAVERSE_SERVER_URL= process.env.HIFI_METAVERSE_URL ? process.env.HIFI_METAVERSE_URL : 'https://highfidelity.com' +const METAVERSE_SERVER_URL= process.env.HIFI_METAVERSE_URL ? process.env.HIFI_METAVERSE_URL : 'https://metaverse.highfidelity.com' const STORIES_URL= '/api/v1/user_stories'; const USERS_URL= '/api/v1/users'; const ECONOMIC_ACTIVITY_URL= '/api/v1/commerce/history'; const UPDATES_URL= '/api/v1/commerce/available_updates'; +const MAX_NOTIFICATION_ITEMS=30 const StartInterface=hfApp.startInterface; @@ -31,55 +35,60 @@ function HifiNotification(notificationType, notificationData) { HifiNotification.prototype = { show: function() { + var text = ""; + var message = ""; + var url = null; + var app = null; switch(this.type) { case NotificationType.GOTO: - var text = this.data.username + " " + this.data.action_string + " in " + this.data.place_name; - notifier.notify({ - notificationType: this.type, - icon: notificationIcon, - title: text, - message: "Click to goto " + this.data.place_name, - wait: true, - url: "hifi://" + this.data.place_name + this.data.path - }); + text = this.data.username + " " + this.data.action_string + " in " + this.data.place_name; + message = "Click to go to " + this.data.place_name; + url = "hifi://" + this.data.place_name + this.data.path; break; - case NotificationType.PEOPLE: - var text = this.data.username + " has logged in."; - notifier.notify({ - notificationType: this.type, - icon: notificationIcon, - title: text, - message: "Click to join them in " + this.data.location.root.name, - wait: true, - url: "hifi://" + this.data.location.root.name + this.data.location.path - }); + text = this.data.username + " is available in " + this.data.location.root.name + "!"; + message = "Click to join them."; + url="hifi://" + this.data.location.root.name + this.data.location.path; break; - case NotificationType.WALLET: - var text = "Economic activity."; - notifier.notify({ - notificationType: this.type, - icon: notificationIcon, - title: text, - message: "Click to open your wallet", - wait: true, - app: "Wallet" - }); + if(typeof(this.data) == "number") { + text = "You have " + this.data + " unread Wallet notifications!"; + message = "Click to open your wallet." + url = "hifiapp:hifi/commerce/wallet/Wallet.qml"; + break; + } + text = "Economic activity."; + var memo = ""; + if(this.data.sent_certs <= 0 && this.data.received_certs <= 0) { + if(this.data.received_money > 0) { + text = this.data.sender_name + " sent you " + this.data.received_money + " HFC!"; + memo = "memo: \"" + this.data.message + "\" "; + } + else { + return; + } + } + else { + text = this.data.message.replace(/<\/?[^>]+(>|$)/g, ""); + } + message = memo + "Click to open your wallet."; + url = "hifiapp:hifi/commerce/wallet/Wallet.qml"; break; - case NotificationType.MARKETPLACE: - var text = "One of your marketplace items has an update."; - notifier.notify({ - notificationType: this.type, - icon: notificationIcon, - title: text, - message: "Click to start the marketplace app", - wait: true, - app: "Marketplace" - }); + text = "There's an update available for your version of " + this.data.base_item_title + "!"; + message = "Click to open the marketplace."; + url = "hifiapp:hifi/commerce/purchases/Purchases.qml"; break; } + notifier.notify({ + notificationType: this.type, + icon: notificationIcon, + title: text, + message: message, + wait: true, + appID: buildInfo.appUserModelId, + url: url + }); } } @@ -89,7 +98,6 @@ function HifiNotifications(config, callback) { this.since = new Date(this.config.get("notifySince", "1970-01-01T00:00:00.000Z")); this.enable(this.enabled()); notifier.on('click', function(notifierObject, options) { - console.log(options); StartInterface(options.url); }); } @@ -100,16 +108,18 @@ HifiNotifications.prototype = { if(enabled) { var _this = this; this.pollTimer = setInterval(function() { + var acctInfo = new AccountInfo(); + var token = acctInfo.accessToken(METAVERSE_SERVER_URL); var _since = _this.since; _this.since = new Date(); IsInterfaceRunning(function(running) { if(running) { return; } - _this.pollForStories(_since, _this.callback); - _this.pollForConnections(_since, _this.callback); - _this.pollForEconomicActivity(_since, _this.callback); - _this.pollForMarketplaceUpdates(_since, _this.callback); + _this.pollForStories(_since, token); + _this.pollForConnections(_since, token); + _this.pollForEconomicActivity(_since, token); + _this.pollForMarketplaceUpdates(_since, token); }); }, NOTIFICATION_POLL_TIME_MS); @@ -127,134 +137,128 @@ HifiNotifications.prototype = { clearInterval(this.pollTimer); } }, - pollForStories: function(since, callback) { + _pollCommon: function(notifyType, error, data, since) { + var maxNotificationItemCount = (since.getTime() == 0) ? MAX_NOTIFICATION_ITEMS : 1; + if (error || !data.body) { + console.log("Error: unable to get " + url); + return false; + } + var content = JSON.parse(data.body); + if(!content || content.status != 'success') { + console.log("Error: unable to get " + url); + return false; + } + console.log(content); + if(!content.total_entries) { + return; + } + this.callback(notifyType, true); + if(content.total_entries >= maxNotificationItemCount) { + var notification = new HifiNotification(notifyType, content.total_entries); + notification.show(); + } + else { + var notifyData = [] + switch(notifyType) { + case NotificationType.GOTO: + notifyData = content.user_stories; + break; + case NotificationType.PEOPLE: + notifyData = content.data.users; + break; + case NotificationType.WALLET: + notifyData = content.data.history; + break; + case NotificationType.MARKETPLACE: + notifyData = content.data.updates; + break; + } + + notifyData.forEach(function(data) { + var notification = new HifiNotification(notifyType, data); + notification.show(); + }); + } + }, + pollForStories: function(since, token) { var _this = this; var actions = 'announcement'; var options = [ 'now=' + new Date().toISOString(), - 'since=' + since.toISOString(), + 'since=' + since.getTime() / 1000, 'include_actions=announcement', 'restriction=open,hifi', - 'require_online=true' + 'require_online=true', + 'per_page='+MAX_NOTIFICATION_ITEMS ]; console.log("Polling for stories"); var url = METAVERSE_SERVER_URL + STORIES_URL + '?' + options.join('&'); + console.log(url); request({ uri: url }, function (error, data) { - if (error || !data.body) { - console.log("Error: unable to get " + url); - return; - } - var content = JSON.parse(data.body); - if(!content || content.status != 'success') { - console.log("Error: unable to get " + url); - return; - } - content.user_stories.forEach(function(story) { - var updated_at = new Date(story.updated_at); - if (updated_at < since) { - return; - } - callback(NotificationType.GOTO); - var notification = new HifiNotification(NotificationType.GOTO, story); - notification.show(); - }); + _this._pollCommon(NotificationType.GOTO, error, data, since); }); }, - pollForConnections: function(since, callback) { + pollForConnections: function(since, token) { var _this = this; var options = [ 'filter=connections', - 'since=' + since.toISOString(), - 'status=online' + 'since=' + since.getTime() / 1000, + 'status=online', + 'page=1', + 'per_page=' + MAX_NOTIFICATION_ITEMS ]; console.log("Polling for connections"); var url = METAVERSE_SERVER_URL + USERS_URL + '?' + options.join('&'); - request({ - uri: url + console.log(url); + request.get({ + uri: url, + 'auth': { + 'bearer': token + } }, function (error, data) { - if (error || !data.body) { - console.log("Error: unable to get " + url); - return; - } - var content = JSON.parse(data.body); - if(!content || content.status != 'success') { - console.log("Error: unable to get " + url); - return; - } - console.log(content.data); - content.data.users.forEach(function(user) { - if(user.online) { - callback(NotificationType.PEOPLE); - var notification = new HifiNotification(NotificationType.PEOPLE, user); - notification.show(); - } - }); + _this._pollCommon(NotificationType.PEOPLE, error, data, since); }); }, - pollForEconomicActivity: function(since, callback) { + pollForEconomicActivity: function(since, token) { var _this = this; var options = [ - 'filter=connections', - 'since=' + since.toISOString(), - 'status=online' + 'since=' + since.getTime() / 1000, + 'page=1', + 'per_page=' + 1000 // total_entries is incorrect for wallet queries if results + // aren't all on one page, so grab them all on a single page + // for now. ]; console.log("Polling for economic activity"); var url = METAVERSE_SERVER_URL + ECONOMIC_ACTIVITY_URL + '?' + options.join('&'); + console.log(url); request.post({ - uri: url + uri: url, + 'auth': { + 'bearer': token + } }, function (error, data) { - if (error || !data.body) { - console.log("Error " + error + ": unable to post " + url); - console.log(data); - return; - } - var content = JSON.parse(data.body); - if(!content || content.status != 'success') { - console.log(data.body); - console.log("Error " + content.status + ": unable to post " + url); - return; - } - console.log(content.data); - content.data.users.forEach(function(user) { - if(user.online) { - callback(NotificationType.PEOPLE); - var notification = new HifiNotification(NotificationType.PEOPLE, user); - notification.show(); - } - }); + _this._pollCommon(NotificationType.WALLET, error, data, since); }); }, - pollForMarketplaceUpdates: function(since, callback) { + pollForMarketplaceUpdates: function(since, token) { var _this = this; var options = [ - 'filter=connections', - 'since=' + since.toISOString(), - 'status=online' + 'since=' + since.getTime() / 1000, + 'page=1', + 'per_page=' + MAX_NOTIFICATION_ITEMS ]; console.log("Polling for marketplace update"); var url = METAVERSE_SERVER_URL + UPDATES_URL + '?' + options.join('&'); + console.log(url); request.put({ - uri: url + uri: url, + 'auth': { + 'bearer': token + } }, function (error, data) { - if (error || !data.body) { - console.log("Error " + error + ": unable to put " + url); - return; - } - var content = JSON.parse(data.body); - if(!content || content.status != 'success') { - console.log(data.body); - console.log("Error " + content.status + ": unable to put " + url); - return; - } - content.data.users.forEach(function(user) { - if(user.online) { - callback(NotificationType.PEOPLE); - var notification = new HifiNotification(NotificationType.PEOPLE, user); - notification.show(); - } - }); + _this._pollCommon(NotificationType.MARKETPLACE, error, data, since); }); } }; From bda179697ebad6c08170bf8ae63660093cdbcfb3 Mon Sep 17 00:00:00 2001 From: Roxanne Skelly Date: Wed, 19 Sep 2018 15:50:50 -0700 Subject: [PATCH 13/38] Tray Notifications - users handling changes Since the 'users' api call doesn't support a 'since', we now query all of the online connections each time to keep track of connections that join or leave. --- .../src/modules/hf-notifications.js | 122 +++++++++++++++--- 1 file changed, 104 insertions(+), 18 deletions(-) diff --git a/server-console/src/modules/hf-notifications.js b/server-console/src/modules/hf-notifications.js index 785ecc4ec0..e4f2d5b408 100644 --- a/server-console/src/modules/hf-notifications.js +++ b/server-console/src/modules/hf-notifications.js @@ -16,6 +16,7 @@ const USERS_URL= '/api/v1/users'; const ECONOMIC_ACTIVITY_URL= '/api/v1/commerce/history'; const UPDATES_URL= '/api/v1/commerce/available_updates'; const MAX_NOTIFICATION_ITEMS=30 +const STARTUP_MAX_NOTIFICATION_ITEMS=5 const StartInterface=hfApp.startInterface; @@ -41,19 +42,34 @@ HifiNotification.prototype = { var app = null; switch(this.type) { case NotificationType.GOTO: - text = this.data.username + " " + this.data.action_string + " in " + this.data.place_name; - message = "Click to go to " + this.data.place_name; - url = "hifi://" + this.data.place_name + this.data.path; + if(typeof(this.data) == "number") { + text = this.data + " events are happening." + message = "Click to open GOTO."; + url="hifiapp:hifi/tablet/TabletAddressDialog.qml" + } + else { + text = this.data.username + " " + this.data.action_string + " in " + this.data.place_name; + message = "Click to go to " + this.data.place_name; + url = "hifi://" + this.data.place_name + this.data.path; + } break; case NotificationType.PEOPLE: - text = this.data.username + " is available in " + this.data.location.root.name + "!"; - message = "Click to join them."; - url="hifi://" + this.data.location.root.name + this.data.location.path; + if(typeof(this.data) == "number") { + text = this.data + " of your connections is online." + message = "Click to open PEOPLE."; + url="hifiapp:hifi/Pal.qml" + } + else { + console.log(this.data); + text = this.data.username + " is available in " + this.data.location.root.name + "!"; + message = "Click to join them."; + url="hifi://" + this.data.location.root.name + this.data.location.path; + } break; case NotificationType.WALLET: if(typeof(this.data) == "number") { text = "You have " + this.data + " unread Wallet notifications!"; - message = "Click to open your wallet." + message = "Click to open WALLET." url = "hifiapp:hifi/commerce/wallet/Wallet.qml"; break; } @@ -71,12 +87,17 @@ HifiNotification.prototype = { else { text = this.data.message.replace(/<\/?[^>]+(>|$)/g, ""); } - message = memo + "Click to open your wallet."; + message = memo + "Click to open WALLET."; url = "hifiapp:hifi/commerce/wallet/Wallet.qml"; break; case NotificationType.MARKETPLACE: - text = "There's an update available for your version of " + this.data.base_item_title + "!"; - message = "Click to open the marketplace."; + if(typeof(this.data) == "number") { + text = this.data + " of your purchased items have updates available!"; + } + else { + text = "There's an update available for your version of " + this.data.base_item_title + "!"; + } + message = "Click to open MARKETPLACE."; url = "hifiapp:hifi/commerce/purchases/Purchases.qml"; break; } @@ -95,6 +116,7 @@ HifiNotification.prototype = { function HifiNotifications(config, callback) { this.config = config; this.callback = callback; + this.onlineUsers = new Set([]); this.since = new Date(this.config.get("notifySince", "1970-01-01T00:00:00.000Z")); this.enable(this.enabled()); notifier.on('click', function(notifierObject, options) { @@ -137,8 +159,24 @@ HifiNotifications.prototype = { clearInterval(this.pollTimer); } }, + _pollToDisableHighlight: function(notifyType, error, data) { + if (error || !data.body) { + console.log("Error: unable to get " + url); + return false; + } + console.log(data.body); + var content = JSON.parse(data.body); + if(!content || content.status != 'success') { + console.log("Error: unable to get " + url); + return false; + } + console.log(content); + if(!content.total_entries) { + this.callback(notifyType, false); + } + }, _pollCommon: function(notifyType, error, data, since) { - var maxNotificationItemCount = (since.getTime() == 0) ? MAX_NOTIFICATION_ITEMS : 1; + var maxNotificationItemCount = since.getTime() ? MAX_NOTIFICATION_ITEMS : STARTUP_MAX_NOTIFICATION_ITEMS; if (error || !data.body) { console.log("Error: unable to get " + url); return false; @@ -174,14 +212,15 @@ HifiNotifications.prototype = { break; } - notifyData.forEach(function(data) { - var notification = new HifiNotification(notifyType, data); + notifyData.forEach(function(notifyDataEntry) { + var notification = new HifiNotification(notifyType, notifyDataEntry); notification.show(); }); } }, pollForStories: function(since, token) { var _this = this; + var _token = token; var actions = 'announcement'; var options = [ 'now=' + new Date().toISOString(), @@ -194,17 +233,36 @@ HifiNotifications.prototype = { console.log("Polling for stories"); var url = METAVERSE_SERVER_URL + STORIES_URL + '?' + options.join('&'); console.log(url); - request({ - uri: url - }, function (error, data) { + request.get({ + uri: url, + 'auth': { + 'bearer': _token + } + }, function (error, data) { _this._pollCommon(NotificationType.GOTO, error, data, since); + var options = [ + 'now=' + new Date().toISOString(), + 'include_actions=announcement', + 'restriction=open,hifi', + 'require_online=true', + 'per_page=1' + ]; + var url = METAVERSE_SERVER_URL + STORIES_URL + '?' + options.join('&'); + request.get({ + uri: url, + 'auth': { + 'bearer': _token + } + }, function(error, data) { + _this._pollToDisableHighlight(NotificationType.GOTO, error, data); + }); }); }, pollForConnections: function(since, token) { var _this = this; + var _since = since; var options = [ 'filter=connections', - 'since=' + since.getTime() / 1000, 'status=online', 'page=1', 'per_page=' + MAX_NOTIFICATION_ITEMS @@ -218,7 +276,35 @@ HifiNotifications.prototype = { 'bearer': token } }, function (error, data) { - _this._pollCommon(NotificationType.PEOPLE, error, data, since); + // Users is a special case as we keep track of online users locally. + var maxNotificationItemCount = since.getTime() ? MAX_NOTIFICATION_ITEMS : STARTUP_MAX_NOTIFICATION_ITEMS; + if (error || !data.body) { + console.log("Error: unable to get " + url); + return false; + } + var content = JSON.parse(data.body); + if(!content || content.status != 'success') { + console.log("Error: unable to get " + url); + return false; + } + console.log(content); + if(!content.total_entries) { + _this.callback(NotificationType.PEOPLE, false); + _this.onlineUsers = new Set([]); + return; + } + + var currentUsers = new Set([]); + content.data.users.forEach(function(user) { + currentUsers.add(user.username); + if(!_this.onlineUsers.has(user.username)) { + _this.callback(NotificationType.PEOPLE, true); + _this.onlineUsers.add(user.username); + var notification = new HifiNotification(NotificationType.PEOPLE, user); + notification.show(); + } + }); + _this.onlineUsers = currentUsers; }); }, pollForEconomicActivity: function(since, token) { From ed84b49ece9fe29171d7c5864fb4405d09014797 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 19 Sep 2018 16:15:59 -0700 Subject: [PATCH 14/38] Small bugfixes and using original endpoints --- .../icons/tablet-icons/goto-a-msg.svg | 57 +++++++++++++++++++ .../{goto-msg.svg => goto-i-msg.svg} | 0 .../icons/tablet-icons/wallet-a-msg.svg | 6 ++ .../icons/tablet-icons/wallet-i-msg.svg | 16 ++++++ .../qml/hifi/commerce/purchases/Purchases.qml | 2 +- scripts/system/commerce/wallet.js | 2 +- scripts/system/marketplaces/marketplaces.js | 5 +- scripts/system/pal.js | 2 +- scripts/system/tablet-goto.js | 2 +- 9 files changed, 85 insertions(+), 7 deletions(-) create mode 100644 interface/resources/icons/tablet-icons/goto-a-msg.svg rename interface/resources/icons/tablet-icons/{goto-msg.svg => goto-i-msg.svg} (100%) create mode 100644 interface/resources/icons/tablet-icons/wallet-a-msg.svg create mode 100644 interface/resources/icons/tablet-icons/wallet-i-msg.svg diff --git a/interface/resources/icons/tablet-icons/goto-a-msg.svg b/interface/resources/icons/tablet-icons/goto-a-msg.svg new file mode 100644 index 0000000000..f1f611adb9 --- /dev/null +++ b/interface/resources/icons/tablet-icons/goto-a-msg.svg @@ -0,0 +1,57 @@ + + + +image/svg+xml + + \ No newline at end of file diff --git a/interface/resources/icons/tablet-icons/goto-msg.svg b/interface/resources/icons/tablet-icons/goto-i-msg.svg similarity index 100% rename from interface/resources/icons/tablet-icons/goto-msg.svg rename to interface/resources/icons/tablet-icons/goto-i-msg.svg diff --git a/interface/resources/icons/tablet-icons/wallet-a-msg.svg b/interface/resources/icons/tablet-icons/wallet-a-msg.svg new file mode 100644 index 0000000000..d51c3e99a2 --- /dev/null +++ b/interface/resources/icons/tablet-icons/wallet-a-msg.svg @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/interface/resources/icons/tablet-icons/wallet-i-msg.svg b/interface/resources/icons/tablet-icons/wallet-i-msg.svg new file mode 100644 index 0000000000..676f97a966 --- /dev/null +++ b/interface/resources/icons/tablet-icons/wallet-i-msg.svg @@ -0,0 +1,16 @@ + + + + + + + + + diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml index 3b8e2c0f4d..2435678e77 100644 --- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml +++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml @@ -93,7 +93,7 @@ Rectangle { console.log("Failed to get Available Updates", result.data.message); } else { sendToScript({method: 'purchases_availableUpdatesReceived', numUpdates: result.data.updates.length }); - root.numUpdatesAvailable = result.data.updates.length; + root.numUpdatesAvailable = result.total_entries; } } diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js index 2f3f5c109d..c903080f62 100644 --- a/scripts/system/commerce/wallet.js +++ b/scripts/system/commerce/wallet.js @@ -601,7 +601,7 @@ function startup() { onOpened: walletOpened, onClosed: walletClosed, onMessage: fromQml, - notificationPollEndpoint: "/api/v1/notifications?source=commerce-history&per_page=10", + notificationPollEndpoint: "/api/v1/commerce/history?per_page=10", notificationPollTimeoutMs: 60000, notificationDataProcessPage: notificationDataProcessPage, notificationPollCallback: notificationPollCallback, diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index 1bb0713f50..9bd3a9facf 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -137,7 +137,6 @@ function onUsernameChanged() { } } -var userHasUpdates = false; function sendCommerceSettings() { ui.sendToHtml({ type: "marketplaces", @@ -147,7 +146,7 @@ function sendCommerceSettings() { userIsLoggedIn: Account.loggedIn, walletNeedsSetup: Wallet.walletStatus === 1, metaverseServerURL: Account.metaverseServerURL, - messagesWaiting: userHasUpdates + messagesWaiting: shouldShowDot } }); } @@ -1077,7 +1076,7 @@ function startup() { home: MARKETPLACE_URL_INITIAL, onScreenChanged: onTabletScreenChanged, onMessage: onQmlMessageReceived, - notificationPollEndpoint: "/api/v1/notifications?source=commerce-available_updates&per_page=10", + notificationPollEndpoint: "/api/v1/commerce/available_updates?per_page=10", notificationPollTimeoutMs: 60000, notificationDataProcessPage: notificationDataProcessPage, notificationPollCallback: notificationPollCallback, diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 355ed0a504..b3499d759a 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -891,7 +891,7 @@ function startup() { onOpened: palOpened, onClosed: off, onMessage: fromQml, - notificationPollEndpoint: "/api/v1/notifications?source=users&filter=connections&per_page=10", + notificationPollEndpoint: "/api/v1/users?filter=connections&per_page=10", notificationPollTimeoutMs: 60000, notificationDataProcessPage: notificationDataProcessPage, notificationPollCallback: notificationPollCallback, diff --git a/scripts/system/tablet-goto.js b/scripts/system/tablet-goto.js index 63bc8431e8..f37b13c406 100644 --- a/scripts/system/tablet-goto.js +++ b/scripts/system/tablet-goto.js @@ -113,7 +113,7 @@ function startup() { 'protocol=' + encodeURIComponent(Window.protocolSignature()), 'per_page=10' ]; - var endpoint = '/api/v1/notifications?source=user_stories?' + options.join('&'); + var endpoint = '/api/v1/user_stories?' + options.join('&'); ui = new AppUi({ buttonName: BUTTON_NAME, From 87e91a44015710713c9bf5ed0a881df06b7be1fe Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 20 Sep 2018 13:36:50 -0700 Subject: [PATCH 15/38] GOTO doesn't care about SINCE; reduce data for PEOPLE --- scripts/system/pal.js | 16 +++++++--------- scripts/system/tablet-goto.js | 2 +- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/scripts/system/pal.js b/scripts/system/pal.js index b3499d759a..02bf92dcfe 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -841,15 +841,13 @@ function notificationPollCallback(connectionsArray) { return; } - if (user.online) { - newOnlineUsers++; - storedOnlineUsers[user.username] = user; + newOnlineUsers++; + storedOnlineUsers[user.username] = user; - if (!ui.isOpen && ui.notificationInitialCallbackMade) { - message = user.username + " is available in " + - user.location.root.name + "! Open PEOPLE to join them."; - ui.notificationDisplayBanner(message); - } + if (!ui.isOpen && ui.notificationInitialCallbackMade) { + message = user.username + " is available in " + + user.location.root.name + "! Open PEOPLE to join them."; + ui.notificationDisplayBanner(message); } }); var key; @@ -891,7 +889,7 @@ function startup() { onOpened: palOpened, onClosed: off, onMessage: fromQml, - notificationPollEndpoint: "/api/v1/users?filter=connections&per_page=10", + notificationPollEndpoint: "/api/v1/users?filter=connections&status=online&per_page=10", notificationPollTimeoutMs: 60000, notificationDataProcessPage: notificationDataProcessPage, notificationPollCallback: notificationPollCallback, diff --git a/scripts/system/tablet-goto.js b/scripts/system/tablet-goto.js index f37b13c406..fde558d728 100644 --- a/scripts/system/tablet-goto.js +++ b/scripts/system/tablet-goto.js @@ -125,7 +125,7 @@ function startup() { notificationDataProcessPage: notificationDataProcessPage, notificationPollCallback: notificationPollCallback, notificationPollStopPaginatingConditionMet: isReturnedDataEmpty, - notificationPollCaresAboutSince: true + notificationPollCaresAboutSince: false }); } From 33c04631ea1b459924f8c2dfa15bafe491d88fbd Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 20 Sep 2018 14:34:55 -0700 Subject: [PATCH 16/38] Comments on Confluence doc --- scripts/system/commerce/wallet.js | 23 ++++++--------------- scripts/system/marketplaces/marketplaces.js | 8 +++---- scripts/system/pal.js | 4 ++-- scripts/system/tablet-goto.js | 11 +++++----- 4 files changed, 18 insertions(+), 28 deletions(-) diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js index c903080f62..1fce45bb6f 100644 --- a/scripts/system/commerce/wallet.js +++ b/scripts/system/commerce/wallet.js @@ -543,37 +543,26 @@ function notificationPollCallback(historyArray) { var message; if (!ui.notificationInitialCallbackMade) { message = "You have " + notificationCount + " unread wallet " + - "notification" + (notificationCount === 1 ? "" : "s") + "! Open WALLET to see all activity."; + "transaction" + (notificationCount === 1 ? "" : "s") + ". Open WALLET to see all activity."; ui.notificationDisplayBanner(message); } else { - var currentItemName, senderName; for (i = 0; i < someoneElsePurchasedArray.length; i++) { - currentItemName = (someoneElsePurchasedArray[i].message).match('(.*)')[1]; - message = "Someone purchased your item \"" + currentItemName + "\" from the Marketplace! " + + message = '"' + (someoneElsePurchasedArray[i].message) + '" ' + "Open WALLET to see all activity."; ui.notificationDisplayBanner(message); } for (i = 0; i < proofIssuedArray.length; i++) { - currentItemName = (proofIssuedArray[i].message).match('(.*)')[1]; - message = "You have been issued a proof for your Marketplace item \"" + currentItemName + "\"! " + + message = '"' + (proofIssuedArray[i].message) + '" ' + "Open WALLET to see all activity."; ui.notificationDisplayBanner(message); } for (i = 0; i < moneyReceivedArray.length; i++) { - senderName = moneyReceivedArray[i].sender_name; - if (senderName === "") { - senderName = "Someone"; - } - message = senderName + " sent you " + moneyReceivedArray[i].received_money + " HFC! " + + message = '"' + (moneyReceivedArray[i].message) + '" ' + "Open WALLET to see all activity."; ui.notificationDisplayBanner(message); } for (i = 0; i < giftReceivedArray.length; i++) { - senderName = giftReceivedArray[i].sender_name; - if (senderName === "") { - senderName = "Someone"; - } - message = senderName + " sent you a gift! " + + message = '"' + (giftReceivedArray[i].message) + '" ' + "Open WALLET to see all activity."; ui.notificationDisplayBanner(message); } @@ -602,7 +591,7 @@ function startup() { onClosed: walletClosed, onMessage: fromQml, notificationPollEndpoint: "/api/v1/commerce/history?per_page=10", - notificationPollTimeoutMs: 60000, + notificationPollTimeoutMs: 300000, notificationDataProcessPage: notificationDataProcessPage, notificationPollCallback: notificationPollCallback, notificationPollStopPaginatingConditionMet: isReturnedDataEmpty, diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index 9bd3a9facf..d535884c94 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -1040,15 +1040,15 @@ function notificationPollCallback(updatesArray) { if (updatesArray.length > 0) { var message; if (!ui.notificationInitialCallbackMade) { - message = updatesArray.length + " of your purchased items have updates available! " + + message = updatesArray.length + " of your purchased items have updates available. " + "Open MARKET to update."; ui.notificationDisplayBanner(message); ui.notificationPollCaresAboutSince = true; } else { for (var i = 0; i < updatesArray.length; i++) { - message = "There's an update available for your version of \"" + - updatesArray[i].marketplace_item_name + "\"!" + + message = "Update available for \"" + + updatesArray[i].marketplace_item_name + "\"." + "Open MARKET to update."; ui.notificationDisplayBanner(message); } @@ -1077,7 +1077,7 @@ function startup() { onScreenChanged: onTabletScreenChanged, onMessage: onQmlMessageReceived, notificationPollEndpoint: "/api/v1/commerce/available_updates?per_page=10", - notificationPollTimeoutMs: 60000, + notificationPollTimeoutMs: 300000, notificationDataProcessPage: notificationDataProcessPage, notificationPollCallback: notificationPollCallback, notificationPollStopPaginatingConditionMet: isReturnedDataEmpty, diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 02bf92dcfe..a2ebae1a33 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -846,7 +846,7 @@ function notificationPollCallback(connectionsArray) { if (!ui.isOpen && ui.notificationInitialCallbackMade) { message = user.username + " is available in " + - user.location.root.name + "! Open PEOPLE to join them."; + user.location.root.name + ". Open PEOPLE to join them."; ui.notificationDisplayBanner(message); } }); @@ -870,7 +870,7 @@ function notificationPollCallback(connectionsArray) { if (newOnlineUsers > 0 && !ui.notificationInitialCallbackMade) { message = newOnlineUsers + " of your connections " + - (newOnlineUsers === 1 ? "is" : "are") + " online! Open PEOPLE to join them."; + (newOnlineUsers === 1 ? "is" : "are") + " available online. Open PEOPLE to join them."; ui.notificationDisplayBanner(message); } } diff --git a/scripts/system/tablet-goto.js b/scripts/system/tablet-goto.js index fde558d728..22a9752db8 100644 --- a/scripts/system/tablet-goto.js +++ b/scripts/system/tablet-goto.js @@ -57,15 +57,15 @@ function notificationPollCallback(userStoriesArray) { if (shouldNotifyIndividually) { message = storedAnnouncements[key].username + " says something is happening in " + - storedAnnouncements[key].place_name + "! Open GOTO to join them."; + storedAnnouncements[key].place_name + ". Open GOTO to join them."; ui.notificationDisplayBanner(message); } } else if (story.audience === "for_feed") { storedFeaturedStories[story.id] = story; if (shouldNotifyIndividually) { - message = storedFeaturedStories[key].username + " has invited you to an event in " + - storedFeaturedStories[key].place_name + "! Open GOTO to join them."; + message = storedFeaturedStories[key].username + " invites you to an event in " + + storedFeaturedStories[key].place_name + ". Open GOTO to join them."; ui.notificationDisplayBanner(message); } } @@ -91,8 +91,9 @@ function notificationPollCallback(userStoriesArray) { ui.messagesWaiting(shouldShowDot && !ui.isOpen); if (totalStories > 0 && !ui.isOpen && !ui.notificationInitialCallbackMade) { - message = "You have " + totalStories + "event invitations pending! " + - "Open GOTO to see them."; + message = "There " + (totalStories === 1 ? "is " : "are ") + totalStories + "event" + + (totalStories === 1 ? "" : "s") + " to know about. " + + "Open GOTO to see " + (totalStories === 1 ? "it" : "them") + "."; ui.notificationDisplayBanner(message); } } From 6e051b7431795c06402cee3161c9cd45c3dd6830 Mon Sep 17 00:00:00 2001 From: Roxanne Skelly Date: Thu, 20 Sep 2018 15:55:35 -0700 Subject: [PATCH 17/38] Checkpoint tray notifications * Fix app launch * refactor notifications code * fixup wording --- interface/src/commerce/QmlCommerce.cpp | 6 +- .../resources/tray-menu-notification.png | Bin 319 -> 319 bytes server-console/src/main.js | 2 +- server-console/src/modules/hf-acctinfo.js | 5 +- .../src/modules/hf-notifications.js | 449 +++++++++++------- 5 files changed, 277 insertions(+), 185 deletions(-) diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp index e1f9f63bfb..8a77c078b9 100644 --- a/interface/src/commerce/QmlCommerce.cpp +++ b/interface/src/commerce/QmlCommerce.cpp @@ -49,11 +49,11 @@ QmlCommerce::QmlCommerce() { void QmlCommerce::openSystemApp(const QString& appPath) { - QUrl appUrl = PathUtils::qmlUrl(appPath); - auto tablet = dynamic_cast( DependencyManager::get()->getTablet("com.highfidelity.interface.tablet.system")); - tablet->loadQMLSource(appUrl); + tablet->loadQMLSource(appPath); + + DependencyManager::get()->openTablet(); } diff --git a/server-console/resources/tray-menu-notification.png b/server-console/resources/tray-menu-notification.png index 569ee95d7ed77761062251173dda4a02f2d40e75..0d6e15752ff20fe09ab20ace9cdc5e915af37c42 100644 GIT binary patch delta 150 zcmV;H0BQff0>1)~B!3xnMObuGZ)S9NVRB^vL1b@YWgtmyVP|DhWnpA_ami&o0000{ zNkl1)~B!2;OQb$4nuFf3k00004XF*Lt006O%3;baP00009a7bBm000id z000id0mpBsWB>pF)Ja4^R47v|PCIS_F%W%YEwD(TpaHswD{uiQlAeMFrGbWX(a>># zR5=0#X;UC1Hi<~K;A?EJCr?X8dY 0) { - text = this.data.sender_name + " sent you " + this.data.received_money + " HFC!"; - memo = "memo: \"" + this.data.message + "\" "; - } - else { - return; - } - } - else { - text = this.data.message.replace(/<\/?[^>]+(>|$)/g, ""); - } - message = memo + "Click to open WALLET."; + text = this.data.message.replace(/<\/?[^>]+(>|$)/g, ""); + message = "Click to open WALLET."; url = "hifiapp:hifi/commerce/wallet/Wallet.qml"; break; + case NotificationType.MARKETPLACE: if(typeof(this.data) == "number") { - text = this.data + " of your purchased items have updates available!"; + if (this.data == 1) { + text = this.data + " of your purchased items has an update available."; + } + else { + text = this.data + " of your purchased items have updates available."; + } } else { - text = "There's an update available for your version of " + this.data.base_item_title + "!"; + text = "Update available for " + this.data.base_item_title + "."; } - message = "Click to open MARKETPLACE."; + message = "Click to open MARKET."; url = "hifiapp:hifi/commerce/purchases/Purchases.qml"; break; } @@ -113,11 +126,15 @@ HifiNotification.prototype = { } } -function HifiNotifications(config, callback) { +function HifiNotifications(config, menuNotificationCallback) { this.config = config; - this.callback = callback; + this.menuNotificationCallback = menuNotificationCallback; this.onlineUsers = new Set([]); - this.since = new Date(this.config.get("notifySince", "1970-01-01T00:00:00.000Z")); + this.storiesSince = new Date(this.config.get("storiesNotifySince", "1970-01-01T00:00:00.000Z")); + this.peopleSince = new Date(this.config.get("peopleNotifySince", "1970-01-01T00:00:00.000Z")); + this.walletSince = new Date(this.config.get("walletNotifySince", "1970-01-01T00:00:00.000Z")); + this.marketplaceSince = new Date(this.config.get("marketplaceNotifySince", "1970-01-01T00:00:00.000Z")); + this.enable(this.enabled()); notifier.on('click', function(notifierObject, options) { StartInterface(options.url); @@ -129,35 +146,59 @@ HifiNotifications.prototype = { this.config.set("enableTrayNotifications", enabled); if(enabled) { var _this = this; - this.pollTimer = setInterval(function() { - var acctInfo = new AccountInfo(); - var token = acctInfo.accessToken(METAVERSE_SERVER_URL); - var _since = _this.since; - _this.since = new Date(); - IsInterfaceRunning(function(running) { - if(running) { - return; - } - _this.pollForStories(_since, token); - _this.pollForConnections(_since, token); - _this.pollForEconomicActivity(_since, token); - _this.pollForMarketplaceUpdates(_since, token); - }); + this.storiesPollTimer = setInterval(function() { + var _since = _this.storiesSince; + _this.storiesSince = new Date(); + _this.pollForStories(_since); }, - NOTIFICATION_POLL_TIME_MS); + STORIES_NOTIFICATION_POLL_TIME_MS); + + this.peoplePollTimer = setInterval(function() { + var _since = _this.peopleSince; + _this.peopleSince = new Date(); + _this.pollForConnections(_since); + }, + PEOPLE_NOTIFICATION_POLL_TIME_MS); + + this.walletPollTimer = setInterval(function() { + var _since = _this.walletSince; + _this.walletSince = new Date(); + _this.pollForEconomicActivity(_since); + }, + WALLET_NOTIFICATION_POLL_TIME_MS); + + this.marketplacePollTimer = setInterval(function() { + var _since = _this.marketplaceSince; + _this.marketplaceSince = new Date(); + _this.pollForMarketplaceUpdates(_since); + }, + MARKETPLACE_NOTIFICATION_POLL_TIME_MS); } - else if(this.pollTimer) { - clearInterval(this.pollTimer); + else { + if(this.storiesTimer) { + clearInterval(this.storiesTimer); + } + if(this.peoplePollTimer) { + clearInterval(this.peoplePollTimer); + } + if(this.walletPollTimer) { + clearInterval(this.walletPollTimer); + } + if(this.marketplacePollTimer) { + clearInterval(this.marketplacePollTimer); + } } }, enabled: function() { return this.config.get("enableTrayNotifications", true); }, stopPolling: function() { - this.config.set("notifySince", this.since.toISOString()); - if(this.pollTimer) { - clearInterval(this.pollTimer); - } + this.config.set("storiesNotifySince", this.storiesSince.toISOString()); + this.config.set("peopleNotifySince", this.peopleSince.toISOString()); + this.config.set("walletNotifySince", this.walletSince.toISOString()); + this.config.set("marketplaceNotifySince", this.marketplaceSince.toISOString()); + + this.enable(false); }, _pollToDisableHighlight: function(notifyType, error, data) { if (error || !data.body) { @@ -172,58 +213,81 @@ HifiNotifications.prototype = { } console.log(content); if(!content.total_entries) { - this.callback(notifyType, false); + this.menuNotificationCallback(notifyType, false); } }, - _pollCommon: function(notifyType, error, data, since) { - var maxNotificationItemCount = since.getTime() ? MAX_NOTIFICATION_ITEMS : STARTUP_MAX_NOTIFICATION_ITEMS; - if (error || !data.body) { - console.log("Error: unable to get " + url); - return false; - } - var content = JSON.parse(data.body); - if(!content || content.status != 'success') { - console.log("Error: unable to get " + url); - return false; - } - console.log(content); - if(!content.total_entries) { - return; - } - this.callback(notifyType, true); - if(content.total_entries >= maxNotificationItemCount) { - var notification = new HifiNotification(notifyType, content.total_entries); - notification.show(); - } - else { - var notifyData = [] - switch(notifyType) { - case NotificationType.GOTO: - notifyData = content.user_stories; - break; - case NotificationType.PEOPLE: - notifyData = content.data.users; - break; - case NotificationType.WALLET: - notifyData = content.data.history; - break; - case NotificationType.MARKETPLACE: - notifyData = content.data.updates; - break; - } + _pollCommon: function(notifyType, url, since, finished) { - notifyData.forEach(function(notifyDataEntry) { - var notification = new HifiNotification(notifyType, notifyDataEntry); - notification.show(); - }); - } - }, - pollForStories: function(since, token) { var _this = this; - var _token = token; + IsInterfaceRunning(function(running) { + if(running) { + finished(false); + return; + } + var acctInfo = new AccountInfo(); + var token = acctInfo.accessToken(METAVERSE_SERVER_URL); + if(!token) { + return; + } + request.get({ + uri: url, + 'auth': { + 'bearer': token + } + }, function (error, data) { + + var maxNotificationItemCount = since.getTime() ? MAX_NOTIFICATION_ITEMS : STARTUP_MAX_NOTIFICATION_ITEMS; + if (error || !data.body) { + console.log("Error: unable to get " + url); + finished(false); + return; + } + var content = JSON.parse(data.body); + if(!content || content.status != 'success') { + console.log("Error: unable to get " + url); + finished(false); + return; + } + console.log(content); + if(!content.total_entries) { + finished(true, token); + return; + } + _this.menuNotificationCallback(notifyType, true); + if(content.total_entries >= maxNotificationItemCount) { + var notification = new HifiNotification(notifyType, content.total_entries); + notification.show(); + } + else { + var notifyData = [] + switch(notifyType) { + case NotificationType.GOTO: + notifyData = content.user_stories; + break; + case NotificationType.PEOPLE: + notifyData = content.data.users; + break; + case NotificationType.WALLET: + notifyData = content.data.history; + break; + case NotificationType.MARKETPLACE: + notifyData = content.data.updates; + break; + } + + notifyData.forEach(function(notifyDataEntry) { + var notification = new HifiNotification(notifyType, notifyDataEntry); + notification.show(); + }); + } + finished(true, token); + }); + }); + }, + pollForStories: function(since) { + var _this = this; var actions = 'announcement'; var options = [ - 'now=' + new Date().toISOString(), 'since=' + since.getTime() / 1000, 'include_actions=announcement', 'restriction=open,hifi', @@ -233,81 +297,105 @@ HifiNotifications.prototype = { console.log("Polling for stories"); var url = METAVERSE_SERVER_URL + STORIES_URL + '?' + options.join('&'); console.log(url); - request.get({ - uri: url, - 'auth': { - 'bearer': _token - } - }, function (error, data) { - _this._pollCommon(NotificationType.GOTO, error, data, since); + + _this._pollCommon(NotificationType.STORIES, + url, + since, + function (success, token) { + if(success) { + var options = [ + 'now=' + new Date().toISOString(), + 'include_actions=announcement', + 'restriction=open,hifi', + 'require_online=true', + 'per_page=1' + ]; + var url = METAVERSE_SERVER_URL + STORIES_URL + '?' + options.join('&'); + // call a second time to determine if there are no more stories and we should + // put out the light. + request.get({ + uri: url, + 'auth': { + 'bearer': token + } + }, function(error, data) { + _this._pollToDisableHighlight(NotificationType.GOTO, error, data); + }); + } + }); + }, + pollForConnections: function(since) { + var _this = this; + var _since = since; + IsInterfaceRunning(function(running) { + if(running) { + return; + } var options = [ - 'now=' + new Date().toISOString(), - 'include_actions=announcement', - 'restriction=open,hifi', - 'require_online=true', - 'per_page=1' - ]; - var url = METAVERSE_SERVER_URL + STORIES_URL + '?' + options.join('&'); + 'filter=connections', + 'status=online', + 'page=1', + 'per_page=' + MAX_NOTIFICATION_ITEMS + ]; + console.log("Polling for connections"); + var url = METAVERSE_SERVER_URL + USERS_URL + '?' + options.join('&'); + console.log(url); + var acctInfo = new AccountInfo(); + var token = acctInfo.accessToken(METAVERSE_SERVER_URL); + if(!token) { + return; + } request.get({ uri: url, 'auth': { - 'bearer': _token - } - }, function(error, data) { - _this._pollToDisableHighlight(NotificationType.GOTO, error, data); - }); - }); - }, - pollForConnections: function(since, token) { - var _this = this; - var _since = since; - var options = [ - 'filter=connections', - 'status=online', - 'page=1', - 'per_page=' + MAX_NOTIFICATION_ITEMS - ]; - console.log("Polling for connections"); - var url = METAVERSE_SERVER_URL + USERS_URL + '?' + options.join('&'); - console.log(url); - request.get({ - uri: url, - 'auth': { - 'bearer': token - } - }, function (error, data) { - // Users is a special case as we keep track of online users locally. - var maxNotificationItemCount = since.getTime() ? MAX_NOTIFICATION_ITEMS : STARTUP_MAX_NOTIFICATION_ITEMS; - if (error || !data.body) { - console.log("Error: unable to get " + url); - return false; - } - var content = JSON.parse(data.body); - if(!content || content.status != 'success') { - console.log("Error: unable to get " + url); - return false; - } - console.log(content); - if(!content.total_entries) { - _this.callback(NotificationType.PEOPLE, false); - _this.onlineUsers = new Set([]); - return; - } - - var currentUsers = new Set([]); - content.data.users.forEach(function(user) { - currentUsers.add(user.username); - if(!_this.onlineUsers.has(user.username)) { - _this.callback(NotificationType.PEOPLE, true); - _this.onlineUsers.add(user.username); - var notification = new HifiNotification(NotificationType.PEOPLE, user); - notification.show(); + 'bearer': token } + }, function (error, data) { + // Users is a special case as we keep track of online users locally. + var maxNotificationItemCount = _since.getTime() ? MAX_NOTIFICATION_ITEMS : STARTUP_MAX_NOTIFICATION_ITEMS; + if (error || !data.body) { + console.log("Error: unable to get " + url); + return false; + } + var content = JSON.parse(data.body); + if(!content || content.status != 'success') { + console.log("Error: unable to get " + url); + return false; + } + console.log(content); + if(!content.total_entries) { + _this.menuNotificationCallback(NotificationType.PEOPLE, false); + _this.onlineUsers = new Set([]); + return; + } + + var currentUsers = new Set([]); + var newUsers = new Set([]); + content.data.users.forEach(function(user) { + currentUsers.add(user.username); + if(!_this.onlineUsers.has(user.username)) { + newUsers.add(user); + _this.onlineUsers.add(user.username); + } + }); + _this.onlineUsers = currentUsers; + if(newUsers.size) { + _this.menuNotificationCallback(NotificationType.PEOPLE, true); + } + + if(newUsers.size >= maxNotificationItemCount) { + var notification = new HifiNotification(NotificationType.PEOPLE, newUsers.size); + notification.show(); + return; + } + newUsers.forEach(function(user) { + var notification = new HifiNotification(NotificationType.PEOPLE, user); + notification.show(); + }); }); - _this.onlineUsers = currentUsers; }); }, - pollForEconomicActivity: function(since, token) { + pollForEconomicActivity: function(since) { var _this = this; var options = [ 'since=' + since.getTime() / 1000, @@ -319,16 +407,9 @@ HifiNotifications.prototype = { console.log("Polling for economic activity"); var url = METAVERSE_SERVER_URL + ECONOMIC_ACTIVITY_URL + '?' + options.join('&'); console.log(url); - request.post({ - uri: url, - 'auth': { - 'bearer': token - } - }, function (error, data) { - _this._pollCommon(NotificationType.WALLET, error, data, since); - }); + _this._pollCommon(NotificationType.WALLET, url, since, function () {}); }, - pollForMarketplaceUpdates: function(since, token) { + pollForMarketplaceUpdates: function(since) { var _this = this; var options = [ 'since=' + since.getTime() / 1000, @@ -338,13 +419,21 @@ HifiNotifications.prototype = { console.log("Polling for marketplace update"); var url = METAVERSE_SERVER_URL + UPDATES_URL + '?' + options.join('&'); console.log(url); - request.put({ - uri: url, - 'auth': { - 'bearer': token - } - }, function (error, data) { - _this._pollCommon(NotificationType.MARKETPLACE, error, data, since); + _this._pollCommon(NotificationType.MARKETPLACE, url, since, function (success, token) { + if(success) { + var options = [ + 'page=1', + 'per_page=1' + ]; + request.get({ + uri: url, + 'auth': { + 'bearer': token + } + }, function(error, data) { + _this._pollToDisableHighlight(NotificationType.MARKETPLACE, error, data); + }); + } }); } }; From d5c0c05ab2bfcaa534ef6c22a207e28386041f5d Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 20 Sep 2018 14:27:24 -0700 Subject: [PATCH 18/38] wait for an entity's script to load before adding it to the contain-avatar list. do this so the script doesn't miss the 'enterEntity' entity-method due to not being loaded. --- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 3d782f69a7..4bbc09ff8a 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -512,7 +512,11 @@ bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(QVectorshouldPreloadScript())) { // now check to see if the point contains our entity, this can be expensive if // the entity has a collision hull if (entity->contains(_avatarPosition)) { From f6e57f54b00082d12b9983f4ac914312d6e64d8b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 21 Sep 2018 10:26:31 -0700 Subject: [PATCH 19/38] don't call enterEntity until script preload has finished --- .../src/EntityTreeRenderer.cpp | 8 ++++++- libraries/entities/src/EntityItem.cpp | 23 +++++++++++++++++++ libraries/entities/src/EntityItem.h | 10 ++++---- libraries/script-engine/src/ScriptEngine.cpp | 2 ++ libraries/script-engine/src/ScriptEngine.h | 7 ++++++ 5 files changed, 45 insertions(+), 5 deletions(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 4bbc09ff8a..c78036d5ed 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -187,6 +187,11 @@ void EntityTreeRenderer::resetEntitiesScriptEngine() { connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverLeaveEntity, _entitiesScriptEngine.data(), [&](const EntityItemID& entityID, const PointerEvent& event) { _entitiesScriptEngine->callEntityScriptMethod(entityID, "hoverLeaveEntity", event); }); + + connect(_entitiesScriptEngine.data(), &ScriptEngine::entityScriptPreloadFinished, [&](const EntityItemID& entityID) { + EntityItemPointer entity = getTree()->findEntityByID(entityID); + entity->setScriptHasFinishedPreload(true); + }); } void EntityTreeRenderer::clear() { @@ -516,7 +521,7 @@ bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(QVectorshouldPreloadScript())) { + (hasScript && entity->isScriptPreloadFinished())) { // now check to see if the point contains our entity, this can be expensive if // the entity has a collision hull if (entity->contains(_avatarPosition)) { @@ -976,6 +981,7 @@ void EntityTreeRenderer::checkAndCallPreload(const EntityItemID& entityID, bool entity->scriptHasUnloaded(); } if (shouldLoad) { + entity->setScriptHasFinishedPreload(false); _entitiesScriptEngine->loadEntityScript(entityID, resolveScriptURL(scriptUrl), reload); entity->scriptHasPreloaded(); } diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 8e382fabd4..7a0e61b29a 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -3197,3 +3197,26 @@ void EntityItem::setCloneIDs(const QVector& cloneIDs) { _cloneIDs = cloneIDs; }); } + +bool EntityItem::shouldPreloadScript() const { + return !_script.isEmpty() && ((_loadedScript != _script) || (_loadedScriptTimestamp != _scriptTimestamp)); +} + +void EntityItem::scriptHasPreloaded() { + _loadedScript = _script; + _loadedScriptTimestamp = _scriptTimestamp; +} + +void EntityItem::scriptHasUnloaded() { + _loadedScript = ""; + _loadedScriptTimestamp = 0; + _scriptPreloadFinished = false; +} + +void EntityItem::setScriptHasFinishedPreload(bool value) { + _scriptPreloadFinished = value; +} + +bool EntityItem::isScriptPreloadFinished() { + return _scriptPreloadFinished; +} diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 490f9b9e6b..405b114ab3 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -470,10 +470,11 @@ public: /// We only want to preload if: /// there is some script, and either the script value or the scriptTimestamp /// value have changed since our last preload - bool shouldPreloadScript() const { return !_script.isEmpty() && - ((_loadedScript != _script) || (_loadedScriptTimestamp != _scriptTimestamp)); } - void scriptHasPreloaded() { _loadedScript = _script; _loadedScriptTimestamp = _scriptTimestamp; } - void scriptHasUnloaded() { _loadedScript = ""; _loadedScriptTimestamp = 0; } + bool shouldPreloadScript() const; + void scriptHasPreloaded(); + void scriptHasUnloaded(); + void setScriptHasFinishedPreload(bool value); + bool isScriptPreloadFinished(); bool getClientOnly() const { return _clientOnly; } virtual void setClientOnly(bool clientOnly) { _clientOnly = clientOnly; } @@ -584,6 +585,7 @@ protected: QString _script { ENTITY_ITEM_DEFAULT_SCRIPT }; /// the value of the script property QString _loadedScript; /// the value of _script when the last preload signal was sent quint64 _scriptTimestamp { ENTITY_ITEM_DEFAULT_SCRIPT_TIMESTAMP }; /// the script loaded property used for forced reload + bool _scriptPreloadFinished { false }; QString _serverScripts; /// keep track of time when _serverScripts property was last changed diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index cfd155e14b..4d395070d6 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -2442,6 +2442,8 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co // if we got this far, then call the preload method callEntityScriptMethod(entityID, "preload"); + emit entityScriptPreloadFinished(entityID); + _occupiedScriptURLs.remove(entityScript); processDeferredEntityLoads(entityScript, entityID); } diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 08e2c492e8..17afd3dbbd 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -712,6 +712,13 @@ signals: // script is updated (goes from RUNNING to ERROR_RUNNING_SCRIPT, for example) void entityScriptDetailsUpdated(); + /**jsdoc + * @function Script.entityScriptPreloadFinished + * @returns {Signal} + */ + // Emitted when an entity script has finished running preload + void entityScriptPreloadFinished(const EntityItemID& entityID); + protected: void init(); From 6eb3fa251dbd59420b74a334462023c35961b1d6 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 21 Sep 2018 10:39:41 -0700 Subject: [PATCH 20/38] guard against null deref --- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index c78036d5ed..dbbf8af4b9 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -190,7 +190,9 @@ void EntityTreeRenderer::resetEntitiesScriptEngine() { connect(_entitiesScriptEngine.data(), &ScriptEngine::entityScriptPreloadFinished, [&](const EntityItemID& entityID) { EntityItemPointer entity = getTree()->findEntityByID(entityID); - entity->setScriptHasFinishedPreload(true); + if (entity) { + entity->setScriptHasFinishedPreload(true); + } }); } From 6284074ff96f076f9395fdc02a7e478b577ab29a Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 21 Sep 2018 10:46:49 -0700 Subject: [PATCH 21/38] Don't show banner when app is open but continue updating data --- scripts/modules/appUi.js | 8 +++++--- scripts/system/marketplaces/marketplaces.js | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/scripts/modules/appUi.js b/scripts/modules/appUi.js index 10c3ed023c..78e9ed38f0 100644 --- a/scripts/modules/appUi.js +++ b/scripts/modules/appUi.js @@ -107,7 +107,9 @@ function AppUi(properties) { that.notificationPollCaresAboutSince = false; that.notificationInitialCallbackMade = false; that.notificationDisplayBanner = function (message) { - Window.displayAnnouncement(message); + if (that.isOpen) { + Window.displayAnnouncement(message); + } }; // // END Notification Handling Defaults @@ -155,8 +157,8 @@ function AppUi(properties) { return; } - // User is "appearing offline", or is offline, or the app is open - if (GlobalServices.findableBy === "none" || Account.username === "" || that.isOpen) { + // User is "appearing offline" or is offline + if (GlobalServices.findableBy === "none" || Account.username === "") { that.notificationPollTimeout = Script.setTimeout(that.notificationPoll, that.notificationPollTimeoutMs); return; } diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index d535884c94..3a239aa774 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -909,7 +909,7 @@ var onQmlMessageReceived = function onQmlMessageReceived(message) { break; case 'purchases_availableUpdatesReceived': shouldShowDot = message.numUpdates > 0; - ui.messagesWaiting(shouldShowDot); + ui.messagesWaiting(shouldShowDot && !ui.isOpen); break; case 'purchases_updateWearables': var currentlyWornWearables = []; @@ -1035,7 +1035,7 @@ function notificationDataProcessPage(data) { var shouldShowDot = false; function notificationPollCallback(updatesArray) { shouldShowDot = shouldShowDot || updatesArray.length > 0; - ui.messagesWaiting(shouldShowDot); + ui.messagesWaiting(shouldShowDot && !ui.isOpen); if (updatesArray.length > 0) { var message; From d5baadbefa38e57af918056dd116419a5d84c97a Mon Sep 17 00:00:00 2001 From: Roxanne Skelly Date: Mon, 24 Sep 2018 13:43:55 -0700 Subject: [PATCH 22/38] Modify --url hifiapp: behavior to trigger through appUI when first starting interface. Also, menu names and order follow UX documentation. --- interface/src/Application.cpp | 3 +- interface/src/commerce/QmlCommerce.cpp | 42 ++++++++++++++++++- scripts/modules/appUi.js | 6 +++ server-console/src/main.js | 34 +++++++-------- .../src/modules/hf-notifications.js | 22 +++++----- 5 files changed, 76 insertions(+), 31 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 26c244a9d3..2eb6336e77 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3429,8 +3429,7 @@ void Application::handleSandboxStatus(QNetworkReply* reply) { if (urlIndex != -1) { QUrl url(arguments().value(urlIndex + 1)); if (url.scheme() == URL_SCHEME_HIFIAPP) { - QmlCommerce commerce; - commerce.openSystemApp(url.path()); + Setting::Handle("startUpApp").set(url.path()); } else { addressLookupString = arguments().value(urlIndex + 1); } diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp index 8a77c078b9..f6f5d64f67 100644 --- a/interface/src/commerce/QmlCommerce.cpp +++ b/interface/src/commerce/QmlCommerce.cpp @@ -47,11 +47,49 @@ QmlCommerce::QmlCommerce() { _appsPath = PathUtils::getAppDataPath() + "Apps/"; } -void QmlCommerce::openSystemApp(const QString& appPath) { + + + +void QmlCommerce::openSystemApp(const QString& appName) { + static QMap systemApps { + {"GOTO", "hifi/tablet/TabletAddressDialog.qml"}, + {"PEOPLE", "hifi/Pal.qml"}, + {"WALLET", "hifi/commerce/wallet/Wallet.qml"}, + {"MARKET", "/marketplace.html"} + }; + + static QMap systemInject{ + {"MARKET", "/scripts/system/html/js/marketplacesInject.js"} + }; + auto tablet = dynamic_cast( DependencyManager::get()->getTablet("com.highfidelity.interface.tablet.system")); - tablet->loadQMLSource(appPath); + + QMap::const_iterator appPathIter = systemApps.find(appName); + if (appPathIter != systemApps.end()) { + if (appPathIter->contains(".qml", Qt::CaseInsensitive)) { + tablet->loadQMLSource(*appPathIter); + } + else if (appPathIter->contains(".html", Qt::CaseInsensitive)) { + QMap::const_iterator injectIter = systemInject.find(appName); + if (appPathIter == systemInject.end()) { + tablet->gotoWebScreen(NetworkingConstants::METAVERSE_SERVER_URL().toString() + *appPathIter); + } + else { + QString inject = "file:///" + qApp->applicationDirPath() + *injectIter; + tablet->gotoWebScreen(NetworkingConstants::METAVERSE_SERVER_URL().toString() + *appPathIter, inject); + } + } + else { + qCDebug(commerce) << "Attempted to open unknown type of URL!"; + return; + } + } + else { + qCDebug(commerce) << "Attempted to open unknown APP!"; + return; + } DependencyManager::get()->openTablet(); } diff --git a/scripts/modules/appUi.js b/scripts/modules/appUi.js index dab377911b..0e7461c5f1 100644 --- a/scripts/modules/appUi.js +++ b/scripts/modules/appUi.js @@ -324,5 +324,11 @@ function AppUi(properties) { that.button.clicked.connect(that.onClicked); Script.scriptEnding.connect(that.onScriptEnding); GlobalServices.findableByChanged.connect(availabilityChanged); + if (that.buttonName == Settings.getValue("startUpApp")) { + Settings.setValue("startUpApp", ""); + Script.setTimeout(function () { + that.open(); + }, 1000); + } } module.exports = AppUi; diff --git a/server-console/src/main.js b/server-console/src/main.js index 1a71e9b1d3..16bc74a286 100644 --- a/server-console/src/main.js +++ b/server-console/src/main.js @@ -392,8 +392,8 @@ var labels = { label: 'Version - ' + buildInfo.buildIdentifier, enabled: false }, - enableNotifications: { - label: 'Enable Notifications', + showNotifications: { + label: 'Show Notifications', type: 'checkbox', checked: true, click: function() { @@ -402,9 +402,9 @@ var labels = { } }, goto: { - label: 'Goto', + label: 'GoTo', click: function() { - StartInterface("hifiapp:hifi/tablet/TabletAddressDialog.qml"); + StartInterface("hifiapp:GOTO"); pendingNotifications[HifiNotificationType.GOTO] = false; updateTrayMenu(homeServer ? homeServer.state : ProcessGroupStates.STOPPED); } @@ -412,7 +412,7 @@ var labels = { people: { label: 'People', click: function() { - StartInterface("hifiapp:hifi/Pal.qml"); + StartInterface("hifiapp:PEOPLE"); pendingNotifications[HifiNotificationType.PEOPLE] = false; updateTrayMenu(homeServer ? homeServer.state : ProcessGroupStates.STOPPED); } @@ -420,7 +420,7 @@ var labels = { wallet: { label: 'Wallet', click: function() { - StartInterface("hifiapp:hifi/commerce/wallet/Wallet.qml"); + StartInterface("hifiapp:WALLET"); pendingNotifications[HifiNotificationType.WALLET] = false; updateTrayMenu(homeServer ? homeServer.state : ProcessGroupStates.STOPPED); } @@ -428,7 +428,7 @@ var labels = { marketplace: { label: 'Market', click: function() { - StartInterface("hifiapp:hifi/commerce/purchases/Purchases.qml"); + StartInterface("hifiapp:MARKET"); pendingNotifications[HifiNotificationType.MARKETPLACE] = false; updateTrayMenu(homeServer ? homeServer.state : ProcessGroupStates.STOPPED); } @@ -502,14 +502,6 @@ function buildMenuArray(serverState) { menuArray.push(labels.version); menuArray.push(separator); } - if(isInterfaceInstalled()) { - menuArray.push(labels.enableNotifications); - menuArray.push(labels.goto); - menuArray.push(labels.people); - menuArray.push(labels.wallet); - menuArray.push(labels.marketplace); - menuArray.push(separator); - } if(isServerInstalled() && isInterfaceInstalled()) { menuArray.push(labels.goHome); menuArray.push(separator); @@ -523,10 +515,18 @@ function buildMenuArray(serverState) { } menuArray.push(labels.share); menuArray.push(separator); + if(isInterfaceInstalled()) { + menuArray.push(labels.goto); + menuArray.push(labels.people); + menuArray.push(labels.wallet); + menuArray.push(labels.marketplace); + menuArray.push(separator); + menuArray.push(labels.showNotifications); + menuArray.push(separator); + } menuArray.push(labels.quit); } - return menuArray; } @@ -551,7 +551,7 @@ function updateLabels(serverState) { labels.restart.enabled = false; } - labels.enableNotifications.checked = trayNotifications.enabled(); + labels.showNotifications.checked = trayNotifications.enabled(); labels.people.visible = trayNotifications.enabled(); labels.goto.visible = trayNotifications.enabled(); labels.wallet.visible = trayNotifications.enabled(); diff --git a/server-console/src/modules/hf-notifications.js b/server-console/src/modules/hf-notifications.js index 8fb262e9f0..bfa65f3ae2 100644 --- a/server-console/src/modules/hf-notifications.js +++ b/server-console/src/modules/hf-notifications.js @@ -33,7 +33,7 @@ const NotificationType = { MARKETPLACE: 'marketplace' }; -function HifiNotification(notificationType, notificationData) { +function HifiNotification(notificationType, notificationData, menuNotificationCallback) { this.type = notificationType; this.data = notificationData; } @@ -54,7 +54,7 @@ HifiNotification.prototype = { text = "You have " + this.data + " event invitations pending." } message = "Click to open GOTO."; - url="hifiapp:hifi/tablet/TabletAddressDialog.qml" + url="hifiapp:GOTO" } else { text = this.data.username + " " + this.data.action_string + " in " + this.data.place_name + "."; @@ -72,7 +72,7 @@ HifiNotification.prototype = { text = this.data + " of your connections are online." } message = "Click to open PEOPLE."; - url="hifiapp:hifi/Pal.qml" + url="hifiapp:PEOPLE" } else { text = this.data.username + " is available in " + this.data.location.root.name + "."; @@ -95,7 +95,7 @@ HifiNotification.prototype = { } text = this.data.message.replace(/<\/?[^>]+(>|$)/g, ""); message = "Click to open WALLET."; - url = "hifiapp:hifi/commerce/wallet/Wallet.qml"; + url = "hifiapp:WALLET"; break; case NotificationType.MARKETPLACE: @@ -111,7 +111,7 @@ HifiNotification.prototype = { text = "Update available for " + this.data.base_item_title + "."; } message = "Click to open MARKET."; - url = "hifiapp:hifi/commerce/purchases/Purchases.qml"; + url = "hifiapp:MARKET"; break; } notifier.notify({ @@ -136,8 +136,11 @@ function HifiNotifications(config, menuNotificationCallback) { this.marketplaceSince = new Date(this.config.get("marketplaceNotifySince", "1970-01-01T00:00:00.000Z")); this.enable(this.enabled()); + + var _menuNotificationCallback = menuNotificationCallback; notifier.on('click', function(notifierObject, options) { StartInterface(options.url); + _menuNotificationCallback(options.notificationType, false); }); } @@ -175,8 +178,8 @@ HifiNotifications.prototype = { MARKETPLACE_NOTIFICATION_POLL_TIME_MS); } else { - if(this.storiesTimer) { - clearInterval(this.storiesTimer); + if(this.storiesPollTimer) { + clearInterval(this.storiesPollTimer); } if(this.peoplePollTimer) { clearInterval(this.peoplePollTimer); @@ -205,13 +208,11 @@ HifiNotifications.prototype = { console.log("Error: unable to get " + url); return false; } - console.log(data.body); var content = JSON.parse(data.body); if(!content || content.status != 'success') { console.log("Error: unable to get " + url); return false; } - console.log(content); if(!content.total_entries) { this.menuNotificationCallback(notifyType, false); } @@ -298,7 +299,7 @@ HifiNotifications.prototype = { var url = METAVERSE_SERVER_URL + STORIES_URL + '?' + options.join('&'); console.log(url); - _this._pollCommon(NotificationType.STORIES, + _this._pollCommon(NotificationType.GOTO, url, since, function (success, token) { @@ -425,6 +426,7 @@ HifiNotifications.prototype = { 'page=1', 'per_page=1' ]; + var url = METAVERSE_SERVER_URL + UPDATES_URL + '?' + options.join('&'); request.get({ uri: url, 'auth': { From 16dba169c5d060119374eba7a0600fad4e8023e3 Mon Sep 17 00:00:00 2001 From: Roxanne Skelly Date: Mon, 24 Sep 2018 14:36:54 -0700 Subject: [PATCH 23/38] Tray Notifier code review fixes --- interface/src/Application.cpp | 2 +- interface/src/commerce/QmlCommerce.cpp | 2 +- server-console/src/main.js | 20 +-- .../src/modules/hf-notifications.js | 133 ++++++++---------- 4 files changed, 74 insertions(+), 83 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 2eb6336e77..d3f37cff3a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3431,7 +3431,7 @@ void Application::handleSandboxStatus(QNetworkReply* reply) { if (url.scheme() == URL_SCHEME_HIFIAPP) { Setting::Handle("startUpApp").set(url.path()); } else { - addressLookupString = arguments().value(urlIndex + 1); + addressLookupString = url; } } diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp index f6f5d64f67..7d7f41ad0e 100644 --- a/interface/src/commerce/QmlCommerce.cpp +++ b/interface/src/commerce/QmlCommerce.cpp @@ -401,7 +401,7 @@ bool QmlCommerce::openApp(const QString& itemHref) { // Read from the file to know what .html or .qml document to open QFile appFile(_appsPath + "/" + appHref.fileName()); if (!appFile.open(QIODevice::ReadOnly)) { - qCDebug(commerce) << "Couldn't open local .app.json file:" << _appsPath << "/" << appHref.fileName(); + qCDebug(commerce) << "Couldn't open local .app.json file:" << appFile; return false; } QJsonDocument appFileJsonDocument = QJsonDocument::fromJson(appFile.readAll()); diff --git a/server-console/src/main.js b/server-console/src/main.js index 16bc74a286..b3577e44fe 100644 --- a/server-console/src/main.js +++ b/server-console/src/main.js @@ -155,7 +155,7 @@ function shutdownCallback(idx) { logWindow.close(); } - if(isServerInstalled()) { + if (isServerInstalled()) { if (homeServer) { log.debug("Stoping home server"); homeServer.stop(); @@ -396,14 +396,14 @@ var labels = { label: 'Show Notifications', type: 'checkbox', checked: true, - click: function() { + click: function () { trayNotifications.enable(!trayNotifications.enabled(), notificationCallback); updateTrayMenu(homeServer ? homeServer.state : ProcessGroupStates.STOPPED); } }, goto: { label: 'GoTo', - click: function() { + click: function () { StartInterface("hifiapp:GOTO"); pendingNotifications[HifiNotificationType.GOTO] = false; updateTrayMenu(homeServer ? homeServer.state : ProcessGroupStates.STOPPED); @@ -411,7 +411,7 @@ var labels = { }, people: { label: 'People', - click: function() { + click: function () { StartInterface("hifiapp:PEOPLE"); pendingNotifications[HifiNotificationType.PEOPLE] = false; updateTrayMenu(homeServer ? homeServer.state : ProcessGroupStates.STOPPED); @@ -419,7 +419,7 @@ var labels = { }, wallet: { label: 'Wallet', - click: function() { + click: function () { StartInterface("hifiapp:WALLET"); pendingNotifications[HifiNotificationType.WALLET] = false; updateTrayMenu(homeServer ? homeServer.state : ProcessGroupStates.STOPPED); @@ -427,7 +427,7 @@ var labels = { }, marketplace: { label: 'Market', - click: function() { + click: function () { StartInterface("hifiapp:MARKET"); pendingNotifications[HifiNotificationType.MARKETPLACE] = false; updateTrayMenu(homeServer ? homeServer.state : ProcessGroupStates.STOPPED); @@ -497,16 +497,16 @@ function buildMenuArray(serverState) { if (isShuttingDown) { menuArray.push(labels.shuttingDown); } else { - if(isServerInstalled()) { + if (isServerInstalled()) { menuArray.push(labels.serverState); menuArray.push(labels.version); menuArray.push(separator); } - if(isServerInstalled() && isInterfaceInstalled()) { + if (isServerInstalled() && isInterfaceInstalled()) { menuArray.push(labels.goHome); menuArray.push(separator); } - if(isServerInstalled()) { + if (isServerInstalled()) { menuArray.push(labels.restart); menuArray.push(labels.stopServer); menuArray.push(labels.settings); @@ -515,7 +515,7 @@ function buildMenuArray(serverState) { } menuArray.push(labels.share); menuArray.push(separator); - if(isInterfaceInstalled()) { + if (isInterfaceInstalled()) { menuArray.push(labels.goto); menuArray.push(labels.people); menuArray.push(labels.wallet); diff --git a/server-console/src/modules/hf-notifications.js b/server-console/src/modules/hf-notifications.js index bfa65f3ae2..a9ee2489a9 100644 --- a/server-console/src/modules/hf-notifications.js +++ b/server-console/src/modules/hf-notifications.js @@ -9,10 +9,10 @@ const GetBuildInfo = hfApp.getBuildInfo; const buildInfo = GetBuildInfo(); const notificationIcon = path.join(__dirname, '../../resources/console-notification.png'); -const STORIES_NOTIFICATION_POLL_TIME_MS = 15 * 1000; -const PEOPLE_NOTIFICATION_POLL_TIME_MS = 15 * 1000; -const WALLET_NOTIFICATION_POLL_TIME_MS = 15 * 1000; -const MARKETPLACE_NOTIFICATION_POLL_TIME_MS = 15 * 1000; +const STORIES_NOTIFICATION_POLL_TIME_MS = 15 * 1000; // 120 * 1000; +const PEOPLE_NOTIFICATION_POLL_TIME_MS = 15 * 1000; // 120 * 1000; +const WALLET_NOTIFICATION_POLL_TIME_MS = 15 * 1000; // 600 * 1000; +const MARKETPLACE_NOTIFICATION_POLL_TIME_MS = 15 * 1000; // 600 * 1000; const METAVERSE_SERVER_URL= process.env.HIFI_METAVERSE_URL ? process.env.HIFI_METAVERSE_URL : 'https://metaverse.highfidelity.com' const STORIES_URL= '/api/v1/user_stories'; @@ -39,24 +39,22 @@ function HifiNotification(notificationType, notificationData, menuNotificationCa } HifiNotification.prototype = { - show: function() { + show: function () { var text = ""; var message = ""; var url = null; var app = null; - switch(this.type) { + switch (this.type) { case NotificationType.GOTO: - if(typeof(this.data) == "number") { + if (typeof(this.data) == "number") { if (this.data == 1) { text = "You have " + this.data + " event invitation pending." - } - else { + } else { text = "You have " + this.data + " event invitations pending." } message = "Click to open GOTO."; url="hifiapp:GOTO" - } - else { + } else { text = this.data.username + " " + this.data.action_string + " in " + this.data.place_name + "."; message = "Click to go to " + this.data.place_name + "."; url = "hifi://" + this.data.place_name + this.data.path; @@ -64,17 +62,15 @@ HifiNotification.prototype = { break; case NotificationType.PEOPLE: - if(typeof(this.data) == "number") { + if (typeof(this.data) == "number") { if (this.data == 1) { text = this.data + " of your connections is online." - } - else { + } else { text = this.data + " of your connections are online." } message = "Click to open PEOPLE."; url="hifiapp:PEOPLE" - } - else { + } else { text = this.data.username + " is available in " + this.data.location.root.name + "."; message = "Click to join them."; url="hifi://" + this.data.location.root.name + this.data.location.path; @@ -82,11 +78,10 @@ HifiNotification.prototype = { break; case NotificationType.WALLET: - if(typeof(this.data) == "number") { + if (typeof(this.data) == "number") { if (this.data == 1) { text = "You have " + this.data + " unread Wallet transaction."; - } - else { + } else { text = "You have " + this.data + " unread Wallet transactions."; } message = "Click to open WALLET." @@ -99,15 +94,13 @@ HifiNotification.prototype = { break; case NotificationType.MARKETPLACE: - if(typeof(this.data) == "number") { + if (typeof(this.data) == "number") { if (this.data == 1) { text = this.data + " of your purchased items has an update available."; - } - else { + } else { text = this.data + " of your purchased items have updates available."; } - } - else { + } else { text = "Update available for " + this.data.base_item_title + "."; } message = "Click to open MARKET."; @@ -138,64 +131,63 @@ function HifiNotifications(config, menuNotificationCallback) { this.enable(this.enabled()); var _menuNotificationCallback = menuNotificationCallback; - notifier.on('click', function(notifierObject, options) { + notifier.on('click', function (notifierObject, options) { StartInterface(options.url); _menuNotificationCallback(options.notificationType, false); }); } HifiNotifications.prototype = { - enable: function(enabled) { + enable: function (enabled) { this.config.set("enableTrayNotifications", enabled); - if(enabled) { + if (enabled) { var _this = this; - this.storiesPollTimer = setInterval(function() { + this.storiesPollTimer = setInterval(function () { var _since = _this.storiesSince; _this.storiesSince = new Date(); _this.pollForStories(_since); }, STORIES_NOTIFICATION_POLL_TIME_MS); - this.peoplePollTimer = setInterval(function() { + this.peoplePollTimer = setInterval(function () { var _since = _this.peopleSince; _this.peopleSince = new Date(); _this.pollForConnections(_since); }, PEOPLE_NOTIFICATION_POLL_TIME_MS); - this.walletPollTimer = setInterval(function() { + this.walletPollTimer = setInterval(function () { var _since = _this.walletSince; _this.walletSince = new Date(); _this.pollForEconomicActivity(_since); }, WALLET_NOTIFICATION_POLL_TIME_MS); - this.marketplacePollTimer = setInterval(function() { + this.marketplacePollTimer = setInterval(function () { var _since = _this.marketplaceSince; _this.marketplaceSince = new Date(); _this.pollForMarketplaceUpdates(_since); }, MARKETPLACE_NOTIFICATION_POLL_TIME_MS); - } - else { - if(this.storiesPollTimer) { + } else { + if (this.storiesPollTimer) { clearInterval(this.storiesPollTimer); } - if(this.peoplePollTimer) { + if (this.peoplePollTimer) { clearInterval(this.peoplePollTimer); } - if(this.walletPollTimer) { + if (this.walletPollTimer) { clearInterval(this.walletPollTimer); } - if(this.marketplacePollTimer) { + if (this.marketplacePollTimer) { clearInterval(this.marketplacePollTimer); } } }, - enabled: function() { + enabled: function () { return this.config.get("enableTrayNotifications", true); }, - stopPolling: function() { + stopPolling: function () { this.config.set("storiesNotifySince", this.storiesSince.toISOString()); this.config.set("peopleNotifySince", this.peopleSince.toISOString()); this.config.set("walletNotifySince", this.walletSince.toISOString()); @@ -203,31 +195,31 @@ HifiNotifications.prototype = { this.enable(false); }, - _pollToDisableHighlight: function(notifyType, error, data) { + _pollToDisableHighlight: function (notifyType, error, data) { if (error || !data.body) { console.log("Error: unable to get " + url); return false; } var content = JSON.parse(data.body); - if(!content || content.status != 'success') { + if (!content || content.status != 'success') { console.log("Error: unable to get " + url); return false; } - if(!content.total_entries) { + if (!content.total_entries) { this.menuNotificationCallback(notifyType, false); } }, - _pollCommon: function(notifyType, url, since, finished) { + _pollCommon: function (notifyType, url, since, finished) { var _this = this; - IsInterfaceRunning(function(running) { - if(running) { + IsInterfaceRunning(function (running) { + if (running) { finished(false); return; } var acctInfo = new AccountInfo(); var token = acctInfo.accessToken(METAVERSE_SERVER_URL); - if(!token) { + if (!token) { return; } request.get({ @@ -244,24 +236,23 @@ HifiNotifications.prototype = { return; } var content = JSON.parse(data.body); - if(!content || content.status != 'success') { + if (!content || content.status != 'success') { console.log("Error: unable to get " + url); finished(false); return; } console.log(content); - if(!content.total_entries) { + if (!content.total_entries) { finished(true, token); return; } _this.menuNotificationCallback(notifyType, true); - if(content.total_entries >= maxNotificationItemCount) { + if (content.total_entries >= maxNotificationItemCount) { var notification = new HifiNotification(notifyType, content.total_entries); notification.show(); - } - else { + } else { var notifyData = [] - switch(notifyType) { + switch (notifyType) { case NotificationType.GOTO: notifyData = content.user_stories; break; @@ -276,7 +267,7 @@ HifiNotifications.prototype = { break; } - notifyData.forEach(function(notifyDataEntry) { + notifyData.forEach(function (notifyDataEntry) { var notification = new HifiNotification(notifyType, notifyDataEntry); notification.show(); }); @@ -285,7 +276,7 @@ HifiNotifications.prototype = { }); }); }, - pollForStories: function(since) { + pollForStories: function (since) { var _this = this; var actions = 'announcement'; var options = [ @@ -303,7 +294,7 @@ HifiNotifications.prototype = { url, since, function (success, token) { - if(success) { + if (success) { var options = [ 'now=' + new Date().toISOString(), 'include_actions=announcement', @@ -319,17 +310,17 @@ HifiNotifications.prototype = { 'auth': { 'bearer': token } - }, function(error, data) { + }, function (error, data) { _this._pollToDisableHighlight(NotificationType.GOTO, error, data); }); } }); }, - pollForConnections: function(since) { + pollForConnections: function (since) { var _this = this; var _since = since; - IsInterfaceRunning(function(running) { - if(running) { + IsInterfaceRunning(function (running) { + if (running) { return; } var options = [ @@ -343,7 +334,7 @@ HifiNotifications.prototype = { console.log(url); var acctInfo = new AccountInfo(); var token = acctInfo.accessToken(METAVERSE_SERVER_URL); - if(!token) { + if (!token) { return; } request.get({ @@ -359,12 +350,12 @@ HifiNotifications.prototype = { return false; } var content = JSON.parse(data.body); - if(!content || content.status != 'success') { + if (!content || content.status != 'success') { console.log("Error: unable to get " + url); return false; } console.log(content); - if(!content.total_entries) { + if (!content.total_entries) { _this.menuNotificationCallback(NotificationType.PEOPLE, false); _this.onlineUsers = new Set([]); return; @@ -372,31 +363,31 @@ HifiNotifications.prototype = { var currentUsers = new Set([]); var newUsers = new Set([]); - content.data.users.forEach(function(user) { + content.data.users.forEach(function (user) { currentUsers.add(user.username); - if(!_this.onlineUsers.has(user.username)) { + if (!_this.onlineUsers.has(user.username)) { newUsers.add(user); _this.onlineUsers.add(user.username); } }); _this.onlineUsers = currentUsers; - if(newUsers.size) { + if (newUsers.size) { _this.menuNotificationCallback(NotificationType.PEOPLE, true); } - if(newUsers.size >= maxNotificationItemCount) { + if (newUsers.size >= maxNotificationItemCount) { var notification = new HifiNotification(NotificationType.PEOPLE, newUsers.size); notification.show(); return; } - newUsers.forEach(function(user) { + newUsers.forEach(function (user) { var notification = new HifiNotification(NotificationType.PEOPLE, user); notification.show(); }); }); }); }, - pollForEconomicActivity: function(since) { + pollForEconomicActivity: function (since) { var _this = this; var options = [ 'since=' + since.getTime() / 1000, @@ -410,7 +401,7 @@ HifiNotifications.prototype = { console.log(url); _this._pollCommon(NotificationType.WALLET, url, since, function () {}); }, - pollForMarketplaceUpdates: function(since) { + pollForMarketplaceUpdates: function (since) { var _this = this; var options = [ 'since=' + since.getTime() / 1000, @@ -421,7 +412,7 @@ HifiNotifications.prototype = { var url = METAVERSE_SERVER_URL + UPDATES_URL + '?' + options.join('&'); console.log(url); _this._pollCommon(NotificationType.MARKETPLACE, url, since, function (success, token) { - if(success) { + if (success) { var options = [ 'page=1', 'per_page=1' @@ -432,7 +423,7 @@ HifiNotifications.prototype = { 'auth': { 'bearer': token } - }, function(error, data) { + }, function (error, data) { _this._pollToDisableHighlight(NotificationType.MARKETPLACE, error, data); }); } From a76c3f028d4bff2fd8ce1c0381de7d32169943dc Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 24 Sep 2018 14:46:00 -0700 Subject: [PATCH 24/38] Small bugfixes --- scripts/modules/appUi.js | 3 ++- scripts/system/commerce/wallet.js | 4 +--- scripts/system/marketplaces/marketplaces.js | 11 +++++------ scripts/system/tablet-goto.js | 2 +- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/scripts/modules/appUi.js b/scripts/modules/appUi.js index 78e9ed38f0..db395ea778 100644 --- a/scripts/modules/appUi.js +++ b/scripts/modules/appUi.js @@ -107,7 +107,7 @@ function AppUi(properties) { that.notificationPollCaresAboutSince = false; that.notificationInitialCallbackMade = false; that.notificationDisplayBanner = function (message) { - if (that.isOpen) { + if (!that.isOpen) { Window.displayAnnouncement(message); } }; @@ -120,6 +120,7 @@ function AppUi(properties) { // Set isOpen, wireEventBridge, set buttonActive as appropriate, // and finally call onOpened() or onClosed() IFF defined. that.setCurrentVisibleScreenMetadata(type, url); + if (that.checkIsOpen(type, url)) { that.wireEventBridge(true); if (!that.isOpen) { diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js index 1fce45bb6f..639c8aa0b3 100644 --- a/scripts/system/commerce/wallet.js +++ b/scripts/system/commerce/wallet.js @@ -576,9 +576,7 @@ function isReturnedDataEmpty(data) { return historyArray.length === 0; } -// -// Manage the connection between the button and the window. -// + var BUTTON_NAME = "WALLET"; var WALLET_QML_SOURCE = "hifi/commerce/wallet/Wallet.qml"; var ui; diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index 3a239aa774..27fa929390 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -1040,15 +1040,16 @@ function notificationPollCallback(updatesArray) { if (updatesArray.length > 0) { var message; if (!ui.notificationInitialCallbackMade) { - message = updatesArray.length + " of your purchased items have updates available. " + - "Open MARKET to update."; + message = updatesArray.length + " of your purchased items " + + (updatesArray.length === 1 ? "has an update " : "have updates ") + + "available. Open MARKET to update."; ui.notificationDisplayBanner(message); ui.notificationPollCaresAboutSince = true; } else { for (var i = 0; i < updatesArray.length; i++) { message = "Update available for \"" + - updatesArray[i].marketplace_item_name + "\"." + + updatesArray[i].base_item_title + "\"." + "Open MARKET to update."; ui.notificationDisplayBanner(message); } @@ -1061,9 +1062,7 @@ function isReturnedDataEmpty(data) { return historyArray.length === 0; } -// -// Manage the connection between the button and the window. -// + var BUTTON_NAME = "MARKET"; var MARKETPLACE_URL = METAVERSE_SERVER_URL + "/marketplace"; var MARKETPLACE_URL_INITIAL = MARKETPLACE_URL + "?"; // Append "?" to signal injected script that it's the initial page. diff --git a/scripts/system/tablet-goto.js b/scripts/system/tablet-goto.js index 22a9752db8..0f032ae74d 100644 --- a/scripts/system/tablet-goto.js +++ b/scripts/system/tablet-goto.js @@ -91,7 +91,7 @@ function notificationPollCallback(userStoriesArray) { ui.messagesWaiting(shouldShowDot && !ui.isOpen); if (totalStories > 0 && !ui.isOpen && !ui.notificationInitialCallbackMade) { - message = "There " + (totalStories === 1 ? "is " : "are ") + totalStories + "event" + + message = "There " + (totalStories === 1 ? "is " : "are ") + totalStories + " event" + (totalStories === 1 ? "" : "s") + " to know about. " + "Open GOTO to see " + (totalStories === 1 ? "it" : "them") + "."; ui.notificationDisplayBanner(message); From c1d2f00c9b682b8f7a7a08b637eb610accbe8690 Mon Sep 17 00:00:00 2001 From: Roxanne Skelly Date: Mon, 24 Sep 2018 15:45:38 -0700 Subject: [PATCH 25/38] Fix url.toString() --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d3f37cff3a..2ae5dff573 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3431,7 +3431,7 @@ void Application::handleSandboxStatus(QNetworkReply* reply) { if (url.scheme() == URL_SCHEME_HIFIAPP) { Setting::Handle("startUpApp").set(url.path()); } else { - addressLookupString = url; + addressLookupString = url.toString(); } } From e3943f210d87911f7ae9bb3ed538c320cfd76e85 Mon Sep 17 00:00:00 2001 From: Roxanne Skelly Date: Mon, 24 Sep 2018 16:16:56 -0700 Subject: [PATCH 26/38] Save 'enabled' configuration between restarts --- server-console/src/main.js | 1 + 1 file changed, 1 insertion(+) diff --git a/server-console/src/main.js b/server-console/src/main.js index b3577e44fe..95b5935255 100644 --- a/server-console/src/main.js +++ b/server-console/src/main.js @@ -398,6 +398,7 @@ var labels = { checked: true, click: function () { trayNotifications.enable(!trayNotifications.enabled(), notificationCallback); + userConfig.save(configPath); updateTrayMenu(homeServer ? homeServer.state : ProcessGroupStates.STOPPED); } }, From be304ea97585de71f2217029cc72487b3ec98c13 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 24 Sep 2018 17:32:30 -0700 Subject: [PATCH 27/38] Small bugfixes again --- scripts/modules/appUi.js | 2 +- scripts/system/tablet-goto.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/modules/appUi.js b/scripts/modules/appUi.js index db395ea778..12ba115815 100644 --- a/scripts/modules/appUi.js +++ b/scripts/modules/appUi.js @@ -170,7 +170,7 @@ function AppUi(properties) { var currentTimestamp = new Date().getTime(); var lastPollTimestamp = Settings.getValue(settingsKey, currentTimestamp); if (that.notificationPollCaresAboutSince) { - url = url + "&since=" + lastPollTimestamp; + url = url + "&since=" + lastPollTimestamp/1000; } Settings.setValue(settingsKey, currentTimestamp); diff --git a/scripts/system/tablet-goto.js b/scripts/system/tablet-goto.js index 0f032ae74d..902e1b7fef 100644 --- a/scripts/system/tablet-goto.js +++ b/scripts/system/tablet-goto.js @@ -18,7 +18,8 @@ var AppUi = Script.require('appUi'); function gotoOpened() { - ui.messagesWaiting(false); + shouldShowDot = false; + ui.messagesWaiting(shouldShowDot); } function notificationDataProcessPage(data) { From 1ac2800e181b87ff229ed5d3fe88958ea04b6b69 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Mon, 24 Sep 2018 17:49:52 -0700 Subject: [PATCH 28/38] Fix wallet dot logic --- scripts/system/commerce/wallet.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js index 639c8aa0b3..a9ebe37feb 100644 --- a/scripts/system/commerce/wallet.js +++ b/scripts/system/commerce/wallet.js @@ -488,7 +488,8 @@ function walletOpened() { Controller.mouseMoveEvent.connect(handleMouseMoveEvent); triggerMapping.enable(); triggerPressMapping.enable(); - ui.messagesWaiting(false); + shouldShowDot = false; + ui.messagesWaiting(shouldShowDot); } function walletClosed() { From ac2ad7fc81b2e883f3b4931a8a33717ad6316431 Mon Sep 17 00:00:00 2001 From: Roxanne Skelly Date: Tue, 25 Sep 2018 14:06:09 -0700 Subject: [PATCH 29/38] Fix some coding standard issues found during CR --- server-console/src/modules/hf-acctinfo.js | 28 +++++++++++------------ server-console/src/modules/hf-process.js | 6 ++--- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/server-console/src/modules/hf-acctinfo.js b/server-console/src/modules/hf-acctinfo.js index ba12e6a5ce..828bc781b8 100644 --- a/server-console/src/modules/hf-acctinfo.js +++ b/server-console/src/modules/hf-acctinfo.js @@ -35,8 +35,8 @@ function AccountInfo() { AccountInfo.prototype = { - accessToken: function(metaverseUrl) { - if(this.data && this.data[metaverseUrl] && this.data[metaverseUrl]["accessToken"]) { + accessToken: function (metaverseUrl) { + if (this.data && this.data[metaverseUrl] && this.data[metaverseUrl]["accessToken"]) { return this.data[metaverseUrl]["accessToken"]["token"]; } return null; @@ -49,24 +49,24 @@ AccountInfo.prototype = { this.parseOffset += 4; return result; }, - _parseMap: function() { + _parseMap: function () { var result = {}; var n = this._parseUInt32(); - for(var i = 0; i < n; i++) { + for (var i = 0; i < n; i++) { var key = this._parseQString(); result[key] = this._parseVariant(); } return result; }, - _parseVariant: function() { + _parseVariant: function () { var varType = this._parseUInt32(); var isNull = this.rawData[this.parseOffset++]; - switch(varType) { + switch (varType) { case VariantTypes.USER_TYPE: //user type var userTypeName = this._parseByteArray().toString('ascii').slice(0,-1); - if(userTypeName == "DataServerAccountInfo") { + if (userTypeName == "DataServerAccountInfo") { return this._parseDataServerAccountInfo(); } else { @@ -75,7 +75,7 @@ AccountInfo.prototype = { break; } }, - _parseByteArray: function() { + _parseByteArray: function () { var length = this._parseUInt32(); if (length == 0xffffffff) { return null; @@ -85,17 +85,17 @@ AccountInfo.prototype = { return result; }, - _parseQString: function() { + _parseQString: function () { if (!this.rawData || (this.rawData.length <= this.parseOffset)) { throw "Expected QString"; } // length in bytes; var length = this._parseUInt32(); - if(length == 0xFFFFFFFF) { + if (length == 0xFFFFFFFF) { return null; } - if(this.rawData.length - this.parseOffset < length) { + if (this.rawData.length - this.parseOffset < length) { throw "Insufficient buffer length for QString parsing"; } @@ -106,7 +106,7 @@ AccountInfo.prototype = { this.parseOffset += length; return result; }, - _parseDataServerAccountInfo: function() { + _parseDataServerAccountInfo: function () { return { accessToken: this._parseOAuthAccessToken(), username: this._parseQString(), @@ -120,7 +120,7 @@ AccountInfo.prototype = { } }, - _parseOAuthAccessToken: function() { + _parseOAuthAccessToken: function () { return { token: this._parseQString(), timestampHigh: this._parseUInt32(), @@ -129,7 +129,7 @@ AccountInfo.prototype = { refreshToken: this._parseQString() } }, - _parseUUID: function() { + _parseUUID: function () { this.parseOffset += 16; return null; } diff --git a/server-console/src/modules/hf-process.js b/server-console/src/modules/hf-process.js index 7fbc9a894e..dca97d1eed 100644 --- a/server-console/src/modules/hf-process.js +++ b/server-console/src/modules/hf-process.js @@ -259,12 +259,12 @@ Process.prototype = extend(Process.prototype, { }; return logs; }, - isRunning: function(done) { + isRunning: function (done) { var _command = this.command; if (os.type == 'Windows_NT') { - childProcess.exec('tasklist /FO CSV', function(err, stdout, stderr) { + childProcess.exec('tasklist /FO CSV', function (err, stdout, stderr) { var running = false; - stdout.split("\n").forEach(function(line) { + stdout.split("\n").forEach(function (line) { var exeData = line.split(","); var executable = exeData[0].replace(/\"/g, "").toLowerCase(); if(executable == _command) { From 3deb3bc77177ebbbec766322a8bbe805a42f7488 Mon Sep 17 00:00:00 2001 From: Roxanne Skelly Date: Tue, 25 Sep 2018 14:17:15 -0700 Subject: [PATCH 30/38] Coding standard issue found during CR --- server-console/src/modules/hf-process.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server-console/src/modules/hf-process.js b/server-console/src/modules/hf-process.js index dca97d1eed..cf94ec6b29 100644 --- a/server-console/src/modules/hf-process.js +++ b/server-console/src/modules/hf-process.js @@ -267,7 +267,7 @@ Process.prototype = extend(Process.prototype, { stdout.split("\n").forEach(function (line) { var exeData = line.split(","); var executable = exeData[0].replace(/\"/g, "").toLowerCase(); - if(executable == _command) { + if (executable == _command) { running = true; } }); From 7257a994140f4b7e4d018a4b813c35cb6e4fe45a Mon Sep 17 00:00:00 2001 From: Roxanne Skelly Date: Wed, 26 Sep 2018 10:46:19 -0700 Subject: [PATCH 31/38] Checkpoint sysTray Installer --- cmake/macros/SetPackagingParameters.cmake | 10 +- cmake/templates/CPackProperties.cmake.in | 2 +- cmake/templates/NSIS.template.in | 173 +++++++++++----------- server-console/CMakeLists.txt | 4 +- server-console/src/main.js | 76 +++++----- server-console/src/modules/hf-app.js | 2 +- 6 files changed, 127 insertions(+), 140 deletions(-) diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake index 0f8975e9b5..164d326b20 100644 --- a/cmake/macros/SetPackagingParameters.cmake +++ b/cmake/macros/SetPackagingParameters.cmake @@ -18,7 +18,7 @@ macro(SET_PACKAGING_PARAMETERS) set(BUILD_GLOBAL_SERVICES "DEVELOPMENT") set(USE_STABLE_GLOBAL_SERVICES 0) set(BUILD_NUMBER 0) - set(APP_USER_MODEL_ID "com.highfidelity.sandbox-dev") + set(APP_USER_MODEL_ID "com.highfidelity.console") set_from_env(RELEASE_TYPE RELEASE_TYPE "DEV") set_from_env(RELEASE_NUMBER RELEASE_NUMBER "") @@ -176,15 +176,15 @@ macro(SET_PACKAGING_PARAMETERS) # shortcut names if (PRODUCTION_BUILD) set(INTERFACE_SHORTCUT_NAME "High Fidelity Interface") - set(CONSOLE_SHORTCUT_NAME "Sandbox") - set(APP_USER_MODEL_ID "com.highfidelity.sandbox") + set(CONSOLE_SHORTCUT_NAME "High Fidelity Console") + set(APP_USER_MODEL_ID "com.highfidelity.console") else () set(INTERFACE_SHORTCUT_NAME "High Fidelity Interface - ${BUILD_VERSION_NO_SHA}") - set(CONSOLE_SHORTCUT_NAME "Sandbox - ${BUILD_VERSION_NO_SHA}") + set(CONSOLE_SHORTCUT_NAME "High Fidelity Console - ${BUILD_VERSION_NO_SHA}") endif () set(INTERFACE_HF_SHORTCUT_NAME "${INTERFACE_SHORTCUT_NAME}") - set(CONSOLE_HF_SHORTCUT_NAME "High Fidelity ${CONSOLE_SHORTCUT_NAME}") + set(CONSOLE_HF_SHORTCUT_NAME "${CONSOLE_SHORTCUT_NAME}") set(PRE_SANDBOX_INTERFACE_SHORTCUT_NAME "High Fidelity") set(PRE_SANDBOX_CONSOLE_SHORTCUT_NAME "Server Console") diff --git a/cmake/templates/CPackProperties.cmake.in b/cmake/templates/CPackProperties.cmake.in index 1d7effd18f..0a56181138 100644 --- a/cmake/templates/CPackProperties.cmake.in +++ b/cmake/templates/CPackProperties.cmake.in @@ -13,7 +13,7 @@ set(INTERFACE_DISPLAY_NAME "Interface") set(INTERFACE_SHORTCUT_NAME "@INTERFACE_SHORTCUT_NAME@") set(INTERFACE_HF_SHORTCUT_NAME "@INTERFACE_HF_SHORTCUT_NAME@") set(INTERFACE_WIN_EXEC_NAME "@INTERFACE_EXEC_PREFIX@.exe") -set(CONSOLE_DISPLAY_NAME "Sandbox") +set(CONSOLE_DISPLAY_NAME "Console") set(CONSOLE_INSTALL_SUBDIR "@CONSOLE_INSTALL_DIR@") set(CONSOLE_SHORTCUT_NAME "@CONSOLE_SHORTCUT_NAME@") set(CONSOLE_HF_SHORTCUT_NAME "@CONSOLE_HF_SHORTCUT_NAME@") diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index 7f6884f478..b7564f45e5 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -405,6 +405,14 @@ Var GAClientID Section "-Previous Install Cleanup" ; Remove the resources folder so we don't end up including removed QML files RMDir /r "$INSTDIR\resources" + + ; delete old assignment-client and domain-server so they're no longer present + ; in client only installs. + Delete "$INSTDIR\@DS_EXEC_NAME@" + Delete "$INSTDIR\@AC_EXEC_NAME@" + + ; delete interface so it's not there for server-only installs + Delete "$INSTDIR\@INTERFACE_WIN_EXEC_NAME@" SectionEnd @CPACK_NSIS_INSTALLATION_TYPES@ @@ -532,9 +540,9 @@ SectionEnd Var PostInstallDialog Var DesktopClientCheckbox -Var DesktopServerCheckbox -Var ServerStartupCheckbox -Var LaunchServerNowCheckbox +Var DesktopConsoleCheckbox +Var ConsoleStartupCheckbox +Var LaunchConsoleNowCheckbox Var LaunchClientNowCheckbox Var CleanInstallCheckbox Var CurrentOffset @@ -746,28 +754,8 @@ Function PostInstallOptionsPage !insertmacro SetInstallOption $DesktopClientCheckbox @CLIENT_DESKTOP_SHORTCUT_REG_KEY@ ${BST_CHECKED} ${EndIf} - ${If} @SERVER_COMPONENT_CONDITIONAL@ - ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Create a desktop shortcut for @CONSOLE_HF_SHORTCUT_NAME@" - Pop $DesktopServerCheckbox - IntOp $CurrentOffset $CurrentOffset + 15 - - ; set the checkbox state depending on what is present in the registry - !insertmacro SetInstallOption $DesktopServerCheckbox @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ ${BST_UNCHECKED} - ${EndIf} - - ${If} @SERVER_COMPONENT_CONDITIONAL@ - ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @CONSOLE_HF_SHORTCUT_NAME@ after install" - Pop $LaunchServerNowCheckbox - - ; set the checkbox state depending on what is present in the registry - !insertmacro SetInstallOption $LaunchServerNowCheckbox @SERVER_LAUNCH_NOW_REG_KEY@ ${BST_CHECKED} - ${StrContains} $substringResult "/forceNoLaunchServer" $CMDLINE - ${IfNot} $substringResult == "" - ${NSD_SetState} $LaunchServerNowCheckbox ${BST_UNCHECKED} - ${EndIf} - - IntOp $CurrentOffset $CurrentOffset + 15 - ${EndIf} + ; set the checkbox state depending on what is present in the registry + !insertmacro SetInstallOption $DesktopConsoleCheckbox @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ ${BST_UNCHECKED} ${If} @CLIENT_COMPONENT_CONDITIONAL@ ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @INTERFACE_HF_SHORTCUT_NAME@ after install" @@ -782,28 +770,42 @@ Function PostInstallOptionsPage ${EndIf} ${EndIf} - ${If} @SERVER_COMPONENT_CONDITIONAL@ - ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @CONSOLE_HF_SHORTCUT_NAME@ on startup" - Pop $ServerStartupCheckbox - IntOp $CurrentOffset $CurrentOffset + 15 + ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Create a desktop shortcut for @CONSOLE_HF_SHORTCUT_NAME@" + Pop $DesktopConsoleCheckbox + IntOp $CurrentOffset $CurrentOffset + 15 - ; set the checkbox state depending on what is present in the registry - !insertmacro SetInstallOption $ServerStartupCheckbox @CONSOLE_STARTUP_REG_KEY@ ${BST_CHECKED} + ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @CONSOLE_HF_SHORTCUT_NAME@ after install" + Pop $LaunchConsoleNowCheckbox + + ; set the checkbox state depending on what is present in the registry + !insertmacro SetInstallOption $LaunchConsoleNowCheckbox @SERVER_LAUNCH_NOW_REG_KEY@ ${BST_CHECKED} + ${StrContains} $substringResult "/forceNoLaunchServer" $CMDLINE + ${IfNot} $substringResult == "" + ${NSD_SetState} $LaunchConsoleNowCheckbox ${BST_UNCHECKED} ${EndIf} + IntOp $CurrentOffset $CurrentOffset + 15 + + ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @CONSOLE_HF_SHORTCUT_NAME@ on startup" + Pop $ConsoleStartupCheckbox + IntOp $CurrentOffset $CurrentOffset + 15 + + ; set the checkbox state depending on what is present in the registry + !insertmacro SetInstallOption $ConsoleStartupCheckbox @CONSOLE_STARTUP_REG_KEY@ ${BST_CHECKED} + ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Perform a clean install (Delete older settings and content)" Pop $CleanInstallCheckbox IntOp $CurrentOffset $CurrentOffset + 15 ${If} @PR_BUILD@ == 1 - ; a PR build defaults all install options expect LaunchServerNowCheckbox, LaunchClientNowCheckbox and the settings copy to unchecked + ; a PR build defaults all install options expect LaunchConsoleNowCheckbox, LaunchClientNowCheckbox and the settings copy to unchecked ${If} @CLIENT_COMPONENT_CONDITIONAL@ ${NSD_SetState} $DesktopClientCheckbox ${BST_UNCHECKED} ${EndIf} ${If} @SERVER_COMPONENT_CONDITIONAL@ - ${NSD_SetState} $DesktopServerCheckbox ${BST_UNCHECKED} - ${NSD_SetState} $ServerStartupCheckbox ${BST_UNCHECKED} + ${NSD_SetState} $DesktopConsoleCheckbox ${BST_UNCHECKED} + ${NSD_SetState} $ConsoleStartupCheckbox ${BST_UNCHECKED} ${EndIf} ; push the offset @@ -824,9 +826,9 @@ FunctionEnd !macroend Var DesktopClientState -Var DesktopServerState -Var ServerStartupState -Var LaunchServerNowState +Var DesktopConsoleState +Var ConsoleStartupState +Var LaunchConsoleNowState Var LaunchClientNowState Var CopyFromProductionState Var CleanInstallState @@ -842,11 +844,11 @@ Function ReadInstallTypes StrCpy $Express "1" StrCpy $DesktopClientState ${BST_CHECKED} - StrCpy $ServerStartupState ${BST_CHECKED} - StrCpy $LaunchServerNowState ${BST_CHECKED} + StrCpy $ConsoleStartupState ${BST_CHECKED} + StrCpy $LaunchConsoleNowState ${BST_CHECKED} StrCpy $LaunchClientNowState ${BST_CHECKED} StrCpy $CleanInstallState ${BST_UNCHECKED} - StrCpy $DesktopServerState ${BST_UNCHECKED} + StrCpy $DesktopConsoleState ${BST_UNCHECKED} ${If} @PR_BUILD@ == 1 StrCpy $CopyFromProductionState ${BST_UNCHECKED} @@ -860,28 +862,25 @@ Function ReadInstallTypes FunctionEnd Function ReadPostInstallOptions + + ; check if the user asked for a desktop shortcut to console + ${NSD_GetState} $DesktopConsoleCheckbox $DesktopConsoleState + + ; check if the user asked to have console launched every startup + ${NSD_GetState} $ConsoleStartupCheckbox $ConsoleStartupState + ${If} @CLIENT_COMPONENT_CONDITIONAL@ ; check if the user asked for a desktop shortcut to High Fidelity ${NSD_GetState} $DesktopClientCheckbox $DesktopClientState ${EndIf} - ${If} @SERVER_COMPONENT_CONDITIONAL@ - ; check if the user asked for a desktop shortcut to Sandbox - ${NSD_GetState} $DesktopServerCheckbox $DesktopServerState - - ; check if the user asked to have Sandbox launched every startup - ${NSD_GetState} $ServerStartupCheckbox $ServerStartupState - ${EndIf} - ${If} @PR_BUILD@ == 1 ; check if we need to copy settings/content from production for this PR build ${NSD_GetState} $CopyFromProductionCheckbox $CopyFromProductionState ${EndIf} - ${If} @SERVER_COMPONENT_CONDITIONAL@ - ; check if we need to launch the server post-install - ${NSD_GetState} $LaunchServerNowCheckbox $LaunchServerNowState - ${EndIf} + ; check if we need to launch the console post-install + ${NSD_GetState} $LaunchConsoleNowCheckbox $LaunchConsoleNowState ${If} @CLIENT_COMPONENT_CONDITIONAL@ ; check if we need to launch the client post-install @@ -893,6 +892,17 @@ Function ReadPostInstallOptions FunctionEnd Function HandlePostInstallOptions + + ; check if the user asked for a desktop shortcut to the console + ${If} $DesktopConsoleState == ${BST_CHECKED} + CreateShortCut "$DESKTOP\@CONSOLE_HF_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@" + !insertmacro WriteInstallOption @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ YES + ; Set appUserModelId + ApplicationID::Set "$DESKTOP\@CONSOLE_HF_SHORTCUT_NAME@.lnk" "@APP_USER_MODEL_ID@" + ${Else} + !insertmacro WriteInstallOption @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ NO + ${EndIf} + ${If} @CLIENT_COMPONENT_CONDITIONAL@ ; check if the user asked for a desktop shortcut to High Fidelity ${If} $DesktopClientState == ${BST_CHECKED} @@ -901,38 +911,24 @@ Function HandlePostInstallOptions ${Else} !insertmacro WriteInstallOption @CLIENT_DESKTOP_SHORTCUT_REG_KEY@ NO ${EndIf} - ${EndIf} - ${If} @SERVER_COMPONENT_CONDITIONAL@ - ; check if the user asked for a desktop shortcut to Sandbox - ${If} $DesktopServerState == ${BST_CHECKED} - CreateShortCut "$DESKTOP\@CONSOLE_HF_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@" - !insertmacro WriteInstallOption @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ YES - ; Set appUserModelId - ApplicationID::Set "$DESKTOP\@CONSOLE_HF_SHORTCUT_NAME@.lnk" "@APP_USER_MODEL_ID@" - ${Else} - !insertmacro WriteInstallOption @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ NO - ${EndIf} + ; check if the user asked to have Console launched every startup + ${If} $ConsoleStartupState == ${BST_CHECKED} + ; in case we added a shortcut in the global context, pull that now + SetShellVarContext all + Delete "$SMSTARTUP\@PRE_SANDBOX_CONSOLE_SHORTCUT_NAME@.lnk" + ; make a startup shortcut in this user's current context + SetShellVarContext current + CreateShortCut "$SMSTARTUP\@CONSOLE_HF_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@" - ; check if the user asked to have Sandbox launched every startup - ${If} $ServerStartupState == ${BST_CHECKED} - ; in case we added a shortcut in the global context, pull that now - SetShellVarContext all - Delete "$SMSTARTUP\@PRE_SANDBOX_CONSOLE_SHORTCUT_NAME@.lnk" + ; reset the shell var context back + SetShellVarContext all - ; make a startup shortcut in this user's current context - SetShellVarContext current - CreateShortCut "$SMSTARTUP\@CONSOLE_HF_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@" - - ; reset the shell var context back - SetShellVarContext all - - !insertmacro WriteInstallOption @CONSOLE_STARTUP_REG_KEY@ YES - ${Else} - !insertmacro WriteInstallOption @CONSOLE_STARTUP_REG_KEY@ NO - ${EndIf} + !insertmacro WriteInstallOption @CONSOLE_STARTUP_REG_KEY@ YES + ${Else} + !insertmacro WriteInstallOption @CONSOLE_STARTUP_REG_KEY@ NO ${EndIf} ; check if the user asked for a clean install @@ -982,16 +978,15 @@ Function HandlePostInstallOptions ${EndIf} ${EndIf} - ${If} @SERVER_COMPONENT_CONDITIONAL@ - ${AndIf} $LaunchServerNowState == ${BST_CHECKED} + ${If} $LaunchConsoleNowState == ${BST_CHECKED} !insertmacro WriteInstallOption @SERVER_LAUNCH_NOW_REG_KEY@ YES ; both launches use the explorer trick in case the user has elevated permissions for the installer ${If} $LaunchClientNowState == ${BST_CHECKED} !insertmacro WriteInstallOption @CLIENT_LAUNCH_NOW_REG_KEY@ YES ; create shortcut with ARGUMENTS - CreateShortCut "$TEMP\SandboxShortcut.lnk" "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@" "-- --launchInterface" - Exec '"$WINDIR\explorer.exe" "$TEMP\SandboxShortcut.lnk"' + CreateShortCut "$TEMP\ConsoleShortcut.lnk" "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@" "-- --launchInterface" + Exec '"$WINDIR\explorer.exe" "$TEMP\ConsoleShortcut.lnk"' ${Else} !insertmacro WriteInstallOption @CLIENT_LAUNCH_NOW_REG_KEY@ NO Exec '"$WINDIR\explorer.exe" "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@"' @@ -1164,13 +1159,11 @@ Section "-Core installation" ${EndIf} - ; Conditional handling for server console shortcut - ${If} @SERVER_COMPONENT_CONDITIONAL@ - CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\@CONSOLE_SHORTCUT_NAME@.lnk" \ - "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@" - ; Set appUserModelId - ApplicationID::Set "$SMPROGRAMS\$STARTMENU_FOLDER\@CONSOLE_SHORTCUT_NAME@.lnk" "@APP_USER_MODEL_ID@" - ${EndIf} + ; handling for server console shortcut + CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\@CONSOLE_SHORTCUT_NAME@.lnk" \ + "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@" + ; Set appUserModelId + ApplicationID::Set "$SMPROGRAMS\$STARTMENU_FOLDER\@CONSOLE_SHORTCUT_NAME@.lnk" "@APP_USER_MODEL_ID@" CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\@UNINSTALLER_NAME@" diff --git a/server-console/CMakeLists.txt b/server-console/CMakeLists.txt index 1c6e40c582..bdcefda5d8 100644 --- a/server-console/CMakeLists.txt +++ b/server-console/CMakeLists.txt @@ -19,7 +19,7 @@ set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Server Console") set_target_properties(${TARGET_NAME}-npm-install PROPERTIES FOLDER "hidden/Server Console") # add a dependency from the package target to the server components -add_dependencies(${TARGET_NAME} assignment-client domain-server) +add_dependencies(${TARGET_NAME} assignment-client domain-server interface) # set the packaged console folder depending on platform, so we can copy it if (APPLE) @@ -36,6 +36,7 @@ if (APPLE) PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/${PACKAGED_CONSOLE_FOLDER}" DESTINATION ${CONSOLE_INSTALL_DIR} COMPONENT ${SERVER_COMPONENT} + COMPONENT ${CLIENT_COMPONENT} ) elseif (WIN32) set(CONSOLE_DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/${PACKAGED_CONSOLE_FOLDER}") @@ -44,6 +45,7 @@ elseif (WIN32) DIRECTORY "${CONSOLE_DESTINATION}/" DESTINATION ${CONSOLE_INSTALL_DIR} COMPONENT ${SERVER_COMPONENT} + COMPONENT ${CLIENT_COMPONENT} ) # sign the copied server console executable after install diff --git a/server-console/src/main.js b/server-console/src/main.js index 95b5935255..08692fbd50 100644 --- a/server-console/src/main.js +++ b/server-console/src/main.js @@ -104,12 +104,12 @@ userConfig.load(configPath); const ipcMain = electron.ipcMain; -function isServerInstalled() { - return interfacePath && userConfig.get("serverInstalled", true); +function isInterfaceInstalled() { + return interfacePath; } -function isInterfaceInstalled() { - return dsPath && acPath && userConfig.get("interfaceInstalled", true); +function isServerInstalled() { + return dsPath && acPath; } var isShuttingDown = false; @@ -263,6 +263,10 @@ interfacePath = pathFinder.discoveredPath("Interface", binaryType, buildInfo.rel dsPath = pathFinder.discoveredPath("domain-server", binaryType, buildInfo.releaseType); acPath = pathFinder.discoveredPath("assignment-client", binaryType, buildInfo.releaseType); +console.log("Domain Server Path: " + dsPath); +console.log("Assignment Client Path: " + acPath); +console.log("Interface Path: " + interfacePath); + function binaryMissingMessage(displayName, executableName, required) { var message = "The " + displayName + " executable was not found.\n"; @@ -286,18 +290,6 @@ function binaryMissingMessage(displayName, executableName, required) { return message; } -// if at this point any of the paths are null, we're missing something we wanted to find - -if (!dsPath) { - dialog.showErrorBox("Domain Server Not Found", binaryMissingMessage("domain-server", "domain-server", true)); - app.exit(0); -} - -if (!acPath) { - dialog.showErrorBox("Assignment Client Not Found", binaryMissingMessage("assignment-client", "assignment-client", true)); - app.exit(0); -} - function openFileBrowser(path) { // Add quotes around path path = '"' + path + '"'; @@ -815,33 +807,33 @@ function onContentLoaded() { // Disable splash window for now. // maybeShowSplash(); - if (buildInfo.releaseType == 'PRODUCTION' && !argv.noUpdater) { - - const CHECK_FOR_UPDATES_INTERVAL_SECONDS = 60 * 30; - var hasShownUpdateNotification = false; - const updateChecker = new updater.UpdateChecker(buildInfo, CHECK_FOR_UPDATES_INTERVAL_SECONDS); - updateChecker.on('update-available', function(latestVersion, url) { - if (!hasShownUpdateNotification) { - notifier.notify({ - icon: notificationIcon, - title: 'An update is available!', - message: 'High Fidelity version ' + latestVersion + ' is available', - wait: true, - appID: buildInfo.appUserModelId, - url: url - }); - hasShownUpdateNotification = true; - } - }); - notifier.on('click', function(notifierObject, options) { - log.debug("Got click", options.url); - shell.openExternal(options.url); - }); - } - - deleteOldFiles(logPath, DELETE_LOG_FILES_OLDER_THAN_X_SECONDS, LOG_FILE_REGEX); - if (isServerInstalled()) { + if (buildInfo.releaseType == 'PRODUCTION' && !argv.noUpdater) { + + const CHECK_FOR_UPDATES_INTERVAL_SECONDS = 60 * 30; + var hasShownUpdateNotification = false; + const updateChecker = new updater.UpdateChecker(buildInfo, CHECK_FOR_UPDATES_INTERVAL_SECONDS); + updateChecker.on('update-available', function(latestVersion, url) { + if (!hasShownUpdateNotification) { + notifier.notify({ + icon: notificationIcon, + title: 'An update is available!', + message: 'High Fidelity version ' + latestVersion + ' is available', + wait: true, + appID: buildInfo.appUserModelId, + url: url + }); + hasShownUpdateNotification = true; + } + }); + notifier.on('click', function(notifierObject, options) { + log.debug("Got click", options.url); + shell.openExternal(options.url); + }); + } + + deleteOldFiles(logPath, DELETE_LOG_FILES_OLDER_THAN_X_SECONDS, LOG_FILE_REGEX); + var dsArguments = ['--get-temp-name', '--parent-pid', process.pid]; domainServer = new Process('domain-server', dsPath, dsArguments, logPath); diff --git a/server-console/src/modules/hf-app.js b/server-console/src/modules/hf-app.js index 625715b392..1b1171baef 100644 --- a/server-console/src/modules/hf-app.js +++ b/server-console/src/modules/hf-app.js @@ -34,7 +34,7 @@ exports.getBuildInfo = function() { buildNumber: "0", stableBuild: "0", organization: "High Fidelity - dev", - appUserModelId: "com.highfidelity.sandbox-dev" + appUserModelId: "com.highfidelity.console" }; var buildInfo = DEFAULT_BUILD_INFO; From 6877af04f118edf56562113d60ed28b951603c28 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 26 Sep 2018 14:57:32 -0700 Subject: [PATCH 32/38] Fix GOTO notifs; fix WALLET notifs (pending backend change) --- scripts/system/commerce/wallet.js | 54 ++----------------------------- scripts/system/tablet-goto.js | 8 ++--- 2 files changed, 7 insertions(+), 55 deletions(-) diff --git a/scripts/system/commerce/wallet.js b/scripts/system/commerce/wallet.js index 639c8aa0b3..c0e044c84b 100644 --- a/scripts/system/commerce/wallet.js +++ b/scripts/system/commerce/wallet.js @@ -501,41 +501,8 @@ function notificationDataProcessPage(data) { var shouldShowDot = false; function notificationPollCallback(historyArray) { - var i; - var someoneElsePurchasedArray = []; - var proofIssuedArray = []; - var moneyReceivedArray = []; - var giftReceivedArray = []; - for (i = 0; i < historyArray.length; i++) { - var currentHistoryTxn = historyArray[i]; - - if (currentHistoryTxn.sent_certs <= 0 && - currentHistoryTxn.received_certs <= 0) { - // This is an HFC transfer. - if (currentHistoryTxn.received_money > 0) { - if (currentHistoryTxn.sender_name === "marketplace") { - someoneElsePurchasedArray.push(currentHistoryTxn); - } else { - moneyReceivedArray.push(currentHistoryTxn); - } - } - } else if (currentHistoryTxn.sent_money <= 0 && - currentHistoryTxn.received_money <= 0 && - currentHistoryTxn.received_certs > 0) { - // This is a non-HFC asset transfer. - if (currentHistoryTxn.sender_name === "marketplace") { - proofIssuedArray.push(currentHistoryTxn); - } else { - giftReceivedArray.push(currentHistoryTxn); - } - } - } - if (!ui.isOpen) { - var notificationCount = someoneElsePurchasedArray.length + - proofIssuedArray.length + - moneyReceivedArray.length + - giftReceivedArray.length; + var notificationCount = historyArray.length; shouldShowDot = shouldShowDot || notificationCount > 0; ui.messagesWaiting(shouldShowDot); @@ -546,23 +513,8 @@ function notificationPollCallback(historyArray) { "transaction" + (notificationCount === 1 ? "" : "s") + ". Open WALLET to see all activity."; ui.notificationDisplayBanner(message); } else { - for (i = 0; i < someoneElsePurchasedArray.length; i++) { - message = '"' + (someoneElsePurchasedArray[i].message) + '" ' + - "Open WALLET to see all activity."; - ui.notificationDisplayBanner(message); - } - for (i = 0; i < proofIssuedArray.length; i++) { - message = '"' + (proofIssuedArray[i].message) + '" ' + - "Open WALLET to see all activity."; - ui.notificationDisplayBanner(message); - } - for (i = 0; i < moneyReceivedArray.length; i++) { - message = '"' + (moneyReceivedArray[i].message) + '" ' + - "Open WALLET to see all activity."; - ui.notificationDisplayBanner(message); - } - for (i = 0; i < giftReceivedArray.length; i++) { - message = '"' + (giftReceivedArray[i].message) + '" ' + + for (var i = 0; i < notificationCount; i++) { + message = '"' + (historyArray[i].message) + '" ' + "Open WALLET to see all activity."; ui.notificationDisplayBanner(message); } diff --git a/scripts/system/tablet-goto.js b/scripts/system/tablet-goto.js index 902e1b7fef..6d8ba3a927 100644 --- a/scripts/system/tablet-goto.js +++ b/scripts/system/tablet-goto.js @@ -57,16 +57,16 @@ function notificationPollCallback(userStoriesArray) { storedAnnouncements[story.id] = story; if (shouldNotifyIndividually) { - message = storedAnnouncements[key].username + " says something is happening in " + - storedAnnouncements[key].place_name + ". Open GOTO to join them."; + message = story.username + " says something is happening in " + + story.place_name + ". Open GOTO to join them."; ui.notificationDisplayBanner(message); } } else if (story.audience === "for_feed") { storedFeaturedStories[story.id] = story; if (shouldNotifyIndividually) { - message = storedFeaturedStories[key].username + " invites you to an event in " + - storedFeaturedStories[key].place_name + ". Open GOTO to join them."; + message = story.username + " invites you to an event in " + + story.place_name + ". Open GOTO to join them."; ui.notificationDisplayBanner(message); } } From a8f7ff7d8a24d0734c37aae943862aa75ca55644 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Wed, 26 Sep 2018 18:18:20 -0700 Subject: [PATCH 33/38] Add HRTF reset() --- libraries/audio/src/AudioHRTF.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/libraries/audio/src/AudioHRTF.h b/libraries/audio/src/AudioHRTF.h index 8993842d6e..c50b4dfc0b 100644 --- a/libraries/audio/src/AudioHRTF.h +++ b/libraries/audio/src/AudioHRTF.h @@ -13,6 +13,7 @@ #define hifi_AudioHRTF_h #include +#include static const int HRTF_AZIMUTHS = 72; // 360 / 5-degree steps static const int HRTF_TAPS = 64; // minimum-phase FIR coefficients @@ -56,6 +57,27 @@ public: void setGainAdjustment(float gain) { _gainAdjust = HRTF_GAIN * gain; }; float getGainAdjustment() { return _gainAdjust; } + // clear internal state, but retain settings + void reset() { + // FIR history + memset(_firState, 0, sizeof(_firState)); + + // integer delay history + memset(_delayState, 0, sizeof(_delayState)); + + // biquad history + memset(_bqState, 0, sizeof(_bqState)); + + // parameter history + _azimuthState = 0.0f; + _distanceState = 0.0f; + _gainState = 0.0f; + + // _gainAdjust is retained + + _silentState = false; + } + private: AudioHRTF(const AudioHRTF&) = delete; AudioHRTF& operator=(const AudioHRTF&) = delete; From 9dc0aa5c8d33b8ae7de1a2bb8eb3bd54d813bf2e Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Wed, 26 Sep 2018 18:23:26 -0700 Subject: [PATCH 34/38] HRTF starts in silent state --- libraries/audio/src/AudioHRTF.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/audio/src/AudioHRTF.h b/libraries/audio/src/AudioHRTF.h index c50b4dfc0b..65b28bc5f8 100644 --- a/libraries/audio/src/AudioHRTF.h +++ b/libraries/audio/src/AudioHRTF.h @@ -75,7 +75,7 @@ public: // _gainAdjust is retained - _silentState = false; + _silentState = true; } private: @@ -110,7 +110,7 @@ private: // global and local gain adjustment float _gainAdjust = HRTF_GAIN; - bool _silentState = false; + bool _silentState = true; }; #endif // AudioHRTF_h From 330789471d1b40a72f41f29e195de24eabd811b0 Mon Sep 17 00:00:00 2001 From: Roxanne Skelly Date: Thu, 27 Sep 2018 12:03:37 -0700 Subject: [PATCH 35/38] Fix merge conflict and set proper polling times --- scripts/modules/appUi.js | 28 +++++++++++++------ .../src/modules/hf-notifications.js | 8 +++--- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/scripts/modules/appUi.js b/scripts/modules/appUi.js index 0e7461c5f1..83d99cd42b 100644 --- a/scripts/modules/appUi.js +++ b/scripts/modules/appUi.js @@ -107,7 +107,9 @@ function AppUi(properties) { that.notificationPollCaresAboutSince = false; that.notificationInitialCallbackMade = false; that.notificationDisplayBanner = function (message) { - Window.displayAnnouncement(message); + if (!that.isOpen) { + Window.displayAnnouncement(message); + } }; // // END Notification Handling Defaults @@ -118,6 +120,7 @@ function AppUi(properties) { // Set isOpen, wireEventBridge, set buttonActive as appropriate, // and finally call onOpened() or onClosed() IFF defined. that.setCurrentVisibleScreenMetadata(type, url); + if (that.checkIsOpen(type, url)) { that.wireEventBridge(true); if (!that.isOpen) { @@ -155,17 +158,21 @@ function AppUi(properties) { return; } - // User is "appearing offline" - if (GlobalServices.findableBy === "none") { + // User is "appearing offline" or is offline + if (GlobalServices.findableBy === "none" || Account.username === "") { that.notificationPollTimeout = Script.setTimeout(that.notificationPoll, that.notificationPollTimeoutMs); return; } var url = METAVERSE_BASE + that.notificationPollEndpoint; + var settingsKey = "notifications/" + that.buttonName + "/lastPoll"; + var currentTimestamp = new Date().getTime(); + var lastPollTimestamp = Settings.getValue(settingsKey, currentTimestamp); if (that.notificationPollCaresAboutSince) { - url = url + "&since=" + (new Date().getTime()); + url = url + "&since=" + lastPollTimestamp/1000; } + Settings.setValue(settingsKey, currentTimestamp); console.debug(that.buttonName, 'polling for notifications at endpoint', url); @@ -193,17 +200,18 @@ function AppUi(properties) { } else { concatenatedServerResponse = concatenatedServerResponse.concat(that.notificationDataProcessPage(response)); currentDataPageToRetrieve++; - request({ uri: (url + "&page=" + currentDataPageToRetrieve) }, requestCallback); + request({ json: true, uri: (url + "&page=" + currentDataPageToRetrieve) }, requestCallback); } } - request({ uri: url }, requestCallback); + request({ json: true, uri: url }, requestCallback); }; // This won't do anything if there isn't a notification endpoint set that.notificationPoll(); - function availabilityChanged() { + function restartNotificationPoll() { + that.notificationInitialCallbackMade = false; if (that.notificationPollTimeout) { Script.clearTimeout(that.notificationPollTimeout); that.notificationPollTimeout = false; @@ -303,7 +311,8 @@ function AppUi(properties) { } : that.ignore; that.onScriptEnding = function onScriptEnding() { // Close if necessary, clean up any remaining handlers, and remove the button. - GlobalServices.findableByChanged.disconnect(availabilityChanged); + GlobalServices.myUsernameChanged.disconnect(restartNotificationPoll); + GlobalServices.findableByChanged.disconnect(restartNotificationPoll); if (that.isOpen) { that.close(); } @@ -323,7 +332,8 @@ function AppUi(properties) { that.tablet.screenChanged.connect(that.onScreenChanged); that.button.clicked.connect(that.onClicked); Script.scriptEnding.connect(that.onScriptEnding); - GlobalServices.findableByChanged.connect(availabilityChanged); + GlobalServices.findableByChanged.connect(restartNotificationPoll); + GlobalServices.myUsernameChanged.connect(restartNotificationPoll); if (that.buttonName == Settings.getValue("startUpApp")) { Settings.setValue("startUpApp", ""); Script.setTimeout(function () { diff --git a/server-console/src/modules/hf-notifications.js b/server-console/src/modules/hf-notifications.js index a9ee2489a9..281ca1cb53 100644 --- a/server-console/src/modules/hf-notifications.js +++ b/server-console/src/modules/hf-notifications.js @@ -9,10 +9,10 @@ const GetBuildInfo = hfApp.getBuildInfo; const buildInfo = GetBuildInfo(); const notificationIcon = path.join(__dirname, '../../resources/console-notification.png'); -const STORIES_NOTIFICATION_POLL_TIME_MS = 15 * 1000; // 120 * 1000; -const PEOPLE_NOTIFICATION_POLL_TIME_MS = 15 * 1000; // 120 * 1000; -const WALLET_NOTIFICATION_POLL_TIME_MS = 15 * 1000; // 600 * 1000; -const MARKETPLACE_NOTIFICATION_POLL_TIME_MS = 15 * 1000; // 600 * 1000; +const STORIES_NOTIFICATION_POLL_TIME_MS = 120 * 1000; +const PEOPLE_NOTIFICATION_POLL_TIME_MS = 120 * 1000; +const WALLET_NOTIFICATION_POLL_TIME_MS = 600 * 1000; +const MARKETPLACE_NOTIFICATION_POLL_TIME_MS = 600 * 1000; const METAVERSE_SERVER_URL= process.env.HIFI_METAVERSE_URL ? process.env.HIFI_METAVERSE_URL : 'https://metaverse.highfidelity.com' const STORIES_URL= '/api/v1/user_stories'; From eec565e7f4d6de1500c75f46032332bd074557ce Mon Sep 17 00:00:00 2001 From: Roxanne Skelly Date: Thu, 27 Sep 2018 12:58:33 -0700 Subject: [PATCH 36/38] Revert "Checkpoint sysTray Installer" This reverts commit 7257a994140f4b7e4d018a4b813c35cb6e4fe45a. --- cmake/macros/SetPackagingParameters.cmake | 10 +- cmake/templates/CPackProperties.cmake.in | 2 +- cmake/templates/NSIS.template.in | 173 +++++++++++----------- server-console/CMakeLists.txt | 4 +- server-console/src/main.js | 76 +++++----- server-console/src/modules/hf-app.js | 2 +- 6 files changed, 140 insertions(+), 127 deletions(-) diff --git a/cmake/macros/SetPackagingParameters.cmake b/cmake/macros/SetPackagingParameters.cmake index 164d326b20..0f8975e9b5 100644 --- a/cmake/macros/SetPackagingParameters.cmake +++ b/cmake/macros/SetPackagingParameters.cmake @@ -18,7 +18,7 @@ macro(SET_PACKAGING_PARAMETERS) set(BUILD_GLOBAL_SERVICES "DEVELOPMENT") set(USE_STABLE_GLOBAL_SERVICES 0) set(BUILD_NUMBER 0) - set(APP_USER_MODEL_ID "com.highfidelity.console") + set(APP_USER_MODEL_ID "com.highfidelity.sandbox-dev") set_from_env(RELEASE_TYPE RELEASE_TYPE "DEV") set_from_env(RELEASE_NUMBER RELEASE_NUMBER "") @@ -176,15 +176,15 @@ macro(SET_PACKAGING_PARAMETERS) # shortcut names if (PRODUCTION_BUILD) set(INTERFACE_SHORTCUT_NAME "High Fidelity Interface") - set(CONSOLE_SHORTCUT_NAME "High Fidelity Console") - set(APP_USER_MODEL_ID "com.highfidelity.console") + set(CONSOLE_SHORTCUT_NAME "Sandbox") + set(APP_USER_MODEL_ID "com.highfidelity.sandbox") else () set(INTERFACE_SHORTCUT_NAME "High Fidelity Interface - ${BUILD_VERSION_NO_SHA}") - set(CONSOLE_SHORTCUT_NAME "High Fidelity Console - ${BUILD_VERSION_NO_SHA}") + set(CONSOLE_SHORTCUT_NAME "Sandbox - ${BUILD_VERSION_NO_SHA}") endif () set(INTERFACE_HF_SHORTCUT_NAME "${INTERFACE_SHORTCUT_NAME}") - set(CONSOLE_HF_SHORTCUT_NAME "${CONSOLE_SHORTCUT_NAME}") + set(CONSOLE_HF_SHORTCUT_NAME "High Fidelity ${CONSOLE_SHORTCUT_NAME}") set(PRE_SANDBOX_INTERFACE_SHORTCUT_NAME "High Fidelity") set(PRE_SANDBOX_CONSOLE_SHORTCUT_NAME "Server Console") diff --git a/cmake/templates/CPackProperties.cmake.in b/cmake/templates/CPackProperties.cmake.in index 0a56181138..1d7effd18f 100644 --- a/cmake/templates/CPackProperties.cmake.in +++ b/cmake/templates/CPackProperties.cmake.in @@ -13,7 +13,7 @@ set(INTERFACE_DISPLAY_NAME "Interface") set(INTERFACE_SHORTCUT_NAME "@INTERFACE_SHORTCUT_NAME@") set(INTERFACE_HF_SHORTCUT_NAME "@INTERFACE_HF_SHORTCUT_NAME@") set(INTERFACE_WIN_EXEC_NAME "@INTERFACE_EXEC_PREFIX@.exe") -set(CONSOLE_DISPLAY_NAME "Console") +set(CONSOLE_DISPLAY_NAME "Sandbox") set(CONSOLE_INSTALL_SUBDIR "@CONSOLE_INSTALL_DIR@") set(CONSOLE_SHORTCUT_NAME "@CONSOLE_SHORTCUT_NAME@") set(CONSOLE_HF_SHORTCUT_NAME "@CONSOLE_HF_SHORTCUT_NAME@") diff --git a/cmake/templates/NSIS.template.in b/cmake/templates/NSIS.template.in index b7564f45e5..7f6884f478 100644 --- a/cmake/templates/NSIS.template.in +++ b/cmake/templates/NSIS.template.in @@ -405,14 +405,6 @@ Var GAClientID Section "-Previous Install Cleanup" ; Remove the resources folder so we don't end up including removed QML files RMDir /r "$INSTDIR\resources" - - ; delete old assignment-client and domain-server so they're no longer present - ; in client only installs. - Delete "$INSTDIR\@DS_EXEC_NAME@" - Delete "$INSTDIR\@AC_EXEC_NAME@" - - ; delete interface so it's not there for server-only installs - Delete "$INSTDIR\@INTERFACE_WIN_EXEC_NAME@" SectionEnd @CPACK_NSIS_INSTALLATION_TYPES@ @@ -540,9 +532,9 @@ SectionEnd Var PostInstallDialog Var DesktopClientCheckbox -Var DesktopConsoleCheckbox -Var ConsoleStartupCheckbox -Var LaunchConsoleNowCheckbox +Var DesktopServerCheckbox +Var ServerStartupCheckbox +Var LaunchServerNowCheckbox Var LaunchClientNowCheckbox Var CleanInstallCheckbox Var CurrentOffset @@ -754,8 +746,28 @@ Function PostInstallOptionsPage !insertmacro SetInstallOption $DesktopClientCheckbox @CLIENT_DESKTOP_SHORTCUT_REG_KEY@ ${BST_CHECKED} ${EndIf} - ; set the checkbox state depending on what is present in the registry - !insertmacro SetInstallOption $DesktopConsoleCheckbox @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ ${BST_UNCHECKED} + ${If} @SERVER_COMPONENT_CONDITIONAL@ + ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Create a desktop shortcut for @CONSOLE_HF_SHORTCUT_NAME@" + Pop $DesktopServerCheckbox + IntOp $CurrentOffset $CurrentOffset + 15 + + ; set the checkbox state depending on what is present in the registry + !insertmacro SetInstallOption $DesktopServerCheckbox @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ ${BST_UNCHECKED} + ${EndIf} + + ${If} @SERVER_COMPONENT_CONDITIONAL@ + ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @CONSOLE_HF_SHORTCUT_NAME@ after install" + Pop $LaunchServerNowCheckbox + + ; set the checkbox state depending on what is present in the registry + !insertmacro SetInstallOption $LaunchServerNowCheckbox @SERVER_LAUNCH_NOW_REG_KEY@ ${BST_CHECKED} + ${StrContains} $substringResult "/forceNoLaunchServer" $CMDLINE + ${IfNot} $substringResult == "" + ${NSD_SetState} $LaunchServerNowCheckbox ${BST_UNCHECKED} + ${EndIf} + + IntOp $CurrentOffset $CurrentOffset + 15 + ${EndIf} ${If} @CLIENT_COMPONENT_CONDITIONAL@ ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @INTERFACE_HF_SHORTCUT_NAME@ after install" @@ -770,42 +782,28 @@ Function PostInstallOptionsPage ${EndIf} ${EndIf} - ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Create a desktop shortcut for @CONSOLE_HF_SHORTCUT_NAME@" - Pop $DesktopConsoleCheckbox - IntOp $CurrentOffset $CurrentOffset + 15 + ${If} @SERVER_COMPONENT_CONDITIONAL@ + ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @CONSOLE_HF_SHORTCUT_NAME@ on startup" + Pop $ServerStartupCheckbox + IntOp $CurrentOffset $CurrentOffset + 15 - ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @CONSOLE_HF_SHORTCUT_NAME@ after install" - Pop $LaunchConsoleNowCheckbox - - ; set the checkbox state depending on what is present in the registry - !insertmacro SetInstallOption $LaunchConsoleNowCheckbox @SERVER_LAUNCH_NOW_REG_KEY@ ${BST_CHECKED} - ${StrContains} $substringResult "/forceNoLaunchServer" $CMDLINE - ${IfNot} $substringResult == "" - ${NSD_SetState} $LaunchConsoleNowCheckbox ${BST_UNCHECKED} + ; set the checkbox state depending on what is present in the registry + !insertmacro SetInstallOption $ServerStartupCheckbox @CONSOLE_STARTUP_REG_KEY@ ${BST_CHECKED} ${EndIf} - IntOp $CurrentOffset $CurrentOffset + 15 - - ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Launch @CONSOLE_HF_SHORTCUT_NAME@ on startup" - Pop $ConsoleStartupCheckbox - IntOp $CurrentOffset $CurrentOffset + 15 - - ; set the checkbox state depending on what is present in the registry - !insertmacro SetInstallOption $ConsoleStartupCheckbox @CONSOLE_STARTUP_REG_KEY@ ${BST_CHECKED} - ${NSD_CreateCheckbox} 0 $CurrentOffset$OffsetUnits 100% 10u "&Perform a clean install (Delete older settings and content)" Pop $CleanInstallCheckbox IntOp $CurrentOffset $CurrentOffset + 15 ${If} @PR_BUILD@ == 1 - ; a PR build defaults all install options expect LaunchConsoleNowCheckbox, LaunchClientNowCheckbox and the settings copy to unchecked + ; a PR build defaults all install options expect LaunchServerNowCheckbox, LaunchClientNowCheckbox and the settings copy to unchecked ${If} @CLIENT_COMPONENT_CONDITIONAL@ ${NSD_SetState} $DesktopClientCheckbox ${BST_UNCHECKED} ${EndIf} ${If} @SERVER_COMPONENT_CONDITIONAL@ - ${NSD_SetState} $DesktopConsoleCheckbox ${BST_UNCHECKED} - ${NSD_SetState} $ConsoleStartupCheckbox ${BST_UNCHECKED} + ${NSD_SetState} $DesktopServerCheckbox ${BST_UNCHECKED} + ${NSD_SetState} $ServerStartupCheckbox ${BST_UNCHECKED} ${EndIf} ; push the offset @@ -826,9 +824,9 @@ FunctionEnd !macroend Var DesktopClientState -Var DesktopConsoleState -Var ConsoleStartupState -Var LaunchConsoleNowState +Var DesktopServerState +Var ServerStartupState +Var LaunchServerNowState Var LaunchClientNowState Var CopyFromProductionState Var CleanInstallState @@ -844,11 +842,11 @@ Function ReadInstallTypes StrCpy $Express "1" StrCpy $DesktopClientState ${BST_CHECKED} - StrCpy $ConsoleStartupState ${BST_CHECKED} - StrCpy $LaunchConsoleNowState ${BST_CHECKED} + StrCpy $ServerStartupState ${BST_CHECKED} + StrCpy $LaunchServerNowState ${BST_CHECKED} StrCpy $LaunchClientNowState ${BST_CHECKED} StrCpy $CleanInstallState ${BST_UNCHECKED} - StrCpy $DesktopConsoleState ${BST_UNCHECKED} + StrCpy $DesktopServerState ${BST_UNCHECKED} ${If} @PR_BUILD@ == 1 StrCpy $CopyFromProductionState ${BST_UNCHECKED} @@ -862,25 +860,28 @@ Function ReadInstallTypes FunctionEnd Function ReadPostInstallOptions - - ; check if the user asked for a desktop shortcut to console - ${NSD_GetState} $DesktopConsoleCheckbox $DesktopConsoleState - - ; check if the user asked to have console launched every startup - ${NSD_GetState} $ConsoleStartupCheckbox $ConsoleStartupState - ${If} @CLIENT_COMPONENT_CONDITIONAL@ ; check if the user asked for a desktop shortcut to High Fidelity ${NSD_GetState} $DesktopClientCheckbox $DesktopClientState ${EndIf} + ${If} @SERVER_COMPONENT_CONDITIONAL@ + ; check if the user asked for a desktop shortcut to Sandbox + ${NSD_GetState} $DesktopServerCheckbox $DesktopServerState + + ; check if the user asked to have Sandbox launched every startup + ${NSD_GetState} $ServerStartupCheckbox $ServerStartupState + ${EndIf} + ${If} @PR_BUILD@ == 1 ; check if we need to copy settings/content from production for this PR build ${NSD_GetState} $CopyFromProductionCheckbox $CopyFromProductionState ${EndIf} - ; check if we need to launch the console post-install - ${NSD_GetState} $LaunchConsoleNowCheckbox $LaunchConsoleNowState + ${If} @SERVER_COMPONENT_CONDITIONAL@ + ; check if we need to launch the server post-install + ${NSD_GetState} $LaunchServerNowCheckbox $LaunchServerNowState + ${EndIf} ${If} @CLIENT_COMPONENT_CONDITIONAL@ ; check if we need to launch the client post-install @@ -892,17 +893,6 @@ Function ReadPostInstallOptions FunctionEnd Function HandlePostInstallOptions - - ; check if the user asked for a desktop shortcut to the console - ${If} $DesktopConsoleState == ${BST_CHECKED} - CreateShortCut "$DESKTOP\@CONSOLE_HF_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@" - !insertmacro WriteInstallOption @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ YES - ; Set appUserModelId - ApplicationID::Set "$DESKTOP\@CONSOLE_HF_SHORTCUT_NAME@.lnk" "@APP_USER_MODEL_ID@" - ${Else} - !insertmacro WriteInstallOption @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ NO - ${EndIf} - ${If} @CLIENT_COMPONENT_CONDITIONAL@ ; check if the user asked for a desktop shortcut to High Fidelity ${If} $DesktopClientState == ${BST_CHECKED} @@ -911,24 +901,38 @@ Function HandlePostInstallOptions ${Else} !insertmacro WriteInstallOption @CLIENT_DESKTOP_SHORTCUT_REG_KEY@ NO ${EndIf} + ${EndIf} - ; check if the user asked to have Console launched every startup - ${If} $ConsoleStartupState == ${BST_CHECKED} - ; in case we added a shortcut in the global context, pull that now - SetShellVarContext all - Delete "$SMSTARTUP\@PRE_SANDBOX_CONSOLE_SHORTCUT_NAME@.lnk" + ${If} @SERVER_COMPONENT_CONDITIONAL@ + ; check if the user asked for a desktop shortcut to Sandbox + ${If} $DesktopServerState == ${BST_CHECKED} + CreateShortCut "$DESKTOP\@CONSOLE_HF_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@" + !insertmacro WriteInstallOption @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ YES + ; Set appUserModelId + ApplicationID::Set "$DESKTOP\@CONSOLE_HF_SHORTCUT_NAME@.lnk" "@APP_USER_MODEL_ID@" + ${Else} + !insertmacro WriteInstallOption @CONSOLE_DESKTOP_SHORTCUT_REG_KEY@ NO + ${EndIf} - ; make a startup shortcut in this user's current context - SetShellVarContext current - CreateShortCut "$SMSTARTUP\@CONSOLE_HF_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@" - ; reset the shell var context back - SetShellVarContext all + ; check if the user asked to have Sandbox launched every startup + ${If} $ServerStartupState == ${BST_CHECKED} + ; in case we added a shortcut in the global context, pull that now + SetShellVarContext all + Delete "$SMSTARTUP\@PRE_SANDBOX_CONSOLE_SHORTCUT_NAME@.lnk" - !insertmacro WriteInstallOption @CONSOLE_STARTUP_REG_KEY@ YES - ${Else} - !insertmacro WriteInstallOption @CONSOLE_STARTUP_REG_KEY@ NO + ; make a startup shortcut in this user's current context + SetShellVarContext current + CreateShortCut "$SMSTARTUP\@CONSOLE_HF_SHORTCUT_NAME@.lnk" "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@" + + ; reset the shell var context back + SetShellVarContext all + + !insertmacro WriteInstallOption @CONSOLE_STARTUP_REG_KEY@ YES + ${Else} + !insertmacro WriteInstallOption @CONSOLE_STARTUP_REG_KEY@ NO + ${EndIf} ${EndIf} ; check if the user asked for a clean install @@ -978,15 +982,16 @@ Function HandlePostInstallOptions ${EndIf} ${EndIf} - ${If} $LaunchConsoleNowState == ${BST_CHECKED} + ${If} @SERVER_COMPONENT_CONDITIONAL@ + ${AndIf} $LaunchServerNowState == ${BST_CHECKED} !insertmacro WriteInstallOption @SERVER_LAUNCH_NOW_REG_KEY@ YES ; both launches use the explorer trick in case the user has elevated permissions for the installer ${If} $LaunchClientNowState == ${BST_CHECKED} !insertmacro WriteInstallOption @CLIENT_LAUNCH_NOW_REG_KEY@ YES ; create shortcut with ARGUMENTS - CreateShortCut "$TEMP\ConsoleShortcut.lnk" "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@" "-- --launchInterface" - Exec '"$WINDIR\explorer.exe" "$TEMP\ConsoleShortcut.lnk"' + CreateShortCut "$TEMP\SandboxShortcut.lnk" "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@" "-- --launchInterface" + Exec '"$WINDIR\explorer.exe" "$TEMP\SandboxShortcut.lnk"' ${Else} !insertmacro WriteInstallOption @CLIENT_LAUNCH_NOW_REG_KEY@ NO Exec '"$WINDIR\explorer.exe" "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@"' @@ -1159,11 +1164,13 @@ Section "-Core installation" ${EndIf} - ; handling for server console shortcut - CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\@CONSOLE_SHORTCUT_NAME@.lnk" \ - "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@" - ; Set appUserModelId - ApplicationID::Set "$SMPROGRAMS\$STARTMENU_FOLDER\@CONSOLE_SHORTCUT_NAME@.lnk" "@APP_USER_MODEL_ID@" + ; Conditional handling for server console shortcut + ${If} @SERVER_COMPONENT_CONDITIONAL@ + CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\@CONSOLE_SHORTCUT_NAME@.lnk" \ + "$INSTDIR\@CONSOLE_INSTALL_SUBDIR@\@CONSOLE_WIN_EXEC_NAME@" + ; Set appUserModelId + ApplicationID::Set "$SMPROGRAMS\$STARTMENU_FOLDER\@CONSOLE_SHORTCUT_NAME@.lnk" "@APP_USER_MODEL_ID@" + ${EndIf} CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\@UNINSTALLER_NAME@" diff --git a/server-console/CMakeLists.txt b/server-console/CMakeLists.txt index bdcefda5d8..1c6e40c582 100644 --- a/server-console/CMakeLists.txt +++ b/server-console/CMakeLists.txt @@ -19,7 +19,7 @@ set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Server Console") set_target_properties(${TARGET_NAME}-npm-install PROPERTIES FOLDER "hidden/Server Console") # add a dependency from the package target to the server components -add_dependencies(${TARGET_NAME} assignment-client domain-server interface) +add_dependencies(${TARGET_NAME} assignment-client domain-server) # set the packaged console folder depending on platform, so we can copy it if (APPLE) @@ -36,7 +36,6 @@ if (APPLE) PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/${PACKAGED_CONSOLE_FOLDER}" DESTINATION ${CONSOLE_INSTALL_DIR} COMPONENT ${SERVER_COMPONENT} - COMPONENT ${CLIENT_COMPONENT} ) elseif (WIN32) set(CONSOLE_DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/${PACKAGED_CONSOLE_FOLDER}") @@ -45,7 +44,6 @@ elseif (WIN32) DIRECTORY "${CONSOLE_DESTINATION}/" DESTINATION ${CONSOLE_INSTALL_DIR} COMPONENT ${SERVER_COMPONENT} - COMPONENT ${CLIENT_COMPONENT} ) # sign the copied server console executable after install diff --git a/server-console/src/main.js b/server-console/src/main.js index 08692fbd50..95b5935255 100644 --- a/server-console/src/main.js +++ b/server-console/src/main.js @@ -104,12 +104,12 @@ userConfig.load(configPath); const ipcMain = electron.ipcMain; -function isInterfaceInstalled() { - return interfacePath; +function isServerInstalled() { + return interfacePath && userConfig.get("serverInstalled", true); } -function isServerInstalled() { - return dsPath && acPath; +function isInterfaceInstalled() { + return dsPath && acPath && userConfig.get("interfaceInstalled", true); } var isShuttingDown = false; @@ -263,10 +263,6 @@ interfacePath = pathFinder.discoveredPath("Interface", binaryType, buildInfo.rel dsPath = pathFinder.discoveredPath("domain-server", binaryType, buildInfo.releaseType); acPath = pathFinder.discoveredPath("assignment-client", binaryType, buildInfo.releaseType); -console.log("Domain Server Path: " + dsPath); -console.log("Assignment Client Path: " + acPath); -console.log("Interface Path: " + interfacePath); - function binaryMissingMessage(displayName, executableName, required) { var message = "The " + displayName + " executable was not found.\n"; @@ -290,6 +286,18 @@ function binaryMissingMessage(displayName, executableName, required) { return message; } +// if at this point any of the paths are null, we're missing something we wanted to find + +if (!dsPath) { + dialog.showErrorBox("Domain Server Not Found", binaryMissingMessage("domain-server", "domain-server", true)); + app.exit(0); +} + +if (!acPath) { + dialog.showErrorBox("Assignment Client Not Found", binaryMissingMessage("assignment-client", "assignment-client", true)); + app.exit(0); +} + function openFileBrowser(path) { // Add quotes around path path = '"' + path + '"'; @@ -807,33 +815,33 @@ function onContentLoaded() { // Disable splash window for now. // maybeShowSplash(); + if (buildInfo.releaseType == 'PRODUCTION' && !argv.noUpdater) { + + const CHECK_FOR_UPDATES_INTERVAL_SECONDS = 60 * 30; + var hasShownUpdateNotification = false; + const updateChecker = new updater.UpdateChecker(buildInfo, CHECK_FOR_UPDATES_INTERVAL_SECONDS); + updateChecker.on('update-available', function(latestVersion, url) { + if (!hasShownUpdateNotification) { + notifier.notify({ + icon: notificationIcon, + title: 'An update is available!', + message: 'High Fidelity version ' + latestVersion + ' is available', + wait: true, + appID: buildInfo.appUserModelId, + url: url + }); + hasShownUpdateNotification = true; + } + }); + notifier.on('click', function(notifierObject, options) { + log.debug("Got click", options.url); + shell.openExternal(options.url); + }); + } + + deleteOldFiles(logPath, DELETE_LOG_FILES_OLDER_THAN_X_SECONDS, LOG_FILE_REGEX); + if (isServerInstalled()) { - if (buildInfo.releaseType == 'PRODUCTION' && !argv.noUpdater) { - - const CHECK_FOR_UPDATES_INTERVAL_SECONDS = 60 * 30; - var hasShownUpdateNotification = false; - const updateChecker = new updater.UpdateChecker(buildInfo, CHECK_FOR_UPDATES_INTERVAL_SECONDS); - updateChecker.on('update-available', function(latestVersion, url) { - if (!hasShownUpdateNotification) { - notifier.notify({ - icon: notificationIcon, - title: 'An update is available!', - message: 'High Fidelity version ' + latestVersion + ' is available', - wait: true, - appID: buildInfo.appUserModelId, - url: url - }); - hasShownUpdateNotification = true; - } - }); - notifier.on('click', function(notifierObject, options) { - log.debug("Got click", options.url); - shell.openExternal(options.url); - }); - } - - deleteOldFiles(logPath, DELETE_LOG_FILES_OLDER_THAN_X_SECONDS, LOG_FILE_REGEX); - var dsArguments = ['--get-temp-name', '--parent-pid', process.pid]; domainServer = new Process('domain-server', dsPath, dsArguments, logPath); diff --git a/server-console/src/modules/hf-app.js b/server-console/src/modules/hf-app.js index 1b1171baef..625715b392 100644 --- a/server-console/src/modules/hf-app.js +++ b/server-console/src/modules/hf-app.js @@ -34,7 +34,7 @@ exports.getBuildInfo = function() { buildNumber: "0", stableBuild: "0", organization: "High Fidelity - dev", - appUserModelId: "com.highfidelity.console" + appUserModelId: "com.highfidelity.sandbox-dev" }; var buildInfo = DEFAULT_BUILD_INFO; From f96c7f4db472ca27c5e137497226231a4e12a156 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Thu, 27 Sep 2018 17:05:18 -0700 Subject: [PATCH 37/38] minimal time handshake --- scripts/system/makeUserConnection.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/makeUserConnection.js b/scripts/system/makeUserConnection.js index 5dee36d147..d205d368dd 100644 --- a/scripts/system/makeUserConnection.js +++ b/scripts/system/makeUserConnection.js @@ -32,7 +32,7 @@ var WAITING_INTERVAL = 100; // ms var CONNECTING_INTERVAL = 100; // ms var MAKING_CONNECTION_TIMEOUT = 800; // ms - var CONNECTING_TIME = 1600; // ms + var CONNECTING_TIME = 100; // ms One interval. var PARTICLE_RADIUS = 0.15; // m var PARTICLE_ANGLE_INCREMENT = 360 / 45; // 1hz var HANDSHAKE_SOUND_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/davidkelly/production/audio/4beat_sweep.wav"; From 440e2062f5db2a3a2bb4128a8351f5ca7a73c420 Mon Sep 17 00:00:00 2001 From: Kerry Ivan Kurian Date: Thu, 27 Sep 2018 22:14:02 -0700 Subject: [PATCH 38/38] Fix application uninstall in marketplace item tester --- .../commerce/marketplaceItemTester/MarketplaceItemTester.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml b/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml index 8f391f24c0..c3d87ca2f5 100644 --- a/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml +++ b/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml @@ -131,7 +131,7 @@ Rectangle { print("Marketplace item tester unsupported assetType " + assetType); } }, - "trash": function(){ + "trash": function(resource, assetType){ if ("application" === assetType) { Commerce.uninstallApp(resource); }