adapt to new nip-01, change "attempt" notification logic.

This commit is contained in:
fiatjaf
2021-02-15 00:15:24 -03:00
parent d355bbead4
commit c03f8d1c56
3 changed files with 66 additions and 89 deletions

View File

@@ -1,6 +1,6 @@
{ {
"name": "nostr-tools", "name": "nostr-tools",
"version": "0.3.2", "version": "0.4.0",
"description": "Tools for making a Nostr client.", "description": "Tools for making a Nostr client.",
"main": "index.js", "main": "index.js",
"repository": { "repository": {
@@ -10,6 +10,7 @@
"dependencies": { "dependencies": {
"buffer": "^6.0.3", "buffer": "^6.0.3",
"noble-secp256k1": "^1.1.1", "noble-secp256k1": "^1.1.1",
"ramda": "^0.27.1",
"websocket-polyfill": "^0.0.3" "websocket-polyfill": "^0.0.3"
}, },
"keywords": [ "keywords": [
@@ -23,14 +24,5 @@
"censorship", "censorship",
"censorship-resistance", "censorship-resistance",
"client" "client"
], ]
"devDependencies": {
"@babel/core": "^7.12.10",
"@babel/preset-env": "^7.12.11",
"@rollup/plugin-babel": "^5.2.2",
"@rollup/plugin-node-resolve": "^11.0.1",
"rollup": "^2.36.1",
"rollup-plugin-ignore": "^1.0.9",
"rollup-plugin-terser": "^7.0.2"
}
} }

84
pool.js
View File

@@ -1,10 +1,11 @@
import R from 'ramda'
import {getEventHash, signEvent} from './event' import {getEventHash, signEvent} from './event'
import {relayConnect, normalizeRelayURL} from './relay' import {relayConnect, normalizeRelayURL} from './relay'
export function relayPool(globalPrivateKey) { export function relayPool(globalPrivateKey) {
const relays = {} const relays = {}
const globalSub = [] const globalSub = []
const attemptCallbacks = []
const eventCallbacks = [] const eventCallbacks = []
const noticeCallbacks = [] const noticeCallbacks = []
@@ -20,21 +21,19 @@ export function relayPool(globalPrivateKey) {
noticeCallbacks[i](notice, relay) noticeCallbacks[i](notice, relay)
} }
} }
function propagateAttempt(eventId, status, relayURL) {
for (let i = 0; i < attemptCallbacks.length; i++) {
let {relay} = relays[relayURL]
attemptCallbacks[i](eventId, status, relay)
}
}
async function relaysEach(fn, policyFilter) { const sub = async (cb, params) => {
for (let relayURL in relays) { const subControllers = R.map(relay => {
let {relay, policy} = relays[relayURL] return relay.sub(params, cb.bind(null, relay))
if (policyFilter.write && policy.write) { }, R.filter(R.pipe(R.prop('policy'), R.prop('write'), R.equals(true)), relays))
await fn(relay)
} else if (policyFilter.read && policy.read) { return {
await fn(relay) sub: (cb, params) =>
} R.map(
R.pipe(R.prop('sub'), R.flip(R.apply)([cb, params])),
subControllers
),
unsub: () => R.map(R.pipe(R.prop('unsub'), R.call), subControllers)
} }
} }
@@ -72,9 +71,6 @@ export function relayPool(globalPrivateKey) {
relay.close() relay.close()
delete relays[relayURL] delete relays[relayURL]
}, },
onEvent(cb) {
eventCallbacks.push(cb)
},
offEvent(cb) { offEvent(cb) {
let index = eventCallbacks.indexOf(cb) let index = eventCallbacks.indexOf(cb)
if (index !== -1) eventCallbacks.splice(index, 1) if (index !== -1) eventCallbacks.splice(index, 1)
@@ -86,14 +82,7 @@ export function relayPool(globalPrivateKey) {
let index = noticeCallbacks.indexOf(cb) let index = noticeCallbacks.indexOf(cb)
if (index !== -1) noticeCallbacks.splice(index, 1) if (index !== -1) noticeCallbacks.splice(index, 1)
}, },
onAttempt(cb) { async publish(event, statusCallback) {
attemptCallbacks.push(cb)
},
offAttempt(cb) {
let index = attemptCallbacks.indexOf(cb)
if (index !== -1) attemptCallbacks.splice(index, 1)
},
async publish(event) {
if (!event.sig) { if (!event.sig) {
event.tags = event.tags || [] event.tags = event.tags || []
@@ -107,36 +96,23 @@ export function relayPool(globalPrivateKey) {
} }
} }
await relaysEach( await R.map(async relay => {
async relay => { try {
try { await relay.publish(event)
await relay.publish(event) statusCallback(0, relay.url)
propagateAttempt(event.id, 'sent', relay.url) let {unsub} = relay.sub(
} catch (err) { () => {
propagateAttempt(event.id, 'failed', relay.url) statusCallback(1, relay.url)
} },
}, {id: event.id}
{write: true} )
) setTimeout(unsub, 5000)
} catch (err) {
statusCallback(-1, relay.url)
}
}, R.filter(R.pipe(R.prop('policy'), R.prop('write'), R.equals(true)), relays))
return event return event
},
async subKey(key) {
globalSub[key] = true
await relaysEach(async relay => relay.subKey(key), {read: true})
},
async unsubKey(key) {
delete globalSub[key]
await relaysEach(async relay => relay.unsubKey(key), {read: true})
},
async reqFeed(params = {}) {
await relaysEach(async relay => relay.reqFeed(params), {read: true})
},
async reqEvent(params) {
await relaysEach(async relay => relay.reqEvent(params), {read: true})
},
async reqKey(params) {
await relaysEach(async relay => relay.reqKey(params), {read: true})
} }
} }
} }

View File

@@ -1,6 +1,8 @@
import 'websocket-polyfill' import 'websocket-polyfill'
import R from 'ramda'
import {verifySignature} from './event' import {verifySignature} from './event'
import {sha256} from './utils'
export function normalizeRelayURL(url) { export function normalizeRelayURL(url) {
let [host, ...qs] = url.split('?') let [host, ...qs] = url.split('?')
@@ -10,10 +12,10 @@ export function normalizeRelayURL(url) {
return [host, ...qs].join('?') return [host, ...qs].join('?')
} }
export function relayConnect(url, onEvent, onNotice) { export function relayConnect(url, onNotice) {
url = normalizeRelayURL(url) url = normalizeRelayURL(url)
let ws, resolveOpen, untilOpen, rejectOpen var ws, resolveOpen, untilOpen, rejectOpen
let attemptNumber = 1 let attemptNumber = 1
function resetOpenState() { function resetOpenState() {
@@ -23,6 +25,8 @@ export function relayConnect(url, onEvent, onNotice) {
}) })
} }
var channels = {}
function connect() { function connect() {
ws = new WebSocket( ws = new WebSocket(
url + (url.indexOf('?') !== -1 ? '&' : '?') + `session=${Math.random()}` url + (url.indexOf('?') !== -1 ? '&' : '?') + `session=${Math.random()}`
@@ -63,23 +67,29 @@ export function relayConnect(url, onEvent, onNotice) {
return return
} }
if (data[0] === 'notice') { if (data[0] === 'NOTICE') {
if (data.length < 2) return
console.log('message from relay ' + url + ': ' + data[1]) console.log('message from relay ' + url + ': ' + data[1])
onNotice(data[1]) onNotice(data[1])
return return
} }
if (typeof data[0] === 'object') { if (data[0] === 'EVENT') {
let event = data[0] if (data.length < 3) return
let context = data[1]
let channel = data[1]
let event = data[2]
if (await verifySignature(event)) { if (await verifySignature(event)) {
onEvent(event, context) if (channels[channel]) {
channels[channel](event)
}
} else { } else {
console.warn( console.warn(
'got event with invalid signature from ' + url, 'got event with invalid signature from ' + url,
event, event,
context id
) )
} }
return return
@@ -94,7 +104,9 @@ export function relayConnect(url, onEvent, onNotice) {
connect() connect()
} catch (err) {} } catch (err) {}
async function trySend(msg) { async function trySend(params) {
let msg = JSON.stringify(params)
if (ws && ws.readyState === WebSocket.OPEN) { if (ws && ws.readyState === WebSocket.OPEN) {
ws.send(msg) ws.send(msg)
} else { } else {
@@ -107,23 +119,20 @@ export function relayConnect(url, onEvent, onNotice) {
} }
} }
const sub = async (channel, cb, params) => {
trySend(['REQ', channel, params])
channels[channel] = cb
return {
sub: R.partial(sub, [channel]),
unsub: () => trySend(['CLOSE', channel])
}
}
return { return {
url, url,
async subKey(key) { sub: R.partial(sub, [sha256(Math.random().toString())]),
trySend('sub-key:' + key)
},
async unsubKey(key) {
trySend('unsub-key:' + key)
},
async reqFeed(params = {}) {
trySend('req-feed:' + JSON.stringify(params))
},
async reqEvent(params) {
trySend('req-event:' + JSON.stringify(params))
},
async reqKey(params) {
trySend('req-key:' + JSON.stringify(params))
},
async publish(event) { async publish(event) {
trySend(JSON.stringify(event)) trySend(JSON.stringify(event))
}, },