mirror of
https://github.com/coracle-social/coracle.git
synced 2024-09-18 19:23:40 +00:00
Disconnect after connecting user, shorted retry timeout for connections
This commit is contained in:
parent
96d8f148c2
commit
eed863143d
@ -1,18 +1,18 @@
|
||||
import {nip04, getPublicKey, getEventHash, signEvent} from 'nostr-tools'
|
||||
import {get} from 'svelte/store'
|
||||
import {error} from 'src/util/logger'
|
||||
import {synced} from 'src/util/misc'
|
||||
import {nip04, getPublicKey, getEventHash, signEvent} from "nostr-tools"
|
||||
import {get} from "svelte/store"
|
||||
import {error} from "src/util/logger"
|
||||
import {synced} from "src/util/misc"
|
||||
|
||||
const method = synced('agent/keys/method')
|
||||
const pubkey = synced('agent/keys/pubkey')
|
||||
const privkey = synced('agent/keys/privkey')
|
||||
const method = synced("agent/keys/method")
|
||||
const pubkey = synced("agent/keys/pubkey")
|
||||
const privkey = synced("agent/keys/privkey")
|
||||
const getExtension = () => (window as {nostr?: any}).nostr
|
||||
const canSign = () => ['privkey', 'extension'].includes(get(method))
|
||||
const canSign = () => ["privkey", "extension"].includes(get(method))
|
||||
|
||||
const login = ($method, key) => {
|
||||
method.set($method)
|
||||
|
||||
if ($method === 'privkey') {
|
||||
if ($method === "privkey") {
|
||||
privkey.set(key)
|
||||
pubkey.set(getPublicKey(key))
|
||||
} else {
|
||||
@ -33,13 +33,13 @@ const sign = event => {
|
||||
event.pubkey = get(pubkey)
|
||||
event.id = getEventHash(event)
|
||||
|
||||
if ($method === 'privkey') {
|
||||
if ($method === "privkey") {
|
||||
return Object.assign(event, {
|
||||
sig: signEvent(event, get(privkey)),
|
||||
})
|
||||
}
|
||||
|
||||
if ($method === 'extension') {
|
||||
if ($method === "extension") {
|
||||
return getExtension().signEvent(event)
|
||||
}
|
||||
|
||||
@ -49,7 +49,7 @@ const sign = event => {
|
||||
const getCrypt = () => {
|
||||
const $method = get(method)
|
||||
|
||||
if ($method === 'privkey') {
|
||||
if ($method === "privkey") {
|
||||
const $privkey = get(privkey)
|
||||
|
||||
return {
|
||||
@ -66,7 +66,7 @@ const getCrypt = () => {
|
||||
}
|
||||
}
|
||||
|
||||
if ($method === 'extension') {
|
||||
if ($method === "extension") {
|
||||
return {
|
||||
encrypt: (pubkey, message) => getExtension().nip04.encrypt(pubkey, message),
|
||||
decrypt: async (pubkey, message) => {
|
||||
@ -81,9 +81,16 @@ const getCrypt = () => {
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error('No encryption method available.')
|
||||
throw new Error("No encryption method available.")
|
||||
}
|
||||
|
||||
export default {
|
||||
pubkey, privkey, canSign, login, clear, sign, getCrypt,
|
||||
method,
|
||||
pubkey,
|
||||
privkey,
|
||||
canSign,
|
||||
login,
|
||||
clear,
|
||||
sign,
|
||||
getCrypt,
|
||||
}
|
||||
|
@ -1,22 +1,22 @@
|
||||
import type {Relay, Filter} from 'nostr-tools'
|
||||
import type {MyEvent} from 'src/util/types'
|
||||
import {relayInit} from 'nostr-tools'
|
||||
import {pluck, is} from 'ramda'
|
||||
import {ensurePlural} from 'hurdak/lib/hurdak'
|
||||
import {warn, log, error} from 'src/util/logger'
|
||||
import {union, difference} from 'src/util/misc'
|
||||
import {isRelay, normalizeRelayUrl} from 'src/util/nostr'
|
||||
import type {Relay, Filter} from "nostr-tools"
|
||||
import type {MyEvent} from "src/util/types"
|
||||
import {relayInit} from "nostr-tools"
|
||||
import {pluck, is} from "ramda"
|
||||
import {ensurePlural} from "hurdak/lib/hurdak"
|
||||
import {warn, log, error} from "src/util/logger"
|
||||
import {union, difference} from "src/util/misc"
|
||||
import {isRelay, normalizeRelayUrl} from "src/util/nostr"
|
||||
|
||||
// Connection management
|
||||
|
||||
const connections = {}
|
||||
|
||||
const CONNECTION_STATUS = {
|
||||
NEW: 'new',
|
||||
ERROR: 'error',
|
||||
PENDING: 'pending',
|
||||
CLOSED: 'closed',
|
||||
READY: 'ready',
|
||||
NEW: "new",
|
||||
ERROR: "error",
|
||||
PENDING: "pending",
|
||||
CLOSED: "closed",
|
||||
READY: "ready",
|
||||
}
|
||||
|
||||
class Connection {
|
||||
@ -28,7 +28,7 @@ class Connection {
|
||||
constructor(url) {
|
||||
this.promise = null
|
||||
this.nostr = relayInit(url)
|
||||
this.status = 'new'
|
||||
this.status = "new"
|
||||
this.stats = {
|
||||
timeouts: 0,
|
||||
subsCount: 0,
|
||||
@ -42,32 +42,27 @@ class Connection {
|
||||
}
|
||||
hasRecentError() {
|
||||
return (
|
||||
this.status === CONNECTION_STATUS.ERROR
|
||||
&& Date.now() - this.lastConnectionAttempt < 60_000
|
||||
this.status === CONNECTION_STATUS.ERROR && Date.now() - this.lastConnectionAttempt < 10_000
|
||||
)
|
||||
}
|
||||
async connect() {
|
||||
const shouldConnect = (
|
||||
this.status === CONNECTION_STATUS.NEW
|
||||
|| (
|
||||
this.status === CONNECTION_STATUS.ERROR
|
||||
&& Date.now() - this.lastConnectionAttempt > 60_000
|
||||
)
|
||||
)
|
||||
const shouldConnect =
|
||||
this.status === CONNECTION_STATUS.NEW ||
|
||||
(this.status === CONNECTION_STATUS.ERROR && Date.now() - this.lastConnectionAttempt > 10_000)
|
||||
|
||||
if (shouldConnect) {
|
||||
this.status = CONNECTION_STATUS.PENDING
|
||||
this.promise = this.nostr.connect()
|
||||
|
||||
this.nostr.on('connect', () => {
|
||||
this.nostr.on("connect", () => {
|
||||
this.status = CONNECTION_STATUS.READY
|
||||
})
|
||||
|
||||
this.nostr.on('error', () => {
|
||||
this.nostr.on("error", () => {
|
||||
this.status = CONNECTION_STATUS.ERROR
|
||||
})
|
||||
|
||||
this.nostr.on('disconnect', () => {
|
||||
this.nostr.on("disconnect", () => {
|
||||
this.status = CONNECTION_STATUS.CLOSED
|
||||
})
|
||||
}
|
||||
@ -82,6 +77,11 @@ class Connection {
|
||||
|
||||
return this
|
||||
}
|
||||
disconnect() {
|
||||
this.nostr.close()
|
||||
|
||||
delete connections[this.nostr.url]
|
||||
}
|
||||
getQuality() {
|
||||
if (this.status === CONNECTION_STATUS.ERROR) {
|
||||
return [0, "Failed to connect"]
|
||||
@ -146,7 +146,7 @@ const publish = async ({relays, event, onProgress, timeout = 5000}) => {
|
||||
log(`Publishing to ${relays.length} relays`, event, relays)
|
||||
}
|
||||
|
||||
const urls = new Set(pluck('url', relays))
|
||||
const urls = new Set(pluck("url", relays))
|
||||
|
||||
if (urls.size !== relays.length) {
|
||||
warn(`Attempted to publish to non-unique relays`)
|
||||
@ -200,14 +200,14 @@ const publish = async ({relays, event, onProgress, timeout = 5000}) => {
|
||||
if (conn.status === CONNECTION_STATUS.READY) {
|
||||
const pub = conn.nostr.publish(event)
|
||||
|
||||
pub.on('ok', () => {
|
||||
pub.on("ok", () => {
|
||||
succeeded.add(relay.url)
|
||||
timeouts.delete(relay.url)
|
||||
failed.delete(relay.url)
|
||||
attemptToResolve()
|
||||
})
|
||||
|
||||
pub.on('failed', reason => {
|
||||
pub.on("failed", reason => {
|
||||
failed.add(relay.url)
|
||||
timeouts.delete(relay.url)
|
||||
attemptToResolve()
|
||||
@ -230,9 +230,7 @@ type SubscribeOpts = {
|
||||
onEose?: (url: string) => void
|
||||
}
|
||||
|
||||
const subscribe = async (
|
||||
{relays, filter, onEvent, onEose, onError}: SubscribeOpts
|
||||
) => {
|
||||
const subscribe = async ({relays, filter, onEvent, onEose, onError}: SubscribeOpts) => {
|
||||
filter = ensurePlural(filter)
|
||||
|
||||
const id = createFilterId(filter)
|
||||
@ -248,14 +246,14 @@ const subscribe = async (
|
||||
log(`Starting subscription ${id} with ${relays.length} relays`, filter, relays)
|
||||
}
|
||||
|
||||
if (relays.length !== new Set(pluck('url', relays)).size) {
|
||||
if (relays.length !== new Set(pluck("url", relays)).size) {
|
||||
error(`Subscribed to non-unique relays`, relays)
|
||||
}
|
||||
|
||||
const promises = relays.map(async relay => {
|
||||
const conn = await connect(relay.url)
|
||||
|
||||
if (conn.status !== 'ready') {
|
||||
if (conn.status !== "ready") {
|
||||
if (onError) {
|
||||
onError(relay.url)
|
||||
}
|
||||
@ -265,21 +263,21 @@ const subscribe = async (
|
||||
|
||||
const sub = conn.nostr.sub(filter, {
|
||||
id,
|
||||
alreadyHaveEvent: (id) => {
|
||||
alreadyHaveEvent: id => {
|
||||
conn.stats.eventsCount += 1
|
||||
let has = false
|
||||
if (seen.has(id)) has = true
|
||||
seen.add(id)
|
||||
return has
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
sub.on('event', e => {
|
||||
// Normalize events here, annotate with relay url
|
||||
onEvent({...e, seen_on: relay.url, content: e.content || ''})
|
||||
sub.on("event", e => {
|
||||
// Normalize events here, annotate with relay url
|
||||
onEvent({...e, seen_on: relay.url, content: e.content || ""})
|
||||
})
|
||||
|
||||
sub.on('eose', () => {
|
||||
sub.on("eose", () => {
|
||||
if (onEose) {
|
||||
onEose(conn.nostr.url)
|
||||
}
|
||||
@ -329,12 +327,12 @@ const subscribe = async (
|
||||
// Utils
|
||||
|
||||
const createFilterId = filters =>
|
||||
[Math.random().toString().slice(2, 6), filters.map(describeFilter).join(':')].join('-')
|
||||
[Math.random().toString().slice(2, 6), filters.map(describeFilter).join(":")].join("-")
|
||||
|
||||
const describeFilter = ({kinds = [], ...filter}) => {
|
||||
const parts = []
|
||||
|
||||
parts.push(kinds.join(','))
|
||||
parts.push(kinds.join(","))
|
||||
|
||||
for (const [key, value] of Object.entries(filter)) {
|
||||
if (is(Array, value)) {
|
||||
@ -344,9 +342,13 @@ const describeFilter = ({kinds = [], ...filter}) => {
|
||||
}
|
||||
}
|
||||
|
||||
return '(' + parts.join(',') + ')'
|
||||
return "(" + parts.join(",") + ")"
|
||||
}
|
||||
|
||||
export default {
|
||||
getConnections, getConnection, connect, publish, subscribe,
|
||||
getConnections,
|
||||
getConnection,
|
||||
connect,
|
||||
publish,
|
||||
subscribe,
|
||||
}
|
||||
|
@ -165,11 +165,12 @@ const profileHandler = (key, getValue) => e => {
|
||||
return
|
||||
}
|
||||
|
||||
user.profile.update($p => ({
|
||||
...$p,
|
||||
[key]: getValue(e, $p),
|
||||
[updated_at_key]: e.created_at,
|
||||
}))
|
||||
user.profile.update($p => {
|
||||
const value = getValue(e, $p)
|
||||
|
||||
// If we didn't get a value, don't update the key
|
||||
return value ? {...$p, [key]: value, [updated_at_key]: e.created_at} : $p
|
||||
})
|
||||
}
|
||||
|
||||
addHandler(
|
||||
@ -180,21 +181,19 @@ addHandler(
|
||||
addHandler(
|
||||
3,
|
||||
profileHandler("relays", (e, p) => {
|
||||
return (
|
||||
tryJson(() => {
|
||||
return Object.entries(JSON.parse(e.content))
|
||||
.map(([url, conditions]) => {
|
||||
const {write, read} = conditions as Record<string, boolean | string>
|
||||
return tryJson(() => {
|
||||
return Object.entries(JSON.parse(e.content))
|
||||
.map(([url, conditions]) => {
|
||||
const {write, read} = conditions as Record<string, boolean | string>
|
||||
|
||||
return {
|
||||
url: normalizeRelayUrl(url),
|
||||
write: [false, "!"].includes(write) ? false : true,
|
||||
read: [false, "!"].includes(read) ? false : true,
|
||||
}
|
||||
})
|
||||
.filter(r => isRelay(r.url))
|
||||
}) || p.relays
|
||||
)
|
||||
return {
|
||||
url: normalizeRelayUrl(url),
|
||||
write: [false, "!"].includes(write) ? false : true,
|
||||
read: [false, "!"].includes(read) ? false : true,
|
||||
}
|
||||
})
|
||||
.filter(r => isRelay(r.url))
|
||||
})
|
||||
})
|
||||
)
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
import {watch} from "src/agent/storage"
|
||||
import network from "src/agent/network"
|
||||
import user from "src/agent/user"
|
||||
import pool from "src/agent/pool"
|
||||
import {loadAppData} from "src/app"
|
||||
import {toast} from "src/app/ui"
|
||||
|
||||
@ -65,6 +66,8 @@
|
||||
await Promise.all([loadAppData(user.getPubkey()), sleep(3000)])
|
||||
|
||||
navigate("/notes/follows")
|
||||
} else {
|
||||
pool.getConnection(relay.url).disconnect()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user