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:
{
const userInfo = res.get(event.pubkey);
const profileEvent = ProfileFromNostrEvent({
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,
});
const profileEvent = event;
if (userInfo) {
if (userInfo.profile) {
if (profileEvent.created_at > userInfo.profile?.created_at) {
@ -133,9 +124,8 @@ export function getAllUsersInformation(
pubkey: PublicKey.FromHex(event.pubkey) as PublicKey,
newestEventReceivedByMe: undefined,
newestEventSendByMe: undefined,
profile: undefined,
profile: profileEvent,
};
newUserInfo.profile = profileEvent;
res.set(event.pubkey, newUserInfo);
}
}

View File

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

View File

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