2018-08-30 14:55:42 +00:00
|
|
|
package client
|
|
|
|
|
2018-09-25 19:18:30 +00:00
|
|
|
/*
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <td/telegram/td_json_client.h>
|
|
|
|
*/
|
2018-08-30 14:55:42 +00:00
|
|
|
import "C"
|
|
|
|
|
|
|
|
import (
|
2018-10-23 12:38:10 +00:00
|
|
|
"encoding/json"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"strconv"
|
|
|
|
"time"
|
|
|
|
"unsafe"
|
2018-08-30 14:55:42 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type JsonClient struct {
|
2021-04-05 03:04:54 +00:00
|
|
|
id int
|
2018-08-30 14:55:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewJsonClient() *JsonClient {
|
2018-10-23 12:38:10 +00:00
|
|
|
return &JsonClient{
|
2021-04-05 03:04:54 +00:00
|
|
|
id: int(C.td_create_client_id()),
|
2018-10-23 12:38:10 +00:00
|
|
|
}
|
2018-08-30 14:55:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Sends request to the TDLib client. May be called from any thread.
|
|
|
|
func (jsonClient *JsonClient) Send(req Request) {
|
2018-10-23 12:38:10 +00:00
|
|
|
data, _ := json.Marshal(req)
|
2018-08-30 14:55:42 +00:00
|
|
|
|
2018-10-23 12:38:10 +00:00
|
|
|
query := C.CString(string(data))
|
|
|
|
defer C.free(unsafe.Pointer(query))
|
2018-08-30 14:55:42 +00:00
|
|
|
|
2021-04-05 03:04:54 +00:00
|
|
|
C.td_send(C.int(jsonClient.id), query)
|
2018-08-30 14:55:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Receives incoming updates and request responses from the TDLib client. May be called from any thread, but
|
|
|
|
// shouldn't be called simultaneously from two different threads.
|
|
|
|
// 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.
|
2018-10-09 03:08:28 +00:00
|
|
|
func (jsonClient *JsonClient) Receive(timeout time.Duration) (*Response, error) {
|
2021-04-05 03:04:54 +00:00
|
|
|
result := C.td_receive(C.double(float64(timeout) / float64(time.Second)))
|
2018-10-23 12:38:10 +00:00
|
|
|
if result == nil {
|
|
|
|
return nil, errors.New("update receiving timeout")
|
|
|
|
}
|
2018-08-30 14:55:42 +00:00
|
|
|
|
2018-10-23 12:38:10 +00:00
|
|
|
data := []byte(C.GoString(result))
|
2018-08-30 14:55:42 +00:00
|
|
|
|
2018-10-23 12:38:10 +00:00
|
|
|
var resp Response
|
2018-08-30 14:55:42 +00:00
|
|
|
|
2018-10-23 12:38:10 +00:00
|
|
|
err := json.Unmarshal(data, &resp)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2018-08-30 14:55:42 +00:00
|
|
|
|
2021-04-05 03:04:54 +00:00
|
|
|
if resp.ClientId != jsonClient.id {
|
|
|
|
return nil, errors.New("wrong @client_id")
|
|
|
|
}
|
|
|
|
|
2018-10-23 12:38:10 +00:00
|
|
|
resp.Data = data
|
2018-08-30 14:55:42 +00:00
|
|
|
|
2018-10-23 12:38:10 +00:00
|
|
|
return &resp, nil
|
2018-08-30 14:55:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Synchronously executes TDLib request. May be called from any thread.
|
|
|
|
// Only a few requests can be executed synchronously.
|
|
|
|
// 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) {
|
2018-10-23 12:38:10 +00:00
|
|
|
data, _ := json.Marshal(req)
|
2018-08-30 14:55:42 +00:00
|
|
|
|
2018-10-23 12:38:10 +00:00
|
|
|
query := C.CString(string(data))
|
|
|
|
defer C.free(unsafe.Pointer(query))
|
2021-04-05 03:04:54 +00:00
|
|
|
result := C.td_execute(query)
|
2018-10-23 12:38:10 +00:00
|
|
|
if result == nil {
|
|
|
|
return nil, errors.New("request can't be parsed")
|
|
|
|
}
|
2018-08-30 14:55:42 +00:00
|
|
|
|
2018-10-23 12:38:10 +00:00
|
|
|
data = []byte(C.GoString(result))
|
2018-08-30 14:55:42 +00:00
|
|
|
|
2018-10-23 12:38:10 +00:00
|
|
|
var resp Response
|
2018-08-30 14:55:42 +00:00
|
|
|
|
2018-10-23 12:38:10 +00:00
|
|
|
err := json.Unmarshal(data, &resp)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2018-08-30 14:55:42 +00:00
|
|
|
|
2018-10-23 12:38:10 +00:00
|
|
|
resp.Data = data
|
2018-08-30 14:55:42 +00:00
|
|
|
|
2018-10-23 12:38:10 +00:00
|
|
|
return &resp, nil
|
2018-08-30 14:55:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type meta struct {
|
2021-04-05 03:04:54 +00:00
|
|
|
Type string `json:"@type"`
|
|
|
|
Extra string `json:"@extra"`
|
|
|
|
ClientId int `json:"@client_id"`
|
2018-08-30 14:55:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type Request struct {
|
2018-10-23 12:38:10 +00:00
|
|
|
meta
|
|
|
|
Data map[string]interface{}
|
2018-08-30 14:55:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (req Request) MarshalJSON() ([]byte, error) {
|
2018-10-23 12:38:10 +00:00
|
|
|
req.Data["@type"] = req.Type
|
|
|
|
req.Data["@extra"] = req.Extra
|
2018-08-30 14:55:42 +00:00
|
|
|
|
2018-10-23 12:38:10 +00:00
|
|
|
return json.Marshal(req.Data)
|
2018-08-30 14:55:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type Response struct {
|
2018-10-23 12:38:10 +00:00
|
|
|
meta
|
|
|
|
Data json.RawMessage
|
2018-08-30 14:55:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type ResponseError struct {
|
2018-10-23 12:38:10 +00:00
|
|
|
Err *Error
|
2018-08-30 14:55:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (responseError ResponseError) Error() string {
|
2018-10-23 12:38:10 +00:00
|
|
|
return fmt.Sprintf("%d %s", responseError.Err.Code, responseError.Err.Message)
|
2018-08-30 14:55:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func buildResponseError(data json.RawMessage) error {
|
2018-10-23 12:38:10 +00:00
|
|
|
respErr, err := UnmarshalError(data)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-08-30 14:55:42 +00:00
|
|
|
|
2018-10-23 12:38:10 +00:00
|
|
|
return ResponseError{
|
|
|
|
Err: respErr,
|
|
|
|
}
|
2018-08-30 14:55:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// JsonInt64 alias for int64, in order to deal with json big number problem
|
|
|
|
type JsonInt64 int64
|
|
|
|
|
|
|
|
// MarshalJSON marshals to json
|
2019-11-05 20:11:39 +00:00
|
|
|
func (jsonInt64 JsonInt64) MarshalJSON() ([]byte, error) {
|
2019-11-06 17:23:19 +00:00
|
|
|
return []byte(`"` + strconv.FormatInt(int64(jsonInt64), 10) + `"`), nil
|
2018-08-30 14:55:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// UnmarshalJSON unmarshals from json
|
|
|
|
func (jsonInt64 *JsonInt64) UnmarshalJSON(data []byte) error {
|
2020-11-30 09:33:47 +00:00
|
|
|
if len(data) > 2 && data[0] == '"' && data[len(data)-1] == '"' {
|
|
|
|
data = data[1 : len(data)-1]
|
|
|
|
}
|
|
|
|
|
|
|
|
jsonBigInt, err := strconv.ParseInt(string(data), 10, 64)
|
2018-10-23 12:38:10 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-08-30 14:55:42 +00:00
|
|
|
|
2018-10-23 12:38:10 +00:00
|
|
|
*jsonInt64 = JsonInt64(jsonBigInt)
|
2018-08-30 14:55:42 +00:00
|
|
|
|
2018-10-23 12:38:10 +00:00
|
|
|
return nil
|
2018-08-30 14:55:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type Type interface {
|
2018-10-23 12:38:10 +00:00
|
|
|
GetType() string
|
|
|
|
GetClass() string
|
2018-08-30 14:55:42 +00:00
|
|
|
}
|