2020-05-01 07:01:50 -05:00
|
|
|
package internal
|
2020-04-29 05:34:31 -05:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2020-10-09 18:21:15 -05:00
|
|
|
"encoding/json"
|
2020-06-25 09:04:48 -05:00
|
|
|
"errors"
|
2020-04-29 09:29:39 -05:00
|
|
|
"fmt"
|
|
|
|
"time"
|
2020-04-29 05:34:31 -05:00
|
|
|
|
2020-06-25 09:04:48 -05:00
|
|
|
"github.com/matrix-org/gomatrix"
|
2020-04-29 09:29:39 -05:00
|
|
|
"github.com/matrix-org/gomatrixserverlib"
|
2023-04-06 03:55:01 -05:00
|
|
|
"github.com/matrix-org/gomatrixserverlib/fclient"
|
2023-04-19 09:50:33 -05:00
|
|
|
"github.com/matrix-org/gomatrixserverlib/spec"
|
2020-05-04 07:53:47 -05:00
|
|
|
"github.com/matrix-org/util"
|
|
|
|
"github.com/sirupsen/logrus"
|
2022-10-07 09:00:12 -05:00
|
|
|
|
|
|
|
"github.com/matrix-org/dendrite/federationapi/api"
|
|
|
|
"github.com/matrix-org/dendrite/federationapi/consumers"
|
2023-01-23 11:55:12 -06:00
|
|
|
"github.com/matrix-org/dendrite/federationapi/statistics"
|
2022-10-07 09:00:12 -05:00
|
|
|
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
|
2023-04-27 06:54:20 -05:00
|
|
|
"github.com/matrix-org/dendrite/roomserver/types"
|
2022-10-07 09:00:12 -05:00
|
|
|
"github.com/matrix-org/dendrite/roomserver/version"
|
2020-04-29 05:34:31 -05:00
|
|
|
)
|
|
|
|
|
2021-11-24 04:45:23 -06:00
|
|
|
// PerformLeaveRequest implements api.FederationInternalAPI
|
|
|
|
func (r *FederationInternalAPI) PerformDirectoryLookup(
|
2020-05-04 07:53:47 -05:00
|
|
|
ctx context.Context,
|
|
|
|
request *api.PerformDirectoryLookupRequest,
|
|
|
|
response *api.PerformDirectoryLookupResponse,
|
|
|
|
) (err error) {
|
2023-01-23 11:55:12 -06:00
|
|
|
if !r.shouldAttemptDirectFederation(request.ServerName) {
|
|
|
|
return fmt.Errorf("relay servers have no meaningful response for directory lookup.")
|
|
|
|
}
|
|
|
|
|
2020-05-04 07:53:47 -05:00
|
|
|
dir, err := r.federation.LookupRoomAlias(
|
|
|
|
ctx,
|
2022-11-15 09:05:23 -06:00
|
|
|
r.cfg.Matrix.ServerName,
|
2020-05-04 07:53:47 -05:00
|
|
|
request.ServerName,
|
|
|
|
request.RoomAlias,
|
|
|
|
)
|
|
|
|
if err != nil {
|
Improve federation sender performance, implement backoff and blacklisting, fix up invites a bit (#1007)
* Improve federation sender performance and behaviour, add backoff
* Tweaks
* Tweaks
* Tweaks
* Take copies of events before passing to destination queues
* Don't accidentally drop queued messages
* Don't take copies again
* Tidy up a bit
* Break out statistics (tracked component-wide), report success and failures from Perform actions
* Fix comment, use atomic add
* Improve logic a bit, don't block on wakeup, move idle check
* Don't retry sucessful invites, don't dispatch sendEvent, sendInvite etc
* Dedupe destinations, fix other bug hopefully
* Dispatch sends again
* Federation sender to ignore invites that are destined locally
* Loopback invite events
* Remodel a bit with channels
* Linter
* Only loopback invite event if we know the room
* We should tell other resident servers about the invite if we know about the room
* Correct invite signing
* Fix invite loopback
* Check HTTP response codes, push new invites to front of queue
* Review comments
2020-05-07 06:42:06 -05:00
|
|
|
r.statistics.ForServer(request.ServerName).Failure()
|
2020-05-04 07:53:47 -05:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
response.RoomID = dir.RoomID
|
|
|
|
response.ServerNames = dir.Servers
|
2023-01-23 11:55:12 -06:00
|
|
|
r.statistics.ForServer(request.ServerName).Success(statistics.SendDirect)
|
2020-05-04 07:53:47 -05:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-09-22 05:05:45 -05:00
|
|
|
type federatedJoin struct {
|
|
|
|
UserID string
|
|
|
|
RoomID string
|
|
|
|
}
|
|
|
|
|
2021-11-24 04:45:23 -06:00
|
|
|
// PerformJoin implements api.FederationInternalAPI
|
|
|
|
func (r *FederationInternalAPI) PerformJoin(
|
2020-04-29 05:34:31 -05:00
|
|
|
ctx context.Context,
|
|
|
|
request *api.PerformJoinRequest,
|
|
|
|
response *api.PerformJoinResponse,
|
2020-06-25 09:04:48 -05:00
|
|
|
) {
|
2020-09-22 05:05:45 -05:00
|
|
|
// Check that a join isn't already in progress for this user/room.
|
|
|
|
j := federatedJoin{request.UserID, request.RoomID}
|
|
|
|
if _, found := r.joins.Load(j); found {
|
|
|
|
response.LastError = &gomatrix.HTTPError{
|
|
|
|
Code: 429,
|
|
|
|
Message: `{
|
|
|
|
"errcode": "M_LIMIT_EXCEEDED",
|
|
|
|
"error": "There is already a federated join to this room in progress. Please wait for it to finish."
|
|
|
|
}`, // TODO: Why do none of our error types play nicely with each other?
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
r.joins.Store(j, nil)
|
|
|
|
defer r.joins.Delete(j)
|
|
|
|
|
2020-05-29 07:50:06 -05:00
|
|
|
// Deduplicate the server names we were provided but keep the ordering
|
|
|
|
// as this encodes useful information about which servers are most likely
|
|
|
|
// to respond.
|
2023-04-19 09:50:33 -05:00
|
|
|
seenSet := make(map[spec.ServerName]bool)
|
|
|
|
var uniqueList []spec.ServerName
|
2020-05-29 07:50:06 -05:00
|
|
|
for _, srv := range request.ServerNames {
|
2022-10-26 06:59:19 -05:00
|
|
|
if seenSet[srv] || r.cfg.Matrix.IsLocalServerName(srv) {
|
2020-05-29 07:50:06 -05:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
seenSet[srv] = true
|
|
|
|
uniqueList = append(uniqueList, srv)
|
|
|
|
}
|
|
|
|
request.ServerNames = uniqueList
|
2020-04-29 09:29:39 -05:00
|
|
|
|
2020-05-04 07:53:47 -05:00
|
|
|
// Try each server that we were provided until we land on one that
|
|
|
|
// successfully completes the make-join send-join dance.
|
2020-06-25 09:04:48 -05:00
|
|
|
var lastErr error
|
2020-05-04 07:53:47 -05:00
|
|
|
for _, serverName := range request.ServerNames {
|
2020-05-15 07:55:14 -05:00
|
|
|
if err := r.performJoinUsingServer(
|
2020-05-04 07:53:47 -05:00
|
|
|
ctx,
|
|
|
|
request.RoomID,
|
|
|
|
request.UserID,
|
2020-05-15 07:55:14 -05:00
|
|
|
request.Content,
|
2020-05-04 07:53:47 -05:00
|
|
|
serverName,
|
2022-10-07 09:00:12 -05:00
|
|
|
request.Unsigned,
|
2020-05-04 07:53:47 -05:00
|
|
|
); err != nil {
|
2020-05-15 07:55:14 -05:00
|
|
|
logrus.WithError(err).WithFields(logrus.Fields{
|
|
|
|
"server_name": serverName,
|
|
|
|
"room_id": request.RoomID,
|
|
|
|
}).Warnf("Failed to join room through server")
|
2020-06-25 09:04:48 -05:00
|
|
|
lastErr = err
|
2020-05-04 07:53:47 -05:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// We're all good.
|
2020-11-19 05:34:59 -06:00
|
|
|
response.JoinedVia = serverName
|
2020-06-25 09:04:48 -05:00
|
|
|
return
|
2020-04-29 09:29:39 -05:00
|
|
|
}
|
|
|
|
|
2020-05-04 07:53:47 -05:00
|
|
|
// If we reach here then we didn't complete a join for some reason.
|
2020-06-25 09:04:48 -05:00
|
|
|
var httpErr gomatrix.HTTPError
|
|
|
|
if ok := errors.As(lastErr, &httpErr); ok {
|
|
|
|
httpErr.Message = string(httpErr.Contents)
|
|
|
|
response.LastError = &httpErr
|
|
|
|
} else {
|
|
|
|
response.LastError = &gomatrix.HTTPError{
|
|
|
|
Code: 0,
|
|
|
|
WrappedError: nil,
|
2020-09-15 05:17:46 -05:00
|
|
|
Message: "Unknown HTTP error",
|
|
|
|
}
|
|
|
|
if lastErr != nil {
|
|
|
|
response.LastError.Message = lastErr.Error()
|
2020-06-25 09:04:48 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
logrus.Errorf(
|
|
|
|
"failed to join user %q to room %q through %d server(s): last error %s",
|
|
|
|
request.UserID, request.RoomID, len(request.ServerNames), lastErr,
|
2020-05-04 07:53:47 -05:00
|
|
|
)
|
2020-04-29 05:34:31 -05:00
|
|
|
}
|
|
|
|
|
2021-11-24 04:45:23 -06:00
|
|
|
func (r *FederationInternalAPI) performJoinUsingServer(
|
2020-05-15 07:55:14 -05:00
|
|
|
ctx context.Context,
|
|
|
|
roomID, userID string,
|
|
|
|
content map[string]interface{},
|
2023-04-19 09:50:33 -05:00
|
|
|
serverName spec.ServerName,
|
2022-10-07 09:00:12 -05:00
|
|
|
unsigned map[string]interface{},
|
2020-05-15 07:55:14 -05:00
|
|
|
) error {
|
2023-01-23 11:55:12 -06:00
|
|
|
if !r.shouldAttemptDirectFederation(serverName) {
|
|
|
|
return fmt.Errorf("relay servers have no meaningful response for join.")
|
|
|
|
}
|
|
|
|
|
2023-04-26 19:43:46 -05:00
|
|
|
user, err := spec.NewUserID(userID, true)
|
2022-11-15 09:05:23 -06:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2023-04-27 19:34:43 -05:00
|
|
|
room, err := spec.NewRoomID(roomID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-11-15 09:05:23 -06:00
|
|
|
|
2023-04-26 19:43:46 -05:00
|
|
|
joinInput := gomatrixserverlib.PerformJoinInput{
|
|
|
|
UserID: user,
|
2023-04-27 19:34:43 -05:00
|
|
|
RoomID: room,
|
2023-04-26 19:43:46 -05:00
|
|
|
ServerName: serverName,
|
|
|
|
Content: content,
|
|
|
|
Unsigned: unsigned,
|
|
|
|
PrivateKey: r.cfg.Matrix.PrivateKey,
|
|
|
|
KeyID: r.cfg.Matrix.KeyID,
|
|
|
|
KeyRing: r.keyRing,
|
|
|
|
EventProvider: federatedEventProvider(ctx, r.federation, r.keyRing, user.Domain(), serverName),
|
2020-05-15 07:55:14 -05:00
|
|
|
}
|
2023-04-26 19:43:46 -05:00
|
|
|
response, joinErr := gomatrixserverlib.PerformJoin(ctx, r, joinInput)
|
2020-10-13 05:53:20 -05:00
|
|
|
|
2023-04-26 19:43:46 -05:00
|
|
|
if joinErr != nil {
|
|
|
|
if !joinErr.Reachable {
|
|
|
|
r.statistics.ForServer(joinErr.ServerName).Failure()
|
|
|
|
} else {
|
|
|
|
r.statistics.ForServer(joinErr.ServerName).Success(statistics.SendDirect)
|
2022-05-25 08:31:07 -05:00
|
|
|
}
|
2023-04-26 19:43:46 -05:00
|
|
|
return joinErr.Err
|
2022-05-25 04:05:30 -05:00
|
|
|
}
|
2023-04-26 19:43:46 -05:00
|
|
|
r.statistics.ForServer(serverName).Success(statistics.SendDirect)
|
|
|
|
if response == nil {
|
|
|
|
return fmt.Errorf("Received nil response from gomatrixserverlib.PerformJoin")
|
2022-02-02 11:33:36 -06:00
|
|
|
}
|
2020-09-22 05:05:45 -05:00
|
|
|
|
2022-05-17 07:23:35 -05:00
|
|
|
// We need to immediately update our list of joined hosts for this room now as we are technically
|
|
|
|
// joined. We must do this synchronously: we cannot rely on the roomserver output events as they
|
|
|
|
// will happen asyncly. If we don't update this table, you can end up with bad failure modes like
|
|
|
|
// joining a room, waiting for 200 OK then changing device keys and have those keys not be sent
|
|
|
|
// to other servers (this was a cause of a flakey sytest "Local device key changes get to remote servers")
|
|
|
|
// The events are trusted now as we performed auth checks above.
|
2023-04-26 19:43:46 -05:00
|
|
|
joinedHosts, err := consumers.JoinedHostsFromEvents(response.StateSnapshot.GetStateEvents().TrustedEvents(response.JoinEvent.Version(), false))
|
2022-05-17 07:23:35 -05:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("JoinedHostsFromEvents: failed to get joined hosts: %s", err)
|
|
|
|
}
|
2023-04-26 19:43:46 -05:00
|
|
|
|
2022-10-06 04:07:13 -05:00
|
|
|
logrus.WithField("room", roomID).Infof("Joined federated room with %d hosts", len(joinedHosts))
|
2022-05-17 07:23:35 -05:00
|
|
|
if _, err = r.db.UpdateRoom(context.Background(), roomID, joinedHosts, nil, true); err != nil {
|
|
|
|
return fmt.Errorf("UpdatedRoom: failed to update room with joined hosts: %s", err)
|
|
|
|
}
|
|
|
|
|
2023-04-26 19:43:46 -05:00
|
|
|
// TODO: Can I change this to not take respState but instead just take an opaque list of events?
|
2022-02-02 11:33:36 -06:00
|
|
|
if err = roomserverAPI.SendEventWithState(
|
|
|
|
context.Background(),
|
|
|
|
r.rsAPI,
|
2023-04-26 19:43:46 -05:00
|
|
|
user.Domain(),
|
2022-02-02 11:33:36 -06:00
|
|
|
roomserverAPI.KindNew,
|
2023-04-26 19:43:46 -05:00
|
|
|
response.StateSnapshot,
|
2023-05-02 09:03:16 -05:00
|
|
|
&types.HeaderedEvent{PDU: response.JoinEvent},
|
2022-02-02 11:33:36 -06:00
|
|
|
serverName,
|
|
|
|
nil,
|
|
|
|
false,
|
|
|
|
); err != nil {
|
|
|
|
return fmt.Errorf("roomserverAPI.SendEventWithState: %w", err)
|
|
|
|
}
|
2020-05-15 07:55:14 -05:00
|
|
|
return nil
|
|
|
|
}
|
2021-01-22 08:55:08 -06:00
|
|
|
|
2021-11-24 04:45:23 -06:00
|
|
|
// PerformOutboundPeekRequest implements api.FederationInternalAPI
|
|
|
|
func (r *FederationInternalAPI) PerformOutboundPeek(
|
2021-01-22 08:55:08 -06:00
|
|
|
ctx context.Context,
|
|
|
|
request *api.PerformOutboundPeekRequest,
|
|
|
|
response *api.PerformOutboundPeekResponse,
|
|
|
|
) error {
|
|
|
|
// Look up the supported room versions.
|
|
|
|
var supportedVersions []gomatrixserverlib.RoomVersion
|
|
|
|
for version := range version.SupportedRoomVersions() {
|
|
|
|
supportedVersions = append(supportedVersions, version)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Deduplicate the server names we were provided but keep the ordering
|
|
|
|
// as this encodes useful information about which servers are most likely
|
|
|
|
// to respond.
|
2023-04-19 09:50:33 -05:00
|
|
|
seenSet := make(map[spec.ServerName]bool)
|
|
|
|
var uniqueList []spec.ServerName
|
2021-01-22 08:55:08 -06:00
|
|
|
for _, srv := range request.ServerNames {
|
|
|
|
if seenSet[srv] {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
seenSet[srv] = true
|
|
|
|
uniqueList = append(uniqueList, srv)
|
|
|
|
}
|
|
|
|
request.ServerNames = uniqueList
|
|
|
|
|
|
|
|
// See if there's an existing outbound peek for this room ID with
|
|
|
|
// one of the specified servers.
|
|
|
|
if peeks, err := r.db.GetOutboundPeeks(ctx, request.RoomID); err == nil {
|
|
|
|
for _, peek := range peeks {
|
|
|
|
if _, ok := seenSet[peek.ServerName]; ok {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Try each server that we were provided until we land on one that
|
|
|
|
// successfully completes the peek
|
|
|
|
var lastErr error
|
|
|
|
for _, serverName := range request.ServerNames {
|
|
|
|
if err := r.performOutboundPeekUsingServer(
|
|
|
|
ctx,
|
|
|
|
request.RoomID,
|
|
|
|
serverName,
|
|
|
|
supportedVersions,
|
|
|
|
); err != nil {
|
|
|
|
logrus.WithError(err).WithFields(logrus.Fields{
|
|
|
|
"server_name": serverName,
|
|
|
|
"room_id": request.RoomID,
|
|
|
|
}).Warnf("Failed to peek room through server")
|
|
|
|
lastErr = err
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// We're all good.
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we reach here then we didn't complete a peek for some reason.
|
|
|
|
var httpErr gomatrix.HTTPError
|
|
|
|
if ok := errors.As(lastErr, &httpErr); ok {
|
|
|
|
httpErr.Message = string(httpErr.Contents)
|
|
|
|
response.LastError = &httpErr
|
|
|
|
} else {
|
|
|
|
response.LastError = &gomatrix.HTTPError{
|
|
|
|
Code: 0,
|
|
|
|
WrappedError: nil,
|
|
|
|
Message: lastErr.Error(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
logrus.Errorf(
|
|
|
|
"failed to peek room %q through %d server(s): last error %s",
|
|
|
|
request.RoomID, len(request.ServerNames), lastErr,
|
|
|
|
)
|
|
|
|
|
|
|
|
return lastErr
|
|
|
|
}
|
|
|
|
|
2021-11-24 04:45:23 -06:00
|
|
|
func (r *FederationInternalAPI) performOutboundPeekUsingServer(
|
2021-01-22 08:55:08 -06:00
|
|
|
ctx context.Context,
|
|
|
|
roomID string,
|
2023-04-19 09:50:33 -05:00
|
|
|
serverName spec.ServerName,
|
2021-01-22 08:55:08 -06:00
|
|
|
supportedVersions []gomatrixserverlib.RoomVersion,
|
|
|
|
) error {
|
2023-01-23 11:55:12 -06:00
|
|
|
if !r.shouldAttemptDirectFederation(serverName) {
|
|
|
|
return fmt.Errorf("relay servers have no meaningful response for outbound peek.")
|
|
|
|
}
|
|
|
|
|
2021-01-22 08:55:08 -06:00
|
|
|
// create a unique ID for this peek.
|
|
|
|
// for now we just use the room ID again. In future, if we ever
|
|
|
|
// support concurrent peeks to the same room with different filters
|
|
|
|
// then we would need to disambiguate further.
|
|
|
|
peekID := roomID
|
|
|
|
|
|
|
|
// check whether we're peeking already to try to avoid needlessly
|
|
|
|
// re-peeking on the server. we don't need a transaction for this,
|
|
|
|
// given this is a nice-to-have.
|
|
|
|
outboundPeek, err := r.db.GetOutboundPeek(ctx, serverName, roomID, peekID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
renewing := false
|
|
|
|
if outboundPeek != nil {
|
|
|
|
nowMilli := time.Now().UnixNano() / int64(time.Millisecond)
|
|
|
|
if nowMilli > outboundPeek.RenewedTimestamp+outboundPeek.RenewalInterval {
|
|
|
|
logrus.Infof("stale outbound peek to %s for %s already exists; renewing", serverName, roomID)
|
|
|
|
renewing = true
|
|
|
|
} else {
|
|
|
|
logrus.Infof("live outbound peek to %s for %s already exists", serverName, roomID)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Try to perform an outbound /peek using the information supplied in the
|
|
|
|
// request.
|
|
|
|
respPeek, err := r.federation.Peek(
|
|
|
|
ctx,
|
2022-11-15 09:05:23 -06:00
|
|
|
r.cfg.Matrix.ServerName,
|
2021-01-22 08:55:08 -06:00
|
|
|
serverName,
|
|
|
|
roomID,
|
|
|
|
peekID,
|
|
|
|
supportedVersions,
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
r.statistics.ForServer(serverName).Failure()
|
|
|
|
return fmt.Errorf("r.federation.Peek: %w", err)
|
|
|
|
}
|
2023-01-23 11:55:12 -06:00
|
|
|
r.statistics.ForServer(serverName).Success(statistics.SendDirect)
|
2021-01-22 08:55:08 -06:00
|
|
|
|
|
|
|
// Work out if we support the room version that has been supplied in
|
|
|
|
// the peek response.
|
|
|
|
if respPeek.RoomVersion == "" {
|
|
|
|
respPeek.RoomVersion = gomatrixserverlib.RoomVersionV1
|
|
|
|
}
|
2023-04-21 11:06:29 -05:00
|
|
|
if !gomatrixserverlib.KnownRoomVersion(respPeek.RoomVersion) {
|
|
|
|
return fmt.Errorf("unknown room version: %s", respPeek.RoomVersion)
|
2021-01-22 08:55:08 -06:00
|
|
|
}
|
|
|
|
|
2021-01-22 11:16:35 -06:00
|
|
|
// we have the peek state now so let's process regardless of whether upstream gives up
|
|
|
|
ctx = context.Background()
|
2022-04-05 08:43:44 -05:00
|
|
|
|
2021-01-22 11:16:35 -06:00
|
|
|
// authenticate the state returned (check its auth events etc)
|
2021-01-22 08:55:08 -06:00
|
|
|
// the equivalent of CheckSendJoinResponse()
|
2023-04-14 06:32:42 -05:00
|
|
|
authEvents, stateEvents, err := gomatrixserverlib.CheckStateResponse(
|
2023-04-26 19:43:46 -05:00
|
|
|
ctx, &respPeek, respPeek.RoomVersion, r.keyRing, federatedEventProvider(ctx, r.federation, r.keyRing, r.cfg.Matrix.ServerName, serverName),
|
2023-04-14 06:32:42 -05:00
|
|
|
)
|
2022-04-05 08:43:44 -05:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("error checking state returned from peeking: %w", err)
|
|
|
|
}
|
2023-04-26 19:43:46 -05:00
|
|
|
if err = checkEventsContainCreateEvent(authEvents); err != nil {
|
2021-01-22 11:16:35 -06:00
|
|
|
return fmt.Errorf("sanityCheckAuthChain: %w", err)
|
|
|
|
}
|
2021-01-22 08:55:08 -06:00
|
|
|
|
|
|
|
// If we've got this far, the remote server is peeking.
|
|
|
|
if renewing {
|
|
|
|
if err = r.db.RenewOutboundPeek(ctx, serverName, roomID, peekID, respPeek.RenewalInterval); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if err = r.db.AddOutboundPeek(ctx, serverName, roomID, peekID, respPeek.RenewalInterval); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// logrus.Warnf("got respPeek %#v", respPeek)
|
|
|
|
// Send the newly returned state to the roomserver to update our local view.
|
|
|
|
if err = roomserverAPI.SendEventWithState(
|
2022-11-15 09:05:23 -06:00
|
|
|
ctx, r.rsAPI, r.cfg.Matrix.ServerName,
|
2021-01-22 08:55:08 -06:00
|
|
|
roomserverAPI.KindNew,
|
2023-04-14 06:32:42 -05:00
|
|
|
// use the authorized state from CheckStateResponse
|
|
|
|
&fclient.RespState{
|
|
|
|
StateEvents: gomatrixserverlib.NewEventJSONsFromEvents(stateEvents),
|
|
|
|
AuthEvents: gomatrixserverlib.NewEventJSONsFromEvents(authEvents),
|
|
|
|
},
|
2023-05-02 09:03:16 -05:00
|
|
|
&types.HeaderedEvent{PDU: respPeek.LatestEvent},
|
2022-01-27 08:29:14 -06:00
|
|
|
serverName,
|
|
|
|
nil,
|
|
|
|
false,
|
2021-01-22 08:55:08 -06:00
|
|
|
); err != nil {
|
|
|
|
return fmt.Errorf("r.producer.SendEventWithState: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2020-05-15 07:55:14 -05:00
|
|
|
|
2021-11-24 04:45:23 -06:00
|
|
|
// PerformLeaveRequest implements api.FederationInternalAPI
|
|
|
|
func (r *FederationInternalAPI) PerformLeave(
|
2020-04-29 05:34:31 -05:00
|
|
|
ctx context.Context,
|
|
|
|
request *api.PerformLeaveRequest,
|
|
|
|
response *api.PerformLeaveResponse,
|
|
|
|
) (err error) {
|
2022-11-15 09:05:23 -06:00
|
|
|
_, origin, err := r.cfg.Matrix.SplitLocalID('@', request.UserID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-05-04 12:34:09 -05:00
|
|
|
// Deduplicate the server names we were provided.
|
2020-05-07 11:14:32 -05:00
|
|
|
util.SortAndUnique(request.ServerNames)
|
2020-05-04 12:34:09 -05:00
|
|
|
|
|
|
|
// Try each server that we were provided until we land on one that
|
|
|
|
// successfully completes the make-leave send-leave dance.
|
|
|
|
for _, serverName := range request.ServerNames {
|
2023-01-23 11:55:12 -06:00
|
|
|
if !r.shouldAttemptDirectFederation(serverName) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2020-05-04 12:34:09 -05:00
|
|
|
// Try to perform a make_leave using the information supplied in the
|
|
|
|
// request.
|
|
|
|
respMakeLeave, err := r.federation.MakeLeave(
|
|
|
|
ctx,
|
2022-11-15 09:05:23 -06:00
|
|
|
origin,
|
2020-05-04 12:34:09 -05:00
|
|
|
serverName,
|
|
|
|
request.RoomID,
|
|
|
|
request.UserID,
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
// TODO: Check if the user was not allowed to leave the room.
|
|
|
|
logrus.WithError(err).Warnf("r.federation.MakeLeave failed")
|
Improve federation sender performance, implement backoff and blacklisting, fix up invites a bit (#1007)
* Improve federation sender performance and behaviour, add backoff
* Tweaks
* Tweaks
* Tweaks
* Take copies of events before passing to destination queues
* Don't accidentally drop queued messages
* Don't take copies again
* Tidy up a bit
* Break out statistics (tracked component-wide), report success and failures from Perform actions
* Fix comment, use atomic add
* Improve logic a bit, don't block on wakeup, move idle check
* Don't retry sucessful invites, don't dispatch sendEvent, sendInvite etc
* Dedupe destinations, fix other bug hopefully
* Dispatch sends again
* Federation sender to ignore invites that are destined locally
* Loopback invite events
* Remodel a bit with channels
* Linter
* Only loopback invite event if we know the room
* We should tell other resident servers about the invite if we know about the room
* Correct invite signing
* Fix invite loopback
* Check HTTP response codes, push new invites to front of queue
* Review comments
2020-05-07 06:42:06 -05:00
|
|
|
r.statistics.ForServer(serverName).Failure()
|
2020-05-04 12:34:09 -05:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2023-04-21 11:06:29 -05:00
|
|
|
// Work out if we support the room version that has been supplied in
|
|
|
|
// the make_leave response.
|
|
|
|
_, err = gomatrixserverlib.GetRoomVersion(respMakeLeave.RoomVersion)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-05-04 12:34:09 -05:00
|
|
|
// Set all the fields to be what they should be, this should be a no-op
|
|
|
|
// but it's possible that the remote server returned us something "odd"
|
2023-04-19 09:50:33 -05:00
|
|
|
respMakeLeave.LeaveEvent.Type = spec.MRoomMember
|
2020-05-04 12:34:09 -05:00
|
|
|
respMakeLeave.LeaveEvent.Sender = request.UserID
|
|
|
|
respMakeLeave.LeaveEvent.StateKey = &request.UserID
|
|
|
|
respMakeLeave.LeaveEvent.RoomID = request.RoomID
|
|
|
|
respMakeLeave.LeaveEvent.Redacts = ""
|
|
|
|
if respMakeLeave.LeaveEvent.Content == nil {
|
|
|
|
content := map[string]interface{}{
|
|
|
|
"membership": "leave",
|
|
|
|
}
|
|
|
|
if err = respMakeLeave.LeaveEvent.SetContent(content); err != nil {
|
|
|
|
logrus.WithError(err).Warnf("respMakeLeave.LeaveEvent.SetContent failed")
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if err = respMakeLeave.LeaveEvent.SetUnsigned(struct{}{}); err != nil {
|
|
|
|
logrus.WithError(err).Warnf("respMakeLeave.LeaveEvent.SetUnsigned failed")
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// Build the leave event.
|
|
|
|
event, err := respMakeLeave.LeaveEvent.Build(
|
|
|
|
time.Now(),
|
2022-11-15 09:05:23 -06:00
|
|
|
origin,
|
2020-05-04 12:34:09 -05:00
|
|
|
r.cfg.Matrix.KeyID,
|
|
|
|
r.cfg.Matrix.PrivateKey,
|
|
|
|
respMakeLeave.RoomVersion,
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
logrus.WithError(err).Warnf("respMakeLeave.LeaveEvent.Build failed")
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// Try to perform a send_leave using the newly built event.
|
|
|
|
err = r.federation.SendLeave(
|
|
|
|
ctx,
|
2022-11-15 09:05:23 -06:00
|
|
|
origin,
|
2020-05-04 12:34:09 -05:00
|
|
|
serverName,
|
|
|
|
event,
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
logrus.WithError(err).Warnf("r.federation.SendLeave failed")
|
Improve federation sender performance, implement backoff and blacklisting, fix up invites a bit (#1007)
* Improve federation sender performance and behaviour, add backoff
* Tweaks
* Tweaks
* Tweaks
* Take copies of events before passing to destination queues
* Don't accidentally drop queued messages
* Don't take copies again
* Tidy up a bit
* Break out statistics (tracked component-wide), report success and failures from Perform actions
* Fix comment, use atomic add
* Improve logic a bit, don't block on wakeup, move idle check
* Don't retry sucessful invites, don't dispatch sendEvent, sendInvite etc
* Dedupe destinations, fix other bug hopefully
* Dispatch sends again
* Federation sender to ignore invites that are destined locally
* Loopback invite events
* Remodel a bit with channels
* Linter
* Only loopback invite event if we know the room
* We should tell other resident servers about the invite if we know about the room
* Correct invite signing
* Fix invite loopback
* Check HTTP response codes, push new invites to front of queue
* Review comments
2020-05-07 06:42:06 -05:00
|
|
|
r.statistics.ForServer(serverName).Failure()
|
2020-05-04 12:34:09 -05:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2023-01-23 11:55:12 -06:00
|
|
|
r.statistics.ForServer(serverName).Success(statistics.SendDirect)
|
2020-05-04 12:34:09 -05:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we reach here then we didn't complete a leave for some reason.
|
|
|
|
return fmt.Errorf(
|
2021-09-08 11:31:03 -05:00
|
|
|
"failed to leave room %q through %d server(s)",
|
2020-05-04 12:34:09 -05:00
|
|
|
request.RoomID, len(request.ServerNames),
|
|
|
|
)
|
2020-04-29 05:34:31 -05:00
|
|
|
}
|
2020-06-01 12:34:08 -05:00
|
|
|
|
2021-11-24 04:45:23 -06:00
|
|
|
// PerformLeaveRequest implements api.FederationInternalAPI
|
|
|
|
func (r *FederationInternalAPI) PerformInvite(
|
2020-08-17 05:40:49 -05:00
|
|
|
ctx context.Context,
|
|
|
|
request *api.PerformInviteRequest,
|
|
|
|
response *api.PerformInviteResponse,
|
|
|
|
) (err error) {
|
2022-11-15 09:05:23 -06:00
|
|
|
_, origin, err := r.cfg.Matrix.SplitLocalID('@', request.Event.Sender())
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-08-17 05:40:49 -05:00
|
|
|
if request.Event.StateKey() == nil {
|
|
|
|
return errors.New("invite must be a state event")
|
|
|
|
}
|
|
|
|
|
|
|
|
_, destination, err := gomatrixserverlib.SplitID('@', *request.Event.StateKey())
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("gomatrixserverlib.SplitID: %w", err)
|
|
|
|
}
|
|
|
|
|
2023-01-23 11:55:12 -06:00
|
|
|
// TODO (devon): This should be allowed via a relay. Currently only transactions
|
|
|
|
// can be sent to relays. Would need to extend relays to handle invites.
|
|
|
|
if !r.shouldAttemptDirectFederation(destination) {
|
|
|
|
return fmt.Errorf("relay servers have no meaningful response for invite.")
|
|
|
|
}
|
|
|
|
|
2020-08-17 05:40:49 -05:00
|
|
|
logrus.WithFields(logrus.Fields{
|
|
|
|
"event_id": request.Event.EventID(),
|
|
|
|
"user_id": *request.Event.StateKey(),
|
|
|
|
"room_id": request.Event.RoomID(),
|
|
|
|
"room_version": request.RoomVersion,
|
|
|
|
"destination": destination,
|
|
|
|
}).Info("Sending invite")
|
|
|
|
|
2023-05-02 09:03:16 -05:00
|
|
|
inviteReq, err := fclient.NewInviteV2Request(request.Event.PDU, request.InviteRoomState)
|
2020-08-17 05:40:49 -05:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("gomatrixserverlib.NewInviteV2Request: %w", err)
|
|
|
|
}
|
|
|
|
|
2022-11-15 09:05:23 -06:00
|
|
|
inviteRes, err := r.federation.SendInviteV2(ctx, origin, destination, inviteReq)
|
2020-08-17 05:40:49 -05:00
|
|
|
if err != nil {
|
2022-02-09 14:31:24 -06:00
|
|
|
return fmt.Errorf("r.federation.SendInviteV2: failed to send invite: %w", err)
|
2020-08-17 05:40:49 -05:00
|
|
|
}
|
2023-04-21 11:06:29 -05:00
|
|
|
verImpl, err := gomatrixserverlib.GetRoomVersion(request.RoomVersion)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-08-17 05:40:49 -05:00
|
|
|
|
2023-04-21 11:06:29 -05:00
|
|
|
inviteEvent, err := verImpl.NewEventFromUntrustedJSON(inviteRes.Event)
|
2022-02-09 14:31:24 -06:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("r.federation.SendInviteV2 failed to decode event response: %w", err)
|
|
|
|
}
|
2023-05-02 09:03:16 -05:00
|
|
|
response.Event = &types.HeaderedEvent{PDU: inviteEvent}
|
2020-08-17 05:40:49 -05:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-11-24 04:45:23 -06:00
|
|
|
// PerformServersAlive implements api.FederationInternalAPI
|
|
|
|
func (r *FederationInternalAPI) PerformBroadcastEDU(
|
2020-07-16 07:52:08 -05:00
|
|
|
ctx context.Context,
|
|
|
|
request *api.PerformBroadcastEDURequest,
|
|
|
|
response *api.PerformBroadcastEDUResponse,
|
|
|
|
) (err error) {
|
|
|
|
destinations, err := r.db.GetAllJoinedHosts(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("r.db.GetAllJoinedHosts: %w", err)
|
|
|
|
}
|
2020-08-06 10:00:42 -05:00
|
|
|
if len(destinations) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
logrus.WithContext(ctx).Infof("Sending wake-up EDU to %d destination(s)", len(destinations))
|
2020-07-16 07:52:08 -05:00
|
|
|
|
|
|
|
edu := &gomatrixserverlib.EDU{
|
|
|
|
Type: "org.matrix.dendrite.wakeup",
|
|
|
|
Origin: string(r.cfg.Matrix.ServerName),
|
|
|
|
}
|
|
|
|
if err = r.queues.SendEDU(edu, r.cfg.Matrix.ServerName, destinations); err != nil {
|
|
|
|
return fmt.Errorf("r.queues.SendEDU: %w", err)
|
|
|
|
}
|
2022-05-06 06:39:26 -05:00
|
|
|
r.MarkServersAlive(destinations)
|
2020-08-06 10:00:42 -05:00
|
|
|
|
2020-07-16 07:52:08 -05:00
|
|
|
return nil
|
|
|
|
}
|
2020-10-09 18:21:15 -05:00
|
|
|
|
2022-11-17 18:29:23 -06:00
|
|
|
// PerformWakeupServers implements api.FederationInternalAPI
|
|
|
|
func (r *FederationInternalAPI) PerformWakeupServers(
|
|
|
|
ctx context.Context,
|
|
|
|
request *api.PerformWakeupServersRequest,
|
|
|
|
response *api.PerformWakeupServersResponse,
|
|
|
|
) (err error) {
|
|
|
|
r.MarkServersAlive(request.ServerNames)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-04-19 09:50:33 -05:00
|
|
|
func (r *FederationInternalAPI) MarkServersAlive(destinations []spec.ServerName) {
|
2022-05-06 06:39:26 -05:00
|
|
|
for _, srv := range destinations {
|
2023-01-23 11:55:12 -06:00
|
|
|
wasBlacklisted := r.statistics.ForServer(srv).MarkServerAlive()
|
|
|
|
r.queues.RetryServer(srv, wasBlacklisted)
|
2022-05-06 06:39:26 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-02 09:03:16 -05:00
|
|
|
func checkEventsContainCreateEvent(events []gomatrixserverlib.PDU) error {
|
2020-10-09 18:21:15 -05:00
|
|
|
// sanity check we have a create event and it has a known room version
|
2023-04-26 19:43:46 -05:00
|
|
|
for _, ev := range events {
|
2023-04-19 09:50:33 -05:00
|
|
|
if ev.Type() == spec.MRoomCreate && ev.StateKeyEquals("") {
|
2020-10-09 18:21:15 -05:00
|
|
|
// make sure the room version is known
|
|
|
|
content := ev.Content()
|
|
|
|
verBody := struct {
|
|
|
|
Version string `json:"room_version"`
|
|
|
|
}{}
|
|
|
|
err := json.Unmarshal(content, &verBody)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if verBody.Version == "" {
|
|
|
|
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-create
|
|
|
|
// The version of the room. Defaults to "1" if the key does not exist.
|
|
|
|
verBody.Version = "1"
|
|
|
|
}
|
|
|
|
knownVersions := gomatrixserverlib.RoomVersions()
|
|
|
|
if _, ok := knownVersions[gomatrixserverlib.RoomVersion(verBody.Version)]; !ok {
|
2023-04-26 19:43:46 -05:00
|
|
|
return fmt.Errorf("m.room.create event has an unknown room version: %s", verBody.Version)
|
2020-10-09 18:21:15 -05:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
2023-04-26 19:43:46 -05:00
|
|
|
return fmt.Errorf("response is missing m.room.create event")
|
2020-10-09 18:21:15 -05:00
|
|
|
}
|
2021-01-22 11:16:35 -06:00
|
|
|
|
2023-04-26 19:43:46 -05:00
|
|
|
// federatedEventProvider is an event provider which fetches events from the server provided
|
|
|
|
func federatedEventProvider(
|
2023-04-24 11:23:25 -05:00
|
|
|
ctx context.Context, federation fclient.FederationClient,
|
2023-04-19 09:50:33 -05:00
|
|
|
keyRing gomatrixserverlib.JSONVerifier, origin, server spec.ServerName,
|
2023-04-26 19:43:46 -05:00
|
|
|
) gomatrixserverlib.EventProvider {
|
2021-01-22 11:16:35 -06:00
|
|
|
// A list of events that we have retried, if they were not included in
|
|
|
|
// the auth events supplied in the send_join.
|
2023-04-27 10:35:19 -05:00
|
|
|
retries := map[string][]gomatrixserverlib.PDU{}
|
2021-01-22 11:16:35 -06:00
|
|
|
|
|
|
|
// Define a function which we can pass to Check to retrieve missing
|
|
|
|
// auth events inline. This greatly increases our chances of not having
|
|
|
|
// to repeat the entire set of checks just for a missing event or two.
|
2023-04-27 10:35:19 -05:00
|
|
|
return func(roomVersion gomatrixserverlib.RoomVersion, eventIDs []string) ([]gomatrixserverlib.PDU, error) {
|
|
|
|
returning := []gomatrixserverlib.PDU{}
|
2023-04-21 11:06:29 -05:00
|
|
|
verImpl, err := gomatrixserverlib.GetRoomVersion(roomVersion)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-01-22 11:16:35 -06:00
|
|
|
|
|
|
|
// See if we have retry entries for each of the supplied event IDs.
|
|
|
|
for _, eventID := range eventIDs {
|
|
|
|
// If we've already satisfied a request for this event ID before then
|
|
|
|
// just append the results. We won't retry the request.
|
|
|
|
if retry, ok := retries[eventID]; ok {
|
|
|
|
if retry == nil {
|
|
|
|
return nil, fmt.Errorf("missingAuth: not retrying failed event ID %q", eventID)
|
|
|
|
}
|
|
|
|
returning = append(returning, retry...)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make a note of the fact that we tried to do something with this
|
|
|
|
// event ID, even if we don't succeed.
|
|
|
|
retries[eventID] = nil
|
|
|
|
|
|
|
|
// Try to retrieve the event from the server that sent us the send
|
|
|
|
// join response.
|
2022-11-15 09:05:23 -06:00
|
|
|
tx, txerr := federation.GetEvent(ctx, origin, server, eventID)
|
2021-01-22 11:16:35 -06:00
|
|
|
if txerr != nil {
|
|
|
|
return nil, fmt.Errorf("missingAuth r.federation.GetEvent: %w", txerr)
|
|
|
|
}
|
|
|
|
|
|
|
|
// For each event returned, add it to the set of return events. We
|
|
|
|
// also will populate the retries, in case someone asks for this
|
|
|
|
// event ID again.
|
|
|
|
for _, pdu := range tx.PDUs {
|
|
|
|
// Try to parse the event.
|
2023-04-21 11:06:29 -05:00
|
|
|
ev, everr := verImpl.NewEventFromUntrustedJSON(pdu)
|
2021-01-22 11:16:35 -06:00
|
|
|
if everr != nil {
|
|
|
|
return nil, fmt.Errorf("missingAuth gomatrixserverlib.NewEventFromUntrustedJSON: %w", everr)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check the signatures of the event.
|
2023-04-27 10:35:19 -05:00
|
|
|
if err := gomatrixserverlib.VerifyEventSignatures(ctx, ev, keyRing); err != nil {
|
2021-01-22 11:16:35 -06:00
|
|
|
return nil, fmt.Errorf("missingAuth VerifyEventSignatures: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the event is OK then add it to the results and the retry map.
|
|
|
|
returning = append(returning, ev)
|
|
|
|
retries[ev.EventID()] = append(retries[ev.EventID()], ev)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return returning, nil
|
|
|
|
}
|
|
|
|
}
|
2023-01-23 11:55:12 -06:00
|
|
|
|
|
|
|
// P2PQueryRelayServers implements api.FederationInternalAPI
|
|
|
|
func (r *FederationInternalAPI) P2PQueryRelayServers(
|
|
|
|
ctx context.Context,
|
|
|
|
request *api.P2PQueryRelayServersRequest,
|
|
|
|
response *api.P2PQueryRelayServersResponse,
|
|
|
|
) error {
|
|
|
|
logrus.Infof("Getting relay servers for: %s", request.Server)
|
|
|
|
relayServers, err := r.db.P2PGetRelayServersForServer(ctx, request.Server)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
response.RelayServers = relayServers
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-01-28 17:27:53 -06:00
|
|
|
// P2PAddRelayServers implements api.FederationInternalAPI
|
|
|
|
func (r *FederationInternalAPI) P2PAddRelayServers(
|
|
|
|
ctx context.Context,
|
|
|
|
request *api.P2PAddRelayServersRequest,
|
|
|
|
response *api.P2PAddRelayServersResponse,
|
|
|
|
) error {
|
|
|
|
logrus.Infof("Adding relay servers for: %s", request.Server)
|
|
|
|
err := r.db.P2PAddRelayServersForServer(ctx, request.Server, request.RelayServers)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// P2PRemoveRelayServers implements api.FederationInternalAPI
|
|
|
|
func (r *FederationInternalAPI) P2PRemoveRelayServers(
|
|
|
|
ctx context.Context,
|
|
|
|
request *api.P2PRemoveRelayServersRequest,
|
|
|
|
response *api.P2PRemoveRelayServersResponse,
|
|
|
|
) error {
|
|
|
|
logrus.Infof("Adding relay servers for: %s", request.Server)
|
|
|
|
err := r.db.P2PRemoveRelayServersForServer(ctx, request.Server, request.RelayServers)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-01-23 11:55:12 -06:00
|
|
|
func (r *FederationInternalAPI) shouldAttemptDirectFederation(
|
2023-04-19 09:50:33 -05:00
|
|
|
destination spec.ServerName,
|
2023-01-23 11:55:12 -06:00
|
|
|
) bool {
|
|
|
|
var shouldRelay bool
|
|
|
|
stats := r.statistics.ForServer(destination)
|
|
|
|
if stats.AssumedOffline() && len(stats.KnownRelayServers()) > 0 {
|
|
|
|
shouldRelay = true
|
|
|
|
}
|
|
|
|
|
|
|
|
return !shouldRelay
|
|
|
|
}
|