Adds an active relay information to the screen.

This commit is contained in:
Vitor Pamplona 2023-08-03 14:55:52 -04:00
parent 7cca63f7ea
commit 9242781670
3 changed files with 122 additions and 30 deletions

View File

@ -108,11 +108,17 @@
id="fetching-progress" id="fetching-progress"
name="fetching-progress" name="fetching-progress"
min="0" min="0"
max="300" max="180"
value="0" value="0"
style="visibility: hidden" /> style="visibility: hidden" />
</p> </p>
</div> </div>
<div class="box-content" id="checking-relays-header-box">
<p id="checking-relays-header"></p>
</div>
<div class="box-content" id="checking-relays-box">
<p id="checking-relays"></p>
</div>
<div class="box-content"> <div class="box-content">
<p id="file-download"></p> <p id="file-download"></p>
<p id="events-found"></p> <p id="events-found"></p>
@ -125,7 +131,7 @@
id="broadcasting-progress" id="broadcasting-progress"
name="broadcasting-progress" name="broadcasting-progress"
min="0" min="0"
max="300" max="180"
value="0" value="0"
style="visibility: hidden" /> style="visibility: hidden" />
</p> </p>

View File

@ -16,6 +16,7 @@ const fetchAndBroadcast = async () => {
fetching: 'Fetching from relays... ', fetching: 'Fetching from relays... ',
download: `Downloading Backup file... ${checkMark}`, download: `Downloading Backup file... ${checkMark}`,
} }
$('#checking-relays-header').text("Waiting for Relays: ")
// parse pubkey ('npub' or hexa) // parse pubkey ('npub' or hexa)
const pubkey = parsePubkey($('#pubkey').val()) const pubkey = parsePubkey($('#pubkey').val())
if (!pubkey) return if (!pubkey) return
@ -25,18 +26,22 @@ const fetchAndBroadcast = async () => {
$('#fetching-status').text(txt.fetching) $('#fetching-status').text(txt.fetching)
// show and update fetching progress bar // show and update fetching progress bar
$('#fetching-progress').css('visibility', 'visible') $('#fetching-progress').css('visibility', 'visible')
const fetchInterval = setInterval(() => { $('#fetching-progress').prop('max', relays.length)
// update fetching progress bar
const currValue = parseInt($('#fetching-progress').val()) $('#checking-relays-header-box').css('display', 'flex')
$('#fetching-progress').val(currValue + 1) $('#checking-relays-box').css('display', 'flex')
}, 1000) $('#checking-relays-header').text("Waiting for Relays:")
// get all events from relays // get all events from relays
const filters =[{ authors: [pubkey] }, { "#p": [pubkey] }] const filters =[{ authors: [pubkey] }, { "#p": [pubkey] }]
const data = await getEvents(filters) const data = await getEvents(filters)
$('#checking-relays-header-box').css('display', 'none')
$('#checking-relays-box').css('display', 'none')
// inform user fetching is done // inform user fetching is done
$('#fetching-status').html(txt.fetching + checkMark) $('#fetching-status').html(txt.fetching + checkMark)
clearInterval(fetchInterval) $('#fetching-progress').val(relays.length)
$('#fetching-progress').val(300)
// inform user that backup file (js format) is being downloaded // inform user that backup file (js format) is being downloaded
$('#file-download').html(txt.download) $('#file-download').html(txt.download)
downloadFile(data, 'nostr-backup.js') downloadFile(data, 'nostr-backup.js')
@ -44,16 +49,19 @@ const fetchAndBroadcast = async () => {
$('#broadcasting-status').html(txt.broadcasting) $('#broadcasting-status').html(txt.broadcasting)
// show and update broadcasting progress bar // show and update broadcasting progress bar
$('#broadcasting-progress').css('visibility', 'visible') $('#broadcasting-progress').css('visibility', 'visible')
const broadcastInterval = setInterval(() => { $('#broadcasting-progress').prop('max', relays.length)
// update fetching progress bar
const currValue = parseInt($('#broadcasting-progress').val()) $('#checking-relays-header-box').css('display', 'flex')
$('#broadcasting-progress').val(currValue + 1) $('#checking-relays-box').css('display', 'flex')
}, 1000) $('#checking-relays-header').text("Waiting for Relays:")
await broadcastEvents(data) await broadcastEvents(data)
$('#checking-relays-header-box').css('display', 'none')
$('#checking-relays-box').css('display', 'none')
// inform user that broadcasting is done // inform user that broadcasting is done
$('#broadcasting-status').html(txt.broadcasting + checkMark) $('#broadcasting-status').html(txt.broadcasting + checkMark)
clearInterval(broadcastInterval) $('#broadcasting-progress').val(relays.length)
$('#broadcasting-progress').val(300)
// re-enable broadcast button // re-enable broadcast button
$('#fetch-and-broadcast').prop('disabled', false) $('#fetch-and-broadcast').prop('disabled', false)
} }

View File

@ -47,24 +47,45 @@ function hexToBytes(hex) {
tempLink.click() tempLink.click()
} }
const updateRelayStatus = (relayStatus) => {
if (Object.keys(relayStatus).length > 0) {
let newText = Object.keys(relayStatus).map(
it => it.replace("wss://", "").replace("ws://", "") + ": " + relayStatus[it]
).join("<br />")
$('#checking-relays').html(newText)
} else {
$('#checking-relays-header').html("")
$('#checking-relays').html("")
}
}
// fetch events from relay, returns a promise // fetch events from relay, returns a promise
const fetchFromRelay = async (relay, filters, events) => const fetchFromRelay = async (relay, filters, events, relayStatus) =>
new Promise((resolve, reject) => { new Promise((resolve, reject) => {
try { try {
relayStatus[relay] = "Starting"
updateRelayStatus(relayStatus)
// open websocket // open websocket
const ws = new WebSocket(relay) const ws = new WebSocket(relay)
// prevent hanging forever // prevent hanging forever
setTimeout(() => { let myTimeout = setTimeout(() => {
ws.close() ws.close()
reject('timeout') reject('timeout')
}, 300_000) }, 10_000)
// subscription id // subscription id
const subsId = 'my-sub' const subsId = 'my-sub'
// subscribe to events filtered by author // subscribe to events filtered by author
ws.onopen = () => { ws.onopen = () => {
clearTimeout(myTimeout)
myTimeout = setTimeout(() => {
ws.close()
reject('timeout')
}, 10_000)
relayStatus[relay] = "Downloading"
updateRelayStatus(relayStatus)
ws.send(JSON.stringify(['REQ', subsId].concat(filters))) ws.send(JSON.stringify(['REQ', subsId].concat(filters)))
} }
@ -73,6 +94,12 @@ function hexToBytes(hex) {
const [msgType, subscriptionId, data] = JSON.parse(event.data) const [msgType, subscriptionId, data] = JSON.parse(event.data)
// event messages // event messages
if (msgType === 'EVENT' && subscriptionId === subsId) { if (msgType === 'EVENT' && subscriptionId === subsId) {
clearTimeout(myTimeout)
myTimeout = setTimeout(() => {
ws.close()
reject('timeout')
}, 5_000)
const { id } = data const { id } = data
// prevent duplicated events // prevent duplicated events
if (events[id]) return if (events[id]) return
@ -82,18 +109,27 @@ function hexToBytes(hex) {
} }
// end of subscription messages // end of subscription messages
if (msgType === 'EOSE' && subscriptionId === subsId) { if (msgType === 'EOSE' && subscriptionId === subsId) {
relayStatus[relay] = "Done"
updateRelayStatus(relayStatus)
ws.close() ws.close()
resolve() resolve()
} }
} }
ws.onerror = (err) => { ws.onerror = (err) => {
relayStatus[relay] = "Done"
updateRelayStatus(relayStatus)
ws.close() ws.close()
reject(err) reject(err)
} }
ws.onclose = (socket, event) => { ws.onclose = (socket, event) => {
relayStatus[relay] = "Done"
updateRelayStatus(relayStatus)
resolve() resolve()
} }
} catch (exception) { } catch (exception) {
console.log(exception)
relayStatus[relay] = "Error"
updateRelayStatus(relayStatus)
try { try {
ws.close() ws.close()
} catch (exception) { } catch (exception) {
@ -107,45 +143,87 @@ function hexToBytes(hex) {
const getEvents = async (filters) => { const getEvents = async (filters) => {
// events hash // events hash
const events = {} const events = {}
// wait for all relays to finish
await Promise.allSettled( // batch processing of 10 relays
relays.map((relay) => fetchFromRelay(relay, filters, events)) let fetchFunctions = [...relays]
) while (fetchFunctions.length) {
let relaysForThisRound = fetchFunctions.splice(0, 10)
let relayStatus = {}
$('#fetching-progress').val(relays.length - fetchFunctions.length)
await Promise.allSettled( relaysForThisRound.map((relay) => fetchFromRelay(relay, filters, events, relayStatus)) )
}
updateRelayStatus({})
// return data as an array of events // return data as an array of events
return Object.keys(events).map((id) => events[id]) return Object.keys(events).map((id) => events[id])
} }
// send events to a relay, returns a promisse // send events to a relay, returns a promisse
const sendToRelay = async (relay, data) => const sendToRelay = async (relay, data, relayStatus) =>
new Promise((resolve, reject) => { new Promise((resolve, reject) => {
try { try {
const ws = new WebSocket(relay) const ws = new WebSocket(relay)
relayStatus[relay] = "Starting"
updateRelayStatus(relayStatus)
// prevent hanging forever // prevent hanging forever
setTimeout(() => { let myTimeout = setTimeout(() => {
ws.close() ws.close()
reject('timeout') reject('timeout')
}, 300_000) }, 10_000)
// fetch events from relay // fetch events from relay
ws.onopen = () => { ws.onopen = () => {
console.log("sending ", data.length, "events to ", relay) relayStatus[relay] = "Sending"
updateRelayStatus(relayStatus)
for (evnt of data) { for (evnt of data) {
clearTimeout(myTimeout)
myTimeout = setTimeout(() => {
ws.close()
reject('timeout')
}, 5_000)
ws.send(JSON.stringify(['EVENT', evnt])) ws.send(JSON.stringify(['EVENT', evnt]))
} }
relayStatus[relay] = "Done"
updateRelayStatus(relayStatus)
ws.close() ws.close()
resolve(`done for ${relay}`) resolve(`done for ${relay}`)
} }
ws.onerror = (err) => { ws.onerror = (err) => {
relayStatus[relay] = "Error"
updateRelayStatus(relayStatus)
console.log("Error", err) console.log("Error", err)
ws.close()
reject(err) reject(err)
} }
ws.onclose = (socket, event) => {
relayStatus[relay] = "Done"
updateRelayStatus(relayStatus)
resolve()
}
} catch (exception) { } catch (exception) {
relayStatus[relay] = "Error"
updateRelayStatus(relayStatus)
try {
ws.close()
} catch (exception) {
}
reject(exception) reject(exception)
} }
}) })
// broadcast events to list of relays // broadcast events to list of relays
const broadcastEvents = async (data) => { const broadcastEvents = async (data) => {
await Promise.allSettled(relays.map((relay) => sendToRelay(relay, data))) // batch processing of 10 relays
let broadcastFunctions = [...relays]
while (broadcastFunctions.length) {
let relaysForThisRound = broadcastFunctions.splice(0, 10)
let relayStatus = {}
$('#broadcasting-progress').val(relays.length - broadcastFunctions.length)
await Promise.allSettled( relaysForThisRound.map((relay) => sendToRelay(relay, data, relayStatus)) )
}
updateRelayStatus({})
} }