diff options
author | bodqhrohro <bodqhrohro@gmail.com> | 2019-11-14 23:11:04 +0300 |
---|---|---|
committer | bodqhrohro <bodqhrohro@gmail.com> | 2019-11-14 23:11:04 +0300 |
commit | 736abcb5bc3a7e2c0f1f1dfd3052cb6153b60d02 (patch) | |
tree | d98db15053f0889f999ae60e0fd67be8c3a963f9 /xmpp | |
parent | 47cf94ad01b4db8749c55c1a1dca50c9b94daf02 (diff) |
Send presence for recovered sessions
Diffstat (limited to 'xmpp')
-rw-r--r-- | xmpp/component.go | 102 | ||||
-rw-r--r-- | xmpp/component_test.go | 54 | ||||
-rw-r--r-- | xmpp/extensions.go | 49 |
3 files changed, 202 insertions, 3 deletions
diff --git a/xmpp/component.go b/xmpp/component.go index a341a2e..3e85f28 100644 --- a/xmpp/component.go +++ b/xmpp/component.go @@ -1,6 +1,7 @@ package xmpp import ( + "encoding/xml" "github.com/pkg/errors" "dev.narayana.im/narayana/telegabber/config" @@ -8,12 +9,15 @@ import ( "dev.narayana.im/narayana/telegabber/telegram" log "github.com/sirupsen/logrus" + "github.com/soheilhy/args" "gosrc.io/xmpp" + "gosrc.io/xmpp/stanza" ) var jid *xmpp.Jid var tgConf config.TelegramConfig var sessions map[string]telegram.Client +var queue map[string]*stanza.Presence var db persistence.SessionsYamlDB // NewComponent starts a new component and wraps it in @@ -52,13 +56,16 @@ func NewComponent(conf config.XMPPConfig, tc config.TelegramConfig) (*xmpp.Strea cm := xmpp.NewStreamManager(component, nil) - go maintenance() + go maintenance(component) return cm, nil } -func maintenance() { - // TODO +func maintenance(component *xmpp.Component) { + probeType := SPType("probe") + for jid := range sessions { + sendPresence(component, jid, probeType) + } } func loadSessions(dbPath string) error { @@ -95,3 +102,92 @@ func getTelegramInstance(jid string, savedSession *persistence.Session) (telegra return session, true } + +// 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, PresenceNickExtension{ + Text: SPNickname.Get(args), + }) + } + if SPPhoto.IsSet(args) { + presence.Extensions = append(presence.Extensions, PresenceXVCardUpdateExtension{ + Photo: PresenceXVCardUpdatePhoto{ + Text: SPPhoto.Get(args), + }, + }) + } + + return presence +} + +func sendPresence(component *xmpp.Component, to string, args ...args.V) { + 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 { + log.Debug(xml.Marshal(presence)) + } + + immed := SPImmed.Get(args) + if immed { + component.Send(presence) + } else { + queue[presence.From+presence.To] = &presence + } +} diff --git a/xmpp/component_test.go b/xmpp/component_test.go new file mode 100644 index 0000000..b540ad4 --- /dev/null +++ b/xmpp/component_test.go @@ -0,0 +1,54 @@ +package xmpp + +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, "<presence from=\"test@from@test\" to=\"to@test\"></presence>") +} + +func TestPresenceNoFrom(t *testing.T) { + presence := newPresence("from@test", "to@test") + testPresence(t, presence, "<presence from=\"from@test\" to=\"to@test\"></presence>") +} + +func TestPresenceType(t *testing.T) { + presence := newPresence("from@test", "to@test", SPType("subscribe")) + testPresence(t, presence, "<presence type=\"subscribe\" from=\"from@test\" to=\"to@test\"></presence>") +} + +func TestPresenceShow(t *testing.T) { + presence := newPresence("from@test", "to@test", SPShow("dnd")) + testPresence(t, presence, "<presence from=\"from@test\" to=\"to@test\"><show>dnd</show></presence>") +} + +func TestPresenceStatus(t *testing.T) { + presence := newPresence("from@test", "to@test", SPStatus("cooking")) + testPresence(t, presence, "<presence from=\"from@test\" to=\"to@test\"><status>cooking</status></presence>") +} + +func TestPresenceNickname(t *testing.T) { + presence := newPresence("from@test", "to@test", SPNickname("Ishmael")) + testPresence(t, presence, "<presence from=\"from@test\" to=\"to@test\"><nick xmlns=\"http://jabber.org/protocol/nick\">Ishmael</nick></presence>") +} + +func TestPresencePhoto(t *testing.T) { + presence := newPresence("from@test", "to@test", SPPhoto("01b87fcd030b72895ff8e88db57ec525450f000d")) + testPresence(t, presence, "<presence from=\"from@test\" to=\"to@test\"><x xmlns=\"vcard-temp:x:update\"><photo>01b87fcd030b72895ff8e88db57ec525450f000d</photo></x></presence>") +} diff --git a/xmpp/extensions.go b/xmpp/extensions.go new file mode 100644 index 0000000..2270431 --- /dev/null +++ b/xmpp/extensions.go @@ -0,0 +1,49 @@ +package xmpp + +import ( + "encoding/xml" + + "gosrc.io/xmpp/stanza" +) + +// PresenceNickExtension is from XEP-0172 +type PresenceNickExtension struct { + XMLName xml.Name `xml:"http://jabber.org/protocol/nick nick"` + Text string `xml:",chardata"` +} + +// PresenceXVCardUpdateExtension is from XEP-0153 +type PresenceXVCardUpdateExtension struct { + XMLName xml.Name `xml:"vcard-temp:x:update x"` + Photo PresenceXVCardUpdatePhoto +} + +// PresenceXVCardUpdatePhoto is from XEP-0153 +type PresenceXVCardUpdatePhoto struct { + XMLName xml.Name `xml:"photo"` + Text string `xml:",chardata"` +} + +// Namespace is a namespace! +func (c PresenceNickExtension) Namespace() string { + return c.XMLName.Space +} + +// Namespace is a namespace! +func (c PresenceXVCardUpdateExtension) Namespace() string { + return c.XMLName.Space +} + +func init() { + // presence nick + stanza.TypeRegistry.MapExtension(stanza.PKTPresence, xml.Name{ + "http://jabber.org/protocol/nick", + "nick", + }, PresenceNickExtension{}) + + // presence vcard update + stanza.TypeRegistry.MapExtension(stanza.PKTPresence, xml.Name{ + "vcard-temp:x:update", + "x", + }, PresenceXVCardUpdateExtension{}) +} |