Ad-Hoc support for chat commands

This commit is contained in:
Bohdan Horbeshko 2024-02-10 13:46:02 -05:00
parent a0180eff75
commit b0c5302c82
2 changed files with 108 additions and 140 deletions

View file

@ -14,6 +14,7 @@ import (
"github.com/zelenin/go-tdlib/client" "github.com/zelenin/go-tdlib/client"
) )
const unknownCommand string = "Unknown command"
const notEnoughArguments string = "Not enough arguments" const notEnoughArguments string = "Not enough arguments"
const TelegramNotInitialized string = "Telegram connection is not initialized yet" const TelegramNotInitialized string = "Telegram connection is not initialized yet"
const TelegramAuthDone string = "Authorization is done already" const TelegramAuthDone string = "Authorization is done already"
@ -272,7 +273,7 @@ func (c *Client) ProcessTransportCommand(cmdline string, resource string) string
cmd, args := parseCommand(cmdline) cmd, args := parseCommand(cmdline)
command, ok := transportCommands[cmd] command, ok := transportCommands[cmd]
if !ok { if !ok {
return "Unknown command" return unknownCommand
} }
if len(args) < command.RequiredArgs { if len(args) < command.RequiredArgs {
return notEnoughArguments return notEnoughArguments
@ -498,6 +499,14 @@ func (c *Client) ProcessChatCommand(chatID int64, cmdline string) (string, bool)
} }
cmd, args := parseCommand(cmdline) cmd, args := parseCommand(cmdline)
command, ok := chatCommands[cmd]
if !ok {
return unknownCommand, false
}
if len(args) < command.RequiredArgs {
return notEnoughArguments, true
}
switch cmd { switch cmd {
// delete message // delete message
case "d": case "d":
@ -542,9 +551,6 @@ func (c *Client) ProcessChatCommand(chatID int64, cmdline string) (string, bool)
if c.me == nil { if c.me == nil {
return "@me is not initialized", true return "@me is not initialized", true
} }
if len(args) < 1 {
return "Not enough arguments", true
}
messages, err := c.getLastMessages(chatID, "", c.me.Id, 1) messages, err := c.getLastMessages(chatID, "", c.me.Id, 1)
if err != nil { if err != nil {
@ -575,10 +581,6 @@ func (c *Client) ProcessChatCommand(chatID int64, cmdline string) (string, bool)
} }
// send without sound // send without sound
case "silent": case "silent":
if len(args) < 1 {
return "Not enough arguments", true
}
content := c.PrepareOutgoingMessageContent(rawCmdArguments(cmdline, 0)) content := c.PrepareOutgoingMessageContent(rawCmdArguments(cmdline, 0))
if content != nil { if content != nil {
@ -597,10 +599,6 @@ func (c *Client) ProcessChatCommand(chatID int64, cmdline string) (string, bool)
} }
// schedule a message to timestamp or to going online // schedule a message to timestamp or to going online
case "schedule": case "schedule":
if len(args) < 2 {
return "Not enough arguments", true
}
var state client.MessageSchedulingState var state client.MessageSchedulingState
var result string var result string
due := args[0] due := args[0]
@ -677,10 +675,6 @@ func (c *Client) ProcessChatCommand(chatID int64, cmdline string) (string, bool)
} }
// forward a message to chat // forward a message to chat
case "forward": case "forward":
if len(args) < 2 {
return notEnoughArguments, true
}
messageId, err := strconv.ParseInt(args[0], 10, 64) messageId, err := strconv.ParseInt(args[0], 10, 64)
if err != nil { if err != nil {
return "Cannot parse message ID", true return "Cannot parse message ID", true
@ -742,10 +736,6 @@ func (c *Client) ProcessChatCommand(chatID int64, cmdline string) (string, bool)
} }
// create group chat with current user // create group chat with current user
case "group": case "group":
if len(args) < 1 {
return notEnoughArguments, true
}
_, err := c.client.CreateNewBasicGroupChat(&client.CreateNewBasicGroupChatRequest{ _, err := c.client.CreateNewBasicGroupChat(&client.CreateNewBasicGroupChatRequest{
UserIds: []int64{chatID}, UserIds: []int64{chatID},
Title: args[0], Title: args[0],
@ -773,10 +763,6 @@ func (c *Client) ProcessChatCommand(chatID int64, cmdline string) (string, bool)
} }
// invite @username to current groupchat // invite @username to current groupchat
case "invite": case "invite":
if len(args) < 1 {
return notEnoughArguments, true
}
contact, _, err := c.GetContactByUsername(args[0]) contact, _, err := c.GetContactByUsername(args[0])
if err != nil { if err != nil {
return err.Error(), true return err.Error(), true
@ -801,10 +787,6 @@ func (c *Client) ProcessChatCommand(chatID int64, cmdline string) (string, bool)
return link.InviteLink, true return link.InviteLink, true
// kick @username from current group chat // kick @username from current group chat
case "kick": case "kick":
if len(args) < 1 {
return notEnoughArguments, true
}
contact, _, err := c.GetContactByUsername(args[0]) contact, _, err := c.GetContactByUsername(args[0])
if err != nil { if err != nil {
return err.Error(), true return err.Error(), true
@ -820,10 +802,6 @@ func (c *Client) ProcessChatCommand(chatID int64, cmdline string) (string, bool)
} }
// mute @username [n hours] // mute @username [n hours]
case "mute": case "mute":
if len(args) < 1 {
return notEnoughArguments, true
}
contact, _, err := c.GetContactByUsername(args[0]) contact, _, err := c.GetContactByUsername(args[0])
if err != nil { if err != nil {
return err.Error(), true return err.Error(), true
@ -851,10 +829,6 @@ func (c *Client) ProcessChatCommand(chatID int64, cmdline string) (string, bool)
} }
// unmute @username // unmute @username
case "unmute": case "unmute":
if len(args) < 1 {
return notEnoughArguments, true
}
contact, _, err := c.GetContactByUsername(args[0]) contact, _, err := c.GetContactByUsername(args[0])
if err != nil { if err != nil {
return err.Error(), true return err.Error(), true
@ -874,10 +848,6 @@ func (c *Client) ProcessChatCommand(chatID int64, cmdline string) (string, bool)
} }
// ban @username from current chat [for N hours] // ban @username from current chat [for N hours]
case "ban": case "ban":
if len(args) < 1 {
return notEnoughArguments, true
}
contact, _, err := c.GetContactByUsername(args[0]) contact, _, err := c.GetContactByUsername(args[0])
if err != nil { if err != nil {
return err.Error(), true return err.Error(), true
@ -903,10 +873,6 @@ func (c *Client) ProcessChatCommand(chatID int64, cmdline string) (string, bool)
} }
// unban @username // unban @username
case "unban": case "unban":
if len(args) < 1 {
return notEnoughArguments, true
}
contact, _, err := c.GetContactByUsername(args[0]) contact, _, err := c.GetContactByUsername(args[0])
if err != nil { if err != nil {
return err.Error(), true return err.Error(), true
@ -922,10 +888,6 @@ func (c *Client) ProcessChatCommand(chatID int64, cmdline string) (string, bool)
} }
// promote @username to admin // promote @username to admin
case "promote": case "promote":
if len(args) < 1 {
return notEnoughArguments, true
}
contact, _, err := c.GetContactByUsername(args[0]) contact, _, err := c.GetContactByUsername(args[0])
if err != nil { if err != nil {
return err.Error(), true return err.Error(), true
@ -1133,10 +1095,6 @@ func (c *Client) ProcessChatCommand(chatID int64, cmdline string) (string, bool)
} }
func (c *Client) cmdAdd(args []string) string { func (c *Client) cmdAdd(args []string) string {
if len(args) < 1 {
return notEnoughArguments
}
chat, err := c.client.SearchPublicChat(&client.SearchPublicChatRequest{ chat, err := c.client.SearchPublicChat(&client.SearchPublicChatRequest{
Username: args[0], Username: args[0],
}) })
@ -1153,10 +1111,6 @@ func (c *Client) cmdAdd(args []string) string {
} }
func (c *Client) cmdJoin(args []string) string { func (c *Client) cmdJoin(args []string) string {
if len(args) < 1 {
return notEnoughArguments
}
if strings.HasPrefix(args[0], "@") { if strings.HasPrefix(args[0], "@") {
chat, err := c.client.SearchPublicChat(&client.SearchPublicChatRequest{ chat, err := c.client.SearchPublicChat(&client.SearchPublicChatRequest{
Username: args[0], Username: args[0],
@ -1186,10 +1140,6 @@ func (c *Client) cmdJoin(args []string) string {
} }
func (c *Client) cmdSupergroup(args []string, cmdline string) string { func (c *Client) cmdSupergroup(args []string, cmdline string) string {
if len(args) < 1 {
return notEnoughArguments
}
_, err := c.client.CreateNewSupergroupChat(&client.CreateNewSupergroupChatRequest{ _, err := c.client.CreateNewSupergroupChat(&client.CreateNewSupergroupChatRequest{
Title: args[0], Title: args[0],
Description: rawCmdArguments(cmdline, 1), Description: rawCmdArguments(cmdline, 1),
@ -1202,10 +1152,6 @@ func (c *Client) cmdSupergroup(args []string, cmdline string) string {
} }
func (c *Client) cmdChannel(args []string, cmdline string) string { func (c *Client) cmdChannel(args []string, cmdline string) string {
if len(args) < 1 {
return notEnoughArguments
}
_, err := c.client.CreateNewSupergroupChat(&client.CreateNewSupergroupChatRequest{ _, err := c.client.CreateNewSupergroupChat(&client.CreateNewSupergroupChatRequest{
Title: args[0], Title: args[0],
Description: rawCmdArguments(cmdline, 1), Description: rawCmdArguments(cmdline, 1),

View file

@ -490,23 +490,30 @@ func handleGetDiscoInfo(s xmpp.Sender, iq *stanza.IQ, di *stanza.DiscoInfo) {
disco := answer.DiscoInfo() disco := answer.DiscoInfo()
_, ok := toToID(iq.To) _, ok := toToID(iq.To)
if ok { if di.Node == "" {
disco.AddIdentity("", "account", "registered") if ok {
disco.AddFeatures(stanza.NSMsgChatMarkers) disco.AddIdentity("", "account", "registered")
disco.AddFeatures(stanza.NSMsgReceipts) disco.AddFeatures(stanza.NSMsgChatMarkers)
} else { disco.AddFeatures(stanza.NSMsgReceipts)
if di.Node == "" { } else {
disco.AddIdentity("Telegram Gateway", "gateway", "telegram") disco.AddIdentity("Telegram Gateway", "gateway", "telegram")
disco.AddFeatures("jabber:iq:register") disco.AddFeatures("jabber:iq:register")
disco.AddFeatures(NSCommand) }
disco.AddFeatures(NSCommand)
} else {
var cmdType telegram.CommandType
if ok {
cmdType = telegram.CommandTypeChat
} else { } else {
for name, command := range telegram.GetCommands(telegram.CommandTypeTransport) { cmdType = telegram.CommandTypeTransport
if di.Node == name { }
answer.Payload = di
di.AddIdentity(telegram.CommandToHelpString(name, command), "automation", "command-node") for name, command := range telegram.GetCommands(cmdType) {
di.AddFeatures(NSCommand, "jabber:x:data") if di.Node == name {
break answer.Payload = di
} di.AddIdentity(telegram.CommandToHelpString(name, command), "automation", "command-node")
di.AddFeatures(NSCommand, "jabber:x:data")
break
} }
} }
} }
@ -539,16 +546,22 @@ func handleGetDiscoItems(s xmpp.Sender, iq *stanza.IQ, di *stanza.DiscoItems) {
log.Debugf("discoItems: %#v", di) log.Debugf("discoItems: %#v", di)
_, ok := toToID(iq.To) _, ok := toToID(iq.To)
if !ok { if di.Node == NSCommand {
commands := telegram.GetCommands(telegram.CommandTypeTransport) answer.Payload = di
if di.Node == NSCommand {
answer.Payload = di var cmdType telegram.CommandType
for name, command := range commands { if ok {
di.AddItem(iq.To, name, telegram.CommandToHelpString(name, command)) cmdType = telegram.CommandTypeChat
}
} else { } else {
answer.Payload = answer.DiscoItems() cmdType = telegram.CommandTypeTransport
} }
commands := telegram.GetCommands(cmdType)
for name, command := range commands {
di.AddItem(iq.To, name, telegram.CommandToHelpString(name, command))
}
} else {
answer.Payload = answer.DiscoItems()
} }
component, ok := s.(*xmpp.Component) component, ok := s.(*xmpp.Component)
@ -706,66 +719,70 @@ func handleSetQueryCommand(s xmpp.Sender, iq *stanza.IQ, command *stanza.Command
if !ok { if !ok {
return return
} }
_, toOk := toToID(iq.To) toId, toOk := toToID(iq.To)
var cmdString string var cmdString string
if !toOk { var cmdType telegram.CommandType
form, formOk := command.CommandElement.(*stanza.Form) form, formOk := command.CommandElement.(*stanza.Form)
if formOk { if toOk {
// just for the case the client messed the order somehow cmdType = telegram.CommandTypeChat
sort.Slice(form.Fields, func(i int, j int) bool { } else {
iField := form.Fields[i] cmdType = telegram.CommandTypeTransport
jField := form.Fields[j] }
if iField != nil && jField != nil { if formOk {
ii, iErr := strconv.ParseInt(iField.Var, 10, 64) // just for the case the client messed the order somehow
ji, jErr := strconv.ParseInt(jField.Var, 10, 64) sort.Slice(form.Fields, func(i int, j int) bool {
return iErr == nil && jErr == nil && ii < ji iField := form.Fields[i]
} jField := form.Fields[j]
return false if iField != nil && jField != nil {
}) ii, iErr := strconv.ParseInt(iField.Var, 10, 64)
ji, jErr := strconv.ParseInt(jField.Var, 10, 64)
var cmd strings.Builder return iErr == nil && jErr == nil && ii < ji
cmd.WriteString("/")
cmd.WriteString(command.Node)
for _, field := range form.Fields {
cmd.WriteString(" ")
if len(field.ValuesList) > 0 {
cmd.WriteString(field.ValuesList[0])
}
} }
return false
})
cmdString = cmd.String() var cmd strings.Builder
} else { cmd.WriteString("/")
if command.Action == "" || command.Action == stanza.CommandActionExecute { cmd.WriteString(command.Node)
cmd, ok := telegram.GetCommand(telegram.CommandTypeTransport, command.Node) for _, field := range form.Fields {
if ok && cmd.RequiredArgs > 0 { cmd.WriteString(" ")
var fields []*stanza.Field if len(field.ValuesList) > 0 {
for i, arg := range cmd.Arguments { cmd.WriteString(field.ValuesList[0])
fields = append(fields, &stanza.Field{ }
Var: strconv.FormatInt(int64(i), 10), }
Label: arg,
}) cmdString = cmd.String()
} } else {
answer.Payload = &stanza.Command{ if command.Action == "" || command.Action == stanza.CommandActionExecute {
SessionId: command.Node, cmd, ok := telegram.GetCommand(cmdType, command.Node)
Node: command.Node, if ok && len(cmd.Arguments) > 0 {
Status: stanza.CommandStatusExecuting, var fields []*stanza.Field
CommandElement: &stanza.Form{ for i, arg := range cmd.Arguments {
Type: stanza.FormTypeForm, fields = append(fields, &stanza.Field{
Title: command.Node, Var: strconv.FormatInt(int64(i), 10),
Instructions: []string{cmd.Description}, Label: arg,
Fields: fields, })
},
}
} else {
cmdString = "/" + command.Node
} }
} else if command.Action == stanza.CommandActionCancel {
answer.Payload = &stanza.Command{ answer.Payload = &stanza.Command{
SessionId: command.Node, SessionId: command.Node,
Node: command.Node, Node: command.Node,
Status: stanza.CommandStatusCancelled, Status: stanza.CommandStatusExecuting,
CommandElement: &stanza.Form{
Type: stanza.FormTypeForm,
Title: command.Node,
Instructions: []string{cmd.Description},
Fields: fields,
},
} }
} else {
cmdString = "/" + command.Node
}
} else if command.Action == stanza.CommandActionCancel {
answer.Payload = &stanza.Command{
SessionId: command.Node,
Node: command.Node,
Status: stanza.CommandStatusCancelled,
} }
} }
} }
@ -776,7 +793,12 @@ func handleSetQueryCommand(s xmpp.Sender, iq *stanza.IQ, command *stanza.Command
return return
} }
response := session.ProcessTransportCommand(cmdString, resource) var response string
if toOk {
response, _ = session.ProcessChatCommand(toId, cmdString)
} else {
response = session.ProcessTransportCommand(cmdString, resource)
}
answer.Payload = &stanza.Command{ answer.Payload = &stanza.Command{
SessionId: command.Node, SessionId: command.Node,