Merge branch 'main' of github.com:matrix-org/dendrite into s7evink/acls

This commit is contained in:
Till Faelligen 2023-03-22 09:31:56 +01:00
commit e448ce0098
No known key found for this signature in database
GPG key ID: ACCDC9606D472758
108 changed files with 1736 additions and 1268 deletions

View file

@ -21,6 +21,8 @@ import (
"sync" "sync"
"time" "time"
"github.com/matrix-org/dendrite/setup/jetstream"
"github.com/matrix-org/dendrite/setup/process"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
@ -29,7 +31,6 @@ import (
"github.com/matrix-org/dendrite/appservice/consumers" "github.com/matrix-org/dendrite/appservice/consumers"
"github.com/matrix-org/dendrite/appservice/query" "github.com/matrix-org/dendrite/appservice/query"
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api" roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
"github.com/matrix-org/dendrite/setup/base"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
userapi "github.com/matrix-org/dendrite/userapi/api" userapi "github.com/matrix-org/dendrite/userapi/api"
) )
@ -37,7 +38,9 @@ import (
// NewInternalAPI returns a concerete implementation of the internal API. Callers // NewInternalAPI returns a concerete implementation of the internal API. Callers
// can call functions directly on the returned API or via an HTTP interface using AddInternalRoutes. // can call functions directly on the returned API or via an HTTP interface using AddInternalRoutes.
func NewInternalAPI( func NewInternalAPI(
base *base.BaseDendrite, processContext *process.ProcessContext,
cfg *config.Dendrite,
natsInstance *jetstream.NATSInstance,
userAPI userapi.AppserviceUserAPI, userAPI userapi.AppserviceUserAPI,
rsAPI roomserverAPI.RoomserverInternalAPI, rsAPI roomserverAPI.RoomserverInternalAPI,
) appserviceAPI.AppServiceInternalAPI { ) appserviceAPI.AppServiceInternalAPI {
@ -46,7 +49,7 @@ func NewInternalAPI(
Transport: &http.Transport{ Transport: &http.Transport{
DisableKeepAlives: true, DisableKeepAlives: true,
TLSClientConfig: &tls.Config{ TLSClientConfig: &tls.Config{
InsecureSkipVerify: base.Cfg.AppServiceAPI.DisableTLSValidation, InsecureSkipVerify: cfg.AppServiceAPI.DisableTLSValidation,
}, },
Proxy: http.ProxyFromEnvironment, Proxy: http.ProxyFromEnvironment,
}, },
@ -55,21 +58,21 @@ func NewInternalAPI(
// outbound and inbound requests (inbound only for the internal API) // outbound and inbound requests (inbound only for the internal API)
appserviceQueryAPI := &query.AppServiceQueryAPI{ appserviceQueryAPI := &query.AppServiceQueryAPI{
HTTPClient: client, HTTPClient: client,
Cfg: &base.Cfg.AppServiceAPI, Cfg: &cfg.AppServiceAPI,
ProtocolCache: map[string]appserviceAPI.ASProtocolResponse{}, ProtocolCache: map[string]appserviceAPI.ASProtocolResponse{},
CacheMu: sync.Mutex{}, CacheMu: sync.Mutex{},
} }
if len(base.Cfg.Derived.ApplicationServices) == 0 { if len(cfg.Derived.ApplicationServices) == 0 {
return appserviceQueryAPI return appserviceQueryAPI
} }
// Wrap application services in a type that relates the application service and // Wrap application services in a type that relates the application service and
// a sync.Cond object that can be used to notify workers when there are new // a sync.Cond object that can be used to notify workers when there are new
// events to be sent out. // events to be sent out.
for _, appservice := range base.Cfg.Derived.ApplicationServices { for _, appservice := range cfg.Derived.ApplicationServices {
// Create bot account for this AS if it doesn't already exist // Create bot account for this AS if it doesn't already exist
if err := generateAppServiceAccount(userAPI, appservice, base.Cfg.Global.ServerName); err != nil { if err := generateAppServiceAccount(userAPI, appservice, cfg.Global.ServerName); err != nil {
logrus.WithFields(logrus.Fields{ logrus.WithFields(logrus.Fields{
"appservice": appservice.ID, "appservice": appservice.ID,
}).WithError(err).Panicf("failed to generate bot account for appservice") }).WithError(err).Panicf("failed to generate bot account for appservice")
@ -78,9 +81,9 @@ func NewInternalAPI(
// Only consume if we actually have ASes to track, else we'll just chew cycles needlessly. // Only consume if we actually have ASes to track, else we'll just chew cycles needlessly.
// We can't add ASes at runtime so this is safe to do. // We can't add ASes at runtime so this is safe to do.
js, _ := base.NATS.Prepare(base.ProcessContext, &base.Cfg.Global.JetStream) js, _ := natsInstance.Prepare(processContext, &cfg.Global.JetStream)
consumer := consumers.NewOutputRoomEventConsumer( consumer := consumers.NewOutputRoomEventConsumer(
base.ProcessContext, &base.Cfg.AppServiceAPI, processContext, &cfg.AppServiceAPI,
client, js, rsAPI, client, js, rsAPI,
) )
if err := consumer.Start(); err != nil { if err := consumer.Start(); err != nil {

View file

@ -9,11 +9,15 @@ import (
"regexp" "regexp"
"strings" "strings"
"testing" "testing"
"time"
"github.com/matrix-org/dendrite/appservice" "github.com/matrix-org/dendrite/appservice"
"github.com/matrix-org/dendrite/appservice/api" "github.com/matrix-org/dendrite/appservice/api"
"github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/roomserver" "github.com/matrix-org/dendrite/roomserver"
"github.com/matrix-org/dendrite/setup/config" "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/test"
"github.com/matrix-org/dendrite/userapi" "github.com/matrix-org/dendrite/userapi"
@ -104,11 +108,11 @@ func TestAppserviceInternalAPI(t *testing.T) {
} }
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
base, closeBase := testrig.CreateBaseDendrite(t, dbType) cfg, ctx, close := testrig.CreateConfig(t, dbType)
defer closeBase() defer close()
// Create a dummy application service // Create a dummy application service
base.Cfg.AppServiceAPI.Derived.ApplicationServices = []config.ApplicationService{ cfg.AppServiceAPI.Derived.ApplicationServices = []config.ApplicationService{
{ {
ID: "someID", ID: "someID",
URL: srv.URL, URL: srv.URL,
@ -123,10 +127,17 @@ func TestAppserviceInternalAPI(t *testing.T) {
}, },
} }
t.Cleanup(func() {
ctx.ShutdownDendrite()
ctx.WaitForShutdown()
})
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
// Create required internal APIs // Create required internal APIs
rsAPI := roomserver.NewInternalAPI(base) natsInstance := jetstream.NATSInstance{}
usrAPI := userapi.NewInternalAPI(base, rsAPI, nil) cm := sqlutil.NewConnectionManager(ctx, cfg.Global.DatabaseOptions)
asAPI := appservice.NewInternalAPI(base, usrAPI, rsAPI) rsAPI := roomserver.NewInternalAPI(ctx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
usrAPI := userapi.NewInternalAPI(ctx, cfg, cm, &natsInstance, rsAPI, nil)
asAPI := appservice.NewInternalAPI(ctx, cfg, &natsInstance, usrAPI, rsAPI)
runCases(t, asAPI) runCases(t, asAPI)
}) })

View file

@ -29,11 +29,14 @@ import (
"github.com/matrix-org/dendrite/cmd/dendrite-demo-pinecone/rooms" "github.com/matrix-org/dendrite/cmd/dendrite-demo-pinecone/rooms"
"github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/signing" "github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/signing"
"github.com/matrix-org/dendrite/federationapi" "github.com/matrix-org/dendrite/federationapi"
"github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/httputil" "github.com/matrix-org/dendrite/internal/httputil"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/roomserver" "github.com/matrix-org/dendrite/roomserver"
"github.com/matrix-org/dendrite/setup" "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/config"
"github.com/matrix-org/dendrite/setup/jetstream"
"github.com/matrix-org/dendrite/setup/process"
"github.com/matrix-org/dendrite/userapi" "github.com/matrix-org/dendrite/userapi"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
@ -157,9 +160,8 @@ func startup() {
pManager.AddPeer("wss://pinecone.matrix.org/public") pManager.AddPeer("wss://pinecone.matrix.org/public")
cfg := &config.Dendrite{} cfg := &config.Dendrite{}
cfg.Defaults(true) cfg.Defaults(config.DefaultOpts{Generate: true, SingleDatabase: false})
cfg.UserAPI.AccountDatabase.ConnectionString = "file:/idb/dendritejs_account.db" cfg.UserAPI.AccountDatabase.ConnectionString = "file:/idb/dendritejs_account.db"
cfg.AppServiceAPI.Database.ConnectionString = "file:/idb/dendritejs_appservice.db"
cfg.FederationAPI.Database.ConnectionString = "file:/idb/dendritejs_fedsender.db" cfg.FederationAPI.Database.ConnectionString = "file:/idb/dendritejs_fedsender.db"
cfg.MediaAPI.Database.ConnectionString = "file:/idb/dendritejs_mediaapi.db" cfg.MediaAPI.Database.ConnectionString = "file:/idb/dendritejs_mediaapi.db"
cfg.RoomServer.Database.ConnectionString = "file:/idb/dendritejs_roomserver.db" cfg.RoomServer.Database.ConnectionString = "file:/idb/dendritejs_roomserver.db"
@ -176,28 +178,30 @@ func startup() {
if err := cfg.Derive(); err != nil { if err := cfg.Derive(); err != nil {
logrus.Fatalf("Failed to derive values from config: %s", err) logrus.Fatalf("Failed to derive values from config: %s", err)
} }
base := base.NewBaseDendrite(cfg) natsInstance := jetstream.NATSInstance{}
defer base.Close() // nolint: errcheck processCtx := process.NewProcessContext()
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
routers := httputil.NewRouters()
caches := caching.NewRistrettoCache(cfg.Global.Cache.EstimatedMaxSize, cfg.Global.Cache.MaxAge, caching.EnableMetrics)
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.EnableMetrics)
rsAPI := roomserver.NewInternalAPI(base) federation := conn.CreateFederationClient(cfg, pSessions)
federation := conn.CreateFederationClient(base, pSessions)
serverKeyAPI := &signing.YggdrasilKeys{} serverKeyAPI := &signing.YggdrasilKeys{}
keyRing := serverKeyAPI.KeyRing() keyRing := serverKeyAPI.KeyRing()
userAPI := userapi.NewInternalAPI(base, rsAPI, federation) userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, federation)
asQuery := appservice.NewInternalAPI( asQuery := appservice.NewInternalAPI(
base, userAPI, rsAPI, processCtx, cfg, &natsInstance, userAPI, rsAPI,
) )
rsAPI.SetAppserviceAPI(asQuery) rsAPI.SetAppserviceAPI(asQuery)
fedSenderAPI := federationapi.NewInternalAPI(base, federation, rsAPI, base.Caches, keyRing, true) fedSenderAPI := federationapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, federation, rsAPI, caches, keyRing, true)
rsAPI.SetFederationAPI(fedSenderAPI, keyRing) rsAPI.SetFederationAPI(fedSenderAPI, keyRing)
monolith := setup.Monolith{ monolith := setup.Monolith{
Config: base.Cfg, Config: cfg,
Client: conn.CreateClient(base, pSessions), Client: conn.CreateClient(pSessions),
FedClient: federation, FedClient: federation,
KeyRing: keyRing, KeyRing: keyRing,
@ -208,15 +212,15 @@ func startup() {
//ServerKeyAPI: serverKeyAPI, //ServerKeyAPI: serverKeyAPI,
ExtPublicRoomsProvider: rooms.NewPineconeRoomProvider(pRouter, pSessions, fedSenderAPI, federation), ExtPublicRoomsProvider: rooms.NewPineconeRoomProvider(pRouter, pSessions, fedSenderAPI, federation),
} }
monolith.AddAllPublicRoutes(base) monolith.AddAllPublicRoutes(processCtx, cfg, routers, cm, &natsInstance, caches, caching.EnableMetrics)
httpRouter := mux.NewRouter().SkipClean(true).UseEncodedPath() httpRouter := mux.NewRouter().SkipClean(true).UseEncodedPath()
httpRouter.PathPrefix(httputil.PublicClientPathPrefix).Handler(base.PublicClientAPIMux) httpRouter.PathPrefix(httputil.PublicClientPathPrefix).Handler(routers.Client)
httpRouter.PathPrefix(httputil.PublicMediaPathPrefix).Handler(base.PublicMediaAPIMux) httpRouter.PathPrefix(httputil.PublicMediaPathPrefix).Handler(routers.Media)
p2pRouter := pSessions.Protocol("matrix").HTTP().Mux() p2pRouter := pSessions.Protocol("matrix").HTTP().Mux()
p2pRouter.Handle(httputil.PublicFederationPathPrefix, base.PublicFederationAPIMux) p2pRouter.Handle(httputil.PublicFederationPathPrefix, routers.Federation)
p2pRouter.Handle(httputil.PublicMediaPathPrefix, base.PublicMediaAPIMux) p2pRouter.Handle(httputil.PublicMediaPathPrefix, routers.Media)
// Expose the matrix APIs via fetch - for local traffic // Expose the matrix APIs via fetch - for local traffic
go func() { go func() {

View file

@ -30,6 +30,9 @@ import (
"github.com/matrix-org/dendrite/cmd/dendrite-demo-pinecone/relay" "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/cmd/dendrite-demo-yggdrasil/signing"
"github.com/matrix-org/dendrite/federationapi/api" "github.com/matrix-org/dendrite/federationapi/api"
"github.com/matrix-org/dendrite/internal/httputil"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/setup/process"
userapiAPI "github.com/matrix-org/dendrite/userapi/api" userapiAPI "github.com/matrix-org/dendrite/userapi/api"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/pinecone/types" "github.com/matrix-org/pinecone/types"
@ -187,7 +190,7 @@ func (m *DendriteMonolith) SetRelayServers(nodeID string, uris string) {
relay.UpdateNodeRelayServers( relay.UpdateNodeRelayServers(
gomatrixserverlib.ServerName(nodeKey), gomatrixserverlib.ServerName(nodeKey),
relays, relays,
m.p2pMonolith.BaseDendrite.Context(), m.p2pMonolith.ProcessCtx.Context(),
m.p2pMonolith.GetFederationAPI(), m.p2pMonolith.GetFederationAPI(),
) )
} }
@ -214,7 +217,7 @@ func (m *DendriteMonolith) GetRelayServers(nodeID string) string {
} else { } else {
request := api.P2PQueryRelayServersRequest{Server: gomatrixserverlib.ServerName(nodeKey)} request := api.P2PQueryRelayServersRequest{Server: gomatrixserverlib.ServerName(nodeKey)}
response := api.P2PQueryRelayServersResponse{} response := api.P2PQueryRelayServersResponse{}
err := m.p2pMonolith.GetFederationAPI().P2PQueryRelayServers(m.p2pMonolith.BaseDendrite.Context(), &request, &response) err := m.p2pMonolith.GetFederationAPI().P2PQueryRelayServers(m.p2pMonolith.ProcessCtx.Context(), &request, &response)
if err != nil { if err != nil {
logrus.Warnf("Failed obtaining list of this node's relay servers: %s", err.Error()) logrus.Warnf("Failed obtaining list of this node's relay servers: %s", err.Error())
return "" return ""
@ -346,10 +349,14 @@ func (m *DendriteMonolith) Start() {
// This isn't actually fixed: https://github.com/blevesearch/zapx/pull/147 // This isn't actually fixed: https://github.com/blevesearch/zapx/pull/147
cfg.SyncAPI.Fulltext.Enabled = false cfg.SyncAPI.Fulltext.Enabled = false
processCtx := process.NewProcessContext()
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
routers := httputil.NewRouters()
enableRelaying := false enableRelaying := false
enableMetrics := false enableMetrics := false
enableWebsockets := false enableWebsockets := false
m.p2pMonolith.SetupDendrite(cfg, 65432, enableRelaying, enableMetrics, enableWebsockets) m.p2pMonolith.SetupDendrite(processCtx, cfg, cm, routers, 65432, enableRelaying, enableMetrics, enableWebsockets)
m.p2pMonolith.StartMonolith() m.p2pMonolith.StartMonolith()
} }

View file

@ -12,6 +12,7 @@ import (
"path/filepath" "path/filepath"
"time" "time"
"github.com/getsentry/sentry-go"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/matrix-org/dendrite/appservice" "github.com/matrix-org/dendrite/appservice"
"github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/signing" "github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/signing"
@ -19,11 +20,15 @@ import (
"github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/yggrooms" "github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/yggrooms"
"github.com/matrix-org/dendrite/federationapi" "github.com/matrix-org/dendrite/federationapi"
"github.com/matrix-org/dendrite/federationapi/api" "github.com/matrix-org/dendrite/federationapi/api"
"github.com/matrix-org/dendrite/internal"
"github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/httputil" "github.com/matrix-org/dendrite/internal/httputil"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/roomserver" "github.com/matrix-org/dendrite/roomserver"
"github.com/matrix-org/dendrite/setup" "github.com/matrix-org/dendrite/setup"
"github.com/matrix-org/dendrite/setup/base" basepkg "github.com/matrix-org/dendrite/setup/base"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/dendrite/setup/jetstream"
"github.com/matrix-org/dendrite/setup/process" "github.com/matrix-org/dendrite/setup/process"
"github.com/matrix-org/dendrite/test" "github.com/matrix-org/dendrite/test"
"github.com/matrix-org/dendrite/userapi" "github.com/matrix-org/dendrite/userapi"
@ -148,25 +153,71 @@ func (m *DendriteMonolith) Start() {
panic(err) panic(err)
} }
base := base.NewBaseDendrite(cfg) configErrors := &config.ConfigErrors{}
base.ConfigureAdminEndpoints() cfg.Verify(configErrors)
m.processContext = base.ProcessContext if len(*configErrors) > 0 {
defer base.Close() // nolint: errcheck for _, err := range *configErrors {
logrus.Errorf("Configuration error: %s", err)
}
logrus.Fatalf("Failed to start due to configuration errors")
}
federation := ygg.CreateFederationClient(base) internal.SetupStdLogging()
internal.SetupHookLogging(cfg.Logging)
internal.SetupPprof()
logrus.Infof("Dendrite version %s", internal.VersionString())
if !cfg.ClientAPI.RegistrationDisabled && cfg.ClientAPI.OpenRegistrationWithoutVerificationEnabled {
logrus.Warn("Open registration is enabled")
}
closer, err := cfg.SetupTracing()
if err != nil {
logrus.WithError(err).Panicf("failed to start opentracing")
}
defer closer.Close()
if cfg.Global.Sentry.Enabled {
logrus.Info("Setting up Sentry for debugging...")
err = sentry.Init(sentry.ClientOptions{
Dsn: cfg.Global.Sentry.DSN,
Environment: cfg.Global.Sentry.Environment,
Debug: true,
ServerName: string(cfg.Global.ServerName),
Release: "dendrite@" + internal.VersionString(),
AttachStacktrace: true,
})
if err != nil {
logrus.WithError(err).Panic("failed to start Sentry")
}
}
processCtx := process.NewProcessContext()
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
routers := httputil.NewRouters()
basepkg.ConfigureAdminEndpoints(processCtx, routers)
m.processContext = processCtx
defer func() {
processCtx.ShutdownDendrite()
processCtx.WaitForShutdown()
}() // nolint: errcheck
federation := ygg.CreateFederationClient(cfg)
serverKeyAPI := &signing.YggdrasilKeys{} serverKeyAPI := &signing.YggdrasilKeys{}
keyRing := serverKeyAPI.KeyRing() keyRing := serverKeyAPI.KeyRing()
rsAPI := roomserver.NewInternalAPI(base) caches := caching.NewRistrettoCache(cfg.Global.Cache.EstimatedMaxSize, cfg.Global.Cache.MaxAge, caching.EnableMetrics)
natsInstance := jetstream.NATSInstance{}
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.EnableMetrics)
fsAPI := federationapi.NewInternalAPI( fsAPI := federationapi.NewInternalAPI(
base, federation, rsAPI, base.Caches, keyRing, true, processCtx, cfg, cm, &natsInstance, federation, rsAPI, caches, keyRing, true,
) )
userAPI := userapi.NewInternalAPI(base, rsAPI, federation) userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, federation)
asAPI := appservice.NewInternalAPI(base, userAPI, rsAPI) asAPI := appservice.NewInternalAPI(processCtx, cfg, &natsInstance, userAPI, rsAPI)
rsAPI.SetAppserviceAPI(asAPI) rsAPI.SetAppserviceAPI(asAPI)
// The underlying roomserver implementation needs to be able to call the fedsender. // The underlying roomserver implementation needs to be able to call the fedsender.
@ -174,8 +225,8 @@ func (m *DendriteMonolith) Start() {
rsAPI.SetFederationAPI(fsAPI, keyRing) rsAPI.SetFederationAPI(fsAPI, keyRing)
monolith := setup.Monolith{ monolith := setup.Monolith{
Config: base.Cfg, Config: cfg,
Client: ygg.CreateClient(base), Client: ygg.CreateClient(),
FedClient: federation, FedClient: federation,
KeyRing: keyRing, KeyRing: keyRing,
@ -187,17 +238,17 @@ func (m *DendriteMonolith) Start() {
ygg, fsAPI, federation, ygg, fsAPI, federation,
), ),
} }
monolith.AddAllPublicRoutes(base) monolith.AddAllPublicRoutes(processCtx, cfg, routers, cm, &natsInstance, caches, caching.EnableMetrics)
httpRouter := mux.NewRouter() httpRouter := mux.NewRouter()
httpRouter.PathPrefix(httputil.PublicClientPathPrefix).Handler(base.PublicClientAPIMux) httpRouter.PathPrefix(httputil.PublicClientPathPrefix).Handler(routers.Client)
httpRouter.PathPrefix(httputil.PublicMediaPathPrefix).Handler(base.PublicMediaAPIMux) httpRouter.PathPrefix(httputil.PublicMediaPathPrefix).Handler(routers.Media)
httpRouter.PathPrefix(httputil.DendriteAdminPathPrefix).Handler(base.DendriteAdminMux) httpRouter.PathPrefix(httputil.DendriteAdminPathPrefix).Handler(routers.DendriteAdmin)
httpRouter.PathPrefix(httputil.SynapseAdminPathPrefix).Handler(base.SynapseAdminMux) httpRouter.PathPrefix(httputil.SynapseAdminPathPrefix).Handler(routers.SynapseAdmin)
yggRouter := mux.NewRouter() yggRouter := mux.NewRouter()
yggRouter.PathPrefix(httputil.PublicFederationPathPrefix).Handler(base.PublicFederationAPIMux) yggRouter.PathPrefix(httputil.PublicFederationPathPrefix).Handler(routers.Federation)
yggRouter.PathPrefix(httputil.PublicMediaPathPrefix).Handler(base.PublicMediaAPIMux) yggRouter.PathPrefix(httputil.PublicMediaPathPrefix).Handler(routers.Media)
// Build both ends of a HTTP multiplex. // Build both ends of a HTTP multiplex.
m.httpServer = &http.Server{ m.httpServer = &http.Server{

View file

@ -5,12 +5,17 @@ import (
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"testing" "testing"
"time"
"github.com/matrix-org/dendrite/clientapi/auth/authtypes" "github.com/matrix-org/dendrite/clientapi/auth/authtypes"
"github.com/matrix-org/dendrite/federationapi" "github.com/matrix-org/dendrite/federationapi"
"github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/httputil"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/roomserver" "github.com/matrix-org/dendrite/roomserver"
"github.com/matrix-org/dendrite/roomserver/api" "github.com/matrix-org/dendrite/roomserver/api"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/dendrite/setup/jetstream"
"github.com/matrix-org/dendrite/syncapi" "github.com/matrix-org/dendrite/syncapi"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/util" "github.com/matrix-org/util"
@ -29,19 +34,22 @@ func TestAdminResetPassword(t *testing.T) {
ctx := context.Background() ctx := context.Background()
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
base, baseClose := testrig.CreateBaseDendrite(t, dbType) cfg, processCtx, close := testrig.CreateConfig(t, dbType)
defer baseClose() defer close()
natsInstance := jetstream.NATSInstance{}
// add a vhost // add a vhost
base.Cfg.Global.VirtualHosts = append(base.Cfg.Global.VirtualHosts, &config.VirtualHost{ cfg.Global.VirtualHosts = append(cfg.Global.VirtualHosts, &config.VirtualHost{
SigningIdentity: gomatrixserverlib.SigningIdentity{ServerName: "vh1"}, SigningIdentity: gomatrixserverlib.SigningIdentity{ServerName: "vh1"},
}) })
rsAPI := roomserver.NewInternalAPI(base) routers := httputil.NewRouters()
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
// Needed for changing the password/login // Needed for changing the password/login
userAPI := userapi.NewInternalAPI(base, rsAPI, nil) userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil)
// We mostly need the userAPI for this test, so nil for other APIs/caches etc. // We mostly need the userAPI for this test, so nil for other APIs/caches etc.
AddPublicRoutes(base, nil, rsAPI, nil, nil, nil, userAPI, nil, nil) AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, rsAPI, nil, nil, nil, userAPI, nil, nil, caching.DisableMetrics)
// Create the users in the userapi and login // Create the users in the userapi and login
accessTokens := map[*test.User]string{ accessTokens := map[*test.User]string{
@ -71,7 +79,7 @@ func TestAdminResetPassword(t *testing.T) {
"password": password, "password": password,
})) }))
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
base.PublicClientAPIMux.ServeHTTP(rec, req) routers.Client.ServeHTTP(rec, req)
if rec.Code != http.StatusOK { if rec.Code != http.StatusOK {
t.Fatalf("failed to login: %s", rec.Body.String()) t.Fatalf("failed to login: %s", rec.Body.String())
} }
@ -124,7 +132,7 @@ func TestAdminResetPassword(t *testing.T) {
} }
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
base.DendriteAdminMux.ServeHTTP(rec, req) routers.DendriteAdmin.ServeHTTP(rec, req)
t.Logf("%s", rec.Body.String()) t.Logf("%s", rec.Body.String())
if tc.wantOK && rec.Code != http.StatusOK { if tc.wantOK && rec.Code != http.StatusOK {
t.Fatalf("expected http status %d, got %d: %s", http.StatusOK, rec.Code, rec.Body.String()) t.Fatalf("expected http status %d, got %d: %s", http.StatusOK, rec.Code, rec.Body.String())
@ -147,16 +155,19 @@ func TestPurgeRoom(t *testing.T) {
ctx := context.Background() ctx := context.Background()
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
base, baseClose := testrig.CreateBaseDendrite(t, dbType) cfg, processCtx, close := testrig.CreateConfig(t, dbType)
defer baseClose() caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
natsInstance := jetstream.NATSInstance{}
defer close()
fedClient := base.CreateFederationClient() routers := httputil.NewRouters()
rsAPI := roomserver.NewInternalAPI(base) cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
userAPI := userapi.NewInternalAPI(base, rsAPI, nil) rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil)
// this starts the JetStream consumers // this starts the JetStream consumers
syncapi.AddPublicRoutes(base, userAPI, rsAPI) syncapi.AddPublicRoutes(processCtx, routers, cfg, cm, &natsInstance, userAPI, rsAPI, caches, caching.DisableMetrics)
federationapi.NewInternalAPI(base, fedClient, rsAPI, base.Caches, nil, true) federationapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, nil, rsAPI, caches, nil, true)
rsAPI.SetFederationAPI(nil, nil) rsAPI.SetFederationAPI(nil, nil)
// Create the room // Create the room
@ -165,7 +176,7 @@ func TestPurgeRoom(t *testing.T) {
} }
// We mostly need the rsAPI for this test, so nil for other APIs/caches etc. // We mostly need the rsAPI for this test, so nil for other APIs/caches etc.
AddPublicRoutes(base, nil, rsAPI, nil, nil, nil, userAPI, nil, nil) AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, rsAPI, nil, nil, nil, userAPI, nil, nil, caching.DisableMetrics)
// Create the users in the userapi and login // Create the users in the userapi and login
accessTokens := map[*test.User]string{ accessTokens := map[*test.User]string{
@ -193,7 +204,7 @@ func TestPurgeRoom(t *testing.T) {
"password": password, "password": password,
})) }))
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
base.PublicClientAPIMux.ServeHTTP(rec, req) routers.Client.ServeHTTP(rec, req)
if rec.Code != http.StatusOK { if rec.Code != http.StatusOK {
t.Fatalf("failed to login: %s", rec.Body.String()) t.Fatalf("failed to login: %s", rec.Body.String())
} }
@ -218,7 +229,7 @@ func TestPurgeRoom(t *testing.T) {
req.Header.Set("Authorization", "Bearer "+accessTokens[aliceAdmin]) req.Header.Set("Authorization", "Bearer "+accessTokens[aliceAdmin])
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
base.DendriteAdminMux.ServeHTTP(rec, req) routers.DendriteAdmin.ServeHTTP(rec, req)
t.Logf("%s", rec.Body.String()) t.Logf("%s", rec.Body.String())
if tc.wantOK && rec.Code != http.StatusOK { if tc.wantOK && rec.Code != http.StatusOK {
t.Fatalf("expected http status %d, got %d: %s", http.StatusOK, rec.Code, rec.Body.String()) t.Fatalf("expected http status %d, got %d: %s", http.StatusOK, rec.Code, rec.Body.String())

View file

@ -15,6 +15,9 @@
package clientapi package clientapi
import ( import (
"github.com/matrix-org/dendrite/internal/httputil"
"github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/dendrite/setup/process"
userapi "github.com/matrix-org/dendrite/userapi/api" userapi "github.com/matrix-org/dendrite/userapi/api"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
@ -25,13 +28,15 @@ import (
federationAPI "github.com/matrix-org/dendrite/federationapi/api" federationAPI "github.com/matrix-org/dendrite/federationapi/api"
"github.com/matrix-org/dendrite/internal/transactions" "github.com/matrix-org/dendrite/internal/transactions"
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api" roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
"github.com/matrix-org/dendrite/setup/base"
"github.com/matrix-org/dendrite/setup/jetstream" "github.com/matrix-org/dendrite/setup/jetstream"
) )
// AddPublicRoutes sets up and registers HTTP handlers for the ClientAPI component. // AddPublicRoutes sets up and registers HTTP handlers for the ClientAPI component.
func AddPublicRoutes( func AddPublicRoutes(
base *base.BaseDendrite, processContext *process.ProcessContext,
routers httputil.Routers,
cfg *config.Dendrite,
natsInstance *jetstream.NATSInstance,
federation *gomatrixserverlib.FederationClient, federation *gomatrixserverlib.FederationClient,
rsAPI roomserverAPI.ClientRoomserverAPI, rsAPI roomserverAPI.ClientRoomserverAPI,
asAPI appserviceAPI.AppServiceInternalAPI, asAPI appserviceAPI.AppServiceInternalAPI,
@ -39,27 +44,25 @@ func AddPublicRoutes(
fsAPI federationAPI.ClientFederationAPI, fsAPI federationAPI.ClientFederationAPI,
userAPI userapi.ClientUserAPI, userAPI userapi.ClientUserAPI,
userDirectoryProvider userapi.QuerySearchProfilesAPI, userDirectoryProvider userapi.QuerySearchProfilesAPI,
extRoomsProvider api.ExtraPublicRoomsProvider, extRoomsProvider api.ExtraPublicRoomsProvider, enableMetrics bool,
) { ) {
cfg := &base.Cfg.ClientAPI js, natsClient := natsInstance.Prepare(processContext, &cfg.Global.JetStream)
mscCfg := &base.Cfg.MSCs
js, natsClient := base.NATS.Prepare(base.ProcessContext, &cfg.Matrix.JetStream)
syncProducer := &producers.SyncAPIProducer{ syncProducer := &producers.SyncAPIProducer{
JetStream: js, JetStream: js,
TopicReceiptEvent: cfg.Matrix.JetStream.Prefixed(jetstream.OutputReceiptEvent), TopicReceiptEvent: cfg.Global.JetStream.Prefixed(jetstream.OutputReceiptEvent),
TopicSendToDeviceEvent: cfg.Matrix.JetStream.Prefixed(jetstream.OutputSendToDeviceEvent), TopicSendToDeviceEvent: cfg.Global.JetStream.Prefixed(jetstream.OutputSendToDeviceEvent),
TopicTypingEvent: cfg.Matrix.JetStream.Prefixed(jetstream.OutputTypingEvent), TopicTypingEvent: cfg.Global.JetStream.Prefixed(jetstream.OutputTypingEvent),
TopicPresenceEvent: cfg.Matrix.JetStream.Prefixed(jetstream.OutputPresenceEvent), TopicPresenceEvent: cfg.Global.JetStream.Prefixed(jetstream.OutputPresenceEvent),
UserAPI: userAPI, UserAPI: userAPI,
ServerName: cfg.Matrix.ServerName, ServerName: cfg.Global.ServerName,
} }
routing.Setup( routing.Setup(
base, routers,
cfg, rsAPI, asAPI, cfg, rsAPI, asAPI,
userAPI, userDirectoryProvider, federation, userAPI, userDirectoryProvider, federation,
syncProducer, transactionsCache, fsAPI, syncProducer, transactionsCache, fsAPI,
extRoomsProvider, mscCfg, natsClient, extRoomsProvider, natsClient, enableMetrics,
) )
} }

View file

@ -10,30 +10,28 @@ import (
"github.com/matrix-org/dendrite/clientapi/auth/authtypes" "github.com/matrix-org/dendrite/clientapi/auth/authtypes"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/dendrite/test/testrig"
) )
func Test_AuthFallback(t *testing.T) { func Test_AuthFallback(t *testing.T) {
base, _, _ := testrig.Base(nil) cfg := config.Dendrite{}
defer base.Close() cfg.Defaults(config.DefaultOpts{Generate: true, SingleDatabase: true})
for _, useHCaptcha := range []bool{false, true} { for _, useHCaptcha := range []bool{false, true} {
for _, recaptchaEnabled := range []bool{false, true} { for _, recaptchaEnabled := range []bool{false, true} {
for _, wantErr := range []bool{false, true} { for _, wantErr := range []bool{false, true} {
t.Run(fmt.Sprintf("useHCaptcha(%v) - recaptchaEnabled(%v) - wantErr(%v)", useHCaptcha, recaptchaEnabled, wantErr), func(t *testing.T) { t.Run(fmt.Sprintf("useHCaptcha(%v) - recaptchaEnabled(%v) - wantErr(%v)", useHCaptcha, recaptchaEnabled, wantErr), func(t *testing.T) {
// Set the defaults for each test // Set the defaults for each test
base.Cfg.ClientAPI.Defaults(config.DefaultOpts{Generate: true, SingleDatabase: true}) cfg.ClientAPI.Defaults(config.DefaultOpts{Generate: true, SingleDatabase: true})
base.Cfg.ClientAPI.RecaptchaEnabled = recaptchaEnabled cfg.ClientAPI.RecaptchaEnabled = recaptchaEnabled
base.Cfg.ClientAPI.RecaptchaPublicKey = "pub" cfg.ClientAPI.RecaptchaPublicKey = "pub"
base.Cfg.ClientAPI.RecaptchaPrivateKey = "priv" cfg.ClientAPI.RecaptchaPrivateKey = "priv"
if useHCaptcha { if useHCaptcha {
base.Cfg.ClientAPI.RecaptchaSiteVerifyAPI = "https://hcaptcha.com/siteverify" cfg.ClientAPI.RecaptchaSiteVerifyAPI = "https://hcaptcha.com/siteverify"
base.Cfg.ClientAPI.RecaptchaApiJsUrl = "https://js.hcaptcha.com/1/api.js" cfg.ClientAPI.RecaptchaApiJsUrl = "https://js.hcaptcha.com/1/api.js"
base.Cfg.ClientAPI.RecaptchaFormField = "h-captcha-response" cfg.ClientAPI.RecaptchaFormField = "h-captcha-response"
base.Cfg.ClientAPI.RecaptchaSitekeyClass = "h-captcha" cfg.ClientAPI.RecaptchaSitekeyClass = "h-captcha"
} }
cfgErrs := &config.ConfigErrors{} cfgErrs := &config.ConfigErrors{}
base.Cfg.ClientAPI.Verify(cfgErrs) cfg.ClientAPI.Verify(cfgErrs)
if len(*cfgErrs) > 0 { if len(*cfgErrs) > 0 {
t.Fatalf("(hCaptcha=%v) unexpected config errors: %s", useHCaptcha, cfgErrs.Error()) t.Fatalf("(hCaptcha=%v) unexpected config errors: %s", useHCaptcha, cfgErrs.Error())
} }
@ -41,7 +39,7 @@ func Test_AuthFallback(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/?session=1337", nil) req := httptest.NewRequest(http.MethodGet, "/?session=1337", nil)
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
AuthFallback(rec, req, authtypes.LoginTypeRecaptcha, &base.Cfg.ClientAPI) AuthFallback(rec, req, authtypes.LoginTypeRecaptcha, &cfg.ClientAPI)
if !recaptchaEnabled { if !recaptchaEnabled {
if rec.Code != http.StatusBadRequest { if rec.Code != http.StatusBadRequest {
t.Fatalf("unexpected response code: %d, want %d", rec.Code, http.StatusBadRequest) t.Fatalf("unexpected response code: %d, want %d", rec.Code, http.StatusBadRequest)
@ -50,8 +48,8 @@ func Test_AuthFallback(t *testing.T) {
t.Fatalf("unexpected response body: %s", rec.Body.String()) t.Fatalf("unexpected response body: %s", rec.Body.String())
} }
} else { } else {
if !strings.Contains(rec.Body.String(), base.Cfg.ClientAPI.RecaptchaSitekeyClass) { if !strings.Contains(rec.Body.String(), cfg.ClientAPI.RecaptchaSitekeyClass) {
t.Fatalf("body does not contain %s: %s", base.Cfg.ClientAPI.RecaptchaSitekeyClass, rec.Body.String()) t.Fatalf("body does not contain %s: %s", cfg.ClientAPI.RecaptchaSitekeyClass, rec.Body.String())
} }
} }
@ -64,14 +62,14 @@ func Test_AuthFallback(t *testing.T) {
})) }))
defer srv.Close() // nolint: errcheck defer srv.Close() // nolint: errcheck
base.Cfg.ClientAPI.RecaptchaSiteVerifyAPI = srv.URL cfg.ClientAPI.RecaptchaSiteVerifyAPI = srv.URL
// check the result after sending the captcha // check the result after sending the captcha
req = httptest.NewRequest(http.MethodPost, "/?session=1337", nil) req = httptest.NewRequest(http.MethodPost, "/?session=1337", nil)
req.Form = url.Values{} req.Form = url.Values{}
req.Form.Add(base.Cfg.ClientAPI.RecaptchaFormField, "someRandomValue") req.Form.Add(cfg.ClientAPI.RecaptchaFormField, "someRandomValue")
rec = httptest.NewRecorder() rec = httptest.NewRecorder()
AuthFallback(rec, req, authtypes.LoginTypeRecaptcha, &base.Cfg.ClientAPI) AuthFallback(rec, req, authtypes.LoginTypeRecaptcha, &cfg.ClientAPI)
if recaptchaEnabled { if recaptchaEnabled {
if !wantErr { if !wantErr {
if rec.Code != http.StatusOK { if rec.Code != http.StatusOK {
@ -105,7 +103,7 @@ func Test_AuthFallback(t *testing.T) {
t.Run("unknown fallbacks are handled correctly", func(t *testing.T) { t.Run("unknown fallbacks are handled correctly", func(t *testing.T) {
req := httptest.NewRequest(http.MethodPost, "/?session=1337", nil) req := httptest.NewRequest(http.MethodPost, "/?session=1337", nil)
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
AuthFallback(rec, req, "DoesNotExist", &base.Cfg.ClientAPI) AuthFallback(rec, req, "DoesNotExist", &cfg.ClientAPI)
if rec.Code != http.StatusNotImplemented { if rec.Code != http.StatusNotImplemented {
t.Fatalf("unexpected http status: %d, want %d", rec.Code, http.StatusNotImplemented) t.Fatalf("unexpected http status: %d, want %d", rec.Code, http.StatusNotImplemented)
} }
@ -114,7 +112,7 @@ func Test_AuthFallback(t *testing.T) {
t.Run("unknown methods are handled correctly", func(t *testing.T) { t.Run("unknown methods are handled correctly", func(t *testing.T) {
req := httptest.NewRequest(http.MethodDelete, "/?session=1337", nil) req := httptest.NewRequest(http.MethodDelete, "/?session=1337", nil)
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
AuthFallback(rec, req, authtypes.LoginTypeRecaptcha, &base.Cfg.ClientAPI) AuthFallback(rec, req, authtypes.LoginTypeRecaptcha, &cfg.ClientAPI)
if rec.Code != http.StatusMethodNotAllowed { if rec.Code != http.StatusMethodNotAllowed {
t.Fatalf("unexpected http status: %d, want %d", rec.Code, http.StatusMethodNotAllowed) t.Fatalf("unexpected http status: %d, want %d", rec.Code, http.StatusMethodNotAllowed)
} }
@ -123,7 +121,7 @@ func Test_AuthFallback(t *testing.T) {
t.Run("missing session parameter is handled correctly", func(t *testing.T) { t.Run("missing session parameter is handled correctly", func(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/", nil) req := httptest.NewRequest(http.MethodGet, "/", nil)
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
AuthFallback(rec, req, authtypes.LoginTypeRecaptcha, &base.Cfg.ClientAPI) AuthFallback(rec, req, authtypes.LoginTypeRecaptcha, &cfg.ClientAPI)
if rec.Code != http.StatusBadRequest { if rec.Code != http.StatusBadRequest {
t.Fatalf("unexpected http status: %d, want %d", rec.Code, http.StatusBadRequest) t.Fatalf("unexpected http status: %d, want %d", rec.Code, http.StatusBadRequest)
} }
@ -132,7 +130,7 @@ func Test_AuthFallback(t *testing.T) {
t.Run("missing session parameter is handled correctly", func(t *testing.T) { t.Run("missing session parameter is handled correctly", func(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/", nil) req := httptest.NewRequest(http.MethodGet, "/", nil)
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
AuthFallback(rec, req, authtypes.LoginTypeRecaptcha, &base.Cfg.ClientAPI) AuthFallback(rec, req, authtypes.LoginTypeRecaptcha, &cfg.ClientAPI)
if rec.Code != http.StatusBadRequest { if rec.Code != http.StatusBadRequest {
t.Fatalf("unexpected http status: %d, want %d", rec.Code, http.StatusBadRequest) t.Fatalf("unexpected http status: %d, want %d", rec.Code, http.StatusBadRequest)
} }
@ -141,7 +139,7 @@ func Test_AuthFallback(t *testing.T) {
t.Run("missing 'response' is handled correctly", func(t *testing.T) { t.Run("missing 'response' is handled correctly", func(t *testing.T) {
req := httptest.NewRequest(http.MethodPost, "/?session=1337", nil) req := httptest.NewRequest(http.MethodPost, "/?session=1337", nil)
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
AuthFallback(rec, req, authtypes.LoginTypeRecaptcha, &base.Cfg.ClientAPI) AuthFallback(rec, req, authtypes.LoginTypeRecaptcha, &cfg.ClientAPI)
if rec.Code != http.StatusBadRequest { if rec.Code != http.StatusBadRequest {
t.Fatalf("unexpected http status: %d, want %d", rec.Code, http.StatusBadRequest) t.Fatalf("unexpected http status: %d, want %d", rec.Code, http.StatusBadRequest)
} }

View file

@ -7,6 +7,9 @@ import (
"testing" "testing"
"time" "time"
"github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/setup/jetstream"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/dendrite/appservice" "github.com/matrix-org/dendrite/appservice"
@ -24,12 +27,15 @@ func TestJoinRoomByIDOrAlias(t *testing.T) {
ctx := context.Background() ctx := context.Background()
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
base, baseClose := testrig.CreateBaseDendrite(t, dbType) cfg, processCtx, close := testrig.CreateConfig(t, dbType)
defer baseClose() defer close()
rsAPI := roomserver.NewInternalAPI(base) cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
userAPI := userapi.NewInternalAPI(base, rsAPI, nil) caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
asAPI := appservice.NewInternalAPI(base, userAPI, rsAPI) natsInstance := jetstream.NATSInstance{}
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil)
asAPI := appservice.NewInternalAPI(processCtx, cfg, &natsInstance, userAPI, rsAPI)
rsAPI.SetFederationAPI(nil, nil) // creates the rs.Inputer etc rsAPI.SetFederationAPI(nil, nil) // creates the rs.Inputer etc
// Create the users in the userapi // Create the users in the userapi
@ -61,7 +67,7 @@ func TestJoinRoomByIDOrAlias(t *testing.T) {
RoomAliasName: "alias", RoomAliasName: "alias",
Invite: []string{bob.ID}, Invite: []string{bob.ID},
GuestCanJoin: false, GuestCanJoin: false,
}, aliceDev, &base.Cfg.ClientAPI, userAPI, rsAPI, asAPI, time.Now()) }, aliceDev, &cfg.ClientAPI, userAPI, rsAPI, asAPI, time.Now())
crResp, ok := resp.JSON.(createRoomResponse) crResp, ok := resp.JSON.(createRoomResponse)
if !ok { if !ok {
t.Fatalf("response is not a createRoomResponse: %+v", resp) t.Fatalf("response is not a createRoomResponse: %+v", resp)
@ -76,7 +82,7 @@ func TestJoinRoomByIDOrAlias(t *testing.T) {
Preset: presetPublicChat, Preset: presetPublicChat,
Invite: []string{charlie.ID}, Invite: []string{charlie.ID},
GuestCanJoin: true, GuestCanJoin: true,
}, aliceDev, &base.Cfg.ClientAPI, userAPI, rsAPI, asAPI, time.Now()) }, aliceDev, &cfg.ClientAPI, userAPI, rsAPI, asAPI, time.Now())
crRespWithGuestAccess, ok := resp.JSON.(createRoomResponse) crRespWithGuestAccess, ok := resp.JSON.(createRoomResponse)
if !ok { if !ok {
t.Fatalf("response is not a createRoomResponse: %+v", resp) t.Fatalf("response is not a createRoomResponse: %+v", resp)

View file

@ -7,10 +7,15 @@ import (
"net/http/httptest" "net/http/httptest"
"strings" "strings"
"testing" "testing"
"time"
"github.com/matrix-org/dendrite/clientapi/auth/authtypes" "github.com/matrix-org/dendrite/clientapi/auth/authtypes"
"github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/httputil"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/roomserver" "github.com/matrix-org/dendrite/roomserver"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/dendrite/setup/jetstream"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/util" "github.com/matrix-org/util"
@ -28,20 +33,24 @@ func TestLogin(t *testing.T) {
ctx := context.Background() ctx := context.Background()
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
base, baseClose := testrig.CreateBaseDendrite(t, dbType) cfg, processCtx, close := testrig.CreateConfig(t, dbType)
defer baseClose() defer close()
base.Cfg.ClientAPI.RateLimiting.Enabled = false cfg.ClientAPI.RateLimiting.Enabled = false
natsInstance := jetstream.NATSInstance{}
// add a vhost // add a vhost
base.Cfg.Global.VirtualHosts = append(base.Cfg.Global.VirtualHosts, &config.VirtualHost{ cfg.Global.VirtualHosts = append(cfg.Global.VirtualHosts, &config.VirtualHost{
SigningIdentity: gomatrixserverlib.SigningIdentity{ServerName: "vh1"}, SigningIdentity: gomatrixserverlib.SigningIdentity{ServerName: "vh1"},
}) })
rsAPI := roomserver.NewInternalAPI(base) cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
routers := httputil.NewRouters()
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
// Needed for /login // Needed for /login
userAPI := userapi.NewInternalAPI(base, rsAPI, nil) userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil)
// We mostly need the userAPI for this test, so nil for other APIs/caches etc. // We mostly need the userAPI for this test, so nil for other APIs/caches etc.
Setup(base, &base.Cfg.ClientAPI, nil, nil, userAPI, nil, nil, nil, nil, nil, nil, &base.Cfg.MSCs, nil) Setup(routers, cfg, nil, nil, userAPI, nil, nil, nil, nil, nil, nil, nil, caching.DisableMetrics)
// Create password // Create password
password := util.RandomString(8) password := util.RandomString(8)
@ -114,7 +123,7 @@ func TestLogin(t *testing.T) {
"password": password, "password": password,
})) }))
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
base.PublicClientAPIMux.ServeHTTP(rec, req) routers.Client.ServeHTTP(rec, req)
if tc.wantOK && rec.Code != http.StatusOK { if tc.wantOK && rec.Code != http.StatusOK {
t.Fatalf("failed to login: %s", rec.Body.String()) t.Fatalf("failed to login: %s", rec.Body.String())
} }

View file

@ -30,8 +30,11 @@ import (
"github.com/matrix-org/dendrite/clientapi/auth/authtypes" "github.com/matrix-org/dendrite/clientapi/auth/authtypes"
"github.com/matrix-org/dendrite/clientapi/jsonerror" "github.com/matrix-org/dendrite/clientapi/jsonerror"
"github.com/matrix-org/dendrite/internal" "github.com/matrix-org/dendrite/internal"
"github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/roomserver" "github.com/matrix-org/dendrite/roomserver"
"github.com/matrix-org/dendrite/setup/config" "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/test"
"github.com/matrix-org/dendrite/test/testrig" "github.com/matrix-org/dendrite/test/testrig"
"github.com/matrix-org/dendrite/userapi" "github.com/matrix-org/dendrite/userapi"
@ -404,11 +407,15 @@ func Test_register(t *testing.T) {
} }
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
base, baseClose := testrig.CreateBaseDendrite(t, dbType) cfg, processCtx, close := testrig.CreateConfig(t, dbType)
defer baseClose() defer close()
rsAPI := roomserver.NewInternalAPI(base) caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
userAPI := userapi.NewInternalAPI(base, rsAPI, nil) natsInstance := jetstream.NATSInstance{}
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil)
for _, tc := range testCases { for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
@ -430,16 +437,16 @@ func Test_register(t *testing.T) {
} }
})) }))
defer srv.Close() defer srv.Close()
base.Cfg.ClientAPI.RecaptchaSiteVerifyAPI = srv.URL cfg.ClientAPI.RecaptchaSiteVerifyAPI = srv.URL
} }
if err := base.Cfg.Derive(); err != nil { if err := cfg.Derive(); err != nil {
t.Fatalf("failed to derive config: %s", err) t.Fatalf("failed to derive config: %s", err)
} }
base.Cfg.ClientAPI.RecaptchaEnabled = tc.enableRecaptcha cfg.ClientAPI.RecaptchaEnabled = tc.enableRecaptcha
base.Cfg.ClientAPI.RegistrationDisabled = tc.registrationDisabled cfg.ClientAPI.RegistrationDisabled = tc.registrationDisabled
base.Cfg.ClientAPI.GuestsDisabled = tc.guestsDisabled cfg.ClientAPI.GuestsDisabled = tc.guestsDisabled
if tc.kind == "" { if tc.kind == "" {
tc.kind = "user" tc.kind = "user"
@ -467,15 +474,15 @@ func Test_register(t *testing.T) {
req := httptest.NewRequest(http.MethodPost, fmt.Sprintf("/?kind=%s", tc.kind), body) req := httptest.NewRequest(http.MethodPost, fmt.Sprintf("/?kind=%s", tc.kind), body)
resp := Register(req, userAPI, &base.Cfg.ClientAPI) resp := Register(req, userAPI, &cfg.ClientAPI)
t.Logf("Resp: %+v", resp) t.Logf("Resp: %+v", resp)
// The first request should return a userInteractiveResponse // The first request should return a userInteractiveResponse
switch r := resp.JSON.(type) { switch r := resp.JSON.(type) {
case userInteractiveResponse: case userInteractiveResponse:
// Check that the flows are the ones we configured // Check that the flows are the ones we configured
if !reflect.DeepEqual(r.Flows, base.Cfg.Derived.Registration.Flows) { if !reflect.DeepEqual(r.Flows, cfg.Derived.Registration.Flows) {
t.Fatalf("unexpected registration flows: %+v, want %+v", r.Flows, base.Cfg.Derived.Registration.Flows) t.Fatalf("unexpected registration flows: %+v, want %+v", r.Flows, cfg.Derived.Registration.Flows)
} }
case *jsonerror.MatrixError: case *jsonerror.MatrixError:
if !reflect.DeepEqual(tc.wantResponse, resp) { if !reflect.DeepEqual(tc.wantResponse, resp) {
@ -531,7 +538,7 @@ func Test_register(t *testing.T) {
req = httptest.NewRequest(http.MethodPost, "/", body) req = httptest.NewRequest(http.MethodPost, "/", body)
resp = Register(req, userAPI, &base.Cfg.ClientAPI) resp = Register(req, userAPI, &cfg.ClientAPI)
switch resp.JSON.(type) { switch resp.JSON.(type) {
case *jsonerror.MatrixError: case *jsonerror.MatrixError:
@ -574,16 +581,19 @@ func Test_register(t *testing.T) {
func TestRegisterUserWithDisplayName(t *testing.T) { func TestRegisterUserWithDisplayName(t *testing.T) {
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
base, baseClose := testrig.CreateBaseDendrite(t, dbType) cfg, processCtx, close := testrig.CreateConfig(t, dbType)
defer baseClose() defer close()
base.Cfg.Global.ServerName = "server" cfg.Global.ServerName = "server"
rsAPI := roomserver.NewInternalAPI(base) caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
userAPI := userapi.NewInternalAPI(base, rsAPI, nil) natsInstance := jetstream.NATSInstance{}
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil)
deviceName, deviceID := "deviceName", "deviceID" deviceName, deviceID := "deviceName", "deviceID"
expectedDisplayName := "DisplayName" expectedDisplayName := "DisplayName"
response := completeRegistration( response := completeRegistration(
base.Context(), processCtx.Context(),
userAPI, userAPI,
"user", "user",
"server", "server",
@ -603,7 +613,7 @@ func TestRegisterUserWithDisplayName(t *testing.T) {
req := api.QueryProfileRequest{UserID: "@user:server"} req := api.QueryProfileRequest{UserID: "@user:server"}
var res api.QueryProfileResponse var res api.QueryProfileResponse
err := userAPI.QueryProfile(base.Context(), &req, &res) err := userAPI.QueryProfile(processCtx.Context(), &req, &res)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, expectedDisplayName, res.DisplayName) assert.Equal(t, expectedDisplayName, res.DisplayName)
}) })
@ -611,14 +621,17 @@ func TestRegisterUserWithDisplayName(t *testing.T) {
func TestRegisterAdminUsingSharedSecret(t *testing.T) { func TestRegisterAdminUsingSharedSecret(t *testing.T) {
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
base, baseClose := testrig.CreateBaseDendrite(t, dbType) cfg, processCtx, close := testrig.CreateConfig(t, dbType)
defer baseClose() defer close()
base.Cfg.Global.ServerName = "server" natsInstance := jetstream.NATSInstance{}
cfg.Global.ServerName = "server"
sharedSecret := "dendritetest" sharedSecret := "dendritetest"
base.Cfg.ClientAPI.RegistrationSharedSecret = sharedSecret cfg.ClientAPI.RegistrationSharedSecret = sharedSecret
rsAPI := roomserver.NewInternalAPI(base) cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
userAPI := userapi.NewInternalAPI(base, rsAPI, nil) caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil)
expectedDisplayName := "rabbit" expectedDisplayName := "rabbit"
jsonStr := []byte(`{"admin":true,"mac":"24dca3bba410e43fe64b9b5c28306693bf3baa9f","nonce":"759f047f312b99ff428b21d581256f8592b8976e58bc1b543972dc6147e529a79657605b52d7becd160ff5137f3de11975684319187e06901955f79e5a6c5a79","password":"wonderland","username":"alice","displayname":"rabbit"}`) jsonStr := []byte(`{"admin":true,"mac":"24dca3bba410e43fe64b9b5c28306693bf3baa9f","nonce":"759f047f312b99ff428b21d581256f8592b8976e58bc1b543972dc6147e529a79657605b52d7becd160ff5137f3de11975684319187e06901955f79e5a6c5a79","password":"wonderland","username":"alice","displayname":"rabbit"}`)
@ -642,7 +655,7 @@ func TestRegisterAdminUsingSharedSecret(t *testing.T) {
ssrr := httptest.NewRequest(http.MethodPost, "/", body) ssrr := httptest.NewRequest(http.MethodPost, "/", body)
response := handleSharedSecretRegistration( response := handleSharedSecretRegistration(
&base.Cfg.ClientAPI, &cfg.ClientAPI,
userAPI, userAPI,
r, r,
ssrr, ssrr,
@ -651,7 +664,7 @@ func TestRegisterAdminUsingSharedSecret(t *testing.T) {
profilReq := api.QueryProfileRequest{UserID: "@alice:server"} profilReq := api.QueryProfileRequest{UserID: "@alice:server"}
var profileRes api.QueryProfileResponse var profileRes api.QueryProfileResponse
err = userAPI.QueryProfile(base.Context(), &profilReq, &profileRes) err = userAPI.QueryProfile(processCtx.Context(), &profilReq, &profileRes)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, expectedDisplayName, profileRes.DisplayName) assert.Equal(t, expectedDisplayName, profileRes.DisplayName)
}) })

View file

@ -21,7 +21,6 @@ import (
"sync" "sync"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/matrix-org/dendrite/setup/base"
userapi "github.com/matrix-org/dendrite/userapi/api" userapi "github.com/matrix-org/dendrite/userapi/api"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/util" "github.com/matrix-org/util"
@ -50,8 +49,8 @@ import (
// applied: // applied:
// nolint: gocyclo // nolint: gocyclo
func Setup( func Setup(
base *base.BaseDendrite, routers httputil.Routers,
cfg *config.ClientAPI, dendriteCfg *config.Dendrite,
rsAPI roomserverAPI.ClientRoomserverAPI, rsAPI roomserverAPI.ClientRoomserverAPI,
asAPI appserviceAPI.AppServiceInternalAPI, asAPI appserviceAPI.AppServiceInternalAPI,
userAPI userapi.ClientUserAPI, userAPI userapi.ClientUserAPI,
@ -61,14 +60,16 @@ func Setup(
transactionsCache *transactions.Cache, transactionsCache *transactions.Cache,
federationSender federationAPI.ClientFederationAPI, federationSender federationAPI.ClientFederationAPI,
extRoomsProvider api.ExtraPublicRoomsProvider, extRoomsProvider api.ExtraPublicRoomsProvider,
mscCfg *config.MSCs, natsClient *nats.Conn, natsClient *nats.Conn, enableMetrics bool,
) { ) {
publicAPIMux := base.PublicClientAPIMux cfg := &dendriteCfg.ClientAPI
wkMux := base.PublicWellKnownAPIMux mscCfg := &dendriteCfg.MSCs
synapseAdminRouter := base.SynapseAdminMux publicAPIMux := routers.Client
dendriteAdminRouter := base.DendriteAdminMux wkMux := routers.WellKnown
synapseAdminRouter := routers.SynapseAdmin
dendriteAdminRouter := routers.DendriteAdmin
if base.EnableMetrics { if enableMetrics {
prometheus.MustRegister(amtRegUsers, sendEventDuration) prometheus.MustRegister(amtRegUsers, sendEventDuration)
} }
@ -656,7 +657,7 @@ func Setup(
).Methods(http.MethodGet, http.MethodPost, http.MethodOptions) ).Methods(http.MethodGet, http.MethodPost, http.MethodOptions)
v3mux.Handle("/auth/{authType}/fallback/web", v3mux.Handle("/auth/{authType}/fallback/web",
httputil.MakeHTMLAPI("auth_fallback", base.EnableMetrics, func(w http.ResponseWriter, req *http.Request) { httputil.MakeHTMLAPI("auth_fallback", enableMetrics, func(w http.ResponseWriter, req *http.Request) {
vars := mux.Vars(req) vars := mux.Vars(req)
AuthFallback(w, req, vars["authType"], cfg) AuthFallback(w, req, vars["authType"], cfg)
}), }),

View file

@ -21,7 +21,7 @@ import (
"net/http" "net/http"
"strings" "strings"
"github.com/matrix-org/dendrite/setup/base" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"nhooyr.io/websocket" "nhooyr.io/websocket"
@ -90,7 +90,7 @@ func createTransport(s *pineconeSessions.Sessions) *http.Transport {
} }
func CreateClient( func CreateClient(
base *base.BaseDendrite, s *pineconeSessions.Sessions, s *pineconeSessions.Sessions,
) *gomatrixserverlib.Client { ) *gomatrixserverlib.Client {
return gomatrixserverlib.NewClient( return gomatrixserverlib.NewClient(
gomatrixserverlib.WithTransport(createTransport(s)), gomatrixserverlib.WithTransport(createTransport(s)),
@ -98,10 +98,10 @@ func CreateClient(
} }
func CreateFederationClient( func CreateFederationClient(
base *base.BaseDendrite, s *pineconeSessions.Sessions, cfg *config.Dendrite, s *pineconeSessions.Sessions,
) *gomatrixserverlib.FederationClient { ) *gomatrixserverlib.FederationClient {
return gomatrixserverlib.NewFederationClient( return gomatrixserverlib.NewFederationClient(
base.Cfg.Global.SigningIdentities(), cfg.Global.SigningIdentities(),
gomatrixserverlib.WithTransport(createTransport(s)), gomatrixserverlib.WithTransport(createTransport(s)),
) )
} }

View file

@ -27,8 +27,11 @@ import (
"github.com/matrix-org/dendrite/cmd/dendrite-demo-pinecone/monolith" "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/cmd/dendrite-demo-yggdrasil/signing"
"github.com/matrix-org/dendrite/internal" "github.com/matrix-org/dendrite/internal"
"github.com/matrix-org/dendrite/internal/httputil"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/setup" "github.com/matrix-org/dendrite/setup"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/dendrite/setup/process"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
@ -87,9 +90,13 @@ func main() {
} }
} }
processCtx := process.NewProcessContext()
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
routers := httputil.NewRouters()
enableMetrics := true enableMetrics := true
enableWebsockets := true enableWebsockets := true
p2pMonolith.SetupDendrite(cfg, *instancePort, *instanceRelayingEnabled, enableMetrics, enableWebsockets) p2pMonolith.SetupDendrite(processCtx, cfg, cm, routers, *instancePort, *instanceRelayingEnabled, enableMetrics, enableWebsockets)
p2pMonolith.StartMonolith() p2pMonolith.StartMonolith()
p2pMonolith.WaitForShutdown() p2pMonolith.WaitForShutdown()

View file

@ -23,6 +23,7 @@ import (
"net" "net"
"net/http" "net/http"
"path/filepath" "path/filepath"
"sync"
"time" "time"
"github.com/gorilla/mux" "github.com/gorilla/mux"
@ -37,7 +38,9 @@ import (
"github.com/matrix-org/dendrite/federationapi" "github.com/matrix-org/dendrite/federationapi"
federationAPI "github.com/matrix-org/dendrite/federationapi/api" federationAPI "github.com/matrix-org/dendrite/federationapi/api"
"github.com/matrix-org/dendrite/federationapi/producers" "github.com/matrix-org/dendrite/federationapi/producers"
"github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/httputil" "github.com/matrix-org/dendrite/internal/httputil"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/relayapi" "github.com/matrix-org/dendrite/relayapi"
relayAPI "github.com/matrix-org/dendrite/relayapi/api" relayAPI "github.com/matrix-org/dendrite/relayapi/api"
"github.com/matrix-org/dendrite/roomserver" "github.com/matrix-org/dendrite/roomserver"
@ -45,6 +48,7 @@ import (
"github.com/matrix-org/dendrite/setup/base" "github.com/matrix-org/dendrite/setup/base"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/dendrite/setup/jetstream" "github.com/matrix-org/dendrite/setup/jetstream"
"github.com/matrix-org/dendrite/setup/process"
"github.com/matrix-org/dendrite/userapi" "github.com/matrix-org/dendrite/userapi"
userAPI "github.com/matrix-org/dendrite/userapi/api" userAPI "github.com/matrix-org/dendrite/userapi/api"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
@ -60,13 +64,13 @@ import (
const SessionProtocol = "matrix" const SessionProtocol = "matrix"
type P2PMonolith struct { type P2PMonolith struct {
BaseDendrite *base.BaseDendrite
Sessions *pineconeSessions.Sessions Sessions *pineconeSessions.Sessions
Multicast *pineconeMulticast.Multicast Multicast *pineconeMulticast.Multicast
ConnManager *pineconeConnections.ConnectionManager ConnManager *pineconeConnections.ConnectionManager
Router *pineconeRouter.Router Router *pineconeRouter.Router
EventChannel chan pineconeEvents.Event EventChannel chan pineconeEvents.Event
RelayRetriever relay.RelayServerRetriever RelayRetriever relay.RelayServerRetriever
ProcessCtx *process.ProcessContext
dendrite setup.Monolith dendrite setup.Monolith
port int port int
@ -76,6 +80,7 @@ type P2PMonolith struct {
listener net.Listener listener net.Listener
httpListenAddr string httpListenAddr string
stopHandlingEvents chan bool stopHandlingEvents chan bool
httpServerMu sync.Mutex
} }
func GenerateDefaultConfig(sk ed25519.PrivateKey, storageDir string, cacheDir string, dbPrefix string) *config.Dendrite { func GenerateDefaultConfig(sk ed25519.PrivateKey, storageDir string, cacheDir string, dbPrefix string) *config.Dendrite {
@ -120,53 +125,52 @@ func (p *P2PMonolith) SetupPinecone(sk ed25519.PrivateKey) {
p.ConnManager = pineconeConnections.NewConnectionManager(p.Router, nil) p.ConnManager = pineconeConnections.NewConnectionManager(p.Router, nil)
} }
func (p *P2PMonolith) SetupDendrite(cfg *config.Dendrite, port int, enableRelaying bool, enableMetrics bool, enableWebsockets bool) { func (p *P2PMonolith) SetupDendrite(
if enableMetrics { processCtx *process.ProcessContext, cfg *config.Dendrite, cm sqlutil.Connections, routers httputil.Routers,
p.BaseDendrite = base.NewBaseDendrite(cfg) port int, enableRelaying bool, enableMetrics bool, enableWebsockets bool) {
} else {
p.BaseDendrite = base.NewBaseDendrite(cfg, base.DisableMetrics)
}
p.port = port
p.BaseDendrite.ConfigureAdminEndpoints()
federation := conn.CreateFederationClient(p.BaseDendrite, p.Sessions) p.port = port
base.ConfigureAdminEndpoints(processCtx, routers)
federation := conn.CreateFederationClient(cfg, p.Sessions)
serverKeyAPI := &signing.YggdrasilKeys{} serverKeyAPI := &signing.YggdrasilKeys{}
keyRing := serverKeyAPI.KeyRing() keyRing := serverKeyAPI.KeyRing()
rsComponent := roomserver.NewInternalAPI(p.BaseDendrite) caches := caching.NewRistrettoCache(cfg.Global.Cache.EstimatedMaxSize, cfg.Global.Cache.MaxAge, enableMetrics)
rsAPI := rsComponent natsInstance := jetstream.NATSInstance{}
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, enableMetrics)
fsAPI := federationapi.NewInternalAPI( fsAPI := federationapi.NewInternalAPI(
p.BaseDendrite, federation, rsAPI, p.BaseDendrite.Caches, keyRing, true, processCtx, cfg, cm, &natsInstance, federation, rsAPI, caches, keyRing, true,
) )
userAPI := userapi.NewInternalAPI(p.BaseDendrite, rsAPI, federation) userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, federation)
asAPI := appservice.NewInternalAPI(p.BaseDendrite, userAPI, rsAPI) asAPI := appservice.NewInternalAPI(processCtx, cfg, &natsInstance, userAPI, rsAPI)
rsComponent.SetFederationAPI(fsAPI, keyRing) rsAPI.SetFederationAPI(fsAPI, keyRing)
userProvider := users.NewPineconeUserProvider(p.Router, p.Sessions, userAPI, federation) userProvider := users.NewPineconeUserProvider(p.Router, p.Sessions, userAPI, federation)
roomProvider := rooms.NewPineconeRoomProvider(p.Router, p.Sessions, fsAPI, federation) roomProvider := rooms.NewPineconeRoomProvider(p.Router, p.Sessions, fsAPI, federation)
js, _ := p.BaseDendrite.NATS.Prepare(p.BaseDendrite.ProcessContext, &p.BaseDendrite.Cfg.Global.JetStream) js, _ := natsInstance.Prepare(processCtx, &cfg.Global.JetStream)
producer := &producers.SyncAPIProducer{ producer := &producers.SyncAPIProducer{
JetStream: js, JetStream: js,
TopicReceiptEvent: p.BaseDendrite.Cfg.Global.JetStream.Prefixed(jetstream.OutputReceiptEvent), TopicReceiptEvent: cfg.Global.JetStream.Prefixed(jetstream.OutputReceiptEvent),
TopicSendToDeviceEvent: p.BaseDendrite.Cfg.Global.JetStream.Prefixed(jetstream.OutputSendToDeviceEvent), TopicSendToDeviceEvent: cfg.Global.JetStream.Prefixed(jetstream.OutputSendToDeviceEvent),
TopicTypingEvent: p.BaseDendrite.Cfg.Global.JetStream.Prefixed(jetstream.OutputTypingEvent), TopicTypingEvent: cfg.Global.JetStream.Prefixed(jetstream.OutputTypingEvent),
TopicPresenceEvent: p.BaseDendrite.Cfg.Global.JetStream.Prefixed(jetstream.OutputPresenceEvent), TopicPresenceEvent: cfg.Global.JetStream.Prefixed(jetstream.OutputPresenceEvent),
TopicDeviceListUpdate: p.BaseDendrite.Cfg.Global.JetStream.Prefixed(jetstream.InputDeviceListUpdate), TopicDeviceListUpdate: cfg.Global.JetStream.Prefixed(jetstream.InputDeviceListUpdate),
TopicSigningKeyUpdate: p.BaseDendrite.Cfg.Global.JetStream.Prefixed(jetstream.InputSigningKeyUpdate), TopicSigningKeyUpdate: cfg.Global.JetStream.Prefixed(jetstream.InputSigningKeyUpdate),
Config: &p.BaseDendrite.Cfg.FederationAPI, Config: &cfg.FederationAPI,
UserAPI: userAPI, UserAPI: userAPI,
} }
relayAPI := relayapi.NewRelayInternalAPI(p.BaseDendrite, federation, rsAPI, keyRing, producer, enableRelaying) relayAPI := relayapi.NewRelayInternalAPI(cfg, cm, federation, rsAPI, keyRing, producer, enableRelaying, caches)
logrus.Infof("Relaying enabled: %v", relayAPI.RelayingEnabled()) logrus.Infof("Relaying enabled: %v", relayAPI.RelayingEnabled())
p.dendrite = setup.Monolith{ p.dendrite = setup.Monolith{
Config: p.BaseDendrite.Cfg, Config: cfg,
Client: conn.CreateClient(p.BaseDendrite, p.Sessions), Client: conn.CreateClient(p.Sessions),
FedClient: federation, FedClient: federation,
KeyRing: keyRing, KeyRing: keyRing,
@ -178,9 +182,10 @@ func (p *P2PMonolith) SetupDendrite(cfg *config.Dendrite, port int, enableRelayi
ExtPublicRoomsProvider: roomProvider, ExtPublicRoomsProvider: roomProvider,
ExtUserDirectoryProvider: userProvider, ExtUserDirectoryProvider: userProvider,
} }
p.dendrite.AddAllPublicRoutes(p.BaseDendrite) p.ProcessCtx = processCtx
p.dendrite.AddAllPublicRoutes(processCtx, cfg, routers, cm, &natsInstance, caches, enableMetrics)
p.setupHttpServers(userProvider, enableWebsockets) p.setupHttpServers(userProvider, routers, enableWebsockets)
} }
func (p *P2PMonolith) GetFederationAPI() federationAPI.FederationInternalAPI { func (p *P2PMonolith) GetFederationAPI() federationAPI.FederationInternalAPI {
@ -202,20 +207,22 @@ func (p *P2PMonolith) StartMonolith() {
func (p *P2PMonolith) Stop() { func (p *P2PMonolith) Stop() {
logrus.Info("Stopping monolith") logrus.Info("Stopping monolith")
_ = p.BaseDendrite.Close() p.ProcessCtx.ShutdownDendrite()
p.WaitForShutdown() p.WaitForShutdown()
logrus.Info("Stopped monolith") logrus.Info("Stopped monolith")
} }
func (p *P2PMonolith) WaitForShutdown() { func (p *P2PMonolith) WaitForShutdown() {
p.BaseDendrite.WaitForShutdown() p.ProcessCtx.WaitForShutdown()
p.closeAllResources() p.closeAllResources()
} }
func (p *P2PMonolith) closeAllResources() { func (p *P2PMonolith) closeAllResources() {
logrus.Info("Closing monolith resources") logrus.Info("Closing monolith resources")
p.httpServerMu.Lock()
if p.httpServer != nil { if p.httpServer != nil {
_ = p.httpServer.Shutdown(context.Background()) _ = p.httpServer.Shutdown(context.Background())
p.httpServerMu.Unlock()
} }
select { select {
@ -245,12 +252,12 @@ func (p *P2PMonolith) Addr() string {
return p.httpListenAddr return p.httpListenAddr
} }
func (p *P2PMonolith) setupHttpServers(userProvider *users.PineconeUserProvider, enableWebsockets bool) { func (p *P2PMonolith) setupHttpServers(userProvider *users.PineconeUserProvider, routers httputil.Routers, enableWebsockets bool) {
p.httpMux = mux.NewRouter().SkipClean(true).UseEncodedPath() p.httpMux = mux.NewRouter().SkipClean(true).UseEncodedPath()
p.httpMux.PathPrefix(httputil.PublicClientPathPrefix).Handler(p.BaseDendrite.PublicClientAPIMux) p.httpMux.PathPrefix(httputil.PublicClientPathPrefix).Handler(routers.Client)
p.httpMux.PathPrefix(httputil.PublicMediaPathPrefix).Handler(p.BaseDendrite.PublicMediaAPIMux) p.httpMux.PathPrefix(httputil.PublicMediaPathPrefix).Handler(routers.Media)
p.httpMux.PathPrefix(httputil.DendriteAdminPathPrefix).Handler(p.BaseDendrite.DendriteAdminMux) p.httpMux.PathPrefix(httputil.DendriteAdminPathPrefix).Handler(routers.DendriteAdmin)
p.httpMux.PathPrefix(httputil.SynapseAdminPathPrefix).Handler(p.BaseDendrite.SynapseAdminMux) p.httpMux.PathPrefix(httputil.SynapseAdminPathPrefix).Handler(routers.SynapseAdmin)
if enableWebsockets { if enableWebsockets {
wsUpgrader := websocket.Upgrader{ wsUpgrader := websocket.Upgrader{
@ -283,8 +290,8 @@ func (p *P2PMonolith) setupHttpServers(userProvider *users.PineconeUserProvider,
p.pineconeMux = mux.NewRouter().SkipClean(true).UseEncodedPath() p.pineconeMux = mux.NewRouter().SkipClean(true).UseEncodedPath()
p.pineconeMux.PathPrefix(users.PublicURL).HandlerFunc(userProvider.FederatedUserProfiles) p.pineconeMux.PathPrefix(users.PublicURL).HandlerFunc(userProvider.FederatedUserProfiles)
p.pineconeMux.PathPrefix(httputil.PublicFederationPathPrefix).Handler(p.BaseDendrite.PublicFederationAPIMux) p.pineconeMux.PathPrefix(httputil.PublicFederationPathPrefix).Handler(routers.Federation)
p.pineconeMux.PathPrefix(httputil.PublicMediaPathPrefix).Handler(p.BaseDendrite.PublicMediaAPIMux) p.pineconeMux.PathPrefix(httputil.PublicMediaPathPrefix).Handler(routers.Media)
pHTTP := p.Sessions.Protocol(SessionProtocol).HTTP() pHTTP := p.Sessions.Protocol(SessionProtocol).HTTP()
pHTTP.Mux().Handle(users.PublicURL, p.pineconeMux) pHTTP.Mux().Handle(users.PublicURL, p.pineconeMux)
@ -294,6 +301,7 @@ func (p *P2PMonolith) setupHttpServers(userProvider *users.PineconeUserProvider,
func (p *P2PMonolith) startHTTPServers() { func (p *P2PMonolith) startHTTPServers() {
go func() { go func() {
p.httpServerMu.Lock()
// Build both ends of a HTTP multiplex. // Build both ends of a HTTP multiplex.
p.httpServer = &http.Server{ p.httpServer = &http.Server{
Addr: ":0", Addr: ":0",
@ -306,7 +314,7 @@ func (p *P2PMonolith) startHTTPServers() {
}, },
Handler: p.pineconeMux, Handler: p.pineconeMux,
} }
p.httpServerMu.Unlock()
pubkey := p.Router.PublicKey() pubkey := p.Router.PublicKey()
pubkeyString := hex.EncodeToString(pubkey[:]) pubkeyString := hex.EncodeToString(pubkey[:])
logrus.Info("Listening on ", pubkeyString) logrus.Info("Listening on ", pubkeyString)
@ -368,7 +376,7 @@ func (p *P2PMonolith) startEventHandler() {
ServerNames: []gomatrixserverlib.ServerName{gomatrixserverlib.ServerName(e.PeerID)}, ServerNames: []gomatrixserverlib.ServerName{gomatrixserverlib.ServerName(e.PeerID)},
} }
res := &federationAPI.PerformWakeupServersResponse{} res := &federationAPI.PerformWakeupServersResponse{}
if err := p.dendrite.FederationAPI.PerformWakeupServers(p.BaseDendrite.Context(), req, res); err != nil { if err := p.dendrite.FederationAPI.PerformWakeupServers(p.ProcessCtx.Context(), req, res); err != nil {
eLog.WithError(err).Error("Failed to wakeup destination", e.PeerID) eLog.WithError(err).Error("Failed to wakeup destination", e.PeerID)
} }
} }

View file

@ -27,6 +27,11 @@ import (
"path/filepath" "path/filepath"
"time" "time"
"github.com/getsentry/sentry-go"
"github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/setup/jetstream"
"github.com/matrix-org/dendrite/setup/process"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/gorilla/mux" "github.com/gorilla/mux"
@ -41,7 +46,7 @@ import (
"github.com/matrix-org/dendrite/internal/httputil" "github.com/matrix-org/dendrite/internal/httputil"
"github.com/matrix-org/dendrite/roomserver" "github.com/matrix-org/dendrite/roomserver"
"github.com/matrix-org/dendrite/setup" "github.com/matrix-org/dendrite/setup"
"github.com/matrix-org/dendrite/setup/base" basepkg "github.com/matrix-org/dendrite/setup/base"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/dendrite/setup/mscs" "github.com/matrix-org/dendrite/setup/mscs"
"github.com/matrix-org/dendrite/test" "github.com/matrix-org/dendrite/test"
@ -57,6 +62,7 @@ var (
instanceDir = flag.String("dir", ".", "the directory to store the databases in (if --config not specified)") instanceDir = flag.String("dir", ".", "the directory to store the databases in (if --config not specified)")
) )
// nolint: gocyclo
func main() { func main() {
flag.Parse() flag.Parse()
internal.SetupPprof() internal.SetupPprof()
@ -142,37 +148,83 @@ func main() {
cfg.Global.ServerName = gomatrixserverlib.ServerName(hex.EncodeToString(pk)) cfg.Global.ServerName = gomatrixserverlib.ServerName(hex.EncodeToString(pk))
cfg.Global.KeyID = gomatrixserverlib.KeyID(signing.KeyID) cfg.Global.KeyID = gomatrixserverlib.KeyID(signing.KeyID)
base := base.NewBaseDendrite(cfg) configErrors := &config.ConfigErrors{}
base.ConfigureAdminEndpoints() cfg.Verify(configErrors)
defer base.Close() // nolint: errcheck if len(*configErrors) > 0 {
for _, err := range *configErrors {
logrus.Errorf("Configuration error: %s", err)
}
logrus.Fatalf("Failed to start due to configuration errors")
}
internal.SetupStdLogging()
internal.SetupHookLogging(cfg.Logging)
internal.SetupPprof()
logrus.Infof("Dendrite version %s", internal.VersionString())
if !cfg.ClientAPI.RegistrationDisabled && cfg.ClientAPI.OpenRegistrationWithoutVerificationEnabled {
logrus.Warn("Open registration is enabled")
}
closer, err := cfg.SetupTracing()
if err != nil {
logrus.WithError(err).Panicf("failed to start opentracing")
}
defer closer.Close() // nolint: errcheck
if cfg.Global.Sentry.Enabled {
logrus.Info("Setting up Sentry for debugging...")
err = sentry.Init(sentry.ClientOptions{
Dsn: cfg.Global.Sentry.DSN,
Environment: cfg.Global.Sentry.Environment,
Debug: true,
ServerName: string(cfg.Global.ServerName),
Release: "dendrite@" + internal.VersionString(),
AttachStacktrace: true,
})
if err != nil {
logrus.WithError(err).Panic("failed to start Sentry")
}
}
processCtx := process.NewProcessContext()
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
routers := httputil.NewRouters()
basepkg.ConfigureAdminEndpoints(processCtx, routers)
defer func() {
processCtx.ShutdownDendrite()
processCtx.WaitForShutdown()
}() // nolint: errcheck
ygg, err := yggconn.Setup(sk, *instanceName, ".", *instancePeer, *instanceListen) ygg, err := yggconn.Setup(sk, *instanceName, ".", *instancePeer, *instanceListen)
if err != nil { if err != nil {
panic(err) panic(err)
} }
federation := ygg.CreateFederationClient(base) federation := ygg.CreateFederationClient(cfg)
serverKeyAPI := &signing.YggdrasilKeys{} serverKeyAPI := &signing.YggdrasilKeys{}
keyRing := serverKeyAPI.KeyRing() keyRing := serverKeyAPI.KeyRing()
rsAPI := roomserver.NewInternalAPI( caches := caching.NewRistrettoCache(cfg.Global.Cache.EstimatedMaxSize, cfg.Global.Cache.MaxAge, caching.EnableMetrics)
base, natsInstance := jetstream.NATSInstance{}
) rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.EnableMetrics)
userAPI := userapi.NewInternalAPI(base, rsAPI, federation) userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, federation)
asAPI := appservice.NewInternalAPI(base, userAPI, rsAPI) asAPI := appservice.NewInternalAPI(processCtx, cfg, &natsInstance, userAPI, rsAPI)
rsAPI.SetAppserviceAPI(asAPI) rsAPI.SetAppserviceAPI(asAPI)
fsAPI := federationapi.NewInternalAPI( fsAPI := federationapi.NewInternalAPI(
base, federation, rsAPI, base.Caches, keyRing, true, processCtx, cfg, cm, &natsInstance, federation, rsAPI, caches, keyRing, true,
) )
rsAPI.SetFederationAPI(fsAPI, keyRing) rsAPI.SetFederationAPI(fsAPI, keyRing)
monolith := setup.Monolith{ monolith := setup.Monolith{
Config: base.Cfg, Config: cfg,
Client: ygg.CreateClient(base), Client: ygg.CreateClient(),
FedClient: federation, FedClient: federation,
KeyRing: keyRing, KeyRing: keyRing,
@ -184,21 +236,21 @@ func main() {
ygg, fsAPI, federation, ygg, fsAPI, federation,
), ),
} }
monolith.AddAllPublicRoutes(base) monolith.AddAllPublicRoutes(processCtx, cfg, routers, cm, &natsInstance, caches, caching.EnableMetrics)
if err := mscs.Enable(base, &monolith); err != nil { if err := mscs.Enable(cfg, cm, routers, &monolith, caches); err != nil {
logrus.WithError(err).Fatalf("Failed to enable MSCs") logrus.WithError(err).Fatalf("Failed to enable MSCs")
} }
httpRouter := mux.NewRouter().SkipClean(true).UseEncodedPath() httpRouter := mux.NewRouter().SkipClean(true).UseEncodedPath()
httpRouter.PathPrefix(httputil.PublicClientPathPrefix).Handler(base.PublicClientAPIMux) httpRouter.PathPrefix(httputil.PublicClientPathPrefix).Handler(routers.Client)
httpRouter.PathPrefix(httputil.PublicMediaPathPrefix).Handler(base.PublicMediaAPIMux) httpRouter.PathPrefix(httputil.PublicMediaPathPrefix).Handler(routers.Media)
httpRouter.PathPrefix(httputil.DendriteAdminPathPrefix).Handler(base.DendriteAdminMux) httpRouter.PathPrefix(httputil.DendriteAdminPathPrefix).Handler(routers.DendriteAdmin)
httpRouter.PathPrefix(httputil.SynapseAdminPathPrefix).Handler(base.SynapseAdminMux) httpRouter.PathPrefix(httputil.SynapseAdminPathPrefix).Handler(routers.SynapseAdmin)
embed.Embed(httpRouter, *instancePort, "Yggdrasil Demo") embed.Embed(httpRouter, *instancePort, "Yggdrasil Demo")
yggRouter := mux.NewRouter().SkipClean(true).UseEncodedPath() yggRouter := mux.NewRouter().SkipClean(true).UseEncodedPath()
yggRouter.PathPrefix(httputil.PublicFederationPathPrefix).Handler(base.PublicFederationAPIMux) yggRouter.PathPrefix(httputil.PublicFederationPathPrefix).Handler(routers.Federation)
yggRouter.PathPrefix(httputil.PublicMediaPathPrefix).Handler(base.PublicMediaAPIMux) yggRouter.PathPrefix(httputil.PublicMediaPathPrefix).Handler(routers.Media)
// Build both ends of a HTTP multiplex. // Build both ends of a HTTP multiplex.
httpServer := &http.Server{ httpServer := &http.Server{
@ -232,5 +284,5 @@ func main() {
}() }()
// We want to block forever to let the HTTP and HTTPS handler serve the APIs // We want to block forever to let the HTTP and HTTPS handler serve the APIs
base.WaitForShutdown() basepkg.WaitForShutdown(processCtx)
} }

View file

@ -4,7 +4,7 @@ import (
"net/http" "net/http"
"time" "time"
"github.com/matrix-org/dendrite/setup/base" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
) )
@ -17,9 +17,7 @@ func (y *yggroundtripper) RoundTrip(req *http.Request) (*http.Response, error) {
return y.inner.RoundTrip(req) return y.inner.RoundTrip(req)
} }
func (n *Node) CreateClient( func (n *Node) CreateClient() *gomatrixserverlib.Client {
base *base.BaseDendrite,
) *gomatrixserverlib.Client {
tr := &http.Transport{} tr := &http.Transport{}
tr.RegisterProtocol( tr.RegisterProtocol(
"matrix", &yggroundtripper{ "matrix", &yggroundtripper{
@ -39,7 +37,7 @@ func (n *Node) CreateClient(
} }
func (n *Node) CreateFederationClient( func (n *Node) CreateFederationClient(
base *base.BaseDendrite, cfg *config.Dendrite,
) *gomatrixserverlib.FederationClient { ) *gomatrixserverlib.FederationClient {
tr := &http.Transport{} tr := &http.Transport{}
tr.RegisterProtocol( tr.RegisterProtocol(
@ -55,7 +53,7 @@ func (n *Node) CreateFederationClient(
}, },
) )
return gomatrixserverlib.NewFederationClient( return gomatrixserverlib.NewFederationClient(
base.Cfg.Global.SigningIdentities(), cfg.Global.SigningIdentities(),
gomatrixserverlib.WithTransport(tr), gomatrixserverlib.WithTransport(tr),
) )
} }

View file

@ -259,10 +259,20 @@ func buildDendrite(httpClient *http.Client, dockerClient *client.Client, tmpDir
func getAndSortVersionsFromGithub(httpClient *http.Client) (semVers []*semver.Version, err error) { func getAndSortVersionsFromGithub(httpClient *http.Client) (semVers []*semver.Version, err error) {
u := "https://api.github.com/repos/matrix-org/dendrite/tags" u := "https://api.github.com/repos/matrix-org/dendrite/tags"
res, err := httpClient.Get(u)
if err != nil { var res *http.Response
return nil, err for i := 0; i < 3; i++ {
res, err = httpClient.Get(u)
if err != nil {
return nil, err
}
if res.StatusCode == 200 {
break
}
log.Printf("Github API returned HTTP %d, retrying\n", res.StatusCode)
time.Sleep(time.Second * 5)
} }
if res.StatusCode != 200 { if res.StatusCode != 200 {
return nil, fmt.Errorf("%s returned HTTP %d", u, res.StatusCode) return nil, fmt.Errorf("%s returned HTTP %d", u, res.StatusCode)
} }

View file

@ -16,8 +16,16 @@ package main
import ( import (
"flag" "flag"
"io/fs" "time"
"github.com/getsentry/sentry-go"
"github.com/matrix-org/dendrite/internal"
"github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/httputil"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/setup/jetstream"
"github.com/matrix-org/dendrite/setup/process"
"github.com/matrix-org/gomatrixserverlib"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/matrix-org/dendrite/appservice" "github.com/matrix-org/dendrite/appservice"
@ -34,8 +42,8 @@ var (
unixSocket = flag.String("unix-socket", "", unixSocket = flag.String("unix-socket", "",
"EXPERIMENTAL(unstable): The HTTP listening unix socket for the server (disables http[s]-bind-address feature)", "EXPERIMENTAL(unstable): The HTTP listening unix socket for the server (disables http[s]-bind-address feature)",
) )
unixSocketPermission = flag.Int("unix-socket-permission", 0755, unixSocketPermission = flag.String("unix-socket-permission", "755",
"EXPERIMENTAL(unstable): The HTTP listening unix socket permission for the server", "EXPERIMENTAL(unstable): The HTTP listening unix socket permission for the server (in chmod format like 755)",
) )
httpBindAddr = flag.String("http-bind-address", ":8008", "The HTTP listening port for the server") httpBindAddr = flag.String("http-bind-address", ":8008", "The HTTP listening port for the server")
httpsBindAddr = flag.String("https-bind-address", ":8448", "The HTTPS listening port for the server") httpsBindAddr = flag.String("https-bind-address", ":8448", "The HTTPS listening port for the server")
@ -59,27 +67,97 @@ func main() {
} }
httpsAddr = https httpsAddr = https
} else { } else {
httpAddr = config.UnixSocketAddress(*unixSocket, fs.FileMode(*unixSocketPermission)) socket, err := config.UnixSocketAddress(*unixSocket, *unixSocketPermission)
if err != nil {
logrus.WithError(err).Fatalf("Failed to parse unix socket")
}
httpAddr = socket
} }
options := []basepkg.BaseDendriteOptions{} configErrors := &config.ConfigErrors{}
cfg.Verify(configErrors)
if len(*configErrors) > 0 {
for _, err := range *configErrors {
logrus.Errorf("Configuration error: %s", err)
}
logrus.Fatalf("Failed to start due to configuration errors")
}
processCtx := process.NewProcessContext()
base := basepkg.NewBaseDendrite(cfg, options...) internal.SetupStdLogging()
defer base.Close() // nolint: errcheck internal.SetupHookLogging(cfg.Logging)
internal.SetupPprof()
federation := base.CreateFederationClient() basepkg.PlatformSanityChecks()
rsAPI := roomserver.NewInternalAPI(base) logrus.Infof("Dendrite version %s", internal.VersionString())
if !cfg.ClientAPI.RegistrationDisabled && cfg.ClientAPI.OpenRegistrationWithoutVerificationEnabled {
logrus.Warn("Open registration is enabled")
}
// create DNS cache
var dnsCache *gomatrixserverlib.DNSCache
if cfg.Global.DNSCache.Enabled {
dnsCache = gomatrixserverlib.NewDNSCache(
cfg.Global.DNSCache.CacheSize,
cfg.Global.DNSCache.CacheLifetime,
)
logrus.Infof(
"DNS cache enabled (size %d, lifetime %s)",
cfg.Global.DNSCache.CacheSize,
cfg.Global.DNSCache.CacheLifetime,
)
}
// setup tracing
closer, err := cfg.SetupTracing()
if err != nil {
logrus.WithError(err).Panicf("failed to start opentracing")
}
defer closer.Close() // nolint: errcheck
// setup sentry
if cfg.Global.Sentry.Enabled {
logrus.Info("Setting up Sentry for debugging...")
err = sentry.Init(sentry.ClientOptions{
Dsn: cfg.Global.Sentry.DSN,
Environment: cfg.Global.Sentry.Environment,
Debug: true,
ServerName: string(cfg.Global.ServerName),
Release: "dendrite@" + internal.VersionString(),
AttachStacktrace: true,
})
if err != nil {
logrus.WithError(err).Panic("failed to start Sentry")
}
go func() {
processCtx.ComponentStarted()
<-processCtx.WaitForShutdown()
if !sentry.Flush(time.Second * 5) {
logrus.Warnf("failed to flush all Sentry events!")
}
processCtx.ComponentFinished()
}()
}
federationClient := basepkg.CreateFederationClient(cfg, dnsCache)
httpClient := basepkg.CreateClient(cfg, dnsCache)
// prepare required dependencies
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
routers := httputil.NewRouters()
caches := caching.NewRistrettoCache(cfg.Global.Cache.EstimatedMaxSize, cfg.Global.Cache.MaxAge, caching.EnableMetrics)
natsInstance := jetstream.NATSInstance{}
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.EnableMetrics)
fsAPI := federationapi.NewInternalAPI( fsAPI := federationapi.NewInternalAPI(
base, federation, rsAPI, base.Caches, nil, false, processCtx, cfg, cm, &natsInstance, federationClient, rsAPI, caches, nil, false,
) )
keyRing := fsAPI.KeyRing() keyRing := fsAPI.KeyRing()
userAPI := userapi.NewInternalAPI(base, rsAPI, federation) userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, federationClient)
asAPI := appservice.NewInternalAPI(processCtx, cfg, &natsInstance, userAPI, rsAPI)
asAPI := appservice.NewInternalAPI(base, userAPI, rsAPI)
// The underlying roomserver implementation needs to be able to call the fedsender. // 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 // This is different to rsAPI which can be the http client which doesn't need this
@ -89,9 +167,9 @@ func main() {
rsAPI.SetUserAPI(userAPI) rsAPI.SetUserAPI(userAPI)
monolith := setup.Monolith{ monolith := setup.Monolith{
Config: base.Cfg, Config: cfg,
Client: base.CreateClient(), Client: httpClient,
FedClient: federation, FedClient: federationClient,
KeyRing: keyRing, KeyRing: keyRing,
AppserviceAPI: asAPI, AppserviceAPI: asAPI,
@ -101,25 +179,25 @@ func main() {
RoomserverAPI: rsAPI, RoomserverAPI: rsAPI,
UserAPI: userAPI, UserAPI: userAPI,
} }
monolith.AddAllPublicRoutes(base) monolith.AddAllPublicRoutes(processCtx, cfg, routers, cm, &natsInstance, caches, caching.EnableMetrics)
if len(base.Cfg.MSCs.MSCs) > 0 { if len(cfg.MSCs.MSCs) > 0 {
if err := mscs.Enable(base, &monolith); err != nil { if err := mscs.Enable(cfg, cm, routers, &monolith, caches); err != nil {
logrus.WithError(err).Fatalf("Failed to enable MSCs") logrus.WithError(err).Fatalf("Failed to enable MSCs")
} }
} }
// Expose the matrix APIs directly rather than putting them under a /api path. // Expose the matrix APIs directly rather than putting them under a /api path.
go func() { go func() {
base.SetupAndServeHTTP(httpAddr, nil, nil) basepkg.SetupAndServeHTTP(processCtx, cfg, routers, httpAddr, nil, nil)
}() }()
// Handle HTTPS if certificate and key are provided // Handle HTTPS if certificate and key are provided
if *unixSocket == "" && *certFile != "" && *keyFile != "" { if *unixSocket == "" && *certFile != "" && *keyFile != "" {
go func() { go func() {
base.SetupAndServeHTTP(httpsAddr, certFile, keyFile) basepkg.SetupAndServeHTTP(processCtx, cfg, routers, httpsAddr, certFile, keyFile)
}() }()
} }
// We want to block forever to let the HTTP and HTTPS handler serve the APIs // We want to block forever to let the HTTP and HTTPS handler serve the APIs
base.WaitForShutdown() basepkg.WaitForShutdown(processCtx)
} }

View file

@ -10,12 +10,13 @@ import (
"time" "time"
"github.com/matrix-org/dendrite/internal/caching" "github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/roomserver/state" "github.com/matrix-org/dendrite/roomserver/state"
"github.com/matrix-org/dendrite/roomserver/storage" "github.com/matrix-org/dendrite/roomserver/storage"
"github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/roomserver/types"
"github.com/matrix-org/dendrite/setup" "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/config"
"github.com/matrix-org/dendrite/setup/process"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
) )
@ -40,7 +41,7 @@ func main() {
Level: "error", Level: "error",
}) })
cfg.ClientAPI.RegistrationDisabled = true cfg.ClientAPI.RegistrationDisabled = true
base := base.NewBaseDendrite(cfg, base.DisableMetrics)
args := flag.Args() args := flag.Args()
fmt.Println("Room version", *roomVersion) fmt.Println("Room version", *roomVersion)
@ -54,8 +55,10 @@ func main() {
fmt.Println("Fetching", len(snapshotNIDs), "snapshot NIDs") fmt.Println("Fetching", len(snapshotNIDs), "snapshot NIDs")
processCtx := process.NewProcessContext()
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
roomserverDB, err := storage.Open( roomserverDB, err := storage.Open(
base, &cfg.RoomServer.Database, processCtx.Context(), cm, &cfg.RoomServer.Database,
caching.NewRistrettoCache(128*1024*1024, time.Hour, true), caching.NewRistrettoCache(128*1024*1024, time.Hour, true),
) )
if err != nil { if err != nil {

View file

@ -17,6 +17,10 @@ package federationapi
import ( import (
"time" "time"
"github.com/matrix-org/dendrite/internal/httputil"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/dendrite/setup/process"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/matrix-org/dendrite/federationapi/api" "github.com/matrix-org/dendrite/federationapi/api"
@ -29,7 +33,6 @@ import (
"github.com/matrix-org/dendrite/federationapi/storage" "github.com/matrix-org/dendrite/federationapi/storage"
"github.com/matrix-org/dendrite/internal/caching" "github.com/matrix-org/dendrite/internal/caching"
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api" roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
"github.com/matrix-org/dendrite/setup/base"
"github.com/matrix-org/dendrite/setup/jetstream" "github.com/matrix-org/dendrite/setup/jetstream"
userapi "github.com/matrix-org/dendrite/userapi/api" userapi "github.com/matrix-org/dendrite/userapi/api"
@ -40,17 +43,21 @@ import (
// AddPublicRoutes sets up and registers HTTP handlers on the base API muxes for the FederationAPI component. // AddPublicRoutes sets up and registers HTTP handlers on the base API muxes for the FederationAPI component.
func AddPublicRoutes( func AddPublicRoutes(
base *base.BaseDendrite, processContext *process.ProcessContext,
routers httputil.Routers,
dendriteConfig *config.Dendrite,
natsInstance *jetstream.NATSInstance,
userAPI userapi.FederationUserAPI, userAPI userapi.FederationUserAPI,
federation *gomatrixserverlib.FederationClient, federation *gomatrixserverlib.FederationClient,
keyRing gomatrixserverlib.JSONVerifier, keyRing gomatrixserverlib.JSONVerifier,
rsAPI roomserverAPI.FederationRoomserverAPI, rsAPI roomserverAPI.FederationRoomserverAPI,
fedAPI federationAPI.FederationInternalAPI, fedAPI federationAPI.FederationInternalAPI,
servers federationAPI.ServersInRoomProvider, servers federationAPI.ServersInRoomProvider,
enableMetrics bool,
) { ) {
cfg := &base.Cfg.FederationAPI cfg := &dendriteConfig.FederationAPI
mscCfg := &base.Cfg.MSCs mscCfg := &dendriteConfig.MSCs
js, _ := base.NATS.Prepare(base.ProcessContext, &cfg.Matrix.JetStream) js, _ := natsInstance.Prepare(processContext, &cfg.Matrix.JetStream)
producer := &producers.SyncAPIProducer{ producer := &producers.SyncAPIProducer{
JetStream: js, JetStream: js,
TopicReceiptEvent: cfg.Matrix.JetStream.Prefixed(jetstream.OutputReceiptEvent), TopicReceiptEvent: cfg.Matrix.JetStream.Prefixed(jetstream.OutputReceiptEvent),
@ -75,26 +82,30 @@ func AddPublicRoutes(
} }
routing.Setup( routing.Setup(
base, routers,
dendriteConfig,
rsAPI, f, keyRing, rsAPI, f, keyRing,
federation, userAPI, mscCfg, federation, userAPI, mscCfg,
servers, producer, servers, producer, enableMetrics,
) )
} }
// NewInternalAPI returns a concerete implementation of the internal API. Callers // NewInternalAPI returns a concerete implementation of the internal API. Callers
// can call functions directly on the returned API or via an HTTP interface using AddInternalRoutes. // can call functions directly on the returned API or via an HTTP interface using AddInternalRoutes.
func NewInternalAPI( func NewInternalAPI(
base *base.BaseDendrite, processContext *process.ProcessContext,
dendriteCfg *config.Dendrite,
cm sqlutil.Connections,
natsInstance *jetstream.NATSInstance,
federation api.FederationClient, federation api.FederationClient,
rsAPI roomserverAPI.FederationRoomserverAPI, rsAPI roomserverAPI.FederationRoomserverAPI,
caches *caching.Caches, caches *caching.Caches,
keyRing *gomatrixserverlib.KeyRing, keyRing *gomatrixserverlib.KeyRing,
resetBlacklist bool, resetBlacklist bool,
) api.FederationInternalAPI { ) api.FederationInternalAPI {
cfg := &base.Cfg.FederationAPI cfg := &dendriteCfg.FederationAPI
federationDB, err := storage.NewDatabase(base, &cfg.Database, base.Caches, base.Cfg.Global.IsLocalServerName) federationDB, err := storage.NewDatabase(processContext.Context(), cm, &cfg.Database, caches, dendriteCfg.Global.IsLocalServerName)
if err != nil { if err != nil {
logrus.WithError(err).Panic("failed to connect to federation sender db") logrus.WithError(err).Panic("failed to connect to federation sender db")
} }
@ -108,51 +119,51 @@ func NewInternalAPI(
cfg.FederationMaxRetries+1, cfg.FederationMaxRetries+1,
cfg.P2PFederationRetriesUntilAssumedOffline+1) cfg.P2PFederationRetriesUntilAssumedOffline+1)
js, nats := base.NATS.Prepare(base.ProcessContext, &cfg.Matrix.JetStream) js, nats := natsInstance.Prepare(processContext, &cfg.Matrix.JetStream)
signingInfo := base.Cfg.Global.SigningIdentities() signingInfo := dendriteCfg.Global.SigningIdentities()
queues := queue.NewOutgoingQueues( queues := queue.NewOutgoingQueues(
federationDB, base.ProcessContext, federationDB, processContext,
cfg.Matrix.DisableFederation, cfg.Matrix.DisableFederation,
cfg.Matrix.ServerName, federation, &stats, cfg.Matrix.ServerName, federation, &stats,
signingInfo, signingInfo,
) )
rsConsumer := consumers.NewOutputRoomEventConsumer( rsConsumer := consumers.NewOutputRoomEventConsumer(
base.ProcessContext, cfg, js, nats, queues, processContext, cfg, js, nats, queues,
federationDB, rsAPI, federationDB, rsAPI,
) )
if err = rsConsumer.Start(); err != nil { if err = rsConsumer.Start(); err != nil {
logrus.WithError(err).Panic("failed to start room server consumer") logrus.WithError(err).Panic("failed to start room server consumer")
} }
tsConsumer := consumers.NewOutputSendToDeviceConsumer( tsConsumer := consumers.NewOutputSendToDeviceConsumer(
base.ProcessContext, cfg, js, queues, federationDB, processContext, cfg, js, queues, federationDB,
) )
if err = tsConsumer.Start(); err != nil { if err = tsConsumer.Start(); err != nil {
logrus.WithError(err).Panic("failed to start send-to-device consumer") logrus.WithError(err).Panic("failed to start send-to-device consumer")
} }
receiptConsumer := consumers.NewOutputReceiptConsumer( receiptConsumer := consumers.NewOutputReceiptConsumer(
base.ProcessContext, cfg, js, queues, federationDB, processContext, cfg, js, queues, federationDB,
) )
if err = receiptConsumer.Start(); err != nil { if err = receiptConsumer.Start(); err != nil {
logrus.WithError(err).Panic("failed to start receipt consumer") logrus.WithError(err).Panic("failed to start receipt consumer")
} }
typingConsumer := consumers.NewOutputTypingConsumer( typingConsumer := consumers.NewOutputTypingConsumer(
base.ProcessContext, cfg, js, queues, federationDB, processContext, cfg, js, queues, federationDB,
) )
if err = typingConsumer.Start(); err != nil { if err = typingConsumer.Start(); err != nil {
logrus.WithError(err).Panic("failed to start typing consumer") logrus.WithError(err).Panic("failed to start typing consumer")
} }
keyConsumer := consumers.NewKeyChangeConsumer( keyConsumer := consumers.NewKeyChangeConsumer(
base.ProcessContext, &base.Cfg.KeyServer, js, queues, federationDB, rsAPI, processContext, &dendriteCfg.KeyServer, js, queues, federationDB, rsAPI,
) )
if err = keyConsumer.Start(); err != nil { if err = keyConsumer.Start(); err != nil {
logrus.WithError(err).Panic("failed to start key server consumer") logrus.WithError(err).Panic("failed to start key server consumer")
} }
presenceConsumer := consumers.NewOutputPresenceConsumer( presenceConsumer := consumers.NewOutputPresenceConsumer(
base.ProcessContext, cfg, js, queues, federationDB, rsAPI, processContext, cfg, js, queues, federationDB, rsAPI,
) )
if err = presenceConsumer.Start(); err != nil { if err = presenceConsumer.Start(); err != nil {
logrus.WithError(err).Panic("failed to start presence consumer") logrus.WithError(err).Panic("failed to start presence consumer")
@ -161,7 +172,7 @@ func NewInternalAPI(
var cleanExpiredEDUs func() var cleanExpiredEDUs func()
cleanExpiredEDUs = func() { cleanExpiredEDUs = func() {
logrus.Infof("Cleaning expired EDUs") logrus.Infof("Cleaning expired EDUs")
if err := federationDB.DeleteExpiredEDUs(base.Context()); err != nil { if err := federationDB.DeleteExpiredEDUs(processContext.Context()); err != nil {
logrus.WithError(err).Error("Failed to clean expired EDUs") logrus.WithError(err).Error("Failed to clean expired EDUs")
} }
time.AfterFunc(time.Hour, cleanExpiredEDUs) time.AfterFunc(time.Hour, cleanExpiredEDUs)

View file

@ -12,12 +12,14 @@ import (
"testing" "testing"
"time" "time"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/setup/jetstream"
"github.com/matrix-org/dendrite/setup/process"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/dendrite/federationapi/api" "github.com/matrix-org/dendrite/federationapi/api"
"github.com/matrix-org/dendrite/federationapi/routing" "github.com/matrix-org/dendrite/federationapi/routing"
"github.com/matrix-org/dendrite/internal/caching" "github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/setup/base"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
) )
@ -65,7 +67,7 @@ func TestMain(m *testing.M) {
// Create a new cache but don't enable prometheus! // Create a new cache but don't enable prometheus!
s.cache = caching.NewRistrettoCache(8*1024*1024, time.Hour, false) s.cache = caching.NewRistrettoCache(8*1024*1024, time.Hour, false)
natsInstance := jetstream.NATSInstance{}
// Create a temporary directory for JetStream. // Create a temporary directory for JetStream.
d, err := os.MkdirTemp("./", "jetstream*") d, err := os.MkdirTemp("./", "jetstream*")
if err != nil { if err != nil {
@ -109,8 +111,9 @@ func TestMain(m *testing.M) {
) )
// Finally, build the server key APIs. // Finally, build the server key APIs.
sbase := base.NewBaseDendrite(cfg, base.DisableMetrics) processCtx := process.NewProcessContext()
s.api = NewInternalAPI(sbase, s.fedclient, nil, s.cache, nil, true) cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
s.api = NewInternalAPI(processCtx, cfg, cm, &natsInstance, s.fedclient, nil, s.cache, nil, true)
} }
// Now that we have built our server key APIs, start the // Now that we have built our server key APIs, start the

View file

@ -10,6 +10,9 @@ import (
"testing" "testing"
"time" "time"
"github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/httputil"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/gomatrix" "github.com/matrix-org/gomatrix"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/nats-io/nats.go" "github.com/nats-io/nats.go"
@ -18,8 +21,6 @@ import (
"github.com/matrix-org/dendrite/federationapi/api" "github.com/matrix-org/dendrite/federationapi/api"
"github.com/matrix-org/dendrite/federationapi/internal" "github.com/matrix-org/dendrite/federationapi/internal"
rsapi "github.com/matrix-org/dendrite/roomserver/api" rsapi "github.com/matrix-org/dendrite/roomserver/api"
"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/setup/jetstream"
"github.com/matrix-org/dendrite/test" "github.com/matrix-org/dendrite/test"
"github.com/matrix-org/dendrite/test/testrig" "github.com/matrix-org/dendrite/test/testrig"
@ -162,21 +163,24 @@ func TestFederationAPIJoinThenKeyUpdate(t *testing.T) {
} }
func testFederationAPIJoinThenKeyUpdate(t *testing.T, dbType test.DBType) { func testFederationAPIJoinThenKeyUpdate(t *testing.T, dbType test.DBType) {
base, close := testrig.CreateBaseDendrite(t, dbType) cfg, processCtx, close := testrig.CreateConfig(t, dbType)
base.Cfg.FederationAPI.PreferDirectFetch = true cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
base.Cfg.FederationAPI.KeyPerspectives = nil caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
natsInstance := jetstream.NATSInstance{}
cfg.FederationAPI.PreferDirectFetch = true
cfg.FederationAPI.KeyPerspectives = nil
defer close() defer close()
jsctx, _ := base.NATS.Prepare(base.ProcessContext, &base.Cfg.Global.JetStream) jsctx, _ := natsInstance.Prepare(processCtx, &cfg.Global.JetStream)
defer jetstream.DeleteAllStreams(jsctx, &base.Cfg.Global.JetStream) defer jetstream.DeleteAllStreams(jsctx, &cfg.Global.JetStream)
serverA := gomatrixserverlib.ServerName("server.a") serverA := gomatrixserverlib.ServerName("server.a")
serverAKeyID := gomatrixserverlib.KeyID("ed25519:servera") serverAKeyID := gomatrixserverlib.KeyID("ed25519:servera")
serverAPrivKey := test.PrivateKeyA serverAPrivKey := test.PrivateKeyA
creator := test.NewUser(t, test.WithSigningServer(serverA, serverAKeyID, serverAPrivKey)) creator := test.NewUser(t, test.WithSigningServer(serverA, serverAKeyID, serverAPrivKey))
myServer := base.Cfg.Global.ServerName myServer := cfg.Global.ServerName
myServerKeyID := base.Cfg.Global.KeyID myServerKeyID := cfg.Global.KeyID
myServerPrivKey := base.Cfg.Global.PrivateKey myServerPrivKey := cfg.Global.PrivateKey
joiningUser := test.NewUser(t, test.WithSigningServer(myServer, myServerKeyID, myServerPrivKey)) joiningUser := test.NewUser(t, test.WithSigningServer(myServer, myServerKeyID, myServerPrivKey))
fmt.Printf("creator: %v joining user: %v\n", creator.ID, joiningUser.ID) fmt.Printf("creator: %v joining user: %v\n", creator.ID, joiningUser.ID)
room := test.NewRoom(t, creator) room := test.NewRoom(t, creator)
@ -212,7 +216,7 @@ func testFederationAPIJoinThenKeyUpdate(t *testing.T, dbType test.DBType) {
}, },
}, },
} }
fsapi := federationapi.NewInternalAPI(base, fc, rsapi, base.Caches, nil, false) fsapi := federationapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, fc, rsapi, caches, nil, false)
var resp api.PerformJoinResponse var resp api.PerformJoinResponse
fsapi.PerformJoin(context.Background(), &api.PerformJoinRequest{ fsapi.PerformJoin(context.Background(), &api.PerformJoinRequest{
@ -245,7 +249,7 @@ func testFederationAPIJoinThenKeyUpdate(t *testing.T, dbType test.DBType) {
} }
msg := &nats.Msg{ msg := &nats.Msg{
Subject: base.Cfg.Global.JetStream.Prefixed(jetstream.OutputKeyChangeEvent), Subject: cfg.Global.JetStream.Prefixed(jetstream.OutputKeyChangeEvent),
Header: nats.Header{}, Header: nats.Header{},
Data: b, Data: b,
} }
@ -263,30 +267,6 @@ func testFederationAPIJoinThenKeyUpdate(t *testing.T, dbType test.DBType) {
// Tests that event IDs with '/' in them (escaped as %2F) are correctly passed to the right handler and don't 404. // Tests that event IDs with '/' in them (escaped as %2F) are correctly passed to the right handler and don't 404.
// Relevant for v3 rooms and a cause of flakey sytests as the IDs are randomly generated. // Relevant for v3 rooms and a cause of flakey sytests as the IDs are randomly generated.
func TestRoomsV3URLEscapeDoNot404(t *testing.T) { func TestRoomsV3URLEscapeDoNot404(t *testing.T) {
_, privKey, _ := ed25519.GenerateKey(nil)
cfg := &config.Dendrite{}
cfg.Defaults(config.DefaultOpts{
Generate: true,
SingleDatabase: false,
})
cfg.Global.KeyID = gomatrixserverlib.KeyID("ed25519:auto")
cfg.Global.ServerName = gomatrixserverlib.ServerName("localhost")
cfg.Global.PrivateKey = privKey
cfg.Global.JetStream.InMemory = true
b := base.NewBaseDendrite(cfg, base.DisableMetrics)
keyRing := &test.NopJSONVerifier{}
// TODO: This is pretty fragile, as if anything calls anything on these nils this test will break.
// Unfortunately, it makes little sense to instantiate these dependencies when we just want to test routing.
federationapi.AddPublicRoutes(b, nil, nil, keyRing, nil, &internal.FederationInternalAPI{}, nil)
baseURL, cancel := test.ListenAndServe(t, b.PublicFederationAPIMux, true)
defer cancel()
serverName := gomatrixserverlib.ServerName(strings.TrimPrefix(baseURL, "https://"))
fedCli := gomatrixserverlib.NewFederationClient(
cfg.Global.SigningIdentities(),
gomatrixserverlib.WithSkipVerify(true),
)
testCases := []struct { testCases := []struct {
roomVer gomatrixserverlib.RoomVersion roomVer gomatrixserverlib.RoomVersion
eventJSON string eventJSON string
@ -315,6 +295,29 @@ func TestRoomsV3URLEscapeDoNot404(t *testing.T) {
}, },
} }
cfg, processCtx, close := testrig.CreateConfig(t, test.DBTypeSQLite)
defer close()
routers := httputil.NewRouters()
_, privKey, _ := ed25519.GenerateKey(nil)
cfg.Global.KeyID = gomatrixserverlib.KeyID("ed25519:auto")
cfg.Global.ServerName = gomatrixserverlib.ServerName("localhost")
cfg.Global.PrivateKey = privKey
cfg.Global.JetStream.InMemory = true
keyRing := &test.NopJSONVerifier{}
natsInstance := jetstream.NATSInstance{}
// TODO: This is pretty fragile, as if anything calls anything on these nils this test will break.
// Unfortunately, it makes little sense to instantiate these dependencies when we just want to test routing.
federationapi.AddPublicRoutes(processCtx, routers, cfg, &natsInstance, nil, nil, keyRing, nil, &internal.FederationInternalAPI{}, nil, caching.DisableMetrics)
baseURL, cancel := test.ListenAndServe(t, routers.Federation, true)
defer cancel()
serverName := gomatrixserverlib.ServerName(strings.TrimPrefix(baseURL, "https://"))
fedCli := gomatrixserverlib.NewFederationClient(
cfg.Global.SigningIdentities(),
gomatrixserverlib.WithSkipVerify(true),
)
for _, tc := range testCases { for _, tc := range testCases {
ev, err := gomatrixserverlib.NewEventFromTrustedJSON([]byte(tc.eventJSON), false, tc.roomVer) ev, err := gomatrixserverlib.NewEventFromTrustedJSON([]byte(tc.eventJSON), false, tc.roomVer)
if err != nil { if err != nil {

View file

@ -21,6 +21,9 @@ import (
"testing" "testing"
"time" "time"
"github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/test/testrig"
"go.uber.org/atomic" "go.uber.org/atomic"
"gotest.tools/v3/poll" "gotest.tools/v3/poll"
@ -33,31 +36,29 @@ import (
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/dendrite/setup/process" "github.com/matrix-org/dendrite/setup/process"
"github.com/matrix-org/dendrite/test" "github.com/matrix-org/dendrite/test"
"github.com/matrix-org/dendrite/test/testrig"
) )
func mustCreateFederationDatabase(t *testing.T, dbType test.DBType, realDatabase bool) (storage.Database, *process.ProcessContext, func()) { func mustCreateFederationDatabase(t *testing.T, dbType test.DBType, realDatabase bool) (storage.Database, *process.ProcessContext, func()) {
if realDatabase { if realDatabase {
// Real Database/s // Real Database/s
b, baseClose := testrig.CreateBaseDendrite(t, dbType) cfg, processCtx, close := testrig.CreateConfig(t, dbType)
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
connStr, dbClose := test.PrepareDBConnectionString(t, dbType) connStr, dbClose := test.PrepareDBConnectionString(t, dbType)
db, err := storage.NewDatabase(b, &config.DatabaseOptions{ db, err := storage.NewDatabase(processCtx.Context(), cm, &config.DatabaseOptions{
ConnectionString: config.DataSource(connStr), ConnectionString: config.DataSource(connStr),
}, b.Caches, b.Cfg.Global.IsLocalServerName) }, caches, cfg.Global.IsLocalServerName)
if err != nil { if err != nil {
t.Fatalf("NewDatabase returned %s", err) t.Fatalf("NewDatabase returned %s", err)
} }
return db, b.ProcessContext, func() { return db, processCtx, func() {
close()
dbClose() dbClose()
baseClose()
} }
} else { } else {
// Fake Database // Fake Database
db := test.NewInMemoryFederationDatabase() db := test.NewInMemoryFederationDatabase()
b := struct { return db, process.NewProcessContext(), func() {}
ProcessContext *process.ProcessContext
}{ProcessContext: process.NewProcessContext()}
return db, b.ProcessContext, func() {}
} }
} }

View file

@ -27,7 +27,10 @@ import (
fedAPI "github.com/matrix-org/dendrite/federationapi" fedAPI "github.com/matrix-org/dendrite/federationapi"
fedInternal "github.com/matrix-org/dendrite/federationapi/internal" fedInternal "github.com/matrix-org/dendrite/federationapi/internal"
"github.com/matrix-org/dendrite/federationapi/routing" "github.com/matrix-org/dendrite/federationapi/routing"
"github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/httputil" "github.com/matrix-org/dendrite/internal/httputil"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/setup/jetstream"
"github.com/matrix-org/dendrite/test" "github.com/matrix-org/dendrite/test"
"github.com/matrix-org/dendrite/test/testrig" "github.com/matrix-org/dendrite/test/testrig"
userAPI "github.com/matrix-org/dendrite/userapi/api" userAPI "github.com/matrix-org/dendrite/userapi/api"
@ -46,23 +49,26 @@ func (u *fakeUserAPI) QueryProfile(ctx context.Context, req *userAPI.QueryProfil
func TestHandleQueryProfile(t *testing.T) { func TestHandleQueryProfile(t *testing.T) {
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
base, close := testrig.CreateBaseDendrite(t, dbType) cfg, processCtx, close := testrig.CreateConfig(t, dbType)
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
routers := httputil.NewRouters()
defer close() defer close()
fedMux := mux.NewRouter().SkipClean(true).PathPrefix(httputil.PublicFederationPathPrefix).Subrouter().UseEncodedPath() fedMux := mux.NewRouter().SkipClean(true).PathPrefix(httputil.PublicFederationPathPrefix).Subrouter().UseEncodedPath()
base.PublicFederationAPIMux = fedMux natsInstance := jetstream.NATSInstance{}
base.Cfg.FederationAPI.Matrix.SigningIdentity.ServerName = testOrigin routers.Federation = fedMux
base.Cfg.FederationAPI.Matrix.Metrics.Enabled = false cfg.FederationAPI.Matrix.SigningIdentity.ServerName = testOrigin
cfg.FederationAPI.Matrix.Metrics.Enabled = false
fedClient := fakeFedClient{} fedClient := fakeFedClient{}
serverKeyAPI := &signing.YggdrasilKeys{} serverKeyAPI := &signing.YggdrasilKeys{}
keyRing := serverKeyAPI.KeyRing() keyRing := serverKeyAPI.KeyRing()
fedapi := fedAPI.NewInternalAPI(base, &fedClient, nil, nil, keyRing, true) fedapi := fedAPI.NewInternalAPI(processCtx, cfg, cm, &natsInstance, &fedClient, nil, nil, keyRing, true)
userapi := fakeUserAPI{} userapi := fakeUserAPI{}
r, ok := fedapi.(*fedInternal.FederationInternalAPI) r, ok := fedapi.(*fedInternal.FederationInternalAPI)
if !ok { if !ok {
panic("This is a programming error.") panic("This is a programming error.")
} }
routing.Setup(base, nil, r, keyRing, &fedClient, &userapi, &base.Cfg.MSCs, nil, nil) routing.Setup(routers, cfg, nil, r, keyRing, &fedClient, &userapi, &cfg.MSCs, nil, nil, caching.DisableMetrics)
handler := fedMux.Get(routing.QueryProfileRouteName).GetHandler().ServeHTTP handler := fedMux.Get(routing.QueryProfileRouteName).GetHandler().ServeHTTP
_, sk, _ := ed25519.GenerateKey(nil) _, sk, _ := ed25519.GenerateKey(nil)

View file

@ -28,7 +28,10 @@ import (
fedclient "github.com/matrix-org/dendrite/federationapi/api" fedclient "github.com/matrix-org/dendrite/federationapi/api"
fedInternal "github.com/matrix-org/dendrite/federationapi/internal" fedInternal "github.com/matrix-org/dendrite/federationapi/internal"
"github.com/matrix-org/dendrite/federationapi/routing" "github.com/matrix-org/dendrite/federationapi/routing"
"github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/httputil" "github.com/matrix-org/dendrite/internal/httputil"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/setup/jetstream"
"github.com/matrix-org/dendrite/test" "github.com/matrix-org/dendrite/test"
"github.com/matrix-org/dendrite/test/testrig" "github.com/matrix-org/dendrite/test/testrig"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
@ -46,23 +49,26 @@ func (f *fakeFedClient) LookupRoomAlias(ctx context.Context, origin, s gomatrixs
func TestHandleQueryDirectory(t *testing.T) { func TestHandleQueryDirectory(t *testing.T) {
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
base, close := testrig.CreateBaseDendrite(t, dbType) cfg, processCtx, close := testrig.CreateConfig(t, dbType)
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
routers := httputil.NewRouters()
defer close() defer close()
fedMux := mux.NewRouter().SkipClean(true).PathPrefix(httputil.PublicFederationPathPrefix).Subrouter().UseEncodedPath() fedMux := mux.NewRouter().SkipClean(true).PathPrefix(httputil.PublicFederationPathPrefix).Subrouter().UseEncodedPath()
base.PublicFederationAPIMux = fedMux natsInstance := jetstream.NATSInstance{}
base.Cfg.FederationAPI.Matrix.SigningIdentity.ServerName = testOrigin routers.Federation = fedMux
base.Cfg.FederationAPI.Matrix.Metrics.Enabled = false cfg.FederationAPI.Matrix.SigningIdentity.ServerName = testOrigin
cfg.FederationAPI.Matrix.Metrics.Enabled = false
fedClient := fakeFedClient{} fedClient := fakeFedClient{}
serverKeyAPI := &signing.YggdrasilKeys{} serverKeyAPI := &signing.YggdrasilKeys{}
keyRing := serverKeyAPI.KeyRing() keyRing := serverKeyAPI.KeyRing()
fedapi := fedAPI.NewInternalAPI(base, &fedClient, nil, nil, keyRing, true) fedapi := fedAPI.NewInternalAPI(processCtx, cfg, cm, &natsInstance, &fedClient, nil, nil, keyRing, true)
userapi := fakeUserAPI{} userapi := fakeUserAPI{}
r, ok := fedapi.(*fedInternal.FederationInternalAPI) r, ok := fedapi.(*fedInternal.FederationInternalAPI)
if !ok { if !ok {
panic("This is a programming error.") panic("This is a programming error.")
} }
routing.Setup(base, nil, r, keyRing, &fedClient, &userapi, &base.Cfg.MSCs, nil, nil) routing.Setup(routers, cfg, nil, r, keyRing, &fedClient, &userapi, &cfg.MSCs, nil, nil, caching.DisableMetrics)
handler := fedMux.Get(routing.QueryDirectoryRouteName).GetHandler().ServeHTTP handler := fedMux.Get(routing.QueryDirectoryRouteName).GetHandler().ServeHTTP
_, sk, _ := ed25519.GenerateKey(nil) _, sk, _ := ed25519.GenerateKey(nil)

View file

@ -31,7 +31,6 @@ import (
"github.com/matrix-org/dendrite/internal/httputil" "github.com/matrix-org/dendrite/internal/httputil"
"github.com/matrix-org/dendrite/roomserver/api" "github.com/matrix-org/dendrite/roomserver/api"
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api" roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
"github.com/matrix-org/dendrite/setup/base"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
userapi "github.com/matrix-org/dendrite/userapi/api" userapi "github.com/matrix-org/dendrite/userapi/api"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
@ -55,7 +54,8 @@ const (
// applied: // applied:
// nolint: gocyclo // nolint: gocyclo
func Setup( func Setup(
base *base.BaseDendrite, routers httputil.Routers,
dendriteCfg *config.Dendrite,
rsAPI roomserverAPI.FederationRoomserverAPI, rsAPI roomserverAPI.FederationRoomserverAPI,
fsAPI *fedInternal.FederationInternalAPI, fsAPI *fedInternal.FederationInternalAPI,
keys gomatrixserverlib.JSONVerifier, keys gomatrixserverlib.JSONVerifier,
@ -63,14 +63,14 @@ func Setup(
userAPI userapi.FederationUserAPI, userAPI userapi.FederationUserAPI,
mscCfg *config.MSCs, mscCfg *config.MSCs,
servers federationAPI.ServersInRoomProvider, servers federationAPI.ServersInRoomProvider,
producer *producers.SyncAPIProducer, producer *producers.SyncAPIProducer, enableMetrics bool,
) { ) {
fedMux := base.PublicFederationAPIMux fedMux := routers.Federation
keyMux := base.PublicKeyAPIMux keyMux := routers.Keys
wkMux := base.PublicWellKnownAPIMux wkMux := routers.WellKnown
cfg := &base.Cfg.FederationAPI cfg := &dendriteCfg.FederationAPI
if base.EnableMetrics { if enableMetrics {
prometheus.MustRegister( prometheus.MustRegister(
internal.PDUCountTotal, internal.EDUCountTotal, internal.PDUCountTotal, internal.EDUCountTotal,
) )

View file

@ -25,7 +25,10 @@ import (
fedAPI "github.com/matrix-org/dendrite/federationapi" fedAPI "github.com/matrix-org/dendrite/federationapi"
fedInternal "github.com/matrix-org/dendrite/federationapi/internal" fedInternal "github.com/matrix-org/dendrite/federationapi/internal"
"github.com/matrix-org/dendrite/federationapi/routing" "github.com/matrix-org/dendrite/federationapi/routing"
"github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/httputil" "github.com/matrix-org/dendrite/internal/httputil"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/setup/jetstream"
"github.com/matrix-org/dendrite/test" "github.com/matrix-org/dendrite/test"
"github.com/matrix-org/dendrite/test/testrig" "github.com/matrix-org/dendrite/test/testrig"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
@ -44,21 +47,24 @@ type sendContent struct {
func TestHandleSend(t *testing.T) { func TestHandleSend(t *testing.T) {
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
base, close := testrig.CreateBaseDendrite(t, dbType) cfg, processCtx, close := testrig.CreateConfig(t, dbType)
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
routers := httputil.NewRouters()
defer close() defer close()
fedMux := mux.NewRouter().SkipClean(true).PathPrefix(httputil.PublicFederationPathPrefix).Subrouter().UseEncodedPath() fedMux := mux.NewRouter().SkipClean(true).PathPrefix(httputil.PublicFederationPathPrefix).Subrouter().UseEncodedPath()
base.PublicFederationAPIMux = fedMux natsInstance := jetstream.NATSInstance{}
base.Cfg.FederationAPI.Matrix.SigningIdentity.ServerName = testOrigin routers.Federation = fedMux
base.Cfg.FederationAPI.Matrix.Metrics.Enabled = false cfg.FederationAPI.Matrix.SigningIdentity.ServerName = testOrigin
fedapi := fedAPI.NewInternalAPI(base, nil, nil, nil, nil, true) cfg.FederationAPI.Matrix.Metrics.Enabled = false
fedapi := fedAPI.NewInternalAPI(processCtx, cfg, cm, &natsInstance, nil, nil, nil, nil, true)
serverKeyAPI := &signing.YggdrasilKeys{} serverKeyAPI := &signing.YggdrasilKeys{}
keyRing := serverKeyAPI.KeyRing() keyRing := serverKeyAPI.KeyRing()
r, ok := fedapi.(*fedInternal.FederationInternalAPI) r, ok := fedapi.(*fedInternal.FederationInternalAPI)
if !ok { if !ok {
panic("This is a programming error.") panic("This is a programming error.")
} }
routing.Setup(base, nil, r, keyRing, nil, nil, &base.Cfg.MSCs, nil, nil) routing.Setup(routers, cfg, nil, r, keyRing, nil, nil, &cfg.MSCs, nil, nil, caching.DisableMetrics)
handler := fedMux.Get(routing.SendRouteName).GetHandler().ServeHTTP handler := fedMux.Get(routing.SendRouteName).GetHandler().ServeHTTP
_, sk, _ := ed25519.GenerateKey(nil) _, sk, _ := ed25519.GenerateKey(nil)

View file

@ -16,6 +16,7 @@
package postgres package postgres
import ( import (
"context"
"database/sql" "database/sql"
"fmt" "fmt"
@ -23,7 +24,6 @@ import (
"github.com/matrix-org/dendrite/federationapi/storage/shared" "github.com/matrix-org/dendrite/federationapi/storage/shared"
"github.com/matrix-org/dendrite/internal/caching" "github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/sqlutil" "github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/setup/base"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
) )
@ -36,10 +36,10 @@ type Database struct {
} }
// NewDatabase opens a new database // NewDatabase opens a new database
func NewDatabase(base *base.BaseDendrite, dbProperties *config.DatabaseOptions, cache caching.FederationCache, isLocalServerName func(gomatrixserverlib.ServerName) bool) (*Database, error) { func NewDatabase(ctx context.Context, conMan sqlutil.Connections, dbProperties *config.DatabaseOptions, cache caching.FederationCache, isLocalServerName func(gomatrixserverlib.ServerName) bool) (*Database, error) {
var d Database var d Database
var err error var err error
if d.db, d.writer, err = base.DatabaseConnection(dbProperties, sqlutil.NewDummyWriter()); err != nil { if d.db, d.writer, err = conMan.Connection(dbProperties); err != nil {
return nil, err return nil, err
} }
blacklist, err := NewPostgresBlacklistTable(d.db) blacklist, err := NewPostgresBlacklistTable(d.db)
@ -95,7 +95,7 @@ func NewDatabase(base *base.BaseDendrite, dbProperties *config.DatabaseOptions,
Version: "federationsender: drop federationsender_rooms", Version: "federationsender: drop federationsender_rooms",
Up: deltas.UpRemoveRoomsTable, Up: deltas.UpRemoveRoomsTable,
}) })
err = m.Up(base.Context()) err = m.Up(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -15,13 +15,13 @@
package sqlite3 package sqlite3
import ( import (
"context"
"database/sql" "database/sql"
"github.com/matrix-org/dendrite/federationapi/storage/shared" "github.com/matrix-org/dendrite/federationapi/storage/shared"
"github.com/matrix-org/dendrite/federationapi/storage/sqlite3/deltas" "github.com/matrix-org/dendrite/federationapi/storage/sqlite3/deltas"
"github.com/matrix-org/dendrite/internal/caching" "github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/sqlutil" "github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/setup/base"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
) )
@ -34,10 +34,10 @@ type Database struct {
} }
// NewDatabase opens a new database // NewDatabase opens a new database
func NewDatabase(base *base.BaseDendrite, dbProperties *config.DatabaseOptions, cache caching.FederationCache, isLocalServerName func(gomatrixserverlib.ServerName) bool) (*Database, error) { func NewDatabase(ctx context.Context, conMan sqlutil.Connections, dbProperties *config.DatabaseOptions, cache caching.FederationCache, isLocalServerName func(gomatrixserverlib.ServerName) bool) (*Database, error) {
var d Database var d Database
var err error var err error
if d.db, d.writer, err = base.DatabaseConnection(dbProperties, sqlutil.NewExclusiveWriter()); err != nil { if d.db, d.writer, err = conMan.Connection(dbProperties); err != nil {
return nil, err return nil, err
} }
blacklist, err := NewSQLiteBlacklistTable(d.db) blacklist, err := NewSQLiteBlacklistTable(d.db)
@ -93,7 +93,7 @@ func NewDatabase(base *base.BaseDendrite, dbProperties *config.DatabaseOptions,
Version: "federationsender: drop federationsender_rooms", Version: "federationsender: drop federationsender_rooms",
Up: deltas.UpRemoveRoomsTable, Up: deltas.UpRemoveRoomsTable,
}) })
err = m.Up(base.Context()) err = m.Up(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -18,23 +18,24 @@
package storage package storage
import ( import (
"context"
"fmt" "fmt"
"github.com/matrix-org/dendrite/federationapi/storage/postgres" "github.com/matrix-org/dendrite/federationapi/storage/postgres"
"github.com/matrix-org/dendrite/federationapi/storage/sqlite3" "github.com/matrix-org/dendrite/federationapi/storage/sqlite3"
"github.com/matrix-org/dendrite/internal/caching" "github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/setup/base" "github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
) )
// NewDatabase opens a new database // NewDatabase opens a new database
func NewDatabase(base *base.BaseDendrite, dbProperties *config.DatabaseOptions, cache caching.FederationCache, isLocalServerName func(gomatrixserverlib.ServerName) bool) (Database, error) { func NewDatabase(ctx context.Context, conMan sqlutil.Connections, dbProperties *config.DatabaseOptions, cache caching.FederationCache, isLocalServerName func(gomatrixserverlib.ServerName) bool) (Database, error) {
switch { switch {
case dbProperties.ConnectionString.IsSQLite(): case dbProperties.ConnectionString.IsSQLite():
return sqlite3.NewDatabase(base, dbProperties, cache, isLocalServerName) return sqlite3.NewDatabase(ctx, conMan, dbProperties, cache, isLocalServerName)
case dbProperties.ConnectionString.IsPostgres(): case dbProperties.ConnectionString.IsPostgres():
return postgres.NewDatabase(base, dbProperties, cache, isLocalServerName) return postgres.NewDatabase(ctx, conMan, dbProperties, cache, isLocalServerName)
default: default:
return nil, fmt.Errorf("unexpected database type") return nil, fmt.Errorf("unexpected database type")
} }

View file

@ -7,26 +7,28 @@ import (
"time" "time"
"github.com/matrix-org/dendrite/federationapi/storage" "github.com/matrix-org/dendrite/federationapi/storage"
"github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/dendrite/test" "github.com/matrix-org/dendrite/test"
"github.com/matrix-org/dendrite/test/testrig"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/util" "github.com/matrix-org/util"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func mustCreateFederationDatabase(t *testing.T, dbType test.DBType) (storage.Database, func()) { func mustCreateFederationDatabase(t *testing.T, dbType test.DBType) (storage.Database, func()) {
b, baseClose := testrig.CreateBaseDendrite(t, dbType) caches := caching.NewRistrettoCache(8*1024*1024, time.Hour, false)
connStr, dbClose := test.PrepareDBConnectionString(t, dbType) connStr, dbClose := test.PrepareDBConnectionString(t, dbType)
db, err := storage.NewDatabase(b, &config.DatabaseOptions{ ctx := context.Background()
cm := sqlutil.NewConnectionManager(nil, config.DatabaseOptions{})
db, err := storage.NewDatabase(ctx, cm, &config.DatabaseOptions{
ConnectionString: config.DataSource(connStr), ConnectionString: config.DataSource(connStr),
}, b.Caches, func(server gomatrixserverlib.ServerName) bool { return server == "localhost" }) }, caches, func(server gomatrixserverlib.ServerName) bool { return server == "localhost" })
if err != nil { if err != nil {
t.Fatalf("NewDatabase returned %s", err) t.Fatalf("NewDatabase returned %s", err)
} }
return db, func() { return db, func() {
dbClose() dbClose()
baseClose()
} }
} }

View file

@ -15,20 +15,21 @@
package storage package storage
import ( import (
"context"
"fmt" "fmt"
"github.com/matrix-org/dendrite/federationapi/storage/sqlite3" "github.com/matrix-org/dendrite/federationapi/storage/sqlite3"
"github.com/matrix-org/dendrite/internal/caching" "github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/setup/base" "github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
) )
// NewDatabase opens a new database // NewDatabase opens a new database
func NewDatabase(base *base.BaseDendrite, dbProperties *config.DatabaseOptions, cache caching.FederationCache, serverName gomatrixserverlib.ServerName) (Database, error) { func NewDatabase(ctx context.Context, conMan sqlutil.Connections, dbProperties *config.DatabaseOptions, cache caching.FederationCache, isLocalServerName func(gomatrixserverlib.ServerName) bool) (Database, error) {
switch { switch {
case dbProperties.ConnectionString.IsSQLite(): case dbProperties.ConnectionString.IsSQLite():
return sqlite3.NewDatabase(base, dbProperties, cache, serverName) return sqlite3.NewDatabase(ctx, conMan, dbProperties, cache, isLocalServerName)
case dbProperties.ConnectionString.IsPostgres(): case dbProperties.ConnectionString.IsPostgres():
return nil, fmt.Errorf("can't use Postgres implementation") return nil, fmt.Errorf("can't use Postgres implementation")
default: default:

2
go.mod
View file

@ -22,7 +22,7 @@ require (
github.com/matrix-org/dugong v0.0.0-20210921133753-66e6b1c67e2e 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/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91
github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530 github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530
github.com/matrix-org/gomatrixserverlib v0.0.0-20230131183213-122f1e0e3fa1 github.com/matrix-org/gomatrixserverlib v0.0.0-20230320105331-4dd7ff2f0e3a
github.com/matrix-org/pinecone v0.11.1-0.20230210171230-8c3b24f2649a github.com/matrix-org/pinecone v0.11.1-0.20230210171230-8c3b24f2649a
github.com/matrix-org/util v0.0.0-20221111132719-399730281e66 github.com/matrix-org/util v0.0.0-20221111132719-399730281e66
github.com/mattn/go-sqlite3 v1.14.16 github.com/mattn/go-sqlite3 v1.14.16

4
go.sum
View file

@ -321,8 +321,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/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 h1:kHKxCOLcHH8r4Fzarl4+Y3K5hjothkVW5z7T1dUM11U=
github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530/go.mod h1:/gBX06Kw0exX1HrwmoBibFA98yBk/jxKpGVeyQbff+s= github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530/go.mod h1:/gBX06Kw0exX1HrwmoBibFA98yBk/jxKpGVeyQbff+s=
github.com/matrix-org/gomatrixserverlib v0.0.0-20230131183213-122f1e0e3fa1 h1:JSw0nmjMrgBmoM2aQsa78LTpI5BnuD9+vOiEQ4Qo0qw= github.com/matrix-org/gomatrixserverlib v0.0.0-20230320105331-4dd7ff2f0e3a h1:F6K1i61KcJ8cX/y0Q8/44Dh1w+fpESQd92gq885FDrI=
github.com/matrix-org/gomatrixserverlib v0.0.0-20230131183213-122f1e0e3fa1/go.mod h1:Mtifyr8q8htcBeugvlDnkBcNUy5LO8OzUoplAf1+mb4= github.com/matrix-org/gomatrixserverlib v0.0.0-20230320105331-4dd7ff2f0e3a/go.mod h1:7HTbSZe+CIdmeqVyFMekwD5dFU8khWQyngKATvd12FU=
github.com/matrix-org/pinecone v0.11.1-0.20230210171230-8c3b24f2649a h1:awrPDf9LEFySxTLKYBMCiObelNx/cBuv/wzllvCCH3A= github.com/matrix-org/pinecone v0.11.1-0.20230210171230-8c3b24f2649a h1:awrPDf9LEFySxTLKYBMCiObelNx/cBuv/wzllvCCH3A=
github.com/matrix-org/pinecone v0.11.1-0.20230210171230-8c3b24f2649a/go.mod h1:HchJX9oKMXaT2xYFs0Ha/6Zs06mxLU8k6F1ODnrGkeQ= github.com/matrix-org/pinecone v0.11.1-0.20230210171230-8c3b24f2649a/go.mod h1:HchJX9oKMXaT2xYFs0Ha/6Zs06mxLU8k6F1ODnrGkeQ=
github.com/matrix-org/util v0.0.0-20221111132719-399730281e66 h1:6z4KxomXSIGWqhHcfzExgkH3Z3UkIXry4ibJS4Aqz2Y= github.com/matrix-org/util v0.0.0-20221111132719-399730281e66 h1:6z4KxomXSIGWqhHcfzExgkH3Z3UkIXry4ibJS4Aqz2Y=

View file

@ -46,6 +46,11 @@ const (
eventStateKeyNIDCache eventStateKeyNIDCache
) )
const (
DisableMetrics = false
EnableMetrics = true
)
func NewRistrettoCache(maxCost config.DataUnit, maxAge time.Duration, enablePrometheus bool) *Caches { func NewRistrettoCache(maxCost config.DataUnit, maxAge time.Duration, enablePrometheus bool) *Caches {
cache, err := ristretto.NewCache(&ristretto.Config{ cache, err := ristretto.NewCache(&ristretto.Config{
NumCounters: int64((maxCost / 1024) * 10), // 10 counters per 1KB data, affects bloom filter size NumCounters: int64((maxCost / 1024) * 10), // 10 counters per 1KB data, affects bloom filter size

View file

@ -18,10 +18,10 @@
package fulltext package fulltext
import ( import (
"context"
"strings" "strings"
"github.com/blevesearch/bleve/v2" "github.com/blevesearch/bleve/v2"
// side effect imports to allow all possible languages // side effect imports to allow all possible languages
_ "github.com/blevesearch/bleve/v2/analysis/lang/ar" _ "github.com/blevesearch/bleve/v2/analysis/lang/ar"
_ "github.com/blevesearch/bleve/v2/analysis/lang/cjk" _ "github.com/blevesearch/bleve/v2/analysis/lang/cjk"
@ -55,6 +55,13 @@ type Search struct {
FulltextIndex bleve.Index FulltextIndex bleve.Index
} }
type Indexer interface {
Index(elements ...IndexElement) error
Delete(eventID string) error
Search(term string, roomIDs, keys []string, limit, from int, orderByStreamPos bool) (*bleve.SearchResult, error)
Close() error
}
// IndexElement describes the layout of an element to index // IndexElement describes the layout of an element to index
type IndexElement struct { type IndexElement struct {
EventID string EventID string
@ -77,12 +84,18 @@ func (i *IndexElement) SetContentType(v string) {
} }
// New opens a new/existing fulltext index // New opens a new/existing fulltext index
func New(cfg config.Fulltext) (fts *Search, err error) { func New(ctx context.Context, cfg config.Fulltext) (fts *Search, err error) {
fts = &Search{} fts = &Search{}
fts.FulltextIndex, err = openIndex(cfg) fts.FulltextIndex, err = openIndex(cfg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
go func() {
// Wait for the context (should be from process.ProcessContext) to be
// done, indicating that Dendrite is shutting down.
<-ctx.Done()
_ = fts.Close()
}()
return fts, nil return fts, nil
} }

View file

@ -18,6 +18,7 @@ import (
"reflect" "reflect"
"testing" "testing"
"github.com/matrix-org/dendrite/setup/process"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/util" "github.com/matrix-org/util"
@ -25,7 +26,7 @@ import (
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
) )
func mustOpenIndex(t *testing.T, tempDir string) *fulltext.Search { func mustOpenIndex(t *testing.T, tempDir string) (*fulltext.Search, *process.ProcessContext) {
t.Helper() t.Helper()
cfg := config.Fulltext{ cfg := config.Fulltext{
Enabled: true, Enabled: true,
@ -36,11 +37,12 @@ func mustOpenIndex(t *testing.T, tempDir string) *fulltext.Search {
cfg.IndexPath = config.Path(tempDir) cfg.IndexPath = config.Path(tempDir)
cfg.InMemory = false cfg.InMemory = false
} }
fts, err := fulltext.New(cfg) ctx := process.NewProcessContext()
fts, err := fulltext.New(ctx.Context(), cfg)
if err != nil { if err != nil {
t.Fatal("failed to open fulltext index:", err) t.Fatal("failed to open fulltext index:", err)
} }
return fts return fts, ctx
} }
func mustAddTestData(t *testing.T, fts *fulltext.Search, firstStreamPos int64) (eventIDs, roomIDs []string) { func mustAddTestData(t *testing.T, fts *fulltext.Search, firstStreamPos int64) (eventIDs, roomIDs []string) {
@ -93,19 +95,17 @@ func mustAddTestData(t *testing.T, fts *fulltext.Search, firstStreamPos int64) (
func TestOpen(t *testing.T) { func TestOpen(t *testing.T) {
dataDir := t.TempDir() dataDir := t.TempDir()
fts := mustOpenIndex(t, dataDir) _, ctx := mustOpenIndex(t, dataDir)
if err := fts.Close(); err != nil { ctx.ShutdownDendrite()
t.Fatal("unable to close fulltext index", err)
}
// open existing index // open existing index
fts = mustOpenIndex(t, dataDir) _, ctx = mustOpenIndex(t, dataDir)
defer fts.Close() ctx.ShutdownDendrite()
} }
func TestIndex(t *testing.T) { func TestIndex(t *testing.T) {
fts := mustOpenIndex(t, "") fts, ctx := mustOpenIndex(t, "")
defer fts.Close() defer ctx.ShutdownDendrite()
// add some data // add some data
var streamPos int64 = 1 var streamPos int64 = 1
@ -128,8 +128,8 @@ func TestIndex(t *testing.T) {
} }
func TestDelete(t *testing.T) { func TestDelete(t *testing.T) {
fts := mustOpenIndex(t, "") fts, ctx := mustOpenIndex(t, "")
defer fts.Close() defer ctx.ShutdownDendrite()
eventIDs, roomIDs := mustAddTestData(t, fts, 0) eventIDs, roomIDs := mustAddTestData(t, fts, 0)
res1, err := fts.Search("lorem", roomIDs[:1], nil, 50, 0, false) res1, err := fts.Search("lorem", roomIDs[:1], nil, 50, 0, false)
if err != nil { if err != nil {
@ -224,7 +224,8 @@ func TestSearch(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
f := mustOpenIndex(t, "") f, ctx := mustOpenIndex(t, "")
defer ctx.ShutdownDendrite()
eventIDs, roomIDs := mustAddTestData(t, f, 0) eventIDs, roomIDs := mustAddTestData(t, f, 0)
var searchRooms []string var searchRooms []string
for _, x := range tt.args.roomIndex { for _, x := range tt.args.roomIndex {

View file

@ -15,8 +15,9 @@
package fulltext package fulltext
import ( import (
"github.com/matrix-org/dendrite/setup/config"
"time" "time"
"github.com/matrix-org/dendrite/setup/config"
) )
type Search struct{} type Search struct{}
@ -28,6 +29,13 @@ type IndexElement struct {
StreamPosition int64 StreamPosition int64
} }
type Indexer interface {
Index(elements ...IndexElement) error
Delete(eventID string) error
Search(term string, roomIDs, keys []string, limit, from int, orderByStreamPos bool) (SearchResult, error)
Close() error
}
type SearchResult struct { type SearchResult struct {
Status interface{} `json:"status"` Status interface{} `json:"status"`
Request *interface{} `json:"request"` Request *interface{} `json:"request"`
@ -48,7 +56,7 @@ func (f *Search) Close() error {
return nil return nil
} }
func (f *Search) Index(e IndexElement) error { func (f *Search) Index(e ...IndexElement) error {
return nil return nil
} }

View file

@ -15,7 +15,10 @@
package httputil package httputil
import ( import (
"net/http"
"net/url" "net/url"
"github.com/gorilla/mux"
) )
// URLDecodeMapValues is a function that iterates through each of the items in a // URLDecodeMapValues is a function that iterates through each of the items in a
@ -33,3 +36,52 @@ func URLDecodeMapValues(vmap map[string]string) (map[string]string, error) {
return decoded, nil return decoded, nil
} }
type Routers struct {
Client *mux.Router
Federation *mux.Router
Keys *mux.Router
Media *mux.Router
WellKnown *mux.Router
Static *mux.Router
DendriteAdmin *mux.Router
SynapseAdmin *mux.Router
}
func NewRouters() Routers {
r := Routers{
Client: mux.NewRouter().SkipClean(true).PathPrefix(PublicClientPathPrefix).Subrouter().UseEncodedPath(),
Federation: mux.NewRouter().SkipClean(true).PathPrefix(PublicFederationPathPrefix).Subrouter().UseEncodedPath(),
Keys: mux.NewRouter().SkipClean(true).PathPrefix(PublicKeyPathPrefix).Subrouter().UseEncodedPath(),
Media: mux.NewRouter().SkipClean(true).PathPrefix(PublicMediaPathPrefix).Subrouter().UseEncodedPath(),
WellKnown: mux.NewRouter().SkipClean(true).PathPrefix(PublicWellKnownPrefix).Subrouter().UseEncodedPath(),
Static: mux.NewRouter().SkipClean(true).PathPrefix(PublicStaticPath).Subrouter().UseEncodedPath(),
DendriteAdmin: mux.NewRouter().SkipClean(true).PathPrefix(DendriteAdminPathPrefix).Subrouter().UseEncodedPath(),
SynapseAdmin: mux.NewRouter().SkipClean(true).PathPrefix(SynapseAdminPathPrefix).Subrouter().UseEncodedPath(),
}
r.configureHTTPErrors()
return r
}
var NotAllowedHandler = WrapHandlerInCORS(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusMethodNotAllowed)
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`{"errcode":"M_UNRECOGNIZED","error":"Unrecognized request"}`)) // nolint:misspell
}))
var NotFoundCORSHandler = WrapHandlerInCORS(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNotFound)
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`{"errcode":"M_UNRECOGNIZED","error":"Unrecognized request"}`)) // nolint:misspell
}))
func (r *Routers) configureHTTPErrors() {
for _, router := range []*mux.Router{
r.Client, r.Federation, r.Keys,
r.Media, r.WellKnown, r.Static,
r.DendriteAdmin, r.SynapseAdmin,
} {
router.NotFoundHandler = NotFoundCORSHandler
router.MethodNotAllowedHandler = NotAllowedHandler
}
}

View file

@ -0,0 +1,38 @@
package httputil
import (
"net/http"
"net/http/httptest"
"path/filepath"
"testing"
)
func TestRoutersError(t *testing.T) {
r := NewRouters()
// not found test
rec := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, filepath.Join(PublicFederationPathPrefix, "doesnotexist"), nil)
r.Federation.ServeHTTP(rec, req)
if rec.Code != http.StatusNotFound {
t.Fatalf("unexpected status code: %d - %s", rec.Code, rec.Body.String())
}
if ct := rec.Header().Get("Content-Type"); ct != "application/json" {
t.Fatalf("unexpected content-type: %s", ct)
}
// not allowed test
r.DendriteAdmin.
Handle("/test", http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {})).
Methods(http.MethodPost)
rec = httptest.NewRecorder()
req = httptest.NewRequest(http.MethodGet, filepath.Join(DendriteAdminPathPrefix, "test"), nil)
r.DendriteAdmin.ServeHTTP(rec, req)
if rec.Code != http.StatusMethodNotAllowed {
t.Fatalf("unexpected status code: %d - %s", rec.Code, rec.Body.String())
}
if ct := rec.Header().Get("Content-Type"); ct != "application/json" {
t.Fatalf("unexpected content-type: %s", ct)
}
}

View file

@ -0,0 +1,75 @@
// 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 sqlutil
import (
"database/sql"
"fmt"
"github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/dendrite/setup/process"
)
type Connections struct {
db *sql.DB
writer Writer
globalConfig config.DatabaseOptions
processContext *process.ProcessContext
}
func NewConnectionManager(processCtx *process.ProcessContext, globalConfig config.DatabaseOptions) Connections {
return Connections{
globalConfig: globalConfig,
processContext: processCtx,
}
}
func (c *Connections) Connection(dbProperties *config.DatabaseOptions) (*sql.DB, Writer, error) {
writer := NewDummyWriter()
if dbProperties.ConnectionString.IsSQLite() {
writer = NewExclusiveWriter()
}
var err error
if dbProperties.ConnectionString == "" {
// if no connectionString was provided, try the global one
dbProperties = &c.globalConfig
}
if dbProperties.ConnectionString != "" || c.db == nil {
// Open a new database connection using the supplied config.
c.db, err = Open(dbProperties, writer)
if err != nil {
return nil, nil, err
}
c.writer = writer
go func() {
if c.processContext == nil {
return
}
// If we have a ProcessContext, start a component and wait for
// Dendrite to shut down to cleanly close the database connection.
c.processContext.ComponentStarted()
<-c.processContext.WaitForShutdown()
_ = c.db.Close()
c.processContext.ComponentFinished()
}()
return c.db, c.writer, nil
}
if c.db != nil && c.writer != nil {
// Ignore the supplied config and return the global pool and
// writer.
return c.db, c.writer, nil
}
return nil, nil, fmt.Errorf("no database connections configured")
}

View file

@ -0,0 +1,56 @@
package sqlutil_test
import (
"reflect"
"testing"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/dendrite/test"
)
func TestConnectionManager(t *testing.T) {
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
conStr, close := test.PrepareDBConnectionString(t, dbType)
t.Cleanup(close)
cm := sqlutil.NewConnectionManager(nil, config.DatabaseOptions{})
dbProps := &config.DatabaseOptions{ConnectionString: config.DataSource(conStr)}
db, writer, err := cm.Connection(dbProps)
if err != nil {
t.Fatal(err)
}
switch dbType {
case test.DBTypeSQLite:
_, ok := writer.(*sqlutil.ExclusiveWriter)
if !ok {
t.Fatalf("expected exclusive writer")
}
case test.DBTypePostgres:
_, ok := writer.(*sqlutil.DummyWriter)
if !ok {
t.Fatalf("expected dummy writer")
}
}
// test global db pool
dbGlobal, writerGlobal, err := cm.Connection(&config.DatabaseOptions{})
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(db, dbGlobal) {
t.Fatalf("expected database connection to be reused")
}
if !reflect.DeepEqual(writer, writerGlobal) {
t.Fatalf("expected database writer to be reused")
}
// test invalid connection string configured
cm2 := sqlutil.NewConnectionManager(nil, config.DatabaseOptions{})
_, _, err = cm2.Connection(&config.DatabaseOptions{ConnectionString: "http://"})
if err == nil {
t.Fatal("expected an error but got none")
}
})
}

View file

@ -22,6 +22,12 @@ import (
"testing" "testing"
"time" "time"
"github.com/matrix-org/gomatrixserverlib"
"github.com/nats-io/nats.go"
"github.com/stretchr/testify/assert"
"go.uber.org/atomic"
"gotest.tools/v3/poll"
"github.com/matrix-org/dendrite/federationapi/producers" "github.com/matrix-org/dendrite/federationapi/producers"
rsAPI "github.com/matrix-org/dendrite/roomserver/api" rsAPI "github.com/matrix-org/dendrite/roomserver/api"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
@ -30,11 +36,6 @@ import (
"github.com/matrix-org/dendrite/syncapi/types" "github.com/matrix-org/dendrite/syncapi/types"
"github.com/matrix-org/dendrite/test" "github.com/matrix-org/dendrite/test"
keyAPI "github.com/matrix-org/dendrite/userapi/api" keyAPI "github.com/matrix-org/dendrite/userapi/api"
"github.com/matrix-org/gomatrixserverlib"
"github.com/nats-io/nats.go"
"github.com/stretchr/testify/assert"
"go.uber.org/atomic"
"gotest.tools/v3/poll"
) )
const ( const (
@ -427,7 +428,7 @@ func TestProcessTransactionRequestEDUReceipt(t *testing.T) {
roomID: map[string]interface{}{ roomID: map[string]interface{}{
"m.read": map[string]interface{}{ "m.read": map[string]interface{}{
"@john:kaer.morhen": map[string]interface{}{ "@john:kaer.morhen": map[string]interface{}{
"data": map[string]interface{}{ "data": map[string]int64{
"ts": 1533358089009, "ts": 1533358089009,
}, },
"event_ids": []string{ "event_ids": []string{
@ -446,7 +447,7 @@ func TestProcessTransactionRequestEDUReceipt(t *testing.T) {
roomID: map[string]interface{}{ roomID: map[string]interface{}{
"m.read": map[string]interface{}{ "m.read": map[string]interface{}{
"johnkaer.morhen": map[string]interface{}{ "johnkaer.morhen": map[string]interface{}{
"data": map[string]interface{}{ "data": map[string]int64{
"ts": 1533358089009, "ts": 1533358089009,
}, },
"event_ids": []string{ "event_ids": []string{
@ -463,7 +464,7 @@ func TestProcessTransactionRequestEDUReceipt(t *testing.T) {
roomID: map[string]interface{}{ roomID: map[string]interface{}{
"m.read": map[string]interface{}{ "m.read": map[string]interface{}{
"@john:bad.domain": map[string]interface{}{ "@john:bad.domain": map[string]interface{}{
"data": map[string]interface{}{ "data": map[string]int64{
"ts": 1533358089009, "ts": 1533358089009,
}, },
"event_ids": []string{ "event_ids": []string{

View file

@ -15,9 +15,11 @@
package mediaapi package mediaapi
import ( import (
"github.com/gorilla/mux"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/mediaapi/routing" "github.com/matrix-org/dendrite/mediaapi/routing"
"github.com/matrix-org/dendrite/mediaapi/storage" "github.com/matrix-org/dendrite/mediaapi/storage"
"github.com/matrix-org/dendrite/setup/base" "github.com/matrix-org/dendrite/setup/config"
userapi "github.com/matrix-org/dendrite/userapi/api" userapi "github.com/matrix-org/dendrite/userapi/api"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
@ -25,19 +27,18 @@ import (
// AddPublicRoutes sets up and registers HTTP handlers for the MediaAPI component. // AddPublicRoutes sets up and registers HTTP handlers for the MediaAPI component.
func AddPublicRoutes( func AddPublicRoutes(
base *base.BaseDendrite, mediaRouter *mux.Router,
cm sqlutil.Connections,
cfg *config.Dendrite,
userAPI userapi.MediaUserAPI, userAPI userapi.MediaUserAPI,
client *gomatrixserverlib.Client, client *gomatrixserverlib.Client,
) { ) {
cfg := &base.Cfg.MediaAPI mediaDB, err := storage.NewMediaAPIDatasource(cm, &cfg.MediaAPI.Database)
rateCfg := &base.Cfg.ClientAPI.RateLimiting
mediaDB, err := storage.NewMediaAPIDatasource(base, &cfg.Database)
if err != nil { if err != nil {
logrus.WithError(err).Panicf("failed to connect to media db") logrus.WithError(err).Panicf("failed to connect to media db")
} }
routing.Setup( routing.Setup(
base.PublicMediaAPIMux, cfg, rateCfg, mediaDB, userAPI, client, mediaRouter, cfg, mediaDB, userAPI, client,
) )
} }

View file

@ -35,7 +35,7 @@ import (
// configResponse is the response to GET /_matrix/media/r0/config // configResponse is the response to GET /_matrix/media/r0/config
// https://matrix.org/docs/spec/client_server/latest#get-matrix-media-r0-config // https://matrix.org/docs/spec/client_server/latest#get-matrix-media-r0-config
type configResponse struct { type configResponse struct {
UploadSize *config.FileSizeBytes `json:"m.upload.size"` UploadSize *config.FileSizeBytes `json:"m.upload.size,omitempty"`
} }
// Setup registers the media API HTTP handlers // Setup registers the media API HTTP handlers
@ -45,13 +45,12 @@ type configResponse struct {
// nolint: gocyclo // nolint: gocyclo
func Setup( func Setup(
publicAPIMux *mux.Router, publicAPIMux *mux.Router,
cfg *config.MediaAPI, cfg *config.Dendrite,
rateLimit *config.RateLimiting,
db storage.Database, db storage.Database,
userAPI userapi.MediaUserAPI, userAPI userapi.MediaUserAPI,
client *gomatrixserverlib.Client, client *gomatrixserverlib.Client,
) { ) {
rateLimits := httputil.NewRateLimits(rateLimit) rateLimits := httputil.NewRateLimits(&cfg.ClientAPI.RateLimiting)
v3mux := publicAPIMux.PathPrefix("/{apiversion:(?:r0|v1|v3)}/").Subrouter() v3mux := publicAPIMux.PathPrefix("/{apiversion:(?:r0|v1|v3)}/").Subrouter()
@ -65,7 +64,7 @@ func Setup(
if r := rateLimits.Limit(req, dev); r != nil { if r := rateLimits.Limit(req, dev); r != nil {
return *r return *r
} }
return Upload(req, cfg, dev, db, activeThumbnailGeneration) return Upload(req, &cfg.MediaAPI, dev, db, activeThumbnailGeneration)
}, },
) )
@ -73,8 +72,8 @@ func Setup(
if r := rateLimits.Limit(req, device); r != nil { if r := rateLimits.Limit(req, device); r != nil {
return *r return *r
} }
respondSize := &cfg.MaxFileSizeBytes respondSize := &cfg.MediaAPI.MaxFileSizeBytes
if cfg.MaxFileSizeBytes == 0 { if cfg.MediaAPI.MaxFileSizeBytes == 0 {
respondSize = nil respondSize = nil
} }
return util.JSONResponse{ return util.JSONResponse{
@ -90,12 +89,12 @@ func Setup(
MXCToResult: map[string]*types.RemoteRequestResult{}, MXCToResult: map[string]*types.RemoteRequestResult{},
} }
downloadHandler := makeDownloadAPI("download", cfg, rateLimits, db, client, activeRemoteRequests, activeThumbnailGeneration) downloadHandler := makeDownloadAPI("download", &cfg.MediaAPI, rateLimits, db, client, activeRemoteRequests, activeThumbnailGeneration)
v3mux.Handle("/download/{serverName}/{mediaId}", downloadHandler).Methods(http.MethodGet, http.MethodOptions) v3mux.Handle("/download/{serverName}/{mediaId}", downloadHandler).Methods(http.MethodGet, http.MethodOptions)
v3mux.Handle("/download/{serverName}/{mediaId}/{downloadName}", downloadHandler).Methods(http.MethodGet, http.MethodOptions) v3mux.Handle("/download/{serverName}/{mediaId}/{downloadName}", downloadHandler).Methods(http.MethodGet, http.MethodOptions)
v3mux.Handle("/thumbnail/{serverName}/{mediaId}", v3mux.Handle("/thumbnail/{serverName}/{mediaId}",
makeDownloadAPI("thumbnail", cfg, rateLimits, db, client, activeRemoteRequests, activeThumbnailGeneration), makeDownloadAPI("thumbnail", &cfg.MediaAPI, rateLimits, db, client, activeRemoteRequests, activeThumbnailGeneration),
).Methods(http.MethodGet, http.MethodOptions) ).Methods(http.MethodGet, http.MethodOptions)
} }

View file

@ -9,6 +9,7 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/mediaapi/fileutils" "github.com/matrix-org/dendrite/mediaapi/fileutils"
"github.com/matrix-org/dendrite/mediaapi/storage" "github.com/matrix-org/dendrite/mediaapi/storage"
"github.com/matrix-org/dendrite/mediaapi/types" "github.com/matrix-org/dendrite/mediaapi/types"
@ -49,8 +50,8 @@ func Test_uploadRequest_doUpload(t *testing.T) {
// create testdata folder and remove when done // create testdata folder and remove when done
_ = os.Mkdir(testdataPath, os.ModePerm) _ = os.Mkdir(testdataPath, os.ModePerm)
defer fileutils.RemoveDir(types.Path(testdataPath), nil) defer fileutils.RemoveDir(types.Path(testdataPath), nil)
cm := sqlutil.NewConnectionManager(nil, config.DatabaseOptions{})
db, err := storage.NewMediaAPIDatasource(nil, &config.DatabaseOptions{ db, err := storage.NewMediaAPIDatasource(cm, &config.DatabaseOptions{
ConnectionString: "file::memory:?cache=shared", ConnectionString: "file::memory:?cache=shared",
MaxOpenConnections: 100, MaxOpenConnections: 100,
MaxIdleConnections: 2, MaxIdleConnections: 2,

View file

@ -20,13 +20,12 @@ import (
_ "github.com/lib/pq" _ "github.com/lib/pq"
"github.com/matrix-org/dendrite/internal/sqlutil" "github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/mediaapi/storage/shared" "github.com/matrix-org/dendrite/mediaapi/storage/shared"
"github.com/matrix-org/dendrite/setup/base"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
) )
// NewDatabase opens a postgres database. // NewDatabase opens a postgres database.
func NewDatabase(base *base.BaseDendrite, dbProperties *config.DatabaseOptions) (*shared.Database, error) { func NewDatabase(conMan sqlutil.Connections, dbProperties *config.DatabaseOptions) (*shared.Database, error) {
db, writer, err := base.DatabaseConnection(dbProperties, sqlutil.NewDummyWriter()) db, writer, err := conMan.Connection(dbProperties)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -19,13 +19,12 @@ import (
// Import the postgres database driver. // Import the postgres database driver.
"github.com/matrix-org/dendrite/internal/sqlutil" "github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/mediaapi/storage/shared" "github.com/matrix-org/dendrite/mediaapi/storage/shared"
"github.com/matrix-org/dendrite/setup/base"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
) )
// NewDatabase opens a SQLIte database. // NewDatabase opens a SQLIte database.
func NewDatabase(base *base.BaseDendrite, dbProperties *config.DatabaseOptions) (*shared.Database, error) { func NewDatabase(conMan sqlutil.Connections, dbProperties *config.DatabaseOptions) (*shared.Database, error) {
db, writer, err := base.DatabaseConnection(dbProperties, sqlutil.NewExclusiveWriter()) db, writer, err := conMan.Connection(dbProperties)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -20,19 +20,19 @@ package storage
import ( import (
"fmt" "fmt"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/mediaapi/storage/postgres" "github.com/matrix-org/dendrite/mediaapi/storage/postgres"
"github.com/matrix-org/dendrite/mediaapi/storage/sqlite3" "github.com/matrix-org/dendrite/mediaapi/storage/sqlite3"
"github.com/matrix-org/dendrite/setup/base"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
) )
// NewMediaAPIDatasource opens a database connection. // NewMediaAPIDatasource opens a database connection.
func NewMediaAPIDatasource(base *base.BaseDendrite, dbProperties *config.DatabaseOptions) (Database, error) { func NewMediaAPIDatasource(conMan sqlutil.Connections, dbProperties *config.DatabaseOptions) (Database, error) {
switch { switch {
case dbProperties.ConnectionString.IsSQLite(): case dbProperties.ConnectionString.IsSQLite():
return sqlite3.NewDatabase(base, dbProperties) return sqlite3.NewDatabase(conMan, dbProperties)
case dbProperties.ConnectionString.IsPostgres(): case dbProperties.ConnectionString.IsPostgres():
return postgres.NewDatabase(base, dbProperties) return postgres.NewDatabase(conMan, dbProperties)
default: default:
return nil, fmt.Errorf("unexpected database type") return nil, fmt.Errorf("unexpected database type")
} }

View file

@ -5,6 +5,7 @@ import (
"reflect" "reflect"
"testing" "testing"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/mediaapi/storage" "github.com/matrix-org/dendrite/mediaapi/storage"
"github.com/matrix-org/dendrite/mediaapi/types" "github.com/matrix-org/dendrite/mediaapi/types"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
@ -13,7 +14,8 @@ import (
func mustCreateDatabase(t *testing.T, dbType test.DBType) (storage.Database, func()) { func mustCreateDatabase(t *testing.T, dbType test.DBType) (storage.Database, func()) {
connStr, close := test.PrepareDBConnectionString(t, dbType) connStr, close := test.PrepareDBConnectionString(t, dbType)
db, err := storage.NewMediaAPIDatasource(nil, &config.DatabaseOptions{ cm := sqlutil.NewConnectionManager(nil, config.DatabaseOptions{})
db, err := storage.NewMediaAPIDatasource(cm, &config.DatabaseOptions{
ConnectionString: config.DataSource(connStr), ConnectionString: config.DataSource(connStr),
}) })
if err != nil { if err != nil {

View file

@ -17,16 +17,16 @@ package storage
import ( import (
"fmt" "fmt"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/mediaapi/storage/sqlite3" "github.com/matrix-org/dendrite/mediaapi/storage/sqlite3"
"github.com/matrix-org/dendrite/setup/base"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
) )
// Open opens a postgres database. // Open opens a postgres database.
func NewMediaAPIDatasource(base *base.BaseDendrite, dbProperties *config.DatabaseOptions) (Database, error) { func NewMediaAPIDatasource(conMan sqlutil.Connections, dbProperties *config.DatabaseOptions) (Database, error) {
switch { switch {
case dbProperties.ConnectionString.IsSQLite(): case dbProperties.ConnectionString.IsSQLite():
return sqlite3.NewDatabase(base, dbProperties) return sqlite3.NewDatabase(conMan, dbProperties)
case dbProperties.ConnectionString.IsPostgres(): case dbProperties.ConnectionString.IsPostgres():
return nil, fmt.Errorf("can't use Postgres implementation") return nil, fmt.Errorf("can't use Postgres implementation")
default: default:

View file

@ -16,24 +16,26 @@ package relayapi
import ( import (
"github.com/matrix-org/dendrite/federationapi/producers" "github.com/matrix-org/dendrite/federationapi/producers"
"github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/httputil"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/relayapi/api" "github.com/matrix-org/dendrite/relayapi/api"
"github.com/matrix-org/dendrite/relayapi/internal" "github.com/matrix-org/dendrite/relayapi/internal"
"github.com/matrix-org/dendrite/relayapi/routing" "github.com/matrix-org/dendrite/relayapi/routing"
"github.com/matrix-org/dendrite/relayapi/storage" "github.com/matrix-org/dendrite/relayapi/storage"
rsAPI "github.com/matrix-org/dendrite/roomserver/api" rsAPI "github.com/matrix-org/dendrite/roomserver/api"
"github.com/matrix-org/dendrite/setup/base" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
// AddPublicRoutes sets up and registers HTTP handlers on the base API muxes for the FederationAPI component. // AddPublicRoutes sets up and registers HTTP handlers on the base API muxes for the FederationAPI component.
func AddPublicRoutes( func AddPublicRoutes(
base *base.BaseDendrite, routers httputil.Routers,
dendriteCfg *config.Dendrite,
keyRing gomatrixserverlib.JSONVerifier, keyRing gomatrixserverlib.JSONVerifier,
relayAPI api.RelayInternalAPI, relayAPI api.RelayInternalAPI,
) { ) {
fedCfg := &base.Cfg.FederationAPI
relay, ok := relayAPI.(*internal.RelayInternalAPI) relay, ok := relayAPI.(*internal.RelayInternalAPI)
if !ok { if !ok {
panic("relayapi.AddPublicRoutes called with a RelayInternalAPI impl which was not " + panic("relayapi.AddPublicRoutes called with a RelayInternalAPI impl which was not " +
@ -41,24 +43,24 @@ func AddPublicRoutes(
} }
routing.Setup( routing.Setup(
base.PublicFederationAPIMux, routers.Federation,
fedCfg, &dendriteCfg.FederationAPI,
relay, relay,
keyRing, keyRing,
) )
} }
func NewRelayInternalAPI( func NewRelayInternalAPI(
base *base.BaseDendrite, dendriteCfg *config.Dendrite,
cm sqlutil.Connections,
fedClient *gomatrixserverlib.FederationClient, fedClient *gomatrixserverlib.FederationClient,
rsAPI rsAPI.RoomserverInternalAPI, rsAPI rsAPI.RoomserverInternalAPI,
keyRing *gomatrixserverlib.KeyRing, keyRing *gomatrixserverlib.KeyRing,
producer *producers.SyncAPIProducer, producer *producers.SyncAPIProducer,
relayingEnabled bool, relayingEnabled bool,
caches caching.FederationCache,
) api.RelayInternalAPI { ) api.RelayInternalAPI {
cfg := &base.Cfg.RelayAPI relayDB, err := storage.NewDatabase(cm, &dendriteCfg.RelayAPI.Database, caches, dendriteCfg.Global.IsLocalServerName)
relayDB, err := storage.NewDatabase(base, &cfg.Database, base.Caches, base.Cfg.Global.IsLocalServerName)
if err != nil { if err != nil {
logrus.WithError(err).Panic("failed to connect to relay db") logrus.WithError(err).Panic("failed to connect to relay db")
} }
@ -69,8 +71,8 @@ func NewRelayInternalAPI(
rsAPI, rsAPI,
keyRing, keyRing,
producer, producer,
base.Cfg.Global.Presence.EnableInbound, dendriteCfg.Global.Presence.EnableInbound,
base.Cfg.Global.ServerName, dendriteCfg.Global.ServerName,
relayingEnabled, relayingEnabled,
) )
} }

View file

@ -21,9 +21,13 @@ import (
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"testing" "testing"
"time"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/signing" "github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/signing"
"github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/httputil"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/relayapi" "github.com/matrix-org/dendrite/relayapi"
"github.com/matrix-org/dendrite/test" "github.com/matrix-org/dendrite/test"
"github.com/matrix-org/dendrite/test/testrig" "github.com/matrix-org/dendrite/test/testrig"
@ -33,37 +37,38 @@ import (
func TestCreateNewRelayInternalAPI(t *testing.T) { func TestCreateNewRelayInternalAPI(t *testing.T) {
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
base, close := testrig.CreateBaseDendrite(t, dbType) cfg, processCtx, close := testrig.CreateConfig(t, dbType)
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
defer close() defer close()
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
relayAPI := relayapi.NewRelayInternalAPI(base, nil, nil, nil, nil, true) relayAPI := relayapi.NewRelayInternalAPI(cfg, cm, nil, nil, nil, nil, true, caches)
assert.NotNil(t, relayAPI) assert.NotNil(t, relayAPI)
}) })
} }
func TestCreateRelayInternalInvalidDatabasePanics(t *testing.T) { func TestCreateRelayInternalInvalidDatabasePanics(t *testing.T) {
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
base, close := testrig.CreateBaseDendrite(t, dbType) cfg, processCtx, close := testrig.CreateConfig(t, dbType)
if dbType == test.DBTypeSQLite { if dbType == test.DBTypeSQLite {
base.Cfg.RelayAPI.Database.ConnectionString = "file:" cfg.RelayAPI.Database.ConnectionString = "file:"
} else { } else {
base.Cfg.RelayAPI.Database.ConnectionString = "test" cfg.RelayAPI.Database.ConnectionString = "test"
} }
defer close() defer close()
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
assert.Panics(t, func() { assert.Panics(t, func() {
relayapi.NewRelayInternalAPI(base, nil, nil, nil, nil, true) relayapi.NewRelayInternalAPI(cfg, cm, nil, nil, nil, nil, true, nil)
}) })
}) })
} }
func TestCreateInvalidRelayPublicRoutesPanics(t *testing.T) { func TestCreateInvalidRelayPublicRoutesPanics(t *testing.T) {
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
base, close := testrig.CreateBaseDendrite(t, dbType) cfg, _, close := testrig.CreateConfig(t, dbType)
defer close() defer close()
routers := httputil.NewRouters()
assert.Panics(t, func() { assert.Panics(t, func() {
relayapi.AddPublicRoutes(base, nil, nil) relayapi.AddPublicRoutes(routers, cfg, nil, nil)
}) })
}) })
} }
@ -105,15 +110,19 @@ func createSendRelayTxnHTTPRequest(serverName gomatrixserverlib.ServerName, txnI
func TestCreateRelayPublicRoutes(t *testing.T) { func TestCreateRelayPublicRoutes(t *testing.T) {
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
base, close := testrig.CreateBaseDendrite(t, dbType) cfg, processCtx, close := testrig.CreateConfig(t, dbType)
defer close() defer close()
routers := httputil.NewRouters()
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
relayAPI := relayapi.NewRelayInternalAPI(base, nil, nil, nil, nil, true) cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
relayAPI := relayapi.NewRelayInternalAPI(cfg, cm, nil, nil, nil, nil, true, caches)
assert.NotNil(t, relayAPI) assert.NotNil(t, relayAPI)
serverKeyAPI := &signing.YggdrasilKeys{} serverKeyAPI := &signing.YggdrasilKeys{}
keyRing := serverKeyAPI.KeyRing() keyRing := serverKeyAPI.KeyRing()
relayapi.AddPublicRoutes(base, keyRing, relayAPI) relayapi.AddPublicRoutes(routers, cfg, keyRing, relayAPI)
testCases := []struct { testCases := []struct {
name string name string
@ -122,29 +131,29 @@ func TestCreateRelayPublicRoutes(t *testing.T) {
}{ }{
{ {
name: "relay_txn invalid user id", name: "relay_txn invalid user id",
req: createGetRelayTxnHTTPRequest(base.Cfg.Global.ServerName, "user:local"), req: createGetRelayTxnHTTPRequest(cfg.Global.ServerName, "user:local"),
wantCode: 400, wantCode: 400,
}, },
{ {
name: "relay_txn valid user id", name: "relay_txn valid user id",
req: createGetRelayTxnHTTPRequest(base.Cfg.Global.ServerName, "@user:local"), req: createGetRelayTxnHTTPRequest(cfg.Global.ServerName, "@user:local"),
wantCode: 200, wantCode: 200,
}, },
{ {
name: "send_relay invalid user id", name: "send_relay invalid user id",
req: createSendRelayTxnHTTPRequest(base.Cfg.Global.ServerName, "123", "user:local"), req: createSendRelayTxnHTTPRequest(cfg.Global.ServerName, "123", "user:local"),
wantCode: 400, wantCode: 400,
}, },
{ {
name: "send_relay valid user id", name: "send_relay valid user id",
req: createSendRelayTxnHTTPRequest(base.Cfg.Global.ServerName, "123", "@user:local"), req: createSendRelayTxnHTTPRequest(cfg.Global.ServerName, "123", "@user:local"),
wantCode: 200, wantCode: 200,
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
w := httptest.NewRecorder() w := httptest.NewRecorder()
base.PublicFederationAPIMux.ServeHTTP(w, tc.req) routers.Federation.ServeHTTP(w, tc.req)
if w.Code != tc.wantCode { if w.Code != tc.wantCode {
t.Fatalf("%s: got HTTP %d want %d", tc.name, w.Code, tc.wantCode) t.Fatalf("%s: got HTTP %d want %d", tc.name, w.Code, tc.wantCode)
} }
@ -154,15 +163,19 @@ func TestCreateRelayPublicRoutes(t *testing.T) {
func TestDisableRelayPublicRoutes(t *testing.T) { func TestDisableRelayPublicRoutes(t *testing.T) {
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
base, close := testrig.CreateBaseDendrite(t, dbType) cfg, processCtx, close := testrig.CreateConfig(t, dbType)
defer close() defer close()
routers := httputil.NewRouters()
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
relayAPI := relayapi.NewRelayInternalAPI(base, nil, nil, nil, nil, false) cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
relayAPI := relayapi.NewRelayInternalAPI(cfg, cm, nil, nil, nil, nil, false, caches)
assert.NotNil(t, relayAPI) assert.NotNil(t, relayAPI)
serverKeyAPI := &signing.YggdrasilKeys{} serverKeyAPI := &signing.YggdrasilKeys{}
keyRing := serverKeyAPI.KeyRing() keyRing := serverKeyAPI.KeyRing()
relayapi.AddPublicRoutes(base, keyRing, relayAPI) relayapi.AddPublicRoutes(routers, cfg, keyRing, relayAPI)
testCases := []struct { testCases := []struct {
name string name string
@ -171,19 +184,19 @@ func TestDisableRelayPublicRoutes(t *testing.T) {
}{ }{
{ {
name: "relay_txn valid user id", name: "relay_txn valid user id",
req: createGetRelayTxnHTTPRequest(base.Cfg.Global.ServerName, "@user:local"), req: createGetRelayTxnHTTPRequest(cfg.Global.ServerName, "@user:local"),
wantCode: 404, wantCode: 404,
}, },
{ {
name: "send_relay valid user id", name: "send_relay valid user id",
req: createSendRelayTxnHTTPRequest(base.Cfg.Global.ServerName, "123", "@user:local"), req: createSendRelayTxnHTTPRequest(cfg.Global.ServerName, "123", "@user:local"),
wantCode: 404, wantCode: 404,
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
w := httptest.NewRecorder() w := httptest.NewRecorder()
base.PublicFederationAPIMux.ServeHTTP(w, tc.req) routers.Federation.ServeHTTP(w, tc.req)
if w.Code != tc.wantCode { if w.Code != tc.wantCode {
t.Fatalf("%s: got HTTP %d want %d", tc.name, w.Code, tc.wantCode) t.Fatalf("%s: got HTTP %d want %d", tc.name, w.Code, tc.wantCode)
} }

View file

@ -20,7 +20,6 @@ import (
"github.com/matrix-org/dendrite/internal/caching" "github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/sqlutil" "github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/relayapi/storage/shared" "github.com/matrix-org/dendrite/relayapi/storage/shared"
"github.com/matrix-org/dendrite/setup/base"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
) )
@ -34,14 +33,14 @@ type Database struct {
// NewDatabase opens a new database // NewDatabase opens a new database
func NewDatabase( func NewDatabase(
base *base.BaseDendrite, conMan sqlutil.Connections,
dbProperties *config.DatabaseOptions, dbProperties *config.DatabaseOptions,
cache caching.FederationCache, cache caching.FederationCache,
isLocalServerName func(gomatrixserverlib.ServerName) bool, isLocalServerName func(gomatrixserverlib.ServerName) bool,
) (*Database, error) { ) (*Database, error) {
var d Database var d Database
var err error var err error
if d.db, d.writer, err = base.DatabaseConnection(dbProperties, sqlutil.NewDummyWriter()); err != nil { if d.db, d.writer, err = conMan.Connection(dbProperties); err != nil {
return nil, err return nil, err
} }
queue, err := NewPostgresRelayQueueTable(d.db) queue, err := NewPostgresRelayQueueTable(d.db)

View file

@ -20,7 +20,6 @@ import (
"github.com/matrix-org/dendrite/internal/caching" "github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/sqlutil" "github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/relayapi/storage/shared" "github.com/matrix-org/dendrite/relayapi/storage/shared"
"github.com/matrix-org/dendrite/setup/base"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
) )
@ -34,14 +33,14 @@ type Database struct {
// NewDatabase opens a new database // NewDatabase opens a new database
func NewDatabase( func NewDatabase(
base *base.BaseDendrite, conMan sqlutil.Connections,
dbProperties *config.DatabaseOptions, dbProperties *config.DatabaseOptions,
cache caching.FederationCache, cache caching.FederationCache,
isLocalServerName func(gomatrixserverlib.ServerName) bool, isLocalServerName func(gomatrixserverlib.ServerName) bool,
) (*Database, error) { ) (*Database, error) {
var d Database var d Database
var err error var err error
if d.db, d.writer, err = base.DatabaseConnection(dbProperties, sqlutil.NewExclusiveWriter()); err != nil { if d.db, d.writer, err = conMan.Connection(dbProperties); err != nil {
return nil, err return nil, err
} }
queue, err := NewSQLiteRelayQueueTable(d.db) queue, err := NewSQLiteRelayQueueTable(d.db)

View file

@ -21,25 +21,25 @@ import (
"fmt" "fmt"
"github.com/matrix-org/dendrite/internal/caching" "github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/relayapi/storage/postgres" "github.com/matrix-org/dendrite/relayapi/storage/postgres"
"github.com/matrix-org/dendrite/relayapi/storage/sqlite3" "github.com/matrix-org/dendrite/relayapi/storage/sqlite3"
"github.com/matrix-org/dendrite/setup/base"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
) )
// NewDatabase opens a new database // NewDatabase opens a new database
func NewDatabase( func NewDatabase(
base *base.BaseDendrite, conMan sqlutil.Connections,
dbProperties *config.DatabaseOptions, dbProperties *config.DatabaseOptions,
cache caching.FederationCache, cache caching.FederationCache,
isLocalServerName func(gomatrixserverlib.ServerName) bool, isLocalServerName func(gomatrixserverlib.ServerName) bool,
) (Database, error) { ) (Database, error) {
switch { switch {
case dbProperties.ConnectionString.IsSQLite(): case dbProperties.ConnectionString.IsSQLite():
return sqlite3.NewDatabase(base, dbProperties, cache, isLocalServerName) return sqlite3.NewDatabase(conMan, dbProperties, cache, isLocalServerName)
case dbProperties.ConnectionString.IsPostgres(): case dbProperties.ConnectionString.IsPostgres():
return postgres.NewDatabase(base, dbProperties, cache, isLocalServerName) return postgres.NewDatabase(conMan, dbProperties, cache, isLocalServerName)
default: default:
return nil, fmt.Errorf("unexpected database type") return nil, fmt.Errorf("unexpected database type")
} }

View file

@ -0,0 +1,42 @@
// 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 storage
import (
"fmt"
"github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/relayapi/storage/sqlite3"
"github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/gomatrixserverlib"
)
// NewDatabase opens a new database
func NewDatabase(
conMan sqlutil.Connections,
dbProperties *config.DatabaseOptions,
cache caching.FederationCache,
isLocalServerName func(gomatrixserverlib.ServerName) bool,
) (Database, error) {
switch {
case dbProperties.ConnectionString.IsSQLite():
return sqlite3.NewDatabase(conMan, dbProperties, cache, isLocalServerName)
case dbProperties.ConnectionString.IsPostgres():
return nil, fmt.Errorf("can't use Postgres implementation")
default:
return nil, fmt.Errorf("unexpected database type")
}
}

View file

@ -117,7 +117,7 @@ func (r *RoomserverInternalAPI) RemoveRoomAlias(
request *api.RemoveRoomAliasRequest, request *api.RemoveRoomAliasRequest,
response *api.RemoveRoomAliasResponse, response *api.RemoveRoomAliasResponse,
) error { ) error {
_, virtualHost, err := r.Cfg.Matrix.SplitLocalID('@', request.UserID) _, virtualHost, err := r.Cfg.Global.SplitLocalID('@', request.UserID)
if err != nil { if err != nil {
return err return err
} }
@ -175,12 +175,12 @@ func (r *RoomserverInternalAPI) RemoveRoomAlias(
sender = ev.Sender() sender = ev.Sender()
} }
_, senderDomain, err := r.Cfg.Matrix.SplitLocalID('@', sender) _, senderDomain, err := r.Cfg.Global.SplitLocalID('@', sender)
if err != nil { if err != nil {
return err return err
} }
identity, err := r.Cfg.Matrix.SigningIdentityFor(senderDomain) identity, err := r.Cfg.Global.SigningIdentityFor(senderDomain)
if err != nil { if err != nil {
return err return err
} }
@ -206,7 +206,7 @@ func (r *RoomserverInternalAPI) RemoveRoomAlias(
return err return err
} }
newEvent, err := eventutil.BuildEvent(ctx, builder, r.Cfg.Matrix, identity, time.Now(), &eventsNeeded, stateRes) newEvent, err := eventutil.BuildEvent(ctx, builder, &r.Cfg.Global, identity, time.Now(), &eventsNeeded, stateRes)
if err != nil { if err != nil {
return err return err
} }

View file

@ -18,7 +18,6 @@ import (
"github.com/matrix-org/dendrite/roomserver/internal/query" "github.com/matrix-org/dendrite/roomserver/internal/query"
"github.com/matrix-org/dendrite/roomserver/producers" "github.com/matrix-org/dendrite/roomserver/producers"
"github.com/matrix-org/dendrite/roomserver/storage" "github.com/matrix-org/dendrite/roomserver/storage"
"github.com/matrix-org/dendrite/setup/base"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/dendrite/setup/jetstream" "github.com/matrix-org/dendrite/setup/jetstream"
"github.com/matrix-org/dendrite/setup/process" "github.com/matrix-org/dendrite/setup/process"
@ -41,9 +40,8 @@ type RoomserverInternalAPI struct {
*perform.Upgrader *perform.Upgrader
*perform.Admin *perform.Admin
ProcessContext *process.ProcessContext ProcessContext *process.ProcessContext
Base *base.BaseDendrite
DB storage.Database DB storage.Database
Cfg *config.RoomServer Cfg *config.Dendrite
Cache caching.RoomServerCaches Cache caching.RoomServerCaches
ServerName gomatrixserverlib.ServerName ServerName gomatrixserverlib.ServerName
KeyRing gomatrixserverlib.JSONVerifier KeyRing gomatrixserverlib.JSONVerifier
@ -56,43 +54,44 @@ type RoomserverInternalAPI struct {
InputRoomEventTopic string // JetStream topic for new input room events InputRoomEventTopic string // JetStream topic for new input room events
OutputProducer *producers.RoomEventProducer OutputProducer *producers.RoomEventProducer
PerspectiveServerNames []gomatrixserverlib.ServerName PerspectiveServerNames []gomatrixserverlib.ServerName
enableMetrics bool
} }
func NewRoomserverAPI( func NewRoomserverAPI(
base *base.BaseDendrite, roomserverDB storage.Database, processContext *process.ProcessContext, dendriteCfg *config.Dendrite, roomserverDB storage.Database,
js nats.JetStreamContext, nc *nats.Conn, js nats.JetStreamContext, nc *nats.Conn, caches caching.RoomServerCaches, enableMetrics bool,
) *RoomserverInternalAPI { ) *RoomserverInternalAPI {
var perspectiveServerNames []gomatrixserverlib.ServerName var perspectiveServerNames []gomatrixserverlib.ServerName
for _, kp := range base.Cfg.FederationAPI.KeyPerspectives { for _, kp := range dendriteCfg.FederationAPI.KeyPerspectives {
perspectiveServerNames = append(perspectiveServerNames, kp.ServerName) perspectiveServerNames = append(perspectiveServerNames, kp.ServerName)
} }
serverACLs := acls.NewServerACLs(roomserverDB) serverACLs := acls.NewServerACLs(roomserverDB)
producer := &producers.RoomEventProducer{ producer := &producers.RoomEventProducer{
Topic: string(base.Cfg.Global.JetStream.Prefixed(jetstream.OutputRoomEvent)), Topic: string(dendriteCfg.Global.JetStream.Prefixed(jetstream.OutputRoomEvent)),
JetStream: js, JetStream: js,
ACLs: serverACLs, ACLs: serverACLs,
} }
a := &RoomserverInternalAPI{ a := &RoomserverInternalAPI{
ProcessContext: base.ProcessContext, ProcessContext: processContext,
DB: roomserverDB, DB: roomserverDB,
Base: base, Cfg: dendriteCfg,
Cfg: &base.Cfg.RoomServer, Cache: caches,
Cache: base.Caches, ServerName: dendriteCfg.Global.ServerName,
ServerName: base.Cfg.Global.ServerName,
PerspectiveServerNames: perspectiveServerNames, PerspectiveServerNames: perspectiveServerNames,
InputRoomEventTopic: base.Cfg.Global.JetStream.Prefixed(jetstream.InputRoomEvent), InputRoomEventTopic: dendriteCfg.Global.JetStream.Prefixed(jetstream.InputRoomEvent),
OutputProducer: producer, OutputProducer: producer,
JetStream: js, JetStream: js,
NATSClient: nc, NATSClient: nc,
Durable: base.Cfg.Global.JetStream.Durable("RoomserverInputConsumer"), Durable: dendriteCfg.Global.JetStream.Durable("RoomserverInputConsumer"),
ServerACLs: serverACLs, ServerACLs: serverACLs,
Queryer: &query.Queryer{ Queryer: &query.Queryer{
DB: roomserverDB, DB: roomserverDB,
Cache: base.Caches, Cache: caches,
IsLocalServerName: base.Cfg.Global.IsLocalServerName, IsLocalServerName: dendriteCfg.Global.IsLocalServerName,
ServerACLs: serverACLs, ServerACLs: serverACLs,
}, },
enableMetrics: enableMetrics,
// perform-er structs get initialised when we have a federation sender to use // perform-er structs get initialised when we have a federation sender to use
} }
return a return a
@ -105,15 +104,14 @@ func (r *RoomserverInternalAPI) SetFederationAPI(fsAPI fsAPI.RoomserverFederatio
r.fsAPI = fsAPI r.fsAPI = fsAPI
r.KeyRing = keyRing r.KeyRing = keyRing
identity, err := r.Cfg.Matrix.SigningIdentityFor(r.ServerName) identity, err := r.Cfg.Global.SigningIdentityFor(r.ServerName)
if err != nil { if err != nil {
logrus.Panic(err) logrus.Panic(err)
} }
r.Inputer = &input.Inputer{ r.Inputer = &input.Inputer{
Cfg: &r.Base.Cfg.RoomServer, Cfg: &r.Cfg.RoomServer,
Base: r.Base, ProcessContext: r.ProcessContext,
ProcessContext: r.Base.ProcessContext,
DB: r.DB, DB: r.DB,
InputRoomEventTopic: r.InputRoomEventTopic, InputRoomEventTopic: r.InputRoomEventTopic,
OutputProducer: r.OutputProducer, OutputProducer: r.OutputProducer,
@ -129,12 +127,12 @@ func (r *RoomserverInternalAPI) SetFederationAPI(fsAPI fsAPI.RoomserverFederatio
} }
r.Inviter = &perform.Inviter{ r.Inviter = &perform.Inviter{
DB: r.DB, DB: r.DB,
Cfg: r.Cfg, Cfg: &r.Cfg.RoomServer,
FSAPI: r.fsAPI, FSAPI: r.fsAPI,
Inputer: r.Inputer, Inputer: r.Inputer,
} }
r.Joiner = &perform.Joiner{ r.Joiner = &perform.Joiner{
Cfg: r.Cfg, Cfg: &r.Cfg.RoomServer,
DB: r.DB, DB: r.DB,
FSAPI: r.fsAPI, FSAPI: r.fsAPI,
RSAPI: r, RSAPI: r,
@ -143,7 +141,7 @@ func (r *RoomserverInternalAPI) SetFederationAPI(fsAPI fsAPI.RoomserverFederatio
} }
r.Peeker = &perform.Peeker{ r.Peeker = &perform.Peeker{
ServerName: r.ServerName, ServerName: r.ServerName,
Cfg: r.Cfg, Cfg: &r.Cfg.RoomServer,
DB: r.DB, DB: r.DB,
FSAPI: r.fsAPI, FSAPI: r.fsAPI,
Inputer: r.Inputer, Inputer: r.Inputer,
@ -154,12 +152,12 @@ func (r *RoomserverInternalAPI) SetFederationAPI(fsAPI fsAPI.RoomserverFederatio
} }
r.Unpeeker = &perform.Unpeeker{ r.Unpeeker = &perform.Unpeeker{
ServerName: r.ServerName, ServerName: r.ServerName,
Cfg: r.Cfg, Cfg: &r.Cfg.RoomServer,
FSAPI: r.fsAPI, FSAPI: r.fsAPI,
Inputer: r.Inputer, Inputer: r.Inputer,
} }
r.Leaver = &perform.Leaver{ r.Leaver = &perform.Leaver{
Cfg: r.Cfg, Cfg: &r.Cfg.RoomServer,
DB: r.DB, DB: r.DB,
FSAPI: r.fsAPI, FSAPI: r.fsAPI,
Inputer: r.Inputer, Inputer: r.Inputer,
@ -168,7 +166,7 @@ func (r *RoomserverInternalAPI) SetFederationAPI(fsAPI fsAPI.RoomserverFederatio
DB: r.DB, DB: r.DB,
} }
r.Backfiller = &perform.Backfiller{ r.Backfiller = &perform.Backfiller{
IsLocalServerName: r.Cfg.Matrix.IsLocalServerName, IsLocalServerName: r.Cfg.Global.IsLocalServerName,
DB: r.DB, DB: r.DB,
FSAPI: r.fsAPI, FSAPI: r.fsAPI,
KeyRing: r.KeyRing, KeyRing: r.KeyRing,
@ -181,12 +179,12 @@ func (r *RoomserverInternalAPI) SetFederationAPI(fsAPI fsAPI.RoomserverFederatio
DB: r.DB, DB: r.DB,
} }
r.Upgrader = &perform.Upgrader{ r.Upgrader = &perform.Upgrader{
Cfg: r.Cfg, Cfg: &r.Cfg.RoomServer,
URSAPI: r, URSAPI: r,
} }
r.Admin = &perform.Admin{ r.Admin = &perform.Admin{
DB: r.DB, DB: r.DB,
Cfg: r.Cfg, Cfg: &r.Cfg.RoomServer,
Inputer: r.Inputer, Inputer: r.Inputer,
Queryer: r.Queryer, Queryer: r.Queryer,
Leaver: r.Leaver, Leaver: r.Leaver,

View file

@ -3,26 +3,28 @@ package helpers
import ( import (
"context" "context"
"testing" "testing"
"time"
"github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/setup/config"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/roomserver/types"
"github.com/matrix-org/dendrite/setup/base"
"github.com/matrix-org/dendrite/test"
"github.com/matrix-org/dendrite/test/testrig"
"github.com/matrix-org/dendrite/roomserver/storage" "github.com/matrix-org/dendrite/roomserver/storage"
"github.com/matrix-org/dendrite/test"
) )
func mustCreateDatabase(t *testing.T, dbType test.DBType) (*base.BaseDendrite, storage.Database, func()) { func mustCreateDatabase(t *testing.T, dbType test.DBType) (storage.Database, func()) {
base, close := testrig.CreateBaseDendrite(t, dbType) conStr, close := test.PrepareDBConnectionString(t, dbType)
db, err := storage.Open(base, &base.Cfg.RoomServer.Database, base.Caches) caches := caching.NewRistrettoCache(8*1024*1024, time.Hour, caching.DisableMetrics)
cm := sqlutil.NewConnectionManager(nil, config.DatabaseOptions{})
db, err := storage.Open(context.Background(), cm, &config.DatabaseOptions{ConnectionString: config.DataSource(conStr)}, caches)
if err != nil { if err != nil {
t.Fatalf("failed to create Database: %v", err) t.Fatalf("failed to create Database: %v", err)
} }
return base, db, close return db, close
} }
func TestIsInvitePendingWithoutNID(t *testing.T) { func TestIsInvitePendingWithoutNID(t *testing.T) {
@ -32,7 +34,7 @@ func TestIsInvitePendingWithoutNID(t *testing.T) {
room := test.NewRoom(t, alice, test.RoomPreset(test.PresetPublicChat)) room := test.NewRoom(t, alice, test.RoomPreset(test.PresetPublicChat))
_ = bob _ = bob
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
_, db, close := mustCreateDatabase(t, dbType) db, close := mustCreateDatabase(t, dbType)
defer close() defer close()
// store all events // store all events

View file

@ -39,7 +39,6 @@ import (
"github.com/matrix-org/dendrite/roomserver/producers" "github.com/matrix-org/dendrite/roomserver/producers"
"github.com/matrix-org/dendrite/roomserver/storage" "github.com/matrix-org/dendrite/roomserver/storage"
"github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/roomserver/types"
"github.com/matrix-org/dendrite/setup/base"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/dendrite/setup/jetstream" "github.com/matrix-org/dendrite/setup/jetstream"
"github.com/matrix-org/dendrite/setup/process" "github.com/matrix-org/dendrite/setup/process"
@ -74,7 +73,6 @@ import (
// or C. // or C.
type Inputer struct { type Inputer struct {
Cfg *config.RoomServer Cfg *config.RoomServer
Base *base.BaseDendrite
ProcessContext *process.ProcessContext ProcessContext *process.ProcessContext
DB storage.RoomDatabase DB storage.RoomDatabase
NATSClient *nats.Conn NATSClient *nats.Conn
@ -89,8 +87,9 @@ type Inputer struct {
OutputProducer *producers.RoomEventProducer OutputProducer *producers.RoomEventProducer
workers sync.Map // room ID -> *worker workers sync.Map // room ID -> *worker
Queryer *query.Queryer Queryer *query.Queryer
UserAPI userapi.RoomserverUserAPI UserAPI userapi.RoomserverUserAPI
enableMetrics bool
} }
// If a room consumer is inactive for a while then we will allow NATS // If a room consumer is inactive for a while then we will allow NATS
@ -177,7 +176,7 @@ func (r *Inputer) startWorkerForRoom(roomID string) {
// will look to see if we have a worker for that room which has its // will look to see if we have a worker for that room which has its
// own consumer. If we don't, we'll start one. // own consumer. If we don't, we'll start one.
func (r *Inputer) Start() error { func (r *Inputer) Start() error {
if r.Base.EnableMetrics { if r.enableMetrics {
prometheus.MustRegister(roomserverInputBackpressure, processRoomEventDuration) prometheus.MustRegister(roomserverInputBackpressure, processRoomEventDuration)
} }
_, err := r.JetStream.Subscribe( _, err := r.JetStream.Subscribe(

View file

@ -2,82 +2,69 @@ package input_test
import ( import (
"context" "context"
"os"
"testing" "testing"
"time" "time"
"github.com/matrix-org/dendrite/internal/caching" "github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/roomserver"
"github.com/matrix-org/dendrite/roomserver/api" "github.com/matrix-org/dendrite/roomserver/api"
"github.com/matrix-org/dendrite/roomserver/internal/input" "github.com/matrix-org/dendrite/roomserver/internal/input"
"github.com/matrix-org/dendrite/roomserver/storage" "github.com/matrix-org/dendrite/setup/jetstream"
"github.com/matrix-org/dendrite/setup/base" "github.com/matrix-org/dendrite/test"
"github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/dendrite/test/testrig" "github.com/matrix-org/dendrite/test/testrig"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/nats-io/nats.go"
) )
var js nats.JetStreamContext
var jc *nats.Conn
func TestMain(m *testing.M) {
var b *base.BaseDendrite
b, js, jc = testrig.Base(nil)
code := m.Run()
b.ShutdownDendrite()
b.WaitForComponentsToFinish()
os.Exit(code)
}
func TestSingleTransactionOnInput(t *testing.T) { func TestSingleTransactionOnInput(t *testing.T) {
deadline, _ := t.Deadline() test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
if max := time.Now().Add(time.Second * 3); deadline.After(max) { cfg, processCtx, close := testrig.CreateConfig(t, dbType)
deadline = max defer close()
} cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
ctx, cancel := context.WithDeadline(context.Background(), deadline)
defer cancel()
event, err := gomatrixserverlib.NewEventFromTrustedJSON( natsInstance := &jetstream.NATSInstance{}
[]byte(`{"auth_events":[],"content":{"creator":"@neilalexander:dendrite.matrix.org","room_version":"6"},"depth":1,"hashes":{"sha256":"jqOqdNEH5r0NiN3xJtj0u5XUVmRqq9YvGbki1wxxuuM"},"origin":"dendrite.matrix.org","origin_server_ts":1644595362726,"prev_events":[],"prev_state":[],"room_id":"!jSZZRknA6GkTBXNP:dendrite.matrix.org","sender":"@neilalexander:dendrite.matrix.org","signatures":{"dendrite.matrix.org":{"ed25519:6jB2aB":"bsQXO1wketf1OSe9xlndDIWe71W9KIundc6rBw4KEZdGPW7x4Tv4zDWWvbxDsG64sS2IPWfIm+J0OOozbrWIDw"}},"state_key":"","type":"m.room.create"}`), js, jc := natsInstance.Prepare(processCtx, &cfg.Global.JetStream)
false, gomatrixserverlib.RoomVersionV6, caches := caching.NewRistrettoCache(8*1024*1024, time.Hour, caching.DisableMetrics)
) rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, natsInstance, caches, caching.DisableMetrics)
if err != nil { rsAPI.SetFederationAPI(nil, nil)
t.Fatal(err)
} deadline, _ := t.Deadline()
in := api.InputRoomEvent{ if max := time.Now().Add(time.Second * 3); deadline.Before(max) {
Kind: api.KindOutlier, // don't panic if we generate an output event deadline = max
Event: event.Headered(gomatrixserverlib.RoomVersionV6), }
} ctx, cancel := context.WithDeadline(processCtx.Context(), deadline)
db, err := storage.Open( defer cancel()
nil,
&config.DatabaseOptions{ event, err := gomatrixserverlib.NewEventFromTrustedJSON(
ConnectionString: "", []byte(`{"auth_events":[],"content":{"creator":"@neilalexander:dendrite.matrix.org","room_version":"6"},"depth":1,"hashes":{"sha256":"jqOqdNEH5r0NiN3xJtj0u5XUVmRqq9YvGbki1wxxuuM"},"origin":"dendrite.matrix.org","origin_server_ts":1644595362726,"prev_events":[],"prev_state":[],"room_id":"!jSZZRknA6GkTBXNP:dendrite.matrix.org","sender":"@neilalexander:dendrite.matrix.org","signatures":{"dendrite.matrix.org":{"ed25519:6jB2aB":"bsQXO1wketf1OSe9xlndDIWe71W9KIundc6rBw4KEZdGPW7x4Tv4zDWWvbxDsG64sS2IPWfIm+J0OOozbrWIDw"}},"state_key":"","type":"m.room.create"}`),
MaxOpenConnections: 1, false, gomatrixserverlib.RoomVersionV6,
MaxIdleConnections: 1, )
}, if err != nil {
caching.NewRistrettoCache(8*1024*1024, time.Hour, false), t.Fatal(err)
) }
if err != nil { in := api.InputRoomEvent{
t.Logf("PostgreSQL not available (%s), skipping", err) Kind: api.KindOutlier, // don't panic if we generate an output event
t.SkipNow() Event: event.Headered(gomatrixserverlib.RoomVersionV6),
} }
inputter := &input.Inputer{
DB: db, inputter := &input.Inputer{
JetStream: js, JetStream: js,
NATSClient: jc, NATSClient: jc,
} Cfg: &cfg.RoomServer,
res := &api.InputRoomEventsResponse{} }
inputter.InputRoomEvents( res := &api.InputRoomEventsResponse{}
ctx, inputter.InputRoomEvents(
&api.InputRoomEventsRequest{ ctx,
InputRoomEvents: []api.InputRoomEvent{in}, &api.InputRoomEventsRequest{
Asynchronous: false, InputRoomEvents: []api.InputRoomEvent{in},
}, Asynchronous: false,
res, },
) res,
// If we fail here then it's because we've hit the test deadline, )
// so we probably deadlocked // If we fail here then it's because we've hit the test deadline,
if err := res.Err(); err != nil { // so we probably deadlocked
t.Fatal(err) if err := res.Err(); err != nil {
} t.Fatal(err)
}
})
} }

View file

@ -15,28 +15,35 @@
package roomserver package roomserver
import ( import (
"github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/dendrite/setup/jetstream"
"github.com/matrix-org/dendrite/setup/process"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/matrix-org/dendrite/roomserver/api" "github.com/matrix-org/dendrite/roomserver/api"
"github.com/matrix-org/dendrite/roomserver/internal" "github.com/matrix-org/dendrite/roomserver/internal"
"github.com/matrix-org/dendrite/roomserver/storage" "github.com/matrix-org/dendrite/roomserver/storage"
"github.com/matrix-org/dendrite/setup/base"
) )
// NewInternalAPI returns a concrete implementation of the internal API. // NewInternalAPI returns a concrete implementation of the internal API.
func NewInternalAPI( func NewInternalAPI(
base *base.BaseDendrite, processContext *process.ProcessContext,
cfg *config.Dendrite,
cm sqlutil.Connections,
natsInstance *jetstream.NATSInstance,
caches caching.RoomServerCaches,
enableMetrics bool,
) api.RoomserverInternalAPI { ) api.RoomserverInternalAPI {
cfg := &base.Cfg.RoomServer roomserverDB, err := storage.Open(processContext.Context(), cm, &cfg.RoomServer.Database, caches)
roomserverDB, err := storage.Open(base, &cfg.Database, base.Caches)
if err != nil { if err != nil {
logrus.WithError(err).Panicf("failed to connect to room server db") logrus.WithError(err).Panicf("failed to connect to room server db")
} }
js, nc := base.NATS.Prepare(base.ProcessContext, &cfg.Matrix.JetStream) js, nc := natsInstance.Prepare(processContext, &cfg.Global.JetStream)
return internal.NewRoomserverAPI( return internal.NewRoomserverAPI(
base, roomserverDB, js, nc, processContext, cfg, roomserverDB, js, nc, caches, enableMetrics,
) )
} }

View file

@ -7,12 +7,15 @@ import (
"testing" "testing"
"time" "time"
"github.com/matrix-org/dendrite/roomserver/acls" "github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/httputil"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/matrix-org/dendrite/roomserver/acls"
"github.com/matrix-org/dendrite/roomserver/state" "github.com/matrix-org/dendrite/roomserver/state"
"github.com/matrix-org/dendrite/roomserver/storage"
"github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/roomserver/types"
"github.com/matrix-org/dendrite/setup/base"
"github.com/matrix-org/dendrite/userapi" "github.com/matrix-org/dendrite/userapi"
userAPI "github.com/matrix-org/dendrite/userapi/api" userAPI "github.com/matrix-org/dendrite/userapi/api"
@ -25,26 +28,18 @@ import (
"github.com/matrix-org/dendrite/roomserver" "github.com/matrix-org/dendrite/roomserver"
"github.com/matrix-org/dendrite/roomserver/api" "github.com/matrix-org/dendrite/roomserver/api"
"github.com/matrix-org/dendrite/roomserver/storage"
"github.com/matrix-org/dendrite/test" "github.com/matrix-org/dendrite/test"
"github.com/matrix-org/dendrite/test/testrig" "github.com/matrix-org/dendrite/test/testrig"
) )
func mustCreateDatabase(t *testing.T, dbType test.DBType) (*base.BaseDendrite, storage.Database, func()) {
t.Helper()
base, close := testrig.CreateBaseDendrite(t, dbType)
db, err := storage.Open(base, &base.Cfg.RoomServer.Database, base.Caches)
if err != nil {
t.Fatalf("failed to create Database: %v", err)
}
return base, db, close
}
func TestUsers(t *testing.T) { func TestUsers(t *testing.T) {
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
base, close := testrig.CreateBaseDendrite(t, dbType) cfg, processCtx, close := testrig.CreateConfig(t, dbType)
defer close() defer close()
rsAPI := roomserver.NewInternalAPI(base) caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
natsInstance := jetstream.NATSInstance{}
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
// SetFederationAPI starts the room event input consumer // SetFederationAPI starts the room event input consumer
rsAPI.SetFederationAPI(nil, nil) rsAPI.SetFederationAPI(nil, nil)
@ -53,7 +48,7 @@ func TestUsers(t *testing.T) {
}) })
t.Run("kick users", func(t *testing.T) { t.Run("kick users", func(t *testing.T) {
usrAPI := userapi.NewInternalAPI(base, rsAPI, nil) usrAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil)
rsAPI.SetUserAPI(usrAPI) rsAPI.SetUserAPI(usrAPI)
testKickUsers(t, rsAPI, usrAPI) testKickUsers(t, rsAPI, usrAPI)
}) })
@ -179,10 +174,13 @@ func Test_QueryLeftUsers(t *testing.T) {
ctx := context.Background() ctx := context.Background()
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
base, _, close := mustCreateDatabase(t, dbType) cfg, processCtx, close := testrig.CreateConfig(t, dbType)
defer close() defer close()
rsAPI := roomserver.NewInternalAPI(base) caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
natsInstance := jetstream.NATSInstance{}
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
// SetFederationAPI starts the room event input consumer // SetFederationAPI starts the room event input consumer
rsAPI.SetFederationAPI(nil, nil) rsAPI.SetFederationAPI(nil, nil)
// Create the room // Create the room
@ -226,29 +224,35 @@ func TestPurgeRoom(t *testing.T) {
ctx := context.Background() ctx := context.Background()
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
base, db, close := mustCreateDatabase(t, dbType) cfg, processCtx, close := testrig.CreateConfig(t, dbType)
natsInstance := jetstream.NATSInstance{}
defer close() defer close()
routers := httputil.NewRouters()
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
db, err := storage.Open(processCtx.Context(), cm, &cfg.RoomServer.Database, caches)
if err != nil {
t.Fatal(err)
}
jsCtx, _ := natsInstance.Prepare(processCtx, &cfg.Global.JetStream)
defer jetstream.DeleteAllStreams(jsCtx, &cfg.Global.JetStream)
jsCtx, _ := base.NATS.Prepare(base.ProcessContext, &base.Cfg.Global.JetStream) rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
defer jetstream.DeleteAllStreams(jsCtx, &base.Cfg.Global.JetStream) userAPI := userapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, rsAPI, nil)
fedClient := base.CreateFederationClient()
rsAPI := roomserver.NewInternalAPI(base)
userAPI := userapi.NewInternalAPI(base, rsAPI, nil)
// this starts the JetStream consumers // this starts the JetStream consumers
syncapi.AddPublicRoutes(base, userAPI, rsAPI) syncapi.AddPublicRoutes(processCtx, routers, cfg, cm, &natsInstance, userAPI, rsAPI, caches, caching.DisableMetrics)
federationapi.NewInternalAPI(base, fedClient, rsAPI, base.Caches, nil, true) federationapi.NewInternalAPI(processCtx, cfg, cm, &natsInstance, nil, rsAPI, caches, nil, true)
rsAPI.SetFederationAPI(nil, nil) rsAPI.SetFederationAPI(nil, nil)
// Create the room // Create the room
if err := api.SendEvents(ctx, rsAPI, api.KindNew, room.Events(), "test", "test", "test", nil, false); err != nil { if err = api.SendEvents(ctx, rsAPI, api.KindNew, room.Events(), "test", "test", "test", nil, false); err != nil {
t.Fatalf("failed to send events: %v", err) t.Fatalf("failed to send events: %v", err)
} }
// some dummy entries to validate after purging // some dummy entries to validate after purging
publishResp := &api.PerformPublishResponse{} publishResp := &api.PerformPublishResponse{}
if err := rsAPI.PerformPublish(ctx, &api.PerformPublishRequest{RoomID: room.ID, Visibility: "public"}, publishResp); err != nil { if err = rsAPI.PerformPublish(ctx, &api.PerformPublishRequest{RoomID: room.ID, Visibility: "public"}, publishResp); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if publishResp.Error != nil { if publishResp.Error != nil {
@ -336,7 +340,7 @@ func TestPurgeRoom(t *testing.T) {
t.Fatalf("test timed out after %s", timeout) t.Fatalf("test timed out after %s", timeout)
} }
sum = 0 sum = 0
consumerCh := jsCtx.Consumers(base.Cfg.Global.JetStream.Prefixed(jetstream.OutputRoomEvent)) consumerCh := jsCtx.Consumers(cfg.Global.JetStream.Prefixed(jetstream.OutputRoomEvent))
for x := range consumerCh { for x := range consumerCh {
sum += x.NumAckPending sum += x.NumAckPending
} }
@ -504,8 +508,14 @@ func TestRedaction(t *testing.T) {
ctx := context.Background() ctx := context.Background()
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
_, db, close := mustCreateDatabase(t, dbType) cfg, processCtx, close := testrig.CreateConfig(t, dbType)
defer close() defer close()
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
db, err := storage.Open(processCtx.Context(), cm, &cfg.RoomServer.Database, caches)
if err != nil {
t.Fatal(err)
}
for _, tc := range testCases { for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
@ -586,11 +596,14 @@ func TestNewServerACLs(t *testing.T) {
roomWithoutACL := test.NewRoom(t, alice) roomWithoutACL := test.NewRoom(t, alice)
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
base, db, closeBase := mustCreateDatabase(t, dbType) cfg, processCtx, closeDB := testrig.CreateConfig(t, dbType)
defer closeBase() defer closeDB()
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
natsInstance := &jetstream.NATSInstance{}
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
// start JetStream listeners // start JetStream listeners
rsAPI := roomserver.NewInternalAPI(base) rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, natsInstance, caches, caching.DisableMetrics)
rsAPI.SetFederationAPI(nil, nil) rsAPI.SetFederationAPI(nil, nil)
// let the RS create the events // let the RS create the events
@ -599,6 +612,8 @@ func TestNewServerACLs(t *testing.T) {
err = api.SendEvents(context.Background(), rsAPI, api.KindNew, roomWithoutACL.Events(), "test", "test", "test", nil, false) err = api.SendEvents(context.Background(), rsAPI, api.KindNew, roomWithoutACL.Events(), "test", "test", "test", nil, false)
assert.NoError(t, err) assert.NoError(t, err)
db, err := storage.Open(processCtx.Context(), cm, &cfg.RoomServer.Database, caches)
assert.NoError(t, err)
// create new server ACLs and verify server is banned/not banned // create new server ACLs and verify server is banned/not banned
serverACLs := acls.NewServerACLs(db) serverACLs := acls.NewServerACLs(db)
banned := serverACLs.IsServerBannedFromRoom("localhost", roomWithACL.ID) banned := serverACLs.IsServerBannedFromRoom("localhost", roomWithACL.ID)

View file

@ -28,7 +28,6 @@ import (
"github.com/matrix-org/dendrite/internal/sqlutil" "github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/roomserver/storage/postgres/deltas" "github.com/matrix-org/dendrite/roomserver/storage/postgres/deltas"
"github.com/matrix-org/dendrite/roomserver/storage/shared" "github.com/matrix-org/dendrite/roomserver/storage/shared"
"github.com/matrix-org/dendrite/setup/base"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
) )
@ -38,10 +37,10 @@ type Database struct {
} }
// Open a postgres database. // Open a postgres database.
func Open(base *base.BaseDendrite, dbProperties *config.DatabaseOptions, cache caching.RoomServerCaches) (*Database, error) { func Open(ctx context.Context, conMan sqlutil.Connections, dbProperties *config.DatabaseOptions, cache caching.RoomServerCaches) (*Database, error) {
var d Database var d Database
var err error var err error
db, writer, err := base.DatabaseConnection(dbProperties, sqlutil.NewDummyWriter()) db, writer, err := conMan.Connection(dbProperties)
if err != nil { if err != nil {
return nil, fmt.Errorf("sqlutil.Open: %w", err) return nil, fmt.Errorf("sqlutil.Open: %w", err)
} }
@ -53,7 +52,7 @@ func Open(base *base.BaseDendrite, dbProperties *config.DatabaseOptions, cache c
// Special case, since this migration uses several tables, so it needs to // Special case, since this migration uses several tables, so it needs to
// be sure that all tables are created first. // be sure that all tables are created first.
if err = executeMigration(base.Context(), db); err != nil { if err = executeMigration(ctx, db); err != nil {
return nil, err return nil, err
} }

View file

@ -15,14 +15,12 @@ import (
"github.com/matrix-org/dendrite/roomserver/storage/tables" "github.com/matrix-org/dendrite/roomserver/storage/tables"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/dendrite/test" "github.com/matrix-org/dendrite/test"
"github.com/matrix-org/dendrite/test/testrig"
) )
func mustCreateRoomserverDatabase(t *testing.T, dbType test.DBType) (*shared.Database, func()) { func mustCreateRoomserverDatabase(t *testing.T, dbType test.DBType) (*shared.Database, func()) {
t.Helper() t.Helper()
connStr, clearDB := test.PrepareDBConnectionString(t, dbType) connStr, clearDB := test.PrepareDBConnectionString(t, dbType)
base, _, _ := testrig.Base(nil)
dbOpts := &config.DatabaseOptions{ConnectionString: config.DataSource(connStr)} dbOpts := &config.DatabaseOptions{ConnectionString: config.DataSource(connStr)}
db, err := sqlutil.Open(dbOpts, sqlutil.NewExclusiveWriter()) db, err := sqlutil.Open(dbOpts, sqlutil.NewExclusiveWriter())
@ -61,8 +59,6 @@ func mustCreateRoomserverDatabase(t *testing.T, dbType test.DBType) (*shared.Dat
Writer: sqlutil.NewExclusiveWriter(), Writer: sqlutil.NewExclusiveWriter(),
Cache: cache, Cache: cache,
}, func() { }, func() {
err := base.Close()
assert.NoError(t, err)
clearDB() clearDB()
err = db.Close() err = db.Close()
assert.NoError(t, err) assert.NoError(t, err)

View file

@ -28,7 +28,6 @@ import (
"github.com/matrix-org/dendrite/roomserver/storage/shared" "github.com/matrix-org/dendrite/roomserver/storage/shared"
"github.com/matrix-org/dendrite/roomserver/storage/sqlite3/deltas" "github.com/matrix-org/dendrite/roomserver/storage/sqlite3/deltas"
"github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/roomserver/types"
"github.com/matrix-org/dendrite/setup/base"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
) )
@ -38,10 +37,10 @@ type Database struct {
} }
// Open a sqlite database. // Open a sqlite database.
func Open(base *base.BaseDendrite, dbProperties *config.DatabaseOptions, cache caching.RoomServerCaches) (*Database, error) { func Open(ctx context.Context, conMan sqlutil.Connections, dbProperties *config.DatabaseOptions, cache caching.RoomServerCaches) (*Database, error) {
var d Database var d Database
var err error var err error
db, writer, err := base.DatabaseConnection(dbProperties, sqlutil.NewExclusiveWriter()) db, writer, err := conMan.Connection(dbProperties)
if err != nil { if err != nil {
return nil, fmt.Errorf("sqlutil.Open: %w", err) return nil, fmt.Errorf("sqlutil.Open: %w", err)
} }
@ -62,7 +61,7 @@ func Open(base *base.BaseDendrite, dbProperties *config.DatabaseOptions, cache c
// Special case, since this migration uses several tables, so it needs to // Special case, since this migration uses several tables, so it needs to
// be sure that all tables are created first. // be sure that all tables are created first.
if err = executeMigration(base.Context(), db); err != nil { if err = executeMigration(ctx, db); err != nil {
return nil, err return nil, err
} }

View file

@ -18,22 +18,23 @@
package storage package storage
import ( import (
"context"
"fmt" "fmt"
"github.com/matrix-org/dendrite/internal/caching" "github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/roomserver/storage/postgres" "github.com/matrix-org/dendrite/roomserver/storage/postgres"
"github.com/matrix-org/dendrite/roomserver/storage/sqlite3" "github.com/matrix-org/dendrite/roomserver/storage/sqlite3"
"github.com/matrix-org/dendrite/setup/base"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
) )
// Open opens a database connection. // Open opens a database connection.
func Open(base *base.BaseDendrite, dbProperties *config.DatabaseOptions, cache caching.RoomServerCaches) (Database, error) { func Open(ctx context.Context, conMan sqlutil.Connections, dbProperties *config.DatabaseOptions, cache caching.RoomServerCaches) (Database, error) {
switch { switch {
case dbProperties.ConnectionString.IsSQLite(): case dbProperties.ConnectionString.IsSQLite():
return sqlite3.Open(base, dbProperties, cache) return sqlite3.Open(ctx, conMan, dbProperties, cache)
case dbProperties.ConnectionString.IsPostgres(): case dbProperties.ConnectionString.IsPostgres():
return postgres.Open(base, dbProperties, cache) return postgres.Open(ctx, conMan, dbProperties, cache)
default: default:
return nil, fmt.Errorf("unexpected database type") return nil, fmt.Errorf("unexpected database type")
} }

View file

@ -15,19 +15,20 @@
package storage package storage
import ( import (
"context"
"fmt" "fmt"
"github.com/matrix-org/dendrite/internal/caching" "github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/roomserver/storage/sqlite3" "github.com/matrix-org/dendrite/roomserver/storage/sqlite3"
"github.com/matrix-org/dendrite/setup/base"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
) )
// NewPublicRoomsServerDatabase opens a database connection. // NewPublicRoomsServerDatabase opens a database connection.
func Open(base *base.BaseDendrite, dbProperties *config.DatabaseOptions, cache caching.RoomServerCaches) (Database, error) { func Open(ctx context.Context, conMan sqlutil.Connections, dbProperties *config.DatabaseOptions, cache caching.RoomServerCaches) (Database, error) {
switch { switch {
case dbProperties.ConnectionString.IsSQLite(): case dbProperties.ConnectionString.IsSQLite():
return sqlite3.Open(base, dbProperties, cache) return sqlite3.Open(ctx, conMan, dbProperties, cache)
case dbProperties.ConnectionString.IsPostgres(): case dbProperties.ConnectionString.IsPostgres():
return nil, fmt.Errorf("can't use Postgres implementation") return nil, fmt.Errorf("can't use Postgres implementation")
default: default:

View file

@ -17,254 +17,55 @@ package base
import ( import (
"bytes" "bytes"
"context" "context"
"database/sql"
"embed" "embed"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"html/template" "html/template"
"io"
"io/fs" "io/fs"
"net" "net"
"net/http" "net/http"
_ "net/http/pprof" _ "net/http/pprof"
"os" "os"
"os/signal" "os/signal"
"sync"
"syscall" "syscall"
"time" "time"
"github.com/getsentry/sentry-go"
sentryhttp "github.com/getsentry/sentry-go/http" sentryhttp "github.com/getsentry/sentry-go/http"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/client_golang/prometheus/promhttp"
"go.uber.org/atomic" "go.uber.org/atomic"
"github.com/matrix-org/dendrite/internal"
"github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/fulltext"
"github.com/matrix-org/dendrite/internal/httputil"
"github.com/matrix-org/dendrite/internal/pushgateway"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/kardianos/minwinsvc" "github.com/kardianos/minwinsvc"
"github.com/matrix-org/dendrite/internal"
"github.com/matrix-org/dendrite/internal/httputil"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/dendrite/setup/jetstream"
"github.com/matrix-org/dendrite/setup/process" "github.com/matrix-org/dendrite/setup/process"
) )
//go:embed static/*.gotmpl //go:embed static/*.gotmpl
var staticContent embed.FS 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
// should only be used during start up.
// Must be closed when shutting down.
type BaseDendrite struct {
*process.ProcessContext
tracerCloser io.Closer
PublicClientAPIMux *mux.Router
PublicFederationAPIMux *mux.Router
PublicKeyAPIMux *mux.Router
PublicMediaAPIMux *mux.Router
PublicWellKnownAPIMux *mux.Router
PublicStaticMux *mux.Router
DendriteAdminMux *mux.Router
SynapseAdminMux *mux.Router
NATS *jetstream.NATSInstance
Cfg *config.Dendrite
Caches *caching.Caches
DNSCache *gomatrixserverlib.DNSCache
Database *sql.DB
DatabaseWriter sqlutil.Writer
EnableMetrics bool
Fulltext *fulltext.Search
startupLock sync.Mutex
}
const HTTPServerTimeout = time.Minute * 5 const HTTPServerTimeout = time.Minute * 5
type BaseDendriteOptions int
const (
DisableMetrics BaseDendriteOptions = iota
)
// NewBaseDendrite creates a new instance to be used by a component.
func NewBaseDendrite(cfg *config.Dendrite, options ...BaseDendriteOptions) *BaseDendrite {
platformSanityChecks()
enableMetrics := true
for _, opt := range options {
switch opt {
case DisableMetrics:
enableMetrics = false
}
}
configErrors := &config.ConfigErrors{}
cfg.Verify(configErrors)
if len(*configErrors) > 0 {
for _, err := range *configErrors {
logrus.Errorf("Configuration error: %s", err)
}
logrus.Fatalf("Failed to start due to configuration errors")
}
internal.SetupStdLogging()
internal.SetupHookLogging(cfg.Logging)
internal.SetupPprof()
logrus.Infof("Dendrite version %s", internal.VersionString())
if !cfg.ClientAPI.RegistrationDisabled && cfg.ClientAPI.OpenRegistrationWithoutVerificationEnabled {
logrus.Warn("Open registration is enabled")
}
closer, err := cfg.SetupTracing()
if err != nil {
logrus.WithError(err).Panicf("failed to start opentracing")
}
var fts *fulltext.Search
if cfg.SyncAPI.Fulltext.Enabled {
fts, err = fulltext.New(cfg.SyncAPI.Fulltext)
if err != nil {
logrus.WithError(err).Panicf("failed to create full text")
}
}
if cfg.Global.Sentry.Enabled {
logrus.Info("Setting up Sentry for debugging...")
err = sentry.Init(sentry.ClientOptions{
Dsn: cfg.Global.Sentry.DSN,
Environment: cfg.Global.Sentry.Environment,
Debug: true,
ServerName: string(cfg.Global.ServerName),
Release: "dendrite@" + internal.VersionString(),
AttachStacktrace: true,
})
if err != nil {
logrus.WithError(err).Panic("failed to start Sentry")
}
}
var dnsCache *gomatrixserverlib.DNSCache
if cfg.Global.DNSCache.Enabled {
dnsCache = gomatrixserverlib.NewDNSCache(
cfg.Global.DNSCache.CacheSize,
cfg.Global.DNSCache.CacheLifetime,
)
logrus.Infof(
"DNS cache enabled (size %d, lifetime %s)",
cfg.Global.DNSCache.CacheSize,
cfg.Global.DNSCache.CacheLifetime,
)
}
// If we're in monolith mode, we'll set up a global pool of database
// connections. A component is welcome to use this pool if they don't
// have a separate database config of their own.
var db *sql.DB
var writer sqlutil.Writer
if cfg.Global.DatabaseOptions.ConnectionString != "" {
if cfg.Global.DatabaseOptions.ConnectionString.IsSQLite() {
logrus.Panic("Using a global database connection pool is not supported with SQLite databases")
}
writer = sqlutil.NewDummyWriter()
if db, err = sqlutil.Open(&cfg.Global.DatabaseOptions, writer); err != nil {
logrus.WithError(err).Panic("Failed to set up global database connections")
}
logrus.Debug("Using global database connection pool")
}
// Ideally we would only use SkipClean on routes which we know can allow '/' but due to
// https://github.com/gorilla/mux/issues/460 we have to attach this at the top router.
// When used in conjunction with UseEncodedPath() we get the behaviour we want when parsing
// path parameters:
// /foo/bar%2Fbaz == [foo, bar%2Fbaz] (from UseEncodedPath)
// /foo/bar%2F%2Fbaz == [foo, bar%2F%2Fbaz] (from SkipClean)
// In particular, rooms v3 event IDs are not urlsafe and can include '/' and because they
// are randomly generated it results in flakey tests.
// We need to be careful with media APIs if they read from a filesystem to make sure they
// are not inadvertently reading paths without cleaning, else this could introduce a
// directory traversal attack e.g /../../../etc/passwd
return &BaseDendrite{
ProcessContext: process.NewProcessContext(),
tracerCloser: closer,
Cfg: cfg,
Caches: caching.NewRistrettoCache(cfg.Global.Cache.EstimatedMaxSize, cfg.Global.Cache.MaxAge, enableMetrics),
DNSCache: dnsCache,
PublicClientAPIMux: mux.NewRouter().SkipClean(true).PathPrefix(httputil.PublicClientPathPrefix).Subrouter().UseEncodedPath(),
PublicFederationAPIMux: mux.NewRouter().SkipClean(true).PathPrefix(httputil.PublicFederationPathPrefix).Subrouter().UseEncodedPath(),
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(),
DendriteAdminMux: mux.NewRouter().SkipClean(true).PathPrefix(httputil.DendriteAdminPathPrefix).Subrouter().UseEncodedPath(),
SynapseAdminMux: mux.NewRouter().SkipClean(true).PathPrefix(httputil.SynapseAdminPathPrefix).Subrouter().UseEncodedPath(),
NATS: &jetstream.NATSInstance{},
Database: db, // set if monolith with global connection pool only
DatabaseWriter: writer, // set if monolith with global connection pool only
EnableMetrics: enableMetrics,
Fulltext: fts,
}
}
// Close implements io.Closer
func (b *BaseDendrite) Close() error {
b.ProcessContext.ShutdownDendrite()
b.ProcessContext.WaitForShutdown()
return b.tracerCloser.Close()
}
// DatabaseConnection assists in setting up a database connection. It accepts
// the database properties and a new writer for the given component. If we're
// running in monolith mode with a global connection pool configured then we
// will return that connection, along with the global writer, effectively
// ignoring the options provided. Otherwise we'll open a new database connection
// using the supplied options and writer. Note that it's possible for the pointer
// receiver to be nil here that's deliberate as some of the unit tests don't
// have a BaseDendrite and just want a connection with the supplied config
// without any pooling stuff.
func (b *BaseDendrite) DatabaseConnection(dbProperties *config.DatabaseOptions, writer sqlutil.Writer) (*sql.DB, sqlutil.Writer, error) {
if dbProperties.ConnectionString != "" || b == nil {
// Open a new database connection using the supplied config.
db, err := sqlutil.Open(dbProperties, writer)
return db, writer, err
}
if b.Database != nil && b.DatabaseWriter != nil {
// Ignore the supplied config and return the global pool and
// writer.
return b.Database, b.DatabaseWriter, nil
}
return nil, nil, fmt.Errorf("no database connections configured")
}
// PushGatewayHTTPClient returns a new client for interacting with (external) Push Gateways.
func (b *BaseDendrite) PushGatewayHTTPClient() pushgateway.Client {
return pushgateway.NewHTTPClient(b.Cfg.UserAPI.PushGatewayDisableTLSValidation)
}
// CreateClient creates a new client (normally used for media fetch requests). // CreateClient creates a new client (normally used for media fetch requests).
// Should only be called once per component. // Should only be called once per component.
func (b *BaseDendrite) CreateClient() *gomatrixserverlib.Client { func CreateClient(cfg *config.Dendrite, dnsCache *gomatrixserverlib.DNSCache) *gomatrixserverlib.Client {
if b.Cfg.Global.DisableFederation { if cfg.Global.DisableFederation {
return gomatrixserverlib.NewClient( return gomatrixserverlib.NewClient(
gomatrixserverlib.WithTransport(noOpHTTPTransport), gomatrixserverlib.WithTransport(noOpHTTPTransport),
) )
} }
opts := []gomatrixserverlib.ClientOption{ opts := []gomatrixserverlib.ClientOption{
gomatrixserverlib.WithSkipVerify(b.Cfg.FederationAPI.DisableTLSValidation), gomatrixserverlib.WithSkipVerify(cfg.FederationAPI.DisableTLSValidation),
gomatrixserverlib.WithWellKnownSRVLookups(true), gomatrixserverlib.WithWellKnownSRVLookups(true),
} }
if b.Cfg.Global.DNSCache.Enabled { if cfg.Global.DNSCache.Enabled && dnsCache != nil {
opts = append(opts, gomatrixserverlib.WithDNSCache(b.DNSCache)) opts = append(opts, gomatrixserverlib.WithDNSCache(dnsCache))
} }
client := gomatrixserverlib.NewClient(opts...) client := gomatrixserverlib.NewClient(opts...)
client.SetUserAgent(fmt.Sprintf("Dendrite/%s", internal.VersionString())) client.SetUserAgent(fmt.Sprintf("Dendrite/%s", internal.VersionString()))
@ -273,20 +74,20 @@ func (b *BaseDendrite) CreateClient() *gomatrixserverlib.Client {
// CreateFederationClient creates a new federation client. Should only be called // CreateFederationClient creates a new federation client. Should only be called
// once per component. // once per component.
func (b *BaseDendrite) CreateFederationClient() *gomatrixserverlib.FederationClient { func CreateFederationClient(cfg *config.Dendrite, dnsCache *gomatrixserverlib.DNSCache) *gomatrixserverlib.FederationClient {
identities := b.Cfg.Global.SigningIdentities() identities := cfg.Global.SigningIdentities()
if b.Cfg.Global.DisableFederation { if cfg.Global.DisableFederation {
return gomatrixserverlib.NewFederationClient( return gomatrixserverlib.NewFederationClient(
identities, gomatrixserverlib.WithTransport(noOpHTTPTransport), identities, gomatrixserverlib.WithTransport(noOpHTTPTransport),
) )
} }
opts := []gomatrixserverlib.ClientOption{ opts := []gomatrixserverlib.ClientOption{
gomatrixserverlib.WithTimeout(time.Minute * 5), gomatrixserverlib.WithTimeout(time.Minute * 5),
gomatrixserverlib.WithSkipVerify(b.Cfg.FederationAPI.DisableTLSValidation), gomatrixserverlib.WithSkipVerify(cfg.FederationAPI.DisableTLSValidation),
gomatrixserverlib.WithKeepAlives(!b.Cfg.FederationAPI.DisableHTTPKeepalives), gomatrixserverlib.WithKeepAlives(!cfg.FederationAPI.DisableHTTPKeepalives),
} }
if b.Cfg.Global.DNSCache.Enabled { if cfg.Global.DNSCache.Enabled {
opts = append(opts, gomatrixserverlib.WithDNSCache(b.DNSCache)) opts = append(opts, gomatrixserverlib.WithDNSCache(dnsCache))
} }
client := gomatrixserverlib.NewFederationClient( client := gomatrixserverlib.NewFederationClient(
identities, opts..., identities, opts...,
@ -295,41 +96,12 @@ func (b *BaseDendrite) CreateFederationClient() *gomatrixserverlib.FederationCli
return client return client
} }
func (b *BaseDendrite) configureHTTPErrors() { func ConfigureAdminEndpoints(processContext *process.ProcessContext, routers httputil.Routers) {
notAllowedHandler := func(w http.ResponseWriter, r *http.Request) { routers.DendriteAdmin.HandleFunc("/monitor/up", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusMethodNotAllowed)
_, _ = w.Write([]byte(fmt.Sprintf("405 %s not allowed on this endpoint", r.Method)))
}
clientNotFoundHandler := func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNotFound)
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`{"errcode":"M_UNRECOGNIZED","error":"Unrecognized request"}`)) // nolint:misspell
}
notFoundCORSHandler := httputil.WrapHandlerInCORS(http.NotFoundHandler())
notAllowedCORSHandler := httputil.WrapHandlerInCORS(http.HandlerFunc(notAllowedHandler))
for _, router := range []*mux.Router{
b.PublicMediaAPIMux, b.DendriteAdminMux,
b.SynapseAdminMux, b.PublicWellKnownAPIMux,
b.PublicStaticMux,
} {
router.NotFoundHandler = notFoundCORSHandler
router.MethodNotAllowedHandler = notAllowedCORSHandler
}
// Special case so that we don't upset clients on the CS API.
b.PublicClientAPIMux.NotFoundHandler = http.HandlerFunc(clientNotFoundHandler)
b.PublicClientAPIMux.MethodNotAllowedHandler = http.HandlerFunc(clientNotFoundHandler)
}
func (b *BaseDendrite) ConfigureAdminEndpoints() {
b.DendriteAdminMux.HandleFunc("/monitor/up", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200) w.WriteHeader(200)
}) })
b.DendriteAdminMux.HandleFunc("/monitor/health", func(w http.ResponseWriter, r *http.Request) { routers.DendriteAdmin.HandleFunc("/monitor/health", func(w http.ResponseWriter, r *http.Request) {
if isDegraded, reasons := b.ProcessContext.IsDegraded(); isDegraded { if isDegraded, reasons := processContext.IsDegraded(); isDegraded {
w.WriteHeader(503) w.WriteHeader(503)
_ = json.NewEncoder(w).Encode(struct { _ = json.NewEncoder(w).Encode(struct {
Warnings []string `json:"warnings"` Warnings []string `json:"warnings"`
@ -344,14 +116,13 @@ func (b *BaseDendrite) ConfigureAdminEndpoints() {
// SetupAndServeHTTP sets up the HTTP server to serve client & federation APIs // SetupAndServeHTTP sets up the HTTP server to serve client & federation APIs
// and adds a prometheus handler under /_dendrite/metrics. // and adds a prometheus handler under /_dendrite/metrics.
func (b *BaseDendrite) SetupAndServeHTTP( func SetupAndServeHTTP(
processContext *process.ProcessContext,
cfg *config.Dendrite,
routers httputil.Routers,
externalHTTPAddr config.ServerAddress, externalHTTPAddr config.ServerAddress,
certFile, keyFile *string, certFile, keyFile *string,
) { ) {
// Manually unlocked right before actually serving requests,
// as we don't return from this method (defer doesn't work).
b.startupLock.Lock()
externalRouter := mux.NewRouter().SkipClean(true).UseEncodedPath() externalRouter := mux.NewRouter().SkipClean(true).UseEncodedPath()
externalServ := &http.Server{ externalServ := &http.Server{
@ -359,22 +130,20 @@ func (b *BaseDendrite) SetupAndServeHTTP(
WriteTimeout: HTTPServerTimeout, WriteTimeout: HTTPServerTimeout,
Handler: externalRouter, Handler: externalRouter,
BaseContext: func(_ net.Listener) context.Context { BaseContext: func(_ net.Listener) context.Context {
return b.ProcessContext.Context() return processContext.Context()
}, },
} }
b.configureHTTPErrors()
//Redirect for Landing Page //Redirect for Landing Page
externalRouter.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { externalRouter.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, httputil.PublicStaticPath, http.StatusFound) http.Redirect(w, r, httputil.PublicStaticPath, http.StatusFound)
}) })
if b.Cfg.Global.Metrics.Enabled { if cfg.Global.Metrics.Enabled {
externalRouter.Handle("/metrics", httputil.WrapHandlerInBasicAuth(promhttp.Handler(), b.Cfg.Global.Metrics.BasicAuth)) externalRouter.Handle("/metrics", httputil.WrapHandlerInBasicAuth(promhttp.Handler(), cfg.Global.Metrics.BasicAuth))
} }
b.ConfigureAdminEndpoints() ConfigureAdminEndpoints(processContext, routers)
// Parse and execute the landing page template // Parse and execute the landing page template
tmpl := template.Must(template.ParseFS(staticContent, "static/*.gotmpl")) tmpl := template.Must(template.ParseFS(staticContent, "static/*.gotmpl"))
@ -385,47 +154,48 @@ func (b *BaseDendrite) SetupAndServeHTTP(
logrus.WithError(err).Fatal("failed to execute landing page template") logrus.WithError(err).Fatal("failed to execute landing page template")
} }
b.PublicStaticMux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { routers.Static.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write(landingPage.Bytes()) _, _ = w.Write(landingPage.Bytes())
}) })
var clientHandler http.Handler var clientHandler http.Handler
clientHandler = b.PublicClientAPIMux clientHandler = routers.Client
if b.Cfg.Global.Sentry.Enabled { if cfg.Global.Sentry.Enabled {
sentryHandler := sentryhttp.New(sentryhttp.Options{ sentryHandler := sentryhttp.New(sentryhttp.Options{
Repanic: true, Repanic: true,
}) })
clientHandler = sentryHandler.Handle(b.PublicClientAPIMux) clientHandler = sentryHandler.Handle(routers.Client)
} }
var federationHandler http.Handler var federationHandler http.Handler
federationHandler = b.PublicFederationAPIMux federationHandler = routers.Federation
if b.Cfg.Global.Sentry.Enabled { if cfg.Global.Sentry.Enabled {
sentryHandler := sentryhttp.New(sentryhttp.Options{ sentryHandler := sentryhttp.New(sentryhttp.Options{
Repanic: true, Repanic: true,
}) })
federationHandler = sentryHandler.Handle(b.PublicFederationAPIMux) federationHandler = sentryHandler.Handle(routers.Federation)
} }
externalRouter.PathPrefix(httputil.DendriteAdminPathPrefix).Handler(b.DendriteAdminMux) externalRouter.PathPrefix(httputil.DendriteAdminPathPrefix).Handler(routers.DendriteAdmin)
externalRouter.PathPrefix(httputil.PublicClientPathPrefix).Handler(clientHandler) externalRouter.PathPrefix(httputil.PublicClientPathPrefix).Handler(clientHandler)
if !b.Cfg.Global.DisableFederation { if !cfg.Global.DisableFederation {
externalRouter.PathPrefix(httputil.PublicKeyPathPrefix).Handler(b.PublicKeyAPIMux) externalRouter.PathPrefix(httputil.PublicKeyPathPrefix).Handler(routers.Keys)
externalRouter.PathPrefix(httputil.PublicFederationPathPrefix).Handler(federationHandler) externalRouter.PathPrefix(httputil.PublicFederationPathPrefix).Handler(federationHandler)
} }
externalRouter.PathPrefix(httputil.SynapseAdminPathPrefix).Handler(b.SynapseAdminMux) externalRouter.PathPrefix(httputil.SynapseAdminPathPrefix).Handler(routers.SynapseAdmin)
externalRouter.PathPrefix(httputil.PublicMediaPathPrefix).Handler(b.PublicMediaAPIMux) externalRouter.PathPrefix(httputil.PublicMediaPathPrefix).Handler(routers.Media)
externalRouter.PathPrefix(httputil.PublicWellKnownPrefix).Handler(b.PublicWellKnownAPIMux) externalRouter.PathPrefix(httputil.PublicWellKnownPrefix).Handler(routers.WellKnown)
externalRouter.PathPrefix(httputil.PublicStaticPath).Handler(b.PublicStaticMux) externalRouter.PathPrefix(httputil.PublicStaticPath).Handler(routers.Static)
b.startupLock.Unlock() externalRouter.NotFoundHandler = httputil.NotFoundCORSHandler
externalRouter.MethodNotAllowedHandler = httputil.NotAllowedHandler
if externalHTTPAddr.Enabled() { if externalHTTPAddr.Enabled() {
go func() { go func() {
var externalShutdown atomic.Bool // RegisterOnShutdown can be called more than once var externalShutdown atomic.Bool // RegisterOnShutdown can be called more than once
logrus.Infof("Starting external listener on %s", externalServ.Addr) logrus.Infof("Starting external listener on %s", externalServ.Addr)
b.ProcessContext.ComponentStarted() processContext.ComponentStarted()
externalServ.RegisterOnShutdown(func() { externalServ.RegisterOnShutdown(func() {
if externalShutdown.CompareAndSwap(false, true) { if externalShutdown.CompareAndSwap(false, true) {
b.ProcessContext.ComponentFinished() processContext.ComponentFinished()
logrus.Infof("Stopped external HTTP listener") logrus.Infof("Stopped external HTTP listener")
} }
}) })
@ -467,38 +237,27 @@ func (b *BaseDendrite) SetupAndServeHTTP(
}() }()
} }
minwinsvc.SetOnExit(b.ProcessContext.ShutdownDendrite) minwinsvc.SetOnExit(processContext.ShutdownDendrite)
<-b.ProcessContext.WaitForShutdown() <-processContext.WaitForShutdown()
logrus.Infof("Stopping HTTP listeners") logrus.Infof("Stopping HTTP listeners")
_ = externalServ.Shutdown(context.Background()) _ = externalServ.Shutdown(context.Background())
logrus.Infof("Stopped HTTP listeners") logrus.Infof("Stopped HTTP listeners")
} }
func (b *BaseDendrite) WaitForShutdown() { func WaitForShutdown(processCtx *process.ProcessContext) {
sigs := make(chan os.Signal, 1) sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
select { select {
case <-sigs: case <-sigs:
case <-b.ProcessContext.WaitForShutdown(): case <-processCtx.WaitForShutdown():
} }
signal.Reset(syscall.SIGINT, syscall.SIGTERM) signal.Reset(syscall.SIGINT, syscall.SIGTERM)
logrus.Warnf("Shutdown signal received") logrus.Warnf("Shutdown signal received")
b.ProcessContext.ShutdownDendrite() processCtx.ShutdownDendrite()
b.ProcessContext.WaitForComponentsToFinish() processCtx.WaitForComponentsToFinish()
if b.Cfg.Global.Sentry.Enabled {
if !sentry.Flush(time.Second * 5) {
logrus.Warnf("failed to flush all Sentry events!")
}
}
if b.Fulltext != nil {
err := b.Fulltext.Close()
if err != nil {
logrus.Warnf("failed to close full text search!")
}
}
logrus.Warnf("Dendrite is exiting now") logrus.Warnf("Dendrite is exiting now")
} }

View file

@ -13,8 +13,10 @@ import (
"time" "time"
"github.com/matrix-org/dendrite/internal" "github.com/matrix-org/dendrite/internal"
"github.com/matrix-org/dendrite/internal/httputil"
basepkg "github.com/matrix-org/dendrite/setup/base"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/dendrite/test/testrig" "github.com/matrix-org/dendrite/setup/process"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -30,8 +32,10 @@ func TestLandingPage_Tcp(t *testing.T) {
}) })
assert.NoError(t, err) assert.NoError(t, err)
b, _, _ := testrig.Base(nil) processCtx := process.NewProcessContext()
defer b.Close() routers := httputil.NewRouters()
cfg := config.Dendrite{}
cfg.Defaults(config.DefaultOpts{Generate: true, SingleDatabase: true})
// hack: create a server and close it immediately, just to get a random port assigned // hack: create a server and close it immediately, just to get a random port assigned
s := httptest.NewServer(nil) s := httptest.NewServer(nil)
@ -40,7 +44,7 @@ func TestLandingPage_Tcp(t *testing.T) {
// start base with the listener and wait for it to be started // start base with the listener and wait for it to be started
address, err := config.HTTPAddress(s.URL) address, err := config.HTTPAddress(s.URL)
assert.NoError(t, err) assert.NoError(t, err)
go b.SetupAndServeHTTP(address, nil, nil) go basepkg.SetupAndServeHTTP(processCtx, &cfg, routers, address, nil, nil)
time.Sleep(time.Millisecond * 10) time.Sleep(time.Millisecond * 10)
// When hitting /, we should be redirected to /_matrix/static, which should contain the landing page // When hitting /, we should be redirected to /_matrix/static, which should contain the landing page
@ -70,15 +74,17 @@ func TestLandingPage_UnixSocket(t *testing.T) {
}) })
assert.NoError(t, err) assert.NoError(t, err)
b, _, _ := testrig.Base(nil) processCtx := process.NewProcessContext()
defer b.Close() routers := httputil.NewRouters()
cfg := config.Dendrite{}
cfg.Defaults(config.DefaultOpts{Generate: true, SingleDatabase: true})
tempDir := t.TempDir() tempDir := t.TempDir()
socket := path.Join(tempDir, "socket") socket := path.Join(tempDir, "socket")
// start base with the listener and wait for it to be started // start base with the listener and wait for it to be started
address := config.UnixSocketAddress(socket, 0755) address, err := config.UnixSocketAddress(socket, "755")
assert.NoError(t, err) assert.NoError(t, err)
go b.SetupAndServeHTTP(address, nil, nil) go basepkg.SetupAndServeHTTP(processCtx, &cfg, routers, address, nil, nil)
time.Sleep(time.Millisecond * 100) time.Sleep(time.Millisecond * 100)
client := &http.Client{ client := &http.Client{

View file

@ -3,6 +3,6 @@
package base package base
func platformSanityChecks() { func PlatformSanityChecks() {
// Nothing to do yet. // Nothing to do yet.
} }

View file

@ -9,7 +9,7 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
func platformSanityChecks() { func PlatformSanityChecks() {
// Dendrite needs a relatively high number of file descriptors in order // Dendrite needs a relatively high number of file descriptors in order
// to function properly, particularly when federating with lots of servers. // to function properly, particularly when federating with lots of servers.
// If we run out of file descriptors, we might run into problems accessing // If we run out of file descriptors, we might run into problems accessing

View file

@ -3,6 +3,7 @@ package config
import ( import (
"io/fs" "io/fs"
"net/url" "net/url"
"strconv"
) )
const ( const (
@ -32,8 +33,12 @@ func (s ServerAddress) Network() string {
} }
} }
func UnixSocketAddress(path string, perm fs.FileMode) ServerAddress { func UnixSocketAddress(path string, perm string) (ServerAddress, error) {
return ServerAddress{Address: path, Scheme: NetworkUnix, UnixSocketPermission: perm} permission, err := strconv.ParseInt(perm, 8, 32)
if err != nil {
return ServerAddress{}, err
}
return ServerAddress{Address: path, Scheme: NetworkUnix, UnixSocketPermission: fs.FileMode(permission)}, nil
} }
func HTTPAddress(urlAddress string) (ServerAddress, error) { func HTTPAddress(urlAddress string) (ServerAddress, error) {

View file

@ -20,6 +20,24 @@ func TestHttpAddress_ParseBad(t *testing.T) {
} }
func TestUnixSocketAddress_Network(t *testing.T) { func TestUnixSocketAddress_Network(t *testing.T) {
address := UnixSocketAddress("/tmp", fs.FileMode(0755)) address, err := UnixSocketAddress("/tmp", "0755")
assert.NoError(t, err)
assert.Equal(t, "unix", address.Network()) assert.Equal(t, "unix", address.Network())
} }
func TestUnixSocketAddress_Permission_LeadingZero_Ok(t *testing.T) {
address, err := UnixSocketAddress("/tmp", "0755")
assert.NoError(t, err)
assert.Equal(t, fs.FileMode(0755), address.UnixSocketPermission)
}
func TestUnixSocketAddress_Permission_NoLeadingZero_Ok(t *testing.T) {
address, err := UnixSocketAddress("/tmp", "755")
assert.NoError(t, err)
assert.Equal(t, fs.FileMode(0755), address.UnixSocketPermission)
}
func TestUnixSocketAddress_Permission_NonOctal_Bad(t *testing.T) {
_, err := UnixSocketAddress("/tmp", "855")
assert.Error(t, err)
}

View file

@ -20,6 +20,8 @@ import (
type NATSInstance struct { type NATSInstance struct {
*natsserver.Server *natsserver.Server
nc *natsclient.Conn
js natsclient.JetStreamContext
} }
var natsLock sync.Mutex var natsLock sync.Mutex
@ -54,7 +56,9 @@ func (s *NATSInstance) Prepare(process *process.ProcessContext, cfg *config.JetS
if err != nil { if err != nil {
panic(err) panic(err)
} }
s.SetLogger(NewLogAdapter(), opts.Debug, opts.Trace) if !cfg.NoLog {
s.SetLogger(NewLogAdapter(), opts.Debug, opts.Trace)
}
go func() { go func() {
process.ComponentStarted() process.ComponentStarted()
s.Start() s.Start()
@ -69,11 +73,18 @@ func (s *NATSInstance) Prepare(process *process.ProcessContext, cfg *config.JetS
if !s.ReadyForConnections(time.Second * 10) { if !s.ReadyForConnections(time.Second * 10) {
logrus.Fatalln("NATS did not start in time") logrus.Fatalln("NATS did not start in time")
} }
// reuse existing connections
if s.nc != nil {
return s.js, s.nc
}
nc, err := natsclient.Connect("", natsclient.InProcessServer(s)) nc, err := natsclient.Connect("", natsclient.InProcessServer(s))
if err != nil { if err != nil {
logrus.Fatalln("Failed to create NATS client") logrus.Fatalln("Failed to create NATS client")
} }
return setupNATS(process, cfg, nc) js, _ := setupNATS(process, cfg, nc)
s.js = js
s.nc = nc
return js, nc
} }
func setupNATS(process *process.ProcessContext, cfg *config.JetStream, nc *natsclient.Conn) (natsclient.JetStreamContext, *natsclient.Conn) { func setupNATS(process *process.ProcessContext, cfg *config.JetStream, nc *natsclient.Conn) (natsclient.JetStreamContext, *natsclient.Conn) {

View file

@ -20,13 +20,17 @@ import (
"github.com/matrix-org/dendrite/clientapi/api" "github.com/matrix-org/dendrite/clientapi/api"
"github.com/matrix-org/dendrite/federationapi" "github.com/matrix-org/dendrite/federationapi"
federationAPI "github.com/matrix-org/dendrite/federationapi/api" federationAPI "github.com/matrix-org/dendrite/federationapi/api"
"github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/httputil"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/internal/transactions" "github.com/matrix-org/dendrite/internal/transactions"
"github.com/matrix-org/dendrite/mediaapi" "github.com/matrix-org/dendrite/mediaapi"
"github.com/matrix-org/dendrite/relayapi" "github.com/matrix-org/dendrite/relayapi"
relayAPI "github.com/matrix-org/dendrite/relayapi/api" relayAPI "github.com/matrix-org/dendrite/relayapi/api"
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api" roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
"github.com/matrix-org/dendrite/setup/base"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/dendrite/setup/jetstream"
"github.com/matrix-org/dendrite/setup/process"
"github.com/matrix-org/dendrite/syncapi" "github.com/matrix-org/dendrite/syncapi"
userapi "github.com/matrix-org/dendrite/userapi/api" userapi "github.com/matrix-org/dendrite/userapi/api"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
@ -52,23 +56,31 @@ type Monolith struct {
} }
// AddAllPublicRoutes attaches all public paths to the given router // AddAllPublicRoutes attaches all public paths to the given router
func (m *Monolith) AddAllPublicRoutes(base *base.BaseDendrite) { func (m *Monolith) AddAllPublicRoutes(
processCtx *process.ProcessContext,
cfg *config.Dendrite,
routers httputil.Routers,
cm sqlutil.Connections,
natsInstance *jetstream.NATSInstance,
caches *caching.Caches,
enableMetrics bool,
) {
userDirectoryProvider := m.ExtUserDirectoryProvider userDirectoryProvider := m.ExtUserDirectoryProvider
if userDirectoryProvider == nil { if userDirectoryProvider == nil {
userDirectoryProvider = m.UserAPI userDirectoryProvider = m.UserAPI
} }
clientapi.AddPublicRoutes( clientapi.AddPublicRoutes(
base, m.FedClient, m.RoomserverAPI, m.AppserviceAPI, transactions.New(), processCtx, routers, cfg, natsInstance, m.FedClient, m.RoomserverAPI, m.AppserviceAPI, transactions.New(),
m.FederationAPI, m.UserAPI, userDirectoryProvider, m.FederationAPI, m.UserAPI, userDirectoryProvider,
m.ExtPublicRoomsProvider, m.ExtPublicRoomsProvider, enableMetrics,
) )
federationapi.AddPublicRoutes( federationapi.AddPublicRoutes(
base, m.UserAPI, m.FedClient, m.KeyRing, m.RoomserverAPI, m.FederationAPI, nil, processCtx, routers, cfg, natsInstance, m.UserAPI, m.FedClient, m.KeyRing, m.RoomserverAPI, m.FederationAPI, nil, enableMetrics,
) )
mediaapi.AddPublicRoutes(base, m.UserAPI, m.Client) mediaapi.AddPublicRoutes(routers.Media, cm, cfg, m.UserAPI, m.Client)
syncapi.AddPublicRoutes(base, m.UserAPI, m.RoomserverAPI) syncapi.AddPublicRoutes(processCtx, routers, cfg, cm, natsInstance, m.UserAPI, m.RoomserverAPI, caches, enableMetrics)
if m.RelayAPI != nil { if m.RelayAPI != nil {
relayapi.AddPublicRoutes(base, m.KeyRing, m.RelayAPI) relayapi.AddPublicRoutes(routers, cfg, m.KeyRing, m.RelayAPI)
} }
} }

View file

@ -31,8 +31,9 @@ import (
fs "github.com/matrix-org/dendrite/federationapi/api" fs "github.com/matrix-org/dendrite/federationapi/api"
"github.com/matrix-org/dendrite/internal/hooks" "github.com/matrix-org/dendrite/internal/hooks"
"github.com/matrix-org/dendrite/internal/httputil" "github.com/matrix-org/dendrite/internal/httputil"
"github.com/matrix-org/dendrite/internal/sqlutil"
roomserver "github.com/matrix-org/dendrite/roomserver/api" roomserver "github.com/matrix-org/dendrite/roomserver/api"
"github.com/matrix-org/dendrite/setup/base" "github.com/matrix-org/dendrite/setup/config"
userapi "github.com/matrix-org/dendrite/userapi/api" userapi "github.com/matrix-org/dendrite/userapi/api"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/util" "github.com/matrix-org/util"
@ -99,10 +100,10 @@ func toClientResponse(res *MSC2836EventRelationshipsResponse) *EventRelationship
// Enable this MSC // Enable this MSC
func Enable( func Enable(
base *base.BaseDendrite, rsAPI roomserver.RoomserverInternalAPI, fsAPI fs.FederationInternalAPI, cfg *config.Dendrite, cm sqlutil.Connections, routers httputil.Routers, rsAPI roomserver.RoomserverInternalAPI, fsAPI fs.FederationInternalAPI,
userAPI userapi.UserInternalAPI, keyRing gomatrixserverlib.JSONVerifier, userAPI userapi.UserInternalAPI, keyRing gomatrixserverlib.JSONVerifier,
) error { ) error {
db, err := NewDatabase(base, &base.Cfg.MSCs.Database) db, err := NewDatabase(cm, &cfg.MSCs.Database)
if err != nil { if err != nil {
return fmt.Errorf("cannot enable MSC2836: %w", err) return fmt.Errorf("cannot enable MSC2836: %w", err)
} }
@ -125,14 +126,14 @@ func Enable(
} }
}) })
base.PublicClientAPIMux.Handle("/unstable/event_relationships", routers.Client.Handle("/unstable/event_relationships",
httputil.MakeAuthAPI("eventRelationships", userAPI, eventRelationshipHandler(db, rsAPI, fsAPI)), httputil.MakeAuthAPI("eventRelationships", userAPI, eventRelationshipHandler(db, rsAPI, fsAPI)),
).Methods(http.MethodPost, http.MethodOptions) ).Methods(http.MethodPost, http.MethodOptions)
base.PublicFederationAPIMux.Handle("/unstable/event_relationships", httputil.MakeExternalAPI( routers.Federation.Handle("/unstable/event_relationships", httputil.MakeExternalAPI(
"msc2836_event_relationships", func(req *http.Request) util.JSONResponse { "msc2836_event_relationships", func(req *http.Request) util.JSONResponse {
fedReq, errResp := gomatrixserverlib.VerifyHTTPRequest( fedReq, errResp := gomatrixserverlib.VerifyHTTPRequest(
req, time.Now(), base.Cfg.Global.ServerName, base.Cfg.Global.IsLocalServerName, keyRing, req, time.Now(), cfg.Global.ServerName, cfg.Global.IsLocalServerName, keyRing,
) )
if fedReq == nil { if fedReq == nil {
return errResp return errResp

View file

@ -15,12 +15,13 @@ import (
"time" "time"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/matrix-org/dendrite/setup/process"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/dendrite/internal/hooks" "github.com/matrix-org/dendrite/internal/hooks"
"github.com/matrix-org/dendrite/internal/httputil" "github.com/matrix-org/dendrite/internal/httputil"
"github.com/matrix-org/dendrite/internal/sqlutil"
roomserver "github.com/matrix-org/dendrite/roomserver/api" roomserver "github.com/matrix-org/dendrite/roomserver/api"
"github.com/matrix-org/dendrite/setup/base"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/dendrite/setup/mscs/msc2836" "github.com/matrix-org/dendrite/setup/mscs/msc2836"
userapi "github.com/matrix-org/dendrite/userapi/api" userapi "github.com/matrix-org/dendrite/userapi/api"
@ -554,20 +555,18 @@ func injectEvents(t *testing.T, userAPI userapi.UserInternalAPI, rsAPI roomserve
cfg.Global.ServerName = "localhost" cfg.Global.ServerName = "localhost"
cfg.MSCs.Database.ConnectionString = "file:msc2836_test.db" cfg.MSCs.Database.ConnectionString = "file:msc2836_test.db"
cfg.MSCs.MSCs = []string{"msc2836"} cfg.MSCs.MSCs = []string{"msc2836"}
base := &base.BaseDendrite{
Cfg: cfg,
PublicClientAPIMux: mux.NewRouter().PathPrefix(httputil.PublicClientPathPrefix).Subrouter(),
PublicFederationAPIMux: mux.NewRouter().PathPrefix(httputil.PublicFederationPathPrefix).Subrouter(),
}
err := msc2836.Enable(base, rsAPI, nil, userAPI, nil) processCtx := process.NewProcessContext()
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
routers := httputil.NewRouters()
err := msc2836.Enable(cfg, cm, routers, rsAPI, nil, userAPI, nil)
if err != nil { if err != nil {
t.Fatalf("failed to enable MSC2836: %s", err) t.Fatalf("failed to enable MSC2836: %s", err)
} }
for _, ev := range events { for _, ev := range events {
hooks.Run(hooks.KindNewEventPersisted, ev) hooks.Run(hooks.KindNewEventPersisted, ev)
} }
return base.PublicClientAPIMux return routers.Client
} }
type fledglingEvent struct { type fledglingEvent struct {

View file

@ -8,7 +8,6 @@ import (
"encoding/json" "encoding/json"
"github.com/matrix-org/dendrite/internal/sqlutil" "github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/setup/base"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/util" "github.com/matrix-org/util"
@ -59,17 +58,17 @@ type DB struct {
} }
// NewDatabase loads the database for msc2836 // NewDatabase loads the database for msc2836
func NewDatabase(base *base.BaseDendrite, dbOpts *config.DatabaseOptions) (Database, error) { func NewDatabase(conMan sqlutil.Connections, dbOpts *config.DatabaseOptions) (Database, error) {
if dbOpts.ConnectionString.IsPostgres() { if dbOpts.ConnectionString.IsPostgres() {
return newPostgresDatabase(base, dbOpts) return newPostgresDatabase(conMan, dbOpts)
} }
return newSQLiteDatabase(base, dbOpts) return newSQLiteDatabase(conMan, dbOpts)
} }
func newPostgresDatabase(base *base.BaseDendrite, dbOpts *config.DatabaseOptions) (Database, error) { func newPostgresDatabase(conMan sqlutil.Connections, dbOpts *config.DatabaseOptions) (Database, error) {
d := DB{} d := DB{}
var err error var err error
if d.db, d.writer, err = base.DatabaseConnection(dbOpts, sqlutil.NewDummyWriter()); err != nil { if d.db, d.writer, err = conMan.Connection(dbOpts); err != nil {
return nil, err return nil, err
} }
_, err = d.db.Exec(` _, err = d.db.Exec(`
@ -144,10 +143,10 @@ func newPostgresDatabase(base *base.BaseDendrite, dbOpts *config.DatabaseOptions
return &d, err return &d, err
} }
func newSQLiteDatabase(base *base.BaseDendrite, dbOpts *config.DatabaseOptions) (Database, error) { func newSQLiteDatabase(conMan sqlutil.Connections, dbOpts *config.DatabaseOptions) (Database, error) {
d := DB{} d := DB{}
var err error var err error
if d.db, d.writer, err = base.DatabaseConnection(dbOpts, sqlutil.NewExclusiveWriter()); err != nil { if d.db, d.writer, err = conMan.Connection(dbOpts); err != nil {
return nil, err return nil, err
} }
_, err = d.db.Exec(` _, err = d.db.Exec(`

View file

@ -33,7 +33,7 @@ import (
"github.com/matrix-org/dendrite/internal/caching" "github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/httputil" "github.com/matrix-org/dendrite/internal/httputil"
roomserver "github.com/matrix-org/dendrite/roomserver/api" roomserver "github.com/matrix-org/dendrite/roomserver/api"
"github.com/matrix-org/dendrite/setup/base" "github.com/matrix-org/dendrite/setup/config"
userapi "github.com/matrix-org/dendrite/userapi/api" userapi "github.com/matrix-org/dendrite/userapi/api"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/util" "github.com/matrix-org/util"
@ -54,17 +54,17 @@ type MSC2946ClientResponse struct {
// Enable this MSC // Enable this MSC
func Enable( func Enable(
base *base.BaseDendrite, rsAPI roomserver.RoomserverInternalAPI, userAPI userapi.UserInternalAPI, cfg *config.Dendrite, routers httputil.Routers, rsAPI roomserver.RoomserverInternalAPI, userAPI userapi.UserInternalAPI,
fsAPI fs.FederationInternalAPI, keyRing gomatrixserverlib.JSONVerifier, cache caching.SpaceSummaryRoomsCache, fsAPI fs.FederationInternalAPI, keyRing gomatrixserverlib.JSONVerifier, cache caching.SpaceSummaryRoomsCache,
) error { ) error {
clientAPI := httputil.MakeAuthAPI("spaces", userAPI, spacesHandler(rsAPI, fsAPI, cache, base.Cfg.Global.ServerName), httputil.WithAllowGuests()) clientAPI := httputil.MakeAuthAPI("spaces", userAPI, spacesHandler(rsAPI, fsAPI, cache, cfg.Global.ServerName), httputil.WithAllowGuests())
base.PublicClientAPIMux.Handle("/v1/rooms/{roomID}/hierarchy", clientAPI).Methods(http.MethodGet, http.MethodOptions) routers.Client.Handle("/v1/rooms/{roomID}/hierarchy", clientAPI).Methods(http.MethodGet, http.MethodOptions)
base.PublicClientAPIMux.Handle("/unstable/org.matrix.msc2946/rooms/{roomID}/hierarchy", clientAPI).Methods(http.MethodGet, http.MethodOptions) routers.Client.Handle("/unstable/org.matrix.msc2946/rooms/{roomID}/hierarchy", clientAPI).Methods(http.MethodGet, http.MethodOptions)
fedAPI := httputil.MakeExternalAPI( fedAPI := httputil.MakeExternalAPI(
"msc2946_fed_spaces", func(req *http.Request) util.JSONResponse { "msc2946_fed_spaces", func(req *http.Request) util.JSONResponse {
fedReq, errResp := gomatrixserverlib.VerifyHTTPRequest( fedReq, errResp := gomatrixserverlib.VerifyHTTPRequest(
req, time.Now(), base.Cfg.Global.ServerName, base.Cfg.Global.IsLocalServerName, keyRing, req, time.Now(), cfg.Global.ServerName, cfg.Global.IsLocalServerName, keyRing,
) )
if fedReq == nil { if fedReq == nil {
return errResp return errResp
@ -75,11 +75,11 @@ func Enable(
return util.ErrorResponse(err) return util.ErrorResponse(err)
} }
roomID := params["roomID"] roomID := params["roomID"]
return federatedSpacesHandler(req.Context(), fedReq, roomID, cache, rsAPI, fsAPI, base.Cfg.Global.ServerName) return federatedSpacesHandler(req.Context(), fedReq, roomID, cache, rsAPI, fsAPI, cfg.Global.ServerName)
}, },
) )
base.PublicFederationAPIMux.Handle("/unstable/org.matrix.msc2946/hierarchy/{roomID}", fedAPI).Methods(http.MethodGet) routers.Federation.Handle("/unstable/org.matrix.msc2946/hierarchy/{roomID}", fedAPI).Methods(http.MethodGet)
base.PublicFederationAPIMux.Handle("/v1/hierarchy/{roomID}", fedAPI).Methods(http.MethodGet) routers.Federation.Handle("/v1/hierarchy/{roomID}", fedAPI).Methods(http.MethodGet)
return nil return nil
} }

View file

@ -19,30 +19,33 @@ import (
"context" "context"
"fmt" "fmt"
"github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/httputil"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/setup" "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/mscs/msc2836" "github.com/matrix-org/dendrite/setup/mscs/msc2836"
"github.com/matrix-org/dendrite/setup/mscs/msc2946" "github.com/matrix-org/dendrite/setup/mscs/msc2946"
"github.com/matrix-org/util" "github.com/matrix-org/util"
) )
// Enable MSCs - returns an error on unknown MSCs // Enable MSCs - returns an error on unknown MSCs
func Enable(base *base.BaseDendrite, monolith *setup.Monolith) error { func Enable(cfg *config.Dendrite, cm sqlutil.Connections, routers httputil.Routers, monolith *setup.Monolith, caches *caching.Caches) error {
for _, msc := range base.Cfg.MSCs.MSCs { for _, msc := range cfg.MSCs.MSCs {
util.GetLogger(context.Background()).WithField("msc", msc).Info("Enabling MSC") util.GetLogger(context.Background()).WithField("msc", msc).Info("Enabling MSC")
if err := EnableMSC(base, monolith, msc); err != nil { if err := EnableMSC(cfg, cm, routers, monolith, msc, caches); err != nil {
return err return err
} }
} }
return nil return nil
} }
func EnableMSC(base *base.BaseDendrite, monolith *setup.Monolith, msc string) error { func EnableMSC(cfg *config.Dendrite, cm sqlutil.Connections, routers httputil.Routers, monolith *setup.Monolith, msc string, caches *caching.Caches) error {
switch msc { switch msc {
case "msc2836": case "msc2836":
return msc2836.Enable(base, monolith.RoomserverAPI, monolith.FederationAPI, monolith.UserAPI, monolith.KeyRing) return msc2836.Enable(cfg, cm, routers, monolith.RoomserverAPI, monolith.FederationAPI, monolith.UserAPI, monolith.KeyRing)
case "msc2946": case "msc2946":
return msc2946.Enable(base, monolith.RoomserverAPI, monolith.UserAPI, monolith.FederationAPI, monolith.KeyRing, base.Caches) return msc2946.Enable(cfg, routers, monolith.RoomserverAPI, monolith.UserAPI, monolith.FederationAPI, monolith.KeyRing, caches)
case "msc2444": // enabled inside federationapi case "msc2444": // enabled inside federationapi
case "msc2753": // enabled inside clientapi case "msc2753": // enabled inside clientapi
default: default:

View file

@ -50,7 +50,7 @@ type OutputClientDataConsumer struct {
stream streams.StreamProvider stream streams.StreamProvider
notifier *notifier.Notifier notifier *notifier.Notifier
serverName gomatrixserverlib.ServerName serverName gomatrixserverlib.ServerName
fts *fulltext.Search fts fulltext.Indexer
cfg *config.SyncAPI cfg *config.SyncAPI
} }

View file

@ -51,7 +51,7 @@ type OutputRoomEventConsumer struct {
pduStream streams.StreamProvider pduStream streams.StreamProvider
inviteStream streams.StreamProvider inviteStream streams.StreamProvider
notifier *notifier.Notifier notifier *notifier.Notifier
fts *fulltext.Search fts fulltext.Indexer
} }
// NewOutputRoomEventConsumer creates a new OutputRoomEventConsumer. Call Start() to begin consuming from room servers. // NewOutputRoomEventConsumer creates a new OutputRoomEventConsumer. Call Start() to begin consuming from room servers.

View file

@ -43,7 +43,7 @@ func Setup(
rsAPI api.SyncRoomserverAPI, rsAPI api.SyncRoomserverAPI,
cfg *config.SyncAPI, cfg *config.SyncAPI,
lazyLoadCache caching.LazyLoadCache, lazyLoadCache caching.LazyLoadCache,
fts *fulltext.Search, fts fulltext.Indexer,
) { ) {
v1unstablemux := csMux.PathPrefix("/{apiversion:(?:v1|unstable)}/").Subrouter() v1unstablemux := csMux.PathPrefix("/{apiversion:(?:v1|unstable)}/").Subrouter()
v3mux := csMux.PathPrefix("/{apiversion:(?:r0|v3)}/").Subrouter() v3mux := csMux.PathPrefix("/{apiversion:(?:r0|v3)}/").Subrouter()

View file

@ -37,7 +37,7 @@ import (
) )
// nolint:gocyclo // nolint:gocyclo
func Search(req *http.Request, device *api.Device, syncDB storage.Database, fts *fulltext.Search, from *string) util.JSONResponse { func Search(req *http.Request, device *api.Device, syncDB storage.Database, fts fulltext.Indexer, from *string) util.JSONResponse {
start := time.Now() start := time.Now()
var ( var (
searchReq SearchRequest searchReq SearchRequest

View file

@ -16,12 +16,12 @@
package postgres package postgres
import ( import (
"context"
"database/sql" "database/sql"
// Import the postgres database driver. // Import the postgres database driver.
_ "github.com/lib/pq" _ "github.com/lib/pq"
"github.com/matrix-org/dendrite/internal/sqlutil" "github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/setup/base"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/dendrite/syncapi/storage/postgres/deltas" "github.com/matrix-org/dendrite/syncapi/storage/postgres/deltas"
"github.com/matrix-org/dendrite/syncapi/storage/shared" "github.com/matrix-org/dendrite/syncapi/storage/shared"
@ -36,10 +36,10 @@ type SyncServerDatasource struct {
} }
// NewDatabase creates a new sync server database // NewDatabase creates a new sync server database
func NewDatabase(base *base.BaseDendrite, dbProperties *config.DatabaseOptions) (*SyncServerDatasource, error) { func NewDatabase(ctx context.Context, cm sqlutil.Connections, dbProperties *config.DatabaseOptions) (*SyncServerDatasource, error) {
var d SyncServerDatasource var d SyncServerDatasource
var err error var err error
if d.db, d.writer, err = base.DatabaseConnection(dbProperties, sqlutil.NewDummyWriter()); err != nil { if d.db, d.writer, err = cm.Connection(dbProperties); err != nil {
return nil, err return nil, err
} }
accountData, err := NewPostgresAccountDataTable(d.db) accountData, err := NewPostgresAccountDataTable(d.db)
@ -111,7 +111,7 @@ func NewDatabase(base *base.BaseDendrite, dbProperties *config.DatabaseOptions)
Up: deltas.UpSetHistoryVisibility, // Requires current_room_state and output_room_events to be created. Up: deltas.UpSetHistoryVisibility, // Requires current_room_state and output_room_events to be created.
}, },
) )
err = m.Up(base.Context()) err = m.Up(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -20,7 +20,6 @@ import (
"database/sql" "database/sql"
"github.com/matrix-org/dendrite/internal/sqlutil" "github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/setup/base"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/dendrite/syncapi/storage/shared" "github.com/matrix-org/dendrite/syncapi/storage/shared"
"github.com/matrix-org/dendrite/syncapi/storage/sqlite3/deltas" "github.com/matrix-org/dendrite/syncapi/storage/sqlite3/deltas"
@ -37,13 +36,14 @@ type SyncServerDatasource struct {
// NewDatabase creates a new sync server database // NewDatabase creates a new sync server database
// nolint: gocyclo // nolint: gocyclo
func NewDatabase(base *base.BaseDendrite, dbProperties *config.DatabaseOptions) (*SyncServerDatasource, error) { func NewDatabase(ctx context.Context, conMan sqlutil.Connections, dbProperties *config.DatabaseOptions) (*SyncServerDatasource, error) {
var d SyncServerDatasource var d SyncServerDatasource
var err error var err error
if d.db, d.writer, err = base.DatabaseConnection(dbProperties, sqlutil.NewExclusiveWriter()); err != nil {
if d.db, d.writer, err = conMan.Connection(dbProperties); err != nil {
return nil, err return nil, err
} }
if err = d.prepare(base.Context()); err != nil { if err = d.prepare(ctx); err != nil {
return nil, err return nil, err
} }
return &d, nil return &d, nil

View file

@ -18,21 +18,22 @@
package storage package storage
import ( import (
"context"
"fmt" "fmt"
"github.com/matrix-org/dendrite/setup/base" "github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/dendrite/syncapi/storage/postgres" "github.com/matrix-org/dendrite/syncapi/storage/postgres"
"github.com/matrix-org/dendrite/syncapi/storage/sqlite3" "github.com/matrix-org/dendrite/syncapi/storage/sqlite3"
) )
// NewSyncServerDatasource opens a database connection. // NewSyncServerDatasource opens a database connection.
func NewSyncServerDatasource(base *base.BaseDendrite, dbProperties *config.DatabaseOptions) (Database, error) { func NewSyncServerDatasource(ctx context.Context, conMan sqlutil.Connections, dbProperties *config.DatabaseOptions) (Database, error) {
switch { switch {
case dbProperties.ConnectionString.IsSQLite(): case dbProperties.ConnectionString.IsSQLite():
return sqlite3.NewDatabase(base, dbProperties) return sqlite3.NewDatabase(ctx, conMan, dbProperties)
case dbProperties.ConnectionString.IsPostgres(): case dbProperties.ConnectionString.IsPostgres():
return postgres.NewDatabase(base, dbProperties) return postgres.NewDatabase(ctx, conMan, dbProperties)
default: default:
return nil, fmt.Errorf("unexpected database type") return nil, fmt.Errorf("unexpected database type")
} }

View file

@ -9,27 +9,27 @@ import (
"reflect" "reflect"
"testing" "testing"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/dendrite/syncapi/storage" "github.com/matrix-org/dendrite/syncapi/storage"
"github.com/matrix-org/dendrite/syncapi/types" "github.com/matrix-org/dendrite/syncapi/types"
"github.com/matrix-org/dendrite/test" "github.com/matrix-org/dendrite/test"
"github.com/matrix-org/dendrite/test/testrig"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
var ctx = context.Background() var ctx = context.Background()
func MustCreateDatabase(t *testing.T, dbType test.DBType) (storage.Database, func(), func()) { func MustCreateDatabase(t *testing.T, dbType test.DBType) (storage.Database, func()) {
connStr, close := test.PrepareDBConnectionString(t, dbType) connStr, close := test.PrepareDBConnectionString(t, dbType)
base, closeBase := testrig.CreateBaseDendrite(t, dbType) cm := sqlutil.NewConnectionManager(nil, config.DatabaseOptions{})
db, err := storage.NewSyncServerDatasource(base, &config.DatabaseOptions{ db, err := storage.NewSyncServerDatasource(context.Background(), cm, &config.DatabaseOptions{
ConnectionString: config.DataSource(connStr), ConnectionString: config.DataSource(connStr),
}) })
if err != nil { if err != nil {
t.Fatalf("NewSyncServerDatasource returned %s", err) t.Fatalf("NewSyncServerDatasource returned %s", err)
} }
return db, close, closeBase return db, close
} }
func MustWriteEvents(t *testing.T, db storage.Database, events []*gomatrixserverlib.HeaderedEvent) (positions []types.StreamPosition) { func MustWriteEvents(t *testing.T, db storage.Database, events []*gomatrixserverlib.HeaderedEvent) (positions []types.StreamPosition) {
@ -55,9 +55,8 @@ func TestWriteEvents(t *testing.T) {
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
alice := test.NewUser(t) alice := test.NewUser(t)
r := test.NewRoom(t, alice) r := test.NewRoom(t, alice)
db, close, closeBase := MustCreateDatabase(t, dbType) db, close := MustCreateDatabase(t, dbType)
defer close() defer close()
defer closeBase()
MustWriteEvents(t, db, r.Events()) MustWriteEvents(t, db, r.Events())
}) })
} }
@ -76,9 +75,8 @@ func WithSnapshot(t *testing.T, db storage.Database, f func(snapshot storage.Dat
// These tests assert basic functionality of RecentEvents for PDUs // These tests assert basic functionality of RecentEvents for PDUs
func TestRecentEventsPDU(t *testing.T) { func TestRecentEventsPDU(t *testing.T) {
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
db, close, closeBase := MustCreateDatabase(t, dbType) db, close := MustCreateDatabase(t, dbType)
defer close() defer close()
defer closeBase()
alice := test.NewUser(t) alice := test.NewUser(t)
// dummy room to make sure SQL queries are filtering on room ID // dummy room to make sure SQL queries are filtering on room ID
MustWriteEvents(t, db, test.NewRoom(t, alice).Events()) MustWriteEvents(t, db, test.NewRoom(t, alice).Events())
@ -191,9 +189,8 @@ func TestRecentEventsPDU(t *testing.T) {
// The purpose of this test is to ensure that backfill does indeed go backwards, using a topology token // The purpose of this test is to ensure that backfill does indeed go backwards, using a topology token
func TestGetEventsInRangeWithTopologyToken(t *testing.T) { func TestGetEventsInRangeWithTopologyToken(t *testing.T) {
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
db, close, closeBase := MustCreateDatabase(t, dbType) db, close := MustCreateDatabase(t, dbType)
defer close() defer close()
defer closeBase()
alice := test.NewUser(t) alice := test.NewUser(t)
r := test.NewRoom(t, alice) r := test.NewRoom(t, alice)
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
@ -276,9 +273,8 @@ func TestStreamToTopologicalPosition(t *testing.T) {
} }
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
db, close, closeBase := MustCreateDatabase(t, dbType) db, close := MustCreateDatabase(t, dbType)
defer close() defer close()
defer closeBase()
txn, err := db.NewDatabaseTransaction(ctx) txn, err := db.NewDatabaseTransaction(ctx)
if err != nil { if err != nil {
@ -514,9 +510,8 @@ func TestSendToDeviceBehaviour(t *testing.T) {
bob := test.NewUser(t) bob := test.NewUser(t)
deviceID := "one" deviceID := "one"
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
db, close, closeBase := MustCreateDatabase(t, dbType) db, close := MustCreateDatabase(t, dbType)
defer close() defer close()
defer closeBase()
// At this point there should be no messages. We haven't sent anything // At this point there should be no messages. We haven't sent anything
// yet. // yet.
@ -899,9 +894,8 @@ func TestRoomSummary(t *testing.T) {
} }
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
db, close, closeBase := MustCreateDatabase(t, dbType) db, close := MustCreateDatabase(t, dbType)
defer close() defer close()
defer closeBase()
for _, tc := range testCases { for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
@ -939,11 +933,8 @@ func TestRecentEvents(t *testing.T) {
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
filter := gomatrixserverlib.DefaultRoomEventFilter() filter := gomatrixserverlib.DefaultRoomEventFilter()
db, close, closeBase := MustCreateDatabase(t, dbType) db, close := MustCreateDatabase(t, dbType)
t.Cleanup(func() { t.Cleanup(close)
close()
closeBase()
})
MustWriteEvents(t, db, room1.Events()) MustWriteEvents(t, db, room1.Events())
MustWriteEvents(t, db, room2.Events()) MustWriteEvents(t, db, room2.Events())

View file

@ -15,18 +15,19 @@
package storage package storage
import ( import (
"context"
"fmt" "fmt"
"github.com/matrix-org/dendrite/setup/base" "github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/dendrite/syncapi/storage/sqlite3" "github.com/matrix-org/dendrite/syncapi/storage/sqlite3"
) )
// NewPublicRoomsServerDatabase opens a database connection. // NewPublicRoomsServerDatabase opens a database connection.
func NewSyncServerDatasource(base *base.BaseDendrite, dbProperties *config.DatabaseOptions) (Database, error) { func NewSyncServerDatasource(ctx context.Context, conMan sqlutil.Connections, dbProperties *config.DatabaseOptions) (Database, error) {
switch { switch {
case dbProperties.ConnectionString.IsSQLite(): case dbProperties.ConnectionString.IsSQLite():
return sqlite3.NewDatabase(base, dbProperties) return sqlite3.NewDatabase(ctx, conMan, dbProperties)
case dbProperties.ConnectionString.IsPostgres(): case dbProperties.ConnectionString.IsPostgres():
return nil, fmt.Errorf("can't use Postgres implementation") return nil, fmt.Errorf("can't use Postgres implementation")
default: default:

View file

@ -17,12 +17,16 @@ package syncapi
import ( import (
"context" "context"
"github.com/matrix-org/dendrite/internal/fulltext"
"github.com/matrix-org/dendrite/internal/httputil"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/dendrite/setup/process"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/matrix-org/dendrite/internal/caching" "github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/roomserver/api" "github.com/matrix-org/dendrite/roomserver/api"
"github.com/matrix-org/dendrite/setup/base"
"github.com/matrix-org/dendrite/setup/jetstream" "github.com/matrix-org/dendrite/setup/jetstream"
userapi "github.com/matrix-org/dendrite/userapi/api" userapi "github.com/matrix-org/dendrite/userapi/api"
@ -38,45 +42,58 @@ import (
// AddPublicRoutes sets up and registers HTTP handlers for the SyncAPI // AddPublicRoutes sets up and registers HTTP handlers for the SyncAPI
// component. // component.
func AddPublicRoutes( func AddPublicRoutes(
base *base.BaseDendrite, processContext *process.ProcessContext,
routers httputil.Routers,
dendriteCfg *config.Dendrite,
cm sqlutil.Connections,
natsInstance *jetstream.NATSInstance,
userAPI userapi.SyncUserAPI, userAPI userapi.SyncUserAPI,
rsAPI api.SyncRoomserverAPI, rsAPI api.SyncRoomserverAPI,
caches caching.LazyLoadCache,
enableMetrics bool,
) { ) {
cfg := &base.Cfg.SyncAPI js, natsClient := natsInstance.Prepare(processContext, &dendriteCfg.Global.JetStream)
js, natsClient := base.NATS.Prepare(base.ProcessContext, &cfg.Matrix.JetStream) syncDB, err := storage.NewSyncServerDatasource(processContext.Context(), cm, &dendriteCfg.SyncAPI.Database)
syncDB, err := storage.NewSyncServerDatasource(base, &cfg.Database)
if err != nil { if err != nil {
logrus.WithError(err).Panicf("failed to connect to sync db") logrus.WithError(err).Panicf("failed to connect to sync db")
} }
eduCache := caching.NewTypingCache() eduCache := caching.NewTypingCache()
notifier := notifier.NewNotifier() notifier := notifier.NewNotifier()
streams := streams.NewSyncStreamProviders(syncDB, userAPI, rsAPI, eduCache, base.Caches, notifier) streams := streams.NewSyncStreamProviders(syncDB, userAPI, rsAPI, eduCache, caches, notifier)
notifier.SetCurrentPosition(streams.Latest(context.Background())) notifier.SetCurrentPosition(streams.Latest(context.Background()))
if err = notifier.Load(context.Background(), syncDB); err != nil { if err = notifier.Load(context.Background(), syncDB); err != nil {
logrus.WithError(err).Panicf("failed to load notifier ") logrus.WithError(err).Panicf("failed to load notifier ")
} }
var fts *fulltext.Search
if dendriteCfg.SyncAPI.Fulltext.Enabled {
fts, err = fulltext.New(processContext.Context(), dendriteCfg.SyncAPI.Fulltext)
if err != nil {
logrus.WithError(err).Panicf("failed to create full text")
}
processContext.ComponentStarted()
}
federationPresenceProducer := &producers.FederationAPIPresenceProducer{ federationPresenceProducer := &producers.FederationAPIPresenceProducer{
Topic: cfg.Matrix.JetStream.Prefixed(jetstream.OutputPresenceEvent), Topic: dendriteCfg.Global.JetStream.Prefixed(jetstream.OutputPresenceEvent),
JetStream: js, JetStream: js,
} }
presenceConsumer := consumers.NewPresenceConsumer( presenceConsumer := consumers.NewPresenceConsumer(
base.ProcessContext, cfg, js, natsClient, syncDB, processContext, &dendriteCfg.SyncAPI, js, natsClient, syncDB,
notifier, streams.PresenceStreamProvider, notifier, streams.PresenceStreamProvider,
userAPI, userAPI,
) )
requestPool := sync.NewRequestPool(syncDB, cfg, userAPI, rsAPI, streams, notifier, federationPresenceProducer, presenceConsumer, base.EnableMetrics) requestPool := sync.NewRequestPool(syncDB, &dendriteCfg.SyncAPI, userAPI, rsAPI, streams, notifier, federationPresenceProducer, presenceConsumer, enableMetrics)
if err = presenceConsumer.Start(); err != nil { if err = presenceConsumer.Start(); err != nil {
logrus.WithError(err).Panicf("failed to start presence consumer") logrus.WithError(err).Panicf("failed to start presence consumer")
} }
keyChangeConsumer := consumers.NewOutputKeyChangeEventConsumer( keyChangeConsumer := consumers.NewOutputKeyChangeEventConsumer(
base.ProcessContext, cfg, cfg.Matrix.JetStream.Prefixed(jetstream.OutputKeyChangeEvent), processContext, &dendriteCfg.SyncAPI, dendriteCfg.Global.JetStream.Prefixed(jetstream.OutputKeyChangeEvent),
js, rsAPI, syncDB, notifier, js, rsAPI, syncDB, notifier,
streams.DeviceListStreamProvider, streams.DeviceListStreamProvider,
) )
@ -85,51 +102,51 @@ func AddPublicRoutes(
} }
roomConsumer := consumers.NewOutputRoomEventConsumer( roomConsumer := consumers.NewOutputRoomEventConsumer(
base.ProcessContext, cfg, js, syncDB, notifier, streams.PDUStreamProvider, processContext, &dendriteCfg.SyncAPI, js, syncDB, notifier, streams.PDUStreamProvider,
streams.InviteStreamProvider, rsAPI, base.Fulltext, streams.InviteStreamProvider, rsAPI, fts,
) )
if err = roomConsumer.Start(); err != nil { if err = roomConsumer.Start(); err != nil {
logrus.WithError(err).Panicf("failed to start room server consumer") logrus.WithError(err).Panicf("failed to start room server consumer")
} }
clientConsumer := consumers.NewOutputClientDataConsumer( clientConsumer := consumers.NewOutputClientDataConsumer(
base.ProcessContext, cfg, js, natsClient, syncDB, notifier, processContext, &dendriteCfg.SyncAPI, js, natsClient, syncDB, notifier,
streams.AccountDataStreamProvider, base.Fulltext, streams.AccountDataStreamProvider, fts,
) )
if err = clientConsumer.Start(); err != nil { if err = clientConsumer.Start(); err != nil {
logrus.WithError(err).Panicf("failed to start client data consumer") logrus.WithError(err).Panicf("failed to start client data consumer")
} }
notificationConsumer := consumers.NewOutputNotificationDataConsumer( notificationConsumer := consumers.NewOutputNotificationDataConsumer(
base.ProcessContext, cfg, js, syncDB, notifier, streams.NotificationDataStreamProvider, processContext, &dendriteCfg.SyncAPI, js, syncDB, notifier, streams.NotificationDataStreamProvider,
) )
if err = notificationConsumer.Start(); err != nil { if err = notificationConsumer.Start(); err != nil {
logrus.WithError(err).Panicf("failed to start notification data consumer") logrus.WithError(err).Panicf("failed to start notification data consumer")
} }
typingConsumer := consumers.NewOutputTypingEventConsumer( typingConsumer := consumers.NewOutputTypingEventConsumer(
base.ProcessContext, cfg, js, eduCache, notifier, streams.TypingStreamProvider, processContext, &dendriteCfg.SyncAPI, js, eduCache, notifier, streams.TypingStreamProvider,
) )
if err = typingConsumer.Start(); err != nil { if err = typingConsumer.Start(); err != nil {
logrus.WithError(err).Panicf("failed to start typing consumer") logrus.WithError(err).Panicf("failed to start typing consumer")
} }
sendToDeviceConsumer := consumers.NewOutputSendToDeviceEventConsumer( sendToDeviceConsumer := consumers.NewOutputSendToDeviceEventConsumer(
base.ProcessContext, cfg, js, syncDB, userAPI, notifier, streams.SendToDeviceStreamProvider, processContext, &dendriteCfg.SyncAPI, js, syncDB, userAPI, notifier, streams.SendToDeviceStreamProvider,
) )
if err = sendToDeviceConsumer.Start(); err != nil { if err = sendToDeviceConsumer.Start(); err != nil {
logrus.WithError(err).Panicf("failed to start send-to-device consumer") logrus.WithError(err).Panicf("failed to start send-to-device consumer")
} }
receiptConsumer := consumers.NewOutputReceiptEventConsumer( receiptConsumer := consumers.NewOutputReceiptEventConsumer(
base.ProcessContext, cfg, js, syncDB, notifier, streams.ReceiptStreamProvider, processContext, &dendriteCfg.SyncAPI, js, syncDB, notifier, streams.ReceiptStreamProvider,
) )
if err = receiptConsumer.Start(); err != nil { if err = receiptConsumer.Start(); err != nil {
logrus.WithError(err).Panicf("failed to start receipts consumer") logrus.WithError(err).Panicf("failed to start receipts consumer")
} }
routing.Setup( routing.Setup(
base.PublicClientAPIMux, requestPool, syncDB, userAPI, routers.Client, requestPool, syncDB, userAPI,
rsAPI, cfg, base.Caches, base.Fulltext, rsAPI, &dendriteCfg.SyncAPI, caches, fts,
) )
} }

View file

@ -10,6 +10,10 @@ import (
"testing" "testing"
"time" "time"
"github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/httputil"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/nats-io/nats.go" "github.com/nats-io/nats.go"
"github.com/tidwall/gjson" "github.com/tidwall/gjson"
@ -21,7 +25,6 @@ import (
"github.com/matrix-org/dendrite/roomserver" "github.com/matrix-org/dendrite/roomserver"
"github.com/matrix-org/dendrite/roomserver/api" "github.com/matrix-org/dendrite/roomserver/api"
rsapi "github.com/matrix-org/dendrite/roomserver/api" rsapi "github.com/matrix-org/dendrite/roomserver/api"
"github.com/matrix-org/dendrite/setup/base"
"github.com/matrix-org/dendrite/setup/jetstream" "github.com/matrix-org/dendrite/setup/jetstream"
"github.com/matrix-org/dendrite/syncapi/types" "github.com/matrix-org/dendrite/syncapi/types"
"github.com/matrix-org/dendrite/test" "github.com/matrix-org/dendrite/test"
@ -113,13 +116,17 @@ func testSyncAccessTokens(t *testing.T, dbType test.DBType) {
AccountType: userapi.AccountTypeUser, AccountType: userapi.AccountTypeUser,
} }
base, close := testrig.CreateBaseDendrite(t, dbType) cfg, processCtx, close := testrig.CreateConfig(t, dbType)
routers := httputil.NewRouters()
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
natsInstance := jetstream.NATSInstance{}
defer close() defer close()
jsctx, _ := base.NATS.Prepare(base.ProcessContext, &base.Cfg.Global.JetStream) jsctx, _ := natsInstance.Prepare(processCtx, &cfg.Global.JetStream)
defer jetstream.DeleteAllStreams(jsctx, &base.Cfg.Global.JetStream) defer jetstream.DeleteAllStreams(jsctx, &cfg.Global.JetStream)
msgs := toNATSMsgs(t, base, room.Events()...) msgs := toNATSMsgs(t, cfg, room.Events()...)
AddPublicRoutes(base, &syncUserAPI{accounts: []userapi.Device{alice}}, &syncRoomserverAPI{rooms: []*test.Room{room}}) AddPublicRoutes(processCtx, routers, cfg, cm, &natsInstance, &syncUserAPI{accounts: []userapi.Device{alice}}, &syncRoomserverAPI{rooms: []*test.Room{room}}, caches, caching.DisableMetrics)
testrig.MustPublishMsgs(t, jsctx, msgs...) testrig.MustPublishMsgs(t, jsctx, msgs...)
testCases := []struct { testCases := []struct {
@ -154,7 +161,7 @@ func testSyncAccessTokens(t *testing.T, dbType test.DBType) {
}, },
} }
syncUntil(t, base, alice.AccessToken, false, func(syncBody string) bool { syncUntil(t, routers, alice.AccessToken, false, func(syncBody string) bool {
// wait for the last sent eventID to come down sync // wait for the last sent eventID to come down sync
path := fmt.Sprintf(`rooms.join.%s.timeline.events.#(event_id=="%s")`, room.ID, room.Events()[len(room.Events())-1].EventID()) path := fmt.Sprintf(`rooms.join.%s.timeline.events.#(event_id=="%s")`, room.ID, room.Events()[len(room.Events())-1].EventID())
return gjson.Get(syncBody, path).Exists() return gjson.Get(syncBody, path).Exists()
@ -162,7 +169,7 @@ func testSyncAccessTokens(t *testing.T, dbType test.DBType) {
for _, tc := range testCases { for _, tc := range testCases {
w := httptest.NewRecorder() w := httptest.NewRecorder()
base.PublicClientAPIMux.ServeHTTP(w, tc.req) routers.Client.ServeHTTP(w, tc.req)
if w.Code != tc.wantCode { if w.Code != tc.wantCode {
t.Fatalf("%s: got HTTP %d want %d", tc.name, w.Code, tc.wantCode) t.Fatalf("%s: got HTTP %d want %d", tc.name, w.Code, tc.wantCode)
} }
@ -205,25 +212,29 @@ func testSyncAPICreateRoomSyncEarly(t *testing.T, dbType test.DBType) {
AccountType: userapi.AccountTypeUser, AccountType: userapi.AccountTypeUser,
} }
base, close := testrig.CreateBaseDendrite(t, dbType) cfg, processCtx, close := testrig.CreateConfig(t, dbType)
routers := httputil.NewRouters()
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
defer close() defer close()
natsInstance := jetstream.NATSInstance{}
jsctx, _ := base.NATS.Prepare(base.ProcessContext, &base.Cfg.Global.JetStream) jsctx, _ := natsInstance.Prepare(processCtx, &cfg.Global.JetStream)
defer jetstream.DeleteAllStreams(jsctx, &base.Cfg.Global.JetStream) defer jetstream.DeleteAllStreams(jsctx, &cfg.Global.JetStream)
// order is: // order is:
// m.room.create // m.room.create
// m.room.member // m.room.member
// m.room.power_levels // m.room.power_levels
// m.room.join_rules // m.room.join_rules
// m.room.history_visibility // m.room.history_visibility
msgs := toNATSMsgs(t, base, room.Events()...) msgs := toNATSMsgs(t, cfg, room.Events()...)
sinceTokens := make([]string, len(msgs)) sinceTokens := make([]string, len(msgs))
AddPublicRoutes(base, &syncUserAPI{accounts: []userapi.Device{alice}}, &syncRoomserverAPI{rooms: []*test.Room{room}}) AddPublicRoutes(processCtx, routers, cfg, cm, &natsInstance, &syncUserAPI{accounts: []userapi.Device{alice}}, &syncRoomserverAPI{rooms: []*test.Room{room}}, caches, caching.DisableMetrics)
for i, msg := range msgs { for i, msg := range msgs {
testrig.MustPublishMsgs(t, jsctx, msg) testrig.MustPublishMsgs(t, jsctx, msg)
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
w := httptest.NewRecorder() w := httptest.NewRecorder()
base.PublicClientAPIMux.ServeHTTP(w, test.NewRequest(t, "GET", "/_matrix/client/v3/sync", test.WithQueryParams(map[string]string{ routers.Client.ServeHTTP(w, test.NewRequest(t, "GET", "/_matrix/client/v3/sync", test.WithQueryParams(map[string]string{
"access_token": alice.AccessToken, "access_token": alice.AccessToken,
"timeout": "0", "timeout": "0",
}))) })))
@ -253,7 +264,7 @@ func testSyncAPICreateRoomSyncEarly(t *testing.T, dbType test.DBType) {
t.Logf("waited for events to be consumed; syncing with %v", sinceTokens) t.Logf("waited for events to be consumed; syncing with %v", sinceTokens)
for i, since := range sinceTokens { for i, since := range sinceTokens {
w := httptest.NewRecorder() w := httptest.NewRecorder()
base.PublicClientAPIMux.ServeHTTP(w, test.NewRequest(t, "GET", "/_matrix/client/v3/sync", test.WithQueryParams(map[string]string{ routers.Client.ServeHTTP(w, test.NewRequest(t, "GET", "/_matrix/client/v3/sync", test.WithQueryParams(map[string]string{
"access_token": alice.AccessToken, "access_token": alice.AccessToken,
"timeout": "0", "timeout": "0",
"since": since, "since": since,
@ -295,16 +306,20 @@ func testSyncAPIUpdatePresenceImmediately(t *testing.T, dbType test.DBType) {
AccountType: userapi.AccountTypeUser, AccountType: userapi.AccountTypeUser,
} }
base, close := testrig.CreateBaseDendrite(t, dbType) cfg, processCtx, close := testrig.CreateConfig(t, dbType)
base.Cfg.Global.Presence.EnableOutbound = true routers := httputil.NewRouters()
base.Cfg.Global.Presence.EnableInbound = true cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
cfg.Global.Presence.EnableOutbound = true
cfg.Global.Presence.EnableInbound = true
defer close() defer close()
natsInstance := jetstream.NATSInstance{}
jsctx, _ := base.NATS.Prepare(base.ProcessContext, &base.Cfg.Global.JetStream) jsctx, _ := natsInstance.Prepare(processCtx, &cfg.Global.JetStream)
defer jetstream.DeleteAllStreams(jsctx, &base.Cfg.Global.JetStream) defer jetstream.DeleteAllStreams(jsctx, &cfg.Global.JetStream)
AddPublicRoutes(base, &syncUserAPI{accounts: []userapi.Device{alice}}, &syncRoomserverAPI{}) AddPublicRoutes(processCtx, routers, cfg, cm, &natsInstance, &syncUserAPI{accounts: []userapi.Device{alice}}, &syncRoomserverAPI{}, caches, caching.DisableMetrics)
w := httptest.NewRecorder() w := httptest.NewRecorder()
base.PublicClientAPIMux.ServeHTTP(w, test.NewRequest(t, "GET", "/_matrix/client/v3/sync", test.WithQueryParams(map[string]string{ routers.Client.ServeHTTP(w, test.NewRequest(t, "GET", "/_matrix/client/v3/sync", test.WithQueryParams(map[string]string{
"access_token": alice.AccessToken, "access_token": alice.AccessToken,
"timeout": "0", "timeout": "0",
"set_presence": "online", "set_presence": "online",
@ -410,17 +425,20 @@ func testHistoryVisibility(t *testing.T, dbType test.DBType) {
userType = "real user" userType = "real user"
} }
base, close := testrig.CreateBaseDendrite(t, dbType) cfg, processCtx, close := testrig.CreateConfig(t, dbType)
routers := httputil.NewRouters()
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
defer close() defer close()
natsInstance := jetstream.NATSInstance{}
jsctx, _ := base.NATS.Prepare(base.ProcessContext, &base.Cfg.Global.JetStream) jsctx, _ := natsInstance.Prepare(processCtx, &cfg.Global.JetStream)
defer jetstream.DeleteAllStreams(jsctx, &base.Cfg.Global.JetStream) defer jetstream.DeleteAllStreams(jsctx, &cfg.Global.JetStream)
// Use the actual internal roomserver API // Use the actual internal roomserver API
rsAPI := roomserver.NewInternalAPI(base) rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
rsAPI.SetFederationAPI(nil, nil) rsAPI.SetFederationAPI(nil, nil)
AddPublicRoutes(processCtx, routers, cfg, cm, &natsInstance, &syncUserAPI{accounts: []userapi.Device{aliceDev, bobDev}}, rsAPI, caches, caching.DisableMetrics)
AddPublicRoutes(base, &syncUserAPI{accounts: []userapi.Device{aliceDev, bobDev}}, rsAPI)
for _, tc := range testCases { for _, tc := range testCases {
testname := fmt.Sprintf("%s - %s", tc.historyVisibility, userType) testname := fmt.Sprintf("%s - %s", tc.historyVisibility, userType)
@ -435,7 +453,7 @@ func testHistoryVisibility(t *testing.T, dbType test.DBType) {
if err := api.SendEvents(ctx, rsAPI, api.KindNew, eventsToSend, "test", "test", "test", nil, false); err != nil { if err := api.SendEvents(ctx, rsAPI, api.KindNew, eventsToSend, "test", "test", "test", nil, false); err != nil {
t.Fatalf("failed to send events: %v", err) t.Fatalf("failed to send events: %v", err)
} }
syncUntil(t, base, aliceDev.AccessToken, false, syncUntil(t, routers, aliceDev.AccessToken, false,
func(syncBody string) bool { func(syncBody string) bool {
path := fmt.Sprintf(`rooms.join.%s.timeline.events.#(content.body=="%s")`, room.ID, beforeJoinBody) path := fmt.Sprintf(`rooms.join.%s.timeline.events.#(content.body=="%s")`, room.ID, beforeJoinBody)
return gjson.Get(syncBody, path).Exists() return gjson.Get(syncBody, path).Exists()
@ -444,7 +462,7 @@ func testHistoryVisibility(t *testing.T, dbType test.DBType) {
// There is only one event, we expect only to be able to see this, if the room is world_readable // There is only one event, we expect only to be able to see this, if the room is world_readable
w := httptest.NewRecorder() w := httptest.NewRecorder()
base.PublicClientAPIMux.ServeHTTP(w, test.NewRequest(t, "GET", fmt.Sprintf("/_matrix/client/v3/rooms/%s/messages", room.ID), test.WithQueryParams(map[string]string{ routers.Client.ServeHTTP(w, test.NewRequest(t, "GET", fmt.Sprintf("/_matrix/client/v3/rooms/%s/messages", room.ID), test.WithQueryParams(map[string]string{
"access_token": bobDev.AccessToken, "access_token": bobDev.AccessToken,
"dir": "b", "dir": "b",
"filter": `{"lazy_load_members":true}`, // check that lazy loading doesn't break history visibility "filter": `{"lazy_load_members":true}`, // check that lazy loading doesn't break history visibility
@ -475,7 +493,7 @@ func testHistoryVisibility(t *testing.T, dbType test.DBType) {
if err := api.SendEvents(ctx, rsAPI, api.KindNew, eventsToSend, "test", "test", "test", nil, false); err != nil { if err := api.SendEvents(ctx, rsAPI, api.KindNew, eventsToSend, "test", "test", "test", nil, false); err != nil {
t.Fatalf("failed to send events: %v", err) t.Fatalf("failed to send events: %v", err)
} }
syncUntil(t, base, aliceDev.AccessToken, false, syncUntil(t, routers, aliceDev.AccessToken, false,
func(syncBody string) bool { func(syncBody string) bool {
path := fmt.Sprintf(`rooms.join.%s.timeline.events.#(content.body=="%s")`, room.ID, afterJoinBody) path := fmt.Sprintf(`rooms.join.%s.timeline.events.#(content.body=="%s")`, room.ID, afterJoinBody)
return gjson.Get(syncBody, path).Exists() return gjson.Get(syncBody, path).Exists()
@ -484,7 +502,7 @@ func testHistoryVisibility(t *testing.T, dbType test.DBType) {
// Verify the messages after/before invite are visible or not // Verify the messages after/before invite are visible or not
w = httptest.NewRecorder() w = httptest.NewRecorder()
base.PublicClientAPIMux.ServeHTTP(w, test.NewRequest(t, "GET", fmt.Sprintf("/_matrix/client/v3/rooms/%s/messages", room.ID), test.WithQueryParams(map[string]string{ routers.Client.ServeHTTP(w, test.NewRequest(t, "GET", fmt.Sprintf("/_matrix/client/v3/rooms/%s/messages", room.ID), test.WithQueryParams(map[string]string{
"access_token": bobDev.AccessToken, "access_token": bobDev.AccessToken,
"dir": "b", "dir": "b",
}))) })))
@ -710,17 +728,20 @@ func TestGetMembership(t *testing.T) {
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
base, close := testrig.CreateBaseDendrite(t, dbType) cfg, processCtx, close := testrig.CreateConfig(t, dbType)
routers := httputil.NewRouters()
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
defer close() defer close()
natsInstance := jetstream.NATSInstance{}
jsctx, _ := base.NATS.Prepare(base.ProcessContext, &base.Cfg.Global.JetStream) jsctx, _ := natsInstance.Prepare(processCtx, &cfg.Global.JetStream)
defer jetstream.DeleteAllStreams(jsctx, &base.Cfg.Global.JetStream) defer jetstream.DeleteAllStreams(jsctx, &cfg.Global.JetStream)
// Use an actual roomserver for this // Use an actual roomserver for this
rsAPI := roomserver.NewInternalAPI(base) rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
rsAPI.SetFederationAPI(nil, nil) rsAPI.SetFederationAPI(nil, nil)
AddPublicRoutes(base, &syncUserAPI{accounts: []userapi.Device{aliceDev, bobDev}}, rsAPI) AddPublicRoutes(processCtx, routers, cfg, cm, &natsInstance, &syncUserAPI{accounts: []userapi.Device{aliceDev, bobDev}}, rsAPI, caches, caching.DisableMetrics)
for _, tc := range testCases { for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
@ -740,7 +761,7 @@ func TestGetMembership(t *testing.T) {
if tc.useSleep { if tc.useSleep {
time.Sleep(time.Millisecond * 100) time.Sleep(time.Millisecond * 100)
} else { } else {
syncUntil(t, base, aliceDev.AccessToken, false, func(syncBody string) bool { syncUntil(t, routers, aliceDev.AccessToken, false, func(syncBody string) bool {
// wait for the last sent eventID to come down sync // wait for the last sent eventID to come down sync
path := fmt.Sprintf(`rooms.join.%s.timeline.events.#(event_id=="%s")`, room.ID, room.Events()[len(room.Events())-1].EventID()) path := fmt.Sprintf(`rooms.join.%s.timeline.events.#(event_id=="%s")`, room.ID, room.Events()[len(room.Events())-1].EventID())
return gjson.Get(syncBody, path).Exists() return gjson.Get(syncBody, path).Exists()
@ -748,7 +769,7 @@ func TestGetMembership(t *testing.T) {
} }
w := httptest.NewRecorder() w := httptest.NewRecorder()
base.PublicClientAPIMux.ServeHTTP(w, tc.request(t, room)) routers.Client.ServeHTTP(w, tc.request(t, room))
if w.Code != 200 && tc.wantOK { if w.Code != 200 && tc.wantOK {
t.Logf("%s", w.Body.String()) t.Logf("%s", w.Body.String())
t.Fatalf("got HTTP %d want %d", w.Code, 200) t.Fatalf("got HTTP %d want %d", w.Code, 200)
@ -781,16 +802,19 @@ func testSendToDevice(t *testing.T, dbType test.DBType) {
AccountType: userapi.AccountTypeUser, AccountType: userapi.AccountTypeUser,
} }
base, baseClose := testrig.CreateBaseDendrite(t, dbType) cfg, processCtx, close := testrig.CreateConfig(t, dbType)
defer baseClose() routers := httputil.NewRouters()
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
defer close()
natsInstance := jetstream.NATSInstance{}
jsctx, _ := base.NATS.Prepare(base.ProcessContext, &base.Cfg.Global.JetStream) jsctx, _ := natsInstance.Prepare(processCtx, &cfg.Global.JetStream)
defer jetstream.DeleteAllStreams(jsctx, &base.Cfg.Global.JetStream) defer jetstream.DeleteAllStreams(jsctx, &cfg.Global.JetStream)
AddPublicRoutes(processCtx, routers, cfg, cm, &natsInstance, &syncUserAPI{accounts: []userapi.Device{alice}}, &syncRoomserverAPI{}, caches, caching.DisableMetrics)
AddPublicRoutes(base, &syncUserAPI{accounts: []userapi.Device{alice}}, &syncRoomserverAPI{})
producer := producers.SyncAPIProducer{ producer := producers.SyncAPIProducer{
TopicSendToDeviceEvent: base.Cfg.Global.JetStream.Prefixed(jetstream.OutputSendToDeviceEvent), TopicSendToDeviceEvent: cfg.Global.JetStream.Prefixed(jetstream.OutputSendToDeviceEvent),
JetStream: jsctx, JetStream: jsctx,
} }
@ -876,7 +900,7 @@ func testSendToDevice(t *testing.T, dbType test.DBType) {
} }
} }
syncUntil(t, base, alice.AccessToken, syncUntil(t, routers, alice.AccessToken,
len(tc.want) == 0, len(tc.want) == 0,
func(body string) bool { func(body string) bool {
return gjson.Get(body, fmt.Sprintf(`to_device.events.#(content.dummy=="message %d")`, msgCounter)).Exists() return gjson.Get(body, fmt.Sprintf(`to_device.events.#(content.dummy=="message %d")`, msgCounter)).Exists()
@ -885,7 +909,7 @@ func testSendToDevice(t *testing.T, dbType test.DBType) {
// Execute a /sync request, recording the response // Execute a /sync request, recording the response
w := httptest.NewRecorder() w := httptest.NewRecorder()
base.PublicClientAPIMux.ServeHTTP(w, test.NewRequest(t, "GET", "/_matrix/client/v3/sync", test.WithQueryParams(map[string]string{ routers.Client.ServeHTTP(w, test.NewRequest(t, "GET", "/_matrix/client/v3/sync", test.WithQueryParams(map[string]string{
"access_token": alice.AccessToken, "access_token": alice.AccessToken,
"since": tc.since, "since": tc.since,
}))) })))
@ -999,14 +1023,18 @@ func testContext(t *testing.T, dbType test.DBType) {
AccountType: userapi.AccountTypeUser, AccountType: userapi.AccountTypeUser,
} }
base, baseClose := testrig.CreateBaseDendrite(t, dbType) cfg, processCtx, close := testrig.CreateConfig(t, dbType)
defer baseClose() routers := httputil.NewRouters()
cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
caches := caching.NewRistrettoCache(128*1024*1024, time.Hour, caching.DisableMetrics)
defer close()
// Use an actual roomserver for this // Use an actual roomserver for this
rsAPI := roomserver.NewInternalAPI(base) natsInstance := jetstream.NATSInstance{}
rsAPI := roomserver.NewInternalAPI(processCtx, cfg, cm, &natsInstance, caches, caching.DisableMetrics)
rsAPI.SetFederationAPI(nil, nil) rsAPI.SetFederationAPI(nil, nil)
AddPublicRoutes(base, &syncUserAPI{accounts: []userapi.Device{alice}}, rsAPI) AddPublicRoutes(processCtx, routers, cfg, cm, &natsInstance, &syncUserAPI{accounts: []userapi.Device{alice}}, rsAPI, caches, caching.DisableMetrics)
room := test.NewRoom(t, user) room := test.NewRoom(t, user)
@ -1019,10 +1047,10 @@ func testContext(t *testing.T, dbType test.DBType) {
t.Fatalf("failed to send events: %v", err) t.Fatalf("failed to send events: %v", err)
} }
jsctx, _ := base.NATS.Prepare(base.ProcessContext, &base.Cfg.Global.JetStream) jsctx, _ := natsInstance.Prepare(processCtx, &cfg.Global.JetStream)
defer jetstream.DeleteAllStreams(jsctx, &base.Cfg.Global.JetStream) defer jetstream.DeleteAllStreams(jsctx, &cfg.Global.JetStream)
syncUntil(t, base, alice.AccessToken, false, func(syncBody string) bool { syncUntil(t, routers, alice.AccessToken, false, func(syncBody string) bool {
// wait for the last sent eventID to come down sync // wait for the last sent eventID to come down sync
path := fmt.Sprintf(`rooms.join.%s.timeline.events.#(event_id=="%s")`, room.ID, thirdMsg.EventID()) path := fmt.Sprintf(`rooms.join.%s.timeline.events.#(event_id=="%s")`, room.ID, thirdMsg.EventID())
return gjson.Get(syncBody, path).Exists() return gjson.Get(syncBody, path).Exists()
@ -1049,7 +1077,7 @@ func testContext(t *testing.T, dbType test.DBType) {
params[k] = v params[k] = v
} }
} }
base.PublicClientAPIMux.ServeHTTP(w, test.NewRequest(t, "GET", requestPath, test.WithQueryParams(params))) routers.Client.ServeHTTP(w, test.NewRequest(t, "GET", requestPath, test.WithQueryParams(params)))
if tc.wantError && w.Code == 200 { if tc.wantError && w.Code == 200 {
t.Fatalf("Expected an error, but got none") t.Fatalf("Expected an error, but got none")
@ -1137,9 +1165,10 @@ func TestUpdateRelations(t *testing.T) {
room := test.NewRoom(t, alice) room := test.NewRoom(t, alice)
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) { test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
base, shutdownBase := testrig.CreateBaseDendrite(t, dbType) cfg, processCtx, close := testrig.CreateConfig(t, dbType)
t.Cleanup(shutdownBase) cm := sqlutil.NewConnectionManager(processCtx, cfg.Global.DatabaseOptions)
db, err := storage.NewSyncServerDatasource(base, &base.Cfg.SyncAPI.Database) t.Cleanup(close)
db, err := storage.NewSyncServerDatasource(processCtx.Context(), cm, &cfg.SyncAPI.Database)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -1161,10 +1190,11 @@ func TestUpdateRelations(t *testing.T) {
} }
func syncUntil(t *testing.T, func syncUntil(t *testing.T,
base *base.BaseDendrite, accessToken string, routers httputil.Routers, accessToken string,
skip bool, skip bool,
checkFunc func(syncBody string) bool, checkFunc func(syncBody string) bool,
) { ) {
t.Helper()
if checkFunc == nil { if checkFunc == nil {
t.Fatalf("No checkFunc defined") t.Fatalf("No checkFunc defined")
} }
@ -1178,7 +1208,7 @@ func syncUntil(t *testing.T,
go func() { go func() {
for { for {
w := httptest.NewRecorder() w := httptest.NewRecorder()
base.PublicClientAPIMux.ServeHTTP(w, test.NewRequest(t, "GET", "/_matrix/client/v3/sync", test.WithQueryParams(map[string]string{ routers.Client.ServeHTTP(w, test.NewRequest(t, "GET", "/_matrix/client/v3/sync", test.WithQueryParams(map[string]string{
"access_token": accessToken, "access_token": accessToken,
"timeout": "1000", "timeout": "1000",
}))) })))
@ -1196,14 +1226,14 @@ func syncUntil(t *testing.T,
} }
} }
func toNATSMsgs(t *testing.T, base *base.BaseDendrite, input ...*gomatrixserverlib.HeaderedEvent) []*nats.Msg { func toNATSMsgs(t *testing.T, cfg *config.Dendrite, input ...*gomatrixserverlib.HeaderedEvent) []*nats.Msg {
result := make([]*nats.Msg, len(input)) result := make([]*nats.Msg, len(input))
for i, ev := range input { for i, ev := range input {
var addsStateIDs []string var addsStateIDs []string
if ev.StateKey() != nil { if ev.StateKey() != nil {
addsStateIDs = append(addsStateIDs, ev.EventID()) addsStateIDs = append(addsStateIDs, ev.EventID())
} }
result[i] = testrig.NewOutputEventMsg(t, base, ev.RoomID(), api.OutputEvent{ result[i] = testrig.NewOutputEventMsg(t, cfg, ev.RoomID(), api.OutputEvent{
Type: rsapi.OutputTypeNewRoomEvent, Type: rsapi.OutputTypeNewRoomEvent,
NewRoomEvent: &rsapi.OutputNewRoomEvent{ NewRoomEvent: &rsapi.OutputNewRoomEvent{
Event: ev, Event: ev,

View file

@ -19,13 +19,12 @@ import (
"path/filepath" "path/filepath"
"testing" "testing"
"github.com/matrix-org/dendrite/setup/base"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/dendrite/setup/process"
"github.com/matrix-org/dendrite/test" "github.com/matrix-org/dendrite/test"
"github.com/nats-io/nats.go"
) )
func CreateBaseDendrite(t *testing.T, dbType test.DBType) (*base.BaseDendrite, func()) { func CreateConfig(t *testing.T, dbType test.DBType) (*config.Dendrite, *process.ProcessContext, func()) {
var cfg config.Dendrite var cfg config.Dendrite
cfg.Defaults(config.DefaultOpts{ cfg.Defaults(config.DefaultOpts{
Generate: false, Generate: false,
@ -33,6 +32,7 @@ func CreateBaseDendrite(t *testing.T, dbType test.DBType) (*base.BaseDendrite, f
}) })
cfg.Global.JetStream.InMemory = true cfg.Global.JetStream.InMemory = true
cfg.FederationAPI.KeyPerspectives = nil cfg.FederationAPI.KeyPerspectives = nil
ctx := process.NewProcessContext()
switch dbType { switch dbType {
case test.DBTypePostgres: case test.DBTypePostgres:
cfg.Global.Defaults(config.DefaultOpts{ // autogen a signing key cfg.Global.Defaults(config.DefaultOpts{ // autogen a signing key
@ -51,18 +51,18 @@ func CreateBaseDendrite(t *testing.T, dbType test.DBType) (*base.BaseDendrite, f
// use a distinct prefix else concurrent postgres/sqlite runs will clash since NATS will use // use a distinct prefix else concurrent postgres/sqlite runs will clash since NATS will use
// the file system event with InMemory=true :( // the file system event with InMemory=true :(
cfg.Global.JetStream.TopicPrefix = fmt.Sprintf("Test_%d_", dbType) cfg.Global.JetStream.TopicPrefix = fmt.Sprintf("Test_%d_", dbType)
connStr, close := test.PrepareDBConnectionString(t, dbType)
connStr, closeDb := test.PrepareDBConnectionString(t, dbType)
cfg.Global.DatabaseOptions = config.DatabaseOptions{ cfg.Global.DatabaseOptions = config.DatabaseOptions{
ConnectionString: config.DataSource(connStr), ConnectionString: config.DataSource(connStr),
MaxOpenConnections: 10, MaxOpenConnections: 10,
MaxIdleConnections: 2, MaxIdleConnections: 2,
ConnMaxLifetimeSeconds: 60, ConnMaxLifetimeSeconds: 60,
} }
base := base.NewBaseDendrite(&cfg, base.DisableMetrics) return &cfg, ctx, func() {
return base, func() { ctx.ShutdownDendrite()
base.ShutdownDendrite() ctx.WaitForShutdown()
base.WaitForShutdown() closeDb()
close()
} }
case test.DBTypeSQLite: case test.DBTypeSQLite:
cfg.Defaults(config.DefaultOpts{ cfg.Defaults(config.DefaultOpts{
@ -86,30 +86,13 @@ func CreateBaseDendrite(t *testing.T, dbType test.DBType) (*base.BaseDendrite, f
cfg.UserAPI.AccountDatabase.ConnectionString = config.DataSource(filepath.Join("file://", tempDir, "userapi.db")) cfg.UserAPI.AccountDatabase.ConnectionString = config.DataSource(filepath.Join("file://", tempDir, "userapi.db"))
cfg.RelayAPI.Database.ConnectionString = config.DataSource(filepath.Join("file://", tempDir, "relayapi.db")) cfg.RelayAPI.Database.ConnectionString = config.DataSource(filepath.Join("file://", tempDir, "relayapi.db"))
base := base.NewBaseDendrite(&cfg, base.DisableMetrics) return &cfg, ctx, func() {
return base, func() { ctx.ShutdownDendrite()
base.ShutdownDendrite() ctx.WaitForShutdown()
base.WaitForShutdown()
t.Cleanup(func() {}) // removes t.TempDir, where all database files are created t.Cleanup(func() {}) // removes t.TempDir, where all database files are created
} }
default: default:
t.Fatalf("unknown db type: %v", dbType) t.Fatalf("unknown db type: %v", dbType)
} }
return nil, nil return &config.Dendrite{}, nil, func() {}
}
func Base(cfg *config.Dendrite) (*base.BaseDendrite, nats.JetStreamContext, *nats.Conn) {
if cfg == nil {
cfg = &config.Dendrite{}
cfg.Defaults(config.DefaultOpts{
Generate: true,
SingleDatabase: false,
})
}
cfg.Global.JetStream.InMemory = true
cfg.SyncAPI.Fulltext.InMemory = true
cfg.FederationAPI.KeyPerspectives = nil
base := base.NewBaseDendrite(cfg, base.DisableMetrics)
js, jc := base.NATS.Prepare(base.ProcessContext, &cfg.Global.JetStream)
return base, js, jc
} }

View file

@ -4,10 +4,10 @@ import (
"encoding/json" "encoding/json"
"testing" "testing"
"github.com/matrix-org/dendrite/setup/config"
"github.com/nats-io/nats.go" "github.com/nats-io/nats.go"
"github.com/matrix-org/dendrite/roomserver/api" "github.com/matrix-org/dendrite/roomserver/api"
"github.com/matrix-org/dendrite/setup/base"
"github.com/matrix-org/dendrite/setup/jetstream" "github.com/matrix-org/dendrite/setup/jetstream"
) )
@ -20,9 +20,9 @@ func MustPublishMsgs(t *testing.T, jsctx nats.JetStreamContext, msgs ...*nats.Ms
} }
} }
func NewOutputEventMsg(t *testing.T, base *base.BaseDendrite, roomID string, update api.OutputEvent) *nats.Msg { func NewOutputEventMsg(t *testing.T, cfg *config.Dendrite, roomID string, update api.OutputEvent) *nats.Msg {
t.Helper() t.Helper()
msg := nats.NewMsg(base.Cfg.Global.JetStream.Prefixed(jetstream.OutputRoomEvent)) msg := nats.NewMsg(cfg.Global.JetStream.Prefixed(jetstream.OutputRoomEvent))
msg.Header.Set(jetstream.RoomEventType, string(update.Type)) msg.Header.Set(jetstream.RoomEventType, string(update.Type))
msg.Header.Set(jetstream.RoomID, roomID) msg.Header.Set(jetstream.RoomID, roomID)
var err error var err error

View file

@ -7,22 +7,22 @@ import (
"testing" "testing"
"time" "time"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/matrix-org/dendrite/internal/pushrules" "github.com/matrix-org/dendrite/internal/pushrules"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/dendrite/test" "github.com/matrix-org/dendrite/test"
"github.com/matrix-org/dendrite/test/testrig"
"github.com/matrix-org/dendrite/userapi/storage" "github.com/matrix-org/dendrite/userapi/storage"
userAPITypes "github.com/matrix-org/dendrite/userapi/types" userAPITypes "github.com/matrix-org/dendrite/userapi/types"
) )
func mustCreateDatabase(t *testing.T, dbType test.DBType) (storage.UserDatabase, func()) { func mustCreateDatabase(t *testing.T, dbType test.DBType) (storage.UserDatabase, func()) {
base, baseclose := testrig.CreateBaseDendrite(t, dbType)
t.Helper() t.Helper()
connStr, close := test.PrepareDBConnectionString(t, dbType) connStr, close := test.PrepareDBConnectionString(t, dbType)
db, err := storage.NewUserDatabase(base, &config.DatabaseOptions{ cm := sqlutil.NewConnectionManager(nil, config.DatabaseOptions{})
db, err := storage.NewUserDatabase(context.Background(), cm, &config.DatabaseOptions{
ConnectionString: config.DataSource(connStr), ConnectionString: config.DataSource(connStr),
}, "", 4, 0, 0, "") }, "", 4, 0, 0, "")
if err != nil { if err != nil {
@ -30,7 +30,6 @@ func mustCreateDatabase(t *testing.T, dbType test.DBType) (storage.UserDatabase,
} }
return db, func() { return db, func() {
close() close()
baseclose()
} }
} }

View file

@ -27,13 +27,13 @@ import (
"testing" "testing"
"time" "time"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
roomserver "github.com/matrix-org/dendrite/roomserver/api" roomserver "github.com/matrix-org/dendrite/roomserver/api"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/dendrite/setup/process" "github.com/matrix-org/dendrite/setup/process"
"github.com/matrix-org/dendrite/test" "github.com/matrix-org/dendrite/test"
"github.com/matrix-org/dendrite/test/testrig"
"github.com/matrix-org/dendrite/userapi/api" "github.com/matrix-org/dendrite/userapi/api"
"github.com/matrix-org/dendrite/userapi/storage" "github.com/matrix-org/dendrite/userapi/storage"
) )
@ -363,9 +363,9 @@ func TestDebounce(t *testing.T) {
func mustCreateKeyserverDB(t *testing.T, dbType test.DBType) (storage.KeyDatabase, func()) { func mustCreateKeyserverDB(t *testing.T, dbType test.DBType) (storage.KeyDatabase, func()) {
t.Helper() t.Helper()
base, _, _ := testrig.Base(nil)
connStr, clearDB := test.PrepareDBConnectionString(t, dbType) connStr, clearDB := test.PrepareDBConnectionString(t, dbType)
db, err := storage.NewKeyDatabase(base, &config.DatabaseOptions{ConnectionString: config.DataSource(connStr)}) cm := sqlutil.NewConnectionManager(nil, config.DatabaseOptions{})
db, err := storage.NewKeyDatabase(cm, &config.DatabaseOptions{ConnectionString: config.DataSource(connStr)})
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View file

@ -5,9 +5,9 @@ import (
"reflect" "reflect"
"testing" "testing"
"github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/dendrite/test" "github.com/matrix-org/dendrite/test"
"github.com/matrix-org/dendrite/test/testrig"
"github.com/matrix-org/dendrite/userapi/api" "github.com/matrix-org/dendrite/userapi/api"
"github.com/matrix-org/dendrite/userapi/internal" "github.com/matrix-org/dendrite/userapi/internal"
"github.com/matrix-org/dendrite/userapi/storage" "github.com/matrix-org/dendrite/userapi/storage"
@ -16,15 +16,14 @@ import (
func mustCreateDatabase(t *testing.T, dbType test.DBType) (storage.KeyDatabase, func()) { func mustCreateDatabase(t *testing.T, dbType test.DBType) (storage.KeyDatabase, func()) {
t.Helper() t.Helper()
connStr, close := test.PrepareDBConnectionString(t, dbType) connStr, close := test.PrepareDBConnectionString(t, dbType)
base, _, _ := testrig.Base(nil) cm := sqlutil.NewConnectionManager(nil, config.DatabaseOptions{})
db, err := storage.NewKeyDatabase(base, &config.DatabaseOptions{ db, err := storage.NewKeyDatabase(cm, &config.DatabaseOptions{
ConnectionString: config.DataSource(connStr), ConnectionString: config.DataSource(connStr),
}) })
if err != nil { if err != nil {
t.Fatalf("failed to create new user db: %v", err) t.Fatalf("failed to create new user db: %v", err)
} }
return db, func() { return db, func() {
base.Close()
close() close()
} }
} }

View file

@ -23,7 +23,6 @@ import (
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/dendrite/internal/sqlutil" "github.com/matrix-org/dendrite/internal/sqlutil"
"github.com/matrix-org/dendrite/setup/base"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/dendrite/userapi/storage/postgres/deltas" "github.com/matrix-org/dendrite/userapi/storage/postgres/deltas"
"github.com/matrix-org/dendrite/userapi/storage/shared" "github.com/matrix-org/dendrite/userapi/storage/shared"
@ -33,8 +32,8 @@ import (
) )
// NewDatabase creates a new accounts and profiles database // NewDatabase creates a new accounts and profiles database
func NewDatabase(base *base.BaseDendrite, dbProperties *config.DatabaseOptions, serverName gomatrixserverlib.ServerName, bcryptCost int, openIDTokenLifetimeMS int64, loginTokenLifetime time.Duration, serverNoticesLocalpart string) (*shared.Database, error) { func NewDatabase(ctx context.Context, conMan sqlutil.Connections, dbProperties *config.DatabaseOptions, serverName gomatrixserverlib.ServerName, bcryptCost int, openIDTokenLifetimeMS int64, loginTokenLifetime time.Duration, serverNoticesLocalpart string) (*shared.Database, error) {
db, writer, err := base.DatabaseConnection(dbProperties, sqlutil.NewDummyWriter()) db, writer, err := conMan.Connection(dbProperties)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -51,7 +50,7 @@ func NewDatabase(base *base.BaseDendrite, dbProperties *config.DatabaseOptions,
return deltas.UpServerNames(ctx, txn, serverName) return deltas.UpServerNames(ctx, txn, serverName)
}, },
}) })
if err = m.Up(base.Context()); err != nil { if err = m.Up(ctx); err != nil {
return nil, err return nil, err
} }
@ -111,7 +110,7 @@ func NewDatabase(base *base.BaseDendrite, dbProperties *config.DatabaseOptions,
return deltas.UpServerNamesPopulate(ctx, txn, serverName) return deltas.UpServerNamesPopulate(ctx, txn, serverName)
}, },
}) })
if err = m.Up(base.Context()); err != nil { if err = m.Up(ctx); err != nil {
return nil, err return nil, err
} }
@ -137,8 +136,8 @@ func NewDatabase(base *base.BaseDendrite, dbProperties *config.DatabaseOptions,
}, nil }, nil
} }
func NewKeyDatabase(base *base.BaseDendrite, dbProperties *config.DatabaseOptions) (*shared.KeyDatabase, error) { func NewKeyDatabase(conMan sqlutil.Connections, dbProperties *config.DatabaseOptions) (*shared.KeyDatabase, error) {
db, writer, err := base.DatabaseConnection(dbProperties, sqlutil.NewDummyWriter()) db, writer, err := conMan.Connection(dbProperties)
if err != nil { if err != nil {
return nil, err return nil, err
} }

Some files were not shown because too many files have changed in this diff Show more