aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBohdan Horbeshko <bodqhrohro@gmail.com>2022-01-06 00:04:22 +0300
committerBohdan Horbeshko <bodqhrohro@gmail.com>2022-01-06 00:04:22 +0300
commit077edae986f2229d263f978b7cf35ed88254c042 (patch)
tree01877034c1989565e2de30bce04d1c15eb06579e
parentd48cb8b58682d3b9c5798913de35ae62dd20dd38 (diff)
Add keeponline option
-rw-r--r--persistence/sessions.go40
-rw-r--r--telegram/commands.go4
-rw-r--r--telegram/connect.go4
-rw-r--r--telegram/utils.go12
-rw-r--r--xmpp/component.go47
-rw-r--r--xmpp/gateway/gateway.go4
-rw-r--r--xmpp/handlers.go2
7 files changed, 94 insertions, 19 deletions
diff --git a/persistence/sessions.go b/persistence/sessions.go
index fd520d1..b42d3a3 100644
--- a/persistence/sessions.go
+++ b/persistence/sessions.go
@@ -34,8 +34,14 @@ type SessionsMap struct {
// Session is a key-values subtree
type Session struct {
- Login string `yaml:":login"`
- Timezone string `yaml:":timezone"`
+ Login string `yaml:":login"`
+ Timezone string `yaml:":timezone"`
+ KeepOnline bool `yaml:":keeponline"`
+}
+
+var configKeys = []string{
+ "timezone",
+ "keeponline",
}
var sessionDB *SessionsYamlDB
@@ -102,6 +108,8 @@ func (s *Session) Get(key string) (string, error) {
switch key {
case "timezone":
return s.Timezone, nil
+ case "keeponline":
+ return fromBool(s.KeepOnline), nil
}
return "", errors.New("Unknown session property")
@@ -110,7 +118,7 @@ func (s *Session) Get(key string) (string, error) {
// ToMap converts the session to a map
func (s *Session) ToMap() map[string]string {
m := make(map[string]string)
- for _, configKey := range []string{"timezone"} {
+ for _, configKey := range configKeys {
value, _ := s.Get(configKey)
m[configKey] = value
}
@@ -124,6 +132,13 @@ func (s *Session) Set(key string, value string) (string, error) {
case "timezone":
s.Timezone = value
return value, nil
+ case "keeponline":
+ b, err := toBool(value)
+ if err != nil {
+ return "", err
+ }
+ s.KeepOnline = b
+ return value, nil
}
return "", errors.New("Unknown session property")
@@ -139,3 +154,22 @@ func (s *Session) TimezoneToLocation() *time.Location {
// default
return zeroLocation
}
+
+func fromBool(b bool) string {
+ if b {
+ return "true"
+ } else {
+ return "false"
+ }
+}
+
+func toBool(s string) (bool, error) {
+ switch s {
+ case "true":
+ return true, nil
+ case "false":
+ return false, nil
+ }
+
+ return false, errors.New("Invalid boolean value")
+}
diff --git a/telegram/commands.go b/telegram/commands.go
index 4b0ee13..82dca91 100644
--- a/telegram/commands.go
+++ b/telegram/commands.go
@@ -53,7 +53,8 @@ var chatCommands = map[string]command{
}
var transportConfigurationOptions = map[string]configurationOption{
- "timezone": configurationOption{"00:00", "adjust timezone for Telegram user statuses"},
+ "timezone": configurationOption{"<timezone>", "adjust timezone for Telegram user statuses (example: +02:00)"},
+ "keeponline": configurationOption{"<bool>", "always keep telegram session online and rely on jabber offline messages (example: true)"},
}
type command struct {
@@ -293,6 +294,7 @@ func (c *Client) ProcessTransportCommand(cmdline string, resource string) string
if err != nil {
return err.Error()
}
+ gateway.DirtySessions = true
return fmt.Sprintf("%s set to %s", args[0], value)
} else if len(args) > 0 {
diff --git a/telegram/connect.go b/telegram/connect.go
index 8cee376..f2ea01d 100644
--- a/telegram/connect.go
+++ b/telegram/connect.go
@@ -91,7 +91,7 @@ func (c *Client) Connect(resource string) error {
c.locks.authorizationReady.Wait()
if c.Online() {
- c.refresh(resource)
+ c.roster(resource)
return nil
}
@@ -157,7 +157,7 @@ func (c *Client) Disconnect(resource string, quit bool) bool {
c.deleteResource(resource)
}
// other resources are still active
- if len(c.resources) > 0 && !quit {
+ if (len(c.resources) > 0 || c.Session.KeepOnline) && !quit {
log.Infof("Resource %v for account %v has disconnected, %v remaining", resource, c.Session.Login, len(c.resources))
log.Debugf("Resources: %#v", c.resources)
return false
diff --git a/telegram/utils.go b/telegram/utils.go
index cdd2914..4c73f9e 100644
--- a/telegram/utils.go
+++ b/telegram/utils.go
@@ -48,7 +48,7 @@ func (c *Client) GetContactByUsername(username string) (*client.Chat, *client.Us
// GetContactByID gets user and chat information from cache (or tries to retrieve it, if missing)
func (c *Client) GetContactByID(id int64, chat *client.Chat) (*client.Chat, *client.User, error) {
- if !c.Online() {
+ if !c.Online() || id == 0 {
return nil, nil, errOffline
}
@@ -600,17 +600,19 @@ func (c *Client) deleteResource(resource string) {
}
}
-// refresh roster
-func (c *Client) refresh(resource string) {
+// resend statuses to (to another resource, for example)
+func (c *Client) roster(resource string) {
if _, ok := c.resources[resource]; ok {
- return
+ return // we know it
}
- log.Warnf("Refreshing roster for resource %v", resource)
+ log.Warnf("Sending roster for %v", resource)
for _, chat := range c.cache.ChatsKeys() {
c.ProcessStatusUpdate(chat, "", "")
}
+ gateway.SendPresence(c.xmpp, c.jid, gateway.SPStatus("Logged in as: "+c.Session.Login))
+
c.addResource(resource)
}
diff --git a/xmpp/component.go b/xmpp/component.go
index 109d3d5..4f5ad79 100644
--- a/xmpp/component.go
+++ b/xmpp/component.go
@@ -2,6 +2,7 @@ package xmpp
import (
"github.com/pkg/errors"
+ "sync"
"time"
"dev.narayana.im/narayana/telegabber/config"
@@ -17,6 +18,7 @@ import (
var tgConf config.TelegramConfig
var sessions map[string]*telegram.Client
var db *persistence.SessionsYamlDB
+var sessionLock sync.Mutex
// NewComponent starts a new component and wraps it in
// a stream manager that you should start yourself
@@ -69,12 +71,14 @@ func heartbeat(component *xmpp.Component) {
var err error
probeType := gateway.SPType("probe")
+ sessionLock.Lock()
for jid := range sessions {
err = gateway.SendPresence(component, jid, probeType)
if err != nil {
log.Error(err)
}
}
+ sessionLock.Unlock()
log.Info("Starting heartbeat queue")
@@ -89,6 +93,13 @@ func heartbeat(component *xmpp.Component) {
delete(gateway.Queue, key)
}
}
+
+ if gateway.DirtySessions {
+ gateway.DirtySessions = false
+ // no problem if a dirty flag gets set again here,
+ // it would be resolved on the next iteration
+ SaveSessions()
+ }
}
}
@@ -104,7 +115,10 @@ func loadSessions(dbPath string, component *xmpp.Component) error {
db.Transaction(func() bool {
for jid, session := range db.Data.Sessions {
- getTelegramInstance(jid, &session, component)
+ // copy the session struct, otherwise all of them would reference
+ // the same temporary range variable
+ currentSession := session
+ getTelegramInstance(jid, &currentSession, component)
}
return false
@@ -122,29 +136,46 @@ func getTelegramInstance(jid string, savedSession *persistence.Session, componen
log.Error(errors.Wrap(err, "TDlib initialization failure"))
return session, false
}
+ if savedSession.KeepOnline {
+ if err = session.Connect(""); err != nil {
+ log.Error(err)
+ return session, false
+ }
+ }
+ sessionLock.Lock()
sessions[jid] = session
+ sessionLock.Unlock()
}
return session, true
}
+// SaveSessions dumps current sessions to the file
+func SaveSessions() {
+ sessionLock.Lock()
+ defer sessionLock.Unlock()
+ db.Transaction(func() bool {
+ for jid, session := range sessions {
+ db.Data.Sessions[jid] = *session.Session
+ }
+
+ return true
+ }, persistence.SessionMarshaller)
+}
+
// Close gracefully terminates the component and saves active sessions
func Close(component *xmpp.Component) {
log.Error("Disconnecting...")
+ sessionLock.Lock()
// close all sessions
for _, session := range sessions {
session.Disconnect("", true)
}
+ sessionLock.Unlock()
// save sessions
- db.Transaction(func() bool {
- for jid, session := range sessions {
- db.Data.Sessions[jid] = *session.Session
- }
-
- return true
- }, persistence.SessionMarshaller)
+ SaveSessions()
// close stream
component.Disconnect()
diff --git a/xmpp/gateway/gateway.go b/xmpp/gateway/gateway.go
index eb46e48..a4f3aca 100644
--- a/xmpp/gateway/gateway.go
+++ b/xmpp/gateway/gateway.go
@@ -18,6 +18,10 @@ var Queue = make(map[string]*stanza.Presence)
// Jid stores the component's JID object
var Jid *stanza.Jid
+// DirtySessions denotes that some Telegram session configurations
+// were changed and need to be re-flushed to the YamlDB
+var DirtySessions = false
+
// SendMessage creates and sends a message stanza
func SendMessage(to string, from string, body string, component *xmpp.Component) {
componentJid := Jid.Full()
diff --git a/xmpp/handlers.go b/xmpp/handlers.go
index 59d4c62..1b4f6a3 100644
--- a/xmpp/handlers.go
+++ b/xmpp/handlers.go
@@ -170,7 +170,9 @@ func handlePresence(s xmpp.Sender, p stanza.Presence) {
// destroy session
case "unsubscribed", "unsubscribe":
if session.Disconnect(fromJid.Resource, false) {
+ sessionLock.Lock()
delete(sessions, bareFromJid)
+ sessionLock.Unlock()
}
// go offline
case "unavailable", "error":