Merge pull request #2 from L11R/master

go fmt formatted project
This commit is contained in:
Aleksandr Zelenin 2018-10-23 17:05:23 +03:00 committed by GitHub
commit 4fbb5dd875
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 21168 additions and 21168 deletions

View file

@ -16,3 +16,4 @@ generate-code:
-functionFile function.go \
-typeFile type.go \
-unmarshalerFile unmarshaler.go
go fmt ./...

View file

@ -1,214 +1,214 @@
package client
import (
"errors"
"fmt"
"time"
"errors"
"fmt"
"time"
)
var ErrNotSupportedAuthorizationState = errors.New("not supported state")
type AuthorizationStateHandler interface {
Handle(client *Client, state AuthorizationState) error
Handle(client *Client, state AuthorizationState) error
}
func Authorize(client *Client, authorizationStateHandler AuthorizationStateHandler) error {
for {
state, err := client.GetAuthorizationState()
if err != nil {
return err
}
for {
state, err := client.GetAuthorizationState()
if err != nil {
return err
}
err = authorizationStateHandler.Handle(client, state)
if err != nil {
return err
}
err = authorizationStateHandler.Handle(client, state)
if err != nil {
return err
}
if state.AuthorizationStateType() == TypeAuthorizationStateReady {
// dirty hack for db flush after authorization
time.Sleep(1 * time.Second)
return nil
}
}
if state.AuthorizationStateType() == TypeAuthorizationStateReady {
// dirty hack for db flush after authorization
time.Sleep(1 * time.Second)
return nil
}
}
}
type clientAuthorizer struct {
TdlibParameters chan *TdlibParameters
PhoneNumber chan string
Code chan string
State chan AuthorizationState
FirstName chan string
LastName chan string
TdlibParameters chan *TdlibParameters
PhoneNumber chan string
Code chan string
State chan AuthorizationState
FirstName chan string
LastName chan string
}
func ClientAuthorizer() *clientAuthorizer {
return &clientAuthorizer{
TdlibParameters: make(chan *TdlibParameters, 1),
PhoneNumber: make(chan string, 1),
Code: make(chan string, 1),
State: make(chan AuthorizationState, 10),
FirstName: make(chan string, 1),
LastName: make(chan string, 1),
}
return &clientAuthorizer{
TdlibParameters: make(chan *TdlibParameters, 1),
PhoneNumber: make(chan string, 1),
Code: make(chan string, 1),
State: make(chan AuthorizationState, 10),
FirstName: make(chan string, 1),
LastName: make(chan string, 1),
}
}
func (stateHandler *clientAuthorizer) Handle(client *Client, state AuthorizationState) error {
stateHandler.State <- state
stateHandler.State <- state
switch state.AuthorizationStateType() {
case TypeAuthorizationStateWaitTdlibParameters:
_, err := client.SetTdlibParameters(&SetTdlibParametersRequest{
Parameters: <-stateHandler.TdlibParameters,
})
return err
switch state.AuthorizationStateType() {
case TypeAuthorizationStateWaitTdlibParameters:
_, err := client.SetTdlibParameters(&SetTdlibParametersRequest{
Parameters: <-stateHandler.TdlibParameters,
})
return err
case TypeAuthorizationStateWaitEncryptionKey:
_, err := client.CheckDatabaseEncryptionKey(&CheckDatabaseEncryptionKeyRequest{})
return err
case TypeAuthorizationStateWaitEncryptionKey:
_, err := client.CheckDatabaseEncryptionKey(&CheckDatabaseEncryptionKeyRequest{})
return err
case TypeAuthorizationStateWaitPhoneNumber:
_, err := client.SetAuthenticationPhoneNumber(&SetAuthenticationPhoneNumberRequest{
PhoneNumber: <-stateHandler.PhoneNumber,
AllowFlashCall: false,
IsCurrentPhoneNumber: false,
})
return err
case TypeAuthorizationStateWaitPhoneNumber:
_, err := client.SetAuthenticationPhoneNumber(&SetAuthenticationPhoneNumberRequest{
PhoneNumber: <-stateHandler.PhoneNumber,
AllowFlashCall: false,
IsCurrentPhoneNumber: false,
})
return err
case TypeAuthorizationStateWaitCode:
_, err := client.CheckAuthenticationCode(&CheckAuthenticationCodeRequest{
Code: <-stateHandler.Code,
FirstName: <-stateHandler.FirstName,
LastName: <-stateHandler.LastName,
})
return err
case TypeAuthorizationStateWaitCode:
_, err := client.CheckAuthenticationCode(&CheckAuthenticationCodeRequest{
Code: <-stateHandler.Code,
FirstName: <-stateHandler.FirstName,
LastName: <-stateHandler.LastName,
})
return err
case TypeAuthorizationStateWaitPassword:
return ErrNotSupportedAuthorizationState
case TypeAuthorizationStateWaitPassword:
return ErrNotSupportedAuthorizationState
case TypeAuthorizationStateReady:
close(stateHandler.TdlibParameters)
close(stateHandler.PhoneNumber)
close(stateHandler.Code)
close(stateHandler.State)
close(stateHandler.FirstName)
close(stateHandler.LastName)
case TypeAuthorizationStateReady:
close(stateHandler.TdlibParameters)
close(stateHandler.PhoneNumber)
close(stateHandler.Code)
close(stateHandler.State)
close(stateHandler.FirstName)
close(stateHandler.LastName)
return nil
return nil
case TypeAuthorizationStateLoggingOut:
return ErrNotSupportedAuthorizationState
case TypeAuthorizationStateLoggingOut:
return ErrNotSupportedAuthorizationState
case TypeAuthorizationStateClosing:
return ErrNotSupportedAuthorizationState
case TypeAuthorizationStateClosing:
return ErrNotSupportedAuthorizationState
case TypeAuthorizationStateClosed:
return ErrNotSupportedAuthorizationState
}
case TypeAuthorizationStateClosed:
return ErrNotSupportedAuthorizationState
}
return ErrNotSupportedAuthorizationState
return ErrNotSupportedAuthorizationState
}
func CliInteractor(clientAuthorizer *clientAuthorizer) {
for {
select {
case state := <-clientAuthorizer.State:
switch state.AuthorizationStateType() {
case TypeAuthorizationStateWaitPhoneNumber:
fmt.Println("Enter phone number: ")
var phoneNumber string
fmt.Scanln(&phoneNumber)
for {
select {
case state := <-clientAuthorizer.State:
switch state.AuthorizationStateType() {
case TypeAuthorizationStateWaitPhoneNumber:
fmt.Println("Enter phone number: ")
var phoneNumber string
fmt.Scanln(&phoneNumber)
clientAuthorizer.PhoneNumber <- phoneNumber
clientAuthorizer.PhoneNumber <- phoneNumber
case TypeAuthorizationStateWaitCode:
var code string
var firstName string
var lastName string
case TypeAuthorizationStateWaitCode:
var code string
var firstName string
var lastName string
fmt.Println("Enter code: ")
fmt.Scanln(&code)
fmt.Println("Enter code: ")
fmt.Scanln(&code)
if !state.(*AuthorizationStateWaitCode).IsRegistered {
fmt.Println("Phone number is not registered.")
if !state.(*AuthorizationStateWaitCode).IsRegistered {
fmt.Println("Phone number is not registered.")
fmt.Println("Enter first name: ")
fmt.Scanln(&firstName)
fmt.Println("Enter first name: ")
fmt.Scanln(&firstName)
fmt.Println("Enter last name: ")
fmt.Scanln(&lastName)
}
fmt.Println("Enter last name: ")
fmt.Scanln(&lastName)
}
clientAuthorizer.Code <- code
clientAuthorizer.FirstName <- firstName
clientAuthorizer.LastName <- lastName
clientAuthorizer.Code <- code
clientAuthorizer.FirstName <- firstName
clientAuthorizer.LastName <- lastName
case TypeAuthorizationStateReady:
return
}
}
}
case TypeAuthorizationStateReady:
return
}
}
}
}
type botAuthorizer struct {
TdlibParameters chan *TdlibParameters
Token chan string
State chan AuthorizationState
TdlibParameters chan *TdlibParameters
Token chan string
State chan AuthorizationState
}
func BotAuthorizer(token string) *botAuthorizer {
botAuthorizer := &botAuthorizer{
TdlibParameters: make(chan *TdlibParameters, 1),
Token: make(chan string, 1),
State: make(chan AuthorizationState, 10),
}
botAuthorizer := &botAuthorizer{
TdlibParameters: make(chan *TdlibParameters, 1),
Token: make(chan string, 1),
State: make(chan AuthorizationState, 10),
}
botAuthorizer.Token <- token
botAuthorizer.Token <- token
return botAuthorizer
return botAuthorizer
}
func (stateHandler *botAuthorizer) Handle(client *Client, state AuthorizationState) error {
stateHandler.State <- state
stateHandler.State <- state
switch state.AuthorizationStateType() {
case TypeAuthorizationStateWaitTdlibParameters:
_, err := client.SetTdlibParameters(&SetTdlibParametersRequest{
Parameters: <-stateHandler.TdlibParameters,
})
return err
switch state.AuthorizationStateType() {
case TypeAuthorizationStateWaitTdlibParameters:
_, err := client.SetTdlibParameters(&SetTdlibParametersRequest{
Parameters: <-stateHandler.TdlibParameters,
})
return err
case TypeAuthorizationStateWaitEncryptionKey:
_, err := client.CheckDatabaseEncryptionKey(&CheckDatabaseEncryptionKeyRequest{})
return err
case TypeAuthorizationStateWaitEncryptionKey:
_, err := client.CheckDatabaseEncryptionKey(&CheckDatabaseEncryptionKeyRequest{})
return err
case TypeAuthorizationStateWaitPhoneNumber:
_, err := client.CheckAuthenticationBotToken(&CheckAuthenticationBotTokenRequest{
Token: <-stateHandler.Token,
})
return err
case TypeAuthorizationStateWaitPhoneNumber:
_, err := client.CheckAuthenticationBotToken(&CheckAuthenticationBotTokenRequest{
Token: <-stateHandler.Token,
})
return err
case TypeAuthorizationStateWaitCode:
return ErrNotSupportedAuthorizationState
case TypeAuthorizationStateWaitCode:
return ErrNotSupportedAuthorizationState
case TypeAuthorizationStateWaitPassword:
return ErrNotSupportedAuthorizationState
case TypeAuthorizationStateWaitPassword:
return ErrNotSupportedAuthorizationState
case TypeAuthorizationStateReady:
close(stateHandler.TdlibParameters)
close(stateHandler.Token)
close(stateHandler.State)
case TypeAuthorizationStateReady:
close(stateHandler.TdlibParameters)
close(stateHandler.Token)
close(stateHandler.State)
return nil
return nil
case TypeAuthorizationStateLoggingOut:
return ErrNotSupportedAuthorizationState
case TypeAuthorizationStateLoggingOut:
return ErrNotSupportedAuthorizationState
case TypeAuthorizationStateClosing:
return ErrNotSupportedAuthorizationState
case TypeAuthorizationStateClosing:
return ErrNotSupportedAuthorizationState
case TypeAuthorizationStateClosed:
return ErrNotSupportedAuthorizationState
}
case TypeAuthorizationStateClosed:
return ErrNotSupportedAuthorizationState
}
return ErrNotSupportedAuthorizationState
return ErrNotSupportedAuthorizationState
}

View file

@ -1,145 +1,145 @@
package client
import (
"errors"
"sync"
"time"
"errors"
"sync"
"time"
)
type Client struct {
jsonClient *JsonClient
extraGenerator ExtraGenerator
catcher chan *Response
listenerStore *listenerStore
catchersStore *sync.Map
updatesTimeout time.Duration
catchTimeout time.Duration
jsonClient *JsonClient
extraGenerator ExtraGenerator
catcher chan *Response
listenerStore *listenerStore
catchersStore *sync.Map
updatesTimeout time.Duration
catchTimeout time.Duration
}
type Option func(*Client)
func WithExtraGenerator(extraGenerator ExtraGenerator) Option {
return func(client *Client) {
client.extraGenerator = extraGenerator
}
return func(client *Client) {
client.extraGenerator = extraGenerator
}
}
func WithCatchTimeout(timeout time.Duration) Option {
return func(client *Client) {
client.catchTimeout = timeout
}
return func(client *Client) {
client.catchTimeout = timeout
}
}
func WithUpdatesTimeout(timeout time.Duration) Option {
return func(client *Client) {
client.updatesTimeout = timeout
}
return func(client *Client) {
client.updatesTimeout = timeout
}
}
func NewClient(authorizationStateHandler AuthorizationStateHandler, options ...Option) (*Client, error) {
catchersListener := make(chan *Response, 1000)
catchersListener := make(chan *Response, 1000)
client := &Client{
jsonClient: NewJsonClient(),
catcher: catchersListener,
listenerStore: newListenerStore(),
catchersStore: &sync.Map{},
}
client := &Client{
jsonClient: NewJsonClient(),
catcher: catchersListener,
listenerStore: newListenerStore(),
catchersStore: &sync.Map{},
}
for _, option := range options {
option(client)
}
for _, option := range options {
option(client)
}
if client.extraGenerator == nil {
client.extraGenerator = UuidV4Generator()
}
if client.extraGenerator == nil {
client.extraGenerator = UuidV4Generator()
}
if client.catchTimeout == 0 {
client.catchTimeout = 60 * time.Second
}
if client.catchTimeout == 0 {
client.catchTimeout = 60 * time.Second
}
if client.updatesTimeout == 0 {
client.updatesTimeout = 60 * time.Second
}
if client.updatesTimeout == 0 {
client.updatesTimeout = 60 * time.Second
}
go client.receive()
go client.catch(catchersListener)
go client.receive()
go client.catch(catchersListener)
err := Authorize(client, authorizationStateHandler)
if err != nil {
return nil, err
}
err := Authorize(client, authorizationStateHandler)
if err != nil {
return nil, err
}
return client, nil
return client, nil
}
func (client *Client) receive() {
for {
resp, err := client.jsonClient.Receive(client.updatesTimeout)
if err != nil {
continue
}
client.catcher <- resp
for {
resp, err := client.jsonClient.Receive(client.updatesTimeout)
if err != nil {
continue
}
client.catcher <- resp
typ, err := UnmarshalType(resp.Data)
if err != nil {
continue
}
typ, err := UnmarshalType(resp.Data)
if err != nil {
continue
}
needGc := false
for _, listener := range client.listenerStore.Listeners() {
if listener.IsActive() {
listener.Updates <- typ
} else {
needGc = true
}
}
if needGc {
client.listenerStore.gc()
}
}
needGc := false
for _, listener := range client.listenerStore.Listeners() {
if listener.IsActive() {
listener.Updates <- typ
} else {
needGc = true
}
}
if needGc {
client.listenerStore.gc()
}
}
}
func (client *Client) catch(updates chan *Response) {
for update := range updates {
if update.Extra != "" {
value, ok := client.catchersStore.Load(update.Extra)
if ok {
value.(chan *Response) <- update
}
}
}
for update := range updates {
if update.Extra != "" {
value, ok := client.catchersStore.Load(update.Extra)
if ok {
value.(chan *Response) <- update
}
}
}
}
func (client *Client) Send(req Request) (*Response, error) {
req.Extra = client.extraGenerator()
req.Extra = client.extraGenerator()
catcher := make(chan *Response, 1)
catcher := make(chan *Response, 1)
client.catchersStore.Store(req.Extra, catcher)
client.catchersStore.Store(req.Extra, catcher)
defer func() {
close(catcher)
client.catchersStore.Delete(req.Extra)
}()
defer func() {
close(catcher)
client.catchersStore.Delete(req.Extra)
}()
client.jsonClient.Send(req)
client.jsonClient.Send(req)
select {
case response := <-catcher:
return response, nil
select {
case response := <-catcher:
return response, nil
case <-time.After(client.catchTimeout):
return nil, errors.New("response catching timeout")
}
case <-time.After(client.catchTimeout):
return nil, errors.New("response catching timeout")
}
}
func (client *Client) GetListener() *Listener {
listener := &Listener{
isActive: true,
Updates: make(chan Type, 1000),
}
client.listenerStore.Add(listener)
listener := &Listener{
isActive: true,
Updates: make(chan Type, 1000),
}
client.listenerStore.Add(listener)
return listener
return listener
}

View file

@ -1,20 +1,20 @@
package client
import (
"fmt"
"math/rand"
"fmt"
"math/rand"
)
type ExtraGenerator func() string
func UuidV4Generator() ExtraGenerator {
return func() string {
var uuid [16]byte
rand.Read(uuid[:])
return func() string {
var uuid [16]byte
rand.Read(uuid[:])
uuid[6] = (uuid[6] & 0x0f) | 0x40
uuid[8] = (uuid[8] & 0x3f) | 0x80
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:])
}
return fmt.Sprintf("%08x-%04x-%04x-%04x-%012x", uuid[:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:])
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,66 +1,66 @@
package client
import (
"sync"
"sync"
)
func newListenerStore() *listenerStore {
return &listenerStore{
listeners: []*Listener{},
}
return &listenerStore{
listeners: []*Listener{},
}
}
type listenerStore struct {
sync.Mutex
listeners []*Listener
sync.Mutex
listeners []*Listener
}
func (store *listenerStore) Add(listener *Listener) {
store.Lock()
defer store.Unlock()
store.Lock()
defer store.Unlock()
store.listeners = append(store.listeners, listener)
store.listeners = append(store.listeners, listener)
}
func (store *listenerStore) Listeners() []*Listener {
store.Lock()
defer store.Unlock()
store.Lock()
defer store.Unlock()
return store.listeners
return store.listeners
}
func (store *listenerStore) gc() {
store.Lock()
defer store.Unlock()
store.Lock()
defer store.Unlock()
oldListeners := store.listeners
oldListeners := store.listeners
store.listeners = []*Listener{}
store.listeners = []*Listener{}
for _, listener := range oldListeners {
if listener.IsActive() {
store.listeners = append(store.listeners, listener)
}
}
for _, listener := range oldListeners {
if listener.IsActive() {
store.listeners = append(store.listeners, listener)
}
}
}
type Listener struct {
mu sync.Mutex
isActive bool
Updates chan Type
mu sync.Mutex
isActive bool
Updates chan Type
}
func (listener *Listener) Close() {
listener.mu.Lock()
defer listener.mu.Unlock()
listener.mu.Lock()
defer listener.mu.Unlock()
listener.isActive = false
close(listener.Updates)
listener.isActive = false
close(listener.Updates)
}
func (listener *Listener) IsActive() bool {
listener.mu.Lock()
defer listener.mu.Unlock()
listener.mu.Lock()
defer listener.mu.Unlock()
return listener.isActive
return listener.isActive
}

View file

@ -1,52 +1,52 @@
package puller
import (
"github.com/zelenin/go-tdlib/client"
"github.com/zelenin/go-tdlib/client"
)
func ChatHistory(tdlibClient *client.Client, chatId int64) (chan *client.Message, chan error) {
messageChan := make(chan *client.Message, 10)
errChan := make(chan error, 1)
messageChan := make(chan *client.Message, 10)
errChan := make(chan error, 1)
var fromMessageId int64 = 0
var offset int32 = 0
var limit int32 = 100
var fromMessageId int64 = 0
var offset int32 = 0
var limit int32 = 100
go chatHistory(tdlibClient, messageChan, errChan, chatId, fromMessageId, offset, limit, false)
go chatHistory(tdlibClient, messageChan, errChan, chatId, fromMessageId, offset, limit, false)
return messageChan, errChan
return messageChan, errChan
}
func chatHistory(tdlibClient *client.Client, messageChan chan *client.Message, errChan chan error, chatId int64, fromMessageId int64, offset int32, limit int32, onlyLocal bool) {
defer func() {
close(messageChan)
close(errChan)
}()
defer func() {
close(messageChan)
close(errChan)
}()
for {
messages, err := tdlibClient.GetChatHistory(&client.GetChatHistoryRequest{
ChatId: chatId,
FromMessageId: fromMessageId,
Offset: offset,
Limit: limit,
OnlyLocal: onlyLocal,
})
if err != nil {
errChan <- err
for {
messages, err := tdlibClient.GetChatHistory(&client.GetChatHistoryRequest{
ChatId: chatId,
FromMessageId: fromMessageId,
Offset: offset,
Limit: limit,
OnlyLocal: onlyLocal,
})
if err != nil {
errChan <- err
return
}
return
}
if len(messages.Messages) == 0 {
errChan <- EOP
if len(messages.Messages) == 0 {
errChan <- EOP
break
}
break
}
for _, message := range messages.Messages {
fromMessageId = message.Id
for _, message := range messages.Messages {
fromMessageId = message.Id
messageChan <- message
}
}
messageChan <- message
}
}
}

View file

@ -1,62 +1,62 @@
package puller
import (
"math"
"math"
"github.com/zelenin/go-tdlib/client"
"github.com/zelenin/go-tdlib/client"
)
func Chats(tdlibClient *client.Client) (chan *client.Chat, chan error) {
chatChan := make(chan *client.Chat, 10)
errChan := make(chan error, 1)
chatChan := make(chan *client.Chat, 10)
errChan := make(chan error, 1)
var offsetOrder client.JsonInt64 = math.MaxInt64
var offsetChatId int64 = 0
var limit int32 = 100
var offsetOrder client.JsonInt64 = math.MaxInt64
var offsetChatId int64 = 0
var limit int32 = 100
go chats(tdlibClient, chatChan, errChan, offsetOrder, offsetChatId, limit)
go chats(tdlibClient, chatChan, errChan, offsetOrder, offsetChatId, limit)
return chatChan, errChan
return chatChan, errChan
}
func chats(tdlibClient *client.Client, chatChan chan *client.Chat, errChan chan error, offsetOrder client.JsonInt64, offsetChatId int64, limit int32) {
defer func() {
close(chatChan)
close(errChan)
}()
defer func() {
close(chatChan)
close(errChan)
}()
for {
chats, err := tdlibClient.GetChats(&client.GetChatsRequest{
OffsetOrder: offsetOrder,
OffsetChatId: offsetChatId,
Limit: limit,
})
if err != nil {
errChan <- err
for {
chats, err := tdlibClient.GetChats(&client.GetChatsRequest{
OffsetOrder: offsetOrder,
OffsetChatId: offsetChatId,
Limit: limit,
})
if err != nil {
errChan <- err
return
}
return
}
if len(chats.ChatIds) == 0 {
errChan <- EOP
if len(chats.ChatIds) == 0 {
errChan <- EOP
break
}
break
}
for _, chatId := range chats.ChatIds {
chat, err := tdlibClient.GetChat(&client.GetChatRequest{
ChatId: chatId,
})
if err != nil {
errChan <- err
for _, chatId := range chats.ChatIds {
chat, err := tdlibClient.GetChat(&client.GetChatRequest{
ChatId: chatId,
})
if err != nil {
errChan <- err
return
}
return
}
offsetOrder = chat.Order
offsetChatId = chat.Id
offsetOrder = chat.Order
offsetChatId = chat.Id
chatChan <- chat
}
}
chatChan <- chat
}
}
}

View file

@ -1,7 +1,7 @@
package puller
import (
"errors"
"errors"
)
var EOP = errors.New("end of pull")

View file

@ -1,53 +1,53 @@
package puller
import (
"github.com/zelenin/go-tdlib/client"
"github.com/zelenin/go-tdlib/client"
)
func SupergroupMembers(tdlibClient *client.Client, supergroupId int32) (chan *client.ChatMember, chan error) {
chatMemberChan := make(chan *client.ChatMember, 10)
errChan := make(chan error, 1)
chatMemberChan := make(chan *client.ChatMember, 10)
errChan := make(chan error, 1)
var filter client.SupergroupMembersFilter = nil
var offset int32 = 0
var limit int32 = 200
var filter client.SupergroupMembersFilter = nil
var offset int32 = 0
var limit int32 = 200
go supergroupMembers(tdlibClient, chatMemberChan, errChan, supergroupId, filter, offset, limit)
go supergroupMembers(tdlibClient, chatMemberChan, errChan, supergroupId, filter, offset, limit)
return chatMemberChan, errChan
return chatMemberChan, errChan
}
func supergroupMembers(tdlibClient *client.Client, chatMemberChan chan *client.ChatMember, errChan chan error, supergroupId int32, filter client.SupergroupMembersFilter, offset int32, limit int32) {
defer func() {
close(chatMemberChan)
close(errChan)
}()
defer func() {
close(chatMemberChan)
close(errChan)
}()
var page int32 = 0
var page int32 = 0
for {
chatMembers, err := tdlibClient.GetSupergroupMembers(&client.GetSupergroupMembersRequest{
SupergroupId: supergroupId,
Filter: filter,
Offset: page*limit + offset,
Limit: limit,
})
if err != nil {
errChan <- err
for {
chatMembers, err := tdlibClient.GetSupergroupMembers(&client.GetSupergroupMembersRequest{
SupergroupId: supergroupId,
Filter: filter,
Offset: page*limit + offset,
Limit: limit,
})
if err != nil {
errChan <- err
return
}
return
}
if len(chatMembers.Members) == 0 {
errChan <- EOP
if len(chatMembers.Members) == 0 {
errChan <- EOP
break
}
break
}
for _, member := range chatMembers.Members {
chatMemberChan <- member
}
for _, member := range chatMembers.Members {
chatMemberChan <- member
}
page++
}
page++
}
}

View file

@ -8,32 +8,32 @@ package client
import "C"
import (
"encoding/json"
"errors"
"fmt"
"strconv"
"time"
"unsafe"
"encoding/json"
"errors"
"fmt"
"strconv"
"time"
"unsafe"
)
type JsonClient struct {
jsonClient unsafe.Pointer
jsonClient unsafe.Pointer
}
func NewJsonClient() *JsonClient {
return &JsonClient{
jsonClient: C.td_json_client_create(),
}
return &JsonClient{
jsonClient: C.td_json_client_create(),
}
}
// Sends request to the TDLib client. May be called from any thread.
func (jsonClient *JsonClient) Send(req Request) {
data, _ := json.Marshal(req)
data, _ := json.Marshal(req)
query := C.CString(string(data))
defer C.free(unsafe.Pointer(query))
query := C.CString(string(data))
defer C.free(unsafe.Pointer(query))
C.td_json_client_send(jsonClient.jsonClient, query)
C.td_json_client_send(jsonClient.jsonClient, query)
}
// Receives incoming updates and request responses from the TDLib client. May be called from any thread, but
@ -41,23 +41,23 @@ func (jsonClient *JsonClient) Send(req Request) {
// Returned pointer will be deallocated by TDLib during next call to td_json_client_receive or td_json_client_execute
// in the same thread, so it can't be used after that.
func (jsonClient *JsonClient) Receive(timeout time.Duration) (*Response, error) {
result := C.td_json_client_receive(jsonClient.jsonClient, C.double(float64(timeout)/float64(time.Second)))
if result == nil {
return nil, errors.New("update receiving timeout")
}
result := C.td_json_client_receive(jsonClient.jsonClient, C.double(float64(timeout)/float64(time.Second)))
if result == nil {
return nil, errors.New("update receiving timeout")
}
data := []byte(C.GoString(result))
data := []byte(C.GoString(result))
var resp Response
var resp Response
err := json.Unmarshal(data, &resp)
if err != nil {
return nil, err
}
err := json.Unmarshal(data, &resp)
if err != nil {
return nil, err
}
resp.Data = data
resp.Data = data
return &resp, nil
return &resp, nil
}
// Synchronously executes TDLib request. May be called from any thread.
@ -65,96 +65,96 @@ func (jsonClient *JsonClient) Receive(timeout time.Duration) (*Response, error)
// Returned pointer will be deallocated by TDLib during next call to td_json_client_receive or td_json_client_execute
// in the same thread, so it can't be used after that.
func (jsonClient *JsonClient) Execute(req Request) (*Response, error) {
data, _ := json.Marshal(req)
data, _ := json.Marshal(req)
query := C.CString(string(data))
defer C.free(unsafe.Pointer(query))
query := C.CString(string(data))
defer C.free(unsafe.Pointer(query))
result := C.td_json_client_execute(jsonClient.jsonClient, query)
if result == nil {
return nil, errors.New("request can't be parsed")
}
result := C.td_json_client_execute(jsonClient.jsonClient, query)
if result == nil {
return nil, errors.New("request can't be parsed")
}
data = []byte(C.GoString(result))
data = []byte(C.GoString(result))
var resp Response
var resp Response
err := json.Unmarshal(data, &resp)
if err != nil {
return nil, err
}
err := json.Unmarshal(data, &resp)
if err != nil {
return nil, err
}
resp.Data = data
resp.Data = data
return &resp, nil
return &resp, nil
}
// Destroys the TDLib client instance. After this is called the client instance shouldn't be used anymore.
func (jsonClient *JsonClient) DestroyInstance() {
C.td_json_client_destroy(jsonClient.jsonClient)
C.td_json_client_destroy(jsonClient.jsonClient)
}
// Sets the path to the file where the internal TDLib log will be written.
// By default TDLib writes logs to stderr or an OS specific log.
// Use this method to write the log to a file instead.
func SetLogFilePath(filePath string) {
query := C.CString(filePath)
defer C.free(unsafe.Pointer(query))
query := C.CString(filePath)
defer C.free(unsafe.Pointer(query))
C.td_set_log_file_path(query)
C.td_set_log_file_path(query)
}
// Sets maximum size of the file to where the internal TDLib log is written before the file will be auto-rotated.
// Unused if log is not written to a file. Defaults to 10 MB.
func SetLogMaxFileSize(maxFileSize int64) {
C.td_set_log_max_file_size(C.longlong(maxFileSize))
C.td_set_log_max_file_size(C.longlong(maxFileSize))
}
// Sets the verbosity level of the internal logging of TDLib.
// By default the TDLib uses a log verbosity level of 5
func SetLogVerbosityLevel(newVerbosityLevel int) {
C.td_set_log_verbosity_level(C.int(newVerbosityLevel))
C.td_set_log_verbosity_level(C.int(newVerbosityLevel))
}
type meta struct {
Type string `json:"@type"`
Extra string `json:"@extra"`
Type string `json:"@type"`
Extra string `json:"@extra"`
}
type Request struct {
meta
Data map[string]interface{}
meta
Data map[string]interface{}
}
func (req Request) MarshalJSON() ([]byte, error) {
req.Data["@type"] = req.Type
req.Data["@extra"] = req.Extra
req.Data["@type"] = req.Type
req.Data["@extra"] = req.Extra
return json.Marshal(req.Data)
return json.Marshal(req.Data)
}
type Response struct {
meta
Data json.RawMessage
meta
Data json.RawMessage
}
type ResponseError struct {
Err *Error
Err *Error
}
func (responseError ResponseError) Error() string {
return fmt.Sprintf("%d %s", responseError.Err.Code, responseError.Err.Message)
return fmt.Sprintf("%d %s", responseError.Err.Code, responseError.Err.Message)
}
func buildResponseError(data json.RawMessage) error {
respErr, err := UnmarshalError(data)
if err != nil {
return err
}
respErr, err := UnmarshalError(data)
if err != nil {
return err
}
return ResponseError{
Err: respErr,
}
return ResponseError{
Err: respErr,
}
}
// JsonInt64 alias for int64, in order to deal with json big number problem
@ -162,22 +162,22 @@ type JsonInt64 int64
// MarshalJSON marshals to json
func (jsonInt64 *JsonInt64) MarshalJSON() ([]byte, error) {
return []byte(strconv.FormatInt(int64(*jsonInt64), 10)), nil
return []byte(strconv.FormatInt(int64(*jsonInt64), 10)), nil
}
// UnmarshalJSON unmarshals from json
func (jsonInt64 *JsonInt64) UnmarshalJSON(data []byte) error {
jsonBigInt, err := strconv.ParseInt(string(data[1:len(data)-1]), 10, 64)
if err != nil {
return err
}
jsonBigInt, err := strconv.ParseInt(string(data[1:len(data)-1]), 10, 64)
if err != nil {
return err
}
*jsonInt64 = JsonInt64(jsonBigInt)
*jsonInt64 = JsonInt64(jsonBigInt)
return nil
return nil
}
type Type interface {
GetType() string
GetClass() string
GetType() string
GetClass() string
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,86 +1,86 @@
package main
import (
"bufio"
"flag"
"log"
"net/http"
"os"
"path/filepath"
"bufio"
"flag"
"log"
"net/http"
"os"
"path/filepath"
"github.com/zelenin/go-tdlib/tlparser"
"github.com/zelenin/go-tdlib/codegen"
"github.com/zelenin/go-tdlib/codegen"
"github.com/zelenin/go-tdlib/tlparser"
)
type config struct {
version string
outputDirPath string
packageName string
functionFileName string
typeFileName string
unmarshalerFileName string
version string
outputDirPath string
packageName string
functionFileName string
typeFileName string
unmarshalerFileName string
}
func main() {
var config config
var config config
flag.StringVar(&config.version, "version", "", "TDLib version")
flag.StringVar(&config.outputDirPath, "outputDir", "./tdlib", "output directory")
flag.StringVar(&config.packageName, "package", "tdlib", "package name")
flag.StringVar(&config.functionFileName, "functionFile", "function.go", "functions filename")
flag.StringVar(&config.typeFileName, "typeFile", "type.go", "types filename")
flag.StringVar(&config.unmarshalerFileName, "unmarshalerFile", "unmarshaler.go", "unmarshalers filename")
flag.StringVar(&config.version, "version", "", "TDLib version")
flag.StringVar(&config.outputDirPath, "outputDir", "./tdlib", "output directory")
flag.StringVar(&config.packageName, "package", "tdlib", "package name")
flag.StringVar(&config.functionFileName, "functionFile", "function.go", "functions filename")
flag.StringVar(&config.typeFileName, "typeFile", "type.go", "types filename")
flag.StringVar(&config.unmarshalerFileName, "unmarshalerFile", "unmarshaler.go", "unmarshalers filename")
flag.Parse()
flag.Parse()
resp, err := http.Get("https://raw.githubusercontent.com/tdlib/td/" + config.version + "/td/generate/scheme/td_api.tl")
if err != nil {
log.Fatalf("http.Get error: %s", err)
return
}
defer resp.Body.Close()
resp, err := http.Get("https://raw.githubusercontent.com/tdlib/td/" + config.version + "/td/generate/scheme/td_api.tl")
if err != nil {
log.Fatalf("http.Get error: %s", err)
return
}
defer resp.Body.Close()
schema, err := tlparser.Parse(resp.Body)
if err != nil {
log.Fatalf("schema parse error: %s", err)
return
}
schema, err := tlparser.Parse(resp.Body)
if err != nil {
log.Fatalf("schema parse error: %s", err)
return
}
err = os.MkdirAll(config.outputDirPath, 0755)
if err != nil {
log.Fatalf("error creating %s: %s", config.outputDirPath, err)
}
err = os.MkdirAll(config.outputDirPath, 0755)
if err != nil {
log.Fatalf("error creating %s: %s", config.outputDirPath, err)
}
functionFilePath := filepath.Join(config.outputDirPath, config.functionFileName)
functionFilePath := filepath.Join(config.outputDirPath, config.functionFileName)
os.Remove(functionFilePath)
functionFile, err := os.OpenFile(functionFilePath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.ModePerm)
if err != nil {
log.Fatalf("functionFile open error: %s", err)
}
defer functionFile.Close()
os.Remove(functionFilePath)
functionFile, err := os.OpenFile(functionFilePath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.ModePerm)
if err != nil {
log.Fatalf("functionFile open error: %s", err)
}
defer functionFile.Close()
bufio.NewWriter(functionFile).Write(codegen.GenerateFunctions(schema, config.packageName))
bufio.NewWriter(functionFile).Write(codegen.GenerateFunctions(schema, config.packageName))
typeFilePath := filepath.Join(config.outputDirPath, config.typeFileName)
typeFilePath := filepath.Join(config.outputDirPath, config.typeFileName)
os.Remove(typeFilePath)
typeFile, err := os.OpenFile(typeFilePath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.ModePerm)
if err != nil {
log.Fatalf("typeFile open error: %s", err)
}
defer typeFile.Close()
os.Remove(typeFilePath)
typeFile, err := os.OpenFile(typeFilePath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.ModePerm)
if err != nil {
log.Fatalf("typeFile open error: %s", err)
}
defer typeFile.Close()
bufio.NewWriter(typeFile).Write(codegen.GenerateTypes(schema, config.packageName))
bufio.NewWriter(typeFile).Write(codegen.GenerateTypes(schema, config.packageName))
unmarshalerFilePath := filepath.Join(config.outputDirPath, config.unmarshalerFileName)
unmarshalerFilePath := filepath.Join(config.outputDirPath, config.unmarshalerFileName)
os.Remove(unmarshalerFilePath)
unmarshalerFile, err := os.OpenFile(unmarshalerFilePath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.ModePerm)
if err != nil {
log.Fatalf("unmarshalerFile open error: %s", err)
}
defer unmarshalerFile.Close()
os.Remove(unmarshalerFilePath)
unmarshalerFile, err := os.OpenFile(unmarshalerFilePath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.ModePerm)
if err != nil {
log.Fatalf("unmarshalerFile open error: %s", err)
}
defer unmarshalerFile.Close()
bufio.NewWriter(unmarshalerFile).Write(codegen.GenerateUnmarshalers(schema, config.packageName))
bufio.NewWriter(unmarshalerFile).Write(codegen.GenerateUnmarshalers(schema, config.packageName))
}

View file

@ -1,67 +1,67 @@
package main
import (
"bufio"
"encoding/json"
"flag"
"log"
"net/http"
"os"
"path/filepath"
"strings"
"github.com/zelenin/go-tdlib/tlparser"
"bufio"
"encoding/json"
"flag"
"github.com/zelenin/go-tdlib/tlparser"
"log"
"net/http"
"os"
"path/filepath"
"strings"
)
func main() {
var version string
var outputFilePath string
var version string
var outputFilePath string
flag.StringVar(&version, "version", "", "TDLib version")
flag.StringVar(&outputFilePath, "output", "./td_api.json", "json schema file")
flag.StringVar(&version, "version", "", "TDLib version")
flag.StringVar(&outputFilePath, "output", "./td_api.json", "json schema file")
flag.Parse()
flag.Parse()
resp, err := http.Get("https://raw.githubusercontent.com/tdlib/td/" + version + "/td/generate/scheme/td_api.tl")
if err != nil {
log.Fatalf("http.Get error: %s", err)
return
}
defer resp.Body.Close()
resp, err := http.Get("https://raw.githubusercontent.com/tdlib/td/" + version + "/td/generate/scheme/td_api.tl")
if err != nil {
log.Fatalf("http.Get error: %s", err)
return
}
defer resp.Body.Close()
schema, err := tlparser.Parse(resp.Body)
if err != nil {
log.Fatalf("schema parse error: %s", err)
return
}
schema, err := tlparser.Parse(resp.Body)
if err != nil {
log.Fatalf("schema parse error: %s", err)
return
}
resp, err = http.Get("https://raw.githubusercontent.com/tdlib/td/" + version + "/td/telegram/Td.cpp")
if err != nil {
log.Fatalf("http.Get error: %s", err)
return
}
defer resp.Body.Close()
resp, err = http.Get("https://raw.githubusercontent.com/tdlib/td/" + version + "/td/telegram/Td.cpp")
if err != nil {
log.Fatalf("http.Get error: %s", err)
return
}
defer resp.Body.Close()
err = tlparser.ParseCode(resp.Body, schema)
if err != nil {
log.Fatalf("parse code error: %s", err)
return
}
err = tlparser.ParseCode(resp.Body, schema)
if err != nil {
log.Fatalf("parse code error: %s", err)
return
}
err = os.MkdirAll(filepath.Dir(outputFilePath), os.ModePerm)
if err != nil {
log.Fatalf("make dir error: %s", filepath.Dir(outputFilePath))
}
err = os.MkdirAll(filepath.Dir(outputFilePath), os.ModePerm)
if err != nil {
log.Fatalf("make dir error: %s", filepath.Dir(outputFilePath))
}
file, err := os.OpenFile(outputFilePath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.ModePerm)
if err != nil {
log.Fatalf("open file error: %s", err)
return
}
file, err := os.OpenFile(outputFilePath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.ModePerm)
if err != nil {
log.Fatalf("open file error: %s", err)
return
}
data, err := json.MarshalIndent(schema, "", strings.Repeat(" ", 4))
if err != nil {
log.Fatalf("json marshal error: %s", err)
return
}
bufio.NewWriter(file).Write(data)
data, err := json.MarshalIndent(schema, "", strings.Repeat(" ", 4))
if err != nil {
log.Fatalf("json marshal error: %s", err)
return
}
bufio.NewWriter(file).Write(data)
}

View file

@ -1,83 +1,83 @@
package codegen
import (
"bytes"
"fmt"
"bytes"
"fmt"
"github.com/zelenin/go-tdlib/tlparser"
"github.com/zelenin/go-tdlib/tlparser"
)
func GenerateFunctions(schema *tlparser.Schema, packageName string) []byte {
buf := bytes.NewBufferString("")
buf := bytes.NewBufferString("")
buf.WriteString(fmt.Sprintf("%s\n\npackage %s\n\n", header, packageName))
buf.WriteString(fmt.Sprintf("%s\n\npackage %s\n\n", header, packageName))
buf.WriteString(`import (
buf.WriteString(`import (
"errors"
)`)
buf.WriteString("\n")
buf.WriteString("\n")
for _, function := range schema.Functions {
tdlibFunction := TdlibFunction(function.Name, schema)
tdlibFunctionReturn := TdlibFunctionReturn(function.Class, schema)
for _, function := range schema.Functions {
tdlibFunction := TdlibFunction(function.Name, schema)
tdlibFunctionReturn := TdlibFunctionReturn(function.Class, schema)
if len(function.Properties) > 0 {
buf.WriteString("\n")
buf.WriteString(fmt.Sprintf("type %sRequest struct { \n", tdlibFunction.ToGoName()))
for _, property := range function.Properties {
tdlibTypeProperty := TdlibTypeProperty(property.Name, property.Type, schema)
if len(function.Properties) > 0 {
buf.WriteString("\n")
buf.WriteString(fmt.Sprintf("type %sRequest struct { \n", tdlibFunction.ToGoName()))
for _, property := range function.Properties {
tdlibTypeProperty := TdlibTypeProperty(property.Name, property.Type, schema)
buf.WriteString(fmt.Sprintf(" // %s\n", property.Description))
buf.WriteString(fmt.Sprintf(" %s %s `json:\"%s\"`\n", tdlibTypeProperty.ToGoName(), tdlibTypeProperty.ToGoType(), property.Name))
}
buf.WriteString("}\n")
}
buf.WriteString(fmt.Sprintf(" // %s\n", property.Description))
buf.WriteString(fmt.Sprintf(" %s %s `json:\"%s\"`\n", tdlibTypeProperty.ToGoName(), tdlibTypeProperty.ToGoType(), property.Name))
}
buf.WriteString("}\n")
}
buf.WriteString("\n")
buf.WriteString("// " + function.Description)
buf.WriteString("\n")
buf.WriteString("\n")
buf.WriteString("// " + function.Description)
buf.WriteString("\n")
requestArgument := ""
if len(function.Properties) > 0 {
requestArgument = fmt.Sprintf("req *%sRequest", tdlibFunction.ToGoName())
}
requestArgument := ""
if len(function.Properties) > 0 {
requestArgument = fmt.Sprintf("req *%sRequest", tdlibFunction.ToGoName())
}
buf.WriteString(fmt.Sprintf("func (client *Client) %s(%s) (%s, error) {\n", tdlibFunction.ToGoName(), requestArgument, tdlibFunctionReturn.ToGoReturn()))
buf.WriteString(fmt.Sprintf("func (client *Client) %s(%s) (%s, error) {\n", tdlibFunction.ToGoName(), requestArgument, tdlibFunctionReturn.ToGoReturn()))
sendMethod := "Send"
if function.IsSynchronous {
sendMethod = "jsonClient.Execute"
}
sendMethod := "Send"
if function.IsSynchronous {
sendMethod = "jsonClient.Execute"
}
if len(function.Properties) > 0 {
buf.WriteString(fmt.Sprintf(` result, err := client.%s(Request{
if len(function.Properties) > 0 {
buf.WriteString(fmt.Sprintf(` result, err := client.%s(Request{
meta: meta{
Type: "%s",
},
Data: map[string]interface{}{
`, sendMethod, function.Name))
for _, property := range function.Properties {
tdlibTypeProperty := TdlibTypeProperty(property.Name, property.Type, schema)
for _, property := range function.Properties {
tdlibTypeProperty := TdlibTypeProperty(property.Name, property.Type, schema)
buf.WriteString(fmt.Sprintf(" \"%s\": req.%s,\n", property.Name, tdlibTypeProperty.ToGoName()))
}
buf.WriteString(fmt.Sprintf(" \"%s\": req.%s,\n", property.Name, tdlibTypeProperty.ToGoName()))
}
buf.WriteString(` },
buf.WriteString(` },
})
`)
} else {
buf.WriteString(fmt.Sprintf(` result, err := client.%s(Request{
} else {
buf.WriteString(fmt.Sprintf(` result, err := client.%s(Request{
meta: meta{
Type: "%s",
},
Data: map[string]interface{}{},
})
`, sendMethod, function.Name))
}
}
buf.WriteString(` if err != nil {
buf.WriteString(` if err != nil {
return nil, err
}
@ -87,29 +87,29 @@ func GenerateFunctions(schema *tlparser.Schema, packageName string) []byte {
`)
if tdlibFunctionReturn.IsClass() {
buf.WriteString(" switch result.Type {\n")
if tdlibFunctionReturn.IsClass() {
buf.WriteString(" switch result.Type {\n")
for _, subType := range tdlibFunctionReturn.GetClass().GetSubTypes() {
buf.WriteString(fmt.Sprintf(` case %s:
for _, subType := range tdlibFunctionReturn.GetClass().GetSubTypes() {
buf.WriteString(fmt.Sprintf(` case %s:
return Unmarshal%s(result.Data)
`, subType.ToTypeConst(), subType.ToGoType()))
}
}
buf.WriteString(` default:
buf.WriteString(` default:
return nil, errors.New("invalid type")
`)
buf.WriteString(" }\n")
} else {
buf.WriteString(fmt.Sprintf(` return Unmarshal%s(result.Data)
buf.WriteString(" }\n")
} else {
buf.WriteString(fmt.Sprintf(` return Unmarshal%s(result.Data)
`, tdlibFunctionReturn.ToGoType()))
}
}
buf.WriteString("}\n")
}
buf.WriteString("}\n")
}
return buf.Bytes()
return buf.Bytes()
}

View file

@ -1,26 +1,26 @@
package codegen
import (
"strings"
"unicode"
"strings"
"unicode"
)
func firstUpper(str string) string {
for i, r := range str {
return string(unicode.ToUpper(r)) + str[i+1:]
}
for i, r := range str {
return string(unicode.ToUpper(r)) + str[i+1:]
}
return str
return str
}
func firstLower(str string) string {
for i, r := range str {
return string(unicode.ToLower(r)) + str[i+1:]
}
for i, r := range str {
return string(unicode.ToLower(r)) + str[i+1:]
}
return str
return str
}
func underscoreToCamelCase(s string) string {
return strings.Replace(strings.Title(strings.Replace(strings.ToLower(s), "_", " ", -1)), " ", "", -1)
return strings.Replace(strings.Title(strings.Replace(strings.ToLower(s), "_", " ", -1)), " ", "", -1)
}

View file

@ -1,487 +1,487 @@
package codegen
import (
"github.com/zelenin/go-tdlib/tlparser"
"strings"
"log"
"github.com/zelenin/go-tdlib/tlparser"
"log"
"strings"
)
type tdlibFunction struct {
name string
schema *tlparser.Schema
name string
schema *tlparser.Schema
}
func TdlibFunction(name string, schema *tlparser.Schema) *tdlibFunction {
return &tdlibFunction{
name: name,
schema: schema,
}
return &tdlibFunction{
name: name,
schema: schema,
}
}
func (entity *tdlibFunction) ToGoName() string {
return firstUpper(entity.name)
return firstUpper(entity.name)
}
type tdlibFunctionReturn struct {
name string
schema *tlparser.Schema
name string
schema *tlparser.Schema
}
func TdlibFunctionReturn(name string, schema *tlparser.Schema) *tdlibFunctionReturn {
return &tdlibFunctionReturn{
name: name,
schema: schema,
}
return &tdlibFunctionReturn{
name: name,
schema: schema,
}
}
func (entity *tdlibFunctionReturn) IsType() bool {
return isType(entity.name, func(entity *tlparser.Type) string {
return entity.Class
}, entity.schema)
return isType(entity.name, func(entity *tlparser.Type) string {
return entity.Class
}, entity.schema)
}
func (entity *tdlibFunctionReturn) GetType() *tdlibType {
return getType(entity.name, func(entity *tlparser.Type) string {
return entity.Class
}, entity.schema)
return getType(entity.name, func(entity *tlparser.Type) string {
return entity.Class
}, entity.schema)
}
func (entity *tdlibFunctionReturn) IsClass() bool {
return isClass(entity.name, func(entity *tlparser.Class) string {
return entity.Name
}, entity.schema)
return isClass(entity.name, func(entity *tlparser.Class) string {
return entity.Name
}, entity.schema)
}
func (entity *tdlibFunctionReturn) GetClass() *tdlibClass {
return getClass(entity.name, func(entity *tlparser.Class) string {
return entity.Name
}, entity.schema)
return getClass(entity.name, func(entity *tlparser.Class) string {
return entity.Name
}, entity.schema)
}
func (entity *tdlibFunctionReturn) ToGoReturn() string {
if strings.HasPrefix(entity.name, "vector<") {
log.Fatal("vectors are not supported")
}
if strings.HasPrefix(entity.name, "vector<") {
log.Fatal("vectors are not supported")
}
if entity.IsClass() {
return entity.GetClass().ToGoType()
}
if entity.IsClass() {
return entity.GetClass().ToGoType()
}
if entity.GetType().IsInternal() {
return entity.GetType().ToGoType()
}
if entity.GetType().IsInternal() {
return entity.GetType().ToGoType()
}
return "*" + entity.GetType().ToGoType()
return "*" + entity.GetType().ToGoType()
}
func (entity *tdlibFunctionReturn) ToGoType() string {
if strings.HasPrefix(entity.name, "vector<") {
log.Fatal("vectors are not supported")
}
if strings.HasPrefix(entity.name, "vector<") {
log.Fatal("vectors are not supported")
}
if entity.IsClass() {
return entity.GetClass().ToGoType()
}
if entity.IsClass() {
return entity.GetClass().ToGoType()
}
return entity.GetType().ToGoType()
return entity.GetType().ToGoType()
}
type tdlibFunctionProperty struct {
name string
propertyType string
schema *tlparser.Schema
name string
propertyType string
schema *tlparser.Schema
}
func TdlibFunctionProperty(name string, propertyType string, schema *tlparser.Schema) *tdlibFunctionProperty {
return &tdlibFunctionProperty{
name: name,
propertyType: propertyType,
schema: schema,
}
return &tdlibFunctionProperty{
name: name,
propertyType: propertyType,
schema: schema,
}
}
func (entity *tdlibFunctionProperty) GetPrimitive() string {
primitive := entity.propertyType
primitive := entity.propertyType
for strings.HasPrefix(primitive, "vector<") {
primitive = strings.TrimSuffix(strings.TrimPrefix(primitive, "vector<"), ">")
}
for strings.HasPrefix(primitive, "vector<") {
primitive = strings.TrimSuffix(strings.TrimPrefix(primitive, "vector<"), ">")
}
return primitive
return primitive
}
func (entity *tdlibFunctionProperty) IsType() bool {
primitive := entity.GetPrimitive()
return isType(primitive, func(entity *tlparser.Type) string {
return entity.Name
}, entity.schema)
primitive := entity.GetPrimitive()
return isType(primitive, func(entity *tlparser.Type) string {
return entity.Name
}, entity.schema)
}
func (entity *tdlibFunctionProperty) GetType() *tdlibType {
primitive := entity.GetPrimitive()
return getType(primitive, func(entity *tlparser.Type) string {
return entity.Name
}, entity.schema)
primitive := entity.GetPrimitive()
return getType(primitive, func(entity *tlparser.Type) string {
return entity.Name
}, entity.schema)
}
func (entity *tdlibFunctionProperty) IsClass() bool {
primitive := entity.GetPrimitive()
return isClass(primitive, func(entity *tlparser.Class) string {
return entity.Name
}, entity.schema)
primitive := entity.GetPrimitive()
return isClass(primitive, func(entity *tlparser.Class) string {
return entity.Name
}, entity.schema)
}
func (entity *tdlibFunctionProperty) GetClass() *tdlibClass {
primitive := entity.GetPrimitive()
return getClass(primitive, func(entity *tlparser.Class) string {
return entity.Name
}, entity.schema)
primitive := entity.GetPrimitive()
return getClass(primitive, func(entity *tlparser.Class) string {
return entity.Name
}, entity.schema)
}
func (entity *tdlibFunctionProperty) ToGoName() string {
name := firstLower(underscoreToCamelCase(entity.name))
if name == "type" {
name += "Param"
}
name := firstLower(underscoreToCamelCase(entity.name))
if name == "type" {
name += "Param"
}
return name
return name
}
func (entity *tdlibFunctionProperty) ToGoType() string {
tdlibType := entity.propertyType
goType := ""
tdlibType := entity.propertyType
goType := ""
for strings.HasPrefix(tdlibType, "vector<") {
goType = goType + "[]"
tdlibType = strings.TrimSuffix(strings.TrimPrefix(tdlibType, "vector<"), ">")
}
for strings.HasPrefix(tdlibType, "vector<") {
goType = goType + "[]"
tdlibType = strings.TrimSuffix(strings.TrimPrefix(tdlibType, "vector<"), ">")
}
if entity.IsClass() {
return goType + entity.GetClass().ToGoType()
}
if entity.IsClass() {
return goType + entity.GetClass().ToGoType()
}
if entity.GetType().IsInternal() {
return goType + entity.GetType().ToGoType()
}
if entity.GetType().IsInternal() {
return goType + entity.GetType().ToGoType()
}
return goType + "*" + entity.GetType().ToGoType()
return goType + "*" + entity.GetType().ToGoType()
}
type tdlibType struct {
name string
schema *tlparser.Schema
name string
schema *tlparser.Schema
}
func TdlibType(name string, schema *tlparser.Schema) *tdlibType {
return &tdlibType{
name: name,
schema: schema,
}
return &tdlibType{
name: name,
schema: schema,
}
}
func (entity *tdlibType) IsInternal() bool {
switch entity.name {
case "double":
return true
switch entity.name {
case "double":
return true
case "string":
return true
case "string":
return true
case "int32":
return true
case "int32":
return true
case "int53":
return true
case "int53":
return true
case "int64":
return true
case "int64":
return true
case "bytes":
return true
case "bytes":
return true
case "boolFalse":
return true
case "boolFalse":
return true
case "boolTrue":
return true
case "boolTrue":
return true
case "vector<t>":
return true
}
case "vector<t>":
return true
}
return false
return false
}
func (entity *tdlibType) GetType() *tlparser.Type {
name := normalizeEntityName(entity.name)
for _, typ := range entity.schema.Types {
if typ.Name == name {
return typ
}
}
return nil
name := normalizeEntityName(entity.name)
for _, typ := range entity.schema.Types {
if typ.Name == name {
return typ
}
}
return nil
}
func (entity *tdlibType) ToGoType() string {
if strings.HasPrefix(entity.name, "vector<") {
log.Fatal("vectors are not supported")
}
if strings.HasPrefix(entity.name, "vector<") {
log.Fatal("vectors are not supported")
}
switch entity.name {
case "double":
return "float64"
switch entity.name {
case "double":
return "float64"
case "string":
return "string"
case "string":
return "string"
case "int32":
return "int32"
case "int32":
return "int32"
case "int53":
return "int64"
case "int53":
return "int64"
case "int64":
return "JsonInt64"
case "int64":
return "JsonInt64"
case "bytes":
return "[]byte"
case "bytes":
return "[]byte"
case "boolFalse":
return "bool"
case "boolFalse":
return "bool"
case "boolTrue":
return "bool"
}
case "boolTrue":
return "bool"
}
return firstUpper(entity.name)
return firstUpper(entity.name)
}
func (entity *tdlibType) ToType() string {
return entity.ToGoType() + "Type"
return entity.ToGoType() + "Type"
}
func (entity *tdlibType) HasClass() bool {
className := entity.GetType().Class
for _, class := range entity.schema.Classes {
if class.Name == className {
return true
}
}
className := entity.GetType().Class
for _, class := range entity.schema.Classes {
if class.Name == className {
return true
}
}
return false
return false
}
func (entity *tdlibType) GetClass() *tlparser.Class {
className := entity.GetType().Class
for _, class := range entity.schema.Classes {
if class.Name == className {
return class
}
}
className := entity.GetType().Class
for _, class := range entity.schema.Classes {
if class.Name == className {
return class
}
}
return nil
return nil
}
func (entity *tdlibType) HasClassProperties() bool {
for _, prop := range entity.GetType().Properties {
tdlibTypeProperty := TdlibTypeProperty(prop.Name, prop.Type, entity.schema)
if tdlibTypeProperty.IsClass() && !tdlibTypeProperty.IsList() {
return true
}
for _, prop := range entity.GetType().Properties {
tdlibTypeProperty := TdlibTypeProperty(prop.Name, prop.Type, entity.schema)
if tdlibTypeProperty.IsClass() && !tdlibTypeProperty.IsList() {
return true
}
}
}
return false
return false
}
func (entity *tdlibType) IsList() bool {
return strings.HasPrefix(entity.name, "vector<")
return strings.HasPrefix(entity.name, "vector<")
}
func (entity *tdlibType) ToClassConst() string {
if entity.HasClass() {
return "Class" + TdlibClass(entity.GetType().Class, entity.schema).ToGoType()
}
return "Class" + entity.ToGoType()
if entity.HasClass() {
return "Class" + TdlibClass(entity.GetType().Class, entity.schema).ToGoType()
}
return "Class" + entity.ToGoType()
}
func (entity *tdlibType) ToTypeConst() string {
return "Type" + entity.ToGoType()
return "Type" + entity.ToGoType()
}
type tdlibClass struct {
name string
schema *tlparser.Schema
name string
schema *tlparser.Schema
}
func TdlibClass(name string, schema *tlparser.Schema) *tdlibClass {
return &tdlibClass{
name: name,
schema: schema,
}
return &tdlibClass{
name: name,
schema: schema,
}
}
func (entity *tdlibClass) ToGoType() string {
return firstUpper(entity.name)
return firstUpper(entity.name)
}
func (entity *tdlibClass) ToType() string {
return entity.ToGoType() + "Type"
return entity.ToGoType() + "Type"
}
func (entity *tdlibClass) GetSubTypes() []*tdlibType {
types := []*tdlibType{}
types := []*tdlibType{}
for _, t := range entity.schema.Types {
if t.Class == entity.name {
types = append(types, TdlibType(t.Name, entity.schema))
}
}
for _, t := range entity.schema.Types {
if t.Class == entity.name {
types = append(types, TdlibType(t.Name, entity.schema))
}
}
return types
return types
}
func (entity *tdlibClass) ToClassConst() string {
return "Class" + entity.ToGoType()
return "Class" + entity.ToGoType()
}
type tdlibTypeProperty struct {
name string
propertyType string
schema *tlparser.Schema
name string
propertyType string
schema *tlparser.Schema
}
func TdlibTypeProperty(name string, propertyType string, schema *tlparser.Schema) *tdlibTypeProperty {
return &tdlibTypeProperty{
name: name,
propertyType: propertyType,
schema: schema,
}
return &tdlibTypeProperty{
name: name,
propertyType: propertyType,
schema: schema,
}
}
func (entity *tdlibTypeProperty) IsList() bool {
return strings.HasPrefix(entity.propertyType, "vector<")
return strings.HasPrefix(entity.propertyType, "vector<")
}
func (entity *tdlibTypeProperty) GetPrimitive() string {
primitive := entity.propertyType
primitive := entity.propertyType
for strings.HasPrefix(primitive, "vector<") {
primitive = strings.TrimSuffix(strings.TrimPrefix(primitive, "vector<"), ">")
}
for strings.HasPrefix(primitive, "vector<") {
primitive = strings.TrimSuffix(strings.TrimPrefix(primitive, "vector<"), ">")
}
return primitive
return primitive
}
func (entity *tdlibTypeProperty) IsType() bool {
primitive := entity.GetPrimitive()
return isType(primitive, func(entity *tlparser.Type) string {
return entity.Name
}, entity.schema)
primitive := entity.GetPrimitive()
return isType(primitive, func(entity *tlparser.Type) string {
return entity.Name
}, entity.schema)
}
func (entity *tdlibTypeProperty) GetType() *tdlibType {
primitive := entity.GetPrimitive()
return getType(primitive, func(entity *tlparser.Type) string {
return entity.Name
}, entity.schema)
primitive := entity.GetPrimitive()
return getType(primitive, func(entity *tlparser.Type) string {
return entity.Name
}, entity.schema)
}
func (entity *tdlibTypeProperty) IsClass() bool {
primitive := entity.GetPrimitive()
return isClass(primitive, func(entity *tlparser.Class) string {
return entity.Name
}, entity.schema)
primitive := entity.GetPrimitive()
return isClass(primitive, func(entity *tlparser.Class) string {
return entity.Name
}, entity.schema)
}
func (entity *tdlibTypeProperty) GetClass() *tdlibClass {
primitive := entity.GetPrimitive()
return getClass(primitive, func(entity *tlparser.Class) string {
return entity.Name
}, entity.schema)
primitive := entity.GetPrimitive()
return getClass(primitive, func(entity *tlparser.Class) string {
return entity.Name
}, entity.schema)
}
func (entity *tdlibTypeProperty) ToGoName() string {
return firstUpper(underscoreToCamelCase(entity.name))
return firstUpper(underscoreToCamelCase(entity.name))
}
func (entity *tdlibTypeProperty) ToGoFunctionPropertyName() string {
name := firstLower(underscoreToCamelCase(entity.name))
if name == "type" {
name += "Param"
}
name := firstLower(underscoreToCamelCase(entity.name))
if name == "type" {
name += "Param"
}
return name
return name
}
func (entity *tdlibTypeProperty) ToGoType() string {
tdlibType := entity.propertyType
goType := ""
tdlibType := entity.propertyType
goType := ""
for strings.HasPrefix(tdlibType, "vector<") {
goType = goType + "[]"
tdlibType = strings.TrimSuffix(strings.TrimPrefix(tdlibType, "vector<"), ">")
}
for strings.HasPrefix(tdlibType, "vector<") {
goType = goType + "[]"
tdlibType = strings.TrimSuffix(strings.TrimPrefix(tdlibType, "vector<"), ">")
}
if entity.IsClass() {
return goType + entity.GetClass().ToGoType()
}
if entity.IsClass() {
return goType + entity.GetClass().ToGoType()
}
if entity.GetType().IsInternal() {
return goType + entity.GetType().ToGoType()
}
if entity.GetType().IsInternal() {
return goType + entity.GetType().ToGoType()
}
return goType + "*" + entity.GetType().ToGoType()
return goType + "*" + entity.GetType().ToGoType()
}
func isType(name string, field func(entity *tlparser.Type) string, schema *tlparser.Schema) bool {
name = normalizeEntityName(name)
for _, entity := range schema.Types {
if name == field(entity) {
return true
}
}
name = normalizeEntityName(name)
for _, entity := range schema.Types {
if name == field(entity) {
return true
}
}
return false
return false
}
func getType(name string, field func(entity *tlparser.Type) string, schema *tlparser.Schema) *tdlibType {
name = normalizeEntityName(name)
for _, entity := range schema.Types {
if name == field(entity) {
return TdlibType(entity.Name, schema)
}
}
name = normalizeEntityName(name)
for _, entity := range schema.Types {
if name == field(entity) {
return TdlibType(entity.Name, schema)
}
}
return nil
return nil
}
func isClass(name string, field func(entity *tlparser.Class) string, schema *tlparser.Schema) bool {
name = normalizeEntityName(name)
for _, entity := range schema.Classes {
if name == field(entity) {
return true
}
}
name = normalizeEntityName(name)
for _, entity := range schema.Classes {
if name == field(entity) {
return true
}
}
return false
return false
}
func getClass(name string, field func(entity *tlparser.Class) string, schema *tlparser.Schema) *tdlibClass {
name = normalizeEntityName(name)
for _, entity := range schema.Classes {
if name == field(entity) {
return TdlibClass(entity.Name, schema)
}
}
name = normalizeEntityName(name)
for _, entity := range schema.Classes {
if name == field(entity) {
return TdlibClass(entity.Name, schema)
}
}
return nil
return nil
}
func normalizeEntityName(name string) string {
if name == "Bool" {
name = "boolFalse"
}
if name == "Bool" {
name = "boolFalse"
}
return name
return name
}

View file

@ -1,91 +1,91 @@
package codegen
import (
"bytes"
"fmt"
"bytes"
"fmt"
"github.com/zelenin/go-tdlib/tlparser"
"github.com/zelenin/go-tdlib/tlparser"
)
func GenerateTypes(schema *tlparser.Schema, packageName string) []byte {
buf := bytes.NewBufferString("")
buf := bytes.NewBufferString("")
buf.WriteString(fmt.Sprintf("%s\n\npackage %s\n\n", header, packageName))
buf.WriteString(fmt.Sprintf("%s\n\npackage %s\n\n", header, packageName))
buf.WriteString(`import (
buf.WriteString(`import (
"encoding/json"
)
`)
buf.WriteString("const (\n")
for _, entity := range schema.Classes {
tdlibClass := TdlibClass(entity.Name, schema)
buf.WriteString(fmt.Sprintf(" %s = %q\n", tdlibClass.ToClassConst(), entity.Name))
}
for _, entity := range schema.Types {
tdlibType := TdlibType(entity.Name, schema)
if tdlibType.IsInternal() || tdlibType.HasClass() {
continue
}
buf.WriteString(fmt.Sprintf(" %s = %q\n", tdlibType.ToClassConst(), entity.Class))
}
buf.WriteString(")")
buf.WriteString("const (\n")
for _, entity := range schema.Classes {
tdlibClass := TdlibClass(entity.Name, schema)
buf.WriteString(fmt.Sprintf(" %s = %q\n", tdlibClass.ToClassConst(), entity.Name))
}
for _, entity := range schema.Types {
tdlibType := TdlibType(entity.Name, schema)
if tdlibType.IsInternal() || tdlibType.HasClass() {
continue
}
buf.WriteString(fmt.Sprintf(" %s = %q\n", tdlibType.ToClassConst(), entity.Class))
}
buf.WriteString(")")
buf.WriteString("\n\n")
buf.WriteString("\n\n")
buf.WriteString("const (\n")
for _, entity := range schema.Types {
tdlibType := TdlibType(entity.Name, schema)
if tdlibType.IsInternal() {
continue
}
buf.WriteString(fmt.Sprintf(" %s = %q\n", tdlibType.ToTypeConst(), entity.Name))
}
buf.WriteString(")")
buf.WriteString("const (\n")
for _, entity := range schema.Types {
tdlibType := TdlibType(entity.Name, schema)
if tdlibType.IsInternal() {
continue
}
buf.WriteString(fmt.Sprintf(" %s = %q\n", tdlibType.ToTypeConst(), entity.Name))
}
buf.WriteString(")")
buf.WriteString("\n\n")
buf.WriteString("\n\n")
for _, class := range schema.Classes {
tdlibClass := TdlibClass(class.Name, schema)
for _, class := range schema.Classes {
tdlibClass := TdlibClass(class.Name, schema)
buf.WriteString(fmt.Sprintf(`// %s
buf.WriteString(fmt.Sprintf(`// %s
type %s interface {
%sType() string
}
`, class.Description, tdlibClass.ToGoType(), tdlibClass.ToGoType()))
}
}
for _, typ := range schema.Types {
tdlibType := TdlibType(typ.Name, schema)
if tdlibType.IsInternal() {
continue
}
for _, typ := range schema.Types {
tdlibType := TdlibType(typ.Name, schema)
if tdlibType.IsInternal() {
continue
}
buf.WriteString("// " + typ.Description + "\n")
buf.WriteString("// " + typ.Description + "\n")
if len(typ.Properties) > 0 {
buf.WriteString(`type ` + tdlibType.ToGoType() + ` struct {
if len(typ.Properties) > 0 {
buf.WriteString(`type ` + tdlibType.ToGoType() + ` struct {
meta
`)
for _, property := range typ.Properties {
tdlibTypeProperty := TdlibTypeProperty(property.Name, property.Type, schema)
for _, property := range typ.Properties {
tdlibTypeProperty := TdlibTypeProperty(property.Name, property.Type, schema)
buf.WriteString(fmt.Sprintf(" // %s\n", property.Description))
buf.WriteString(fmt.Sprintf(" %s %s `json:\"%s\"`\n", tdlibTypeProperty.ToGoName(), tdlibTypeProperty.ToGoType(), property.Name))
}
buf.WriteString(fmt.Sprintf(" // %s\n", property.Description))
buf.WriteString(fmt.Sprintf(" %s %s `json:\"%s\"`\n", tdlibTypeProperty.ToGoName(), tdlibTypeProperty.ToGoType(), property.Name))
}
buf.WriteString("}\n\n")
} else {
buf.WriteString(`type ` + tdlibType.ToGoType() + ` struct{
buf.WriteString("}\n\n")
} else {
buf.WriteString(`type ` + tdlibType.ToGoType() + ` struct{
meta
}
`)
}
}
buf.WriteString(fmt.Sprintf(`func (entity *%s) MarshalJSON() ([]byte, error) {
buf.WriteString(fmt.Sprintf(`func (entity *%s) MarshalJSON() ([]byte, error) {
entity.meta.Type = entity.GetType()
type stub %s
@ -95,7 +95,7 @@ type %s interface {
`, tdlibType.ToGoType(), tdlibType.ToGoType()))
buf.WriteString(fmt.Sprintf(`func (*%s) GetClass() string {
buf.WriteString(fmt.Sprintf(`func (*%s) GetClass() string {
return %s
}
@ -105,35 +105,35 @@ func (*%s) GetType() string {
`, tdlibType.ToGoType(), tdlibType.ToClassConst(), tdlibType.ToGoType(), tdlibType.ToTypeConst()))
if tdlibType.HasClass() {
tdlibClass := TdlibClass(tdlibType.GetClass().Name, schema)
if tdlibType.HasClass() {
tdlibClass := TdlibClass(tdlibType.GetClass().Name, schema)
buf.WriteString(fmt.Sprintf(`func (*%s) %sType() string {
buf.WriteString(fmt.Sprintf(`func (*%s) %sType() string {
return %s
}
`, tdlibType.ToGoType(), tdlibClass.ToGoType(), tdlibType.ToTypeConst()))
}
}
if tdlibType.HasClassProperties() {
buf.WriteString(fmt.Sprintf(`func (%s *%s) UnmarshalJSON(data []byte) error {
if tdlibType.HasClassProperties() {
buf.WriteString(fmt.Sprintf(`func (%s *%s) UnmarshalJSON(data []byte) error {
var tmp struct {
`, typ.Name, tdlibType.ToGoType()))
var countSimpleProperties int
var countSimpleProperties int
for _, property := range typ.Properties {
tdlibTypeProperty := TdlibTypeProperty(property.Name, property.Type, schema)
for _, property := range typ.Properties {
tdlibTypeProperty := TdlibTypeProperty(property.Name, property.Type, schema)
if !tdlibTypeProperty.IsClass() || tdlibTypeProperty.IsList() {
buf.WriteString(fmt.Sprintf(" %s %s `json:\"%s\"`\n", tdlibTypeProperty.ToGoName(), tdlibTypeProperty.ToGoType(), property.Name))
countSimpleProperties++
} else {
buf.WriteString(fmt.Sprintf(" %s %s `json:\"%s\"`\n", tdlibTypeProperty.ToGoName(), "json.RawMessage", property.Name))
}
}
if !tdlibTypeProperty.IsClass() || tdlibTypeProperty.IsList() {
buf.WriteString(fmt.Sprintf(" %s %s `json:\"%s\"`\n", tdlibTypeProperty.ToGoName(), tdlibTypeProperty.ToGoType(), property.Name))
countSimpleProperties++
} else {
buf.WriteString(fmt.Sprintf(" %s %s `json:\"%s\"`\n", tdlibTypeProperty.ToGoName(), "json.RawMessage", property.Name))
}
}
buf.WriteString(` }
buf.WriteString(` }
err := json.Unmarshal(data, &tmp)
if err != nil {
@ -142,35 +142,35 @@ func (*%s) GetType() string {
`)
for _, property := range typ.Properties {
tdlibTypeProperty := TdlibTypeProperty(property.Name, property.Type, schema)
for _, property := range typ.Properties {
tdlibTypeProperty := TdlibTypeProperty(property.Name, property.Type, schema)
if !tdlibTypeProperty.IsClass() || tdlibTypeProperty.IsList() {
buf.WriteString(fmt.Sprintf(" %s.%s = tmp.%s\n", typ.Name, tdlibTypeProperty.ToGoName(), tdlibTypeProperty.ToGoName()))
}
}
if !tdlibTypeProperty.IsClass() || tdlibTypeProperty.IsList() {
buf.WriteString(fmt.Sprintf(" %s.%s = tmp.%s\n", typ.Name, tdlibTypeProperty.ToGoName(), tdlibTypeProperty.ToGoName()))
}
}
if countSimpleProperties > 0 {
buf.WriteString("\n")
}
if countSimpleProperties > 0 {
buf.WriteString("\n")
}
for _, property := range typ.Properties {
tdlibTypeProperty := TdlibTypeProperty(property.Name, property.Type, schema)
for _, property := range typ.Properties {
tdlibTypeProperty := TdlibTypeProperty(property.Name, property.Type, schema)
if tdlibTypeProperty.IsClass() && !tdlibTypeProperty.IsList() {
buf.WriteString(fmt.Sprintf(` field%s, _ := Unmarshal%s(tmp.%s)
if tdlibTypeProperty.IsClass() && !tdlibTypeProperty.IsList() {
buf.WriteString(fmt.Sprintf(` field%s, _ := Unmarshal%s(tmp.%s)
%s.%s = field%s
`, tdlibTypeProperty.ToGoName(), tdlibTypeProperty.ToGoType(), tdlibTypeProperty.ToGoName(), typ.Name, tdlibTypeProperty.ToGoName(), tdlibTypeProperty.ToGoName()))
}
}
}
}
buf.WriteString(` return nil
buf.WriteString(` return nil
}
`)
}
}
}
}
return buf.Bytes()
return buf.Bytes()
}

View file

@ -1,27 +1,27 @@
package codegen
import (
"github.com/zelenin/go-tdlib/tlparser"
"fmt"
"bytes"
"bytes"
"fmt"
"github.com/zelenin/go-tdlib/tlparser"
)
func GenerateUnmarshalers(schema *tlparser.Schema, packageName string) []byte {
buf := bytes.NewBufferString("")
buf := bytes.NewBufferString("")
buf.WriteString(fmt.Sprintf("%s\n\npackage %s\n\n", header, packageName))
buf.WriteString(fmt.Sprintf("%s\n\npackage %s\n\n", header, packageName))
buf.WriteString(`import (
buf.WriteString(`import (
"encoding/json"
"fmt"
)
`)
for _, class := range schema.Classes {
tdlibClass := TdlibClass(class.Name, schema)
for _, class := range schema.Classes {
tdlibClass := TdlibClass(class.Name, schema)
buf.WriteString(fmt.Sprintf(`func Unmarshal%s(data json.RawMessage) (%s, error) {
buf.WriteString(fmt.Sprintf(`func Unmarshal%s(data json.RawMessage) (%s, error) {
var meta meta
err := json.Unmarshal(data, &meta)
@ -32,30 +32,30 @@ func GenerateUnmarshalers(schema *tlparser.Schema, packageName string) []byte {
switch meta.Type {
`, tdlibClass.ToGoType(), tdlibClass.ToGoType()))
for _, subType := range tdlibClass.GetSubTypes() {
buf.WriteString(fmt.Sprintf(` case %s:
for _, subType := range tdlibClass.GetSubTypes() {
buf.WriteString(fmt.Sprintf(` case %s:
return Unmarshal%s(data)
`, subType.ToTypeConst(), subType.ToGoType()))
}
}
buf.WriteString(` default:
buf.WriteString(` default:
return nil, fmt.Errorf("Error unmarshaling. Unknown type: " + meta.Type)
}
}
`)
}
}
for _, typ := range schema.Types {
tdlibType := TdlibType(typ.Name, schema)
for _, typ := range schema.Types {
tdlibType := TdlibType(typ.Name, schema)
if tdlibType.IsList() || tdlibType.IsInternal() {
continue
}
if tdlibType.IsList() || tdlibType.IsInternal() {
continue
}
buf.WriteString(fmt.Sprintf(`func Unmarshal%s(data json.RawMessage) (*%s, error) {
buf.WriteString(fmt.Sprintf(`func Unmarshal%s(data json.RawMessage) (*%s, error) {
var resp %s
err := json.Unmarshal(data, &resp)
@ -65,9 +65,9 @@ func GenerateUnmarshalers(schema *tlparser.Schema, packageName string) []byte {
`, tdlibType.ToGoType(), tdlibType.ToGoType(), tdlibType.ToGoType()))
}
}
buf.WriteString(`func UnmarshalType(data json.RawMessage) (Type, error) {
buf.WriteString(`func UnmarshalType(data json.RawMessage) (Type, error) {
var meta meta
err := json.Unmarshal(data, &meta)
@ -78,25 +78,25 @@ func GenerateUnmarshalers(schema *tlparser.Schema, packageName string) []byte {
switch meta.Type {
`)
for _, typ := range schema.Types {
tdlibType := TdlibType(typ.Name, schema)
for _, typ := range schema.Types {
tdlibType := TdlibType(typ.Name, schema)
if tdlibType.IsList() || tdlibType.IsInternal() {
continue
}
if tdlibType.IsList() || tdlibType.IsInternal() {
continue
}
buf.WriteString(fmt.Sprintf(` case %s:
buf.WriteString(fmt.Sprintf(` case %s:
return Unmarshal%s(data)
`, tdlibType.ToTypeConst(), tdlibType.ToGoType()))
}
}
buf.WriteString(` default:
buf.WriteString(` default:
return nil, fmt.Errorf("Error unmarshaling. Unknown type: " + meta.Type)
}
}
`)
return buf.Bytes()
return buf.Bytes()
}

View file

@ -1,74 +1,74 @@
package tlparser
import (
"bufio"
"fmt"
"io"
"strings"
"bufio"
"fmt"
"io"
"strings"
)
func ParseCode(reader io.Reader, schema *Schema) error {
var prevLine string
var curLine string
var prevLine string
var curLine string
userMethods := map[string]bool{}
botMethods := map[string]bool{}
userMethods := map[string]bool{}
botMethods := map[string]bool{}
scanner := bufio.NewScanner(reader)
for scanner.Scan() {
prevLine = curLine
curLine = scanner.Text()
scanner := bufio.NewScanner(reader)
for scanner.Scan() {
prevLine = curLine
curLine = scanner.Text()
if strings.Contains(curLine, "CHECK_IS_USER();") {
fields := strings.Fields(prevLine)
for _, field := range fields {
var methodName string
n, err := fmt.Sscanf(field, "td_api::%s", &methodName)
if err == nil && n > 0 {
userMethods[methodName] = true
}
}
}
if strings.Contains(curLine, "CHECK_IS_USER();") {
fields := strings.Fields(prevLine)
for _, field := range fields {
var methodName string
n, err := fmt.Sscanf(field, "td_api::%s", &methodName)
if err == nil && n > 0 {
userMethods[methodName] = true
}
}
}
if strings.Contains(curLine, "CHECK_IS_BOT();") {
fields := strings.Fields(prevLine)
for _, field := range fields {
var methodName string
n, err := fmt.Sscanf(field, "td_api::%s", &methodName)
if err == nil && n > 0 {
botMethods[methodName] = true
}
}
}
}
if strings.Contains(curLine, "CHECK_IS_BOT();") {
fields := strings.Fields(prevLine)
for _, field := range fields {
var methodName string
n, err := fmt.Sscanf(field, "td_api::%s", &methodName)
if err == nil && n > 0 {
botMethods[methodName] = true
}
}
}
}
err := scanner.Err()
if err != nil {
return err
}
err := scanner.Err()
if err != nil {
return err
}
var ok bool
var ok bool
for index, _ := range schema.Functions {
hasType := false
_, ok = userMethods[schema.Functions[index].Name]
if ok {
schema.Functions[index].Type = FUNCTION_TYPE_USER
hasType = true
}
for index, _ := range schema.Functions {
hasType := false
_, ok = userMethods[schema.Functions[index].Name]
if ok {
schema.Functions[index].Type = FUNCTION_TYPE_USER
hasType = true
}
_, ok = botMethods[schema.Functions[index].Name]
if ok {
schema.Functions[index].Type = FUNCTION_TYPE_BOT
hasType = true
}
_, ok = botMethods[schema.Functions[index].Name]
if ok {
schema.Functions[index].Type = FUNCTION_TYPE_BOT
hasType = true
}
if !hasType {
schema.Functions[index].Type = FUNCTION_TYPE_COMMON
}
if !hasType {
schema.Functions[index].Type = FUNCTION_TYPE_COMMON
}
ok = false
}
ok = false
}
return nil
return nil
}

View file

@ -1,174 +1,174 @@
package tlparser
import (
"io"
"strings"
"bufio"
"bufio"
"io"
"strings"
)
func Parse(reader io.Reader) (*Schema, error) {
schema := &Schema{
Types: []*Type{},
Classes: []*Class{},
Functions: []*Function{},
}
schema := &Schema{
Types: []*Type{},
Classes: []*Class{},
Functions: []*Function{},
}
scanner := bufio.NewScanner(reader)
scanner := bufio.NewScanner(reader)
hitFunctions := false
hitFunctions := false
for scanner.Scan() {
line := scanner.Text()
for scanner.Scan() {
line := scanner.Text()
switch {
case strings.HasPrefix(line, "//@description"):
if hitFunctions {
schema.Functions = append(schema.Functions, parseFunction(line, scanner))
} else {
schema.Types = append(schema.Types, parseType(line, scanner))
}
switch {
case strings.HasPrefix(line, "//@description"):
if hitFunctions {
schema.Functions = append(schema.Functions, parseFunction(line, scanner))
} else {
schema.Types = append(schema.Types, parseType(line, scanner))
}
case strings.HasPrefix(line, "//@class"):
schema.Classes = append(schema.Classes, parseClass(line, scanner))
case strings.HasPrefix(line, "//@class"):
schema.Classes = append(schema.Classes, parseClass(line, scanner))
case strings.Contains(line, "---functions---"):
hitFunctions = true
case strings.Contains(line, "---functions---"):
hitFunctions = true
case line == "":
case line == "":
default:
bodyFields := strings.Fields(line)
name := bodyFields[0]
class := strings.TrimRight(bodyFields[len(bodyFields)-1], ";")
if hitFunctions {
schema.Functions = append(schema.Functions, &Function{
Name: name,
Description: "",
Class: class,
Properties: []*Property{},
IsSynchronous: false,
Type: FUNCTION_TYPE_UNKNOWN,
})
} else {
if name == "vector" {
name = "vector<t>"
class = "Vector<T>"
}
default:
bodyFields := strings.Fields(line)
name := bodyFields[0]
class := strings.TrimRight(bodyFields[len(bodyFields)-1], ";")
if hitFunctions {
schema.Functions = append(schema.Functions, &Function{
Name: name,
Description: "",
Class: class,
Properties: []*Property{},
IsSynchronous: false,
Type: FUNCTION_TYPE_UNKNOWN,
})
} else {
if name == "vector" {
name = "vector<t>"
class = "Vector<T>"
}
schema.Types = append(schema.Types, &Type{
Name: name,
Description: "",
Class: class,
Properties: []*Property{},
})
}
}
}
schema.Types = append(schema.Types, &Type{
Name: name,
Description: "",
Class: class,
Properties: []*Property{},
})
}
}
}
return schema, nil
return schema, nil
}
func parseType(firstLine string, scanner *bufio.Scanner) *Type {
name, description, class, properties, _ := parseEntity(firstLine, scanner)
return &Type{
Name: name,
Description: description,
Class: class,
Properties: properties,
}
name, description, class, properties, _ := parseEntity(firstLine, scanner)
return &Type{
Name: name,
Description: description,
Class: class,
Properties: properties,
}
}
func parseFunction(firstLine string, scanner *bufio.Scanner) *Function {
name, description, class, properties, isSynchronous := parseEntity(firstLine, scanner)
return &Function{
Name: name,
Description: description,
Class: class,
Properties: properties,
IsSynchronous: isSynchronous,
Type: FUNCTION_TYPE_UNKNOWN,
}
name, description, class, properties, isSynchronous := parseEntity(firstLine, scanner)
return &Function{
Name: name,
Description: description,
Class: class,
Properties: properties,
IsSynchronous: isSynchronous,
Type: FUNCTION_TYPE_UNKNOWN,
}
}
func parseClass(firstLine string, scanner *bufio.Scanner) *Class {
class := &Class{
Name: "",
Description: "",
}
class := &Class{
Name: "",
Description: "",
}
classLineParts := strings.Split(firstLine, "@")
classLineParts := strings.Split(firstLine, "@")
_, class.Name = parseProperty(classLineParts[1])
_, class.Description = parseProperty(classLineParts[2])
_, class.Name = parseProperty(classLineParts[1])
_, class.Description = parseProperty(classLineParts[2])
return class
return class
}
func parseEntity(firstLine string, scanner *bufio.Scanner) (string, string, string, []*Property, bool) {
name := ""
description := ""
class := ""
properties := []*Property{}
name := ""
description := ""
class := ""
properties := []*Property{}
propertiesLine := strings.TrimLeft(firstLine, "//")
propertiesLine := strings.TrimLeft(firstLine, "//")
Loop:
for scanner.Scan() {
line := scanner.Text()
for scanner.Scan() {
line := scanner.Text()
switch {
case strings.HasPrefix(line, "//@"):
propertiesLine += " " + strings.TrimLeft(line, "//")
switch {
case strings.HasPrefix(line, "//@"):
propertiesLine += " " + strings.TrimLeft(line, "//")
case strings.HasPrefix(line, "//-"):
propertiesLine += " " + strings.TrimLeft(line, "//-")
case strings.HasPrefix(line, "//-"):
propertiesLine += " " + strings.TrimLeft(line, "//-")
default:
bodyFields := strings.Fields(line)
name = bodyFields[0]
default:
bodyFields := strings.Fields(line)
name = bodyFields[0]
for _, rawProperty := range bodyFields[1 : len(bodyFields)-2] {
propertyParts := strings.Split(rawProperty, ":")
property := &Property{
Name: propertyParts[0],
Type: propertyParts[1],
}
properties = append(properties, property)
}
class = strings.TrimRight(bodyFields[len(bodyFields)-1], ";")
break Loop
}
}
for _, rawProperty := range bodyFields[1 : len(bodyFields)-2] {
propertyParts := strings.Split(rawProperty, ":")
property := &Property{
Name: propertyParts[0],
Type: propertyParts[1],
}
properties = append(properties, property)
}
class = strings.TrimRight(bodyFields[len(bodyFields)-1], ";")
break Loop
}
}
rawProperties := strings.Split(propertiesLine, "@")
for _, rawProperty := range rawProperties[1:] {
name, value := parseProperty(rawProperty)
switch {
case name == "description":
description = value
default:
name = strings.TrimPrefix(name, "param_")
property := getProperty(properties, name)
property.Description = value
rawProperties := strings.Split(propertiesLine, "@")
for _, rawProperty := range rawProperties[1:] {
name, value := parseProperty(rawProperty)
switch {
case name == "description":
description = value
default:
name = strings.TrimPrefix(name, "param_")
property := getProperty(properties, name)
property.Description = value
}
}
}
}
return name, description, class, properties, strings.Contains(description, "Can be called synchronously")
return name, description, class, properties, strings.Contains(description, "Can be called synchronously")
}
func parseProperty(str string) (string, string) {
strParts := strings.Fields(str)
strParts := strings.Fields(str)
return strParts[0], strings.Join(strParts[1:], " ")
return strParts[0], strings.Join(strParts[1:], " ")
}
func getProperty(properties []*Property, name string) *Property {
for _, property := range properties {
if property.Name == name {
return property
}
}
for _, property := range properties {
if property.Name == name {
return property
}
}
return nil
return nil
}

View file

@ -1,43 +1,43 @@
package tlparser
type Schema struct {
Types []*Type `json:"types"`
Classes []*Class `json:"classes"`
Functions []*Function `json:"functions"`
Types []*Type `json:"types"`
Classes []*Class `json:"classes"`
Functions []*Function `json:"functions"`
}
type Type struct {
Name string `json:"name"`
Description string `json:"description"`
Class string `json:"class"`
Properties []*Property `json:"properties"`
Name string `json:"name"`
Description string `json:"description"`
Class string `json:"class"`
Properties []*Property `json:"properties"`
}
type Class struct {
Name string `json:"name"`
Description string `json:"description"`
Name string `json:"name"`
Description string `json:"description"`
}
type FunctionType int
const (
FUNCTION_TYPE_UNKNOWN FunctionType = iota
FUNCTION_TYPE_COMMON
FUNCTION_TYPE_USER
FUNCTION_TYPE_BOT
FUNCTION_TYPE_UNKNOWN FunctionType = iota
FUNCTION_TYPE_COMMON
FUNCTION_TYPE_USER
FUNCTION_TYPE_BOT
)
type Function struct {
Name string `json:"name"`
Description string `json:"description"`
Class string `json:"class"`
Properties []*Property `json:"properties"`
IsSynchronous bool `json:"is_synchronous"`
Type FunctionType `json:"type"`
Name string `json:"name"`
Description string `json:"description"`
Class string `json:"class"`
Properties []*Property `json:"properties"`
IsSynchronous bool `json:"is_synchronous"`
Type FunctionType `json:"type"`
}
type Property struct {
Name string `json:"name"`
Type string `json:"type"`
Description string `json:"description"`
Name string `json:"name"`
Type string `json:"type"`
Description string `json:"description"`
}