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

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()