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 \ -functionFile function.go \
-typeFile type.go \ -typeFile type.go \
-unmarshalerFile unmarshaler.go -unmarshalerFile unmarshaler.go
go fmt ./...

View file

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

View file

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

View file

@ -1,20 +1,20 @@
package client package client
import ( import (
"fmt" "fmt"
"math/rand" "math/rand"
) )
type ExtraGenerator func() string type ExtraGenerator func() string
func UuidV4Generator() ExtraGenerator { func UuidV4Generator() ExtraGenerator {
return func() string { return func() string {
var uuid [16]byte var uuid [16]byte
rand.Read(uuid[:]) rand.Read(uuid[:])
uuid[6] = (uuid[6] & 0x0f) | 0x40 uuid[6] = (uuid[6] & 0x0f) | 0x40
uuid[8] = (uuid[8] & 0x3f) | 0x80 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 package client
import ( import (
"sync" "sync"
) )
func newListenerStore() *listenerStore { func newListenerStore() *listenerStore {
return &listenerStore{ return &listenerStore{
listeners: []*Listener{}, listeners: []*Listener{},
} }
} }
type listenerStore struct { type listenerStore struct {
sync.Mutex sync.Mutex
listeners []*Listener listeners []*Listener
} }
func (store *listenerStore) Add(listener *Listener) { func (store *listenerStore) Add(listener *Listener) {
store.Lock() store.Lock()
defer store.Unlock() defer store.Unlock()
store.listeners = append(store.listeners, listener) store.listeners = append(store.listeners, listener)
} }
func (store *listenerStore) Listeners() []*Listener { func (store *listenerStore) Listeners() []*Listener {
store.Lock() store.Lock()
defer store.Unlock() defer store.Unlock()
return store.listeners return store.listeners
} }
func (store *listenerStore) gc() { func (store *listenerStore) gc() {
store.Lock() store.Lock()
defer store.Unlock() defer store.Unlock()
oldListeners := store.listeners oldListeners := store.listeners
store.listeners = []*Listener{} store.listeners = []*Listener{}
for _, listener := range oldListeners { for _, listener := range oldListeners {
if listener.IsActive() { if listener.IsActive() {
store.listeners = append(store.listeners, listener) store.listeners = append(store.listeners, listener)
} }
} }
} }
type Listener struct { type Listener struct {
mu sync.Mutex mu sync.Mutex
isActive bool isActive bool
Updates chan Type Updates chan Type
} }
func (listener *Listener) Close() { func (listener *Listener) Close() {
listener.mu.Lock() listener.mu.Lock()
defer listener.mu.Unlock() defer listener.mu.Unlock()
listener.isActive = false listener.isActive = false
close(listener.Updates) close(listener.Updates)
} }
func (listener *Listener) IsActive() bool { func (listener *Listener) IsActive() bool {
listener.mu.Lock() listener.mu.Lock()
defer listener.mu.Unlock() defer listener.mu.Unlock()
return listener.isActive return listener.isActive
} }

View file

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

View file

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

View file

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

View file

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

View file

@ -8,32 +8,32 @@ package client
import "C" import "C"
import ( import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"strconv" "strconv"
"time" "time"
"unsafe" "unsafe"
) )
type JsonClient struct { type JsonClient struct {
jsonClient unsafe.Pointer jsonClient unsafe.Pointer
} }
func NewJsonClient() *JsonClient { func NewJsonClient() *JsonClient {
return &JsonClient{ return &JsonClient{
jsonClient: C.td_json_client_create(), jsonClient: C.td_json_client_create(),
} }
} }
// Sends request to the TDLib client. May be called from any thread. // Sends request to the TDLib client. May be called from any thread.
func (jsonClient *JsonClient) Send(req Request) { func (jsonClient *JsonClient) Send(req Request) {
data, _ := json.Marshal(req) data, _ := json.Marshal(req)
query := C.CString(string(data)) query := C.CString(string(data))
defer C.free(unsafe.Pointer(query)) 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 // 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 // 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. // in the same thread, so it can't be used after that.
func (jsonClient *JsonClient) Receive(timeout time.Duration) (*Response, error) { func (jsonClient *JsonClient) Receive(timeout time.Duration) (*Response, error) {
result := C.td_json_client_receive(jsonClient.jsonClient, C.double(float64(timeout)/float64(time.Second))) result := C.td_json_client_receive(jsonClient.jsonClient, C.double(float64(timeout)/float64(time.Second)))
if result == nil { if result == nil {
return nil, errors.New("update receiving timeout") 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) err := json.Unmarshal(data, &resp)
if err != nil { if err != nil {
return nil, err 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. // 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 // 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. // in the same thread, so it can't be used after that.
func (jsonClient *JsonClient) Execute(req Request) (*Response, error) { func (jsonClient *JsonClient) Execute(req Request) (*Response, error) {
data, _ := json.Marshal(req) data, _ := json.Marshal(req)
query := C.CString(string(data)) query := C.CString(string(data))
defer C.free(unsafe.Pointer(query)) defer C.free(unsafe.Pointer(query))
result := C.td_json_client_execute(jsonClient.jsonClient, query) result := C.td_json_client_execute(jsonClient.jsonClient, query)
if result == nil { if result == nil {
return nil, errors.New("request can't be parsed") 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) err := json.Unmarshal(data, &resp)
if err != nil { if err != nil {
return nil, err 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. // Destroys the TDLib client instance. After this is called the client instance shouldn't be used anymore.
func (jsonClient *JsonClient) DestroyInstance() { 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. // 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. // By default TDLib writes logs to stderr or an OS specific log.
// Use this method to write the log to a file instead. // Use this method to write the log to a file instead.
func SetLogFilePath(filePath string) { func SetLogFilePath(filePath string) {
query := C.CString(filePath) query := C.CString(filePath)
defer C.free(unsafe.Pointer(query)) 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. // 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. // Unused if log is not written to a file. Defaults to 10 MB.
func SetLogMaxFileSize(maxFileSize int64) { 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. // Sets the verbosity level of the internal logging of TDLib.
// By default the TDLib uses a log verbosity level of 5 // By default the TDLib uses a log verbosity level of 5
func SetLogVerbosityLevel(newVerbosityLevel int) { 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 meta struct {
Type string `json:"@type"` Type string `json:"@type"`
Extra string `json:"@extra"` Extra string `json:"@extra"`
} }
type Request struct { type Request struct {
meta meta
Data map[string]interface{} Data map[string]interface{}
} }
func (req Request) MarshalJSON() ([]byte, error) { func (req Request) MarshalJSON() ([]byte, error) {
req.Data["@type"] = req.Type req.Data["@type"] = req.Type
req.Data["@extra"] = req.Extra req.Data["@extra"] = req.Extra
return json.Marshal(req.Data) return json.Marshal(req.Data)
} }
type Response struct { type Response struct {
meta meta
Data json.RawMessage Data json.RawMessage
} }
type ResponseError struct { type ResponseError struct {
Err *Error Err *Error
} }
func (responseError ResponseError) Error() string { 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 { func buildResponseError(data json.RawMessage) error {
respErr, err := UnmarshalError(data) respErr, err := UnmarshalError(data)
if err != nil { if err != nil {
return err return err
} }
return ResponseError{ return ResponseError{
Err: respErr, Err: respErr,
} }
} }
// JsonInt64 alias for int64, in order to deal with json big number problem // JsonInt64 alias for int64, in order to deal with json big number problem
@ -162,22 +162,22 @@ type JsonInt64 int64
// MarshalJSON marshals to json // MarshalJSON marshals to json
func (jsonInt64 *JsonInt64) MarshalJSON() ([]byte, error) { 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 // UnmarshalJSON unmarshals from json
func (jsonInt64 *JsonInt64) UnmarshalJSON(data []byte) error { func (jsonInt64 *JsonInt64) UnmarshalJSON(data []byte) error {
jsonBigInt, err := strconv.ParseInt(string(data[1:len(data)-1]), 10, 64) jsonBigInt, err := strconv.ParseInt(string(data[1:len(data)-1]), 10, 64)
if err != nil { if err != nil {
return err return err
} }
*jsonInt64 = JsonInt64(jsonBigInt) *jsonInt64 = JsonInt64(jsonBigInt)
return nil return nil
} }
type Type interface { type Type interface {
GetType() string GetType() string
GetClass() 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 package main
import ( import (
"bufio" "bufio"
"flag" "flag"
"log" "log"
"net/http" "net/http"
"os" "os"
"path/filepath" "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 { type config struct {
version string version string
outputDirPath string outputDirPath string
packageName string packageName string
functionFileName string functionFileName string
typeFileName string typeFileName string
unmarshalerFileName string unmarshalerFileName string
} }
func main() { func main() {
var config config var config config
flag.StringVar(&config.version, "version", "", "TDLib version") flag.StringVar(&config.version, "version", "", "TDLib version")
flag.StringVar(&config.outputDirPath, "outputDir", "./tdlib", "output directory") flag.StringVar(&config.outputDirPath, "outputDir", "./tdlib", "output directory")
flag.StringVar(&config.packageName, "package", "tdlib", "package name") flag.StringVar(&config.packageName, "package", "tdlib", "package name")
flag.StringVar(&config.functionFileName, "functionFile", "function.go", "functions filename") flag.StringVar(&config.functionFileName, "functionFile", "function.go", "functions filename")
flag.StringVar(&config.typeFileName, "typeFile", "type.go", "types filename") flag.StringVar(&config.typeFileName, "typeFile", "type.go", "types filename")
flag.StringVar(&config.unmarshalerFileName, "unmarshalerFile", "unmarshaler.go", "unmarshalers 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") resp, err := http.Get("https://raw.githubusercontent.com/tdlib/td/" + config.version + "/td/generate/scheme/td_api.tl")
if err != nil { if err != nil {
log.Fatalf("http.Get error: %s", err) log.Fatalf("http.Get error: %s", err)
return return
} }
defer resp.Body.Close() defer resp.Body.Close()
schema, err := tlparser.Parse(resp.Body) schema, err := tlparser.Parse(resp.Body)
if err != nil { if err != nil {
log.Fatalf("schema parse error: %s", err) log.Fatalf("schema parse error: %s", err)
return return
} }
err = os.MkdirAll(config.outputDirPath, 0755) err = os.MkdirAll(config.outputDirPath, 0755)
if err != nil { if err != nil {
log.Fatalf("error creating %s: %s", config.outputDirPath, err) 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) os.Remove(functionFilePath)
functionFile, err := os.OpenFile(functionFilePath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.ModePerm) functionFile, err := os.OpenFile(functionFilePath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.ModePerm)
if err != nil { if err != nil {
log.Fatalf("functionFile open error: %s", err) log.Fatalf("functionFile open error: %s", err)
} }
defer functionFile.Close() 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) os.Remove(typeFilePath)
typeFile, err := os.OpenFile(typeFilePath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.ModePerm) typeFile, err := os.OpenFile(typeFilePath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.ModePerm)
if err != nil { if err != nil {
log.Fatalf("typeFile open error: %s", err) log.Fatalf("typeFile open error: %s", err)
} }
defer typeFile.Close() 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) os.Remove(unmarshalerFilePath)
unmarshalerFile, err := os.OpenFile(unmarshalerFilePath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.ModePerm) unmarshalerFile, err := os.OpenFile(unmarshalerFilePath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.ModePerm)
if err != nil { if err != nil {
log.Fatalf("unmarshalerFile open error: %s", err) log.Fatalf("unmarshalerFile open error: %s", err)
} }
defer unmarshalerFile.Close() 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 package main
import ( import (
"bufio" "bufio"
"encoding/json" "encoding/json"
"flag" "flag"
"log" "github.com/zelenin/go-tdlib/tlparser"
"net/http" "log"
"os" "net/http"
"path/filepath" "os"
"strings" "path/filepath"
"github.com/zelenin/go-tdlib/tlparser" "strings"
) )
func main() { func main() {
var version string var version string
var outputFilePath string var outputFilePath string
flag.StringVar(&version, "version", "", "TDLib version") flag.StringVar(&version, "version", "", "TDLib version")
flag.StringVar(&outputFilePath, "output", "./td_api.json", "json schema file") 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") resp, err := http.Get("https://raw.githubusercontent.com/tdlib/td/" + version + "/td/generate/scheme/td_api.tl")
if err != nil { if err != nil {
log.Fatalf("http.Get error: %s", err) log.Fatalf("http.Get error: %s", err)
return return
} }
defer resp.Body.Close() defer resp.Body.Close()
schema, err := tlparser.Parse(resp.Body) schema, err := tlparser.Parse(resp.Body)
if err != nil { if err != nil {
log.Fatalf("schema parse error: %s", err) log.Fatalf("schema parse error: %s", err)
return return
} }
resp, err = http.Get("https://raw.githubusercontent.com/tdlib/td/" + version + "/td/telegram/Td.cpp") resp, err = http.Get("https://raw.githubusercontent.com/tdlib/td/" + version + "/td/telegram/Td.cpp")
if err != nil { if err != nil {
log.Fatalf("http.Get error: %s", err) log.Fatalf("http.Get error: %s", err)
return return
} }
defer resp.Body.Close() defer resp.Body.Close()
err = tlparser.ParseCode(resp.Body, schema) err = tlparser.ParseCode(resp.Body, schema)
if err != nil { if err != nil {
log.Fatalf("parse code error: %s", err) log.Fatalf("parse code error: %s", err)
return return
} }
err = os.MkdirAll(filepath.Dir(outputFilePath), os.ModePerm) err = os.MkdirAll(filepath.Dir(outputFilePath), os.ModePerm)
if err != nil { if err != nil {
log.Fatalf("make dir error: %s", filepath.Dir(outputFilePath)) 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) file, err := os.OpenFile(outputFilePath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.ModePerm)
if err != nil { if err != nil {
log.Fatalf("open file error: %s", err) log.Fatalf("open file error: %s", err)
return return
} }
data, err := json.MarshalIndent(schema, "", strings.Repeat(" ", 4)) data, err := json.MarshalIndent(schema, "", strings.Repeat(" ", 4))
if err != nil { if err != nil {
log.Fatalf("json marshal error: %s", err) log.Fatalf("json marshal error: %s", err)
return return
} }
bufio.NewWriter(file).Write(data) bufio.NewWriter(file).Write(data)
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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