Skip to content

Commit 19e4fd8

Browse files
committed
Debug
1 parent 22247e0 commit 19e4fd8

1 file changed

Lines changed: 186 additions & 60 deletions

File tree

nostr-no-bullshit.html

Lines changed: 186 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -14,76 +14,191 @@
1414
const TIMEOUT = 7000
1515

1616
const $ = id => document.getElementById(id)
17-
const lines = el => [...new Set($(el).value.split("\n").map(i => i.trim()).filter(Boolean))]
17+
const lines = el => [...new Set($(el).value
18+
.split("\n")
19+
.map(i => i.trim())
20+
.filter(Boolean)
21+
)]
1822
const out = i => $("status").textContent += `${i}\n`
1923

20-
function request(url, message) {
21-
return new Promise(resolve => {
22-
const ws = new WebSocket(url), result = []
23-
const timer = setTimeout(() => {
24-
ws.close()
25-
resolve(result)
26-
}, TIMEOUT)
27-
ws.onopen = () => ws.send(JSON.stringify(message))
28-
ws.onmessage = e => {
29-
const message = JSON.parse(e.data)
30-
if (message[0] === "EVENT") result.push(message[2])
31-
if (message[0] === "EOSE") {
32-
clearTimeout(timer)
33-
ws.close()
34-
resolve(result)
24+
const connections = new Map()
25+
26+
function connect(url) {
27+
const existing = connections.get(url)
28+
29+
if (existing?.ws?.readyState === WebSocket.OPEN) {
30+
return Promise.resolve(existing)
31+
}
32+
33+
if (existing?.connecting) {
34+
return existing.connecting
35+
}
36+
37+
const state = {
38+
ws: null,
39+
connecting: null,
40+
requests: new Map(),
41+
events: new Map()
42+
}
43+
44+
state.connecting = new Promise((resolve, reject) => {
45+
const ws = new WebSocket(url)
46+
state.ws = ws
47+
48+
const fail = error => {
49+
for (const request of state.requests.values()) {
50+
clearTimeout(request.timer)
51+
request.resolve([])
52+
}
53+
54+
for (const request of state.events.values()) {
55+
clearTimeout(request.timer)
56+
request.resolve(false)
57+
}
58+
59+
state.requests.clear()
60+
state.events.clear()
61+
62+
if (connections.get(url) === state) {
63+
connections.delete(url)
3564
}
65+
66+
state.connecting = null
67+
reject(error)
68+
}
69+
70+
ws.onopen = () => {
71+
state.connecting = null
72+
resolve(state)
3673
}
37-
ws.onerror = () => {
38-
clearTimeout(timer)
39-
ws.close()
40-
resolve(result)
74+
75+
ws.onmessage = e => {
76+
let message
77+
78+
try {
79+
message = JSON.parse(e.data)
80+
} catch {
81+
return
82+
}
83+
84+
const type = message[0]
85+
86+
if (type === "EVENT") {
87+
const subscriptionId = message[1]
88+
const request = state.requests.get(subscriptionId)
89+
90+
if (request) {
91+
request.result.push(message[2])
92+
}
93+
94+
return
95+
}
96+
97+
if (type === "EOSE") {
98+
const subscriptionId = message[1]
99+
const request = state.requests.get(subscriptionId)
100+
101+
if (!request) return
102+
103+
clearTimeout(request.timer)
104+
state.requests.delete(subscriptionId)
105+
request.resolve(request.result)
106+
107+
ws.send(JSON.stringify(["CLOSE", subscriptionId]))
108+
return
109+
}
110+
111+
if (type === "OK") {
112+
const eventId = message[1]
113+
const request = state.events.get(eventId)
114+
115+
if (!request) return
116+
117+
clearTimeout(request.timer)
118+
state.events.delete(eventId)
119+
request.resolve(Boolean(message[2]))
120+
}
41121
}
122+
123+
ws.onerror = fail
124+
ws.onclose = () => fail(new Error("Relay connection closed"))
42125
})
126+
127+
connections.set(url, state)
128+
return state.connecting
43129
}
44130

45-
function send(url, event) {
131+
async function request(url, filters) {
132+
const connection = await connect(url)
133+
const { ws } = connection
134+
const subscriptionId = crypto.randomUUID()
135+
46136
return new Promise(resolve => {
47-
const ws = new WebSocket(url)
48137
const timer = setTimeout(() => {
49-
ws.close()
50-
resolve(false)
138+
connection.requests.delete(subscriptionId)
139+
resolve([])
51140
}, TIMEOUT)
52-
ws.onopen = () => ws.send(JSON.stringify(["EVENT", event]))
53-
ws.onmessage = e => {
54-
const message = JSON.parse(e.data)
55-
if (message[0] === "OK") {
56-
clearTimeout(timer)
57-
ws.close()
58-
resolve(message[2])
59-
}
60-
}
61-
ws.onerror = () => {
62-
clearTimeout(timer)
63-
ws.close()
141+
142+
connection.requests.set(subscriptionId, {
143+
timer,
144+
result: [],
145+
resolve
146+
})
147+
148+
ws.send(JSON.stringify([
149+
"REQ",
150+
subscriptionId,
151+
...filters
152+
]))
153+
})
154+
}
155+
156+
async function send(url, event) {
157+
const connection = await connect(url)
158+
const { ws } = connection
159+
160+
return new Promise(resolve => {
161+
const timer = setTimeout(() => {
162+
connection.events.delete(event.id)
64163
resolve(false)
65-
}
164+
}, TIMEOUT)
165+
166+
connection.events.set(event.id, {
167+
timer,
168+
resolve
169+
})
170+
171+
ws.send(JSON.stringify(["EVENT", event]))
66172
})
67173
}
68174

69175
function values(event, key) {
70-
return event.tags.filter(i => i[0] === key && i[1]).map(i => i[1])
176+
return event.tags
177+
.filter(tag => tag[0] === key && tag[1])
178+
.map(tag => tag[1])
71179
}
72180

73181
async function existing(relays, pubkey, kind, tags) {
74-
const wanted = new Set(tags.map(i => i[1]))
182+
const wanted = new Set(tags.map(tag => tag[1]))
183+
const key = tags[0][0]
184+
75185
for (const relay of relays) {
76-
const events = await request(relay, [
77-
"REQ", crypto.randomUUID(),
78-
{ authors: [pubkey], kinds: [kind], limit: 100 }
79-
])
186+
const events = await request(relay, [{
187+
authors: [pubkey],
188+
kinds: [kind],
189+
limit: 100
190+
}])
191+
80192
for (const event of events) {
81-
const got = values(event, tags[0][0])
193+
const got = values(event, key)
194+
82195
if (got.length === wanted.size && got.every(i => wanted.has(i))) {
83196
return event
84197
}
85198
}
86199
}
200+
201+
return null
87202
}
88203

89204
async function publish(kind, key, relays, profileRelays, pubkey) {
@@ -97,18 +212,24 @@
97212
tags,
98213
content: ""
99214
})
215+
100216
out(`Signed new event kind ${kind}`)
101217
} else {
102218
out(`Reusing existing event kind ${kind}`)
103219
}
104220

105-
const results = await Promise.allSettled(profileRelays.map(relay => send(relay, event)))
106-
out(`Event kind ${kind}: ${results.filter(Boolean).length}/${profileRelays.length} relays accepted`)
221+
const results = await Promise.all(
222+
profileRelays.map(relay => send(relay, event))
223+
)
224+
225+
const accepted = results.filter(Boolean).length
226+
227+
out(`Event kind ${kind}: ${accepted}/${profileRelays.length} relays accepted`)
107228
}
108229

109230
document.addEventListener("DOMContentLoaded", () => {
110231
$("publish").onclick = async () => {
111-
$("status").textContent = ""
232+
$("status").textContent = "Wait for success...\n"
112233
$("publish").disabled = true
113234

114235
const content = lines("content")
@@ -117,32 +238,37 @@
117238

118239
if (!content.length || !dm.length || !profile.length) {
119240
out("Fill all inputs")
241+
$("publish").disabled = false
120242
return
121243
}
122244

123245
try {
124246
const pubkey = await window.nostr.getPublicKey()
247+
125248
await publish(10002, "r", content, profile, pubkey)
126249
await publish(10050, "relay", dm, profile, pubkey)
127250
await publish(10051, "relay", keypackage, profile, pubkey)
128251
await publish(10063, "server", blossom, profile, pubkey)
129-
out(`https://nostria.app/p/${pubkey} is now ready to use 🎉`)
252+
253+
out(`🎉 Success! https://nostria.app/p/${pubkey} is now ready to use`)
130254
} catch (e) {
131255
out(e.message || String(e))
256+
} finally {
257+
$("publish").disabled = false
132258
}
133259
}
134260

135-
const params = new URLSearchParams(window.location.hash.split("#")[1])
136-
const append = params.get("append") !== "0"
137-
params.delete("append")
138-
for (const [k, v] of params.entries()) {
139-
let value = $(k).value
140-
if (!append) {
141-
value = ""
142-
}
143-
const items = [...new Set([...value.split("\n"), ...v.split(",")])]
144-
$(k).value = items.join("\n").trim()
145-
}
261+
const params = new URLSearchParams(window.location.hash.split("#")[1])
262+
const append = params.get("append") !== "0"
263+
params.delete("append")
264+
for (const [k, v] of params.entries()) {
265+
let value = $(k).value
266+
if (!append) {
267+
value = ""
268+
}
269+
const items = [...new Set([...value.split("\n"), ...v.split(",")])]
270+
$(k).value = items.join("\n").trim()
271+
}
146272

147273
const example = new URL(window.location.href)
148274
example.hash = "#content=wss://theforest.nostr1.com,wss://relay.primal.net&blossom=https://blossom.primal.net&append=0"
@@ -158,7 +284,7 @@
158284
console.log(e.message || String(e))
159285
}
160286
}
161-
}, 500)
287+
}, 300)
162288
})
163289
</script>
164290
</head>

0 commit comments

Comments
 (0)