commit 1f8a4b72987f22a23ab5eafc02296708a49588ea
parent 3d86c3e024c6de1b98cbd39f619b3a3b7e21f50b
Author: MTRNord <mtrnord1@gmail.com>
Date: Tue, 9 May 2023 20:31:44 +0200
Add local echo
Diffstat:
5 files changed, 82 insertions(+), 34 deletions(-)
diff --git a/src/app/sdk/api/events.ts b/src/app/sdk/api/events.ts
@@ -5,7 +5,9 @@ export interface IRoomEvent<Content = any> {
origin_server_ts: number;
sender: string;
type: string;
- unsigned?: any;
+ unsigned?: {
+ transaction_id?: string;
+ };
"m.relates.to"?: any;
[key: string]: any;
}
diff --git a/src/app/sdk/ownUser.ts b/src/app/sdk/ownUser.ts
@@ -19,7 +19,8 @@ export class OwnUser {
// TODO: call logout endpoint on logout
public async logout() {
if (!this.mxid) {
- throw Error("Not logged in");
+ console.log("Not logged in");
+ return;
}
if (!this.access_token) {
throw Error("Not logged in");
diff --git a/src/app/sdk/room.ts b/src/app/sdk/room.ts
@@ -32,6 +32,7 @@ export declare interface Room {
export class Room extends EventEmitter {
private events: IRoomEvent[] = [];
+ private pendingEvents: IRoomEvent[] = [];
private stateEvents: IRoomStateEvent[] = [];
private name?: string;
@@ -52,10 +53,16 @@ export class Room extends EventEmitter {
public addEvents(events: IRoomEvent[]) {
events.forEach((newEvent) => {
+ console.log("newEvent", newEvent)
+ if (newEvent.unsigned?.transaction_id) {
+ console.log("Found transaction id. Trying to remove pending event")
+ this.pendingEvents = this.pendingEvents.filter((event) => event.unsigned?.transaction_id !== newEvent.unsigned?.transaction_id);
+ }
+
this.events.push(newEvent);
});
- this.emit("events", this.events);
+ this.emit("events", this.getEvents());
}
public addStateEvents(state: IRoomStateEvent[]) {
@@ -195,6 +202,10 @@ export class Room extends EventEmitter {
}
public getEvents(): IRoomEvent[] {
+ return [...this.events, ...this.pendingEvents];
+ }
+
+ public getPureEvents(): IRoomEvent[] {
return this.events;
}
@@ -235,25 +246,47 @@ export class Room extends EventEmitter {
return isEncrypted;
}
- public async sendHtmlMessage(html: string, plainText: string): Promise<string> {
+ // TODO: Workaround since txn id doesnt come down sync
+ private deletePendingByEventID(eventID: string) {
+ this.pendingEvents = this.pendingEvents.filter((event) => event.eventID !== eventID);
+ }
+
+ public async sendHtmlMessage(html: string, plainText: string, callbackLocalEcho: () => void): Promise<string> {
+ const txn_id = Date.now().toString();
+ // @ts-ignore: Intentionally incomplete
+ const event = {
+ type: "m.room.message",
+ unsigned: {
+ transaction_id: txn_id
+ },
+ origin_server_ts: txn_id,
+ sender: this.client.mxid,
+ event_id: txn_id,
+ content: {
+ "msgtype": "m.text",
+ "body": plainText,
+ "format": "org.matrix.custom.html",
+ "formatted_body": html
+ }
+ } as IRoomEvent;
+ this.pendingEvents.push(event);
+ this.emit("events", this.getEvents());
+ callbackLocalEcho();
+
if (!this.isEncrypted()) {
- const resp = await fetch(`${this.hostname}/_matrix/client/v3/rooms/${this.roomID}/send/m.room.message/${Date.now().toString()}`, {
+ const resp = await fetch(`${this.hostname}/_matrix/client/v3/rooms/${this.roomID}/send/m.room.message/${event.unsigned?.transaction_id}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${this.client.accessToken}`
},
- body: JSON.stringify({
- "msgtype": "m.text",
- "body": plainText,
- "format": "org.matrix.custom.html",
- "formatted_body": html
- })
+ body: JSON.stringify(event.content)
});
if (!resp.ok) {
throw new Error(`Failed to send message: ${resp.status} ${resp.statusText}`);
}
const json = await resp.json();
+ this.deletePendingByEventID(event.event_id);
return json.event_id;
} else {
console.log("Sending encrypted message");
@@ -262,14 +295,9 @@ export class Room extends EventEmitter {
const encrypted = await this.e2ee.encryptRoomEvent(
new RoomId(this.roomID),
"m.room.message",
- JSON.stringify({
- "msgtype": "m.text",
- "body": plainText,
- "format": "org.matrix.custom.html",
- "formatted_body": html
- })
+ JSON.stringify(event.content)
);
- const resp = await fetch(`${this.hostname}/_matrix/client/v3/rooms/${this.roomID}/send/m.room.encrypted/${Date.now().toString()}`, {
+ const resp = await fetch(`${this.hostname}/_matrix/client/v3/rooms/${this.roomID}/send/m.room.encrypted/${event.unsigned?.transaction_id}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
@@ -281,27 +309,45 @@ export class Room extends EventEmitter {
throw new Error(`Failed to send message: ${resp.status} ${resp.statusText}`);
}
const json = await resp.json();
+ this.deletePendingByEventID(event.event_id);
return json.event_id;
}
}
- public async sendTextMessage(text: string): Promise<string> {
+ public async sendTextMessage(text: string, callbackLocalEcho: () => void): Promise<string> {
+ const txn_id = Date.now().toString();
+ // @ts-ignore: Intentionally incomplete
+ const event = {
+ type: "m.room.message",
+ unsigned: {
+ transaction_id: txn_id
+ },
+ origin_server_ts: txn_id,
+ event_id: txn_id,
+ sender: this.client.mxid,
+ content: {
+ "msgtype": "m.text",
+ "body": text,
+ }
+ } as IRoomEvent;
+ this.pendingEvents.push(event);
+ this.emit("events", this.getEvents());
+ callbackLocalEcho();
+
if (!this.isEncrypted()) {
- const resp = await fetch(`${this.hostname}/_matrix/client/v3/rooms/${this.roomID}/send/m.room.message/${Date.now().toString()}`, {
+ const resp = await fetch(`${this.hostname}/_matrix/client/v3/rooms/${this.roomID}/send/m.room.message/${event.unsigned?.transaction_id}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${this.client.accessToken}`
},
- body: JSON.stringify({
- "msgtype": "m.text",
- "body": text
- })
+ body: JSON.stringify(event.content)
});
if (!resp.ok) {
throw new Error(`Failed to send message: ${resp.status} ${resp.statusText}`);
}
const json = await resp.json();
+ this.deletePendingByEventID(event.event_id);
return json.event_id;
} else {
console.log("Sending encrypted message2");
@@ -310,12 +356,9 @@ export class Room extends EventEmitter {
const encrypted = await this.e2ee.encryptRoomEvent(
new RoomId(this.roomID),
"m.room.message",
- JSON.stringify({
- "msgtype": "m.text",
- "body": text
- })
+ JSON.stringify(event.content)
);
- const resp = await fetch(`${this.hostname}/_matrix/client/v3/rooms/${this.roomID}/send/m.room.encrypted/${Date.now().toString()}`, {
+ const resp = await fetch(`${this.hostname}/_matrix/client/v3/rooms/${this.roomID}/send/m.room.encrypted/${event.unsigned?.transaction_id}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
@@ -327,6 +370,7 @@ export class Room extends EventEmitter {
throw new Error(`Failed to send message: ${resp.status} ${resp.statusText}`);
}
const json = await resp.json();
+ this.deletePendingByEventID(event.event_id);
return json.event_id;
}
}
@@ -388,7 +432,7 @@ export function useEvents(room?: Room) {
setEvents(room?.getEvents() || []);
// Listen for event updates
const listenForEvents = (events: IRoomEvent[]) => {
- setEvents([...events]);
+ setEvents(events);
};
room.on("events", listenForEvents);
return () => {
diff --git a/src/app/sdk/slidingSync.ts b/src/app/sdk/slidingSync.ts
@@ -175,7 +175,8 @@ export class MatrixSlidingSync extends EventEmitter {
throw Error("Hostname must be set first");
}
- await this.user.e2ee.sendIdentifyAndOneTimeKeys();
+ // TODO: This might cause future issues
+ Promise.all([this.user.e2ee.sendIdentifyAndOneTimeKeys()]);
// This is the initial sync case for each list
let lists_ranges: {
@@ -710,7 +711,7 @@ export class MatrixSlidingSync extends EventEmitter {
highlight_count: roomObj.getNotificationHighlightCount(),
joined_count: roomObj.getJoinedCount(),
invited_count: roomObj.getInvitedCount(),
- events: roomObj.getEvents(),
+ events: roomObj.getPureEvents(),
stateEvents: roomObj.getStateEvents(),
avatarUrl: roomObj.getAvatarURL(),
isSpace: roomObj.isSpace(),
diff --git a/src/components/input/chat/input.tsx b/src/components/input/chat/input.tsx
@@ -154,7 +154,7 @@ const SendButton: FC<SendButtonProps> = memo(({ roomID, onStartSending, onStopSe
console.log("Sending message to: ", roomID)
if (htmlMessage !== '<p class="editor-paragraph"><br></p>') {
- room.sendHtmlMessage(htmlMessage, plainMessage).then(() => {
+ room.sendHtmlMessage(htmlMessage, plainMessage, () => {
editor.dispatchCommand(CLEAR_EDITOR_COMMAND, undefined);
editor.dispatchCommand(CLEAR_HISTORY_COMMAND, undefined);
localStorage.removeItem(`editor-${roomID}`);
@@ -164,7 +164,7 @@ const SendButton: FC<SendButtonProps> = memo(({ roomID, onStartSending, onStopSe
onStopSending();
})
} else {
- room.sendTextMessage(plainMessage).then(() => {
+ room.sendTextMessage(plainMessage, () => {
editor.dispatchCommand(CLEAR_EDITOR_COMMAND, undefined);
editor.dispatchCommand(CLEAR_HISTORY_COMMAND, undefined);
localStorage.removeItem(`editor-${roomID}`);