From 54c13efe6ae1bcc00cb439782dd893bc4ecb9d59 Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Wed, 20 Jan 2016 14:40:12 -0800 Subject: [PATCH 1/6] add migration for stack manager content --- server-console/package.json | 2 +- server-console/src/main.js | 152 +++++++++++++++++++++-- server-console/src/modules/hf-process.js | 5 +- 3 files changed, 147 insertions(+), 12 deletions(-) diff --git a/server-console/package.json b/server-console/package.json index 3e74186122..44f7b3d05e 100644 --- a/server-console/package.json +++ b/server-console/package.json @@ -27,7 +27,7 @@ "always-tail": "0.2.0", "cheerio": "^0.19.0", "extend": "^3.0.0", - "mkdirp": "^0.5.1", + "fs-extra": "^0.26.4", "node-notifier": "^4.4.0", "os-homedir": "^1.0.1", "request": "2.67.0", diff --git a/server-console/src/main.js b/server-console/src/main.js index e6eba4d605..594f5afddc 100644 --- a/server-console/src/main.js +++ b/server-console/src/main.js @@ -13,7 +13,7 @@ const shell = require('shell'); const os = require('os'); const childProcess = require('child_process'); const path = require('path'); -const fs = require('fs'); +const fs = require('fs-extra'); const Tail = require('always-tail'); const http = require('http'); const unzip = require('unzip'); @@ -72,7 +72,6 @@ const buildInfo = getBuildInfo(); console.log("build info", buildInfo); - function getRootHifiDataDirectory() { var organization = "High Fidelity"; if (buildInfo.releaseType != "PRODUCTION") { @@ -260,12 +259,6 @@ global.domainServer = null; global.acMonitor = null; global.userConfig = userConfig; -const GO_HOME_INDEX = 2; -const SERVER_LABEL_INDEX = 0; -const RESTART_INDEX = 4; -const STOP_INDEX = 5; -const SETTINGS_INDEX = 6; - var LogWindow = function(ac, ds) { this.ac = ac; this.ds = ds; @@ -308,6 +301,132 @@ function goHomeClicked() { } } +function stackManagerBasePath() { + var dataPath = 'High Fidelity/Stack Manager/resources'; + + if (process.platform == "win32") { + return path.resolve(osHomeDir(), 'AppData/Local', dataPath); + } else if (process.platform == "darwin") { + return path.resolve(osHomeDir(), 'Library/Application Support', dataPath); + } else { + return "" + } +} + +function isStackManagerContentPresent() { + var modelsPath = path.resolve(stackManagerBasePath(), 'models.json.gz'); + + try { + var stats = fs.lstatSync(modelsPath); + + if (stats.isFile()) { + console.log("Stack Manager entities file discovered at " + modelsPath) + // we found a content file + return true; + } + } catch (e) { + console.log("Stack Manager entities file not found at " + modelsPath); + } +} + +function promptToMigrateContent() { + var idx = dialog.showMessageBox({ + type: 'question', + buttons: ['Yes', 'No'], + title: 'Migrate Content', + message: 'Are you sure?\n\nThis will stop your home server and replace everything in your home with your content from Stack Manager.' + }); + + if (idx == 0) { + if (homeServer.state != ProcessGroupStates.STOPPED) { + homeServer.on('state-update', function(processGroup) { + if (processGroup.state == ProcessGroupStates.STOPPED) { + performContentMigration(); + } + }); + + homeServer.stop(); + + } else { + performContentMigration(); + } + } +} + +function performContentMigration() { + // check if there is a models file to migrate + var modelsPath = path.resolve(stackManagerBasePath(), 'models.json.gz'); + + try { + var stats = fs.lstatSync(modelsPath); + } catch (e) { + // no entities file + dialog.showMessageBox({ + type: 'info', + buttons: ['OK'], + title: 'Models File Not Found', + message: 'There is no models file at ' + modelsPath + '\n\nStack Manager content migration can not proceed.' + }); + + return; + } + + var copyError = null; + + function showMigrationCompletionDialog(copyError) { + if (!copyError) { + // show message for successful migration + dialog.showMessageBox({ + type: 'info', + buttons: ['OK'], + title: 'Migration Complete', + message: 'Your Stack Manager content has been migrated.\n\nYour home server will now be restarted.' + }); + } else { + // show error message for copy fail + dialog.showMessageBox({ + type: 'info', + buttons: ['OK'], + title: 'Migration Failed', + message: 'There was an error copying your Stack Manager content: ' + copyError + '\n\nPlease try again.' + }); + } + } + + // we have a models file, try and copy it + var newModelsPath = path.resolve(getAssignmentClientResourcesDirectory(), 'entities/models.json.gz') + console.log("Copying Stack Manager entity file from " + modelsPath + " to " + newModelsPath); + + fs.copy(modelsPath, newModelsPath, function(error){ + if (!error) { + // check if there are any assets to copy + var oldAssetsPath = path.resolve(stackManagerBasePath(), 'assets'); + + fs.readdir(oldAssetsPath, function(error, data){ + if (error) { + showMigrationCompletionDialog(error); + } else if (data.length > 0) { + + // assume this means the directory is not empty + // and that we should copy it + var newAssetsPath = path.resolve(getAssignmentClientResourcesDirectory(), 'assets'); + + console.log("Copying Stack Manager assets from " + oldAssetsPath + " to " + newAssetsPath); + + // attempt to copy the assets folder, show correct dialog depending on success/failure + fs.copy(oldAssetsPath, newAssetsPath, showMigrationCompletionDialog); + } else { + showMigrationCompletionDialog(null); + } + }); + } else { + showMigrationCompletionDialog(error); + } + }); + + homeServer.start(); +} + var logWindow = null; function buildMenuArray(serverState) { @@ -372,12 +491,29 @@ function buildMenuArray(serverState) { } ]; + var foundStackManagerContent = isStackManagerContentPresent(); + if (foundStackManagerContent) { + // add a separator and the stack manager content migration option + menuArray.splice(menuArray.length - 1, 0, { + label: 'Migrate Stack Manager Content', + click: function() { promptToMigrateContent(); } + }, { + type: 'separator' + }); + } + updateMenuArray(menuArray, serverState); } return menuArray; } +const GO_HOME_INDEX = 2; +const SERVER_LABEL_INDEX = 0; +const RESTART_INDEX = 4; +const STOP_INDEX = 5; +const SETTINGS_INDEX = 6; + function updateMenuArray(menuArray, serverState) { // update the tray menu state var running = serverState == ProcessGroupStates.STARTED; diff --git a/server-console/src/modules/hf-process.js b/server-console/src/modules/hf-process.js index 5192e44bb6..c7f21ebbe5 100755 --- a/server-console/src/modules/hf-process.js +++ b/server-console/src/modules/hf-process.js @@ -5,8 +5,7 @@ const extend = require('extend'); const util = require('util'); const events = require('events'); const childProcess = require('child_process'); -const fs = require('fs'); -const mkdirp = require('mkdirp'); +const fs = require('fs-extra'); const os = require('os'); const path = require('path'); @@ -133,7 +132,7 @@ Process.prototype = extend(Process.prototype, { var logDirectoryCreated = false; try { - mkdirp.sync(this.logDirectory); + fs.mkdirsSync(this.logDirectory); logDirectoryCreated = true; } catch (e) { if (e.code == 'EEXIST') { From 278ab0fa8f5bb52ffee9bd2f86c83a7a96129f3c Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Wed, 20 Jan 2016 14:54:52 -0800 Subject: [PATCH 2/6] don't make the dialogs synchronous --- server-console/src/main.js | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/server-console/src/main.js b/server-console/src/main.js index 594f5afddc..d360dbd32c 100644 --- a/server-console/src/main.js +++ b/server-console/src/main.js @@ -330,27 +330,27 @@ function isStackManagerContentPresent() { } function promptToMigrateContent() { - var idx = dialog.showMessageBox({ + dialog.showMessageBox({ type: 'question', buttons: ['Yes', 'No'], title: 'Migrate Content', message: 'Are you sure?\n\nThis will stop your home server and replace everything in your home with your content from Stack Manager.' - }); + }, function(index) { + if (index == 0) { + if (homeServer.state != ProcessGroupStates.STOPPED) { + homeServer.on('state-update', function(processGroup) { + if (processGroup.state == ProcessGroupStates.STOPPED) { + performContentMigration(); + } + }); - if (idx == 0) { - if (homeServer.state != ProcessGroupStates.STOPPED) { - homeServer.on('state-update', function(processGroup) { - if (processGroup.state == ProcessGroupStates.STOPPED) { - performContentMigration(); - } - }); + homeServer.stop(); - homeServer.stop(); - - } else { - performContentMigration(); + } else { + performContentMigration(); + } } - } + }); } function performContentMigration() { @@ -366,7 +366,7 @@ function performContentMigration() { buttons: ['OK'], title: 'Models File Not Found', message: 'There is no models file at ' + modelsPath + '\n\nStack Manager content migration can not proceed.' - }); + }, null); return; } @@ -381,7 +381,7 @@ function performContentMigration() { buttons: ['OK'], title: 'Migration Complete', message: 'Your Stack Manager content has been migrated.\n\nYour home server will now be restarted.' - }); + }, null); } else { // show error message for copy fail dialog.showMessageBox({ @@ -389,7 +389,7 @@ function performContentMigration() { buttons: ['OK'], title: 'Migration Failed', message: 'There was an error copying your Stack Manager content: ' + copyError + '\n\nPlease try again.' - }); + }, null); } } From 430d1351db214a7ee22624f24a9a8f8f5f6be9ad Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Wed, 20 Jan 2016 14:58:15 -0800 Subject: [PATCH 3/6] preserve timestamps for assets copy --- server-console/src/main.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/server-console/src/main.js b/server-console/src/main.js index d360dbd32c..28a69527a1 100644 --- a/server-console/src/main.js +++ b/server-console/src/main.js @@ -414,7 +414,9 @@ function performContentMigration() { console.log("Copying Stack Manager assets from " + oldAssetsPath + " to " + newAssetsPath); // attempt to copy the assets folder, show correct dialog depending on success/failure - fs.copy(oldAssetsPath, newAssetsPath, showMigrationCompletionDialog); + fs.copy(oldAssetsPath, newAssetsPath, { + preserveTimestamps: true + }, showMigrationCompletionDialog); } else { showMigrationCompletionDialog(null); } From 6ec55dc74602f9ac21b82c3c0ddc09ba807ff768 Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Wed, 20 Jan 2016 15:06:46 -0800 Subject: [PATCH 4/6] only wait for state change for migration once --- server-console/src/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server-console/src/main.js b/server-console/src/main.js index 28a69527a1..52c56df5e3 100644 --- a/server-console/src/main.js +++ b/server-console/src/main.js @@ -338,7 +338,7 @@ function promptToMigrateContent() { }, function(index) { if (index == 0) { if (homeServer.state != ProcessGroupStates.STOPPED) { - homeServer.on('state-update', function(processGroup) { + homeServer.once('state-update', function(processGroup) { if (processGroup.state == ProcessGroupStates.STOPPED) { performContentMigration(); } From d08a64a4d608ac7d37b10da7e54bdc257238c45b Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Wed, 20 Jan 2016 15:25:58 -0800 Subject: [PATCH 5/6] use a big try-catch for migration block --- server-console/src/main.js | 55 +++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/server-console/src/main.js b/server-console/src/main.js index 52c56df5e3..e13d99b455 100644 --- a/server-console/src/main.js +++ b/server-console/src/main.js @@ -338,11 +338,17 @@ function promptToMigrateContent() { }, function(index) { if (index == 0) { if (homeServer.state != ProcessGroupStates.STOPPED) { - homeServer.once('state-update', function(processGroup) { - if (processGroup.state == ProcessGroupStates.STOPPED) { + var stopThenMigrateCallback = function(processGroup) { + if (isShuttingDown) { + homeServer.removeListener('state-update', stopThenMigrateCallback); + } else if (processGroup.state == ProcessGroupStates.STOPPED) { performContentMigration(); + + homeServer.removeListener('state-update', stopThenMigrateCallback); } - }); + }; + + homeServer.on('state-update', stopThenMigrateCallback); homeServer.stop(); @@ -397,34 +403,33 @@ function performContentMigration() { var newModelsPath = path.resolve(getAssignmentClientResourcesDirectory(), 'entities/models.json.gz') console.log("Copying Stack Manager entity file from " + modelsPath + " to " + newModelsPath); - fs.copy(modelsPath, newModelsPath, function(error){ - if (!error) { - // check if there are any assets to copy - var oldAssetsPath = path.resolve(stackManagerBasePath(), 'assets'); + var entitiesCopied = false; - fs.readdir(oldAssetsPath, function(error, data){ - if (error) { - showMigrationCompletionDialog(error); - } else if (data.length > 0) { + try { + fs.copySync(modelsPath, newModelsPath); - // assume this means the directory is not empty - // and that we should copy it - var newAssetsPath = path.resolve(getAssignmentClientResourcesDirectory(), 'assets'); + // check if there are any assets to copy + var oldAssetsPath = path.resolve(stackManagerBasePath(), 'assets'); - console.log("Copying Stack Manager assets from " + oldAssetsPath + " to " + newAssetsPath); + var assets = fs.readdirSync(oldAssetsPath); - // attempt to copy the assets folder, show correct dialog depending on success/failure - fs.copy(oldAssetsPath, newAssetsPath, { - preserveTimestamps: true - }, showMigrationCompletionDialog); - } else { - showMigrationCompletionDialog(null); - } + if (assets.length > 0) { + // assume this means the directory is not empty + // and that we should copy it + var newAssetsPath = path.resolve(getAssignmentClientResourcesDirectory(), 'assets'); + + console.log("Copying Stack Manager assets from " + oldAssetsPath + " to " + newAssetsPath); + + // attempt to copy the assets folder, show correct dialog depending on success/failure + fs.copySync(oldAssetsPath, newAssetsPath, { + preserveTimestamps: true }); - } else { - showMigrationCompletionDialog(error); } - }); + + showMigrationCompletionDialog(null); + } catch (error) { + showMigrationCompletionDialog(error); + } homeServer.start(); } From f872dfac0420a6acc09a2fde5eb7bbf5693940ed Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Wed, 20 Jan 2016 15:31:23 -0800 Subject: [PATCH 6/6] remove some unused variables --- server-console/src/main.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/server-console/src/main.js b/server-console/src/main.js index e13d99b455..a32e9328ff 100644 --- a/server-console/src/main.js +++ b/server-console/src/main.js @@ -349,7 +349,6 @@ function promptToMigrateContent() { }; homeServer.on('state-update', stopThenMigrateCallback); - homeServer.stop(); } else { @@ -377,8 +376,6 @@ function performContentMigration() { return; } - var copyError = null; - function showMigrationCompletionDialog(copyError) { if (!copyError) { // show message for successful migration @@ -403,8 +400,6 @@ function performContentMigration() { var newModelsPath = path.resolve(getAssignmentClientResourcesDirectory(), 'entities/models.json.gz') console.log("Copying Stack Manager entity file from " + modelsPath + " to " + newModelsPath); - var entitiesCopied = false; - try { fs.copySync(modelsPath, newModelsPath); @@ -420,7 +415,7 @@ function performContentMigration() { console.log("Copying Stack Manager assets from " + oldAssetsPath + " to " + newAssetsPath); - // attempt to copy the assets folder, show correct dialog depending on success/failure + // attempt to copy the assets folder fs.copySync(oldAssetsPath, newAssetsPath, { preserveTimestamps: true });