From 8b726849693f0685301b7d449aed13a1ff994f4c Mon Sep 17 00:00:00 2001 From: dskvr Date: Thu, 24 Nov 2022 12:20:28 +0100 Subject: [PATCH] fixed bugs --- docker-compose.yaml | 2 +- relays.yaml | 52 +-- src/components/BaseRelays.vue | 610 +++++++++++++++------------------- 3 files changed, 299 insertions(+), 365 deletions(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index 45a6d00..7ce033d 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -6,4 +6,4 @@ services: logging: options: max-size: 1g - image: nrr + image: nostr-relay-status diff --git a/relays.yaml b/relays.yaml index 99fed70..9f517c9 100644 --- a/relays.yaml +++ b/relays.yaml @@ -1,28 +1,28 @@ relays: - # - 'wss://rsslay.fiatjaf.com' - # - 'wss://freedom-relay.herokuapp.com/ws' - # - 'wss://nostr-relay.freeberty.net' - # - 'wss://nostr.bitcoiner.social' - # - 'wss://nostr-relay.wlvs.space' - # - 'wss://nostr.onsats.org' - # - 'wss://nostr-relay.untethr.me' - # - 'wss://nostr.unknown.place' - # - 'wss://nostr.semisol.dev' - # - 'wss://nostr-pub.semisol.dev' - # - 'wss://nostr-verified.wellorder.net' - # - 'wss://nostr.drss.io' - # - 'wss://relay.damus.io' - # - 'wss://nostr.openchain.fr' - # - 'wss://nostr.delo.software' - # - 'wss://relay.nostr.info' - # - 'wss://relay.minds.com/nostr/v1/ws' - # - 'wss://nostr.zaprite.io' - # - 'wss://nostr.oxtr.dev' - # - 'wss://nostr.ono.re' - # - 'wss://relay.grunch.dev' - # - 'wss://relay.cynsar.foundation' - # - 'wss://nostr-pub.wellorder.net' - # - 'wss://relayer.fiatjaf.com' - # - 'wss://nostr.rocks' - # - 'wss://none.sandwich.farm' + - 'wss://rsslay.fiatjaf.com' + - 'wss://freedom-relay.herokuapp.com/ws' + - 'wss://nostr-relay.freeberty.net' + - 'wss://nostr-relay.wlvs.space' + - 'wss://nostr.onsats.org' + - 'wss://nostr-relay.untethr.me' + - 'wss://nostr.unknown.place' + - 'wss://nostr.semisol.dev' + - 'wss://nostr-pub.semisol.dev' + - 'wss://nostr-verified.wellorder.net' + - 'wss://nostr.drss.io' + - 'wss://relay.damus.io' + - 'wss://nostr.rocks' + - 'wss://nostr.bitcoiner.social' + - 'wss://nostr.openchain.fr' + - 'wss://nostr.delo.software' + - 'wss://relay.nostr.info' + - 'wss://relay.minds.com/nostr/v1/ws' + - 'wss://nostr.zaprite.io' + - 'wss://nostr.oxtr.dev' + - 'wss://nostr.ono.re' + - 'wss://relay.grunch.dev' + - 'wss://relay.cynsar.foundation' + - 'wss://nostr-pub.wellorder.net' + - 'wss://relayer.fiatjaf.com' - 'wss://nostr.sandwich.farm' + - 'wss://none.sandwich.farm' diff --git a/src/components/BaseRelays.vue b/src/components/BaseRelays.vue index 32996f1..8444ae1 100644 --- a/src/components/BaseRelays.vue +++ b/src/components/BaseRelays.vue @@ -1,122 +1,150 @@ @@ -159,163 +187,71 @@ export default defineComponent({ data() { return { relays, - status: {}, + result: {}, lastPing: Date.now(), nextPing: Date.now() + (60*1000), connections: {}, - latency: {}, pool: null, timeouts: {}, nips: {}, + messages: {}, + count: 0, } }, - mounted() { - this.relays.forEach(async relay => { - this.status[relay] = {} - const inspect = new Inspector(relay) - console.dir(inspect) - inspect.run() - // await this.testRelay(url) - }) - - // let latencyIntVal - // let counterIntVal - // - // // eslint-disable-next-line - // let latencyTimeout = setTimeout(() => { - // this.testRelayLatency() - // // eslint-disable-next-line - // latencyIntVal = setInterval(() => { this.testRelayLatency() }, refreshMillis) - // // eslint-disable-next-line - // latencyIntVal = setInterval(() => { this.nextPing = Math.round((this.lastPing + refreshMillis - Date.now())/1000)}, 1000) + async mounted() { + // //console.log(this.relays.filter((relay) => this.result?.[relay] && !this.result?.[relay].state=='complete').length) + this.relays.forEach(relay => { this.check(relay) }) + // setTimeout(() => { + // this.relays.forEach(relay => { this.checkLatency(relay) }) // }, 10000) - }, - methods: { - - hardFail(url) { - if(!this.status[url]) this.status[url] = {} - this.status[url].didConnect = false - this.status[url].didRead = false - this.status[url].didWrite = false - this.tryComplete(url) - if(this.connections[url].close) this.connections[url].close() - }, - - async testRelay (url) { - this.lastPing = Date.now() - this.latency[url] = {} - this.timeouts[url] = {} - this.status[url].notes = {} - this.status[url].state = 'pending' - this.nips[url] = new Array(99).fill(null); - this.status[url].readEventCount = 0 - this.status[url].writeEventCount = 0 - this.status[url].latencyEventCount = 0 - this.status[url].didNip15 = false - this.status[url].didNip20 = false - - this.timeouts[url].didConnect = setTimeout(() => { - console.log(url, "TIMEOUT") - if(Object.keys(this.status[url].notes).length == 0) this.status[url].notes['Reason: Timeout'] = {} - this.hardFail(url) - }, 20000) - - let relay = Relay(url, {reconnect: false}) - relay.on('open', e => { - console.log(url, "OPEN") - clearTimeout(this.timeouts[url].didConnect) - this.status[url].didConnect = true - this.testRead(url, "testRead") - this.testWrite(url, "testWrite") - this.tryComplete(url) - console.log(url, "did connect", this.status[url].didConnect) - }) - relay.on('eose', e => { - //console.log('EOSE', e) - // relay.close() - this.tryComplete(url) - this.status[url].didNip15 = true - }) - relay.on('error', (e) => { - //console.log('ERROR', e) - clearTimeout(this.timeouts[url].didConnect) - this.status[url].notes['Reason: Error'] = {} - this.hardFail(url) - }) + }, - relay.on('ok', () => { - this.status[url].didNip20 = true - }) + computed: {}, - relay.on('close', (e) => { - console.log('close', e) - // console.dir(arguments) - }) + methods: { - relay.on('other', (e) => { - // console.log('OTHER!!!!', e) - }) + check(relay){ - relay.on('event', (sub_id, ev) => { - // console.log('event', sub_id, ev) - if(sub_id == this.getID(url, "testRead")) { - // console.log("SUCCESS:", "READ") - this.status[url].readEventCount++ - this.status[url].didRead = true - clearTimeout(this.timeouts[url].testRead) - this.connections[url].unsubscribe(sub_id) - // this.tryComplete(url) - this.tryComplete(url) - } - if(sub_id == this.getID(url, "testWrite")) { - if(this.status[url].writeEventCount < 1) { - // console.log("SUCCESS:", "WRITE") - this.status[url].didWrite = true - console.log(ev) - // this.tryComplete(url) - //console.log(url, this.timeouts[url].testWrite) - clearTimeout(this.timeouts[url].testWrite) - this.tryComplete(url) - } - this.status[url].writeEventCount++ - } - if(sub_id == this.getID(url, "testLatency")) { - if(this.status[url].latencyEventCount < 1) { - console.log(url, "SUCCESS:", "test latency") - clearTimeout(this.timeouts[url].testLatency) - console.log(this.latency[url].start, this.latency[url].final) - this.latency[url].final = Date.now() - this.latency[url].start - this.setLatency(url) - } - this.status[url].latencyEventCount++ - // this.tryComplete(url) - //console.log(url, this.timeouts[url].testRead) - } - // relay.unsubscribe(sub_id) - }) - - relay.on('message', (message) => { - // console.log('message', message) - // console.dir(arguments) - }) + //console.log(relay, 'checking', this.count++) + let inspect = new Inspector(relay, { + checkLatency: true, + run: true, + setIP: true, + setGeo: true + }) + .on('open', (e, result) => { + this.result[relay] = result + }) + .on('complete', (instance) => { + this.result[relay] = instance.result + this.messages[relay] = instance.inbox + this.setFlag(relay) + this.setAggregateResult(relay) + //console.log('result state', instance.result) + //console.log('messages', this.messages[relay].notices.length ? this.messages[relay].notices : null) + // this.adjustResult(relay) + // //console.log(this.connections[relay]) - relay.on('notice', (message) => { - const hash = this.sha1(message) - let message_obj = RELAY_MESSAGES[hash] - let code_obj = RELAY_CODES[message_obj.code] + }) + .on('close', () => { + // delete this.connections[relay] + }) + // + // setTimeout( () => { + // inspect + // .reset() + // inspect + // .run() + // //console.log('reset and run') + // }, 25000) + this.connections[relay] = inspect + }, - message_obj.type = code_obj.type - message_obj.hash = hash - this.status[url].notes[code_obj.description] = message_obj - // this.adjustStatus(url, hash) - }) - this.connections[url] = relay - await this.getIP(url) - await this.setGeo(url) - this.setFlag(url) - // this.setNip05(url) + checkLatency(relay) { + this.connections[relay].opts.checkLatency = true + this.connections[relay].checkLatency() }, // query (group, filterType) { @@ -323,78 +259,92 @@ export default defineComponent({ let unordered, filterFn - // if(filterByType) { - // filterFn = (relay) => this.status?.[relay]?.aggregate == group || this.status?.[relay]?.[filterType]; - // } else { - filterFn = (relay) => this.status?.[relay]?.aggregate == group - // } + filterFn = (relay) => this.result?.[relay]?.aggregate == group unordered = this.relays.filter(filterFn); if (unordered.length) { return unordered.sort((relay1, relay2) => { - return this.status?.[relay1]?.latency - this.status?.[relay2]?.latency + return this.result?.[relay1]?.latency.final - this.result?.[relay2]?.latency.final }) } return [] }, - getAggregateStatusClass (url) { - let status = '' - if (this.status?.[url]?.aggregate == null) { - status = 'unprocessed' + adjustResult (url) { + Object.entries(this.messages[url].notices).forEach( ([key, value]) => { + if(!value.hasOwnProperty("hash")) return + let code = RELAY_MESSAGES[value.hash].code, + type = RELAY_CODES[code].type + + this.result[url][type] = code + if (type == "maybe_public") { + this.result[url].check.write = false + this.result[url].aggregate = 'public' + } + if (type == "write_restricted") { + this.result[url].check.write = false + } + }) + }, + + getAggregateResultClass (url) { + let result = '' + if (this.result?.[url]?.aggregate == null) { + result = 'unprocessed' } - else if (this.status?.[url]?.aggregate == 'public') { - status = 'readwrite' + else if (this.result?.[url]?.aggregate == 'public') { + result = 'readwrite' } - else if (this.status?.[url]?.aggregate == 'restricted') { - if(this.status?.[url]?.didWrite) { - status = 'write-only' + else if (this.result?.[url]?.aggregate == 'restricted') { + if(this.result?.[url]?.check.write) { + result = 'write-only' } else { - status = 'read-only' + result = 'read-only' } } - else if (this.status?.[url]?.aggregate == 'offline') { - status = 'offline' + else if (this.result?.[url]?.aggregate == 'offline') { + result = 'offline' } - return `aggregate indicator ${status}` + return `aggregate indicator ${result}` }, - getStatusClass (url, key) { - let status = this.status?.[url]?.[key] === true + getResultClass (url, key) { + + let result = this.result?.[url]?.check?.[key] === true ? 'success' - : this.status?.[url]?.[key] === false + : this.result?.[url]?.check?.[key] === false ? 'failure' : 'pending' - return `indicator ${status}` + return `indicator ${result}` }, getLoadingClass (url) { - return this.status?.[url]?.complete ? "relay loaded" : "relay" + return this.result?.[url]?.state == 'complete' ? "relay loaded" : "relay" }, // setNip05(url){ // const data = nip05(url.replace('wss://', '')) // if(data.length) { // this.nips[url][5] = data - // this.status[url].nip05 = true + // this.result[url].nip05 = true // } // }, - setAggregateStatus (url) { + setAggregateResult (url) { let aggregateTally = 0 - aggregateTally += this.status?.[url]?.didConnect ? 1 : 0 - aggregateTally += this.status?.[url]?.didRead ? 1 : 0 - aggregateTally += this.status?.[url]?.didWrite ? 1 : 0 + aggregateTally += this.result?.[url]?.check.connect ? 1 : 0 + aggregateTally += this.result?.[url]?.check.read ? 1 : 0 + aggregateTally += this.result?.[url]?.check.write ? 1 : 0 if (aggregateTally == 3) { - this.status[url].aggregate = 'public' + this.result[url].aggregate = 'public' } else if (aggregateTally == 0) { - this.status[url].aggregate = 'offline' + this.result[url].aggregate = 'offline' } else { - this.status[url].aggregate = 'restricted' + this.result[url].aggregate = 'restricted' } }, @@ -402,66 +352,14 @@ export default defineComponent({ try { await navigator.clipboard.writeText(text); } catch($e) { - console.log('Cannot copy'); + //console.log('Cannot copy'); } }, - tryComplete (url) { - let connect = typeof this.status?.[url]?.didConnect !== 'undefined', - read = typeof this.status?.[url]?.didRead !== 'undefined', - write = typeof this.status?.[url]?.didWrite !== 'undefined' - - console.log(url, 'trying complete', connect, read, write) - - if(connect && read && write) { - console.log(url, 'did complete') - this.setAggregateStatus(url) - this.adjustStatus(url) - this.status[url].complete = true - this.status[url].testing = false - if(this.status[url].readEventCount > 1) { - this.status[url].didSubscribeFilterLimit = false - } else { - this.status[url].didSubscribeFilterLimit = true - } - } - }, generateKey (url, key) { return `${url}_${key}` }, - async testRead (url, id, benchmark) { - const subid = this.getID(url, id) - if(benchmark) this.latency[url].start = Date.now() - if(benchmark) console.log(url, subid, this.latency[url].start) - this.connections[url].subscribe(subid, {limit: 1, kinds:[1]}) - this.timeouts[url][id] = setTimeout(() => { - if(!benchmark) this.status[url].didRead = false - this.tryComplete(url) - }, 3000) - }, - - async testWrite (url, id, benchmark) { - // console.log(url, "WRITE", "TEST") - const message = { - id: '41ce9bc50da77dda5542f020370ecc2b056d8f2be93c1cedf1bf57efcab095b0', - pubkey: - '5a462fa6044b4b8da318528a6987a45e3adf832bd1c64bd6910eacfecdf07541', - created_at: 1640305962, - kind: 1, - tags: [], - content: 'running branle', - sig: '08e6303565e9282f32bed41eee4136f45418f366c0ec489ef4f90d13de1b3b9fb45e14c74f926441f8155236fb2f6fef5b48a5c52b19298a0585a2c06afe39ed' - } - this.connections[url].send(["EVENT", message]) - this.connections[url].subscribe(this.getID(url, id), {limit: 1, kinds:[1], ids:['41ce9bc50da77dda5542f020370ecc2b056d8f2be93c1cedf1bf57efcab095b0']}) - this.timeouts[url][id] = setTimeout(() => { - console.log(url, "did write", id, false) - if(!benchmark) this.status[url].didWrite = false - this.tryComplete(url) - }, 10000) - }, - getID(url, keyword) { return `${keyword}_${url}` }, @@ -471,43 +369,17 @@ export default defineComponent({ }, setLatency(url) { - // console.log(this.status[url].didConnect === true, this.status[url]. latency,this.latency[url].final) - if (this.status[url].didConnect === true) this.status[url].latency = this.latency[url].final - // console.log(this.status[url].didConnect === true, this.status[url]. latency,this.latency[url].final) - console.log("latency",this.latency[url]) + // //console.log(this.result[url].check.connect === true, this.result[url]. latency,this.latency[url].final) + if (this.result[url].check.connect === true) this.result[url].latency = this.latency[url].final + // //console.log(this.result[url].check.connect === true, this.result[url]. latency,this.latency[url].final) + //console.log("latency",this.latency[url]) }, - testRelayLatency(){ - console.log('testing latency') - this.relays.forEach(url => { - console.log(url, 'did read', this.status[url].didRead) - if(this.status[url].didRead) { - console.log(url, 'testing read') - this.testRead(url, "testLatency", true) - } - this.lastPing = Date.now() - }) - }, - async getIP(url){ - let ip - await fetch(`https://1.1.1.1/dns-query?name=${url.replace('wss://', '')}`, { headers: { 'accept': 'application/dns-json' } }) - .then(response => response.json()) - .then((data) => { ip = data.Answer ? data.Answer[data.Answer.length-1].data : false }); - this.status[url].ip = ip - // console.log('IP:', ip) - }, - async setGeo(url){ - if (!this.status[url].ip) return - await fetch(`http://ip-api.com/json/${this.status[url].ip}`, { headers: { 'accept': 'application/dns-json' } }) - .then(response => response.json()) - .then((data) => { this.status[url].geo = data }); - // console.dir(this.status[url].geo) - }, setFlag (url) { - this.status[url].flag = this.status[url].geo?.countryCode ? countryCodeEmoji(this.status[url].geo.countryCode) : emoji.get('shrug'); + this.result[url].flag = this.result[url].geo?.countryCode ? countryCodeEmoji(this.result[url].geo.countryCode) : emoji.get('shrug'); }, setCheck (bool) { @@ -522,28 +394,24 @@ export default defineComponent({ return !bool ? '⚠ī¸' : '' }, + relaysTotal () { + return this.relays.length + }, + relaysConnected () { + return Object.keys(this.result).length + }, - adjustStatus (url) { - Object.entries(this.status[url].notes).forEach( ([key, value]) => { - if(!value.hasOwnProperty("hash")) return - let code = RELAY_MESSAGES[value.hash].code, - type = RELAY_CODES[code].type - - this.status[url][type] = code - if (type == "maybe_public") { - this.status[url].didWrite = false - this.status[url].aggregate = 'public' - } - if (type == "write_restricted") { - this.status[url].didWrite = false - } - }) + relaysCompleted () { + let value = Object.entries(this.result).length + console.log(value) + return value }, + sha1 (message) { const hash = crypto.createHash('sha1').update(JSON.stringify(message)).digest('hex') - // console.log(message, ':', hash) + // //console.log(message, ':', hash) return hash }, }, @@ -602,7 +470,7 @@ tr.relay.loaded td { .badge.write-only, .badge.read-only, -table.online.public .indicator.failure { +tr.online.public .indicator.failure { background-color:orange !important; } @@ -687,7 +555,7 @@ border-color: rgba(255,0,0,0.5); border-color: rgba(255,0,0,0.5); } -table.online .relay-url { +tr.online .relay-url { cursor: pointer; } @@ -730,11 +598,77 @@ sup { .credit { display:inline-block; - text-decoration:none; + color:#333; - text-transform: uppercase; + text-transform: lowercase; font-size:12px; margin-top:25px; } +.credit a { + text-decoration:none; +} + +#wrapper { + max-width:1400px; + margin:0 auto; +} + +div.block { + display:block; + margin:40px 0; +} + +.title-card { + text-align:left; +} + +.title-card h1 { + font-size:4.5em; + text-align:left; +} + +.row { + -webkit-box-shadow: 0px 1px 32px 4px rgba(0,0,0,0.16); + -moz-box-shadow: 0px 1px 32px 4px rgba(0,0,0,0.16); + box-shadow: 0px 1px 32px 4px rgba(0,0,0,0.16); +} + +.title-info-card { + border-radius: 20px; + text-align:center; +} + +.title-info-card span { + display:inline-block; + margin-top:0.80em; + font-size: 4em; + letter-spacing: -0.1em; + text-align:right; +} + + +.gradient { + animation-duration: 1.8s; + animation-fill-mode: forwards; + animation-iteration-count: infinite; + animation-name: placeHolderShimmer; + animation-timing-function: linear; + background: #f6f7f8; + background: linear-gradient(to right, #fafafa 8%, #f4f4f4 38%, #fafafa 54%); + background-size: 1000px 640px; + + position: relative; + +} + +@keyframes placeHolderShimmer{ + 0%{ + background-position: -468px 0 + } + 100%{ + background-position: 468px 0 + } +} +