From ad5e2ef72fb9ad2ca76404ae71bb4effced26c07 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 20 Jun 2018 23:28:01 +0300 Subject: [PATCH] Fill event values with matched command stuff --- matrix.go | 10 +++++++ matrix/commands.go | 73 ++++++++++++++++++++++++++++++++++++++++------ matrix/matrix.go | 1 + 3 files changed, 75 insertions(+), 9 deletions(-) diff --git a/matrix.go b/matrix.go index 04a0ae7..01219b3 100644 --- a/matrix.go +++ b/matrix.go @@ -110,6 +110,8 @@ type Unsigned struct { PrevSender string `json:"prev_sender,omitempty"` ReplacesState string `json:"replaces_state,omitempty"` Age int64 `json:"age"` + + PassiveCommand MatchedPassiveCommand `json:"m.passive_command,omitempty"` } func (unsigned Unsigned) Equals(otherUnsigned *Unsigned) bool { @@ -171,6 +173,14 @@ type MatchedCommand struct { Arguments map[string]string `json:"arguments"` } +type MatchedPassiveCommand struct { + Matched string `json:"matched"` + Values []string `json:"captured"` + + BackCompatCommand string `json:"command"` + BackCompatArguments map[string]string `json:"arguments"` +} + type RelatesTo struct { InReplyTo InReplyTo `json:"m.in_reply_to,omitempty"` } diff --git a/matrix/commands.go b/matrix/commands.go index 62bee76..b4ec037 100644 --- a/matrix/commands.go +++ b/matrix/commands.go @@ -28,6 +28,8 @@ import ( type ParsedCommand struct { Name string + IsPassive bool + Arguments []string StartsWith string Matches *regexp.Regexp MatchAgainst string @@ -43,12 +45,14 @@ func (pc *ParsedCommand) parseCommandSyntax(command maubot.Command) error { words := strings.Split(command.Syntax, " ") for i, word := range words { argument, ok := command.Arguments[word] - if ok { + // TODO enable $ check? + if ok && len(word) > 0 /*&& word[0] == '$'*/ { argumentEncountered = true regex := argument.Matches if argument.Required { regex = fmt.Sprintf("(?:%s)?", regex) } + pc.Arguments = append(pc.Arguments, word) regexBuilder.WriteString(regex) } else { if !argumentEncountered { @@ -57,7 +61,7 @@ func (pc *ParsedCommand) parseCommandSyntax(command maubot.Command) error { regexBuilder.WriteString(regexp.QuoteMeta(word)) } - if i < len(words) - 1 { + if i < len(words)-1 { if !argumentEncountered { swBuilder.WriteRune(' ') } @@ -78,7 +82,7 @@ func (pc *ParsedCommand) parseCommandSyntax(command maubot.Command) error { func (pc *ParsedCommand) parsePassiveCommandSyntax(command maubot.PassiveCommand) error { pc.MatchAgainst = command.MatchAgainst var err error - pc.Matches, err = regexp.Compile(command.Matches) + pc.Matches, err = regexp.Compile(fmt.Sprintf("(%s)", command.Matches)) pc.MatchesEvent = command.MatchEvent return err } @@ -86,7 +90,8 @@ func (pc *ParsedCommand) parsePassiveCommandSyntax(command maubot.PassiveCommand func ParseSpec(spec *maubot.CommandSpec) (commands []*ParsedCommand) { for _, command := range spec.Commands { parsing := &ParsedCommand{ - Name: command.Syntax, + Name: command.Syntax, + IsPassive: false, } err := parsing.parseCommandSyntax(command) if err != nil { @@ -97,7 +102,8 @@ func ParseSpec(spec *maubot.CommandSpec) (commands []*ParsedCommand) { } for _, command := range spec.PassiveCommands { parsing := &ParsedCommand{ - Name: command.Name, + Name: command.Name, + IsPassive: true, } err := parsing.parsePassiveCommandSyntax(command) if err != nil { @@ -126,13 +132,62 @@ func deepGet(from map[string]interface{}, path string) interface{} { } } -func (pc *ParsedCommand) Match(evt *maubot.Event) bool { +func (pc *ParsedCommand) MatchActive(evt *maubot.Event) bool { + if !strings.HasPrefix(evt.Content.Body, pc.StartsWith) { + return false + } + match := pc.Matches.FindStringSubmatch(evt.Content.Body) + if match == nil { + return false + } + // First element is whole content + match = match[1:] + + evt.Content.Command.Arguments = make(map[string]string) + for i, value := range match { + if i >= len(pc.Arguments) { + break + } + key := pc.Arguments[i] + evt.Content.Command.Arguments[key] = value + } + + evt.Content.Command.Matched = pc.Name + // TODO add evt.Content.Command.Target? + + return true +} + +func (pc *ParsedCommand) MatchPassive(evt *maubot.Event) bool { matchAgainst, ok := deepGet(evt.Content.Raw, pc.MatchAgainst).(string) if !ok { matchAgainst = evt.Content.Body } - return strings.HasPrefix(matchAgainst, pc.StartsWith) && - pc.Matches.MatchString(matchAgainst) && - (pc.MatchesEvent == nil || pc.MatchesEvent.Equals(evt)) + if pc.MatchesEvent != nil && !pc.MatchesEvent.Equals(evt) { + return false + } + + matches := pc.Matches.FindAllStringSubmatch(matchAgainst, -1) + if matches == nil { + return false + } + + values := make([]string, len(matches)) + for i, match := range matches { + values[i] = match[0] + } + + evt.Unsigned.PassiveCommand.Matched = pc.Name + evt.Unsigned.PassiveCommand.Values = values + + return true +} + +func (pc *ParsedCommand) Match(evt *maubot.Event) bool { + if pc.IsPassive { + return pc.MatchPassive(evt) + } else { + return pc.MatchActive(evt) + } } diff --git a/matrix/matrix.go b/matrix/matrix.go index bb4bdbe..fd1f925 100644 --- a/matrix/matrix.go +++ b/matrix/matrix.go @@ -104,6 +104,7 @@ func (client *Client) TriggerCommand(command *ParsedCommand, evt *maubot.Event) log.Warnf("Command %s triggered by %s doesn't have any handlers.", command.Name, evt.Sender) return maubot.Continue } + log.Debugf("Command %s on client %s triggered by %s\n", command.Name, client.UserID, evt.Sender) for _, handler := range handlers { result := handler(evt)