feed: update subscriptions
ci/woodpecker/pr/woodpecker Pipeline was successful Details
ci/woodpecker/push/woodpecker Pipeline was successful Details

playing around with subscriptions, feed now loads profile names,
profile views also show replied to notes and notes recursively
search for replies or replies.

this commit does too many subscriptions, ideally a max of three
subscriptions are done at once. in future commit it would be nice
to subscribe modularly, have done callbacks or push into subscribe
next queues.
pull/73/head
OFF0 12 months ago
parent 7113bf1a4d
commit 30809ccbce
Signed by: offbyn
GPG Key ID: 94A2F643C51F37FA

@ -49,17 +49,17 @@ const renderFeed = bounce(() => {
switch (view.type) {
case 'note':
textNoteList
.concat(replyList)
.concat(replyList) // search id in notes and replies
.filter(note => note.id === view.id)
.forEach(renderNote);
break;
case 'profile':
const isEvent = <T>(evt?: T): evt is T => evt !== undefined;
[
...textNoteList
...textNoteList // get notes
.filter(note => note.pubkey === view.id),
...replyList.filter(reply => reply.pubkey === view.id)
.map(reply => textNoteList.find(note => note.id === reply.replyTo) || replyList.find(note => note.id === reply.replyTo) )
...replyList.filter(reply => reply.pubkey === view.id) // and replies
.map(reply => textNoteList.find(note => note.id === reply.replyTo)) // and the replied to notes
.filter(isEvent)
]
.sort(sortByCreatedAt)

@ -8,11 +8,12 @@ type SubCallback = (
type Subscribe = {
cb: SubCallback;
filter: Filter;
unsub?: boolean;
};
const relayList: Array<Relay> = [];
const subList: Array<Sub> = [];
const currentSubList: Array<Subscribe> = [];
const relayMap = new Map<string, Relay>();
export const addRelay = async (url: string) => {
const relay = relayInit(url);
@ -25,13 +26,13 @@ export const addRelay = async (url: string) => {
try {
await relay.connect();
currentSubList.forEach(({cb, filter}) => subscribe(cb, filter, relay));
relayList.push(relay);
relayMap.set(url, relay);
} catch {
console.warn(`could not connect to ${url}`);
}
};
const unsubscribe = (sub: Sub) => {
export const unsubscribe = (sub: Sub) => {
sub.unsub();
subList.splice(subList.indexOf(sub), 1);
};
@ -40,28 +41,38 @@ const subscribe = (
cb: SubCallback,
filter: Filter,
relay: Relay,
unsub?: boolean
) => {
const sub = relay.sub([filter]);
subList.push(sub);
sub.on('event', (event: Event) => {
cb(event, relay.url);
});
sub.on('eose', () => {
// console.log('eose', relay.url);
// unsubscribe(sub);
});
};
const subscribeAll = (
cb: SubCallback,
filter: Filter,
) => {
relayList.forEach(relay => subscribe(cb, filter, relay));
if (unsub) {
sub.on('eose', () => {
console.log('eose', relay.url);
unsubscribe(sub);
});
}
return sub;
};
export const sub = (obj: Subscribe) => {
currentSubList.push(obj);
subscribeAll(obj.cb, obj.filter);
relayMap.forEach((relay) => subscribe(obj.cb, obj.filter, relay, obj.unsub));
};
export const subOnce = (
obj: Subscribe & {relay: string}
) => {
const relay = relayMap.get(obj.relay);
if (relay) {
const sub = subscribe(obj.cb, obj.filter, relay);
sub.on('eose', () => {
console.log('eose', obj.relay);
unsubscribe(sub);
});
}
};
export const unsubAll = () => {
@ -78,7 +89,7 @@ export const publish = (
event: Event,
cb: PublishCallback,
) => {
relayList.forEach(relay => {
relayMap.forEach((relay, url) => {
const pub = relay.publish(event);
pub.on('ok', () => {
console.info(`${relay.url} has accepted our event`);
@ -91,9 +102,10 @@ export const publish = (
});
};
addRelay('wss://relay.snort.social'); // good one
addRelay('wss://relay.snort.social');
addRelay('wss://nostr.bitcoiner.social');
addRelay('wss://nostr.mom');
addRelay('wss://relay.nostr.bg');
addRelay('wss://nos.lol');
addRelay('wss://relay.nostr.ch');
// addRelay('wss://relay.nostr.ch');

@ -1,5 +1,6 @@
import {Event} from 'nostr-tools';
import {sub, unsubAll} from './relays';
import {getReplyTo, hasEventTag, isMention} from './events';
import {sub, subOnce, unsubAll} from './relays';
type SubCallback = (
event: Event,
@ -9,17 +10,86 @@ type SubCallback = (
/** subscribe to global feed */
export const sub24hFeed = (onEvent: SubCallback) => {
unsubAll();
const now = Math.floor(Date.now() * 0.001);
const pubkeys = new Set<string>();
const notes = new Set<string>();
sub({ // get past events
cb: (evt, relay) => {
pubkeys.add(evt.pubkey);
notes.add(evt.id);
onEvent(evt, relay);
},
filter: {
kinds: [1],
until: now,
since: Math.floor(now - (24 * 60 * 60)),
limit: 100,
},
unsub: true
});
setTimeout(() => {
// get profile info
sub({
cb: onEvent,
filter: {
authors: Array.from(pubkeys),
kinds: [0],
limit: pubkeys.size,
},
unsub: true,
});
pubkeys.clear();
// get reactions
sub({
cb: onEvent,
filter: {
'#e': Array.from(notes),
kinds: [7],
until: now,
since: Math.floor(now - (24 * 60 * 60)),
},
unsub: true,
});
notes.clear();
}, 2000);
// subscribe to future notes, reactions and profile updates
sub({
cb: onEvent,
cb: (evt, relay) => {
onEvent(evt, relay);
subOnce({ // get profil data
relay,
cb: onEvent,
filter: {
authors: [evt.pubkey],
kinds: [0],
limit: 1,
}
});
},
filter: {
kinds: [0, 1, 2, 7],
// until: Math.floor(Date.now() * 0.001),
since: Math.floor((Date.now() * 0.001) - (24 * 60 * 60)),
limit: 50,
}
kinds: [0, 1, 7],
since: now,
},
});
};
/** subscribe to global feed */
// export const simpleSub24hFeed = (onEvent: SubCallback) => {
// unsubAll();
// sub({
// cb: onEvent,
// filter: {
// kinds: [0, 1, 2, 7],
// // until: Math.floor(Date.now() * 0.001),
// since: Math.floor((Date.now() * 0.001) - (24 * 60 * 60)),
// limit: 250,
// }
// });
// };
/** subscribe to a note id (nip-19) */
export const subNote = (
eventId: string,
@ -32,14 +102,34 @@ export const subNote = (
ids: [eventId],
kinds: [1],
limit: 1,
}
},
unsub: true,
});
const replies = new Set<string>();
const onReply = (evt: Event, relay: string) => {
replies.add(evt.id)
onEvent(evt, relay);
unsubAll();
sub({
cb: onEvent,
filter: {
'#e': Array.from(replies),
kinds: [1, 7],
},
unsub: true,
});
};
replies.add(eventId)
sub({
cb: onEvent,
cb: onReply,
filter: {
'#e': [eventId],
kinds: [1, 7],
}
},
unsub: true,
});
};
@ -59,7 +149,25 @@ export const subProfile = (
});
// get notes for profile
sub({
cb: onEvent,
cb: (evt, relay) => {
const repliesTo = new Set<string>();
if (evt.tags.some(hasEventTag) && !evt.tags.some(isMention)) {
const note = getReplyTo(evt);
if (note && !repliesTo.has(note)) {
repliesTo.add(note);
subOnce({
relay,
cb: onEvent,
filter: {
ids: [note],
kinds: [1],
limit: 1,
}
})
}
}
onEvent(evt, relay);
},
filter: {
authors: [pubkey],
kinds: [1],

@ -184,8 +184,8 @@ export const updateElemHeight = (
export const elemArticle = (
content: Array<HTMLElement>,
attrs: Attributes<HTMLElementTagNameMap['div']> = {}
attrs: Attributes<HTMLElementTagNameMap['div']> = {},
) => {
const className = attrs.className ? ['mbox', attrs?.className].join(' ') : 'mbox';
const className = attrs.className ? `mbox ${attrs.className}` : 'mbox';
return elem('article', {...attrs, className}, content);
};

Loading…
Cancel
Save