From b5965eee1a2fcdefdeebd8d152d0d98b0bdc2ea1 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Thu, 29 Oct 2020 16:08:41 +0000 Subject: [PATCH] Add mscs/hooks package, begin work for msc2836 --- cmd/dendrite-monolith-server/main.go | 7 +++ internal/config/config.go | 6 ++- internal/config/config_mscs.go | 19 ++++++++ internal/hooks/hooks.go | 21 +++++++++ internal/mscs/msc2836/msc2836.go | 67 ++++++++++++++++++++++++++++ internal/mscs/msc2836/storage.go | 59 ++++++++++++++++++++++++ internal/mscs/mscs.go | 42 +++++++++++++++++ 7 files changed, 220 insertions(+), 1 deletion(-) create mode 100644 internal/config/config_mscs.go create mode 100644 internal/hooks/hooks.go create mode 100644 internal/mscs/msc2836/msc2836.go create mode 100644 internal/mscs/msc2836/storage.go create mode 100644 internal/mscs/mscs.go diff --git a/cmd/dendrite-monolith-server/main.go b/cmd/dendrite-monolith-server/main.go index e935805f6..70b81bbc8 100644 --- a/cmd/dendrite-monolith-server/main.go +++ b/cmd/dendrite-monolith-server/main.go @@ -23,6 +23,7 @@ import ( "github.com/matrix-org/dendrite/eduserver/cache" "github.com/matrix-org/dendrite/federationsender" "github.com/matrix-org/dendrite/internal/config" + "github.com/matrix-org/dendrite/internal/mscs" "github.com/matrix-org/dendrite/internal/setup" "github.com/matrix-org/dendrite/keyserver" "github.com/matrix-org/dendrite/roomserver" @@ -148,6 +149,12 @@ func main() { base.PublicMediaAPIMux, ) + if len(base.Cfg.MSCs.MSCs) > 0 { + if err := mscs.Enable(base, &monolith); err != nil { + logrus.WithError(err).Fatalf("Failed to enable MSCs") + } + } + // Expose the matrix APIs directly rather than putting them under a /api path. go func() { base.SetupAndServeHTTP( diff --git a/internal/config/config.go b/internal/config/config.go index 9d9e2414f..b8b12d0c1 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -66,6 +66,8 @@ type Dendrite struct { SyncAPI SyncAPI `yaml:"sync_api"` UserAPI UserAPI `yaml:"user_api"` + MSCs MSCs `yaml:"mscs"` + // The config for tracing the dendrite servers. Tracing struct { // Set to true to enable tracer hooks. If false, no tracing is set up. @@ -306,6 +308,7 @@ func (c *Dendrite) Defaults() { c.SyncAPI.Defaults() c.UserAPI.Defaults() c.AppServiceAPI.Defaults() + c.MSCs.Defaults() c.Wiring() } @@ -319,7 +322,7 @@ func (c *Dendrite) Verify(configErrs *ConfigErrors, isMonolith bool) { &c.EDUServer, &c.FederationAPI, &c.FederationSender, &c.KeyServer, &c.MediaAPI, &c.RoomServer, &c.SigningKeyServer, &c.SyncAPI, &c.UserAPI, - &c.AppServiceAPI, + &c.AppServiceAPI, &c.MSCs, } { c.Verify(configErrs, isMonolith) } @@ -337,6 +340,7 @@ func (c *Dendrite) Wiring() { c.SyncAPI.Matrix = &c.Global c.UserAPI.Matrix = &c.Global c.AppServiceAPI.Matrix = &c.Global + c.MSCs.Matrix = &c.Global c.ClientAPI.Derived = &c.Derived c.AppServiceAPI.Derived = &c.Derived diff --git a/internal/config/config_mscs.go b/internal/config/config_mscs.go new file mode 100644 index 000000000..776d0b641 --- /dev/null +++ b/internal/config/config_mscs.go @@ -0,0 +1,19 @@ +package config + +type MSCs struct { + Matrix *Global `yaml:"-"` + + // The MSCs to enable, currently only `msc2836` is supported. + MSCs []string `yaml:"mscs"` + + Database DatabaseOptions `yaml:"database"` +} + +func (c *MSCs) Defaults() { + c.Database.Defaults() + c.Database.ConnectionString = "file:mscs.db" +} + +func (c *MSCs) Verify(configErrs *ConfigErrors, isMonolith bool) { + checkNotEmpty(configErrs, "mscs.database.connection_string", string(c.Database.ConnectionString)) +} diff --git a/internal/hooks/hooks.go b/internal/hooks/hooks.go new file mode 100644 index 000000000..c3d661afb --- /dev/null +++ b/internal/hooks/hooks.go @@ -0,0 +1,21 @@ +// Copyright 2020 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 hooks exposes places in Dendrite where custom code can be executed, useful for MSCs. +// Hooks can only be run in monolith mode. +package hooks + +func Attach() { + +} diff --git a/internal/mscs/msc2836/msc2836.go b/internal/mscs/msc2836/msc2836.go new file mode 100644 index 000000000..491b89e14 --- /dev/null +++ b/internal/mscs/msc2836/msc2836.go @@ -0,0 +1,67 @@ +// Copyright 2020 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 msc2836 'Threading' implements https://github.com/matrix-org/matrix-doc/pull/2836 +package msc2836 + +import ( + "encoding/json" + "fmt" + "net/http" + + "github.com/matrix-org/dendrite/clientapi/jsonerror" + "github.com/matrix-org/dendrite/internal/httputil" + "github.com/matrix-org/dendrite/internal/setup" + userapi "github.com/matrix-org/dendrite/userapi/api" + "github.com/matrix-org/util" +) + +type eventRelationshipRequest struct { + EventID string `json:"event_id"` + MaxDepth int `json:"max_depth"` + MaxBreadth int `json:"max_breadth"` + Limit int `json:"limit"` + DepthFirst bool `json:"depth_first"` + RecentFirst bool `json:"recent_first"` + IncludeParent bool `json:"include_parent"` + IncludeChildren bool `json:"include_children"` + Direction string `json:"direction"` + Batch string `json:"batch"` +} + +// Enable this MSC +func Enable(base *setup.BaseDendrite, monolith *setup.Monolith) error { + _, err := NewDatabase(&base.Cfg.MSCs.Database) + if err != nil { + return fmt.Errorf("Cannot enable MSC2836: %w", err) + } + + base.PublicClientAPIMux.Handle("/unstable/event_relationships", + httputil.MakeAuthAPI("eventRelationships", monolith.UserAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse { + var relation eventRelationshipRequest + if err := json.NewDecoder(req.Body).Decode(&relation); err != nil { + util.GetLogger(req.Context()).WithError(err).Error("failed to decode HTTP request as JSON") + return util.JSONResponse{ + Code: 400, + JSON: jsonerror.BadJSON(fmt.Sprintf("invalid json: %s", err)), + } + } + return util.JSONResponse{ + Code: 200, + JSON: struct{}{}, + } + }), + ).Methods(http.MethodPost, http.MethodOptions) + return nil +} diff --git a/internal/mscs/msc2836/storage.go b/internal/mscs/msc2836/storage.go new file mode 100644 index 000000000..2a8cb99a6 --- /dev/null +++ b/internal/mscs/msc2836/storage.go @@ -0,0 +1,59 @@ +package msc2836 + +import ( + "context" + "database/sql" + + "github.com/matrix-org/dendrite/internal/config" + "github.com/matrix-org/dendrite/internal/sqlutil" + "github.com/matrix-org/gomatrixserverlib" +) + +type Database interface { + // StoreRelation stores the parent->child and child->parent relationship for later querying. + StoreRelation(ctx context.Context, ev *gomatrixserverlib.HeaderedEvent) error +} + +type Postgres struct { + db *sql.DB +} + +func NewPostgresDatabase(dbOpts *config.DatabaseOptions) (Database, error) { + var p Postgres + var err error + if p.db, err = sqlutil.Open(dbOpts); err != nil { + return nil, err + } + return &p, nil +} + +func (db *Postgres) StoreRelation(ctx context.Context, ev *gomatrixserverlib.HeaderedEvent) error { + return nil +} + +type SQLite struct { + db *sql.DB + writer sqlutil.Writer +} + +func NewSQLiteDatabase(dbOpts *config.DatabaseOptions) (Database, error) { + var s SQLite + var err error + if s.db, err = sqlutil.Open(dbOpts); err != nil { + return nil, err + } + s.writer = sqlutil.NewExclusiveWriter() + return &s, nil +} + +func (db *SQLite) StoreRelation(ctx context.Context, ev *gomatrixserverlib.HeaderedEvent) error { + return nil +} + +// NewDatabase loads the database for msc2836 +func NewDatabase(dbOpts *config.DatabaseOptions) (Database, error) { + if dbOpts.ConnectionString.IsPostgres() { + return NewPostgresDatabase(dbOpts) + } + return NewSQLiteDatabase(dbOpts) +} diff --git a/internal/mscs/mscs.go b/internal/mscs/mscs.go new file mode 100644 index 000000000..e5bd3308d --- /dev/null +++ b/internal/mscs/mscs.go @@ -0,0 +1,42 @@ +// Copyright 2020 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 mscs implements Matrix Spec Changes from https://github.com/matrix-org/matrix-doc +package mscs + +import ( + "fmt" + + "github.com/matrix-org/dendrite/internal/mscs/msc2836" + "github.com/matrix-org/dendrite/internal/setup" +) + +// Enable MSCs - returns an error on unknown MSCs +func Enable(base *setup.BaseDendrite, monolith *setup.Monolith) error { + for _, msc := range base.Cfg.MSCs.MSCs { + if err := EnableMSC(base, monolith, msc); err != nil { + return err + } + } + return nil +} + +func EnableMSC(base *setup.BaseDendrite, monolith *setup.Monolith, msc string) error { + switch msc { + case "msc2836": + return msc2836.Enable(base, monolith) + default: + return fmt.Errorf("EnableMSC: unknown msc '%s'", msc) + } +}