events.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. package gomatrix
  2. import (
  3. "encoding/json"
  4. "strings"
  5. "sync"
  6. )
  7. type EventTypeClass int
  8. const (
  9. // Normal message events
  10. MessageEventType EventTypeClass = iota
  11. // State events
  12. StateEventType
  13. // Ephemeral events
  14. EphemeralEventType
  15. // Account data events
  16. AccountDataEventType
  17. // Unknown events
  18. UnknownEventType
  19. )
  20. type EventType struct {
  21. Type string
  22. Class EventTypeClass
  23. }
  24. func NewEventType(name string) EventType {
  25. evtType := EventType{Type: name}
  26. evtType.Class = evtType.GuessClass()
  27. return evtType
  28. }
  29. func (et *EventType) IsState() bool {
  30. return et.Class == StateEventType
  31. }
  32. func (et *EventType) IsEphemeral() bool {
  33. return et.Class == EphemeralEventType
  34. }
  35. func (et *EventType) IsCustom() bool {
  36. return !strings.HasPrefix(et.Type, "m.")
  37. }
  38. func (et *EventType) GuessClass() EventTypeClass {
  39. switch et.Type {
  40. case StateAliases.Type, StateCanonicalAlias.Type, StateCreate.Type, StateJoinRules.Type, StateMember.Type,
  41. StatePowerLevels.Type, StateRoomName.Type, StateRoomAvatar.Type, StateTopic.Type, StatePinnedEvents.Type:
  42. return StateEventType
  43. case EphemeralEventReceipt.Type, EphemeralEventTyping.Type:
  44. return EphemeralEventType
  45. case AccountDataDirectChats.Type, AccountDataPushRules.Type, AccountDataRoomTags.Type:
  46. return AccountDataEventType
  47. case EventRedaction.Type, EventMessage.Type, EventSticker.Type:
  48. return MessageEventType
  49. default:
  50. return UnknownEventType
  51. }
  52. }
  53. func (et *EventType) UnmarshalJSON(data []byte) error {
  54. err := json.Unmarshal(data, &et.Type)
  55. if err != nil {
  56. return err
  57. }
  58. et.Class = et.GuessClass()
  59. return nil
  60. }
  61. func (et *EventType) MarshalJSON() ([]byte, error) {
  62. return json.Marshal(&et.Type)
  63. }
  64. func (et *EventType) String() string {
  65. return et.Type
  66. }
  67. // State events
  68. var (
  69. StateAliases = EventType{"m.room.aliases", StateEventType}
  70. StateCanonicalAlias = EventType{"m.room.canonical_alias", StateEventType}
  71. StateCreate = EventType{"m.room.create", StateEventType}
  72. StateJoinRules = EventType{"m.room.join_rules", StateEventType}
  73. StateMember = EventType{"m.room.member", StateEventType}
  74. StatePowerLevels = EventType{"m.room.power_levels", StateEventType}
  75. StateRoomName = EventType{"m.room.name", StateEventType}
  76. StateTopic = EventType{"m.room.topic", StateEventType}
  77. StateRoomAvatar = EventType{"m.room.avatar", StateEventType}
  78. StatePinnedEvents = EventType{"m.room.pinned_events", StateEventType}
  79. )
  80. // Message events
  81. var (
  82. EventRedaction = EventType{"m.room.redaction", MessageEventType}
  83. EventMessage = EventType{"m.room.message", MessageEventType}
  84. EventSticker = EventType{"m.sticker", MessageEventType}
  85. )
  86. // Ephemeral events
  87. var (
  88. EphemeralEventReceipt = EventType{"m.receipt", EphemeralEventType}
  89. EphemeralEventTyping = EventType{"m.typing", EphemeralEventType}
  90. )
  91. // Account data events
  92. var (
  93. AccountDataDirectChats = EventType{"m.direct", AccountDataEventType}
  94. AccountDataPushRules = EventType{"m.push_rules", AccountDataEventType}
  95. AccountDataRoomTags = EventType{"m.tag", AccountDataEventType}
  96. )
  97. type MessageType string
  98. // Msgtypes
  99. const (
  100. MsgText MessageType = "m.text"
  101. MsgEmote = "m.emote"
  102. MsgNotice = "m.notice"
  103. MsgImage = "m.image"
  104. MsgLocation = "m.location"
  105. MsgVideo = "m.video"
  106. MsgAudio = "m.audio"
  107. MsgFile = "m.file"
  108. )
  109. type Format string
  110. // Message formats
  111. const (
  112. FormatHTML Format = "org.matrix.custom.html"
  113. )
  114. // Event represents a single Matrix event.
  115. type Event struct {
  116. StateKey *string `json:"state_key,omitempty"` // The state key for the event. Only present on State Events.
  117. Sender string `json:"sender"` // The user ID of the sender of the event
  118. Type EventType `json:"type"` // The event type
  119. Timestamp int64 `json:"origin_server_ts"` // The unix timestamp when this message was sent by the origin server
  120. ID string `json:"event_id"` // The unique ID of this event
  121. RoomID string `json:"room_id"` // The room the event was sent to. May be nil (e.g. for presence)
  122. Content Content `json:"content"` // The JSON content of the event.
  123. Redacts string `json:"redacts,omitempty"` // The event ID that was redacted if a m.room.redaction event
  124. Unsigned Unsigned `json:"unsigned,omitempty"` // Unsigned content set by own homeserver.
  125. InviteRoomState []StrippedState `json:"invite_room_state"`
  126. }
  127. func (evt *Event) GetStateKey() string {
  128. if evt.StateKey != nil {
  129. return *evt.StateKey
  130. }
  131. return ""
  132. }
  133. type StrippedState struct {
  134. Content Content `json:"content"`
  135. Type EventType `json:"type"`
  136. StateKey string `json:"state_key"`
  137. }
  138. type Unsigned struct {
  139. PrevContent *Content `json:"prev_content,omitempty"`
  140. PrevSender string `json:"prev_sender,omitempty"`
  141. ReplacesState string `json:"replaces_state,omitempty"`
  142. Age int64 `json:"age,omitempty"`
  143. PassiveCommand map[string]*MatchedPassiveCommand `json:"m.passive_command,omitempty"`
  144. }
  145. type MatchedPassiveCommand struct {
  146. // Matched string `json:"matched"`
  147. // Value string `json:"value"`
  148. Captured [][]string `json:"captured"`
  149. BackCompatCommand string `json:"command"`
  150. BackCompatArguments map[string]string `json:"arguments"`
  151. }
  152. type Content struct {
  153. VeryRaw json.RawMessage `json:"-"`
  154. Raw map[string]interface{} `json:"-"`
  155. MsgType MessageType `json:"msgtype,omitempty"`
  156. Body string `json:"body,omitempty"`
  157. Format Format `json:"format,omitempty"`
  158. FormattedBody string `json:"formatted_body,omitempty"`
  159. Info *FileInfo `json:"info,omitempty"`
  160. URL string `json:"url,omitempty"`
  161. // Membership key for easy access in m.room.member events
  162. Membership Membership `json:"membership,omitempty"`
  163. RelatesTo *RelatesTo `json:"m.relates_to,omitempty"`
  164. Command *MatchedCommand `json:"m.command,omitempty"`
  165. PowerLevels
  166. Member
  167. Aliases []string `json:"aliases,omitempty"`
  168. CanonicalAlias
  169. RoomName
  170. RoomTopic
  171. RoomTags Tags `json:"tags,omitempty"`
  172. TypingUserIDs []string `json:"user_ids,omitempty"`
  173. }
  174. type serializableContent Content
  175. var DisableFancyEventParsing = false
  176. func (content *Content) UnmarshalJSON(data []byte) error {
  177. content.VeryRaw = data
  178. if err := json.Unmarshal(data, &content.Raw); err != nil || DisableFancyEventParsing {
  179. return err
  180. }
  181. return json.Unmarshal(data, (*serializableContent)(content))
  182. }
  183. func (content *Content) GetCommand() *MatchedCommand {
  184. if content.Command == nil {
  185. content.Command = &MatchedCommand{}
  186. }
  187. return content.Command
  188. }
  189. func (content *Content) GetRelatesTo() *RelatesTo {
  190. if content.RelatesTo == nil {
  191. content.RelatesTo = &RelatesTo{}
  192. }
  193. return content.RelatesTo
  194. }
  195. func (content *Content) UnmarshalPowerLevels() (pl PowerLevels, err error) {
  196. err = json.Unmarshal(content.VeryRaw, &pl)
  197. return
  198. }
  199. func (content *Content) UnmarshalMember() (m Member, err error) {
  200. err = json.Unmarshal(content.VeryRaw, &m)
  201. return
  202. }
  203. func (content *Content) UnmarshalCanonicalAlias() (ca CanonicalAlias, err error) {
  204. err = json.Unmarshal(content.VeryRaw, &ca)
  205. return
  206. }
  207. func (content *Content) GetInfo() *FileInfo {
  208. if content.Info == nil {
  209. content.Info = &FileInfo{}
  210. }
  211. return content.Info
  212. }
  213. type Tags map[string]struct {
  214. Order string `json:"order"`
  215. }
  216. type RoomName struct {
  217. Name string `json:"name,omitempty"`
  218. }
  219. type RoomTopic struct {
  220. Topic string `json:"topic,omitempty"`
  221. }
  222. // Membership is an enum specifying the membership state of a room member.
  223. type Membership string
  224. // The allowed membership states as specified in spec section 10.5.5.
  225. const (
  226. MembershipJoin Membership = "join"
  227. MembershipLeave Membership = "leave"
  228. MembershipInvite Membership = "invite"
  229. MembershipBan Membership = "ban"
  230. MembershipKnock Membership = "knock"
  231. )
  232. type Member struct {
  233. Membership Membership `json:"membership,omitempty"`
  234. AvatarURL string `json:"avatar_url,omitempty"`
  235. Displayname string `json:"displayname,omitempty"`
  236. ThirdPartyInvite *ThirdPartyInvite `json:"third_party_invite,omitempty"`
  237. Reason string `json:"reason,omitempty"`
  238. }
  239. type ThirdPartyInvite struct {
  240. DisplayName string `json:"display_name"`
  241. Signed struct {
  242. Token string `json:"token"`
  243. Signatures json.RawMessage `json:"signatures"`
  244. MXID string `json:"mxid"`
  245. }
  246. }
  247. type CanonicalAlias struct {
  248. Alias string `json:"alias,omitempty"`
  249. }
  250. type PowerLevels struct {
  251. usersLock sync.RWMutex `json:"-"`
  252. Users map[string]int `json:"users,omitempty"`
  253. UsersDefault int `json:"users_default,omitempty"`
  254. eventsLock sync.RWMutex `json:"-"`
  255. Events map[string]int `json:"events,omitempty"`
  256. EventsDefault int `json:"events_default,omitempty"`
  257. StateDefaultPtr *int `json:"state_default,omitempty"`
  258. InvitePtr *int `json:"invite,omitempty"`
  259. KickPtr *int `json:"kick,omitempty"`
  260. BanPtr *int `json:"ban,omitempty"`
  261. RedactPtr *int `json:"redact,omitempty"`
  262. }
  263. func (pl *PowerLevels) Invite() int {
  264. if pl.InvitePtr != nil {
  265. return *pl.InvitePtr
  266. }
  267. return 50
  268. }
  269. func (pl *PowerLevels) Kick() int {
  270. if pl.KickPtr != nil {
  271. return *pl.KickPtr
  272. }
  273. return 50
  274. }
  275. func (pl *PowerLevels) Ban() int {
  276. if pl.BanPtr != nil {
  277. return *pl.BanPtr
  278. }
  279. return 50
  280. }
  281. func (pl *PowerLevels) Redact() int {
  282. if pl.RedactPtr != nil {
  283. return *pl.RedactPtr
  284. }
  285. return 50
  286. }
  287. func (pl *PowerLevels) StateDefault() int {
  288. if pl.StateDefaultPtr != nil {
  289. return *pl.StateDefaultPtr
  290. }
  291. return 50
  292. }
  293. func (pl *PowerLevels) GetUserLevel(userID string) int {
  294. pl.usersLock.RLock()
  295. defer pl.usersLock.RUnlock()
  296. level, ok := pl.Users[userID]
  297. if !ok {
  298. return pl.UsersDefault
  299. }
  300. return level
  301. }
  302. func (pl *PowerLevels) SetUserLevel(userID string, level int) {
  303. pl.usersLock.Lock()
  304. defer pl.usersLock.Unlock()
  305. if level == pl.UsersDefault {
  306. delete(pl.Users, userID)
  307. } else {
  308. pl.Users[userID] = level
  309. }
  310. }
  311. func (pl *PowerLevels) EnsureUserLevel(userID string, level int) bool {
  312. existingLevel := pl.GetUserLevel(userID)
  313. if existingLevel != level {
  314. pl.SetUserLevel(userID, level)
  315. return true
  316. }
  317. return false
  318. }
  319. func (pl *PowerLevels) GetEventLevel(eventType EventType) int {
  320. pl.eventsLock.RLock()
  321. defer pl.eventsLock.RUnlock()
  322. level, ok := pl.Events[eventType.String()]
  323. if !ok {
  324. if eventType.IsState() {
  325. return pl.StateDefault()
  326. }
  327. return pl.EventsDefault
  328. }
  329. return level
  330. }
  331. func (pl *PowerLevels) SetEventLevel(eventType EventType, level int) {
  332. pl.eventsLock.Lock()
  333. defer pl.eventsLock.Unlock()
  334. if (eventType.IsState() && level == pl.StateDefault()) || (!eventType.IsState() && level == pl.EventsDefault) {
  335. delete(pl.Events, eventType.String())
  336. } else {
  337. pl.Events[eventType.String()] = level
  338. }
  339. }
  340. func (pl *PowerLevels) EnsureEventLevel(eventType EventType, level int) bool {
  341. existingLevel := pl.GetEventLevel(eventType)
  342. if existingLevel != level {
  343. pl.SetEventLevel(eventType, level)
  344. return true
  345. }
  346. return false
  347. }
  348. type FileInfo struct {
  349. MimeType string `json:"mimetype,omitempty"`
  350. ThumbnailInfo *FileInfo `json:"thumbnail_info,omitempty"`
  351. ThumbnailURL string `json:"thumbnail_url,omitempty"`
  352. Height int `json:"h,omitempty"`
  353. Width int `json:"w,omitempty"`
  354. Duration uint `json:"duration,omitempty"`
  355. Size int `json:"size,omitempty"`
  356. }
  357. func (fileInfo *FileInfo) GetThumbnailInfo() *FileInfo {
  358. if fileInfo.ThumbnailInfo == nil {
  359. fileInfo.ThumbnailInfo = &FileInfo{}
  360. }
  361. return fileInfo.ThumbnailInfo
  362. }
  363. type RelatesTo struct {
  364. InReplyTo InReplyTo `json:"m.in_reply_to,omitempty"`
  365. }
  366. type InReplyTo struct {
  367. EventID string `json:"event_id,omitempty"`
  368. // Not required, just for future-proofing
  369. RoomID string `json:"room_id,omitempty"`
  370. }
  371. type MatchedCommand struct {
  372. Target string `json:"target"`
  373. Matched string `json:"matched"`
  374. Arguments map[string]string `json:"arguments"`
  375. }