diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000..c16c082c --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,232 @@ +var OFF = 0, WARN = 1, ERROR = 2; + +module.exports = exports = { + "env": { + "es6": true, + "node": true, + "browser": true + }, + + "extends": "eslint:recommended", + + // "ecmaFeatures": { + // // env=es6 doesn't include modules, which we are using + // "modules": true + // }, + // + + "rules": { + "no-console": "off" + }, + + "globals": { + "W": "writable", + "node": "writable", + "J": "writable", + "JSUS": "writable" + } + + // + // "rules": { + // // Possible Errors (overrides from recommended set) + // "no-extra-parens": ERROR, + // "no-unexpected-multiline": ERROR, + // // All JSDoc comments must be valid + // "valid-jsdoc": [ ERROR, { + // "requireReturn": false, + // "requireReturnDescription": false, + // "requireParamDescription": true, + // "prefer": { + // "return": "returns" + // } + // }], + // + // // Best Practices + // + // // Allowed a getter without setter, but all setters require getters + // "accessor-pairs": [ ERROR, { + // "getWithoutSet": false, + // "setWithoutGet": true + // }], + // "block-scoped-var": WARN, + // "consistent-return": ERROR, + // "curly": ERROR, + // "default-case": WARN, + // // the dot goes with the property when doing multiline + // "dot-location": [ WARN, "property" ], + // "dot-notation": WARN, + // "eqeqeq": [ ERROR, "smart" ], + // "guard-for-in": WARN, + // "no-alert": ERROR, + // "no-caller": ERROR, + // "no-case-declarations": WARN, + // "no-div-regex": WARN, + // "no-else-return": WARN, + // "no-empty-label": WARN, + // "no-empty-pattern": WARN, + // "no-eq-null": WARN, + // "no-eval": ERROR, + // "no-extend-native": ERROR, + // "no-extra-bind": WARN, + // "no-floating-decimal": WARN, + // "no-implicit-coercion": [ WARN, { + // "boolean": true, + // "number": true, + // "string": true + // }], + // "no-implied-eval": ERROR, + // "no-invalid-this": ERROR, + // "no-iterator": ERROR, + // "no-labels": WARN, + // "no-lone-blocks": WARN, + // "no-loop-func": ERROR, + // "no-magic-numbers": WARN, + // "no-multi-spaces": ERROR, + // "no-multi-str": WARN, + // "no-native-reassign": ERROR, + // "no-new-func": ERROR, + // "no-new-wrappers": ERROR, + // "no-new": ERROR, + // "no-octal-escape": ERROR, + // "no-param-reassign": ERROR, + // "no-process-env": WARN, + // "no-proto": ERROR, + // "no-redeclare": ERROR, + // "no-return-assign": ERROR, + // "no-script-url": ERROR, + // "no-self-compare": ERROR, + // "no-throw-literal": ERROR, + // "no-unused-expressions": ERROR, + // "no-useless-call": ERROR, + // "no-useless-concat": ERROR, + // "no-void": WARN, + // // Produce warnings when something is commented as TODO or FIXME + // "no-warning-comments": [ WARN, { + // "terms": [ "TODO", "FIXME" ], + // "location": "start" + // }], + // "no-with": WARN, + // "radix": WARN, + // "vars-on-top": ERROR, + // // Enforces the style of wrapped functions + // "wrap-iife": [ ERROR, "outside" ], + // "yoda": ERROR, + // + // // Strict Mode - for ES6, never use strict. + // "strict": [ ERROR, "never" ], + // + // // Variables + // "init-declarations": [ ERROR, "always" ], + // "no-catch-shadow": WARN, + // "no-delete-var": ERROR, + // "no-label-var": ERROR, + // "no-shadow-restricted-names": ERROR, + // "no-shadow": WARN, + // // We require all vars to be initialized (see init-declarations) + // // If we NEED a var to be initialized to undefined, + // // it needs to be explicit + // "no-undef-init": OFF, + // "no-undef": ERROR, + // "no-undefined": OFF, + // "no-unused-vars": WARN, + // // Disallow hoisting - let & const don't allow hoisting anyhow + // "no-use-before-define": ERROR, + // + // // Node.js and CommonJS + // "callback-return": [ WARN, [ "callback", "next" ]], + // "global-require": ERROR, + // "handle-callback-err": WARN, + // "no-mixed-requires": WARN, + // "no-new-require": ERROR, + // // Use path.concat instead + // "no-path-concat": ERROR, + // "no-process-exit": ERROR, + // "no-restricted-modules": OFF, + // "no-sync": WARN, + // + // // ECMAScript 6 support + // "arrow-body-style": [ ERROR, "always" ], + // "arrow-parens": [ ERROR, "always" ], + // "arrow-spacing": [ ERROR, { "before": true, "after": true }], + // "constructor-super": ERROR, + // "generator-star-spacing": [ ERROR, "before" ], + // "no-arrow-condition": ERROR, + // "no-class-assign": ERROR, + // "no-const-assign": ERROR, + // "no-dupe-class-members": ERROR, + // "no-this-before-super": ERROR, + // "no-var": WARN, + // "object-shorthand": [ WARN, "never" ], + // "prefer-arrow-callback": WARN, + // "prefer-spread": WARN, + // "prefer-template": WARN, + // "require-yield": ERROR, + // + // // Stylistic - everything here is a warning because of style. + // "array-bracket-spacing": [ WARN, "always" ], + // "block-spacing": [ WARN, "always" ], + // "brace-style": [ WARN, "1tbs", { "allowSingleLine": false } ], + // "camelcase": WARN, + // "comma-spacing": [ WARN, { "before": false, "after": true } ], + // "comma-style": [ WARN, "last" ], + // "computed-property-spacing": [ WARN, "never" ], + // "consistent-this": [ WARN, "self" ], + // "eol-last": WARN, + // "func-names": WARN, + // "func-style": [ WARN, "declaration" ], + // "id-length": [ WARN, { "min": 2, "max": 32 } ], + // "indent": [ WARN, 4 ], + // "jsx-quotes": [ WARN, "prefer-double" ], + // // "linebreak-style": [ WARN, "unix" ], + // "lines-around-comment": [ WARN, { "beforeBlockComment": true } ], + // "max-depth": [ WARN, 8 ], + // "max-len": [ WARN, 132 ], + // "max-nested-callbacks": [ WARN, 8 ], + // "max-params": [ WARN, 8 ], + // "new-cap": WARN, + // "new-parens": WARN, + // "no-array-constructor": WARN, + // "no-bitwise": OFF, + // "no-continue": OFF, + // "no-inline-comments": OFF, + // "no-lonely-if": WARN, + // "no-mixed-spaces-and-tabs": WARN, + // "no-multiple-empty-lines": WARN, + // "no-negated-condition": OFF, + // "no-nested-ternary": WARN, + // "no-new-object": WARN, + // "no-plusplus": OFF, + // "no-spaced-func": WARN, + // "no-ternary": OFF, + // "no-trailing-spaces": WARN, + // "no-underscore-dangle": WARN, + // "no-unneeded-ternary": WARN, + // "object-curly-spacing": [ WARN, "always" ], + // "one-var": OFF, + // "operator-assignment": [ WARN, "never" ], + // "operator-linebreak": [ WARN, "after" ], + // "padded-blocks": [ WARN, "never" ], + // "quote-props": [ WARN, "consistent-as-needed" ], + // // "quotes": [ WARN, "single" ], + // "require-jsdoc": [ WARN, { + // "require": { + // "FunctionDeclaration": true, + // "MethodDefinition": true, + // "ClassDeclaration": false + // } + // }], + // "semi-spacing": [ WARN, { "before": false, "after": true }], + // "semi": [ ERROR, "always" ], + // "sort-vars": OFF, + // "space-after-keywords": [ WARN, "always" ], + // "space-before-blocks": [ WARN, "always" ], + // "space-before-function-paren": [ WARN, "never" ], + // "space-before-keywords": [ WARN, "always" ], + // "space-in-parens": [ WARN, "never" ], + // "space-infix-ops": [ WARN, { "int32Hint": true } ], + // "space-return-throw-case": ERROR, + // "space-unary-ops": ERROR, + // "spaced-comment": [ WARN, "always" ], + // "wrap-regex": WARN + // } +}; diff --git a/CHANGELOG b/CHANGELOG index b41d64b4..c0f95498 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,11 +1,112 @@ # nodeGame Changelog +# 7.1.0 +- New release, updated installer. + +# 7.0.4 +- Updated installer. +- Minor fixes. + +# 7.0.3 +- Minor, installation fixes. + +# 7.0.0 +- Dropped --phantoms option in launcher. +- More robust paths in launcher. +- Added nodeGameRoot path in launcher. +- Installer adapted to support alpha releases. + +# 6.3.0 +- Fixed installer getting stuck on versions and help. +- Added installer option --no-games to skip installing default games. +- New release. + +# 6.2.4 (6.2.1-6.2.3 deprecated) +- Fixed "default" option in launcher for Commander v7. +- New release, fixed support for images loaded in mainframe. + +# 6.2.0 +- Removed debugger from launcher.js. +- Updated server with more options for WaitingRoom. + +# 6.1.1 +- Built widgets. + +# 6.1.0 +- Fixed launcher for Commander v7. +- Updated server,client,window,widgets. + +# 6.0.3 +- Fixed corrupted build in 6.0.2 (thanks jjensenius3). + +# 6.0.2 +- Fixed bug create-game missing private folder in stable version (thanks +jjensenius3). + +# 6.0.1 +- Updated server. + +# 6.0.0 +- Option --port to specify the port of the server in launcher. + +# 5.11.2 +- Fixing version numbers. + +# 5.11.0 +- Small update to client and bug fixes. + +# 5.10.1 +- Now really updated installer, as claimed in 5.10.0 + +# 5.10.0 +- New release, updated installer. + +# 5.9.0 +- New release, updated installer. + +# 5.8.1 +- New release, updated installer. + +# 5.8.0 +- Game.stepBack. + +# 5.7.0 +- GameRoom.computeBonus handles disconnected players in dump file. + +# 5.6.0-5 +- New release, updated installer. + +# 5.4.0 +- New release, updated server, widgets, window. + +:# 5.3.1 +- Minor fixes to installer. + +# 5.3.0 +- Improved servernode.js conf file. +- Improved installer: --dry option. +- Improved installer: better handling of parent node_modules folders. + +# 5.1.0 +- Minor update to installer. +- Widgets: CustomInput, and garbage collection. +- Window and Client: check frame height automatically. + +# 5.0.1 +- Minor update to installer. +- Fixed VisualTimer.restart bug introduced in v5. +- Server does not scan hidden folders inside the games directory. +- Generator does not allow to create games starting with a dot. + # 5.0.0 - Updated installer, now installing latest versions of v3, v4, v5. - Updated installer, checks for node_modules folder above the current folder. - Updated package.json with stricter version numbers. # 4.3.3 +- Updated package.json to fix the version numbers of v4 + +# 4.3.2 - Re-enabled support for games without treatment description (bug introduced in 4.3.0) - Installer checks better for -v and -h options. @@ -58,7 +159,7 @@ treatment for the game. # 2.0.2 - Fixed install.stable script. -- Fixing launcher options. +- Fixing launcher options. # 2.0.0 (current) - Added -s option to launcher. Starts the server in SSL mode. Can be empty (loads nodegame-server/ssl/), or a path to a SSL directory. diff --git a/bin/legacy/pull-all.sh b/bin/legacy/pull-all.sh index 0fc564cc..364f8961 100755 --- a/bin/legacy/pull-all.sh +++ b/bin/legacy/pull-all.sh @@ -7,17 +7,21 @@ echo_and_pull() { git pull || echo ' FAILED!' } -GAMES=(ultimatum) +GAMES=(ultimatum-game) MODULES=(nodegame-client nodegame-server nodegame-window nodegame-widgets nodegame-requirements nodegame-game-template nodegame-monitor JSUS NDDB - shelf.js descil-mturk nodegame-db nodegame-mongodb nodegame-generator) + nodegame-generator nodegame-mturk) + +## Removed modules for now. +## nodegame-db nodegame-mongodb # Change the current working directory to the parent directory of the script, # i.e. the nodegame directory. Using the below command instead of simply # "cd .." makes sure that it does not matter from where the script is executed -cd "$(dirname "${BASH_SOURCE[0]}")/.." +# cd "$(dirname "${BASH_SOURCE[0]}")/.." -echo_and_pull nodegame +## Not yet, this fails, we just update the modules. +## echo_and_pull nodegame for GAME in "${GAMES[@]}"; do ( diff --git a/bin/nodegame-installer.js b/bin/nodegame-installer.js index 2f4d6c30..91c0cfbf 100755 --- a/bin/nodegame-installer.js +++ b/bin/nodegame-installer.js @@ -1,7 +1,7 @@ #!/usr/local/bin/node /** * # nodeGame Installer - * Copyright(c) 2011-2018 Stefano Balietti + * Copyright(c) 2011-2023 Stefano Balietti * MIT Licensed * * http://www.nodegame.org @@ -32,20 +32,28 @@ const warn = txt => { console.error(' Warning: ' + txt); }; -const MAIN_MODULE = 'nodegame'; +// const MAIN_MODULE = 'nodegame'; +let MAIN_MODULE = 'nodegame'; // All stable versions. // Versions below < 3 are not available. const STABLE_VERSIONS = { v3: '3.5.3', v4: '4.3.3', - v5: '5.0.0' + v5: '5.11.2', + v6: '6.3.0', + v7: '7.1.0' + // v8: '8.0.0' }; const AVAILABLE_VERSIONS = Object.keys(STABLE_VERSIONS).concat(['dev']); // Installer default version. -const INSTALLER_VERSION = 'v5'; +const INSTALLER_VERSION = 'v7'; + +// If node_modules folders are detected, their paths (without node_modules) +// is stored in here. +var parentNodeModules; // The actual version being installed, user can change it. var version = STABLE_VERSIONS[INSTALLER_VERSION]; @@ -60,7 +68,7 @@ else if (p === '--list-versions') { console.log(' List of stable versions:'); for (let i in STABLE_VERSIONS) { if (STABLE_VERSIONS.hasOwnProperty(i)) { - console.log(' - ' + i + ': ' + STABLE_VERSIONS[i]); + console.log(' @' + i + ': ' + STABLE_VERSIONS[i]); } } return; @@ -70,6 +78,12 @@ else if (p === '--version' || p === '-v') { return; } +var rl = readline.createInterface({ + input: process.stdin, + output: process.stdout +}); + +var alpha = false; var verbose = false; var nodeModulesExisting = false; var isDev = false; @@ -77,8 +91,13 @@ var doSSH = false; var noSpinner = false; var doNotMoveInstall = false; var yes; +var noParentDirCheck; var branch; var warnings; +var dry; + +// Add default games in games/ and games_available/. +var addGames = true; // User requested version. var requestedVersion = '@' + version; @@ -93,6 +112,17 @@ for (let i = 0; i < process.argv.length; i++) { isDev = true; requestedVersion = '@' + version; + // For testing alpha versions. + // MAIN_MODULE = 'nodegame-test'; + // version = '7.0.4'; + // requestedVersion = '@' + version; + // alpha = true; + } + else if (requestedVersion === 'alpha') { + // For testing alpha versions. + MAIN_MODULE = 'nodegame-test'; + requestedVersion = '@latest'; + alpha = true; } else { version = STABLE_VERSIONS[requestedVersion]; @@ -111,6 +141,9 @@ for (let i = 0; i < process.argv.length; i++) { else if (option === '--yes') { yes = true; } + else if (option === '--no-parent-dir-check') { + noParentDirCheck = true; + } else if (option === '--branch') { branch = process.argv[i+1]; if (!branch) { @@ -123,6 +156,12 @@ for (let i = 0; i < process.argv.length; i++) { else if (option === '--ssh') { doSSH = true; } + else if (option === '--dry') { + dry = true; + } + else if (option === '--no-games') { + addGames = false; + } } if ((doSSH || branch) && !isDev) { @@ -133,7 +172,7 @@ if ((doSSH || branch) && !isDev) { // nodeGame version. const VERSION = isDev ? "v" + version + '-dev' : "v" + version; -const NODEGAME_AND_VERSION = 'nodegame-' + VERSION; +const NODEGAME_AND_VERSION = 'nodegame-' + VERSION + (alpha ? '-alpha' : ''); const ROOT_DIR = process.cwd() const NODE_MODULES_DIR = path.resolve(ROOT_DIR, 'node_modules'); @@ -171,12 +210,19 @@ const NODEGAME_MODULES = [ 'JSUS', 'NDDB', 'ultimatum-game' ]; -const N_MODULES = NODEGAME_MODULES.length; const GAMES_AVAILABLE_DIR = path.resolve(INSTALL_DIR, 'games_available'); const GAMES_ENABLED_DIR = path.resolve(INSTALL_DIR, 'games'); +// Making sure we do not slip out on an exception. + +process.on('uncaughtException', function(err) { + warn('A generic error occurred during the installation:\n'); + log(err.stack) + installationFailed(); +}); + // Printing Info. // Print cool nodegame logo. @@ -188,34 +234,40 @@ printInstallInfo(); // Check node version is. var nodeVersion = process.versions.node.split('.'); -if (parseInt(nodeVersion[0], 10) < 4) { - err('node version >= 4.x is required.\n' + +if (parseInt(nodeVersion[0], 10) < 10) { + err('node version >= 10.x is required.\n' + 'Please upgrade your Node.Js installation, ' + 'visit: http://nodejs.org'); - log(); + installationAborted(); return; } // Check if install dir exists (abort). if (fs.existsSync(INSTALL_DIR)) { err('installation directory already existing.'); - log(); + installationAborted(); return; } // Check if node_modules exists (prompt continue?) if (fs.existsSync(NODE_MODULES_DIR)) { nodeModulesExisting = true; - warn('node_modules directory already existing.'); + warn('A "node_modules" folder was detected in this directory.'); + log(); + log('If you continue, it will become a subfolder of the nodeGame '); + log('installation. This might affect live node processes, as well as '); + log('other Node.JS packages relying on this node_modules folder. If '); + log('unsure, choose No and try to install nodeGame on another path.'); if (!yes) { - confirm(' Continue? [y/n] ', function(ok) { + log(); + confirm('Continue? [y/n]', function(ok) { if (ok) { - process.stdin.destroy(); log(); - doInstall(); + log(); + checkParentNodeModules(); } else { - log('Installation aborted.'); + installationAborted(true); log(); } }) @@ -228,18 +280,60 @@ if (fs.existsSync(NODE_MODULES_DIR)) { } // Install. -if (isDev) checkGitExists(doInstall); -else doInstall(); +if (isDev) checkGitExists(checkParentNodeModules); +else checkParentNodeModules(); // Helper functions. /////////////////////////////////////////////////////////////////////////////// +function checkParentNodeModules() { + parentNodeModules = getParentNodeModules(); + + // Check if a node_modules folder exists in any folder from the one above. + // to top /. + if (!noParentDirCheck && parentNodeModules.length) { + let str; + str = 'A "node_modules" folder was detected in '; + str += parentNodeModules.length === 1 ? 'a parent directory: ' : + 'these parent directories: '; + warn(str); + parentNodeModules.forEach(dir => logList(dir)); + log(); + + str = 'If you continue, ' + (parentNodeModules.length === 1 ? + 'that folder' : 'those folders'); + log(str + ' will be temporarily renamed. This'); + log('might affect only live node processes. If unsure, choose No '); + log('and try to install nodeGame on another path.'); + log(); + if (!yes) { + confirm('Continue? [y/n]', renameParentCb); + } + else { + log('Continue? [y/n] --yes'); + log(); + renameParentCb(true); + } + } + else { + doInstall(); + } +} + function doInstall() { var sp; + // Create spinner. log('Downloading and installing nodeGame packages.'); + if (dry) { + log(); + warn('Dry run: aborting.'); + closeRL(2); + return; + } + if (!noSpinner) { sp = new Spinner(' This might take a few minutes %s '); sp.start(); @@ -263,10 +357,26 @@ function doInstall() { log(); logList(stderr.trim()); log(); + installationFailed(); return; } else { - if (verbose) logList(stdout.trim()); + if (verbose) { + log(); + logList(stdout.trim()); + } + if (!fs.existsSync(path.resolve(NODE_MODULES_DIR))) { + log(); + log(); + log('Doh! It looks like npm has a different default ' + + 'installation folder.'); + log('This can happen if you have a directory called '+ + '"node_modules" in any of '); + log('the parent folders. Please try using a ' + + 'different path.'); + installationFailed(); + return; + } log(); log('Done! Now some final magic...'); try { @@ -304,6 +414,7 @@ function doInstall() { return; } } + return; }); } @@ -326,17 +437,25 @@ function checkGitExists(cb) { function printNodeGameInfo() { log(); - log('*********************************************** '); - log('** WELCOME TO NODEGAME INSTALLER v' + version + - ' ** '); - log('*********************************************** '); + if (alpha) { + log('***************************************************** '); + log('** WELCOME TO NODEGAME INSTALLER v' + version + + (alpha ? '-alpha' : '') + ' ** '); + log('***************************************************** '); + } + else { + log('*********************************************** '); + log('** WELCOME TO NODEGAME INSTALLER v' + version + ' ** '); + log('*********************************************** '); + } + log(); log('nodeGame: fast, scalable JavaScript for online, large-scale,'); log('multiplayer, real-time games and experiments in the browser.'); log(); log('creator: Stefano Balietti'); - log('website: http://nodegame.org'); + log('website: https://nodegame.org'); log('license: MIT'); log('mail: info@nodegame.org'); log('twitter: @nodegameorg'); @@ -346,13 +465,12 @@ function printNodeGameInfo() { } function printInstallInfo() { - let str; log(); log('----------------------------------------------'); log(); log('node version: ' + process.version); - str = 'nodeGame version: ' + VERSION; + let str = 'nodeGame version: ' + VERSION; if (branch) str += ' (' + branch + ')'; log(str); str = 'install directory: ' + INSTALL_DIR; @@ -404,8 +522,14 @@ function printFinalInfo() { log(); } +function closeRL(code) { + // rl.clearLine(); + rl.close(); + // if (force) process.stdin.destroy(); + process.exit(code); +} -function someMagic() { +function someMagic(cb) { let mainNgDir = path.resolve(NODE_MODULES_DIR, MAIN_MODULE); // Check if log and private directories have been created. @@ -415,42 +539,67 @@ function someMagic() { if (!fs.existsSync(path.resolve(mainNgDir, 'private'))) { fs.mkdirSync(path.resolve(mainNgDir, 'private')); } + if (!fs.existsSync(path.resolve(mainNgDir, 'export'))) { + fs.mkdirSync(path.resolve(mainNgDir, 'export')); + } if (!doNotMoveInstall) { // Move nodegame folder outside node_modules. fs.renameSync(mainNgDir, INSTALL_DIR); - // Old npms put already all modules under nodegame. - if (!fs.existsSync(INSTALL_DIR_MODULES)) { - fs.renameSync(NODE_MODULES_DIR, - INSTALL_DIR_MODULES); + try { + // Old npms put already all modules under nodegame. + if (!fs.existsSync(INSTALL_DIR_MODULES)) { + fs.renameSync(NODE_MODULES_DIR, + INSTALL_DIR_MODULES); + } + else if (!nodeModulesExisting) { + fs.rmdirSync(NODE_MODULES_DIR); + } } - else if (!nodeModulesExisting) { - fs.rmdirSync(NODE_MODULES_DIR); + catch(e) { + let keep = nodeModulesExisting; + moveFolderSync(NODE_MODULES_DIR, INSTALL_DIR_MODULES, keep); } } if (isDev) { getAllGitModules(function() { - // Move games from node_modules. - copyGameFromNodeModules('ultimatum-game'); + + if (addGames) { + // Move games from node_modules. + copyGameFromNodeModules('ultimatum-game'); + } // Generator. fixGenerator(); + // Restore any parent node_modules folder that was renamed. + restoreParentNodeModules(); + // Print final Information. printFinalInfo(); + + closeRL(0); }); } else { - // Move games from node_modules. - copyGameFromNodeModules('ultimatum-game'); + + if (addGames) { + // Move games from node_modules. + copyGameFromNodeModules('ultimatum-game'); + } // Generator. fixGenerator(); + // Restore any parent node_modules folder that was renamed. + restoreParentNodeModules(); + // Print final Information. printFinalInfo(); + + closeRL(0); } } @@ -460,17 +609,15 @@ function fixGenerator() { 'nodegame-generator', 'bin', 'nodegame'), path.resolve(INSTALL_DIR, 'bin', 'nodegame'), - 'file'); + 'file'); fs.writeFileSync(path.resolve(INSTALL_DIR_MODULES, - 'nodegame-generator', - 'conf', - 'generator.conf.json'), - JSON.stringify({ - author: "", - email: "", - ngDir: INSTALL_DIR - }, 4)); + 'nodegame-generator', 'conf', 'generator.conf.json'), + JSON.stringify({ + author: "", + email: "", + ngDir: INSTALL_DIR + }, 4)); } function getAllGitModules(cb) { @@ -513,9 +660,9 @@ function getAllGitModules(cb) { fs.renameSync(nodeModulesCopy, nodeModulesPath); } // Copy pre-commit hook. - copyFileSync(gitPrecommitHook, - path.resolve(modulePath, '.git', 'hooks', - 'pre-commit')); + fs.copyFileSync(gitPrecommitHook, + path.resolve(modulePath, '.git', 'hooks', + 'pre-commit')); counter--; if (counter == 0 && cb) cb(); }); @@ -596,15 +743,9 @@ function copyGameFromNodeModules(game, enable) { makeLink(gameDir, path.resolve(GAMES_ENABLED_DIR, game)); } -function confirm(msg, callback) { - var rl = readline.createInterface({ - input: process.stdin, - output: process.stdout - }); - - rl.question(msg, function(input) { - rl.close(); - callback(/^y|yes|ok|true$/i.test(input)); +function confirm(msg, callback, ...params) { + rl.question(' ' + msg + ' ', function(input) { + callback(/^y|yes|ok|true$/i.test(input, ...params)); }); } @@ -630,10 +771,77 @@ function removeDirRecursiveSync(dir) { }); fs.rmdirSync(dir); } -}; +} -function installationFailed() { +function getParentNodeModules() { + let tks = ROOT_DIR.split(path.sep); + let found = []; + let dirPath = tks[0]; + for (let i = 0 ; i < (tks.length - 1) ; i++) { + if (i !== 0) dirPath = path.join(dirPath, tks[i]); + if (fs.existsSync(path.join(dirPath, 'node_modules'))) { + found.push(dirPath); + } + } + return found; +} + +// Need this wrapper because --yes option +function renameParentCb(ok) { + if (ok) { + log(); + let res = renameParentNodeModules(parentNodeModules); + if (res !== true) { + err('Could not rename "node_modules" folder in: ' + res[0]); + installationFailed(); + } + log(); + doInstall(); + } + else { + installationAborted(true); + return; + } +} + +function renameParentNodeModules(parents, restore) { + let out = []; + for (let i = 0; i < parents.length; i++) { + try { + let f1 = path.join(parents[i], 'node_modules'); + let f2 = f1 + '_backup'; + // Add _bak or remove _bak from parent node_modules folders. + if (restore) fs.renameSync(f2, f1); + else fs.renameSync(f1, f2); + } + catch(e) { + out.push(parents[i]); + // If we are not restoring original folders, exit immediately. + if (!restore) return(out); + } + } + return true; +} + +function restoreParentNodeModules() { + if (!parentNodeModules || !parentNodeModules.length) return; + let res = renameParentNodeModules(parentNodeModules, true); + if (res !== true) { + log(); + warn('Could not restore parent "node_modules" folder in: '); + res.forEach(dir => logList(dir)); + } +} + +function installationAborted(byUser) { + let str = 'Installation aborted' + (byUser ? ' by user.' : '.'); + log(); + log(str); + closeRL(1); + return; +} +function installationFailed() { log(); log('Installation did not complete successfully.'); @@ -646,31 +854,35 @@ function installationFailed() { 'https://github.com/nodeGame/nodegame/issues'); log(' - send an email to info@nodegame.org'); log(); + + // Restore any parent node_modules folder that was renamed. + restoreParentNodeModules(); + closeRL(1); } function printHelp() { log(); - log('@ Install a specific version (>=3.5.1)'); - log('@dev Install latest nodeGame from git repos'); - log(' --branch Checkout this branch on all git repos'); - log(' --ssh Use ssh to get all git repos'); - log('--yes Answer yes to all questions'); - log('--install-dir Set the name of the installation directory;'); + log('@ Installs a specific version (v3, v4, v5, v6)'); + log('@dev Installs latest nodeGame from git repos'); + log('--branch Checkouts this branch on all git repos'); + log('--ssh Uses ssh to get all git repos'); + log('--yes Answers yes to all questions'); + log('--install-dir Sets the name of the installation directory;'); log(' if equals to node_modules, the npm structure'); log(' stays unchanged'); log('--no-spinner Does not start the spinner'); + log('--dry Does not actually install anything'); log('--list-versions Lists stable versions'); - log('--version Print installer version'); - log('--help Print this help'); + log('--no-games Does not install default games'); + log('--version Prints installer version'); + log('--help Prints this help'); log(); } // Kudos: cli-spinner package. function Spinner(text) { - var that; - that = this; this.spinners = [ "|/-\\", @@ -740,10 +952,10 @@ function Spinner(text) { readline.clearLine(stream, 0); readline.cursorTo(stream, 0); }; -}; +} function inArray(needle, haystack) { - var func, i, len; + var i, len; len = haystack.length; for (i = 0; i < len; i++) { if (needle === haystack[i]) { @@ -753,75 +965,23 @@ function inArray(needle, haystack) { return false; } +function moveFolderSync(from, to, copy) { + if (!fs.existsSync(to)) fs.mkdirSync(to); + fs.readdirSync(from).forEach(element => { + let fileFrom = path.join(from, element); + let fileTo = path.join(to, element); -// Kudos. Adapted from: -// https://github.com/coderaiser/ -// fs-copy-file-sync/blob/master/lib/fs-copy-file-sync.js -function _copyFileSync(src, dest, flag) { - const SIZE = 65536; - - const COPYFILE_EXCL = 1; - const COPYFILE_FICLONE = 2; - const COPYFILE_FICLONE_FORCE = 4; - - const constants = { - COPYFILE_EXCL, - COPYFILE_FICLONE, - COPYFILE_FICLONE_FORCE, - }; - - const isNumber = (a) => typeof a === 'number'; - const or = (a, b) => a | b; - const getValue = (obj) => (key) => obj[key]; - - const getMaxMask = (obj) => Object - .keys(obj) - .map(getValue(obj)) - .reduce(or); - - const MAX_MASK = getMaxMask(constants); - const isExcl = (flags) => flags & COPYFILE_EXCL; - - - const writeFlag = isExcl(flag) ? 'wx' : 'w'; - - const { - size, - mode, - } = fs.statSync(src); - - const fdSrc = fs.openSync(src, 'r'); - const fdDest = fs.openSync(dest, writeFlag, mode); - - const length = size < SIZE ? size : SIZE; - - let pos = 0; - const peaceSize = size < SIZE ? 0 : size % SIZE; - const offset = 0; - - let buffer = Buffer.allocUnsafe(length); - for (let i = 0; length + pos + peaceSize <= size; i++, pos = length * i) { - fs.readSync(fdSrc, buffer, offset, length, pos); - fs.writeSync(fdDest, buffer, offset, length, pos); - } - - if (peaceSize) { - const length = peaceSize; - buffer = Buffer.allocUnsafe(length); - fs.readSync(fdSrc, buffer, offset, length, pos); - fs.writeSync(fdDest, buffer, offset, length, pos); - } - - fs.closeSync(fdSrc); - fs.closeSync(fdDest); -} + let stats = fs.lstatSync(fileFrom); + if (stats.isFile() || stats.isSymbolicLink()) { + if (copy) fs.copyFileSync(fileFrom, fileTo); + else fs.renameSync(fileFrom, fileTo); + } + else { + moveFolderSync(fileFrom, fileTo); + } + }); + // ALl files moved, removed dir. + if (!copy) fs.rmdirSync(from); -function copyFileSync(from, to) { - if ('function' === typeof fs.copyFileSync) { - fs.copyFileSync(from, to); - } - else { - _copyFileSync(from, to); - } } diff --git a/conf/http.js b/conf/http.js index 5f5f9c17..c2e17367 100644 --- a/conf/http.js +++ b/conf/http.js @@ -1,7 +1,7 @@ /** * # http.js * - * Copyright(c) 2013 Stefano Balietti + * Copyright(c) 2020 Stefano Balietti * MIT Licensed * * Configuration file for ServerNode in nodegame-server. @@ -10,8 +10,9 @@ module.exports = configure; function configure(app, servernode) { - // Nothing extra to configure. - // Default configuration set already in: + + // Edit this file to modify the default configuration options in: // node_modules/nodegame-server/conf/http.js + return true; }; diff --git a/conf/loggers.js b/conf/loggers.js index 3d1e7eac..472aa322 100644 --- a/conf/loggers.js +++ b/conf/loggers.js @@ -1,46 +1,60 @@ +/** + * # servernode.js + * + * Copyright(c) 2020 Stefano Balietti + * MIT Licensed + * + * Configuration file for ServerNode in nodegame-server. + * --- + */ module.exports = configure; -var path = require('path'); +const path = require('path'); -function configure (loggers) { +function configure(loggers) { -// var config = { -// levels: { -// silly: 0, -// verbose: 1, -// info: 2, -// data: 3, -// warn: 4, -// debug: 5, -// error: 6 -// }, -// colors: { -// silly: 'magenta', -// verbose: 'cyan', -// info: 'green', -// data: 'grey', -// warn: 'yellow', -// debug: 'blue', -// error: 'red' -// } -// }; + // Edit this file to modify the default configuration options in: + // node_modules/nodegame-server/conf/loggers.js -// var rootDir = path.resolve(__dirname, '..'); -// var logDir = rootDir + '/log/'; -// -// loggers.add('ultimatumchannel', { -// console: { -// level: 'silly', -// colorize: true, -// }, -// file: { -// level: 'silly', -// timestamp: true, -// filename: logDir + 'channel', -// maxsize: 1000, -// maxFiles: 10, -// }, -// }); -// - return true; + // For instance: + + // let config = { + // levels: { + // silly: 0, + // verbose: 1, + // info: 2, + // data: 3, + // warn: 4, + // debug: 5, + // error: 6 + // }, + // colors: { + // silly: 'magenta', + // verbose: 'cyan', + // info: 'green', + // data: 'grey', + // warn: 'yellow', + // debug: 'blue', + // error: 'red' + // } + // }; + + // let rootDir = path.resolve(__dirname, '..'); + // let logDir = rootDir + '/log/'; + // + // loggers.add('ultimatumchannel', { + // console: { + // level: 'silly', + // colorize: true, + // }, + // file: { + // level: 'silly', + // timestamp: true, + // filename: logDir + 'channel', + // maxsize: 1000, + // maxFiles: 10, + // }, + // }); + + return true; } diff --git a/conf/servernode.js b/conf/servernode.js index 54ad0e89..645c5f2c 100644 --- a/conf/servernode.js +++ b/conf/servernode.js @@ -1,7 +1,7 @@ /** * # servernode.js * - * Copyright(c) 2017 Stefano Balietti + * Copyright(c) 2020 Stefano Balietti * MIT Licensed * * Configuration file for ServerNode in nodegame-server. @@ -10,11 +10,13 @@ module.exports = configure; function configure(servernode) { - // Extra configuration goes here, e.g.: - // servernode.port = 80; - // Default configuration set already in: + // Edit this file to modify the default configuration options in: // node_modules/nodegame-server/conf/servernode.js + // Extra configuration goes here, e.g.: + // servernode.port = 80; + // servernode.homePage = false; + return true; } diff --git a/conf/sio.js b/conf/sio.js index 64012fa7..ba122f02 100644 --- a/conf/sio.js +++ b/conf/sio.js @@ -1,7 +1,7 @@ /** * # sio.js * - * Copyright(c) 2013 Stefano Balietti + * Copyright(c) 2020 Stefano Balietti * MIT Licensed * * Configuration file for the Socket.io server in nodegame-server. @@ -10,8 +10,9 @@ module.exports = configure; function configure(sio, servernode) { - // Nothing extra to configure. - // Default configuration set already in: + + // Edit this file to modify the default configuration options in: // node_modules/nodegame-server/conf/sio.js + return true; }; diff --git a/launcher.js b/launcher.js index 01953274..6251ed8e 100644 --- a/launcher.js +++ b/launcher.js @@ -1,6 +1,6 @@ /** * # Launcher file for nodeGame Server - * Copyright(c) 2011-2018 Stefano Balietti + * Copyright(c) 2011-2020 Stefano Balietti * MIT Licensed * * Load configuration options and start the server @@ -16,7 +16,7 @@ const path = require('path'); const exec = require('child_process').exec; const J = require('JSUS').JSUS; -var NDDB; +// TODO: refactor, eliminate var; check new Commander options. // Load commander. var program = require('commander'); @@ -33,12 +33,9 @@ var sn; // ServerNode options. var options; -// Conf file for all variables. -var confFile; - // Other local options. var confDir, logDir, gamesDir, debug, infoQuery, runTests; -var nClients, clientType, killServer, auth, wait; +var nClients, clientType, killServer, auth, wait, port; var codesDb; var cert, key; @@ -59,13 +56,11 @@ ignoredOptions = []; // Defaults. -confFile = null; - -confDir = './conf'; -logDir = './log'; -gamesDir = './games'; -debug = false; -infoQuery = false; +confDir = path.resolve(__dirname, 'conf'); +logDir = path.resolve(__dirname, 'log'); +gamesDir = path.resolve(__dirname, 'games'); +debug = undefined; +infoQuery = undefined; nClients = 4; clientType = 'autoplay'; @@ -88,57 +83,71 @@ program 'Sets the configuration directory') .option('-l, --logDir ', 'Sets the log directory') + .option('-L, --logLevel ', + 'Sets the log level. Values: error(default)|warn|info|silly') .option('-g, --gamesDir ', 'Sets the games directory') .option('-d, --debug', 'Enables the debug mode') - .option('-i, --infoQuery', + .option('-i, --infoQuery [false]', 'Enables getting information via query-string ?q=') .option('-b, --build [components]', 'Rebuilds the specified components', list) .option('-s, --ssl [path-to-ssl-dir]', 'Starts the server with SSL encryption') + .option('-f, --default [channel]', + 'Sets the default channel') + .option('-P, --port [port]', + 'Sets the port of the server') + // Connect phantoms. .option('-p, --phantoms ', - 'Connect phantoms to the specified channel') - .option('-n, --nClients ', - 'Sets the number of clients phantoms to connect (default: 4)') - .option('-t, --clientType ', - 'Sets the client type of connecting phantoms (default: autoplay)') - .option('-T, --runTests', - 'Run tests after all phantoms have reached game over ' + - '(overwrites settings.js in test/ folder') - .option('-k, --killServer', - 'Kill server after all phantoms have reached game over') - .option('-a --auth [option]', - 'Phantoms pass through /auth/. Options: createNew|new|' + - 'nextAvailable|next|code|id:code&pwd:password|file:path/to/file. ' + - 'Default: "new".') - .option('-w --wait [milliseconds]', - 'Waits before connecting the next phantom. Default: 1000') + 'Connect phantoms to the specified channel **DISCONTINUED**') + // .option('-n, --nClients ', + // 'Sets the number of clients phantoms to connect (default: 4)') + // .option('-t, --clientType ', + // 'Sets the client type of connecting phantoms (default: autoplay)') + // .option('-T, --runTests', + // 'Run tests after all phantoms are game-over ' + + // '(overwrites settings.js in test/)') + // .option('-k, --killServer', + // 'Kill server after all phantoms are game-over') + // .option('-a --auth [option]', + // 'Phantoms auth options. Values: new(default)|createNew|' + + // 'nextAvailable|next|code|id:code&pwd:password|file:path/to/file.') + // .option('-w --wait [milliseconds]', + // 'Waits before connecting the next phantom. Default: 1000') .parse(process.argv); +// User options (Commander >= 7). +let opts = program.opts(); + +if (opts.phantoms) { + console.log('***Err: option --phantoms no longer supported. ' + + 'PhantomJS support discontinued.'); + return false; +} -if (program.confFile) { - if (!fs.existsSync(program.ConfFile)) { - return printErr('--confFile ' + program.confFile + ' not found.'); +if (opts.confFile) { + if (!fs.existsSync(opts.confFile)) { + return printErr('--confFile ' + opts.confFile + ' not found.'); } - options = require(program.confFile); + options = require(opts.confFile); if ('object' !== typeof options) { - return printErr('--confFile ' + program.confFile + ' did not return ' + + return printErr('--confFile ' + opts.confFile + ' did not return ' + 'a configuration object.'); } - if (program.confDir) ignoredOptions.push('--confDir'); - if (program.logDir) ignoredOptions.push('--logDir'); - if (program.gamesDir) ignoredOptions.push('--gamesDir'); - if (program.debug) ignoredOptions.push('--debug'); - if (program.infoQuery) ignoredOptions.push('--infoQuery'); + if (opts.confDir) ignoredOptions.push('--confDir'); + if (opts.logDir) ignoredOptions.push('--logDir'); + if (opts.gamesDir) ignoredOptions.push('--gamesDir'); + if (opts.debug) ignoredOptions.push('--debug'); + if (opts.infoQuery) ignoredOptions.push('--infoQuery'); } else { @@ -155,67 +164,82 @@ else { // Adds a new game directory (Default is nodegame-server/games). servernode.gamesDirs.push(gamesDir); - // Sets the debug mode, exceptions will be thrown. - servernode.debug = debug; - // Can get information from /?q= - servernode.enableInfoQuery = infoQuery; + + // Sets the debug mode, exceptions will be thrown, if TRUE. + if ('undefined' !== typeof debug) { + servernode.debug = debug; + } + // Can get information from /?q=, if TRUE + if ('undefined' !== typeof infoQuery) { + servernode.enableInfoQuery = infoQuery; + } // Basepath (without trailing slash). // servernode.basepath = '/mybasepath'; return true; }, - http: function(http) { - // Special configuration for Express goes here. - return true; - }, - sio: function(sio) { - // Special configuration for Socket.Io goes here here. - // Might not work in Socket.IO 1.x (check). - - // sio.set('transports', ['xhr-polling']); - // sio.set('transports', ['jsonp-polling']); - - // sio.set('transports', [ - // 'websocket' - // , 'flashsocket' - // , 'htmlfile' - // , 'xhr-polling' - // , 'jsonp-polling' - // ]); - - return true; - } + // http: function(http) { + // // Special configuration for Express goes here. + // return true; + // }, + // sio: function(sio) { + // // Special configuration for Socket.Io goes here here. + // // Might not work in Socket.IO 1.x (check). + // + // // sio.set('transports', ['xhr-polling']); + // // sio.set('transports', ['jsonp-polling']); + // + // // sio.set('transports', [ + // // 'websocket' + // // , 'flashsocket' + // // , 'htmlfile' + // // , 'xhr-polling' + // // , 'jsonp-polling' + // // ]); + // + // return true; + // } }; // Validate other options. - if (program.confDir) { - if (!fs.existsSync(program.confDir)) { - return printErr('--confDir ' + program.confDir + ' not found.'); + if (opts.confDir) { + if (!fs.existsSync(opts.confDir)) { + return printErr('--confDir ' + opts.confDir + ' not found.'); + } + confDir = opts.confDir; + } + if (opts.logDir) { + if (!fs.existsSync(opts.logDir)) { + return printErr('--logDir ' + opts.logDir + ' not found.'); } - confDir = program.confDir; + logDir = opts.logDir; } - if (program.logDir) { - if (!fs.existsSync(program.logDir)) { - return printErr('--logDir ' + program.logDir + ' not found.'); + if (opts.gamesDir) { + if (!fs.existsSync(opts.gamesDir)) { + return printErr('--gamesDir ' + opts.gamesDir + ' not found.'); } - logDir = program.logDir; + gamesDir = opts.gamesDir; } - if (program.gamesDir) { - if (!fs.existsSync(program.gamesDir)) { - return printErr('--gamesDir ' + program.gamesDir + ' not found.'); + if (opts.debug) debug = true; + + // Parse infoQuery. + if (opts.infoQuery) { + if ('boolean' === typeof opts.infoQuery) { + infoQuery = opts.infoQuery; + } + else { + let i = opts.infoQuery.toLowerCase(); + infoQuery = i === 'f' || i === 'false' || i === '0' ? false : true; } - gamesDir = program.gamesDir; } - if (program.debug) debug = true; - if (program.infoQuery) infoQuery = true; } // Validate general options. -if ('boolean' === typeof program.ssl) { +if ('boolean' === typeof opts.ssl) { options.ssl = true; } -else if ('string' === typeof program.ssl) { +else if ('string' === typeof opts.ssl) { options.ssl = (function(dir) { var ssl; @@ -242,65 +266,82 @@ else if ('string' === typeof program.ssl) { return ssl; - })(program.ssl); + })(opts.ssl); if (!options.ssl) return; } -if (program.nClients) { - if (!program.phantoms) ignoredOptions.push('--nClients'); +if (opts['default']) { + options.defaultChannel = opts['default']; +} + +if (opts.port) { + port = J.isInt(opts.port, 0); + if (!port) { + return printErr('--port ' + opts.port + + ' is not a positive number.'); + } + options.port = port; +} + +if (opts.logLevel) { + options.logLevel = opts.logLevel; +} + +if (opts.nClients) { + if (!opts.phantoms) ignoredOptions.push('--nClients'); else { - nClients = parseInt(program.nClients, 10); + nClients = parseInt(opts.nClients, 10); if (isNaN(nClients)) { - return printErr('--nClients ' + program.nClients + + return printErr('--nClients ' + opts.nClients + ' is invalid.'); } } } -if (program.clientType) { - if (!program.phantoms) ignoredOptions.push('--clientType'); - else clientType = program.clientType; +if (opts.clientType) { + if (!opts.phantoms) ignoredOptions.push('--clientType'); + else clientType = opts.clientType; } -if (program.runTests) { - if (!program.runTests) ignoredOptions.push('--runTests'); - else runTests = program.runTests; +if (opts.runTests) { + if (!opts.runTests) ignoredOptions.push('--runTests'); + else runTests = opts.runTests; } -if (program.killServer) { - if (!program.phantoms) ignoredOptions.push('--killServer'); +if (opts.killServer) { + if (!opts.phantoms) ignoredOptions.push('--killServer'); else killServer = true; } -if (program.wait) { - if (!program.phantoms) { +if (opts.wait) { + if (!opts.phantoms) { ignoredOptions.push('--wait'); } else { - if (true === program.wait) { + if (true === opts.wait) { wait = 1000; } else { - wait = J.isInt(program.wait, 0); + wait = J.isInt(opts.wait, 0); if (false === wait) { printErr('--wait must be a positive number or undefined. ' + - 'Found:' + program.wait); + 'Found:' + opts.wait); process.exit(); } } } } -if (program.auth) { - if (!program.phantoms) { +if (opts.auth) { + if (!opts.phantoms) { ignoredOptions.push('--auth'); } - else if ('string' === typeof program.auth) { + else if ('string' === typeof opts.auth) { auth = (function(idIdx, pwdIdx) { var auth; - idIdx = program.auth.indexOf('id:'); + idIdx = opts.auth.indexOf('id:'); if (idIdx === 0) { - pwdIdx = program.auth.indexOf('&pwd:'); + pwdIdx = opts.auth.indexOf('&pwd:'); if (pwdIdx !== -1) { auth = { - id: program.auth.substr(3, (pwdIdx-3)), - pwd: program.auth.substr(pwdIdx+5) + id: opts.auth.substr(3, (pwdIdx-3)), + pwd: opts.auth.substr(pwdIdx+5) }; } else { @@ -309,67 +350,65 @@ if (program.auth) { process.exit(); } } - else if (program.auth === 'new') { + else if (opts.auth === 'new') { auth = 'createNew'; } - else if (program.auth === 'next') { + else if (opts.auth === 'next') { auth = 'nextAvailable'; } - else if (program.auth.indexOf('file:') === 0) { - NDDB = require('NDDB').NDDB; + else if (opts.auth.indexOf('file:') === 0) { + const NDDB = require('NDDB').NDDB; codesDb = new NDDB(); - codesDb.loadSync(program.auth.substr(5)); + codesDb.loadSync(opts.auth.substr(5)); if (!codesDb.size()) { - printErr('--auth no auth codes found: program.auth'); + printErr('--auth no auth codes found: opts.auth'); process.exit(); } codesDb = codesDb.db; } else { - auth = program.auth; + auth = opts.auth; } return auth; })(); } - else if ('boolean' === typeof program.auth) { + else if ('boolean' === typeof opts.auth) { auth = 'createNew'; } - else if ('number' === typeof program.auth || - 'object' === typeof program.auth) { + else if ('number' === typeof opts.auth || + 'object' === typeof opts.auth) { - auth = program.auth; + auth = opts.auth; } } // Rebuild server files as needed. -if (program.build) { +if (opts.build) { (function() { - var i, len, opts, modules; - var info, module, out; - var cssAlso, cssOnly; + let cssAlso, cssOnly; - len = program.build.length; + let len = opts.build.length; if (!len) { - program.build = [ 'client' ]; + opts.build = [ 'client' ]; } else if (len === 1) { - if (program.build[0] === 'all') { + if (opts.build[0] === 'all') { // Client will be done anyway. - program.build = [ 'window', 'widgets', 'JSUS', 'NDDB' ]; + opts.build = [ 'window', 'widgets', 'JSUS', 'NDDB' ]; } - else if (program.build[0] === 'css') { + else if (opts.build[0] === 'css') { cssOnly = true; } } - - info = J.resolveModuleDir('nodegame-server', __dirname); + + let info = J.resolveModuleDir('nodegame-server', __dirname); info = require(path.resolve(info, 'bin', 'info.js')); - + if (!cssOnly) { - out = 'nodegame-full.js'; + let out = 'nodegame-full.js'; - modules = { + let modules = { window: 'window', client: 'client', widgets: 'widgets', @@ -377,11 +416,11 @@ if (program.build) { NDDB: 'NDDB', css: 'css' }; - + // Starting build. - i = -1, len = program.build.length; + let i = -1; for ( ; ++i < len ; ) { - module = program.build[i]; + let module = opts.build[i]; if (!modules[module]) { throw new Error('unknown build component: ' + module); } @@ -398,9 +437,7 @@ if (program.build) { continue; } - opts = { all: true, clean: true }; - - info.build[module](opts); + info.build[module]({ all: true, clean: true }); console.log(''); } // Do client last. @@ -410,11 +447,11 @@ if (program.build) { output: out }); J.copyFile(path.resolve(info.modulesDir.client, 'build', out), - path.resolve(info.serverDir.build, 'nodegame-full.js')); + path.resolve(info.serverDir.build, out)); console.log(info.serverDir.build + out + ' rebuilt.'); console.log(''); } - + if (cssAlso || cssOnly) { info.build.css(info.serverDir.css, function(err) { if (!err) { @@ -427,7 +464,7 @@ if (program.build) { startServer(); } - })(program.build); + })(); } else { startServer(); @@ -443,6 +480,8 @@ function startServer() { // Add nodeGame version (might be higher than server version) to options. options.nodeGameVersion = version; + options.nodeGameRoot = __dirname; + // Start server, options parameter is optional. sn = new ServerNode(options); @@ -454,9 +493,9 @@ function startServer() { var numFinished; // If there are not bots to add returns. - if (!program.phantoms) return; + if (!opts.phantoms) return; - gameName = program.phantoms; + gameName = opts.phantoms; channel = sn.channels[gameName]; if (!channel) { printErr('channel ' + gameName + ' was not found.'); @@ -506,7 +545,7 @@ function startServer() { }; } - + startPhantom = function(i) { var str, config; str = 'Connecting phantom #' + (i+1) + '/' + nClients; @@ -541,7 +580,7 @@ function startServer() { phantoms = [], numFinished = 0; for (i = 0; i < nClients; ++i) { if (i > 0 && wait) { - (function(i) { + (function(i) { setTimeout(function() { startPhantom(i); }, wait * i); })(i); } diff --git a/package.json b/package.json index edf06b7f..a912f1f5 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nodegame", "description": "Fast, scalable JavaScript for large-scale, online, multiplayer, real-time games and experiments.", - "version": "5.0.0", + "version": "7.1.0", "homepage": "http://nodegame.org", "author": "Stefano Balietti ", "contributors": [ @@ -15,24 +15,24 @@ "url": "https://github.com/nodeGame/nodegame.git" }, "engines": { - "node": ">= 6.0.0" + "node": ">= 10.0.0" }, "dependencies": { - "nodegame-server": "^5.0.0", - "nodegame-client": "^5.0.0", - "nodegame-window": "^5.0.0", - "nodegame-widgets": "^5.0.0", - "nodegame-requirements": "^5.0.0", - "nodegame-game-template": "^5.0.0", - "nodegame-monitor": "^5.0.0", - "nodegame-generator": "^5.0.0", - "nodegame-mturk": "^5.0.0", - "ultimatum-game": "^5.0.0", - "JSUS": ">= 1.1.0", - "NDDB": ">= 1.18.1", + "nodegame-client": ">=7.1.0", + "nodegame-server": ">=7.0.3", + "nodegame-window": ">=7.0.0", + "nodegame-widgets": ">=7.0.2", + "nodegame-requirements": ">=7.0.0", + "nodegame-game-template": ">=7.0.0", + "nodegame-monitor": ">=7.0.0", + "nodegame-generator": ">=7.0.0", + "ultimatum-game": ">=7.0.0", + "nodegame-mturk": ">=7.0.0", + "JSUS": ">=1.1.0", + "NDDB": ">=3.0.2", "nodegame-db": "*", "nodegame-mongodb": "*", - "commander": "*", + "commander": "^7.0.0", "fs-extra": "*", "smoosh": "0.4.0" },