Support pending updates
This commit is contained in:
parent
a339293774
commit
6400f59b1b
100
client/client.go
100
client/client.go
|
@ -9,10 +9,13 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var pendingUpdateType []Type
|
||||||
|
|
||||||
type Client struct {
|
type Client struct {
|
||||||
jsonClient *JsonClient
|
jsonClient *JsonClient
|
||||||
extraGenerator ExtraGenerator
|
extraGenerator ExtraGenerator
|
||||||
responses chan *Response
|
responses chan *Response
|
||||||
|
pendingResp chan *Response
|
||||||
listenerStore *listenerStore
|
listenerStore *listenerStore
|
||||||
catchersStore *sync.Map
|
catchersStore *sync.Map
|
||||||
successMsgStore *sync.Map
|
successMsgStore *sync.Map
|
||||||
|
@ -56,10 +59,18 @@ 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) {
|
func NewClient(authorizationStateHandler AuthorizationStateHandler, options ...Option) (*Client, error) {
|
||||||
client := &Client{
|
client := &Client{
|
||||||
jsonClient: NewJsonClient(),
|
jsonClient: NewJsonClient(),
|
||||||
responses: make(chan *Response, 1000),
|
responses: make(chan *Response, 1000),
|
||||||
|
pendingResp: make(chan *Response, 1000),
|
||||||
listenerStore: newListenerStore(),
|
listenerStore: newListenerStore(),
|
||||||
catchersStore: &sync.Map{},
|
catchersStore: &sync.Map{},
|
||||||
successMsgStore: &sync.Map{},
|
successMsgStore: &sync.Map{},
|
||||||
|
@ -74,6 +85,7 @@ func NewClient(authorizationStateHandler AuthorizationStateHandler, options ...O
|
||||||
|
|
||||||
tdlibInstance.addClient(client)
|
tdlibInstance.addClient(client)
|
||||||
|
|
||||||
|
go client.processPendingResponse()
|
||||||
go client.receiver()
|
go client.receiver()
|
||||||
|
|
||||||
err := Authorize(client, authorizationStateHandler)
|
err := Authorize(client, authorizationStateHandler)
|
||||||
|
@ -84,40 +96,72 @@ func NewClient(authorizationStateHandler AuthorizationStateHandler, options ...O
|
||||||
return client, nil
|
return client, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (client *Client) processResponse(response *Response) {
|
||||||
|
if response.Extra != "" {
|
||||||
|
value, ok := client.catchersStore.Load(response.Extra)
|
||||||
|
if ok {
|
||||||
|
value.(chan *Response) <- response
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typ, err := UnmarshalType(response.Data)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if typ.GetType() == (&UpdateMessageSendSucceeded{}).GetType() {
|
||||||
|
value, ok := client.successMsgStore.Load(typ.(*UpdateMessageSendSucceeded).OldMessageId)
|
||||||
|
if ok {
|
||||||
|
value.(chan *Response) <- response
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(client.listenerStore.Listeners()) == 0 {
|
||||||
|
for _, p := range pendingUpdateType {
|
||||||
|
if typ.GetType() == p.GetType() {
|
||||||
|
client.pendingResp <- 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
|
||||||
|
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
|
||||||
|
needGc = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if needGc {
|
||||||
|
client.listenerStore.gc()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (client *Client) receiver() {
|
func (client *Client) receiver() {
|
||||||
for response := range client.responses {
|
for response := range client.responses {
|
||||||
if response.Extra != "" {
|
client.processResponse(response)
|
||||||
value, ok := client.catchersStore.Load(response.Extra)
|
}
|
||||||
if ok {
|
}
|
||||||
value.(chan *Response) <- response
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
typ, err := UnmarshalType(response.Data)
|
func (client *Client) processPendingResponse() {
|
||||||
if err != nil {
|
// No need to process pending response if no pending list.
|
||||||
continue
|
if len(pendingUpdateType) == 0 {
|
||||||
}
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if typ.GetType() == (&UpdateMessageSendSucceeded{}).GetType() {
|
// Wait for listener to be ready.
|
||||||
value, ok := client.successMsgStore.Load(typ.(*UpdateMessageSendSucceeded).OldMessageId)
|
for {
|
||||||
if ok {
|
if len(client.listenerStore.Listeners()) > 0 {
|
||||||
value.(chan *Response) <- response
|
break
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
needGc := false
|
// Start processing pending response
|
||||||
for _, listener := range client.listenerStore.Listeners() {
|
for response := range client.pendingResp {
|
||||||
if listener.IsActive() && listener.Updates != nil && typ.GetType() == listener.Filter.GetType() { // All updates go to Updates channel if type == filter
|
client.processResponse(response)
|
||||||
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
|
|
||||||
needGc = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if needGc {
|
|
||||||
client.listenerStore.gc()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
107
example/pending/PendingUpdate.go
Normal file
107
example/pending/PendingUpdate.go
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
tdlib "github.com/c0re100/gotdlib/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetTdParameters() *tdlib.TdlibParameters {
|
||||||
|
return &tdlib.TdlibParameters{
|
||||||
|
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",
|
||||||
|
EnableStorageOptimizer: true,
|
||||||
|
IgnoreFileNames: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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("%s connected", me.Username)
|
||||||
|
|
||||||
|
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,
|
||||||
|
ReplyToMessageId: msgId,
|
||||||
|
InputMessageContent: &tdlib.InputMessageText{
|
||||||
|
Text: text,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
log.Printf("Message sent, ID: %d", m.Id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue