Re-work relay selection

This commit is contained in:
Jonathan Staab 2023-02-09 17:57:37 -06:00
parent 0fe2afb3a8
commit 5f1f9f9b69
24 changed files with 177 additions and 167 deletions

View File

@ -30,6 +30,7 @@ If you like Coracle and want to support its development, you can donate sats via
- [ ] Attachments (a tag w/content type and url)
- [ ] Linkify bech32 entities w/ NIP 21 https://github.com/nostr-protocol/nips/blob/master/21.md
- [ ] Sign in as user with one click to view things from their pubkey's perspective - do this with multiple accounts
- [ ] QR code generation/scanner to share nprofile https://cdn.jb55.com/s/d966a729777c2021.MP4
# Missions
@ -73,6 +74,7 @@ If you like Coracle and want to support its development, you can donate sats via
- [ ] Implement gossip model https://bountsr.org/code/2023/02/03/gossip-model.html
- [ ] Add nip 05 to calculation
- [ ] Add connection failures to calculation
- [ ] Make feeds page customizable. This could potentially use the "lists" NIP
- [ ] Show notification at top of feeds: "Showing notes from 3 relays". Click to customize.
- [ ] Click through on relays page to view a feed for only that relay.

View File

@ -13,7 +13,7 @@
import {displayPerson, isLike} from 'src/util/nostr'
import {timedelta, shuffle, now, sleep} from 'src/util/misc'
import cmd from 'src/agent/cmd'
import {user, getRelays} from 'src/agent/helpers'
import {user, getUserRelays} from 'src/agent/helpers'
import database from 'src/agent/database'
import keys from 'src/agent/keys'
import network from 'src/agent/network'
@ -65,6 +65,7 @@
menuIsOpen.set(false)
}
const {ready} = database
const {lastCheckedAlerts, mostRecentAlert} = alerts
const {lastCheckedByPubkey, mostRecentByPubkey} = messages
@ -97,7 +98,7 @@
const alertSlowConnections = () => {
// Only notify about relays the user is actually subscribed to
const relayUrls = pluck('url', getRelays())
const relayUrls = pluck('url', getUserRelays('read'))
// Prune connections we haven't used in a while
pool.getConnections()
@ -201,6 +202,7 @@
<Router {url}>
<div use:links class="h-full">
{#if $ready}
<div class="pt-16 text-white h-full lg:ml-56">
<Route path="/alerts" component={Alerts} />
<Route path="/search/:activeTab" component={Search} />
@ -234,6 +236,7 @@
</Route>
<Route path="*" component={NotFound} />
</div>
{/if}
<ul
class="py-20 w-56 bg-dark fixed top-0 bottom-0 left-0 transition-all shadow-xl

View File

@ -1,8 +1,8 @@
import {prop, pick, join, uniqBy, last} from 'ramda'
import {get} from 'svelte/store'
import {first} from "hurdak/lib/hurdak"
import {Tags, isRelay, roomAttrs, displayPerson} from 'src/util/nostr'
import {getWriteRelays} from 'src/agent/helpers'
import {roomAttrs, displayPerson} from 'src/util/nostr'
import {getBestRelay} from 'src/agent/helpers'
import database from 'src/agent/database'
import network from 'src/agent/network'
import keys from 'src/agent/keys'
@ -29,15 +29,14 @@ const createChatMessage = (relays, roomId, content) =>
publishEvent(relays, 42, {content, tags: [["e", roomId, prop('url', first(relays)), "root"]]})
const createDirectMessage = (relays, pubkey, content) =>
// todo, encrypt messages
publishEvent(relays, 4, {content, tags: [["p", pubkey]]})
const createNote = (relays, content, mentions = [], topics = []) => {
mentions = mentions.map(p => {
const {url} = first(getWriteRelays(p))
const name = displayPerson(database.getPersonWithFallback(p))
mentions = mentions.map(pubkey => {
const name = displayPerson(database.getPersonWithFallback(pubkey))
const {url} = getBestRelay(pubkey, 'write')
return ["p", p, url, name]
return ["p", pubkey, url, name]
})
topics = topics.map(t => ["t", t])
@ -46,7 +45,7 @@ const createNote = (relays, content, mentions = [], topics = []) => {
}
const createReaction = (relays, note, content) => {
const {url} = getBestRelay(relays, note)
const {url} = getBestRelay(note.pubkey, 'write')
const tags = uniqBy(
join(':'),
note.tags
@ -59,10 +58,10 @@ const createReaction = (relays, note, content) => {
}
const createReply = (relays, note, content, mentions = [], topics = []) => {
mentions = mentions.map(p => ["p", p, prop('url', first(getWriteRelays(p)))])
mentions = mentions.map(pubkey => ["p", pubkey, prop('url', getBestRelay(pubkey))])
topics = topics.map(t => ["t", t])
const {url} = getBestRelay(relays, note)
const {url} = getBestRelay(note.pubkey, 'write')
const tags = uniqBy(
join(':'),
note.tags
@ -80,24 +79,6 @@ const deleteEvent = (relays, ids) =>
// Utils
const getBestRelay = (relays, event) => {
// Find the best relay, based on reply, root, or pubkey. Fall back to a
// relay we're going to send the event to
const tags = Tags.from(event).type("e")
const reply = tags.mark("reply").values().first()
const root = tags.mark("root").values().first()
if (isRelay(reply)) {
return reply
}
if (isRelay(root)) {
return root
}
return first(getWriteRelays(event.pubkey).concat(relays))
}
const publishEvent = (relays, kind, {content = '', tags = []} = {}) => {
if (relays.length === 0) {
throw new Error("Unable to publish, no relays specified")

View File

@ -1,8 +1,8 @@
import {debounce} from 'throttle-debounce'
import {is, prop, without} from 'ramda'
import {writable} from 'svelte/store'
import {switcherFn, createMap, ensurePlural, first} from 'hurdak/lib/hurdak'
import {defer, asyncIterableToArray} from 'src/util/misc'
import {is, prop, find, without, pluck, all, identity} from 'ramda'
import {writable, derived} from 'svelte/store'
import {switcherFn, createMap, ensurePlural} from 'hurdak/lib/hurdak'
import {defer, where, asyncIterableToArray} from 'src/util/misc'
// Types
@ -18,8 +18,9 @@ type Table = {
patch: (data: object) => void
bulkPut: (data: object) => void
bulkPatch: (data: object) => void
all: (where?: object) => Promise<any>
get: (key: string) => any
iter: (spec?: object) => Promise<Array<Record<string, any>>>
all: (spec?: object) => Array<Record<string, any>>
get: (key: string) => Record<string, any>
}
// Plumbing
@ -142,6 +143,8 @@ const defineTable = (name: string, pk: string): Table => {
let listeners = []
let data = {}
const ready = writable(false)
const subscribe = f => {
listeners.push(f)
@ -196,8 +199,10 @@ const defineTable = (name: string, pk: string): Table => {
const put = item => bulkPut(createMap(pk, [item]))
const patch = item => bulkPatch(createMap(pk, [item]))
const all = (where = {}) => asyncIterableToArray(iterate(name, where), prop('v'))
const one = (where = {}) => first(all(where))
const toArray = () => Object.values(data)
const iter = (spec = {}) => asyncIterableToArray(iterate(name, spec), prop('v'))
const all = (spec = {}) => toArray().filter(where(spec))
const one = (spec = {}) => find(where(spec), toArray())
const get = k => data[k]
// Sync from storage initially
@ -208,9 +213,13 @@ const defineTable = (name: string, pk: string): Table => {
}
setAndNotify(initialData)
ready.set(true)
})()
registry[name] = {name, subscribe, bulkPut, bulkPatch, put, patch, all, one, get}
registry[name] = {
name, subscribe, bulkPut, bulkPatch, put, patch, toArray, iter, all, one, get,
ready,
}
return registry[name]
}
@ -277,8 +286,10 @@ const getPersonWithFallback = pubkey => people.get(pubkey) || {pubkey}
const clearAll = () => Promise.all(Object.keys(registry).map(clear))
const ready = derived(pluck('ready', Object.values(registry)), all(identity))
export default {
getItem, setItem, removeItem, length, clear, keys, iterate, watch,
getPersonWithFallback, clearAll, people, rooms, messages, alerts, relays,
routes,
routes, ready,
}

View File

@ -1,6 +1,7 @@
import type {Person} from 'src/util/types'
import type {Readable} from 'svelte/store'
import {uniq, reject, last, propEq, uniqBy, prop} from 'ramda'
import {isEmpty, pick, identity, sortBy, uniq, reject, groupBy, last, propEq, uniqBy, prop} from 'ramda'
import {first} from 'hurdak/lib/hurdak'
import {derived, get} from 'svelte/store'
import {Tags} from 'src/util/nostr'
import {now, timedelta} from 'src/util/misc'
@ -37,27 +38,33 @@ export const getFollows = pubkey => {
return Tags.wrap(person.petnames || defaults.petnames).values().all()
}
export const getRelays = (pubkey?: string) => {
let relays = database.getPersonWithFallback(pubkey).relays
export const getPersonRelays = (person, mode = 'all') => {
const relays = isEmpty(person?.relays || []) ? defaults.relays : person.relays
if (!relays?.length) {
relays = database.getPersonWithFallback(get(keys.pubkey)).relays
}
if (!relays?.length) {
relays = defaults.relays
}
return relays
return reject(propEq(mode, '!'), relays)
}
export const getWriteRelays = (...args) =>
reject(propEq('write', '!'), getRelays(...args))
export const getUserRelays = (mode = 'all') =>
getPersonRelays(get(user), mode)
export const getPubkeyRelays = (pubkey, mode = 'all') =>
getPersonRelays(database.people.get(pubkey), mode)
export const getTopRelays = (pubkeys, mode = 'all') => {
const routes = database.routes.all({mode, pubkey: pubkeys})
const routesByPubkey = groupBy(prop('pubkey'), routes)
const selectRoute = k => first(sortBy(prop('score'), routesByPubkey[k] || []))
return uniqBy(prop('url'), pubkeys.map(selectRoute).filter(identity)).map(pick(['url']))
}
export const getBestRelay = (pubkey, mode = 'all') =>
first(getTopRelays([pubkey], mode).concat(getPubkeyRelays(pubkey, mode)))
export const getEventRelays = event => {
return uniqBy(
prop('url'),
getRelays(event.pubkey)
getPubkeyRelays(event.pubkey, 'write')
.concat(Tags.from(event).relays())
.concat({url: event.seen_on})
)

View File

@ -1,7 +1,7 @@
import lf from 'localforage'
import memoryStorageDriver from 'localforage-memoryStorageDriver'
import {is, complement, equals, isNil, pipe, prop, identity, allPass} from 'ramda'
import {switcherFn} from 'hurdak/lib/hurdak'
import {where} from 'src/util/misc'
// Firefox private mode doesn't have access to any storage options
lf.defineDriver(memoryStorageDriver)
@ -28,41 +28,9 @@ addEventListener('message', async ({data: {topic, payload, channel}}) => {
reply('localforage.return', result)
},
'localforage.iterate': async () => {
const {storeName, where} = payload
const matchesFilter = allPass(
Object.entries(where)
.map(([key, value]) => {
let [field, operator = 'eq'] = key.split(':')
let test, modifier = identity
const matchesFilter = where(payload.where)
if (operator.startsWith('!')) {
operator = operator.slice(1)
modifier = complement
}
if (operator === 'eq' && is(Array, value)) {
test = v => value.includes(v)
} else if (operator === 'eq') {
test = equals(value)
} else if (operator === 'lt') {
test = v => (v || 0) < value
} else if (operator === 'lte') {
test = v => (v || 0) <= value
} else if (operator === 'gt') {
test = v => (v || 0) > value
} else if (operator === 'gte') {
test = v => (v || 0) >= value
} else if (operator === 'nil') {
test = isNil
} else {
throw new Error(`Invalid operator ${operator}`)
}
return pipe(prop(field), modifier(test))
})
)
getStore(storeName).iterate(
getStore(payload.storeName).iterate(
(v, k, i) => {
if (matchesFilter(v)) {
reply('localforage.item', {v, k, i})

View File

@ -5,7 +5,7 @@ import {createMap, ellipsize} from 'hurdak/lib/hurdak'
import {get} from 'svelte/store'
import {renderContent} from 'src/util/html'
import {Tags, displayPerson, findReplyId} from 'src/util/nostr'
import {user, getRelays, getWriteRelays} from 'src/agent/helpers'
import {user, getUserRelays} from 'src/agent/helpers'
import defaults from 'src/agent/defaults'
import database from 'src/agent/database'
import network from 'src/agent/network'
@ -18,11 +18,13 @@ import {toast, routes, modal, settings, logUsage} from 'src/app/ui'
export {toast, modal, settings, alerts, messages, logUsage}
export const loadAppData = pubkey => {
const relays = getUserRelays('read')
return Promise.all([
network.loadNetwork(getRelays(), pubkey),
alerts.load(getRelays(), pubkey),
alerts.listen(getRelays(), pubkey),
messages.listen(getRelays(), pubkey),
network.loadNetwork(relays, pubkey),
alerts.load(relays, pubkey),
alerts.listen(relays, pubkey),
messages.listen(relays, pubkey),
])
}
@ -39,7 +41,7 @@ export const login = async ({privkey, pubkey}: {privkey?: string, pubkey?: strin
loadAppData(pubkey)
// Load our user so we can populate network and show profile info
await network.loadPeople(getRelays(), [pubkey])
await network.loadPeople(getUserRelays('read'), [pubkey])
// Not ideal, but the network tab depends on the user's social network being
// loaded, so put them on global when they first log in so we're not slowing
@ -73,7 +75,7 @@ export const removeRelay = async url => {
defaults.relays = modify(defaults.relays)
if (person) {
await cmd.setRelays(getWriteRelays(), modify(person.relays || []))
await cmd.setRelays(getUserRelays('write'), modify(person.relays || []))
}
}
@ -85,7 +87,7 @@ export const setRelayWriteCondition = async (url, write) => {
defaults.relays = modify(defaults.relays)
if (person) {
await cmd.setRelays(getWriteRelays(), modify(person.relays || []))
await cmd.setRelays(getUserRelays('write'), modify(person.relays || []))
}
}

View File

@ -16,7 +16,7 @@
let prevContent = ''
let search
database.people.all({'name:!nil': null}).then(people => {
database.people.iter({'name:!nil': null}).then(people => {
search = fuzzy(people, {keys: ["name", "pubkey"]})
})

View File

@ -4,7 +4,7 @@
import {nip19} from 'nostr-tools'
import {navigate} from "svelte-routing"
import {fuzzy} from "src/util/misc"
import {getRelays, user} from 'src/agent/helpers'
import {getUserRelays, getTopRelays, user} from 'src/agent/helpers'
import network from 'src/agent/network'
import database from 'src/agent/database'
import {modal, messages} from 'src/app'
@ -24,7 +24,7 @@
const messages = await database.messages.all()
const pubkeys = without([$user.pubkey], uniq(messages.flatMap(m => [m.pubkey, m.recipient])))
await network.loadPeople(getRelays(), pubkeys)
await network.loadPeople(getTopRelays(pubkeys, 'write'), pubkeys)
return sortBy(k => -(mostRecentByPubkey[k] || 0), pubkeys)
.map(k => ({type: 'npub', id: k, ...database.getPersonWithFallback(k)}))
@ -58,7 +58,7 @@
}
onMount(() => {
const sub = network.listen(getRelays(), [{kinds: [40, 41]}])
const sub = network.listen(getUserRelays('read'), [{kinds: [40, 41]}])
return () => {
sub.then(s => {

View File

@ -3,7 +3,7 @@
import {nip19} from 'nostr-tools'
import {now, batch} from 'src/util/misc'
import Channel from 'src/partials/Channel.svelte'
import {getRelays, user} from 'src/agent/helpers'
import {getEventRelays, user} from 'src/agent/helpers'
import database from 'src/agent/database'
import network from 'src/agent/network'
import {modal} from 'src/app'
@ -11,21 +11,11 @@
export let entity
let {data: roomId} = nip19.decode(entity) as {data: string}
let room = database.watch('rooms', rooms => rooms.get(roomId))
const getRoomRelays = () => {
let relays = getRelays()
if ($room) {
relays = relays.concat(getRelays($room.pubkey))
}
return relays
}
const {data: roomId} = nip19.decode(entity) as {data: string}
const room = database.watch('rooms', rooms => rooms.get(roomId))
const listenForMessages = async cb => {
const relays = getRoomRelays()
const relays = getEventRelays($room)
return network.listen(
relays,
@ -43,7 +33,7 @@
}
const loadMessages = async ({until, limit}) => {
const relays = getRoomRelays()
const relays = getEventRelays($room)
const events = await network.load(relays, {kinds: [42], '#e': [roomId], until, limit})
if (events.length) {
@ -58,7 +48,7 @@
}
const sendMessage = content =>
cmd.createChatMessage(getRoomRelays(), roomId, content)
cmd.createChatMessage(getEventRelays($room), roomId, content)
</script>
<Channel

View File

@ -4,7 +4,7 @@
import {personKinds} from 'src/util/nostr'
import {batch, now} from 'src/util/misc'
import Channel from 'src/partials/Channel.svelte'
import {getRelays, getWriteRelays, user} from 'src/agent/helpers'
import {getUserRelays, getPubkeyRelays, user} from 'src/agent/helpers'
import database from 'src/agent/database'
import network from 'src/agent/network'
import keys from 'src/agent/keys'
@ -20,6 +20,8 @@
messages.lastCheckedByPubkey.update($obj => ({...$obj, [pubkey]: now()}))
const getRelays = () => getUserRelays('write').concat(getPubkeyRelays(pubkey, 'write'))
const decryptMessages = async events => {
// Gotta do it in serial because of extension limitations
for (const event of events) {
@ -32,7 +34,7 @@
}
const listenForMessages = cb => network.listen(
getRelays().concat(getRelays(pubkey)),
getRelays(),
[{kinds: personKinds, authors: [pubkey]},
{kinds: [4], authors: [$user.pubkey], '#p': [pubkey]},
{kinds: [4], authors: [pubkey], '#p': [$user.pubkey]}],
@ -55,9 +57,8 @@
}
const sendMessage = async content => {
const relays = getWriteRelays().concat(getRelays(pubkey))
const cyphertext = await crypt.encrypt(pubkey, content)
const event = await cmd.createDirectMessage(relays, pubkey, cyphertext)
const event = await cmd.createDirectMessage(getRelays(), pubkey, cyphertext)
// Return unencrypted content so we can display it immediately
return {...event, content}

View File

@ -2,7 +2,6 @@
import {last, find, reject} from 'ramda'
import {onMount, onDestroy} from 'svelte'
import {nip19} from 'nostr-tools'
import {first} from 'hurdak/lib/hurdak'
import {fly} from 'svelte/transition'
import {navigate} from 'svelte-routing'
import {renderContent} from 'src/util/html'
@ -14,7 +13,7 @@
import Notes from "src/views/person/Notes.svelte"
import Likes from "src/views/person/Likes.svelte"
import Network from "src/views/person/Network.svelte"
import {getRelays, getWriteRelays, user} from "src/agent/helpers"
import {getPubkeyRelays, getUserRelays, user} from "src/agent/helpers"
import network from "src/agent/network"
import keys from "src/agent/keys"
import database from "src/agent/database"
@ -24,7 +23,7 @@
export let npub
export let activeTab
export let relays = null
export let relays = []
let subs = []
let pubkey = nip19.decode(npub).data as string
@ -37,22 +36,27 @@
$: following = find(t => t[1] === pubkey, $user?.petnames || [])
onMount(async () => {
// Add all the relays we know the person uses
relays = relays.concat(getPubkeyRelays(pubkey))
// Refresh our person if needed
network.loadPeople(relays || getRelays(pubkey), [pubkey]).then(() => {
network.loadPeople(relays, [pubkey]).then(() => {
person = database.getPersonWithFallback(pubkey)
loading = false
})
// Get our followers count
subs.push(await network.listen(
relays || getRelays(pubkey),
[{kinds: [3], '#p': [pubkey]}],
e => {
followers.add(e.pubkey)
followersCount = followers.size
},
{shouldProcess: false},
))
subs.push(
await network.listen(
relays,
[{kinds: [3], '#p': [pubkey]}],
e => {
followers.add(e.pubkey)
followersCount = followers.size
},
{shouldProcess: false},
)
)
})
onDestroy(() => {
@ -74,17 +78,16 @@
}
const follow = async () => {
const relay = first(relays || getRelays(pubkey))
const tag = ["p", pubkey, relay.url, person.name || ""]
const tag = ["p", pubkey, relays[0].url, person.name || ""]
const petnames = reject(t => t[1] === pubkey, $user.petnames).concat([tag])
cmd.setPetnames(getWriteRelays(), petnames)
cmd.setPetnames(getUserRelays('write'), petnames)
}
const unfollow = async () => {
const petnames = reject(t => t[1] === pubkey, $user.petnames)
cmd.setPetnames(getWriteRelays(), petnames)
cmd.setPetnames(getUserRelays('write'), petnames)
}
const openAdvanced = () => {

View File

@ -10,7 +10,7 @@
import Button from "src/partials/Button.svelte"
import Content from "src/partials/Content.svelte"
import Heading from "src/partials/Heading.svelte"
import {user, getWriteRelays} from "src/agent/helpers"
import {user, getUserRelays} from "src/agent/helpers"
import cmd from "src/agent/cmd"
import {toast} from "src/app"
import {routes} from "src/app/ui"
@ -45,7 +45,7 @@
const submit = async event => {
event.preventDefault()
await cmd.updateUser(getWriteRelays(), values)
await cmd.updateUser(getUserRelays('write'), values)
navigate(routes.person($user.pubkey, 'profile'))

View File

@ -1,5 +1,5 @@
import {debounce} from 'throttle-debounce'
import {pluck, identity, sortBy} from "ramda"
import {allPass, prop, pipe, isNil, complement, equals, is, pluck, sum, identity, sortBy} from "ramda"
import Fuse from "fuse.js/dist/fuse.min.js"
import {writable} from 'svelte/store'
import {isObject} from 'hurdak/lib/hurdak'
@ -145,7 +145,7 @@ export const getLastSync = (k, fallback = 0) => {
export class Cursor {
until: number
limit: number
constructor(limit = 10) {
constructor(limit = 50) {
this.until = now()
this.limit = limit
}
@ -197,3 +197,40 @@ export const asyncIterableToArray = async (it, f = identity) => {
return result
}
export const avg = xs => sum(xs) / xs.length
export const where = filters =>
allPass(
Object.entries(filters)
.map(([key, value]) => {
/* eslint prefer-const: 0 */
let [field, operator = 'eq'] = key.split(':')
let test, modifier = identity
if (operator.startsWith('!')) {
operator = operator.slice(1)
modifier = complement
}
if (operator === 'eq' && is(Array, value)) {
test = v => (value as Array<any>).includes(v)
} else if (operator === 'eq') {
test = equals(value)
} else if (operator === 'lt') {
test = v => (v || 0) < value
} else if (operator === 'lte') {
test = v => (v || 0) <= value
} else if (operator === 'gt') {
test = v => (v || 0) > value
} else if (operator === 'gte') {
test = v => (v || 0) >= value
} else if (operator === 'nil') {
test = isNil
} else {
throw new Error(`Invalid operator ${operator}`)
}
return pipe(prop(field), modifier(test))
})
)

View File

@ -6,7 +6,7 @@
import Content from "src/partials/Content.svelte"
import Textarea from "src/partials/Textarea.svelte"
import Button from "src/partials/Button.svelte"
import {getWriteRelays} from 'src/agent/helpers'
import {getUserRelays} from 'src/agent/helpers'
import database from 'src/agent/database'
import cmd from "src/agent/cmd"
import {toast, modal} from "src/app"
@ -36,8 +36,8 @@
toast.show("error", "Please enter a name for your room.")
} else {
const event = room.id
? await cmd.updateRoom(getWriteRelays(), room)
: await cmd.createRoom(getWriteRelays(), room)
? await cmd.updateRoom(getUserRelays('write'), room)
: await cmd.createRoom(getUserRelays('write'), room)
await database.rooms.patch({id: room.id || event.id, joined: true})

View File

@ -13,13 +13,13 @@
import Content from "src/partials/Content.svelte"
import Modal from "src/partials/Modal.svelte"
import Heading from 'src/partials/Heading.svelte'
import {user, getWriteRelays} from "src/agent/helpers"
import {user, getUserRelays} from "src/agent/helpers"
import database from 'src/agent/database'
import cmd from "src/agent/cmd"
import {toast, modal} from "src/app"
let input = null
let relays = getWriteRelays()
let relays = getUserRelays('write')
let showSettings = false
let q = ''
let search

View File

@ -2,7 +2,7 @@
import {onMount} from 'svelte'
import {nip19} from 'nostr-tools'
import {fly} from 'svelte/transition'
import {getRelays} from 'src/agent/helpers'
import {getEventRelays, getUserRelays} from 'src/agent/helpers'
import network from 'src/agent/network'
import {annotate} from 'src/app'
import Note from 'src/partials/Note.svelte'
@ -10,7 +10,7 @@
import Spinner from 'src/partials/Spinner.svelte'
export let note
export let relays = getRelays()
export let relays = getUserRelays().concat(getEventRelays(note))
let loading = true
@ -21,6 +21,7 @@
// Show the main note without waiting for context
if (!note.pubkey) {
note = annotate(found, [])
relays = getEventRelays(note)
}
const context = await network.loadContext(relays, found, {

View File

@ -1,15 +1,16 @@
<script type="ts">
import Content from 'src/partials/Content.svelte'
import PersonInfo from 'src/partials/PersonInfo.svelte'
import {getRelays} from 'src/agent/helpers'
import {getUserRelays, getTopRelays} from 'src/agent/helpers'
import database from 'src/agent/database'
import network from 'src/agent/network'
export let pubkeys
const relays = getUserRelays('read').concat(getTopRelays(pubkeys, 'write'))
const people = database.watch('people', people => people.all({pubkey: pubkeys}))
network.loadPeople(getRelays(), pubkeys)
network.loadPeople(relays, pubkeys)
</script>
<Content gap={2}>

View File

@ -5,7 +5,7 @@
import Button from "src/partials/Button.svelte"
import Content from 'src/partials/Content.svelte'
import SelectButton from "src/partials/SelectButton.svelte"
import {user, getWriteRelays} from 'src/agent/helpers'
import {user, getUserRelays} from 'src/agent/helpers'
import cmd from 'src/agent/cmd'
import {modal} from 'src/app'
@ -28,7 +28,7 @@
.concat([["p", $modal.person.pubkey, muffleValue.toString()]])
.filter(t => last(t) !== "1")
cmd.muffle(getWriteRelays(), muffleTags)
cmd.muffle(getUserRelays('write'), muffleTags)
history.back()
}

View File

@ -8,7 +8,7 @@
let search
database.people.all({'name:!nil': null}).then(people => {
database.people.iter({'name:!nil': null}).then(people => {
search = fuzzy(people, {keys: ["name", "about", "pubkey"]})
})
</script>

View File

@ -1,11 +1,11 @@
<script>
import Notes from "src/partials/Notes.svelte"
import {Cursor, now, batch} from 'src/util/misc'
import {getRelays, getMuffle} from 'src/agent/helpers'
import {getUserRelays, getMuffle} from 'src/agent/helpers'
import network from 'src/agent/network'
import {threadify} from 'src/app'
const relays = getRelays()
const relays = getUserRelays('read')
const filter = {kinds: [1, 5, 7]}
const cursor = new Cursor()

View File

@ -1,8 +1,8 @@
<script>
import {uniqBy, prop} from 'ramda'
import {uniq} from 'ramda'
import Notes from "src/partials/Notes.svelte"
import {now, Cursor, shuffle, batch} from 'src/util/misc'
import {user, getRelays, getFollows, getMuffle} from 'src/agent/helpers'
import {user, getTopRelays, getFollows, getMuffle} from 'src/agent/helpers'
import network from 'src/agent/network'
import {threadify} from 'src/app'
@ -10,20 +10,23 @@
// sending too many pubkeys. This will also result in some variety.
const follows = shuffle(getFollows($user?.pubkey))
const others = shuffle(follows.flatMap(getFollows)).slice(0, 50)
const authors = follows.concat(others).slice(0, 100)
const authors = uniq(follows.concat(others)).slice(0, 100)
const filter = {kinds: [1, 7], authors}
const cursor = new Cursor()
const relays = uniqBy(prop('url'), follows.flatMap(getRelays))
const listenForNotes = onNotes =>
network.listen(relays, {...filter, since: now()}, batch(300, async notes => {
const listenForNotes = async onNotes => {
const relays = getTopRelays(authors, 'write')
return network.listen(relays, {...filter, since: now()}, batch(300, async notes => {
const context = await network.loadContext(relays, notes)
onNotes(threadify(notes, context, {muffle: getMuffle(), showReplies: false}))
}))
}
const loadNotes = async () => {
const {limit, until} = cursor
const relays = getTopRelays(authors, 'write')
const notes = await network.load(relays, {...filter, limit, until})
const context = await network.loadContext(relays, notes)

View File

@ -1,13 +1,13 @@
<script>
import Notes from "src/partials/Notes.svelte"
import {now, batch, Cursor} from 'src/util/misc'
import {getRelays, getMuffle} from 'src/agent/helpers'
import {getPubkeyRelays, getMuffle} from 'src/agent/helpers'
import network from 'src/agent/network'
import {threadify} from 'src/app'
export let pubkey
const relays = getRelays(pubkey)
const relays = getPubkeyRelays(pubkey, 'write')
const filter = {kinds: [7], authors: [pubkey]}
const cursor = new Cursor()

View File

@ -1,13 +1,13 @@
<script>
import Notes from "src/partials/Notes.svelte"
import {now, batch, Cursor} from 'src/util/misc'
import {getRelays, getMuffle} from 'src/agent/helpers'
import {getPubkeyRelays, getMuffle} from 'src/agent/helpers'
import network from 'src/agent/network'
import {threadify} from 'src/app'
export let pubkey
const relays = getRelays(pubkey)
const relays = getPubkeyRelays(pubkey, 'write')
const filter = {kinds: [1], authors: [pubkey]}
const cursor = new Cursor()