2020-09-02 17:13:15 +01:00
|
|
|
// Copyright 2020 The Matrix.org Foundation C.I.C.
|
2017-04-20 23:40:52 +01:00
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
2020-09-02 17:13:15 +01:00
|
|
|
package query
|
2017-03-06 14:29:39 +00:00
|
|
|
|
|
|
|
import (
|
2017-09-13 13:37:50 +01:00
|
|
|
"context"
|
2020-09-03 17:20:54 +01:00
|
|
|
"errors"
|
2020-04-28 11:46:47 +01:00
|
|
|
"fmt"
|
2017-07-13 11:41:30 +01:00
|
|
|
|
2020-09-03 17:20:54 +01:00
|
|
|
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
2020-09-02 17:13:15 +01:00
|
|
|
"github.com/matrix-org/dendrite/internal/caching"
|
2020-09-03 17:20:54 +01:00
|
|
|
"github.com/matrix-org/dendrite/roomserver/acls"
|
2017-03-06 14:29:39 +00:00
|
|
|
"github.com/matrix-org/dendrite/roomserver/api"
|
2020-09-02 13:47:31 +01:00
|
|
|
"github.com/matrix-org/dendrite/roomserver/internal/helpers"
|
2017-03-09 15:07:18 +00:00
|
|
|
"github.com/matrix-org/dendrite/roomserver/state"
|
2020-09-02 17:13:15 +01:00
|
|
|
"github.com/matrix-org/dendrite/roomserver/storage"
|
2017-03-06 14:29:39 +00:00
|
|
|
"github.com/matrix-org/dendrite/roomserver/types"
|
2020-02-05 18:06:39 +00:00
|
|
|
"github.com/matrix-org/dendrite/roomserver/version"
|
2017-03-06 14:29:39 +00:00
|
|
|
"github.com/matrix-org/gomatrixserverlib"
|
|
|
|
"github.com/matrix-org/util"
|
2020-04-28 11:46:47 +01:00
|
|
|
"github.com/sirupsen/logrus"
|
2017-03-06 14:29:39 +00:00
|
|
|
)
|
|
|
|
|
2020-09-02 17:13:15 +01:00
|
|
|
type Queryer struct {
|
2020-09-03 17:20:54 +01:00
|
|
|
DB storage.Database
|
|
|
|
Cache caching.RoomServerCaches
|
|
|
|
ServerACLs *acls.ServerACLs
|
2020-09-02 17:13:15 +01:00
|
|
|
}
|
|
|
|
|
2020-05-01 10:48:17 +01:00
|
|
|
// QueryLatestEventsAndState implements api.RoomserverInternalAPI
|
2020-09-02 17:13:15 +01:00
|
|
|
func (r *Queryer) QueryLatestEventsAndState(
|
2017-09-13 13:37:50 +01:00
|
|
|
ctx context.Context,
|
2017-03-06 14:29:39 +00:00
|
|
|
request *api.QueryLatestEventsAndStateRequest,
|
|
|
|
response *api.QueryLatestEventsAndStateResponse,
|
2017-06-02 14:32:36 +01:00
|
|
|
) error {
|
2020-09-02 17:13:15 +01:00
|
|
|
return helpers.QueryLatestEventsAndState(ctx, r.DB, request, response)
|
2017-05-30 17:44:31 +01:00
|
|
|
}
|
|
|
|
|
2020-05-01 10:48:17 +01:00
|
|
|
// QueryStateAfterEvents implements api.RoomserverInternalAPI
|
2020-09-02 17:13:15 +01:00
|
|
|
func (r *Queryer) QueryStateAfterEvents(
|
2017-09-13 13:37:50 +01:00
|
|
|
ctx context.Context,
|
2017-05-30 17:44:31 +01:00
|
|
|
request *api.QueryStateAfterEventsRequest,
|
|
|
|
response *api.QueryStateAfterEventsResponse,
|
2017-06-02 14:32:36 +01:00
|
|
|
) error {
|
2020-09-01 12:40:49 +01:00
|
|
|
info, err := r.DB.RoomInfo(ctx, request.RoomID)
|
2017-05-30 17:44:31 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-09-02 10:02:48 +01:00
|
|
|
if info == nil || info.IsStub {
|
2017-05-30 17:44:31 +01:00
|
|
|
return nil
|
|
|
|
}
|
2020-09-02 10:02:48 +01:00
|
|
|
|
|
|
|
roomState := state.NewStateResolution(r.DB, *info)
|
2017-05-30 17:44:31 +01:00
|
|
|
response.RoomExists = true
|
2020-09-02 10:02:48 +01:00
|
|
|
response.RoomVersion = info.RoomVersion
|
2017-05-30 17:44:31 +01:00
|
|
|
|
2017-09-13 16:30:19 +01:00
|
|
|
prevStates, err := r.DB.StateAtEventIDs(ctx, request.PrevEventIDs)
|
2017-05-30 17:44:31 +01:00
|
|
|
if err != nil {
|
2017-06-07 14:32:53 +01:00
|
|
|
switch err.(type) {
|
|
|
|
case types.MissingEventError:
|
2020-09-16 13:00:52 +01:00
|
|
|
util.GetLogger(ctx).Errorf("QueryStateAfterEvents: MissingEventError: %s", err)
|
2017-06-07 14:32:53 +01:00
|
|
|
return nil
|
|
|
|
default:
|
|
|
|
return err
|
|
|
|
}
|
2017-05-30 17:44:31 +01:00
|
|
|
}
|
|
|
|
response.PrevEventsExist = true
|
|
|
|
|
2017-08-23 15:08:48 +01:00
|
|
|
// Look up the currrent state for the requested tuples.
|
2020-02-05 18:06:39 +00:00
|
|
|
stateEntries, err := roomState.LoadStateAfterEventsForStringTuples(
|
2020-09-02 10:02:48 +01:00
|
|
|
ctx, prevStates, request.StateToFetch,
|
2017-09-13 16:30:19 +01:00
|
|
|
)
|
2017-05-30 17:44:31 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-09-02 13:47:31 +01:00
|
|
|
stateEvents, err := helpers.LoadStateEvents(ctx, r.DB, stateEntries)
|
2017-05-30 17:44:31 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-03-16 17:29:52 +00:00
|
|
|
for _, event := range stateEvents {
|
2020-09-02 10:02:48 +01:00
|
|
|
response.StateEvents = append(response.StateEvents, event.Headered(info.RoomVersion))
|
2020-03-16 17:29:52 +00:00
|
|
|
}
|
|
|
|
|
2017-05-30 17:44:31 +01:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-09-29 13:40:29 +01:00
|
|
|
// QueryMissingAuthPrevEvents implements api.RoomserverInternalAPI
|
|
|
|
func (r *Queryer) QueryMissingAuthPrevEvents(
|
|
|
|
ctx context.Context,
|
|
|
|
request *api.QueryMissingAuthPrevEventsRequest,
|
|
|
|
response *api.QueryMissingAuthPrevEventsResponse,
|
|
|
|
) error {
|
|
|
|
info, err := r.DB.RoomInfo(ctx, request.RoomID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if info == nil {
|
|
|
|
return errors.New("room doesn't exist")
|
|
|
|
}
|
|
|
|
|
|
|
|
response.RoomExists = !info.IsStub
|
|
|
|
response.RoomVersion = info.RoomVersion
|
|
|
|
|
|
|
|
for _, authEventID := range request.AuthEventIDs {
|
|
|
|
if nids, err := r.DB.EventNIDs(ctx, []string{authEventID}); err != nil || len(nids) == 0 {
|
|
|
|
response.MissingAuthEventIDs = append(response.MissingAuthEventIDs, authEventID)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, prevEventID := range request.PrevEventIDs {
|
2020-10-12 15:56:15 +01:00
|
|
|
if state, err := r.DB.StateAtEventIDs(ctx, []string{prevEventID}); err != nil || len(state) == 0 {
|
2020-09-29 13:40:29 +01:00
|
|
|
response.MissingPrevEventIDs = append(response.MissingPrevEventIDs, prevEventID)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-05-01 10:48:17 +01:00
|
|
|
// QueryEventsByID implements api.RoomserverInternalAPI
|
2020-09-02 17:13:15 +01:00
|
|
|
func (r *Queryer) QueryEventsByID(
|
2017-09-13 13:37:50 +01:00
|
|
|
ctx context.Context,
|
2017-06-02 14:32:36 +01:00
|
|
|
request *api.QueryEventsByIDRequest,
|
|
|
|
response *api.QueryEventsByIDResponse,
|
|
|
|
) error {
|
2017-09-13 16:30:19 +01:00
|
|
|
eventNIDMap, err := r.DB.EventNIDs(ctx, request.EventIDs)
|
2017-06-02 14:32:36 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
var eventNIDs []types.EventNID
|
|
|
|
for _, nid := range eventNIDMap {
|
|
|
|
eventNIDs = append(eventNIDs, nid)
|
|
|
|
}
|
|
|
|
|
2020-09-02 13:47:31 +01:00
|
|
|
events, err := helpers.LoadEvents(ctx, r.DB, eventNIDs)
|
2017-06-02 14:32:36 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-03-16 17:29:52 +00:00
|
|
|
for _, event := range events {
|
2020-09-02 10:02:48 +01:00
|
|
|
roomVersion, verr := r.roomVersion(event.RoomID())
|
2020-03-17 18:00:10 +00:00
|
|
|
if verr != nil {
|
|
|
|
return verr
|
|
|
|
}
|
2020-03-16 17:29:52 +00:00
|
|
|
|
2020-03-17 11:01:25 +00:00
|
|
|
response.Events = append(response.Events, event.Headered(roomVersion))
|
2020-03-16 17:29:52 +00:00
|
|
|
}
|
|
|
|
|
2017-06-02 14:32:36 +01:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-05-01 10:48:17 +01:00
|
|
|
// QueryMembershipForUser implements api.RoomserverInternalAPI
|
2020-09-02 17:13:15 +01:00
|
|
|
func (r *Queryer) QueryMembershipForUser(
|
2018-07-11 11:10:37 +01:00
|
|
|
ctx context.Context,
|
|
|
|
request *api.QueryMembershipForUserRequest,
|
|
|
|
response *api.QueryMembershipForUserResponse,
|
|
|
|
) error {
|
2020-09-01 12:40:49 +01:00
|
|
|
info, err := r.DB.RoomInfo(ctx, request.RoomID)
|
2018-07-11 11:10:37 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-09-07 12:38:09 +01:00
|
|
|
if info == nil {
|
|
|
|
return fmt.Errorf("QueryMembershipForUser: unknown room %s", request.RoomID)
|
|
|
|
}
|
2018-07-11 11:10:37 +01:00
|
|
|
|
2020-09-01 12:40:49 +01:00
|
|
|
membershipEventNID, stillInRoom, err := r.DB.GetMembership(ctx, info.RoomNID, request.UserID)
|
2018-07-11 11:10:37 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if membershipEventNID == 0 {
|
|
|
|
response.HasBeenInRoom = false
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
response.IsInRoom = stillInRoom
|
2020-07-28 10:09:10 +01:00
|
|
|
response.HasBeenInRoom = true
|
2020-06-24 18:19:54 +01:00
|
|
|
|
|
|
|
evs, err := r.DB.Events(ctx, []types.EventNID{membershipEventNID})
|
2018-07-11 11:10:37 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-06-24 18:19:54 +01:00
|
|
|
if len(evs) != 1 {
|
|
|
|
return fmt.Errorf("failed to load membership event for event NID %d", membershipEventNID)
|
|
|
|
}
|
2018-07-11 11:10:37 +01:00
|
|
|
|
2020-06-24 18:19:54 +01:00
|
|
|
response.EventID = evs[0].EventID()
|
|
|
|
response.Membership, err = evs[0].Membership()
|
|
|
|
return err
|
2018-07-11 11:10:37 +01:00
|
|
|
}
|
|
|
|
|
2020-05-01 10:48:17 +01:00
|
|
|
// QueryMembershipsForRoom implements api.RoomserverInternalAPI
|
2020-09-02 17:13:15 +01:00
|
|
|
func (r *Queryer) QueryMembershipsForRoom(
|
2017-09-13 13:37:50 +01:00
|
|
|
ctx context.Context,
|
2017-08-21 16:34:26 +01:00
|
|
|
request *api.QueryMembershipsForRoomRequest,
|
|
|
|
response *api.QueryMembershipsForRoomResponse,
|
|
|
|
) error {
|
2020-09-01 12:40:49 +01:00
|
|
|
info, err := r.DB.RoomInfo(ctx, request.RoomID)
|
2017-08-21 16:34:26 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-09-01 12:40:49 +01:00
|
|
|
membershipEventNID, stillInRoom, err := r.DB.GetMembership(ctx, info.RoomNID, request.Sender)
|
2017-08-21 16:34:26 +01:00
|
|
|
if err != nil {
|
2018-07-11 13:16:38 +01:00
|
|
|
return err
|
2017-08-21 16:34:26 +01:00
|
|
|
}
|
|
|
|
|
2017-08-24 16:00:14 +01:00
|
|
|
if membershipEventNID == 0 {
|
2017-08-21 16:34:26 +01:00
|
|
|
response.HasBeenInRoom = false
|
|
|
|
response.JoinEvents = nil
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
response.HasBeenInRoom = true
|
|
|
|
response.JoinEvents = []gomatrixserverlib.ClientEvent{}
|
2017-08-24 16:00:14 +01:00
|
|
|
|
|
|
|
var events []types.Event
|
2020-04-29 18:41:45 +01:00
|
|
|
var stateEntries []types.StateEntry
|
2017-08-24 16:00:14 +01:00
|
|
|
if stillInRoom {
|
|
|
|
var eventNIDs []types.EventNID
|
2020-09-01 12:40:49 +01:00
|
|
|
eventNIDs, err = r.DB.GetMembershipEventNIDsForRoom(ctx, info.RoomNID, request.JoinedOnly, false)
|
2017-08-24 16:00:14 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-09-13 16:30:19 +01:00
|
|
|
events, err = r.DB.Events(ctx, eventNIDs)
|
2017-08-24 16:00:14 +01:00
|
|
|
} else {
|
2020-09-02 13:47:31 +01:00
|
|
|
stateEntries, err = helpers.StateBeforeEvent(ctx, r.DB, *info, membershipEventNID)
|
2020-04-29 18:41:45 +01:00
|
|
|
if err != nil {
|
|
|
|
logrus.WithField("membership_event_nid", membershipEventNID).WithError(err).Error("failed to load state before event")
|
|
|
|
return err
|
|
|
|
}
|
2020-09-02 13:47:31 +01:00
|
|
|
events, err = helpers.GetMembershipsAtState(ctx, r.DB, stateEntries, request.JoinedOnly)
|
2017-08-24 16:00:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-08-21 16:34:26 +01:00
|
|
|
for _, event := range events {
|
|
|
|
clientEvent := gomatrixserverlib.ToClientEvent(event.Event, gomatrixserverlib.FormatAll)
|
|
|
|
response.JoinEvents = append(response.JoinEvents, clientEvent)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-09-24 16:18:13 +01:00
|
|
|
// QueryServerJoinedToRoom implements api.RoomserverInternalAPI
|
|
|
|
func (r *Queryer) QueryServerJoinedToRoom(
|
|
|
|
ctx context.Context,
|
|
|
|
request *api.QueryServerJoinedToRoomRequest,
|
|
|
|
response *api.QueryServerJoinedToRoomResponse,
|
|
|
|
) error {
|
|
|
|
info, err := r.DB.RoomInfo(ctx, request.RoomID)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("r.DB.RoomInfo: %w", err)
|
|
|
|
}
|
|
|
|
if info == nil || info.IsStub {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
response.RoomExists = true
|
|
|
|
|
|
|
|
eventNIDs, err := r.DB.GetMembershipEventNIDsForRoom(ctx, info.RoomNID, true, false)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("r.DB.GetMembershipEventNIDsForRoom: %w", err)
|
|
|
|
}
|
|
|
|
if len(eventNIDs) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
events, err := r.DB.Events(ctx, eventNIDs)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("r.DB.Events: %w", err)
|
|
|
|
}
|
|
|
|
|
2020-09-29 13:40:29 +01:00
|
|
|
servers := map[gomatrixserverlib.ServerName]struct{}{}
|
2020-09-24 16:18:13 +01:00
|
|
|
for _, e := range events {
|
|
|
|
if e.Type() == gomatrixserverlib.MRoomMember && e.StateKey() != nil {
|
|
|
|
_, serverName, err := gomatrixserverlib.SplitID('@', *e.StateKey())
|
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
2020-09-29 13:40:29 +01:00
|
|
|
servers[serverName] = struct{}{}
|
2020-09-24 16:18:13 +01:00
|
|
|
if serverName == request.ServerName {
|
|
|
|
response.IsInRoom = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-29 13:40:29 +01:00
|
|
|
for server := range servers {
|
|
|
|
response.ServerNames = append(response.ServerNames, server)
|
|
|
|
}
|
|
|
|
|
2020-09-24 16:18:13 +01:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-05-01 10:48:17 +01:00
|
|
|
// QueryServerAllowedToSeeEvent implements api.RoomserverInternalAPI
|
2020-09-02 17:13:15 +01:00
|
|
|
func (r *Queryer) QueryServerAllowedToSeeEvent(
|
2017-09-13 13:37:50 +01:00
|
|
|
ctx context.Context,
|
2017-09-06 12:38:22 +01:00
|
|
|
request *api.QueryServerAllowedToSeeEventRequest,
|
|
|
|
response *api.QueryServerAllowedToSeeEventResponse,
|
2018-06-26 11:25:49 +01:00
|
|
|
) (err error) {
|
2020-03-24 12:20:10 +00:00
|
|
|
events, err := r.DB.EventsFromIDs(ctx, []string{request.EventID})
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if len(events) == 0 {
|
|
|
|
response.AllowedToSeeEvent = false // event doesn't exist so not allowed to see
|
|
|
|
return
|
|
|
|
}
|
2020-09-02 10:02:48 +01:00
|
|
|
roomID := events[0].RoomID()
|
2020-09-02 13:47:31 +01:00
|
|
|
isServerInRoom, err := helpers.IsServerCurrentlyInRoom(ctx, r.DB, request.ServerName, roomID)
|
2020-03-24 12:20:10 +00:00
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
2020-09-02 10:02:48 +01:00
|
|
|
info, err := r.DB.RoomInfo(ctx, roomID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if info == nil {
|
|
|
|
return fmt.Errorf("QueryServerAllowedToSeeEvent: no room info for room %s", roomID)
|
|
|
|
}
|
2020-09-02 13:47:31 +01:00
|
|
|
response.AllowedToSeeEvent, err = helpers.CheckServerAllowedToSeeEvent(
|
|
|
|
ctx, r.DB, *info, request.EventID, request.ServerName, isServerInRoom,
|
2018-06-26 11:25:49 +01:00
|
|
|
)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-05-01 10:48:17 +01:00
|
|
|
// QueryMissingEvents implements api.RoomserverInternalAPI
|
2020-09-02 10:02:48 +01:00
|
|
|
// nolint:gocyclo
|
2020-09-02 17:13:15 +01:00
|
|
|
func (r *Queryer) QueryMissingEvents(
|
2018-06-26 11:25:49 +01:00
|
|
|
ctx context.Context,
|
|
|
|
request *api.QueryMissingEventsRequest,
|
|
|
|
response *api.QueryMissingEventsResponse,
|
|
|
|
) error {
|
|
|
|
var front []string
|
2019-01-14 10:20:19 +00:00
|
|
|
eventsToFilter := make(map[string]bool, len(request.LatestEvents))
|
2018-06-26 11:25:49 +01:00
|
|
|
visited := make(map[string]bool, request.Limit) // request.Limit acts as a hint to size.
|
|
|
|
for _, id := range request.EarliestEvents {
|
|
|
|
visited[id] = true
|
|
|
|
}
|
2017-09-06 12:38:22 +01:00
|
|
|
|
2018-06-26 11:25:49 +01:00
|
|
|
for _, id := range request.LatestEvents {
|
|
|
|
if !visited[id] {
|
|
|
|
front = append(front, id)
|
2019-01-14 10:20:19 +00:00
|
|
|
eventsToFilter[id] = true
|
2017-09-06 12:38:22 +01:00
|
|
|
}
|
2018-06-26 11:25:49 +01:00
|
|
|
}
|
2020-09-02 10:02:48 +01:00
|
|
|
events, err := r.DB.EventsFromIDs(ctx, front)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if len(events) == 0 {
|
|
|
|
return nil // we are missing the events being asked to search from, give up.
|
|
|
|
}
|
|
|
|
info, err := r.DB.RoomInfo(ctx, events[0].RoomID())
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if info == nil || info.IsStub {
|
|
|
|
return fmt.Errorf("missing RoomInfo for room %s", events[0].RoomID())
|
|
|
|
}
|
2017-09-06 12:38:22 +01:00
|
|
|
|
2020-09-02 13:47:31 +01:00
|
|
|
resultNIDs, err := helpers.ScanEventTree(ctx, r.DB, *info, front, visited, request.Limit, request.ServerName)
|
2018-11-07 11:38:01 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-09-02 13:47:31 +01:00
|
|
|
loadedEvents, err := helpers.LoadEvents(ctx, r.DB, resultNIDs)
|
2019-01-14 10:20:19 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-03-16 17:29:52 +00:00
|
|
|
response.Events = make([]gomatrixserverlib.HeaderedEvent, 0, len(loadedEvents)-len(eventsToFilter))
|
2019-01-14 10:20:19 +00:00
|
|
|
for _, event := range loadedEvents {
|
|
|
|
if !eventsToFilter[event.EventID()] {
|
2020-09-02 10:02:48 +01:00
|
|
|
roomVersion, verr := r.roomVersion(event.RoomID())
|
2020-03-17 18:00:10 +00:00
|
|
|
if verr != nil {
|
|
|
|
return verr
|
|
|
|
}
|
2020-03-16 17:29:52 +00:00
|
|
|
|
2020-03-17 11:01:25 +00:00
|
|
|
response.Events = append(response.Events, event.Headered(roomVersion))
|
2019-01-14 10:20:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-07 11:38:01 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-05-01 10:48:17 +01:00
|
|
|
// QueryStateAndAuthChain implements api.RoomserverInternalAPI
|
2020-09-02 17:13:15 +01:00
|
|
|
func (r *Queryer) QueryStateAndAuthChain(
|
2017-11-27 10:20:00 +00:00
|
|
|
ctx context.Context,
|
|
|
|
request *api.QueryStateAndAuthChainRequest,
|
|
|
|
response *api.QueryStateAndAuthChainResponse,
|
|
|
|
) error {
|
2020-09-01 12:40:49 +01:00
|
|
|
info, err := r.DB.RoomInfo(ctx, request.RoomID)
|
2017-11-27 10:20:00 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-09-02 10:02:48 +01:00
|
|
|
if info == nil || info.IsStub {
|
2017-11-27 10:20:00 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
response.RoomExists = true
|
2020-09-01 12:40:49 +01:00
|
|
|
response.RoomVersion = info.RoomVersion
|
2020-03-17 18:00:10 +00:00
|
|
|
|
2020-09-02 10:02:48 +01:00
|
|
|
stateEvents, err := r.loadStateAtEventIDs(ctx, *info, request.PrevEventIDs)
|
2017-11-27 10:20:00 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-03-17 17:18:48 +00:00
|
|
|
response.PrevEventsExist = true
|
2017-11-27 10:20:00 +00:00
|
|
|
|
2020-03-17 17:18:48 +00:00
|
|
|
// add the auth event IDs for the current state events too
|
|
|
|
var authEventIDs []string
|
|
|
|
authEventIDs = append(authEventIDs, request.AuthEventIDs...)
|
|
|
|
for _, se := range stateEvents {
|
|
|
|
authEventIDs = append(authEventIDs, se.AuthEventIDs()...)
|
2017-11-27 10:20:00 +00:00
|
|
|
}
|
2020-03-17 17:18:48 +00:00
|
|
|
authEventIDs = util.UniqueStrings(authEventIDs) // de-dupe
|
2017-11-27 10:20:00 +00:00
|
|
|
|
2020-04-24 10:38:58 +01:00
|
|
|
authEvents, err := getAuthChain(ctx, r.DB.EventsFromIDs, authEventIDs)
|
2020-03-16 17:29:52 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
Federation for v3/v4 rooms (#954)
* Update gomatrixserverlib
* Default to room version 4
* Update gomatrixserverlib
* Limit prev_events and auth_events
* Fix auth_events, prev_events
* Fix linter issues
* Update gomatrixserverlib
* Fix getState
* Update sytest-whitelist
* Squashed commit of the following:
commit 067b87506357c996fd6ddb11271db9469ad4ce80
Author: Neil Alexander <neilalexander@users.noreply.github.com>
Date: Fri Apr 3 14:29:06 2020 +0100
Invites v2 endpoint (#952)
* Start converting v1 invite endpoint to v2
* Update gomatrixserverlib
* Early federationsender code for sending invites
* Sending invites sorta happens now
* Populate invite request with stripped state
* Remodel a bit, don't reflect received invites
* Handle invite_room_state
* Handle room versions a bit better
* Update gomatrixserverlib
* Tweak order in destinationQueue.next
* Revert check in processMessage
* Tweak federation sender destination queue code a bit
* Add comments
commit 955244c09298d0e6c870377dad3af2ffa1f5e578
Author: Ben B <benne@klimlive.de>
Date: Fri Apr 3 12:40:50 2020 +0200
use custom http client instead of the http DefaultClient (#823)
This commit replaces the default client from the http lib with a custom one.
The previously used default client doesn't come with a timeout. This could cause
unwanted locks.
That solution chosen here creates a http client in the base component dendrite
with a constant timeout of 30 seconds. If it should be necessary to overwrite
this, we could include the timeout in the dendrite configuration.
Here it would be a good idea to extend the type "Address" by a timeout and
create an http client for each service.
Closes #820
Signed-off-by: Benedikt Bongartz <benne@klimlive.de>
Co-authored-by: Kegsay <kegan@matrix.org>
* Update sytest-whitelist, sytest-blacklist
* Update go.mod/go.sum
* Add some error wrapping for debug
* Add a NOTSPEC to common/events.go
* Perform state resolution at send_join
* Set default room version to v2 again
* Tweak GetCapabilities
* Add comments to ResolveConflictsAdhoc
* Update sytest-blacklist
* go mod tidy
* Update sytest-whitelist, sytest-blacklist
* Update versions
* Updates from review comments
* Update sytest-blacklist, sytest-whitelist
* Check room versions compatible at make_join, add some comments, update gomatrixserverlib, other tweaks
* Set default room version back to v2
* Update gomatrixserverlib, sytest-whitelist
2020-04-09 15:46:06 +01:00
|
|
|
if request.ResolveState {
|
|
|
|
if stateEvents, err = state.ResolveConflictsAdhoc(
|
2020-09-01 12:40:49 +01:00
|
|
|
info.RoomVersion, stateEvents, authEvents,
|
Federation for v3/v4 rooms (#954)
* Update gomatrixserverlib
* Default to room version 4
* Update gomatrixserverlib
* Limit prev_events and auth_events
* Fix auth_events, prev_events
* Fix linter issues
* Update gomatrixserverlib
* Fix getState
* Update sytest-whitelist
* Squashed commit of the following:
commit 067b87506357c996fd6ddb11271db9469ad4ce80
Author: Neil Alexander <neilalexander@users.noreply.github.com>
Date: Fri Apr 3 14:29:06 2020 +0100
Invites v2 endpoint (#952)
* Start converting v1 invite endpoint to v2
* Update gomatrixserverlib
* Early federationsender code for sending invites
* Sending invites sorta happens now
* Populate invite request with stripped state
* Remodel a bit, don't reflect received invites
* Handle invite_room_state
* Handle room versions a bit better
* Update gomatrixserverlib
* Tweak order in destinationQueue.next
* Revert check in processMessage
* Tweak federation sender destination queue code a bit
* Add comments
commit 955244c09298d0e6c870377dad3af2ffa1f5e578
Author: Ben B <benne@klimlive.de>
Date: Fri Apr 3 12:40:50 2020 +0200
use custom http client instead of the http DefaultClient (#823)
This commit replaces the default client from the http lib with a custom one.
The previously used default client doesn't come with a timeout. This could cause
unwanted locks.
That solution chosen here creates a http client in the base component dendrite
with a constant timeout of 30 seconds. If it should be necessary to overwrite
this, we could include the timeout in the dendrite configuration.
Here it would be a good idea to extend the type "Address" by a timeout and
create an http client for each service.
Closes #820
Signed-off-by: Benedikt Bongartz <benne@klimlive.de>
Co-authored-by: Kegsay <kegan@matrix.org>
* Update sytest-whitelist, sytest-blacklist
* Update go.mod/go.sum
* Add some error wrapping for debug
* Add a NOTSPEC to common/events.go
* Perform state resolution at send_join
* Set default room version to v2 again
* Tweak GetCapabilities
* Add comments to ResolveConflictsAdhoc
* Update sytest-blacklist
* go mod tidy
* Update sytest-whitelist, sytest-blacklist
* Update versions
* Updates from review comments
* Update sytest-blacklist, sytest-whitelist
* Check room versions compatible at make_join, add some comments, update gomatrixserverlib, other tweaks
* Set default room version back to v2
* Update gomatrixserverlib, sytest-whitelist
2020-04-09 15:46:06 +01:00
|
|
|
); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-16 17:29:52 +00:00
|
|
|
for _, event := range stateEvents {
|
2020-09-01 12:40:49 +01:00
|
|
|
response.StateEvents = append(response.StateEvents, event.Headered(info.RoomVersion))
|
2020-03-16 17:29:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, event := range authEvents {
|
2020-09-01 12:40:49 +01:00
|
|
|
response.AuthChainEvents = append(response.AuthChainEvents, event.Headered(info.RoomVersion))
|
2020-03-16 17:29:52 +00:00
|
|
|
}
|
|
|
|
|
2017-11-27 10:20:00 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-09-02 17:13:15 +01:00
|
|
|
func (r *Queryer) loadStateAtEventIDs(ctx context.Context, roomInfo types.RoomInfo, eventIDs []string) ([]gomatrixserverlib.Event, error) {
|
2020-09-02 10:02:48 +01:00
|
|
|
roomState := state.NewStateResolution(r.DB, roomInfo)
|
2020-03-17 17:18:48 +00:00
|
|
|
prevStates, err := r.DB.StateAtEventIDs(ctx, eventIDs)
|
|
|
|
if err != nil {
|
|
|
|
switch err.(type) {
|
|
|
|
case types.MissingEventError:
|
|
|
|
return nil, nil
|
|
|
|
default:
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Look up the currrent state for the requested tuples.
|
|
|
|
stateEntries, err := roomState.LoadCombinedStateAfterEvents(
|
|
|
|
ctx, prevStates,
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-09-02 13:47:31 +01:00
|
|
|
return helpers.LoadStateEvents(ctx, r.DB, stateEntries)
|
2020-03-17 17:18:48 +00:00
|
|
|
}
|
|
|
|
|
2020-04-24 10:38:58 +01:00
|
|
|
type eventsFromIDs func(context.Context, []string) ([]types.Event, error)
|
|
|
|
|
2020-01-10 12:11:44 +00:00
|
|
|
// getAuthChain fetches the auth chain for the given auth events. An auth chain
|
|
|
|
// is the list of all events that are referenced in the auth_events section, and
|
|
|
|
// all their auth_events, recursively. The returned set of events contain the
|
|
|
|
// given events. Will *not* error if we don't have all auth events.
|
2017-11-27 10:20:00 +00:00
|
|
|
func getAuthChain(
|
2020-04-24 10:38:58 +01:00
|
|
|
ctx context.Context, fn eventsFromIDs, authEventIDs []string,
|
2017-11-27 10:20:00 +00:00
|
|
|
) ([]gomatrixserverlib.Event, error) {
|
2020-01-10 12:11:44 +00:00
|
|
|
// List of event IDs to fetch. On each pass, these events will be requested
|
|
|
|
// from the database and the `eventsToFetch` will be updated with any new
|
|
|
|
// events that we have learned about and need to find. When `eventsToFetch`
|
|
|
|
// is eventually empty, we should have reached the end of the chain.
|
2017-11-27 10:20:00 +00:00
|
|
|
eventsToFetch := authEventIDs
|
2020-01-10 12:11:44 +00:00
|
|
|
authEventsMap := make(map[string]gomatrixserverlib.Event)
|
2017-11-27 10:20:00 +00:00
|
|
|
|
|
|
|
for len(eventsToFetch) > 0 {
|
2020-01-10 12:11:44 +00:00
|
|
|
// Try to retrieve the events from the database.
|
2020-04-24 10:38:58 +01:00
|
|
|
events, err := fn(ctx, eventsToFetch)
|
2017-11-27 10:20:00 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-01-10 12:11:44 +00:00
|
|
|
// We've now fetched these events so clear out `eventsToFetch`. Soon we may
|
|
|
|
// add newly discovered events to this for the next pass.
|
2017-11-27 10:20:00 +00:00
|
|
|
eventsToFetch = eventsToFetch[:0]
|
2020-01-10 12:11:44 +00:00
|
|
|
|
2017-11-27 10:20:00 +00:00
|
|
|
for _, event := range events {
|
2020-01-10 12:11:44 +00:00
|
|
|
// Store the event in the event map - this prevents us from requesting it
|
|
|
|
// from the database again.
|
|
|
|
authEventsMap[event.EventID()] = event.Event
|
|
|
|
|
|
|
|
// Extract all of the auth events from the newly obtained event. If we
|
|
|
|
// don't already have a record of the event, record it in the list of
|
|
|
|
// events we want to request for the next pass.
|
|
|
|
for _, authEvent := range event.AuthEvents() {
|
|
|
|
if _, ok := authEventsMap[authEvent.EventID]; !ok {
|
|
|
|
eventsToFetch = append(eventsToFetch, authEvent.EventID)
|
2017-11-27 10:20:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-10 12:11:44 +00:00
|
|
|
// We've now retrieved all of the events we can. Flatten them down into an
|
|
|
|
// array and return them.
|
|
|
|
var authEvents []gomatrixserverlib.Event
|
|
|
|
for _, event := range authEventsMap {
|
|
|
|
authEvents = append(authEvents, event)
|
|
|
|
}
|
|
|
|
|
2017-11-27 10:20:00 +00:00
|
|
|
return authEvents, nil
|
|
|
|
}
|
|
|
|
|
2020-05-01 10:48:17 +01:00
|
|
|
// QueryRoomVersionCapabilities implements api.RoomserverInternalAPI
|
2020-09-02 17:13:15 +01:00
|
|
|
func (r *Queryer) QueryRoomVersionCapabilities(
|
2020-02-05 18:06:39 +00:00
|
|
|
ctx context.Context,
|
|
|
|
request *api.QueryRoomVersionCapabilitiesRequest,
|
|
|
|
response *api.QueryRoomVersionCapabilitiesResponse,
|
|
|
|
) error {
|
2020-03-19 12:07:01 +00:00
|
|
|
response.DefaultRoomVersion = version.DefaultRoomVersion()
|
|
|
|
response.AvailableRoomVersions = make(map[gomatrixserverlib.RoomVersion]string)
|
2020-03-16 16:05:29 +00:00
|
|
|
for v, desc := range version.SupportedRoomVersions() {
|
2020-02-05 18:06:39 +00:00
|
|
|
if desc.Stable {
|
2020-03-19 12:07:01 +00:00
|
|
|
response.AvailableRoomVersions[v] = "stable"
|
2020-02-05 18:06:39 +00:00
|
|
|
} else {
|
2020-03-19 12:07:01 +00:00
|
|
|
response.AvailableRoomVersions[v] = "unstable"
|
2020-02-05 18:06:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-05-01 10:48:17 +01:00
|
|
|
// QueryRoomVersionCapabilities implements api.RoomserverInternalAPI
|
2020-09-02 17:13:15 +01:00
|
|
|
func (r *Queryer) QueryRoomVersionForRoom(
|
2020-03-27 16:28:22 +00:00
|
|
|
ctx context.Context,
|
|
|
|
request *api.QueryRoomVersionForRoomRequest,
|
|
|
|
response *api.QueryRoomVersionForRoomResponse,
|
|
|
|
) error {
|
2020-06-05 16:42:01 +01:00
|
|
|
if roomVersion, ok := r.Cache.GetRoomVersion(request.RoomID); ok {
|
2020-04-22 13:00:05 +01:00
|
|
|
response.RoomVersion = roomVersion
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-09-02 10:02:48 +01:00
|
|
|
info, err := r.DB.RoomInfo(ctx, request.RoomID)
|
2020-03-27 16:28:22 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-09-02 10:02:48 +01:00
|
|
|
if info == nil {
|
|
|
|
return fmt.Errorf("QueryRoomVersionForRoom: missing room info for room %s", request.RoomID)
|
|
|
|
}
|
|
|
|
response.RoomVersion = info.RoomVersion
|
2020-06-05 16:42:01 +01:00
|
|
|
r.Cache.StoreRoomVersion(request.RoomID, response.RoomVersion)
|
2020-03-27 16:28:22 +00:00
|
|
|
return nil
|
|
|
|
}
|
2020-07-02 15:41:18 +01:00
|
|
|
|
2020-09-02 17:13:15 +01:00
|
|
|
func (r *Queryer) roomVersion(roomID string) (gomatrixserverlib.RoomVersion, error) {
|
2020-09-02 10:02:48 +01:00
|
|
|
var res api.QueryRoomVersionForRoomResponse
|
|
|
|
err := r.QueryRoomVersionForRoom(context.Background(), &api.QueryRoomVersionForRoomRequest{
|
|
|
|
RoomID: roomID,
|
|
|
|
}, &res)
|
|
|
|
return res.RoomVersion, err
|
|
|
|
}
|
|
|
|
|
2020-09-02 17:13:15 +01:00
|
|
|
func (r *Queryer) QueryPublishedRooms(
|
2020-07-02 15:41:18 +01:00
|
|
|
ctx context.Context,
|
|
|
|
req *api.QueryPublishedRoomsRequest,
|
|
|
|
res *api.QueryPublishedRoomsResponse,
|
|
|
|
) error {
|
|
|
|
rooms, err := r.DB.GetPublishedRooms(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
res.RoomIDs = rooms
|
|
|
|
return nil
|
|
|
|
}
|
2020-09-03 17:20:54 +01:00
|
|
|
|
|
|
|
func (r *Queryer) QueryCurrentState(ctx context.Context, req *api.QueryCurrentStateRequest, res *api.QueryCurrentStateResponse) error {
|
|
|
|
res.StateEvents = make(map[gomatrixserverlib.StateKeyTuple]*gomatrixserverlib.HeaderedEvent)
|
|
|
|
for _, tuple := range req.StateTuples {
|
|
|
|
ev, err := r.DB.GetStateEvent(ctx, req.RoomID, tuple.EventType, tuple.StateKey)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if ev != nil {
|
|
|
|
res.StateEvents[tuple] = ev
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *Queryer) QueryRoomsForUser(ctx context.Context, req *api.QueryRoomsForUserRequest, res *api.QueryRoomsForUserResponse) error {
|
|
|
|
roomIDs, err := r.DB.GetRoomsByMembership(ctx, req.UserID, req.WantMembership)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
res.RoomIDs = roomIDs
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *Queryer) QueryKnownUsers(ctx context.Context, req *api.QueryKnownUsersRequest, res *api.QueryKnownUsersResponse) error {
|
|
|
|
users, err := r.DB.GetKnownUsers(ctx, req.UserID, req.SearchString, req.Limit)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
for _, user := range users {
|
|
|
|
res.Users = append(res.Users, authtypes.FullyQualifiedProfile{
|
|
|
|
UserID: user,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *Queryer) QueryBulkStateContent(ctx context.Context, req *api.QueryBulkStateContentRequest, res *api.QueryBulkStateContentResponse) error {
|
|
|
|
events, err := r.DB.GetBulkStateContent(ctx, req.RoomIDs, req.StateTuples, req.AllowWildcards)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
res.Rooms = make(map[string]map[gomatrixserverlib.StateKeyTuple]string)
|
|
|
|
for _, ev := range events {
|
|
|
|
if res.Rooms[ev.RoomID] == nil {
|
|
|
|
res.Rooms[ev.RoomID] = make(map[gomatrixserverlib.StateKeyTuple]string)
|
|
|
|
}
|
|
|
|
room := res.Rooms[ev.RoomID]
|
|
|
|
room[gomatrixserverlib.StateKeyTuple{
|
|
|
|
EventType: ev.EventType,
|
|
|
|
StateKey: ev.StateKey,
|
|
|
|
}] = ev.ContentValue
|
|
|
|
res.Rooms[ev.RoomID] = room
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *Queryer) QuerySharedUsers(ctx context.Context, req *api.QuerySharedUsersRequest, res *api.QuerySharedUsersResponse) error {
|
|
|
|
roomIDs, err := r.DB.GetRoomsByMembership(ctx, req.UserID, "join")
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
roomIDs = append(roomIDs, req.IncludeRoomIDs...)
|
|
|
|
excludeMap := make(map[string]bool)
|
|
|
|
for _, roomID := range req.ExcludeRoomIDs {
|
|
|
|
excludeMap[roomID] = true
|
|
|
|
}
|
|
|
|
// filter out excluded rooms
|
|
|
|
j := 0
|
|
|
|
for i := range roomIDs {
|
|
|
|
// move elements to include to the beginning of the slice
|
|
|
|
// then trim elements on the right
|
|
|
|
if !excludeMap[roomIDs[i]] {
|
|
|
|
roomIDs[j] = roomIDs[i]
|
|
|
|
j++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
roomIDs = roomIDs[:j]
|
|
|
|
|
|
|
|
users, err := r.DB.JoinedUsersSetInRooms(ctx, roomIDs)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
res.UserIDsToCount = users
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *Queryer) QueryServerBannedFromRoom(ctx context.Context, req *api.QueryServerBannedFromRoomRequest, res *api.QueryServerBannedFromRoomResponse) error {
|
|
|
|
if r.ServerACLs == nil {
|
|
|
|
return errors.New("no server ACL tracking")
|
|
|
|
}
|
|
|
|
res.Banned = r.ServerACLs.IsServerBannedFromRoom(req.ServerName, req.RoomID)
|
|
|
|
return nil
|
|
|
|
}
|