Basic Ad-Hoc support for transport commands
This commit is contained in:
parent
20e6d2558e
commit
fd0d7411c2
2
go.mod
2
go.mod
|
@ -33,5 +33,5 @@ require (
|
|||
nhooyr.io/websocket v1.6.5 // indirect
|
||||
)
|
||||
|
||||
replace gosrc.io/xmpp => dev.narayana.im/narayana/go-xmpp v0.0.0-20220524203317-306b4ff58e8f
|
||||
replace gosrc.io/xmpp => dev.narayana.im/narayana/go-xmpp v0.0.0-20240131013505-18c46e6c59fd
|
||||
replace github.com/zelenin/go-tdlib => dev.narayana.im/narayana/go-tdlib v0.0.0-20240124222245-b4c12addb061
|
||||
|
|
2
go.sum
2
go.sum
|
@ -7,6 +7,8 @@ dev.narayana.im/narayana/go-tdlib v0.0.0-20240124222245-b4c12addb061 h1:CWAQT74L
|
|||
dev.narayana.im/narayana/go-tdlib v0.0.0-20240124222245-b4c12addb061/go.mod h1:Xs8fXbk5n7VaPyrSs9DP7QYoBScWYsjX+lUcWmx1DIU=
|
||||
dev.narayana.im/narayana/go-xmpp v0.0.0-20220524203317-306b4ff58e8f h1:6249ajbMjgYz53Oq0IjTvjHXbxTfu29Mj1J/6swRHs4=
|
||||
dev.narayana.im/narayana/go-xmpp v0.0.0-20220524203317-306b4ff58e8f/go.mod h1:L3NFMqYOxyLz3JGmgFyWf7r9htE91zVGiK40oW4RwdY=
|
||||
dev.narayana.im/narayana/go-xmpp v0.0.0-20240131013505-18c46e6c59fd h1:+UW+E7JjI88aH4beDn1cw6D8rs1I061hN91HU4Y4pT8=
|
||||
dev.narayana.im/narayana/go-xmpp v0.0.0-20240131013505-18c46e6c59fd/go.mod h1:L3NFMqYOxyLz3JGmgFyWf7r9htE91zVGiK40oW4RwdY=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/agnivade/wasmbrowsertest v0.3.1/go.mod h1:zQt6ZTdl338xxRaMW395qccVE2eQm0SjC/SDz0mPWQI=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
|
|
|
@ -48,6 +48,7 @@ var permissionsMember = client.ChatPermissions{
|
|||
var permissionsReadonly = client.ChatPermissions{}
|
||||
|
||||
var transportCommands = map[string]command{
|
||||
"help": command{"", "help"},
|
||||
"login": command{"phone", "sign in"},
|
||||
"logout": command{"", "sign out"},
|
||||
"cancelauth": command{"", "quit the signin wizard"},
|
||||
|
@ -66,6 +67,7 @@ var transportCommands = map[string]command{
|
|||
}
|
||||
|
||||
var chatCommands = map[string]command{
|
||||
"help": command{"", "help"},
|
||||
"d": command{"[n]", "delete your last message(s)"},
|
||||
"s": command{"edited message", "edit your last message"},
|
||||
"silent": command{"message", "send a message without sound"},
|
||||
|
@ -110,38 +112,56 @@ type command struct {
|
|||
}
|
||||
type configurationOption command
|
||||
|
||||
type helpType int
|
||||
// CommandType disinguishes command sets by chat
|
||||
type CommandType int
|
||||
|
||||
const (
|
||||
helpTypeTransport helpType = iota
|
||||
helpTypeChat
|
||||
CommandTypeTransport CommandType = iota
|
||||
CommandTypeChat
|
||||
)
|
||||
|
||||
func helpString(ht helpType) string {
|
||||
var str strings.Builder
|
||||
// GetCommands exposes the set of commands
|
||||
func GetCommands(typ CommandType) map[string]command {
|
||||
var commandMap map[string]command
|
||||
|
||||
switch ht {
|
||||
case helpTypeTransport:
|
||||
switch typ {
|
||||
case CommandTypeTransport:
|
||||
commandMap = transportCommands
|
||||
case helpTypeChat:
|
||||
case CommandTypeChat:
|
||||
commandMap = chatCommands
|
||||
}
|
||||
|
||||
return commandMap
|
||||
}
|
||||
|
||||
// CommandToHelpString builds a text description of a command
|
||||
func CommandToHelpString(name string, cmd command) string {
|
||||
var str strings.Builder
|
||||
|
||||
str.WriteString("/")
|
||||
str.WriteString(name)
|
||||
if cmd.arguments != "" {
|
||||
str.WriteString(" ")
|
||||
str.WriteString(cmd.arguments)
|
||||
}
|
||||
str.WriteString(" — ")
|
||||
str.WriteString(cmd.description)
|
||||
|
||||
return str.String()
|
||||
}
|
||||
|
||||
func helpString(typ CommandType) string {
|
||||
var str strings.Builder
|
||||
|
||||
commandMap := GetCommands(typ)
|
||||
|
||||
str.WriteString("Available commands:\n")
|
||||
for name, command := range commandMap {
|
||||
str.WriteString("/")
|
||||
str.WriteString(name)
|
||||
if command.arguments != "" {
|
||||
str.WriteString(" ")
|
||||
str.WriteString(command.arguments)
|
||||
}
|
||||
str.WriteString(" — ")
|
||||
str.WriteString(command.description)
|
||||
str.WriteString(CommandToHelpString(name, command))
|
||||
str.WriteString("\n")
|
||||
}
|
||||
|
||||
if ht == helpTypeTransport {
|
||||
if typ == CommandTypeTransport {
|
||||
str.WriteString("Configuration options\n")
|
||||
for name, option := range transportConfigurationOptions {
|
||||
str.WriteString(name)
|
||||
|
@ -448,7 +468,7 @@ func (c *Client) ProcessTransportCommand(cmdline string, resource string) string
|
|||
case "channel":
|
||||
return c.cmdChannel(args, cmdline)
|
||||
case "help":
|
||||
return helpString(helpTypeTransport)
|
||||
return helpString(CommandTypeTransport)
|
||||
}
|
||||
|
||||
return ""
|
||||
|
@ -1088,7 +1108,7 @@ func (c *Client) ProcessChatCommand(chatID int64, cmdline string) (string, bool)
|
|||
|
||||
return strings.Join(entries, "\n"), true
|
||||
case "help":
|
||||
return helpString(helpTypeChat), true
|
||||
return helpString(CommandTypeChat), true
|
||||
default:
|
||||
return "", false
|
||||
}
|
||||
|
|
100
xmpp/handlers.go
100
xmpp/handlers.go
|
@ -26,6 +26,7 @@ const (
|
|||
TypeVCard4
|
||||
)
|
||||
const NodeVCard4 string = "urn:xmpp:vcard4"
|
||||
const NSCommand string = "http://jabber.org/protocol/commands"
|
||||
|
||||
func logPacketType(p stanza.Packet) {
|
||||
log.Warnf("Ignoring packet: %T\n", p)
|
||||
|
@ -53,14 +54,14 @@ func HandleIq(s xmpp.Sender, p stanza.Packet) {
|
|||
return
|
||||
}
|
||||
}
|
||||
_, ok = iq.Payload.(*stanza.DiscoInfo)
|
||||
discoInfo, ok := iq.Payload.(*stanza.DiscoInfo)
|
||||
if ok {
|
||||
go handleGetDiscoInfo(s, iq)
|
||||
go handleGetDiscoInfo(s, iq, discoInfo)
|
||||
return
|
||||
}
|
||||
_, ok = iq.Payload.(*stanza.DiscoItems)
|
||||
discoItems, ok := iq.Payload.(*stanza.DiscoItems)
|
||||
if ok {
|
||||
go handleGetDiscoItems(s, iq)
|
||||
go handleGetDiscoItems(s, iq, discoItems)
|
||||
return
|
||||
}
|
||||
_, ok = iq.Payload.(*extensions.QueryRegister)
|
||||
|
@ -74,6 +75,11 @@ func HandleIq(s xmpp.Sender, p stanza.Packet) {
|
|||
go handleSetQueryRegister(s, iq, query)
|
||||
return
|
||||
}
|
||||
command, ok := iq.Payload.(*stanza.Command)
|
||||
if ok {
|
||||
go handleSetQueryCommand(s, iq, command)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -468,7 +474,7 @@ func handleGetVcardIq(s xmpp.Sender, iq *stanza.IQ, typ byte) {
|
|||
_ = gateway.ResumableSend(component, &answer)
|
||||
}
|
||||
|
||||
func handleGetDiscoInfo(s xmpp.Sender, iq *stanza.IQ) {
|
||||
func handleGetDiscoInfo(s xmpp.Sender, iq *stanza.IQ, di *stanza.DiscoInfo) {
|
||||
answer, err := stanza.NewIQ(stanza.Attrs{
|
||||
Type: stanza.IQTypeResult,
|
||||
From: iq.To,
|
||||
|
@ -488,8 +494,20 @@ func handleGetDiscoInfo(s xmpp.Sender, iq *stanza.IQ) {
|
|||
disco.AddFeatures(stanza.NSMsgChatMarkers)
|
||||
disco.AddFeatures(stanza.NSMsgReceipts)
|
||||
} else {
|
||||
disco.AddIdentity("Telegram Gateway", "gateway", "telegram")
|
||||
disco.AddFeatures("jabber:iq:register")
|
||||
if di.Node == "" {
|
||||
disco.AddIdentity("Telegram Gateway", "gateway", "telegram")
|
||||
disco.AddFeatures("jabber:iq:register")
|
||||
disco.AddFeatures(NSCommand)
|
||||
} else {
|
||||
for name, command := range telegram.GetCommands(telegram.CommandTypeTransport) {
|
||||
if di.Node == name {
|
||||
answer.Payload = di
|
||||
di.AddIdentity(telegram.CommandToHelpString(name, command), "automation", "command-node")
|
||||
di.AddFeatures(NSCommand, "jabber:x:data")
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
answer.Payload = disco
|
||||
|
||||
|
@ -504,7 +522,7 @@ func handleGetDiscoInfo(s xmpp.Sender, iq *stanza.IQ) {
|
|||
_ = gateway.ResumableSend(component, answer)
|
||||
}
|
||||
|
||||
func handleGetDiscoItems(s xmpp.Sender, iq *stanza.IQ) {
|
||||
func handleGetDiscoItems(s xmpp.Sender, iq *stanza.IQ, di *stanza.DiscoItems) {
|
||||
answer, err := stanza.NewIQ(stanza.Attrs{
|
||||
Type: stanza.IQTypeResult,
|
||||
From: iq.To,
|
||||
|
@ -517,7 +535,20 @@ func handleGetDiscoItems(s xmpp.Sender, iq *stanza.IQ) {
|
|||
return
|
||||
}
|
||||
|
||||
answer.Payload = answer.DiscoItems()
|
||||
log.Debugf("discoItems: %#v", di)
|
||||
|
||||
_, ok := toToID(iq.To)
|
||||
if !ok {
|
||||
commands := telegram.GetCommands(telegram.CommandTypeTransport)
|
||||
if di.Node == NSCommand {
|
||||
answer.Payload = di
|
||||
for name, command := range commands {
|
||||
di.AddItem(iq.To, name, telegram.CommandToHelpString(name, command))
|
||||
}
|
||||
} else {
|
||||
answer.Payload = answer.DiscoItems()
|
||||
}
|
||||
}
|
||||
|
||||
component, ok := s.(*xmpp.Component)
|
||||
if !ok {
|
||||
|
@ -647,6 +678,57 @@ func handleSetQueryRegister(s xmpp.Sender, iq *stanza.IQ, query *extensions.Quer
|
|||
}
|
||||
}
|
||||
|
||||
func handleSetQueryCommand(s xmpp.Sender, iq *stanza.IQ, command *stanza.Command) {
|
||||
component, ok := s.(*xmpp.Component)
|
||||
if !ok {
|
||||
log.Error("Not a component")
|
||||
return
|
||||
}
|
||||
|
||||
answer, err := stanza.NewIQ(stanza.Attrs{
|
||||
Type: stanza.IQTypeResult,
|
||||
From: iq.To,
|
||||
To: iq.From,
|
||||
Id: iq.Id,
|
||||
Lang: "en",
|
||||
})
|
||||
if err != nil {
|
||||
log.Errorf("Failed to create answer IQ: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
defer gateway.ResumableSend(component, answer)
|
||||
|
||||
log.Debugf("command: %#v", command)
|
||||
|
||||
if command.Action == "" || command.Action == stanza.CommandActionExecute {
|
||||
_, ok := toToID(iq.To)
|
||||
if !ok {
|
||||
bare, resource, ok := gateway.SplitJID(iq.From)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
session, ok := sessions[bare]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
response := session.ProcessTransportCommand("/" + command.Node, resource)
|
||||
|
||||
answer.Payload = &stanza.Command{
|
||||
Node: command.Node,
|
||||
Status: stanza.CommandStatusCompleted,
|
||||
CommandElement: &stanza.Note{
|
||||
Text: response,
|
||||
Type: stanza.CommandNoteTypeInfo,
|
||||
},
|
||||
}
|
||||
log.Debugf("command response: %#v", answer.Payload)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func iqAnswerSetError(answer *stanza.IQ, payload *extensions.QueryRegister, code int) {
|
||||
answer.Type = stanza.IQTypeError
|
||||
answer.Payload = *payload
|
||||
|
|
Loading…
Reference in a new issue