You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
148 lines
3.9 KiB
148 lines
3.9 KiB
const { RelayPool, Relay } = require('nostr'),
|
|
crypto = require('crypto'),
|
|
writeYamlFile = require('write-yaml-file'),
|
|
fs = require('fs'),
|
|
fetch = require('cross-fetch'),
|
|
yaml= require('js-yaml');
|
|
|
|
const result = {},
|
|
relays_endpoint = 'https://nostr.watch/relays.json'
|
|
|
|
let relays = [],
|
|
relaysKnown = [],
|
|
relaysRemote = {},
|
|
remove = [],
|
|
uniques = null
|
|
|
|
const run = async function(){
|
|
//discover relays [kind:3], "remoteRelays"
|
|
await discover().catch( err => console.warn(err) )
|
|
|
|
//Sanitize knownRelays to prevent dupes in uniques
|
|
sanitizeKnownRelays()
|
|
|
|
//sanitize remoteRelays
|
|
sanitizeRemoteRelays()
|
|
|
|
//check remoteRelays
|
|
await checkRemoteRelays()
|
|
|
|
//Remove offline remoteRelays
|
|
removeOfflineRelays()
|
|
|
|
//Combine knownRelays and remoteRelays
|
|
concatRelays()
|
|
|
|
//set uniques
|
|
uniques = new Set(relays)
|
|
|
|
//Write to file
|
|
await writeYamlFile('./relays.yaml', { relays: Array.from(uniques) })
|
|
|
|
process.exit()
|
|
|
|
}
|
|
|
|
const concatRelays = function(){
|
|
relays = relaysKnown.concat(relaysRemote)
|
|
}
|
|
|
|
async function getRelays(){
|
|
// return await fetch(relays_endpoint, { method: "Get" })
|
|
// .then(res => res.json())
|
|
// .then(json => relaysKnown = json.relays)
|
|
const relaysObj = yaml.load(fs.readFileSync('./relays.yaml', 'utf8'))
|
|
relaysKnown = relaysObj.relays
|
|
//console.log(relaysKnown)
|
|
return
|
|
}
|
|
|
|
async function discover(){
|
|
await getRelays()
|
|
|
|
return new Promise(resolve => {
|
|
const subid = crypto.randomBytes(40).toString('hex')
|
|
const pool = RelayPool(['wss://nostr.sandwich.farm'])
|
|
pool
|
|
.on('open', relay => {
|
|
// //console.log('open')
|
|
relay.subscribe(subid, {limit: 1000, kinds:[3]})
|
|
})
|
|
.on('close', () => {
|
|
// //console.log('close')
|
|
})
|
|
.on('event', (relay, _subid, event) => {
|
|
if(subid == _subid) {
|
|
try {
|
|
relaysRemote = Object.assign(relaysRemote, JSON.parse(event.content))
|
|
relay.close()
|
|
} catch(e) {""}
|
|
}
|
|
})
|
|
|
|
setTimeout( () => {
|
|
pool.close()
|
|
resolve(true)
|
|
}, 10*1000 )
|
|
})
|
|
}
|
|
|
|
const sanitizeRemoteRelays = function(){
|
|
remote1 = Object.entries(relaysRemote)
|
|
.filter( relay => Array.isArray(relay) )
|
|
.map( relay => sanitizeRelay(relay[0]) )
|
|
.filter( relay => relay.startsWith('wss://') )
|
|
.filter( relay => !relay.includes('localhost') )
|
|
|
|
remote2 = Object.entries(relaysRemote)
|
|
.filter( relay => relay instanceof String )
|
|
.map( relay => sanitizeRelay(relay) )
|
|
.filter( relay => relay.startsWith('wss://') )
|
|
.filter( relay => !relay.includes('localhost') )
|
|
|
|
relaysRemote = remote1.concat(remote2)
|
|
}
|
|
|
|
const sanitizeKnownRelays = function(){
|
|
relaysKnown = relaysKnown.map( relay => sanitizeRelay(relay) ) //Known relays may have trailing slash
|
|
}
|
|
|
|
const sanitizeRelay = function(relay) {
|
|
return relay
|
|
.toLowerCase()
|
|
.trim()
|
|
.replace(/\s\t/g, '')
|
|
.replace(/\r?\n|\r/g, "")
|
|
.replace(/\/+$/, '')
|
|
.replace(/^[^a-z\d]*|[^a-z\d]*$/gi, '');
|
|
}
|
|
|
|
const checkRemoteRelays = async function(){
|
|
for(let i=0;i<relaysRemote.length;i++) {
|
|
// //console.log('check for connect', remoteMerged[i])
|
|
await checkRelay(relaysRemote[i])
|
|
.catch( () => {
|
|
remove.push(relaysRemote[i])
|
|
//console.log('removals:', remove.length, relaysRemote[i])
|
|
})
|
|
}
|
|
}
|
|
|
|
const checkRelay = async function(relay){
|
|
return new Promise( (resolve, reject) => {
|
|
let socket = new Relay(relay)
|
|
socket
|
|
.on('open', relay => {
|
|
socket.close()
|
|
resolve()
|
|
})
|
|
.on('error', reject )
|
|
setTimeout( reject, 500 )
|
|
})
|
|
}
|
|
|
|
const removeOfflineRelays = function(){
|
|
relaysRemote = relaysRemote.filter( relay => !remove.includes(relay) )
|
|
}
|
|
|
|
run()
|