gomuks/pkg/hicli/json-commands.go

179 lines
5.5 KiB
Go

// Copyright (c) 2024 Tulir Asokan
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package hicli
import (
"context"
"encoding/json"
"errors"
"fmt"
"time"
"maunium.net/go/mautrix"
"maunium.net/go/mautrix/event"
"maunium.net/go/mautrix/id"
"go.mau.fi/gomuks/pkg/hicli/database"
)
func (h *HiClient) handleJSONCommand(ctx context.Context, req *JSONCommand) (any, error) {
switch req.Command {
case "get_state":
return h.State(), nil
case "cancel":
return unmarshalAndCall(req.Data, func(params *cancelRequestParams) (bool, error) {
h.jsonRequestsLock.Lock()
cancelTarget, ok := h.jsonRequests[params.RequestID]
h.jsonRequestsLock.Unlock()
if ok {
return false, nil
}
if params.Reason == "" {
cancelTarget(nil)
} else {
cancelTarget(errors.New(params.Reason))
}
return true, nil
})
case "send_message":
return unmarshalAndCall(req.Data, func(params *sendMessageParams) (*database.Event, error) {
return h.SendMessage(ctx, params.RoomID, params.Text, params.MediaPath, params.ReplyTo, params.Mentions)
})
case "send_event":
return unmarshalAndCall(req.Data, func(params *sendEventParams) (*database.Event, error) {
return h.Send(ctx, params.RoomID, params.EventType, params.Content)
})
case "mark_read":
return unmarshalAndCall(req.Data, func(params *markReadParams) (bool, error) {
return true, h.MarkRead(ctx, params.RoomID, params.EventID, params.ReceiptType)
})
case "set_typing":
return unmarshalAndCall(req.Data, func(params *setTypingParams) (bool, error) {
return true, h.SetTyping(ctx, params.RoomID, time.Duration(params.Timeout)*time.Millisecond)
})
case "get_event":
return unmarshalAndCall(req.Data, func(params *getEventParams) (*database.Event, error) {
return h.GetEvent(ctx, params.RoomID, params.EventID)
})
case "get_events_by_rowids":
return unmarshalAndCall(req.Data, func(params *getEventsByRowIDsParams) ([]*database.Event, error) {
return h.GetEventsByRowIDs(ctx, params.RowIDs)
})
case "get_room_state":
return unmarshalAndCall(req.Data, func(params *getRoomStateParams) ([]*database.Event, error) {
return h.GetRoomState(ctx, params.RoomID, params.FetchMembers, params.Refetch)
})
case "paginate":
return unmarshalAndCall(req.Data, func(params *paginateParams) (*PaginationResponse, error) {
return h.Paginate(ctx, params.RoomID, params.MaxTimelineID, params.Limit)
})
case "paginate_server":
return unmarshalAndCall(req.Data, func(params *paginateParams) (*PaginationResponse, error) {
return h.PaginateServer(ctx, params.RoomID, params.Limit)
})
case "ensure_group_session_shared":
return unmarshalAndCall(req.Data, func(params *ensureGroupSessionSharedParams) (bool, error) {
return true, h.EnsureGroupSessionShared(ctx, params.RoomID)
})
case "login":
return unmarshalAndCall(req.Data, func(params *loginParams) (bool, error) {
return true, h.LoginPassword(ctx, params.HomeserverURL, params.Username, params.Password)
})
case "verify":
return unmarshalAndCall(req.Data, func(params *verifyParams) (bool, error) {
return true, h.VerifyWithRecoveryKey(ctx, params.RecoveryKey)
})
case "discover_homeserver":
return unmarshalAndCall(req.Data, func(params *discoverHomeserverParams) (*mautrix.ClientWellKnown, error) {
_, homeserver, err := params.UserID.Parse()
if err != nil {
return nil, err
}
return mautrix.DiscoverClientAPI(ctx, homeserver)
})
default:
return nil, fmt.Errorf("unknown command %q", req.Command)
}
}
func unmarshalAndCall[T, O any](data json.RawMessage, fn func(*T) (O, error)) (output O, err error) {
var input T
err = json.Unmarshal(data, &input)
if err != nil {
return
}
return fn(&input)
}
type cancelRequestParams struct {
RequestID int64 `json:"request_id"`
Reason string `json:"reason"`
}
type sendMessageParams struct {
RoomID id.RoomID `json:"room_id"`
Text string `json:"text"`
MediaPath string `json:"media_path"`
ReplyTo id.EventID `json:"reply_to"`
Mentions *event.Mentions `json:"mentions"`
}
type sendEventParams struct {
RoomID id.RoomID `json:"room_id"`
EventType event.Type `json:"type"`
Content json.RawMessage `json:"content"`
}
type markReadParams struct {
RoomID id.RoomID `json:"room_id"`
EventID id.EventID `json:"event_id"`
ReceiptType event.ReceiptType `json:"receipt_type"`
}
type setTypingParams struct {
RoomID id.RoomID `json:"room_id"`
Timeout int `json:"timeout"`
}
type getEventParams struct {
RoomID id.RoomID `json:"room_id"`
EventID id.EventID `json:"event_id"`
}
type getEventsByRowIDsParams struct {
RowIDs []database.EventRowID `json:"row_ids"`
}
type getRoomStateParams struct {
RoomID id.RoomID `json:"room_id"`
Refetch bool `json:"refetch"`
FetchMembers bool `json:"fetch_members"`
}
type ensureGroupSessionSharedParams struct {
RoomID id.RoomID `json:"room_id"`
}
type loginParams struct {
HomeserverURL string `json:"homeserver_url"`
Username string `json:"username"`
Password string `json:"password"`
}
type verifyParams struct {
RecoveryKey string `json:"recovery_key"`
}
type discoverHomeserverParams struct {
UserID id.UserID `json:"user_id"`
}
type paginateParams struct {
RoomID id.RoomID `json:"room_id"`
MaxTimelineID database.TimelineRowID `json:"max_timeline_id"`
Limit int `json:"limit"`
}