1// Copyright 2017 Vector Creations Ltd
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package api
16
17import (
18	"github.com/matrix-org/gomatrixserverlib"
19)
20
21// An OutputType is a type of roomserver output.
22type OutputType string
23
24const (
25	// OutputTypeNewRoomEvent indicates that the event is an OutputNewRoomEvent
26	OutputTypeNewRoomEvent OutputType = "new_room_event"
27	// OutputTypeOldRoomEvent indicates that the event is an OutputOldRoomEvent
28	OutputTypeOldRoomEvent OutputType = "old_room_event"
29	// OutputTypeNewInviteEvent indicates that the event is an OutputNewInviteEvent
30	OutputTypeNewInviteEvent OutputType = "new_invite_event"
31	// OutputTypeRetireInviteEvent indicates that the event is an OutputRetireInviteEvent
32	OutputTypeRetireInviteEvent OutputType = "retire_invite_event"
33	// OutputTypeRedactedEvent indicates that the event is an OutputRedactedEvent
34	//
35	// This event is emitted when a redaction has been 'validated' (meaning both the redaction and the event to redact are known).
36	// Redaction validation happens when the roomserver receives either:
37	// - A redaction for which we have the event to redact.
38	// - Any event for which we have a redaction.
39	// When the roomserver receives an event, it will check against the redactions table to see if there is a matching redaction
40	// for the event. If there is, it will mark the redaction as validated and emit this event. In the common case of a redaction
41	// happening after receiving the event to redact, the roomserver will emit a OutputTypeNewRoomEvent of m.room.redaction
42	// immediately followed by a OutputTypeRedactedEvent. In the uncommon case of receiving the redaction BEFORE the event to redact,
43	// the roomserver will emit a OutputTypeNewRoomEvent of the event to redact immediately followed by a OutputTypeRedactedEvent.
44	//
45	// In order to honour redactions correctly, downstream components must ignore m.room.redaction events emitted via OutputTypeNewRoomEvent.
46	// When downstream components receive an OutputTypeRedactedEvent they must:
47	// - Pull out the event to redact from the database. They should have this because the redaction is validated.
48	// - Redact the event and set the corresponding `unsigned` fields to indicate it as redacted.
49	// - Replace the event in the database.
50	OutputTypeRedactedEvent OutputType = "redacted_event"
51
52	// OutputTypeNewPeek indicates that the kafka event is an OutputNewPeek
53	OutputTypeNewPeek OutputType = "new_peek"
54	// OutputTypeNewInboundPeek indicates that the kafka event is an OutputNewInboundPeek
55	OutputTypeNewInboundPeek OutputType = "new_inbound_peek"
56	// OutputTypeRetirePeek indicates that the kafka event is an OutputRetirePeek
57	OutputTypeRetirePeek OutputType = "retire_peek"
58)
59
60// An OutputEvent is an entry in the roomserver output kafka log.
61// Consumers should check the type field when consuming this event.
62type OutputEvent struct {
63	// What sort of event this is.
64	Type OutputType `json:"type"`
65	// The content of event with type OutputTypeNewRoomEvent
66	NewRoomEvent *OutputNewRoomEvent `json:"new_room_event,omitempty"`
67	// The content of event with type OutputTypeOldRoomEvent
68	OldRoomEvent *OutputOldRoomEvent `json:"old_room_event,omitempty"`
69	// The content of event with type OutputTypeNewInviteEvent
70	NewInviteEvent *OutputNewInviteEvent `json:"new_invite_event,omitempty"`
71	// The content of event with type OutputTypeRetireInviteEvent
72	RetireInviteEvent *OutputRetireInviteEvent `json:"retire_invite_event,omitempty"`
73	// The content of event with type OutputTypeRedactedEvent
74	RedactedEvent *OutputRedactedEvent `json:"redacted_event,omitempty"`
75	// The content of event with type OutputTypeNewPeek
76	NewPeek *OutputNewPeek `json:"new_peek,omitempty"`
77	// The content of event with type OutputTypeNewInboundPeek
78	NewInboundPeek *OutputNewInboundPeek `json:"new_inbound_peek,omitempty"`
79	// The content of event with type OutputTypeRetirePeek
80	RetirePeek *OutputRetirePeek `json:"retire_peek,omitempty"`
81}
82
83// Type of the OutputNewRoomEvent.
84type OutputRoomEventType int
85
86const (
87	// The event is a timeline event and likely just happened.
88	OutputRoomTimeline OutputRoomEventType = iota
89
90	// The event is a state event and quite possibly happened in the past.
91	OutputRoomState
92)
93
94// An OutputNewRoomEvent is written when the roomserver receives a new event.
95// It contains the full matrix room event and enough information for a
96// consumer to construct the current state of the room and the state before the
97// event.
98//
99// When we talk about state in a matrix room we are talking about the state
100// after a list of events. The current state is the state after the latest
101// event IDs in the room. The state before an event is the state after its
102// prev_events.
103type OutputNewRoomEvent struct {
104	// The Event.
105	Event *gomatrixserverlib.HeaderedEvent `json:"event"`
106	// Does the event completely rewrite the room state? If so, then AddsStateEventIDs
107	// will contain the entire room state.
108	RewritesState bool `json:"rewrites_state"`
109	// The latest events in the room after this event.
110	// This can be used to set the prev events for new events in the room.
111	// This also can be used to get the full current state after this event.
112	LatestEventIDs []string `json:"latest_event_ids"`
113	// The state event IDs that were added to the state of the room by this event.
114	// Together with RemovesStateEventIDs this allows the receiver to keep an up to date
115	// view of the current state of the room.
116	AddsStateEventIDs []string `json:"adds_state_event_ids"`
117	// All extra newly added state events. This is only set if there are *extra* events
118	// other than `Event`. This can happen when forks get merged because state resolution
119	// may decide a bunch of state events on one branch are now valid, so they will be
120	// present in this list. This is useful when trying to maintain the current state of a room
121	// as to do so you need to include both these events and `Event`.
122	AddStateEvents []*gomatrixserverlib.HeaderedEvent `json:"adds_state_events"`
123
124	// The state event IDs that were removed from the state of the room by this event.
125	RemovesStateEventIDs []string `json:"removes_state_event_ids"`
126	// The ID of the event that was output before this event.
127	// Or the empty string if this is the first event output for this room.
128	// This is used by consumers to check if they can safely update their
129	// current state using the delta supplied in AddsStateEventIDs and
130	// RemovesStateEventIDs.
131	//
132	// If the LastSentEventID doesn't match what they were expecting it to be
133	// they can use the LatestEventIDs to request the full current state.
134	LastSentEventID string `json:"last_sent_event_id"`
135	// The state event IDs that are part of the state at the event, but not
136	// part of the current state. Together with the StateBeforeRemovesEventIDs
137	// this can be used to construct the state before the event from the
138	// current state. The StateBeforeAddsEventIDs and StateBeforeRemovesEventIDs
139	// delta is applied after the AddsStateEventIDs and RemovesStateEventIDs.
140	//
141	// Consumers need to know the state at each event in order to determine
142	// which users and servers are allowed to see the event. This information
143	// is needed to apply the history visibility rules and to tell which
144	// servers we need to push events to over federation.
145	//
146	// The state is given as a delta against the current state because they are
147	// usually either the same state, or differ by just a couple of events.
148	StateBeforeAddsEventIDs []string `json:"state_before_adds_event_ids"`
149	// The state event IDs that are part of the current state, but not part
150	// of the state at the event.
151	StateBeforeRemovesEventIDs []string `json:"state_before_removes_event_ids"`
152	// The server name to use to push this event to other servers.
153	// Or empty if this event shouldn't be pushed to other servers.
154	//
155	// This is used by the federation sender component. We need to tell it what
156	// event it needs to send because it can't tell on its own. Normally if an
157	// event was created on this server then we are responsible for sending it.
158	// However there are a couple of exceptions. The first is that when the
159	// server joins a remote room through another matrix server, it is the job
160	// of the other matrix server to send the event over federation. The second
161	// is the reverse of the first, that is when a remote server joins a room
162	// that we are in over federation using our server it is our responsibility
163	// to send the join event to other matrix servers.
164	//
165	// We encode the server name that the event should be sent using here to
166	// future proof the API for virtual hosting.
167	SendAsServer string `json:"send_as_server"`
168	// The transaction ID of the send request if sent by a local user and one
169	// was specified
170	TransactionID *TransactionID `json:"transaction_id"`
171}
172
173// AddsState returns all added state events from this event.
174//
175// This function is needed because `AddStateEvents` will not include a copy of
176// the original event to save space, so you cannot use that slice alone.
177// Instead, use this function which will add the original event if it is present
178// in `AddsStateEventIDs`.
179func (ore *OutputNewRoomEvent) AddsState() []*gomatrixserverlib.HeaderedEvent {
180	includeOutputEvent := false
181	for _, id := range ore.AddsStateEventIDs {
182		if id == ore.Event.EventID() {
183			includeOutputEvent = true
184			break
185		}
186	}
187	if !includeOutputEvent {
188		return ore.AddStateEvents
189	}
190	return append(ore.AddStateEvents, ore.Event)
191}
192
193// An OutputOldRoomEvent is written when the roomserver receives an old event.
194// This will typically happen as a result of getting either missing events
195// or backfilling. Downstream components may wish to send these events to
196// clients when it is advantageous to do so, but with the consideration that
197// the event is likely a historic event.
198//
199// Old events do not update forward extremities or the current room state,
200// therefore they must not be treated as if they do. Downstream components
201// should build their current room state up from OutputNewRoomEvents only.
202type OutputOldRoomEvent struct {
203	// The Event.
204	Event *gomatrixserverlib.HeaderedEvent `json:"event"`
205}
206
207// An OutputNewInviteEvent is written whenever an invite becomes active.
208// Invite events can be received outside of an existing room so have to be
209// tracked separately from the room events themselves.
210type OutputNewInviteEvent struct {
211	// The room version of the invited room.
212	RoomVersion gomatrixserverlib.RoomVersion `json:"room_version"`
213	// The "m.room.member" invite event.
214	Event *gomatrixserverlib.HeaderedEvent `json:"event"`
215}
216
217// An OutputRetireInviteEvent is written whenever an existing invite is no longer
218// active. An invite stops being active if the user joins the room or if the
219// invite is rejected by the user.
220type OutputRetireInviteEvent struct {
221	// The ID of the "m.room.member" invite event.
222	EventID string
223	// The target user ID of the "m.room.member" invite event that was retired.
224	TargetUserID string
225	// Optional event ID of the event that replaced the invite.
226	// This can be empty if the invite was rejected locally and we were unable
227	// to reach the server that originally sent the invite.
228	RetiredByEventID string
229	// The "membership" of the user after retiring the invite. One of "join"
230	// "leave" or "ban".
231	Membership string
232}
233
234// An OutputRedactedEvent is written whenever a redaction has been /validated/.
235// Downstream components MUST redact the given event ID if they have stored the
236// event JSON. It is guaranteed that this event ID has been seen before.
237type OutputRedactedEvent struct {
238	// The event ID that was redacted
239	RedactedEventID string
240	// The value of `unsigned.redacted_because` - the redaction event itself
241	RedactedBecause *gomatrixserverlib.HeaderedEvent
242}
243
244// An OutputNewPeek is written whenever a user starts peeking into a room
245// using a given device.
246type OutputNewPeek struct {
247	RoomID   string
248	UserID   string
249	DeviceID string
250}
251
252// An OutputNewInboundPeek is written whenever a server starts peeking into a room
253type OutputNewInboundPeek struct {
254	RoomID string
255	PeekID string
256	// the event ID at which the peek begins (so we can avoid
257	// a race between tracking the state returned by /peek and emitting subsequent
258	// peeked events)
259	LatestEventID string
260	ServerName    gomatrixserverlib.ServerName
261	// how often we told the peeking server to renew the peek
262	RenewalInterval int64
263}
264
265// An OutputRetirePeek is written whenever a user stops peeking into a room.
266type OutputRetirePeek struct {
267	RoomID   string
268	UserID   string
269	DeviceID string
270}
271