From 8fa337f6f9f94b5ed3b5b6644af63f3c7b296e41 Mon Sep 17 00:00:00 2001 From: Joe Uhren Date: Fri, 1 Jul 2022 21:11:57 -0600 Subject: [PATCH] Network peer updates -Added a new port_filter setting to the 3 network_page tables which allows showing only results from peers on the selected port -Added a new hide_protocols setting to the 3 network_page tables which allows hiding results from peers on the selected protocols -Added a Port column to the data table on the Network page Connections tab -The data table on the Network page Connections tab is now sortable -The peer sync now refreshes data for peers that existed since last sync -Adding and updating peers now displays the port # in the log output -The /ext/getnetworkpeers api is now sorted by ip4/ip6, address and port which also means all data on the Network page is sorted this way by default as well -The /ext/getnetworkpeers api no longer requires the internal argument for calls originating from the Network page -The Network page now only makes a single call to the /ext/getnetworkpeers api instead of 3 calls -The find_peer and drop_peer functions now requiresa port to distinguish between multiple connections to the same peer on different ports --- app.js | 30 ++--- lib/database.js | 10 +- lib/settings.js | 27 +++- scripts/sync.js | 23 +++- settings.json.template | 27 +++- views/network.pug | 279 +++++++++++++++++++++++------------------ 6 files changed, 245 insertions(+), 151 deletions(-) diff --git a/app.js b/app.js index 9593b13..c2fb42d 100644 --- a/app.js +++ b/app.js @@ -505,13 +505,6 @@ app.use('/ext/getsummary', function(req, res) { app.use('/ext/getnetworkpeers', function(req, res) { // check if the getnetworkpeers api is enabled or else check the headers to see if it matches an internal ajax request from the explorer itself (TODO: come up with a more secure method of whitelisting ajax calls from the explorer) if ((settings.api_page.enabled == true && settings.api_page.public_apis.ext.getnetworkpeers.enabled == true) || (req.headers['x-requested-with'] != null && req.headers['x-requested-with'].toLowerCase() == 'xmlhttprequest' && req.headers.referer != null && req.headers.accept.indexOf('text/javascript') > -1 && req.headers.accept.indexOf('application/json') > -1)) { - var internal = false; - // split url suffix by forward slash and remove blank entries - var split = req.url.split('/').filter(function(v) { return v; }); - // check if this is an internal request - if (split.length > 0 && split[0].indexOf('internal') > -1) - internal = true; - // get list of peers db.get_peers(function(peers) { // loop through peers list and remove the mongo _id and __v keys @@ -520,14 +513,21 @@ app.use('/ext/getnetworkpeers', function(req, res) { delete peers[i]['_doc']['__v']; } - // check if this is an internal request - if (internal) { - // display data formatted for internal datatable - res.json({"data": peers}); - } else { - // display data in more readable format for public api - res.json(peers); - } + // sort ip6 addresses to the bottom + peers.sort(function(a, b) { + var address1 = a.address.indexOf(':') > -1; + var address2 = b.address.indexOf(':') > -1; + + if (address1 < address2) + return -1; + else if (address1 > address2) + return 1; + else + return 0; + }); + + // return peer data + res.json(peers); }); } else res.end('This method is disabled'); diff --git a/lib/database.js b/lib/database.js index 5ccd6e8..64919cb 100644 --- a/lib/database.js +++ b/lib/database.js @@ -1242,8 +1242,8 @@ module.exports = { }); }, - find_peer: function(address, cb) { - Peers.findOne({address: address}, function(err, peer) { + find_peer: function(address, port, cb) { + Peers.findOne({address: address, port: port}, function(err, peer) { if (err) return cb(null); else { @@ -1255,8 +1255,8 @@ module.exports = { }); }, - drop_peer: function(address, cb) { - Peers.deleteOne({address: address}, function(err) { + drop_peer: function(address, port, cb) { + Peers.deleteOne({address: address, port: port}, function(err) { if (err) { console.log(err); return cb(); @@ -1276,7 +1276,7 @@ module.exports = { }, get_peers: function(cb) { - Peers.find({}, function(err, peers) { + Peers.find().sort({address: 1, port: 1}).exec(function (err, peers) { if (err) return cb([]); else diff --git a/lib/settings.js b/lib/settings.js index 98345b4..1300155 100644 --- a/lib/settings.js +++ b/lib/settings.js @@ -618,7 +618,14 @@ exports.network_page = { // page_length_options: An array of page length options that determine how many items/records to display in the table at any given time "page_length_options": [ 10, 25, 50, 75, 100 ], // items_per_page: The default amount of items/records to display in the table at any given time - "items_per_page": 10 + "items_per_page": 10, + // port_filter: Specify a port number to only allow showing peers on the selected port. + // Set this value to 0 to show all peers on any port. + "port_filter": 0, + // hide_protocols: An array of protocol numbers that will be filtered out of the table results + // If a peer connects to the explorer wallet with one of these protocol numbers, that record will not be displayed in this table + // Add as many protocol values as necessary in the following format: [ 0, 70803, 70819 ] + "hide_protocols": [ ] }, // addnodes_table: a collection of settings that pertain to the add nodes table on the network page // Table data is populated via the /ext/getnetworkpeers api @@ -626,7 +633,14 @@ exports.network_page = { // page_length_options: An array of page length options that determine how many items/records to display in the table at any given time "page_length_options": [ 10, 25, 50, 75, 100 ], // items_per_page: The default amount of items/records to display in the table at any given time - "items_per_page": 10 + "items_per_page": 10, + // port_filter: Specify a port number to only allow showing peers on the selected port. + // Set this value to 0 to show all peers on any port. + "port_filter": 0, + // hide_protocols: An array of protocol numbers that will be filtered out of the table results + // If a peer connects to the explorer wallet with one of these protocol numbers, that record will not be displayed in this table + // Add as many protocol values as necessary in the following format: [ 0, 70803, 70819 ] + "hide_protocols": [ ] }, // onetry_table: a collection of settings that pertain to the one try table on the network page // Table data is populated via the /ext/getnetworkpeers api @@ -634,7 +648,14 @@ exports.network_page = { // page_length_options: An array of page length options that determine how many items/records to display in the table at any given time "page_length_options": [ 10, 25, 50, 75, 100 ], // items_per_page: The default amount of items/records to display in the table at any given time - "items_per_page": 10 + "items_per_page": 10, + // port_filter: Specify a port number to only allow showing peers on the selected port. + // Set this value to 0 to show all peers on any port. + "port_filter": 0, + // hide_protocols: An array of protocol numbers that will be filtered out of the table results + // If a peer connects to the explorer wallet with one of these protocol numbers, that record will not be displayed in this table + // Add as many protocol values as necessary in the following format: [ 0, 70803, 70819 ] + "hide_protocols": [ ] } }; diff --git a/scripts/sync.js b/scripts/sync.js index da7821f..aeedc4b 100644 --- a/scripts/sync.js +++ b/scripts/sync.js @@ -436,7 +436,7 @@ if (lib.is_locked([database]) == false) { address = address.replace("[", "").replace("]", ""); } - db.find_peer(address, function(peer) { + db.find_peer(address, port, function(peer) { if (peer) { if ((peer['port'] != null && (isNaN(peer['port']) || peer['port'].length < 2)) || peer['country'].length < 1 || peer['country_code'].length < 1) { db.drop_peers(function() { @@ -445,9 +445,22 @@ if (lib.is_locked([database]) == false) { }); } - // peer already exists - console.log('Updated peer %s [%s/%s]', address, (i + 1).toString(), body.length.toString()); - loop.next(); + // peer already exists and should be refreshed + // drop peer + db.drop_peer(address, port, function() { + // re-add the peer to refresh the data and extend the expiry date + db.create_peer({ + address: address, + port: port, + protocol: peer.protocol, + version: peer.version, + country: peer.country, + country_code: peer.country_code + }, function() { + console.log('Updated peer %s:%s [%s/%s]', address, port.toString(), (i + 1).toString(), body.length.toString()); + loop.next(); + }); + }); } else { const rateLimitLib = require('../lib/ratelimit'); const rateLimit = new rateLimitLib.RateLimit(1, 2000, false); @@ -471,7 +484,7 @@ if (lib.is_locked([database]) == false) { country: geo.country_name, country_code: geo.country_code }, function() { - console.log('Added new peer %s [%s/%s]', address, (i + 1).toString(), body.length.toString()); + console.log('Added new peer %s:%s [%s/%s]', address, port.toString(), (i + 1).toString(), body.length.toString()); loop.next(); }); } diff --git a/settings.json.template b/settings.json.template index 0930ecc..bd88ba0 100644 --- a/settings.json.template +++ b/settings.json.template @@ -702,7 +702,14 @@ // page_length_options: An array of page length options that determine how many items/records to display in the table at any given time "page_length_options": [ 10, 25, 50, 75, 100 ], // items_per_page: The default amount of items/records to display in the table at any given time - "items_per_page": 10 + "items_per_page": 10, + // port_filter: Specify a port number to only allow showing peers on the selected port. + // Set this value to 0 to show all peers on any port. + "port_filter": 0, + // hide_protocols: An array of protocol numbers that will be filtered out of the table results + // If a peer connects to the explorer wallet with one of these protocol numbers, that record will not be displayed in this table + // Add as many protocol values as necessary in the following format: [ 0, 70803, 70819 ] + "hide_protocols": [ ] }, // addnodes_table: a collection of settings that pertain to the add nodes table on the network page // Table data is populated via the /ext/getnetworkpeers api @@ -710,7 +717,14 @@ // page_length_options: An array of page length options that determine how many items/records to display in the table at any given time "page_length_options": [ 10, 25, 50, 75, 100 ], // items_per_page: The default amount of items/records to display in the table at any given time - "items_per_page": 10 + "items_per_page": 10, + // port_filter: Specify a port number to only allow showing peers on the selected port. + // Set this value to 0 to show all peers on any port. + "port_filter": 0, + // hide_protocols: An array of protocol numbers that will be filtered out of the table results + // If a peer connects to the explorer wallet with one of these protocol numbers, that record will not be displayed in this table + // Add as many protocol values as necessary in the following format: [ 0, 70803, 70819 ] + "hide_protocols": [ ] }, // onetry_table: a collection of settings that pertain to the one try table on the network page // Table data is populated via the /ext/getnetworkpeers api @@ -718,7 +732,14 @@ // page_length_options: An array of page length options that determine how many items/records to display in the table at any given time "page_length_options": [ 10, 25, 50, 75, 100 ], // items_per_page: The default amount of items/records to display in the table at any given time - "items_per_page": 10 + "items_per_page": 10, + // port_filter: Specify a port number to only allow showing peers on the selected port. + // Set this value to 0 to show all peers on any port. + "port_filter": 0, + // hide_protocols: An array of protocol numbers that will be filtered out of the table results + // If a peer connects to the explorer wallet with one of these protocol numbers, that record will not be displayed in this table + // Add as many protocol values as necessary in the following format: [ 0, 70803, 70819 ] + "hide_protocols": [ ] } }, diff --git a/views/network.pug b/views/network.pug index 5ec8658..f3dd6b0 100644 --- a/views/network.pug +++ b/views/network.pug @@ -19,128 +19,166 @@ block content return lengthMenuOpts; } $(document).ready(function() { - var setting_txPerPage = parseInt("#{settings.network_page.connections_table.items_per_page}"); - $('#connections-table').dataTable({ - autoWidth: true, - searching: false, - ordering: false, - responsive: true, - lengthChange: true, - processing: true, - iDisplayLength: setting_txPerPage, - lengthMenu: generateLengthMenu(setting_txPerPage, !{JSON.stringify(settings.network_page.connections_table.page_length_options)}), - scrollX: true, - language: { - paginate: { - previous: '<', - next: '>' - } - }, - ajax: { - url: '/ext/getnetworkpeers/internal', - dataSrc: function (json) { - return json.data; - } - }, - rowCallback: function (row, data, index) { - var flagBlock = ''; - if (data['country_code'].length > 1) { - flagBlock = '
'; - } - $("td:eq(0)", row).html(data['address']).addClass('breakWord'); - $("td:eq(1)", row).html(data['protocol']); - $("td:eq(2)", row).html(data['version']); - $("td:eq(3)", row).html(data['country']+flagBlock); - }, - fnDrawCallback: function(settings) { - fixDataTableColumns(); - fixFooterHeightAndPosition(); - }, - columns: [ - { data: 'address', width: '25%' }, - { data: 'protocol', width: '25%' }, - { data: 'version', width:'25%' }, - { data: 'country', width: '25%'} - ] + $.ajax({ + method: 'GET', + url: '/ext/getnetworkpeers/internal', + dataType: 'json' + }).done(function(peers) { + var setting_txPerPage = parseInt("#{settings.network_page.connections_table.items_per_page}"); + var setting_con_port_filter = "#{settings.network_page.connections_table.port_filter}"; + var setting_con_hide_protocols = !{JSON.stringify(settings.network_page.connections_table.hide_protocols)}; + var connectionRows = peers; + + if (setting_con_port_filter == null || setting_con_port_filter == '') + setting_con_port_filter = '0'; + + if (setting_con_port_filter != '0') + connectionRows = connectionRows.filter(v => v.port == setting_con_port_filter); + + setting_con_hide_protocols.forEach(function (protocol) { + connectionRows = connectionRows.filter(v => v.protocol != protocol); + }); + + $('#connections-table').dataTable({ + autoWidth: true, + searching: false, + ordering: true, + order: [], + responsive: true, + lengthChange: true, + processing: true, + iDisplayLength: setting_txPerPage, + lengthMenu: generateLengthMenu(setting_txPerPage, !{JSON.stringify(settings.network_page.connections_table.page_length_options)}), + scrollX: true, + language: { + paginate: { + previous: '<', + next: '>' + } + }, + data: connectionRows, + rowCallback: function (row, data, index) { + var flagBlock = ''; + if (data['country_code'].length > 1) { + flagBlock = '
'; + } + $("td:eq(0)", row).html(data['address']).addClass('breakWord'); + $("td:eq(1)", row).html(data['port']); + $("td:eq(2)", row).html(data['protocol']); + $("td:eq(3)", row).html(data['version']); + $("td:eq(4)", row).html(data['country']+flagBlock); + }, + fnDrawCallback: function(settings) { + fixDataTableColumns(); + fixFooterHeightAndPosition(); + }, + columns: [ + { data: 'address', width: '20%' }, + { data: 'port', width: '20%' }, + { data: 'protocol', width: '20%' }, + { data: 'version', width:'20%' }, + { data: 'country', width: '20%'} + ] + }); + + setting_txPerPage = parseInt("#{settings.network_page.addnodes_table.items_per_page}"); + + var addNodeRows = []; + var setting_add_port_filter = "#{settings.network_page.addnodes_table.port_filter}"; + var setting_add_hide_protocols = !{JSON.stringify(settings.network_page.addnodes_table.hide_protocols)}; + var addNodePeers = peers; + + if (setting_add_port_filter == null || setting_add_port_filter == '') + setting_add_port_filter = '0'; + + if (setting_add_port_filter != '0') + addNodePeers = addNodePeers.filter(v => v.port == setting_add_port_filter); + + setting_add_hide_protocols.forEach(function (protocol) { + addNodePeers = addNodePeers.filter(v => v.protocol != protocol); + }); + + for (var i=0; i < addNodePeers.length; i++) + addNodeRows.push({'nodes': 'addnode=' + (addNodePeers[i]['address'] != null && addNodePeers[i]['address'].indexOf(':') > -1 ? '[' + addNodePeers[i]['address'] + ']' : addNodePeers[i]['address']) + (addNodePeers[i]['port'] == null ? '' : ':' + addNodePeers[i]['port'])}); + + $('#addnodes-table').dataTable({ + autoWidth: true, + searching: false, + ordering: false, + responsive: true, + lengthChange: true, + processing: true, + iDisplayLength: setting_txPerPage, + lengthMenu: generateLengthMenu(setting_txPerPage, !{JSON.stringify(settings.network_page.addnodes_table.page_length_options)}), + scrollX: true, + language: { + paginate: { + previous: '<', + next: '>' + } + }, + data: addNodeRows, + fnDrawCallback: function(settings) { + fixDataTableColumns(); + fixFooterHeightAndPosition(); + }, + columns: [ + {data: 'nodes', width: '100%'} + ], + columnDefs: [ + {targets: '_all', className: 'text-start'} + ] + }); + + setting_txPerPage = parseInt("#{settings.network_page.onetry_table.items_per_page}"); + + var oneTryRows = []; + var setting_one_port_filter = "#{settings.network_page.onetry_table.port_filter}"; + var setting_one_hide_protocols = !{JSON.stringify(settings.network_page.onetry_table.hide_protocols)}; + + if (setting_one_port_filter == null || setting_one_port_filter == '') + setting_one_port_filter = '0'; + + if (setting_one_port_filter != '0') + peers = peers.filter(v => v.port == setting_one_port_filter); + + setting_one_hide_protocols.forEach(function (protocol) { + peers = peers.filter(v => v.protocol != protocol); + }); + + for (var i=0; i < peers.length; i++) + oneTryRows.push({'nodes': 'addnode ' + (peers[i]['address'] != null && peers[i]['address'].indexOf(':') > -1 ? '[' + peers[i]['address'] + ']' : peers[i]['address']) + (peers[i]['port'] == null ? '' : ':' + peers[i]['port']) + ' onetry'}); + + $('#onetry-table').dataTable({ + autoWidth: true, + searching: false, + ordering: false, + responsive: true, + lengthChange: true, + processing: true, + iDisplayLength: setting_txPerPage, + lengthMenu: generateLengthMenu(setting_txPerPage, !{JSON.stringify(settings.network_page.onetry_table.page_length_options)}), + scrollX: true, + language: { + paginate: { + previous: '<', + next: '>' + } + }, + data: oneTryRows, + fnDrawCallback: function(settings) { + fixDataTableColumns(); + fixFooterHeightAndPosition(); + }, + columns: [ + {data: 'nodes', width: '100%'} + ], + columnDefs: [ + {targets: '_all', className: 'text-start'} + ] + }); }); - setting_txPerPage = parseInt("#{settings.network_page.addnodes_table.items_per_page}"); - $('#addnodes-table').dataTable({ - autoWidth: true, - searching: false, - ordering: false, - responsive: true, - lengthChange: true, - processing: true, - iDisplayLength: setting_txPerPage, - lengthMenu: generateLengthMenu(setting_txPerPage, !{JSON.stringify(settings.network_page.addnodes_table.page_length_options)}), - scrollX: true, - language: { - paginate: { - previous: '<', - next: '>' - } - }, - ajax: { - url: '/ext/getnetworkpeers/internal', - dataSrc: function (json) { - var rows = []; - for (var i=0; i -1 ? '[' + json.data[i]['address'] + ']' : json.data[i]['address']) + (json.data[i]['port'] == null ? '' : ':' + json.data[i]['port'])}); - - return rows; - } - }, - fnDrawCallback: function(settings) { - fixDataTableColumns(); - fixFooterHeightAndPosition(); - }, - columns: [ - {data: 'nodes', width: '100%'} - ], - columnDefs: [ - {targets: '_all', className: 'text-start'} - ] - }); - setting_txPerPage = parseInt("#{settings.network_page.onetry_table.items_per_page}"); - $('#onetry-table').dataTable({ - autoWidth: true, - searching: false, - ordering: false, - responsive: true, - lengthChange: true, - processing: true, - iDisplayLength: setting_txPerPage, - lengthMenu: generateLengthMenu(setting_txPerPage, !{JSON.stringify(settings.network_page.onetry_table.page_length_options)}), - scrollX: true, - language: { - paginate: { - previous: '<', - next: '>' - } - }, - ajax: { - url: '/ext/getnetworkpeers/internal', - dataSrc: function (json) { - var rows = []; - - for (var i=0; i -1 ? '[' + json.data[i]['address'] + ']' : json.data[i]['address']) + (json.data[i]['port'] == null ? '' : ':' + json.data[i]['port']) + ' onetry'}); - - return rows; - } - }, - fnDrawCallback: function(settings) { - fixDataTableColumns(); - fixFooterHeightAndPosition(); - }, - columns: [ - {data: 'nodes', width: '100%'} - ], - columnDefs: [ - {targets: '_all', className: 'text-start'} - ] - }); $('a[data-bs-toggle="tab"]').on('shown.bs.tab', function (e) { fixDataTableColumns(); fixFooterHeightAndPosition(); @@ -204,6 +242,7 @@ block content thead tr(class=theadClasses) th.text-center #{settings.locale.net_address} + th.text-center='Port' th.text-center #{settings.locale.net_protocol} th.text-center #{settings.locale.net_subversion} th.text-center #{settings.locale.net_country}