Refactor groupChats and add images to group chats msgs (#145)

This commit is contained in:
Szymon Szlachtowicz 2021-12-03 14:36:06 +01:00 committed by GitHub
parent ff733a15fc
commit 3d48c1fe98
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 135 additions and 92 deletions

View File

@ -10,6 +10,7 @@ import {
import { ChannelData, ChannelsData } from "../../models/ChannelData"; import { ChannelData, ChannelsData } from "../../models/ChannelData";
import { ChatMessage } from "../../models/ChatMessage"; import { ChatMessage } from "../../models/ChatMessage";
import { Contact } from "../../models/Contact"; import { Contact } from "../../models/Contact";
import { uintToImgUrl } from "../../utils";
export function useGroupChats( export function useGroupChats(
messenger: Messenger | undefined, messenger: Messenger | undefined,
@ -54,11 +55,21 @@ export function useGroupChats(
type: "channel", type: "channel",
} as ChannelData); } as ChannelData);
}; };
const handleMessage = (msg: StatusChatMessage, sender: string) => const handleMessage = (msg: StatusChatMessage, sender: string) => {
let image: string | undefined = undefined;
if (msg.image) {
image = uintToImgUrl(msg.image.payload);
}
addChatMessage( addChatMessage(
new ChatMessage(msg.text ?? "", new Date(msg.clock ?? 0), sender), new ChatMessage(
msg.text ?? "",
new Date(msg.clock ?? 0),
sender,
image
),
msg.chatId msg.chatId
); );
};
return new GroupChats( return new GroupChats(
identity, identity,
messenger.waku, messenger.waku,

View File

@ -200,21 +200,25 @@ export function useMessenger(
const sendMessage = useCallback( const sendMessage = useCallback(
async (messageText?: string, image?: Uint8Array) => { async (messageText?: string, image?: Uint8Array) => {
if (activeChannel.type === "group") { let content;
groupChat?.sendMessage(activeChannel.id, messageText ?? ""); if (messageText) {
} else { content = {
if (messageText) { text: messageText,
await messenger?.sendMessage(activeChannel.id, { contentType: 0,
text: messageText, };
contentType: 0, }
}); if (image) {
} content = {
if (image) { image,
await messenger?.sendMessage(activeChannel.id, { imageType: 1,
image, contentType: 2,
imageType: 1, };
contentType: 2, }
}); if (content) {
if (activeChannel.type === "group") {
await groupChat?.sendMessage(activeChannel.id, content);
} else {
await messenger?.sendMessage(activeChannel.id, content);
} }
} }
}, },

View File

@ -4,9 +4,12 @@ import { Identity } from "./identity";
import { MembershipUpdateEvent_EventType } from "./proto/communities/v1/membership_update_message"; import { MembershipUpdateEvent_EventType } from "./proto/communities/v1/membership_update_message";
import { getNegotiatedTopic, getPartitionedTopic } from "./topics"; import { getNegotiatedTopic, getPartitionedTopic } from "./topics";
import { bufToHex } from "./utils"; import { bufToHex } from "./utils";
import { MembershipUpdateMessage } from "./wire/membership_update_message"; import {
MembershipSignedEvent,
MembershipUpdateMessage,
} from "./wire/membership_update_message";
import { ChatMessage, ContentType } from "."; import { ChatMessage, Content } from ".";
export type GroupChat = { export type GroupChat = {
chatId: string; chatId: string;
@ -65,16 +68,18 @@ export class GroupChats {
* *
* @param text text message to send * @param text text message to send
*/ */
public async sendMessage(chatId: string, text: string): Promise<void> { public async sendMessage(chatId: string, content: Content): Promise<void> {
const now = Date.now(); const now = Date.now();
const chat = this.chats[chatId]; const chat = this.chats[chatId];
if (chat) { if (chat) {
await Promise.all( await Promise.all(
chat.members.map(async (member) => { chat.members.map(async (member) => {
const chatMessage = ChatMessage.createMessage(now, now, chatId, { const chatMessage = ChatMessage.createMessage(
text, now,
contentType: ContentType.Text, now,
}); chatId,
content
);
const wakuMessage = await WakuMessage.fromBytes( const wakuMessage = await WakuMessage.fromBytes(
chatMessage.encode(), chatMessage.encode(),
await getNegotiatedTopic(this.identity, member) await getNegotiatedTopic(this.identity, member)
@ -85,82 +90,90 @@ export class GroupChats {
} }
} }
private async handleUpdateEvent(
chatId: string,
event: MembershipSignedEvent,
useCallback: boolean
): Promise<void> {
const signer = event.signer ? bufToHex(event.signer) : "";
const thisUser = bufToHex(this.identity.publicKey);
const chat: GroupChat | undefined = this.chats[chatId];
if (signer) {
switch (event.event.type) {
case MembershipUpdateEvent_EventType.CHAT_CREATED: {
await this.addChat(
{
chatId: chatId,
members: event.event.members,
admins: [signer],
removed: false,
},
useCallback
);
break;
}
case MembershipUpdateEvent_EventType.MEMBER_REMOVED: {
if (chat) {
chat.members = chat.members.filter(
(member) => !event.event.members.includes(member)
);
if (event.event.members.includes(thisUser)) {
await this.removeChat(
{
...chat,
removed: true,
},
useCallback
);
} else {
if (!chat.removed && useCallback) {
this.callback(this.chats[chatId]);
}
}
}
break;
}
case MembershipUpdateEvent_EventType.MEMBERS_ADDED: {
if (chat && chat.admins?.includes(signer)) {
chat.members.push(...event.event.members);
if (chat.members.includes(thisUser)) {
chat.removed = false;
await this.addChat(chat, useCallback);
}
}
break;
}
case MembershipUpdateEvent_EventType.NAME_CHANGED: {
if (chat) {
if (chat.admins?.includes(signer)) {
chat.name = event.event.name;
this.callback(chat);
}
}
break;
}
}
}
}
private async decodeUpdateMessage( private async decodeUpdateMessage(
message: WakuMessage, message: WakuMessage,
useCallback: boolean useCallback: boolean
): Promise<void> { ): Promise<void> {
try { try {
if (message.payload) { if (message?.payload) {
const membershipUpdate = MembershipUpdateMessage.decode( const membershipUpdate = MembershipUpdateMessage.decode(
message?.payload message.payload
); );
await Promise.all( await Promise.all(
membershipUpdate.events.map(async (event) => { membershipUpdate.events.map(
const signer = event.signer ? bufToHex(event.signer) : ""; async (event) =>
const thisUser = bufToHex(this.identity.publicKey); await this.handleUpdateEvent(
const chatId = membershipUpdate.chatId; membershipUpdate.chatId,
const chat: GroupChat | undefined = this.chats[chatId]; event,
useCallback
if (signer) { )
switch (event.event.type) { )
case MembershipUpdateEvent_EventType.CHAT_CREATED: {
await this.addChat(
{
chatId: chatId,
members: event.event.members,
admins: [signer],
removed: false,
},
useCallback
);
break;
}
case MembershipUpdateEvent_EventType.MEMBER_REMOVED: {
if (chat) {
chat.members = chat.members.filter(
(member) => !event.event.members.includes(member)
);
if (event.event.members.includes(thisUser)) {
await this.removeChat(
{
...chat,
removed: true,
},
useCallback
);
} else {
if (!chat.removed && useCallback) {
this.callback(this.chats[chatId]);
}
}
}
break;
}
case MembershipUpdateEvent_EventType.MEMBERS_ADDED: {
if (chat) {
chat.members.push(...event.event.members);
if (
chat.members.includes(thisUser) &&
chat.admins?.includes(signer)
) {
chat.removed = false;
await this.addChat(chat, useCallback);
}
}
break;
}
case MembershipUpdateEvent_EventType.NAME_CHANGED: {
if (chat) {
if (chat.admins?.includes(signer)) {
chat.name = event.event.name;
this.callback(chat);
}
}
break;
}
}
}
})
); );
} }
} catch { } catch {
@ -224,6 +237,7 @@ export class GroupChats {
): Promise<void> { ): Promise<void> {
this.chats[chat.chatId] = chat; this.chats[chat.chatId] = chat;
if (useCallback) { if (useCallback) {
await this.handleChatObserver(chat, true);
this.removeCallback(chat); this.removeCallback(chat);
} }
} }
@ -268,6 +282,13 @@ export class GroupChats {
wakuMessages.forEach((msg) => this.waku.relay.send(msg)); wakuMessages.forEach((msg) => this.waku.relay.send(msg));
} }
/**
* Sends a change chat name chat membership update message
*
* @param chatId a chat id to which message is to be sent
*
* @param name a name which chat should be changed to
*/
public async changeChatName(chatId: string, name: string): Promise<void> { public async changeChatName(chatId: string, name: string): Promise<void> {
const payload = MembershipUpdateMessage.create(chatId, this.identity); const payload = MembershipUpdateMessage.create(chatId, this.identity);
const chat = this.chats[chatId]; const chat = this.chats[chatId];
@ -277,6 +298,13 @@ export class GroupChats {
} }
} }
/**
* Sends a add members group chat membership update message with given members
*
* @param chatId a chat id to which message is to be sent
*
* @param members a list of members to be added
*/
public async addMembers(chatId: string, members: string[]): Promise<void> { public async addMembers(chatId: string, members: string[]): Promise<void> {
const payload = MembershipUpdateMessage.create(chatId, this.identity); const payload = MembershipUpdateMessage.create(chatId, this.identity);
const chat = this.chats[chatId]; const chat = this.chats[chatId];