summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/lrstanley/girc/cmdhandler
diff options
context:
space:
mode:
authorWim <wim@42.be>2017-11-08 22:47:18 +0100
committerWim <wim@42.be>2017-11-08 22:47:18 +0100
commite3131541346e49f7f1f789f30c3262421d462458 (patch)
tree8001cd0766f60ad935da8e18de7f7e97aabed1e6 /vendor/github.com/lrstanley/girc/cmdhandler
parent27e94c438d370c77aa3b2634b615ffafe1828310 (diff)
downloadmatterbridge-msglm-e3131541346e49f7f1f789f30c3262421d462458.tar.gz
matterbridge-msglm-e3131541346e49f7f1f789f30c3262421d462458.tar.bz2
matterbridge-msglm-e3131541346e49f7f1f789f30c3262421d462458.zip
Vendor github.com/lrstanley/girc
Diffstat (limited to 'vendor/github.com/lrstanley/girc/cmdhandler')
-rw-r--r--vendor/github.com/lrstanley/girc/cmdhandler/cmd.go197
1 files changed, 197 insertions, 0 deletions
diff --git a/vendor/github.com/lrstanley/girc/cmdhandler/cmd.go b/vendor/github.com/lrstanley/girc/cmdhandler/cmd.go
new file mode 100644
index 00000000..71bb9f89
--- /dev/null
+++ b/vendor/github.com/lrstanley/girc/cmdhandler/cmd.go
@@ -0,0 +1,197 @@
+package cmdhandler
+
+import (
+ "errors"
+ "fmt"
+ "regexp"
+ "strings"
+ "sync"
+
+ "github.com/lrstanley/girc"
+)
+
+// Input is a wrapper for events, based around private messages.
+type Input struct {
+ Origin *girc.Event
+ Args []string
+}
+
+// Command is an IRC command, supporting aliases, help documentation and easy
+// wrapping for message inputs.
+type Command struct {
+ // Name of command, e.g. "search" or "ping".
+ Name string
+ // Aliases for the above command, e.g. "s" for search, or "p" for "ping".
+ Aliases []string
+ // Help documentation. Should be in the format "<arg> <arg> [arg] --
+ // something useful here"
+ Help string
+ // MinArgs is the minimum required arguments for the command. Defaults to
+ // 0, which means multiple, or no arguments can be supplied. If set
+ // above 0, this means that the command handler will throw an error asking
+ // the person to check "<prefix>help <command>" for more info.
+ MinArgs int
+ // Fn is the function which is executed when the command is ran from a
+ // private message, or channel.
+ Fn func(*girc.Client, *Input)
+}
+
+func (c *Command) genHelp(prefix string) string {
+ out := "{b}" + prefix + c.Name + "{b}"
+
+ if c.Aliases != nil && len(c.Aliases) > 0 {
+ out += " ({b}" + prefix + strings.Join(c.Aliases, "{b}, {b}"+prefix) + "{b})"
+ }
+
+ out += " :: " + c.Help
+
+ return out
+}
+
+// CmdHandler is an irc command parser and execution format which you could
+// use as an example for building your own version/bot.
+//
+// An example of how you would register this with girc:
+//
+// ch, err := cmdhandler.New("!")
+// if err != nil {
+// panic(err)
+// }
+//
+// ch.Add(&cmdhandler.Command{
+// Name: "ping",
+// Help: "Sends a pong reply back to the original user.",
+// Fn: func(c *girc.Client, input *cmdhandler.Input) {
+// c.Commands.ReplyTo(*input.Origin, "pong!")
+// },
+// })
+//
+// client.Handlers.AddHandler(girc.PRIVMSG, ch)
+type CmdHandler struct {
+ prefix string
+ re *regexp.Regexp
+
+ mu sync.Mutex
+ cmds map[string]*Command
+}
+
+var cmdMatch = `^%s([a-z0-9-_]{1,20})(?: (.*))?$`
+
+// New returns a new CmdHandler based on the specified command prefix. A good
+// prefix is a single character, and easy to remember/use. E.g. "!", or ".".
+func New(prefix string) (*CmdHandler, error) {
+ re, err := regexp.Compile(fmt.Sprintf(cmdMatch, regexp.QuoteMeta(prefix)))
+ if err != nil {
+ return nil, err
+ }
+
+ return &CmdHandler{prefix: prefix, re: re, cmds: make(map[string]*Command)}, nil
+}
+
+var validName = regexp.MustCompile(`^[a-z0-9-_]{1,20}$`)
+
+// Add registers a new command to the handler. Note that you cannot remove
+// commands once added, unless you add another CmdHandler to the client.
+func (ch *CmdHandler) Add(cmd *Command) error {
+ if cmd == nil {
+ return errors.New("nil command provided to CmdHandler")
+ }
+
+ cmd.Name = strings.ToLower(cmd.Name)
+ if !validName.MatchString(cmd.Name) {
+ return fmt.Errorf("invalid command name: %q (req: %q)", cmd.Name, validName.String())
+ }
+
+ if cmd.Aliases != nil {
+ for i := 0; i < len(cmd.Aliases); i++ {
+ cmd.Aliases[i] = strings.ToLower(cmd.Aliases[i])
+ if !validName.MatchString(cmd.Aliases[i]) {
+ return fmt.Errorf("invalid command name: %q (req: %q)", cmd.Aliases[i], validName.String())
+ }
+ }
+ }
+
+ if cmd.MinArgs < 0 {
+ cmd.MinArgs = 0
+ }
+
+ ch.mu.Lock()
+ defer ch.mu.Unlock()
+
+ if _, ok := ch.cmds[cmd.Name]; ok {
+ return fmt.Errorf("command already registered: %s", cmd.Name)
+ }
+
+ ch.cmds[cmd.Name] = cmd
+
+ // Since we'd be storing pointers, duplicates do not matter.
+ for i := 0; i < len(cmd.Aliases); i++ {
+ if _, ok := ch.cmds[cmd.Aliases[i]]; ok {
+ return fmt.Errorf("alias already registered: %s", cmd.Aliases[i])
+ }
+
+ ch.cmds[cmd.Aliases[i]] = cmd
+ }
+
+ return nil
+}
+
+// Execute satisfies the girc.Handler interface.
+func (ch *CmdHandler) Execute(client *girc.Client, event girc.Event) {
+ if event.Source == nil || event.Command != girc.PRIVMSG {
+ return
+ }
+
+ parsed := ch.re.FindStringSubmatch(event.Trailing)
+ if len(parsed) != 3 {
+ return
+ }
+
+ invCmd := strings.ToLower(parsed[1])
+ args := strings.Split(parsed[2], " ")
+ if len(args) == 1 && args[0] == "" {
+ args = []string{}
+ }
+
+ ch.mu.Lock()
+ defer ch.mu.Unlock()
+
+ if invCmd == "help" {
+ if len(args) == 0 {
+ client.Cmd.ReplyTo(event, girc.Fmt("type '{b}!help {blue}<command>{c}{b}' to optionally get more info about a specific command."))
+ return
+ }
+
+ args[0] = strings.ToLower(args[0])
+
+ if _, ok := ch.cmds[args[0]]; !ok {
+ client.Cmd.ReplyTof(event, girc.Fmt("unknown command {b}%q{b}."), args[0])
+ return
+ }
+
+ if ch.cmds[args[0]].Help == "" {
+ client.Cmd.ReplyTof(event, girc.Fmt("there is no help documentation for {b}%q{b}"), args[0])
+ return
+ }
+
+ client.Cmd.ReplyTo(event, girc.Fmt(ch.cmds[args[0]].genHelp(ch.prefix)))
+ return
+ }
+
+ cmd, ok := ch.cmds[invCmd]
+ if !ok {
+ return
+ }
+
+ if len(args) < cmd.MinArgs {
+ client.Cmd.ReplyTof(event, girc.Fmt("not enough arguments supplied for {b}%q{b}. try '{b}%shelp %s{b}'?"), invCmd, ch.prefix, invCmd)
+ return
+ }
+
+ in := &Input{
+ Origin: &event,
+ Args: args,
+ }
+
+ go cmd.Fn(client, in)
+}