From bd96687205a0402cb44fef5fbabe530b6ea830ef Mon Sep 17 00:00:00 2001 From: BlowaterNostr <127284497+BlowaterNostr@users.noreply.github.com> Date: Sun, 16 Jul 2023 23:04:23 +0800 Subject: [PATCH] Optimize Parse Event Content (#83) Co-authored-by: Foodstr --- UI/app.tsx | 1 + UI/app_update.ts | 3 +- UI/dm.ts | 9 +++- UI/dm.tsx | 1 + UI/event_syncer.ts | 7 +-- UI/message-panel.tsx | 94 +++++++++++++++++++++++-------------- UI/message-thread-panel.tsx | 9 +++- UI/message.test.ts | 10 +++- UI/message.ts | 56 ++++++++++++++++++---- database.ts | 8 +++- features/profile.ts | 7 +-- features/social.ts | 7 ++- nostr.test.ts | 33 +++++++++++-- nostr.ts | 16 +++++-- 14 files changed, 188 insertions(+), 73 deletions(-) diff --git a/UI/app.tsx b/UI/app.tsx index 36440a7..0a921c1 100644 --- a/UI/app.tsx +++ b/UI/app.tsx @@ -308,6 +308,7 @@ export function AppComponent(props: { eventEmitter={app.eventBus} profilesSyncer={app.profileSyncer} eventSyncer={app.eventSyncer} + allUserInfo={app.allUsersInfo.userInfos} /> ); diff --git a/UI/app_update.ts b/UI/app_update.ts index d2e8c42..9ab55d7 100644 --- a/UI/app_update.ts +++ b/UI/app_update.ts @@ -7,7 +7,7 @@ import * as csp from "https://raw.githubusercontent.com/BlowaterNostr/csp/master import { Database_Contextual_View } from "../database.ts"; import { convertEventsToChatMessages } from "./dm.ts"; -import { get_Kind4_Events_Between, sendDMandImages, sendSocialPost } from "../features/dm.ts"; +import { sendDMandImages, sendSocialPost } from "../features/dm.ts"; import { notify } from "./notification.ts"; import { EventBus, EventEmitter } from "../event-bus.ts"; import { ContactUpdate } from "./contact-list.tsx"; @@ -21,7 +21,6 @@ import { fromEvents, LamportTime } from "../time.ts"; import { PublicKey } from "https://raw.githubusercontent.com/BlowaterNostr/nostr.ts/main/key.ts"; import { NostrAccountContext, - NostrEvent, NostrKind, prepareCustomAppDataEvent, } from "https://raw.githubusercontent.com/BlowaterNostr/nostr.ts/main/nostr.ts"; diff --git a/UI/dm.ts b/UI/dm.ts index 52352b3..a07a895 100644 --- a/UI/dm.ts +++ b/UI/dm.ts @@ -1,5 +1,10 @@ import { NostrEvent } from "https://raw.githubusercontent.com/BlowaterNostr/nostr.ts/main/nostr.ts"; -import { getTags, groupImageEvents, reassembleBase64ImageFromEvents } from "../nostr.ts"; +import { + getTags, + groupImageEvents, + PlainText_Nostr_Event, + reassembleBase64ImageFromEvents, +} from "../nostr.ts"; import { ChatMessage } from "./message.ts"; import { PublicKey } from "https://raw.githubusercontent.com/BlowaterNostr/nostr.ts/main/key.ts"; import { ContactGroup } from "./contact-list.tsx"; @@ -17,7 +22,7 @@ export type DM_Container_Model = { }; export function convertEventsToChatMessages( - events: Iterable, + events: Iterable, userProfiles: Map, ): ChatMessage[] { const messages: ChatMessage[] = []; diff --git a/UI/dm.tsx b/UI/dm.tsx index bbe6dc4..ccf7562 100644 --- a/UI/dm.tsx +++ b/UI/dm.tsx @@ -109,6 +109,7 @@ export function DirectMessageContainer(props: DirectMessageContainerProps) { db: props.db, profilesSyncer: props.profilesSyncer, eventSyncer: props.eventSyncer, + allUserInfo: props.allUserInfo, }); } diff --git a/UI/event_syncer.ts b/UI/event_syncer.ts index 75b0f2e..e925fd3 100644 --- a/UI/event_syncer.ts +++ b/UI/event_syncer.ts @@ -9,9 +9,10 @@ import { verifyEvent } from "https://raw.githubusercontent.com/BlowaterNostr/nos export class EventSyncer { constructor(private readonly pool: ConnectionPool, private readonly db: Database_Contextual_View) {} syncEvent(id: NoteID) { - const iter = Array.from(this.db.filterEvents((e) => e.id == id.hex)); - if (iter.length > 0) { - return iter[0]; + for (const e of this.db.events) { + if (e.id == id.hex) { + return e; + } } return (async () => { let events = await this.pool.newSub("EventSyncer", { diff --git a/UI/message-panel.tsx b/UI/message-panel.tsx index f3329aa..4e583a5 100644 --- a/UI/message-panel.tsx +++ b/UI/message-panel.tsx @@ -9,7 +9,7 @@ import { DividerClass, IconButtonClass } from "./components/tw.ts"; import { sleep } from "https://raw.githubusercontent.com/BlowaterNostr/csp/master/csp.ts"; import { EventEmitter } from "../event-bus.ts"; -import { ChatMessage, groupContinuousMessages, parseContent, sortMessage, urlIsImage } from "./message.ts"; +import { ChatMessage, groupContinuousMessages, sortMessage, urlIsImage } from "./message.ts"; import { PublicKey } from "https://raw.githubusercontent.com/BlowaterNostr/nostr.ts/main/key.ts"; import { NostrEvent, @@ -28,7 +28,7 @@ import { UserDetail } from "./user-detail.tsx"; import { MessageThreadPanel } from "./message-thread-panel.tsx"; import { Database_Contextual_View } from "../database.ts"; import { HoverButtonBackgroudColor, LinkColor, PrimaryTextColor } from "./style/colors.ts"; -import { ProfilesSyncer } from "./contact-list.ts"; +import { ProfilesSyncer, UserInfo } from "./contact-list.ts"; import { NoteID } from "https://raw.githubusercontent.com/BlowaterNostr/nostr.ts/main/nip19.ts"; import { EventSyncer } from "./event_syncer.ts"; @@ -55,6 +55,7 @@ interface DirectMessagePanelProps { >; profilesSyncer: ProfilesSyncer; eventSyncer: EventSyncer; + allUserInfo: Map; } export type RightPanelModel = { @@ -102,6 +103,7 @@ export function MessagePanel(props: DirectMessagePanelProps) { editorModel={props.focusedContent.editor} profilesSyncer={props.profilesSyncer} eventSyncer={props.eventSyncer} + allUserInfo={props.allUserInfo} /> ); } else if (props.focusedContent.type == "ProfileData") { @@ -140,6 +142,7 @@ export function MessagePanel(props: DirectMessagePanelProps) { db={props.db} profilesSyncer={props.profilesSyncer} eventSyncer={props.eventSyncer} + allUserInfo={props.allUserInfo} /> } { @@ -187,6 +190,7 @@ interface MessageListProps { eventEmitter: EventEmitter; profilesSyncer: ProfilesSyncer; eventSyncer: EventSyncer; + allUserInfo: Map; } interface MessageListState { @@ -246,10 +250,12 @@ export class MessageList extends Component { }); console.log("MessageList:groupContinuousMessages", Date.now() - t); const messageBoxGroups = []; + let i = 0; for (const threads of groups) { messageBoxGroups.push( MessageBoxGroup({ messageGroup: threads.map((thread) => { + i++; return { msg: thread.root, replyCount: thread.replies.length, @@ -260,10 +266,11 @@ export class MessageList extends Component { db: this.props.db, profilesSyncer: this.props.profilesSyncer, eventSyncer: this.props.eventSyncer, + allUserInfo: this.props.allUserInfo, }), ); } - console.log("MessageList:elements", Date.now() - t); + console.log(`MessageList:elements ${i}`, Date.now() - t); const vNode = (
; eventEmitter: EventEmitter; profilesSyncer: ProfilesSyncer; eventSyncer: EventSyncer; @@ -355,7 +363,13 @@ function MessageBoxGroup(props: {
-                                {ParseMessageContent(msg.msg, props.db, props.profilesSyncer, props.eventSyncer, props.eventEmitter)}
+                                {ParseMessageContent(
+                                    msg.msg,
+                                    props.allUserInfo,
+                                    props.profilesSyncer,
+                                    props.eventSyncer,
+                                    props.eventEmitter,
+                                    )}
                             
{msg.replyCount > 0 ? ( @@ -443,7 +457,7 @@ export function NameAndTime(message: ChatMessage, index: number, myPublicKey: Pu export function ParseMessageContent( message: ChatMessage, - db: Database_Contextual_View, + allUserInfo: Map, profilesSyncer: ProfilesSyncer, eventSyncer: EventSyncer, eventEmitter: EventEmitter, @@ -454,44 +468,52 @@ export function ParseMessageContent( const vnode = []; let start = 0; - for (const item of parseContent(message.content)) { - const itemStr = message.content.slice(item.start, item.end + 1); + for (const item of message.event.parsedContentItems) { vnode.push(message.content.slice(start, item.start)); + const itemStr = message.content.slice(item.start, item.end + 1); switch (item.type) { case "url": - if (urlIsImage(itemStr)) { - vnode.push(); - } else { - vnode.push( - - {itemStr} - , - ); + { + if (urlIsImage(itemStr)) { + vnode.push(); + } else { + vnode.push( + + {itemStr} + , + ); + } } break; case "npub": - const pubkey = PublicKey.FromBech32(itemStr); - if (pubkey instanceof Error) { - continue; - } - const profile = getProfileEvent(db, pubkey); - if (profile) { - vnode.push(ProfileCard(profile.profile, pubkey, eventEmitter)); - } else { - profilesSyncer.add(pubkey.hex); + { + const userInfo = allUserInfo.get(item.pubkey); + if (userInfo) { + const profile = userInfo.profile; + if (profile) { + vnode.push( + ProfileCard( + profile.profile, + PublicKey.FromHex(item.pubkey) as PublicKey, + eventEmitter, + ), + ); + } else { + profilesSyncer.add(item.pubkey); + } + } else { + profilesSyncer.add(item.pubkey); + } } break; case "note": - const note = NoteID.FromBech32(itemStr); - if (note instanceof Error) { - console.error(note); - break; + { + const event = eventSyncer.syncEvent(item.noteID); + if (event instanceof Promise) { + break; + } + vnode.push(NoteCard(event, eventEmitter, allUserInfo)); } - const event = eventSyncer.syncEvent(note); - if (event instanceof Promise) { - break; - } - vnode.push(NoteCard(event, eventEmitter, db)); break; case "tag": // todo @@ -519,7 +541,7 @@ function ProfileCard(profile: ProfileData, pubkey: PublicKey, eventEmitter: Even

- {profile.name || pubkey.bech32} + {profile.name || pubkey.bech32()}

@@ -531,14 +553,14 @@ function ProfileCard(profile: ProfileData, pubkey: PublicKey, eventEmitter: Even function NoteCard( event: Profile_Nostr_Event | PlainText_Nostr_Event | Decrypted_Nostr_Event, eventEmitter: EventEmitter, - db: Database_Contextual_View, + allUserInfo: Map, ) { switch (event.kind) { case NostrKind.META_DATA: return ProfileCard(event.profile, event.publicKey, eventEmitter); case NostrKind.TEXT_NOTE: case NostrKind.DIRECT_MESSAGE: - const profile = getProfileEvent(db, event.publicKey); + const profile = allUserInfo.get(event.pubkey)?.profile; return (
diff --git a/UI/message-thread-panel.tsx b/UI/message-thread-panel.tsx index 220153e..3d67d7e 100644 --- a/UI/message-thread-panel.tsx +++ b/UI/message-thread-panel.tsx @@ -14,7 +14,7 @@ import { PublicKey } from "https://raw.githubusercontent.com/BlowaterNostr/nostr import { ChatMessage, groupContinuousMessages } from "./message.ts"; import { Editor, EditorEvent, EditorModel } from "./editor.tsx"; import { Database_Contextual_View } from "../database.ts"; -import { ProfilesSyncer } from "./contact-list.ts"; +import { ProfilesSyncer, UserInfo } from "./contact-list.ts"; import { EventSyncer } from "./event_syncer.ts"; interface MessageThreadProps { @@ -25,6 +25,7 @@ interface MessageThreadProps { editorModel: EditorModel; profilesSyncer: ProfilesSyncer; eventSyncer: EventSyncer; + allUserInfo: Map; } export function MessageThreadPanel(props: MessageThreadProps) { @@ -48,6 +49,7 @@ export function MessageThreadPanel(props: MessageThreadProps) { profilesSyncer={props.profilesSyncer} eventSyncer={props.eventSyncer} eventEmitter={props.eventEmitter} + allUserInfo={props.allUserInfo} />
@@ -68,6 +70,7 @@ function MessageThreadList(props: { profilesSyncer: ProfilesSyncer; eventSyncer: EventSyncer; eventEmitter: EventEmitter; + allUserInfo: Map; }) { let groups = groupContinuousMessages(props.messages, (pre, cur) => { const sameAuthor = pre.event.pubkey == cur.event.pubkey; @@ -84,6 +87,7 @@ function MessageThreadList(props: { profilesSyncer={props.profilesSyncer} eventSyncer={props.eventSyncer} eventEmitter={props.eventEmitter} + allUserInfo={props.allUserInfo} />, ); } @@ -103,6 +107,7 @@ function MessageThreadBoxGroup(props: { profilesSyncer: ProfilesSyncer; eventSyncer: EventSyncer; eventEmitter: EventEmitter; + allUserInfo: Map; }) { const vnode = (
    @@ -120,7 +125,7 @@ function MessageThreadBoxGroup(props: {
    -                                {ParseMessageContent(msg, props.db, props.profilesSyncer, props.eventSyncer, props.eventEmitter)}
    +                                {ParseMessageContent(msg, props.allUserInfo, props.profilesSyncer, props.eventSyncer, props.eventEmitter)}
                                 
diff --git a/UI/message.test.ts b/UI/message.test.ts index 62d5c33..dee8220 100644 --- a/UI/message.test.ts +++ b/UI/message.test.ts @@ -1,7 +1,6 @@ import { assertEquals } from "https://deno.land/std@0.176.0/testing/asserts.ts"; import { ChatMessage, groupContinuousMessages, parseContent } from "./message.ts"; -import { PublicKey } from "https://raw.githubusercontent.com/BlowaterNostr/nostr.ts/main/key.ts"; -import { PrivateKey } from "https://raw.githubusercontent.com/BlowaterNostr/nostr.ts/main/key.ts"; +import { PrivateKey, PublicKey } from "https://raw.githubusercontent.com/BlowaterNostr/nostr.ts/main/key.ts"; Deno.test("inline parse", async (t) => { const data = [ @@ -69,6 +68,7 @@ Deno.test("inline parse", async (t) => { input: `nostr:npub17dxnfw2vrhgtk4fgqdmpuqxv05u9raau3w0shay7msmr0dzs4m7s6ng4ylログボ`, output: [{ type: "npub", + pubkey: "f34d34b94c1dd0bb552803761e00cc7d3851f7bc8b9f0bf49edc3637b450aefd", start: 6, end: 68, }], @@ -117,6 +117,12 @@ Deno.test("message group", () => { pubkey: "", sig: "", tags: [], + parsedContentItems: [], + parsedTags: { + e: [], + p: [], + }, + publicKey: PrivateKey.Generate().toPublicKey(), }, "content": "sendDirectMessage", "type": "text", diff --git a/UI/message.ts b/UI/message.ts index 384e86a..401e7c7 100644 --- a/UI/message.ts +++ b/UI/message.ts @@ -1,6 +1,7 @@ import { PublicKey } from "https://raw.githubusercontent.com/BlowaterNostr/nostr.ts/main/key.ts"; import { MessageThread } from "./dm.tsx"; -import { NostrEvent } from "https://raw.githubusercontent.com/BlowaterNostr/nostr.ts/main/nostr.ts"; +import { PlainText_Nostr_Event } from "../nostr.ts"; +import { NoteID } from "https://raw.githubusercontent.com/BlowaterNostr/nostr.ts/main/nip19.ts"; export function* parseContent(content: string) { // URLs @@ -27,24 +28,61 @@ function* match(regex: RegExp, content: string, type: ItemType): Generator, ) { const t = Date.now(); - const events = db.filterEvents((e) => e.kind == NostrKind.TEXT_NOTE); + const events = []; + for (const e of db.events) { + if (e.kind == NostrKind.TEXT_NOTE) { + events.push(e); + } + } console.log("getSocialPosts:filterEvents", Date.now() - t); const threads = computeThreads(events); console.log("getSocialPosts:computeThreads", Date.now() - t); diff --git a/nostr.test.ts b/nostr.test.ts index 8993e2c..b147f03 100644 --- a/nostr.test.ts +++ b/nostr.test.ts @@ -19,13 +19,15 @@ import { groupImageEvents, Parsed_Event, parsedTagsEvent, + PlainText_Nostr_Event, prepareNostrImageEvents, prepareReplyEvent, reassembleBase64ImageFromEvents, } from "./nostr.ts"; import { LamportTime } from "./time.ts"; -import { PrivateKey } from "https://raw.githubusercontent.com/BlowaterNostr/nostr.ts/main/key.ts"; +import { PrivateKey, PublicKey } from "https://raw.githubusercontent.com/BlowaterNostr/nostr.ts/main/key.ts"; import { ParseMessageContent } from "./UI/message-panel.tsx"; +import { parseContent } from "./UI/message.ts"; Deno.test("prepareNostrImageEvents", async (t) => { const pri = PrivateKey.Generate(); @@ -109,14 +111,37 @@ Deno.test("groupImageEvents", async () => { fail(imgEvents2.message); } const [events2, id2] = imgEvents2; - const groups = groupImageEvents(events1.concat(events2)); + const groups = groupImageEvents( + events1.concat(events2).map((e): Parsed_Event => ({ + ...e, + kind: e.kind as NostrKind.DIRECT_MESSAGE, + publicKey: PublicKey.FromHex(e.pubkey) as PublicKey, + parsedTags: getTags(e), + })), + ); assertEquals(groups.size, 2); - const group1 = groups.get(id1); + const group1 = groups.get(id1)?.map((e): NostrEvent => ({ + content: e.content, + created_at: e.created_at, + id: e.id, + kind: e.kind, + pubkey: e.pubkey, + sig: e.sig, + tags: e.tags, + })); assertNotEquals(group1, undefined); assertEquals(group1, events1); - const group2 = groups.get(id2); + const group2 = groups.get(id2)?.map((e): NostrEvent => ({ + content: e.content, + created_at: e.created_at, + id: e.id, + kind: e.kind, + pubkey: e.pubkey, + sig: e.sig, + tags: e.tags, + })); assertNotEquals(group2, undefined); assertEquals(group2, events2); }); diff --git a/nostr.ts b/nostr.ts index 6beb064..3c6e6f5 100644 --- a/nostr.ts +++ b/nostr.ts @@ -11,6 +11,7 @@ import { TagPubKey, } from "https://raw.githubusercontent.com/BlowaterNostr/nostr.ts/main/nostr.ts"; import { ProfileData } from "./features/profile.ts"; +import { ContentItem } from "./UI/message.ts"; type TotolChunks = string; type ChunkIndex = string; // 0-indexed @@ -145,9 +146,9 @@ export function reassembleBase64ImageFromEvents( return chunks.join(""); } -export function groupImageEvents(events: Iterable) { +export function groupImageEvents(events: Iterable) { return groupBy(events, (event) => { - const tags = getTags(event); + const tags = event.parsedTags; const imageTag = tags.image; if (imageTag == undefined) { return undefined; @@ -287,9 +288,14 @@ export type Decrypted_Nostr_Event = Parsed_Event & { export type Decryptable_Nostr_Event = nostr.NostrEvent; -export type PlainText_Nostr_Event = Parsed_Event< - Exclude // todo: exclude DM as well ->; +export type PlainText_Nostr_Event = + & Parsed_Event< + Exclude // todo: exclude DM as well + > + & { + parsedContentItems: ContentItem[]; + }; + export type Profile_Nostr_Event = Parsed_Event & { profile: ProfileData; };