From 2701ea4b6c2eb4bc4ffa1282b2729842140fd46f Mon Sep 17 00:00:00 2001 From: Exodus4D Date: Mon, 9 Jan 2017 21:01:24 +0100 Subject: [PATCH] - improved /setup page for WebSocket config check, #420 - improved /setup page for Redis server config check, --- app/main/controller/setup.php | 66 ++++++++------- app/main/lib/socket.php | 26 +++++- app/requirements.ini | 7 ++ js/app/map/worker.js | 1 + js/app/setup.js | 102 +++++++++++++++++++++-- public/js/v1.2.0/app/map/worker.js | 1 + public/js/v1.2.0/app/setup.js | 102 +++++++++++++++++++++-- public/templates/dialog/map_manual.html | 2 +- public/templates/ui/notice.html | 7 +- public/templates/view/login.html | 2 +- public/templates/view/setup.html | 103 ++++++++++++++---------- 11 files changed, 326 insertions(+), 93 deletions(-) diff --git a/app/main/controller/setup.php b/app/main/controller/setup.php index 72f65af2..789f3b18 100644 --- a/app/main/controller/setup.php +++ b/app/main/controller/setup.php @@ -424,55 +424,48 @@ class Setup extends Controller { 'version' => strstr(PCRE_VERSION, ' ', true), 'check' => version_compare( strstr(PCRE_VERSION, ' ', true), $f3->get('REQUIREMENTS.PHP.PCRE_VERSION'), '>=') ], - 'pdo' => [ + 'ext_pdo' => [ 'label' => 'PDO', 'required' => 'installed', 'version' => extension_loaded('pdo') ? 'installed' : 'missing', 'check' => extension_loaded('pdo') ], - 'pdoMysql' => [ + 'ext_pdoMysql' => [ 'label' => 'PDO_MYSQL', 'required' => 'installed', 'version' => extension_loaded('pdo_mysql') ? 'installed' : 'missing', 'check' => extension_loaded('pdo_mysql') ], - 'openssl' => [ + 'ext_openssl' => [ 'label' => 'OpenSSL', 'required' => 'installed', 'version' => extension_loaded('openssl') ? 'installed' : 'missing', 'check' => extension_loaded('openssl') ], - 'mcrypt' => [ + 'ext_mcrypt' => [ 'label' => 'Mcrypt', 'required' => 'installed', 'version' => (extension_loaded('mcrypt')) ? 'installed' : 'missing', 'check' => extension_loaded('mcrypt') ], - 'xml' => [ + 'ext_xml' => [ 'label' => 'XML', 'required' => 'installed', 'version' => extension_loaded('xml') ? 'installed' : 'missing', 'check' => extension_loaded('xml') ], - 'gd' => [ + 'ext_gd' => [ 'label' => 'GD Library (for Image plugin)', 'required' => 'installed', 'version' => (extension_loaded('gd') && function_exists('gd_info')) ? 'installed' : 'missing', 'check' => (extension_loaded('gd') && function_exists('gd_info')) ], - 'curl' => [ + 'ext_curl' => [ 'label' => 'cURL (for Web plugin)', 'required' => 'installed', 'version' => (extension_loaded('curl') && function_exists('curl_version')) ? 'installed' : 'missing', 'check' => (extension_loaded('curl') && function_exists('curl_version')) ], - 'redis' => [ - 'label' => 'Redis [optional]', - 'required' => $f3->get('REQUIREMENTS.PHP.REDIS'), - 'version' => extension_loaded('redis') ? phpversion('redis') : 'missing', - 'check' => version_compare( phpversion('redis'), $f3->get('REQUIREMENTS.PHP.REDIS'), '>='), - 'tooltip' => 'Redis can replace the default file-caching mechanic. It is much faster (preferred)!' - ], 'maxInputVars' => [ 'label' => 'max_input_vars', 'required' => $f3->get('REQUIREMENTS.PHP.MAX_INPUT_VARS'), @@ -486,6 +479,33 @@ class Setup extends Controller { 'version' => ini_get('max_execution_time'), 'check' => ini_get('max_execution_time') >= $f3->get('REQUIREMENTS.PHP.MAX_EXECUTION_TIME'), 'tooltip' => 'PHP default = 30. Max execution time for PHP scripts.' + ], + [ + 'label' => 'Redis Server [optional]' + ], + 'ext_redis' => [ + 'label' => 'Redis', + 'required' => $f3->get('REQUIREMENTS.PHP.REDIS'), + 'version' => extension_loaded('redis') ? phpversion('redis') : 'missing', + 'check' => version_compare( phpversion('redis'), $f3->get('REQUIREMENTS.PHP.REDIS'), '>='), + 'tooltip' => 'Redis can replace the default file-caching mechanic. It is much faster!' + ], + [ + 'label' => 'ØMQ TCP sockets [optional]' + ], + 'ext_zmq' => [ + 'label' => 'ZeroMQ extension', + 'required' => $f3->get('REQUIREMENTS.PHP.ZMQ'), + 'version' => extension_loaded('zmq') ? phpversion('zmq') : 'missing', + 'check' => version_compare( phpversion('zmq'), $f3->get('REQUIREMENTS.PHP.ZMQ'), '>='), + 'tooltip' => 'ØMQ PHP extension. Required for WebSocket configuration.' + ], + 'lib_zmq' => [ + 'label' => 'ZeroMQ installation', + 'required' => $f3->get('REQUIREMENTS.LIBS.ZMQ'), + 'version' => (class_exists('ZMQ') && defined('ZMQ::LIBZMQ_VER')) ? \ZMQ::LIBZMQ_VER : 'unknown', + 'check' => version_compare( (class_exists('ZMQ') && defined('ZMQ::LIBZMQ_VER')) ? \ZMQ::LIBZMQ_VER : 0, $f3->get('REQUIREMENTS.LIBS.ZMQ'), '>='), + 'tooltip' => 'ØMQ version. Required for WebSocket configuration.' ] ]; @@ -949,24 +969,12 @@ class Setup extends Controller { ], 'webSocket' => [ 'label' => 'WebSocket (clients) [HTTP]', - 'online' => true, + 'online' => false, 'data' => [ [ - 'label' => 'HOST', - 'value' => 'pathfinder.local', - 'check' => true - ],[ - 'label' => 'PORT', - 'value' => 80, - 'check' => true - ],[ 'label' => 'URI', - 'value' => 'ws://pathfinder.local/ws/map/update', - 'check' => true - ],[ - 'label' => 'timeout (ms)', - 'value' => $ttl, - 'check' => !empty( $ttl ) + 'value' => '', + 'check' => false ] ] ] diff --git a/app/main/lib/socket.php b/app/main/lib/socket.php index 57bffd0c..1f29f163 100644 --- a/app/main/lib/socket.php +++ b/app/main/lib/socket.php @@ -47,9 +47,12 @@ class Socket { protected $maxRetries = self::DEFAULT_RETRY_MAX; public function __construct($uri, $ttl = self::DEFAULT_TTL_MAX, $maxRetries = self::DEFAULT_RETRY_MAX){ - $this->setSocketUri($uri); $this->setTtl($ttl, $maxRetries); - $this->initSocket(); + + if( self::checkRequirements() ){ + $this->setSocketUri($uri); + $this->initSocket(); + } } /** @@ -155,5 +158,24 @@ class Socket { return $response; } + /** + * check whether this installation fulfills all requirements + * -> check for ZMQ PHP extension and installed ZQM version + * -> this does NOT check versions! -> those can be verified on /setup page + * @return bool + */ + static function checkRequirements(){ + $check = false; + + if( + extension_loaded('zmq') && + class_exists('ZMQ') + ){ + $check = true; + } + + return $check; + } + } \ No newline at end of file diff --git a/app/requirements.ini b/app/requirements.ini index dd554eb9..8c39671c 100644 --- a/app/requirements.ini +++ b/app/requirements.ini @@ -20,6 +20,9 @@ PCRE_VERSION = 8.02 ; Redis extension (optional), required if you want to use Redis as caching Engine (recommended) REDIS = 3.0.0 +; ZeroMQ (ØMQ) extension (optional) required for WebSocket Server extension (recommended) +ZMQ = 1.1.3 + ; max execution time for requests MAX_EXECUTION_TIME = 10 @@ -29,6 +32,10 @@ MAX_EXECUTION_TIME = 10 ; PHP default = 1000 MAX_INPUT_VARS = 3000 +[REQUIREMENTS.LIBS] + +ZMQ = 4.1.3 + [REQUIREMENTS.MYSQL] ; min MySQL Version ; newer "deviation" of MySQL like "MariaDB" > 10.1 are recommended diff --git a/js/app/map/worker.js b/js/app/map/worker.js index eb744e29..851e1447 100644 --- a/js/app/map/worker.js +++ b/js/app/map/worker.js @@ -120,6 +120,7 @@ define([ }; return { + getWebSocketURL: getWebSocketURL, init: init, send: send }; diff --git a/js/app/setup.js b/js/app/setup.js index 1e133a6c..d6c32146 100644 --- a/js/app/setup.js +++ b/js/app/setup.js @@ -5,19 +5,20 @@ define([ 'jquery', 'app/init', - 'app/util' -], function($, Init, Util) { + 'app/util', + 'app/map/worker' +], function($, Init, Util, MapWorker) { 'use strict'; - var config = { + let config = { splashOverlayClass: 'pf-splash' // class for "splash" overlay }; /** * set page observer */ - var setPageObserver = function(){ - var body = $('body'); + let setPageObserver = () => { + let body = $('body'); // collapse --------------------------------------- body.find('[data-toggle="collapse"]').css({cursor: 'pointer'}).on('click', function(){ @@ -39,10 +40,97 @@ define([ } }; + /** + * perform a basic check if Clients (browser) can connect to the webSocket server + */ + let testWebSocket = () => { + let webSocketPanel = $('#pf-setup-webSocket'); + let WebSocketURI = MapWorker.getWebSocketURL(); + + webSocketPanel.showLoadingAnimation(); + + let removeColorClasses = (el) => { + el.removeClass (function (index, css) { + return (css.match (/\btxt-color-\S+/g) || []).join(' '); + }); + }; + + /** + * updates the WebSocket panel with new data + * @param data + */ + let updateWebSocketPanel = (data) => { + if(data.uri){ + let uriRow = webSocketPanel.find('.panel-body table tr'); + uriRow.find('td:nth-child(2) kbd').text(data.uri.value); + if(data.uri.status){ + let statusIcon = uriRow.find('td:nth-child(3) i'); + removeColorClasses(statusIcon); + + statusIcon.toggleClass('fa-warning', false).toggleClass('fa-check', true).addClass('txt-color-success'); + } + } + + if(data.status){ + let footer = webSocketPanel.find('.panel-footer h3'); + removeColorClasses(footer); + footer.text(data.status.label).addClass(data.status.class); + } + }; + + // update initial + updateWebSocketPanel({ + uri: { + value: WebSocketURI, + status: true + }, + status: { + label: 'CONNECTING...', + class: 'txt-color-warning' + } + }); + + // try to connect to WebSocket server + let socket = new WebSocket(WebSocketURI); + + socket.onopen = (e) => { + updateWebSocketPanel({ + status: { + label: 'CONNECTED', + class: 'txt-color-success' + } + }); + + webSocketPanel.hideLoadingAnimation(); + }; + + socket.onerror = (e) => { + updateWebSocketPanel({ + status: { + label: 'CONNECTION FAILED', + class: 'txt-color-danger' + } + }); + + webSocketPanel.hideLoadingAnimation(); + }; + + socket.onclose = (closeEvent) => { + updateWebSocketPanel({ + status: { + label: 'CONNECTION FAILED', + class: 'txt-color-danger' + } + }); + + webSocketPanel.hideLoadingAnimation(); + }; + }; + /** * main init "setup" page */ - $(function(){ + $(() => { // show app information in browser console -------- Util.showVersionInfo(); @@ -51,5 +139,7 @@ define([ $('.' + config.splashOverlayClass).hideSplashOverlay(); setPageObserver(); + + testWebSocket(); }); }); \ No newline at end of file diff --git a/public/js/v1.2.0/app/map/worker.js b/public/js/v1.2.0/app/map/worker.js index eb744e29..851e1447 100644 --- a/public/js/v1.2.0/app/map/worker.js +++ b/public/js/v1.2.0/app/map/worker.js @@ -120,6 +120,7 @@ define([ }; return { + getWebSocketURL: getWebSocketURL, init: init, send: send }; diff --git a/public/js/v1.2.0/app/setup.js b/public/js/v1.2.0/app/setup.js index 1e133a6c..d6c32146 100644 --- a/public/js/v1.2.0/app/setup.js +++ b/public/js/v1.2.0/app/setup.js @@ -5,19 +5,20 @@ define([ 'jquery', 'app/init', - 'app/util' -], function($, Init, Util) { + 'app/util', + 'app/map/worker' +], function($, Init, Util, MapWorker) { 'use strict'; - var config = { + let config = { splashOverlayClass: 'pf-splash' // class for "splash" overlay }; /** * set page observer */ - var setPageObserver = function(){ - var body = $('body'); + let setPageObserver = () => { + let body = $('body'); // collapse --------------------------------------- body.find('[data-toggle="collapse"]').css({cursor: 'pointer'}).on('click', function(){ @@ -39,10 +40,97 @@ define([ } }; + /** + * perform a basic check if Clients (browser) can connect to the webSocket server + */ + let testWebSocket = () => { + let webSocketPanel = $('#pf-setup-webSocket'); + let WebSocketURI = MapWorker.getWebSocketURL(); + + webSocketPanel.showLoadingAnimation(); + + let removeColorClasses = (el) => { + el.removeClass (function (index, css) { + return (css.match (/\btxt-color-\S+/g) || []).join(' '); + }); + }; + + /** + * updates the WebSocket panel with new data + * @param data + */ + let updateWebSocketPanel = (data) => { + if(data.uri){ + let uriRow = webSocketPanel.find('.panel-body table tr'); + uriRow.find('td:nth-child(2) kbd').text(data.uri.value); + if(data.uri.status){ + let statusIcon = uriRow.find('td:nth-child(3) i'); + removeColorClasses(statusIcon); + + statusIcon.toggleClass('fa-warning', false).toggleClass('fa-check', true).addClass('txt-color-success'); + } + } + + if(data.status){ + let footer = webSocketPanel.find('.panel-footer h3'); + removeColorClasses(footer); + footer.text(data.status.label).addClass(data.status.class); + } + }; + + // update initial + updateWebSocketPanel({ + uri: { + value: WebSocketURI, + status: true + }, + status: { + label: 'CONNECTING...', + class: 'txt-color-warning' + } + }); + + // try to connect to WebSocket server + let socket = new WebSocket(WebSocketURI); + + socket.onopen = (e) => { + updateWebSocketPanel({ + status: { + label: 'CONNECTED', + class: 'txt-color-success' + } + }); + + webSocketPanel.hideLoadingAnimation(); + }; + + socket.onerror = (e) => { + updateWebSocketPanel({ + status: { + label: 'CONNECTION FAILED', + class: 'txt-color-danger' + } + }); + + webSocketPanel.hideLoadingAnimation(); + }; + + socket.onclose = (closeEvent) => { + updateWebSocketPanel({ + status: { + label: 'CONNECTION FAILED', + class: 'txt-color-danger' + } + }); + + webSocketPanel.hideLoadingAnimation(); + }; + }; + /** * main init "setup" page */ - $(function(){ + $(() => { // show app information in browser console -------- Util.showVersionInfo(); @@ -51,5 +139,7 @@ define([ $('.' + config.splashOverlayClass).hideSplashOverlay(); setPageObserver(); + + testWebSocket(); }); }); \ No newline at end of file diff --git a/public/templates/dialog/map_manual.html b/public/templates/dialog/map_manual.html index d8897d14..02bb6ef7 100644 --- a/public/templates/dialog/map_manual.html +++ b/public/templates/dialog/map_manual.html @@ -87,7 +87,7 @@

The "Update counter" starts counting backwards during map interaction. While the counter is active, no data is pushed to server. Once the counter hits 0, all map date will be stored and active pilots will receive the map updates.
- There is no need for any save/edit buttons. + There is no need for any safe/edit buttons.

diff --git a/public/templates/ui/notice.html b/public/templates/ui/notice.html index 8e8ce277..dcf8d45f 100644 --- a/public/templates/ui/notice.html +++ b/public/templates/ui/notice.html @@ -7,11 +7,8 @@
    -
  • NEW option for auto-delete expired (WH) connections
  • -
  • NEW option for hide "current location
  • -
  • improved "Route finder" module
  • -
  • improved "Statistics" module
  • -
  • improved "System notes" UI (new scrollbars)
  • +
  • NEW WebSocket server. Map updates are pushed to clients immediately
  • +
  • NEW "Route finder" option for "safer search" (HighSec)
  • Complete changelog
diff --git a/public/templates/view/login.html b/public/templates/view/login.html index 0177e5d9..290ed67d 100644 --- a/public/templates/view/login.html +++ b/public/templates/view/login.html @@ -846,7 +846,7 @@ Cookies are valid for {{ @PATHFINDER.LOGIN.COOKIE_EXPIRE }} days and will be destroyed on 'logout'. Read more.

-

Are my data save?

+

Are my data safe?

Whoever said, his program is "bullet proof", is lying! But I promise to give my very best to protect any personal or map data that is stored on my server. The login process is handled by CCP´s SSO. There is no account data (or even your EVE Online login data) stored or available to Pathfinder.
diff --git a/public/templates/view/setup.html b/public/templates/view/setup.html index 25f26a00..84e6ae8b 100644 --- a/public/templates/view/setup.html +++ b/public/templates/view/setup.html @@ -92,42 +92,59 @@ - - - - {{@requirement.label}} - - - - - - - {{@requirement.required}} - - - - - - {{@requirement.version}} - - - {{@requirement.version}} - {* Check failed *} - - - - - - - - - - - - - - - + + + {* if for optional divider *} + + + + + +

+ + + + + + + + + + + + +
+ {{@requirement.label}} + + + + + + {{@requirement.required}} + + + + + {{@requirement.version}} + + + {{@requirement.version}} + {* Check failed *} + + + + + + + + + + + + +
@@ -136,7 +153,7 @@ @@ -800,9 +817,9 @@
- +
-
+

{{ @socketData.label }}

@@ -835,10 +852,10 @@