123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- package bridge
- import (
- "errors"
- "fmt"
- "sync"
- "time"
- log "maunium.net/go/maulogger/v2"
- "maunium.net/go/mautrix"
- "maunium.net/go/mautrix/appservice"
- "maunium.net/go/mautrix/id"
- "go.mau.fi/mautrix-discord/config"
- "go.mau.fi/mautrix-discord/database"
- "go.mau.fi/mautrix-discord/version"
- )
- const (
- reconnectDelay = 10 * time.Second
- )
- type Bridge struct {
- Config *config.Config
- log log.Logger
- as *appservice.AppService
- db *database.Database
- eventProcessor *appservice.EventProcessor
- matrixHandler *matrixHandler
- bot *appservice.IntentAPI
- provisioning *ProvisioningAPI
- usersByMXID map[id.UserID]*User
- usersByID map[string]*User
- usersLock sync.Mutex
- managementRooms map[id.RoomID]*User
- managementRoomsLock sync.Mutex
- portalsByMXID map[id.RoomID]*Portal
- portalsByID map[database.PortalKey]*Portal
- portalsLock sync.Mutex
- puppets map[string]*Puppet
- puppetsByCustomMXID map[id.UserID]*Puppet
- puppetsLock sync.Mutex
- StateStore *database.SQLStateStore
- crypto Crypto
- }
- func New(cfg *config.Config) (*Bridge, error) {
- // Create the logger.
- logger, err := cfg.CreateLogger()
- if err != nil {
- return nil, err
- }
- logger.Infoln("Initializing version", version.String)
- // Create and initialize the app service.
- appservice, err := cfg.CreateAppService()
- if err != nil {
- return nil, err
- }
- appservice.Log = log.Sub("matrix")
- appservice.Init()
- // Create the bot.
- bot := appservice.BotIntent()
- // Setup the database.
- db, err := cfg.CreateDatabase(logger)
- if err != nil {
- return nil, err
- }
- // Create the state store
- logger.Debugln("Initializing state store")
- stateStore := database.NewSQLStateStore(db)
- appservice.StateStore = stateStore
- // Create the bridge.
- bridge := &Bridge{
- as: appservice,
- db: db,
- bot: bot,
- Config: cfg,
- log: logger,
- usersByMXID: make(map[id.UserID]*User),
- usersByID: make(map[string]*User),
- managementRooms: make(map[id.RoomID]*User),
- portalsByMXID: make(map[id.RoomID]*Portal),
- portalsByID: make(map[database.PortalKey]*Portal),
- puppets: make(map[string]*Puppet),
- puppetsByCustomMXID: make(map[id.UserID]*Puppet),
- StateStore: stateStore,
- }
- bridge.crypto = NewCryptoHelper(bridge)
- if cfg.Appservice.Provisioning.Enabled() {
- bridge.provisioning = newProvisioningAPI(bridge)
- }
- // Setup the event processors
- bridge.setupEvents()
- return bridge, nil
- }
- func (b *Bridge) connect() error {
- b.log.Debugln("Checking connection to homeserver")
- for {
- resp, err := b.bot.Whoami()
- if err != nil {
- if errors.Is(err, mautrix.MUnknownToken) {
- b.log.Fatalln("Access token invalid. Is the registration installed in your homeserver correctly?")
- return fmt.Errorf("invalid access token")
- }
- b.log.Errorfln("Failed to connect to homeserver : %v", err)
- b.log.Errorfln("reconnecting in %s", reconnectDelay)
- time.Sleep(reconnectDelay)
- } else if resp.UserID != b.bot.UserID {
- b.log.Fatalln("Unexpected user ID in whoami call: got %s, expected %s", resp.UserID, b.bot.UserID)
- return fmt.Errorf("expected user id %q but got %q", b.bot.UserID, resp.UserID)
- } else {
- break
- }
- }
- b.log.Debugln("Connected to homeserver")
- return nil
- }
- func (b *Bridge) Start() error {
- b.log.Infoln("Bridge started")
- if err := b.connect(); err != nil {
- return err
- }
- if b.crypto != nil {
- if err := b.crypto.Init(); err != nil {
- b.log.Fatalln("Error initializing end-to-bridge encryption:", err)
- return err
- }
- }
- b.log.Debugln("Starting application service HTTP server")
- go b.as.Start()
- b.log.Debugln("Starting event processor")
- go b.eventProcessor.Start()
- go b.updateBotProfile()
- if b.crypto != nil {
- go b.crypto.Start()
- }
- go b.startUsers()
- // Finally tell the appservice we're ready
- b.as.Ready = true
- return nil
- }
- func (b *Bridge) Stop() {
- if b.crypto != nil {
- b.crypto.Stop()
- }
- b.as.Stop()
- b.eventProcessor.Stop()
- for _, user := range b.usersByMXID {
- if user.Session == nil {
- continue
- }
- b.log.Debugln("Disconnecting", user.MXID)
- user.Session.Close()
- }
- b.log.Infoln("Bridge stopped")
- }
|