Group Chat is working! (#224)

GroupSyncer
This commit is contained in:
BlowaterNostr 2023-10-08 22:08:18 +00:00 committed by GitHub
parent 0bfa86e55d
commit ea4199d05b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 77 additions and 22 deletions

View File

@ -26,10 +26,9 @@ import { About } from "./about.tsx";
import { ProfileSyncer } from "../features/profile.ts";
import { Popover, PopOverInputChannel } from "./components/popover.tsx";
import { Channel } from "https://raw.githubusercontent.com/BlowaterNostr/csp/master/csp.ts";
import { GroupChatController } from "../group-chat.ts";
import { GroupChatController, GroupChatSyncer } from "../group-chat.ts";
import { OtherConfig } from "./config-other.ts";
import { ProfileGetter } from "./search.tsx";
import { ZodError } from "https://esm.sh/zod@3.22.4";
import { fromEvents } from "../time.ts";
export async function Start(database: DexieDatabase) {
@ -138,7 +137,13 @@ export class App {
const conversationLists = new ConversationLists(args.ctx, profileSyncer);
conversationLists.addEvents(args.database.events);
const groupChatController = new GroupChatController(args.ctx, conversationLists);
const groupSyncer = new GroupChatSyncer(args.database, args.pool);
const groupChatController = new GroupChatController(
args.ctx,
conversationLists,
groupSyncer,
profileSyncer,
);
for (const e of args.database.events) {
if (e.kind == NostrKind.Group_Message) {
const err = await groupChatController.addEvent({

View File

@ -11,15 +11,15 @@ import { convertEventsToChatMessages } from "./dm.ts";
import { sendDMandImages } from "../features/dm.ts";
import { notify } from "./notification.ts";
import { emitFunc, EventBus } from "../event-bus.ts";
import { EventBus } from "../event-bus.ts";
import { ContactUpdate } from "./conversation-list.tsx";
import { MyProfileUpdate } from "./edit-profile.tsx";
import { EditorEvent, EditorModel, new_DM_EditorModel, SendMessage } from "./editor.tsx";
import { DirectMessagePanelUpdate } from "./message-panel.tsx";
import { NavigationUpdate } from "./nav.tsx";
import { Model } from "./app_model.ts";
import { SearchUpdate, SelectConversation } from "./search_model.ts";
import { fromEvents, LamportTime } from "../time.ts";
import { SearchUpdate } from "./search_model.ts";
import { LamportTime } from "../time.ts";
import { SignInEvent, signInWithExtension, signInWithPrivateKey } from "./signIn.tsx";
import {
DirectedMessage_Event,
@ -39,11 +39,11 @@ import { EventDetail, EventDetailItem } from "./event-detail.tsx";
import { CreateGroup, CreateGroupChat, StartCreateGroupChat } from "./create-group.tsx";
import { prepareEncryptedNostrEvent, prepareNormalNostrEvent } from "../lib/nostr-ts/event.ts";
import { PublicKey } from "../lib/nostr-ts/key.ts";
import { InMemoryAccountContext, NostrAccountContext, NostrEvent, NostrKind } from "../lib/nostr-ts/nostr.ts";
import { NostrAccountContext, NostrEvent, NostrKind } from "../lib/nostr-ts/nostr.ts";
import { ConnectionPool } from "../lib/nostr-ts/relay.ts";
import { OtherConfig } from "./config-other.ts";
import { EditGroup, EditGroupChatProfile, StartEditGroupChatProfile } from "./edit-group.tsx";
import { GroupChatController, GroupMessage } from "../group-chat.ts";
import { GroupChatController } from "../group-chat.ts";
import { ChatMessage } from "./message.ts";
export type UI_Interaction_Event =
@ -692,19 +692,19 @@ export async function handle_SendMessage(
}
} else {
// todo: hack, change later
const invitation = isInvitation(event.text);
if (invitation) {
const invitationEvent = await groupControl.createInvitation(invitation, event.pubkey);
if (invitationEvent instanceof Error) {
return invitationEvent;
}
console.log(invitationEvent);
const err = await pool.sendEvent(invitationEvent);
if (err instanceof Error) {
return err;
}
return;
}
// const invitation = isInvitation(event.text);
// if (invitation) {
// const invitationEvent = await groupControl.createInvitation(invitation, event.pubkey);
// if (invitationEvent instanceof Error) {
// return invitationEvent;
// }
// console.log(invitationEvent);
// const err = await pool.sendEvent(invitationEvent);
// if (err instanceof Error) {
// return err;
// }
// return;
// }
const events = await sendDMandImages({
sender: ctx,
receiverPublicKey: event.pubkey,

View File

@ -1,6 +1,6 @@
import { z } from "https://esm.sh/zod@3.22.4";
import { ConversationLists, ConversationSummary } from "./UI/conversation-list.ts";
import { parseJSON } from "./features/profile.ts";
import { parseJSON, ProfileSyncer } from "./features/profile.ts";
import { prepareEncryptedNostrEvent } from "./lib/nostr-ts/event.ts";
import { PrivateKey, PublicKey } from "./lib/nostr-ts/key.ts";
import { InMemoryAccountContext, NostrAccountContext, NostrEvent, NostrKind } from "./lib/nostr-ts/nostr.ts";
@ -8,6 +8,9 @@ import { GroupMessageGetter } from "./UI/app_update.tsx";
import { getTags } from "./nostr.ts";
import { ChatMessage } from "./UI/message.ts";
import { GroupChatListGetter } from "./UI/conversation-list.tsx";
import { Channel, semaphore } from "https://raw.githubusercontent.com/BlowaterNostr/csp/master/csp.ts";
import { ConnectionPool } from "./lib/nostr-ts/relay.ts";
import { Database_Contextual_View } from "./database.ts";
export type GM_Types = "gm_creation" | "gm_message" | "gm_invitation";
@ -29,10 +32,13 @@ export class GroupChatController implements GroupMessageGetter, GroupChatListGet
created_groups = new Map<string, GroupChatCreation>();
invitations = new Map<string, GroupChatInvitation>();
messages = new Map<string, ChatMessage[]>();
resync_chan = new Channel<null>();
constructor(
private readonly ctx: NostrAccountContext,
private readonly conversationLists: ConversationLists,
private readonly groupSyncer: GroupChatSyncer,
private readonly profileSyncer: ProfileSyncer,
) {}
getGroupChat() {
@ -79,6 +85,8 @@ export class GroupChatController implements GroupMessageGetter, GroupChatListGet
groupKey: InMemoryAccountContext.New(PrivateKey.Generate()),
};
this.created_groups.set(groupChatCreation.groupKey.publicKey.bech32(), groupChatCreation);
this.groupSyncer.add(groupChatCreation.groupKey.publicKey.hex);
this.profileSyncer.add(groupChatCreation.groupKey.publicKey.hex);
return groupChatCreation;
}
@ -153,6 +161,8 @@ export class GroupChatController implements GroupMessageGetter, GroupChatListGet
groupAddr,
};
this.invitations.set(groupAddr.bech32(), invitation);
this.groupSyncer.add(groupAddr.hex);
this.profileSyncer.add(groupAddr.hex);
}
async handleMessage(event: NostrEvent<NostrKind.Group_Message>) {
@ -249,6 +259,8 @@ export class GroupChatController implements GroupMessageGetter, GroupChatListGet
cipherKey: InMemoryAccountContext.New(cipherKey),
};
this.created_groups.set(groupKey.toPublicKey().bech32(), groupChatCreation);
this.groupSyncer.add(groupKey.toPublicKey().hex);
this.profileSyncer.add(groupKey.toPublicKey().hex);
this.conversationLists.addGroupCreation(groupChatCreation);
} else if (content.type == "gm_message") {
@ -321,3 +333,41 @@ async function eventType(
}
return "gm_message";
}
export class GroupChatSyncer {
readonly groupAddrSet = new Set<string>();
private readonly lock = semaphore(1);
constructor(
private readonly database: Database_Contextual_View,
private readonly pool: ConnectionPool,
) {
}
async add(...groupAddresses: string[]) {
const size = this.groupAddrSet.size;
for (const groupAddr of groupAddresses) {
this.groupAddrSet.add(groupAddr);
}
if (this.groupAddrSet.size == size) {
return;
}
const resp = await this.lock(async () => {
await this.pool.closeSub(GroupChatSyncer.name);
const resp = await this.pool.newSub(GroupChatSyncer.name, {
"#p": Array.from(this.groupAddrSet),
kinds: [NostrKind.Group_Message],
});
return resp;
});
if (resp instanceof Error) {
console.log(resp);
return;
}
for await (let { res: nostrMessage, url: relayUrl } of resp.chan) {
if (nostrMessage.type === "EVENT" && nostrMessage.event.content) {
this.database.addEvent(nostrMessage.event);
}
}
}
}