From 9242781670e2d3ef5ae0ab21dfafff5226bad2e3 Mon Sep 17 00:00:00 2001
From: Vitor Pamplona
Date: Thu, 3 Aug 2023 14:55:52 -0400
Subject: [PATCH] Adds an active relay information to the screen.
---
index.html | 10 +++-
js/nostr-broadcast.js | 36 ++++++++------
js/nostr-utils.js | 106 ++++++++++++++++++++++++++++++++++++------
3 files changed, 122 insertions(+), 30 deletions(-)
diff --git a/index.html b/index.html
index b2fbcf1..27c39d5 100644
--- a/index.html
+++ b/index.html
@@ -108,11 +108,17 @@
id="fetching-progress"
name="fetching-progress"
min="0"
- max="300"
+ max="180"
value="0"
style="visibility: hidden" />
+
+
@@ -125,7 +131,7 @@
id="broadcasting-progress"
name="broadcasting-progress"
min="0"
- max="300"
+ max="180"
value="0"
style="visibility: hidden" />
diff --git a/js/nostr-broadcast.js b/js/nostr-broadcast.js
index fe5d2df..f4707ba 100644
--- a/js/nostr-broadcast.js
+++ b/js/nostr-broadcast.js
@@ -16,6 +16,7 @@ const fetchAndBroadcast = async () => {
fetching: 'Fetching from relays... ',
download: `Downloading Backup file... ${checkMark}`,
}
+ $('#checking-relays-header').text("Waiting for Relays: ")
// parse pubkey ('npub' or hexa)
const pubkey = parsePubkey($('#pubkey').val())
if (!pubkey) return
@@ -25,18 +26,22 @@ const fetchAndBroadcast = async () => {
$('#fetching-status').text(txt.fetching)
// show and update fetching progress bar
$('#fetching-progress').css('visibility', 'visible')
- const fetchInterval = setInterval(() => {
- // update fetching progress bar
- const currValue = parseInt($('#fetching-progress').val())
- $('#fetching-progress').val(currValue + 1)
- }, 1000)
+ $('#fetching-progress').prop('max', relays.length)
+
+ $('#checking-relays-header-box').css('display', 'flex')
+ $('#checking-relays-box').css('display', 'flex')
+ $('#checking-relays-header').text("Waiting for Relays:")
+
// get all events from relays
const filters =[{ authors: [pubkey] }, { "#p": [pubkey] }]
const data = await getEvents(filters)
+
+ $('#checking-relays-header-box').css('display', 'none')
+ $('#checking-relays-box').css('display', 'none')
+
// inform user fetching is done
$('#fetching-status').html(txt.fetching + checkMark)
- clearInterval(fetchInterval)
- $('#fetching-progress').val(300)
+ $('#fetching-progress').val(relays.length)
// inform user that backup file (js format) is being downloaded
$('#file-download').html(txt.download)
downloadFile(data, 'nostr-backup.js')
@@ -44,16 +49,19 @@ const fetchAndBroadcast = async () => {
$('#broadcasting-status').html(txt.broadcasting)
// show and update broadcasting progress bar
$('#broadcasting-progress').css('visibility', 'visible')
- const broadcastInterval = setInterval(() => {
- // update fetching progress bar
- const currValue = parseInt($('#broadcasting-progress').val())
- $('#broadcasting-progress').val(currValue + 1)
- }, 1000)
+ $('#broadcasting-progress').prop('max', relays.length)
+
+ $('#checking-relays-header-box').css('display', 'flex')
+ $('#checking-relays-box').css('display', 'flex')
+ $('#checking-relays-header').text("Waiting for Relays:")
+
await broadcastEvents(data)
+
+ $('#checking-relays-header-box').css('display', 'none')
+ $('#checking-relays-box').css('display', 'none')
// inform user that broadcasting is done
$('#broadcasting-status').html(txt.broadcasting + checkMark)
- clearInterval(broadcastInterval)
- $('#broadcasting-progress').val(300)
+ $('#broadcasting-progress').val(relays.length)
// re-enable broadcast button
$('#fetch-and-broadcast').prop('disabled', false)
}
diff --git a/js/nostr-utils.js b/js/nostr-utils.js
index b50a996..d0d670a 100644
--- a/js/nostr-utils.js
+++ b/js/nostr-utils.js
@@ -46,25 +46,46 @@ function hexToBytes(hex) {
tempLink.setAttribute('download', fileName)
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("
")
+ $('#checking-relays').html(newText)
+ } else {
+ $('#checking-relays-header').html("")
+ $('#checking-relays').html("")
+ }
+ }
+
// fetch events from relay, returns a promise
- const fetchFromRelay = async (relay, filters, events) =>
+ const fetchFromRelay = async (relay, filters, events, relayStatus) =>
new Promise((resolve, reject) => {
try {
-
+ relayStatus[relay] = "Starting"
+ updateRelayStatus(relayStatus)
// open websocket
const ws = new WebSocket(relay)
// prevent hanging forever
- setTimeout(() => {
+ let myTimeout = setTimeout(() => {
ws.close()
reject('timeout')
- }, 300_000)
+ }, 10_000)
+
// subscription id
const subsId = 'my-sub'
// subscribe to events filtered by author
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)))
}
@@ -73,6 +94,12 @@ function hexToBytes(hex) {
const [msgType, subscriptionId, data] = JSON.parse(event.data)
// event messages
if (msgType === 'EVENT' && subscriptionId === subsId) {
+ clearTimeout(myTimeout)
+ myTimeout = setTimeout(() => {
+ ws.close()
+ reject('timeout')
+ }, 5_000)
+
const { id } = data
// prevent duplicated events
if (events[id]) return
@@ -82,18 +109,27 @@ function hexToBytes(hex) {
}
// end of subscription messages
if (msgType === 'EOSE' && subscriptionId === subsId) {
+ relayStatus[relay] = "Done"
+ updateRelayStatus(relayStatus)
ws.close()
resolve()
}
}
ws.onerror = (err) => {
+ relayStatus[relay] = "Done"
+ updateRelayStatus(relayStatus)
ws.close()
reject(err)
}
ws.onclose = (socket, event) => {
+ relayStatus[relay] = "Done"
+ updateRelayStatus(relayStatus)
resolve()
}
} catch (exception) {
+ console.log(exception)
+ relayStatus[relay] = "Error"
+ updateRelayStatus(relayStatus)
try {
ws.close()
} catch (exception) {
@@ -107,45 +143,87 @@ function hexToBytes(hex) {
const getEvents = async (filters) => {
// events hash
const events = {}
- // wait for all relays to finish
- await Promise.allSettled(
- relays.map((relay) => fetchFromRelay(relay, filters, events))
- )
+
+ // batch processing of 10 relays
+ 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 Object.keys(events).map((id) => events[id])
}
// send events to a relay, returns a promisse
- const sendToRelay = async (relay, data) =>
+ const sendToRelay = async (relay, data, relayStatus) =>
new Promise((resolve, reject) => {
try {
const ws = new WebSocket(relay)
+ relayStatus[relay] = "Starting"
+ updateRelayStatus(relayStatus)
+
// prevent hanging forever
- setTimeout(() => {
+ let myTimeout = setTimeout(() => {
ws.close()
reject('timeout')
- }, 300_000)
+ }, 10_000)
// fetch events from relay
ws.onopen = () => {
- console.log("sending ", data.length, "events to ", relay)
+ relayStatus[relay] = "Sending"
+ updateRelayStatus(relayStatus)
for (evnt of data) {
+ clearTimeout(myTimeout)
+ myTimeout = setTimeout(() => {
+ ws.close()
+ reject('timeout')
+ }, 5_000)
+
ws.send(JSON.stringify(['EVENT', evnt]))
}
+ relayStatus[relay] = "Done"
+ updateRelayStatus(relayStatus)
ws.close()
resolve(`done for ${relay}`)
}
ws.onerror = (err) => {
+ relayStatus[relay] = "Error"
+ updateRelayStatus(relayStatus)
console.log("Error", err)
+ ws.close()
reject(err)
}
+ ws.onclose = (socket, event) => {
+ relayStatus[relay] = "Done"
+ updateRelayStatus(relayStatus)
+ resolve()
+ }
} catch (exception) {
+ relayStatus[relay] = "Error"
+ updateRelayStatus(relayStatus)
+ try {
+ ws.close()
+ } catch (exception) {
+ }
reject(exception)
}
})
// broadcast events to list of relays
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({})
}
\ No newline at end of file