diff --git a/pkg/hicli/hitest/hitest.go b/pkg/hicli/hitest/hitest.go index e30d2fb7..e1077bef 100644 --- a/pkg/hicli/hitest/hitest.go +++ b/pkg/hicli/hitest/hitest.go @@ -101,7 +101,7 @@ func main() { resp, err := cli.Send(ctx, id.RoomID(fields[1]), event.EventMessage, &event.MessageEventContent{ Body: strings.Join(fields[2:], " "), MsgType: event.MsgText, - }, false) + }, false, false) _, _ = fmt.Fprintln(rl, err) _, _ = fmt.Fprintf(rl, "%+v\n", resp) } diff --git a/pkg/hicli/json-commands.go b/pkg/hicli/json-commands.go index c39b312b..eafa3875 100644 --- a/pkg/hicli/json-commands.go +++ b/pkg/hicli/json-commands.go @@ -47,7 +47,7 @@ func (h *HiClient) handleJSONCommand(ctx context.Context, req *JSONCommand) (any }) case "send_event": return unmarshalAndCall(req.Data, func(params *sendEventParams) (*database.Event, error) { - return h.Send(ctx, params.RoomID, params.EventType, params.Content, params.DisableEncryption) + return h.Send(ctx, params.RoomID, params.EventType, params.Content, params.DisableEncryption, params.Synchronous) }) case "resend_event": return unmarshalAndCall(req.Data, func(params *resendEventParams) (*database.Event, error) { @@ -284,6 +284,7 @@ type sendEventParams struct { EventType event.Type `json:"type"` Content json.RawMessage `json:"content"` DisableEncryption bool `json:"disable_encryption"` + Synchronous bool `json:"synchronous"` } type resendEventParams struct { diff --git a/pkg/hicli/send.go b/pkg/hicli/send.go index 8a462305..84cb4c11 100644 --- a/pkg/hicli/send.go +++ b/pkg/hicli/send.go @@ -97,7 +97,7 @@ func (h *HiClient) SendMessage( if !json.Valid(content) { return nil, fmt.Errorf("invalid JSON in /raw command") } - return h.send(ctx, roomID, event.Type{Type: parts[1]}, content, "", unencrypted) + return h.send(ctx, roomID, event.Type{Type: parts[1]}, content, "", unencrypted, false) } else if strings.HasPrefix(text, "/rawstate ") { parts := strings.SplitN(text, " ", 4) if len(parts) < 4 || len(parts[1]) == 0 { @@ -182,7 +182,7 @@ func (h *HiClient) SendMessage( content.MsgType = "" evtType = event.EventSticker } - return h.send(ctx, roomID, evtType, &event.Content{Parsed: content, Raw: extra}, origText, unencrypted) + return h.send(ctx, roomID, evtType, &event.Content{Parsed: content, Raw: extra}, origText, unencrypted, false) } func (h *HiClient) MarkRead(ctx context.Context, roomID id.RoomID, eventID id.EventID, receiptType event.ReceiptType) error { @@ -246,12 +246,13 @@ func (h *HiClient) Send( evtType event.Type, content any, disableEncryption bool, + synchronous bool, ) (*database.Event, error) { if evtType == event.EventRedaction { // TODO implement return nil, fmt.Errorf("redaction is not supported") } - return h.send(ctx, roomID, evtType, content, "", disableEncryption) + return h.send(ctx, roomID, evtType, content, "", disableEncryption, synchronous) } func (h *HiClient) Resend(ctx context.Context, txnID string) (*database.Event, error) { @@ -270,7 +271,7 @@ func (h *HiClient) Resend(ctx context.Context, txnID string) (*database.Event, e return nil, fmt.Errorf("unknown room") } dbEvt.SendError = "" - go h.actuallySend(context.WithoutCancel(ctx), room, dbEvt, event.Type{Type: dbEvt.Type, Class: event.MessageEventType}) + go h.actuallySend(context.WithoutCancel(ctx), room, dbEvt, event.Type{Type: dbEvt.Type, Class: event.MessageEventType}, false) return dbEvt, nil } @@ -281,6 +282,7 @@ func (h *HiClient) send( content any, overrideEditSource string, disableEncryption bool, + synchronous bool, ) (*database.Event, error) { room, err := h.DB.Room.Get(ctx, roomID) if err != nil { @@ -339,11 +341,15 @@ func (h *HiClient) send( zerolog.Ctx(ctx).Err(err).Msg("Failed to stop typing while sending message") } }() - go h.actuallySend(ctx, room, dbEvt, evtType) + if synchronous { + h.actuallySend(ctx, room, dbEvt, evtType, true) + } else { + go h.actuallySend(ctx, room, dbEvt, evtType, false) + } return dbEvt, nil } -func (h *HiClient) actuallySend(ctx context.Context, room *database.Room, dbEvt *database.Event, evtType event.Type) { +func (h *HiClient) actuallySend(ctx context.Context, room *database.Room, dbEvt *database.Event, evtType event.Type, synchronous bool) { var err error defer func() { if dbEvt.SendError != "" { @@ -353,10 +359,12 @@ func (h *HiClient) actuallySend(ctx context.Context, room *database.Room, dbEvt Msg("Failed to update send error in database after sending failed") } } - h.EventHandler(&SendComplete{ - Event: dbEvt, - Error: err, - }) + if !synchronous { + h.EventHandler(&SendComplete{ + Event: dbEvt, + Error: err, + }) + } }() if dbEvt.Decrypted != nil && len(dbEvt.Content) <= 2 { var encryptedContent *event.EncryptedEventContent diff --git a/web/src/api/rpc.ts b/web/src/api/rpc.ts index a9be5342..935f953f 100644 --- a/web/src/api/rpc.ts +++ b/web/src/api/rpc.ts @@ -151,9 +151,13 @@ export default abstract class RPCClient { } sendEvent( - room_id: RoomID, type: EventType, content: unknown, disable_encryption: boolean = false, + room_id: RoomID, + type: EventType, + content: unknown, + disable_encryption: boolean = false, + synchronous: boolean = false, ): Promise { - return this.request("send_event", { room_id, type, content, disable_encryption }) + return this.request("send_event", { room_id, type, content, disable_encryption, synchronous }) } resendEvent(transaction_id: string): Promise { diff --git a/web/src/ui/widget/widgetDriver.ts b/web/src/ui/widget/widgetDriver.ts index 00ee40cf..82e058d8 100644 --- a/web/src/ui/widget/widgetDriver.ts +++ b/web/src/ui/widget/widgetDriver.ts @@ -57,7 +57,7 @@ class GomuksWidgetDriver extends WidgetDriver { const eventID = await this.client.rpc.setState(roomID, eventType, stateKey, content) return { eventId: eventID, roomId: roomID } } else { - const rawDBEvt = await this.client.rpc.sendEvent(roomID, eventType, content) + const rawDBEvt = await this.client.rpc.sendEvent(roomID, eventType, content, false, true) return { eventId: rawDBEvt.event_id, roomId: rawDBEvt.room_id } } }