[TASK] improve client + bot (new status version of server)
This commit is contained in:
parent
7d73d323a6
commit
4732e0d292
|
@ -13,6 +13,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (client *Client) auth(password string) error {
|
func (client *Client) auth(password string) error {
|
||||||
|
logCTX := client.Logging.WithField("type", "auth")
|
||||||
f, err := client.startStream()
|
f, err := client.startStream()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -22,7 +23,7 @@ func (client *Client) auth(password string) error {
|
||||||
challenge := &xmpp.SASLChallenge{}
|
challenge := &xmpp.SASLChallenge{}
|
||||||
response := &xmpp.SASLResponse{}
|
response := &xmpp.SASLResponse{}
|
||||||
for _, m := range f.Mechanisms.Mechanism {
|
for _, m := range f.Mechanisms.Mechanism {
|
||||||
client.Logging.Debugf("try auth with '%s'", m)
|
logCTX.Infof("try auth with '%s'", m)
|
||||||
if m == "SCRAM-SHA-1" {
|
if m == "SCRAM-SHA-1" {
|
||||||
/*
|
/*
|
||||||
mechanism = m
|
mechanism = m
|
||||||
|
@ -86,7 +87,7 @@ func (client *Client) auth(password string) error {
|
||||||
if mechanism == "" {
|
if mechanism == "" {
|
||||||
return fmt.Errorf("PLAIN authentication is not an option: %s", f.Mechanisms.Mechanism)
|
return fmt.Errorf("PLAIN authentication is not an option: %s", f.Mechanisms.Mechanism)
|
||||||
}
|
}
|
||||||
client.Logging.Infof("used auth with '%s'", mechanism)
|
logCTX.Infof("used auth with '%s'", mechanism)
|
||||||
|
|
||||||
element, err := client.Read()
|
element, err := client.Read()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -22,23 +22,20 @@ type Client struct {
|
||||||
out *xml.Encoder
|
out *xml.Encoder
|
||||||
in *xml.Decoder
|
in *xml.Decoder
|
||||||
|
|
||||||
Logging *log.Logger
|
Logging *log.Entry
|
||||||
|
|
||||||
JID *xmppbase.JID
|
JID *xmppbase.JID
|
||||||
|
|
||||||
|
SkipError bool
|
||||||
|
msg chan interface{}
|
||||||
reply map[string]chan *xmpp.IQClient
|
reply map[string]chan *xmpp.IQClient
|
||||||
|
|
||||||
skipError bool
|
|
||||||
iq chan *xmpp.IQClient
|
|
||||||
presence chan *xmpp.PresenceClient
|
|
||||||
mesage chan *xmpp.MessageClient
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClient(jid *xmppbase.JID, password string) (*Client, error) {
|
func NewClient(jid *xmppbase.JID, password string) (*Client, error) {
|
||||||
client := &Client{
|
client := &Client{
|
||||||
Protocol: "tcp",
|
Protocol: "tcp",
|
||||||
JID: jid,
|
JID: jid,
|
||||||
Logging: log.New(),
|
Logging: log.New().WithField("jid", jid.String()),
|
||||||
}
|
}
|
||||||
return client, client.Connect(password)
|
return client, client.Connect(password)
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,6 @@ func (client *Client) Read() (*xml.StartElement, error) {
|
||||||
switch nextToken.(type) {
|
switch nextToken.(type) {
|
||||||
case xml.StartElement:
|
case xml.StartElement:
|
||||||
element := nextToken.(xml.StartElement)
|
element := nextToken.(xml.StartElement)
|
||||||
client.Logging.Debug("recv xml: ", xmpp.XMLStartElementToString(&element))
|
|
||||||
return &element, nil
|
return &element, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,11 +22,15 @@ func (client *Client) Read() (*xml.StartElement, error) {
|
||||||
func (client *Client) Decode(p interface{}, element *xml.StartElement) error {
|
func (client *Client) Decode(p interface{}, element *xml.StartElement) error {
|
||||||
err := client.in.DecodeElement(p, element)
|
err := client.in.DecodeElement(p, element)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
client.Logging.Debugf("decode failed xml: %s to: %v", xmpp.XMLStartElementToString(element), p)
|
|
||||||
} else {
|
|
||||||
client.Logging.Debugf("decode xml: %s to: %v with children %s", xmpp.XMLStartElementToString(element), p, xmpp.XMLChildrenString(p))
|
|
||||||
}
|
|
||||||
return err
|
return err
|
||||||
|
} else {
|
||||||
|
if b, err := xml.Marshal(p); err == nil {
|
||||||
|
client.Logging.Debugf("decode %v", string(b))
|
||||||
|
} else {
|
||||||
|
client.Logging.Debugf("decode %v", p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
func (client *Client) ReadDecode(p interface{}) error {
|
func (client *Client) ReadDecode(p interface{}) error {
|
||||||
element, err := client.Read()
|
element, err := client.Read()
|
||||||
|
@ -41,7 +44,7 @@ func (client *Client) ReadDecode(p interface{}) error {
|
||||||
}
|
}
|
||||||
err = client.Decode(iq, element)
|
err = client.Decode(iq, element)
|
||||||
if err == nil && iq.Ping != nil {
|
if err == nil && iq.Ping != nil {
|
||||||
client.Logging.Info("ReadElement: auto answer ping")
|
client.Logging.Info("client.ReadElement: auto answer ping")
|
||||||
iq.Type = xmpp.IQTypeResult
|
iq.Type = xmpp.IQTypeResult
|
||||||
iq.To = iq.From
|
iq.To = iq.From
|
||||||
iq.From = client.JID
|
iq.From = client.JID
|
||||||
|
@ -56,11 +59,15 @@ func (client *Client) ReadDecode(p interface{}) error {
|
||||||
func (client *Client) encode(p interface{}) error {
|
func (client *Client) encode(p interface{}) error {
|
||||||
err := client.out.Encode(p)
|
err := client.out.Encode(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
client.Logging.Debugf("encode failed %v", p)
|
|
||||||
} else {
|
|
||||||
client.Logging.Debugf("encode %v with children %s", p, xmpp.XMLChildrenString(p))
|
|
||||||
}
|
|
||||||
return err
|
return err
|
||||||
|
} else {
|
||||||
|
if b, err := xml.Marshal(p); err == nil {
|
||||||
|
client.Logging.Debugf("encode %v", string(b))
|
||||||
|
} else {
|
||||||
|
client.Logging.Debugf("encode %v", p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (client *Client) Send(p interface{}) error {
|
func (client *Client) Send(p interface{}) error {
|
||||||
|
|
|
@ -19,6 +19,7 @@ func (client *Client) setConnection(conn net.Conn) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (client *Client) startStream() (*xmpp.StreamFeatures, error) {
|
func (client *Client) startStream() (*xmpp.StreamFeatures, error) {
|
||||||
|
logCTX := client.Logging.WithField("type", "stream")
|
||||||
// XMPP-Connection
|
// XMPP-Connection
|
||||||
_, err := fmt.Fprintf(client.conn, "<?xml version='1.0'?>\n"+
|
_, err := fmt.Fprintf(client.conn, "<?xml version='1.0'?>\n"+
|
||||||
"<stream:stream to='%s' xmlns='%s'\n"+
|
"<stream:stream to='%s' xmlns='%s'\n"+
|
||||||
|
@ -38,7 +39,7 @@ func (client *Client) startStream() (*xmpp.StreamFeatures, error) {
|
||||||
if err := client.ReadDecode(f); err != nil {
|
if err := client.ReadDecode(f); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
debug := "stream start >"
|
debug := "start >"
|
||||||
if f.StartTLS != nil {
|
if f.StartTLS != nil {
|
||||||
debug += " tls"
|
debug += " tls"
|
||||||
}
|
}
|
||||||
|
@ -56,7 +57,7 @@ func (client *Client) startStream() (*xmpp.StreamFeatures, error) {
|
||||||
if f.Bind != nil {
|
if f.Bind != nil {
|
||||||
debug += " bind"
|
debug += " bind"
|
||||||
}
|
}
|
||||||
client.Logging.Info(debug)
|
logCTX.Info(debug)
|
||||||
return f, nil
|
return f, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,10 +124,10 @@ func (client *Client) connect(password string) error {
|
||||||
client.JID.Local = bind.JID.Local
|
client.JID.Local = bind.JID.Local
|
||||||
client.JID.Domain = bind.JID.Domain
|
client.JID.Domain = bind.JID.Domain
|
||||||
client.JID.Resource = bind.JID.Resource
|
client.JID.Resource = bind.JID.Resource
|
||||||
client.Logging.Infof("set jid by server bind '%s'", bind.JID.Full())
|
client.Logging.WithField("type", "bind").Infof("set jid by server bind '%s'", bind.JID.Full())
|
||||||
} else if bind.Resource != "" {
|
} else if bind.Resource != "" {
|
||||||
client.JID.Resource = bind.Resource
|
client.JID.Resource = bind.Resource
|
||||||
client.Logging.Infof("set resource by server bind '%s'", bind.Resource)
|
client.Logging.WithField("type", "bind").Infof("set resource by server bind '%s'", bind.Resource)
|
||||||
} else {
|
} else {
|
||||||
return errors.New("bind>jid is nil" + xmpp.XMLChildrenString(bind))
|
return errors.New("bind>jid is nil" + xmpp.XMLChildrenString(bind))
|
||||||
}
|
}
|
||||||
|
|
123
client/start.go
123
client/start.go
|
@ -1,6 +1,7 @@
|
||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"dev.sum7.eu/genofire/yaja/xmpp"
|
"dev.sum7.eu/genofire/yaja/xmpp"
|
||||||
|
@ -9,10 +10,24 @@ import (
|
||||||
var DefaultChannelSize = 30
|
var DefaultChannelSize = 30
|
||||||
|
|
||||||
func (client *Client) Start() error {
|
func (client *Client) Start() error {
|
||||||
client.iq = make(chan *xmpp.IQClient, DefaultChannelSize)
|
if client.msg == nil {
|
||||||
client.presence = make(chan *xmpp.PresenceClient, DefaultChannelSize)
|
client.msg = make(chan interface{}, DefaultChannelSize)
|
||||||
client.mesage = make(chan *xmpp.MessageClient, DefaultChannelSize)
|
}
|
||||||
|
if client.reply == nil {
|
||||||
client.reply = make(map[string]chan *xmpp.IQClient)
|
client.reply = make(map[string]chan *xmpp.IQClient)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
for id, ch := range client.reply {
|
||||||
|
delete(client.reply, id)
|
||||||
|
close(ch)
|
||||||
|
}
|
||||||
|
client.reply = nil
|
||||||
|
close(client.msg)
|
||||||
|
client.Logging.Info("client.Start: close")
|
||||||
|
}()
|
||||||
|
|
||||||
|
client.Logging.Info("client.Start: start")
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
|
||||||
|
@ -20,6 +35,7 @@ func (client *Client) Start() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
client.Logging.Debugf("client.Start: recv msg %v", xmpp.XMLStartElementToString(element))
|
||||||
|
|
||||||
errMSG := &xmpp.StreamError{}
|
errMSG := &xmpp.StreamError{}
|
||||||
err = client.Decode(errMSG, element)
|
err = client.Decode(errMSG, element)
|
||||||
|
@ -31,21 +47,29 @@ func (client *Client) Start() error {
|
||||||
err = client.Decode(iq, element)
|
err = client.Decode(iq, element)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if iq.Ping != nil {
|
if iq.Ping != nil {
|
||||||
client.Logging.Debug("answer ping")
|
client.Logging.Info("client.Start: answer ping")
|
||||||
iq.Type = xmpp.IQTypeResult
|
iq.Type = xmpp.IQTypeResult
|
||||||
iq.To = iq.From
|
iq.To = iq.From
|
||||||
iq.From = client.JID
|
iq.From = client.JID
|
||||||
client.Send(iq)
|
client.Send(iq)
|
||||||
} else {
|
} else {
|
||||||
if client.skipError && iq.Error != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if ch, ok := client.reply[iq.ID]; ok {
|
if ch, ok := client.reply[iq.ID]; ok {
|
||||||
delete(client.reply, iq.ID)
|
delete(client.reply, iq.ID)
|
||||||
ch <- iq
|
//TODO is this usefull?
|
||||||
|
go func() { ch <- iq }()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
client.iq <- iq
|
if client.SkipError && iq.Error != nil {
|
||||||
|
errStr, err := errorString(iq.Error)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if errStr != "" {
|
||||||
|
client.Logging.WithField("to", iq.To.String()).Error(errStr)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
client.msg <- iq
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -53,45 +77,84 @@ func (client *Client) Start() error {
|
||||||
pres := &xmpp.PresenceClient{}
|
pres := &xmpp.PresenceClient{}
|
||||||
err = client.Decode(pres, element)
|
err = client.Decode(pres, element)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if client.skipError && pres.Error != nil {
|
if client.SkipError && pres.Error != nil {
|
||||||
|
errStr, err := errorString(pres.Error)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if errStr != "" {
|
||||||
|
client.Logging.WithField("to", pres.To.String()).Error(errStr)
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
client.presence <- pres
|
client.msg <- pres
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
msg := &xmpp.MessageClient{}
|
msg := &xmpp.MessageClient{}
|
||||||
err = client.Decode(msg, element)
|
err = client.Decode(msg, element)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if client.skipError && msg.Error != nil {
|
if client.SkipError && msg.Error != nil {
|
||||||
|
errStr, err := errorString(msg.Error)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if errStr != "" {
|
||||||
|
client.Logging.WithField("to", msg.To.String()).Error(errStr)
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
client.mesage <- msg
|
client.msg <- msg
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
client.Logging.Warnf("unsupport xml recv: %v", element)
|
client.Logging.Warnf("unsupport xml recv: %v", element)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
func errorString(e *xmpp.ErrorClient) (string, error) {
|
||||||
func (client *Client) SendRecv(iq *xmpp.IQClient) *xmpp.IQClient {
|
str := fmt.Sprintf("[%s] %s", e.Type, xmpp.XMLChildrenString(e))
|
||||||
if iq.ID == "" {
|
if e.Text != nil {
|
||||||
iq.ID = xmpp.CreateCookieString()
|
str = fmt.Sprintf("[%s] %s -> %s", e.Type, e.Text.Body, xmpp.XMLChildrenString(e))
|
||||||
}
|
}
|
||||||
ch := make(chan *xmpp.IQClient, 1)
|
if e.Type == xmpp.ErrorTypeAuth {
|
||||||
client.reply[iq.ID] = ch
|
return "", errors.New(str)
|
||||||
client.Send(iq)
|
}
|
||||||
defer close(ch)
|
if e.RemoteServerNotFound != nil {
|
||||||
return <-ch
|
return "", nil
|
||||||
|
}
|
||||||
|
return str, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (client *Client) RecvIQ() *xmpp.IQClient {
|
func (client *Client) SendRecv(sendIQ *xmpp.IQClient) (*xmpp.IQClient, error) {
|
||||||
return <-client.iq
|
if sendIQ.ID == "" {
|
||||||
|
sendIQ.ID = xmpp.CreateCookieString()
|
||||||
|
}
|
||||||
|
ch := make(chan *xmpp.IQClient)
|
||||||
|
if client.reply == nil {
|
||||||
|
return nil, errors.New("client.SendRecv: not init (run client.Start)")
|
||||||
|
}
|
||||||
|
if client.reply == nil {
|
||||||
|
client.reply = make(map[string]chan *xmpp.IQClient)
|
||||||
|
}
|
||||||
|
client.reply[sendIQ.ID] = ch
|
||||||
|
client.Send(sendIQ)
|
||||||
|
iq := <-ch
|
||||||
|
close(ch)
|
||||||
|
if iq.Error != nil {
|
||||||
|
_, err := errorString(iq.Error)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return iq, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (client *Client) RecvPresence() *xmpp.PresenceClient {
|
func (client *Client) Recv() (msg interface{}, more bool) {
|
||||||
return <-client.presence
|
if client == nil {
|
||||||
}
|
return nil, false
|
||||||
|
}
|
||||||
func (client *Client) RecvMessage() *xmpp.MessageClient {
|
if client.msg == nil {
|
||||||
return <-client.mesage
|
client.msg = make(chan interface{}, DefaultChannelSize)
|
||||||
|
}
|
||||||
|
msg, more = <-client.msg
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,12 +42,12 @@ var TesterCMD = &cobra.Command{
|
||||||
testerInstance.LoggingBots = configTester.LoggingBots
|
testerInstance.LoggingBots = configTester.LoggingBots
|
||||||
clientLogger := log.New()
|
clientLogger := log.New()
|
||||||
clientLogger.SetLevel(configTester.LoggingClients)
|
clientLogger.SetLevel(configTester.LoggingClients)
|
||||||
testerInstance.LoggingClients = clientLogger
|
testerInstance.LoggingClients = clientLogger.WithField("log", "client")
|
||||||
|
|
||||||
mainClient := &client.Client{
|
mainClient := &client.Client{
|
||||||
JID: configTester.Client.JID,
|
JID: configTester.Client.JID,
|
||||||
Timeout: configTester.Timeout.Duration,
|
Timeout: configTester.Timeout.Duration,
|
||||||
Logging: clientLogger,
|
Logging: clientLogger.WithField("jid", configTester.Client.JID.String()),
|
||||||
}
|
}
|
||||||
err := mainClient.Connect(configTester.Client.Password)
|
err := mainClient.Connect(configTester.Client.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -10,49 +10,37 @@ import (
|
||||||
"dev.sum7.eu/genofire/yaja/xmpp/base"
|
"dev.sum7.eu/genofire/yaja/xmpp/base"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (t *Tester) StartBot(status *Status) {
|
func (t *Tester) startBot(status *Status) {
|
||||||
logger := log.New()
|
logger := log.New()
|
||||||
logger.SetLevel(t.LoggingBots)
|
logger.SetLevel(t.LoggingBots)
|
||||||
logCTX := logger.WithFields(log.Fields{
|
logCTX := logger.WithFields(log.Fields{
|
||||||
"type": "bot",
|
"log": "bot",
|
||||||
"jid": status.client.JID.Full(),
|
"jid": status.client.JID.Full(),
|
||||||
})
|
})
|
||||||
for {
|
go func(status *Status) {
|
||||||
|
if err := status.client.Start(); err != nil {
|
||||||
element, err := status.client.Read()
|
status.Disconnect(err.Error())
|
||||||
if err != nil {
|
|
||||||
status.Disconnect(fmt.Sprintf("could not read any more data from socket: %s", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
errMSG := &xmpp.StreamError{}
|
|
||||||
err = status.client.Decode(errMSG, element)
|
|
||||||
if err == nil {
|
|
||||||
status.Disconnect(fmt.Sprintf("recv stream error: %s: %s -> %s", errMSG.Text, xmpp.XMLChildrenString(errMSG.StreamErrorGroup), xmpp.XMLChildrenString(errMSG.Other)))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
iq := &xmpp.IQClient{}
|
|
||||||
err = status.client.Decode(iq, element)
|
|
||||||
if err == nil {
|
|
||||||
if iq.Ping != nil {
|
|
||||||
logCTX.Debug("answer ping")
|
|
||||||
iq.Type = xmpp.IQTypeResult
|
|
||||||
iq.To = iq.From
|
|
||||||
iq.From = status.client.JID
|
|
||||||
status.client.Send(iq)
|
|
||||||
} else {
|
} else {
|
||||||
logCTX.Warnf("recv iq unsupport: %s", xmpp.XMLChildrenString(iq))
|
status.Disconnect("safe closed")
|
||||||
}
|
}
|
||||||
continue
|
}(status)
|
||||||
|
logCTX.Info("start bot")
|
||||||
|
defer logCTX.Info("quit bot")
|
||||||
|
for {
|
||||||
|
element, more := status.client.Recv()
|
||||||
|
if !more {
|
||||||
|
logCTX.Info("could not recv msg, closed")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
logCTX.Debugf("recv msg %v", element)
|
||||||
|
|
||||||
pres := &xmpp.PresenceClient{}
|
switch element.(type) {
|
||||||
err = status.client.Decode(pres, element)
|
case *xmpp.PresenceClient:
|
||||||
if err == nil {
|
pres := element.(*xmpp.PresenceClient)
|
||||||
sender := pres.From
|
sender := pres.From
|
||||||
logPres := logCTX.WithField("from", sender.Full())
|
logPres := logCTX.WithField("from", sender.Full())
|
||||||
if pres.Type == xmpp.PresenceTypeSubscribe {
|
switch pres.Type {
|
||||||
|
case xmpp.PresenceTypeSubscribe:
|
||||||
logPres.Debugf("recv presence subscribe")
|
logPres.Debugf("recv presence subscribe")
|
||||||
pres.Type = xmpp.PresenceTypeSubscribed
|
pres.Type = xmpp.PresenceTypeSubscribed
|
||||||
pres.To = sender
|
pres.To = sender
|
||||||
|
@ -64,47 +52,33 @@ func (t *Tester) StartBot(status *Status) {
|
||||||
pres.ID = ""
|
pres.ID = ""
|
||||||
status.client.Send(pres)
|
status.client.Send(pres)
|
||||||
logPres.Info("request also subscribe")
|
logPres.Info("request also subscribe")
|
||||||
} else if pres.Type == xmpp.PresenceTypeSubscribed {
|
case xmpp.PresenceTypeSubscribed:
|
||||||
logPres.Info("recv presence accepted subscribe")
|
logPres.Info("recv presence accepted subscribe")
|
||||||
} else if pres.Type == xmpp.PresenceTypeUnsubscribe {
|
case xmpp.PresenceTypeUnsubscribe:
|
||||||
logPres.Info("recv presence remove subscribe")
|
logPres.Info("recv presence remove subscribe")
|
||||||
} else if pres.Type == xmpp.PresenceTypeUnsubscribed {
|
case xmpp.PresenceTypeUnsubscribed:
|
||||||
logPres.Info("recv presence removed subscribe")
|
logPres.Info("recv presence removed subscribe")
|
||||||
} else if pres.Type == xmpp.PresenceTypeUnavailable {
|
case xmpp.PresenceTypeUnavailable:
|
||||||
logPres.Debug("recv presence unavailable")
|
logPres.Debug("recv presence unavailable")
|
||||||
} else {
|
default:
|
||||||
logCTX.Warnf("recv presence unsupported: %s -> %s", pres.Type, xmpp.XMLChildrenString(pres))
|
logCTX.Warnf("recv presence unsupported: %s -> %s", pres.Type, xmpp.XMLChildrenString(pres))
|
||||||
}
|
}
|
||||||
continue
|
case *xmpp.MessageClient:
|
||||||
}
|
msg := element.(*xmpp.MessageClient)
|
||||||
|
logMSG := logCTX.WithField("from", msg.From.Full()).WithField("msg-recv", msg.Body)
|
||||||
msg := &xmpp.MessageClient{}
|
|
||||||
err = status.client.Decode(msg, element)
|
|
||||||
if err != nil {
|
|
||||||
logCTX.Warnf("unsupport xml recv: %s <-> %v", err, element)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
logCTX = logCTX.WithField("from", msg.From.Full()).WithField("msg-recv", msg.Body)
|
|
||||||
if msg.Error != nil {
|
|
||||||
if msg.Error.Type == "auth" {
|
|
||||||
status.Disconnect("recv msg with error not auth")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
logCTX.Debugf("recv msg with error %s[%s]: %s -> %s -> %s", msg.Error.Code, msg.Error.Type, msg.Error.Text, xmpp.XMLChildrenString(msg.Error.StanzaErrorGroup), xmpp.XMLChildrenString(msg.Error.Other))
|
|
||||||
continue
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
msgText := strings.SplitN(msg.Body, " ", 2)
|
msgText := strings.SplitN(msg.Body, " ", 2)
|
||||||
switch msgText[0] {
|
switch msgText[0] {
|
||||||
|
|
||||||
case "ping":
|
case "ping":
|
||||||
status.client.Send(xmpp.MessageClient{Type: msg.Type, To: msg.From, Body: "pong"})
|
status.client.Send(xmpp.MessageClient{Type: msg.Type, To: msg.From, Body: "pong"})
|
||||||
|
logMSG.Info("answer ping")
|
||||||
|
|
||||||
case "admin":
|
case "admin":
|
||||||
if len(msgText) == 2 {
|
if len(msgText) == 2 {
|
||||||
botAdmin(strings.SplitN(msgText[1], " ", 2), logCTX, status, msg.From, botAllowed(t.Admins, status.account.Admins))
|
botAdmin(strings.SplitN(msgText[1], " ", 2), logMSG, status, msg.From, botAllowed(t.Admins, status.account.Admins))
|
||||||
} else {
|
} else {
|
||||||
status.client.Send(xmpp.MessageClient{Type: msg.Type, To: msg.From, Body: "list, add JID-BARE, del JID-BARE"})
|
status.client.Send(xmpp.MessageClient{Type: msg.Type, To: msg.From, Body: "list, add JID-BARE, del JID-BARE"})
|
||||||
|
logMSG.Info("answer admin help")
|
||||||
}
|
}
|
||||||
case "disconnect":
|
case "disconnect":
|
||||||
first := true
|
first := true
|
||||||
|
@ -121,7 +95,6 @@ func (t *Tester) StartBot(status *Status) {
|
||||||
if jid.Bare().IsEqual(fromBare) {
|
if jid.Bare().IsEqual(fromBare) {
|
||||||
isAdmin = true
|
isAdmin = true
|
||||||
status.client.Send(xmpp.MessageClient{Type: msg.Type, To: jid, Body: "last message, disconnect requested by " + fromBare.String()})
|
status.client.Send(xmpp.MessageClient{Type: msg.Type, To: jid, Body: "last message, disconnect requested by " + fromBare.String()})
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if isAdmin {
|
if isAdmin {
|
||||||
|
@ -129,16 +102,20 @@ func (t *Tester) StartBot(status *Status) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
status.client.Send(xmpp.MessageClient{Type: msg.Type, To: msg.From, Body: "not allowed, ask " + allAdmins})
|
status.client.Send(xmpp.MessageClient{Type: msg.Type, To: msg.From, Body: "not allowed, ask " + allAdmins})
|
||||||
|
logMSG.Info("answer disconnect not allowed")
|
||||||
|
|
||||||
case "checkmsg":
|
case "checkmsg":
|
||||||
if len(msgText) == 2 {
|
if len(msgText) == 2 {
|
||||||
t.UpdateConnectionStatus(msg.From, status.client.JID, msgText[1])
|
t.updateConnectionStatus(msg.From, status.client.JID, msgText[1])
|
||||||
} else {
|
} else {
|
||||||
logCTX.Debug("undetect")
|
logMSG.Debug("undetect")
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
logCTX.Debug("undetect")
|
logMSG.Debug("undetect")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
logCTX.Debug("unhandle")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -187,4 +164,5 @@ func botAdmin(cmd []string, log *log.Entry, status *Status, from *xmppbase.JID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
status.client.Send(xmpp.MessageClient{Type: xmpp.MessageTypeChat, To: from, Body: msg})
|
status.client.Send(xmpp.MessageClient{Type: xmpp.MessageTypeChat, To: from, Body: msg})
|
||||||
|
log.Infof("admin[%s]: %s", from.String(), msg)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"dev.sum7.eu/genofire/yaja/client"
|
"dev.sum7.eu/genofire/yaja/client"
|
||||||
"dev.sum7.eu/genofire/yaja/xmpp"
|
"dev.sum7.eu/genofire/yaja/xmpp"
|
||||||
"dev.sum7.eu/genofire/yaja/xmpp/base"
|
"dev.sum7.eu/genofire/yaja/xmpp/base"
|
||||||
|
"dev.sum7.eu/genofire/yaja/xmpp/iq"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Status struct {
|
type Status struct {
|
||||||
|
@ -22,6 +23,8 @@ type Status struct {
|
||||||
TLSVersion string `json:"tls_version"`
|
TLSVersion string `json:"tls_version"`
|
||||||
IPv4 bool `json:"ipv4"`
|
IPv4 bool `json:"ipv4"`
|
||||||
IPv6 bool `json:"ipv6"`
|
IPv6 bool `json:"ipv6"`
|
||||||
|
Software string `json:"software,omitempty"`
|
||||||
|
OS string `json:"os,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStatus(backupClient *client.Client, acc *Account) *Status {
|
func NewStatus(backupClient *client.Client, acc *Account) *Status {
|
||||||
|
@ -47,13 +50,13 @@ func (s *Status) Disconnect(reason string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.client.Logging.Warn(reason)
|
s.client.Logging.Warnf("status-disconnect: %s", reason)
|
||||||
s.client.Close()
|
s.client.Close()
|
||||||
s.Login = false
|
s.Login = false
|
||||||
s.TLSVersion = ""
|
s.TLSVersion = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Status) Update(timeout time.Duration) {
|
func (s *Status) update(timeout time.Duration) {
|
||||||
if s.client == nil || !s.Login {
|
if s.client == nil || !s.Login {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -61,7 +64,7 @@ func (s *Status) Update(timeout time.Duration) {
|
||||||
c := &client.Client{
|
c := &client.Client{
|
||||||
JID: s.account.JID.Bare(),
|
JID: s.account.JID.Bare(),
|
||||||
Protocol: "tcp4",
|
Protocol: "tcp4",
|
||||||
Logging: s.client.Logging,
|
Logging: s.client.Logging.WithField("status", "ipv4"),
|
||||||
Timeout: timeout / 2,
|
Timeout: timeout / 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,6 +75,7 @@ func (s *Status) Update(timeout time.Duration) {
|
||||||
s.IPv4 = false
|
s.IPv4 = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.Logging = s.client.Logging.WithField("status", "ipv4")
|
||||||
c.JID = s.account.JID.Bare()
|
c.JID = s.account.JID.Bare()
|
||||||
c.Protocol = "tcp6"
|
c.Protocol = "tcp6"
|
||||||
|
|
||||||
|
@ -101,4 +105,32 @@ func (s *Status) Update(timeout time.Duration) {
|
||||||
} else {
|
} else {
|
||||||
s.TLSVersion = ""
|
s.TLSVersion = ""
|
||||||
}
|
}
|
||||||
|
iq, err := s.client.SendRecv(&xmpp.IQClient{
|
||||||
|
To: &xmppbase.JID{Domain: s.JID.Domain},
|
||||||
|
Type: xmpp.IQTypeGet,
|
||||||
|
Version: &xmppiq.Version{},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
s.client.Logging.Errorf("status-update: %s", err.Error())
|
||||||
|
} else if iq != nil {
|
||||||
|
if iq.Error != nil && iq.Error.ServiceUnavailable != nil {
|
||||||
|
s.Software = "unknown"
|
||||||
|
s.OS = "unknown"
|
||||||
|
} else if iq.Version != nil {
|
||||||
|
s.Software = iq.Version.Name
|
||||||
|
if iq.Version.Version != "" {
|
||||||
|
s.Software += "-" + iq.Version.Version
|
||||||
|
}
|
||||||
|
if s.Software == "" {
|
||||||
|
s.Software = "unknown"
|
||||||
|
}
|
||||||
|
s.OS = iq.Version.OS
|
||||||
|
if s.OS == "" {
|
||||||
|
s.OS = "unknown"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s.Software = ""
|
||||||
|
s.OS = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ type Tester struct {
|
||||||
Accounts map[string]*Account `json:"accounts"`
|
Accounts map[string]*Account `json:"accounts"`
|
||||||
Status map[string]*Status `json:"-"`
|
Status map[string]*Status `json:"-"`
|
||||||
mux sync.Mutex
|
mux sync.Mutex
|
||||||
LoggingClients *log.Logger `json:"-"`
|
LoggingClients *log.Entry `json:"-"`
|
||||||
LoggingBots log.Level `json:"-"`
|
LoggingBots log.Level `json:"-"`
|
||||||
Admins []*xmppbase.JID `json:"-"`
|
Admins []*xmppbase.JID `json:"-"`
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ func NewTester() *Tester {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tester) Start(mainClient *client.Client, password string) {
|
func (t *Tester) Start(mainClient *client.Client, password string) {
|
||||||
|
mainClient.SkipError = true
|
||||||
t.mainClient = mainClient
|
t.mainClient = mainClient
|
||||||
|
|
||||||
status := NewStatus(mainClient, &Account{
|
status := NewStatus(mainClient, &Account{
|
||||||
|
@ -39,13 +39,13 @@ func (t *Tester) Start(mainClient *client.Client, password string) {
|
||||||
})
|
})
|
||||||
status.client = mainClient
|
status.client = mainClient
|
||||||
status.Login = true
|
status.Login = true
|
||||||
status.Update(t.Timeout)
|
|
||||||
|
|
||||||
t.mux.Lock()
|
t.mux.Lock()
|
||||||
defer t.mux.Unlock()
|
defer t.mux.Unlock()
|
||||||
|
|
||||||
t.Status[mainClient.JID.Bare().String()] = status
|
t.Status[mainClient.JID.Bare().String()] = status
|
||||||
go t.StartBot(status)
|
go t.startBot(status)
|
||||||
|
status.update(t.Timeout)
|
||||||
|
|
||||||
for _, acc := range t.Accounts {
|
for _, acc := range t.Accounts {
|
||||||
t.Connect(acc)
|
t.Connect(acc)
|
||||||
|
@ -74,7 +74,8 @@ func (t *Tester) Connect(acc *Account) {
|
||||||
c := &client.Client{
|
c := &client.Client{
|
||||||
Timeout: t.Timeout,
|
Timeout: t.Timeout,
|
||||||
JID: acc.JID,
|
JID: acc.JID,
|
||||||
Logging: t.LoggingClients,
|
Logging: t.LoggingClients.WithField("jid", acc.JID.String()),
|
||||||
|
SkipError: true,
|
||||||
}
|
}
|
||||||
err := c.Connect(acc.Password)
|
err := c.Connect(acc.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -85,12 +86,12 @@ func (t *Tester) Connect(acc *Account) {
|
||||||
status.client = c
|
status.client = c
|
||||||
status.account.JID = c.JID
|
status.account.JID = c.JID
|
||||||
status.JID = c.JID
|
status.JID = c.JID
|
||||||
status.Update(t.Timeout)
|
go t.startBot(status)
|
||||||
go t.StartBot(status)
|
status.update(t.Timeout)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tester) UpdateConnectionStatus(from, to *xmppbase.JID, recvmsg string) {
|
func (t *Tester) updateConnectionStatus(from, to *xmppbase.JID, recvmsg string) {
|
||||||
logCTX := log.WithFields(log.Fields{
|
logCTX := log.WithFields(log.Fields{
|
||||||
"jid": to.Full(),
|
"jid": to.Full(),
|
||||||
"from": from.Full(),
|
"from": from.Full(),
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
// Version implements XEP-0092: Software Version - 4
|
// Version implements XEP-0092: Software Version - 4
|
||||||
type Version struct {
|
type Version struct {
|
||||||
XMLName xml.Name `xml:"jabber:iq:version query"`
|
XMLName xml.Name `xml:"jabber:iq:version query"`
|
||||||
Name string `xml:"name"` //required
|
Name string `xml:"name,omitempty"` //required
|
||||||
Version string `xml:"version"` //required
|
Version string `xml:"version,omitempty"` //required
|
||||||
OS string `xml:"os,omitempty"`
|
OS string `xml:"os,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
Reference in New Issue