user.go 19 KB

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