1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
|
// Copyright (c) 2020 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 event
import (
"encoding/json"
"maunium.net/go/mautrix/id"
)
// Event represents a single Matrix event.
type Event struct {
StateKey *string `json:"state_key,omitempty"` // The state key for the event. Only present on State Events.
Sender id.UserID `json:"sender,omitempty"` // The user ID of the sender of the event
Type Type `json:"type"` // The event type
Timestamp int64 `json:"origin_server_ts,omitempty"` // The unix timestamp when this message was sent by the origin server
ID id.EventID `json:"event_id,omitempty"` // The unique ID of this event
RoomID id.RoomID `json:"room_id,omitempty"` // The room the event was sent to. May be nil (e.g. for presence)
Content Content `json:"content"` // The JSON content of the event.
Redacts id.EventID `json:"redacts,omitempty"` // The event ID that was redacted if a m.room.redaction event
Unsigned Unsigned `json:"unsigned,omitempty"` // Unsigned content set by own homeserver.
Mautrix MautrixInfo `json:"-"`
ToUserID id.UserID `json:"to_user_id,omitempty"` // The user ID that the to-device event was sent to. Only present in MSC2409 appservice transactions.
ToDeviceID id.DeviceID `json:"to_device_id,omitempty"` // The device ID that the to-device event was sent to. Only present in MSC2409 appservice transactions.
}
type eventForMarshaling struct {
StateKey *string `json:"state_key,omitempty"`
Sender id.UserID `json:"sender,omitempty"`
Type Type `json:"type"`
Timestamp int64 `json:"origin_server_ts,omitempty"`
ID id.EventID `json:"event_id,omitempty"`
RoomID id.RoomID `json:"room_id,omitempty"`
Content Content `json:"content"`
Redacts id.EventID `json:"redacts,omitempty"`
Unsigned *Unsigned `json:"unsigned,omitempty"`
PrevContent *Content `json:"prev_content,omitempty"`
ReplacesState *id.EventID `json:"replaces_state,omitempty"`
ToUserID id.UserID `json:"to_user_id,omitempty"`
ToDeviceID id.DeviceID `json:"to_device_id,omitempty"`
}
// UnmarshalJSON unmarshals the event, including moving prev_content from the top level to inside unsigned.
func (evt *Event) UnmarshalJSON(data []byte) error {
var efm eventForMarshaling
err := json.Unmarshal(data, &efm)
if err != nil {
return err
}
evt.StateKey = efm.StateKey
evt.Sender = efm.Sender
evt.Type = efm.Type
evt.Timestamp = efm.Timestamp
evt.ID = efm.ID
evt.RoomID = efm.RoomID
evt.Content = efm.Content
evt.Redacts = efm.Redacts
if efm.Unsigned != nil {
evt.Unsigned = *efm.Unsigned
}
if efm.PrevContent != nil && evt.Unsigned.PrevContent == nil {
evt.Unsigned.PrevContent = efm.PrevContent
}
if efm.ReplacesState != nil && *efm.ReplacesState != "" && evt.Unsigned.ReplacesState == "" {
evt.Unsigned.ReplacesState = *efm.ReplacesState
}
evt.ToUserID = efm.ToUserID
evt.ToDeviceID = efm.ToDeviceID
return nil
}
// MarshalJSON marshals the event, including omitting the unsigned field if it's empty.
//
// This is necessary because Unsigned is not a pointer (for convenience reasons),
// and encoding/json doesn't know how to check if a non-pointer struct is empty.
//
// TODO(tulir): maybe it makes more sense to make Unsigned a pointer and make an easy and safe way to access it?
func (evt *Event) MarshalJSON() ([]byte, error) {
unsigned := &evt.Unsigned
if unsigned.IsEmpty() {
unsigned = nil
}
return json.Marshal(&eventForMarshaling{
StateKey: evt.StateKey,
Sender: evt.Sender,
Type: evt.Type,
Timestamp: evt.Timestamp,
ID: evt.ID,
RoomID: evt.RoomID,
Content: evt.Content,
Redacts: evt.Redacts,
Unsigned: unsigned,
ToUserID: evt.ToUserID,
ToDeviceID: evt.ToDeviceID,
})
}
type MautrixInfo struct {
Verified bool
}
func (evt *Event) GetStateKey() string {
if evt.StateKey != nil {
return *evt.StateKey
}
return ""
}
type StrippedState struct {
Content Content `json:"content"`
Type Type `json:"type"`
StateKey string `json:"state_key"`
}
type Unsigned struct {
PrevContent *Content `json:"prev_content,omitempty"`
PrevSender id.UserID `json:"prev_sender,omitempty"`
ReplacesState id.EventID `json:"replaces_state,omitempty"`
Age int64 `json:"age,omitempty"`
TransactionID string `json:"transaction_id,omitempty"`
Relations Relations `json:"m.relations,omitempty"`
RedactedBecause *Event `json:"redacted_because,omitempty"`
InviteRoomState []StrippedState `json:"invite_room_state,omitempty"`
}
func (us *Unsigned) IsEmpty() bool {
return us.PrevContent == nil && us.PrevSender == "" && us.ReplacesState == "" && us.Age == 0 &&
us.TransactionID == "" && us.RedactedBecause == nil && us.InviteRoomState == nil && us.Relations.Raw == nil &&
us.Relations.Annotations.Map == nil && us.Relations.References.List == nil && us.Relations.Replaces.List == nil
}
|