user.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823
  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. "gitlab.com/beeper/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. guilds map[string]*database.Guild
  27. guildsLock sync.Mutex
  28. Session *discordgo.Session
  29. }
  30. // this assume you are holding the guilds lock!!!
  31. func (u *User) loadGuilds() {
  32. u.guilds = map[string]*database.Guild{}
  33. for _, guild := range u.bridge.db.Guild.GetAll(u.ID) {
  34. u.guilds[guild.GuildID] = guild
  35. }
  36. }
  37. func (b *Bridge) loadUser(dbUser *database.User, mxid *id.UserID) *User {
  38. // If we weren't passed in a user we attempt to create one if we were given
  39. // a matrix id.
  40. if dbUser == nil {
  41. if mxid == nil {
  42. return nil
  43. }
  44. dbUser = b.db.User.New()
  45. dbUser.MXID = *mxid
  46. dbUser.Insert()
  47. }
  48. user := b.NewUser(dbUser)
  49. // We assume the usersLock was acquired by our caller.
  50. b.usersByMXID[user.MXID] = user
  51. if user.ID != "" {
  52. b.usersByID[user.ID] = user
  53. }
  54. if user.ManagementRoom != "" {
  55. // Lock the management rooms for our update
  56. b.managementRoomsLock.Lock()
  57. b.managementRooms[user.ManagementRoom] = user
  58. b.managementRoomsLock.Unlock()
  59. }
  60. // Load our guilds state from the database and turn it into a map
  61. user.guildsLock.Lock()
  62. user.loadGuilds()
  63. user.guildsLock.Unlock()
  64. return user
  65. }
  66. func (b *Bridge) GetUserByMXID(userID id.UserID) *User {
  67. // TODO: check if puppet
  68. b.usersLock.Lock()
  69. defer b.usersLock.Unlock()
  70. user, ok := b.usersByMXID[userID]
  71. if !ok {
  72. return b.loadUser(b.db.User.GetByMXID(userID), &userID)
  73. }
  74. return user
  75. }
  76. func (b *Bridge) GetUserByID(id string) *User {
  77. b.usersLock.Lock()
  78. defer b.usersLock.Unlock()
  79. user, ok := b.usersByID[id]
  80. if !ok {
  81. return b.loadUser(b.db.User.GetByID(id), nil)
  82. }
  83. return user
  84. }
  85. func (b *Bridge) NewUser(dbUser *database.User) *User {
  86. user := &User{
  87. User: dbUser,
  88. bridge: b,
  89. log: b.log.Sub("User").Sub(string(dbUser.MXID)),
  90. guilds: map[string]*database.Guild{},
  91. }
  92. return user
  93. }
  94. func (b *Bridge) getAllUsers() []*User {
  95. b.usersLock.Lock()
  96. defer b.usersLock.Unlock()
  97. dbUsers := b.db.User.GetAll()
  98. users := make([]*User, len(dbUsers))
  99. for idx, dbUser := range dbUsers {
  100. user, ok := b.usersByMXID[dbUser.MXID]
  101. if !ok {
  102. user = b.loadUser(dbUser, nil)
  103. }
  104. users[idx] = user
  105. }
  106. return users
  107. }
  108. func (b *Bridge) startUsers() {
  109. b.log.Debugln("Starting users")
  110. for _, user := range b.getAllUsers() {
  111. go user.Connect()
  112. }
  113. b.log.Debugln("Starting custom puppets")
  114. for _, customPuppet := range b.GetAllPuppetsWithCustomMXID() {
  115. go func(puppet *Puppet) {
  116. b.log.Debugln("Starting custom puppet", puppet.CustomMXID)
  117. if err := puppet.StartCustomMXID(true); err != nil {
  118. puppet.log.Errorln("Failed to start custom puppet:", err)
  119. }
  120. }(customPuppet)
  121. }
  122. }
  123. func (u *User) SetManagementRoom(roomID id.RoomID) {
  124. u.bridge.managementRoomsLock.Lock()
  125. defer u.bridge.managementRoomsLock.Unlock()
  126. existing, ok := u.bridge.managementRooms[roomID]
  127. if ok {
  128. // If there's a user already assigned to this management room, clear it
  129. // out.
  130. // I think this is due a name change or something? I dunno, leaving it
  131. // for now.
  132. existing.ManagementRoom = ""
  133. existing.Update()
  134. }
  135. u.ManagementRoom = roomID
  136. u.bridge.managementRooms[u.ManagementRoom] = u
  137. u.Update()
  138. }
  139. func (u *User) sendQRCode(bot *appservice.IntentAPI, roomID id.RoomID, code string) (id.EventID, error) {
  140. url, err := u.uploadQRCode(code)
  141. if err != nil {
  142. return "", err
  143. }
  144. content := event.MessageEventContent{
  145. MsgType: event.MsgImage,
  146. Body: code,
  147. URL: url.CUString(),
  148. }
  149. resp, err := bot.SendMessageEvent(roomID, event.EventMessage, &content)
  150. if err != nil {
  151. return "", err
  152. }
  153. return resp.EventID, nil
  154. }
  155. func (u *User) uploadQRCode(code string) (id.ContentURI, error) {
  156. qrCode, err := qrcode.Encode(code, qrcode.Low, 256)
  157. if err != nil {
  158. u.log.Errorln("Failed to encode QR code:", err)
  159. return id.ContentURI{}, err
  160. }
  161. bot := u.bridge.as.BotClient()
  162. resp, err := bot.UploadBytes(qrCode, "image/png")
  163. if err != nil {
  164. u.log.Errorln("Failed to upload QR code:", err)
  165. return id.ContentURI{}, err
  166. }
  167. return resp.ContentURI, nil
  168. }
  169. func (u *User) tryAutomaticDoublePuppeting() {
  170. u.Lock()
  171. defer u.Unlock()
  172. if !u.bridge.Config.CanAutoDoublePuppet(u.MXID) {
  173. return
  174. }
  175. u.log.Debugln("Checking if double puppeting needs to be enabled")
  176. puppet := u.bridge.GetPuppetByID(u.ID)
  177. if puppet.CustomMXID != "" {
  178. u.log.Debugln("User already has double-puppeting enabled")
  179. return
  180. }
  181. accessToken, err := puppet.loginWithSharedSecret(u.MXID)
  182. if err != nil {
  183. u.log.Warnln("Failed to login with shared secret:", err)
  184. return
  185. }
  186. err = puppet.SwitchCustomMXID(accessToken, u.MXID)
  187. if err != nil {
  188. puppet.log.Warnln("Failed to switch to auto-logined custom puppet:", err)
  189. return
  190. }
  191. u.log.Infoln("Successfully automatically enabled custom puppet")
  192. }
  193. func (u *User) syncChatDoublePuppetDetails(portal *Portal, justCreated bool) {
  194. doublePuppet := portal.bridge.GetPuppetByCustomMXID(u.MXID)
  195. if doublePuppet == nil {
  196. return
  197. }
  198. if doublePuppet == nil || doublePuppet.CustomIntent() == nil || portal.MXID == "" {
  199. return
  200. }
  201. // TODO sync mute status
  202. }
  203. func (u *User) Login(token string) error {
  204. if token == "" {
  205. return fmt.Errorf("No token specified")
  206. }
  207. u.Token = token
  208. u.Update()
  209. return u.Connect()
  210. }
  211. func (u *User) LoggedIn() bool {
  212. u.Lock()
  213. defer u.Unlock()
  214. return u.Token != ""
  215. }
  216. func (u *User) Logout() error {
  217. u.Lock()
  218. defer u.Unlock()
  219. if u.Session == nil {
  220. return ErrNotLoggedIn
  221. }
  222. puppet := u.bridge.GetPuppetByID(u.ID)
  223. if puppet.CustomMXID != "" {
  224. err := puppet.SwitchCustomMXID("", "")
  225. if err != nil {
  226. u.log.Warnln("Failed to logout-matrix while logging out of Discord:", err)
  227. }
  228. }
  229. if err := u.Session.Close(); err != nil {
  230. return err
  231. }
  232. u.Session = nil
  233. u.Token = ""
  234. u.Update()
  235. return nil
  236. }
  237. func (u *User) Connected() bool {
  238. u.Lock()
  239. defer u.Unlock()
  240. return u.Session != nil
  241. }
  242. func (u *User) Connect() error {
  243. u.Lock()
  244. defer u.Unlock()
  245. if u.Token == "" {
  246. return ErrNotLoggedIn
  247. }
  248. u.log.Debugln("connecting to discord")
  249. session, err := discordgo.New(u.Token)
  250. if err != nil {
  251. return err
  252. }
  253. u.Session = session
  254. // Add our event handlers
  255. u.Session.AddHandler(u.readyHandler)
  256. u.Session.AddHandler(u.connectedHandler)
  257. u.Session.AddHandler(u.disconnectedHandler)
  258. u.Session.AddHandler(u.guildCreateHandler)
  259. u.Session.AddHandler(u.guildDeleteHandler)
  260. u.Session.AddHandler(u.guildUpdateHandler)
  261. u.Session.AddHandler(u.channelCreateHandler)
  262. u.Session.AddHandler(u.channelDeleteHandler)
  263. u.Session.AddHandler(u.channelPinsUpdateHandler)
  264. u.Session.AddHandler(u.channelUpdateHandler)
  265. u.Session.AddHandler(u.messageCreateHandler)
  266. u.Session.AddHandler(u.messageDeleteHandler)
  267. u.Session.AddHandler(u.messageUpdateHandler)
  268. u.Session.AddHandler(u.reactionAddHandler)
  269. u.Session.AddHandler(u.reactionRemoveHandler)
  270. u.Session.Identify.Presence.Status = "online"
  271. return u.Session.Open()
  272. }
  273. func (u *User) Disconnect() error {
  274. u.Lock()
  275. defer u.Unlock()
  276. if u.Session == nil {
  277. return ErrNotConnected
  278. }
  279. if err := u.Session.Close(); err != nil {
  280. return err
  281. }
  282. u.Session = nil
  283. return nil
  284. }
  285. func (u *User) bridgeMessage(guildID string) bool {
  286. // Non guild message always get bridged.
  287. if guildID == "" {
  288. return true
  289. }
  290. u.guildsLock.Lock()
  291. defer u.guildsLock.Unlock()
  292. if guild, found := u.guilds[guildID]; found {
  293. if guild.Bridge {
  294. return true
  295. }
  296. }
  297. u.log.Debugfln("ignoring message for non-bridged guild %s-%s", u.ID, guildID)
  298. return false
  299. }
  300. func (u *User) readyHandler(s *discordgo.Session, r *discordgo.Ready) {
  301. u.log.Debugln("discord connection ready")
  302. // Update our user fields
  303. u.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. u.guildsLock.Lock()
  311. defer u.guildsLock.Unlock()
  312. // build a list of the current guilds we're in so we can prune the old ones
  313. current := []string{}
  314. u.log.Debugln("database guild count", len(u.guilds))
  315. u.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 := u.guilds[guild.ID]; found {
  321. bridge := val.Bridge
  322. u.guilds[guild.ID].Bridge = bridge
  323. // Update the name if the guild is available
  324. if !guild.Unavailable {
  325. u.guilds[guild.ID].GuildName = guild.Name
  326. }
  327. val.Upsert()
  328. } else {
  329. g := u.bridge.db.Guild.New()
  330. g.DiscordID = u.ID
  331. g.GuildID = guild.ID
  332. u.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. u.bridge.db.Guild.Prune(u.ID, current)
  341. // Finally reload from the database since it purged servers we're not in
  342. // anymore.
  343. u.loadGuilds()
  344. u.log.Debugln("updated database guild count", len(u.guilds))
  345. u.Update()
  346. }
  347. func (u *User) connectedHandler(s *discordgo.Session, c *discordgo.Connect) {
  348. u.log.Debugln("connected to discord")
  349. u.tryAutomaticDoublePuppeting()
  350. }
  351. func (u *User) disconnectedHandler(s *discordgo.Session, d *discordgo.Disconnect) {
  352. u.log.Debugln("disconnected from discord")
  353. }
  354. func (u *User) guildCreateHandler(s *discordgo.Session, g *discordgo.GuildCreate) {
  355. u.guildsLock.Lock()
  356. defer u.guildsLock.Unlock()
  357. // If we somehow already know about the guild, just update it's name
  358. if guild, found := u.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 := u.bridge.db.Guild.New()
  365. guild.DiscordID = u.ID
  366. guild.GuildID = g.ID
  367. guild.GuildName = g.Name
  368. guild.Upsert()
  369. u.guilds[g.ID] = guild
  370. }
  371. func (u *User) guildDeleteHandler(s *discordgo.Session, g *discordgo.GuildDelete) {
  372. u.guildsLock.Lock()
  373. defer u.guildsLock.Unlock()
  374. if guild, found := u.guilds[g.ID]; found {
  375. guild.Delete()
  376. delete(u.guilds, g.ID)
  377. u.log.Debugln("deleted guild", g.Guild.ID)
  378. }
  379. }
  380. func (u *User) guildUpdateHandler(s *discordgo.Session, g *discordgo.GuildUpdate) {
  381. u.guildsLock.Lock()
  382. defer u.guildsLock.Unlock()
  383. // If we somehow already know about the guild, just update it's name
  384. if guild, found := u.guilds[g.ID]; found {
  385. guild.GuildName = g.Name
  386. guild.Upsert()
  387. u.log.Debugln("updated guild", g.ID)
  388. }
  389. }
  390. func (u *User) createChannel(c *discordgo.Channel) {
  391. key := database.NewPortalKey(c.ID, u.User.ID)
  392. portal := u.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. u.log.Debugln("channel icon", c.Icon)
  404. }
  405. portal.Update()
  406. portal.createMatrixRoom(u, c)
  407. }
  408. func (u *User) channelCreateHandler(s *discordgo.Session, c *discordgo.ChannelCreate) {
  409. u.createChannel(c.Channel)
  410. }
  411. func (u *User) channelDeleteHandler(s *discordgo.Session, c *discordgo.ChannelDelete) {
  412. u.log.Debugln("channel delete handler")
  413. }
  414. func (u *User) channelPinsUpdateHandler(s *discordgo.Session, c *discordgo.ChannelPinsUpdate) {
  415. u.log.Debugln("channel pins update")
  416. }
  417. func (u *User) channelUpdateHandler(s *discordgo.Session, c *discordgo.ChannelUpdate) {
  418. key := database.NewPortalKey(c.ID, u.User.ID)
  419. portal := u.bridge.GetPortalByID(key)
  420. portal.update(u, c.Channel)
  421. }
  422. func (u *User) messageCreateHandler(s *discordgo.Session, m *discordgo.MessageCreate) {
  423. if !u.bridgeMessage(m.GuildID) {
  424. return
  425. }
  426. key := database.NewPortalKey(m.ChannelID, u.ID)
  427. portal := u.bridge.GetPortalByID(key)
  428. msg := portalDiscordMessage{
  429. msg: m,
  430. user: u,
  431. }
  432. portal.discordMessages <- msg
  433. }
  434. func (u *User) messageDeleteHandler(s *discordgo.Session, m *discordgo.MessageDelete) {
  435. if !u.bridgeMessage(m.GuildID) {
  436. return
  437. }
  438. key := database.NewPortalKey(m.ChannelID, u.ID)
  439. portal := u.bridge.GetPortalByID(key)
  440. msg := portalDiscordMessage{
  441. msg: m,
  442. user: u,
  443. }
  444. portal.discordMessages <- msg
  445. }
  446. func (u *User) messageUpdateHandler(s *discordgo.Session, m *discordgo.MessageUpdate) {
  447. if !u.bridgeMessage(m.GuildID) {
  448. return
  449. }
  450. key := database.NewPortalKey(m.ChannelID, u.ID)
  451. portal := u.bridge.GetPortalByID(key)
  452. msg := portalDiscordMessage{
  453. msg: m,
  454. user: u,
  455. }
  456. portal.discordMessages <- msg
  457. }
  458. func (u *User) reactionAddHandler(s *discordgo.Session, m *discordgo.MessageReactionAdd) {
  459. if !u.bridgeMessage(m.MessageReaction.GuildID) {
  460. return
  461. }
  462. key := database.NewPortalKey(m.ChannelID, u.User.ID)
  463. portal := u.bridge.GetPortalByID(key)
  464. msg := portalDiscordMessage{
  465. msg: m,
  466. user: u,
  467. }
  468. portal.discordMessages <- msg
  469. }
  470. func (u *User) reactionRemoveHandler(s *discordgo.Session, m *discordgo.MessageReactionRemove) {
  471. if !u.bridgeMessage(m.MessageReaction.GuildID) {
  472. return
  473. }
  474. key := database.NewPortalKey(m.ChannelID, u.User.ID)
  475. portal := u.bridge.GetPortalByID(key)
  476. msg := portalDiscordMessage{
  477. msg: m,
  478. user: u,
  479. }
  480. portal.discordMessages <- msg
  481. }
  482. func (u *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 := u.bridge.GetPuppetByCustomMXID(u.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, u.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. u.bridge.StateStore.SetMembership(roomID, u.MXID, event.MembershipJoin)
  499. ret = true
  500. } else if err != nil {
  501. u.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. u.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 (u *User) getDirectChats() map[id.UserID][]id.RoomID {
  517. chats := map[id.UserID][]id.RoomID{}
  518. privateChats := u.bridge.db.Portal.FindPrivateChats(u.ID)
  519. for _, portal := range privateChats {
  520. if portal.MXID != "" {
  521. puppetMXID := u.bridge.FormatPuppetMXID(portal.Key.Receiver)
  522. chats[puppetMXID] = []id.RoomID{portal.MXID}
  523. }
  524. }
  525. return chats
  526. }
  527. func (u *User) updateDirectChats(chats map[id.UserID][]id.RoomID) {
  528. if !u.bridge.Config.Bridge.SyncDirectChatList {
  529. return
  530. }
  531. puppet := u.bridge.GetPuppetByMXID(u.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 = u.getDirectChats()
  542. method = http.MethodPut
  543. }
  544. u.log.Debugln("Updating m.direct list on homeserver")
  545. var err error
  546. if u.bridge.Config.Homeserver.Asmux {
  547. urlPath := intent.BuildBaseURL("_matrix", "client", "unstable", "com.beeper.asmux", "dms")
  548. _, err = intent.MakeFullRequest(mautrix.FullRequest{
  549. Method: method,
  550. URL: urlPath,
  551. Headers: http.Header{"X-Asmux-Auth": {u.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. u.log.Warnln("Failed to get m.direct list to update it:", err)
  559. return
  560. }
  561. for userID, rooms := range existingChats {
  562. if _, ok := u.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. u.log.Warnln("Failed to update m.direct list:", err)
  574. }
  575. }
  576. func (u *User) bridgeGuild(guildID string, everything bool) error {
  577. u.guildsLock.Lock()
  578. defer u.guildsLock.Unlock()
  579. guild, found := u.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 := u.Session.GuildChannels(guildID)
  589. if err != nil {
  590. return err
  591. }
  592. for _, channel := range channels {
  593. if channelIsBridgeable(channel) {
  594. u.createChannel(channel)
  595. }
  596. }
  597. }
  598. return nil
  599. }
  600. func (u *User) unbridgeGuild(guildID string) error {
  601. u.guildsLock.Lock()
  602. defer u.guildsLock.Unlock()
  603. guild, exists := u.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 := u.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: u.ID,
  625. }
  626. portal := u.bridge.GetPortalByID(key)
  627. portal.leave(u)
  628. }
  629. }
  630. return nil
  631. }