73 lines
2.3 KiB
Go
73 lines
2.3 KiB
Go
package main
|
|
|
|
import "encoding/json"
|
|
|
|
// Event is a Matrix ClientEvent as delivered in an appservice transaction. Each
|
|
// event carries its own room_id (unlike /sync, where it's implied by the room
|
|
// bucket). Content stays raw so each handler decodes only the shape it needs.
|
|
type Event struct {
|
|
Type string `json:"type"`
|
|
RoomID string `json:"room_id"`
|
|
Sender string `json:"sender"`
|
|
EventID string `json:"event_id"`
|
|
OriginServerTS int64 `json:"origin_server_ts"`
|
|
StateKey *string `json:"state_key,omitempty"`
|
|
Content json.RawMessage `json:"content"`
|
|
}
|
|
|
|
// Mentions is the MSC3952 intentional-mentions block. It can legitimately be the
|
|
// empty object `{}` (cinny writes it on every send), so UserIDs may be nil —
|
|
// callers must safe-deref (F29).
|
|
type Mentions struct {
|
|
UserIDs []string `json:"user_ids"`
|
|
Room bool `json:"room"`
|
|
}
|
|
|
|
type InReplyTo struct {
|
|
EventID string `json:"event_id"`
|
|
}
|
|
|
|
type RelatesTo struct {
|
|
RelType string `json:"rel_type"`
|
|
EventID string `json:"event_id"`
|
|
InReplyTo *InReplyTo `json:"m.in_reply_to"`
|
|
}
|
|
|
|
// MessageContent is the decoded m.room.message content we care about.
|
|
type MessageContent struct {
|
|
MsgType string `json:"msgtype"`
|
|
Body string `json:"body"`
|
|
Format string `json:"format"`
|
|
FormattedBody string `json:"formatted_body"`
|
|
Mentions *Mentions `json:"m.mentions"`
|
|
RelatesTo *RelatesTo `json:"m.relates_to"`
|
|
NewContent json.RawMessage `json:"m.new_content"`
|
|
}
|
|
|
|
func (e *Event) DecodeMessage() (*MessageContent, bool) {
|
|
if e.Type != "m.room.message" {
|
|
return nil, false
|
|
}
|
|
var mc MessageContent
|
|
if err := json.Unmarshal(e.Content, &mc); err != nil {
|
|
return nil, false
|
|
}
|
|
return &mc, true
|
|
}
|
|
|
|
// IsReplace reports whether the message is an `m.replace` edit. Edits re-carry
|
|
// m.mentions and must NOT re-trigger or double-bill (F16).
|
|
func (mc *MessageContent) IsReplace() bool {
|
|
return mc.RelatesTo != nil && mc.RelatesTo.RelType == "m.replace"
|
|
}
|
|
|
|
// membershipOf extracts the membership from an m.room.member event content.
|
|
func (e *Event) membershipOf() string {
|
|
var m struct {
|
|
Membership string `json:"membership"`
|
|
}
|
|
if json.Unmarshal(e.Content, &m) != nil {
|
|
return ""
|
|
}
|
|
return m.Membership
|
|
}
|