diff --git a/Makefile b/Makefile index d53a133..662ce26 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ all: go build -o telegabber test: - go test -v ./config ./ ./telegram ./xmpp + go test -v ./config ./ ./telegram ./xmpp/gateway lint: $(GOPATH)/bin/golint ./... diff --git a/xmpp/component.go b/xmpp/component.go index 7e2d16e..c0b4a23 100644 --- a/xmpp/component.go +++ b/xmpp/component.go @@ -1,7 +1,6 @@ package xmpp import ( - "encoding/xml" "github.com/pkg/errors" "time" @@ -11,16 +10,14 @@ import ( "dev.narayana.im/narayana/telegabber/xmpp/gateway" log "github.com/sirupsen/logrus" - "github.com/soheilhy/args" "gosrc.io/xmpp" - "gosrc.io/xmpp/stanza" ) const pollingInterval time.Duration = 1e7 var tgConf config.TelegramConfig var sessions map[string]*telegram.Client -var queue map[string]*stanza.Presence +var queue gateway.Queue var db persistence.SessionsYamlDB // NewComponent starts a new component and wraps it in @@ -33,6 +30,8 @@ func NewComponent(conf config.XMPPConfig, tc config.TelegramConfig) (*xmpp.Strea return nil, nil, err } + queue = make(gateway.Queue) + tgConf = tc options := xmpp.ComponentOptions{ @@ -64,19 +63,13 @@ func NewComponent(conf config.XMPPConfig, tc config.TelegramConfig) (*xmpp.Strea return sm, component, nil } -func logPresence(err error, presence *stanza.Presence) { - log.WithFields(log.Fields{ - "presence": *presence, - }).Error(errors.Wrap(err, "Couldn't send presence")) -} - func heartbeat(component *xmpp.Component) { var err error - probeType := SPType("probe") + probeType := gateway.SPType("probe") for jid := range sessions { for { - err = sendPresence(component, jid, probeType) + err = gateway.SendPresence(component, queue, jid, probeType) if err == nil { break } @@ -90,7 +83,7 @@ func heartbeat(component *xmpp.Component) { for key, presence := range queue { err = component.Send(presence) if err != nil { - logPresence(err, presence) + gateway.LogBadPresence(err, presence) } else { delete(queue, key) } @@ -135,106 +128,6 @@ func getTelegramInstance(jid string, savedSession *persistence.Session, componen 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) error { - var logFrom string - bareJid := gateway.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 { - logPresence(err, &presence) - return err - } - } else { - queue[presence.From+presence.To] = &presence - } - - return nil -} - // Close gracefully terminates the component and saves active sessions func Close(component *xmpp.Component) { log.Error("Disconnecting...") diff --git a/xmpp/extensions.go b/xmpp/extensions/extensions.go similarity index 98% rename from xmpp/extensions.go rename to xmpp/extensions/extensions.go index 2270431..ec94837 100644 --- a/xmpp/extensions.go +++ b/xmpp/extensions/extensions.go @@ -1,4 +1,4 @@ -package xmpp +package extensions import ( "encoding/xml" 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/component_test.go b/xmpp/gateway/gateway_test.go similarity index 99% rename from xmpp/component_test.go rename to xmpp/gateway/gateway_test.go index b540ad4..6191844 100644 --- a/xmpp/component_test.go +++ b/xmpp/gateway/gateway_test.go @@ -1,4 +1,4 @@ -package xmpp +package gateway import ( "encoding/xml"