Clean up nostr utils

This commit is contained in:
Jonathan Staab 2023-01-11 04:27:35 -08:00
parent bb39245d70
commit ee1accf001
7 changed files with 49 additions and 72 deletions

View File

@ -53,8 +53,6 @@ If you like Coracle and want to support its development, you can donate sats via
- [x] Use user relays for feeds
- [x] Publish to user relays + target relays:
- [x] Add correct recommended relay to tags
- [ ] Clean up nostr utils
- [ ] Close connections that haven't been used in a while
- [ ] Support some read/write config on relays page
- [ ] Get real home relays for default pubkeys
- [ ] Add settings storage on nostr, maybe use kind 0?
@ -69,6 +67,8 @@ If you like Coracle and want to support its development, you can donate sats via
- [ ] Alerts still aren't great. Maybe lazy load? We delete old events, so context will disappear and notes will become empty.
- [ ] Only use dexie for alerts rather than all events
- Load feeds by setting a listener since now, paginating using limit (of 2 maybe), and awaiting context for each page. Listener appends to "newNotes", cursor appends to "notes", load more moves new notes into notes. Use the note originally loaded as the anchor, don't re-process the whole list
- [ ] Close connections that haven't been used in a while
- [ ] Load feeds from network rather than user relays? This could make global feed more useful: global for _my_ relays
## 0.2.6

View File

@ -4,7 +4,7 @@ import {get} from 'svelte/store'
import {groupBy, prop, flatten, pick} from 'ramda'
import {ensurePlural, switcherFn} from 'hurdak/lib/hurdak'
import {synced, now, timedelta} from 'src/util/misc'
import {filterTags, personKinds, findReply, findRoot} from 'src/util/nostr'
import {Tags, personKinds, findReply, findRoot} from 'src/util/nostr'
import keys from 'src/agent/keys'
export const db = new Dexie('agent/data/db')
@ -68,7 +68,7 @@ export const processEvents = async events => {
// Delete stuff that needs to be deleted
if (deletions.length > 0) {
const eventIds = deletions.flatMap(e => filterTags({tag: "e"}, e))
const eventIds = Tags.from(deletions).type("e").values().all()
db.events.where('id').anyOf(eventIds).delete()
db.tags.where('event').anyOf(eventIds).delete()

View File

@ -1,7 +1,8 @@
import {isNil, join, uniqBy, last} from 'ramda'
import {join, uniqBy, last} from 'ramda'
import {get} from 'svelte/store'
import {first} from "hurdak/lib/hurdak"
import {keys, publish, user, getRelays} from 'src/agent'
import {Tags} from 'src/util/nostr'
import {keys, publish, getRelays} from 'src/agent'
const updateUser = (relays, updates) =>
publishEvent(relays, 0, {content: JSON.stringify(updates)})
@ -61,19 +62,19 @@ const deleteEvent = (relays, ids) =>
const getBestRelay = event => {
// Find the best relay, based on reply, root, or pubkey
const reply = findTag({tag: "e", type: "reply"}, e)
const reply = Tags.from(event).type("e").mark("reply").first()
if (reply && reply[2].startsWith('ws')) {
return reply[2]
}
const root = findTag({tag: "e", type: "root"}, e)
const root = Tags.from(event).type("e").mark("root").first()
if (root && root[2].startsWith('ws')) {
return root[2]
}
return first(getRelays(note.pubkey))
return first(getRelays(event.pubkey))
}
const publishEvent = (relays, kind, {content = '', tags = []} = {}) => {

View File

@ -2,7 +2,7 @@ import {get} from 'svelte/store'
import {intersection, sortBy, propEq, uniqBy, groupBy, concat, prop, isNil, identity} from 'ramda'
import {ensurePlural, createMap, ellipsize} from 'hurdak/lib/hurdak'
import {renderContent} from 'src/util/html'
import {filterTags, displayPerson, getTagValues, findReply, findRoot} from 'src/util/nostr'
import {Tags, displayPerson, getTagValues, findReply, findRoot} from 'src/util/nostr'
import {db, people, getPerson} from 'src/agent'
import {routes} from "src/app/ui"
@ -132,7 +132,7 @@ const renderNote = async (note, {showEntire = false}) => {
const $people = get(people)
const peopleByPubkey = createMap(
'pubkey',
filterTags({tag: "p"}, note).map(k => $people[k]).filter(identity)
Tags.from(note).type("p").values().all().map(k => $people[k]).filter(identity)
)
let content

View File

@ -1,19 +0,0 @@
import {intersection} from 'ramda'
import {ensurePlural} from 'hurdak/lib/hurdak'
export const filterMatches = (filter, e) => {
return Boolean(find(
f => {
return (
(!f.ids || f.ids.includes(e.id))
&& (!f.authors || f.authors.includes(e.pubkey))
&& (!f.kinds || f.kinds.includes(e.kind))
&& (!f['#e'] || intersection(f['#e'], e.tags.filter(t => t[0] === 'e').map(t => t[1])))
&& (!f['#p'] || intersection(f['#p'], e.tags.filter(t => t[0] === 'p').map(t => t[1])))
&& (!f.since || f.since >= e.created_at)
&& (!f.until || f.until <= e.created_at)
)
},
ensurePlural(filter)
))
}

View File

@ -1,54 +1,50 @@
import {last, find, intersection} from 'ramda'
import {last, prop} from 'ramda'
import {nip19} from 'nostr-tools'
import {ensurePlural, first} from 'hurdak/lib/hurdak'
export const epoch = 1633046400
export const personKinds = [0, 2, 3, 10001, 12165]
export class Tags {
constructor(tags) {
this.tags = tags
}
static from(events) {
return new Tags(ensurePlural(events).flatMap(prop('tags')))
}
all() {
return this.tags
}
first() {
return first(this.tags)
}
last() {
return last(this.tags)
}
values() {
this.tags = this.tags.map(t => t[0])
return this
}
type(type) {
this.tags = this.tags.filter(t => t[0] === type)
return this
}
mark(mark) {
this.tags = this.tags.filter(t => last(t) === mark)
return this
}
}
export const getTagValues = tags => tags.map(t => t[1])
export const filterTags = (where, events) =>
ensurePlural(events)
.flatMap(
e => e.tags.filter(t => {
if (where.tag && where.tag !== t[0]) {
return false
}
if (where.type && where.type !== last(t)) {
return false
}
return true
}).map(t => t[1])
)
export const findTag = (where, events) => first(filterTags(where, events))
// Support the deprecated version where tags are not marked as replies
export const findReply = e =>
findTag({tag: "e", type: "reply"}, e) || findTag({tag: "e"}, e)
Tags.from(e).type("e").mark("reply").first() || Tags.from(e).type("e").first()
export const findRoot = e =>
findTag({tag: "e", type: "root"}, e)
export const filterMatches = (filter, e) => {
return Boolean(find(
f => {
return (
(!f.ids || f.ids.includes(e.id))
&& (!f.authors || f.authors.includes(e.pubkey))
&& (!f.kinds || f.kinds.includes(e.kind))
&& (!f['#e'] || intersection(f['#e'], e.tags.filter(t => t[0] === 'e').map(t => t[1])))
&& (!f['#p'] || intersection(f['#p'], e.tags.filter(t => t[0] === 'p').map(t => t[1])))
&& (!f.since || f.since >= e.created_at)
&& (!f.until || f.until <= e.created_at)
)
},
ensurePlural(filter)
))
}
Tags.from(e).type("e").mark("root").first()
export const displayPerson = p => {
if (p.name) {

View File

@ -11,9 +11,8 @@
const getFollows = pubkey => {
const person = getPerson(pubkey)
const petnames = person?.petnames || defaults.petnames
return petnames.map(nth(1))
return getTagValues(person?.petnames || defaults.petnames)
}
// Get first- and second-order follows. shuffle and slice network so we're not