starting frontend revamp for fun w/ new geoip on nodes

revamp-ui
lza_menace 2 years ago
parent 2a6d0a8e9c
commit 8e5f35b0d3

@ -30,4 +30,6 @@ Werkzeug==2.2.3
WTForms==3.0.1 WTForms==3.0.1
yarl==1.8.2 yarl==1.8.2
zipp==3.15.0 zipp==3.15.0
dnspython==1.15.0 ipwhois==1.2.0
matplotlib==3.7.1
numpy==1.24.3

@ -8,7 +8,7 @@ import requests
from flask import Blueprint from flask import Blueprint
from urllib.parse import urlparse from urllib.parse import urlparse
from xmrnodes.helpers import determine_crypto, is_onion, is_i2p, make_request from xmrnodes.helpers import determine_crypto, is_onion, is_i2p, make_request, get_whois
from xmrnodes.helpers import retrieve_peers, rw_cache, get_highest_block, get_geoip from xmrnodes.helpers import retrieve_peers, rw_cache, get_highest_block, get_geoip
from xmrnodes.models import Node, HealthCheck, Peer from xmrnodes.models import Node, HealthCheck, Peer
from xmrnodes import config from xmrnodes import config
@ -23,7 +23,7 @@ def init():
@bp.cli.command("check") @bp.cli.command("check")
def check_nodes(): def check_nodes():
diff = datetime.utcnow() - timedelta(hours=72) diff = datetime.utcnow() - timedelta(hours=96)
checks = HealthCheck.select().where(HealthCheck.datetime <= diff) checks = HealthCheck.select().where(HealthCheck.datetime <= diff)
for check in checks: for check in checks:
print("Deleting check", check.id) print("Deleting check", check.id)
@ -194,6 +194,13 @@ def validate():
node.lat = geoip.location.latitude node.lat = geoip.location.latitude
node.lon = geoip.location.longitude node.lon = geoip.location.longitude
logging.info(f"found geo data for {node.url} - {node.country_code}, {node.country_name}, {node.city}") logging.info(f"found geo data for {node.url} - {node.country_code}, {node.country_name}, {node.city}")
whois = get_whois(node.url)
if whois:
logging.info(f"found whois data for {node.url}")
node.asn = whois['asn']
node.asn_cidr = whois['asn_cidr']
node.asn_country_code = whois['asn_country_code']
node.asn_description = whois['asn_description']
node.save() node.save()
logging.info("success") logging.info("success")
else: else:

@ -4,6 +4,7 @@ import pickle
from os import path from os import path
import geoip2.database import geoip2.database
from ipwhois import ipwhois
from requests import get as r_get from requests import get as r_get
from urllib.parse import urlparse from urllib.parse import urlparse
from levin.bucket import Bucket from levin.bucket import Bucket
@ -159,18 +160,21 @@ def get_highest_block(nettype, crypto):
else: else:
return 0 return 0
def get_host(node_url):
def get_geoip(ip_or_dns): host = urlparse(node_url).netloc.split(':')[0]
host = urlparse(ip_or_dns).netloc.split(':')[0]
resolved = socket.gethostbyname(host) resolved = socket.gethostbyname(host)
host = host if resolved == host else resolved return host if resolved == host else resolved
def get_geoip(node_url):
host = get_host(node_url)
with geoip2.database.Reader("./data/GeoLite2-City.mmdb") as reader: with geoip2.database.Reader("./data/GeoLite2-City.mmdb") as reader:
return reader.city(host) return reader.city(host)
def get_whois(ip_or_dns): def get_whois(node_url):
pass host = get_host(node_url)
try:
# asn who = ipwhois.IPWhois(host).lookup_rdap()
# asn_cidr return who
# asn_country_code except:
# asn_description return None

@ -1,4 +1,5 @@
from urllib.parse import urlparse from urllib.parse import urlparse
from statistics import mean
from datetime import datetime from datetime import datetime
from peewee import * from peewee import *
@ -28,6 +29,10 @@ class Node(Model):
postal = IntegerField(null=True) postal = IntegerField(null=True)
lat = FloatField(null=True) lat = FloatField(null=True)
lon = FloatField(null=True) lon = FloatField(null=True)
asn = CharField(null=True)
asn_cidr = CharField(null=True)
asn_country_code = CharField(null=True)
asn_description = CharField(null=True)
datetime_entered = DateTimeField(default=datetime.utcnow) datetime_entered = DateTimeField(default=datetime.utcnow)
datetime_checked = DateTimeField(default=None, null=True) datetime_checked = DateTimeField(default=None, null=True)
datetime_failed = DateTimeField(default=None, null=True) datetime_failed = DateTimeField(default=None, null=True)
@ -47,6 +52,16 @@ class Node(Model):
hcs = HealthCheck.select().where(HealthCheck.node == self) hcs = HealthCheck.select().where(HealthCheck.node == self)
return hcs return hcs
@property
def uptime(self):
hcs = self.healthchecks
ups = [1 for i in hcs if i.health == True]
downs = [0 for i in hcs if i.health == False]
if (len(ups + downs)):
m = mean(ups + downs)
return int(m * 100)
return 0
class Meta: class Meta:
database = db database = db
@ -79,6 +94,10 @@ class HealthCheck(Model):
datetime = DateTimeField(default=datetime.utcnow) datetime = DateTimeField(default=datetime.utcnow)
health = BooleanField() health = BooleanField()
@property
def color(self):
return 'green' if self.health else 'red'
class Meta: class Meta:
database = db database = db

@ -1,9 +1,15 @@
import re import re
from io import BytesIO
from random import shuffle from random import shuffle
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from urllib.parse import urlparse
from flask import request, redirect, Blueprint from flask import request, redirect, Blueprint
from flask import render_template, flash, Response from flask import render_template, flash, Response
from urllib.parse import urlparse from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
from matplotlib.figure import Figure
from xmrnodes.helpers import rw_cache, get_highest_block from xmrnodes.helpers import rw_cache, get_highest_block
from xmrnodes.forms import SubmitNode from xmrnodes.forms import SubmitNode
@ -61,6 +67,33 @@ def index():
) )
@bp.route('/plot/<int:node_id>.png')
def plot_health(node_id):
node = Node.get(node_id).healthchecks
if not node:
return None
df = pd.DataFrame(node.dicts())
df['health'] = df['health'].astype(int)
fig = Figure(figsize=(3,3), tight_layout=True)
output = BytesIO()
axis = fig.add_subplot()
dff = df.groupby(['health']).agg({'health': 'count'})
if 0 not in dff.index:
dff.loc[0] = 0
print(dff.index)
dff = dff.sort_index() # sorting by index
axis.pie(
dff['health'],
colors=['#B76D68', '#78BC61'],
radius=8,
wedgeprops={"linewidth": 2, "edgecolor": "white"},
frame=True
)
axis.axis('off')
FigureCanvas(fig).print_png(output)
return Response(output.getvalue(), mimetype='image/png')
@bp.route("/map") @bp.route("/map")
def map(): def map():
try: try:

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

@ -0,0 +1,271 @@
/*!*****************************************************
Freak Flags, Copyright ©2023 Michael P. Cohen. Freak flags is licenced under the MIT licence.
For complete information visit: www.freakflagsprite.com
******************************************************/
.fflag {
background-image:url(flagSprite42.png);
background-repeat:no-repeat;
background-size: 100% 49494%;
display: inline-block;
overflow: hidden;
position: relative;
vertical-align: middle;
box-sizing: content-box;
}
.fflag-CH,
.fflag-NP {box-shadow: none!important}
.fflag-DZ {background-position:center 0.2287%}
.fflag-AO {background-position:center 0.4524%}
.fflag-BJ {background-position:center 0.6721%}
.fflag-BW {background-position:center 0.8958%}
.fflag-BF {background-position:center 1.1162%}
.fflag-BI {background-position:center 1.3379%}
.fflag-CM {background-position:center 1.5589%}
.fflag-CV {background-position:center 1.7805%}
.fflag-CF {background-position:center 2.0047%}
.fflag-TD {background-position:center 2.2247%}
.fflag-CD {background-position:left 2.4467%}
.fflag-DJ {background-position:left 2.6674%}
.fflag-EG {background-position:center 2.8931%}
.fflag-GQ {background-position:center 3.1125%}
.fflag-ER {background-position:left 3.3325%}
.fflag-ET {background-position:center 3.5542%}
.fflag-GA {background-position:center 3.7759%}
.fflag-GM {background-position:center 4.0015%}
.fflag-GH {background-position:center 4.2229%}
.fflag-GN {background-position:center 4.441%}
.fflag-GW {background-position:left 4.66663%}
.fflag-CI {background-position:center 4.8844%}
.fflag-KE {background-position:center 5.1061%}
.fflag-LS {background-position:center 5.3298%}
.fflag-LR {background-position:left 5.5495%}
.fflag-LY {background-position:center 5.7712%}
.fflag-MG {background-position:center 5.994%}
.fflag-MW {background-position:center 6.2156%}
.fflag-ML {background-position:center 6.4363%}
.fflag-MR {background-position:center 6.658%}
.fflag-MU {background-position:center 6.8805%}
.fflag-YT {background-position:center 7.1038%}
.fflag-MA {background-position:center 7.3231%}
.fflag-MZ {background-position:left 7.5448%}
.fflag-NA {background-position:left 7.7661%}
.fflag-NE {background-position:center 7.98937%}
.fflag-NG {background-position:center 8.2099%}
.fflag-CG {background-position:center 8.4316%}
.fflag-RE {background-position:center 8.6533%}
.fflag-RW {background-position:right 8.875%}
.fflag-SH {background-position:center 9.0967%}
.fflag-ST {background-position:center 9.32237%}
.fflag-SN {background-position:center 9.5426%}
.fflag-SC {background-position:left 9.7628%}
.fflag-SL {background-position:center 9.9845%}
.fflag-SO {background-position:center 10.2052%}
.fflag-ZA {background-position:left 10.4269%}
.fflag-SS {background-position:left 10.6486%}
.fflag-SD {background-position:center 10.8703%}
.fflag-SR {background-position:center 11.0945%}
.fflag-SZ {background-position:center 11.3135%}
.fflag-TG {background-position:left 11.5354%}
.fflag-TN {background-position:center 11.7593%}
.fflag-UG {background-position:center 11.9799%}
.fflag-TZ {background-position:center 12.2005%}
.fflag-EH {background-position:center 12.4222%}
.fflag-YE {background-position:center 12.644%}
.fflag-ZM {background-position:center 12.8664%}
.fflag-ZW {background-position:left 13.0873%}
.fflag-AI {background-position:center 13.309%}
.fflag-AG {background-position:center 13.5307%}
.fflag-AR {background-position:center 13.7524%}
.fflag-AW {background-position:left 13.9741%}
.fflag-BS {background-position:left 14.1958%}
.fflag-BB {background-position:center 14.4175%}
.fflag-BQ {background-position:center 14.6415%}
.fflag-BZ {background-position:center 14.8609%}
.fflag-BM {background-position:center 15.0826%}
.fflag-BO {background-position:center 15.306%}
.fflag-VG {background-position:center 15.528%}
.fflag-BR {background-position:center 15.7496%}
.fflag-CA {background-position:center 15.9694%}
.fflag-KY {background-position:center 16.1911%}
.fflag-CL {background-position:left 16.4128%}
.fflag-CO {background-position:left 16.6345%}
.fflag-KM {background-position:center 16.8562%}
.fflag-CR {background-position:center 17.0779%}
.fflag-CU {background-position:left 17.2996%}
.fflag-CW {background-position:center 17.5213%}
.fflag-DM {background-position:center 17.743%}
.fflag-DO {background-position:center 17.968%}
.fflag-EC {background-position:center 18.1864%}
.fflag-SV {background-position:center 18.4081%}
.fflag-FK {background-position:center 18.6298%}
.fflag-GF {background-position:center 18.8515%}
.fflag-GL {background-position:left 19.0732%}
.fflag-GD {background-position:center 19.2987%}
.fflag-GP {background-position:center 19.518%}
.fflag-GT {background-position:center 19.7383%}
.fflag-GY {background-position:center 19.96%}
.fflag-HT {background-position:center 20.1817%}
.fflag-HN {background-position:center 20.4034%}
.fflag-JM {background-position:center 20.6241%}
.fflag-MQ {background-position:center 20.8468%}
.fflag-MX {background-position:center 21.0685%}
.fflag-MS {background-position:center 21.2902%}
.fflag-NI {background-position:center 21.5119%}
.fflag-PA {background-position:center 21.7336%}
.fflag-PY {background-position:center 21.9553%}
.fflag-PE {background-position:center 22.177%}
.fflag-PR {background-position:left 22.4002%}
.fflag-BL {background-position:center 22.6204%}
.fflag-KN {background-position:center 22.8421%}
.fflag-LC {background-position:center 23.0638%}
.fflag-PM {background-position:center 23.2855%}
.fflag-VC {background-position:center 23.5072%}
.fflag-SX {background-position:left 23.732%}
.fflag-TT {background-position:center 23.9506%}
.fflag-TC {background-position:center 24.1723%}
.fflag-US {background-position:center 24.392%}
.fflag-VI {background-position:center 24.6157%}
.fflag-UY {background-position:left 24.8374%}
.fflag-VE {background-position:center 25.0591%}
.fflag-AB {background-position:center 25.279%}
.fflag-AF {background-position:center 25.5025%}
.fflag-AZ {background-position:center 25.7242%}
.fflag-BD {background-position:center 25.9459%}
.fflag-BT {background-position:center 26.1676%}
.fflag-BN {background-position:center 26.3885%}
.fflag-KH {background-position:center 26.611%}
.fflag-CN {background-position:left 26.8327%}
.fflag-GE {background-position:center 27.0544%}
.fflag-HK {background-position:center 27.2761%}
.fflag-IN {background-position:center 27.4978%}
.fflag-ID {background-position:center 27.7195%}
.fflag-JP {background-position:center 27.9412%}
.fflag-KZ {background-position:center 28.1615%}
.fflag-LA {background-position:center 28.3846%}
.fflag-MO {background-position:center 28.6063%}
.fflag-MY {background-position:center 28.829%}
.fflag-MV {background-position:center 29.0497%}
.fflag-MN {background-position:left 29.2714%}
.fflag-MM {background-position:center 29.4931%}
.fflag-NP {background-position:left 29.7148%}
.fflag-KP {background-position:left 29.9365%}
.fflag-MP {background-position:center 30.1582%}
.fflag-PW {background-position:center 30.3799%}
.fflag-PG {background-position:center 30.6016%}
.fflag-PH {background-position:left 30.8233%}
.fflag-SG {background-position:left 31.045%}
.fflag-KR {background-position:center 31.2667%}
.fflag-LK {background-position:right 31.4884%}
.fflag-TW {background-position:left 31.7101%}
.fflag-TJ {background-position:center 31.9318%}
.fflag-TH {background-position:center 32.1535%}
.fflag-TL {background-position:left 32.3752%}
.fflag-TM {background-position:center 32.5969%}
.fflag-VN {background-position:center 32.8186%}
.fflag-AX {background-position:center 33.0403%}
.fflag-AL {background-position:center 33.25975%}
.fflag-AD {background-position:center 33.4837%}
.fflag-AM {background-position:center 33.7054%}
.fflag-AT {background-position:center 33.9271%}
.fflag-BY {background-position:left 34.1488%}
.fflag-BE {background-position:center 34.3705%}
.fflag-BA {background-position:center 34.5922%}
.fflag-BG {background-position:center 34.8139%}
.fflag-HR {background-position:center 35.0356%}
.fflag-CY {background-position:center 35.2555%}
.fflag-CZ {background-position:left 35.479%}
.fflag-DK {background-position:center 35.7007%}
.fflag-EE {background-position:center 35.9224%}
.fflag-FO {background-position:center 36.1441%}
.fflag-FI {background-position:center 36.3658%}
.fflag-FR {background-position:center 36.5875%}
.fflag-DE {background-position:center 36.8092%}
.fflag-GI {background-position:center 37.0309%}
.fflag-GR {background-position:left 37.2526%}
.fflag-GG {background-position:center 37.4743%}
.fflag-HU {background-position:center 37.696%}
.fflag-IS {background-position:center 37.9177%}
.fflag-IE {background-position:center 38.1394%}
.fflag-IM {background-position:center 38.3611%}
.fflag-IT {background-position:center 38.5828%}
.fflag-JE {background-position:center 38.8045%}
.fflag-XK {background-position:center 39.0262%}
.fflag-LV {background-position:center 39.2479%}
.fflag-LI {background-position:left 39.4696%}
.fflag-LT {background-position:center 39.6913%}
.fflag-LU {background-position:center 39.913%}
.fflag-MT {background-position:left 40.1347%}
.fflag-MD {background-position:center 40.3564%}
.fflag-MC {background-position:center 40.5781%}
.fflag-ME {background-position:center 40.7998%}
.fflag-NL {background-position:center 41.0215%}
.fflag-MK {background-position:center 41.2432%}
.fflag-NO {background-position:center 41.4649%}
.fflag-PL {background-position:center 41.6866%}
.fflag-PT {background-position:center 41.9083%}
.fflag-RO {background-position:center 42.13%}
.fflag-RU {background-position:center 42.3517%}
.fflag-SM {background-position:center 42.5734%}
.fflag-RS {background-position:center 42.7951%}
.fflag-SK {background-position:center 43.0168%}
.fflag-SI {background-position:center 43.2385%}
.fflag-ES {background-position:left 43.4602%}
.fflag-SE {background-position:center 43.6819%}
.fflag-CH {background-position:center 43.9036%}
.fflag-TR {background-position:center 44.1253%}
.fflag-UA {background-position:center 44.347%}
.fflag-GB {background-position:center 44.5687%}
.fflag-VA {background-position:right 44.7904%}
.fflag-BH {background-position:center 45.0121%}
.fflag-IR {background-position:center 45.2338%}
.fflag-IQ {background-position:center 45.4555%}
.fflag-IL {background-position:center 45.6772%}
.fflag-KW {background-position:left 45.897%}
.fflag-JO {background-position:left 46.1206%}
.fflag-KG {background-position:center 46.3423%}
.fflag-LB {background-position:center 46.561%}
.fflag-OM {background-position:left 46.7857%}
.fflag-PK {background-position:center 47.0074%}
.fflag-PS {background-position:center 47.2291%}
.fflag-QA {background-position:center 47.4508%}
.fflag-SA {background-position:center 47.6725%}
.fflag-SY {background-position:center 47.8942%}
.fflag-AE {background-position:center 48.1159%}
.fflag-UZ {background-position:left 48.3376%}
.fflag-AS {background-position:right 48.5593%}
.fflag-AU {background-position:center 48.781%}
.fflag-CX {background-position:center 49.002%}
.fflag-CC {background-position:center 49.2244%}
.fflag-CK {background-position:center 49.4445%}
.fflag-FJ {background-position:center 49.6678%}
.fflag-PF {background-position:center 49.8895%}
.fflag-GU {background-position:center 50.1112%}
.fflag-KI {background-position:center 50.3329%}
.fflag-MH {background-position:left 50.5546%}
.fflag-FM {background-position:center 50.7763%}
.fflag-NC {background-position:center 50.998%}
.fflag-NZ {background-position:center 51.2197%}
.fflag-NR {background-position:left 51.4414%}
.fflag-NU {background-position:center 51.6631%}
.fflag-NF {background-position:center 51.8848%}
.fflag-WS {background-position:left 52.1065%}
.fflag-SB {background-position:left 52.3282%}
.fflag-TK {background-position:center 52.5499%}
.fflag-TO {background-position:left 52.7716%}
.fflag-TV {background-position:center 52.9933%}
.fflag-VU {background-position:left 53.215%}
.fflag-WF {background-position:center 53.4385%}
.fflag-AQ {background-position:center 53.6584%}
.fflag-EU {background-position:center 53.875%}
.fflag-JR {background-position:center 54.099%}
.fflag-OLY {background-position:center 54.32%}
.fflag-UN {background-position:center 54.54%}
.fflag.ff-sm {width: 18px;height: 11px}
.fflag.ff-md {width: 27px;height: 17px}
.fflag.ff-lg {width: 42px;height: 27px}
.fflag.ff-xl {width: 60px;height: 37px}

@ -0,0 +1,82 @@
body {
background-color: #1B2432;
color: #f9f9f9;
font-family: monospace;
font-size: 14px;
}
.media-content .title {
color: #1B2432;
}
.title {
color: #f9f9f9;
}
.card {
background-color: #F1F2EB;
}
.card .media:not(:last-child) {
margin-bottom: 0;
}
.card-content {
padding: 1em;
margin: 1em;
}
.smol {
font-size: .75em;
}
.donationAddress {
font-size: .8em;
user-select: all;
color: #ff006e;
display: block;
padding-top: .35em;
word-wrap: break-word;
}
.asn {
font-size: .8em;
color: #ff006e;
display: block;
word-wrap: break-word;
}
.nodeURL {
user-select: all;
font-size: 1em;
}
.messages {
width: 30em;
padding: 1em;
position: absolute;
right: 0;
}
#addNodeForm {
width: 50%;
}
#webCompat {
margin: 1em;
}
.dot {
height: 10px;
width: 10px;
border-radius: 50%;
display: inline-block;
}
.glowing-green {
background-color: #78BC61;
}
.glowing-red {
background-color: #B76D68;
}

@ -134,6 +134,7 @@ input[type="text"] {
.nodeURL { .nodeURL {
user-select: all; user-select: all;
font-size: 1em;
} }
td img { td img {
@ -149,3 +150,11 @@ td img {
padding-top: .35em; padding-top: .35em;
word-wrap: break-word; word-wrap: break-word;
} }
.asn {
font-size: .8em;
color: #ff006e;
display: block;
padding-top: .35em;
word-wrap: break-word;
}

File diff suppressed because one or more lines are too long

@ -19,36 +19,69 @@
<meta name="application-name" content="XMR Nodes"> <meta name="application-name" content="XMR Nodes">
<meta name="msapplication-TileColor" content="#da532c"> <meta name="msapplication-TileColor" content="#da532c">
<meta name="keywords" content="wownero, monero, xmr, bitmonero, cryptocurrency"> <meta name="keywords" content="wownero, monero, xmr, bitmonero, cryptocurrency">
<link href="/static/css/normalize.css" rel="stylesheet"> <link href="/static/css/freakflags.css" rel="stylesheet">
<link href="/static/css/pure.css" rel="stylesheet"> <link href="/static/css/bulma.min.css" rel="stylesheet">
<link href="/static/css/style.css" rel="stylesheet"> <link href="/static/css/main.css" rel="stylesheet">
<title>XMR Nodes</title> <title>XMR Nodes</title>
</head> </head>
<body> <body>
<nav class="navbar" role="navigation" aria-label="main navigation">
<div class="navbar-brand">
<a class="navbar-item" href="/">
<img src="/static/images/monero.svg" width="25" height="28">.fail
</a>
<a role="button" class="navbar-burger" data-target="navMenu" aria-label="menu" aria-expanded="false">
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div id="navMenu" class="navbar-menu">
<div class="navbar-start">
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link">
Links
</a>
<div class="navbar-dropdown">
<a class="navbar-item" href="{{ url_for('meta.about') }}">
About
</a>
<a class="navbar-item" href="{{ url_for('meta.map') }}">
Map
</a>
<a class="navbar-item" href="mailto:lza_menace@protonmail.com" target="_blank">
Contact
</a>
<a class="navbar-item" href="https://github.com/lalanza808/monero.fail" target="_blank">
Source Code
</a>
<hr class="navbar-divider">
<a class="navbar-item" href="https://moneroinfodump.neocities.org/" target="_blank">
Info Dump
</a>
</div>
</div>
</div>
</div>
</nav>
{% with messages = get_flashed_messages() %} {% with messages = get_flashed_messages() %}
{% if messages %} {% if messages %}
<ul class="flashes pure-u-1 center"> <div class="messages">
{% for message in messages %} {% for message in messages %}
<li>{{ message }}</li> <article class="message is-info">
{% endfor %} <div class="message-body">
</ul> {{ message }}
</div>
</article>
{% endfor %}
</div>
{% endif %} {% endif %}
{% endwith %} {% endwith %}
<div id="" class="center">
<br>
<a href="{{ url_for('meta.about') }}">about</a>
-
<a href="{{ url_for('meta.map') }}">map</a>
-
<a href="https://twitter.com/lza_menace" target="_blank">contact</a>
-
<a href="https://github.com/lalanza808/monero.fail" target="_blank">source</a>
-
<a href="https://moneroinfodump.neocities.org/" target="_blank">infodump</a>
</div>
<!-- Page Content --> <!-- Page Content -->
{% block content %} {% endblock %} {% block content %} {% endblock %}
@ -58,5 +91,19 @@
<a href="#">Go to top</a> <a href="#">Go to top</a>
</div> </div>
<script>
document.addEventListener('DOMContentLoaded', () => {
const $navbarBurgers = Array.prototype.slice.call(document.querySelectorAll('.navbar-burger'), 0);
$navbarBurgers.forEach( el => {
el.addEventListener('click', () => {
const target = el.dataset.target;
const $target = document.getElementById(target);
el.classList.toggle('is-active');
$target.classList.toggle('is-active');
});
});
});
</script>
</body> </body>
</html> </html>

@ -5,33 +5,31 @@
<div id="index" class="container"> <div id="index" class="container">
<div id="addnode" class="pure-g center section"> <div id="addnode" class="section">
<div class="title pure-u-1"> <h2 class="title is-4">Add A Node</h2>
<h2>Add A Node</h2> <form method="POST" action="{{ url_for('meta.add') }}" id="addNodeForm">
</div>
<form method="POST" action="{{ url_for('meta.add') }}" class="pure-form pure-u-1">
{{ form.csrf_token }} {{ form.csrf_token }}
{% for f in form %} <div class="field">
{% if f.name != 'csrf_token' %} <div class="control">
<div class="form-group"> <input class="input" type="text" placeholder="http://mynode.com:18081" id="node_url" name="node_url" required>
{{ f.label }} </div>
{{ f }} </div>
<button type="submit" class="pure-button pure-button-primary">Submit</button> <div class="field is-grouped">
</div> <div class="control">
{% endif %} <button class="button is-link">Submit</button>
{% endfor %} </div>
</div>
<ul> <ul>
{% for field, errors in form.errors.items() %} {% for field, errors in form.errors.items() %}
<li>{{ form[field].label }}: {{ ', '.join(errors) }}</li> <li>{{ form[field].label }}: {{ ', '.join(errors) }}</li>
{% endfor %} {% endfor %}
</ul> </ul>
</form> </form>
</div> </div>
<div id="nodes" class="pure-u-1 section"> <div id="nodes" class="section">
<h2 class="center">Find a Node</h2> <h2 class="title is-4">Find a Node</h2>
<div class="center" id="filters"> <div class="" id="filters">
<form> <form>
<span> <span>
<label for="chainSelect">Chain:</label> <label for="chainSelect">Chain:</label>
@ -40,7 +38,6 @@
<option value="wownero" {% if request.args.get('chain') == 'wownero' %}selected{% endif %}>Wownero</option> <option value="wownero" {% if request.args.get('chain') == 'wownero' %}selected{% endif %}>Wownero</option>
</select> </select>
</span> </span>
<span> <span>
<label for="networkSelect">Network:</label> <label for="networkSelect">Network:</label>
<select name="network" id="networkSelect"> <select name="network" id="networkSelect">
@ -49,48 +46,42 @@
<option value="stagenet" {% if request.args.get('network') == 'stagenet' %}selected{% endif %}>Stagenet</option> <option value="stagenet" {% if request.args.get('network') == 'stagenet' %}selected{% endif %}>Stagenet</option>
</select> </select>
</span> </span>
<span> <span>
<label for="cors">Web (CORS):</label> <label for="cors">CORS:</label>
<input type="checkbox" name="cors" id="cors" {% if request.args.get('cors') == 'on' %}checked{% endif %}> <input type="checkbox" name="cors" id="cors" {% if request.args.get('cors') == 'on' %}checked{% endif %}>
</span> </span>
<span> <span>
<label for="onion">Onion:</label> <label for="onion">Onion:</label>
<input type="checkbox" name="onion" id="onion" {% if request.args.get('onion') == 'on' %}checked{% endif %}> <input type="checkbox" name="onion" id="onion" {% if request.args.get('onion') == 'on' %}checked{% endif %}>
</span> </span>
<span> <span>
<label for="i2p">I2P:</label> <label for="i2p">I2P:</label>
<input type="checkbox" name="i2p" id="i2p" {% if request.args.get('i2p') == 'on' %}checked{% endif %}> <input type="checkbox" name="i2p" id="i2p" {% if request.args.get('i2p') == 'on' %}checked{% endif %}>
</span> </span>
<span> <span>
<input type="submit" value="Filter" class="pure-button pure-pink"> <input type="submit" value="Filter" class="pure-button pure-pink">
</span> </span>
<span> <span>
<a href="/"><input type="button" value="Reset" class="pure-button pure-grey"></a> <a href="/"><input type="button" value="Reset" class="pure-button pure-grey"></a>
</span> </span>
</form> </form>
</div> </div>
{% if nodes %} {% if nodes %}
<div class="xmrnodes"> <div class="xmrnodes">
<p class="center"> <p class="">
{% if web_compatible %} {% if web_compatible %}
<strong> <div class="notification is-info is-light" id="webCompat">
Web compatible means the node is run in such a way that it allows web clients to access their APIs (CORS headers allow all and secure HTTP / TLS terminated). Web compatible means the node is run in such a way that it allows web clients to access their APIs (CORS headers allow all and secure HTTP / TLS terminated).
<br> The more nodes there are running with these settings the more robust web clients will be in the future.
The more nodes there are running with these settings the more robust web clients will be in the future. </div>
</strong>
<br><br>
{% endif %} {% endif %}
<a href="{{ url_for('meta.haproxy', chain=request.args.get('chain'), network=request.args.get('network'), cors=request.args.get('cors'), onion=request.args.get('onion')) }}">Download HAProxy config</a><br /><br /> <a href="{{ url_for('meta.haproxy', chain=request.args.get('chain'), network=request.args.get('network'), cors=request.args.get('cors'), onion=request.args.get('onion')) }}">Download HAProxy config</a><br /><br />
Tracking {{ nodes_all }} {{ nettype }} {{ crypto | capitalize }} nodes in the database. Tracking {{ nodes_all }} {{ nettype }} {{ crypto | capitalize }} nodes in the database.
<br> <br>
Of those, {{ nodes_unhealthy }} nodes failed their last check-in (unresponsive to ping or over 500 blocks away from highest reported block). Of those, {{ nodes_unhealthy }} nodes failed their last check-in (unresponsive to ping or over 500 blocks away from highest reported block).
</p> </p>
<p class="center">Showing {{ nodes | length }} nodes. <p class="">Showing {{ nodes | length }} nodes.
{% if 'all' not in request.args %} {% if 'all' not in request.args %}
<a href="{% if request.args %}{{ request.url }}&{% else %}?{% endif %}all=true">Show All</a> <a href="{% if request.args %}{{ request.url }}&{% else %}?{% endif %}all=true">Show All</a>
{% else %} {% else %}
@ -98,67 +89,125 @@
{% endif %} {% endif %}
</p> </p>
<br> <br>
<table class="pure-table pure-table-horizontal pure-table-striped js-sort-table"> <div>
<thead>
<tr> <div class="columns">
<th class="js-sort-string">Type</th>
<th class="js-sort-string">URL</th> <div class="column">
<th class="js-sort-number">Height</th> {% for node in nodes %}
<th class="js-sort-none">Up</th> <div class="card">
<th class="js-sort-none">Web<br/>Compatible</th>
<th class="js-sort-none">Network</th> <div class="card-content">
<th class="js-sort-none">Last Checked</th>
<th class="js-sort-none">History</th> <div class="media">
</tr> <div class="media-left">
</thead> <figure class="image is-32x32">
<tbody> {% if node.is_tor %}
{% for node in nodes %} <img src="/static/images/tor.svg" />
<tr class="js-sort-table"> {% elif node.is_i2p %}
<td> <img src="/static/images/i2p.svg" />
{% if node.is_tor %} {% else %}
<img src="/static/images/tor.svg" height="20px"> <span class="fflag fflag-{{ node.country_code }} ff-lg mr-4" title="{{ node.asn_description }}"></span>
<span class="hidden">tor</span> {% endif %}
{% elif node.is_i2p %} </figure>
<img src="/static/images/i2p.svg" height="20px"> </div>
<span class="hidden">i2p</span> <div class="media-content">
{% else %} <p class="title is-6 nodeURL">{{ node.url }}</p>
<img src="/static/images/clearnet.svg" height="20px"> {% if node.asn %}
<span class="hidden">clear</span> <p class="subtitle asn">
{% endif %} ASN: {{ node.asn }} -
</td> {{ node.asn_description}}
<td> </p>
<span class="nodeURL">{{ node.url }}</span> {% endif %}
{% if node.donation_address | seems_legit %} <div class="statusDots subtitle">
<span class="donationAddress">{{ node.donation_address }}</span> {% for check in node.healthchecks %}
{% endif %} <span class="dot glowing-{{ check.color }}"></span>
</td> {% endfor %}
<td>{{ node.last_height }}</td> </div>
<td> </div>
{% if node.available %} </div>
<span class="dot glowing-green"></span>
{% else %} <div class="content">
<span class="dot glowing-red""></span> <br>
{% endif %} <p class="smol">
</td> last checked {{ node.datetime_checked | humanize }}<br />
<td> {{ node.uptime }}% uptime
{% if node.web_compatible %} </p>
<img src="/static/images/success.svg" class="filter-green" width=16px> </div>
{% else %}
<img src="/static/images/error.svg" class="filter-red" width=16px> </div>
{% endif %}
</td> <footer class="card-footer">
<td>{{ node.nettype }}</td> <p class="card-footer-item">
<td>{{ node.datetime_checked | humanize }}</td> <span>
<td>{% for hc in node.healthchecks %} View on <a href="https://twitter.com/codinghorror/status/506010907021828096">Twitter</a>
{% if loop.index > loop.length - 6 %} </span>
<span class="dot glowing-{% if hc.health %}green{% else %}red{% endif %}"></span> </p>
{% endif %} <p class="card-footer-item">
<span>
Share on <a href="#">Facebook</a>
</span>
</p>
</footer>
</div>
{% endfor %} {% endfor %}
</td> </div>
</tr>
{% endfor %} <div class="column">
</tbody> <article class="panel is-info">
</table> <p class="panel-heading">
Info
</p>
<p class="panel-tabs">
<a class="is-active">All</a>
<a>Public</a>
<a>Private</a>
<a>Sources</a>
<a>Forks</a>
</p>
<div class="panel-block">
<p class="control has-icons-left">
<input class="input is-info" type="text" placeholder="Search">
<span class="icon is-left">
<i class="fas fa-search" aria-hidden="true"></i>
</span>
</p>
</div>
<a class="panel-block is-active">
<span class="panel-icon">
<i class="fas fa-book" aria-hidden="true"></i>
</span>
bulma
</a>
<a class="panel-block">
<span class="panel-icon">
<i class="fas fa-book" aria-hidden="true"></i>
</span>
marksheet
</a>
<a class="panel-block">
<span class="panel-icon">
<i class="fas fa-book" aria-hidden="true"></i>
</span>
minireset.css
</a>
<a class="panel-block">
<span class="panel-icon">
<i class="fas fa-book" aria-hidden="true"></i>
</span>
jgthms.github.io
</a>
</article>
</div>
</div>
<!-- </tbody>
</table> -->
</div>
</div> </div>
{% else %} {% else %}
<p class="center">No nodes in the database yet...</p> <p class="center">No nodes in the database yet...</p>

@ -1,59 +1,6 @@
<!DOCTYPE html> {% extends 'base.html' %}
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="HandheldFriendly" content="True">
<meta name="MobileOptimized" content="320">
<link rel="shortcut icon" href="/static/favicon.ico" type="image/x-icon" />
<meta property="fb:app_id" content="0" />
<meta property="og:image" content="https://www.getmonero.org/press-kit/symbols/monero-symbol-on-white-480.png" />
<meta property="og:description" content="xmrnodes" />
<meta property="og:url" content="http://localhost" />
<meta property="og:title" content="XMR Nodes" />
<meta property="og:type" content="website" />
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<meta name="theme-color" content="#ffffff">
<meta name="apple-mobile-web-app-title" content="XMR Nodes">
<meta name="application-name" content="XMR Nodes">
<meta name="msapplication-TileColor" content="#da532c">
<meta name="keywords" content="wownero, monero, xmr, bitmonero, cryptocurrency">
<link rel="stylesheet" href="//cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.5.0/css/ol.css" type="text/css">
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" type="text/css">
<style>
.map {
height: 600px;
margin: 2em;
padding: 0;
}
.popover-body {
min-width: 276px;
}
.center.info {
width: 50%;
margin: auto;
padding: 2em;
}
</style>
<script src="https://cdn.polyfill.io/v3/polyfill.min.js?features=fetch,requestAnimationFrame,Element.prototype.classList,URL,TextDecoder"></script>
<script src="//cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.5.0/build/ol.js"></script>
<script src="//code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.bundle.min.js"></script>
<title>XMR Nodes</title>
</head>
<body> {% block content %}
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul class="flashes pure-u-1 center">
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
<div class="center info"> <div class="center info">
<p>Peers seen ~24 hours: {{ peers | length }}</p> <p>Peers seen ~24 hours: {{ peers | length }}</p>
@ -65,12 +12,31 @@
Older peers are shown as more transparent and will be removed Older peers are shown as more transparent and will be removed
if not seen again after {{ config.PEER_LIFETIME }} hours. if not seen again after {{ config.PEER_LIFETIME }} hours.
</p> </p>
<br>
<a href="/">Go home</a>
</div> </div>
<div id="map" class="map"></div> <div id="map" class="map"></div>
<div id="popup" class="popup" title="Welcome to OpenLayers"></div> <div id="popup" class="popup" title="Welcome to OpenLayers"></div>
<link rel="stylesheet" href="//cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.5.0/css/ol.css" type="text/css">
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" type="text/css">
<style>
.map {
height: 600px;
margin: 2em;
padding: 0;
}
.popover-body {
min-width: 276px;
}
.center.info {
width: 50%;
margin: auto;
padding: 2em;
}
</style>
<script src="https://cdn.polyfill.io/v3/polyfill.min.js?features=fetch,requestAnimationFrame,Element.prototype.classList,URL,TextDecoder"></script>
<script src="//cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.5.0/build/ol.js"></script>
<script src="//code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.bundle.min.js"></script>
<script> <script>
// Marker layer // Marker layer
markerLayer = new ol.layer.Vector({ markerLayer = new ol.layer.Vector({
@ -157,6 +123,4 @@
}); });
}); });
</script> </script>
{% endblock %}
</body>
</html>
Loading…
Cancel
Save