diff --git a/platforms/desktop b/platforms/desktop index e0512d76784980a51651bbdcba636404c552c3e8..b7a2318bcbe6a53487267e8efea75252ab81d851 160000 --- a/platforms/desktop +++ b/platforms/desktop @@ -1 +1 @@ -Subproject commit e0512d76784980a51651bbdcba636404c552c3e8 +Subproject commit b7a2318bcbe6a53487267e8efea75252ab81d851 diff --git a/www/css/style.css b/www/css/style.css index b04d50500cffd20010460c370c08a90647acf80c..98eb8b00530660834077a1ff7c2c6005e5c8ea6d 100644 --- a/www/css/style.css +++ b/www/css/style.css @@ -181,6 +181,18 @@ padding-right: 6px; } +.list .item-peer.compacted { + padding-top: 0px; + padding-bottom: 0px; + min-height: 3px !important; + max-height: 3px !important; + border-bottom: double 1px #ddd !important; +} +.list .item-peer.compacted > * { + display: none; +} + + /********** Block items **********/ diff --git a/www/i18n/locale-en-GB.json b/www/i18n/locale-en-GB.json index 3a59b03c090aefbcbe1c7c168241348e0eb526f9..681aabdd04c6d26081c68b65d440ab5af70fc51d 100644 --- a/www/i18n/locale-en-GB.json +++ b/www/i18n/locale-en-GB.json @@ -47,7 +47,6 @@ "CHOOSE_FILE": "Drag your file<br/>or click to select", "DAYS": "days", "NO_ACCOUNT_QUESTION": "Not a member yet? Register now!", - "HAVE_ACCOUNT_QUESTION": "Ya tienes una cuenta?", "SEARCH_NO_RESULT": "No result found", "LOADING": "Loading...", "LOADING_WAIT": "Loading...<br/><small>(Waiting for node availability)</small>", @@ -302,15 +301,18 @@ "PEERS": "Peers", "SIGNED_ON_BLOCK": "Signed on block", "MIRROR": "mirror", - "MIRRORS": "Mirror peers", + "MIRRORS": "Mirrors", + "MIRROR_PEERS": "Mirror peers", "PEER_LIST" : "Peer's list", - "MEMBERS" : "Member peers", + "MEMBERS" : "Members", + "MEMBER_PEERS" : "Member peers", "ALL_PEERS" : "All peers", "DIFFICULTY" : "Difficulty", "API" : "API", "CURRENT_BLOCK" : "Block #", "POPOVER_FILTER_TITLE": "Filter", - "OFFLINE": "Offline peers", + "OFFLINE": "Offline", + "OFFLINE_PEERS": "Offline peers", "BTN_SHOW_PEER": "Show peer", "VIEW": { "TITLE": "Peer", @@ -410,6 +412,7 @@ "PASSWORD_HELP": "Password", "PUBKEY_HELP": "Public key or pseudonym", "NO_ACCOUNT_QUESTION": "Don't have an account yet?", + "HAVE_ACCOUNT_QUESTION": "Already have an account ?", "CREATE_ACCOUNT": "Create an account", "CREATE_FREE_ACCOUNT": "Create a free account", "FORGOTTEN_ID": "Forgot password?", diff --git a/www/i18n/locale-en.json b/www/i18n/locale-en.json index 58187ba52267837ac3626854e84199690380de77..a9cc920ff94e084c9c4942abb81b1f593e9826f3 100644 --- a/www/i18n/locale-en.json +++ b/www/i18n/locale-en.json @@ -301,15 +301,18 @@ "PEERS": "Peers", "SIGNED_ON_BLOCK": "Signed on block", "MIRROR": "mirror", - "MIRRORS": "Mirror peers", + "MIRRORS": "Mirrors", + "MIRROR_PEERS": "Mirror peers", "PEER_LIST" : "Peer's list", - "MEMBERS" : "Member peers", + "MEMBERS" : "Members", + "MEMBER_PEERS" : "Member peers", "ALL_PEERS" : "All peers", "DIFFICULTY" : "Difficulty", "API" : "API", "CURRENT_BLOCK" : "Block #", "POPOVER_FILTER_TITLE": "Filter", - "OFFLINE": "Offline peers", + "OFFLINE": "Offline", + "OFFLINE_PEERS": "Offline peers", "BTN_SHOW_PEER": "Show peer", "VIEW": { "TITLE": "Peer", diff --git a/www/i18n/locale-es-ES.json b/www/i18n/locale-es-ES.json index 97b26b6a83a1214bb50dc21d36ef6ca75ab2b2db..863ef935ab7acd89ad9ab4472d545f64e3cf6571 100644 --- a/www/i18n/locale-es-ES.json +++ b/www/i18n/locale-es-ES.json @@ -291,15 +291,18 @@ "PEERS": "Nodos", "SIGNED_ON_BLOCK": "Firmado sobre el bloque", "MIRROR": "espejo", - "MIRRORS": "Nodos espejo", + "MIRRORS": "Espejo", + "MIRROR_PEERS": "Nodos espejo", "PEER_LIST": "Lista de nodos", - "MEMBERS": "Nodos miembro", + "MEMBERS": "Miembro", + "MEMBER_PEERS": "Nodos miembro", "ALL_PEERS": "Todos los nodos", "DIFFICULTY": "Dificultad", "API": "API", "CURRENT_BLOCK": "Bloque #", "POPOVER_FILTER_TITLE": "Filtro", - "OFFLINE": "Nodos fuera de lÃnea", + "OFFLINE": "Fuera de lÃnea", + "OFFLINE_PEERS": "Nodos fuera de lÃnea", "BTN_SHOW_PEER": "Ver nodo", "VIEW": { "TITLE": "Nodo", diff --git a/www/i18n/locale-fr-FR.json b/www/i18n/locale-fr-FR.json index 789ab385b6dfef40654075aa93d5d2fb96349af3..77dd988a3c6aa76412e6e99e3ecf9c82b15ad1b4 100644 --- a/www/i18n/locale-fr-FR.json +++ b/www/i18n/locale-fr-FR.json @@ -301,15 +301,18 @@ "PEERS": "NÅ“uds", "SIGNED_ON_BLOCK": "Signé sur le bloc", "MIRROR": "miroir", - "MIRRORS": "NÅ“uds miroirs", + "MIRRORS": "Miroirs", + "MIRROR_PEERS": "NÅ“uds miroirs", "PEER_LIST" : "Liste des nÅ“uds", - "MEMBERS" : "NÅ“uds membres", + "MEMBERS" : "Membres", + "MEMBER_PEERS" : "NÅ“uds membres", "ALL_PEERS" : "Tous les nÅ“uds", "DIFFICULTY" : "Difficulté", "API" : "API", "CURRENT_BLOCK" : "Bloc #", "POPOVER_FILTER_TITLE": "Filtre", - "OFFLINE": "NÅ“uds hors ligne", + "OFFLINE": "Hors ligne", + "OFFLINE_PEERS": "NÅ“uds hors ligne", "BTN_SHOW_PEER": "Voir le nÅ“ud", "VIEW": { "TITLE": "NÅ“ud", diff --git a/www/i18n/locale-it-IT.json b/www/i18n/locale-it-IT.json index 20f1c75d7ca338e3dff2a15b223295f8d6c0c71c..c8e5f1466442de8806b8f69f59a14e17ef6e0116 100644 --- a/www/i18n/locale-it-IT.json +++ b/www/i18n/locale-it-IT.json @@ -287,15 +287,18 @@ "PEERS": "Peers-Nodi", "SIGNED_ON_BLOCK": "Firmato nel blocco", "MIRROR": "Specchio", - "MIRRORS": "Peers specchio", + "MIRRORS": "Specchio", + "MIRROR_PEERS": "Peers specchio", "PEER_LIST" : "Lista dei peers", - "MEMBERS" : "Peers membri", + "MEMBERS" : "Membri", + "MEMBER_PEERS" : "Peers membri", "ALL_PEERS" : "Tutti i peers", "DIFFICULTY" : "Difficoltà ", "API" : "API", "CURRENT_BLOCK" : "Blocco #", "POPOVER_FILTER_TITLE": "Filtro", - "OFFLINE": "Peers sconessi", + "OFFLINE": "Sconessi", + "OFFLINE_PEERS": "Peers sconessi", "BTN_SHOW_PEER": "Mostrare peer", "VIEW": { "TITLE": "Peer", diff --git a/www/js/controllers/blockchain-controllers.js b/www/js/controllers/blockchain-controllers.js index fd32c6cb0a2b8d27a0e7756884a0d834d744b257..4c71d672ca136739daee52a5929083c49326725e 100644 --- a/www/js/controllers/blockchain-controllers.js +++ b/www/js/controllers/blockchain-controllers.js @@ -135,10 +135,9 @@ function BlockLookupController($scope, $timeout, $focus, $filter, $state, $ancho useTor: useTor }; var serverParts = state.stateParams.server.split(':'); - if (serverParts.length == 2 || serverParts.length == 3) { + if (serverParts.length == 2) { node.host = serverParts[0]; node.port = serverParts[1]; - node.wsPort = serverParts[2] || serverParts[1]; } if (BMA.node.same(node.host, node.port)) { @@ -147,8 +146,8 @@ function BlockLookupController($scope, $timeout, $focus, $filter, $state, $ancho else { $scope.node = useTor ? // For TOR, use a web2tor to access the endpoint - BMA.instance(node.host + ".to", 443, 443, true/*ssl*/, 600000 /*long timeout*/) : - BMA.instance(node.host, node.port, node.wsPort, node.useSsl); + BMA.instance(node.host + ".to", 443, true/*ssl*/, 600000 /*long timeout*/) : + BMA.instance(node.host, node.port, node.useSsl); return $scope.node.blockchain.parameters() .then(function(json) { $scope.currency = json.currency; @@ -530,10 +529,9 @@ function BlockViewController($scope, $ionicPopover, $state, UIUtils, BMA, csCurr useTor: useTor }; var serverParts = state.stateParams.server.split(':'); - if (serverParts.length == 2 || serverParts.length == 3) { + if (serverParts.length == 2) { node.host = serverParts[0]; node.port = serverParts[1]; - node.wsPort = serverParts[2] || serverParts[1]; } if (BMA.node.same(node.host, node.port)) { @@ -542,8 +540,8 @@ function BlockViewController($scope, $ionicPopover, $state, UIUtils, BMA, csCurr else { $scope.node = useTor ? // For TOR, use a web2tor to access the endpoint - BMA.instance(node.host + ".to", 443, 443, true/*ssl*/, 600000 /*long timeout*/) : - BMA.instance(node.host, node.port, node.wsPort, node.useSsl); + BMA.instance(node.host + ".to", 443, true/*ssl*/, 600000 /*long timeout*/) : + BMA.instance(node.host, node.port, node.useSsl); return $scope.node.blockchain.parameters() .then(function (json) { $scope.currency = json.currency; diff --git a/www/js/controllers/network-controllers.js b/www/js/controllers/network-controllers.js index 77b9d80a73ab8c83397a968104667f92f2e38857..cfc96a8855583d4854515e3859fd25e3f33bd88e 100644 --- a/www/js/controllers/network-controllers.js +++ b/www/js/controllers/network-controllers.js @@ -60,13 +60,17 @@ function NetworkLookupController($scope, $state, $location, $ionicPopover, $win loading: true, type: undefined, results: [], - endpointFilter: null, + endpoint: null, + bma: undefined, + ssl: undefined, + ws2p: undefined, sort : undefined, asc: true }; + $scope.compactMode = true; $scope.listeners = []; $scope.helptipPrefix = 'helptip-network'; - $scope.eanbleLocationHref = true; // can be overrided by sub-controler (e.g. popup) + $scope.enableLocationHref = true; // can be overrided by sub-controler (e.g. popup) $scope.removeListeners = function() { if ($scope.listeners.length) { @@ -89,7 +93,7 @@ function NetworkLookupController($scope, $state, $location, $ionicPopover, $win .then(function (currency) { if (currency) { $scope.node = !BMA.node.same(currency.node.host, currency.node.port) ? - BMA.instance(currency.node.host, currency.node.port, currency.node.wsPort) : BMA; + BMA.instance(currency.node.host, currency.node.port) : BMA; if (state && state.stateParams) { if (state.stateParams.type && ['mirror', 'member', 'offline'].indexOf(state.stateParams.type) != -1) { $scope.search.type = state.stateParams.type; @@ -128,7 +132,10 @@ function NetworkLookupController($scope, $state, $location, $ionicPopover, $win filter: { member: (!$scope.search.type || $scope.search.type === 'member'), mirror: (!$scope.search.type || $scope.search.type === 'mirror'), - endpointFilter : (angular.isDefined($scope.search.endpointFilter) ? $scope.search.endpointFilter : null), + endpoint : (angular.isDefined($scope.search.endpoint) ? $scope.search.endpoint : null), + bma : $scope.search.bma, + ssl : $scope.search.ssl, + ws2p : $scope.search.ws2p, online: !($scope.search.type && $scope.search.type === 'offline') }, sort: { @@ -145,24 +152,25 @@ function NetworkLookupController($scope, $state, $location, $ionicPopover, $win $scope.load = function() { if ($scope.search.loading){ + // Start network scan csNetwork.start($scope.node, $scope.computeOptions()); // Catch event on new peers $scope.refreshing = false; $scope.listeners.push( csNetwork.api.data.on.changed($scope, function(data){ - if (!$scope.refreshing) { - $scope.refreshing = true; - csWot.extendAll(data.peers) - .then(function() { - // Avoid to refresh if view has been leaving - if ($scope.networkStarted) { - $scope.updateView(data); - } - $scope.refreshing = false; - }); - } - })); + if (!$scope.refreshing) { + $scope.refreshing = true; + csWot.extendAll(data.peers) + .then(function() { + // Avoid to refresh if view has been leaving + if ($scope.networkStarted) { + $scope.updateView(data); + } + $scope.refreshing = false; + }); + } + })); } // Show help tip @@ -217,11 +225,11 @@ function NetworkLookupController($scope, $state, $location, $ionicPopover, $win $scope.toggleSearchEndpoint = function(endpoint){ $scope.hideActionsPopover(); - if ($scope.search.endpointFilter === endpoint || endpoint === null) { - $scope.search.endpointFilter = null; + if ($scope.search.endpoint === endpoint || endpoint === null) { + $scope.search.endpoint = null; } else { - $scope.search.endpointFilter = endpoint; + $scope.search.endpoint = endpoint; } $scope.sort(); }; @@ -238,9 +246,19 @@ function NetworkLookupController($scope, $state, $location, $ionicPopover, $win $scope.sort(); }; + $scope.toggleCompactMode = function() { + $scope.compactMode = !$scope.compactMode; + $scope.$broadcast('$$rebind::' + 'rebind'); // force data binding + }; + $scope.selectPeer = function(peer) { - // Skipp offline or WS2P node - if (!peer.online || peer.isWs2p()) return; + if (peer.compacted && $scope.compactMode) { + $scope.toggleCompactMode(); + return; + } + + // Skipp offline or not a BMA peer + if (!peer.online || !peer.hasBma()) return; var stateParams = {server: peer.getServer()}; if (peer.isSsl()) { @@ -253,7 +271,7 @@ function NetworkLookupController($scope, $state, $location, $ionicPopover, $win }; $scope.$on('csView.action.refresh', function(event, context) { - if (context == 'peers') { + if (context === 'peers') { $scope.refresh(); } }); @@ -288,8 +306,8 @@ function NetworkLookupController($scope, $state, $location, $ionicPopover, $win } }; - $scope.showEndpointsPopover = function($event, peer, endpointFilter) { - var endpoints = peer.getEndpoints(endpointFilter); + $scope.showEndpointsPopover = function($event, peer, endpoint) { + var endpoints = peer.getEndpoints(endpoint); endpoints = (endpoints||[]).reduce(function(res, ep) { var bma = BMA.node.parseEndPoint(ep); return res.concat({ @@ -302,7 +320,7 @@ function NetworkLookupController($scope, $state, $location, $ionicPopover, $win UIUtils.popover.show($event, { templateUrl: 'templates/network/popover_endpoints.html', bindings: { - titleKey: 'NETWORK.VIEW.ENDPOINTS.' + endpointFilter, + titleKey: 'NETWORK.VIEW.ENDPOINTS.' + endpoint, items: endpoints } }); @@ -374,7 +392,10 @@ function NetworkLookupModalController($scope, $controller, parameters) { parameters = parameters || {}; $scope.enableFilter = angular.isDefined(parameters.enableFilter) ? parameters.enableFilter : true; $scope.search.type = angular.isDefined(parameters.type) ? parameters.type : $scope.search.type; - $scope.search.endpointFilter = angular.isDefined(parameters.endpointFilter) ? parameters.endpointFilter : $scope.search.endpointFilter; + $scope.search.endpoint = angular.isDefined(parameters.endpoint) ? parameters.endpoint : $scope.search.endpoint; + $scope.search.bma = angular.isDefined(parameters.bma) ? parameters.bma : $scope.search.bma; + $scope.search.ssl = angular.isDefined(parameters.ssl) ? parameters.ssl : $scope.search.ssl; + $scope.search.ws2p = angular.isDefined(parameters.ws2p) ? parameters.ws2p : $scope.search.ws2p; $scope.expertMode = angular.isDefined(parameters.expertMode) ? parameters.expertMode : $scope.expertMode; $scope.ionItemClass = parameters.ionItemClass || 'item-border-large'; $scope.enableLocationHref = false; @@ -406,7 +427,7 @@ function NetworkLookupPopoverController($scope, $controller) { var parameters = parameters || {}; $scope.enableFilter = angular.isDefined(parameters.enableFilter) ? parameters.enableFilter : true; $scope.search.type = angular.isDefined(parameters.type) ? parameters.type : $scope.search.type; - $scope.search.endpointFilter = angular.isDefined(parameters.endpointFilter) ? parameters.endpointFilter : $scope.search.endpointFilter; + $scope.search.endpoint = angular.isDefined(parameters.endpoint) ? parameters.endpoint : $scope.search.endpoint; $scope.expertMode = angular.isDefined(parameters.expertMode) ? parameters.expertMode : $scope.expertMode; $scope.ionItemClass = parameters.ionItemClass || 'item-border-large'; $scope.helptipPrefix = ''; @@ -552,14 +573,13 @@ function PeerViewController($scope, $q, $window, $state, UIUtils, csWot, BMA) { if (serverParts.length == 2) { node.host = serverParts[0]; node.port = serverParts[1]; - node.wsPort = serverParts[2] || serverParts[1]; } angular.merge($scope.node, useTor ? // For TOR, use a web2tor to access the endpoint - BMA.lightInstance(node.host + ".to", 443, 443, true/*ssl*/, 60000 /*long timeout*/) : - BMA.lightInstance(node.host, node.port, node.wsPort, node.useSsl), + BMA.lightInstance(node.host + ".to", 443, true/*ssl*/, 60000 /*long timeout*/) : + BMA.lightInstance(node.host, node.port, node.useSsl), node); $scope.isReachable = !$scope.isHttps || useSsl; @@ -612,8 +632,9 @@ function PeerViewController($scope, $q, $window, $state, UIUtils, csWot, BMA) { .then(function(json) { var peers = json.peers.map(function (p) { var peer = new Peer(p); - peer.online = p.status == 'UP'; - peer.blockNumber = peer.block.replace(/-.+$/, ''); + peer.online = p.status === 'UP'; + peer.buid = peer.block; + peer.blockNumber = peer.buid && peer.buid.split('-')[0]; peer.dns = peer.getDns(); peer.id = peer.keyID(); peer.server = peer.getServer(); diff --git a/www/js/controllers/settings-controllers.js b/www/js/controllers/settings-controllers.js index eac077076c402df1efc9ff928b5ae208780dc07f..56f53743ca3f7906865234e8eef6af5bf9cb10b9 100644 --- a/www/js/controllers/settings-controllers.js +++ b/www/js/controllers/settings-controllers.js @@ -20,8 +20,8 @@ angular.module('cesium.settings.controllers', ['cesium.services', 'cesium.curren .controller('SettingsCtrl', SettingsController) ; -function SettingsController($scope, $q, $ionicHistory, $ionicPopup, $timeout, $translate, $ionicPopover, - UIUtils, Modals, BMA, csHttp, csCurrency, csSettings, csPlatform) { +function SettingsController($scope, $q, $window, $ionicHistory, $ionicPopup, $timeout, $translate, $ionicPopover, + UIUtils, Modals, BMA, csHttp, csConfig, csCurrency, csSettings, csPlatform) { 'ngInject'; $scope.formData = angular.copy(csSettings.data); @@ -193,8 +193,16 @@ function SettingsController($scope, $q, $ionicHistory, $ionicPopup, $timeout, $t }; $scope.showNodeList = function() { + // Check if need a filter on SSL node + var forceUseSsl = (csConfig.httpsMode === 'true' || csConfig.httpsMode === true || csConfig.httpsMode === 'force') || + ($window.location && $window.location.protocol === 'https:') ? true : false; + $ionicPopup._popupStack[0].responseDeferred.promise.close(); - return Modals.showNetworkLookup({enableFilter: true, type: 'member'}) + return Modals.showNetworkLookup({ + enableFilter: true, // enable filter button + bma: true, // only BMA node + ssl: forceUseSsl ? true : undefined + }) .then(function (peer) { if (peer) { var bma = peer.getBMA(); @@ -202,7 +210,7 @@ function SettingsController($scope, $q, $ionicHistory, $ionicPopup, $timeout, $t host: (bma.dns ? bma.dns : (peer.hasValid4(bma) ? bma.ipv4 : bma.ipv6)), port: bma.port || 80, - useSsl: bma.useSsl + useSsl: bma.useSsl || bma.port == 443 }; } }) diff --git a/www/js/entities/peer.js b/www/js/entities/peer.js index cd9649e3caab64f1112122bd1e7834b83c6c3110..7bd9491e648f0acd4144d88734f65910262b820e 100644 --- a/www/js/entities/peer.js +++ b/www/js/entities/peer.js @@ -101,7 +101,6 @@ Peer.prototype.hasEndpoint = function(endpoint){ var endpoints = this.getEndpoints(regExp); if (!endpoints.length) return false; else return true; - }; Peer.prototype.getDns = function() { @@ -166,7 +165,6 @@ Peer.prototype.isTor = function() { return bma.useTor; }; - Peer.prototype.isWs2p = function() { var bma = this.bma || this.getBMA(); return bma.useWs2p; @@ -176,3 +174,7 @@ Peer.prototype.isBma = function() { var bma = this.bma || this.getBMA(); return !bma.useWs2p && !bma.useTor; }; + +Peer.prototype.hasBma = function() { + return this.hasEndpoint('(BASIC_MERKLE_API|BMAS|BMATOR)'); +}; diff --git a/www/js/services/bma-services.js b/www/js/services/bma-services.js index 3a8f2aa6cf363b6801e4cfa753b62a9ee21f491c..658a619ec652a8db6aebee46e4e89e2a6b2deb2b 100644 --- a/www/js/services/bma-services.js +++ b/www/js/services/bma-services.js @@ -20,21 +20,28 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. OUTPUT_OBJ = 'OBJ\\(([0-9]+)\\)', OUTPUT_OBJ_OPERATOR = OUTPUT_OBJ + '[ ]*' + OUTPUT_OPERATOR + '[ ]*' + OUTPUT_OBJ, REGEX_ENDPOINT_PARAMS = "( ([a-z_][a-z0-9-_.ÄŸÄž]*))?( ([0-9.]+))?( ([0-9a-f:]+))?( ([0-9]+))( (.+))?", + api = { + BMA: 'BASIC_MERKLED_API', + BMAS: 'BMAS', + WS2P: 'WS2P', + BMATOR: 'BMATOR', + WS2PTOR: 'WS2PTOR' + }, regexp = { USER_ID: "[A-Za-z0-9_-]+", CURRENCY: "[A-Za-z0-9_-]+", PUBKEY: pubkey, - PUBKEY_WITH_CHECKSUM: "(" + pubkey +")" + ":([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{3})", + PUBKEY_WITH_CHECKSUM: "(" + pubkey +"):([123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{3})", COMMENT: "[ a-zA-Z0-9-_:/;*\\[\\]()?!^\\+=@&~#{}|\\\\<>%.]*", INVALID_COMMENT_CHARS: "[^ a-zA-Z0-9-_:/;*\\[\\]()?!^\\+=@&~#{}|\\\\<>%.]*", // duniter://[uid]:[pubkey]@[host]:[port] URI_WITH_AT: "duniter://(?:([A-Za-z0-9_-]+):)?("+pubkey+"@([a-zA-Z0-9-.]+.[ a-zA-Z0-9-_:/;*?!^\\+=@&~#|<>%.]+)", URI_WITH_PATH: "duniter://([a-zA-Z0-9-.]+.[a-zA-Z0-9-_:.]+)/("+pubkey+")(?:/([A-Za-z0-9_-]+))?", BMA_ENDPOINT: "BASIC_MERKLED_API" + REGEX_ENDPOINT_PARAMS, - BMAS_ENDPOINT: "BMAS" + REGEX_ENDPOINT_PARAMS, - WS2P_ENDPOINT: "WS2P ([a-f0-9]{8})"+ REGEX_ENDPOINT_PARAMS, - BMATOR_ENDPOINT: "BMATOR ([a-z0-9-_.]*|[0-9.]+|[0-9a-f:]+.onion)(?: ([0-9]+))?", - WS2PTOR_ENDPOINT: "WS2PTOR ([a-f0-9]{8}) ([a-z0-9-_.]*|[0-9.]+|[0-9a-f:]+.onion)(?: ([0-9]+))?(?: (.+))?" + BMAS_ENDPOINT: api.BMAS + REGEX_ENDPOINT_PARAMS, + WS2P_ENDPOINT: api.WS2P + " ([a-f0-9]{8})"+ REGEX_ENDPOINT_PARAMS, + BMATOR_ENDPOINT: api.BMATOR + " ([a-z0-9-_.]*|[0-9.]+|[0-9a-f:]+.onion)(?: ([0-9]+))?", + WS2PTOR_ENDPOINT: api.WS2PTOR + " ([a-f0-9]{8}) ([a-z0-9-_.]*|[0-9.]+|[0-9a-f:]+.onion)(?: ([0-9]+))?(?: (.+))?" }, errorCodes = { REVOCATION_ALREADY_REGISTERED: 1002, @@ -58,8 +65,8 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. ROOT_BLOCK_HASH: 'E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855', LIMIT_REQUEST_COUNT: 5, // simultaneous async request to a Duniter node LIMIT_REQUEST_DELAY: 1000, // time (in second) to wait between to call of a rest request - regex: regexp, // deprecated - regexp: regexp + regexp: regexp, + api: api }, listeners, that = this; @@ -921,9 +928,7 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. var service = new BMA(undefined, undefined, undefined, true); service.instance = function(host, port, useSsl, useCache) { - var bma = new BMA(); - bma.init(host, port, useSsl, useCache); - return bma; + return new BMA(host, port, useSsl, useCache); }; service.lightInstance = function(host, port, useSsl, timeout) { diff --git a/www/js/services/http-services.js b/www/js/services/http-services.js index a871ce92c0ed85cb51ccfb97234f0c4a76bb3e23..25974e689047533df16f26a601a8240b2e01511a 100644 --- a/www/js/services/http-services.js +++ b/www/js/services/http-services.js @@ -166,11 +166,11 @@ angular.module('cesium.http.services', ['cesium.cache.services']) } if (self.waitDuration >= timeout) { - console.debug("[http] Will retry opening websocket later..."); - self.waitRetryDelay = 2000; // 2 seconds + self.waitRetryDelay = self.waitRetryDelay && Math.min(self.waitRetryDelay + 2000, 30000) || 2000; // add 2 seconds, until 30s) + console.debug("[http] Will retry websocket [{0}] in {1}s...".format(self.path, Math.round(self.waitRetryDelay/1000))); } - else { - console.debug('[http] Waiting websocket ['+self.path+'] opening...'); + else if (Math.round(self.waitDuration / 1000) % 10 === 0){ + console.debug('[http] Waiting websocket ['+self.path+']...'); } return $timeout(function(){ @@ -202,7 +202,7 @@ angular.module('cesium.http.services', ['cesium.cache.services']) sockets.push(self); self.delegate.openTime = Date.now(); }; - self.delegate.onclose = function() { + self.delegate.onclose = function(closeEvent) { // Remove from sockets arrays var index = _.findIndex(sockets, function(socket){return socket.path === self.path;}); @@ -217,12 +217,24 @@ angular.module('cesium.http.services', ['cesium.cache.services']) // If unexpected close event, reopen the socket (fix #535) else { - console.debug('[http] Unexpected close of websocket ['+path+'] (open '+ (Date.now() - self.delegate.openTime) +'ms ago): re-opening...'); + if (self.delegate.openTime) { + console.debug('[http] Unexpected close of websocket [{0}] (open {1} ms ago): re-opening...', path, (Date.now() - self.delegate.openTime)); - self.delegate = null; + // Force new connection + self.delegate = null; + + // Loop, but without the already registered callback + _open(self, null, params); + } + else if (closeEvent) { + console.debug('[http] TODO -- Unexpected close of websocket [{0}]: error code: '.format(path), closeEvent); + + // Force new connection + self.delegate = null; - // Loop, but without the already registered callback - _open(self, null, params); + // Loop, but without the already registered callback + _open(self, null, params); + } } }; }); @@ -472,8 +484,7 @@ angular.module('cesium.http.services', ['cesium.cache.services']) } function isVersionCompatible(minVersion, actualVersion) { - // TODO: add implementation - console.debug('[http] TODO: implement check version [{0}] compatible with [{1}]'.format(actualVersion, minVersion)); + console.debug('[http] Checking actual version [{0}] is compatible with min expected version [{1}]'.format(actualVersion, minVersion)); return compareVersionNumbers(minVersion, actualVersion) <= 0; } diff --git a/www/js/services/network-services.js b/www/js/services/network-services.js index 1484840cdbc45ef36f6e13ca2839a66943571b7e..00c5945e0f397dbbbd4de4dd113e32c28470f714 100644 --- a/www/js/services/network-services.js +++ b/www/js/services/network-services.js @@ -1,15 +1,16 @@ -angular.module('cesium.network.services', ['ngApi', 'cesium.bma.services', 'cesium.http.services']) +angular.module('cesium.network.services', ['ngApi', 'cesium.currency.services', 'cesium.http.services']) -.factory('csNetwork', function($rootScope, $q, $interval, $timeout, $window, csConfig, BMA, csHttp, Api) { +.factory('csNetwork', function($rootScope, $q, $interval, $timeout, $window, csConfig, BMA, csHttp, csCurrency, Api) { 'ngInject'; - factory = function(id) { + function csNetwork(id) { var interval, constants = { - UNKNOWN_BUID: -1 + UNKNOWN_BUID: -1, + MAX_BLOCK_OFFSET: 1000 }, isHttpsMode = $window.location.protocol === 'https:', api = new Api(this, "csNetwork-" + id), @@ -22,18 +23,22 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.bma.services', 'cesi filter: { member: true, mirror: true, - endpointFilter: null, + endpoint: null, online: false, + bma: false, ssl: undefined, tor: undefined }, sort:{ type: null, - asc: true + asc: true, + compact: true }, + groupBy: 'pubkey', expertMode: false, knownBlocks: [], mainBlock: null, + minOnlineBlockNumber: 0, uidsByPubkeys: null, searchingPeersOnNetwork: false, difficulties: null, @@ -53,17 +58,22 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.bma.services', 'cesi data.filter = { member: true, mirror: true, - endpointFilter: null, - online: true + endpoint: null, + online: true, + bma: false, + ssl: undefined, + tor: undefined }; data.sort = { type: null, asc: true }; + data.groupBy = 'pubkey'; data.expertMode = false; data.memberPeersCount = 0; data.knownBlocks = []; data.mainBlock = null; + data.minOnlineBlockNumber = 0; data.uidsByPubkeys = {}; data.loading = true; data.searchingPeersOnNetwork = false; @@ -172,8 +182,8 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.bma.services', 'cesi data.uidsByPubkeys = uids; }) .catch(function(err) { + console.error(err); data.uidsByPubkeys = {}; - //throw err; }), // Load WS2P heads @@ -186,99 +196,96 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.bma.services', 'cesi } return $q.all(initJobs) - .then(function(){ - // online nodes + .then(function() { + return data.bma.network.peers(); + }) + .then(function(res){ + if (!res || !res.peers || !res.peers.length) return; + + // If filter online peers if (data.filter.online) { - /*return data.bma.network.peering.peers({leaves: true}) - .then(function(res){ - return $q.all(res.leaves.map(function(leaf) { - return data.bma.network.peering.peers({ leaf: leaf }) - .then(function(subres){ - return addOrRefreshPeerFromJson(subres.leaf.value, newPeers); - }); - })); - });*/ - return data.bma.network.peers() - .then(function(res){ - var jobs = []; - _.forEach(res.peers, function(json) { - if (json.status == 'UP') { - jobs.push(addOrRefreshPeerFromJson(json, newPeers)); - - // Mark WS2P - _.forEach(json.endpoints||[], function(ep) { - if (ep.startsWith('WS2P')) { - var key = json.pubkey + '-' + ep.split(' ')[1]; - if (data.ws2pHeads[key]) { - data.ws2pHeads[key].hasEndpoint = true; - } - } - }); - } - }); - - // Add private WS2P endpoints - var privateWs2pHeads = _.values(data.ws2pHeads); - if (privateWs2pHeads && privateWs2pHeads.length) { - var privateEPCount = 0; - //console.debug("[http] Found WS2P endpoints without endpoint:", data.ws2pHeads); - _.forEach(privateWs2pHeads, function(head) { - if (!head.hasEndPoint) { - var peer = new Peer({ - buid: head.buid, - currentNumber: head.buid && head.buid.split('-')[0], - pubkey: head.pubkey, - version: head.version, - powPrefix: head.powPrefix, - online: true, - uid: data.uidsByPubkeys[head.pubkey], - bma: { - useWs2p: true, - private: true, - ws2pid: head.ws2pid - }, - endpoints: [ - // fake endpoint - 'WS2P ' + head.ws2pid - ] - }); - peer.id = peer.keyID(); - if (peer.uid && data.expertMode && data.difficulties) { - peer.difficulty = data.difficulties[peer.uid]; - } - if (applyPeerFilter(peer)) { - newPeers.push(peer); - privateEPCount++; - } - } - }); + var jobs = []; + _.forEach(res.peers, function(json) { + // Exclude, if not UP or on a too old block + if (json.status !== 'UP') return; + json.blockNumber = json.block && parseInt(json.block.split('-')[0]); + if (json.blockNumber && json.blockNumber < data.minOnlineBlockNumber) { + console.debug("[network] Exclude a too old peer document, on pubkey {0}".format(json.pubkey.substring(0,6))); + return; + } - if (privateEPCount) { - console.debug("[http] Found {0} WS2P endpoints without endpoint (private ?)".format(privateEPCount)); + jobs.push(addOrRefreshPeerFromJson(json, newPeers)); + + // Mark WS2P + _.forEach(json.endpoints||[], function(ep) { + if (ep.startsWith('WS2P')) { + var key = json.pubkey + '-' + ep.split(' ')[1]; + if (data.ws2pHeads[key]) { + data.ws2pHeads[key].hasEndpoint = true; } } - - if (jobs.length) return $q.all(jobs); - }) - .catch(function(err) { - // Log and continue - console.error(err); }); - } + }); - // offline nodes - return data.bma.network.peers() - .then(function(res){ - var jobs = []; - _.forEach(res.peers, function(json) { - if (json.status !== 'UP') { - jobs.push(addOrRefreshPeerFromJson(json, newPeers)); + // Add private WS2P endpoints + var privateWs2pHeads = _.values(data.ws2pHeads); + if (privateWs2pHeads && privateWs2pHeads.length) { + var privateEPCount = 0; + //console.debug("[http] Found WS2P endpoints without endpoint:", data.ws2pHeads); + _.forEach(privateWs2pHeads, function(head) { + + if (!head.hasEndPoint) { + var currentNumber = head.buid && parseInt(head.buid.split('-')[0]); + // Exclude if on a too old block + if (currentNumber && currentNumber < data.minOnlineBlockNumber) { + console.debug("[network] Exclude a too old WS2P message, on pubkey {0}".format(head.pubkey.substring(0,6))); + return; + } + + var peer = new Peer({ + buid: head.buid, + currentNumber: currentNumber, + pubkey: head.pubkey, + version: head.version, + powPrefix: head.powPrefix, + online: true, + uid: data.uidsByPubkeys[head.pubkey], + bma: { + useWs2p: true, + private: true, + ws2pid: head.ws2pid + }, + endpoints: [ + // fake endpoint + 'WS2P ' + head.ws2pid + ] + }); + peer.id = peer.keyID(); + if (peer.uid && data.expertMode && data.difficulties) { + peer.difficulty = data.difficulties[peer.uid]; + } + if (applyPeerFilter(peer)) { + newPeers.push(peer); + privateEPCount++; + } } }); - if (jobs.length) return $q.all(jobs); - }); - }) + if (privateEPCount) { + console.debug("[http] Found {0} WS2P endpoints without endpoint (private ?)".format(privateEPCount)); + } + } + + if (jobs.length) return $q.all(jobs); + } + + // If filter offline peers + else { + return $q.all(_(res && res.peers || []).reduce(function(res, json) { + return res.concat(addOrRefreshPeerFromJson(json, newPeers)); + }, [])); + } + }) .then(function(){ data.searchingPeersOnNetwork = false; }) @@ -301,13 +308,23 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.bma.services', 'cesi return false; } - // Filter on endpoints - if (data.filter.endpointFilter && !peer.hasEndpoint(data.filter.endpointFilter)) { + // Filter on endpoint + if (data.filter.endpoint && !peer.hasEndpoint(data.filter.endpoint)) { return false; } // Filter on status - if (!data.filter.online && peer.status == 'UP') { + if ((data.filter.online && peer.status !== 'UP' && peer.oldBlock) || (!data.filter.online && peer.status === 'UP' && !peer.oldBlock)) { + return false; + } + + // Filter on bma + if (angular.isDefined(data.filter.bma) && peer.isBma() != data.filter.bma) { + return false; + } + + // Filter on ws2p + if (angular.isDefined(data.filter.ws2p) && peer.isWs2p() != data.filter.ws2p) { return false; } @@ -327,6 +344,10 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.bma.services', 'cesi addOrRefreshPeerFromJson = function(json, list) { list = list || data.newPeers; + // Analyze the peer document, and exclude using the online filter + json.blockNumber = json.block && parseInt(json.block.split('-')[0]); + json.oldBlock = (json.status === 'UP' && json.blockNumber && json.blockNumber < data.minOnlineBlockNumber); + var peers = createPeerEntities(json); var hasUpdates = false; @@ -410,7 +431,8 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.bma.services', 'cesi peer.bma = ep; peer.server = peer.getServer(); peer.dns = peer.getDns(); - peer.blockNumber = peer.block && peer.block.replace(/-.+$/, ''); + peer.buid = peer.buid || peer.block; + peer.blockNumber = peer.buid && parseInt(peer.buid.split('-')[0]); peer.uid = peer.pubkey && data.uidsByPubkeys[peer.pubkey]; peer.id = peer.keyID(); return [peer]; @@ -421,7 +443,7 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.bma.services', 'cesi // Apply filter if (!applyPeerFilter(peer)) return $q.when(); - if (!data.filter.online || (data.filter.online === 'all' && peer.status === 'DOWN') || !peer.getHost() /*fix #537*/) { + if (!data.filter.online || (!data.filter.online && peer.status === 'DOWN') || !peer.getHost() /*fix #537*/) { peer.online = false; return $q.when(peer); } @@ -432,7 +454,7 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.bma.services', 'cesi delete data.ws2pHeads[ws2pHeadKey]; if (head) { peer.buid = head.buid; - peer.currentNumber=peer.buid && peer.buid.split('-')[0]; + peer.currentNumber=head.buid && parseInt(head.buid.split('-')[0]); peer.version = head.version; peer.powPrefix = head.powPrefix; } @@ -460,7 +482,7 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.bma.services', 'cesi // Do not try to access TOR or WS2P endpoints if (peer.bma.useTor || peer.bma.useWs2p) { - peer.online = (peer.status == 'UP'); + peer.online = (peer.status === 'UP'); peer.buid = constants.UNKNOWN_BUID; delete peer.version; @@ -494,7 +516,7 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.bma.services', 'cesi } if (!peer.secondTry) { var bma = peer.bma || peer.getBMA(); - if (bma.dns && peer.server.indexOf(bma.dns) == -1) { + if (bma.dns && peer.server.indexOf(bma.dns) === -1) { // try again, using DNS instead of IPv4 / IPV6 peer.secondTry = true; peer.api = BMA.lightInstance(bma.dns, bma.port, bma.useSsl); @@ -502,9 +524,10 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.bma.services', 'cesi } } - peer.online=false; - peer.currentNumber = null; peer.buid = null; + peer.blockNumber = null; + peer.currentNumber = null; + peer.online=false; peer.uid = data.uidsByPubkeys[peer.pubkey]; return peer; }) @@ -588,8 +611,8 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.bma.services', 'cesi if (!buid || !buid.medianTime) { buid = { buid: peer.buid, - count: 0, - medianTime: peer.medianTime + medianTime: peer.medianTime, + count: 0 }; buids[peer.buid] = buid; } @@ -597,42 +620,44 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.bma.services', 'cesi else if (!buid.medianTime && peer.medianTime) { buid.medianTime = peer.medianTime; } - if (buid.buid != constants.UNKNOWN_BUID) { + if (buid.buid !== constants.UNKNOWN_BUID) { buid.count++; } } data.memberPeersCount += peer.uid ? 1 : 0; }); - // Compute pct of use, per buid - _.forEach(_.values(buids), function(buid) { - buid.pct = buid.count * 100 / data.peers.length; - }); - var mainBlock = _.max(buids, function(obj) { - return obj.count; - }); - _.forEach(data.peers, function(peer){ - peer.hasMainConsensusBlock = peer.buid == mainBlock.buid; - peer.hasConsensusBlock = peer.buid && !peer.hasMainConsensusBlock && buids[peer.buid].count > 1; - if (peer.hasConsensusBlock) { - peer.consensusBlockDelta = buids[peer.buid].medianTime - mainBlock.medianTime; - } - }); + var mainBlock = data.mainBlock; + if (data.filter.online) { + // Compute pct of use, per buid + _.forEach(_.values(buids), function(buid) { + buid.pct = buid.count * 100 / data.peers.length; + }); + mainBlock = _.max(buids, function(obj) { + return obj.count; + }); + _.forEach(data.peers, function(peer){ + peer.hasMainConsensusBlock = peer.buid === mainBlock.buid; + peer.hasConsensusBlock = peer.buid && !peer.hasMainConsensusBlock && buids[peer.buid].count > 1; + if (peer.hasConsensusBlock) { + peer.consensusBlockDelta = buids[peer.buid].medianTime - mainBlock.medianTime; + } + }); + } data.peers = _.uniq(data.peers, false, function(peer) { return peer.id; }); data.peers = _.sortBy(data.peers, function(peer) { var score = 0; if (data.sort.type) { - var sortScore = 0; - sortScore += (data.sort.type == 'uid' ? computeScoreAlphaValue(peer.uid||peer.pubkey, 3, data.sort.asc) : 0); - sortScore += (data.sort.type == 'api') && + score += (data.sort.type === 'uid' ? computeScoreAlphaValue(peer.uid||peer.pubkey, 3, data.sort.asc) : 0); + score += (data.sort.type === 'api') && ((peer.isWs2p() && (data.sort.asc ? 1 : -1) || 0) + (peer.hasEndpoint('ES_USER_API') && (data.sort.asc ? 0.01 : -0.01) || 0) + (peer.isSsl() && (data.sort.asc ? 0.75 : -0.75) || 0)) || 0; - sortScore += (data.sort.type == 'difficulty' ? (peer.difficulty ? (data.sort.asc ? (10000-peer.difficulty) : peer.difficulty): 0) : 0); - sortScore += (data.sort.type == 'current_block' ? (peer.currentNumber ? (data.sort.asc ? (1000000000 - peer.currentNumber) : peer.currentNumber) : 0) : 0); - score += (10000000000 * sortScore); + score += (data.sort.type === 'difficulty' ? (peer.difficulty ? (data.sort.asc ? (10000-peer.difficulty) : peer.difficulty): 0) : 0); + score += (data.sort.type === 'current_block' ? (peer.currentNumber ? (data.sort.asc ? (1000000000 - peer.currentNumber) : peer.currentNumber) : 0) : 0); } + score = (10000000000 * score); score += (1000000000 * (peer.online ? 1 : 0)); score += (100000000 * (peer.hasMainConsensusBlock ? 1 : 0)); score += (1000000 * (peer.hasConsensusBlock ? buids[peer.buid].pct : 0)); @@ -644,9 +669,18 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.bma.services', 'cesi score += (100 * (peer.uid ? computeScoreAlphaValue(peer.uid, 2, true) : 0)); score += (1 * (!peer.uid ? computeScoreAlphaValue(peer.pubkey, 2, true) : 0)); } + score += (peer.isBma() ? (peer.isSsl() ? 0.01 : 0.001) :0); // If many endpoints: BMAS first, then BMA return -score; }); + if (data.groupBy) { + var previousPeer; + data.peers.forEach(function(peer) { + peer.compacted = (previousPeer && peer[data.groupBy] && peer[data.groupBy] === previousPeer[data.groupBy]); + previousPeer = peer; + }); + } + // Raise event on new main block if (updateMainBuid && mainBlock.buid && (!data.mainBlock || data.mainBlock.buid !== mainBlock.buid)) { data.mainBlock = mainBlock; @@ -718,11 +752,23 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.bma.services', 'cesi return BMA.ready() .then(function() { close(); + data.bma = bma ? bma : BMA; data.filter = options.filter ? angular.merge(data.filter, options.filter) : data.filter; data.sort = options.sort ? angular.merge(data.sort, options.sort) : data.sort; data.expertMode = angular.isDefined(options.expertMode) ? options.expertMode : data.expertMode; data.timeout = angular.isDefined(options.timeout) ? options.timeout : csConfig.timeout; + + // Init a min block number + data.minOnlineBlockNumber = data.mainBlock && data.mainBlock.buid && (parseInt(data.mainBlock.buid.split('-')[0]) - constants.MAX_BLOCK_OFFSET) || undefined; + if (data.minOnlineBlockNumber === undefined) { + return csCurrency.blockchain.current(true/*use cache*/) + .then(function(current) { + data.minOnlineBlockNumber = current.number - constants.MAX_BLOCK_OFFSET; + }); + } + }) + .then(function() { console.info('[network] Starting network from [{0}]'.format(bma.server)); var now = Date.now(); @@ -799,8 +845,11 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.bma.services', 'cesi }; }; - var service = factory('default'); + var service = csNetwork('default'); + + service.instance = function(id) { + return new csNetwork(id); + }; - service.instance = factory; return service; }); diff --git a/www/plugins/es/js/controllers/settings-controllers.js b/www/plugins/es/js/controllers/settings-controllers.js index 6723dd30a311c3c21a7f7a2e750907dc29634ba5..fbc14baad5a970bbef788f171d0032bdf843c82c 100644 --- a/www/plugins/es/js/controllers/settings-controllers.js +++ b/www/plugins/es/js/controllers/settings-controllers.js @@ -48,7 +48,8 @@ function ESExtendSettingsController ($scope, PluginService) { /* * Settings extend controller */ -function ESPluginSettingsController ($scope, $q, $translate, $ionicPopup, UIUtils, Modals, csHttp, csSettings, esHttp, esSettings) { +function ESPluginSettingsController ($scope, $window, $q, $translate, $ionicPopup, + UIUtils, Modals, csHttp, csConfig, csSettings, esHttp, esSettings) { 'ngInject'; $scope.formData = {}; @@ -93,7 +94,6 @@ function ESPluginSettingsController ($scope, $q, $translate, $ionicPopup, UIUti node = node || { host: $scope.formData.host, port: $scope.formData.port && $scope.formData.port != 80 && $scope.formData.port != 443 ? $scope.formData.port : undefined, - wsPort: $scope.formData.wsPort && $scope.formData.wsPort != $scope.formData.port ? $scope.formData.wsPort : undefined, useSsl: angular.isDefined($scope.formData.useSsl) ? $scope.formData.useSsl : ($scope.formData.port == 443) @@ -103,14 +103,13 @@ function ESPluginSettingsController ($scope, $q, $translate, $ionicPopup, UIUti .then(function(newNode) { if (newNode.host == $scope.formData.host && newNode.port == $scope.formData.port && - newNode.wsPort == $scope.formData.wsPort && newNode.useSsl == $scope.formData.useSsl) { UIUtils.loading.hide(); return; // same node = nothing to do } UIUtils.loading.show(); - var newEsNode = esHttp.instance(newNode.host, newNode.port, newNode.wsPort, newNode.useSsl); + var newEsNode = esHttp.instance(newNode.host, newNode.port, newNode.useSsl); return newEsNode.isAlive() // ping the node .then(function(alive) { if (!alive) { @@ -123,7 +122,6 @@ function ESPluginSettingsController ($scope, $q, $translate, $ionicPopup, UIUti $scope.formData.host = newEsNode.host; $scope.formData.port = newEsNode.port; - $scope.formData.wsPort = newEsNode.wsPort; $scope.formData.useSsl = newEsNode.useSsl; return esHttp.copy(newEsNode); @@ -138,13 +136,10 @@ function ESPluginSettingsController ($scope, $q, $translate, $ionicPopup, UIUti // Show node popup $scope.showNodePopup = function(node) { + return $q(function(resolve, reject) { var parts = [node.host]; - if (node.wsPort && node.wsPort != (node.port||80)) { - parts.push(node.port||80); - parts.push(node.wsPort); - } - else if (node.port && node.port != 80) { + if (node.port && node.port != 80) { parts.push(node.port); } $scope.popupData.newNode = parts.join(':'); @@ -187,7 +182,6 @@ function ESPluginSettingsController ($scope, $q, $translate, $ionicPopup, UIUti resolve({ host: parts[0], port: parts[1] || (useSsl ? 443 : 80), - wsPort: parts[2] || parts[1] || (useSsl ? 443 : 80), useSsl: useSsl }); }); @@ -196,10 +190,15 @@ function ESPluginSettingsController ($scope, $q, $translate, $ionicPopup, UIUti }; $scope.showNodeList = function() { + // Check if need a filter on SSL node + var forceUseSsl = (csConfig.httpsMode === 'true' || csConfig.httpsMode === true || csConfig.httpsMode === 'force') || + ($window.location && $window.location.protocol === 'https:') ? true : false; + $ionicPopup._popupStack[0].responseDeferred.promise.close(); return Modals.showNetworkLookup({ enableFilter: true, - endpointFilter: esHttp.constants.ES_USER_API_ENDPOINT + endpoint: esHttp.constants.ES_USER_API_ENDPOINT, + ssl: forceUseSsl ? true: undefined }) .then(function (peer) { if (!peer) return; @@ -212,14 +211,11 @@ function ESPluginSettingsController ($scope, $q, $translate, $ionicPopup, UIUti return { host: (ep.dns ? ep.dns : (peer.hasValid4(ep) ? ep.ipv4 : ep.ipv6)), - port: ep.port || 80 + port: ep.port || 80, + useSsl: ep.useSsl || ep.port == 443 }; }) .then(function(newEsNode) { - if (!newEsNode) { - UIUtils.alert.error('ERROR.INVALID_NODE_SUMMARY'); - return; - } $scope.changeEsNode(newEsNode); }); }; @@ -257,7 +253,6 @@ function ESPluginSettingsController ($scope, $q, $translate, $ionicPopup, UIUti $scope.getServer = function(node) { node = node || $scope.formData; if (!node.host) return undefined; - var server = csHttp.getServer(node.host, node.port); - return server + (node.wsPort && node.wsPort != node.port ? ':' + node.wsPort : ''); + return csHttp.getServer(node.host, node.port); }; } diff --git a/www/plugins/es/js/controllers/subscription-controllers.js b/www/plugins/es/js/controllers/subscription-controllers.js index cbb63ace42febf5462ffbf748fae559c01142b26..397bf94c6bd327739ca67e1b0851ccfe90ae2163 100644 --- a/www/plugins/es/js/controllers/subscription-controllers.js +++ b/www/plugins/es/js/controllers/subscription-controllers.js @@ -324,7 +324,8 @@ function ModalEmailSubscriptionsController($scope, Modals, csSettings, esHttp, c $scope.showNetworkLookup = function() { return Modals.showNetworkLookup({ enableFilter: true, - endpointFilter: esHttp.constants.ES_USER_API_ENDPOINT + endpoint: esHttp.constants.ES_USER_API_ENDPOINT, + bma: false }) .then(function (peer) { if (peer) { diff --git a/www/plugins/es/js/services/http-services.js b/www/plugins/es/js/services/http-services.js index 371c129e60c6a1d4e3f229e81c04c8ddadeb883d..8bdd9b6b3578bdddec9f03e7faa07446f890396a 100644 --- a/www/plugins/es/js/services/http-services.js +++ b/www/plugins/es/js/services/http-services.js @@ -14,7 +14,7 @@ angular.module('cesium.es.http.services', ['ngResource', 'ngApi', 'cesium.servic console.debug('[ES] [https] Enable SSL (forced by config or detected in URL)'); } - function EsHttp(host, port, wsPort, useSsl) { + function EsHttp(host, port, useSsl) { var that = this, @@ -42,21 +42,19 @@ angular.module('cesium.es.http.services', ['ngResource', 'ngApi', 'cesium.servic that.started = false; that.init = init; - init(host, port, wsPort, useSsl); + init(host, port, useSsl); - function init(host, port, wsPort, useSsl) { + function init(host, port, useSsl) { // Use settings as default if (!host && csSettings.data) { host = host || (csSettings.data.plugins && csSettings.data.plugins.es ? csSettings.data.plugins.es.host : null); port = port || (host ? csSettings.data.plugins.es.port : null); - wsPort = wsPort || (host ? csSettings.data.plugins.es.wsPort : null); useSsl = angular.isDefined(useSsl) ? useSsl : (port == 443 || csSettings.data.plugins.es.useSsl || forceUseSsl); } that.alive = false; that.host = host; that.port = port || ((useSsl || forceUseSsl) ? 443 : 80); - that.wsPort = wsPort || that.port; that.useSsl = angular.isDefined(useSsl) ? useSsl : (that.port == 443 || forceUseSsl); that.server = csHttp.getServer(host, port); } @@ -68,15 +66,13 @@ angular.module('cesium.es.http.services', ['ngResource', 'ngApi', 'cesium.servic var host = data.plugins.es.host; var useSsl = data.plugins.es.port == 443 || data.plugins.es.useSsl || forceUseSsl; var port = data.plugins.es.port || (useSsl ? 443 : 80); - var wsPort = data.plugins.es.wsPort || port; - return isSameNode(host, port, wsPort, useSsl); + return isSameNode(host, port, useSsl); } - function isSameNode(host, port, wsPort, useSsl) { + function isSameNode(host, port, useSsl) { return (that.host == host) && (that.port == port) && - (!wsPort || that.wsPort == wsPort) && (angular.isUndefined(useSsl) || useSsl == that.useSsl); } @@ -134,7 +130,7 @@ angular.module('cesium.es.http.services', ['ngResource', 'ngApi', 'cesium.servic that.copy = function(otherNode) { if (that.started) that.stop(); - that.init(otherNode.host, otherNode.port, otherNode.wsPort, otherNode.useSsl || otherNode.port == 443); + that.init(otherNode.host, otherNode.port, otherNode.useSsl || otherNode.port == 443); that.data.isTemporary = false; // reset temporary flag return that.start(true /*skipInit*/); }; @@ -198,7 +194,7 @@ angular.module('cesium.es.http.services', ['ngResource', 'ngApi', 'cesium.servic return function() { var sock = that.cache.wsByPath[path]; if (!sock) { - sock = csHttp.ws(that.host, that.wsPort, path, that.useSsl); + sock = csHttp.ws(that.host, that.port, path, that.useSsl); that.cache.wsByPath[path] = sock; } return sock; @@ -233,8 +229,7 @@ angular.module('cesium.es.http.services', ['ngResource', 'ngApi', 'cesium.servic // Remember the default node defaultSettingsNode = defaultSettingsNode || { host: settings.host, - port: settings.port, - wsPort: settings.wsPort + port: settings.port }; var fallbackNode = settings.fallbackNodes && fallbackNodeIndex < settings.fallbackNodes.length && settings.fallbackNodes[fallbackNodeIndex++]; @@ -252,7 +247,7 @@ angular.module('cesium.es.http.services', ['ngResource', 'ngApi', 'cesium.servic that.cleanCache(); - that.init(fallbackNode.host, fallbackNode.port, fallbackNode.wsPort, fallbackNode.useSsl || fallbackNode.port == 443); + that.init(fallbackNode.host, fallbackNode.port, fallbackNode.useSsl || fallbackNode.port == 443); // check is alive then loop return that.isAlive().then(that.checkNodeAlive); @@ -606,11 +601,13 @@ angular.module('cesium.es.http.services', ['ngResource', 'ngApi', 'cesium.servic function parseEndPoint(endpoint) { var matches = regexp.ES_USER_API_ENDPOINT.exec(endpoint); if (!matches) return; + var port = matches[8] || 80; return { "dns": matches[2] || '', "ipv4": matches[4] || '', "ipv6": matches[6] || '', - "port": matches[8] || 80 + "port": port, + "useSsl": port == 80 ? false : (port == 443) }; } @@ -680,8 +677,8 @@ angular.module('cesium.es.http.services', ['ngResource', 'ngApi', 'cesium.servic var service = new EsHttp(); - service.instance = function(host, port, wsPort, useSsl) { - return new EsHttp(host, port, wsPort, useSsl); + service.instance = function(host, port, useSsl) { + return new EsHttp(host, port, useSsl) }; return service; diff --git a/www/plugins/es/js/services/settings-services.js b/www/plugins/es/js/services/settings-services.js index b12ed7533b30fa67ff1a9e8b50290957fc436e79..d3ee7102e2904781a55ef7f16f06300a30a8c7ad 100644 --- a/www/plugins/es/js/services/settings-services.js +++ b/www/plugins/es/js/services/settings-services.js @@ -20,7 +20,7 @@ angular.module('cesium.es.settings.services', ['cesium.services', 'cesium.es.htt excludes: ['timeout', 'cacheTimeMs', 'time', 'login', 'build'], plugins: { es: { - excludes: ['enable', 'host', 'port', 'wsPort', 'fallbackNodes', 'enableGoogleApi', 'googleApiKey'], + excludes: ['enable', 'host', 'port', 'fallbackNodes', 'enableGoogleApi', 'googleApiKey'], notifications: { } } diff --git a/www/templates/blockchain/list_blocks.html b/www/templates/blockchain/list_blocks.html index 4a5032ca9f2b417aa8d6889c31601fdc18889f76..5721ec6695adbd646e8b009a4a7491abf6a520f4 100644 --- a/www/templates/blockchain/list_blocks.html +++ b/www/templates/blockchain/list_blocks.html @@ -3,7 +3,7 @@ <ion-spinner icon="android"></ion-spinner> </div> - <ion-list class="padding padding-xs list-blocks" ng-class="::motion.ionListClass"> + <ion-list class="padding padding-xs list-blocks {{::motion.ionListClass}}"> <div class="padding gray" ng-if="!search.loading && !search.results.length" translate> BLOCKCHAIN.LOOKUP.NO_BLOCK </div> diff --git a/www/templates/blockchain/list_blocks_lg.html b/www/templates/blockchain/list_blocks_lg.html index 3b7f2accab58a926d6475e26c25dc50faee514b9..8c9d6763eb79ca78be12c950a51146d46b8f5c8a 100644 --- a/www/templates/blockchain/list_blocks_lg.html +++ b/www/templates/blockchain/list_blocks_lg.html @@ -17,7 +17,7 @@ <ion-spinner icon="android"></ion-spinner> </div> - <ion-list class="padding padding-xs list-blocks" ng-class="::motion.ionListClass"> + <ion-list class="padding padding-xs list-blocks {{::motion.ionListClass}}"> <div class="padding gray" ng-if="!search.loading && !search.results.length" translate> BLOCKCHAIN.LOOKUP.NO_BLOCK </div> diff --git a/www/templates/network/item_content_peer.html b/www/templates/network/item_content_peer.html index deffb8e8506eb3942d19f81fc72ab2ea580c101c..54a79865e2bddd1a92c7bbbf82efeea84b719b0d 100644 --- a/www/templates/network/item_content_peer.html +++ b/www/templates/network/item_content_peer.html @@ -19,11 +19,11 @@ <span class="positive" ng-if=":rebind:peer.uid"> <i class="ion-person"></i> {{:rebind:peer.name || peer.uid}} </span> - <span class="gray">{{:rebind:peer.dns && (' | ' + peer.server) + (peer.bma.path||'') }}</span> + <span class="gray" ng-if=":rebind:!compactMode">{{:rebind:peer.dns && (' | ' + peer.server) + (peer.bma.path||'') }}</span> </h4> </div> <div class="col col-15 no-padding text-center hidden-xs hidden-sm" ng-if="::expertMode"> - <div style="min-width: 50px; padding-top: 5px;" > + <div style="min-width: 50px; padding-top: 5px;" ng-if=":rebind:!compactMode"> <span ng-if=":rebind:peer.isSsl()" title="SSL"> <i class="ion-locked"></i><small class="hidden-md"> SSL</small> </span> @@ -60,9 +60,9 @@ </div> <div class="col col-20 no-padding text-center"> <span id="{{$index === 0 ? helptipPrefix + '-peer-0-block' : ''}}" - class="badge" ng-class=":rebind:{'badge-balanced': peer.hasMainConsensusBlock, 'badge-energized': peer.hasConsensusBlock, 'ng-hide': !peer.currentNumber }"> + class="badge" ng-class=":rebind:{'badge-balanced': peer.hasMainConsensusBlock, 'badge-energized': peer.hasConsensusBlock, 'ng-hide': !peer.currentNumber && !peer.blockNumber }"> {{::!expertMode ? ('COMMON.BLOCK'|translate) : '' }} - {{:rebind:peer.currentNumber|formatInteger}}</span> + {{:rebind:(peer.currentNumber || peer.blockNumber) | formatInteger}}</span> <span class="badge badge-secondary" ng-if=":rebind:peer.consensusBlockDelta && expertMode"> <i class="ion-clock"></i> {{:rebind:peer.consensusBlockDelta|formatDurationTime}}</span> diff --git a/www/templates/network/items_peers.html b/www/templates/network/items_peers.html index 7db8f233d536afd3908fe7b8be7034a14c4b0746..2a0cd95147d7662cdb1d449de9e90adcb4d138aa 100644 --- a/www/templates/network/items_peers.html +++ b/www/templates/network/items_peers.html @@ -1,4 +1,4 @@ -<div ng-class="::motion.ionListClass" class="no-padding"> +<div class="no-padding {{::motion.ionListClass}}"> <div class="item item-text-wrap no-border done in gray no-padding-top no-padding-bottom inline text-italic" ng-if="::isHttps && expertMode"> <small><i class="icon ion-alert-circled"></i> {{'NETWORK.INFO.ONLY_SSL_PEERS'|translate}}</small> @@ -26,11 +26,11 @@ </div> <div ng-repeat="peer in :rebind:search.results track by peer.id" - class="item item-peer item-icon-left ink" - ng-class="::ionItemClass" - id="{{helptipPrefix}}-peer-{{$index}}" + class="item item-peer item-icon-left ink {{::ionItemClass}}" + ng-class=":rebind:{'compacted': peer.compacted && compactMode}" + id="{{::helptipPrefix}}-peer-{{::$index}}" ng-click="selectPeer(peer)" - ng-include="'templates/network/item_content_peer.html'"> + ng-include="::'templates/network/item_content_peer.html'"> </div> </div> diff --git a/www/templates/network/modal_network.html b/www/templates/network/modal_network.html index 6392bdbbd52465e15e1a23189cfe87bf760ffcd6..c627cd7029478fc41467868d23cfdd8bd27e9ae4 100644 --- a/www/templates/network/modal_network.html +++ b/www/templates/network/modal_network.html @@ -19,14 +19,11 @@ <div class="padding padding-xs" style="display: block; height: 60px;"> <div class="pull-left"> - <h4 ng-if="enableFilter && search.type=='member'"> - {{'PEER.MEMBERS' | translate}} <span ng-if="!search.loading">({{search.results.length}})</span> - </h4> - <h4 ng-if="enableFilter && search.type=='mirror'"> - {{'PEER.MIRRORS' | translate}} <span ng-if="!search.loading">({{search.results.length}})</span> - </h4> - <h4 ng-if="!enableFilter || !search.type"> - {{'PEER.ALL_PEERS' | translate}} <span ng-if="!search.loading">({{search.results.length}})</span> + <h4> + <span ng-if="enableFilter && search.type=='member'" translate>PEER.MEMBER_PEERS</span> + <span ng-if="enableFilter && search.type=='mirror'" translate>PEER.MIRROR_PEERS</span> + <span ng-if="!enableFilter || !search.type" translate>PEER.ALL_PEERS</span> + <span ng-if="!search.loading">({{search.results.length}})</span> </h4> </div> diff --git a/www/templates/network/view_network.html b/www/templates/network/view_network.html index cebf843e8b28a848a3ef7153bc6027b853511736..3a87285b371f5c41037419b4991ce4dc42c112f3 100644 --- a/www/templates/network/view_network.html +++ b/www/templates/network/view_network.html @@ -16,9 +16,9 @@ <div class="padding padding-xs" style="display: block; height: 60px;"> <div class="pull-left"> <h4> - <span ng-if="enableFilter && search.type=='member'" translate>PEER.MEMBERS</span> - <span ng-if="enableFilter && search.type=='mirror'" translate>PEER.MIRRORS</span> - <span ng-if="enableFilter && search.type=='offline'" translate>PEER.OFFLINE</span> + <span ng-if="enableFilter && search.type=='member'" translate>PEER.MEMBER_PEERS</span> + <span ng-if="enableFilter && search.type=='mirror'" translate>PEER.MIRROR_PEERS</span> + <span ng-if="enableFilter && search.type=='offline'" translate>PEER.OFFLINE_PEERS</span> <span ng-if="!enableFilter || !search.type" translate>PEER.ALL_PEERS</span> <span ng-if="search.results.length">({{search.results.length}})</span> <ion-spinner ng-if="search.loading" class="icon ion-spinner-small" icon="android"></ion-spinner> @@ -28,6 +28,15 @@ <div class="pull-right"> <div class="pull-right" ng-if="enableFilter"> + <a class="button button-text button-small hidden-xs hidden-sm ink" + ng-class="{'button-text-positive': compactMode}" + ng-click="toggleCompactMode()"> + <i class="icon ion-navicon"></i> + <b class="ion-arrow-down-b" style="position: absolute; top: -2px; left: 4px; font-size: 8px;"></b> + <b class="ion-arrow-up-b" style="position: absolute; top: 10px; left: 4px; font-size: 8px;"></b> + <span>{{'BLOCKCHAIN.LOOKUP.BTN_COMPACT'|translate}}</span> + </a> + <a class="button button-text button-small hidden-xs hidden-sm ink" ng-class="{'button-text-positive': search.type=='member'}" ng-click="toggleSearchType('member')"> diff --git a/www/templates/network/view_peer.html b/www/templates/network/view_peer.html index 29b0646489ea32847999853555d62434d1ae8cf0..c90092d4e8d187a99eefd26c5ae85ef086d48262 100644 --- a/www/templates/network/view_peer.html +++ b/www/templates/network/view_peer.html @@ -121,8 +121,7 @@ <div class="list no-padding {{::motion.ionListClass}}" ng-if="isReachable"> <div ng-repeat="peer in :rebind:peers track by peer.id" - class="item item-peer item-icon-left ink" - ng-class="::ionItemClass" + class="item item-peer item-icon-left ink {{::ionItemClass}}" ng-click="selectPeer(peer)" ng-include="'templates/network/item_content_peer.html'"> </div> diff --git a/www/templates/wallet/view_wallet.html b/www/templates/wallet/view_wallet.html index 37d12228d82cdba041b6622bf214a7da6107bc09..623c5b0d289d256f00079641ff4cbb2723f77a69 100644 --- a/www/templates/wallet/view_wallet.html +++ b/www/templates/wallet/view_wallet.html @@ -106,7 +106,7 @@ <div class="col"> - <div class="list" ng-class="::motion.ionListClass" ng-hide="loading"> + <div class="list {{::motion.ionListClass}}" ng-hide="loading"> <span class="item item-divider" translate>WOT.GENERAL_DIVIDER</span> diff --git a/www/templates/wallet/view_wallet_tx.html b/www/templates/wallet/view_wallet_tx.html index 1c893d53579557d85d7bdf585b52f92e4359fa6e..a088fd357176303c200cb8eb9ea1a9e2f5764c9c 100644 --- a/www/templates/wallet/view_wallet_tx.html +++ b/www/templates/wallet/view_wallet_tx.html @@ -85,9 +85,7 @@ <div class="col"> - - - <div class="list" ng-class="::motion.ionListClass"> + <div class="list {{::motion.ionListClass}}"> <!-- Errors transactions--> <a class="item item-icon-left item-icon-right ink" ng-if="formData.tx.errors && formData.tx.errors.length" diff --git a/www/templates/wallet/view_wallet_tx_error.html b/www/templates/wallet/view_wallet_tx_error.html index 588c7adf20377edb5b40c4284fd8f18a33dea883..9fd9439338c16be727adefe65ea78d55ef0cd118 100644 --- a/www/templates/wallet/view_wallet_tx_error.html +++ b/www/templates/wallet/view_wallet_tx_error.html @@ -29,7 +29,7 @@ <div class="col col-20 hidden-xs hidden-sm"> </div> - <div class="col list" ng-class="::motion.ionListClass"> + <div class="col list {{::motion.ionListClass}}"> <!-- Pending received TX --> <div class="item item-divider" > diff --git a/www/templates/wot/view_identity.html b/www/templates/wot/view_identity.html index 411bb4c86dedea409099ad132f15aec18841ad4d..6ec59ae588a06aaf384f28fd79c8cbcf81b089f4 100644 --- a/www/templates/wot/view_identity.html +++ b/www/templates/wot/view_identity.html @@ -78,7 +78,7 @@ <div class="row no-padding" > <div class="col col-20 hidden-xs hidden-sm"> </div> - <div class="col list" ng-class="::motion.ionListClass" bind-notifier="{ rebind:loading}"> + <div class="col list {{::motion.ionListClass}}" bind-notifier="{ rebind:loading}"> <span class="item item-divider" translate>WOT.GENERAL_DIVIDER</span>