From b8095c9625cd685f02d78fb24c2b5823d159853a Mon Sep 17 00:00:00 2001 From: Dan Janosik Date: Wed, 1 Aug 2018 10:36:10 -0400 Subject: [PATCH] add map and some organization to /peers --- app/config.js | 4 +- app/credentials.js | 7 +- app/utils.js | 47 ++++++++---- routes/baseActionsRouter.js | 20 +++++- views/peers.pug | 139 +++++++++++++++++++++++++++--------- 5 files changed, 163 insertions(+), 54 deletions(-) diff --git a/app/config.js b/app/config.js index 548b9bb..597dc63 100644 --- a/app/config.js +++ b/app/config.js @@ -56,7 +56,5 @@ module.exports = { {name: "Litecoin Explorer", url:"https://ltc.chaintools.io", imgUrl:"/img/logo/ltc.svg"}, {name: "Lightning Explorer", url:"https://lightning.chaintools.io", imgUrl:"/img/logo/lightning.svg"}, ] - }, - - ipStackComApiAccessKey:"" + } }; diff --git a/app/credentials.js b/app/credentials.js index edf9ef5..15b553a 100644 --- a/app/credentials.js +++ b/app/credentials.js @@ -8,5 +8,10 @@ module.exports = { port:8332, username:"username", password:"password" - } + }, + + // optional: enter your api access key from ipstack.com below + // to include a map of the estimated locations of your node's + // peers + ipStackComApiAccessKey:"" }; diff --git a/app/utils.js b/app/utils.js index 349f2d1..c0ba002 100644 --- a/app/utils.js +++ b/app/utils.js @@ -5,6 +5,8 @@ var config = require("./config.js"); var coins = require("./coins.js"); var coinConfig = coins[config.coin]; +var ipCache = {}; + var exponentScales = [ {val:1000000000000000000000000000000000, name:"?", abbreviation:"V", exponent:"33"}, {val:1000000000000000000000000000000, name:"?", abbreviation:"W", exponent:"30"}, @@ -270,28 +272,45 @@ function geoLocateIpAddresses(ipAddresses) { ipStr = ipStr + chunks[i][j]; } - var apiUrl = "http://api.ipstack.com/" + ipStr + "?access_key=" + config.ipStackComApiAccessKey; - promises.push(new Promise(function(resolve2, reject2) { - request(apiUrl, function(error, response, body) { - if (error) { - reject2(error); - - } else { - resolve2(response); - } - }); - })); + if (ipCache[ipStr] != null) { + promises.push(new Promise(function(resolve2, reject2) { + resolve2(ipCache[ipStr]); + })); + + } else if (config.credentials.ipStackComApiAccessKey && config.credentials.ipStackComApiAccessKey.trim().length > 0) { + var apiUrl = "http://api.ipstack.com/" + ipStr + "?access_key=" + config.credentials.ipStackComApiAccessKey; + promises.push(new Promise(function(resolve2, reject2) { + request(apiUrl, function(error, response, body) { + if (error) { + reject2(error); + + } else { + resolve2(response); + } + }); + })); + } else { + promises.push(new Promise(function(resolve2, reject2) { + resolve2(null); + })); + } } Promise.all(promises).then(function(results) { - var ipDetails = {}; + var ipDetails = {ips:[], detailsByIp:{}}; for (var i = 0; i < results.length; i++) { var res = results[i]; - if (res["statusCode"] == 200) { + if (res != null && res["statusCode"] == 200) { var resBody = JSON.parse(res["body"]); + var ip = resBody["ip"]; + + ipDetails.ips.push(ip); + ipDetails.detailsByIp[ip] = resBody; - ipDetails[resBody["ip"]] = resBody; + if (ipCache[ip] == null) { + ipCache[ip] = res; + } } } diff --git a/routes/baseActionsRouter.js b/routes/baseActionsRouter.js index 1044ecb..d090b18 100644 --- a/routes/baseActionsRouter.js +++ b/routes/baseActionsRouter.js @@ -135,8 +135,26 @@ router.get("/peers", function(req, res) { coreApi.getPeerSummary().then(function(peerSummary) { res.locals.peerSummary = peerSummary; - res.render("peers"); + var peerIps = []; + for (var i = 0; i < peerSummary.getpeerinfo.length; i++) { + var ipWithPort = peerSummary.getpeerinfo[i].addr; + if (ipWithPort.lastIndexOf(":") >= 0) { + var ip = ipWithPort.substring(0, ipWithPort.lastIndexOf(":")); + if (ip.trim().length > 0) { + peerIps.push(ip.trim()); + } + } + } + if (peerIps.length > 0) { + utils.geoLocateIpAddresses(peerIps).then(function(results) { + res.locals.peerIpSummary = results; + + res.render("peers"); + }); + } else { + res.render("peers"); + } }).catch(function(err) { res.locals.userMessage = "Error: " + err; diff --git a/views/peers.pug b/views/peers.pug index de2b5d2..6f56384 100644 --- a/views/peers.pug +++ b/views/peers.pug @@ -3,6 +3,17 @@ extends layout block headContent title Peers + link(rel="stylesheet", href="https://unpkg.com/leaflet@1.3.3/dist/leaflet.css", integrity="sha512-Rksm5RenBEKSKFjgI3a41vrjkw4EVPlJ3+OiI65vTjIdo9brlAacEuKOiQ5OFh7cOI1bkDwLqdLw3Zg0cRJAAQ==", crossorigin="") + + script(src="https://unpkg.com/leaflet@1.3.3/dist/leaflet.js", integrity="sha512-tAGcCfR4Sc5ZP5ZoVz0quoZDYX5aCtEm/eu1KhSLj2c9eFrylXZknQYmxUssFaVJKvvc0dJQixhGjG2yXWiV9Q==", crossorigin="") + + style. + .versions-hidden-rows, .services-hidden-rows { + display: none; + } + + #map { height: 700px; } + block content h1(class="h3") Peers hr @@ -17,44 +28,54 @@ block content div(class="tab-content") div(id="tab-summary", class="tab-pane active", role="tabpanel") - h2(class="h5") Versions - hr - table(class="table table-striped table-responsive-sm mt-4") - thead - tr - th - th(class="data-header") Version - th(class="data-header") Count - tbody - each item, index in peerSummary.versionSummary - tr - th(class="data-cell") #{index + 1} - - td(class="data-cell") #{item[0]} - td(class="data-cell") #{item[1].toLocaleString()} - - - h2(class="h5") Services - hr - table(class="table table-striped table-responsive-sm mt-4") - thead - tr - th - th(class="data-header") Services - th(class="data-header") Count - tbody - each item, index in peerSummary.servicesSummary - tr - th(class="data-cell") #{index + 1} - - td(class="data-cell") #{item[0]} - td(class="data-cell") #{item[1].toLocaleString()} + h2(class="h5 mb-3") Connected to #{peerSummary.getpeerinfo.length} + if (peerSummary.getpeerinfo.length == 1) + span Peer + else + span Peers + + if (config.credentials.ipStackComApiAccessKey && config.credentials.ipStackComApiAccessKey.trim().length > 0) + div(id="map", class="mb-4") + + div(class="card mb-4") + div(class="card-header") + h2(class="h6 mb-0") Top Versions + div(class="card-body") + table(class="table table-striped table-responsive-sm") + thead + tr + th + th(class="data-header") Version + th(class="data-header") Count + tbody + each item, index in peerSummary.versionSummary + tr(class=(index >= 5 ? "versions-hidden-rows" : false)) + th(class="data-cell") #{index + 1} + + td(class="data-cell") #{item[0]} + td(class="data-cell") #{item[1].toLocaleString()} + + div(class="card mb-4") + div(class="card-header") + h2(class="h6 mb-0") Top Service Flags + div(class="card-body") + table(class="table table-striped table-responsive-sm") + thead + tr + th + th(class="data-header") Services + th(class="data-header") Count + tbody + each item, index in peerSummary.servicesSummary + tr(class=(index >= 5 ? "services-hidden-rows" : false)) + th(class="data-cell") #{index + 1} + + td(class="data-cell") #{item[0]} + td(class="data-cell") #{item[1].toLocaleString()} div(id="tab-details", class="tab-pane", role="tabpanel") - h2(class="h5") Peers List - hr table(class="table table-striped table-responsive-sm mt-4") thead tr @@ -62,6 +83,7 @@ block content th(class="data-header") Version th(class="data-header") Address th(class="data-header") Services + th(class="data-header") Location th(class="data-header") Last Send / Receive tbody @@ -75,12 +97,59 @@ block content td(class="data-cell") #{item.subver} td(class="data-cell") #{item.addr} td(class="data-cell") #{item.services} + td(class="data-cell") + - var ipAddr = item.addr.substring(0, item.addr.lastIndexOf(":")); + if (peerIpSummary.ips.includes(ipAddr)) + - var ipDetails = peerIpSummary.detailsByIp[ipAddr]; + if (ipDetails.city) + span #{ipDetails.city}, + if (ipDetails.country_name) + span #{ipDetails.country_name} + if (ipDetails.location && ipDetails.location.country_flag_emoji) + span #{ipDetails.location.country_flag_emoji} + else + span ? + + - var ipAddr = null; + td(class="data-cell") #{lastSendAgo} / #{lastRecvAgo} div(id="tab-raw", class="tab-pane", role="tabpanel") + h5 GetPeerInfo pre code #{JSON.stringify(peerSummary.getpeerinfo, null, 4)} + h5 IP Summary + pre + code #{JSON.stringify(peerIpSummary, null, 4)} + - \ No newline at end of file +block endOfBody + if (config.credentials.ipStackComApiAccessKey && config.credentials.ipStackComApiAccessKey.trim().length > 0) + script. + var mymap = L.map('map').setView([21.505, -0.09], 3); + + L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw', { + maxZoom: 18, + attribution: 'Map data © OpenStreetMap contributors, ' + + 'CC-BY-SA, ' + + 'Imagery © Mapbox', + id: 'mapbox.streets' + }).addTo(mymap); + + /*L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', { + attribution: '© OpenStreetMap contributors' + }).addTo(mymap);*/ + + $(document).ready(function() { + window.dispatchEvent(new Event('resize')); + }); + + each ipAddress, index in peerIpSummary.ips + - var ipDetails = peerIpSummary.detailsByIp[ipAddress]; + if (ipDetails && ipDetails.latitude && ipDetails.longitude) + script L.marker([#{ipDetails.latitude}, #{ipDetails.longitude}]).addTo(mymap); + + +