Browse Source

optimization round 1, timsort + sort caching

develop
dskvr 2 years ago
parent
commit
f49e7b6c7d
  1. 4
      package.json
  2. 1
      public/index.html
  3. 22
      relays.yaml
  4. 17
      src/App.vue
  5. 189
      src/components/relays/RefreshComponent.vue
  6. 63
      src/components/relays/RelayStatistics.vue
  7. 1
      src/components/relays/SingleClearnet.vue
  8. 40
      src/components/relays/charts/BarChart.vue
  9. 0
      src/components/relays/charts/SoftwareVersionPolar.vue
  10. 15
      src/components/relays/pages/RelaysHome.vue
  11. 13
      src/components/relays/pages/RelaysSingle.vue
  12. 9
      src/main.js
  13. 53
      src/shared/pool.js
  14. 193
      src/shared/relays-lib.js
  15. 2
      src/shared/user-lib.js
  16. 18
      src/store/relays.js
  17. 3
      vue.config.js

4
package.json

@ -23,8 +23,9 @@
"@popperjs/core": "2.11.6",
"@vue-leaflet/vue-leaflet": "0.6.1",
"@vueuse/core": "9.9.0",
"@vueuse/head": "1.0.22",
"alby": "1.0.1",
"chart.js": "4.1.1",
"array-timsort": "1.0.3",
"core-js": "^3.8.3",
"country-code-emoji": "2.3.0",
"cross-fetch": "3.1.5",
@ -42,7 +43,6 @@
"socks-proxy-agent": "7.0.0",
"stream-browserify": "3.0.0",
"vue": "^3.2.45",
"vue-chartjs": "5.1.0",
"vue-final-modal": "3",
"vue-grid-responsive": "1.3.0",
"vue-identify-network": "2.0.0",

1
public/index.html

@ -0,0 +1 @@
<head><title>nostr.watch</title><meta description="A robust client-side nostr relay monitor. Find fast nostr relays, view them on a map and monitor the network status of nostr." /></head><div id=app></div>

22
relays.yaml

@ -1,4 +1,5 @@
relays:
- wss://relay.nostr.vision
- wss://nostr-3.orba.ca
- wss://satstacker.cloud
- wss://freedom-relay.herokuapp.com/ws
@ -14,7 +15,6 @@ relays:
- wss://nostr-verified.wellorder.net
- wss://nostr.drss.io
- wss://nostr.rocks
- wss://nostr.bitcoiner.social
- wss://nostr.openchain.fr
- wss://nostr.delo.software
- wss://relay.nostr.info
@ -59,6 +59,7 @@ relays:
- wss://nostr-relay.nonce.academy
- wss://nostr.rewardsbunny.com
- wss://nostr.slothy.win
- wss://nostr-verif.slothy.win
- wss://nostr.coinos.io
- wss://relay.nostropolis.xyz/websocket
- wss://lv01.tater.ninja
@ -83,7 +84,6 @@ relays:
- wss://nostr.jiashanlu.synology.me
- wss://nostr.radixrat.com
- wss://nostr.shawnyeager.net
- wss://nostr.pobblelabs.org
- wss://relay.dev.kronkltd.net
- wss://nostr2.namek.link
- wss://nostr-dev.wellorder.net
@ -159,9 +159,19 @@ relays:
- wss://btc.klendazu.com
- wss://nostr.hackerman.pro
- wss://relay.realsearch.cc
- wss://nostr3.actn.io
- wss://nostr.pwnshop.cloud
- wss://nostr.mrbits.it
- wss://echo.obsolete.org
- wss://brb.io
- wss://nostr.coollamer.com
- wss://node01.nostress.cc
- wss://nostr.zenon.wtf
- wss://nostr.massmux.com
- wss://no.contry.xyz
- wss://relay.nostr.bg
- wss://nostr.uselessshit.co
- wss://brb.io
- wss://nostream.gromeul.eu
- wss://relay.nostr.ro
- wss://nostr.developer.li
- wss://nostr.screaminglife.io
- wss://deschooling.us
- wss://relay-pub.deschooling.us
- wss://nostr.bitcoiner.social

17
src/App.vue

@ -1,21 +1,17 @@
<template>
<HeaderComponent />
<div class="flex min-h-screen">
<!-- <SidebarComponent /> -->
<div class="flex-1">
<main>
<router-view></router-view>
</main>
</div>
</div>
<!-- <a id="fork-me" href="https://github.com/dskvr/nostr-watch"><img decoding="async" loading="lazy" width="149" height="149" src="https://github.blog/wp-content/uploads/2008/12/forkme_right_darkblue_121621.png?resize=149%2C149" class="attachment-full size-full" alt="Fork me on GitHub" data-recalc-dims="1"></a> -->
</template>
<script>
import { useMeta } from 'vue-meta'
import HeaderComponent from '@/components/layout/HeaderComponent.vue'
// import SidebarComponent from '@/components/layout/SidebarComponent.vue'
import { useHead } from '@vueuse/head'
export default {
name: 'App',
@ -24,9 +20,14 @@ export default {
// SidebarComponent
},
setup () {
useMeta({
title: 'nostr.watch registry & monitor',
htmlAttrs: { lang: 'en', amp: true }
useHead({
title: 'nostr.watch',
meta: [
{
name: `description`,
content: 'A robust client-side nostr relay monitor. Find fast nostr relays, view them on a map and monitor the network status of nostr.',
},
],
})
}
}

189
src/components/relays/RefreshComponent.vue

@ -1,13 +1,14 @@
<template>
<span class="text-white lg:text-sm mr-2 ml-2 mt-1.5 text-xs">
<span v-if="!disableManualRefresh()">Refreshed {{ sinceLast }} ago</span>
<span v-if="disableManualRefresh()" class="italic">Refreshing Now</span>
<span v-if="!store.relays.isProcessing">Refreshed {{ sinceLast }} ago</span>
<span v-if="store.relays.isProcessing" class="italic">Refreshing Now</span>
</span>
<span class="text-white text-sm mr-2 mt-1.5" v-if="!disableManualRefresh()">-</span>
<span class="text-white text-sm mr-2 mt-1.5" v-if="store.prefs.refresh && !disableManualRefresh()">
<span class="text-white text-sm mr-2 mt-1.5" v-if="!store.relays.isProcessing">-</span>
<span class="text-white text-sm mr-2 mt-1.5" v-if="store.prefs.refresh && !store.relays.isProcessing">
Next refresh in: {{ untilNext }}
</span>
<button
v-if="!store.relays.isProcessing"
class="mr-8 my-1 py-0 px-3 text-xs rounded border-b-3 border-slate-700 bg-slate-500 font-bold text-white hover:border-slate-500 hover:bg-slate-400"
:disabled='disabled'
@click="refreshNow()">
@ -23,41 +24,144 @@
import { defineComponent, toRefs } from 'vue'
import RelaysLib from '@/shared/relays-lib.js'
import { setupStore } from '@/store'
import { Inspector } from 'nostr-relay-inspector'
const localMethods = {
timeUntilRefresh(){
return this.timeSince(Date.now()-(this.store.relays.lastUpdate+this.store.prefs.duration-Date.now()))
},
timeSinceRefresh(){
return this.timeSince(this.store.relays.lastUpdate)
},
disableManualRefresh: function(){
//this is a hack.
const lastUpdate = this.store.relays.lastUpdate
if(Math.floor( ( Date.now()-lastUpdate )/1000 ) < 20)
this.disabled = true
else
this.disabled = false
return this.disabled
},
setRefreshInterval: function(){
clearInterval(this.interval)
this.interval = setInterval(() => {
this.prefs = this.store.prefs.get
timeUntilRefresh(){
return this.timeSince(Date.now()-(this.store.relays.lastUpdate+this.store.prefs.duration-Date.now()))
},
timeSinceRefresh(){
return this.timeSince(this.store.relays.lastUpdate)
},
disableManualRefresh: function(){
//this is a hack.
const lastUpdate = this.store.relays.lastUpdate
if(Math.floor( ( Date.now()-lastUpdate )/1000 ) < 20)
this.disabled = true
else
this.disabled = false
return this.disabled
},
setRefreshInterval: function(){
clearInterval(this.interval)
this.interval = setInterval(() => {
if(!this.store.prefs.refresh || !this.windowActive )
return
this.untilNext = this.timeUntilRefresh()
this.sinceLast = this.timeSinceRefresh()
this.untilNext = this.timeUntilRefresh()
this.sinceLast = this.timeSinceRefresh()
if(this.store.prefs.refresh )
this.invalidate()
this.invalidate()
this.disableManualRefresh()
}, 1000)
},
refreshNow(){
this.disabled = true
this.invalidate(true)
}
this.disableManualRefresh()
}, 1000)
},
refreshNow(){
this.disabled = true
this.invalidate(true)
},
handleVisibility(){
if(document.visibilityState === 'hidden')
this.windowActive = false
else
this.windowActive = true
console.log('window active?', this.windowActive)
},
invalidate: async function(force, single){
if( (!this.isExpired() && !force) )
return
this.store.relays.startProcessing()
if(single) {
await this.check(single)
}
else {
const processed = new Set()
for(let index = 0; index < this.relays.length; index++) {
const relay = this.relays[index]
await this.delay(this.averageLatency).then( () => {
this.check(relay)
.then((result) => {
this.results[result.uri] = result
this.setCache(result)
this.store.relays.updateNow()
processed.add(result.uri)
// console.log('processing status', processed, '/', this.relays.length)
console.log('complete?', result.uri, processed.size, this.relays.length)
if(processed.size >= this.relays.length)
this.completeAll()
})
.catch( err => console.error(err) )
}).catch(err => console.error(err))
}
}
},
completeAll: function(){
this.store.relays.finishProcessing()
console.log('all are complete?', this.store.relays.isProcessing)
const aggregates = new Object()
aggregates.all = this.getSortedAllRelays()
aggregates.public = this.getSortedPublicRelays()
aggregates.restricted = this.getSortedRestrictedRelays()
aggregates.offline = this.getOfflineRelays()
this.store.relays.setAggregates(aggregates)
this.getAverageLatency()
},
getDynamicTimeout: function(){
return this.averageLatency*this.relays.length
},
check: async function(relay){
return new Promise( (resolve, reject) => {
const opts = {
checkLatency: true,
getInfo: true,
getIdentities: true,
debug: true,
connectTimeout: this.getDynamicTimeout(),
readTimeout: this.getDynamicTimeout(),
writeTimeout: this.getDynamicTimeout(),
// data: { result: this.store.relays.results[relay] }
}
if(this.store.user.testEvent)
opts.testEvent = this.store.user.testEvent
let socket = new Inspector(relay, opts)
socket
.on('complete', (instance) => {
instance.result.aggregate = this.getAggregate(instance.result)
instance.relay.close()
resolve(instance.result)
})
.on('close', (relay) => {
console.log(`${relay.url} has closed`)
})
.on('error', () => {
reject()
})
.run()
})
},
getAverageLatency: function(){
const latencies = new Array()
this.relays.forEach( relay => {
latencies.push(this.results[relay]?.latency?.final)
})
this.averageLatency = this.average(latencies)
},
average(arr){
let sum = 0,
total = arr.length;
for (let i = 0;i<total;i++)
sum += arr[i];
return Math.floor(parseFloat(sum/total));
}
}
export default defineComponent({
@ -70,7 +174,13 @@ export default defineComponent({
results: results
}
},
created(){
document.addEventListener('visibilitychange', this.handleVisibility, false)
},
mounted(){
if(!this.windowActive)
return
this.relays = this.store.relays.getAll
this.lastUpdate = this.store.relays.lastUpdate
@ -81,6 +191,13 @@ export default defineComponent({
this.untilNext = this.timeUntilRefresh()
this.sinceLast = this.timeSinceRefresh()
//If user leaves page before processing completes, force invalidate cache
console.log('is processing?', this.store.relays.isProcessing)
if(this.store.relays.isProcessing)
this.invalidate(true)
else
this.invalidate()
this.setRefreshInterval()
},
updated(){
@ -106,7 +223,9 @@ export default defineComponent({
lastUpdate: null,
sinceLast: null,
interval: null,
disabled: true
disabled: true,
windowActive: true,
averageLatency: 200
}
},
})

63
src/components/relays/RelayStatistics.vue

@ -10,7 +10,7 @@
Software:
software/versiono
nips:
support by nips
OK support by nips
geo
by country
continent
@ -34,18 +34,61 @@ export default defineComponent({
results: results
}
},
mounted(){
}
data: function(){
return {
relays: this.store.relays.getAll,
geo: this.store.relays.getGeo
}
}
props: {
resultsProp: {
type: Object,
default(){
return {}
resultsProp: {
type: Object,
default(){
return {}
}
},
},
methods: {
collateSupportedNips(){
const nips = new Object()
Object.entries(this.results).forEach( (result) => {
if(result?.info?.supported_nips)
supported_nips.forEach( nip => {
if( !(nips[nip] instanceof Array ))
nips[nip] = new Set
nips[nip].add(result.uri)
})
})
console.log('supported nips', nips)
return nips
},
collateSoftware(){
const software = new Object()
},
collateSoftwareVersion(){
},
collateContinents(){
const byCont = new Object()
this.relays.forEach( relay => {
if( !(this.geo[relay] instanceof Object) ) {
if( !(byCont.unknown instanceof Set) )
byCont.unknown = new Set()
byCont.unknown.add(relay)
}
},
const cont = this.geo[relay].continentName
if( !(byCont[cont] instanceof Set) )
byCont[cont] = new Set()
byCont[cont].add(relay)
})
console.log('continents', byCont)
return byCont;
},
methods: {
async getRelayHistory(){
//subscribe kind 3
}
}
})
</script>

1
src/components/relays/SingleClearnet.vue

@ -248,7 +248,6 @@ td.verified span {
.restricted.aggregate.indicator {
position:relative;
left:-7px;
}
td {

40
src/components/relays/charts/BarChart.vue

@ -1,40 +0,0 @@
<template>
<Bar
id="my-chart-id"
:options="chartOptions"
:data="chartData"
/>
</template>
<script>
import { Bar } from 'vue-chartjs'
import { Chart as ChartJS, Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale } from 'chart.js'
ChartJS.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale)
export default {
name: 'BarChart',
components: { Bar },
props: (){
chartData: {
type: Object,
default: () => {}
},
chartOptions: {
type: Object,
default: () => {}
}
},
// data() {
// return {
// chartData: {
// labels: [ 'January', 'February', 'March' ],
// datasets: [ { data: [40, 20, 12] } ]
// },
// chartOptions: {
// responsive: true
// }
// }
// }
}
</script>

0
src/components/relays/charts/SoftwareVersionPolar.vue

15
src/components/relays/pages/RelaysHome.vue

@ -35,7 +35,7 @@
<script>
//vue
import { defineComponent } from 'vue'
import { useMeta } from 'vue-meta'
import { useHead } from '@vueuse/head'
import { setupStore } from '@/store'
//shared methods
import RelaysLib from '@/shared/relays-lib.js'
@ -61,10 +61,14 @@ export default defineComponent({
},
setup(){
useMeta({
useHead({
title: 'nostr.watch',
description: 'A robust client-side nostr relay monitor. Find fast nostr relays, view them on a map and monitor the network status of nostr.',
htmlAttrs: { lang: 'en', amp: true }
meta: [
{
name: `description`,
content: 'A robust client-side nostr relay monitor. Find fast nostr relays, view them on a map and monitor the network status of nostr.',
},
],
})
return {
store : setupStore()
@ -108,11 +112,8 @@ export default defineComponent({
if(mutation.events.key == 'relays-subnav')
this.activeNavItem = mutation.events.newValue
})
// this.psuedoRouter(this.store.layout.getNavGroup('relays-subnav'))
this.psuedoRouter()
this.invalidate()
},
computed: {

13
src/components/relays/pages/RelaysSingle.vue

@ -134,7 +134,8 @@ import RelaysLib from '@/shared/relays-lib.js'
import { setupStore } from '@/store'
import { useMeta } from 'vue-meta'
import { useHead } from '@vueuse/head'
const localMethods = {
@ -191,10 +192,14 @@ export default defineComponent({
},
setup(){
useMeta({
useHead({
title: 'nostr.watch',
description: 'A robust client-side nostr relay monitor. Find fast nostr relays, view them on a map and monitor the network status of nostr.',
htmlAttrs: { lang: 'en', amp: true }
meta: [
{
name: `description`,
content: 'A robust client-side nostr relay monitor. Find fast nostr relays, view them on a map and monitor the network status of nostr.',
},
],
})
return {
store : setupStore()

9
src/main.js

@ -1,23 +1,18 @@
import { createApp } from 'vue'
import App from './App.vue'
import Vue3Storage from "vue3-storage";
import { createHead } from '@vueuse/head'
import router from './router'
import "./styles/main.scss"
import directives from "./directives/"
// import titleMixin from './mixins/titleMixin'
import {Tabs, Tab} from 'vue3-tabs-component';
import { plugin as storePlugin } from './store'
import { createMetaManager } from 'vue-meta'
import { RelayPool } from 'nostr'
// import { relays } from '../relays.yaml'
// import VueIdentifyNetwork from 'vue-identify-network';
const app = createApp(App)
.use(router)
.use(storePlugin)
// .use(VueIdentifyNetwork)
.use(createMetaManager())
.use(createHead())
.use(Vue3Storage, { namespace: "nw_result_" })
.component('tabs', Tabs)
.component('tab', Tab)

53
src/shared/pool.js

@ -0,0 +1,53 @@
const Pool = function(relays){
if( !(relays instanceof Array) )
console.warn('relays argument must be an instance of Array')
this.pool = null
this.relays = relays
this.handlers = {}
this.subids = {}
this.connected = false
}
Pool.prototype.open = function(){
if(this.connected) {
console.warn(`Pool is already connected, disconnect first, or call another function`)
return
}
this.pool = new RelayPool(this.relays)
this.pool.on('open', (relay) => this.cb(relay))
}
Pool.prototype.close = function(){
this.pool.unsubscribe()
this.pool.close()
this.connected = false
}
Pool.prototype.cb = function(handle){
Object.entries(this.handlers[handle]).forEach( handler => {
const fn = handler[1]
fn(relay)
})
}
Pool.prototype.subscribe = function(filters){
if(!this.connected) {
console.warn(`Pool is not yet connected, cannot subscribe to a closed pool`)
return
}
this.cb(handle)
this.pool.subscribe(this.subids[key], })
}
Pool.prototype.addHandler = function(which, key, fn){
if( !( this.handlers[which] instanceof Object ) )
this.handlers[which] = new Object()
if( typeof this.handlers[which][key] !== 'undefined') {
console.log(`${which}:${key} is already defined. Cannot set.`)
return
}
this.handlers[which][key] = fn
}
Pool.prototype.removeHandler = function(which, key){
delete this.handlers[which][key]
}
export default Pool

193
src/shared/relays-lib.js

@ -1,89 +1,7 @@
import { Inspector } from 'nostr-relay-inspector'
import crypto from "crypto"
import {sort} from 'array-timsort'
export default {
invalidate: async function(force, single){
if( (!this.isExpired() && !force))
return
this.store.relays.startProcessing()
let processed = 0
if(single) {
await this.check(single)
}
else {
for(let index = 0; index < this.relays.length; index++) {
let relay = this.relays[index]
await this.delay(20).then( () => {
this.check(relay)
.then((result) => {
this.results[result.uri] = result
this.setCache(result)
this.store.relays.updateNow()
processed++
// console.log('processing status', processed, '/', this.relays.length)
if(processed >= this.relays.length){
this.store.relays.finishProcessing()
}
})
.catch( err => {
console.log(err)
processed++
})
}).catch(err => console.log(err))
}
}
},
check: async function(relay){
return new Promise( (resolve, reject) => {
// if(!this.isExpired())
// return reject(relay)
const opts = {
checkLatency: true,
getInfo: true,
getIdentities: true,
// debug: true,
// data: { result: this.store.relays.results[relay] }
}
if(this.store.user.testEvent)
opts.testEvent = this.store.user.testEvent
let socket = new Inspector(relay, opts)
socket
.on('complete', (instance) => {
instance.result.aggregate = this.getAggregate(instance.result)
instance.relay.close()
resolve(instance.result)
})
// .on('notice', (notice) => {
// const hash = this.sha1(notice)
// let message_obj = RELAY_MESSAGES[hash]
// if(!message_obj || !Object.prototype.hasOwnProperty.call(message_obj, 'code'))
// return
// // let code_obj = RELAY_CODES[message_obj.code]
// // let response_obj = {...message_obj, ...code_obj}
// // this.store.relays.results[relay].observations.push( new InspectorObservation('notice', response_obj.code, response_obj.description, response_obj.relates_to) )
// })
.on('close', () => {})
.on('error', () => {
reject()
})
.run()
})
},
psuedoRouter: function(){
console.log(this)
const route = this.parseRouterHash()
@ -119,10 +37,19 @@ export default {
},
relaysUpdate: function(){
this.relays = this.store.relays.getAll
this.filterRelays()
this.sortRelays()
// this.setRelayCount()
if(this.store.relays.isProcessing || !this.store.relays.areAggregatesSet ) {
console.log('filtering relays at runtime')
this.relays = this.store.relays.getAll
this.filterRelaysMutate()
this.sortRelaysMutate()
} else {
console.log('getting relays from cache')
if(this.activePageItem == 'favorite')
this.relays = this.sortRelays(this.store.relays.getFavorites)
else
this.relays = this.sortRelaysFavoritesOnTop(this.store.relays.getAggregate(this.activePageItem))
}
return this.relays
},
setRelayCount: function(){
@ -130,41 +57,75 @@ export default {
this.store.relays.setStat(item, this.relays.filter( (relay) => this.results?.[relay]?.aggregate == item))
})
},
filterRelays: function(){
filterRelaysMutate: function(){
if( 'favorite' == this.activePageItem )
this.relays = this.store.relays.getFavorites
this.relays = this.getFavoriteRelays()
if( 'public' == this.activePageItem )
this.relays = this.relays.filter( (relay) => this.results?.[relay]?.aggregate == 'public')
this.relays = this.getPublicRelays()
if( 'restricted' == this.activePageItem )
this.relays = this.relays.filter( (relay) => this.results?.[relay]?.aggregate == 'restricted')
this.relays = this.getRestrictedRelays()
if( 'offline' == this.activePageItem)
this.relays = this.relays.filter( (relay) => this.results?.[relay]?.aggregate == 'offline')
// if( 'onion' == active )
// this.filteredRelays = this.store.relays.getOnion
// console.log('meow', this.activePageItem, this.filteredRelays.length)
// this.store.relays.setStat(this.activePageItem, this.filteredRelays.length)
this.relays = this.getOfflineRelays()
},
getAllRelays: function(){
return this.store.relays.getAll
},
getFavoriteRelays: function(){
return this.store.relays.getFavorites
},
getPublicRelays: function(){
return this.relays.filter( (relay) => this.results?.[relay]?.aggregate == 'public')
},
getRestrictedRelays: function(){
return this.relays.filter( (relay) => this.results?.[relay]?.aggregate == 'restricted')
},
getOfflineRelays: function(){
return this.relays.filter( (relay) => this.results?.[relay]?.aggregate == 'offline')
},
getSortedAllRelays: function(){
return this.sortRelays(this.getAllRelays())
},
getSortedFavoriteRelays: function(){
return this.sortRelays(this.getFavoriteRelays())
},
getSortedPublicRelays: function(){
return this.sortRelays(this.getPublicRelays())
},
getSortedRestrictedRelays: function(){
return this.sortRelays(this.getRestrictedRelays())
},
getSortedOfflineRelays: function(){
return this.sortRelays(this.getOfflineRelays())
},
sortRelays(relays){
sort(relays, (relay1, relay2) => {
return this.results?.[relay1]?.latency.final - this.results?.[relay2]?.latency.final
})
sort(relays, (relay1, relay2) => {
let a = this.results?.[relay1]?.latency.final ,
b = this.results?.[relay2]?.latency.final
return (b != null) - (a != null) || a - b;
})
sort(relays, (relay1, relay2) => {
let x = this.results?.[relay1]?.check?.connect,
y = this.results?.[relay2]?.check?.connect
return (x === y)? 0 : x? -1 : 1;
})
relays = this.sortRelaysFavoritesOnTop(relays)
return relays
},
sortRelaysFavoritesOnTop(relays){
sort(relays, (relay1, relay2) => {
let x = this.store.relays.isFavorite(relay1),
y = this.store.relays.isFavorite(relay2)
return (x === y)? 0 : x? -1 : 1;
})
return relays
},
sortRelays: function() {
sortRelaysMutate: function() {
if (this.relays.length) {
this.relays
.sort((relay1, relay2) => {
return this.results?.[relay1]?.latency.final - this.results?.[relay2]?.latency.final
})
.sort((relay1, relay2) => {
let a = this.results?.[relay1]?.latency.final ,
b = this.results?.[relay2]?.latency.final
return (b != null) - (a != null) || a - b;
})
.sort((relay1, relay2) => {
let x = this.results?.[relay1]?.check?.connect,
y = this.results?.[relay2]?.check?.connect
return (x === y)? 0 : x? -1 : 1;
})
.sort((relay1, relay2) => {
let x = this.store.relays.isFavorite(relay1),
y = this.store.relays.isFavorite(relay2)
return (x === y)? 0 : x? -1 : 1;
})
this.relays = this.sortRelays(this.relays)
// .sort((relay1, relay2) => {
// let x = this.results?.[relay1]?.check?.read,
// y = this.results?.[relay2]?.check?.read

2
src/shared/user-lib.js

@ -3,6 +3,6 @@ export default {
return this.store.user.getPublicKey
},
signOut: function(){
this.store.user.setPublicKey('')
this.store.user.$reset()
}
}

18
src/store/relays.js

@ -8,8 +8,10 @@ export const useRelaysStore = defineStore('relays', {
lastUpdate: null,
count: new Object(),
processing: false,
processedRelays: new Array(),
processedRelays: new Set(),
favorites: new Array(),
aggregates: {},
aggregatesAreSet: false
}),
getters: {
getAll: (state) => state.urls, //clone it
@ -28,7 +30,10 @@ export const useRelaysStore = defineStore('relays', {
getCount: (state) => (type) => state.count[type],
getCounts: (state) => state.count,
getProcessedRelays: (state) => state.processedRelays,
getAggregate: (state) => (which) => state.aggregates[which],
areAggregatesSet: (state) => state.aggregatesAreSet,
getProcessedRelays: (state) => Array.from(state.processedRelays),
isProcessing: (state) => state.processing,
getFavorites: (state) => state.favorites,
@ -53,12 +58,17 @@ export const useRelaysStore = defineStore('relays', {
setStat(type, value){
this.count[type] = value
},
setAggregate(aggregate, arr){ this.aggregates[aggregate] = arr },
setAggregates(obj){
this.aggregatesAreSet = true
this.aggregates = obj
},
addProcessedRelay(relay){
console.log(`this.processedRelays is set`, this.processedRelays instanceof Set)
this.processedRelays.push(relay)
this.processedRelays.add(relay)
},
finishProcessing() { this.processing = false },
startProcessing() { this.processing = true },
completeProcessing() {

3
vue.config.js

@ -28,6 +28,9 @@ module.exports = defineConfig({
},
},
chainWebpack: config => {
config.plugins.delete('prefetch')
config.plugins.delete('preload')
config.module
.rule('yaml')
.test(/\.ya?ml?$/)

Loading…
Cancel
Save