streaming: make user stream mostly work, in a kind of hacky way

This commit is contained in:
Alex Gleason 2023-08-28 13:34:15 -05:00
parent e8a7dfef2b
commit e6d1494a10
No known key found for this signature in database
GPG Key ID: 7211D1F99744FBB7
5 changed files with 36 additions and 15 deletions

View File

@ -1,4 +1,4 @@
import { lodash, nip19, uuid62, z } from '@/deps.ts'; import { lodash, nip19, z } from '@/deps.ts';
import { AppController } from '@/app.ts'; import { AppController } from '@/app.ts';
import { nostrNow } from '@/utils.ts'; import { nostrNow } from '@/utils.ts';
import { parseBody } from '@/utils/web.ts'; import { parseBody } from '@/utils/web.ts';

View File

@ -1,8 +1,10 @@
import { type AppController } from '@/app.ts'; import { type AppController } from '@/app.ts';
import { nip19, z } from '@/deps.ts'; import { z } from '@/deps.ts';
import { type DittoFilter } from '@/filter.ts'; import { type DittoFilter } from '@/filter.ts';
import { getFeedPubkeys } from '@/queries.ts';
import { Sub } from '@/subs.ts'; import { Sub } from '@/subs.ts';
import { toStatus } from '@/transformers/nostr-to-mastoapi.ts'; import { toStatus } from '@/transformers/nostr-to-mastoapi.ts';
import { bech32ToPubkey } from '@/utils.ts';
/** /**
* Streaming timelines/categories. * Streaming timelines/categories.
@ -38,8 +40,8 @@ const streamingController: AppController = (c) => {
return c.json({ error: 'Missing access token' }, 401); return c.json({ error: 'Missing access token' }, 401);
} }
const match = token.match(new RegExp(`^${nip19.BECH32_REGEX.source}$`)); const pubkey = token ? bech32ToPubkey(token) : undefined;
if (!match) { if (!pubkey) {
return c.json({ error: 'Invalid access token' }, 401); return c.json({ error: 'Invalid access token' }, 401);
} }
@ -57,7 +59,7 @@ const streamingController: AppController = (c) => {
socket.onopen = async () => { socket.onopen = async () => {
if (!stream) return; if (!stream) return;
const filter = topicToFilter(stream, c.req.query()); const filter = await topicToFilter(stream, pubkey, c.req.query());
if (filter) { if (filter) {
for await (const event of Sub.sub(socket, '1', [filter])) { for await (const event of Sub.sub(socket, '1', [filter])) {
@ -76,18 +78,27 @@ const streamingController: AppController = (c) => {
return response; return response;
}; };
function topicToFilter(topic: Stream, query?: Record<string, string>): DittoFilter<1> | undefined { async function topicToFilter(
topic: Stream,
pubkey: string,
query: Record<string, string>,
): Promise<DittoFilter<1> | undefined> {
switch (topic) { switch (topic) {
case 'public': case 'public':
return { kinds: [1] }; return { kinds: [1] };
case 'public:local': case 'public:local':
return { kinds: [1], local: true }; return { kinds: [1], local: true };
case 'hashtag': case 'hashtag':
if (query?.tag) return { kinds: [1], '#t': [query.tag] }; if (query.tag) return { kinds: [1], '#t': [query.tag] };
break; break;
case 'hashtag:local': case 'hashtag:local':
if (query?.tag) return { kinds: [1], local: true, '#t': [query.tag] }; if (query.tag) return { kinds: [1], local: true, '#t': [query.tag] };
break; break;
case 'user':
// HACK: this puts the user's entire contacts list into RAM,
// and then calls `matchFilters` over it. Refreshing the page
// is required after following a new user.
return { kinds: [1], authors: await getFeedPubkeys(pubkey) };
} }
} }

View File

@ -37,7 +37,6 @@ import 'npm:linkify-plugin-hashtag@^4.1.1';
export { default as mime } from 'npm:mime@^3.0.0'; export { default as mime } from 'npm:mime@^3.0.0';
export { unfurl } from 'npm:unfurl.js@^6.3.2'; export { unfurl } from 'npm:unfurl.js@^6.3.2';
export { default as TTLCache } from 'npm:@isaacs/ttlcache@^1.4.1'; export { default as TTLCache } from 'npm:@isaacs/ttlcache@^1.4.1';
export { default as uuid62 } from 'npm:uuid62@^1.0.2';
// @deno-types="npm:@types/sanitize-html@2.9.0" // @deno-types="npm:@types/sanitize-html@2.9.0"
export { default as sanitizeHtml } from 'npm:sanitize-html@^2.11.0'; export { default as sanitizeHtml } from 'npm:sanitize-html@^2.11.0';
export { default as ISO6391 } from 'npm:iso-639-1@2.1.15'; export { default as ISO6391 } from 'npm:iso-639-1@2.1.15';

View File

@ -37,16 +37,25 @@ const getFollows = async (pubkey: string, timeout = 1000): Promise<Event<3> | un
return event; return event;
}; };
/** Get events from people the user follows. */ /** Get pubkeys the user follows. */
async function getFeed(pubkey: string, params: PaginationParams): Promise<Event<1>[]> { async function getFollowedPubkeys(pubkey: string): Promise<string[]> {
const event3 = await getFollows(pubkey); const event = await getFollows(pubkey);
if (!event3) return []; if (!event) return [];
const authors = event3.tags return event.tags
.filter((tag) => tag[0] === 'p') .filter((tag) => tag[0] === 'p')
.map((tag) => tag[1]); .map((tag) => tag[1]);
}
authors.push(event3.pubkey); // see own events in feed /** Get pubkeys the user follows, including the user's own pubkey. */
async function getFeedPubkeys(pubkey: string): Promise<string[]> {
const authors = await getFollowedPubkeys(pubkey);
return [...authors, pubkey];
}
/** Get events from people the user follows. */
async function getFeed(pubkey: string, params: PaginationParams): Promise<Event<1>[]> {
const authors = await getFeedPubkeys(pubkey);
const filter: Filter<1> = { const filter: Filter<1> = {
authors, authors,
@ -103,6 +112,7 @@ export {
getDescendants, getDescendants,
getEvent, getEvent,
getFeed, getFeed,
getFeedPubkeys,
getFollows, getFollows,
getPublicFeed, getPublicFeed,
isLocallyFollowed, isLocallyFollowed,

View File

@ -102,6 +102,7 @@ function isFollowing(source: Event<3>, targetPubkey: string): boolean {
} }
export { export {
bech32ToPubkey,
eventAge, eventAge,
eventDateComparator, eventDateComparator,
findTag, findTag,