diff --git a/www/i18n/locale-en-GB.json b/www/i18n/locale-en-GB.json index c9e33e71131303c8748e31b8c1ae1d8f40ac9456..f134785f09bcdb490264ab1b4635c21f18cbf0fd 100644 --- a/www/i18n/locale-en-GB.json +++ b/www/i18n/locale-en-GB.json @@ -5,6 +5,7 @@ "APP_BUILD": "build {{build}}", "PUBKEY": "Public key", "MEMBER": "Member", + "BLOCK" : "Block", "BTN_OK": "OK", "BTN_YES": "Yes", "BTN_NO": "No", diff --git a/www/i18n/locale-en.json b/www/i18n/locale-en.json index 093bbee00ecdd1c7cc46fa0b0f5a302d45230dd4..ddc7b0911bea884f17aecd186cbfa80f779eac59 100644 --- a/www/i18n/locale-en.json +++ b/www/i18n/locale-en.json @@ -5,6 +5,7 @@ "APP_BUILD": "build {{build}}", "PUBKEY": "Public key", "MEMBER": "Member", + "BLOCK" : "Block", "BTN_OK": "OK", "BTN_YES": "Yes", "BTN_NO": "No", diff --git a/www/i18n/locale-es-ES.json b/www/i18n/locale-es-ES.json index 27485257c6c379eed81be5f954c43de30360d397..3d0511283a0d0d410c77fda6cd8da93b0a226379 100644 --- a/www/i18n/locale-es-ES.json +++ b/www/i18n/locale-es-ES.json @@ -5,6 +5,7 @@ "APP_BUILD": "fecha : {{build}}", "PUBKEY": "Llave publica", "MEMBER": "Miembro", + "BLOCK" : "Bloque", "BTN_OK": "OK", "BTN_YES": "Si", "BTN_NO": "No", diff --git a/www/i18n/locale-fr-FR.json b/www/i18n/locale-fr-FR.json index e202e8d1b28fd4584b8d9e7fa3eaa64512439f00..3395f109642ede545d9224ecb426bfbb39a86e49 100644 --- a/www/i18n/locale-fr-FR.json +++ b/www/i18n/locale-fr-FR.json @@ -5,6 +5,7 @@ "APP_BUILD": "date : {{build}}", "PUBKEY": "Clé publique", "MEMBER": "Membre", + "BLOCK" : "Bloc", "BTN_OK": "OK", "BTN_YES": "Oui", "BTN_NO": "Non", diff --git a/www/i18n/locale-nl-NL.json b/www/i18n/locale-nl-NL.json index 28d1f3de0d6f91a33e0a91847261691424fc6340..b1392ca8f4c705f055c496402ec501bd83dfa513 100644 --- a/www/i18n/locale-nl-NL.json +++ b/www/i18n/locale-nl-NL.json @@ -5,6 +5,7 @@ "APP_BUILD": "build {{build}}", "PUBKEY": "Publieke sleutel", "MEMBER": "Lid", + "BLOCK": "Blok", "BTN_OK": "OK", "BTN_YES": "Ja", "BTN_NO": "Nee", @@ -243,6 +244,7 @@ "PEERS": "Knopen", "SIGNED_ON_BLOCK": "Getekend op blok", "MIRROR": "spiegel", + "CURRENT_BLOCK": "Blok #", "VIEW": { "TITLE": "Knoop", "OWNER": "Maakt deel uit van", diff --git a/www/js/config.js b/www/js/config.js index 486133128c90c78836cfa756f1dc4f9db8d5266e..ccbb74c6ab597dcfebf1557a324f4cecef02712b 100644 --- a/www/js/config.js +++ b/www/js/config.js @@ -13,7 +13,7 @@ angular.module("cesium.config", []) "fallbackLanguage": "en", "rememberMe": true, "showUDHistory": false, - "timeout": 300000, + "timeout": 30000, "timeWarningExpireMembership": 5184000, "timeWarningExpire": 7776000, "keepAuthIlde": 600, @@ -71,4 +71,4 @@ angular.module("cesium.config", []) "newIssueUrl": "https://github.com/duniter/cesium/issues/new?labels=bug" }) -; \ No newline at end of file +; diff --git a/www/js/controllers/network-controllers.js b/www/js/controllers/network-controllers.js index d56bc70e179b22795f5a10354051893cd2151f8d..9d68c5cff9f1c4521291edd1c0a536af6a729a43 100644 --- a/www/js/controllers/network-controllers.js +++ b/www/js/controllers/network-controllers.js @@ -223,7 +223,9 @@ function NetworkLookupController($scope, $state, $location, $ionicPopover, $win }; $scope.selectPeer = function(peer) { - if (!peer.online) return; // nothing to do + // Skipp offline or WS2P node + if (!peer.online || peer.isWs2p()) return; + var stateParams = {server: peer.getServer()}; if (peer.isSsl()) { stateParams.ssl = true; diff --git a/www/js/entities/peer.js b/www/js/entities/peer.js index 198a796e468e8b3e8cc6839060941ee30b1b872b..a82bcd44e2f5612093e67346f80e3101470bf510 100644 --- a/www/js/entities/peer.js +++ b/www/js/entities/peer.js @@ -148,3 +148,9 @@ Peer.prototype.isTor = function() { var bma = this.bma || this.getBMA(); return bma.useTor; }; + + +Peer.prototype.isWs2p = function() { + var bma = this.bma || this.getBMA(); + return bma.useWs2p; +}; diff --git a/www/js/services/bma-services.js b/www/js/services/bma-services.js index e68ce2c21f5820d8d19e03dbd0554f9bc58e6945..6a6c495ff86d8d122d8717dd9bd78124c5f7d8b2 100644 --- a/www/js/services/bma-services.js +++ b/www/js/services/bma-services.js @@ -18,7 +18,7 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. OUTPUT_FUNCTIONS = OUTPUT_FUNCTION+'([ ]*' + OUTPUT_OPERATOR + '[ ]*' + OUTPUT_FUNCTION +')*', 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]+))", + REGEX_ENDPOINT_PARAMS = "( ([a-z_][a-z0-9-_./]*))?( ([0-9.]+))?( ([0-9a-f:]+))?( ([0-9]+))( (.+))?", regexp = { USER_ID: "[A-Za-z0-9_-]+", CURRENCY: "[A-Za-z0-9_-]+", @@ -373,7 +373,11 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. self: get('/network/peering'), peers: get('/network/peering/peers') }, - peers: get('/network/peers') + peers: get('/network/peers'), + ws2p: { + info: get('/network/ws2p/info'), + heads: get('/network/ws2p/heads') + } }, wot: { lookup: get('/wot/lookup/:search'), @@ -527,7 +531,9 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. "ipv4": matches[4] || '', "ipv6": matches[6] || '', "port": matches[8] || 80, - "useSsl": matches[8] && matches[8] == 443 + "useSsl": matches[8] && matches[8] == 443, + "path": matches[10], + "useBma": true }; } // Try BMAS @@ -538,7 +544,9 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. "ipv4": matches[4] || '', "ipv6": matches[6] || '', "port": matches[8] || 80, - "useSsl": true + "useSsl": true, + "path": matches[10], + "useBma": true }; } // Try BMATOR @@ -548,7 +556,21 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. "dns": matches[2] || '', "port": matches[4] || 80, "useSsl": false, - "useTor": true + "useTor": true, + "useBma": true + }; + } + // Try WS2P + matches = exports.regexp.WS2P_ENDPOINT.exec(endpoint); + if (matches) { + return { + "uuid": matches[1] || '', + "dns": matches[3] || '', + "ipv4": matches[5] || '', + "ipv6": matches[7] || '', + "port": matches[9] || 80, + "useSsl": matches[9] && matches[9] == 443, + "useWs2p": true }; } }; diff --git a/www/js/services/network-services.js b/www/js/services/network-services.js index f6e98214cadc5baa295098e34d434b79ef842c40..cbb3186129cb013755a2a4f0dc2071290def4174 100644 --- a/www/js/services/network-services.js +++ b/www/js/services/network-services.js @@ -36,7 +36,8 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.bma.services', 'cesi mainBlock: null, uidsByPubkeys: null, searchingPeersOnNetwork: false, - difficulties: null + difficulties: null, + ws2pHeads: null }, // Return the block uid @@ -66,6 +67,7 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.bma.services', 'cesi data.loading = true; data.searchingPeersOnNetwork = false; data.difficulties = null; + data.ws2pHeads = null; }, hasPeers = function() { @@ -84,6 +86,51 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.bma.services', 'cesi return data.knownBlocks; }, + // Load WS2P heads + loadW2spHeads = function() { + return data.bma.network.ws2p.heads() + .then(function (res) { + data.ws2pHeads = res.heads ? res.heads.reduce(function (res, hit) { + if (hit.message && hit.sig) { + var head = hit.message.split(':'); + res[head[2]/*pubkey*/] = head[3]/*buid*/; + } + return res; + }, {}) : {}; + }) + .catch(function(err) { + // When too many request, retry in 3s + if (err && err.ucode == BMA.errorCodes.HTTP_LIMITATION) { + return $timeout(function() { + return loadW2spHeads(); + }, 3000); + } + console.error(err); // can occur on duniter v1.6 + data.ws2pHeads = {}; + }); + }, + + // Load personal difficulties + loadDifficulties = function() { + return data.bma.blockchain.stats.difficulties() + .then(function (res) { + data.difficulties = res.levels ? res.levels.reduce(function (res, hit) { + if (hit.uid && hit.level) res[hit.uid] = hit.level; + return res; + }, {}) : {}; + }) + .catch(function(err) { + // When too many request, retry in 3s + if (err && err.ucode == BMA.errorCodes.HTTP_LIMITATION) { + return $timeout(function() { + return loadDifficulties(); + }, 3000); + } + console.error(err); + data.difficulties = {}; + }); + }, + loadPeers = function() { data.peers = []; data.searchingPeersOnNetwork = true; @@ -110,34 +157,19 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.bma.services', 'cesi } }, 1000); - var initJobs = [data.bma.wot.member.uids() - .then(function(uids) { - data.uidsByPubkeys = uids; - }) + var initJobs = [ + // Load uids + data.bma.wot.member.uids() + .then(function(uids) { + data.uidsByPubkeys = uids; + }), + // Load WS2P heads + loadW2spHeads() ]; - // When SSL is on, get difficulties from the default node - if (isHttpsMode && data.expertMode) { - var getDifficulties = function() { - return data.bma.blockchain.stats.difficulties() - .then(function (res) { - data.difficulties = res.levels ? res.levels.reduce(function (res, hit) { - if (hit.uid && hit.level) res[hit.uid] = hit.level; - return res; - }, {}) : {}; - }) - .catch(function(err) { - // When too many request, retry in 3s - if (err && err.ucode == BMA.errorCodes.HTTP_LIMITATION) { - return $timeout(function() { - return getDifficulties(); - }, 3000); - } - console.error(err); - data.difficulties = {}; - }); - }; - initJobs.push(getDifficulties()); + // Get difficulties (expert mode only) + if (data.expertMode) { + initJobs.push(loadDifficulties()); } return $q.all(initJobs) @@ -245,19 +277,30 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.bma.services', 'cesi hasUpdates = true; } else if (refreshedPeer.buid !== existingMainBuid){ - console.debug('[network] Peer [{0}] new current block'.format(refreshedPeer.server)); + console.debug('[network] {0} endpoint [{1}] new current block'.format( + refreshedPeer.bma.useBma ? 'BMA' : 'WS2P', + refreshedPeer.server)); hasUpdates = true; } else if (existingOnline !== refreshedPeer.online){ - console.debug('[network] Peer [{0}] is now {1}'.format(refreshedPeer.server, refreshedPeer.online ? 'UP' : 'DOWN')); + console.debug('[network] {0} endpoint [{1}] is now {2}'.format( + refreshedPeer.bma.useBma ? 'BMA' : 'WS2P', + refreshedPeer.server, + refreshedPeer.online ? 'UP' : 'DOWN')); hasUpdates = true; } else { - console.debug("[network] Peer [{0}] unchanged".format(refreshedPeer.server)); + console.debug("[network] {0} endpoint [{1}] unchanged".format( + refreshedPeer.bma.useBma ? 'BMA' : 'WS2P', + refreshedPeer.server)); } } else if (refreshedPeer && (refreshedPeer.online === data.filter.online || data.filter.online === 'all')) { - console.debug("[network] Peer [{0}] is {1}".format(refreshedPeer.server, refreshedPeer.online ? 'UP' : 'DOWN')); + console.debug("[network] {0} endpoint [{1}] is {2}".format( + refreshedPeer.bma.useBma ? 'BMA' : 'WS2P', + refreshedPeer.server, + refreshedPeer.online ? 'UP' : 'DOWN' + )); list.push(refreshedPeer); hasUpdates = true; } @@ -270,31 +313,31 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.bma.services', 'cesi }); }, - createPeerEntities = function(json, bma) { + createPeerEntities = function(json, ep) { if (!json) return []; var peer = new Peer(json); // Read bma endpoints - if (!bma) { - var endpoints = peer.getEndpoints(); - if (!endpoints) return []; // no BMA + if (!ep) { + var endpointsAsString = peer.getEndpoints(); + if (!endpointsAsString) return []; // no BMA - var bmas = endpoints.reduce(function (res, ep) { - var bma = BMA.node.parseEndPoint(ep); - return bma ? res.concat(bma) : res; + var endpoints = endpointsAsString.reduce(function (res, ep) { + var ep = BMA.node.parseEndPoint(ep); + return ep ? res.concat(ep) : res; }, []); // recursive call, on each endpoint - if (bmas.length > 1) { - return bmas.reduce(function (res, bma) { - return res.concat(createPeerEntities(json, bma)); + if (endpoints.length > 1) { + return endpoints.reduce(function (res, ep) { + return res.concat(createPeerEntities(json, ep)); }, []); } // if only one bma endpoint: use it and continue - bma = bmas[0]; + ep = endpoints[0]; } - peer.bma = bma; + peer.bma = ep; peer.server = peer.getServer(); peer.dns = peer.getDns(); peer.blockNumber = peer.block.replace(/-.+$/, ''); @@ -313,6 +356,19 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.bma.services', 'cesi return $q.when(peer); } + if (peer.bma.useWs2p && data.ws2pHeads) { + peer.buid = data.ws2pHeads[peer.pubkey]; + peer.online = !!peer.buid; + peer.currentNumber=peer.buid && peer.buid.split('-')[0]; + delete peer.version; + + if (peer.uid && data.expertMode && data.difficulties) { + peer.difficulty = data.difficulties[peer.uid]; + } + + return $q.when(peer); + } + // Cesium running in SSL: Do not try to access not SSL node, if (isHttpsMode && !peer.bma.useSsl) { peer.online = (peer.status === 'UP'); @@ -322,11 +378,12 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.bma.services', 'cesi if (peer.uid && data.expertMode && data.difficulties) { peer.difficulty = data.difficulties[peer.uid]; } + return $q.when(peer); } - // Do not try to access TOR endpoints - if (peer.bma.useTor) { + // Do not try to access TOR or WS2P endpoints + if (peer.bma.useTor || peer.bma.useWs2p) { peer.online = (peer.status == 'UP'); peer.buid = constants.UNKNOWN_BUID; delete peer.version; @@ -486,9 +543,10 @@ angular.module('cesium.network.services', ['ngApi', 'cesium.bma.services', 'cesi 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' ? - (peer.isSsl() ? (data.sort.asc ? 1 : -1) : - (peer.hasEndpoint('ES_USER_API') ? (data.sort.asc ? 0.5 : -0.5) : 0)) : 0); + sortScore += (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); diff --git a/www/templates/network/item_content_peer.html b/www/templates/network/item_content_peer.html index 157bd818dbfaf613b769f07dd5ea416ce82d2673..cb941509379605c10f6a33515f8dee109dc63c47 100644 --- a/www/templates/network/item_content_peer.html +++ b/www/templates/network/item_content_peer.html @@ -28,17 +28,17 @@ <span ng-if=":rebind:peer.isSsl()"> <i class="ion-locked"></i><small class="hidden-md"> SSL</small> </span> - <span ng-if=":rebind:peer.hasEndpoint('WS2P')" title="WS2P"> + <span ng-if=":rebind:peer.isWs2p()" title="WS2P"> <i class="ion-arrow-swap"></i><small class="hidden-md"> WS2P</small> </span> </div> - <div ng-if=":rebind:peer.hasEndpoint('ES_USER_API')" + <div ng-if=":rebind:!peer.isWs2p()&&peer.hasEndpoint('ES_USER_API')" ng-click="showEndpointsPopover($event, peer, 'ES_USER_API')" title="Cesium+"> <i class="ion-es-user-api"></i> <b class="ion-plus dark" style="position: relative; left: -14px; top:-17px; font-size : 16px;"></b> </div> - <div ng-if=":rebind:peer.isTor()" ng-click="showEndpointsPopover($event, peer, 'BMATOR')"> + <div ng-if=":rebind:!peer.isWs2p()&&peer.isTor()" ng-click="showEndpointsPopover($event, peer, 'BMATOR')"> <i class="ion-bma-tor-api"></i> </div> </div> @@ -51,7 +51,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 }">{{:rebind:peer.currentNumber|formatInteger}}</span> + class="badge" ng-class=":rebind:{'badge-balanced': peer.hasMainConsensusBlock, 'badge-energized': peer.hasConsensusBlock, 'ng-hide': !peer.currentNumber }"> + {{::!expertMode ? ('COMMON.BLOCK'|translate) : '' }} + {{:rebind:peer.currentNumber|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 8da1de7571fed875d91a6fe9c9c71a05d0f59c87..7db8f233d536afd3908fe7b8be7034a14c4b0746 100644 --- a/www/templates/network/items_peers.html +++ b/www/templates/network/items_peers.html @@ -1,10 +1,10 @@ <div ng-class="::motion.ionListClass" class="no-padding"> - <div class="item item-text-wrap no-border done in gray no-padding-top no-padding-bottom" ng-if="isHttps && expertMode"> + <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> </div> - <div class="item row row-header hidden-xs hidden-sm done in" ng-if="expertMode"> + <div class="item row row-header hidden-xs hidden-sm done in" ng-if="::expertMode"> <a class="col col-header no-padding dark" ng-click="toggleSort('uid')"> <cs-sort-icon asc="search.asc" sort="search.sort" toggle="'uid'"></cs-sort-icon> {{'COMMON.UID' | translate}} / {{'COMMON.PUBKEY' | translate}} diff --git a/www/templates/network/view_network.html b/www/templates/network/view_network.html index 1ff32b3d4060c2beda9f7010ccead5355631ddeb..cebf843e8b28a848a3ef7153bc6027b853511736 100644 --- a/www/templates/network/view_network.html +++ b/www/templates/network/view_network.html @@ -20,7 +20,7 @@ <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" translate>PEER.ALL_PEERS</span> - <span ng-if="!search.loading">({{search.results.length}})</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> </h4> </div>