bridge.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. package bridge
  2. import (
  3. "errors"
  4. "fmt"
  5. "sync"
  6. "time"
  7. log "maunium.net/go/maulogger/v2"
  8. "maunium.net/go/mautrix"
  9. "maunium.net/go/mautrix/appservice"
  10. "maunium.net/go/mautrix/id"
  11. "gitlab.com/beeper/discord/config"
  12. "gitlab.com/beeper/discord/database"
  13. "gitlab.com/beeper/discord/version"
  14. )
  15. const (
  16. reconnectDelay = 10 * time.Second
  17. )
  18. type Bridge struct {
  19. config *config.Config
  20. log log.Logger
  21. as *appservice.AppService
  22. db *database.Database
  23. eventProcessor *appservice.EventProcessor
  24. matrixHandler *matrixHandler
  25. bot *appservice.IntentAPI
  26. usersByMXID map[id.UserID]*User
  27. usersByID map[string]*User
  28. usersLock sync.Mutex
  29. managementRooms map[id.RoomID]*User
  30. managementRoomsLock sync.Mutex
  31. portalsByMXID map[id.RoomID]*Portal
  32. portalsByID map[database.PortalKey]*Portal
  33. portalsLock sync.Mutex
  34. puppets map[string]*Puppet
  35. puppetsLock sync.Mutex
  36. }
  37. func New(cfg *config.Config) (*Bridge, error) {
  38. // Create the logger.
  39. logger, err := cfg.CreateLogger()
  40. if err != nil {
  41. return nil, err
  42. }
  43. logger.Infoln("Initializing version", version.String)
  44. // Create and initalize the app service.
  45. appservice, err := cfg.CreateAppService()
  46. if err != nil {
  47. return nil, err
  48. }
  49. appservice.Log = log.Sub("matrix")
  50. appservice.Init()
  51. // Create the bot.
  52. bot := appservice.BotIntent()
  53. // Setup the database.
  54. db, err := cfg.CreateDatabase(logger)
  55. if err != nil {
  56. return nil, err
  57. }
  58. // Create the bridge.
  59. bridge := &Bridge{
  60. as: appservice,
  61. db: db,
  62. bot: bot,
  63. config: cfg,
  64. log: logger,
  65. usersByMXID: make(map[id.UserID]*User),
  66. usersByID: make(map[string]*User),
  67. managementRooms: make(map[id.RoomID]*User),
  68. portalsByMXID: make(map[id.RoomID]*Portal),
  69. portalsByID: make(map[database.PortalKey]*Portal),
  70. }
  71. // Setup the event processors
  72. bridge.setupEvents()
  73. return bridge, nil
  74. }
  75. func (b *Bridge) connect() error {
  76. b.log.Debugln("Checking connection to homeserver")
  77. for {
  78. resp, err := b.bot.Whoami()
  79. if err != nil {
  80. if errors.Is(err, mautrix.MUnknownToken) {
  81. b.log.Fatalln("Access token invalid. Is the registration installed in your homeserver correctly?")
  82. return fmt.Errorf("invalid access token")
  83. }
  84. b.log.Errorfln("Failed to connect to homeserver : %v", err)
  85. b.log.Errorfln("reconnecting in %s", reconnectDelay)
  86. time.Sleep(reconnectDelay)
  87. } else if resp.UserID != b.bot.UserID {
  88. b.log.Fatalln("Unexpected user ID in whoami call: got %s, expected %s", resp.UserID, b.bot.UserID)
  89. return fmt.Errorf("expected user id %q but got %q", b.bot.UserID, resp.UserID)
  90. } else {
  91. break
  92. }
  93. }
  94. b.log.Debugln("Connected to homeserver")
  95. return nil
  96. }
  97. func (b *Bridge) Start() error {
  98. b.log.Infoln("Bridge started")
  99. if err := b.connect(); err != nil {
  100. return err
  101. }
  102. b.log.Debugln("Starting application service HTTP server")
  103. go b.as.Start()
  104. b.log.Debugln("Starting event processor")
  105. go b.eventProcessor.Start()
  106. go b.updateBotProfile()
  107. go b.startUsers()
  108. // Finally tell the appservice we're ready
  109. b.as.Ready = true
  110. return nil
  111. }
  112. func (b *Bridge) Stop() {
  113. b.log.Infoln("Bridge stopped")
  114. }