dskvr
2 years ago
13 changed files with 457 additions and 104 deletions
@ -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() |
@ -0,0 +1,7 @@ |
|||
<template> |
|||
|
|||
</template> |
|||
|
|||
<script> |
|||
|
|||
</script> |
@ -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> |
@ -1,5 +1,5 @@ |
|||
export default { |
|||
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 |
|||
}, |
|||
} |
Loading…
Reference in new issue