pre-parse profile data (#79)

This commit is contained in:
BlowaterNostr 2023-07-14 22:13:15 +08:00 committed by GitHub
parent 1099d342fe
commit 4fced3a56a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 115 additions and 84 deletions

View File

@ -109,16 +109,7 @@ export function getAllUsersInformation(
case NostrKind.META_DATA: case NostrKind.META_DATA:
{ {
const userInfo = res.get(event.pubkey); const userInfo = res.get(event.pubkey);
const profileEvent = ProfileFromNostrEvent({ const profileEvent = event;
content: event.content,
created_at: event.created_at,
id: event.id,
kind: event.kind,
parsedTags: event.parsedTags,
pubkey: event.pubkey,
sig: event.sig,
tags: event.tags,
});
if (userInfo) { if (userInfo) {
if (userInfo.profile) { if (userInfo.profile) {
if (profileEvent.created_at > userInfo.profile?.created_at) { if (profileEvent.created_at > userInfo.profile?.created_at) {
@ -133,9 +124,8 @@ export function getAllUsersInformation(
pubkey: PublicKey.FromHex(event.pubkey) as PublicKey, pubkey: PublicKey.FromHex(event.pubkey) as PublicKey,
newestEventReceivedByMe: undefined, newestEventReceivedByMe: undefined,
newestEventSendByMe: undefined, newestEventSendByMe: undefined,
profile: undefined, profile: profileEvent,
}; };
newUserInfo.profile = profileEvent;
res.set(event.pubkey, newUserInfo); res.set(event.pubkey, newUserInfo);
} }
} }

View File

@ -13,10 +13,12 @@ import {
getTags, getTags,
ParsedTag_Nostr_Event, ParsedTag_Nostr_Event,
PlainText_Nostr_Event, PlainText_Nostr_Event,
Profile_Nostr_Event,
Tag, Tag,
} from "./nostr.ts"; } from "./nostr.ts";
import * as csp from "https://raw.githubusercontent.com/BlowaterNostr/csp/master/csp.ts"; import * as csp from "https://raw.githubusercontent.com/BlowaterNostr/csp/master/csp.ts";
import { DexieDatabase } from "./UI/dexie-db.ts"; import { DexieDatabase } from "./UI/dexie-db.ts";
import { parseProfileData, ProfileFromNostrEvent } from "./features/profile.ts";
export const NotFound = Symbol("Not Found"); export const NotFound = Symbol("Not Found");
const buffer_size = 1000; const buffer_size = 1000;
@ -29,30 +31,66 @@ export interface Indices {
} }
export class Database_Contextual_View { export class Database_Contextual_View {
private readonly sourceOfChange = csp.chan<Decrypted_Nostr_Event | PlainText_Nostr_Event>(buffer_size); private readonly sourceOfChange = csp.chan<
private readonly caster = csp.multi<Decrypted_Nostr_Event | PlainText_Nostr_Event>(this.sourceOfChange); PlainText_Nostr_Event | Decrypted_Nostr_Event | Profile_Nostr_Event
>(buffer_size);
private readonly caster = csp.multi<PlainText_Nostr_Event | Decrypted_Nostr_Event | Profile_Nostr_Event>(
this.sourceOfChange,
);
static async New(database: DexieDatabase, ctx: NostrAccountContext) { static async New(database: DexieDatabase, ctx: NostrAccountContext) {
const t = Date.now(); const t = Date.now();
const onload: (NostrEvent)[] = await database.events.filter( const onload: (NostrEvent)[] = await database.events.filter(
(e: NostrEvent) => { (e: NostrEvent) => {
return e.kind != NostrKind.CustomAppData; return e.kind != NostrKind.CustomAppData;
}, },
).toArray(); ).toArray();
const cache: (PlainText_Nostr_Event | Decrypted_Nostr_Event)[] = onload.map((event) => { const cache: (PlainText_Nostr_Event | Decrypted_Nostr_Event | Profile_Nostr_Event)[] = [];
const e: PlainText_Nostr_Event = { for (const event of onload) {
content: event.content, switch (event.kind) {
created_at: event.created_at, case NostrKind.META_DATA:
id: event.id, {
// @ts-ignore const profileData = parseProfileData(event.content);
kind: event.kind, if (profileData instanceof Error) {
pubkey: event.pubkey, console.error(profileData);
sig: event.sig, console.log("Database:delete", event.id);
tags: event.tags, database.events.delete(event.id);
parsedTags: getTags(event), continue;
}; }
return e; const e: Profile_Nostr_Event = {
}); ...event,
kind: event.kind,
parsedTags: getTags(event),
profile: profileData,
};
cache.push(e);
}
break;
case NostrKind.TEXT_NOTE:
case NostrKind.RECOMMED_SERVER:
case NostrKind.CONTACTS:
case NostrKind.DIRECT_MESSAGE:
case NostrKind.DELETE:
{
const e: PlainText_Nostr_Event = {
content: event.content,
created_at: event.created_at,
id: event.id,
kind: event.kind,
pubkey: event.pubkey,
sig: event.sig,
tags: event.tags,
parsedTags: getTags(event),
};
cache.push(e);
}
break;
case NostrKind.CustomAppData:
// ignore
break;
}
}
const db = new Database_Contextual_View( const db = new Database_Contextual_View(
database, database,
cache, cache,
@ -111,7 +149,7 @@ export class Database_Contextual_View {
constructor( constructor(
private readonly database: DexieDatabase, private readonly database: DexieDatabase,
public readonly events: (PlainText_Nostr_Event | Decrypted_Nostr_Event)[], public readonly events: (PlainText_Nostr_Event | Decrypted_Nostr_Event | Profile_Nostr_Event)[],
private readonly ctx: NostrAccountContext, private readonly ctx: NostrAccountContext,
) {} ) {}
@ -123,15 +161,15 @@ export class Database_Contextual_View {
return this.events.filter(filter); return this.events.filter(filter);
}; };
async addEvent(event: NostrEvent) { async addEvent(event: NostrEvent): Promise<boolean> {
const storedEvent = await this.getEvent({ id: event.id }); const storedEvent = await this.getEvent({ id: event.id });
if (storedEvent) { // event exist if (storedEvent) { // event exist
return; return false;
} }
console.log("Database.addEvent", event.id); console.log("Database.addEvent", event.id);
await this.database.events.put(event); let e: PlainText_Nostr_Event | Decrypted_Nostr_Event | Profile_Nostr_Event;
if (event.kind == NostrKind.CustomAppData) { if (event.kind == NostrKind.CustomAppData) {
const e = await transformEvent({ const _e = await transformEvent({
content: event.content, content: event.content,
created_at: event.created_at, created_at: event.created_at,
id: event.id, id: event.id,
@ -140,30 +178,44 @@ export class Database_Contextual_View {
sig: event.sig, sig: event.sig,
tags: event.tags, tags: event.tags,
}, this.ctx); }, this.ctx);
if (e == undefined) { if (_e == undefined) {
return; return false;
} }
if (e instanceof Error) { if (_e instanceof Error) {
console.log("Database:delete", event.id); console.log("Database:delete", event.id);
this.database.events.delete(event.id); this.database.events.delete(event.id); // todo: remove
return; return false;
} }
this.events.push(e); e = _e;
await this.sourceOfChange.put(e);
} else { } else {
const e: PlainText_Nostr_Event = { if (event.kind == NostrKind.META_DATA) {
content: event.content, const profileData = parseProfileData(event.content);
created_at: event.created_at, if (profileData instanceof Error) {
id: event.id, return false;
kind: event.kind, }
pubkey: event.pubkey, e = {
sig: event.sig, ...event,
tags: event.tags, kind: event.kind,
parsedTags: getTags(event), profile: profileData,
}; parsedTags: getTags(event),
this.events.push(e); };
await this.sourceOfChange.put(e); } else {
e = {
content: event.content,
created_at: event.created_at,
id: event.id,
kind: event.kind,
pubkey: event.pubkey,
sig: event.sig,
tags: event.tags,
parsedTags: getTags(event),
};
}
} }
await this.database.events.put(event);
this.events.push(e);
/* not await */ this.sourceOfChange.put(e);
return true;
} }
syncEvents( syncEvents(

View File

@ -75,19 +75,10 @@ export function getProfileEvent(
db: Database_Contextual_View, db: Database_Contextual_View,
pubkey: PublicKey, pubkey: PublicKey,
): Profile_Nostr_Event | undefined { ): Profile_Nostr_Event | undefined {
const events: ParsedTag_Nostr_Event<NostrKind.META_DATA>[] = []; const events: Profile_Nostr_Event[] = [];
for (const e of db.events) { for (const e of db.events) {
if (e.kind === NostrKind.META_DATA && e.pubkey === pubkey.hex) { if (e.kind === NostrKind.META_DATA && e.pubkey === pubkey.hex) {
events.push({ events.push(e);
content: e.content,
kind: e.kind,
created_at: e.created_at,
id: e.id,
parsedTags: e.parsedTags,
pubkey: e.pubkey,
sig: e.sig,
tags: e.tags,
});
} }
} }
if (events.length == 0) { if (events.length == 0) {
@ -95,23 +86,14 @@ export function getProfileEvent(
} }
events.sort((e1, e2) => e2.created_at - e1.created_at); events.sort((e1, e2) => e2.created_at - e1.created_at);
const newest = events[0]; const newest = events[0];
return ProfileFromNostrEvent(newest); return newest;
} }
export function getProfilesByName(db: Database_Contextual_View, name: string): Profile_Nostr_Event[] { export function getProfilesByName(db: Database_Contextual_View, name: string): Profile_Nostr_Event[] {
const events: ParsedTag_Nostr_Event<NostrKind.META_DATA>[] = []; const events: Profile_Nostr_Event[] = [];
for (const e of db.events) { for (const e of db.events) {
if (e.kind === NostrKind.META_DATA) { if (e.kind === NostrKind.META_DATA) {
events.push({ events.push(e);
content: e.content,
kind: e.kind,
created_at: e.created_at,
id: e.id,
parsedTags: e.parsedTags,
pubkey: e.pubkey,
sig: e.sig,
tags: e.tags,
});
} }
} }
if (events.length == 0) { if (events.length == 0) {
@ -122,7 +104,7 @@ export function getProfilesByName(db: Database_Contextual_View, name: string): P
const result = []; const result = [];
for (const events of profilesPerUser.values()) { for (const events of profilesPerUser.values()) {
events.sort((e1, e2) => e2.created_at - e1.created_at); events.sort((e1, e2) => e2.created_at - e1.created_at);
const p = ProfileFromNostrEvent(events[0]); const p = events[0];
if (p.profile.name && p.profile.name?.toLocaleLowerCase().indexOf(name.toLowerCase()) != -1) { if (p.profile.name && p.profile.name?.toLocaleLowerCase().indexOf(name.toLowerCase()) != -1) {
result.push(p); result.push(p);
} }
@ -154,14 +136,12 @@ export interface ProfileData {
export function ProfileFromNostrEvent( export function ProfileFromNostrEvent(
event: ParsedTag_Nostr_Event<NostrKind.META_DATA>, event: ParsedTag_Nostr_Event<NostrKind.META_DATA>,
): Profile_Nostr_Event { ) {
let profileData: ProfileData = {}; const profileData = parseProfileData(event.content);
try { if (profileData instanceof Error) {
profileData = JSON.parse(event.content); return profileData;
} catch (e) {
console.error(event.id, event.content, "is not valid JSON");
} }
return { const e: Profile_Nostr_Event = {
kind: event.kind, kind: event.kind,
id: event.id, id: event.id,
sig: event.sig, sig: event.sig,
@ -172,4 +152,13 @@ export function ProfileFromNostrEvent(
parsedTags: event.parsedTags, parsedTags: event.parsedTags,
profile: profileData, profile: profileData,
}; };
return e;
}
export function parseProfileData(content: string) {
try {
return JSON.parse(content) as ProfileData;
} catch (e) {
return e as Error;
}
} }

View File

@ -284,7 +284,7 @@ export type Decrypted_Nostr_Event = ParsedTag_Nostr_Event<NostrKind.CustomAppDat
export type Decryptable_Nostr_Event = nostr.NostrEvent<NostrKind.CustomAppData>; export type Decryptable_Nostr_Event = nostr.NostrEvent<NostrKind.CustomAppData>;
export type PlainText_Nostr_Event = ParsedTag_Nostr_Event< export type PlainText_Nostr_Event = ParsedTag_Nostr_Event<
Exclude<NostrKind, NostrKind.CustomAppData> // todo: exclude DM as well Exclude<NostrKind, NostrKind.CustomAppData | NostrKind.META_DATA> // todo: exclude DM as well
>; >;
export type Profile_Nostr_Event = ParsedTag_Nostr_Event<NostrKind.META_DATA> & { export type Profile_Nostr_Event = ParsedTag_Nostr_Event<NostrKind.META_DATA> & {
profile: ProfileData; profile: ProfileData;