Browse Source

task queue functional with 1 task type

feature/task-queue
dskvr 2 years ago
parent
commit
60fe3246ca
  1. 1
      .gitignore
  2. 3
      package.json
  3. 213
      scripts/canonicals.js
  4. 6
      src/components/relays/nav/RelaysFindNav.vue
  5. 13
      src/components/relays/nav/RelaysNav.vue
  6. 14
      src/components/relays/tasks/HistoryTask.vue
  7. 87
      src/components/relays/tasks/RefreshTask.vue
  8. 7
      src/components/relays/tasks/RelayCanonicalsTask.vue
  9. 96
      src/components/relays/tasks/TasksManager.vue
  10. 2
      src/shared/computed.js
  11. 29
      src/store/relays.js
  12. 56
      src/store/tasks.js
  13. 28
      yarn.lock

1
.gitignore

@ -5,3 +5,4 @@ public/main.js
lib/nostr-relay-inspector lib/nostr-relay-inspector
dist dist
yarn-error.log yarn-error.log
.env

3
package.json

@ -25,6 +25,7 @@
"array-timsort": "1.0.3", "array-timsort": "1.0.3",
"country-code-emoji": "2.3.0", "country-code-emoji": "2.3.0",
"cross-fetch": "3.1.5", "cross-fetch": "3.1.5",
"dotenv": "16.0.3",
"fast-safe-stringify": "2.1.1", "fast-safe-stringify": "2.1.1",
"js-yaml": "4.1.0", "js-yaml": "4.1.0",
"leaflet": "1.9.3", "leaflet": "1.9.3",
@ -32,7 +33,7 @@
"node-fetch": "3.3.0", "node-fetch": "3.3.0",
"nostr": "0.2.5", "nostr": "0.2.5",
"nostr-relay-inspector": "0.0.23", "nostr-relay-inspector": "0.0.23",
"nostr-tools": "1.0.1", "nostr-tools": "1.1.1",
"object-sizeof": "1.6.3", "object-sizeof": "1.6.3",
"onion-regex": "2.0.8", "onion-regex": "2.0.8",
"path-segments": "0.1.1", "path-segments": "0.1.1",

213
scripts/canonicals.js

@ -0,0 +1,213 @@
require('dotenv').config()
const fs = require('fs'),
yaml= require('js-yaml'),
crypto = require('crypto'),
nostrTools = require('nostr-tools'),
{ RelayPool } = require('nostr'),
{ validateEvent, verifySignature, signEvent, getEventHash, getPublicKey } = nostrTools,
uniques = new Set()
let relays = yaml.load(fs.readFileSync('./relays.yaml', 'utf8')).relays,
canonicals = new Object(),
missing = new Array(),
hashes = new Object(),
discovered = true,
totalSent = 0,
oks = 0,
notices = 0
const pool = RelayPool(relays, {reconnect: false})
pool
.on('ok', (Relay) => {
oks++
// console.log('OK', Relay.url)
})
.on('notice', (Relay, notice) => {
notices++
// console.log('NOTICE', Relay.url, notice)
})
async function run(){
// setup()
// deletions()
// await process.exit()
await discover()
// process.exit()
// console.log(`wtf`, relays.length)
// console.log(`hashes`, Object.keys(hashes).length)
await sieve()
setInterval( ()=> {
console.log('status', '\ntotal sent:', totalSent, '\noks:', oks, '\nnotices:', notices, '\n\n')
}, 60000)
await broadcast()
process.exit()
}
function setup(){
const event = {
"id": "a2640e8a6640c595942ccf290eae404ac58569b59af5c8c8e3334d9cf809fff6",
"pubkey": "b3b0d247f66bf40c4c9f4ce721abfe1fd3b7529fbc1ea5e64d5f0f8df3a4b6e6",
"created_at": 1673275222,
"kind": 1,
"tags": [],
"content": "<3 to all the relays",
"sig": "e536be52a04f95c54e5cc82caafb9b25c8d47e00182c0eac0b6b678b482710288cc7fd85c62b0f97f5ed33dfbd7e15555c9bfeac059794767e414666d807f9cf"
}
pool.send(['EVENT', event])
}
async function discover(){
console.log('relays', relays.length)
return new Promise(resolve => {
const subid = crypto.randomBytes(40).toString('hex')
pool
.on('open', Relay => {
console.log('open', Relay.url)
Relay.subscribe(subid, {limit: relays.length, kinds:[1], "#t": ['canonical'], authors:[ getPublicKey(process.env.PRIVATE_KEY) ] }, )
relays.forEach( relay => {
hashes[hash(relay)] = relay
// Relay.subscribe(`subid_${relay}`, {limit: 1, kinds:[1], authors:[ getPublicKey(process.env.PRIVATE_KEY) ] }, )
})
})
.on('event', (Relay, _subid, event) => {
if(!discovered){
// console.log('published event found', event.id)
}
if(_subid.includes(subid) && discovered) {
// console.log('event', event.content, event.id)
if(uniques.has(event.id))
return
const relayHash = event.tags.map( tag => tag[0]=='h' ? tag[1] : false )[0]
if(!relayHash)
return
// console.log('relay hash', Relay.url, relayHash)
const relay = hashes?.[relayHash]
uniques.add(event.id)
canonicals[relay] = event
}
})
setTimeout( () => {
// pool.close()
discovered = false
resolve(relays)
}, 10*1000 )
})
}
async function sieve(){
console.log('filtering relays', relays.length)
checkMissing()
console.log('missing', missing.length)
return
}
function checkMissing(){
missing = new Array()
relays.forEach( relay => {
// console.log('check missing', relay, (canonicals?.[relay] instanceof Object) )
if( !(canonicals?.[relay] instanceof Object) )
missing.push(relay)
})
}
async function broadcast(){
for(let i=0;i<missing.length;i++){
const relay = missing[i]
const event = {
created_at: Math.floor(Date.now()/1000),
content: `<3 ${relay}, canonical note for https://nostr.watch/relay/${relay.replace('wss://', '')}`,
kind: 1,
tags: [
['h', hash(relay)],
['t', 'canonical'],
['e', process.env.CANONICAL_NOTE, 'wss://nostr.sandwich.farm']
]
}
const signedEvent = await sign(event, relay)
if(!signedEvent)
return
// console.log("sending to pool", signedEvent)
pool.send(['EVENT', signedEvent])
totalSent++
console.log('total sent, backlog', totalSent)
await delay(60*1000)
}
console.log('finished.')
}
async function sign(event, relay){
// console.log('event to sign', event)
event.pubkey = getPublicKey(process.env.PRIVATE_KEY)
event.id = getEventHash(event)
event.sig = await signEvent(event, process.env.PRIVATE_KEY)
let ok = validateEvent(event)
let veryOk = await verifySignature(event)
// if(relay)
// console.log('sign valid', relay, ':', ok, veryOk)
// else
// console.log('sign valid', ':', ok, veryOk)
if( ok && veryOk )
return event
else
console.error('event is invalid', event)
}
async function deletions(){
const tags = [
["e", "8e68215676f0bfcc386e3cc0d9e975e7fab1aed91d781c4ec3aac5f4c2c11e24"],
["e", "00834b0779cd0a87b6eeb5d25e22e887b007a30239a1e75cb567324a687e000b"],
["e", "783f57bfbeb3c4e1cd13cc493b021cb0c353ab98c1d02f5378dfdfb0afcc77fd"]
]
const event = {
"kind": 5,
created_at: Math.floor(Date.now()/1000),
"tags": tags,
"content": "delete dev posts"
}
const signedEvent = await sign(event)
if(!signedEvent)
return
console.log("sending to pool", signedEvent)
pool.send(['EVENT', signedEvent])
return
}
async function delay(ms) {
return new Promise( resolve => setTimeout(resolve, ms) )
}
function hash(relay){
return crypto.createHash('md5').update(relay).digest('hex');
}
run()

6
src/components/relays/nav/RelaysFindNav.vue

@ -15,7 +15,7 @@
</div> </div>
</div> </div>
<div class="flex flex-1 items-center justify-center px-2 lg:ml-6 lg:justify-end"> <div class="flex flex-1 items-center justify-center px-2 lg:ml-6 lg:justify-end">
<RelaysSearchFilter /> <!-- <RelaysSearchFilter /> -->
</div> </div>
<div class="flex items-center lg:hidden"> <div class="flex items-center lg:hidden">
<!-- Mobile menu button --> <!-- Mobile menu button -->
@ -52,7 +52,7 @@ import { defineComponent } from 'vue'
//pinia //pinia
import { setupStore } from '@/store' import { setupStore } from '@/store'
//components //components
import RelaysSearchFilter from '@/components/relays/blocks/RelaysSearchFilter.vue' // import RelaysSearchFilter from '@/components/relays/blocks/RelaysSearchFilter.vue'
//nav conf //nav conf
import { items } from './config/relays.find.yaml' import { items } from './config/relays.find.yaml'
//shared methods //shared methods
@ -67,7 +67,7 @@ export default defineComponent({
title: "nostr.watch registry & network status", title: "nostr.watch registry & network status",
name: 'RelaysFindNav', name: 'RelaysFindNav',
components: { components: {
RelaysSearchFilter, // RelaysSearchFilter,
Disclosure, DisclosureButton, DisclosurePanel, Disclosure, DisclosureButton, DisclosurePanel,
Bars3Icon, XMarkIcon, Bars3Icon, XMarkIcon,
// PreferencesComponent, // PreferencesComponent,

13
src/components/relays/nav/RelaysNav.vue

@ -18,10 +18,9 @@
</div> </div>
</div> </div>
<div class="width-max lg:flex lg:ml-auto"> <div class="width-max lg:flex lg:ml-auto">
<RefreshTask <TasksManager
v-bind:resultsProp="results" :resultsProp="results" />
v-if="path == '/relays/find' || path.includes(`/relay/`)"/> </div>
</div>
</div> </div>
</div> </div>
</template> </template>
@ -35,8 +34,8 @@ import RelaysLib from '@/shared/relays-lib.js'
import { setupNavData, mountNav, setActiveContent, loadNavContent, routeValid, parseHash, contentIsActive } from '@/shared/hash-router.js' import { setupNavData, mountNav, setActiveContent, loadNavContent, routeValid, parseHash, contentIsActive } from '@/shared/hash-router.js'
// import RefreshTask from '@/components/relays/tasks/RefreshTask.vue' // import RefreshTask from '@/components/relays/tasks/RefreshTask.vue'
const RefreshTask = defineAsyncComponent(() => const TasksManager = defineAsyncComponent(() =>
import("@/components/relays/tasks/RefreshTask.vue" /* webpackChunkName: "RefreshTask" */) import("@/components/relays/tasks/TasksManager.vue" /* webpackChunkName: "TasksManager" */)
); );
@ -44,7 +43,7 @@ export default defineComponent({
title: "nostr.watch registry & network status", title: "nostr.watch registry & network status",
name: 'RelaysNav', name: 'RelaysNav',
components: { components: {
RefreshTask, TasksManager,
}, },
props: { props: {
resultsProp: { resultsProp: {

14
src/components/relays/tasks/HistoryTask.vue

@ -265,18 +265,18 @@ export default defineComponent({
methods: Object.assign(RelaysLib, { methods: Object.assign(RelaysLib, {
invalidate: async function(){ invalidate: async function(){
if( !this.store.tasks.isAnyProcessing && this.isExpired() ) { if( !this.store.tasks.isAnyProcessing && this.isExpired('relays/history') ) {
this.store.tasks.startProcessing('history') this.store.tasks.startProcessing('relays/history')
this.store.stats.set( 'nips', this.collateSupportedNips ) this.store.stats.set( 'nips', this.collateSupportedNips )
this.store.tasks.addProcessed('history', 'nips') this.store.tasks.addProcessed('relays/history', 'nips')
this.store.stats.set( 'continents', this.collateContinents ) this.store.stats.set( 'continents', this.collateContinents )
this.store.tasks.addProcessed('history', 'continents') this.store.tasks.addProcessed('relays/history', 'continents')
this.store.stats.set( 'countries', this.collateCountries ) this.store.stats.set( 'countries', this.collateCountries )
this.store.tasks.addProcessed( 'history', 'countries' ) this.store.tasks.addProcessed( 'relays/history', 'countries' )
this.remoteTask = await this.historicalData() this.remoteTask = await this.historicalData()
this.store.tasks.addProcessed( 'history', 'firstSeen' ) this.store.tasks.addProcessed( 'relays/history', 'firstSeen' )
// this.store.stats.setHistory(remoteTask) // this.store.stats.setHistory(remoteTask)
this.store.tasks.finishProcessing( 'history' ) this.store.tasks.finishProcessing( 'relays/history' )
} }
}, },
collateSoftware(){ collateSoftware(){

87
src/components/relays/tasks/RefreshTask.vue

@ -63,10 +63,11 @@ const localMethods = {
} }
}, },
addToQueue: function(id, fn){ addToQueue: function(id, fn, unique){
this.store.tasks.addJob({ this.store.tasks.addJob({
id: id, id: id,
handler: fn.bind(this) handler: fn,
unique: unique
}) })
}, },
@ -102,54 +103,60 @@ const localMethods = {
}, },
invalidate: async function(force, single){ invalidate: async function(force, single){
console.log('expired', !this.store.tasks.getLastUpdate('relays'), Date.now() - this.store.tasks.getLastUpdate('relays') > this.store.prefs.expireAfter) // console.log('expired', !this.store.tasks.getLastUpdate('relays'), Date.now() - this.store.tasks.getLastUpdate('relays') > this.store.prefs.expireAfter)
if( (!this.isExpired && !force) ) if( (!this.isExpired('relays') && !force) )
return return
console.log('windowActive', this.windowActive) // console.log('windowActive', this.windowActive)
if(!this.windowActive) if(!this.windowActive)
return return
this.store.tasks.startProcessing('relays') this.addToQueue('relays', async () => {
const relays = this.relays.filter( relay => !this.store.tasks.isProcessed('relays', relay) )
const relays = this.relays.filter( relay => !this.store.tasks.isProcessed('relays', relay) ) console.log('unprocessed relays',
this.relays.filter( relay => !this.store.tasks.getProcessed('relays').includes(relay)))
console.log('unprocessed relays', if(single) {
this.relays.filter( relay => !this.store.tasks.getProcessed('relays').includes(relay))) await this.check(single)
}
if(single) { else {
await this.check(single) for(let index = 0; index < relays.length; index++) {
} await this.delay(this.averageLatency)
else { const relay = relays[index]
for(let index = 0; index < relays.length; index++) { this.check(relay)
await this.delay(this.averageLatency) .then((result) => this.completeRelay(relay, result) )
const relay = relays[index] // .then( async () => {
this.check(relay) // // this.history = await History()
.then((result) => { // })
if(this.store.tasks.isProcessed('relays', relay)) .catch( () => this.completeRelay(relay) )
return }
this.store.tasks.addProcessed('relays', result.url)
this.results[result.url] = result
this.setCache(result)
if(this.store.tasks.getProcessed('relays').length >= this.relays.length)
this.completeAll()
return this.results
})
.then( async () => {
// this.history = await History()
})
.catch( err => console.error(err) )
} }
}, true)
console.log('queue', this.store.tasks.getActive)
},
completeRelay: function(relay, result){
if(this.store.tasks.isProcessed('relays', relay))
return
this.store.tasks.addProcessed('relays', relay)
if(result) {
this.results[relay] = result
this.setCache(result)
} }
if(this.store.tasks.getProcessed('relays').length >= this.relays.length)
this.completeAll()
}, },
completeAll: function(){ completeAll: function(){
//console.log('completed') //console.log('completed')
this.store.tasks.finishProcessing('relays') this.store.tasks.completeJob()
// this.store.tasks.finishProcessing('relays')
this.store.tasks.updateNow('relays') this.store.tasks.updateNow('relays')
this.store.relays.setAggregateCache('public', Object.keys(this.results).filter( result => this.results[result].aggregate === 'public' )) this.store.relays.setAggregateCache('public', Object.keys(this.results).filter( result => this.results[result].aggregate === 'public' ))
this.store.relays.setAggregateCache('restricted', Object.keys(this.results).filter( result => this.results[result].aggregate === 'restricted' )) this.store.relays.setAggregateCache('restricted', Object.keys(this.results).filter( result => this.results[result].aggregate === 'restricted' ))
@ -164,7 +171,7 @@ const localMethods = {
checkLatency: true, checkLatency: true,
getInfo: true, getInfo: true,
getIdentities: true, getIdentities: true,
// debug: true, debug: true,
connectTimeout: this.getDynamicTimeout, connectTimeout: this.getDynamicTimeout,
readTimeout: this.getDynamicTimeout, readTimeout: this.getDynamicTimeout,
writeTimeout: this.getDynamicTimeout, writeTimeout: this.getDynamicTimeout,
@ -184,6 +191,7 @@ const localMethods = {
}) })
.on('close', () => { .on('close', () => {
//console.log(`${relay.url} has closed`) //console.log(`${relay.url} has closed`)
reject()
}) })
.on('error', () => { .on('error', () => {
reject() reject()
@ -265,6 +273,9 @@ export default defineComponent({
}, },
mounted(){ mounted(){
this.migrateLegacy() this.migrateLegacy()
console.log('is processing', this.store.tasks.isProcessing(`relays`))
if(this.store.tasks.isProcessing(`relays`)) if(this.store.tasks.isProcessing(`relays`))
this.invalidate(true) this.invalidate(true)
else else

7
src/components/relays/tasks/RelayCanonicalsTask.vue

@ -0,0 +1,7 @@
<template>
</template>
<script>
</script>

96
src/components/relays/tasks/TasksManager.vue

@ -0,0 +1,96 @@
<template>
<RefreshTask
v-if="showRefreshRelays"
v-bind:resultsProp="results" />
<RelayCanonicalsTask
v-else-if="showGetRelayCanonicals"
v-bind:resultsProp="results" />
</template>
<script>
import { defineComponent, toRefs } from 'vue'
import { useRoute } from 'vue-router'
import { setupStore } from '@/store'
import SharedComputed from '@/shared/computed.js'
import RefreshTask from './RefreshTask.vue'
export default defineComponent({
name: "TasksManager",
components: {
RefreshTask
},
setup(props){
const {resultsProp: results} = toRefs(props)
return {
store : setupStore(),
results: results
}
},
beforeMount(){
//https://github.com/iendeavor/pinia-plugin-persistedstate-2/issues/136
this.store.tasks.active = new Array()
this.store.tasks.pending = new Array()
this.store.tasks.completed = new Array()
},
mounted(){
this.store.tasks.$subscribe( (mutation) => {
console.log('mutation', mutation.events)
if(mutation.events.key === 'currentTask')
this.processJob()
})
this.processJob()
},
props: {
resultsProp: {
type: String,
default: "Tooltip text",
},
},
methods: {
processJob(){
console.log('trying processJob()')
if(!this.store.tasks.active?.handler)
return
console.log('processJob()', this.store.tasks.active.id)
this.store.tasks.active.handler()
}
},
computed: Object.assign(SharedComputed, {
path: function() { return useRoute().path },
showRefreshRelays: function(){
return (
this.path.includes('/relays/find')
|| this.path.includes(`/relay/`)
)
&&
(
(
this.store.tasks.isProcessing('relays')
&& this.store.tasks.currentTask == 'relays'
)
||
(
!this.store.tasks.isAnyProcessing
)
)
},
showGetRelayCanonicals: function(){
return (
(
this.store.tasks.isProcessing('relays/canonicals')
&& this.store.tasks.currentTask == 'relays/canonicals'
)
||
(
!this.store.tasks.isAnyProcessing
)
)
&&
this.isExpired('relays/canonicals')
}
})
});
</script>

2
src/shared/computed.js

@ -1,5 +1,5 @@
export default { export default {
isExpired: function(){ isExpired: function(){
return !this.store.tasks.getLastUpdate('relays') || Date.now() - this.store.tasks.getLastUpdate('relays') > this.store.prefs.expireAfter return (slug) => !this.store.tasks.getLastUpdate(slug) || Date.now() - this.store.tasks.getLastUpdate(slug) > this.store.prefs.expireAfter
}, },
} }

29
src/store/relays.js

@ -7,14 +7,15 @@ export const useRelaysStore = defineStore('relays', {
urls: new Array(), urls: new Array(),
// results: new Object(), // results: new Object(),
geo: new Object(), geo: new Object(),
lastUpdate: {}, lastUpdate: null,
count: new Object(), count: new Object(),
processing: false, processing: false,
processedRelays: new Set(), processedRelays: new Set(),
favorites: new Array(), favorites: new Array(),
aggregates: {}, aggregates: {},
aggregatesAreSet: false, aggregatesAreSet: false,
cached: new Object() cached: new Object(),
canonicals: new Object()
}), }),
getters: { getters: {
getAll: (state) => state.urls, getAll: (state) => state.urls,
@ -25,7 +26,7 @@ export const useRelaysStore = defineStore('relays', {
return state.favorites return state.favorites
return state.urls.filter( (relay) => results?.[relay]?.aggregate == aggregate) return state.urls.filter( (relay) => results?.[relay]?.aggregate == aggregate)
}, },
getByAggregate: (state) => (aggregate) => { getByAggregate: state => aggregate => {
return state.urls return state.urls
.filter( (relay) => state.results?.[relay]?.aggregate == aggregate) .filter( (relay) => state.results?.[relay]?.aggregate == aggregate)
}, },
@ -33,20 +34,22 @@ export const useRelaysStore = defineStore('relays', {
// getResults: (state) => state.results, // getResults: (state) => state.results,
// getResult: (state) => (relayUrl) => state.results?.[relayUrl], // getResult: (state) => (relayUrl) => state.results?.[relayUrl],
getGeo: (state) => (relayUrl) => state.geo[relayUrl], getGeo: state => relayUrl => state.geo[relayUrl],
getLastUpdate: (state) => state.lastUpdate, getLastUpdate: state => state.lastUpdate,
getCount: (state) => (type) => state.count[type], getCount: state => type => state.count[type],
getCounts: (state) => state.count, getCounts: state => state.count,
getAggregate: (state) => (which) => state.aggregates[which], getAggregate: state => which => state.aggregates[which],
areAggregatesSet: (state) => state.aggregatesAreSet, areAggregatesSet: state => state.aggregatesAreSet,
getFavorites: (state) => state.favorites, getFavorites: state => state.favorites,
isFavorite: (state) => (relayUrl) => state.favorites.includes(relayUrl), isFavorite: state => relayUrl => state.favorites.includes(relayUrl),
getAggregateCache: (state) => (aggregate) => state.cached[aggregate] instanceof Array ? state.cached[aggregate] : [], getAggregateCache: state => aggregate => state.cached[aggregate] instanceof Array ? state.cached[aggregate] : [],
getCanonical: state => relay => state.canonicals[relay]
}, },
actions: { actions: {
addRelay(relayUrl){ this.urls.push(relayUrl) }, addRelay(relayUrl){ this.urls.push(relayUrl) },
@ -62,7 +65,7 @@ export const useRelaysStore = defineStore('relays', {
setGeo(geo){ this.geo = geo }, setGeo(geo){ this.geo = geo },
updateNow(key){ this.lastUpdate[key] = Date.now() },
setStat(type, value){ setStat(type, value){
this.count[type] = value this.count[type] = value

56
src/store/tasks.js

@ -4,15 +4,15 @@ export const useTaskStore = defineStore('tasks', {
state: () => ({ state: () => ({
lastUpdate: new Object(), lastUpdate: new Object(),
//processing cache
processing: new Object(),
processed: new Object(),
currentTask: new String(),
//queue //queue
pending: new Array(), pending: new Array(),
completed: new Array(), completed: new Array(),
active: new Object(), active: new Object(),
//legacy
processing: new Object(),
processed: new Object(),
currentTask: new Object(),
}), }),
getters: { getters: {
getLastUpdate: (state) => (key) => state.lastUpdate[key], getLastUpdate: (state) => (key) => state.lastUpdate[key],
@ -25,39 +25,54 @@ export const useTaskStore = defineStore('tasks', {
}, },
isProcessing: (state) => (key) => state.processing[key], isProcessing: (state) => (key) => state.processing[key],
isProcessed: (state) => (key, relay) => state.getProcessed(key).includes(relay), isProcessed: (state) => (key, relay) => state.getProcessed(key).includes(relay),
isAnyProcessing: (state) => Object.keys(state.processing).filter( key => state.processing[key] ), isAnyProcessing: (state) => Object.keys(state.processing).filter( key => state.processing[key] ).length ? true : false,
//queue/lists //queue/lists
getPending: (state) => state.pending, getPending: (state) => state.pending,
getActive: (state) => state.active, getActive: (state) => state.active,
getActiveSlug: (state) => state.active.id, getActiveSlug: (state) => state.active.id,
getCompleted: (state) => state.completed, getCompleted: (state) => state.completed,
//queue/states //queue/states
isActive: (state) => Object.keys( state.active ).length > 0, isActive: (state) => Object.keys( state.active ).length > 0,
isIdle: (state) => Object.keys( state.active ).length == 0, isIdle: (state) => Object.keys( state.active ).length == 0,
arePending: (state) => state.pending.length > 0, arePending: (state) => state.pending.length > 0,
//
// getRate: (state) => (key) => state.rate[key],
}, },
actions: { actions: {
updateNow(key){ this.lastUpdate[key] = Date.now() }, updateNow(key){ this.lastUpdate[key] = Date.now() },
//queue //queue
addJob(job){ addJob(job){
if(job?.unique){
let exists
exists = this.active.id === job.id
if(!exists)
exists = this.pending.filter( j => j.id === job.id).length ? true : false
if(exists)
return
}
this.pending.push(job) this.pending.push(job)
if( this.isIdle ) if( this.isIdle )
this.startNextJob() this.startNextJob()
}, },
startNextJob(){ startNextJob(){
if( this.isActive ) console.log('task, isactive?', this.isActive)
this.completed.push(this.active)
if( this.arePending ) { if( this.arePending ) {
this.active = this.pending[0] this.active = this.pending[0]
this.pending.shift() this.pending.shift()
this.startProcessing(this.active)
} }
else { else {
console.log('completing active...')
this.active = {} this.active = {}
} }
}, },
completeJob(){
console.log('compelteJob', this.active.id, this.active)
this.finishProcessing(this.active.id)
this.completed.push(this.active)
this.startNextJob()
},
clearJobs(type){ clearJobs(type){
this[type] = new Array() this[type] = new Array()
}, },
@ -69,14 +84,15 @@ export const useTaskStore = defineStore('tasks', {
this.pending.splice( index, 1 ) this.pending.splice( index, 1 )
}, },
//legacy //legacy
startProcessing(key) { startProcessing(job) {
this.processing[key] = true this.addJob(job)
this.currentTask[key] = key this.processing[job.id] = true
this.currentTask = job.id
}, },
finishProcessing(key) { finishProcessing(key) {
this.processed[key] = new Array() this.processed[key] = new Array()
this.processing[key] = false this.processing[key] = false
this.currentTask[key] = null this.currentTask = null
}, },
addProcessed(key, relay){ addProcessed(key, relay){
if( !(this.processed[key] instanceof Array) ) if( !(this.processed[key] instanceof Array) )
@ -86,4 +102,16 @@ export const useTaskStore = defineStore('tasks', {
}, },
}, },
share: {
// An array of fields that the plugin will ignore.
omit: ['pending', 'completed', 'active'],
// Override global config for this store.
enable: true,
},
},
{
persistedState: {
// includePaths: ['lastUpdate', 'processed', 'processing', 'currentTask']
excludePaths: ['pending', 'completed', 'active'],
}
}) })

28
yarn.lock

@ -1302,7 +1302,7 @@
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.6.tgz#cee20bd55e68a1720bdab363ecf0c821ded4cd45" resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.6.tgz#cee20bd55e68a1720bdab363ecf0c821ded4cd45"
integrity sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw== integrity sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==
"@scure/base@~1.1.0": "@scure/base@^1.1.1", "@scure/base@~1.1.0":
version "1.1.1" version "1.1.1"
resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.1.tgz#ebb651ee52ff84f420097055f4bf46cfba403938" resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.1.tgz#ebb651ee52ff84f420097055f4bf46cfba403938"
integrity sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA== integrity sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==
@ -2503,11 +2503,6 @@ balanced-match@^1.0.0:
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
base64-arraybuffer@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz#1c37589a7c4b0746e34bd1feb951da2df01c1bdc"
integrity sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==
base64-js@^1.3.1: base64-js@^1.3.1:
version "1.5.1" version "1.5.1"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
@ -2525,11 +2520,6 @@ batch@0.6.1:
resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16"
integrity sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw== integrity sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==
bech32@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/bech32/-/bech32-2.0.0.tgz#078d3686535075c8c79709f054b1b226a133b355"
integrity sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==
big.js@^5.2.2: big.js@^5.2.2:
version "5.2.2" version "5.2.2"
resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
@ -3732,6 +3722,11 @@ dotenv-expand@^5.1.0:
resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz#3fbaf020bfd794884072ea26b1e9791d45a629f0" resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz#3fbaf020bfd794884072ea26b1e9791d45a629f0"
integrity sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA== integrity sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==
dotenv@16.0.3:
version "16.0.3"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.3.tgz#115aec42bac5053db3c456db30cc243a5a836a07"
integrity sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==
dotenv@^10.0.0: dotenv@^10.0.0:
version "10.0.0" version "10.0.0"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81"
@ -6410,17 +6405,16 @@ nostr-relay-inspector@0.0.23:
tape "5.6.1" tape "5.6.1"
yaml-loader "0.8.0" yaml-loader "0.8.0"
nostr-tools@1.0.1: nostr-tools@1.1.1:
version "1.0.1" version "1.1.1"
resolved "https://registry.yarnpkg.com/nostr-tools/-/nostr-tools-1.0.1.tgz#acf21758fc745674ed047e7dc219b30baf489005" resolved "https://registry.yarnpkg.com/nostr-tools/-/nostr-tools-1.1.1.tgz#2be4cd650bc0a4d20650b6cf46fee451c9f565b8"
integrity sha512-URBNadrVq4qSmndzd4clZqubze4y/LB8cdzzen9mNwlFh3ICDdWp7TCShTbLEZQYPPSVoOe2n13l77jzcVvH/w== integrity sha512-mxgjbHR6nx2ACBNa2tBpeM/glsPWqxHPT1Kszx/XfzL+kUdi1Gm3Xz1UcaODQ2F84IFtCKNLO+aF31ZfTAhSYQ==
dependencies: dependencies:
"@noble/hashes" "^0.5.7" "@noble/hashes" "^0.5.7"
"@noble/secp256k1" "^1.7.0" "@noble/secp256k1" "^1.7.0"
"@scure/base" "^1.1.1"
"@scure/bip32" "^1.1.1" "@scure/bip32" "^1.1.1"
"@scure/bip39" "^1.1.0" "@scure/bip39" "^1.1.0"
base64-arraybuffer "^1.0.2"
bech32 "^2.0.0"
nostr@0.2.5: nostr@0.2.5:
version "0.2.5" version "0.2.5"

Loading…
Cancel
Save