aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config.yml.example1
-rw-r--r--config/config.go6
-rw-r--r--config_schema.json6
-rw-r--r--go.mod3
-rw-r--r--go.sum13
-rw-r--r--telegabber.go10
-rw-r--r--telegram/client.go118
-rw-r--r--test/good_config.yml1
-rw-r--r--xmpp/component.go21
-rw-r--r--xmpp/handlers.go95
10 files changed, 258 insertions, 16 deletions
diff --git a/config.yml.example b/config.yml.example
index 82945b4..a31cffd 100644
--- a/config.yml.example
+++ b/config.yml.example
@@ -13,6 +13,7 @@
:device_model: 'telegabber'
:application_version: '2.0'
:use_chat_info_database: false
+ :use_secret_chats: true
:xmpp:
:loglevel: :warn
diff --git a/config/config.go b/config/config.go
index 6759dd8..bcd493e 100644
--- a/config/config.go
+++ b/config/config.go
@@ -42,9 +42,8 @@ type TelegramContentConfig struct {
// TelegramTdlibConfig is for :tdlib: subtree
type TelegramTdlibConfig struct {
- Path string `yaml:":lib_path"`
- Logfile string `yaml:":logfile"`
- Client TelegramTdlibClientConfig `yaml:":client"`
+ Path string `yaml:":lib_path"`
+ Client TelegramTdlibClientConfig `yaml:":client"`
}
// TelegramTdlibClientConfig is for :client: subtree
@@ -54,6 +53,7 @@ type TelegramTdlibClientConfig struct {
DeviceModel string `yaml:":device_model"`
ApplicationVersion string `yaml:":application_version"`
UseChatInfoDatabase bool `yaml:":use_chat_info_database"`
+ UseSecretChats bool `yaml:":use_secret_chats"`
}
// ReadConfig reads the specified config file, validates it and returns a struct
diff --git a/config_schema.json b/config_schema.json
index 434bde5..48454a5 100644
--- a/config_schema.json
+++ b/config_schema.json
@@ -39,7 +39,8 @@
"required": [":api_id", ":api_hash"],
"properties": {
":api_id": {
- "$ref": "#/definitions/non-empty-string"
+ "type": "string",
+ "pattern": "^[0-9]+$"
},
":api_hash": {
"$ref": "#/definitions/non-empty-string"
@@ -52,6 +53,9 @@
},
":use_chat_info_database": {
"type": "boolean"
+ },
+ ":use_secret_chats": {
+ "type": "boolean"
}
}
}
diff --git a/go.mod b/go.mod
index c6f2878..73af52f 100644
--- a/go.mod
+++ b/go.mod
@@ -3,8 +3,11 @@ module dev.narayana.im/narayana/telegabber
go 1.13
require (
+ github.com/Arman92/go-tdlib v0.0.0-20191002071913-526f4e1d15f7
github.com/pkg/errors v0.8.1
github.com/santhosh-tekuri/jsonschema v1.2.4
+ github.com/sirupsen/logrus v1.4.2
+ github.com/zelenin/go-tdlib v0.1.0
gopkg.in/yaml.v2 v2.2.4
gosrc.io/xmpp v0.1.3
)
diff --git a/go.sum b/go.sum
index 4734020..5c53fc6 100644
--- a/go.sum
+++ b/go.sum
@@ -1,8 +1,21 @@
+github.com/Arman92/go-tdlib v0.0.0-20191002071913-526f4e1d15f7 h1:GbV1Lv3lVHsSeKAqPTBem72OCsGjXntW4jfJdXciE+w=
+github.com/Arman92/go-tdlib v0.0.0-20191002071913-526f4e1d15f7/go.mod h1:ZzkRfuaFj8etIYMj/ECtXtgfz72RE6U+dos27b3XIwk=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/santhosh-tekuri/jsonschema v1.2.4 h1:hNhW8e7t+H1vgY+1QeEQpveR6D4+OwKPXCfD2aieJis=
github.com/santhosh-tekuri/jsonschema v1.2.4/go.mod h1:TEAUOeZSmIxTTuHatJzrvARHiuO9LYd+cIxzgEHCQI4=
+github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/zelenin/go-tdlib v0.1.0 h1:Qq+FGE0/EWdsRB6m26ULDndu2DtW558aFXNzi0Y/FqQ=
+github.com/zelenin/go-tdlib v0.1.0/go.mod h1:Xs8fXbk5n7VaPyrSs9DP7QYoBScWYsjX+lUcWmx1DIU=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/telegabber.go b/telegabber.go
index c5ee366..6754038 100644
--- a/telegabber.go
+++ b/telegabber.go
@@ -1,14 +1,15 @@
package main
import (
- "log"
-
"dev.narayana.im/narayana/telegabber/config"
"dev.narayana.im/narayana/telegabber/xmpp"
+
+ log "github.com/sirupsen/logrus"
)
// YAML config, compatible with the format of Zhabogram 2.0.0
const configPath string = "config.yml"
+
// JSON schema (not for editing by a user)
const schemaPath string = "./config_schema.json"
@@ -18,7 +19,10 @@ func main() {
log.Fatal(err)
}
- cm := xmpp.NewComponent(config.XMPP)
+ cm, err := xmpp.NewComponent(config.XMPP, config.Telegram)
+ if err != nil {
+ log.Fatal(err)
+ }
// reconnect automatically
log.Fatal(cm.Run())
diff --git a/telegram/client.go b/telegram/client.go
new file mode 100644
index 0000000..b0cee44
--- /dev/null
+++ b/telegram/client.go
@@ -0,0 +1,118 @@
+package telegram
+
+import (
+ "fmt"
+ "github.com/pkg/errors"
+ "path/filepath"
+ "strconv"
+
+ "dev.narayana.im/narayana/telegabber/config"
+
+ "github.com/zelenin/go-tdlib/client"
+)
+
+var logConstants = map[string]int32{
+ "fatal": 0,
+ "error": 1,
+ "warn": 2,
+ "info": 3,
+ "debug": 4,
+ "verbose": 5,
+ "all": 1023,
+}
+
+func stringToLogConstant(c string) int32 {
+ level, ok := logConstants[c]
+ if !ok {
+ level = 0
+ }
+
+ return level
+}
+
+type TelegramClient struct {
+ client *client.Client
+ jid string
+ parameters *client.TdlibParameters
+ online bool
+ logVerbosity client.Option
+}
+
+// NewClient instantiates a Telegram App
+func NewClient(conf config.TelegramConfig, jid string) (TelegramClient, error) {
+ logVerbosity := client.WithLogVerbosity(&client.SetLogVerbosityLevelRequest{
+ NewVerbosityLevel: stringToLogConstant(conf.Loglevel),
+ })
+
+ apiId, err := strconv.Atoi(conf.Tdlib.Client.APIID)
+ if err != nil {
+ return TelegramClient{}, errors.Wrap(err, "Wrong api_id")
+ }
+
+ parameters := client.TdlibParameters{
+ UseTestDc: false,
+
+ DatabaseDirectory: filepath.Join("./sessions/", jid),
+ FilesDirectory: filepath.Join("./sessions/", jid, "/files/"),
+
+ UseFileDatabase: true,
+ UseChatInfoDatabase: conf.Tdlib.Client.UseChatInfoDatabase,
+ UseMessageDatabase: true,
+ UseSecretChats: conf.Tdlib.Client.UseSecretChats,
+
+ ApiId: int32(apiId),
+ ApiHash: conf.Tdlib.Client.APIHash,
+
+ SystemLanguageCode: "en",
+ DeviceModel: conf.Tdlib.Client.DeviceModel,
+ SystemVersion: "1.0.0",
+ ApplicationVersion: conf.Tdlib.Client.ApplicationVersion,
+
+ EnableStorageOptimizer: true,
+ IgnoreFileNames: false,
+ }
+
+ return TelegramClient{
+ parameters: &parameters,
+ jid: jid,
+ logVerbosity: logVerbosity,
+ }, nil
+}
+
+func updateHandler(tdlibClient *client.Client) {
+ listener := tdlibClient.GetListener()
+ defer listener.Close()
+
+ for update := range listener.Updates {
+ if update.GetClass() == client.ClassUpdate {
+ fmt.Printf("%#v", update)
+ }
+ }
+}
+
+func (c *TelegramClient) Connect() error {
+ if c.online {
+ return nil
+ }
+
+ authorizer := client.ClientAuthorizer()
+ authorizer.TdlibParameters <- c.parameters
+
+ tdlibClient, err := client.NewClient(authorizer, c.logVerbosity)
+ if err != nil {
+ return errors.Wrap(err, "Coudn't initialize a Telegram client instance")
+ }
+
+ c.client = tdlibClient
+ c.online = true
+
+ go updateHandler(c.client)
+
+ return nil
+}
+
+func (c *TelegramClient) Disconnect() {
+ if !c.online {
+ return
+ }
+}
diff --git a/test/good_config.yml b/test/good_config.yml
index 3ea257c..a60bb4b 100644
--- a/test/good_config.yml
+++ b/test/good_config.yml
@@ -13,6 +13,7 @@
:device_model: 'telegabber'
:application_version: '2.0'
:use_chat_info_database: false
+ :use_secret_chats: true
:xmpp:
:loglevel: :warn
diff --git a/xmpp/component.go b/xmpp/component.go
index d55ed6b..1562224 100644
--- a/xmpp/component.go
+++ b/xmpp/component.go
@@ -1,16 +1,25 @@
package xmpp
import (
- "log"
-
"dev.narayana.im/narayana/telegabber/config"
"gosrc.io/xmpp"
)
+var jid *xmpp.Jid
+var tgConf config.TelegramConfig
+
// NewComponent starts a new component and wraps it in
// a stream manager that you should start yourself
-func NewComponent(conf config.XMPPConfig) *xmpp.StreamManager {
+func NewComponent(conf config.XMPPConfig, tc config.TelegramConfig) (*xmpp.StreamManager, error) {
+ var err error
+ jid, err = xmpp.NewJid(conf.Jid)
+ if err != nil {
+ return nil, err
+ }
+
+ tgConf = tc
+
options := xmpp.ComponentOptions{
Address: conf.Host + ":" + conf.Port,
Domain: conf.Jid,
@@ -19,14 +28,16 @@ func NewComponent(conf config.XMPPConfig) *xmpp.StreamManager {
}
router := xmpp.NewRouter()
+ router.HandleFunc("iq", HandleIq)
+ router.HandleFunc("presence", HandlePresence)
router.HandleFunc("message", HandleMessage)
component, err := xmpp.NewComponent(options, router)
if err != nil {
- log.Fatalf("%+v", err)
+ return nil, err
}
cm := xmpp.NewStreamManager(component, nil)
- return cm
+ return cm, nil
}
diff --git a/xmpp/handlers.go b/xmpp/handlers.go
index 874af49..c7acdce 100644
--- a/xmpp/handlers.go
+++ b/xmpp/handlers.go
@@ -1,22 +1,109 @@
package xmpp
import (
- "fmt"
- "os"
+ "dev.narayana.im/narayana/telegabber/telegram"
+ log "github.com/sirupsen/logrus"
"gosrc.io/xmpp"
"gosrc.io/xmpp/stanza"
)
+var sessions map[string]telegram.TelegramClient
+
+func logPacketType(p stanza.Packet) {
+ log.Warn("Ignoring packet: %T\n", p)
+}
+
+// HandleIq processes an incoming XMPP iq
+func HandleIq(s xmpp.Sender, p stanza.Packet) {
+ iq, ok := p.(stanza.IQ)
+ if !ok {
+ logPacketType(p)
+ return
+ }
+
+ log.Printf("Iq: %#v\n", iq)
+}
+
// HandleMessage processes an incoming XMPP message
func HandleMessage(s xmpp.Sender, p stanza.Packet) {
msg, ok := p.(stanza.Message)
if !ok {
- _, _ = fmt.Fprintf(os.Stdout, "Ignoring packet: %T\n", p)
+ logPacketType(p)
return
}
- _, _ = fmt.Fprintf(os.Stdout, "Body = %s - from = %s\n", msg.Body, msg.From)
+ log.Printf("Message: %#v\n", msg)
reply := stanza.Message{Attrs: stanza.Attrs{To: msg.From}, Body: msg.Body}
_ = s.Send(reply)
}
+
+// HandlePresence processes an incoming XMPP presence
+func HandlePresence(s xmpp.Sender, p stanza.Packet) {
+ prs, ok := p.(stanza.Presence)
+ if !ok {
+ logPacketType(p)
+ return
+ }
+
+ if prs.Type == "subscribe" {
+ handleSubscription(s, prs)
+ } else if prs.To == jid.Bare() {
+ handlePresence(s, prs)
+ }
+}
+
+func handleSubscription(s xmpp.Sender, p stanza.Presence) {
+ log.WithFields(log.Fields{
+ "from": p.From,
+ "to": p.To,
+ }).Warn("Subscription request")
+ log.Debugf("%#v", p)
+
+ reply := stanza.Presence{Attrs: stanza.Attrs{
+ From: p.To,
+ To: p.From,
+ Id: p.Id,
+ Type: "subscribed",
+ }}
+
+ _ = s.Send(reply)
+}
+
+func handlePresence(s xmpp.Sender, p stanza.Presence) {
+ presenceType := p.Type
+ if presenceType == "" {
+ presenceType = "online"
+ }
+
+ log.WithFields(log.Fields{
+ "type": presenceType,
+ "from": p.From,
+ "to": p.To,
+ }).Warn("Presence")
+ log.Debugf("%#v", p)
+
+ fromJid, err := xmpp.NewJid(p.From)
+ if err != nil {
+ log.Error("Invalid from JID!")
+ return
+ }
+ bareFromJid := fromJid.Bare()
+ session, ok := sessions[bareFromJid]
+ if !ok {
+ client, err := telegram.NewClient(tgConf, bareFromJid)
+ if err != nil {
+ log.Error("Invalid from JID!")
+ }
+ sessions[bareFromJid] = client
+ }
+
+ switch p.Type {
+ case "unsubscribed":
+ delete(sessions, bareFromJid)
+ case "unavailable", "error":
+ session.Disconnect()
+ case "":
+ session.Connect()
+ }
+}