user.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826
  1. package bridge
  2. import (
  3. "errors"
  4. "fmt"
  5. "net/http"
  6. "strings"
  7. "sync"
  8. "github.com/bwmarrin/discordgo"
  9. "github.com/skip2/go-qrcode"
  10. log "maunium.net/go/maulogger/v2"
  11. "maunium.net/go/mautrix"
  12. "maunium.net/go/mautrix/appservice"
  13. "maunium.net/go/mautrix/event"
  14. "maunium.net/go/mautrix/id"
  15. "go.mau.fi/mautrix-discord/database"
  16. )
  17. var (
  18. ErrNotConnected = errors.New("not connected")
  19. ErrNotLoggedIn = errors.New("not logged in")
  20. )
  21. type User struct {
  22. *database.User
  23. sync.Mutex
  24. bridge *Bridge
  25. log log.Logger
  26. // TODO finish implementing
  27. Admin bool
  28. guilds map[string]*database.Guild
  29. guildsLock sync.Mutex
  30. Session *discordgo.Session
  31. }
  32. // this assume you are holding the guilds lock!!!
  33. func (u *User) loadGuilds() {
  34. u.guilds = map[string]*database.Guild{}
  35. for _, guild := range u.bridge.db.Guild.GetAll(u.ID) {
  36. u.guilds[guild.GuildID] = guild
  37. }
  38. }
  39. func (b *Bridge) loadUser(dbUser *database.User, mxid *id.UserID) *User {
  40. // If we weren't passed in a user we attempt to create one if we were given
  41. // a matrix id.
  42. if dbUser == nil {
  43. if mxid == nil {
  44. return nil
  45. }
  46. dbUser = b.db.User.New()
  47. dbUser.MXID = *mxid
  48. dbUser.Insert()
  49. }
  50. user := b.NewUser(dbUser)
  51. // We assume the usersLock was acquired by our caller.
  52. b.usersByMXID[user.MXID] = user
  53. if user.ID != "" {
  54. b.usersByID[user.ID] = user
  55. }
  56. if user.ManagementRoom != "" {
  57. // Lock the management rooms for our update
  58. b.managementRoomsLock.Lock()
  59. b.managementRooms[user.ManagementRoom] = user
  60. b.managementRoomsLock.Unlock()
  61. }
  62. // Load our guilds state from the database and turn it into a map
  63. user.guildsLock.Lock()
  64. user.loadGuilds()
  65. user.guildsLock.Unlock()
  66. return user
  67. }
  68. func (b *Bridge) GetUserByMXID(userID id.UserID) *User {
  69. // TODO: check if puppet
  70. b.usersLock.Lock()
  71. defer b.usersLock.Unlock()
  72. user, ok := b.usersByMXID[userID]
  73. if !ok {
  74. return b.loadUser(b.db.User.GetByMXID(userID), &userID)
  75. }
  76. return user
  77. }
  78. func (b *Bridge) GetUserByID(id string) *User {
  79. b.usersLock.Lock()
  80. defer b.usersLock.Unlock()
  81. user, ok := b.usersByID[id]
  82. if !ok {
  83. return b.loadUser(b.db.User.GetByID(id), nil)
  84. }
  85. return user
  86. }
  87. func (b *Bridge) NewUser(dbUser *database.User) *User {
  88. user := &User{
  89. User: dbUser,
  90. bridge: b,
  91. log: b.log.Sub("User").Sub(string(dbUser.MXID)),
  92. guilds: map[string]*database.Guild{},
  93. }
  94. return user
  95. }
  96. func (b *Bridge) getAllUsers() []*User {
  97. b.usersLock.Lock()
  98. defer b.usersLock.Unlock()
  99. dbUsers := b.db.User.GetAll()
  100. users := make([]*User, len(dbUsers))
  101. for idx, dbUser := range dbUsers {
  102. user, ok := b.usersByMXID[dbUser.MXID]
  103. if !ok {
  104. user = b.loadUser(dbUser, nil)
  105. }
  106. users[idx] = user
  107. }
  108. return users
  109. }
  110. func (b *Bridge) startUsers() {
  111. b.log.Debugln("Starting users")
  112. for _, user := range b.getAllUsers() {
  113. go user.Connect()
  114. }
  115. b.log.Debugln("Starting custom puppets")
  116. for _, customPuppet := range b.GetAllPuppetsWithCustomMXID() {
  117. go func(puppet *Puppet) {
  118. b.log.Debugln("Starting custom puppet", puppet.CustomMXID)
  119. if err := puppet.StartCustomMXID(true); err != nil {
  120. puppet.log.Errorln("Failed to start custom puppet:", err)
  121. }
  122. }(customPuppet)
  123. }
  124. }
  125. func (u *User) SetManagementRoom(roomID id.RoomID) {
  126. u.bridge.managementRoomsLock.Lock()
  127. defer u.bridge.managementRoomsLock.Unlock()
  128. existing, ok := u.bridge.managementRooms[roomID]
  129. if ok {
  130. // If there's a user already assigned to this management room, clear it
  131. // out.
  132. // I think this is due a name change or something? I dunno, leaving it
  133. // for now.
  134. existing.ManagementRoom = ""
  135. existing.Update()
  136. }
  137. u.ManagementRoom = roomID
  138. u.bridge.managementRooms[u.ManagementRoom] = u
  139. u.Update()
  140. }
  141. func (u *User) sendQRCode(bot *appservice.IntentAPI, roomID id.RoomID, code string) (id.EventID, error) {
  142. url, err := u.uploadQRCode(code)
  143. if err != nil {
  144. return "", err
  145. }
  146. content := event.MessageEventContent{
  147. MsgType: event.MsgImage,
  148. Body: code,
  149. URL: url.CUString(),
  150. }
  151. resp, err := bot.SendMessageEvent(roomID, event.EventMessage, &content)
  152. if err != nil {
  153. return "", err
  154. }
  155. return resp.EventID, nil
  156. }
  157. func (u *User) uploadQRCode(code string) (id.ContentURI, error) {
  158. qrCode, err := qrcode.Encode(code, qrcode.Low, 256)
  159. if err != nil {
  160. u.log.Errorln("Failed to encode QR code:", err)
  161. return id.ContentURI{}, err
  162. }
  163. bot := u.bridge.as.BotClient()
  164. resp, err := bot.UploadBytes(qrCode, "image/png")
  165. if err != nil {
  166. u.log.Errorln("Failed to upload QR code:", err)
  167. return id.ContentURI{}, err
  168. }
  169. return resp.ContentURI, nil
  170. }
  171. func (u *User) tryAutomaticDoublePuppeting() {
  172. u.Lock()
  173. defer u.Unlock()
  174. if !u.bridge.Config.CanAutoDoublePuppet(u.MXID) {
  175. return
  176. }
  177. u.log.Debugln("Checking if double puppeting needs to be enabled")
  178. puppet := u.bridge.GetPuppetByID(u.ID)
  179. if puppet.CustomMXID != "" {
  180. u.log.Debugln("User already has double-puppeting enabled")
  181. return
  182. }
  183. accessToken, err := puppet.loginWithSharedSecret(u.MXID)
  184. if err != nil {
  185. u.log.Warnln("Failed to login with shared secret:", err)
  186. return
  187. }
  188. err = puppet.SwitchCustomMXID(accessToken, u.MXID)
  189. if err != nil {
  190. puppet.log.Warnln("Failed to switch to auto-logined custom puppet:", err)
  191. return
  192. }
  193. u.log.Infoln("Successfully automatically enabled custom puppet")
  194. }
  195. func (u *User) syncChatDoublePuppetDetails(portal *Portal, justCreated bool) {
  196. doublePuppet := portal.bridge.GetPuppetByCustomMXID(u.MXID)
  197. if doublePuppet == nil {
  198. return
  199. }
  200. if doublePuppet == nil || doublePuppet.CustomIntent() == nil || portal.MXID == "" {
  201. return
  202. }
  203. // TODO sync mute status
  204. }
  205. func (u *User) Login(token string) error {
  206. if token == "" {
  207. return fmt.Errorf("No token specified")
  208. }
  209. u.Token = token
  210. u.Update()
  211. return u.Connect()
  212. }
  213. func (u *User) LoggedIn() bool {
  214. u.Lock()
  215. defer u.Unlock()
  216. return u.Token != ""
  217. }
  218. func (u *User) Logout() error {
  219. u.Lock()
  220. defer u.Unlock()
  221. if u.Session == nil {
  222. return ErrNotLoggedIn
  223. }
  224. puppet := u.bridge.GetPuppetByID(u.ID)
  225. if puppet.CustomMXID != "" {
  226. err := puppet.SwitchCustomMXID("", "")
  227. if err != nil {
  228. u.log.Warnln("Failed to logout-matrix while logging out of Discord:", err)
  229. }
  230. }
  231. if err := u.Session.Close(); err != nil {
  232. return err
  233. }
  234. u.Session = nil
  235. u.Token = ""
  236. u.Update()
  237. return nil
  238. }
  239. func (u *User) Connected() bool {
  240. u.Lock()
  241. defer u.Unlock()
  242. return u.Session != nil
  243. }
  244. func (u *User) Connect() error {
  245. u.Lock()
  246. defer u.Unlock()
  247. if u.Token == "" {
  248. return ErrNotLoggedIn
  249. }
  250. u.log.Debugln("connecting to discord")
  251. session, err := discordgo.New(u.Token)
  252. if err != nil {
  253. return err
  254. }
  255. u.Session = session
  256. // Add our event handlers
  257. u.Session.AddHandler(u.readyHandler)
  258. u.Session.AddHandler(u.connectedHandler)
  259. u.Session.AddHandler(u.disconnectedHandler)
  260. u.Session.AddHandler(u.guildCreateHandler)
  261. u.Session.AddHandler(u.guildDeleteHandler)
  262. u.Session.AddHandler(u.guildUpdateHandler)
  263. u.Session.AddHandler(u.channelCreateHandler)
  264. u.Session.AddHandler(u.channelDeleteHandler)
  265. u.Session.AddHandler(u.channelPinsUpdateHandler)
  266. u.Session.AddHandler(u.channelUpdateHandler)
  267. u.Session.AddHandler(u.messageCreateHandler)
  268. u.Session.AddHandler(u.messageDeleteHandler)
  269. u.Session.AddHandler(u.messageUpdateHandler)
  270. u.Session.AddHandler(u.reactionAddHandler)
  271. u.Session.AddHandler(u.reactionRemoveHandler)
  272. u.Session.Identify.Presence.Status = "online"
  273. return u.Session.Open()
  274. }
  275. func (u *User) Disconnect() error {
  276. u.Lock()
  277. defer u.Unlock()
  278. if u.Session == nil {
  279. return ErrNotConnected
  280. }
  281. if err := u.Session.Close(); err != nil {
  282. return err
  283. }
  284. u.Session = nil
  285. return nil
  286. }
  287. func (u *User) bridgeMessage(guildID string) bool {
  288. // Non guild message always get bridged.
  289. if guildID == "" {
  290. return true
  291. }
  292. u.guildsLock.Lock()
  293. defer u.guildsLock.Unlock()
  294. if guild, found := u.guilds[guildID]; found {
  295. if guild.Bridge {
  296. return true
  297. }
  298. }
  299. u.log.Debugfln("ignoring message for non-bridged guild %s-%s", u.ID, guildID)
  300. return false
  301. }
  302. func (u *User) readyHandler(s *discordgo.Session, r *discordgo.Ready) {
  303. u.log.Debugln("discord connection ready")
  304. // Update our user fields
  305. u.ID = r.User.ID
  306. // Update our guild map to match watch discord thinks we're in. This is the
  307. // only time we can get the full guild map as discordgo doesn't make it
  308. // available to us later. Also, discord might not give us the full guild
  309. // information here, so we use this to remove guilds the user left and only
  310. // add guilds whose full information we have. The are told about the
  311. // "unavailable" guilds later via the GuildCreate handler.
  312. u.guildsLock.Lock()
  313. defer u.guildsLock.Unlock()
  314. // build a list of the current guilds we're in so we can prune the old ones
  315. current := []string{}
  316. u.log.Debugln("database guild count", len(u.guilds))
  317. u.log.Debugln("discord guild count", len(r.Guilds))
  318. for _, guild := range r.Guilds {
  319. current = append(current, guild.ID)
  320. // If we already know about this guild, make sure we reset it's bridge
  321. // status.
  322. if val, found := u.guilds[guild.ID]; found {
  323. bridge := val.Bridge
  324. u.guilds[guild.ID].Bridge = bridge
  325. // Update the name if the guild is available
  326. if !guild.Unavailable {
  327. u.guilds[guild.ID].GuildName = guild.Name
  328. }
  329. val.Upsert()
  330. } else {
  331. g := u.bridge.db.Guild.New()
  332. g.DiscordID = u.ID
  333. g.GuildID = guild.ID
  334. u.guilds[guild.ID] = g
  335. if !guild.Unavailable {
  336. g.GuildName = guild.Name
  337. }
  338. g.Upsert()
  339. }
  340. }
  341. // Sync the guilds to the database.
  342. u.bridge.db.Guild.Prune(u.ID, current)
  343. // Finally reload from the database since it purged servers we're not in
  344. // anymore.
  345. u.loadGuilds()
  346. u.log.Debugln("updated database guild count", len(u.guilds))
  347. u.Update()
  348. }
  349. func (u *User) connectedHandler(s *discordgo.Session, c *discordgo.Connect) {
  350. u.log.Debugln("connected to discord")
  351. u.tryAutomaticDoublePuppeting()
  352. }
  353. func (u *User) disconnectedHandler(s *discordgo.Session, d *discordgo.Disconnect) {
  354. u.log.Debugln("disconnected from discord")
  355. }
  356. func (u *User) guildCreateHandler(s *discordgo.Session, g *discordgo.GuildCreate) {
  357. u.guildsLock.Lock()
  358. defer u.guildsLock.Unlock()
  359. // If we somehow already know about the guild, just update it's name
  360. if guild, found := u.guilds[g.ID]; found {
  361. guild.GuildName = g.Name
  362. guild.Upsert()
  363. return
  364. }
  365. // This is a brand new guild so lets get it added.
  366. guild := u.bridge.db.Guild.New()
  367. guild.DiscordID = u.ID
  368. guild.GuildID = g.ID
  369. guild.GuildName = g.Name
  370. guild.Upsert()
  371. u.guilds[g.ID] = guild
  372. }
  373. func (u *User) guildDeleteHandler(s *discordgo.Session, g *discordgo.GuildDelete) {
  374. u.guildsLock.Lock()
  375. defer u.guildsLock.Unlock()
  376. if guild, found := u.guilds[g.ID]; found {
  377. guild.Delete()
  378. delete(u.guilds, g.ID)
  379. u.log.Debugln("deleted guild", g.Guild.ID)
  380. }
  381. }
  382. func (u *User) guildUpdateHandler(s *discordgo.Session, g *discordgo.GuildUpdate) {
  383. u.guildsLock.Lock()
  384. defer u.guildsLock.Unlock()
  385. // If we somehow already know about the guild, just update it's name
  386. if guild, found := u.guilds[g.ID]; found {
  387. guild.GuildName = g.Name
  388. guild.Upsert()
  389. u.log.Debugln("updated guild", g.ID)
  390. }
  391. }
  392. func (u *User) createChannel(c *discordgo.Channel) {
  393. key := database.NewPortalKey(c.ID, u.User.ID)
  394. portal := u.bridge.GetPortalByID(key)
  395. if portal.MXID != "" {
  396. return
  397. }
  398. portal.Name = c.Name
  399. portal.Topic = c.Topic
  400. portal.Type = c.Type
  401. if portal.Type == discordgo.ChannelTypeDM {
  402. portal.DMUser = c.Recipients[0].ID
  403. }
  404. if c.Icon != "" {
  405. u.log.Debugln("channel icon", c.Icon)
  406. }
  407. portal.Update()
  408. portal.createMatrixRoom(u, c)
  409. }
  410. func (u *User) channelCreateHandler(s *discordgo.Session, c *discordgo.ChannelCreate) {
  411. u.createChannel(c.Channel)
  412. }
  413. func (u *User) channelDeleteHandler(s *discordgo.Session, c *discordgo.ChannelDelete) {
  414. u.log.Debugln("channel delete handler")
  415. }
  416. func (u *User) channelPinsUpdateHandler(s *discordgo.Session, c *discordgo.ChannelPinsUpdate) {
  417. u.log.Debugln("channel pins update")
  418. }
  419. func (u *User) channelUpdateHandler(s *discordgo.Session, c *discordgo.ChannelUpdate) {
  420. key := database.NewPortalKey(c.ID, u.User.ID)
  421. portal := u.bridge.GetPortalByID(key)
  422. portal.update(u, c.Channel)
  423. }
  424. func (u *User) messageCreateHandler(s *discordgo.Session, m *discordgo.MessageCreate) {
  425. if !u.bridgeMessage(m.GuildID) {
  426. return
  427. }
  428. key := database.NewPortalKey(m.ChannelID, u.ID)
  429. portal := u.bridge.GetPortalByID(key)
  430. msg := portalDiscordMessage{
  431. msg: m,
  432. user: u,
  433. }
  434. portal.discordMessages <- msg
  435. }
  436. func (u *User) messageDeleteHandler(s *discordgo.Session, m *discordgo.MessageDelete) {
  437. if !u.bridgeMessage(m.GuildID) {
  438. return
  439. }
  440. key := database.NewPortalKey(m.ChannelID, u.ID)
  441. portal := u.bridge.GetPortalByID(key)
  442. msg := portalDiscordMessage{
  443. msg: m,
  444. user: u,
  445. }
  446. portal.discordMessages <- msg
  447. }
  448. func (u *User) messageUpdateHandler(s *discordgo.Session, m *discordgo.MessageUpdate) {
  449. if !u.bridgeMessage(m.GuildID) {
  450. return
  451. }
  452. key := database.NewPortalKey(m.ChannelID, u.ID)
  453. portal := u.bridge.GetPortalByID(key)
  454. msg := portalDiscordMessage{
  455. msg: m,
  456. user: u,
  457. }
  458. portal.discordMessages <- msg
  459. }
  460. func (u *User) reactionAddHandler(s *discordgo.Session, m *discordgo.MessageReactionAdd) {
  461. if !u.bridgeMessage(m.MessageReaction.GuildID) {
  462. return
  463. }
  464. key := database.NewPortalKey(m.ChannelID, u.User.ID)
  465. portal := u.bridge.GetPortalByID(key)
  466. msg := portalDiscordMessage{
  467. msg: m,
  468. user: u,
  469. }
  470. portal.discordMessages <- msg
  471. }
  472. func (u *User) reactionRemoveHandler(s *discordgo.Session, m *discordgo.MessageReactionRemove) {
  473. if !u.bridgeMessage(m.MessageReaction.GuildID) {
  474. return
  475. }
  476. key := database.NewPortalKey(m.ChannelID, u.User.ID)
  477. portal := u.bridge.GetPortalByID(key)
  478. msg := portalDiscordMessage{
  479. msg: m,
  480. user: u,
  481. }
  482. portal.discordMessages <- msg
  483. }
  484. func (u *User) ensureInvited(intent *appservice.IntentAPI, roomID id.RoomID, isDirect bool) bool {
  485. ret := false
  486. inviteContent := event.Content{
  487. Parsed: &event.MemberEventContent{
  488. Membership: event.MembershipInvite,
  489. IsDirect: isDirect,
  490. },
  491. Raw: map[string]interface{}{},
  492. }
  493. customPuppet := u.bridge.GetPuppetByCustomMXID(u.MXID)
  494. if customPuppet != nil && customPuppet.CustomIntent() != nil {
  495. inviteContent.Raw["fi.mau.will_auto_accept"] = true
  496. }
  497. _, err := intent.SendStateEvent(roomID, event.StateMember, u.MXID.String(), &inviteContent)
  498. var httpErr mautrix.HTTPError
  499. if err != nil && errors.As(err, &httpErr) && httpErr.RespError != nil && strings.Contains(httpErr.RespError.Err, "is already in the room") {
  500. u.bridge.StateStore.SetMembership(roomID, u.MXID, event.MembershipJoin)
  501. ret = true
  502. } else if err != nil {
  503. u.log.Warnfln("Failed to invite user to %s: %v", roomID, err)
  504. } else {
  505. ret = true
  506. }
  507. if customPuppet != nil && customPuppet.CustomIntent() != nil {
  508. err = customPuppet.CustomIntent().EnsureJoined(roomID, appservice.EnsureJoinedParams{IgnoreCache: true})
  509. if err != nil {
  510. u.log.Warnfln("Failed to auto-join %s: %v", roomID, err)
  511. ret = false
  512. } else {
  513. ret = true
  514. }
  515. }
  516. return ret
  517. }
  518. func (u *User) getDirectChats() map[id.UserID][]id.RoomID {
  519. chats := map[id.UserID][]id.RoomID{}
  520. privateChats := u.bridge.db.Portal.FindPrivateChats(u.ID)
  521. for _, portal := range privateChats {
  522. if portal.MXID != "" {
  523. puppetMXID := u.bridge.FormatPuppetMXID(portal.Key.Receiver)
  524. chats[puppetMXID] = []id.RoomID{portal.MXID}
  525. }
  526. }
  527. return chats
  528. }
  529. func (u *User) updateDirectChats(chats map[id.UserID][]id.RoomID) {
  530. if !u.bridge.Config.Bridge.SyncDirectChatList {
  531. return
  532. }
  533. puppet := u.bridge.GetPuppetByMXID(u.MXID)
  534. if puppet == nil {
  535. return
  536. }
  537. intent := puppet.CustomIntent()
  538. if intent == nil {
  539. return
  540. }
  541. method := http.MethodPatch
  542. if chats == nil {
  543. chats = u.getDirectChats()
  544. method = http.MethodPut
  545. }
  546. u.log.Debugln("Updating m.direct list on homeserver")
  547. var err error
  548. if u.bridge.Config.Homeserver.Asmux {
  549. urlPath := intent.BuildURL(mautrix.ClientURLPath{"unstable", "com.beeper.asmux", "dms"})
  550. _, err = intent.MakeFullRequest(mautrix.FullRequest{
  551. Method: method,
  552. URL: urlPath,
  553. Headers: http.Header{"X-Asmux-Auth": {u.bridge.as.Registration.AppToken}},
  554. RequestJSON: chats,
  555. })
  556. } else {
  557. existingChats := map[id.UserID][]id.RoomID{}
  558. err = intent.GetAccountData(event.AccountDataDirectChats.Type, &existingChats)
  559. if err != nil {
  560. u.log.Warnln("Failed to get m.direct list to update it:", err)
  561. return
  562. }
  563. for userID, rooms := range existingChats {
  564. if _, ok := u.bridge.ParsePuppetMXID(userID); !ok {
  565. // This is not a ghost user, include it in the new list
  566. chats[userID] = rooms
  567. } else if _, ok := chats[userID]; !ok && method == http.MethodPatch {
  568. // This is a ghost user, but we're not replacing the whole list, so include it too
  569. chats[userID] = rooms
  570. }
  571. }
  572. err = intent.SetAccountData(event.AccountDataDirectChats.Type, &chats)
  573. }
  574. if err != nil {
  575. u.log.Warnln("Failed to update m.direct list:", err)
  576. }
  577. }
  578. func (u *User) bridgeGuild(guildID string, everything bool) error {
  579. u.guildsLock.Lock()
  580. defer u.guildsLock.Unlock()
  581. guild, found := u.guilds[guildID]
  582. if !found {
  583. return fmt.Errorf("guildID not found")
  584. }
  585. // Update the guild
  586. guild.Bridge = true
  587. guild.Upsert()
  588. // If this is a full bridge, create portals for all the channels
  589. if everything {
  590. channels, err := u.Session.GuildChannels(guildID)
  591. if err != nil {
  592. return err
  593. }
  594. for _, channel := range channels {
  595. if channelIsBridgeable(channel) {
  596. u.createChannel(channel)
  597. }
  598. }
  599. }
  600. return nil
  601. }
  602. func (u *User) unbridgeGuild(guildID string) error {
  603. u.guildsLock.Lock()
  604. defer u.guildsLock.Unlock()
  605. guild, exists := u.guilds[guildID]
  606. if !exists {
  607. return fmt.Errorf("guildID not found")
  608. }
  609. if !guild.Bridge {
  610. return fmt.Errorf("guild not bridged")
  611. }
  612. // First update the guild so we don't have any other go routines recreating
  613. // channels we're about to destroy.
  614. guild.Bridge = false
  615. guild.Upsert()
  616. // Now run through the channels in the guild and remove any portals we
  617. // have for them.
  618. channels, err := u.Session.GuildChannels(guildID)
  619. if err != nil {
  620. return err
  621. }
  622. for _, channel := range channels {
  623. if channelIsBridgeable(channel) {
  624. key := database.PortalKey{
  625. ChannelID: channel.ID,
  626. Receiver: u.ID,
  627. }
  628. portal := u.bridge.GetPortalByID(key)
  629. portal.leave(u)
  630. }
  631. }
  632. return nil
  633. }