Compare commits

..

No commits in common. "master" and "v1.0.1" have entirely different histories.

22 changed files with 35596 additions and 112340 deletions

View file

@ -7,9 +7,8 @@ I realized that zelenin's library doesn't meet my need😕
So I fork it and make some changes
1. Static build by default
2. Add update [event filter](example#event-filter)
3. Add [command](example#command) parser
2. Add update event filter
3. Add command parser
4. Receive correct message id to patch text/dice message response.
5. Add [Pending updates](example#pending-updates)
[Here](example) are a few example codes about how to use **c0re100/gotdlib**.

View file

@ -3,10 +3,7 @@ package client
import (
"errors"
"fmt"
"syscall"
"time"
"golang.org/x/crypto/ssh/terminal"
)
var ErrNotSupportedAuthorizationState = errors.New("not supported state")
@ -46,7 +43,7 @@ func Authorize(client *Client, authorizationStateHandler AuthorizationStateHandl
}
type clientAuthorizer struct {
TdlibParameters chan *SetTdlibParametersRequest
TdlibParameters chan *TdlibParameters
PhoneNumber chan string
Code chan string
State chan AuthorizationState
@ -55,7 +52,7 @@ type clientAuthorizer struct {
func ClientAuthorizer() *clientAuthorizer {
return &clientAuthorizer{
TdlibParameters: make(chan *SetTdlibParametersRequest, 1),
TdlibParameters: make(chan *TdlibParameters, 1),
PhoneNumber: make(chan string, 1),
Code: make(chan string, 1),
State: make(chan AuthorizationState, 10),
@ -68,7 +65,13 @@ func (stateHandler *clientAuthorizer) Handle(client *Client, state Authorization
switch state.AuthorizationStateType() {
case TypeAuthorizationStateWaitTdlibParameters:
_, err := client.SetTdlibParameters(<-stateHandler.TdlibParameters)
_, err := client.SetTdlibParameters(&SetTdlibParametersRequest{
Parameters: <-stateHandler.TdlibParameters,
})
return err
case TypeAuthorizationStateWaitEncryptionKey:
_, err := client.CheckDatabaseEncryptionKey(&CheckDatabaseEncryptionKeyRequest{})
return err
case TypeAuthorizationStateWaitPhoneNumber:
@ -147,13 +150,10 @@ func CliInteractor(clientAuthorizer *clientAuthorizer) {
case TypeAuthorizationStateWaitPassword:
fmt.Println("Enter password: ")
bytePassword, err := terminal.ReadPassword(int(syscall.Stdin))
if err != nil {
fmt.Println(err)
continue
}
var password string
fmt.Scanln(&password)
clientAuthorizer.Password <- string(bytePassword)
clientAuthorizer.Password <- password
case TypeAuthorizationStateReady:
return
@ -163,14 +163,14 @@ func CliInteractor(clientAuthorizer *clientAuthorizer) {
}
type botAuthorizer struct {
TdlibParameters chan *SetTdlibParametersRequest
TdlibParameters chan *TdlibParameters
Token chan string
State chan AuthorizationState
}
func BotAuthorizer(token string) *botAuthorizer {
botAuthorizer := &botAuthorizer{
TdlibParameters: make(chan *SetTdlibParametersRequest, 1),
TdlibParameters: make(chan *TdlibParameters, 1),
Token: make(chan string, 1),
State: make(chan AuthorizationState, 10),
}
@ -185,7 +185,13 @@ func (stateHandler *botAuthorizer) Handle(client *Client, state AuthorizationSta
switch state.AuthorizationStateType() {
case TypeAuthorizationStateWaitTdlibParameters:
_, err := client.SetTdlibParameters(<-stateHandler.TdlibParameters)
_, err := client.SetTdlibParameters(&SetTdlibParametersRequest{
Parameters: <-stateHandler.TdlibParameters,
})
return err
case TypeAuthorizationStateWaitEncryptionKey:
_, err := client.CheckDatabaseEncryptionKey(&CheckDatabaseEncryptionKeyRequest{})
return err
case TypeAuthorizationStateWaitPhoneNumber:

View file

@ -9,19 +9,15 @@ import (
"time"
)
var pendingUpdateType []Type
type Client struct {
jsonClient *JsonClient
extraGenerator ExtraGenerator
responses chan *Response
pendingResp chan *Response
listenerStore *listenerStore
catchersStore *sync.Map
successMsgStore *sync.Map
updatesTimeout time.Duration
catchTimeout time.Duration
DisablePatch bool
}
type Option func(*Client)
@ -44,12 +40,6 @@ func WithProxy(req *AddProxyRequest) Option {
}
}
func WithoutSendMessagePatch() Option {
return func(client *Client) {
client.DisablePatch = true
}
}
func SetLogLevel(level int32) {
_, _ = SetLogVerbosityLevel(&SetLogVerbosityLevelRequest{
NewVerbosityLevel: level,
@ -66,18 +56,10 @@ func SetFilePath(path string) {
})
}
// Keep specific update type in memory when listener is not ready.
func SetPendingUpdateType(update ...Type) {
for _, v := range update {
pendingUpdateType = append(pendingUpdateType, v)
}
}
func NewClient(authorizationStateHandler AuthorizationStateHandler, options ...Option) (*Client, error) {
client := &Client{
jsonClient: NewJsonClient(),
responses: make(chan *Response, 1000),
pendingResp: make(chan *Response, 1000),
listenerStore: newListenerStore(),
catchersStore: &sync.Map{},
successMsgStore: &sync.Map{},
@ -86,15 +68,14 @@ func NewClient(authorizationStateHandler AuthorizationStateHandler, options ...O
client.extraGenerator = UuidV4Generator()
client.catchTimeout = 60 * time.Second
for _, option := range options {
option(client)
}
tdlibInstance.addClient(client)
go client.processPendingResponse()
go client.receiver()
for _, option := range options {
go option(client)
}
err := Authorize(client, authorizationStateHandler)
if err != nil {
return nil, err
@ -103,7 +84,8 @@ func NewClient(authorizationStateHandler AuthorizationStateHandler, options ...O
return client, nil
}
func (client *Client) processResponse(response *Response) {
func (client *Client) receiver() {
for response := range client.responses {
if response.Extra != "" {
value, ok := client.catchersStore.Load(response.Extra)
if ok {
@ -113,39 +95,20 @@ func (client *Client) processResponse(response *Response) {
typ, err := UnmarshalType(response.Data)
if err != nil {
return
continue
}
if !client.DisablePatch && typ.GetType() == (&UpdateMessageSendSucceeded{}).GetType() {
sendVal, sOk := client.successMsgStore.Load(typ.(*UpdateMessageSendSucceeded).OldMessageId)
if sOk {
sendVal.(chan *Response) <- response
}
}
if len(client.listenerStore.Listeners()) == 0 {
for _, p := range pendingUpdateType {
if typ.GetType() == p.GetType() {
client.pendingResp <- response
}
if typ.GetType() == (&UpdateMessageSendSucceeded{}).GetType() {
value, ok := client.successMsgStore.Load(typ.(*UpdateMessageSendSucceeded).OldMessageId)
if ok {
value.(chan *Response) <- response
}
}
needGc := false
for _, listener := range client.listenerStore.Listeners() {
if listener.IsActive() && listener.Updates != nil && typ.GetType() == listener.Filter.GetType() { // All updates go to Updates channel if type == filter
// Make some delay to UpdateMessageSendSucceeded listener
// This can make UpdateMessageSendSucceeded response later than sendMessage response.
// This may help a bot developer to map temporary message id to actual message id easily.
// Cause an event listener slower than sendMessage response, so you have enough time to do mapping stuff.
if typ.GetType() == (&UpdateMessageSendSucceeded{}).GetType() {
go func(listener *Listener, typ Type) {
time.Sleep(5 * time.Millisecond)
listener.Updates <- typ
}(listener, typ)
} else {
listener.Updates <- typ
}
} else if listener.IsActive() && listener.RawUpdates != nil { // All updates go to RawUpdates channel if filter is empty
listener.RawUpdates <- typ
} else if !listener.IsActive() { // GC inactive listener
@ -155,35 +118,6 @@ func (client *Client) processResponse(response *Response) {
if needGc {
client.listenerStore.gc()
}
if typ.GetType() == TypeUpdateAuthorizationState && typ.(*UpdateAuthorizationState).AuthorizationState.AuthorizationStateType() == TypeAuthorizationStateClosed {
close(client.responses)
}
}
func (client *Client) receiver() {
for response := range client.responses {
client.processResponse(response)
}
}
func (client *Client) processPendingResponse() {
// No need to process pending response if no pending list.
if len(pendingUpdateType) == 0 {
return
}
// Wait for listener to be ready.
for {
if len(client.listenerStore.Listeners()) > 0 {
break
}
time.Sleep(1 * time.Second)
}
// Start processing pending response
for response := range client.pendingResp {
client.processResponse(response)
}
}
@ -206,7 +140,7 @@ func (client *Client) Send(req Request) (*Response, error) {
select {
case response := <-catcher:
if !client.DisablePatch && response.Type != "error" && req.Type == "sendMessage" {
if response.Type != "error" && req.Type == "sendMessage" {
m, err := UnmarshalMessage(response.Data)
if err != nil {
return nil, err
@ -227,11 +161,12 @@ func (client *Client) Send(req Request) (*Response, error) {
if err2 != nil {
return response, nil
}
response.Data = bytes.Replace(response.Data, []byte("\"@type\":\"messageSendingStatePending\""), []byte("\"@type\":\"updateMessageSendSucceeded\""), 1)
response.Data = bytes.Replace(response.Data, []byte("\"id\":"+strconv.FormatInt(m.Id, 10)), []byte("\"id\":"+strconv.FormatInt(m2.Message.Id, 10)), 1)
response.Data = bytes.Replace(response.Data, []byte("{\"@type\":\"messageSendingStatePending\"}"), []byte("{\"@type\":\"updateMessageSendSucceeded\"}"), 1)
response.Data = bytes.Replace(response.Data, []byte(strconv.FormatInt(m.Id, 10)), []byte(strconv.FormatInt(m2.Message.Id, 10)), 1)
return response, nil
case <-time.After(1 * time.Second):
return response, nil
client.successMsgStore.Delete(m.Id)
close(successCatcher)
}
}
}
@ -261,3 +196,7 @@ func (client *Client) AddEventReceiver(msgType Type, channelCapacity int) *Liste
return listener
}
func (client *Client) Stop() {
client.Destroy()
}

View file

@ -1,49 +1,67 @@
package client
import (
"fmt"
"math/rand"
"strings"
"github.com/google/uuid"
)
type ExtraGenerator func() string
func UuidV4Generator() ExtraGenerator {
return func() string {
return uuid.NewString()
var uuid [16]byte
rand.Read(uuid[:])
uuid[6] = (uuid[6] & 0x0f) | 0x40
uuid[8] = (uuid[8] & 0x3f) | 0x80
return fmt.Sprintf("%08x-%04x-%04x-%04x-%012x", uuid[:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:])
}
}
func IsCommand(text string) bool {
if i := strings.Index(text, "/"); i == 0 {
func IsCommmand(text string) bool {
if text != "" {
if text[0] == '/' {
return true
}
}
return false
}
func CheckCommand(text string, entities []*TextEntity) string {
if IsCommand(text) {
cmd := text
// e.g. ["/hello 123", "/hell o 123"]
// Result: "/hello", "/hell"
if i := strings.Index(cmd, " "); i != -1 {
cmd = cmd[:i]
if IsCommmand(text) {
// Check text entities and make bot happy!
if len(entities) >= 1 {
// Get first command
if entities[0].Type.TextEntityTypeType() == "textEntityTypeBotCommand" {
// e.g.: { "text": "/hello@world_bot", "textEntity": { offset: 0, length: 16 } }
// Result: "/hello"
if i := strings.Index(text[:entities[0].Length], "@"); i != -1 {
return text[:i]
}
return text[:entities[0].Length]
}
} else {
// Since userbot does not have bot command entities in Private Chat, so make userbot happy too!
// e.g.: ["/hello@world_bot", "/hello@", "/hello@123"]
// Result: "/hello"
if i := strings.Index(cmd, "@"); i != -1 {
cmd = cmd[:i]
if i := strings.Index(text, "@"); i != -1 {
return text[:i]
}
// e.g. ["/hello 123", "/hell o 123"]
// Result: "/hello", "/hell"
if i := strings.Index(text, " "); i != -1 {
return text[:i]
}
return text
}
return cmd
}
return ""
}
func CommandArgument(text string) string {
if IsCommand(text) {
if IsCommmand(text) {
// e.g. ["/hello 123", "/hell o 123"]
// Result: "123", "o 123"
if i := strings.Index(text, " "); i != -1 {

File diff suppressed because it is too large Load diff

View file

@ -1,12 +1,10 @@
package client
//#cgo linux CFLAGS: -I/usr/local/include
//#cgo freebsd CFLAGS: -I/usr/local/include
//#cgo darwin CFLAGS: -I/usr/local/include
//#cgo windows CFLAGS: -IE:/src/tdlib -IE:/src/tdlib/build
//#cgo linux LDFLAGS: -L/usr/local/lib -ltdjson_static -ltdjson_private -ltdclient -ltdcore -ltdapi -ltdactor -ltddb -ltde2e -ltdsqlite -ltdmtproto -ltdnet -ltdutils -lstdc++ -lssl -lcrypto -ldl -lz -lm
//#cgo freebsd LDFLAGS: -L/usr/local/lib -ltdjson_static -ltdjson_private -ltdclient -ltdcore -ltdapi -ltdactor -ltddb -ltde2e -ltdsqlite -ltdmtproto -ltdnet -ltdutils -lstdc++ -lssl -lcrypto -ldl -lz -lm
//#cgo darwin LDFLAGS: -L/usr/local/lib -L/usr/local/opt/openssl/lib -ltdjson_static -ltdjson_private -ltdclient -ltdcore -ltdapi -ltdactor -ltddb -ltde2e -ltdsqlite -ltdmtproto -ltdnet -ltdutils -lstdc++ -lssl -lcrypto -ldl -lz -lm
//#cgo linux LDFLAGS: -L/usr/local/lib -ltdjson_static -ltdjson_private -ltdclient -ltdcore -ltdapi -ltdactor -ltddb -ltdsqlite -ltdnet -ltdutils -lstdc++ -lssl -lcrypto -ldl -lz -lm
//#cgo darwin LDFLAGS: -L/usr/local/lib -L/usr/local/opt/openssl/lib -ltdjson_static -ltdjson_private -ltdclient -ltdcore -ltdapi -ltdactor -ltddb -ltdsqlite -ltdnet -ltdutils -lstdc++ -lssl -lcrypto -ldl -lz -lm
//#cgo windows LDFLAGS: -LE:/src/tdlib/build/Release -ltdjson
//#include <stdlib.h>
//#include <td/telegram/td_json_client.h>

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -13,10 +13,5 @@ So we need to filter update events, like UpdateNewMessage, UpdateMessageSendSucc
### Media
Send photo or album to chat.
### Pending updates
When starting a bot, we may have some updates that are missed to process when a listener IS NOT ready.
So we need to keep specific update types in memory until a listener is set, then we can process those updates again.
### Raw Update
Get update without event filter.

View file

@ -9,8 +9,8 @@ import (
tdlib "github.com/c0re100/gotdlib/client"
)
func GetTdParameters() *tdlib.SetTdlibParametersRequest {
return &tdlib.SetTdlibParametersRequest{
func GetTdParameters() *tdlib.TdlibParameters {
return &tdlib.TdlibParameters{
UseTestDc: false,
DatabaseDirectory: "./tdlib-db",
FilesDirectory: "./tdlib-files",
@ -24,6 +24,8 @@ func GetTdParameters() *tdlib.SetTdlibParametersRequest {
DeviceModel: "HuskyNG",
SystemVersion: "3.0",
ApplicationVersion: "3.0",
EnableStorageOptimizer: true,
IgnoreFileNames: false,
}
}
@ -50,7 +52,7 @@ func main() {
signal.Notify(ch, os.Interrupt, syscall.SIGSEGV)
go func() {
<-ch
client.Close()
client.Destroy()
}()
me, err := client.GetMe()
@ -58,7 +60,7 @@ func main() {
log.Fatalf("GetMe error: %s", err)
}
log.Printf("%v connected", me.Usernames)
log.Printf("%s connected", me.Username)
listener := client.AddEventReceiver(&tdlib.UpdateNewMessage{}, 1000)
@ -85,9 +87,7 @@ func main() {
})
m, err := client.SendMessage(&tdlib.SendMessageRequest{
ChatId: chatId,
ReplyTo: &tdlib.InputMessageReplyToMessage{
MessageId: msgId,
},
ReplyToMessageId: msgId,
InputMessageContent: &tdlib.InputMessageText{
Text: text,
},

View file

@ -17,8 +17,8 @@ func GetSenderId(sender tdlib.MessageSender) int64 {
}
}
func GetTdParameters() *tdlib.SetTdlibParametersRequest {
return &tdlib.SetTdlibParametersRequest{
func GetTdParameters() *tdlib.TdlibParameters {
return &tdlib.TdlibParameters{
UseTestDc: false,
DatabaseDirectory: "./tdlib-db",
FilesDirectory: "./tdlib-files",
@ -32,6 +32,8 @@ func GetTdParameters() *tdlib.SetTdlibParametersRequest {
DeviceModel: "HuskyNG",
SystemVersion: "3.0",
ApplicationVersion: "3.0",
EnableStorageOptimizer: true,
IgnoreFileNames: false,
}
}
@ -58,7 +60,7 @@ func main() {
signal.Notify(ch, os.Interrupt, syscall.SIGSEGV)
go func() {
<-ch
client.Close()
client.Destroy()
}()
me, err := client.GetMe()
@ -66,7 +68,7 @@ func main() {
log.Fatalf("GetMe error: %s", err)
}
log.Printf("%v connected", me.Usernames)
log.Printf("%s connected", me.Username)
listener := client.AddEventReceiver(&tdlib.UpdateNewMessage{}, 1000)
@ -96,9 +98,7 @@ func main() {
})
m, err := client.SendMessage(&tdlib.SendMessageRequest{
ChatId: chatId,
ReplyTo: &tdlib.InputMessageReplyToMessage{
MessageId: msgId,
},
ReplyToMessageId: msgId,
InputMessageContent: &tdlib.InputMessageText{
Text: text,
},
@ -107,20 +107,6 @@ func main() {
continue
}
log.Printf("Message sent, ID: %d", m.Id)
case "/repeat":
m, err := client.SendMessage(&tdlib.SendMessageRequest{
ChatId: chatId,
ReplyTo: &tdlib.InputMessageReplyToMessage{
MessageId: msgId,
},
InputMessageContent: &tdlib.InputMessageText{
Text: &tdlib.FormattedText{Text: tdlib.CommandArgument(msgText)},
},
})
if err != nil {
continue
}
log.Printf("Message sent, ID: %d", m.Id)
}
}
}

View file

@ -17,8 +17,8 @@ func GetSenderId(sender tdlib.MessageSender) int64 {
}
}
func GetTdParameters() *tdlib.SetTdlibParametersRequest {
return &tdlib.SetTdlibParametersRequest{
func GetTdParameters() *tdlib.TdlibParameters {
return &tdlib.TdlibParameters{
UseTestDc: false,
DatabaseDirectory: "./tdlib-db",
FilesDirectory: "./tdlib-files",
@ -32,6 +32,8 @@ func GetTdParameters() *tdlib.SetTdlibParametersRequest {
DeviceModel: "HuskyNG",
SystemVersion: "3.0",
ApplicationVersion: "3.0",
EnableStorageOptimizer: true,
IgnoreFileNames: false,
}
}
@ -58,7 +60,7 @@ func main() {
signal.Notify(ch, os.Interrupt, syscall.SIGSEGV)
go func() {
<-ch
client.Close()
client.Destroy()
}()
me, err := client.GetMe()
@ -66,7 +68,7 @@ func main() {
log.Fatalf("GetMe error: %s", err)
}
log.Printf("%v connected", me.Usernames)
log.Printf("%s connected", me.Username)
listener := client.AddEventReceiver(&tdlib.UpdateNewMessage{}, 1000)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 794 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 900 KiB

View file

@ -17,8 +17,8 @@ func GetSenderId(sender tdlib.MessageSender) int64 {
}
}
func GetTdParameters() *tdlib.SetTdlibParametersRequest {
return &tdlib.SetTdlibParametersRequest{
func GetTdParameters() *tdlib.TdlibParameters {
return &tdlib.TdlibParameters{
UseTestDc: false,
DatabaseDirectory: "./tdlib-db",
FilesDirectory: "./tdlib-files",
@ -32,6 +32,8 @@ func GetTdParameters() *tdlib.SetTdlibParametersRequest {
DeviceModel: "HuskyNG",
SystemVersion: "3.0",
ApplicationVersion: "3.0",
EnableStorageOptimizer: true,
IgnoreFileNames: false,
}
}
@ -58,7 +60,7 @@ func main() {
signal.Notify(ch, os.Interrupt, syscall.SIGSEGV)
go func() {
<-ch
client.Close()
client.Destroy()
}()
me, err := client.GetMe()
@ -66,7 +68,7 @@ func main() {
log.Fatalf("GetMe error: %s", err)
}
log.Printf("%v connected", me.Usernames)
log.Printf("%s connected", me.Username)
listener := client.AddEventReceiver(&tdlib.UpdateNewMessage{}, 1000)
@ -96,12 +98,10 @@ func main() {
})
m, err := client.SendMessage(&tdlib.SendMessageRequest{
ChatId: chatId,
ReplyTo: &tdlib.InputMessageReplyToMessage{
MessageId: msgId,
},
ReplyToMessageId: msgId,
InputMessageContent: &tdlib.InputMessagePhoto{
Photo: &tdlib.InputFileLocal{
Path: "./Meru_01.png",
Path: "./myht9-1486821485193084928.jpg",
},
Caption: text,
},
@ -117,19 +117,17 @@ func main() {
})
m, err := client.SendMessageAlbum(&tdlib.SendMessageAlbumRequest{
ChatId: chatId,
ReplyTo: &tdlib.InputMessageReplyToMessage{
MessageId: msgId,
},
ReplyToMessageId: msgId,
InputMessageContents: []tdlib.InputMessageContent{
&tdlib.InputMessagePhoto{
Photo: &tdlib.InputFileLocal{
Path: "./Meru_01.png",
Path: "./myht9-1486821485193084928.jpg",
},
Caption: text,
},
&tdlib.InputMessagePhoto{
Photo: &tdlib.InputFileLocal{
Path: "./Meru_02.png",
Path: "./hisagi_02-1486983199280738309.jpg",
},
},
},

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

View file

@ -1,107 +0,0 @@
package main
import (
"log"
"os"
"os/signal"
"syscall"
tdlib "github.com/c0re100/gotdlib/client"
)
func GetTdParameters() *tdlib.SetTdlibParametersRequest {
return &tdlib.SetTdlibParametersRequest{
UseTestDc: false,
DatabaseDirectory: "./tdlib-db",
FilesDirectory: "./tdlib-files",
UseFileDatabase: true,
UseChatInfoDatabase: true,
UseMessageDatabase: true,
UseSecretChats: false,
ApiId: 132712,
ApiHash: "e82c07ad653399a37baca8d1e498e472",
SystemLanguageCode: "en",
DeviceModel: "HuskyNG",
SystemVersion: "3.0",
ApplicationVersion: "3.0",
}
}
func main() {
tdlib.SetLogLevel(0)
tdlib.SetFilePath("./errors.txt")
// Set pending update list
tdlib.SetPendingUpdateType(&tdlib.UpdateNewMessage{})
// Of coz, you can set more than one type, depending on your needs
//tdlib.SetPendingUpdateType(&tdlib.UpdateNewMessage{}, &tdlib.UpdateMessageEdited{}, &tdlib.UpdateDeleteMessages{})
botToken := "your_bot_token"
authorizer := tdlib.BotAuthorizer(botToken)
authorizer.TdlibParameters <- GetTdParameters()
client, err := tdlib.NewClient(authorizer)
if err != nil {
log.Fatalf("NewClient error: %s", err)
}
// Handle SIGINT
ch := make(chan os.Signal, 2)
signal.Notify(ch, os.Interrupt, syscall.SIGINT)
signal.Notify(ch, os.Interrupt, syscall.SIGKILL)
signal.Notify(ch, os.Interrupt, syscall.SIGTERM)
signal.Notify(ch, os.Interrupt, syscall.SIGQUIT)
signal.Notify(ch, os.Interrupt, syscall.SIGSEGV)
go func() {
<-ch
client.Close()
}()
me, err := client.GetMe()
if err != nil {
log.Fatalf("GetMe error: %s", err)
}
log.Printf("%v connected", me.Usernames)
listener := client.AddEventReceiver(&tdlib.UpdateNewMessage{}, 1000)
defer listener.Close()
for update := range listener.Updates {
updateMsg := update.(*tdlib.UpdateNewMessage)
chatId := updateMsg.Message.ChatId
msgId := updateMsg.Message.Id
var msgText string
var msgEnt []*tdlib.TextEntity
switch updateMsg.Message.Content.MessageContentType() {
case "messageText":
msgText = updateMsg.Message.Content.(*tdlib.MessageText).Text.Text
msgEnt = updateMsg.Message.Content.(*tdlib.MessageText).Text.Entities
cmd := tdlib.CheckCommand(msgText, msgEnt)
switch cmd {
case "/ping":
text, _ := tdlib.ParseTextEntities(&tdlib.ParseTextEntitiesRequest{
Text: "<b>pong!</b>",
ParseMode: &tdlib.TextParseModeHTML{},
})
m, err := client.SendMessage(&tdlib.SendMessageRequest{
ChatId: chatId,
ReplyTo: &tdlib.InputMessageReplyToMessage{
MessageId: msgId,
},
InputMessageContent: &tdlib.InputMessageText{
Text: text,
},
})
if err != nil {
continue
}
log.Printf("Message sent, ID: %d", m.Id)
}
}
}
}

View file

@ -17,8 +17,8 @@ func GetSenderId(sender tdlib.MessageSender) int64 {
}
}
func GetTdParameters() *tdlib.SetTdlibParametersRequest {
return &tdlib.SetTdlibParametersRequest{
func GetTdParameters() *tdlib.TdlibParameters {
return &tdlib.TdlibParameters{
UseTestDc: false,
DatabaseDirectory: "./tdlib-db",
FilesDirectory: "./tdlib-files",
@ -32,6 +32,8 @@ func GetTdParameters() *tdlib.SetTdlibParametersRequest {
DeviceModel: "HuskyNG",
SystemVersion: "3.0",
ApplicationVersion: "3.0",
EnableStorageOptimizer: true,
IgnoreFileNames: false,
}
}
@ -58,7 +60,7 @@ func main() {
signal.Notify(ch, os.Interrupt, syscall.SIGSEGV)
go func() {
<-ch
client.Close()
client.Destroy()
}()
me, err := client.GetMe()
@ -66,7 +68,7 @@ func main() {
log.Fatalf("GetMe error: %s", err)
}
log.Printf("%v connected", me.Usernames)
log.Printf("%s connected", me.Username)
listener := client.GetListener()

5
go.mod
View file

@ -1,8 +1,3 @@
module github.com/c0re100/gotdlib
go 1.16
require (
github.com/google/uuid v1.6.0
golang.org/x/crypto v0.31.0
)

69
go.sum
View file

@ -1,69 +0,0 @@
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=