commands.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. package bridge
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/alecthomas/kong"
  6. "maunium.net/go/mautrix/appservice"
  7. "maunium.net/go/mautrix/event"
  8. "maunium.net/go/mautrix/format"
  9. "maunium.net/go/mautrix/id"
  10. "gitlab.com/beeper/discord/consts"
  11. "gitlab.com/beeper/discord/remoteauth"
  12. "gitlab.com/beeper/discord/version"
  13. )
  14. type globals struct {
  15. context *kong.Context
  16. bridge *Bridge
  17. bot *appservice.IntentAPI
  18. portal *Portal
  19. handler *commandHandler
  20. roomID id.RoomID
  21. user *User
  22. replyTo id.EventID
  23. }
  24. func (g *globals) reply(msg string) {
  25. content := format.RenderMarkdown(msg, true, false)
  26. content.MsgType = event.MsgNotice
  27. intent := g.bot
  28. if g.portal != nil && g.portal.IsPrivateChat() {
  29. intent = g.portal.MainIntent()
  30. }
  31. _, err := intent.SendMessageEvent(g.roomID, event.EventMessage, content)
  32. if err != nil {
  33. g.handler.log.Warnfln("Failed to reply to command from %q: %v", g.user.MXID, err)
  34. }
  35. }
  36. type commands struct {
  37. globals
  38. Disconnect disconnectCmd `kong:"cmd,help='Disconnect from Discord'"`
  39. Help helpCmd `kong:"cmd,help='Displays this message.'"`
  40. Login loginCmd `kong:"cmd,help='Log in to Discord.'"`
  41. Logout logoutCmd `kong:"cmd,help='Log out of Discord.'"`
  42. Reconnect reconnectCmd `kong:"cmd,help='Reconnect to Discord'"`
  43. Version versionCmd `kong:"cmd,help='Displays the version of the bridge.'"`
  44. }
  45. type helpCmd struct {
  46. Command []string `kong:"arg,optional,help='The command to get help on.'"`
  47. }
  48. func (c *helpCmd) Run(g *globals) error {
  49. ctx, err := kong.Trace(g.context.Kong, c.Command)
  50. if err != nil {
  51. return err
  52. }
  53. if ctx.Error != nil {
  54. return err
  55. }
  56. err = ctx.PrintUsage(true)
  57. if err != nil {
  58. return err
  59. }
  60. fmt.Fprintln(g.context.Stdout)
  61. return nil
  62. }
  63. type versionCmd struct{}
  64. func (c *versionCmd) Run(g *globals) error {
  65. fmt.Fprintln(g.context.Stdout, consts.Name, version.String)
  66. return nil
  67. }
  68. type loginCmd struct{}
  69. func (l *loginCmd) Run(g *globals) error {
  70. if g.user.LoggedIn() {
  71. fmt.Fprintf(g.context.Stdout, "You are already logged in")
  72. return fmt.Errorf("user already logged in")
  73. }
  74. client, err := remoteauth.New()
  75. if err != nil {
  76. return err
  77. }
  78. qrChan := make(chan string)
  79. doneChan := make(chan struct{})
  80. go func() {
  81. code := <-qrChan
  82. _, err := g.user.sendQRCode(g.bot, g.roomID, code)
  83. if err != nil {
  84. fmt.Fprintln(g.context.Stdout, "failed to generate the qrcode")
  85. return
  86. }
  87. }()
  88. ctx := context.Background()
  89. if err := client.Dial(ctx, qrChan, doneChan); err != nil {
  90. close(qrChan)
  91. close(doneChan)
  92. return err
  93. }
  94. <-doneChan
  95. user, err := client.Result()
  96. if err != nil {
  97. fmt.Println(g.context.Stdout, "failed to log in")
  98. return err
  99. }
  100. if err := g.user.Login(user.Token); err != nil {
  101. fmt.Println(g.context.Stdout, "failed to login", err)
  102. return err
  103. }
  104. g.user.ID = user.UserID
  105. g.user.Update()
  106. return nil
  107. }
  108. type logoutCmd struct{}
  109. func (l *logoutCmd) Run(g *globals) error {
  110. if !g.user.LoggedIn() {
  111. fmt.Fprintln(g.context.Stdout, "You are not logged in")
  112. return fmt.Errorf("user is not logged in")
  113. }
  114. err := g.user.Logout()
  115. if err != nil {
  116. fmt.Fprintln(g.context.Stdout, "Failed to log out")
  117. return err
  118. }
  119. fmt.Fprintln(g.context.Stdout, "Successfully logged out")
  120. return nil
  121. }
  122. type disconnectCmd struct{}
  123. func (d *disconnectCmd) Run(g *globals) error {
  124. if !g.user.Connected() {
  125. fmt.Fprintln(g.context.Stdout, "You are not connected")
  126. return fmt.Errorf("user is not connected")
  127. }
  128. if err := g.user.Disconnect(); err != nil {
  129. fmt.Fprintln(g.context.Stdout, "Failed to disconnect")
  130. return err
  131. }
  132. fmt.Fprintln(g.context.Stdout, "Successfully disconnected")
  133. return nil
  134. }
  135. type reconnectCmd struct{}
  136. func (r *reconnectCmd) Run(g *globals) error {
  137. if g.user.Connected() {
  138. fmt.Fprintln(g.context.Stdout, "You are already connected")
  139. return fmt.Errorf("user is already connected")
  140. }
  141. if err := g.user.Connect(); err != nil {
  142. fmt.Fprintln(g.context.Stdout, "Failed to connect")
  143. return err
  144. }
  145. fmt.Fprintln(g.context.Stdout, "Successfully connected")
  146. return nil
  147. }