diff --git a/UI/app.tsx b/UI/app.tsx
index b3e8da9..36440a7 100644
--- a/UI/app.tsx
+++ b/UI/app.tsx
@@ -14,10 +14,9 @@ import { MessagePanel } from "./message-panel.tsx";
import { Setting } from "./setting.tsx";
import { Database_Contextual_View } from "../database.ts";
-import { getAllUsersInformation, ProfilesSyncer, UserInfo } from "./contact-list.ts";
+import { AllUsersInformation, ProfilesSyncer, UserInfo } from "./contact-list.ts";
import { new_DM_EditorModel } from "./editor.tsx";
-import { Channel } from "https://raw.githubusercontent.com/BlowaterNostr/csp/master/csp.ts";
import { initialModel, Model } from "./app_model.ts";
import {
AppEventBus,
@@ -156,6 +155,7 @@ async function initProfileSyncer(
export class App {
profileSyncer!: ProfilesSyncer;
eventSyncer: EventSyncer;
+ public readonly allUsersInfo: AllUsersInformation;
constructor(
public readonly database: Database_Contextual_View,
@@ -166,10 +166,11 @@ export class App {
public readonly relayPool: ConnectionPool,
) {
this.eventSyncer = new EventSyncer(this.relayPool, this.database);
+ this.allUsersInfo = new AllUsersInformation(myAccountContext);
}
initApp = async (accountContext: NostrAccountContext) => {
- const events = this.database.filterEvents((e) => e.kind == NostrKind.TEXT_NOTE);
+ // const events = this.database.filterEvents((e) => e.kind == NostrKind.TEXT_NOTE);
console.log("App.initApp");
const profilesSyncer = await initProfileSyncer(this.relayPool, accountContext, this.database);
@@ -179,15 +180,16 @@ export class App {
this.profileSyncer = profilesSyncer;
- this.model.allUsersInfo = getAllUsersInformation(this.database, this.myAccountContext);
+ this.allUsersInfo.addEvents(this.database.events);
console.log("App allUsersInfo");
- this.model.social.threads = getSocialPosts(this.database, this.model.allUsersInfo);
+ this.model.social.threads = getSocialPosts(this.database, this.allUsersInfo.userInfos);
/* my profile */
- this.model.myProfile = this.model.allUsersInfo.get(accountContext.publicKey.hex)?.profile?.profile;
+ this.model.myProfile = this.allUsersInfo.userInfos.get(accountContext.publicKey.hex)?.profile
+ ?.profile;
/* contacts */
- for (const contact of this.model.allUsersInfo.values()) {
+ for (const contact of this.allUsersInfo.userInfos.values()) {
const editor = this.model.editors.get(contact.pubkey.hex);
if (editor == null) {
const pubkey = PublicKey.FromHex(contact.pubkey.hex);
@@ -206,7 +208,7 @@ export class App {
}
await profilesSyncer.add(
- ...Array.from(this.model.allUsersInfo.keys()),
+ ...Array.from(this.allUsersInfo.userInfos.keys()),
);
console.log("user set", profilesSyncer.userSet);
@@ -221,6 +223,7 @@ export class App {
this.profileSyncer,
this.lamport,
this.eventBus,
+ this.allUsersInfo,
)
) {
render(, document.body);
@@ -261,7 +264,11 @@ export function AppComponent(props: {
if (model.navigationModel.activeNav == "Social") {
let focusedContentGetter = () => {
// console.log("AppComponent:getFocusedContent before", Date.now() - t);
- let _ = getFocusedContent(model.social.focusedContent, model.allUsersInfo, model.social.threads);
+ let _ = getFocusedContent(
+ model.social.focusedContent,
+ app.allUsersInfo.userInfos,
+ model.social.threads,
+ );
// console.log("AppComponent:getFocusedContent", Date.now() - t);
if (_?.type === "MessageThread") {
let editor = model.social.replyEditors.get(_.data.root.event.id);
@@ -354,7 +361,7 @@ export function AppComponent(props: {
myAccountContext: myAccountCtx,
db: app.database,
pool: app.relayPool,
- allUserInfo: model.allUsersInfo,
+ allUserInfo: app.allUsersInfo.userInfos,
profilesSyncer: app.profileSyncer,
eventSyncer: app.eventSyncer,
})}
diff --git a/UI/app_model.ts b/UI/app_model.ts
index 6a10b62..5fbaaf8 100644
--- a/UI/app_model.ts
+++ b/UI/app_model.ts
@@ -24,7 +24,7 @@ export type Model = {
key: string;
value: string;
};
- allUsersInfo: Map;
+ // allUsersInfo: Map;
// social
social: {
@@ -57,7 +57,7 @@ export function initialModel(): Model {
hasNewMessages: new Set(),
currentSelectedContact: undefined,
},
- allUsersInfo: new Map(),
+ // allUsersInfo: new Map(),
editors: editors,
newProfileField: {
key: "",
diff --git a/UI/app_update.ts b/UI/app_update.ts
index 322701f..017e160 100644
--- a/UI/app_update.ts
+++ b/UI/app_update.ts
@@ -1,7 +1,7 @@
import { getProfileEvent, getProfilesByName, saveProfile } from "../features/profile.ts";
import { App } from "./app.tsx";
-import { getAllUsersInformation, getGroupOf, ProfilesSyncer, UserInfo } from "./contact-list.ts";
+import { AllUsersInformation, getGroupOf, ProfilesSyncer, UserInfo } from "./contact-list.ts";
import * as csp from "https://raw.githubusercontent.com/BlowaterNostr/csp/master/csp.ts";
import { Database_Contextual_View } from "../database.ts";
@@ -27,7 +27,15 @@ import {
} from "https://raw.githubusercontent.com/BlowaterNostr/nostr.ts/main/nostr.ts";
import { ConnectionPool } from "https://raw.githubusercontent.com/BlowaterNostr/nostr.ts/main/relay.ts";
import { SignInEvent, signInWithExtension, signInWithPrivateKey } from "./signIn.tsx";
-import { computeThreads, getTags, PinContact, UnpinContact } from "../nostr.ts";
+import {
+ computeThreads,
+ Decrypted_Nostr_Event,
+ getTags,
+ PinContact,
+ PlainText_Nostr_Event,
+ Profile_Nostr_Event,
+ UnpinContact,
+} from "../nostr.ts";
import { MessageThread } from "./dm.tsx";
import { DexieDatabase } from "./dexie-db.ts";
import { getSocialPosts } from "../features/social.ts";
@@ -192,7 +200,7 @@ export async function* UI_Interaction_Update(
};
const group = getGroupOf(
event.pubkey,
- model.allUsersInfo,
+ model.app.allUsersInfo.userInfos,
);
model.dm.selectedContactGroup = group;
updateConversation(model.app.model, event.pubkey);
@@ -440,12 +448,13 @@ export async function* Database_Update(
profileSyncer: ProfilesSyncer,
lamport: LamportTime,
eventEmitter: EventEmitter,
+ allUserInfo: AllUsersInformation,
) {
const changes = database.onChange((_) => true);
while (true) {
await csp.sleep(333);
await changes.ready();
- const changes_events: NostrEvent[] = [];
+ const changes_events: (PlainText_Nostr_Event | Decrypted_Nostr_Event | Profile_Nostr_Event)[] = [];
while (true) {
if (!changes.isReadyToPop()) {
break;
@@ -460,7 +469,7 @@ export async function* Database_Update(
let hasKind_1 = false;
for (let e of changes_events) {
- model.allUsersInfo = getAllUsersInformation(database, ctx);
+ allUserInfo.addEvents([e]);
const t = getTags(e).lamport_timestamp;
if (t) {
lamport.set(t);
@@ -470,7 +479,7 @@ export async function* Database_Update(
await profileSyncer.add(key.hex);
}
if (e.kind == NostrKind.META_DATA || e.kind == NostrKind.DIRECT_MESSAGE) {
- for (const contact of model.allUsersInfo.values()) {
+ for (const contact of allUserInfo.userInfos.values()) {
const editor = model.editors.get(contact.pubkey.hex);
if (editor == null) { // a stranger sends a message
const pubkey = PublicKey.FromHex(contact.pubkey.hex);
@@ -547,7 +556,7 @@ export async function* Database_Update(
}
}
if (hasKind_1) {
- model.social.threads = getSocialPosts(database, model.allUsersInfo);
+ model.social.threads = getSocialPosts(database, allUserInfo.userInfos);
}
yield model;
}
diff --git a/UI/contact-list.ts b/UI/contact-list.ts
index 5ebffe8..a54e241 100644
--- a/UI/contact-list.ts
+++ b/UI/contact-list.ts
@@ -1,5 +1,5 @@
import { Database_Contextual_View } from "../database.ts";
-import { ProfileFromNostrEvent, profilesStream } from "../features/profile.ts";
+import { profilesStream } from "../features/profile.ts";
import { Channel } from "https://raw.githubusercontent.com/BlowaterNostr/csp/master/csp.ts";
import { ContactGroup } from "./contact-list.tsx";
@@ -13,8 +13,13 @@ import {
ConnectionPool,
newSubID,
} from "https://raw.githubusercontent.com/BlowaterNostr/nostr.ts/main/relay.ts";
-import { CustomAppData, getTags, Profile_Nostr_Event } from "../nostr.ts";
-import { assertEquals } from "https://deno.land/std@0.176.0/testing/asserts.ts";
+import {
+ CustomAppData,
+ Decrypted_Nostr_Event,
+ getTags,
+ PlainText_Nostr_Event,
+ Profile_Nostr_Event,
+} from "../nostr.ts";
export interface UserInfo {
pubkey: PublicKey;
@@ -97,18 +102,18 @@ function socialPostsStream(pubkeys: Iterable, pool: ConnectionPool) {
return chan;
}
-export function getAllUsersInformation(
- database: Database_Contextual_View,
- ctx: NostrAccountContext,
-): Map {
- const t = Date.now();
- const res = new Map();
- {
- for (const event of database.filterEvents((_) => true)) {
+export class AllUsersInformation {
+ readonly userInfos = new Map();
+
+ constructor(public readonly ctx: NostrAccountContext) {}
+
+ addEvents(events: (Profile_Nostr_Event | PlainText_Nostr_Event | Decrypted_Nostr_Event)[]) {
+ // const t = Date.now();
+ for (const event of events) {
switch (event.kind) {
case NostrKind.META_DATA:
{
- const userInfo = res.get(event.pubkey);
+ const userInfo = this.userInfos.get(event.pubkey);
const profileEvent = event;
if (userInfo) {
if (userInfo.profile) {
@@ -126,7 +131,7 @@ export function getAllUsersInformation(
newestEventSendByMe: undefined,
profile: profileEvent,
};
- res.set(event.pubkey, newUserInfo);
+ this.userInfos.set(event.pubkey, newUserInfo);
}
}
break;
@@ -139,19 +144,19 @@ export function getAllUsersInformation(
case NostrKind.DIRECT_MESSAGE:
{
let whoAm_I_TalkingTo = "";
- if (event.pubkey == ctx.publicKey.hex) {
+ if (event.pubkey == this.ctx.publicKey.hex) {
// I am the sender
whoAm_I_TalkingTo = getTags(event).p[0];
- } else if (getTags(event).p[0] == ctx.publicKey.hex) {
+ } else if (getTags(event).p[0] == this.ctx.publicKey.hex) {
// I am the receiver
whoAm_I_TalkingTo = event.pubkey;
} else {
// I am neither. Possible because other user has used this device before
break;
}
- const userInfo = res.get(whoAm_I_TalkingTo);
+ const userInfo = this.userInfos.get(whoAm_I_TalkingTo);
if (userInfo) {
- if (whoAm_I_TalkingTo == ctx.publicKey.hex) {
+ if (whoAm_I_TalkingTo == this.ctx.publicKey.hex) {
// talking to myself
if (userInfo.newestEventSendByMe) {
if (event.created_at > userInfo.newestEventSendByMe?.created_at) {
@@ -163,7 +168,7 @@ export function getAllUsersInformation(
userInfo.newestEventReceivedByMe = event;
}
} else {
- if (ctx.publicKey.hex == event.pubkey) {
+ if (this.ctx.publicKey.hex == event.pubkey) {
// I am the sender
if (userInfo.newestEventSendByMe) {
if (event.created_at > userInfo.newestEventSendByMe.created_at) {
@@ -191,12 +196,12 @@ export function getAllUsersInformation(
newestEventSendByMe: undefined,
profile: undefined,
};
- if (whoAm_I_TalkingTo == ctx.publicKey.hex) {
+ if (whoAm_I_TalkingTo == this.ctx.publicKey.hex) {
// talking to myself
newUserInfo.newestEventSendByMe = event;
newUserInfo.newestEventReceivedByMe = event;
} else {
- if (ctx.publicKey.hex == event.pubkey) {
+ if (this.ctx.publicKey.hex == event.pubkey) {
// I am the sender
newUserInfo.newestEventSendByMe = event;
} else {
@@ -204,7 +209,7 @@ export function getAllUsersInformation(
newUserInfo.newestEventReceivedByMe = event;
}
}
- res.set(whoAm_I_TalkingTo, newUserInfo);
+ this.userInfos.set(whoAm_I_TalkingTo, newUserInfo);
}
}
break;
@@ -216,7 +221,7 @@ export function getAllUsersInformation(
}
const obj: CustomAppData = JSON.parse(event.decryptedContent);
if (obj.type == "PinContact" || obj.type == "UnpinContact") {
- const userInfo = res.get(obj.pubkey);
+ const userInfo = this.userInfos.get(obj.pubkey);
if (userInfo) {
if (userInfo.pinEvent) {
if (event.created_at > userInfo.pinEvent.created_at) {
@@ -232,7 +237,7 @@ export function getAllUsersInformation(
};
}
} else {
- res.set(obj.pubkey, {
+ this.userInfos.set(obj.pubkey, {
pubkey: PublicKey.FromHex(obj.pubkey) as PublicKey, // todo: could throw
pinEvent: {
content: obj,
@@ -247,17 +252,8 @@ export function getAllUsersInformation(
}
}
}
+ // console.log("AllUsersInformation:addEvents", Date.now() - t);
}
- // todo: should write a unit test for it instead of runtime assertion
- for (const [pubkey, userInfo] of res) {
- assertEquals(pubkey, userInfo.pubkey.hex);
- if (userInfo.profile) {
- assertEquals(pubkey, userInfo.profile.pubkey);
- }
- }
-
- console.log("getAllUsersInformation", Date.now() - t);
- return res;
}
export const sortUserInfo = (a: UserInfo, b: UserInfo) => {
diff --git a/database.ts b/database.ts
index f55d45f..ba8bd81 100644
--- a/database.ts
+++ b/database.ts
@@ -332,9 +332,11 @@ export class Database_Contextual_View {
//////////////////
// On DB Change //
//////////////////
- onChange(filter: (e: NostrEvent) => boolean) {
+ onChange(filter: (e: PlainText_Nostr_Event | Decrypted_Nostr_Event | Profile_Nostr_Event) => boolean) {
const c = this.caster.copy();
- const res = csp.chan(buffer_size);
+ const res = csp.chan(
+ buffer_size,
+ );
(async () => {
for await (const newE of c) {
if (filter(newE)) {