From d6f6207ebb3d5256256a7810a3d3d0bdc8ba04a5 Mon Sep 17 00:00:00 2001 From: bodqhrohro Date: Mon, 25 Nov 2019 00:20:07 +0200 Subject: Refactoring: move SendPresence to xmpp/gateway package --- xmpp/gateway/gateway.go | 115 +++++++++++++++++++++++++++++++++++++++++++ xmpp/gateway/gateway_test.go | 54 ++++++++++++++++++++ 2 files changed, 169 insertions(+) create mode 100644 xmpp/gateway/gateway_test.go (limited to 'xmpp/gateway') diff --git a/xmpp/gateway/gateway.go b/xmpp/gateway/gateway.go index 0c22677..11f68c1 100644 --- a/xmpp/gateway/gateway.go +++ b/xmpp/gateway/gateway.go @@ -2,12 +2,19 @@ package gateway import ( "encoding/xml" + "github.com/pkg/errors" + + "dev.narayana.im/narayana/telegabber/xmpp/extensions" log "github.com/sirupsen/logrus" + "github.com/soheilhy/args" "gosrc.io/xmpp" "gosrc.io/xmpp/stanza" ) +// Queue stores presences to send later +type Queue map[string]*stanza.Presence + // Jid stores the component's JID object var Jid *xmpp.Jid @@ -51,3 +58,111 @@ func SendMessage(to string, from string, body string, component *xmpp.Component) _ = component.Send(message) } + +// LogBadPresence verbosely logs a presence +func LogBadPresence(err error, presence *stanza.Presence) { + log.WithFields(log.Fields{ + "presence": *presence, + }).Error(errors.Wrap(err, "Couldn't send presence")) +} + +// SPFrom is a Telegram user id +var SPFrom = args.NewString() + +// SPType is a presence type +var SPType = args.NewString() + +// SPShow is a availability status +var SPShow = args.NewString() + +// SPStatus is a verbose status +var SPStatus = args.NewString() + +// SPNickname is a XEP-0172 nickname +var SPNickname = args.NewString() + +// SPPhoto is a XEP-0153 hash of avatar in vCard +var SPPhoto = args.NewString() + +// SPImmed skips queueing +var SPImmed = args.NewBool(args.Default(true)) + +func newPresence(bareJid string, to string, args ...args.V) stanza.Presence { + var presenceFrom string + if SPFrom.IsSet(args) { + presenceFrom = SPFrom.Get(args) + "@" + bareJid + } else { + presenceFrom = bareJid + } + + presence := stanza.Presence{Attrs: stanza.Attrs{ + From: presenceFrom, + To: to, + }} + + if SPType.IsSet(args) { + presence.Attrs.Type = stanza.StanzaType(SPType.Get(args)) + } + if SPShow.IsSet(args) { + presence.Show = stanza.PresenceShow(SPShow.Get(args)) + } + if SPStatus.IsSet(args) { + presence.Status = SPStatus.Get(args) + } + if SPNickname.IsSet(args) { + presence.Extensions = append(presence.Extensions, extensions.PresenceNickExtension{ + Text: SPNickname.Get(args), + }) + } + if SPPhoto.IsSet(args) { + presence.Extensions = append(presence.Extensions, extensions.PresenceXVCardUpdateExtension{ + Photo: extensions.PresenceXVCardUpdatePhoto{ + Text: SPPhoto.Get(args), + }, + }) + } + + return presence +} + +// SendPresence creates and sends a presence stanza +func SendPresence(component *xmpp.Component, queue Queue, to string, args ...args.V) error { + var logFrom string + bareJid := Jid.Bare() + if SPFrom.IsSet(args) { + logFrom = SPFrom.Get(args) + } else { + logFrom = bareJid + } + + log.WithFields(log.Fields{ + "type": SPType.Get(args), + "from": logFrom, + "to": to, + }).Info("Got presence") + + presence := newPresence(bareJid, to, args...) + + // explicit check, as marshalling is expensive + if log.GetLevel() == log.DebugLevel { + xmlPresence, err := xml.Marshal(presence) + if err == nil { + log.Debug(string(xmlPresence)) + } else { + log.Debugf("%#v", presence) + } + } + + immed := SPImmed.Get(args) + if immed { + err := component.Send(presence) + if err != nil { + LogBadPresence(err, &presence) + return err + } + } else { + queue[presence.From+presence.To] = &presence + } + + return nil +} diff --git a/xmpp/gateway/gateway_test.go b/xmpp/gateway/gateway_test.go new file mode 100644 index 0000000..6191844 --- /dev/null +++ b/xmpp/gateway/gateway_test.go @@ -0,0 +1,54 @@ +package gateway + +import ( + "encoding/xml" + "testing" + + "gosrc.io/xmpp/stanza" +) + +func testPresence(t *testing.T, presence stanza.Presence, reference string) { + byteXML, err := xml.Marshal(presence) + if err != nil { + t.Errorf("XML parse error: %v", err) + } + xmlText := string(byteXML) + if xmlText != reference { + t.Errorf("%v does not match %v", xmlText, reference) + } +} + +func TestPresenceFrom(t *testing.T) { + presence := newPresence("from@test", "to@test", SPFrom("test")) + testPresence(t, presence, "") +} + +func TestPresenceNoFrom(t *testing.T) { + presence := newPresence("from@test", "to@test") + testPresence(t, presence, "") +} + +func TestPresenceType(t *testing.T) { + presence := newPresence("from@test", "to@test", SPType("subscribe")) + testPresence(t, presence, "") +} + +func TestPresenceShow(t *testing.T) { + presence := newPresence("from@test", "to@test", SPShow("dnd")) + testPresence(t, presence, "dnd") +} + +func TestPresenceStatus(t *testing.T) { + presence := newPresence("from@test", "to@test", SPStatus("cooking")) + testPresence(t, presence, "cooking") +} + +func TestPresenceNickname(t *testing.T) { + presence := newPresence("from@test", "to@test", SPNickname("Ishmael")) + testPresence(t, presence, "Ishmael") +} + +func TestPresencePhoto(t *testing.T) { + presence := newPresence("from@test", "to@test", SPPhoto("01b87fcd030b72895ff8e88db57ec525450f000d")) + testPresence(t, presence, "01b87fcd030b72895ff8e88db57ec525450f000d") +} -- cgit v1.2.3