commandhandler.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. package bridge
  2. import (
  3. "fmt"
  4. "strings"
  5. "github.com/alecthomas/kong"
  6. "github.com/google/shlex"
  7. "maunium.net/go/maulogger/v2"
  8. "maunium.net/go/mautrix/id"
  9. )
  10. type commandHandler struct {
  11. bridge *Bridge
  12. log maulogger.Logger
  13. }
  14. func newCommandHandler(bridge *Bridge) *commandHandler {
  15. return &commandHandler{
  16. bridge: bridge,
  17. log: bridge.log.Sub("Commands"),
  18. }
  19. }
  20. func commandsHelpPrinter(options kong.HelpOptions, ctx *kong.Context) error {
  21. selected := ctx.Selected()
  22. if selected == nil {
  23. for _, cmd := range ctx.Model.Leaves(true) {
  24. fmt.Fprintf(ctx.Stdout, " * %s - %s\n", cmd.Path(), cmd.Help)
  25. }
  26. } else {
  27. fmt.Fprintf(ctx.Stdout, "%s - %s\n", selected.Path(), selected.Help)
  28. if selected.Detail != "" {
  29. fmt.Fprintf(ctx.Stdout, "\n%s\n", selected.Detail)
  30. }
  31. if len(selected.Positional) > 0 {
  32. fmt.Fprintf(ctx.Stdout, "\nArguments:\n")
  33. for _, arg := range selected.Positional {
  34. fmt.Fprintf(ctx.Stdout, "%s %s\n", arg.Summary(), arg.Help)
  35. }
  36. }
  37. }
  38. return nil
  39. }
  40. func (h *commandHandler) handle(roomID id.RoomID, user *User, message string, replyTo id.EventID) {
  41. cmd := commands{
  42. globals: globals{
  43. bot: h.bridge.bot,
  44. bridge: h.bridge,
  45. portal: h.bridge.GetPortalByMXID(roomID),
  46. handler: h,
  47. roomID: roomID,
  48. user: user,
  49. replyTo: replyTo,
  50. },
  51. }
  52. buf := &strings.Builder{}
  53. parse, err := kong.New(
  54. &cmd,
  55. kong.Exit(func(int) {}),
  56. kong.NoDefaultHelp(),
  57. kong.Writers(buf, buf),
  58. kong.Help(commandsHelpPrinter),
  59. )
  60. if err != nil {
  61. h.log.Warnf("Failed to create argument parser for %q: %v", roomID, err)
  62. cmd.globals.reply("unexpected error, please try again shortly")
  63. return
  64. }
  65. args, err := shlex.Split(message)
  66. if err != nil {
  67. h.log.Warnf("Failed to split message %q: %v", message, err)
  68. cmd.globals.reply("failed to process the command")
  69. return
  70. }
  71. ctx, err := parse.Parse(args)
  72. if err != nil {
  73. h.log.Warnf("Failed to parse command %q: %v", message, err)
  74. cmd.globals.reply(fmt.Sprintf("failed to process the command: %v", err))
  75. return
  76. }
  77. cmd.globals.context = ctx
  78. err = ctx.Run(&cmd.globals)
  79. if err != nil {
  80. h.log.Warnf("Command %q failed: %v", message, err)
  81. output := buf.String()
  82. if output != "" {
  83. cmd.globals.reply(output)
  84. } else {
  85. cmd.globals.reply("unexpected failure")
  86. }
  87. return
  88. }
  89. if buf.Len() > 0 {
  90. cmd.globals.reply(buf.String())
  91. }
  92. }