Browse Source

Initial database setup including migrations

Gary Kramlich 3 years ago
parent
commit
78ab3d3804
10 changed files with 203 additions and 4 deletions
  1. 1 0
      .gitignore
  2. 9 0
      bridge/bridge.go
  3. 4 2
      bridge/matrix.go
  4. 6 0
      config/appservice.go
  5. 58 0
      config/database.go
  6. 46 0
      database/database.go
  7. 11 0
      database/migrations/01-initial.sql
  8. 54 0
      database/migrations/migrations.go
  9. 4 1
      go.mod
  10. 10 1
      go.sum

+ 1 - 0
.gitignore

@@ -1,4 +1,5 @@
 config.yaml
 discord
 logs/
+mautrix-discord.db
 registration.yaml

+ 9 - 0
bridge/bridge.go

@@ -10,6 +10,7 @@ import (
 	"maunium.net/go/mautrix/appservice"
 
 	"gitlab.com/beeper/discord/config"
+	"gitlab.com/beeper/discord/database"
 	"gitlab.com/beeper/discord/version"
 )
 
@@ -23,6 +24,7 @@ type Bridge struct {
 	log log.Logger
 
 	as             *appservice.AppService
+	db             *database.Database
 	eventProcessor *appservice.EventProcessor
 	matrixHandler  *matrixHandler
 	bot            *appservice.IntentAPI
@@ -49,9 +51,16 @@ func New(cfg *config.Config) (*Bridge, error) {
 	// Create the bot.
 	bot := appservice.BotIntent()
 
+	// Setup the database.
+	db, err := cfg.CreateDatabase(logger)
+	if err != nil {
+		return nil, err
+	}
+
 	// Create the bridge.
 	bridge := &Bridge{
 		as:     appservice,
+		db:     db,
 		bot:    bot,
 		config: cfg,
 		log:    logger,

+ 4 - 2
bridge/matrix.go

@@ -2,8 +2,10 @@ package bridge
 
 import (
 	"maunium.net/go/maulogger/v2"
+	"maunium.net/go/mautrix"
 	"maunium.net/go/mautrix/appservice"
 	"maunium.net/go/mautrix/event"
+	"maunium.net/go/mautrix/id"
 )
 
 type matrixHandler struct {
@@ -25,7 +27,7 @@ func (b *Bridge) setupEvents() {
 	b.eventProcessor.On(event.StateMember, b.matrixHandler.handleMembership)
 }
 
-func (mh *MatrixHandler) join(evt *event.Event, intent *appservice.IntentAPI) *mautrix.RespJoinedMembers {
+func (mh *matrixHandler) join(evt *event.Event, intent *appservice.IntentAPI) *mautrix.RespJoinedMembers {
 	resp, err := intent.JoinRoomByID(evt.RoomID)
 	if err != nil {
 		mh.log.Debugfln("Failed to join room %s as %s with invite from %s: %v", evt.RoomID, intent.UserID, evt.Sender, err)
@@ -74,7 +76,7 @@ func (mh *matrixHandler) handleMembership(evt *event.Event) {
 	}
 
 	// Grab the content of the event.
-	content := evt.Content.AsMessage()
+	content := evt.Content.AsMember()
 
 	// TODO: handle invites from ourselfs?
 

+ 6 - 0
config/appservice.go

@@ -13,6 +13,8 @@ type appservice struct {
 
 	Bot bot `yaml:"bot"`
 
+	Database database `yaml:"database"`
+
 	ASToken string `yaml:"as_token"`
 	HSToken string `yaml:"hs_token"`
 }
@@ -34,6 +36,10 @@ func (a *appservice) validate() error {
 		a.Port = 29350
 	}
 
+	if err := a.Database.validate(); err != nil {
+		return err
+	}
+
 	if err := a.Bot.validate(); err != nil {
 		return err
 	}

+ 58 - 0
config/database.go

@@ -0,0 +1,58 @@
+package config
+
+import (
+	log "maunium.net/go/maulogger/v2"
+
+	db "gitlab.com/beeper/discord/database"
+)
+
+type database struct {
+	Type string `yaml:"type"`
+	URI  string `yaml:"uri"`
+
+	MaxOpenConns int `yaml:"max_open_conns"`
+	MaxIdleConns int `yaml:"max_idle_conns"`
+}
+
+func (d *database) validate() error {
+	if d.Type == "" {
+		d.Type = "sqlite3"
+	}
+
+	if d.URI == "" {
+		d.URI = "mautrix-discord.db"
+	}
+
+	if d.MaxOpenConns == 0 {
+		d.MaxOpenConns = 20
+	}
+
+	if d.MaxIdleConns == 0 {
+		d.MaxIdleConns = 2
+	}
+
+	return nil
+}
+
+func (d *database) UnmarshalYAML(unmarshal func(interface{}) error) error {
+	type rawDatabase database
+
+	raw := rawDatabase{}
+	if err := unmarshal(&raw); err != nil {
+		return err
+	}
+
+	*d = database(raw)
+
+	return d.validate()
+}
+
+func (c *Config) CreateDatabase(baseLog log.Logger) (*db.Database, error) {
+	return db.New(
+		c.Appservice.Database.Type,
+		c.Appservice.Database.URI,
+		c.Appservice.Database.MaxOpenConns,
+		c.Appservice.Database.MaxIdleConns,
+		baseLog,
+	)
+}

+ 46 - 0
database/database.go

@@ -0,0 +1,46 @@
+package database
+
+import (
+	"database/sql"
+
+	_ "github.com/lib/pq"
+	_ "github.com/mattn/go-sqlite3"
+
+	log "maunium.net/go/maulogger/v2"
+
+	"gitlab.com/beeper/discord/database/migrations"
+)
+
+type Database struct {
+	*sql.DB
+	log     log.Logger
+	dialect string
+}
+
+func New(dbType, uri string, maxOpenConns, maxIdleConns int, baseLog log.Logger) (*Database, error) {
+	conn, err := sql.Open(dbType, uri)
+	if err != nil {
+		return nil, err
+	}
+
+	if dbType == "sqlite3" {
+		conn.Exec("PRAGMA foreign_keys = ON")
+	}
+
+	conn.SetMaxOpenConns(maxOpenConns)
+	conn.SetMaxIdleConns(maxIdleConns)
+
+	dbLog := baseLog.Sub("Database")
+
+	if err := migrations.Run(conn, dbLog); err != nil {
+		return nil, err
+	}
+
+	db := &Database{
+		DB:      conn,
+		log:     dbLog,
+		dialect: dbType,
+	}
+
+	return db, nil
+}

+ 11 - 0
database/migrations/01-initial.sql

@@ -0,0 +1,11 @@
+CREATE TABLE IF NOT EXISTS portal (
+	did      text,
+	receiver text,
+	mxid     text UNIQUE,
+
+	name   text NOT NULL,
+	topic  text NOT NULL,
+	avatar text NOT NULL,
+
+	PRIMARY KEY (did, receiver)
+);

+ 54 - 0
database/migrations/migrations.go

@@ -0,0 +1,54 @@
+package migrations
+
+import (
+	"database/sql"
+	"embed"
+
+	"github.com/lopezator/migrator"
+	log "maunium.net/go/maulogger/v2"
+)
+
+//go:embed *.sql
+var migrations embed.FS
+
+func migrationFromFile(filename string) *migrator.Migration {
+	return &migrator.Migration{
+		Name: filename,
+		Func: func(tx *sql.Tx) error {
+			data, err := migrations.ReadFile(filename)
+			if err != nil {
+				return err
+			}
+
+			if _, err := tx.Exec(string(data)); err != nil {
+				return err
+			}
+
+			return nil
+		},
+	}
+}
+
+func Run(db *sql.DB, baseLog log.Logger) error {
+	subLogger := baseLog.Sub("Migrations")
+	logger := migrator.LoggerFunc(func(msg string, args ...interface{}) {
+		subLogger.Infof(msg, args...)
+	})
+
+	m, err := migrator.New(
+		migrator.TableName("version"),
+		migrator.WithLogger(logger),
+		migrator.Migrations(
+			migrationFromFile("01-initial.sql"),
+		),
+	)
+	if err != nil {
+		return err
+	}
+
+	if err := m.Migrate(db); err != nil {
+		return err
+	}
+
+	return nil
+}

+ 4 - 1
go.mod

@@ -4,7 +4,11 @@ go 1.17
 
 require (
 	github.com/alecthomas/kong v0.2.18
+	github.com/lib/pq v1.9.0
+	github.com/lopezator/migrator v0.3.0
+	github.com/mattn/go-sqlite3 v1.14.6
 	gopkg.in/yaml.v2 v2.4.0
+	maunium.net/go/maulogger/v2 v2.3.1
 	maunium.net/go/mautrix v0.9.27
 )
 
@@ -15,5 +19,4 @@ require (
 	github.com/pkg/errors v0.9.1 // indirect
 	golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 // indirect
 	golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d // indirect
-	maunium.net/go/maulogger/v2 v2.3.1 // indirect
 )

+ 10 - 1
go.sum

@@ -16,6 +16,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
+github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
 github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
@@ -25,7 +27,12 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO
 github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
 github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
 github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
+github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.9.0 h1:L8nSXQQzAYByakOFMTwpjRoHsMJklur4Gi59b6VivR8=
 github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/lopezator/migrator v0.3.0 h1:VW/rR+J8NYwPdkBxjrFdjwejpgvP59LbmANJxXuNbuk=
+github.com/lopezator/migrator v0.3.0/go.mod h1:bpVAVPkWSvTw8ya2Pk7E/KiNAyDWNImgivQY79o8/8I=
+github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg=
 github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
 github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@@ -48,6 +55,7 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
 golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g=
 golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d h1:1aflnvSoWWLI2k/dMUAl5lvU1YO4Mb4hz0gh+1rjcxU=
@@ -63,6 +71,8 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
@@ -74,7 +84,6 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-maunium.net/go/maulogger/v2 v2.2.4 h1:oV2GDeM4fx1uRysdpDC0FcrPg+thFicSd9XzPcYMbVY=
 maunium.net/go/maulogger/v2 v2.2.4/go.mod h1:TYWy7wKwz/tIXTpsx8G3mZseIRiC5DoMxSZazOHy68A=
 maunium.net/go/maulogger/v2 v2.3.1 h1:fwBYJne0pHvJrrIPHK+TAPfyxxbBEz46oVGez2x0ODE=
 maunium.net/go/maulogger/v2 v2.3.1/go.mod h1:TYWy7wKwz/tIXTpsx8G3mZseIRiC5DoMxSZazOHy68A=