mirror of
https://github.com/matrix-org/dendrite.git
synced 2026-01-12 08:33:10 -06:00
Merge branch 'main' of github.com:matrix-org/dendrite into s7evink/docs
This commit is contained in:
commit
d55e384fdf
3
.github/workflows/dendrite.yml
vendored
3
.github/workflows/dendrite.yml
vendored
|
|
@ -460,7 +460,8 @@ jobs:
|
|||
name: Run Complement Tests
|
||||
env:
|
||||
COMPLEMENT_BASE_IMAGE: complement-dendrite:${{ matrix.postgres }}${{ matrix.api }}${{ matrix.cgo }}
|
||||
API: ${{ matrix.api && 1 }}
|
||||
COMPLEMENT_DENDRITE_API: ${{ matrix.api && 1 }}
|
||||
COMPLEMENT_SHARE_ENV_PREFIX: COMPLEMENT_DENDRITE_
|
||||
working-directory: complement
|
||||
|
||||
integration-tests-done:
|
||||
|
|
|
|||
176
.github/workflows/schedules.yaml
vendored
176
.github/workflows/schedules.yaml
vendored
|
|
@ -19,11 +19,18 @@ jobs:
|
|||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- label: SQLite
|
||||
- label: SQLite native
|
||||
|
||||
- label: SQLite, full HTTP APIs
|
||||
- label: SQLite Cgo
|
||||
cgo: 1
|
||||
|
||||
- label: SQLite native, full HTTP APIs
|
||||
api: full-http
|
||||
|
||||
- label: SQLite Cgo, full HTTP APIs
|
||||
api: full-http
|
||||
cgo: 1
|
||||
|
||||
- label: PostgreSQL
|
||||
postgres: postgres
|
||||
|
||||
|
|
@ -41,6 +48,7 @@ jobs:
|
|||
API: ${{ matrix.api && 1 }}
|
||||
SYTEST_BRANCH: ${{ github.head_ref }}
|
||||
RACE_DETECTION: 1
|
||||
COVER: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache@v3
|
||||
|
|
@ -73,7 +81,171 @@ jobs:
|
|||
path: |
|
||||
/logs/results.tap
|
||||
/logs/**/*.log*
|
||||
|
||||
sytest-coverage:
|
||||
timeout-minutes: 5
|
||||
name: "Sytest Coverage"
|
||||
runs-on: ubuntu-latest
|
||||
needs: sytest # only run once Sytest is done
|
||||
if: ${{ always() }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '>=1.19.0'
|
||||
cache: true
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
- name: Install gocovmerge
|
||||
run: go install github.com/wadey/gocovmerge@latest
|
||||
- name: Run gocovmerge
|
||||
run: |
|
||||
find -name 'integrationcover.log' -printf '"%p"\n' | xargs gocovmerge | grep -Ev 'relayapi|setup/mscs|api_trace' > sytest.cov
|
||||
go tool cover -func=sytest.cov
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
files: ./sytest.cov
|
||||
flags: sytest
|
||||
fail_ci_if_error: true
|
||||
|
||||
# run Complement
|
||||
complement:
|
||||
name: "Complement (${{ matrix.label }})"
|
||||
timeout-minutes: 60
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- label: SQLite native
|
||||
cgo: 0
|
||||
|
||||
- label: SQLite Cgo
|
||||
cgo: 1
|
||||
|
||||
- label: SQLite native, full HTTP APIs
|
||||
api: full-http
|
||||
cgo: 0
|
||||
|
||||
- label: SQLite Cgo, full HTTP APIs
|
||||
api: full-http
|
||||
cgo: 1
|
||||
|
||||
- label: PostgreSQL
|
||||
postgres: Postgres
|
||||
cgo: 0
|
||||
|
||||
- label: PostgreSQL, full HTTP APIs
|
||||
postgres: Postgres
|
||||
api: full-http
|
||||
cgo: 0
|
||||
steps:
|
||||
# Env vars are set file a file given by $GITHUB_PATH. We need both Go 1.17 and GOPATH on env to run Complement.
|
||||
# See https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#adding-a-system-path
|
||||
- name: "Set Go Version"
|
||||
run: |
|
||||
echo "$GOROOT_1_17_X64/bin" >> $GITHUB_PATH
|
||||
echo "~/go/bin" >> $GITHUB_PATH
|
||||
- name: "Install Complement Dependencies"
|
||||
# We don't need to install Go because it is included on the Ubuntu 20.04 image:
|
||||
# See https://github.com/actions/virtual-environments/blob/main/images/linux/Ubuntu2004-Readme.md specifically GOROOT_1_17_X64
|
||||
run: |
|
||||
sudo apt-get update && sudo apt-get install -y libolm3 libolm-dev
|
||||
go get -v github.com/gotesttools/gotestfmt/v2/cmd/gotestfmt@latest
|
||||
- name: Run actions/checkout@v3 for dendrite
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: dendrite
|
||||
|
||||
# Attempt to check out the same branch of Complement as the PR. If it
|
||||
# doesn't exist, fallback to main.
|
||||
- name: Checkout complement
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p complement
|
||||
# Attempt to use the version of complement which best matches the current
|
||||
# build. Depending on whether this is a PR or release, etc. we need to
|
||||
# use different fallbacks.
|
||||
#
|
||||
# 1. First check if there's a similarly named branch (GITHUB_HEAD_REF
|
||||
# for pull requests, otherwise GITHUB_REF).
|
||||
# 2. Attempt to use the base branch, e.g. when merging into release-vX.Y
|
||||
# (GITHUB_BASE_REF for pull requests).
|
||||
# 3. Use the default complement branch ("master").
|
||||
for BRANCH_NAME in "$GITHUB_HEAD_REF" "$GITHUB_BASE_REF" "${GITHUB_REF#refs/heads/}" "master"; do
|
||||
# Skip empty branch names and merge commits.
|
||||
if [[ -z "$BRANCH_NAME" || $BRANCH_NAME =~ ^refs/pull/.* ]]; then
|
||||
continue
|
||||
fi
|
||||
(wget -O - "https://github.com/matrix-org/complement/archive/$BRANCH_NAME.tar.gz" | tar -xz --strip-components=1 -C complement) && break
|
||||
done
|
||||
# Build initial Dendrite image
|
||||
- run: docker build --build-arg=CGO=${{ matrix.cgo }} -t complement-dendrite:${{ matrix.postgres }}${{ matrix.api }}${{ matrix.cgo }} -f build/scripts/Complement${{ matrix.postgres }}.Dockerfile .
|
||||
working-directory: dendrite
|
||||
env:
|
||||
DOCKER_BUILDKIT: 1
|
||||
|
||||
- name: Create post test script
|
||||
run: |
|
||||
cat <<EOF > /tmp/posttest.sh
|
||||
#!/bin/bash
|
||||
mkdir -p /tmp/Complement/logs/\$2/\$1/
|
||||
docker cp \$1:/dendrite/complementcover.log /tmp/Complement/logs/\$2/\$1/
|
||||
EOF
|
||||
|
||||
chmod +x /tmp/posttest.sh
|
||||
# Run Complement
|
||||
- run: |
|
||||
set -o pipefail &&
|
||||
go test -v -json -tags dendrite_blacklist ./tests/... 2>&1 | gotestfmt
|
||||
shell: bash
|
||||
name: Run Complement Tests
|
||||
env:
|
||||
COMPLEMENT_BASE_IMAGE: complement-dendrite:${{ matrix.postgres }}${{ matrix.api }}${{ matrix.cgo }}
|
||||
COMPLEMENT_DENDRITE_API: ${{ matrix.api && 1 }}
|
||||
COMPLEMENT_SHARE_ENV_PREFIX: COMPLEMENT_DENDRITE_
|
||||
COMPLEMENT_DENDRITE_COVER: 1
|
||||
COMPLEMENT_POST_TEST_SCRIPT: /tmp/posttest.sh
|
||||
working-directory: complement
|
||||
|
||||
- name: Upload Complement logs
|
||||
uses: actions/upload-artifact@v2
|
||||
if: ${{ always() }}
|
||||
with:
|
||||
name: Complement Logs - (Dendrite, ${{ join(matrix.*, ', ') }})
|
||||
path: |
|
||||
/tmp/Complement/**/complementcover.log
|
||||
|
||||
complement-coverage:
|
||||
timeout-minutes: 5
|
||||
name: "Complement Coverage"
|
||||
runs-on: ubuntu-latest
|
||||
needs: complement # only run once Complement is done
|
||||
if: ${{ always() }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '>=1.19.0'
|
||||
cache: true
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
- name: Install gocovmerge
|
||||
run: go install github.com/wadey/gocovmerge@latest
|
||||
- name: Run gocovmerge
|
||||
run: |
|
||||
find -name 'complementcover.log' -printf '"%p"\n' | xargs gocovmerge | grep -Ev 'relayapi|setup/mscs|api_trace' > complement.cov
|
||||
go tool cover -func=complement.cov
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
files: ./complement.cov
|
||||
flags: complement
|
||||
fail_ci_if_error: true
|
||||
|
||||
element_web:
|
||||
timeout-minutes: 120
|
||||
runs-on: ubuntu-latest
|
||||
|
|
|
|||
2
build/gobind-pinecone/build.sh
Normal file → Executable file
2
build/gobind-pinecone/build.sh
Normal file → Executable file
|
|
@ -7,7 +7,7 @@ do
|
|||
case "$option"
|
||||
in
|
||||
a) gomobile bind -v -target android -trimpath -ldflags="-s -w" github.com/matrix-org/dendrite/build/gobind-pinecone ;;
|
||||
i) gomobile bind -v -target ios -trimpath -ldflags="" github.com/matrix-org/dendrite/build/gobind-pinecone ;;
|
||||
i) gomobile bind -v -target ios -trimpath -ldflags="" -o ~/DendriteBindings/Gobind.xcframework . ;;
|
||||
*) echo "No target specified, specify -a or -i"; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
|
@ -18,95 +18,65 @@ import (
|
|||
"context"
|
||||
"crypto/ed25519"
|
||||
"crypto/rand"
|
||||
"crypto/tls"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"go.uber.org/atomic"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/matrix-org/dendrite/appservice"
|
||||
"github.com/matrix-org/dendrite/clientapi/userutil"
|
||||
"github.com/matrix-org/dendrite/cmd/dendrite-demo-pinecone/conn"
|
||||
"github.com/matrix-org/dendrite/cmd/dendrite-demo-pinecone/rooms"
|
||||
"github.com/matrix-org/dendrite/cmd/dendrite-demo-pinecone/users"
|
||||
"github.com/matrix-org/dendrite/cmd/dendrite-demo-pinecone/conduit"
|
||||
"github.com/matrix-org/dendrite/cmd/dendrite-demo-pinecone/monolith"
|
||||
"github.com/matrix-org/dendrite/cmd/dendrite-demo-pinecone/relay"
|
||||
"github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/signing"
|
||||
"github.com/matrix-org/dendrite/federationapi"
|
||||
"github.com/matrix-org/dendrite/federationapi/api"
|
||||
"github.com/matrix-org/dendrite/federationapi/producers"
|
||||
"github.com/matrix-org/dendrite/internal/httputil"
|
||||
"github.com/matrix-org/dendrite/keyserver"
|
||||
"github.com/matrix-org/dendrite/relayapi"
|
||||
relayServerAPI "github.com/matrix-org/dendrite/relayapi/api"
|
||||
"github.com/matrix-org/dendrite/roomserver"
|
||||
"github.com/matrix-org/dendrite/setup"
|
||||
"github.com/matrix-org/dendrite/setup/base"
|
||||
"github.com/matrix-org/dendrite/setup/config"
|
||||
"github.com/matrix-org/dendrite/setup/jetstream"
|
||||
"github.com/matrix-org/dendrite/test"
|
||||
"github.com/matrix-org/dendrite/userapi"
|
||||
userapiAPI "github.com/matrix-org/dendrite/userapi/api"
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
"github.com/matrix-org/pinecone/types"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/net/http2"
|
||||
"golang.org/x/net/http2/h2c"
|
||||
|
||||
pineconeConnections "github.com/matrix-org/pinecone/connections"
|
||||
pineconeMulticast "github.com/matrix-org/pinecone/multicast"
|
||||
pineconeRouter "github.com/matrix-org/pinecone/router"
|
||||
pineconeEvents "github.com/matrix-org/pinecone/router/events"
|
||||
pineconeSessions "github.com/matrix-org/pinecone/sessions"
|
||||
"github.com/matrix-org/pinecone/types"
|
||||
|
||||
_ "golang.org/x/mobile/bind"
|
||||
)
|
||||
|
||||
const (
|
||||
PeerTypeRemote = pineconeRouter.PeerTypeRemote
|
||||
PeerTypeMulticast = pineconeRouter.PeerTypeMulticast
|
||||
PeerTypeBluetooth = pineconeRouter.PeerTypeBluetooth
|
||||
PeerTypeBonjour = pineconeRouter.PeerTypeBonjour
|
||||
relayServerRetryInterval = time.Second * 30
|
||||
PeerTypeRemote = pineconeRouter.PeerTypeRemote
|
||||
PeerTypeMulticast = pineconeRouter.PeerTypeMulticast
|
||||
PeerTypeBluetooth = pineconeRouter.PeerTypeBluetooth
|
||||
PeerTypeBonjour = pineconeRouter.PeerTypeBonjour
|
||||
|
||||
MaxFrameSize = types.MaxFrameSize
|
||||
)
|
||||
|
||||
// Re-export Conduit in this package for bindings.
|
||||
type Conduit struct {
|
||||
conduit.Conduit
|
||||
}
|
||||
|
||||
type DendriteMonolith struct {
|
||||
logger logrus.Logger
|
||||
baseDendrite *base.BaseDendrite
|
||||
PineconeRouter *pineconeRouter.Router
|
||||
PineconeMulticast *pineconeMulticast.Multicast
|
||||
PineconeQUIC *pineconeSessions.Sessions
|
||||
PineconeManager *pineconeConnections.ConnectionManager
|
||||
StorageDirectory string
|
||||
CacheDirectory string
|
||||
listener net.Listener
|
||||
httpServer *http.Server
|
||||
userAPI userapiAPI.UserInternalAPI
|
||||
federationAPI api.FederationInternalAPI
|
||||
relayServersQueried map[gomatrixserverlib.ServerName]bool
|
||||
logger logrus.Logger
|
||||
p2pMonolith monolith.P2PMonolith
|
||||
StorageDirectory string
|
||||
CacheDirectory string
|
||||
listener net.Listener
|
||||
}
|
||||
|
||||
func (m *DendriteMonolith) PublicKey() string {
|
||||
return m.PineconeRouter.PublicKey().String()
|
||||
return m.p2pMonolith.Router.PublicKey().String()
|
||||
}
|
||||
|
||||
func (m *DendriteMonolith) BaseURL() string {
|
||||
return fmt.Sprintf("http://%s", m.listener.Addr().String())
|
||||
return fmt.Sprintf("http://%s", m.p2pMonolith.Addr())
|
||||
}
|
||||
|
||||
func (m *DendriteMonolith) PeerCount(peertype int) int {
|
||||
return m.PineconeRouter.PeerCount(peertype)
|
||||
return m.p2pMonolith.Router.PeerCount(peertype)
|
||||
}
|
||||
|
||||
func (m *DendriteMonolith) SessionCount() int {
|
||||
return len(m.PineconeQUIC.Protocol("matrix").Sessions())
|
||||
return len(m.p2pMonolith.Sessions.Protocol(monolith.SessionProtocol).Sessions())
|
||||
}
|
||||
|
||||
type InterfaceInfo struct {
|
||||
|
|
@ -148,55 +118,156 @@ func (m *DendriteMonolith) RegisterNetworkCallback(intfCallback InterfaceRetriev
|
|||
}
|
||||
return intfs
|
||||
}
|
||||
m.PineconeMulticast.RegisterNetworkCallback(callback)
|
||||
m.p2pMonolith.Multicast.RegisterNetworkCallback(callback)
|
||||
}
|
||||
|
||||
func (m *DendriteMonolith) SetMulticastEnabled(enabled bool) {
|
||||
if enabled {
|
||||
m.PineconeMulticast.Start()
|
||||
m.p2pMonolith.Multicast.Start()
|
||||
} else {
|
||||
m.PineconeMulticast.Stop()
|
||||
m.p2pMonolith.Multicast.Stop()
|
||||
m.DisconnectType(int(pineconeRouter.PeerTypeMulticast))
|
||||
}
|
||||
}
|
||||
|
||||
func (m *DendriteMonolith) SetStaticPeer(uri string) {
|
||||
m.PineconeManager.RemovePeers()
|
||||
m.p2pMonolith.ConnManager.RemovePeers()
|
||||
for _, uri := range strings.Split(uri, ",") {
|
||||
m.PineconeManager.AddPeer(strings.TrimSpace(uri))
|
||||
m.p2pMonolith.ConnManager.AddPeer(strings.TrimSpace(uri))
|
||||
}
|
||||
}
|
||||
|
||||
func getServerKeyFromString(nodeID string) (gomatrixserverlib.ServerName, error) {
|
||||
var nodeKey gomatrixserverlib.ServerName
|
||||
if userID, err := gomatrixserverlib.NewUserID(nodeID, false); err == nil {
|
||||
hexKey, decodeErr := hex.DecodeString(string(userID.Domain()))
|
||||
if decodeErr != nil || len(hexKey) != ed25519.PublicKeySize {
|
||||
return "", fmt.Errorf("UserID domain is not a valid ed25519 public key: %v", userID.Domain())
|
||||
} else {
|
||||
nodeKey = userID.Domain()
|
||||
}
|
||||
} else {
|
||||
hexKey, decodeErr := hex.DecodeString(nodeID)
|
||||
if decodeErr != nil || len(hexKey) != ed25519.PublicKeySize {
|
||||
return "", fmt.Errorf("Relay server uri is not a valid ed25519 public key: %v", nodeID)
|
||||
} else {
|
||||
nodeKey = gomatrixserverlib.ServerName(nodeID)
|
||||
}
|
||||
}
|
||||
|
||||
return nodeKey, nil
|
||||
}
|
||||
|
||||
func (m *DendriteMonolith) SetRelayServers(nodeID string, uris string) {
|
||||
relays := []gomatrixserverlib.ServerName{}
|
||||
for _, uri := range strings.Split(uris, ",") {
|
||||
uri = strings.TrimSpace(uri)
|
||||
if len(uri) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
nodeKey, err := getServerKeyFromString(uri)
|
||||
if err != nil {
|
||||
logrus.Errorf(err.Error())
|
||||
continue
|
||||
}
|
||||
relays = append(relays, nodeKey)
|
||||
}
|
||||
|
||||
nodeKey, err := getServerKeyFromString(nodeID)
|
||||
if err != nil {
|
||||
logrus.Errorf(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if string(nodeKey) == m.PublicKey() {
|
||||
logrus.Infof("Setting own relay servers to: %v", relays)
|
||||
m.p2pMonolith.RelayRetriever.SetRelayServers(relays)
|
||||
} else {
|
||||
relay.UpdateNodeRelayServers(
|
||||
gomatrixserverlib.ServerName(nodeKey),
|
||||
relays,
|
||||
m.p2pMonolith.BaseDendrite.Context(),
|
||||
m.p2pMonolith.GetFederationAPI(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *DendriteMonolith) GetRelayServers(nodeID string) string {
|
||||
nodeKey, err := getServerKeyFromString(nodeID)
|
||||
if err != nil {
|
||||
logrus.Errorf(err.Error())
|
||||
return ""
|
||||
}
|
||||
|
||||
relaysString := ""
|
||||
if string(nodeKey) == m.PublicKey() {
|
||||
relays := m.p2pMonolith.RelayRetriever.GetRelayServers()
|
||||
|
||||
for i, relay := range relays {
|
||||
if i != 0 {
|
||||
// Append a comma to the previous entry if there is one.
|
||||
relaysString += ","
|
||||
}
|
||||
relaysString += string(relay)
|
||||
}
|
||||
} else {
|
||||
request := api.P2PQueryRelayServersRequest{Server: gomatrixserverlib.ServerName(nodeKey)}
|
||||
response := api.P2PQueryRelayServersResponse{}
|
||||
err := m.p2pMonolith.GetFederationAPI().P2PQueryRelayServers(m.p2pMonolith.BaseDendrite.Context(), &request, &response)
|
||||
if err != nil {
|
||||
logrus.Warnf("Failed obtaining list of this node's relay servers: %s", err.Error())
|
||||
return ""
|
||||
}
|
||||
|
||||
for i, relay := range response.RelayServers {
|
||||
if i != 0 {
|
||||
// Append a comma to the previous entry if there is one.
|
||||
relaysString += ","
|
||||
}
|
||||
relaysString += string(relay)
|
||||
}
|
||||
}
|
||||
|
||||
return relaysString
|
||||
}
|
||||
|
||||
func (m *DendriteMonolith) RelayingEnabled() bool {
|
||||
return m.p2pMonolith.GetRelayAPI().RelayingEnabled()
|
||||
}
|
||||
|
||||
func (m *DendriteMonolith) SetRelayingEnabled(enabled bool) {
|
||||
m.p2pMonolith.GetRelayAPI().SetRelayingEnabled(enabled)
|
||||
}
|
||||
|
||||
func (m *DendriteMonolith) DisconnectType(peertype int) {
|
||||
for _, p := range m.PineconeRouter.Peers() {
|
||||
for _, p := range m.p2pMonolith.Router.Peers() {
|
||||
if int(peertype) == p.PeerType {
|
||||
m.PineconeRouter.Disconnect(types.SwitchPortID(p.Port), nil)
|
||||
m.p2pMonolith.Router.Disconnect(types.SwitchPortID(p.Port), nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *DendriteMonolith) DisconnectZone(zone string) {
|
||||
for _, p := range m.PineconeRouter.Peers() {
|
||||
for _, p := range m.p2pMonolith.Router.Peers() {
|
||||
if zone == p.Zone {
|
||||
m.PineconeRouter.Disconnect(types.SwitchPortID(p.Port), nil)
|
||||
m.p2pMonolith.Router.Disconnect(types.SwitchPortID(p.Port), nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *DendriteMonolith) DisconnectPort(port int) {
|
||||
m.PineconeRouter.Disconnect(types.SwitchPortID(port), nil)
|
||||
m.p2pMonolith.Router.Disconnect(types.SwitchPortID(port), nil)
|
||||
}
|
||||
|
||||
func (m *DendriteMonolith) Conduit(zone string, peertype int) (*Conduit, error) {
|
||||
l, r := net.Pipe()
|
||||
conduit := &Conduit{conn: r, port: 0}
|
||||
newConduit := Conduit{conduit.NewConduit(r, 0)}
|
||||
go func() {
|
||||
conduit.portMutex.Lock()
|
||||
defer conduit.portMutex.Unlock()
|
||||
|
||||
logrus.Errorf("Attempting authenticated connect")
|
||||
var port types.SwitchPortID
|
||||
var err error
|
||||
if conduit.port, err = m.PineconeRouter.Connect(
|
||||
if port, err = m.p2pMonolith.Router.Connect(
|
||||
l,
|
||||
pineconeRouter.ConnectionZone(zone),
|
||||
pineconeRouter.ConnectionPeerType(peertype),
|
||||
|
|
@ -204,16 +275,17 @@ func (m *DendriteMonolith) Conduit(zone string, peertype int) (*Conduit, error)
|
|||
logrus.Errorf("Authenticated connect failed: %s", err)
|
||||
_ = l.Close()
|
||||
_ = r.Close()
|
||||
_ = conduit.Close()
|
||||
_ = newConduit.Close()
|
||||
return
|
||||
}
|
||||
logrus.Infof("Authenticated connect succeeded (port %d)", conduit.port)
|
||||
newConduit.SetPort(port)
|
||||
logrus.Infof("Authenticated connect succeeded (port %d)", newConduit.Port())
|
||||
}()
|
||||
return conduit, nil
|
||||
return &newConduit, nil
|
||||
}
|
||||
|
||||
func (m *DendriteMonolith) RegisterUser(localpart, password string) (string, error) {
|
||||
pubkey := m.PineconeRouter.PublicKey()
|
||||
pubkey := m.p2pMonolith.Router.PublicKey()
|
||||
userID := userutil.MakeUserID(
|
||||
localpart,
|
||||
gomatrixserverlib.ServerName(hex.EncodeToString(pubkey[:])),
|
||||
|
|
@ -224,7 +296,7 @@ func (m *DendriteMonolith) RegisterUser(localpart, password string) (string, err
|
|||
Password: password,
|
||||
}
|
||||
userRes := &userapiAPI.PerformAccountCreationResponse{}
|
||||
if err := m.userAPI.PerformAccountCreation(context.Background(), userReq, userRes); err != nil {
|
||||
if err := m.p2pMonolith.GetUserAPI().PerformAccountCreation(context.Background(), userReq, userRes); err != nil {
|
||||
return userID, fmt.Errorf("userAPI.PerformAccountCreation: %w", err)
|
||||
}
|
||||
return userID, nil
|
||||
|
|
@ -242,7 +314,7 @@ func (m *DendriteMonolith) RegisterDevice(localpart, deviceID string) (string, e
|
|||
AccessToken: hex.EncodeToString(accessTokenBytes[:n]),
|
||||
}
|
||||
loginRes := &userapiAPI.PerformDeviceCreationResponse{}
|
||||
if err := m.userAPI.PerformDeviceCreation(context.Background(), loginReq, loginRes); err != nil {
|
||||
if err := m.p2pMonolith.GetUserAPI().PerformDeviceCreation(context.Background(), loginReq, loginRes); err != nil {
|
||||
return "", fmt.Errorf("userAPI.PerformDeviceCreation: %w", err)
|
||||
}
|
||||
if !loginRes.DeviceCreated {
|
||||
|
|
@ -251,51 +323,10 @@ func (m *DendriteMonolith) RegisterDevice(localpart, deviceID string) (string, e
|
|||
return loginRes.Device.AccessToken, nil
|
||||
}
|
||||
|
||||
// nolint:gocyclo
|
||||
func (m *DendriteMonolith) Start() {
|
||||
var sk ed25519.PrivateKey
|
||||
var pk ed25519.PublicKey
|
||||
|
||||
keyfile := filepath.Join(m.StorageDirectory, "p2p.pem")
|
||||
if _, err := os.Stat(keyfile); os.IsNotExist(err) {
|
||||
oldkeyfile := filepath.Join(m.StorageDirectory, "p2p.key")
|
||||
if _, err = os.Stat(oldkeyfile); os.IsNotExist(err) {
|
||||
if err = test.NewMatrixKey(keyfile); err != nil {
|
||||
panic("failed to generate a new PEM key: " + err.Error())
|
||||
}
|
||||
if _, sk, err = config.LoadMatrixKey(keyfile, os.ReadFile); err != nil {
|
||||
panic("failed to load PEM key: " + err.Error())
|
||||
}
|
||||
if len(sk) != ed25519.PrivateKeySize {
|
||||
panic("the private key is not long enough")
|
||||
}
|
||||
} else {
|
||||
if sk, err = os.ReadFile(oldkeyfile); err != nil {
|
||||
panic("failed to read the old private key: " + err.Error())
|
||||
}
|
||||
if len(sk) != ed25519.PrivateKeySize {
|
||||
panic("the private key is not long enough")
|
||||
}
|
||||
if err = test.SaveMatrixKey(keyfile, sk); err != nil {
|
||||
panic("failed to convert the private key to PEM format: " + err.Error())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if _, sk, err = config.LoadMatrixKey(keyfile, os.ReadFile); err != nil {
|
||||
panic("failed to load PEM key: " + err.Error())
|
||||
}
|
||||
if len(sk) != ed25519.PrivateKeySize {
|
||||
panic("the private key is not long enough")
|
||||
}
|
||||
}
|
||||
|
||||
pk = sk.Public().(ed25519.PublicKey)
|
||||
|
||||
var err error
|
||||
m.listener, err = net.Listen("tcp", "localhost:65432")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
oldKeyfile := filepath.Join(m.StorageDirectory, "p2p.key")
|
||||
sk, pk := monolith.GetOrCreateKey(keyfile, oldKeyfile)
|
||||
|
||||
m.logger = logrus.Logger{
|
||||
Out: BindLogger{},
|
||||
|
|
@ -303,345 +334,25 @@ func (m *DendriteMonolith) Start() {
|
|||
m.logger.SetOutput(BindLogger{})
|
||||
logrus.SetOutput(BindLogger{})
|
||||
|
||||
pineconeEventChannel := make(chan pineconeEvents.Event)
|
||||
m.PineconeRouter = pineconeRouter.NewRouter(logrus.WithField("pinecone", "router"), sk)
|
||||
m.PineconeRouter.EnableHopLimiting()
|
||||
m.PineconeRouter.EnableWakeupBroadcasts()
|
||||
m.PineconeRouter.Subscribe(pineconeEventChannel)
|
||||
|
||||
m.PineconeQUIC = pineconeSessions.NewSessions(logrus.WithField("pinecone", "sessions"), m.PineconeRouter, []string{"matrix"})
|
||||
m.PineconeMulticast = pineconeMulticast.NewMulticast(logrus.WithField("pinecone", "multicast"), m.PineconeRouter)
|
||||
m.PineconeManager = pineconeConnections.NewConnectionManager(m.PineconeRouter, nil)
|
||||
m.p2pMonolith = monolith.P2PMonolith{}
|
||||
m.p2pMonolith.SetupPinecone(sk)
|
||||
|
||||
prefix := hex.EncodeToString(pk)
|
||||
cfg := &config.Dendrite{}
|
||||
cfg.Defaults(config.DefaultOpts{
|
||||
Generate: true,
|
||||
Monolithic: true,
|
||||
})
|
||||
cfg := monolith.GenerateDefaultConfig(sk, m.StorageDirectory, m.CacheDirectory, prefix)
|
||||
cfg.Global.ServerName = gomatrixserverlib.ServerName(hex.EncodeToString(pk))
|
||||
cfg.Global.PrivateKey = sk
|
||||
cfg.Global.KeyID = gomatrixserverlib.KeyID(signing.KeyID)
|
||||
cfg.Global.JetStream.InMemory = false
|
||||
cfg.Global.JetStream.StoragePath = config.Path(filepath.Join(m.CacheDirectory, prefix))
|
||||
cfg.UserAPI.AccountDatabase.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-account.db", filepath.Join(m.StorageDirectory, prefix)))
|
||||
cfg.MediaAPI.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-mediaapi.db", filepath.Join(m.StorageDirectory, prefix)))
|
||||
cfg.SyncAPI.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-syncapi.db", filepath.Join(m.StorageDirectory, prefix)))
|
||||
cfg.RoomServer.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-roomserver.db", filepath.Join(m.StorageDirectory, prefix)))
|
||||
cfg.KeyServer.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-keyserver.db", filepath.Join(m.StorageDirectory, prefix)))
|
||||
cfg.FederationAPI.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-federationsender.db", filepath.Join(m.StorageDirectory, prefix)))
|
||||
cfg.MediaAPI.BasePath = config.Path(filepath.Join(m.CacheDirectory, "media"))
|
||||
cfg.MediaAPI.AbsBasePath = config.Path(filepath.Join(m.CacheDirectory, "media"))
|
||||
cfg.RelayAPI.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-relayapi.db", filepath.Join(m.StorageDirectory, prefix)))
|
||||
cfg.MSCs.MSCs = []string{"msc2836", "msc2946"}
|
||||
cfg.ClientAPI.RegistrationDisabled = false
|
||||
cfg.ClientAPI.OpenRegistrationWithoutVerificationEnabled = true
|
||||
cfg.SyncAPI.Fulltext.Enabled = true
|
||||
cfg.SyncAPI.Fulltext.IndexPath = config.Path(filepath.Join(m.CacheDirectory, "search"))
|
||||
if err = cfg.Derive(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// NOTE : disabled for now since there is a 64 bit alignment panic on 32 bit systems
|
||||
// This isn't actually fixed: https://github.com/blevesearch/zapx/pull/147
|
||||
cfg.SyncAPI.Fulltext.Enabled = false
|
||||
|
||||
base := base.NewBaseDendrite(cfg, "Monolith", base.DisableMetrics)
|
||||
m.baseDendrite = base
|
||||
base.ConfigureAdminEndpoints()
|
||||
|
||||
federation := conn.CreateFederationClient(base, m.PineconeQUIC)
|
||||
|
||||
serverKeyAPI := &signing.YggdrasilKeys{}
|
||||
keyRing := serverKeyAPI.KeyRing()
|
||||
|
||||
rsAPI := roomserver.NewInternalAPI(base)
|
||||
|
||||
m.federationAPI = federationapi.NewInternalAPI(
|
||||
base, federation, rsAPI, base.Caches, keyRing, true,
|
||||
)
|
||||
|
||||
keyAPI := keyserver.NewInternalAPI(base, &base.Cfg.KeyServer, m.federationAPI, rsAPI)
|
||||
m.userAPI = userapi.NewInternalAPI(base, &cfg.UserAPI, cfg.Derived.ApplicationServices, keyAPI, rsAPI, base.PushGatewayHTTPClient())
|
||||
keyAPI.SetUserAPI(m.userAPI)
|
||||
|
||||
asAPI := appservice.NewInternalAPI(base, m.userAPI, rsAPI)
|
||||
|
||||
// The underlying roomserver implementation needs to be able to call the fedsender.
|
||||
// This is different to rsAPI which can be the http client which doesn't need this dependency
|
||||
rsAPI.SetFederationAPI(m.federationAPI, keyRing)
|
||||
|
||||
userProvider := users.NewPineconeUserProvider(m.PineconeRouter, m.PineconeQUIC, m.userAPI, federation)
|
||||
roomProvider := rooms.NewPineconeRoomProvider(m.PineconeRouter, m.PineconeQUIC, m.federationAPI, federation)
|
||||
|
||||
js, _ := base.NATS.Prepare(base.ProcessContext, &base.Cfg.Global.JetStream)
|
||||
producer := &producers.SyncAPIProducer{
|
||||
JetStream: js,
|
||||
TopicReceiptEvent: base.Cfg.Global.JetStream.Prefixed(jetstream.OutputReceiptEvent),
|
||||
TopicSendToDeviceEvent: base.Cfg.Global.JetStream.Prefixed(jetstream.OutputSendToDeviceEvent),
|
||||
TopicTypingEvent: base.Cfg.Global.JetStream.Prefixed(jetstream.OutputTypingEvent),
|
||||
TopicPresenceEvent: base.Cfg.Global.JetStream.Prefixed(jetstream.OutputPresenceEvent),
|
||||
TopicDeviceListUpdate: base.Cfg.Global.JetStream.Prefixed(jetstream.InputDeviceListUpdate),
|
||||
TopicSigningKeyUpdate: base.Cfg.Global.JetStream.Prefixed(jetstream.InputSigningKeyUpdate),
|
||||
Config: &base.Cfg.FederationAPI,
|
||||
UserAPI: m.userAPI,
|
||||
}
|
||||
relayAPI := relayapi.NewRelayInternalAPI(base, federation, rsAPI, keyRing, producer)
|
||||
|
||||
monolith := setup.Monolith{
|
||||
Config: base.Cfg,
|
||||
Client: conn.CreateClient(base, m.PineconeQUIC),
|
||||
FedClient: federation,
|
||||
KeyRing: keyRing,
|
||||
|
||||
AppserviceAPI: asAPI,
|
||||
FederationAPI: m.federationAPI,
|
||||
RoomserverAPI: rsAPI,
|
||||
UserAPI: m.userAPI,
|
||||
KeyAPI: keyAPI,
|
||||
RelayAPI: relayAPI,
|
||||
ExtPublicRoomsProvider: roomProvider,
|
||||
ExtUserDirectoryProvider: userProvider,
|
||||
}
|
||||
monolith.AddAllPublicRoutes(base)
|
||||
|
||||
httpRouter := mux.NewRouter().SkipClean(true).UseEncodedPath()
|
||||
httpRouter.PathPrefix(httputil.InternalPathPrefix).Handler(base.InternalAPIMux)
|
||||
httpRouter.PathPrefix(httputil.PublicClientPathPrefix).Handler(base.PublicClientAPIMux)
|
||||
httpRouter.PathPrefix(httputil.PublicMediaPathPrefix).Handler(base.PublicMediaAPIMux)
|
||||
httpRouter.PathPrefix(httputil.DendriteAdminPathPrefix).Handler(base.DendriteAdminMux)
|
||||
httpRouter.PathPrefix(httputil.SynapseAdminPathPrefix).Handler(base.SynapseAdminMux)
|
||||
httpRouter.HandleFunc("/pinecone", m.PineconeRouter.ManholeHandler)
|
||||
|
||||
pMux := mux.NewRouter().SkipClean(true).UseEncodedPath()
|
||||
pMux.PathPrefix(users.PublicURL).HandlerFunc(userProvider.FederatedUserProfiles)
|
||||
pMux.PathPrefix(httputil.PublicFederationPathPrefix).Handler(base.PublicFederationAPIMux)
|
||||
pMux.PathPrefix(httputil.PublicMediaPathPrefix).Handler(base.PublicMediaAPIMux)
|
||||
|
||||
pHTTP := m.PineconeQUIC.Protocol("matrix").HTTP()
|
||||
pHTTP.Mux().Handle(users.PublicURL, pMux)
|
||||
pHTTP.Mux().Handle(httputil.PublicFederationPathPrefix, pMux)
|
||||
pHTTP.Mux().Handle(httputil.PublicMediaPathPrefix, pMux)
|
||||
|
||||
// Build both ends of a HTTP multiplex.
|
||||
h2s := &http2.Server{}
|
||||
m.httpServer = &http.Server{
|
||||
Addr: ":0",
|
||||
TLSNextProto: map[string]func(*http.Server, *tls.Conn, http.Handler){},
|
||||
ReadTimeout: 10 * time.Second,
|
||||
WriteTimeout: 10 * time.Second,
|
||||
IdleTimeout: 30 * time.Second,
|
||||
BaseContext: func(_ net.Listener) context.Context {
|
||||
return context.Background()
|
||||
},
|
||||
Handler: h2c.NewHandler(pMux, h2s),
|
||||
}
|
||||
|
||||
go func() {
|
||||
m.logger.Info("Listening on ", cfg.Global.ServerName)
|
||||
|
||||
switch m.httpServer.Serve(m.PineconeQUIC.Protocol("matrix")) {
|
||||
case net.ErrClosed, http.ErrServerClosed:
|
||||
m.logger.Info("Stopped listening on ", cfg.Global.ServerName)
|
||||
default:
|
||||
m.logger.Error("Stopped listening on ", cfg.Global.ServerName)
|
||||
}
|
||||
}()
|
||||
go func() {
|
||||
logrus.Info("Listening on ", m.listener.Addr())
|
||||
|
||||
switch http.Serve(m.listener, httpRouter) {
|
||||
case net.ErrClosed, http.ErrServerClosed:
|
||||
m.logger.Info("Stopped listening on ", cfg.Global.ServerName)
|
||||
default:
|
||||
m.logger.Error("Stopped listening on ", cfg.Global.ServerName)
|
||||
}
|
||||
}()
|
||||
|
||||
go func(ch <-chan pineconeEvents.Event) {
|
||||
eLog := logrus.WithField("pinecone", "events")
|
||||
stopRelayServerSync := make(chan bool)
|
||||
|
||||
relayRetriever := RelayServerRetriever{
|
||||
Context: context.Background(),
|
||||
ServerName: gomatrixserverlib.ServerName(m.PineconeRouter.PublicKey().String()),
|
||||
FederationAPI: m.federationAPI,
|
||||
relayServersQueried: make(map[gomatrixserverlib.ServerName]bool),
|
||||
RelayAPI: monolith.RelayAPI,
|
||||
running: *atomic.NewBool(false),
|
||||
}
|
||||
relayRetriever.InitializeRelayServers(eLog)
|
||||
|
||||
for event := range ch {
|
||||
switch e := event.(type) {
|
||||
case pineconeEvents.PeerAdded:
|
||||
if !relayRetriever.running.Load() {
|
||||
go relayRetriever.SyncRelayServers(stopRelayServerSync)
|
||||
}
|
||||
case pineconeEvents.PeerRemoved:
|
||||
if relayRetriever.running.Load() && m.PineconeRouter.TotalPeerCount() == 0 {
|
||||
stopRelayServerSync <- true
|
||||
}
|
||||
case pineconeEvents.BroadcastReceived:
|
||||
// eLog.Info("Broadcast received from: ", e.PeerID)
|
||||
|
||||
req := &api.PerformWakeupServersRequest{
|
||||
ServerNames: []gomatrixserverlib.ServerName{gomatrixserverlib.ServerName(e.PeerID)},
|
||||
}
|
||||
res := &api.PerformWakeupServersResponse{}
|
||||
if err := m.federationAPI.PerformWakeupServers(base.Context(), req, res); err != nil {
|
||||
eLog.WithError(err).Error("Failed to wakeup destination", e.PeerID)
|
||||
}
|
||||
default:
|
||||
}
|
||||
}
|
||||
}(pineconeEventChannel)
|
||||
enableRelaying := false
|
||||
enableMetrics := false
|
||||
enableWebsockets := false
|
||||
m.p2pMonolith.SetupDendrite(cfg, 65432, enableRelaying, enableMetrics, enableWebsockets)
|
||||
m.p2pMonolith.StartMonolith()
|
||||
}
|
||||
|
||||
func (m *DendriteMonolith) Stop() {
|
||||
m.baseDendrite.Close()
|
||||
m.baseDendrite.WaitForShutdown()
|
||||
_ = m.listener.Close()
|
||||
m.PineconeMulticast.Stop()
|
||||
_ = m.PineconeQUIC.Close()
|
||||
_ = m.PineconeRouter.Close()
|
||||
}
|
||||
|
||||
type RelayServerRetriever struct {
|
||||
Context context.Context
|
||||
ServerName gomatrixserverlib.ServerName
|
||||
FederationAPI api.FederationInternalAPI
|
||||
RelayAPI relayServerAPI.RelayInternalAPI
|
||||
relayServersQueried map[gomatrixserverlib.ServerName]bool
|
||||
queriedServersMutex sync.Mutex
|
||||
running atomic.Bool
|
||||
}
|
||||
|
||||
func (m *RelayServerRetriever) InitializeRelayServers(eLog *logrus.Entry) {
|
||||
request := api.P2PQueryRelayServersRequest{Server: gomatrixserverlib.ServerName(m.ServerName)}
|
||||
response := api.P2PQueryRelayServersResponse{}
|
||||
err := m.FederationAPI.P2PQueryRelayServers(m.Context, &request, &response)
|
||||
if err != nil {
|
||||
eLog.Warnf("Failed obtaining list of this node's relay servers: %s", err.Error())
|
||||
}
|
||||
for _, server := range response.RelayServers {
|
||||
m.relayServersQueried[server] = false
|
||||
}
|
||||
|
||||
eLog.Infof("Registered relay servers: %v", response.RelayServers)
|
||||
}
|
||||
|
||||
func (m *RelayServerRetriever) SyncRelayServers(stop <-chan bool) {
|
||||
defer m.running.Store(false)
|
||||
|
||||
t := time.NewTimer(relayServerRetryInterval)
|
||||
for {
|
||||
relayServersToQuery := []gomatrixserverlib.ServerName{}
|
||||
func() {
|
||||
m.queriedServersMutex.Lock()
|
||||
defer m.queriedServersMutex.Unlock()
|
||||
for server, complete := range m.relayServersQueried {
|
||||
if !complete {
|
||||
relayServersToQuery = append(relayServersToQuery, server)
|
||||
}
|
||||
}
|
||||
}()
|
||||
if len(relayServersToQuery) == 0 {
|
||||
// All relay servers have been synced.
|
||||
return
|
||||
}
|
||||
m.queryRelayServers(relayServersToQuery)
|
||||
t.Reset(relayServerRetryInterval)
|
||||
|
||||
select {
|
||||
case <-stop:
|
||||
if !t.Stop() {
|
||||
<-t.C
|
||||
}
|
||||
return
|
||||
case <-t.C:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *RelayServerRetriever) GetQueriedServerStatus() map[gomatrixserverlib.ServerName]bool {
|
||||
m.queriedServersMutex.Lock()
|
||||
defer m.queriedServersMutex.Unlock()
|
||||
|
||||
result := map[gomatrixserverlib.ServerName]bool{}
|
||||
for server, queried := range m.relayServersQueried {
|
||||
result[server] = queried
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (m *RelayServerRetriever) queryRelayServers(relayServers []gomatrixserverlib.ServerName) {
|
||||
logrus.Info("querying relay servers for any available transactions")
|
||||
for _, server := range relayServers {
|
||||
userID, err := gomatrixserverlib.NewUserID("@user:"+string(m.ServerName), false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = m.RelayAPI.PerformRelayServerSync(context.Background(), *userID, server)
|
||||
if err == nil {
|
||||
func() {
|
||||
m.queriedServersMutex.Lock()
|
||||
defer m.queriedServersMutex.Unlock()
|
||||
m.relayServersQueried[server] = true
|
||||
}()
|
||||
// TODO : What happens if your relay receives new messages after this point?
|
||||
// Should you continue to check with them, or should they try and contact you?
|
||||
// They could send a "new_async_events" message your way maybe?
|
||||
// Then you could mark them as needing to be queried again.
|
||||
// What if you miss this message?
|
||||
// Maybe you should try querying them again after a certain period of time as a backup?
|
||||
} else {
|
||||
logrus.Errorf("Failed querying relay server: %s", err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const MaxFrameSize = types.MaxFrameSize
|
||||
|
||||
type Conduit struct {
|
||||
closed atomic.Bool
|
||||
conn net.Conn
|
||||
port types.SwitchPortID
|
||||
portMutex sync.Mutex
|
||||
}
|
||||
|
||||
func (c *Conduit) Port() int {
|
||||
c.portMutex.Lock()
|
||||
defer c.portMutex.Unlock()
|
||||
return int(c.port)
|
||||
}
|
||||
|
||||
func (c *Conduit) Read(b []byte) (int, error) {
|
||||
if c.closed.Load() {
|
||||
return 0, io.EOF
|
||||
}
|
||||
return c.conn.Read(b)
|
||||
}
|
||||
|
||||
func (c *Conduit) ReadCopy() ([]byte, error) {
|
||||
if c.closed.Load() {
|
||||
return nil, io.EOF
|
||||
}
|
||||
var buf [65535 * 2]byte
|
||||
n, err := c.conn.Read(buf[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf[:n], nil
|
||||
}
|
||||
|
||||
func (c *Conduit) Write(b []byte) (int, error) {
|
||||
if c.closed.Load() {
|
||||
return 0, io.EOF
|
||||
}
|
||||
return c.conn.Write(b)
|
||||
}
|
||||
|
||||
func (c *Conduit) Close() error {
|
||||
if c.closed.Load() {
|
||||
return io.ErrClosedPipe
|
||||
}
|
||||
c.closed.Store(true)
|
||||
return c.conn.Close()
|
||||
m.p2pMonolith.Stop()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,184 +15,138 @@
|
|||
package gobind
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/matrix-org/dendrite/federationapi/api"
|
||||
relayServerAPI "github.com/matrix-org/dendrite/relayapi/api"
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gotest.tools/v3/poll"
|
||||
)
|
||||
|
||||
var TestBuf = []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
|
||||
|
||||
type TestNetConn struct {
|
||||
net.Conn
|
||||
shouldFail bool
|
||||
}
|
||||
|
||||
func (t *TestNetConn) Read(b []byte) (int, error) {
|
||||
if t.shouldFail {
|
||||
return 0, fmt.Errorf("Failed")
|
||||
} else {
|
||||
n := copy(b, TestBuf)
|
||||
return n, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (t *TestNetConn) Write(b []byte) (int, error) {
|
||||
if t.shouldFail {
|
||||
return 0, fmt.Errorf("Failed")
|
||||
} else {
|
||||
return len(b), nil
|
||||
}
|
||||
}
|
||||
|
||||
func (t *TestNetConn) Close() error {
|
||||
if t.shouldFail {
|
||||
return fmt.Errorf("Failed")
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func TestConduitStoresPort(t *testing.T) {
|
||||
conduit := Conduit{port: 7}
|
||||
assert.Equal(t, 7, conduit.Port())
|
||||
}
|
||||
|
||||
func TestConduitRead(t *testing.T) {
|
||||
conduit := Conduit{conn: &TestNetConn{}}
|
||||
b := make([]byte, len(TestBuf))
|
||||
bytes, err := conduit.Read(b)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, len(TestBuf), bytes)
|
||||
assert.Equal(t, TestBuf, b)
|
||||
}
|
||||
|
||||
func TestConduitReadCopy(t *testing.T) {
|
||||
conduit := Conduit{conn: &TestNetConn{}}
|
||||
result, err := conduit.ReadCopy()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, TestBuf, result)
|
||||
}
|
||||
|
||||
func TestConduitWrite(t *testing.T) {
|
||||
conduit := Conduit{conn: &TestNetConn{}}
|
||||
bytes, err := conduit.Write(TestBuf)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, len(TestBuf), bytes)
|
||||
}
|
||||
|
||||
func TestConduitClose(t *testing.T) {
|
||||
conduit := Conduit{conn: &TestNetConn{}}
|
||||
err := conduit.Close()
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, conduit.closed.Load())
|
||||
}
|
||||
|
||||
func TestConduitReadClosed(t *testing.T) {
|
||||
conduit := Conduit{conn: &TestNetConn{}}
|
||||
err := conduit.Close()
|
||||
assert.NoError(t, err)
|
||||
b := make([]byte, len(TestBuf))
|
||||
_, err = conduit.Read(b)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestConduitReadCopyClosed(t *testing.T) {
|
||||
conduit := Conduit{conn: &TestNetConn{}}
|
||||
err := conduit.Close()
|
||||
assert.NoError(t, err)
|
||||
_, err = conduit.ReadCopy()
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestConduitWriteClosed(t *testing.T) {
|
||||
conduit := Conduit{conn: &TestNetConn{}}
|
||||
err := conduit.Close()
|
||||
assert.NoError(t, err)
|
||||
_, err = conduit.Write(TestBuf)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestConduitReadCopyFails(t *testing.T) {
|
||||
conduit := Conduit{conn: &TestNetConn{shouldFail: true}}
|
||||
_, err := conduit.ReadCopy()
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
var testRelayServers = []gomatrixserverlib.ServerName{"relay1", "relay2"}
|
||||
|
||||
type FakeFedAPI struct {
|
||||
api.FederationInternalAPI
|
||||
}
|
||||
|
||||
func (f *FakeFedAPI) P2PQueryRelayServers(ctx context.Context, req *api.P2PQueryRelayServersRequest, res *api.P2PQueryRelayServersResponse) error {
|
||||
res.RelayServers = testRelayServers
|
||||
return nil
|
||||
}
|
||||
|
||||
type FakeRelayAPI struct {
|
||||
relayServerAPI.RelayInternalAPI
|
||||
}
|
||||
|
||||
func (r *FakeRelayAPI) PerformRelayServerSync(ctx context.Context, userID gomatrixserverlib.UserID, relayServer gomatrixserverlib.ServerName) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestRelayRetrieverInitialization(t *testing.T) {
|
||||
retriever := RelayServerRetriever{
|
||||
Context: context.Background(),
|
||||
ServerName: "server",
|
||||
relayServersQueried: make(map[gomatrixserverlib.ServerName]bool),
|
||||
FederationAPI: &FakeFedAPI{},
|
||||
RelayAPI: &FakeRelayAPI{},
|
||||
}
|
||||
|
||||
retriever.InitializeRelayServers(logrus.WithField("test", "relay"))
|
||||
relayServers := retriever.GetQueriedServerStatus()
|
||||
assert.Equal(t, 2, len(relayServers))
|
||||
}
|
||||
|
||||
func TestRelayRetrieverSync(t *testing.T) {
|
||||
retriever := RelayServerRetriever{
|
||||
Context: context.Background(),
|
||||
ServerName: "server",
|
||||
relayServersQueried: make(map[gomatrixserverlib.ServerName]bool),
|
||||
FederationAPI: &FakeFedAPI{},
|
||||
RelayAPI: &FakeRelayAPI{},
|
||||
}
|
||||
|
||||
retriever.InitializeRelayServers(logrus.WithField("test", "relay"))
|
||||
relayServers := retriever.GetQueriedServerStatus()
|
||||
assert.Equal(t, 2, len(relayServers))
|
||||
|
||||
stopRelayServerSync := make(chan bool)
|
||||
go retriever.SyncRelayServers(stopRelayServerSync)
|
||||
|
||||
check := func(log poll.LogT) poll.Result {
|
||||
relayServers := retriever.GetQueriedServerStatus()
|
||||
for _, queried := range relayServers {
|
||||
if !queried {
|
||||
return poll.Continue("waiting for all servers to be queried")
|
||||
}
|
||||
}
|
||||
|
||||
stopRelayServerSync <- true
|
||||
return poll.Success()
|
||||
}
|
||||
poll.WaitOn(t, check, poll.WithTimeout(5*time.Second), poll.WithDelay(100*time.Millisecond))
|
||||
}
|
||||
|
||||
func TestMonolithStarts(t *testing.T) {
|
||||
monolith := DendriteMonolith{}
|
||||
monolith.Start()
|
||||
monolith.PublicKey()
|
||||
monolith.Stop()
|
||||
}
|
||||
|
||||
func TestMonolithSetRelayServers(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
nodeID string
|
||||
relays string
|
||||
expectedRelays string
|
||||
expectSelf bool
|
||||
}{
|
||||
{
|
||||
name: "assorted valid, invalid, empty & self keys",
|
||||
nodeID: "@valid:abcdef123456abcdef123456abcdef123456abcdef123456abcdef123456abcd",
|
||||
relays: "@valid:123456123456abcdef123456abcdef123456abcdef123456abcdef123456abcd,@invalid:notakey,,",
|
||||
expectedRelays: "123456123456abcdef123456abcdef123456abcdef123456abcdef123456abcd",
|
||||
expectSelf: true,
|
||||
},
|
||||
{
|
||||
name: "invalid node key",
|
||||
nodeID: "@invalid:notakey",
|
||||
relays: "@valid:123456123456abcdef123456abcdef123456abcdef123456abcdef123456abcd,@invalid:notakey,,",
|
||||
expectedRelays: "",
|
||||
expectSelf: false,
|
||||
},
|
||||
{
|
||||
name: "node is self",
|
||||
nodeID: "self",
|
||||
relays: "@valid:123456123456abcdef123456abcdef123456abcdef123456abcdef123456abcd,@invalid:notakey,,",
|
||||
expectedRelays: "123456123456abcdef123456abcdef123456abcdef123456abcdef123456abcd",
|
||||
expectSelf: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
monolith := DendriteMonolith{}
|
||||
monolith.Start()
|
||||
|
||||
inputRelays := tc.relays
|
||||
expectedRelays := tc.expectedRelays
|
||||
if tc.expectSelf {
|
||||
inputRelays += "," + monolith.PublicKey()
|
||||
expectedRelays += "," + monolith.PublicKey()
|
||||
}
|
||||
nodeID := tc.nodeID
|
||||
if nodeID == "self" {
|
||||
nodeID = monolith.PublicKey()
|
||||
}
|
||||
|
||||
monolith.SetRelayServers(nodeID, inputRelays)
|
||||
relays := monolith.GetRelayServers(nodeID)
|
||||
monolith.Stop()
|
||||
|
||||
if !containSameKeys(strings.Split(relays, ","), strings.Split(expectedRelays, ",")) {
|
||||
t.Fatalf("%s: expected %s got %s", tc.name, expectedRelays, relays)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func containSameKeys(expected []string, actual []string) bool {
|
||||
if len(expected) != len(actual) {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, expectedKey := range expected {
|
||||
hasMatch := false
|
||||
for _, actualKey := range actual {
|
||||
if actualKey == expectedKey {
|
||||
hasMatch = true
|
||||
}
|
||||
}
|
||||
|
||||
if !hasMatch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func TestParseServerKey(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
serverKey string
|
||||
expectedErr bool
|
||||
expectedKey gomatrixserverlib.ServerName
|
||||
}{
|
||||
{
|
||||
name: "valid userid as key",
|
||||
serverKey: "@valid:abcdef123456abcdef123456abcdef123456abcdef123456abcdef123456abcd",
|
||||
expectedErr: false,
|
||||
expectedKey: "abcdef123456abcdef123456abcdef123456abcdef123456abcdef123456abcd",
|
||||
},
|
||||
{
|
||||
name: "valid key",
|
||||
serverKey: "abcdef123456abcdef123456abcdef123456abcdef123456abcdef123456abcd",
|
||||
expectedErr: false,
|
||||
expectedKey: "abcdef123456abcdef123456abcdef123456abcdef123456abcdef123456abcd",
|
||||
},
|
||||
{
|
||||
name: "invalid userid key",
|
||||
serverKey: "@invalid:notakey",
|
||||
expectedErr: true,
|
||||
expectedKey: "",
|
||||
},
|
||||
{
|
||||
name: "invalid key",
|
||||
serverKey: "@invalid:notakey",
|
||||
expectedErr: true,
|
||||
expectedKey: "",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
key, err := getServerKeyFromString(tc.serverKey)
|
||||
if tc.expectedErr && err == nil {
|
||||
t.Fatalf("%s: expected an error", tc.name)
|
||||
} else if !tc.expectedErr && err != nil {
|
||||
t.Fatalf("%s: didn't expect an error: %s", tc.name, err.Error())
|
||||
}
|
||||
if tc.expectedKey != key {
|
||||
t.Fatalf("%s: keys not equal. expected: %s got: %s", tc.name, tc.expectedKey, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ if [[ "${COVER}" -eq 1 ]]; then
|
|||
--tls-key server.key \
|
||||
--config dendrite.yaml \
|
||||
-api=${API:-0} \
|
||||
--test.coverprofile=integrationcover.log
|
||||
--test.coverprofile=complementcover.log
|
||||
else
|
||||
echo "Not running with coverage"
|
||||
exec /dendrite/dendrite-monolith-server \
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import (
|
|||
"net/http"
|
||||
|
||||
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
||||
"github.com/matrix-org/dendrite/internal/httputil"
|
||||
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
|
||||
"github.com/matrix-org/dendrite/userapi/api"
|
||||
"github.com/matrix-org/util"
|
||||
|
|
@ -44,6 +45,15 @@ func LeaveRoomByID(
|
|||
JSON: jsonerror.LeaveServerNoticeError(),
|
||||
}
|
||||
}
|
||||
switch e := err.(type) {
|
||||
case httputil.InternalAPIError:
|
||||
if e.Message == jsonerror.LeaveServerNoticeError().Error() {
|
||||
return util.JSONResponse{
|
||||
Code: http.StatusForbidden,
|
||||
JSON: jsonerror.LeaveServerNoticeError(),
|
||||
}
|
||||
}
|
||||
}
|
||||
return util.JSONResponse{
|
||||
Code: http.StatusBadRequest,
|
||||
JSON: jsonerror.Unknown(err.Error()),
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/matrix-org/dendrite/internal"
|
||||
internalHTTPUtil "github.com/matrix-org/dendrite/internal/httputil"
|
||||
"github.com/matrix-org/dendrite/internal/sqlutil"
|
||||
"github.com/tidwall/gjson"
|
||||
|
||||
"github.com/matrix-org/dendrite/internal/eventutil"
|
||||
|
|
@ -859,6 +861,16 @@ func completeRegistration(
|
|||
JSON: jsonerror.UserInUse("Desired user ID is already taken."),
|
||||
}
|
||||
}
|
||||
switch e := err.(type) {
|
||||
case internalHTTPUtil.InternalAPIError:
|
||||
conflictErr := &userapi.ErrorConflict{Message: sqlutil.ErrUserExists.Error()}
|
||||
if e.Message == conflictErr.Error() {
|
||||
return util.JSONResponse{
|
||||
Code: http.StatusBadRequest,
|
||||
JSON: jsonerror.UserInUse("Desired user ID is already taken."),
|
||||
}
|
||||
}
|
||||
}
|
||||
return util.JSONResponse{
|
||||
Code: http.StatusInternalServerError,
|
||||
JSON: jsonerror.Unknown("failed to create account: " + err.Error()),
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import (
|
|||
"context"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/matrix-org/dendrite/setup/base"
|
||||
|
|
@ -198,18 +199,24 @@ func Setup(
|
|||
// server notifications
|
||||
if cfg.Matrix.ServerNotices.Enabled {
|
||||
logrus.Info("Enabling server notices at /_synapse/admin/v1/send_server_notice")
|
||||
serverNotificationSender, err := getSenderDevice(context.Background(), rsAPI, userAPI, cfg)
|
||||
if err != nil {
|
||||
logrus.WithError(err).Fatal("unable to get account for sending sending server notices")
|
||||
}
|
||||
var serverNotificationSender *userapi.Device
|
||||
var err error
|
||||
notificationSenderOnce := &sync.Once{}
|
||||
|
||||
synapseAdminRouter.Handle("/admin/v1/send_server_notice/{txnID}",
|
||||
httputil.MakeAuthAPI("send_server_notice", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||
notificationSenderOnce.Do(func() {
|
||||
serverNotificationSender, err = getSenderDevice(context.Background(), rsAPI, userAPI, cfg)
|
||||
if err != nil {
|
||||
logrus.WithError(err).Fatal("unable to get account for sending sending server notices")
|
||||
}
|
||||
})
|
||||
// not specced, but ensure we're rate limiting requests to this endpoint
|
||||
if r := rateLimits.Limit(req, device); r != nil {
|
||||
return *r
|
||||
}
|
||||
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
|
||||
var vars map[string]string
|
||||
vars, err = httputil.URLDecodeMapValues(mux.Vars(req))
|
||||
if err != nil {
|
||||
return util.ErrorResponse(err)
|
||||
}
|
||||
|
|
@ -225,6 +232,12 @@ func Setup(
|
|||
|
||||
synapseAdminRouter.Handle("/admin/v1/send_server_notice",
|
||||
httputil.MakeAuthAPI("send_server_notice", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
|
||||
notificationSenderOnce.Do(func() {
|
||||
serverNotificationSender, err = getSenderDevice(context.Background(), rsAPI, userAPI, cfg)
|
||||
if err != nil {
|
||||
logrus.WithError(err).Fatal("unable to get account for sending sending server notices")
|
||||
}
|
||||
})
|
||||
// not specced, but ensure we're rate limiting requests to this endpoint
|
||||
if r := rateLimits.Limit(req, device); r != nil {
|
||||
return *r
|
||||
|
|
|
|||
84
cmd/dendrite-demo-pinecone/conduit/conduit.go
Normal file
84
cmd/dendrite-demo-pinecone/conduit/conduit.go
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
// Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package conduit
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
"github.com/matrix-org/pinecone/types"
|
||||
"go.uber.org/atomic"
|
||||
)
|
||||
|
||||
type Conduit struct {
|
||||
closed atomic.Bool
|
||||
conn net.Conn
|
||||
portMutex sync.Mutex
|
||||
port types.SwitchPortID
|
||||
}
|
||||
|
||||
func NewConduit(conn net.Conn, port int) Conduit {
|
||||
return Conduit{
|
||||
conn: conn,
|
||||
port: types.SwitchPortID(port),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Conduit) Port() int {
|
||||
c.portMutex.Lock()
|
||||
defer c.portMutex.Unlock()
|
||||
return int(c.port)
|
||||
}
|
||||
|
||||
func (c *Conduit) SetPort(port types.SwitchPortID) {
|
||||
c.portMutex.Lock()
|
||||
defer c.portMutex.Unlock()
|
||||
c.port = port
|
||||
}
|
||||
|
||||
func (c *Conduit) Read(b []byte) (int, error) {
|
||||
if c.closed.Load() {
|
||||
return 0, io.EOF
|
||||
}
|
||||
return c.conn.Read(b)
|
||||
}
|
||||
|
||||
func (c *Conduit) ReadCopy() ([]byte, error) {
|
||||
if c.closed.Load() {
|
||||
return nil, io.EOF
|
||||
}
|
||||
var buf [65535 * 2]byte
|
||||
n, err := c.conn.Read(buf[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf[:n], nil
|
||||
}
|
||||
|
||||
func (c *Conduit) Write(b []byte) (int, error) {
|
||||
if c.closed.Load() {
|
||||
return 0, io.EOF
|
||||
}
|
||||
return c.conn.Write(b)
|
||||
}
|
||||
|
||||
func (c *Conduit) Close() error {
|
||||
if c.closed.Load() {
|
||||
return io.ErrClosedPipe
|
||||
}
|
||||
c.closed.Store(true)
|
||||
return c.conn.Close()
|
||||
}
|
||||
121
cmd/dendrite-demo-pinecone/conduit/conduit_test.go
Normal file
121
cmd/dendrite-demo-pinecone/conduit/conduit_test.go
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
// Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package conduit
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var TestBuf = []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
|
||||
|
||||
type TestNetConn struct {
|
||||
net.Conn
|
||||
shouldFail bool
|
||||
}
|
||||
|
||||
func (t *TestNetConn) Read(b []byte) (int, error) {
|
||||
if t.shouldFail {
|
||||
return 0, fmt.Errorf("Failed")
|
||||
} else {
|
||||
n := copy(b, TestBuf)
|
||||
return n, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (t *TestNetConn) Write(b []byte) (int, error) {
|
||||
if t.shouldFail {
|
||||
return 0, fmt.Errorf("Failed")
|
||||
} else {
|
||||
return len(b), nil
|
||||
}
|
||||
}
|
||||
|
||||
func (t *TestNetConn) Close() error {
|
||||
if t.shouldFail {
|
||||
return fmt.Errorf("Failed")
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func TestConduitStoresPort(t *testing.T) {
|
||||
conduit := Conduit{port: 7}
|
||||
assert.Equal(t, 7, conduit.Port())
|
||||
}
|
||||
|
||||
func TestConduitRead(t *testing.T) {
|
||||
conduit := Conduit{conn: &TestNetConn{}}
|
||||
b := make([]byte, len(TestBuf))
|
||||
bytes, err := conduit.Read(b)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, len(TestBuf), bytes)
|
||||
assert.Equal(t, TestBuf, b)
|
||||
}
|
||||
|
||||
func TestConduitReadCopy(t *testing.T) {
|
||||
conduit := Conduit{conn: &TestNetConn{}}
|
||||
result, err := conduit.ReadCopy()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, TestBuf, result)
|
||||
}
|
||||
|
||||
func TestConduitWrite(t *testing.T) {
|
||||
conduit := Conduit{conn: &TestNetConn{}}
|
||||
bytes, err := conduit.Write(TestBuf)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, len(TestBuf), bytes)
|
||||
}
|
||||
|
||||
func TestConduitClose(t *testing.T) {
|
||||
conduit := Conduit{conn: &TestNetConn{}}
|
||||
err := conduit.Close()
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, conduit.closed.Load())
|
||||
}
|
||||
|
||||
func TestConduitReadClosed(t *testing.T) {
|
||||
conduit := Conduit{conn: &TestNetConn{}}
|
||||
err := conduit.Close()
|
||||
assert.NoError(t, err)
|
||||
b := make([]byte, len(TestBuf))
|
||||
_, err = conduit.Read(b)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestConduitReadCopyClosed(t *testing.T) {
|
||||
conduit := Conduit{conn: &TestNetConn{}}
|
||||
err := conduit.Close()
|
||||
assert.NoError(t, err)
|
||||
_, err = conduit.ReadCopy()
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestConduitWriteClosed(t *testing.T) {
|
||||
conduit := Conduit{conn: &TestNetConn{}}
|
||||
err := conduit.Close()
|
||||
assert.NoError(t, err)
|
||||
_, err = conduit.Write(TestBuf)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestConduitReadCopyFails(t *testing.T) {
|
||||
conduit := Conduit{conn: &TestNetConn{shouldFail: true}}
|
||||
_, err := conduit.ReadCopy()
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
|
@ -15,65 +15,35 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ed25519"
|
||||
"crypto/tls"
|
||||
"encoding/hex"
|
||||
"flag"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/matrix-org/dendrite/appservice"
|
||||
"github.com/matrix-org/dendrite/cmd/dendrite-demo-pinecone/conn"
|
||||
"github.com/matrix-org/dendrite/cmd/dendrite-demo-pinecone/embed"
|
||||
"github.com/matrix-org/dendrite/cmd/dendrite-demo-pinecone/rooms"
|
||||
"github.com/matrix-org/dendrite/cmd/dendrite-demo-pinecone/users"
|
||||
"github.com/matrix-org/dendrite/cmd/dendrite-demo-pinecone/monolith"
|
||||
"github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/signing"
|
||||
"github.com/matrix-org/dendrite/federationapi"
|
||||
"github.com/matrix-org/dendrite/federationapi/api"
|
||||
"github.com/matrix-org/dendrite/federationapi/producers"
|
||||
"github.com/matrix-org/dendrite/internal"
|
||||
"github.com/matrix-org/dendrite/internal/httputil"
|
||||
"github.com/matrix-org/dendrite/keyserver"
|
||||
"github.com/matrix-org/dendrite/relayapi"
|
||||
relayServerAPI "github.com/matrix-org/dendrite/relayapi/api"
|
||||
"github.com/matrix-org/dendrite/roomserver"
|
||||
"github.com/matrix-org/dendrite/setup"
|
||||
"github.com/matrix-org/dendrite/setup/base"
|
||||
"github.com/matrix-org/dendrite/setup/config"
|
||||
"github.com/matrix-org/dendrite/setup/jetstream"
|
||||
"github.com/matrix-org/dendrite/test"
|
||||
"github.com/matrix-org/dendrite/userapi"
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
"go.uber.org/atomic"
|
||||
|
||||
pineconeConnections "github.com/matrix-org/pinecone/connections"
|
||||
pineconeMulticast "github.com/matrix-org/pinecone/multicast"
|
||||
pineconeRouter "github.com/matrix-org/pinecone/router"
|
||||
pineconeEvents "github.com/matrix-org/pinecone/router/events"
|
||||
pineconeSessions "github.com/matrix-org/pinecone/sessions"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
pineconeRouter "github.com/matrix-org/pinecone/router"
|
||||
)
|
||||
|
||||
var (
|
||||
instanceName = flag.String("name", "dendrite-p2p-pinecone", "the name of this P2P demo instance")
|
||||
instancePort = flag.Int("port", 8008, "the port that the client API will listen on")
|
||||
instancePeer = flag.String("peer", "", "the static Pinecone peers to connect to, comma separated-list")
|
||||
instanceListen = flag.String("listen", ":0", "the port Pinecone peers can connect to")
|
||||
instanceDir = flag.String("dir", ".", "the directory to store the databases in (if --config not specified)")
|
||||
instanceName = flag.String("name", "dendrite-p2p-pinecone", "the name of this P2P demo instance")
|
||||
instancePort = flag.Int("port", 8008, "the port that the client API will listen on")
|
||||
instancePeer = flag.String("peer", "", "the static Pinecone peers to connect to, comma separated-list")
|
||||
instanceListen = flag.String("listen", ":0", "the port Pinecone peers can connect to")
|
||||
instanceDir = flag.String("dir", ".", "the directory to store the databases in (if --config not specified)")
|
||||
instanceRelayingEnabled = flag.Bool("relay", false, "whether to enable store & forward relaying for other nodes")
|
||||
)
|
||||
|
||||
const relayServerRetryInterval = time.Second * 30
|
||||
|
||||
// nolint:gocyclo
|
||||
func main() {
|
||||
flag.Parse()
|
||||
internal.SetupPprof()
|
||||
|
|
@ -90,7 +60,7 @@ func main() {
|
|||
}
|
||||
}
|
||||
|
||||
cfg := &config.Dendrite{}
|
||||
var cfg *config.Dendrite
|
||||
|
||||
// use custom config if config flag is set
|
||||
if configFlagSet {
|
||||
|
|
@ -99,89 +69,30 @@ func main() {
|
|||
pk = sk.Public().(ed25519.PublicKey)
|
||||
} else {
|
||||
keyfile := filepath.Join(*instanceDir, *instanceName) + ".pem"
|
||||
if _, err := os.Stat(keyfile); os.IsNotExist(err) {
|
||||
oldkeyfile := *instanceName + ".key"
|
||||
if _, err = os.Stat(oldkeyfile); os.IsNotExist(err) {
|
||||
if err = test.NewMatrixKey(keyfile); err != nil {
|
||||
panic("failed to generate a new PEM key: " + err.Error())
|
||||
}
|
||||
if _, sk, err = config.LoadMatrixKey(keyfile, os.ReadFile); err != nil {
|
||||
panic("failed to load PEM key: " + err.Error())
|
||||
}
|
||||
if len(sk) != ed25519.PrivateKeySize {
|
||||
panic("the private key is not long enough")
|
||||
}
|
||||
} else {
|
||||
if sk, err = os.ReadFile(oldkeyfile); err != nil {
|
||||
panic("failed to read the old private key: " + err.Error())
|
||||
}
|
||||
if len(sk) != ed25519.PrivateKeySize {
|
||||
panic("the private key is not long enough")
|
||||
}
|
||||
if err := test.SaveMatrixKey(keyfile, sk); err != nil {
|
||||
panic("failed to convert the private key to PEM format: " + err.Error())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var err error
|
||||
if _, sk, err = config.LoadMatrixKey(keyfile, os.ReadFile); err != nil {
|
||||
panic("failed to load PEM key: " + err.Error())
|
||||
}
|
||||
if len(sk) != ed25519.PrivateKeySize {
|
||||
panic("the private key is not long enough")
|
||||
}
|
||||
}
|
||||
|
||||
pk = sk.Public().(ed25519.PublicKey)
|
||||
|
||||
cfg.Defaults(config.DefaultOpts{
|
||||
Generate: true,
|
||||
Monolithic: true,
|
||||
})
|
||||
cfg.Global.PrivateKey = sk
|
||||
cfg.Global.JetStream.StoragePath = config.Path(fmt.Sprintf("%s/", filepath.Join(*instanceDir, *instanceName)))
|
||||
cfg.UserAPI.AccountDatabase.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-account.db", filepath.Join(*instanceDir, *instanceName)))
|
||||
cfg.MediaAPI.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-mediaapi.db", filepath.Join(*instanceDir, *instanceName)))
|
||||
cfg.SyncAPI.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-syncapi.db", filepath.Join(*instanceDir, *instanceName)))
|
||||
cfg.RoomServer.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-roomserver.db", filepath.Join(*instanceDir, *instanceName)))
|
||||
cfg.KeyServer.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-keyserver.db", filepath.Join(*instanceDir, *instanceName)))
|
||||
cfg.FederationAPI.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-federationapi.db", filepath.Join(*instanceDir, *instanceName)))
|
||||
cfg.RelayAPI.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-relayapi.db", filepath.Join(*instanceDir, *instanceName)))
|
||||
cfg.MSCs.MSCs = []string{"msc2836", "msc2946"}
|
||||
cfg.MSCs.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-mscs.db", filepath.Join(*instanceDir, *instanceName)))
|
||||
cfg.ClientAPI.RegistrationDisabled = false
|
||||
cfg.ClientAPI.OpenRegistrationWithoutVerificationEnabled = true
|
||||
cfg.MediaAPI.BasePath = config.Path(*instanceDir)
|
||||
cfg.SyncAPI.Fulltext.Enabled = true
|
||||
cfg.SyncAPI.Fulltext.IndexPath = config.Path(*instanceDir)
|
||||
if err := cfg.Derive(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
oldKeyfile := *instanceName + ".key"
|
||||
sk, pk = monolith.GetOrCreateKey(keyfile, oldKeyfile)
|
||||
cfg = monolith.GenerateDefaultConfig(sk, *instanceDir, *instanceDir, *instanceName)
|
||||
}
|
||||
|
||||
cfg.Global.ServerName = gomatrixserverlib.ServerName(hex.EncodeToString(pk))
|
||||
cfg.Global.KeyID = gomatrixserverlib.KeyID(signing.KeyID)
|
||||
|
||||
base := base.NewBaseDendrite(cfg, "Monolith")
|
||||
base.ConfigureAdminEndpoints()
|
||||
defer base.Close() // nolint: errcheck
|
||||
p2pMonolith := monolith.P2PMonolith{}
|
||||
p2pMonolith.SetupPinecone(sk)
|
||||
p2pMonolith.Multicast.Start()
|
||||
|
||||
pineconeEventChannel := make(chan pineconeEvents.Event)
|
||||
pRouter := pineconeRouter.NewRouter(logrus.WithField("pinecone", "router"), sk)
|
||||
pRouter.EnableHopLimiting()
|
||||
pRouter.EnableWakeupBroadcasts()
|
||||
pRouter.Subscribe(pineconeEventChannel)
|
||||
|
||||
pQUIC := pineconeSessions.NewSessions(logrus.WithField("pinecone", "sessions"), pRouter, []string{"matrix"})
|
||||
pMulticast := pineconeMulticast.NewMulticast(logrus.WithField("pinecone", "multicast"), pRouter)
|
||||
pManager := pineconeConnections.NewConnectionManager(pRouter, nil)
|
||||
pMulticast.Start()
|
||||
if instancePeer != nil && *instancePeer != "" {
|
||||
for _, peer := range strings.Split(*instancePeer, ",") {
|
||||
pManager.AddPeer(strings.Trim(peer, " \t\r\n"))
|
||||
p2pMonolith.ConnManager.AddPeer(strings.Trim(peer, " \t\r\n"))
|
||||
}
|
||||
}
|
||||
|
||||
enableMetrics := true
|
||||
enableWebsockets := true
|
||||
p2pMonolith.SetupDendrite(cfg, *instancePort, *instanceRelayingEnabled, enableMetrics, enableWebsockets)
|
||||
p2pMonolith.StartMonolith()
|
||||
p2pMonolith.WaitForShutdown()
|
||||
|
||||
go func() {
|
||||
listener, err := net.Listen("tcp", *instanceListen)
|
||||
if err != nil {
|
||||
|
|
@ -197,7 +108,7 @@ func main() {
|
|||
continue
|
||||
}
|
||||
|
||||
port, err := pRouter.Connect(
|
||||
port, err := p2pMonolith.Router.Connect(
|
||||
conn,
|
||||
pineconeRouter.ConnectionPeerType(pineconeRouter.PeerTypeRemote),
|
||||
)
|
||||
|
|
@ -209,236 +120,4 @@ func main() {
|
|||
fmt.Println("Inbound connection", conn.RemoteAddr(), "is connected to port", port)
|
||||
}
|
||||
}()
|
||||
|
||||
federation := conn.CreateFederationClient(base, pQUIC)
|
||||
|
||||
serverKeyAPI := &signing.YggdrasilKeys{}
|
||||
keyRing := serverKeyAPI.KeyRing()
|
||||
|
||||
rsComponent := roomserver.NewInternalAPI(base)
|
||||
rsAPI := rsComponent
|
||||
fsAPI := federationapi.NewInternalAPI(
|
||||
base, federation, rsAPI, base.Caches, keyRing, true,
|
||||
)
|
||||
|
||||
keyAPI := keyserver.NewInternalAPI(base, &base.Cfg.KeyServer, fsAPI, rsComponent)
|
||||
userAPI := userapi.NewInternalAPI(base, &cfg.UserAPI, nil, keyAPI, rsAPI, base.PushGatewayHTTPClient())
|
||||
keyAPI.SetUserAPI(userAPI)
|
||||
|
||||
asAPI := appservice.NewInternalAPI(base, userAPI, rsAPI)
|
||||
|
||||
rsComponent.SetFederationAPI(fsAPI, keyRing)
|
||||
|
||||
userProvider := users.NewPineconeUserProvider(pRouter, pQUIC, userAPI, federation)
|
||||
roomProvider := rooms.NewPineconeRoomProvider(pRouter, pQUIC, fsAPI, federation)
|
||||
|
||||
js, _ := base.NATS.Prepare(base.ProcessContext, &base.Cfg.Global.JetStream)
|
||||
producer := &producers.SyncAPIProducer{
|
||||
JetStream: js,
|
||||
TopicReceiptEvent: base.Cfg.Global.JetStream.Prefixed(jetstream.OutputReceiptEvent),
|
||||
TopicSendToDeviceEvent: base.Cfg.Global.JetStream.Prefixed(jetstream.OutputSendToDeviceEvent),
|
||||
TopicTypingEvent: base.Cfg.Global.JetStream.Prefixed(jetstream.OutputTypingEvent),
|
||||
TopicPresenceEvent: base.Cfg.Global.JetStream.Prefixed(jetstream.OutputPresenceEvent),
|
||||
TopicDeviceListUpdate: base.Cfg.Global.JetStream.Prefixed(jetstream.InputDeviceListUpdate),
|
||||
TopicSigningKeyUpdate: base.Cfg.Global.JetStream.Prefixed(jetstream.InputSigningKeyUpdate),
|
||||
Config: &base.Cfg.FederationAPI,
|
||||
UserAPI: userAPI,
|
||||
}
|
||||
relayAPI := relayapi.NewRelayInternalAPI(base, federation, rsAPI, keyRing, producer)
|
||||
|
||||
monolith := setup.Monolith{
|
||||
Config: base.Cfg,
|
||||
Client: conn.CreateClient(base, pQUIC),
|
||||
FedClient: federation,
|
||||
KeyRing: keyRing,
|
||||
|
||||
AppserviceAPI: asAPI,
|
||||
FederationAPI: fsAPI,
|
||||
RoomserverAPI: rsAPI,
|
||||
UserAPI: userAPI,
|
||||
KeyAPI: keyAPI,
|
||||
RelayAPI: relayAPI,
|
||||
ExtPublicRoomsProvider: roomProvider,
|
||||
ExtUserDirectoryProvider: userProvider,
|
||||
}
|
||||
monolith.AddAllPublicRoutes(base)
|
||||
|
||||
wsUpgrader := websocket.Upgrader{
|
||||
CheckOrigin: func(_ *http.Request) bool {
|
||||
return true
|
||||
},
|
||||
}
|
||||
httpRouter := mux.NewRouter().SkipClean(true).UseEncodedPath()
|
||||
httpRouter.PathPrefix(httputil.InternalPathPrefix).Handler(base.InternalAPIMux)
|
||||
httpRouter.PathPrefix(httputil.PublicClientPathPrefix).Handler(base.PublicClientAPIMux)
|
||||
httpRouter.PathPrefix(httputil.PublicMediaPathPrefix).Handler(base.PublicMediaAPIMux)
|
||||
httpRouter.PathPrefix(httputil.DendriteAdminPathPrefix).Handler(base.DendriteAdminMux)
|
||||
httpRouter.PathPrefix(httputil.SynapseAdminPathPrefix).Handler(base.SynapseAdminMux)
|
||||
httpRouter.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
|
||||
c, err := wsUpgrader.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
logrus.WithError(err).Error("Failed to upgrade WebSocket connection")
|
||||
return
|
||||
}
|
||||
conn := conn.WrapWebSocketConn(c)
|
||||
if _, err = pRouter.Connect(
|
||||
conn,
|
||||
pineconeRouter.ConnectionZone("websocket"),
|
||||
pineconeRouter.ConnectionPeerType(pineconeRouter.PeerTypeRemote),
|
||||
); err != nil {
|
||||
logrus.WithError(err).Error("Failed to connect WebSocket peer to Pinecone switch")
|
||||
}
|
||||
})
|
||||
httpRouter.HandleFunc("/pinecone", pRouter.ManholeHandler)
|
||||
embed.Embed(httpRouter, *instancePort, "Pinecone Demo")
|
||||
|
||||
pMux := mux.NewRouter().SkipClean(true).UseEncodedPath()
|
||||
pMux.PathPrefix(users.PublicURL).HandlerFunc(userProvider.FederatedUserProfiles)
|
||||
pMux.PathPrefix(httputil.PublicFederationPathPrefix).Handler(base.PublicFederationAPIMux)
|
||||
pMux.PathPrefix(httputil.PublicMediaPathPrefix).Handler(base.PublicMediaAPIMux)
|
||||
|
||||
pHTTP := pQUIC.Protocol("matrix").HTTP()
|
||||
pHTTP.Mux().Handle(users.PublicURL, pMux)
|
||||
pHTTP.Mux().Handle(httputil.PublicFederationPathPrefix, pMux)
|
||||
pHTTP.Mux().Handle(httputil.PublicMediaPathPrefix, pMux)
|
||||
|
||||
// Build both ends of a HTTP multiplex.
|
||||
httpServer := &http.Server{
|
||||
Addr: ":0",
|
||||
TLSNextProto: map[string]func(*http.Server, *tls.Conn, http.Handler){},
|
||||
ReadTimeout: 10 * time.Second,
|
||||
WriteTimeout: 10 * time.Second,
|
||||
IdleTimeout: 60 * time.Second,
|
||||
BaseContext: func(_ net.Listener) context.Context {
|
||||
return context.Background()
|
||||
},
|
||||
Handler: pMux,
|
||||
}
|
||||
|
||||
go func() {
|
||||
pubkey := pRouter.PublicKey()
|
||||
logrus.Info("Listening on ", hex.EncodeToString(pubkey[:]))
|
||||
logrus.Fatal(httpServer.Serve(pQUIC.Protocol("matrix")))
|
||||
}()
|
||||
go func() {
|
||||
httpBindAddr := fmt.Sprintf(":%d", *instancePort)
|
||||
logrus.Info("Listening on ", httpBindAddr)
|
||||
logrus.Fatal(http.ListenAndServe(httpBindAddr, httpRouter))
|
||||
}()
|
||||
|
||||
go func(ch <-chan pineconeEvents.Event) {
|
||||
eLog := logrus.WithField("pinecone", "events")
|
||||
relayServerSyncRunning := atomic.NewBool(false)
|
||||
stopRelayServerSync := make(chan bool)
|
||||
|
||||
m := RelayServerRetriever{
|
||||
Context: context.Background(),
|
||||
ServerName: gomatrixserverlib.ServerName(pRouter.PublicKey().String()),
|
||||
FederationAPI: fsAPI,
|
||||
RelayServersQueried: make(map[gomatrixserverlib.ServerName]bool),
|
||||
RelayAPI: monolith.RelayAPI,
|
||||
}
|
||||
m.InitializeRelayServers(eLog)
|
||||
|
||||
for event := range ch {
|
||||
switch e := event.(type) {
|
||||
case pineconeEvents.PeerAdded:
|
||||
if !relayServerSyncRunning.Load() {
|
||||
go m.syncRelayServers(stopRelayServerSync, *relayServerSyncRunning)
|
||||
}
|
||||
case pineconeEvents.PeerRemoved:
|
||||
if relayServerSyncRunning.Load() && pRouter.TotalPeerCount() == 0 {
|
||||
stopRelayServerSync <- true
|
||||
}
|
||||
case pineconeEvents.BroadcastReceived:
|
||||
// eLog.Info("Broadcast received from: ", e.PeerID)
|
||||
|
||||
req := &api.PerformWakeupServersRequest{
|
||||
ServerNames: []gomatrixserverlib.ServerName{gomatrixserverlib.ServerName(e.PeerID)},
|
||||
}
|
||||
res := &api.PerformWakeupServersResponse{}
|
||||
if err := fsAPI.PerformWakeupServers(base.Context(), req, res); err != nil {
|
||||
eLog.WithError(err).Error("Failed to wakeup destination", e.PeerID)
|
||||
}
|
||||
default:
|
||||
}
|
||||
}
|
||||
}(pineconeEventChannel)
|
||||
|
||||
base.WaitForShutdown()
|
||||
}
|
||||
|
||||
type RelayServerRetriever struct {
|
||||
Context context.Context
|
||||
ServerName gomatrixserverlib.ServerName
|
||||
FederationAPI api.FederationInternalAPI
|
||||
RelayServersQueried map[gomatrixserverlib.ServerName]bool
|
||||
RelayAPI relayServerAPI.RelayInternalAPI
|
||||
}
|
||||
|
||||
func (m *RelayServerRetriever) InitializeRelayServers(eLog *logrus.Entry) {
|
||||
request := api.P2PQueryRelayServersRequest{Server: gomatrixserverlib.ServerName(m.ServerName)}
|
||||
response := api.P2PQueryRelayServersResponse{}
|
||||
err := m.FederationAPI.P2PQueryRelayServers(m.Context, &request, &response)
|
||||
if err != nil {
|
||||
eLog.Warnf("Failed obtaining list of this node's relay servers: %s", err.Error())
|
||||
}
|
||||
for _, server := range response.RelayServers {
|
||||
m.RelayServersQueried[server] = false
|
||||
}
|
||||
|
||||
eLog.Infof("Registered relay servers: %v", response.RelayServers)
|
||||
}
|
||||
|
||||
func (m *RelayServerRetriever) syncRelayServers(stop <-chan bool, running atomic.Bool) {
|
||||
defer running.Store(false)
|
||||
|
||||
t := time.NewTimer(relayServerRetryInterval)
|
||||
for {
|
||||
relayServersToQuery := []gomatrixserverlib.ServerName{}
|
||||
for server, complete := range m.RelayServersQueried {
|
||||
if !complete {
|
||||
relayServersToQuery = append(relayServersToQuery, server)
|
||||
}
|
||||
}
|
||||
if len(relayServersToQuery) == 0 {
|
||||
// All relay servers have been synced.
|
||||
return
|
||||
}
|
||||
m.queryRelayServers(relayServersToQuery)
|
||||
t.Reset(relayServerRetryInterval)
|
||||
|
||||
select {
|
||||
case <-stop:
|
||||
// We have been asked to stop syncing, drain the timer and return.
|
||||
if !t.Stop() {
|
||||
<-t.C
|
||||
}
|
||||
return
|
||||
case <-t.C:
|
||||
// The timer has expired. Continue to the next loop iteration.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *RelayServerRetriever) queryRelayServers(relayServers []gomatrixserverlib.ServerName) {
|
||||
logrus.Info("querying relay servers for any available transactions")
|
||||
for _, server := range relayServers {
|
||||
userID, err := gomatrixserverlib.NewUserID("@user:"+string(m.ServerName), false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = m.RelayAPI.PerformRelayServerSync(context.Background(), *userID, server)
|
||||
if err == nil {
|
||||
m.RelayServersQueried[server] = true
|
||||
// TODO : What happens if your relay receives new messages after this point?
|
||||
// Should you continue to check with them, or should they try and contact you?
|
||||
// They could send a "new_async_events" message your way maybe?
|
||||
// Then you could mark them as needing to be queried again.
|
||||
// What if you miss this message?
|
||||
// Maybe you should try querying them again after a certain period of time as a backup?
|
||||
} else {
|
||||
logrus.Errorf("Failed querying relay server: %s", err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
63
cmd/dendrite-demo-pinecone/monolith/keys.go
Normal file
63
cmd/dendrite-demo-pinecone/monolith/keys.go
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
// Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package monolith
|
||||
|
||||
import (
|
||||
"crypto/ed25519"
|
||||
"os"
|
||||
|
||||
"github.com/matrix-org/dendrite/setup/config"
|
||||
"github.com/matrix-org/dendrite/test"
|
||||
)
|
||||
|
||||
func GetOrCreateKey(keyfile string, oldKeyfile string) (ed25519.PrivateKey, ed25519.PublicKey) {
|
||||
var sk ed25519.PrivateKey
|
||||
var pk ed25519.PublicKey
|
||||
|
||||
if _, err := os.Stat(keyfile); os.IsNotExist(err) {
|
||||
if _, err = os.Stat(oldKeyfile); os.IsNotExist(err) {
|
||||
if err = test.NewMatrixKey(keyfile); err != nil {
|
||||
panic("failed to generate a new PEM key: " + err.Error())
|
||||
}
|
||||
if _, sk, err = config.LoadMatrixKey(keyfile, os.ReadFile); err != nil {
|
||||
panic("failed to load PEM key: " + err.Error())
|
||||
}
|
||||
if len(sk) != ed25519.PrivateKeySize {
|
||||
panic("the private key is not long enough")
|
||||
}
|
||||
} else {
|
||||
if sk, err = os.ReadFile(oldKeyfile); err != nil {
|
||||
panic("failed to read the old private key: " + err.Error())
|
||||
}
|
||||
if len(sk) != ed25519.PrivateKeySize {
|
||||
panic("the private key is not long enough")
|
||||
}
|
||||
if err = test.SaveMatrixKey(keyfile, sk); err != nil {
|
||||
panic("failed to convert the private key to PEM format: " + err.Error())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if _, sk, err = config.LoadMatrixKey(keyfile, os.ReadFile); err != nil {
|
||||
panic("failed to load PEM key: " + err.Error())
|
||||
}
|
||||
if len(sk) != ed25519.PrivateKeySize {
|
||||
panic("the private key is not long enough")
|
||||
}
|
||||
}
|
||||
|
||||
pk = sk.Public().(ed25519.PublicKey)
|
||||
|
||||
return sk, pk
|
||||
}
|
||||
359
cmd/dendrite-demo-pinecone/monolith/monolith.go
Normal file
359
cmd/dendrite-demo-pinecone/monolith/monolith.go
Normal file
|
|
@ -0,0 +1,359 @@
|
|||
// Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package monolith
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ed25519"
|
||||
"crypto/tls"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/matrix-org/dendrite/appservice"
|
||||
"github.com/matrix-org/dendrite/cmd/dendrite-demo-pinecone/conn"
|
||||
"github.com/matrix-org/dendrite/cmd/dendrite-demo-pinecone/embed"
|
||||
"github.com/matrix-org/dendrite/cmd/dendrite-demo-pinecone/relay"
|
||||
"github.com/matrix-org/dendrite/cmd/dendrite-demo-pinecone/rooms"
|
||||
"github.com/matrix-org/dendrite/cmd/dendrite-demo-pinecone/users"
|
||||
"github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/signing"
|
||||
"github.com/matrix-org/dendrite/federationapi"
|
||||
federationAPI "github.com/matrix-org/dendrite/federationapi/api"
|
||||
"github.com/matrix-org/dendrite/federationapi/producers"
|
||||
"github.com/matrix-org/dendrite/internal/httputil"
|
||||
"github.com/matrix-org/dendrite/keyserver"
|
||||
"github.com/matrix-org/dendrite/relayapi"
|
||||
relayAPI "github.com/matrix-org/dendrite/relayapi/api"
|
||||
"github.com/matrix-org/dendrite/roomserver"
|
||||
"github.com/matrix-org/dendrite/setup"
|
||||
"github.com/matrix-org/dendrite/setup/base"
|
||||
"github.com/matrix-org/dendrite/setup/config"
|
||||
"github.com/matrix-org/dendrite/setup/jetstream"
|
||||
"github.com/matrix-org/dendrite/userapi"
|
||||
userAPI "github.com/matrix-org/dendrite/userapi/api"
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
pineconeConnections "github.com/matrix-org/pinecone/connections"
|
||||
pineconeMulticast "github.com/matrix-org/pinecone/multicast"
|
||||
pineconeRouter "github.com/matrix-org/pinecone/router"
|
||||
pineconeEvents "github.com/matrix-org/pinecone/router/events"
|
||||
pineconeSessions "github.com/matrix-org/pinecone/sessions"
|
||||
)
|
||||
|
||||
const SessionProtocol = "matrix"
|
||||
|
||||
type P2PMonolith struct {
|
||||
BaseDendrite *base.BaseDendrite
|
||||
Sessions *pineconeSessions.Sessions
|
||||
Multicast *pineconeMulticast.Multicast
|
||||
ConnManager *pineconeConnections.ConnectionManager
|
||||
Router *pineconeRouter.Router
|
||||
EventChannel chan pineconeEvents.Event
|
||||
RelayRetriever relay.RelayServerRetriever
|
||||
|
||||
dendrite setup.Monolith
|
||||
port int
|
||||
httpMux *mux.Router
|
||||
pineconeMux *mux.Router
|
||||
listener net.Listener
|
||||
httpListenAddr string
|
||||
}
|
||||
|
||||
func GenerateDefaultConfig(sk ed25519.PrivateKey, storageDir string, cacheDir string, dbPrefix string) *config.Dendrite {
|
||||
cfg := config.Dendrite{}
|
||||
cfg.Defaults(config.DefaultOpts{
|
||||
Generate: true,
|
||||
Monolithic: true,
|
||||
})
|
||||
cfg.Global.PrivateKey = sk
|
||||
cfg.Global.JetStream.StoragePath = config.Path(fmt.Sprintf("%s/", filepath.Join(cacheDir, dbPrefix)))
|
||||
cfg.UserAPI.AccountDatabase.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-account.db", filepath.Join(storageDir, dbPrefix)))
|
||||
cfg.MediaAPI.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-mediaapi.db", filepath.Join(storageDir, dbPrefix)))
|
||||
cfg.SyncAPI.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-syncapi.db", filepath.Join(storageDir, dbPrefix)))
|
||||
cfg.RoomServer.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-roomserver.db", filepath.Join(storageDir, dbPrefix)))
|
||||
cfg.KeyServer.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-keyserver.db", filepath.Join(storageDir, dbPrefix)))
|
||||
cfg.FederationAPI.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-federationsender.db", filepath.Join(storageDir, dbPrefix)))
|
||||
cfg.RelayAPI.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-relayapi.db", filepath.Join(storageDir, dbPrefix)))
|
||||
cfg.MSCs.MSCs = []string{"msc2836", "msc2946"}
|
||||
cfg.MSCs.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s-mscs.db", filepath.Join(storageDir, dbPrefix)))
|
||||
cfg.ClientAPI.RegistrationDisabled = false
|
||||
cfg.ClientAPI.OpenRegistrationWithoutVerificationEnabled = true
|
||||
cfg.MediaAPI.BasePath = config.Path(filepath.Join(cacheDir, "media"))
|
||||
cfg.MediaAPI.AbsBasePath = config.Path(filepath.Join(cacheDir, "media"))
|
||||
cfg.SyncAPI.Fulltext.Enabled = true
|
||||
cfg.SyncAPI.Fulltext.IndexPath = config.Path(filepath.Join(cacheDir, "search"))
|
||||
if err := cfg.Derive(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return &cfg
|
||||
}
|
||||
|
||||
func (p *P2PMonolith) SetupPinecone(sk ed25519.PrivateKey) {
|
||||
p.EventChannel = make(chan pineconeEvents.Event)
|
||||
p.Router = pineconeRouter.NewRouter(logrus.WithField("pinecone", "router"), sk)
|
||||
p.Router.EnableHopLimiting()
|
||||
p.Router.EnableWakeupBroadcasts()
|
||||
p.Router.Subscribe(p.EventChannel)
|
||||
|
||||
p.Sessions = pineconeSessions.NewSessions(logrus.WithField("pinecone", "sessions"), p.Router, []string{SessionProtocol})
|
||||
p.Multicast = pineconeMulticast.NewMulticast(logrus.WithField("pinecone", "multicast"), p.Router)
|
||||
p.ConnManager = pineconeConnections.NewConnectionManager(p.Router, nil)
|
||||
}
|
||||
|
||||
func (p *P2PMonolith) SetupDendrite(cfg *config.Dendrite, port int, enableRelaying bool, enableMetrics bool, enableWebsockets bool) {
|
||||
if enableMetrics {
|
||||
p.BaseDendrite = base.NewBaseDendrite(cfg, "Monolith")
|
||||
} else {
|
||||
p.BaseDendrite = base.NewBaseDendrite(cfg, "Monolith", base.DisableMetrics)
|
||||
}
|
||||
p.port = port
|
||||
p.BaseDendrite.ConfigureAdminEndpoints()
|
||||
|
||||
federation := conn.CreateFederationClient(p.BaseDendrite, p.Sessions)
|
||||
|
||||
serverKeyAPI := &signing.YggdrasilKeys{}
|
||||
keyRing := serverKeyAPI.KeyRing()
|
||||
|
||||
rsComponent := roomserver.NewInternalAPI(p.BaseDendrite)
|
||||
rsAPI := rsComponent
|
||||
fsAPI := federationapi.NewInternalAPI(
|
||||
p.BaseDendrite, federation, rsAPI, p.BaseDendrite.Caches, keyRing, true,
|
||||
)
|
||||
|
||||
keyAPI := keyserver.NewInternalAPI(p.BaseDendrite, &p.BaseDendrite.Cfg.KeyServer, fsAPI, rsComponent)
|
||||
userAPI := userapi.NewInternalAPI(p.BaseDendrite, &cfg.UserAPI, nil, keyAPI, rsAPI, p.BaseDendrite.PushGatewayHTTPClient())
|
||||
keyAPI.SetUserAPI(userAPI)
|
||||
|
||||
asAPI := appservice.NewInternalAPI(p.BaseDendrite, userAPI, rsAPI)
|
||||
|
||||
rsComponent.SetFederationAPI(fsAPI, keyRing)
|
||||
|
||||
userProvider := users.NewPineconeUserProvider(p.Router, p.Sessions, userAPI, federation)
|
||||
roomProvider := rooms.NewPineconeRoomProvider(p.Router, p.Sessions, fsAPI, federation)
|
||||
|
||||
js, _ := p.BaseDendrite.NATS.Prepare(p.BaseDendrite.ProcessContext, &p.BaseDendrite.Cfg.Global.JetStream)
|
||||
producer := &producers.SyncAPIProducer{
|
||||
JetStream: js,
|
||||
TopicReceiptEvent: p.BaseDendrite.Cfg.Global.JetStream.Prefixed(jetstream.OutputReceiptEvent),
|
||||
TopicSendToDeviceEvent: p.BaseDendrite.Cfg.Global.JetStream.Prefixed(jetstream.OutputSendToDeviceEvent),
|
||||
TopicTypingEvent: p.BaseDendrite.Cfg.Global.JetStream.Prefixed(jetstream.OutputTypingEvent),
|
||||
TopicPresenceEvent: p.BaseDendrite.Cfg.Global.JetStream.Prefixed(jetstream.OutputPresenceEvent),
|
||||
TopicDeviceListUpdate: p.BaseDendrite.Cfg.Global.JetStream.Prefixed(jetstream.InputDeviceListUpdate),
|
||||
TopicSigningKeyUpdate: p.BaseDendrite.Cfg.Global.JetStream.Prefixed(jetstream.InputSigningKeyUpdate),
|
||||
Config: &p.BaseDendrite.Cfg.FederationAPI,
|
||||
UserAPI: userAPI,
|
||||
}
|
||||
relayAPI := relayapi.NewRelayInternalAPI(p.BaseDendrite, federation, rsAPI, keyRing, producer, enableRelaying)
|
||||
logrus.Infof("Relaying enabled: %v", relayAPI.RelayingEnabled())
|
||||
|
||||
p.dendrite = setup.Monolith{
|
||||
Config: p.BaseDendrite.Cfg,
|
||||
Client: conn.CreateClient(p.BaseDendrite, p.Sessions),
|
||||
FedClient: federation,
|
||||
KeyRing: keyRing,
|
||||
|
||||
AppserviceAPI: asAPI,
|
||||
FederationAPI: fsAPI,
|
||||
RoomserverAPI: rsAPI,
|
||||
UserAPI: userAPI,
|
||||
KeyAPI: keyAPI,
|
||||
RelayAPI: relayAPI,
|
||||
ExtPublicRoomsProvider: roomProvider,
|
||||
ExtUserDirectoryProvider: userProvider,
|
||||
}
|
||||
p.dendrite.AddAllPublicRoutes(p.BaseDendrite)
|
||||
|
||||
p.setupHttpServers(userProvider, enableWebsockets)
|
||||
}
|
||||
|
||||
func (p *P2PMonolith) GetFederationAPI() federationAPI.FederationInternalAPI {
|
||||
return p.dendrite.FederationAPI
|
||||
}
|
||||
|
||||
func (p *P2PMonolith) GetRelayAPI() relayAPI.RelayInternalAPI {
|
||||
return p.dendrite.RelayAPI
|
||||
}
|
||||
|
||||
func (p *P2PMonolith) GetUserAPI() userAPI.UserInternalAPI {
|
||||
return p.dendrite.UserAPI
|
||||
}
|
||||
|
||||
func (p *P2PMonolith) StartMonolith() {
|
||||
p.startHTTPServers()
|
||||
p.startEventHandler()
|
||||
}
|
||||
|
||||
func (p *P2PMonolith) Stop() {
|
||||
_ = p.BaseDendrite.Close()
|
||||
p.WaitForShutdown()
|
||||
}
|
||||
|
||||
func (p *P2PMonolith) WaitForShutdown() {
|
||||
p.BaseDendrite.WaitForShutdown()
|
||||
p.closeAllResources()
|
||||
}
|
||||
|
||||
func (p *P2PMonolith) closeAllResources() {
|
||||
if p.listener != nil {
|
||||
_ = p.listener.Close()
|
||||
}
|
||||
|
||||
if p.Multicast != nil {
|
||||
p.Multicast.Stop()
|
||||
}
|
||||
|
||||
if p.Sessions != nil {
|
||||
_ = p.Sessions.Close()
|
||||
}
|
||||
|
||||
if p.Router != nil {
|
||||
_ = p.Router.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func (p *P2PMonolith) Addr() string {
|
||||
return p.httpListenAddr
|
||||
}
|
||||
|
||||
func (p *P2PMonolith) setupHttpServers(userProvider *users.PineconeUserProvider, enableWebsockets bool) {
|
||||
p.httpMux = mux.NewRouter().SkipClean(true).UseEncodedPath()
|
||||
p.httpMux.PathPrefix(httputil.InternalPathPrefix).Handler(p.BaseDendrite.InternalAPIMux)
|
||||
p.httpMux.PathPrefix(httputil.PublicClientPathPrefix).Handler(p.BaseDendrite.PublicClientAPIMux)
|
||||
p.httpMux.PathPrefix(httputil.PublicMediaPathPrefix).Handler(p.BaseDendrite.PublicMediaAPIMux)
|
||||
p.httpMux.PathPrefix(httputil.DendriteAdminPathPrefix).Handler(p.BaseDendrite.DendriteAdminMux)
|
||||
p.httpMux.PathPrefix(httputil.SynapseAdminPathPrefix).Handler(p.BaseDendrite.SynapseAdminMux)
|
||||
|
||||
if enableWebsockets {
|
||||
wsUpgrader := websocket.Upgrader{
|
||||
CheckOrigin: func(_ *http.Request) bool {
|
||||
return true
|
||||
},
|
||||
}
|
||||
p.httpMux.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
|
||||
c, err := wsUpgrader.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
logrus.WithError(err).Error("Failed to upgrade WebSocket connection")
|
||||
return
|
||||
}
|
||||
conn := conn.WrapWebSocketConn(c)
|
||||
if _, err = p.Router.Connect(
|
||||
conn,
|
||||
pineconeRouter.ConnectionZone("websocket"),
|
||||
pineconeRouter.ConnectionPeerType(pineconeRouter.PeerTypeRemote),
|
||||
); err != nil {
|
||||
logrus.WithError(err).Error("Failed to connect WebSocket peer to Pinecone switch")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
p.httpMux.HandleFunc("/pinecone", p.Router.ManholeHandler)
|
||||
|
||||
if enableWebsockets {
|
||||
embed.Embed(p.httpMux, p.port, "Pinecone Demo")
|
||||
}
|
||||
|
||||
p.pineconeMux = mux.NewRouter().SkipClean(true).UseEncodedPath()
|
||||
p.pineconeMux.PathPrefix(users.PublicURL).HandlerFunc(userProvider.FederatedUserProfiles)
|
||||
p.pineconeMux.PathPrefix(httputil.PublicFederationPathPrefix).Handler(p.BaseDendrite.PublicFederationAPIMux)
|
||||
p.pineconeMux.PathPrefix(httputil.PublicMediaPathPrefix).Handler(p.BaseDendrite.PublicMediaAPIMux)
|
||||
|
||||
pHTTP := p.Sessions.Protocol(SessionProtocol).HTTP()
|
||||
pHTTP.Mux().Handle(users.PublicURL, p.pineconeMux)
|
||||
pHTTP.Mux().Handle(httputil.PublicFederationPathPrefix, p.pineconeMux)
|
||||
pHTTP.Mux().Handle(httputil.PublicMediaPathPrefix, p.pineconeMux)
|
||||
}
|
||||
|
||||
func (p *P2PMonolith) startHTTPServers() {
|
||||
go func() {
|
||||
// Build both ends of a HTTP multiplex.
|
||||
httpServer := &http.Server{
|
||||
Addr: ":0",
|
||||
TLSNextProto: map[string]func(*http.Server, *tls.Conn, http.Handler){},
|
||||
ReadTimeout: 10 * time.Second,
|
||||
WriteTimeout: 10 * time.Second,
|
||||
IdleTimeout: 30 * time.Second,
|
||||
BaseContext: func(_ net.Listener) context.Context {
|
||||
return context.Background()
|
||||
},
|
||||
Handler: p.pineconeMux,
|
||||
}
|
||||
|
||||
pubkey := p.Router.PublicKey()
|
||||
pubkeyString := hex.EncodeToString(pubkey[:])
|
||||
logrus.Info("Listening on ", pubkeyString)
|
||||
|
||||
switch httpServer.Serve(p.Sessions.Protocol(SessionProtocol)) {
|
||||
case net.ErrClosed, http.ErrServerClosed:
|
||||
logrus.Info("Stopped listening on ", pubkeyString)
|
||||
default:
|
||||
logrus.Error("Stopped listening on ", pubkeyString)
|
||||
}
|
||||
}()
|
||||
|
||||
p.httpListenAddr = fmt.Sprintf(":%d", p.port)
|
||||
go func() {
|
||||
logrus.Info("Listening on ", p.httpListenAddr)
|
||||
switch http.ListenAndServe(p.httpListenAddr, p.httpMux) {
|
||||
case net.ErrClosed, http.ErrServerClosed:
|
||||
logrus.Info("Stopped listening on ", p.httpListenAddr)
|
||||
default:
|
||||
logrus.Error("Stopped listening on ", p.httpListenAddr)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (p *P2PMonolith) startEventHandler() {
|
||||
stopRelayServerSync := make(chan bool)
|
||||
eLog := logrus.WithField("pinecone", "events")
|
||||
p.RelayRetriever = relay.NewRelayServerRetriever(
|
||||
context.Background(),
|
||||
gomatrixserverlib.ServerName(p.Router.PublicKey().String()),
|
||||
p.dendrite.FederationAPI,
|
||||
p.dendrite.RelayAPI,
|
||||
stopRelayServerSync,
|
||||
)
|
||||
p.RelayRetriever.InitializeRelayServers(eLog)
|
||||
|
||||
go func(ch <-chan pineconeEvents.Event) {
|
||||
for event := range ch {
|
||||
switch e := event.(type) {
|
||||
case pineconeEvents.PeerAdded:
|
||||
p.RelayRetriever.StartSync()
|
||||
case pineconeEvents.PeerRemoved:
|
||||
if p.RelayRetriever.IsRunning() && p.Router.TotalPeerCount() == 0 {
|
||||
stopRelayServerSync <- true
|
||||
}
|
||||
case pineconeEvents.BroadcastReceived:
|
||||
// eLog.Info("Broadcast received from: ", e.PeerID)
|
||||
|
||||
req := &federationAPI.PerformWakeupServersRequest{
|
||||
ServerNames: []gomatrixserverlib.ServerName{gomatrixserverlib.ServerName(e.PeerID)},
|
||||
}
|
||||
res := &federationAPI.PerformWakeupServersResponse{}
|
||||
if err := p.dendrite.FederationAPI.PerformWakeupServers(p.BaseDendrite.Context(), req, res); err != nil {
|
||||
eLog.WithError(err).Error("Failed to wakeup destination", e.PeerID)
|
||||
}
|
||||
default:
|
||||
}
|
||||
}
|
||||
}(p.EventChannel)
|
||||
}
|
||||
237
cmd/dendrite-demo-pinecone/relay/retriever.go
Normal file
237
cmd/dendrite-demo-pinecone/relay/retriever.go
Normal file
|
|
@ -0,0 +1,237 @@
|
|||
// Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package relay
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
federationAPI "github.com/matrix-org/dendrite/federationapi/api"
|
||||
relayServerAPI "github.com/matrix-org/dendrite/relayapi/api"
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
"github.com/sirupsen/logrus"
|
||||
"go.uber.org/atomic"
|
||||
)
|
||||
|
||||
const (
|
||||
relayServerRetryInterval = time.Second * 30
|
||||
)
|
||||
|
||||
type RelayServerRetriever struct {
|
||||
ctx context.Context
|
||||
serverName gomatrixserverlib.ServerName
|
||||
federationAPI federationAPI.FederationInternalAPI
|
||||
relayAPI relayServerAPI.RelayInternalAPI
|
||||
relayServersQueried map[gomatrixserverlib.ServerName]bool
|
||||
queriedServersMutex sync.Mutex
|
||||
running atomic.Bool
|
||||
quit <-chan bool
|
||||
}
|
||||
|
||||
func NewRelayServerRetriever(
|
||||
ctx context.Context,
|
||||
serverName gomatrixserverlib.ServerName,
|
||||
federationAPI federationAPI.FederationInternalAPI,
|
||||
relayAPI relayServerAPI.RelayInternalAPI,
|
||||
quit <-chan bool,
|
||||
) RelayServerRetriever {
|
||||
return RelayServerRetriever{
|
||||
ctx: ctx,
|
||||
serverName: serverName,
|
||||
federationAPI: federationAPI,
|
||||
relayAPI: relayAPI,
|
||||
relayServersQueried: make(map[gomatrixserverlib.ServerName]bool),
|
||||
running: *atomic.NewBool(false),
|
||||
quit: quit,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *RelayServerRetriever) InitializeRelayServers(eLog *logrus.Entry) {
|
||||
request := federationAPI.P2PQueryRelayServersRequest{Server: gomatrixserverlib.ServerName(r.serverName)}
|
||||
response := federationAPI.P2PQueryRelayServersResponse{}
|
||||
err := r.federationAPI.P2PQueryRelayServers(r.ctx, &request, &response)
|
||||
if err != nil {
|
||||
eLog.Warnf("Failed obtaining list of this node's relay servers: %s", err.Error())
|
||||
}
|
||||
|
||||
r.queriedServersMutex.Lock()
|
||||
defer r.queriedServersMutex.Unlock()
|
||||
for _, server := range response.RelayServers {
|
||||
r.relayServersQueried[server] = false
|
||||
}
|
||||
|
||||
eLog.Infof("Registered relay servers: %v", response.RelayServers)
|
||||
}
|
||||
|
||||
func (r *RelayServerRetriever) SetRelayServers(servers []gomatrixserverlib.ServerName) {
|
||||
UpdateNodeRelayServers(r.serverName, servers, r.ctx, r.federationAPI)
|
||||
|
||||
// Replace list of servers to sync with and mark them all as unsynced.
|
||||
r.queriedServersMutex.Lock()
|
||||
defer r.queriedServersMutex.Unlock()
|
||||
r.relayServersQueried = make(map[gomatrixserverlib.ServerName]bool)
|
||||
for _, server := range servers {
|
||||
r.relayServersQueried[server] = false
|
||||
}
|
||||
|
||||
r.StartSync()
|
||||
}
|
||||
|
||||
func (r *RelayServerRetriever) GetRelayServers() []gomatrixserverlib.ServerName {
|
||||
r.queriedServersMutex.Lock()
|
||||
defer r.queriedServersMutex.Unlock()
|
||||
relayServers := []gomatrixserverlib.ServerName{}
|
||||
for server := range r.relayServersQueried {
|
||||
relayServers = append(relayServers, server)
|
||||
}
|
||||
|
||||
return relayServers
|
||||
}
|
||||
|
||||
func (r *RelayServerRetriever) GetQueriedServerStatus() map[gomatrixserverlib.ServerName]bool {
|
||||
r.queriedServersMutex.Lock()
|
||||
defer r.queriedServersMutex.Unlock()
|
||||
|
||||
result := map[gomatrixserverlib.ServerName]bool{}
|
||||
for server, queried := range r.relayServersQueried {
|
||||
result[server] = queried
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (r *RelayServerRetriever) StartSync() {
|
||||
if !r.running.Load() {
|
||||
logrus.Info("Starting relay server sync")
|
||||
go r.SyncRelayServers(r.quit)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *RelayServerRetriever) IsRunning() bool {
|
||||
return r.running.Load()
|
||||
}
|
||||
|
||||
func (r *RelayServerRetriever) SyncRelayServers(stop <-chan bool) {
|
||||
defer r.running.Store(false)
|
||||
|
||||
t := time.NewTimer(relayServerRetryInterval)
|
||||
for {
|
||||
relayServersToQuery := []gomatrixserverlib.ServerName{}
|
||||
func() {
|
||||
r.queriedServersMutex.Lock()
|
||||
defer r.queriedServersMutex.Unlock()
|
||||
for server, complete := range r.relayServersQueried {
|
||||
if !complete {
|
||||
relayServersToQuery = append(relayServersToQuery, server)
|
||||
}
|
||||
}
|
||||
}()
|
||||
if len(relayServersToQuery) == 0 {
|
||||
// All relay servers have been synced.
|
||||
logrus.Info("Finished syncing with all known relays")
|
||||
return
|
||||
}
|
||||
r.queryRelayServers(relayServersToQuery)
|
||||
t.Reset(relayServerRetryInterval)
|
||||
|
||||
select {
|
||||
case <-stop:
|
||||
if !t.Stop() {
|
||||
<-t.C
|
||||
}
|
||||
return
|
||||
case <-t.C:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *RelayServerRetriever) queryRelayServers(relayServers []gomatrixserverlib.ServerName) {
|
||||
logrus.Info("Querying relay servers for any available transactions")
|
||||
for _, server := range relayServers {
|
||||
userID, err := gomatrixserverlib.NewUserID("@user:"+string(r.serverName), false)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
logrus.Infof("Syncing with relay: %s", string(server))
|
||||
err = r.relayAPI.PerformRelayServerSync(context.Background(), *userID, server)
|
||||
if err == nil {
|
||||
func() {
|
||||
r.queriedServersMutex.Lock()
|
||||
defer r.queriedServersMutex.Unlock()
|
||||
r.relayServersQueried[server] = true
|
||||
}()
|
||||
// TODO : What happens if your relay receives new messages after this point?
|
||||
// Should you continue to check with them, or should they try and contact you?
|
||||
// They could send a "new_async_events" message your way maybe?
|
||||
// Then you could mark them as needing to be queried again.
|
||||
// What if you miss this message?
|
||||
// Maybe you should try querying them again after a certain period of time as a backup?
|
||||
} else {
|
||||
logrus.Errorf("Failed querying relay server: %s", err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func UpdateNodeRelayServers(
|
||||
node gomatrixserverlib.ServerName,
|
||||
relays []gomatrixserverlib.ServerName,
|
||||
ctx context.Context,
|
||||
fedAPI federationAPI.FederationInternalAPI,
|
||||
) {
|
||||
// Get the current relay list
|
||||
request := federationAPI.P2PQueryRelayServersRequest{Server: node}
|
||||
response := federationAPI.P2PQueryRelayServersResponse{}
|
||||
err := fedAPI.P2PQueryRelayServers(ctx, &request, &response)
|
||||
if err != nil {
|
||||
logrus.Warnf("Failed obtaining list of relay servers for %s: %s", node, err.Error())
|
||||
}
|
||||
|
||||
// Remove old, non-matching relays
|
||||
var serversToRemove []gomatrixserverlib.ServerName
|
||||
for _, existingServer := range response.RelayServers {
|
||||
shouldRemove := true
|
||||
for _, newServer := range relays {
|
||||
if newServer == existingServer {
|
||||
shouldRemove = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if shouldRemove {
|
||||
serversToRemove = append(serversToRemove, existingServer)
|
||||
}
|
||||
}
|
||||
removeRequest := federationAPI.P2PRemoveRelayServersRequest{
|
||||
Server: node,
|
||||
RelayServers: serversToRemove,
|
||||
}
|
||||
removeResponse := federationAPI.P2PRemoveRelayServersResponse{}
|
||||
err = fedAPI.P2PRemoveRelayServers(ctx, &removeRequest, &removeResponse)
|
||||
if err != nil {
|
||||
logrus.Warnf("Failed removing old relay servers for %s: %s", node, err.Error())
|
||||
}
|
||||
|
||||
// Add new relays
|
||||
addRequest := federationAPI.P2PAddRelayServersRequest{
|
||||
Server: node,
|
||||
RelayServers: relays,
|
||||
}
|
||||
addResponse := federationAPI.P2PAddRelayServersResponse{}
|
||||
err = fedAPI.P2PAddRelayServers(ctx, &addRequest, &addResponse)
|
||||
if err != nil {
|
||||
logrus.Warnf("Failed adding relay servers for %s: %s", node, err.Error())
|
||||
}
|
||||
}
|
||||
99
cmd/dendrite-demo-pinecone/relay/retriever_test.go
Normal file
99
cmd/dendrite-demo-pinecone/relay/retriever_test.go
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
// Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package relay
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
federationAPI "github.com/matrix-org/dendrite/federationapi/api"
|
||||
relayServerAPI "github.com/matrix-org/dendrite/relayapi/api"
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gotest.tools/v3/poll"
|
||||
)
|
||||
|
||||
var testRelayServers = []gomatrixserverlib.ServerName{"relay1", "relay2"}
|
||||
|
||||
type FakeFedAPI struct {
|
||||
federationAPI.FederationInternalAPI
|
||||
}
|
||||
|
||||
func (f *FakeFedAPI) P2PQueryRelayServers(
|
||||
ctx context.Context,
|
||||
req *federationAPI.P2PQueryRelayServersRequest,
|
||||
res *federationAPI.P2PQueryRelayServersResponse,
|
||||
) error {
|
||||
res.RelayServers = testRelayServers
|
||||
return nil
|
||||
}
|
||||
|
||||
type FakeRelayAPI struct {
|
||||
relayServerAPI.RelayInternalAPI
|
||||
}
|
||||
|
||||
func (r *FakeRelayAPI) PerformRelayServerSync(
|
||||
ctx context.Context,
|
||||
userID gomatrixserverlib.UserID,
|
||||
relayServer gomatrixserverlib.ServerName,
|
||||
) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestRelayRetrieverInitialization(t *testing.T) {
|
||||
retriever := NewRelayServerRetriever(
|
||||
context.Background(),
|
||||
"server",
|
||||
&FakeFedAPI{},
|
||||
&FakeRelayAPI{},
|
||||
make(<-chan bool),
|
||||
)
|
||||
|
||||
retriever.InitializeRelayServers(logrus.WithField("test", "relay"))
|
||||
relayServers := retriever.GetQueriedServerStatus()
|
||||
assert.Equal(t, 2, len(relayServers))
|
||||
}
|
||||
|
||||
func TestRelayRetrieverSync(t *testing.T) {
|
||||
retriever := NewRelayServerRetriever(
|
||||
context.Background(),
|
||||
"server",
|
||||
&FakeFedAPI{},
|
||||
&FakeRelayAPI{},
|
||||
make(<-chan bool),
|
||||
)
|
||||
|
||||
retriever.InitializeRelayServers(logrus.WithField("test", "relay"))
|
||||
relayServers := retriever.GetQueriedServerStatus()
|
||||
assert.Equal(t, 2, len(relayServers))
|
||||
|
||||
stopRelayServerSync := make(chan bool)
|
||||
go retriever.SyncRelayServers(stopRelayServerSync)
|
||||
|
||||
check := func(log poll.LogT) poll.Result {
|
||||
relayServers := retriever.GetQueriedServerStatus()
|
||||
for _, queried := range relayServers {
|
||||
if !queried {
|
||||
return poll.Continue("waiting for all servers to be queried")
|
||||
}
|
||||
}
|
||||
|
||||
stopRelayServerSync <- true
|
||||
return poll.Success()
|
||||
}
|
||||
poll.WaitOn(t, check, poll.WithTimeout(5*time.Second), poll.WithDelay(100*time.Millisecond))
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
activesupport (6.0.5)
|
||||
activesupport (6.0.6.1)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 0.7, < 2)
|
||||
minitest (~> 5.1)
|
||||
|
|
@ -15,7 +15,7 @@ GEM
|
|||
coffee-script-source (1.11.1)
|
||||
colorator (1.1.0)
|
||||
commonmarker (0.23.7)
|
||||
concurrent-ruby (1.1.10)
|
||||
concurrent-ruby (1.2.0)
|
||||
dnsruby (1.61.9)
|
||||
simpleidn (~> 0.1)
|
||||
em-websocket (0.5.3)
|
||||
|
|
@ -229,7 +229,7 @@ GEM
|
|||
jekyll (>= 3.5, < 5.0)
|
||||
jekyll-feed (~> 0.9)
|
||||
jekyll-seo-tag (~> 2.1)
|
||||
minitest (5.15.0)
|
||||
minitest (5.17.0)
|
||||
multipart-post (2.1.1)
|
||||
nokogiri (1.13.10-arm64-darwin)
|
||||
racc (~> 1.4)
|
||||
|
|
@ -265,13 +265,13 @@ GEM
|
|||
thread_safe (0.3.6)
|
||||
typhoeus (1.4.0)
|
||||
ethon (>= 0.9.0)
|
||||
tzinfo (1.2.10)
|
||||
tzinfo (1.2.11)
|
||||
thread_safe (~> 0.1)
|
||||
unf (0.1.4)
|
||||
unf_ext
|
||||
unf_ext (0.0.8.1)
|
||||
unicode-display_width (1.8.0)
|
||||
zeitwerk (2.5.4)
|
||||
zeitwerk (2.6.6)
|
||||
|
||||
PLATFORMS
|
||||
arm64-darwin-21
|
||||
|
|
|
|||
|
|
@ -72,12 +72,26 @@ type RoomserverFederationAPI interface {
|
|||
}
|
||||
|
||||
type P2PFederationAPI interface {
|
||||
// Relay Server sync api used in the pinecone demos.
|
||||
// Get the relay servers associated for the given server.
|
||||
P2PQueryRelayServers(
|
||||
ctx context.Context,
|
||||
request *P2PQueryRelayServersRequest,
|
||||
response *P2PQueryRelayServersResponse,
|
||||
) error
|
||||
|
||||
// Add relay server associations to the given server.
|
||||
P2PAddRelayServers(
|
||||
ctx context.Context,
|
||||
request *P2PAddRelayServersRequest,
|
||||
response *P2PAddRelayServersResponse,
|
||||
) error
|
||||
|
||||
// Remove relay server associations from the given server.
|
||||
P2PRemoveRelayServers(
|
||||
ctx context.Context,
|
||||
request *P2PRemoveRelayServersRequest,
|
||||
response *P2PRemoveRelayServersResponse,
|
||||
) error
|
||||
}
|
||||
|
||||
// KeyserverFederationAPI is a subset of gomatrixserverlib.FederationClient functions which the keyserver
|
||||
|
|
@ -256,3 +270,19 @@ type P2PQueryRelayServersRequest struct {
|
|||
type P2PQueryRelayServersResponse struct {
|
||||
RelayServers []gomatrixserverlib.ServerName
|
||||
}
|
||||
|
||||
type P2PAddRelayServersRequest struct {
|
||||
Server gomatrixserverlib.ServerName
|
||||
RelayServers []gomatrixserverlib.ServerName
|
||||
}
|
||||
|
||||
type P2PAddRelayServersResponse struct {
|
||||
}
|
||||
|
||||
type P2PRemoveRelayServersRequest struct {
|
||||
Server gomatrixserverlib.ServerName
|
||||
RelayServers []gomatrixserverlib.ServerName
|
||||
}
|
||||
|
||||
type P2PRemoveRelayServersResponse struct {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -840,6 +840,36 @@ func (r *FederationInternalAPI) P2PQueryRelayServers(
|
|||
return nil
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
func (r *FederationInternalAPI) shouldAttemptDirectFederation(
|
||||
destination gomatrixserverlib.ServerName,
|
||||
) bool {
|
||||
|
|
|
|||
|
|
@ -123,6 +123,47 @@ func TestQueryRelayServers(t *testing.T) {
|
|||
assert.Equal(t, len(relayServers), len(res.RelayServers))
|
||||
}
|
||||
|
||||
func TestRemoveRelayServers(t *testing.T) {
|
||||
testDB := test.NewInMemoryFederationDatabase()
|
||||
|
||||
server := gomatrixserverlib.ServerName("wakeup")
|
||||
relayServers := []gomatrixserverlib.ServerName{"relay1", "relay2"}
|
||||
err := testDB.P2PAddRelayServersForServer(context.Background(), server, relayServers)
|
||||
assert.NoError(t, err)
|
||||
|
||||
cfg := config.FederationAPI{
|
||||
Matrix: &config.Global{
|
||||
SigningIdentity: gomatrixserverlib.SigningIdentity{
|
||||
ServerName: "relay",
|
||||
},
|
||||
},
|
||||
}
|
||||
fedClient := &testFedClient{}
|
||||
stats := statistics.NewStatistics(testDB, FailuresUntilBlacklist, FailuresUntilAssumedOffline)
|
||||
queues := queue.NewOutgoingQueues(
|
||||
testDB, process.NewProcessContext(),
|
||||
false,
|
||||
cfg.Matrix.ServerName, fedClient, nil, &stats,
|
||||
nil,
|
||||
)
|
||||
fedAPI := NewFederationInternalAPI(
|
||||
testDB, &cfg, nil, fedClient, &stats, nil, queues, nil,
|
||||
)
|
||||
|
||||
req := api.P2PRemoveRelayServersRequest{
|
||||
Server: server,
|
||||
RelayServers: []gomatrixserverlib.ServerName{"relay1"},
|
||||
}
|
||||
res := api.P2PRemoveRelayServersResponse{}
|
||||
err = fedAPI.P2PRemoveRelayServers(context.Background(), &req, &res)
|
||||
assert.NoError(t, err)
|
||||
|
||||
finalRelays, err := testDB.P2PGetRelayServersForServer(context.Background(), server)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, len(finalRelays))
|
||||
assert.Equal(t, gomatrixserverlib.ServerName("relay2"), finalRelays[0])
|
||||
}
|
||||
|
||||
func TestPerformDirectoryLookup(t *testing.T) {
|
||||
testDB := test.NewInMemoryFederationDatabase()
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ const (
|
|||
FederationAPIPerformBroadcastEDUPath = "/federationapi/performBroadcastEDU"
|
||||
FederationAPIPerformWakeupServers = "/federationapi/performWakeupServers"
|
||||
FederationAPIQueryRelayServers = "/federationapi/queryRelayServers"
|
||||
FederationAPIAddRelayServers = "/federationapi/addRelayServers"
|
||||
FederationAPIRemoveRelayServers = "/federationapi/removeRelayServers"
|
||||
|
||||
FederationAPIGetUserDevicesPath = "/federationapi/client/getUserDevices"
|
||||
FederationAPIClaimKeysPath = "/federationapi/client/claimKeys"
|
||||
|
|
@ -522,3 +524,25 @@ func (h *httpFederationInternalAPI) P2PQueryRelayServers(
|
|||
h.httpClient, ctx, request, response,
|
||||
)
|
||||
}
|
||||
|
||||
func (h *httpFederationInternalAPI) P2PAddRelayServers(
|
||||
ctx context.Context,
|
||||
request *api.P2PAddRelayServersRequest,
|
||||
response *api.P2PAddRelayServersResponse,
|
||||
) error {
|
||||
return httputil.CallInternalRPCAPI(
|
||||
"AddRelayServers", h.federationAPIURL+FederationAPIAddRelayServers,
|
||||
h.httpClient, ctx, request, response,
|
||||
)
|
||||
}
|
||||
|
||||
func (h *httpFederationInternalAPI) P2PRemoveRelayServers(
|
||||
ctx context.Context,
|
||||
request *api.P2PRemoveRelayServersRequest,
|
||||
response *api.P2PRemoveRelayServersResponse,
|
||||
) error {
|
||||
return httputil.CallInternalRPCAPI(
|
||||
"RemoveRelayServers", h.federationAPIURL+FederationAPIRemoveRelayServers,
|
||||
h.httpClient, ctx, request, response,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -410,34 +410,49 @@ func (oq *destinationQueue) nextTransaction(
|
|||
defer cancel()
|
||||
|
||||
relayServers := oq.statistics.KnownRelayServers()
|
||||
if oq.statistics.AssumedOffline() && len(relayServers) > 0 {
|
||||
sendMethod = statistics.SendViaRelay
|
||||
relaySuccess := false
|
||||
logrus.Infof("Sending to relay servers: %v", relayServers)
|
||||
// TODO : how to pass through actual userID here?!?!?!?!
|
||||
userID, userErr := gomatrixserverlib.NewUserID("@user:"+string(oq.destination), false)
|
||||
if userErr != nil {
|
||||
return userErr, sendMethod
|
||||
}
|
||||
|
||||
// Attempt sending to each known relay server.
|
||||
for _, relayServer := range relayServers {
|
||||
_, relayErr := oq.client.P2PSendTransactionToRelay(ctx, *userID, t, relayServer)
|
||||
if relayErr != nil {
|
||||
err = relayErr
|
||||
} else {
|
||||
// If sending to one of the relay servers succeeds, consider the send successful.
|
||||
relaySuccess = true
|
||||
}
|
||||
}
|
||||
|
||||
// Clear the error if sending to any of the relay servers succeeded.
|
||||
if relaySuccess {
|
||||
err = nil
|
||||
}
|
||||
} else {
|
||||
hasRelayServers := len(relayServers) > 0
|
||||
shouldSendToRelays := oq.statistics.AssumedOffline() && hasRelayServers
|
||||
if !shouldSendToRelays {
|
||||
sendMethod = statistics.SendDirect
|
||||
_, err = oq.client.SendTransaction(ctx, t)
|
||||
} else {
|
||||
// Try sending directly to the destination first in case they came back online.
|
||||
sendMethod = statistics.SendDirect
|
||||
_, err = oq.client.SendTransaction(ctx, t)
|
||||
if err != nil {
|
||||
// The destination is still offline, try sending to relays.
|
||||
sendMethod = statistics.SendViaRelay
|
||||
relaySuccess := false
|
||||
logrus.Infof("Sending %q to relay servers: %v", t.TransactionID, relayServers)
|
||||
// TODO : how to pass through actual userID here?!?!?!?!
|
||||
userID, userErr := gomatrixserverlib.NewUserID("@user:"+string(oq.destination), false)
|
||||
if userErr != nil {
|
||||
return userErr, sendMethod
|
||||
}
|
||||
|
||||
// Attempt sending to each known relay server.
|
||||
for _, relayServer := range relayServers {
|
||||
_, relayErr := oq.client.P2PSendTransactionToRelay(ctx, *userID, t, relayServer)
|
||||
if relayErr != nil {
|
||||
err = relayErr
|
||||
} else {
|
||||
// If sending to one of the relay servers succeeds, consider the send successful.
|
||||
relaySuccess = true
|
||||
|
||||
// TODO : what about if the dest comes back online but can't see their relay?
|
||||
// How do I sync with the dest in that case?
|
||||
// Should change the database to have a "relay success" flag on events and if
|
||||
// I see the node back online, maybe directly send through the backlog of events
|
||||
// with "relay success"... could lead to duplicate events, but only those that
|
||||
// I sent. And will lead to a much more consistent experience.
|
||||
}
|
||||
}
|
||||
|
||||
// Clear the error if sending to any of the relay servers succeeded.
|
||||
if relaySuccess {
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
switch errResponse := err.(type) {
|
||||
case nil:
|
||||
|
|
|
|||
|
|
@ -923,7 +923,7 @@ func TestSendPDUOnRelaySuccessRemovedFromDB(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
|
||||
check := func(log poll.LogT) poll.Result {
|
||||
if fc.txCount.Load() == 1 {
|
||||
if fc.txCount.Load() >= 1 {
|
||||
if fc.txRelayCount.Load() == 1 {
|
||||
data, dbErr := db.GetPendingPDUs(pc.Context(), destination, 100)
|
||||
assert.NoError(t, dbErr)
|
||||
|
|
@ -962,7 +962,7 @@ func TestSendEDUOnRelaySuccessRemovedFromDB(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
|
||||
check := func(log poll.LogT) poll.Result {
|
||||
if fc.txCount.Load() == 1 {
|
||||
if fc.txCount.Load() >= 1 {
|
||||
if fc.txRelayCount.Load() == 1 {
|
||||
data, dbErr := db.GetPendingEDUs(pc.Context(), destination, 100)
|
||||
assert.NoError(t, dbErr)
|
||||
|
|
|
|||
|
|
@ -164,6 +164,8 @@ func (s *ServerStatistics) Success(method SendMethod) {
|
|||
logrus.WithError(err).Errorf("Failed to remove %q from blacklist", s.serverName)
|
||||
}
|
||||
}
|
||||
|
||||
s.removeAssumedOffline()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
30
go.mod
30
go.mod
|
|
@ -6,7 +6,7 @@ require (
|
|||
github.com/DATA-DOG/go-sqlmock v1.5.0
|
||||
github.com/MFAshby/stdemuxerhook v1.0.0
|
||||
github.com/Masterminds/semver/v3 v3.1.1
|
||||
github.com/blevesearch/bleve/v2 v2.3.4
|
||||
github.com/blevesearch/bleve/v2 v2.3.6
|
||||
github.com/codeclysm/extract v2.2.0+incompatible
|
||||
github.com/dgraph-io/ristretto v0.1.1
|
||||
github.com/docker/docker v20.10.19+incompatible
|
||||
|
|
@ -22,7 +22,7 @@ require (
|
|||
github.com/matrix-org/dugong v0.0.0-20210921133753-66e6b1c67e2e
|
||||
github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91
|
||||
github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530
|
||||
github.com/matrix-org/gomatrixserverlib v0.0.0-20230119205614-cb888d80b00f
|
||||
github.com/matrix-org/gomatrixserverlib v0.0.0-20230131183213-122f1e0e3fa1
|
||||
github.com/matrix-org/pinecone v0.11.1-0.20230111184901-61850f0e63cb
|
||||
github.com/matrix-org/util v0.0.0-20221111132719-399730281e66
|
||||
github.com/mattn/go-sqlite3 v1.14.15
|
||||
|
|
@ -58,24 +58,24 @@ require (
|
|||
require (
|
||||
github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect
|
||||
github.com/Microsoft/go-winio v0.5.2 // indirect
|
||||
github.com/RoaringBitmap/roaring v1.2.1 // indirect
|
||||
github.com/RoaringBitmap/roaring v1.2.3 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.3.3 // indirect
|
||||
github.com/blevesearch/bleve_index_api v1.0.3 // indirect
|
||||
github.com/blevesearch/geo v0.1.14 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.5.0 // indirect
|
||||
github.com/blevesearch/bleve_index_api v1.0.5 // indirect
|
||||
github.com/blevesearch/geo v0.1.17 // indirect
|
||||
github.com/blevesearch/go-porterstemmer v1.0.3 // indirect
|
||||
github.com/blevesearch/gtreap v0.1.1 // indirect
|
||||
github.com/blevesearch/mmap-go v1.0.4 // indirect
|
||||
github.com/blevesearch/scorch_segment_api/v2 v2.1.2 // indirect
|
||||
github.com/blevesearch/segment v0.9.0 // indirect
|
||||
github.com/blevesearch/scorch_segment_api/v2 v2.1.4 // indirect
|
||||
github.com/blevesearch/segment v0.9.1 // indirect
|
||||
github.com/blevesearch/snowballstem v0.9.0 // indirect
|
||||
github.com/blevesearch/upsidedown_store_api v1.0.1 // indirect
|
||||
github.com/blevesearch/vellum v1.0.8 // indirect
|
||||
github.com/blevesearch/zapx/v11 v11.3.5 // indirect
|
||||
github.com/blevesearch/zapx/v12 v12.3.5 // indirect
|
||||
github.com/blevesearch/zapx/v13 v13.3.5 // indirect
|
||||
github.com/blevesearch/zapx/v14 v14.3.5 // indirect
|
||||
github.com/blevesearch/zapx/v15 v15.3.5 // indirect
|
||||
github.com/blevesearch/upsidedown_store_api v1.0.2 // indirect
|
||||
github.com/blevesearch/vellum v1.0.9 // indirect
|
||||
github.com/blevesearch/zapx/v11 v11.3.7 // indirect
|
||||
github.com/blevesearch/zapx/v12 v12.3.7 // indirect
|
||||
github.com/blevesearch/zapx/v13 v13.3.7 // indirect
|
||||
github.com/blevesearch/zapx/v14 v14.3.7 // indirect
|
||||
github.com/blevesearch/zapx/v15 v15.3.8 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/docker/distribution v2.8.1+incompatible // indirect
|
||||
|
|
|
|||
104
go.sum
104
go.sum
|
|
@ -50,9 +50,8 @@ github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0
|
|||
github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA=
|
||||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||
github.com/RoaringBitmap/roaring v0.4.7/go.mod h1:8khRDP4HmeXns4xIj9oGrKSz7XTQiJx2zgh7AcNke4w=
|
||||
github.com/RoaringBitmap/roaring v0.9.4/go.mod h1:icnadbWcNyfEHlYdr+tDlOTih1Bf/h+rzPpv4sbomAA=
|
||||
github.com/RoaringBitmap/roaring v1.2.1 h1:58/LJlg/81wfEHd5L9qsHduznOIhyv4qb1yWcSvVq9A=
|
||||
github.com/RoaringBitmap/roaring v1.2.1/go.mod h1:icnadbWcNyfEHlYdr+tDlOTih1Bf/h+rzPpv4sbomAA=
|
||||
github.com/RoaringBitmap/roaring v1.2.3 h1:yqreLINqIrX22ErkKI0vY47/ivtJr6n+kMhVOVmhWBY=
|
||||
github.com/RoaringBitmap/roaring v1.2.3/go.mod h1:plvDsJQpxOC5bw8LRteu/MLWHsHez/3y6cubLI4/1yE=
|
||||
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
|
|
@ -70,51 +69,45 @@ github.com/anacrolix/missinggo v1.2.1 h1:0IE3TqX5y5D0IxeMwTyIgqdDew4QrzcXaaEnJQy
|
|||
github.com/anacrolix/missinggo v1.2.1/go.mod h1:J5cMhif8jPmFoC3+Uvob3OXXNIhOUikzMt+uUjeM21Y=
|
||||
github.com/anacrolix/missinggo/perf v1.0.0/go.mod h1:ljAFWkBuzkO12MQclXzZrosP5urunoLS0Cbvb4V0uMQ=
|
||||
github.com/anacrolix/tagflag v0.0.0-20180109131632-2146c8d41bf0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
|
||||
github.com/bits-and-blooms/bitset v1.3.3 h1:R1XWiopGiXf66xygsiLpzLo67xEYvMkHw3w+rCOSAwg=
|
||||
github.com/bits-and-blooms/bitset v1.3.3/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
|
||||
github.com/blevesearch/bleve/v2 v2.3.4 h1:SSb7/cwGzo85LWX1jchIsXM8ZiNNMX3shT5lROM63ew=
|
||||
github.com/blevesearch/bleve/v2 v2.3.4/go.mod h1:Ot0zYum8XQRfPcwhae8bZmNyYubynsoMjVvl1jPqL30=
|
||||
github.com/blevesearch/bleve_index_api v1.0.3 h1:DDSWaPXOZZJ2BB73ZTWjKxydAugjwywcqU+91AAqcAg=
|
||||
github.com/blevesearch/bleve_index_api v1.0.3/go.mod h1:fiwKS0xLEm+gBRgv5mumf0dhgFr2mDgZah1pqv1c1M4=
|
||||
github.com/blevesearch/geo v0.1.13/go.mod h1:cRIvqCdk3cgMhGeHNNe6yPzb+w56otxbfo1FBJfR2Pc=
|
||||
github.com/blevesearch/geo v0.1.14 h1:TTDpJN6l9ck/cUYbXSn4aCElNls0Whe44rcQKsB7EfU=
|
||||
github.com/blevesearch/geo v0.1.14/go.mod h1:cRIvqCdk3cgMhGeHNNe6yPzb+w56otxbfo1FBJfR2Pc=
|
||||
github.com/blevesearch/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:9eJDeqxJ3E7WnLebQUlPD7ZjSce7AnDb9vjGmMCbD0A=
|
||||
github.com/bits-and-blooms/bitset v1.5.0 h1:NpE8frKRLGHIcEzkR+gZhiioW1+WbYV6fKwD6ZIpQT8=
|
||||
github.com/bits-and-blooms/bitset v1.5.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
|
||||
github.com/blevesearch/bleve/v2 v2.3.6 h1:NlntUHcV5CSWIhpugx4d/BRMGCiaoI8ZZXrXlahzNq4=
|
||||
github.com/blevesearch/bleve/v2 v2.3.6/go.mod h1:JM2legf1cKVkdV8Ehu7msKIOKC0McSw0Q16Fmv9vsW4=
|
||||
github.com/blevesearch/bleve_index_api v1.0.5 h1:Lc986kpC4Z0/n1g3gg8ul7H+lxgOQPcXb9SxvQGu+tw=
|
||||
github.com/blevesearch/bleve_index_api v1.0.5/go.mod h1:YXMDwaXFFXwncRS8UobWs7nvo0DmusriM1nztTlj1ms=
|
||||
github.com/blevesearch/geo v0.1.17 h1:AguzI6/5mHXapzB0gE9IKWo+wWPHZmXZoscHcjFgAFA=
|
||||
github.com/blevesearch/geo v0.1.17/go.mod h1:uRMGWG0HJYfWfFJpK3zTdnnr1K+ksZTuWKhXeSokfnM=
|
||||
github.com/blevesearch/go-porterstemmer v1.0.3 h1:GtmsqID0aZdCSNiY8SkuPJ12pD4jI+DdXTAn4YRcHCo=
|
||||
github.com/blevesearch/go-porterstemmer v1.0.3/go.mod h1:angGc5Ht+k2xhJdZi511LtmxuEf0OVpvUUNrwmM1P7M=
|
||||
github.com/blevesearch/goleveldb v1.0.1/go.mod h1:WrU8ltZbIp0wAoig/MHbrPCXSOLpe79nz5lv5nqfYrQ=
|
||||
github.com/blevesearch/gtreap v0.1.1 h1:2JWigFrzDMR+42WGIN/V2p0cUvn4UP3C4Q5nmaZGW8Y=
|
||||
github.com/blevesearch/gtreap v0.1.1/go.mod h1:QaQyDRAT51sotthUWAH4Sj08awFSSWzgYICSZ3w0tYk=
|
||||
github.com/blevesearch/mmap-go v1.0.2/go.mod h1:ol2qBqYaOUsGdm7aRMRrYGgPvnwLe6Y+7LMvAB5IbSA=
|
||||
github.com/blevesearch/mmap-go v1.0.4 h1:OVhDhT5B/M1HNPpYPBKIEJaD0F3Si+CrEKULGCDPWmc=
|
||||
github.com/blevesearch/mmap-go v1.0.4/go.mod h1:EWmEAOmdAS9z/pi/+Toxu99DnsbhG1TIxUoRmJw/pSs=
|
||||
github.com/blevesearch/scorch_segment_api/v2 v2.1.2 h1:TAte9VZLWda5WAVlZTTZ+GCzEHqGJb4iB2aiZSA6Iv8=
|
||||
github.com/blevesearch/scorch_segment_api/v2 v2.1.2/go.mod h1:rvoQXZGq8drq7vXbNeyiRzdEOwZkjkiYGf1822i6CRA=
|
||||
github.com/blevesearch/segment v0.9.0 h1:5lG7yBCx98or7gK2cHMKPukPZ/31Kag7nONpoBt22Ac=
|
||||
github.com/blevesearch/segment v0.9.0/go.mod h1:9PfHYUdQCgHktBgvtUOF4x+pc4/l8rdH0u5spnW85UQ=
|
||||
github.com/blevesearch/snowball v0.6.1/go.mod h1:ZF0IBg5vgpeoUhnMza2v0A/z8m1cWPlwhke08LpNusg=
|
||||
github.com/blevesearch/scorch_segment_api/v2 v2.1.4 h1:LmGmo5twU3gV+natJbKmOktS9eMhokPGKWuR+jX84vk=
|
||||
github.com/blevesearch/scorch_segment_api/v2 v2.1.4/go.mod h1:PgVnbbg/t1UkgezPDu8EHLi1BHQ17xUwsFdU6NnOYS0=
|
||||
github.com/blevesearch/segment v0.9.1 h1:+dThDy+Lvgj5JMxhmOVlgFfkUtZV2kw49xax4+jTfSU=
|
||||
github.com/blevesearch/segment v0.9.1/go.mod h1:zN21iLm7+GnBHWTao9I+Au/7MBiL8pPFtJBJTsk6kQw=
|
||||
github.com/blevesearch/snowballstem v0.9.0 h1:lMQ189YspGP6sXvZQ4WZ+MLawfV8wOmPoD/iWeNXm8s=
|
||||
github.com/blevesearch/snowballstem v0.9.0/go.mod h1:PivSj3JMc8WuaFkTSRDW2SlrulNWPl4ABg1tC/hlgLs=
|
||||
github.com/blevesearch/upsidedown_store_api v1.0.1 h1:1SYRwyoFLwG3sj0ed89RLtM15amfX2pXlYbFOnF8zNU=
|
||||
github.com/blevesearch/upsidedown_store_api v1.0.1/go.mod h1:MQDVGpHZrpe3Uy26zJBf/a8h0FZY6xJbthIMm8myH2Q=
|
||||
github.com/blevesearch/vellum v1.0.8 h1:iMGh4lfxza4BnWO/UJTMPlI3HsK9YawjPv+TteVa9ck=
|
||||
github.com/blevesearch/vellum v1.0.8/go.mod h1:+cpRi/tqq49xUYSQN2P7A5zNSNrS+MscLeeaZ3J46UA=
|
||||
github.com/blevesearch/zapx/v11 v11.3.5 h1:eBQWQ7huA+mzm0sAGnZDwgGGli7S45EO+N+ObFWssbI=
|
||||
github.com/blevesearch/zapx/v11 v11.3.5/go.mod h1:5UdIa/HRMdeRCiLQOyFESsnqBGiip7vQmYReA9toevU=
|
||||
github.com/blevesearch/zapx/v12 v12.3.5 h1:5pX2hU+R1aZihT7ac1dNWh1n4wqkIM9pZzWp0ANED9s=
|
||||
github.com/blevesearch/zapx/v12 v12.3.5/go.mod h1:ANcthYRZQycpbRut/6ArF5gP5HxQyJqiFcuJCBju/ss=
|
||||
github.com/blevesearch/zapx/v13 v13.3.5 h1:eJ3gbD+Nu8p36/O6lhfdvWQ4pxsGYSuTOBrLLPVWJ74=
|
||||
github.com/blevesearch/zapx/v13 v13.3.5/go.mod h1:FV+dRnScFgKnRDIp08RQL4JhVXt1x2HE3AOzqYa6fjo=
|
||||
github.com/blevesearch/zapx/v14 v14.3.5 h1:hEvVjZaagFCvOUJrlFQ6/Z6Jjy0opM3g7TMEo58TwP4=
|
||||
github.com/blevesearch/zapx/v14 v14.3.5/go.mod h1:954A/eKFb+pg/ncIYWLWCKY+mIjReM9FGTGIO2Wu1cU=
|
||||
github.com/blevesearch/zapx/v15 v15.3.5 h1:NVD0qq8vRk66ImJn1KloXT5ckqPDUZT7VbVJs9jKlac=
|
||||
github.com/blevesearch/zapx/v15 v15.3.5/go.mod h1:QMUh2hXCaYIWFKPYGavq/Iga2zbHWZ9DZAa9uFbWyvg=
|
||||
github.com/blevesearch/upsidedown_store_api v1.0.2 h1:U53Q6YoWEARVLd1OYNc9kvhBMGZzVrdmaozG2MfoB+A=
|
||||
github.com/blevesearch/upsidedown_store_api v1.0.2/go.mod h1:M01mh3Gpfy56Ps/UXHjEO/knbqyQ1Oamg8If49gRwrQ=
|
||||
github.com/blevesearch/vellum v1.0.9 h1:PL+NWVk3dDGPCV0hoDu9XLLJgqU4E5s/dOeEJByQ2uQ=
|
||||
github.com/blevesearch/vellum v1.0.9/go.mod h1:ul1oT0FhSMDIExNjIxHqJoGpVrBpKCdgDQNxfqgJt7k=
|
||||
github.com/blevesearch/zapx/v11 v11.3.7 h1:Y6yIAF/DVPiqZUA/jNgSLXmqewfzwHzuwfKyfdG+Xaw=
|
||||
github.com/blevesearch/zapx/v11 v11.3.7/go.mod h1:Xk9Z69AoAWIOvWudNDMlxJDqSYGf90LS0EfnaAIvXCA=
|
||||
github.com/blevesearch/zapx/v12 v12.3.7 h1:DfQ6rsmZfEK4PzzJJRXjiM6AObG02+HWvprlXQ1Y7eI=
|
||||
github.com/blevesearch/zapx/v12 v12.3.7/go.mod h1:SgEtYIBGvM0mgIBn2/tQE/5SdrPXaJUaT/kVqpAPxm0=
|
||||
github.com/blevesearch/zapx/v13 v13.3.7 h1:igIQg5eKmjw168I7av0Vtwedf7kHnQro/M+ubM4d2l8=
|
||||
github.com/blevesearch/zapx/v13 v13.3.7/go.mod h1:yyrB4kJ0OT75UPZwT/zS+Ru0/jYKorCOOSY5dBzAy+s=
|
||||
github.com/blevesearch/zapx/v14 v14.3.7 h1:gfe+fbWslDWP/evHLtp/GOvmNM3sw1BbqD7LhycBX20=
|
||||
github.com/blevesearch/zapx/v14 v14.3.7/go.mod h1:9J/RbOkqZ1KSjmkOes03AkETX7hrXT0sFMpWH4ewC4w=
|
||||
github.com/blevesearch/zapx/v15 v15.3.8 h1:q4uMngBHzL1IIhRc8AJUEkj6dGOE3u1l3phLu7hq8uk=
|
||||
github.com/blevesearch/zapx/v15 v15.3.8/go.mod h1:m7Y6m8soYUvS7MjN9eKlz1xrLCcmqfFadmu7GhWIrLY=
|
||||
github.com/bradfitz/iter v0.0.0-20140124041915-454541ec3da2/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo=
|
||||
github.com/bradfitz/iter v0.0.0-20190303215204-33e6a9893b0c/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo=
|
||||
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 h1:GKTyiRCL6zVf5wWaqKnf+7Qs6GbEPfd4iMOitWzXJx8=
|
||||
|
|
@ -130,12 +123,6 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
|
|||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/codeclysm/extract v2.2.0+incompatible h1:q3wyckoA30bhUSiwdQezMqVhwd8+WGE64/GL//LtUhI=
|
||||
github.com/codeclysm/extract v2.2.0+incompatible/go.mod h1:2nhFMPHiU9At61hz+12bfrlpXSUrOnK+wR+KlGO4Uks=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/couchbase/ghistogram v0.1.0/go.mod h1:s1Jhy76zqfEecpNWJfWUiKZookAFaiGOEoyzgHt9i7k=
|
||||
github.com/couchbase/moss v0.2.0/go.mod h1:9MaHIaRuy9pvLPUJxB8sh8OrLfyDczECVL37grCIubs=
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
|
|
@ -164,7 +151,6 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
|
|||
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||
github.com/frankban/quicktest v1.0.0/go.mod h1:R98jIehRai+d1/3Hv2//jOVCTJhW1VBavT6B6CuGq2k=
|
||||
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/getsentry/sentry-go v0.14.0 h1:rlOBkuFZRKKdUnKO+0U3JclRDQKlRu5vVQtkWSQvC70=
|
||||
github.com/getsentry/sentry-go v0.14.0/go.mod h1:RZPJKSw+adu8PBNygiri/A98FqVr2HtRckJk9XVxJ9I=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
|
|
@ -241,7 +227,6 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS
|
|||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/gologme/log v1.3.0 h1:l781G4dE+pbigClDSDzSaaYKtiueHCILUa/qSDsmHAo=
|
||||
|
|
@ -261,7 +246,6 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
|
|
@ -289,15 +273,11 @@ github.com/h2non/filetype v1.1.3/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy
|
|||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/huandu/xstrings v1.0.0 h1:pO2K/gKgKaat5LdpAhxhluX2GPQMaI3W5FUz/I/UnWk=
|
||||
github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||
github.com/json-iterator/go v0.0.0-20171115153421-f7279a603ede/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
|
|
@ -337,7 +317,6 @@ github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw=
|
|||
github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lucas-clemente/quic-go v0.30.0 h1:nwLW0h8ahVQ5EPTIM7uhl/stHqQDea15oRlYKZmw2O0=
|
||||
github.com/lucas-clemente/quic-go v0.30.0/go.mod h1:ssOrRsOmdxa768Wr78vnh2B8JozgLsMzG/g+0qEC7uk=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.3 h1:R4H2Ks8P6pAtUagjFty2p7BVHn3XiwDAl7TTQf5h7TI=
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.3/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4=
|
||||
github.com/marten-seemann/qtls-go1-19 v0.1.1 h1:mnbxeq3oEyQxQXwI4ReCgW9DPoPR94sNlqWoDZnjRIE=
|
||||
|
|
@ -348,8 +327,8 @@ github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91 h1:s7fexw
|
|||
github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91/go.mod h1:e+cg2q7C7yE5QnAXgzo512tgFh1RbQLC0+jozuegKgo=
|
||||
github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530 h1:kHKxCOLcHH8r4Fzarl4+Y3K5hjothkVW5z7T1dUM11U=
|
||||
github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530/go.mod h1:/gBX06Kw0exX1HrwmoBibFA98yBk/jxKpGVeyQbff+s=
|
||||
github.com/matrix-org/gomatrixserverlib v0.0.0-20230119205614-cb888d80b00f h1:niRWEVkeeekpjxwnMhKn8PD0PUloDsNXP8W+Ez/co/M=
|
||||
github.com/matrix-org/gomatrixserverlib v0.0.0-20230119205614-cb888d80b00f/go.mod h1:Mtifyr8q8htcBeugvlDnkBcNUy5LO8OzUoplAf1+mb4=
|
||||
github.com/matrix-org/gomatrixserverlib v0.0.0-20230131183213-122f1e0e3fa1 h1:JSw0nmjMrgBmoM2aQsa78LTpI5BnuD9+vOiEQ4Qo0qw=
|
||||
github.com/matrix-org/gomatrixserverlib v0.0.0-20230131183213-122f1e0e3fa1/go.mod h1:Mtifyr8q8htcBeugvlDnkBcNUy5LO8OzUoplAf1+mb4=
|
||||
github.com/matrix-org/pinecone v0.11.1-0.20230111184901-61850f0e63cb h1:2L+ltfNKab56FoBBqAvbBLjoAbxwwoZie+B8d+Mp3JI=
|
||||
github.com/matrix-org/pinecone v0.11.1-0.20230111184901-61850f0e63cb/go.mod h1:F3GHppRuHCTDeoOmmgjZMeJdbql91+RSGGsATWfC7oc=
|
||||
github.com/matrix-org/util v0.0.0-20221111132719-399730281e66 h1:6z4KxomXSIGWqhHcfzExgkH3Z3UkIXry4ibJS4Aqz2Y=
|
||||
|
|
@ -365,8 +344,6 @@ github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182aff
|
|||
github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
|
||||
github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g=
|
||||
github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae h1:O4SWKdcHVCvYqyDV+9CJA1fcDN2L11Bule0iFy3YlAI=
|
||||
github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
|
|
@ -400,11 +377,8 @@ github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S
|
|||
github.com/ngrok/sqlmw v0.0.0-20220520173518-97c9c04efc79 h1:Dmx8g2747UTVPzSkmohk84S3g/uWqd6+f4SSLPhLcfA=
|
||||
github.com/ngrok/sqlmw v0.0.0-20220520173518-97c9c04efc79/go.mod h1:E26fwEtRNigBfFfHDWsklmo0T7Ixbg0XXgck+Hq4O9k=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo/v2 v2.3.0 h1:kUMoxMoQG3ogk/QWyKh3zibV7BKZ+xBpWil1cTylVqc=
|
||||
github.com/onsi/ginkgo/v2 v2.3.0/go.mod h1:Eew0uilEqZmIEZr8JrvYlvOM7Rr6xzTmMV8AyFNU9d0=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.22.1 h1:pY8O4lBfsHKZHM/6nrxkhVPUznOlIu3quZcKP/M20KI=
|
||||
github.com/onsi/gomega v1.22.1/go.mod h1:x6n7VNe4hw0vkyYUM4mjIXx3JbLiPaBPNgB7PRQ1tuM=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
|
|
@ -415,8 +389,6 @@ github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+
|
|||
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg=
|
||||
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
||||
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
|
||||
|
|
@ -458,7 +430,6 @@ github.com/remyoudompheng/bigfft v0.0.0-20220927061507-ef77025ab5aa/go.mod h1:qq
|
|||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5PCi+MFsC7HjREoAz1BU+Mq60+05gifQSsHSDG/8=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
|
|
@ -468,12 +439,7 @@ github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0
|
|||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
|
|
@ -506,11 +472,9 @@ github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVK
|
|||
github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
|
||||
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
|
||||
github.com/willf/bitset v1.1.9/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
github.com/yggdrasil-network/yggdrasil-go v0.4.6 h1:GALUDV9QPz/5FVkbazpkTc9EABHufA556JwUJZr41j4=
|
||||
github.com/yggdrasil-network/yggdrasil-go v0.4.6/go.mod h1:PBMoAOvQjA9geNEeGyMXA9QgCS6Bu+9V+1VkWM84wpw=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
|
|
@ -519,7 +483,6 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
|||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
|
||||
go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
|
||||
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
|
|
@ -531,7 +494,6 @@ go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
|
|||
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||
golang.org/x/crypto v0.0.0-20180723164146-c126467f60eb/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
|
|
@ -588,7 +550,6 @@ golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I=
|
|||
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
|
@ -645,10 +606,7 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181221143128-b4a75ba826a6/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
|
@ -861,13 +819,11 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8
|
|||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/h2non/bimg.v1 v1.1.9 h1:wZIUbeOnwr37Ta4aofhIv8OI8v4ujpjXC9mXnAGpQjM=
|
||||
gopkg.in/h2non/bimg.v1 v1.1.9/go.mod h1:PgsZL7dLwUbsGm1NYps320GxGgvQNTnecMCZqxV11So=
|
||||
gopkg.in/h2non/gock.v1 v1.1.2 h1:jBbHXgGBK/AoPVfJh5x4r/WxIrElvbLel8TCZkkZJoY=
|
||||
gopkg.in/macaroon.v2 v2.1.0 h1:HZcsjBCzq9t0eBPMKqTN/uSN6JOm78ZJ2INbqcBQOUI=
|
||||
gopkg.in/macaroon.v2 v2.1.0/go.mod h1:OUb+TQP/OP0WOerC2Jp/3CwhIKyIa9kQjuc7H24e6/o=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ const (
|
|||
PublicFederationPathPrefix = "/_matrix/federation/"
|
||||
PublicKeyPathPrefix = "/_matrix/key/"
|
||||
PublicMediaPathPrefix = "/_matrix/media/"
|
||||
PublicStaticPath = "/_matrix/static/"
|
||||
PublicWellKnownPrefix = "/.well-known/matrix/"
|
||||
InternalPathPrefix = "/api/"
|
||||
DendriteAdminPathPrefix = "/_dendrite/"
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ Transactions include a list of PDUs, (which contain, among other things, lists o
|
|||
There is no additional information sent along with the transaction other than what is typically added to them during Matrix federation today.
|
||||
In the future this will probably need to change in order to handle more complex room state resolution during p2p usage.
|
||||
|
||||
### Relay Server Architecture
|
||||
### Design
|
||||
|
||||
```
|
||||
0 +--------------------+
|
||||
|
|
@ -57,3 +57,78 @@ But in order to achieve this, you are either relying on p2p presence broadcasts
|
|||
#### Recipient-Side Relay Servers
|
||||
|
||||
If we have agreed to some static relay server before going off and doing other things, or if we are talking about more global p2p federation, then having a recipient designated relay server can cut down on redundant traffic since it will sit there idle until the recipient pulls events from it.
|
||||
|
||||
### API
|
||||
|
||||
Relay servers make use of 2 new matrix federation endpoints.
|
||||
These are:
|
||||
- PUT /_matrix/federation/v1/send_relay/{txnID}/{userID}
|
||||
- GET /_matrix/federation/v1/relay_txn/{userID}
|
||||
|
||||
#### Send_Relay
|
||||
|
||||
The `send_relay` endpoint is used to send events to a relay server that are destined for some other node. Servers can send events to this endpoint if they wish for the relay server to store & forward events for them when they go offline.
|
||||
|
||||
##### Request
|
||||
|
||||
###### Request Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|--------|--------|-----------------------------------------------------|
|
||||
| txnID | string | **Required:** The transaction ID. |
|
||||
| userID | string | **Required:** The destination for this transaciton. |
|
||||
|
||||
###### Request Body
|
||||
|
||||
| Name | Type | Description |
|
||||
|--------|--------|----------------------------------------|
|
||||
| pdus | [PDU] | **Required:** List of pdus. Max 50. |
|
||||
| edus | [EDU] | List of edus. May be omitted. Max 100. |
|
||||
|
||||
##### Responses
|
||||
|
||||
| Code | Reason |
|
||||
|--------|--------------------------------------------------|
|
||||
| 200 | Successfully stored transaction for forwarding. |
|
||||
| 400 | Invalid userID. |
|
||||
| 400 | Invalid request body. |
|
||||
| 400 | Too many pdus or edus. |
|
||||
| 500 | Server failed processing transaction. |
|
||||
|
||||
#### Relay_Txn
|
||||
|
||||
The `relay_txn` endpoint is used to get events from a relay server that are destined for you. Servers can send events to this endpoint if they wish for the relay server to store & forward events for them when they go offline.
|
||||
|
||||
##### Request
|
||||
|
||||
**This needs to be changed to prevent nodes from obtaining transactions not destined for them. Possibly by adding a signature field to the request.**
|
||||
|
||||
###### Request Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
|--------|--------|----------------------------------------------------------------|
|
||||
| userID | string | **Required:** The user ID that events are being requested for. |
|
||||
|
||||
###### Request Body
|
||||
|
||||
| Name | Type | Description |
|
||||
|----------|--------|----------------------------------------|
|
||||
| entry_id | int64 | **Required:** The id of the previous transaction received from the relay. Provided in the previous response to this endpoint. |
|
||||
|
||||
##### Responses
|
||||
|
||||
| Code | Reason |
|
||||
|--------|--------------------------------------------------|
|
||||
| 200 | Successfully stored transaction for forwarding. |
|
||||
| 400 | Invalid userID. |
|
||||
| 400 | Invalid request body. |
|
||||
| 400 | Invalid previous entry. Must be >= 0 |
|
||||
| 500 | Server failed processing transaction. |
|
||||
|
||||
###### 200 Response Body
|
||||
|
||||
| Name | Type | Description |
|
||||
|----------------|--------------|--------------------------------------------------------------------------|
|
||||
| transaction | Transaction | **Required:** A matrix transaction. |
|
||||
| entry_id | int64 | An ID associated with this transaction. |
|
||||
| entries_queued | bool | **Required:** Whether or not there are more events stored for this user. |
|
||||
|
|
@ -30,6 +30,12 @@ type RelayInternalAPI interface {
|
|||
userID gomatrixserverlib.UserID,
|
||||
relayServer gomatrixserverlib.ServerName,
|
||||
) error
|
||||
|
||||
// Tells the relayapi whether or not it should act as a relay server for external servers.
|
||||
SetRelayingEnabled(bool)
|
||||
|
||||
// Obtain whether the relayapi is currently configured to act as a relay server for external servers.
|
||||
RelayingEnabled() bool
|
||||
}
|
||||
|
||||
// RelayServerAPI exposes the store & query transaction functionality of a relay server.
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@
|
|||
package internal
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
fedAPI "github.com/matrix-org/dendrite/federationapi/api"
|
||||
"github.com/matrix-org/dendrite/federationapi/producers"
|
||||
"github.com/matrix-org/dendrite/relayapi/storage"
|
||||
|
|
@ -30,6 +32,8 @@ type RelayInternalAPI struct {
|
|||
producer *producers.SyncAPIProducer
|
||||
presenceEnabledInbound bool
|
||||
serverName gomatrixserverlib.ServerName
|
||||
relayingEnabledMutex sync.Mutex
|
||||
relayingEnabled bool
|
||||
}
|
||||
|
||||
func NewRelayInternalAPI(
|
||||
|
|
@ -40,6 +44,7 @@ func NewRelayInternalAPI(
|
|||
producer *producers.SyncAPIProducer,
|
||||
presenceEnabledInbound bool,
|
||||
serverName gomatrixserverlib.ServerName,
|
||||
relayingEnabled bool,
|
||||
) *RelayInternalAPI {
|
||||
return &RelayInternalAPI{
|
||||
db: db,
|
||||
|
|
@ -49,5 +54,6 @@ func NewRelayInternalAPI(
|
|||
producer: producer,
|
||||
presenceEnabledInbound: presenceEnabledInbound,
|
||||
serverName: serverName,
|
||||
relayingEnabled: relayingEnabled,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,20 @@ import (
|
|||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// SetRelayingEnabled implements api.RelayInternalAPI
|
||||
func (r *RelayInternalAPI) SetRelayingEnabled(enabled bool) {
|
||||
r.relayingEnabledMutex.Lock()
|
||||
defer r.relayingEnabledMutex.Unlock()
|
||||
r.relayingEnabled = enabled
|
||||
}
|
||||
|
||||
// RelayingEnabled implements api.RelayInternalAPI
|
||||
func (r *RelayInternalAPI) RelayingEnabled() bool {
|
||||
r.relayingEnabledMutex.Lock()
|
||||
defer r.relayingEnabledMutex.Unlock()
|
||||
return r.relayingEnabled
|
||||
}
|
||||
|
||||
// PerformRelayServerSync implements api.RelayInternalAPI
|
||||
func (r *RelayInternalAPI) PerformRelayServerSync(
|
||||
ctx context.Context,
|
||||
|
|
@ -38,7 +52,7 @@ func (r *RelayInternalAPI) PerformRelayServerSync(
|
|||
logrus.Errorf("P2PGetTransactionFromRelay: %s", err.Error())
|
||||
return err
|
||||
}
|
||||
r.processTransaction(&asyncResponse.Txn)
|
||||
r.processTransaction(&asyncResponse.Transaction)
|
||||
|
||||
prevEntry = gomatrixserverlib.RelayEntry{EntryID: asyncResponse.EntryID}
|
||||
for asyncResponse.EntriesQueued {
|
||||
|
|
@ -50,7 +64,7 @@ func (r *RelayInternalAPI) PerformRelayServerSync(
|
|||
logrus.Errorf("P2PGetTransactionFromRelay: %s", err.Error())
|
||||
return err
|
||||
}
|
||||
r.processTransaction(&asyncResponse.Txn)
|
||||
r.processTransaction(&asyncResponse.Transaction)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -46,8 +46,8 @@ func (f *testFedClient) P2PGetTransactionFromRelay(
|
|||
}
|
||||
|
||||
res = gomatrixserverlib.RespGetRelayTransaction{
|
||||
Txn: gomatrixserverlib.Transaction{},
|
||||
EntryID: 0,
|
||||
Transaction: gomatrixserverlib.Transaction{},
|
||||
EntryID: 0,
|
||||
}
|
||||
if f.queueDepth > 0 {
|
||||
res.EntriesQueued = true
|
||||
|
|
@ -72,7 +72,7 @@ func TestPerformRelayServerSync(t *testing.T) {
|
|||
|
||||
fedClient := &testFedClient{}
|
||||
relayAPI := NewRelayInternalAPI(
|
||||
&db, fedClient, nil, nil, nil, false, "",
|
||||
&db, fedClient, nil, nil, nil, false, "", true,
|
||||
)
|
||||
|
||||
err = relayAPI.PerformRelayServerSync(context.Background(), *userID, gomatrixserverlib.ServerName("relay"))
|
||||
|
|
@ -92,7 +92,7 @@ func TestPerformRelayServerSyncFedError(t *testing.T) {
|
|||
|
||||
fedClient := &testFedClient{shouldFail: true}
|
||||
relayAPI := NewRelayInternalAPI(
|
||||
&db, fedClient, nil, nil, nil, false, "",
|
||||
&db, fedClient, nil, nil, nil, false, "", true,
|
||||
)
|
||||
|
||||
err = relayAPI.PerformRelayServerSync(context.Background(), *userID, gomatrixserverlib.ServerName("relay"))
|
||||
|
|
@ -112,7 +112,7 @@ func TestPerformRelayServerSyncRunsUntilQueueEmpty(t *testing.T) {
|
|||
|
||||
fedClient := &testFedClient{queueDepth: 2}
|
||||
relayAPI := NewRelayInternalAPI(
|
||||
&db, fedClient, nil, nil, nil, false, "",
|
||||
&db, fedClient, nil, nil, nil, false, "", true,
|
||||
)
|
||||
|
||||
err = relayAPI.PerformRelayServerSync(context.Background(), *userID, gomatrixserverlib.ServerName("relay"))
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ func NewRelayInternalAPI(
|
|||
rsAPI rsAPI.RoomserverInternalAPI,
|
||||
keyRing *gomatrixserverlib.KeyRing,
|
||||
producer *producers.SyncAPIProducer,
|
||||
relayingEnabled bool,
|
||||
) api.RelayInternalAPI {
|
||||
cfg := &base.Cfg.RelayAPI
|
||||
|
||||
|
|
@ -70,5 +71,6 @@ func NewRelayInternalAPI(
|
|||
producer,
|
||||
base.Cfg.Global.Presence.EnableInbound,
|
||||
base.Cfg.Global.ServerName,
|
||||
relayingEnabled,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ func TestCreateNewRelayInternalAPI(t *testing.T) {
|
|||
base, close := testrig.CreateBaseDendrite(t, dbType)
|
||||
defer close()
|
||||
|
||||
relayAPI := relayapi.NewRelayInternalAPI(base, nil, nil, nil, nil)
|
||||
relayAPI := relayapi.NewRelayInternalAPI(base, nil, nil, nil, nil, true)
|
||||
assert.NotNil(t, relayAPI)
|
||||
})
|
||||
}
|
||||
|
|
@ -52,7 +52,7 @@ func TestCreateRelayInternalInvalidDatabasePanics(t *testing.T) {
|
|||
defer close()
|
||||
|
||||
assert.Panics(t, func() {
|
||||
relayapi.NewRelayInternalAPI(base, nil, nil, nil, nil)
|
||||
relayapi.NewRelayInternalAPI(base, nil, nil, nil, nil, true)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
@ -108,7 +108,7 @@ func TestCreateRelayPublicRoutes(t *testing.T) {
|
|||
base, close := testrig.CreateBaseDendrite(t, dbType)
|
||||
defer close()
|
||||
|
||||
relayAPI := relayapi.NewRelayInternalAPI(base, nil, nil, nil, nil)
|
||||
relayAPI := relayapi.NewRelayInternalAPI(base, nil, nil, nil, nil, true)
|
||||
assert.NotNil(t, relayAPI)
|
||||
|
||||
serverKeyAPI := &signing.YggdrasilKeys{}
|
||||
|
|
@ -116,10 +116,9 @@ func TestCreateRelayPublicRoutes(t *testing.T) {
|
|||
relayapi.AddPublicRoutes(base, keyRing, relayAPI)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
req *http.Request
|
||||
wantCode int
|
||||
wantJoinedRooms []string
|
||||
name string
|
||||
req *http.Request
|
||||
wantCode int
|
||||
}{
|
||||
{
|
||||
name: "relay_txn invalid user id",
|
||||
|
|
@ -152,3 +151,42 @@ func TestCreateRelayPublicRoutes(t *testing.T) {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestDisableRelayPublicRoutes(t *testing.T) {
|
||||
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
|
||||
base, close := testrig.CreateBaseDendrite(t, dbType)
|
||||
defer close()
|
||||
|
||||
relayAPI := relayapi.NewRelayInternalAPI(base, nil, nil, nil, nil, false)
|
||||
assert.NotNil(t, relayAPI)
|
||||
|
||||
serverKeyAPI := &signing.YggdrasilKeys{}
|
||||
keyRing := serverKeyAPI.KeyRing()
|
||||
relayapi.AddPublicRoutes(base, keyRing, relayAPI)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
req *http.Request
|
||||
wantCode int
|
||||
}{
|
||||
{
|
||||
name: "relay_txn valid user id",
|
||||
req: createGetRelayTxnHTTPRequest(base.Cfg.Global.ServerName, "@user:local"),
|
||||
wantCode: 404,
|
||||
},
|
||||
{
|
||||
name: "send_relay valid user id",
|
||||
req: createSendRelayTxnHTTPRequest(base.Cfg.Global.ServerName, "123", "@user:local"),
|
||||
wantCode: 404,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
w := httptest.NewRecorder()
|
||||
base.PublicFederationAPIMux.ServeHTTP(w, tc.req)
|
||||
if w.Code != tc.wantCode {
|
||||
t.Fatalf("%s: got HTTP %d want %d", tc.name, w.Code, tc.wantCode)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,13 +25,7 @@ import (
|
|||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type RelayTransactionResponse struct {
|
||||
Transaction gomatrixserverlib.Transaction `json:"transaction"`
|
||||
EntryID int64 `json:"entry_id,omitempty"`
|
||||
EntriesQueued bool `json:"entries_queued"`
|
||||
}
|
||||
|
||||
// GetTransactionFromRelay implements /_matrix/federation/v1/relay_txn/{userID}
|
||||
// GetTransactionFromRelay implements GET /_matrix/federation/v1/relay_txn/{userID}
|
||||
// This endpoint can be extracted into a separate relay server service.
|
||||
func GetTransactionFromRelay(
|
||||
httpReq *http.Request,
|
||||
|
|
@ -39,9 +33,9 @@ func GetTransactionFromRelay(
|
|||
relayAPI api.RelayInternalAPI,
|
||||
userID gomatrixserverlib.UserID,
|
||||
) util.JSONResponse {
|
||||
logrus.Infof("Handling relay_txn for %s", userID.Raw())
|
||||
logrus.Infof("Processing relay_txn for %s", userID.Raw())
|
||||
|
||||
previousEntry := gomatrixserverlib.RelayEntry{}
|
||||
var previousEntry gomatrixserverlib.RelayEntry
|
||||
if err := json.Unmarshal(fedReq.Content(), &previousEntry); err != nil {
|
||||
return util.JSONResponse{
|
||||
Code: http.StatusInternalServerError,
|
||||
|
|
@ -65,7 +59,7 @@ func GetTransactionFromRelay(
|
|||
|
||||
return util.JSONResponse{
|
||||
Code: http.StatusOK,
|
||||
JSON: RelayTransactionResponse{
|
||||
JSON: gomatrixserverlib.RespGetRelayTransaction{
|
||||
Transaction: response.Transaction,
|
||||
EntryID: response.EntryID,
|
||||
EntriesQueued: response.EntriesQueued,
|
||||
|
|
|
|||
|
|
@ -57,14 +57,14 @@ func TestGetEmptyDatabaseReturnsNothing(t *testing.T) {
|
|||
assert.NoError(t, err, "Failed to store transaction")
|
||||
|
||||
relayAPI := internal.NewRelayInternalAPI(
|
||||
&db, nil, nil, nil, nil, false, "",
|
||||
&db, nil, nil, nil, nil, false, "", true,
|
||||
)
|
||||
|
||||
request := createQuery(*userID, gomatrixserverlib.RelayEntry{})
|
||||
response := routing.GetTransactionFromRelay(httpReq, &request, relayAPI, *userID)
|
||||
assert.Equal(t, http.StatusOK, response.Code)
|
||||
|
||||
jsonResponse := response.JSON.(routing.RelayTransactionResponse)
|
||||
jsonResponse := response.JSON.(gomatrixserverlib.RespGetRelayTransaction)
|
||||
assert.Equal(t, false, jsonResponse.EntriesQueued)
|
||||
assert.Equal(t, gomatrixserverlib.Transaction{}, jsonResponse.Transaction)
|
||||
|
||||
|
|
@ -90,7 +90,7 @@ func TestGetInvalidPrevEntryFails(t *testing.T) {
|
|||
assert.NoError(t, err, "Failed to store transaction")
|
||||
|
||||
relayAPI := internal.NewRelayInternalAPI(
|
||||
&db, nil, nil, nil, nil, false, "",
|
||||
&db, nil, nil, nil, nil, false, "", true,
|
||||
)
|
||||
|
||||
request := createQuery(*userID, gomatrixserverlib.RelayEntry{EntryID: -1})
|
||||
|
|
@ -123,14 +123,14 @@ func TestGetReturnsSavedTransaction(t *testing.T) {
|
|||
assert.NoError(t, err, "Failed to associate transaction with user")
|
||||
|
||||
relayAPI := internal.NewRelayInternalAPI(
|
||||
&db, nil, nil, nil, nil, false, "",
|
||||
&db, nil, nil, nil, nil, false, "", true,
|
||||
)
|
||||
|
||||
request := createQuery(*userID, gomatrixserverlib.RelayEntry{})
|
||||
response := routing.GetTransactionFromRelay(httpReq, &request, relayAPI, *userID)
|
||||
assert.Equal(t, http.StatusOK, response.Code)
|
||||
|
||||
jsonResponse := response.JSON.(routing.RelayTransactionResponse)
|
||||
jsonResponse := response.JSON.(gomatrixserverlib.RespGetRelayTransaction)
|
||||
assert.True(t, jsonResponse.EntriesQueued)
|
||||
assert.Equal(t, transaction, jsonResponse.Transaction)
|
||||
|
||||
|
|
@ -139,7 +139,7 @@ func TestGetReturnsSavedTransaction(t *testing.T) {
|
|||
response = routing.GetTransactionFromRelay(httpReq, &request, relayAPI, *userID)
|
||||
assert.Equal(t, http.StatusOK, response.Code)
|
||||
|
||||
jsonResponse = response.JSON.(routing.RelayTransactionResponse)
|
||||
jsonResponse = response.JSON.(gomatrixserverlib.RespGetRelayTransaction)
|
||||
assert.False(t, jsonResponse.EntriesQueued)
|
||||
assert.Equal(t, gomatrixserverlib.Transaction{}, jsonResponse.Transaction)
|
||||
|
||||
|
|
@ -186,14 +186,14 @@ func TestGetReturnsMultipleSavedTransactions(t *testing.T) {
|
|||
assert.NoError(t, err, "Failed to associate transaction with user")
|
||||
|
||||
relayAPI := internal.NewRelayInternalAPI(
|
||||
&db, nil, nil, nil, nil, false, "",
|
||||
&db, nil, nil, nil, nil, false, "", true,
|
||||
)
|
||||
|
||||
request := createQuery(*userID, gomatrixserverlib.RelayEntry{})
|
||||
response := routing.GetTransactionFromRelay(httpReq, &request, relayAPI, *userID)
|
||||
assert.Equal(t, http.StatusOK, response.Code)
|
||||
|
||||
jsonResponse := response.JSON.(routing.RelayTransactionResponse)
|
||||
jsonResponse := response.JSON.(gomatrixserverlib.RespGetRelayTransaction)
|
||||
assert.True(t, jsonResponse.EntriesQueued)
|
||||
assert.Equal(t, transaction, jsonResponse.Transaction)
|
||||
|
||||
|
|
@ -201,7 +201,7 @@ func TestGetReturnsMultipleSavedTransactions(t *testing.T) {
|
|||
response = routing.GetTransactionFromRelay(httpReq, &request, relayAPI, *userID)
|
||||
assert.Equal(t, http.StatusOK, response.Code)
|
||||
|
||||
jsonResponse = response.JSON.(routing.RelayTransactionResponse)
|
||||
jsonResponse = response.JSON.(gomatrixserverlib.RespGetRelayTransaction)
|
||||
assert.True(t, jsonResponse.EntriesQueued)
|
||||
assert.Equal(t, transaction2, jsonResponse.Transaction)
|
||||
|
||||
|
|
@ -210,7 +210,7 @@ func TestGetReturnsMultipleSavedTransactions(t *testing.T) {
|
|||
response = routing.GetTransactionFromRelay(httpReq, &request, relayAPI, *userID)
|
||||
assert.Equal(t, http.StatusOK, response.Code)
|
||||
|
||||
jsonResponse = response.JSON.(routing.RelayTransactionResponse)
|
||||
jsonResponse = response.JSON.(gomatrixserverlib.RespGetRelayTransaction)
|
||||
assert.False(t, jsonResponse.EntriesQueued)
|
||||
assert.Equal(t, gomatrixserverlib.Transaction{}, jsonResponse.Transaction)
|
||||
|
||||
|
|
|
|||
|
|
@ -27,16 +27,13 @@ import (
|
|||
"github.com/matrix-org/dendrite/setup/config"
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
"github.com/matrix-org/util"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Setup registers HTTP handlers with the given ServeMux.
|
||||
// The provided publicAPIMux MUST have `UseEncodedPath()` enabled or else routes will incorrectly
|
||||
// path unescape twice (once from the router, once from MakeRelayAPI). We need to have this enabled
|
||||
// so we can decode paths like foo/bar%2Fbaz as [foo, bar/baz] - by default it will decode to [foo, bar, baz]
|
||||
//
|
||||
// Due to Setup being used to call many other functions, a gocyclo nolint is
|
||||
// applied:
|
||||
// nolint: gocyclo
|
||||
func Setup(
|
||||
fedMux *mux.Router,
|
||||
cfg *config.FederationAPI,
|
||||
|
|
@ -48,6 +45,14 @@ func Setup(
|
|||
v1fedmux.Handle("/send_relay/{txnID}/{userID}", MakeRelayAPI(
|
||||
"send_relay_transaction", "", cfg.Matrix.IsLocalServerName, keys,
|
||||
func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest, vars map[string]string) util.JSONResponse {
|
||||
logrus.Infof("Handling send_relay from: %s", request.Origin())
|
||||
if !relayAPI.RelayingEnabled() {
|
||||
logrus.Warnf("Dropping send_relay from: %s", request.Origin())
|
||||
return util.JSONResponse{
|
||||
Code: http.StatusNotFound,
|
||||
}
|
||||
}
|
||||
|
||||
userID, err := gomatrixserverlib.NewUserID(vars["userID"], false)
|
||||
if err != nil {
|
||||
return util.JSONResponse{
|
||||
|
|
@ -65,6 +70,14 @@ func Setup(
|
|||
v1fedmux.Handle("/relay_txn/{userID}", MakeRelayAPI(
|
||||
"get_relay_transaction", "", cfg.Matrix.IsLocalServerName, keys,
|
||||
func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest, vars map[string]string) util.JSONResponse {
|
||||
logrus.Infof("Handling relay_txn from: %s", request.Origin())
|
||||
if !relayAPI.RelayingEnabled() {
|
||||
logrus.Warnf("Dropping relay_txn from: %s", request.Origin())
|
||||
return util.JSONResponse{
|
||||
Code: http.StatusNotFound,
|
||||
}
|
||||
}
|
||||
|
||||
userID, err := gomatrixserverlib.NewUserID(vars["userID"], false)
|
||||
if err != nil {
|
||||
return util.JSONResponse{
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ import (
|
|||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// SendTransactionToRelay implements PUT /_matrix/federation/v1/relay_txn/{txnID}/{userID}
|
||||
// SendTransactionToRelay implements PUT /_matrix/federation/v1/send_relay/{txnID}/{userID}
|
||||
// This endpoint can be extracted into a separate relay server service.
|
||||
func SendTransactionToRelay(
|
||||
httpReq *http.Request,
|
||||
|
|
@ -34,11 +34,9 @@ func SendTransactionToRelay(
|
|||
txnID gomatrixserverlib.TransactionID,
|
||||
userID gomatrixserverlib.UserID,
|
||||
) util.JSONResponse {
|
||||
var txnEvents struct {
|
||||
PDUs []json.RawMessage `json:"pdus"`
|
||||
EDUs []gomatrixserverlib.EDU `json:"edus"`
|
||||
}
|
||||
logrus.Infof("Processing send_relay for %s", userID.Raw())
|
||||
|
||||
var txnEvents gomatrixserverlib.RelayEvents
|
||||
if err := json.Unmarshal(fedReq.Content(), &txnEvents); err != nil {
|
||||
logrus.Info("The request body could not be decoded into valid JSON." + err.Error())
|
||||
return util.JSONResponse{
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ func TestForwardEmptyReturnsOk(t *testing.T) {
|
|||
request := createFederationRequest(*userID, txn.TransactionID, txn.Origin, txn.Destination, txn)
|
||||
|
||||
relayAPI := internal.NewRelayInternalAPI(
|
||||
&db, nil, nil, nil, nil, false, "",
|
||||
&db, nil, nil, nil, nil, false, "", true,
|
||||
)
|
||||
|
||||
response := routing.SendTransactionToRelay(httpReq, &request, relayAPI, "1", *userID)
|
||||
|
|
@ -101,7 +101,7 @@ func TestForwardBadJSONReturnsError(t *testing.T) {
|
|||
request := createFederationRequest(*userID, txn.TransactionID, txn.Origin, txn.Destination, content)
|
||||
|
||||
relayAPI := internal.NewRelayInternalAPI(
|
||||
&db, nil, nil, nil, nil, false, "",
|
||||
&db, nil, nil, nil, nil, false, "", true,
|
||||
)
|
||||
|
||||
response := routing.SendTransactionToRelay(httpReq, &request, relayAPI, "1", *userID)
|
||||
|
|
@ -135,7 +135,7 @@ func TestForwardTooManyPDUsReturnsError(t *testing.T) {
|
|||
request := createFederationRequest(*userID, txn.TransactionID, txn.Origin, txn.Destination, content)
|
||||
|
||||
relayAPI := internal.NewRelayInternalAPI(
|
||||
&db, nil, nil, nil, nil, false, "",
|
||||
&db, nil, nil, nil, nil, false, "", true,
|
||||
)
|
||||
|
||||
response := routing.SendTransactionToRelay(httpReq, &request, relayAPI, "1", *userID)
|
||||
|
|
@ -169,7 +169,7 @@ func TestForwardTooManyEDUsReturnsError(t *testing.T) {
|
|||
request := createFederationRequest(*userID, txn.TransactionID, txn.Origin, txn.Destination, content)
|
||||
|
||||
relayAPI := internal.NewRelayInternalAPI(
|
||||
&db, nil, nil, nil, nil, false, "",
|
||||
&db, nil, nil, nil, nil, false, "", true,
|
||||
)
|
||||
|
||||
response := routing.SendTransactionToRelay(httpReq, &request, relayAPI, "1", *userID)
|
||||
|
|
@ -192,7 +192,7 @@ func TestUniqueTransactionStoredInDatabase(t *testing.T) {
|
|||
request := createFederationRequest(*userID, txn.TransactionID, txn.Origin, txn.Destination, txn)
|
||||
|
||||
relayAPI := internal.NewRelayInternalAPI(
|
||||
&db, nil, nil, nil, nil, false, "",
|
||||
&db, nil, nil, nil, nil, false, "", true,
|
||||
)
|
||||
|
||||
response := routing.SendTransactionToRelay(
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
||||
"github.com/matrix-org/gomatrix"
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
"github.com/matrix-org/util"
|
||||
|
|
@ -109,7 +110,7 @@ func (r *Leaver) performLeaveRoomByID(
|
|||
// mimic the returned values from Synapse
|
||||
res.Message = "You cannot reject this invite"
|
||||
res.Code = 403
|
||||
return nil, fmt.Errorf("You cannot reject this invite")
|
||||
return nil, jsonerror.LeaveServerNoticeError()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
// Copyright 2023 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package deltas
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func UpPulishedAppservicePrimaryKey(ctx context.Context, tx *sql.Tx) error {
|
||||
_, err := tx.ExecContext(ctx, `ALTER TABLE roomserver_published RENAME CONSTRAINT roomserver_published_pkey TO roomserver_published_pkeyold;
|
||||
CREATE UNIQUE INDEX roomserver_published_pkey ON roomserver_published (room_id, appservice_id, network_id);
|
||||
ALTER TABLE roomserver_published DROP CONSTRAINT roomserver_published_pkeyold;
|
||||
ALTER TABLE roomserver_published ADD PRIMARY KEY USING INDEX roomserver_published_pkey;`)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute upgrade: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -65,10 +65,16 @@ func CreatePublishedTable(db *sql.DB) error {
|
|||
return err
|
||||
}
|
||||
m := sqlutil.NewMigrator(db)
|
||||
m.AddMigrations(sqlutil.Migration{
|
||||
Version: "roomserver: published appservice",
|
||||
Up: deltas.UpPulishedAppservice,
|
||||
})
|
||||
m.AddMigrations([]sqlutil.Migration{
|
||||
{
|
||||
Version: "roomserver: published appservice",
|
||||
Up: deltas.UpPulishedAppservice,
|
||||
},
|
||||
{
|
||||
Version: "roomserver: published appservice pkey",
|
||||
Up: deltas.UpPulishedAppservicePrimaryKey,
|
||||
},
|
||||
}...)
|
||||
return m.Up(context.Background())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,11 +15,14 @@
|
|||
package base
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"database/sql"
|
||||
"embed"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
|
|
@ -65,6 +68,9 @@ import (
|
|||
userapiinthttp "github.com/matrix-org/dendrite/userapi/inthttp"
|
||||
)
|
||||
|
||||
//go:embed static/*.gotmpl
|
||||
var staticContent embed.FS
|
||||
|
||||
// BaseDendrite is a base for creating new instances of dendrite. It parses
|
||||
// command line flags and config, and exposes methods for creating various
|
||||
// resources. All errors are handled by logging then exiting, so all methods
|
||||
|
|
@ -79,6 +85,7 @@ type BaseDendrite struct {
|
|||
PublicKeyAPIMux *mux.Router
|
||||
PublicMediaAPIMux *mux.Router
|
||||
PublicWellKnownAPIMux *mux.Router
|
||||
PublicStaticMux *mux.Router
|
||||
InternalAPIMux *mux.Router
|
||||
DendriteAdminMux *mux.Router
|
||||
SynapseAdminMux *mux.Router
|
||||
|
|
@ -250,6 +257,7 @@ func NewBaseDendrite(cfg *config.Dendrite, componentName string, options ...Base
|
|||
PublicKeyAPIMux: mux.NewRouter().SkipClean(true).PathPrefix(httputil.PublicKeyPathPrefix).Subrouter().UseEncodedPath(),
|
||||
PublicMediaAPIMux: mux.NewRouter().SkipClean(true).PathPrefix(httputil.PublicMediaPathPrefix).Subrouter().UseEncodedPath(),
|
||||
PublicWellKnownAPIMux: mux.NewRouter().SkipClean(true).PathPrefix(httputil.PublicWellKnownPrefix).Subrouter().UseEncodedPath(),
|
||||
PublicStaticMux: mux.NewRouter().SkipClean(true).PathPrefix(httputil.PublicStaticPath).Subrouter().UseEncodedPath(),
|
||||
InternalAPIMux: mux.NewRouter().SkipClean(true).PathPrefix(httputil.InternalPathPrefix).Subrouter().UseEncodedPath(),
|
||||
DendriteAdminMux: mux.NewRouter().SkipClean(true).PathPrefix(httputil.DendriteAdminPathPrefix).Subrouter().UseEncodedPath(),
|
||||
SynapseAdminMux: mux.NewRouter().SkipClean(true).PathPrefix(httputil.SynapseAdminPathPrefix).Subrouter().UseEncodedPath(),
|
||||
|
|
@ -405,6 +413,7 @@ func (b *BaseDendrite) configureHTTPErrors() {
|
|||
for _, router := range []*mux.Router{
|
||||
b.PublicMediaAPIMux, b.DendriteAdminMux,
|
||||
b.SynapseAdminMux, b.PublicWellKnownAPIMux,
|
||||
b.PublicStaticMux,
|
||||
} {
|
||||
router.NotFoundHandler = notFoundCORSHandler
|
||||
router.MethodNotAllowedHandler = notAllowedCORSHandler
|
||||
|
|
@ -478,6 +487,11 @@ func (b *BaseDendrite) SetupAndServeHTTP(
|
|||
|
||||
b.configureHTTPErrors()
|
||||
|
||||
//Redirect for Landing Page
|
||||
externalRouter.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, httputil.PublicStaticPath, http.StatusFound)
|
||||
})
|
||||
|
||||
internalRouter.PathPrefix(httputil.InternalPathPrefix).Handler(b.InternalAPIMux)
|
||||
if b.Cfg.Global.Metrics.Enabled {
|
||||
internalRouter.Handle("/metrics", httputil.WrapHandlerInBasicAuth(promhttp.Handler(), b.Cfg.Global.Metrics.BasicAuth))
|
||||
|
|
@ -485,6 +499,19 @@ func (b *BaseDendrite) SetupAndServeHTTP(
|
|||
|
||||
b.ConfigureAdminEndpoints()
|
||||
|
||||
// Parse and execute the landing page template
|
||||
tmpl := template.Must(template.ParseFS(staticContent, "static/*.gotmpl"))
|
||||
landingPage := &bytes.Buffer{}
|
||||
if err := tmpl.ExecuteTemplate(landingPage, "index.gotmpl", map[string]string{
|
||||
"Version": internal.VersionString(),
|
||||
}); err != nil {
|
||||
logrus.WithError(err).Fatal("failed to execute landing page template")
|
||||
}
|
||||
|
||||
b.PublicStaticMux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
_, _ = w.Write(landingPage.Bytes())
|
||||
})
|
||||
|
||||
var clientHandler http.Handler
|
||||
clientHandler = b.PublicClientAPIMux
|
||||
if b.Cfg.Global.Sentry.Enabled {
|
||||
|
|
@ -510,6 +537,7 @@ func (b *BaseDendrite) SetupAndServeHTTP(
|
|||
externalRouter.PathPrefix(httputil.SynapseAdminPathPrefix).Handler(b.SynapseAdminMux)
|
||||
externalRouter.PathPrefix(httputil.PublicMediaPathPrefix).Handler(b.PublicMediaAPIMux)
|
||||
externalRouter.PathPrefix(httputil.PublicWellKnownPrefix).Handler(b.PublicWellKnownAPIMux)
|
||||
externalRouter.PathPrefix(httputil.PublicStaticPath).Handler(b.PublicStaticMux)
|
||||
|
||||
b.startupLock.Unlock()
|
||||
if internalAddr != NoListener && internalAddr != externalAddr {
|
||||
|
|
|
|||
57
setup/base/base_test.go
Normal file
57
setup/base/base_test.go
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
package base_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"embed"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/matrix-org/dendrite/internal"
|
||||
"github.com/matrix-org/dendrite/setup/config"
|
||||
"github.com/matrix-org/dendrite/test/testrig"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
//go:embed static/*.gotmpl
|
||||
var staticContent embed.FS
|
||||
|
||||
func TestLandingPage(t *testing.T) {
|
||||
// generate the expected result
|
||||
tmpl := template.Must(template.ParseFS(staticContent, "static/*.gotmpl"))
|
||||
expectedRes := &bytes.Buffer{}
|
||||
err := tmpl.ExecuteTemplate(expectedRes, "index.gotmpl", map[string]string{
|
||||
"Version": internal.VersionString(),
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
b, _, _ := testrig.Base(nil)
|
||||
defer b.Close()
|
||||
|
||||
// hack: create a server and close it immediately, just to get a random port assigned
|
||||
s := httptest.NewServer(nil)
|
||||
s.Close()
|
||||
|
||||
// start base with the listener and wait for it to be started
|
||||
go b.SetupAndServeHTTP("", config.HTTPAddress(s.URL), nil, nil)
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
|
||||
// When hitting /, we should be redirected to /_matrix/static, which should contain the landing page
|
||||
req, err := http.NewRequest(http.MethodGet, s.URL, nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// do the request
|
||||
resp, err := s.Client().Do(req)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||||
|
||||
// read the response
|
||||
buf := &bytes.Buffer{}
|
||||
_, err = buf.ReadFrom(resp.Body)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Using .String() for user friendly output
|
||||
assert.Equal(t, expectedRes.String(), buf.String(), "response mismatch")
|
||||
}
|
||||
63
setup/base/static/index.gotmpl
Normal file
63
setup/base/static/index.gotmpl
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Dendrite is running</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;
|
||||
max-width: 40em;
|
||||
margin: auto;
|
||||
text-align: center;
|
||||
}
|
||||
h1, p {
|
||||
margin: 1.5em;
|
||||
}
|
||||
hr {
|
||||
border: none;
|
||||
background-color: #ccc;
|
||||
color: #ccc;
|
||||
height: 1px;
|
||||
width: 7em;
|
||||
margin-top: 4em;
|
||||
}
|
||||
.logo {
|
||||
display: block;
|
||||
width: 12em;
|
||||
margin: 4em auto;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="logo">
|
||||
<svg role="img" aria-label="[Matrix logo]" viewBox="0 0 200 85" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="parent" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="child" transform="translate(-122.000000, -6.000000)" fill="#000000" fill-rule="nonzero">
|
||||
<g id="matrix-logo" transform="translate(122.000000, 6.000000)">
|
||||
<polygon id="left-bracket" points="2.24708861 1.93811009 2.24708861 82.7268844 8.10278481 82.7268844 8.10278481 84.6652459 0 84.6652459 0 0 8.10278481 0 8.10278481 1.93811009"></polygon>
|
||||
<path d="M24.8073418,27.5493174 L24.8073418,31.6376991 L24.924557,31.6376991 C26.0227848,30.0814294 27.3455696,28.8730642 28.8951899,28.0163743 C30.4437975,27.1611927 32.2189873,26.7318422 34.218481,26.7318422 C36.1394937,26.7318422 37.8946835,27.102622 39.4825316,27.8416679 C41.0708861,28.5819706 42.276962,29.8856073 43.1005063,31.7548404 C44.0017722,30.431345 45.2270886,29.2629486 46.7767089,28.2506569 C48.3253165,27.2388679 50.158481,26.7318422 52.2764557,26.7318422 C53.8843038,26.7318422 55.3736709,26.9269101 56.7473418,27.3162917 C58.1189873,27.7056734 59.295443,28.3285835 60.2759494,29.185022 C61.255443,30.0422147 62.02,31.1615927 62.5701266,32.5426532 C63.1187342,33.9262275 63.3936709,35.5898349 63.3936709,37.5372459 L63.3936709,57.7443688 L55.0410127,57.7441174 L55.0410127,40.6319376 C55.0410127,39.6201486 55.0020253,38.6661761 54.9232911,37.7700202 C54.8440506,36.8751211 54.6293671,36.0968606 54.2764557,35.4339817 C53.9232911,34.772611 53.403038,34.2464807 52.7177215,33.8568477 C52.0313924,33.4689743 51.0997468,33.2731523 49.9235443,33.2731523 C48.7473418,33.2731523 47.7962025,33.4983853 47.0706329,33.944578 C46.344557,34.393033 45.7764557,34.9774826 45.3650633,35.6969211 C44.9534177,36.4181193 44.6787342,37.2353431 44.5417722,38.150855 C44.4037975,39.0653615 44.3356962,39.9904257 44.3356962,40.9247908 L44.3356962,57.7443688 L35.9835443,57.7443688 L35.9835443,40.8079009 C35.9835443,39.9124991 35.963038,39.0263982 35.9253165,38.150855 C35.8853165,37.2743064 35.7192405,36.4666349 35.424557,35.7263321 C35.1303797,34.9872862 34.64,34.393033 33.9539241,33.944578 C33.2675949,33.4983853 32.2579747,33.2731523 30.9248101,33.2731523 C30.5321519,33.2731523 30.0126582,33.3608826 29.3663291,33.5365945 C28.7192405,33.7118037 28.0913924,34.0433688 27.4840506,34.5292789 C26.875443,35.0164459 26.3564557,35.7172826 25.9250633,36.6315376 C25.4934177,37.5470495 25.2779747,38.7436 25.2779747,40.2229486 L25.2779747,57.7441174 L16.9260759,57.7443688 L16.9260759,27.5493174 L24.8073418,27.5493174 Z" id="m"></path>
|
||||
<path d="M68.7455696,31.9886202 C69.6075949,30.7033339 70.7060759,29.672189 72.0397468,28.8926716 C73.3724051,28.1141596 74.8716456,27.5596239 76.5387342,27.2283101 C78.2050633,26.8977505 79.8817722,26.7315908 81.5678481,26.7315908 C83.0974684,26.7315908 84.6458228,26.8391798 86.2144304,27.0525982 C87.7827848,27.2675248 89.2144304,27.6865688 90.5086076,28.3087248 C91.8025316,28.9313835 92.8610127,29.7983798 93.6848101,30.9074514 C94.5083544,32.0170257 94.92,33.4870734 94.92,35.3173431 L94.92,51.026844 C94.92,52.3913138 94.998481,53.6941963 95.1556962,54.9400165 C95.3113924,56.1865908 95.5863291,57.120956 95.9787342,57.7436147 L87.5091139,57.7436147 C87.3518987,57.276055 87.2240506,56.7996972 87.1265823,56.3125303 C87.0278481,55.8266202 86.9592405,55.3301523 86.9207595,54.8236294 C85.5873418,56.1865908 84.0182278,57.1405633 82.2156962,57.6857982 C80.4113924,58.2295248 78.5683544,58.503022 76.6860759,58.503022 C75.2346835,58.503022 73.8817722,58.3275615 72.6270886,57.9776459 C71.3718987,57.6269761 70.2744304,57.082244 69.3334177,56.3411872 C68.3921519,55.602644 67.656962,54.6680275 67.1275949,53.5390972 C66.5982278,52.410167 66.3331646,51.065556 66.3331646,49.5087835 C66.3331646,47.7961578 66.6367089,46.384178 67.2455696,45.2756092 C67.8529114,44.1652807 68.6367089,43.2799339 69.5987342,42.6173064 C70.5589873,41.9556844 71.6567089,41.4592165 72.8924051,41.1284055 C74.1273418,40.7978459 75.3721519,40.5356606 76.6270886,40.3398385 C77.8820253,40.1457761 79.116962,39.9896716 80.3329114,39.873033 C81.5483544,39.7558917 82.6270886,39.5804312 83.5681013,39.3469028 C84.5093671,39.1133743 85.2536709,38.7732624 85.8032911,38.3250587 C86.3513924,37.8773578 86.6063291,37.2252881 86.5678481,36.3680954 C86.5678481,35.4731963 86.4210127,34.7620532 86.1268354,34.2366771 C85.8329114,33.7113009 85.4405063,33.3018092 84.9506329,33.0099615 C84.4602532,32.7181138 83.8916456,32.5232972 83.2450633,32.4255119 C82.5977215,32.3294862 81.9010127,32.2797138 81.156962,32.2797138 C79.5098734,32.2797138 78.2159494,32.6303835 77.2746835,33.3312202 C76.3339241,34.0320569 75.7837975,35.2007046 75.6275949,36.8354037 L67.275443,36.8354037 C67.3924051,34.8892495 67.8817722,33.2726495 68.7455696,31.9886202 Z M85.2440506,43.6984752 C84.7149367,43.873433 84.1460759,44.0189798 83.5387342,44.1361211 C82.9306329,44.253011 82.2936709,44.350545 81.6270886,44.4279688 C80.96,44.5066495 80.2934177,44.6034294 79.6273418,44.7203193 C78.9994937,44.8362037 78.3820253,44.9933138 77.7749367,45.1871248 C77.1663291,45.3829468 76.636962,45.6451321 76.1865823,45.9759431 C75.7349367,46.3070055 75.3724051,46.7263009 75.0979747,47.2313156 C74.8232911,47.7375872 74.6863291,48.380356 74.6863291,49.1588679 C74.6863291,49.8979138 74.8232911,50.5218294 75.0979747,51.026844 C75.3724051,51.5338697 75.7455696,51.9328037 76.2159494,52.2246514 C76.6863291,52.5164991 77.2349367,52.7213706 77.8632911,52.8375064 C78.4898734,52.9546477 79.136962,53.012967 79.8037975,53.012967 C81.4506329,53.012967 82.724557,52.740978 83.6273418,52.1952404 C84.5288608,51.6507596 85.1949367,50.9981872 85.6270886,50.2382771 C86.0579747,49.4793725 86.323038,48.7119211 86.4212658,47.9321523 C86.518481,47.1536404 86.5681013,46.5304789 86.5681013,46.063422 L86.5681013,42.9677248 C86.2146835,43.2799339 85.7736709,43.5230147 85.2440506,43.6984752 Z" id="a"></path>
|
||||
<path d="M116.917975,27.5493174 L116.917975,33.0976917 L110.801266,33.0976917 L110.801266,48.0492936 C110.801266,49.4502128 111.036203,50.3850807 111.507089,50.8518862 C111.976962,51.3191945 112.918734,51.5527229 114.33038,51.5527229 C114.801013,51.5527229 115.251392,51.5336183 115.683038,51.4944037 C116.114177,51.4561945 116.526076,51.3968697 116.917975,51.3194459 L116.917975,57.7438661 C116.212152,57.860756 115.427595,57.9381798 114.565316,57.9778972 C113.702785,58.0153523 112.859747,58.0357138 112.036203,58.0357138 C110.742278,58.0357138 109.516456,57.9477321 108.36,57.7722716 C107.202785,57.5975651 106.183544,57.2577046 105.301519,56.7509303 C104.418987,56.2454128 103.722785,55.5242147 103.213418,54.5898495 C102.703038,53.6562385 102.448608,52.4292716 102.448608,50.9099541 L102.448608,33.0976917 L97.3903797,33.0976917 L97.3903797,27.5493174 L102.448608,27.5493174 L102.448608,18.4967596 L110.801013,18.4967596 L110.801013,27.5493174 L116.917975,27.5493174 Z" id="t"></path>
|
||||
<path d="M128.857975,27.5493174 L128.857975,33.1565138 L128.975696,33.1565138 C129.367089,32.2213945 129.896203,31.3559064 130.563544,30.557033 C131.23038,29.7596679 131.99443,29.0776844 132.857215,28.5130936 C133.719241,27.9495083 134.641266,27.5113596 135.622532,27.1988991 C136.601772,26.8879468 137.622025,26.7315908 138.681013,26.7315908 C139.229873,26.7315908 139.836962,26.8296275 140.504304,27.0239413 L140.504304,34.7336477 C140.111646,34.6552183 139.641013,34.586844 139.092658,34.5290275 C138.543291,34.4704569 138.014177,34.4410459 137.504304,34.4410459 C135.974937,34.4410459 134.681013,34.6949358 133.622785,35.2004532 C132.564051,35.7067248 131.711392,36.397255 131.064051,37.2735523 C130.417215,38.1501009 129.955443,39.1714422 129.681266,40.3398385 C129.407089,41.5074807 129.269873,42.7736624 129.269873,44.1361211 L129.269873,57.7438661 L120.917722,57.7438661 L120.917722,27.5493174 L128.857975,27.5493174 Z" id="r"></path>
|
||||
<path d="M144.033165,22.8767376 L144.033165,16.0435798 L152.386076,16.0435798 L152.386076,22.8767376 L144.033165,22.8767376 Z M152.386076,27.5493174 L152.386076,57.7438661 L144.033165,57.7438661 L144.033165,27.5493174 L152.386076,27.5493174 Z" id="i"></path>
|
||||
<polygon id="x" points="156.738228 27.5493174 166.266582 27.5493174 171.619494 35.4337303 176.913418 27.5493174 186.147848 27.5493174 176.148861 41.6831927 187.383544 57.7441174 177.85443 57.7441174 171.501772 48.2245028 165.148861 57.7441174 155.797468 57.7441174 166.737468 41.8589046"></polygon>
|
||||
<polygon id="right-bracket" points="197.580759 82.7268844 197.580759 1.93811009 191.725063 1.93811009 191.725063 0 199.828354 0 199.828354 84.6652459 191.725063 84.6652459 191.725063 82.7268844"></polygon>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
<h1>It works! Dendrite {{ .Version }} is running</h1>
|
||||
<p>Your Dendrite server is listening on this port and is ready for messages.</p>
|
||||
<p>To use this server you'll need <a href="https://matrix.org/docs/projects/try-matrix-now.html#clients" target="_blank" rel="noopener noreferrer">a Matrix client</a>.
|
||||
</p>
|
||||
<p>Welcome to the Matrix universe :)</p>
|
||||
<hr>
|
||||
<p>
|
||||
<small>
|
||||
<a href="https://matrix.org" target="_blank" rel="noopener noreferrer">
|
||||
matrix.org
|
||||
</a>
|
||||
</small>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -49,7 +49,7 @@ func (c *FederationAPI) Defaults(opts DefaultOpts) {
|
|||
c.Database.Defaults(10)
|
||||
}
|
||||
c.FederationMaxRetries = 16
|
||||
c.P2PFederationRetriesUntilAssumedOffline = 2
|
||||
c.P2PFederationRetriesUntilAssumedOffline = 1
|
||||
c.DisableTLSValidation = false
|
||||
c.DisableHTTPKeepalives = false
|
||||
if opts.Generate {
|
||||
|
|
|
|||
|
|
@ -144,38 +144,42 @@ func TrackChangedUsers(
|
|||
// - Loop set of users and decrement by 1 for each user in newly left room.
|
||||
// - If count=0 then they share no more rooms so inform BOTH parties of this via 'left'=[...] in /sync.
|
||||
var queryRes roomserverAPI.QuerySharedUsersResponse
|
||||
err = rsAPI.QuerySharedUsers(ctx, &roomserverAPI.QuerySharedUsersRequest{
|
||||
UserID: userID,
|
||||
IncludeRoomIDs: newlyLeftRooms,
|
||||
}, &queryRes)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
var stateRes roomserverAPI.QueryBulkStateContentResponse
|
||||
err = rsAPI.QueryBulkStateContent(ctx, &roomserverAPI.QueryBulkStateContentRequest{
|
||||
RoomIDs: newlyLeftRooms,
|
||||
StateTuples: []gomatrixserverlib.StateKeyTuple{
|
||||
{
|
||||
EventType: gomatrixserverlib.MRoomMember,
|
||||
StateKey: "*",
|
||||
},
|
||||
},
|
||||
AllowWildcards: true,
|
||||
}, &stateRes)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
for _, state := range stateRes.Rooms {
|
||||
for tuple, membership := range state {
|
||||
if membership != gomatrixserverlib.Join {
|
||||
continue
|
||||
}
|
||||
queryRes.UserIDsToCount[tuple.StateKey]--
|
||||
if len(newlyLeftRooms) > 0 {
|
||||
err = rsAPI.QuerySharedUsers(ctx, &roomserverAPI.QuerySharedUsersRequest{
|
||||
UserID: userID,
|
||||
IncludeRoomIDs: newlyLeftRooms,
|
||||
}, &queryRes)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
for userID, count := range queryRes.UserIDsToCount {
|
||||
if count <= 0 {
|
||||
left = append(left, userID) // left is returned
|
||||
|
||||
err = rsAPI.QueryBulkStateContent(ctx, &roomserverAPI.QueryBulkStateContentRequest{
|
||||
RoomIDs: newlyLeftRooms,
|
||||
StateTuples: []gomatrixserverlib.StateKeyTuple{
|
||||
{
|
||||
EventType: gomatrixserverlib.MRoomMember,
|
||||
StateKey: "*",
|
||||
},
|
||||
},
|
||||
AllowWildcards: true,
|
||||
}, &stateRes)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
for _, state := range stateRes.Rooms {
|
||||
for tuple, membership := range state {
|
||||
if membership != gomatrixserverlib.Join {
|
||||
continue
|
||||
}
|
||||
queryRes.UserIDsToCount[tuple.StateKey]--
|
||||
}
|
||||
}
|
||||
|
||||
for userID, count := range queryRes.UserIDsToCount {
|
||||
if count <= 0 {
|
||||
left = append(left, userID) // left is returned
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -399,6 +399,33 @@ func (d *InMemoryFederationDatabase) P2PAddRelayServersForServer(
|
|||
return nil
|
||||
}
|
||||
|
||||
func (d *InMemoryFederationDatabase) P2PRemoveRelayServersForServer(
|
||||
ctx context.Context,
|
||||
serverName gomatrixserverlib.ServerName,
|
||||
relayServers []gomatrixserverlib.ServerName,
|
||||
) error {
|
||||
d.dbMutex.Lock()
|
||||
defer d.dbMutex.Unlock()
|
||||
|
||||
if knownRelayServers, ok := d.relayServers[serverName]; ok {
|
||||
for _, relayServer := range relayServers {
|
||||
for i, knownRelayServer := range knownRelayServers {
|
||||
if relayServer == knownRelayServer {
|
||||
d.relayServers[serverName] = append(
|
||||
d.relayServers[serverName][:i],
|
||||
d.relayServers[serverName][i+1:]...,
|
||||
)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
d.relayServers[serverName] = relayServers
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *InMemoryFederationDatabase) FetchKeys(ctx context.Context, requests map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.Timestamp) (map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
|
@ -431,10 +458,6 @@ func (d *InMemoryFederationDatabase) RemoveAllServersAssumedOffline(ctx context.
|
|||
return nil
|
||||
}
|
||||
|
||||
func (d *InMemoryFederationDatabase) P2PRemoveRelayServersForServer(ctx context.Context, serverName gomatrixserverlib.ServerName, relayServers []gomatrixserverlib.ServerName) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *InMemoryFederationDatabase) P2PRemoveAllRelayServersForServer(ctx context.Context, serverName gomatrixserverlib.ServerName) error {
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue