blowater/features/profile.ts

149 lines
4.2 KiB
TypeScript
Raw Normal View History

2023-07-11 09:49:58 +00:00
import { Database_Contextual_View } from "../database.ts";
2023-08-29 22:46:42 +00:00
import { ConnectionPool } from "../lib/nostr-ts/relay.ts";
2023-08-28 17:58:05 +00:00
import { PublicKey } from "../lib/nostr-ts/key.ts";
import { groupBy, NostrAccountContext, NostrKind } from "../lib/nostr-ts/nostr.ts";
import { Parsed_Event, Profile_Nostr_Event } from "../nostr.ts";
import { prepareNormalNostrEvent } from "../lib/nostr-ts/event.ts";
export class ProfilesSyncer {
readonly userSet = new Set<string>();
2023-06-30 14:05:57 +00:00
constructor(
private readonly database: Database_Contextual_View,
private readonly pool: ConnectionPool,
2023-08-29 22:46:42 +00:00
) {}
async add(...users: string[]) {
2023-08-29 22:46:42 +00:00
const size = this.userSet.size;
for (const user of users) {
this.userSet.add(user);
}
if (this.userSet.size == size) {
return;
}
const resp = await this.pool.updateSub(
"profilesStream",
{
authors: Array.from(this.userSet),
kinds: [NostrKind.META_DATA],
},
);
if (resp instanceof Error) {
console.error(resp.message);
return;
}
for await (let { res: nostrMessage, url: relayUrl } of resp.chan) {
if (nostrMessage.type === "EVENT" && nostrMessage.event.content) {
this.database.addEvent(nostrMessage.event);
}
2023-06-30 14:05:57 +00:00
}
}
2023-06-30 14:05:57 +00:00
}
export async function saveProfile(
profile: ProfileData,
sender: NostrAccountContext,
pool: ConnectionPool,
) {
const event = await prepareNormalNostrEvent(
sender,
NostrKind.META_DATA,
[],
JSON.stringify(profile),
);
pool.sendEvent(event);
}
2023-07-14 10:59:25 +00:00
export function getProfileEvent(
db: Database_Contextual_View,
pubkey: PublicKey,
): Profile_Nostr_Event | undefined {
2023-07-14 14:13:15 +00:00
const events: Profile_Nostr_Event[] = [];
2023-07-14 10:59:25 +00:00
for (const e of db.events) {
if (e.kind === NostrKind.META_DATA && e.pubkey === pubkey.hex) {
2023-07-14 14:13:15 +00:00
events.push(e);
2023-07-14 10:59:25 +00:00
}
}
2023-06-30 14:05:57 +00:00
if (events.length == 0) {
return undefined;
}
events.sort((e1, e2) => e2.created_at - e1.created_at);
const newest = events[0];
2023-07-14 14:13:15 +00:00
return newest;
2023-06-30 14:05:57 +00:00
}
2023-07-14 10:59:25 +00:00
export function getProfilesByName(db: Database_Contextual_View, name: string): Profile_Nostr_Event[] {
2023-07-14 14:13:15 +00:00
const events: Profile_Nostr_Event[] = [];
2023-07-14 10:59:25 +00:00
for (const e of db.events) {
if (e.kind === NostrKind.META_DATA) {
2023-07-14 14:13:15 +00:00
events.push(e);
2023-07-14 10:59:25 +00:00
}
}
2023-06-30 14:05:57 +00:00
if (events.length == 0) {
return [];
}
const profilesPerUser = groupBy(events, (e) => e.pubkey);
const result = [];
for (const events of profilesPerUser.values()) {
events.sort((e1, e2) => e2.created_at - e1.created_at);
2023-07-14 14:13:15 +00:00
const p = events[0];
2023-07-14 10:59:25 +00:00
if (p.profile.name && p.profile.name?.toLocaleLowerCase().indexOf(name.toLowerCase()) != -1) {
2023-06-30 14:05:57 +00:00
result.push(p);
}
}
return result;
}
export function getProfiles(
2023-07-11 09:49:58 +00:00
db: Database_Contextual_View,
2023-06-30 14:05:57 +00:00
pubkeys: Set<string>,
2023-07-14 10:59:25 +00:00
): Map<string, /*pubkey*/ Profile_Nostr_Event | undefined> {
const contacts: Map<string, Profile_Nostr_Event | undefined> = new Map();
2023-06-30 14:05:57 +00:00
for (const key of pubkeys) {
const event = getProfileEvent(db, PublicKey.FromHex(key) as PublicKey);
2023-06-30 14:05:57 +00:00
contacts.set(key, event);
}
return contacts;
}
// aka user profile
export interface ProfileData {
name?: string;
picture?: string;
about?: string;
website?: string;
banner?: string;
[key: string]: string | undefined;
}
2023-07-14 10:59:25 +00:00
export function ProfileFromNostrEvent(
2023-07-15 05:58:03 +00:00
event: Parsed_Event<NostrKind.META_DATA>,
2023-07-14 14:13:15 +00:00
) {
const profileData = parseProfileData(event.content);
if (profileData instanceof Error) {
return profileData;
2023-07-07 08:31:06 +00:00
}
2023-07-14 14:13:15 +00:00
const e: Profile_Nostr_Event = {
2023-06-30 14:05:57 +00:00
kind: event.kind,
id: event.id,
sig: event.sig,
created_at: event.created_at,
pubkey: event.pubkey,
tags: event.tags,
2023-07-14 10:59:25 +00:00
content: event.content,
parsedTags: event.parsedTags,
profile: profileData,
2023-07-15 05:58:03 +00:00
publicKey: event.publicKey,
2023-06-30 14:05:57 +00:00
};
2023-07-14 14:13:15 +00:00
return e;
}
export function parseProfileData(content: string) {
try {
return JSON.parse(content) as ProfileData;
} catch (e) {
return e as Error;
}
2023-06-30 14:05:57 +00:00
}