Add initial C# support

GitOrigin-RevId: c0ece19b41ca8e348285df95f9b81b188d3e5835
This commit is contained in:
Arseny Smirnov 2018-02-26 21:08:47 +03:00
parent 9310e29ff4
commit 70ad2664bd
8 changed files with 931 additions and 3 deletions

View File

@ -2,6 +2,10 @@ cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR)
project(TDLib VERSION 1.1.3 LANGUAGES CXX C)
if ("${CMAKE_SYSTEM_NAME}" STREQUAL "WindowsStore")
set(UWP 1)
endif()
option(TD_ENABLE_JNI "Use \"ON\" to enable JNI-compatible TDLib API.")
if (NOT DEFINED CMAKE_MODULE_PATH)
@ -145,6 +149,11 @@ elseif (INTEL)
endif()
if (WIN32)
if (CMAKE_CXX_FLAGS_DEBUG MATCHES "/RTC1")
string(REPLACE "/RTC1" " " CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
endif()
add_definitions(-D_SCL_SECURE_NO_WARNINGS)
add_definitions(-DNTDDI_VERSION=0x06020000 -DWINVER=0x0602 -D_WIN32_WINNT=0x0602 -DNOMINMAX -DUNICODE -D_UNICODE)
endif()
if (CYGWIN)
@ -275,6 +284,12 @@ set(TL_C_SCHEME_SOURCE
${TL_C_AUTO}
)
set_source_files_properties(${TL_WINDOWS_AUTO} PROPERTIES GENERATED TRUE)
set(TL_WINDOWS_SCHEME_SOURCE
${TL_TD_WINDOWS_AUTO}
td/tl/tl_win_object.h
)
set(TDLIB_SOURCE
td/mtproto/AuthData.cpp
td/mtproto/crypto.cpp
@ -583,6 +598,30 @@ if (TD_ENABLE_JNI AND NOT ANDROID) # jni is available by default on Android
target_link_libraries(tdclient PUBLIC ${JAVA_JVM_LIBRARY})
endif()
if (TD_ENABLE_DOTNET)
add_library(TdWindows SHARED
td/telegram/ClientWindows.cpp
td/telegram/LogWindows.cpp
${TL_WINDOWS_SCHEME_SOURCE}
)
target_link_libraries(TdWindows PRIVATE tdclient tdutils)
target_include_directories(TdWindows PUBLIC
$<BUILD_INTERFACE:${TL_TD_AUTO_INCLUDES}>
)
if (NOT CMAKE_CROSSCOMPILING)
add_dependencies(TdWindows generate_td_windows_api)
endif()
if (UWP)
set_target_properties(TdWindows PROPERTIES VS_WINRT_COMPONENT "true")
target_compile_options(TdWindows PUBLIC "/ZW")
else()
set_target_properties(TdWindows PROPERTIES COMPILE_FLAGS "/GR /clr")
target_compile_options(TdWindows PUBLIC "/EHa")
endif()
target_compile_options(TdWindows PUBLIC "/bigobj")
endif()
# tdc - TDLib interface in pure c.
add_library(tdc STATIC ${TL_C_SCHEME_SOURCE} td/telegram/td_c_client.cpp td/telegram/td_c_client.h)
target_include_directories(tdc PUBLIC

View File

@ -27,7 +27,8 @@ set(TL_TD_JSON_AUTO
PARENT_SCOPE
)
set(TL_TD_API_TLO ${CMAKE_CURRENT_SOURCE_DIR}/scheme/td_api.tlo PARENT_SCOPE)
set(TL_TD_API_TLO ${CMAKE_CURRENT_SOURCE_DIR}/scheme/td_api.tlo)
set(TL_TD_API_TLO ${TL_TD_API_TLO} PARENT_SCOPE)
set(TL_C_AUTO
${CMAKE_CURRENT_SOURCE_DIR}/auto/td/telegram/td_tdc_api.cpp
@ -36,6 +37,12 @@ set(TL_C_AUTO
PARENT_SCOPE
)
set(TL_TD_WINDOWS_AUTO
${CMAKE_CURRENT_SOURCE_DIR}/auto/td/telegram/TdWindowsApi.cpp
${CMAKE_CURRENT_SOURCE_DIR}/auto/td/telegram/TdWindowsApi.h
PARENT_SCOPE
)
set(TL_GENERATE_COMMON_SOURCE
generate_common.cpp
@ -76,6 +83,7 @@ set(TL_GENERATE_JSON_SOURCE
tl_json_converter.h
)
if (NOT CMAKE_CROSSCOMPILING)
find_program(PHP_EXECUTABLE php)
@ -89,8 +97,7 @@ if (NOT CMAKE_CROSSCOMPILING)
target_link_libraries(generate_common PRIVATE tdtl)
add_custom_target(tl_generate_common
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND ${GENERATE_COMMON_CMD}
COMMENT "Generate common tl source files"
COMMAND ${GENERATE_COMMON_CMD} COMMENT "Generate common tl source files"
DEPENDS generate_common scheme/mtproto_api.tlo scheme/telegram_api.tlo scheme/secret_api.tlo scheme/td_api.tlo
)
if (TD_ENABLE_JNI)
@ -123,4 +130,13 @@ if (NOT CMAKE_CROSSCOMPILING)
install(FILES JavadocTlDocumentationGenerator.php TlDocumentationGenerator.php DESTINATION bin/td/generate)
install(FILES scheme/td_api.tlo scheme/td_api.tl DESTINATION bin/td/generate/scheme)
endif()
add_executable(generate_td_windows_api_exe generate_td_windows_api.cpp tl_writer_win.h)
target_link_libraries(generate_td_windows_api_exe PRIVATE tdtl)
add_custom_target(generate_td_windows_api
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND generate_td_windows_api_exe ${TL_TD_API_TLO}
COMMENT "Generate tl-files"
DEPENDS generate_td_windows_api_exe ${TL_TD_API_TLO}
)
endif()

View File

@ -0,0 +1,25 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include "td/tl/tl_config.h"
#include "td/tl/tl_generate.h"
#include "tl_writer_win.h"
int main(int argc, char *argv[]) {
if (argc < 2) {
return 1;
}
td::tl::tl_config config_td = td::tl::read_tl_config_from_file(argv[1]);
td::tl::write_tl_to_file(config_td, "auto/td/telegram/TdWindowsApi.cpp",
td::tl::TlWriterWinCommon("TdApi", false, "#include \"td/telegram/TdWindowsApi.h\"\n"));
td::tl::write_tl_to_file(config_td, "auto/td/telegram/TdWindowsApi.h",
td::tl::TlWriterWinCommon("TdApi", true, "#include \"td/telegram/td_api.h\"\n"));
return 0;
}

549
td/generate/tl_writer_win.h Normal file
View File

@ -0,0 +1,549 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#pragma once
#include "td/tl/tl_writer.h"
#include <cassert>
#include <sstream>
#include <string>
#include <vector>
namespace td {
namespace tl {
class TlWriterWinCommon : public TL_writer {
public:
bool is_header_;
std::string prefix_;
TlWriterWinCommon(const std::string &name, bool is_header, const std::string &prefix = "")
: TL_writer(name), is_header_(is_header), prefix_(prefix) {
}
int get_max_arity(void) const override {
return 0;
}
bool is_built_in_simple_type(const std::string &name) const override {
return name == "Bool" || name == "Int32" || name == "Int53" || name == "Int64" || name == "Double" || name == "String" || name == "Bytes";
}
bool is_built_in_complex_type(const std::string &name) const override {
return name == "Vector";
}
bool is_type_bare(const tl_type *t) const override {
return t->simple_constructors <= 1 || (is_built_in_simple_type(t->name) && t->name != "Bool") ||
is_built_in_complex_type(t->name);
}
std::vector<std::string> get_parsers(void) const override {
return {"FromUnmanaged"};
}
int get_parser_type(const tl_combinator *t, const std::string &name) const override {
return 0;
}
Mode get_parser_mode(int type) const override {
return All; // Server;
}
std::vector<std::string> get_storers(void) const override {
return {"ToUnmanaged", "ToString"};
}
std::vector<std::string> get_additional_functions(void) const override {
return {"ToUnmanaged", "FromUnmanaged"};
}
int get_storer_type(const tl_combinator *t, const std::string &name) const override {
return name == "ToString";
}
Mode get_storer_mode(int type) const override {
return type <= 1 ? All : Server;
}
std::string gen_base_tl_class_name(void) const override {
return "BaseObject";
}
std::string gen_base_type_class_name(int arity) const override {
assert(arity == 0);
return "Object";
}
std::string gen_base_function_class_name(void) const override {
return "Function";
}
static std::string to_camelCase(const std::string &name) {
return to_cCamelCase(name, false);
}
static std::string to_CamelCase(const std::string &name) {
return to_cCamelCase(name, true);
}
static std::string to_cCamelCase(const std::string &name, bool flag) {
bool next_to_upper = flag;
std::string result;
for (int i = 0; i < (int)name.size(); i++) {
if (!is_alnum(name[i])) {
next_to_upper = true;
continue;
}
if (next_to_upper) {
result += (char)to_upper(name[i]);
next_to_upper = false;
} else {
result += name[i];
}
}
return result;
}
std::string gen_native_field_name(std::string name) const {
for (int i = 0; i < (int)name.size(); i++) {
if (!is_alnum(name[i])) {
name[i] = '_';
}
}
assert(name.size() > 0);
assert(name[name.size() - 1] != '_');
return name + "_";
}
std::string gen_native_class_name(std::string name) const {
if (name == "Object") {
assert(0);
}
if (name == "#") {
return "int32_t";
}
for (int i = 0; i < (int)name.size(); i++) {
if (!is_alnum(name[i])) {
name[i] = '_';
}
}
return name;
}
std::string gen_class_name(std::string name) const override {
if (name == "Object" || name == "#") {
assert(0);
}
return to_CamelCase(name);
}
std::string gen_field_name(std::string name) const override {
assert(name.size() > 0);
assert(is_alnum(name.back()));
return to_CamelCase(name);
}
std::string gen_type_name(const tl_tree_type *tree_type) const override {
const tl_type *t = tree_type->type;
const std::string &name = t->name;
if (name == "#") {
assert(0);
}
if (name == "Bool") {
return "bool";
}
if (name == "Int32") {
return "int32";
}
if (name == "Int53" || name == "Int64") {
return "int64";
}
if (name == "Double") {
return "float64";
}
if (name == "String") {
return "String^";
}
if (name == "Bytes") {
return "Array<byte>^";
}
if (name == "Vector") {
assert(t->arity == 1);
assert((int)tree_type->children.size() == 1);
assert(tree_type->children[0]->get_type() == NODE_TYPE_TYPE);
const tl_tree_type *child = static_cast<const tl_tree_type *>(tree_type->children[0]);
return "Array<" + gen_type_name(child) + ">^";
}
assert(!is_built_in_simple_type(name) && !is_built_in_complex_type(name));
for (int i = 0; i < (int)tree_type->children.size(); i++) {
assert(tree_type->children[i]->get_type() == NODE_TYPE_NAT_CONST);
}
return gen_main_class_name(t) + "^";
}
std::string gen_output_begin(void) const override {
return prefix_ +
"#include \"td/utils/port/CxCli.h\"\n"
"#include \"td/tl/tl_win_object.h\"\n\n"
"namespace TdWindows {\n";
}
std::string gen_output_end() const override {
return "}\n";
}
std::string gen_forward_class_declaration(const std::string &class_name, bool is_proxy) const override {
if (!is_header_) {
return "";
}
std::stringstream ss;
ss << (is_proxy ? "interface" : "ref") << " class " << class_name << ";\n";
return ss.str();
}
std::string gen_class_begin(const std::string &class_name, const std::string &base_class_name,
bool is_proxy) const override {
if (!is_header_) {
return "";
}
std::stringstream ss;
ss << "\npublic " << (is_proxy ? "interface" : "ref") << " class " << class_name << (is_proxy ? "" : " sealed")
<< (class_name == gen_base_tl_class_name() ? "" : " : " + base_class_name) << " {\n"
<< " public:\n";
return ss.str();
}
std::string gen_class_end(void) const override {
return "";
}
std::string gen_field_definition(const std::string &class_name, const std::string &type_name,
const std::string &field_name) const override {
if (!is_header_) {
return "";
}
auto fixed_field_name = field_name;
if (field_name == class_name) {
fixed_field_name += "Data";
}
if (type_name.substr(0, field_name.size()) == field_name) {
auto fixed_type_name = "::TdWindows::" + type_name;
std::stringstream ss;
ss << "private:\n";
ss << " " << fixed_type_name << " " << fixed_field_name << "Private;\n";
ss << "public:\n";
ss << " property " << fixed_type_name << " " << fixed_field_name << " {\n";
ss << " " << fixed_type_name << " get() {\n";
ss << " return " << fixed_field_name << "Private;\n";
ss << " }\n";
ss << " void set(" << fixed_type_name << " newValue) {\n";
ss << " " << fixed_field_name << "Private = newValue;\n";
ss << " }\n";
ss << " }\n";
return ss.str();
}
return " property " + type_name + " " + fixed_field_name + ";\n";
}
std::string gen_store_function_begin(const std::string &storer_name, const std::string &class_name, int arity,
std::vector<var_description> &vars, int storer_type) const override {
if (storer_type < 0) {
return "";
}
std::stringstream ss;
ss << "\n";
if (storer_type) {
ss << (is_header_ ? " virtual " : "") << "String^ " << (is_header_ ? "" : gen_class_name(class_name) + "::")
<< "ToString()" << (is_header_ ? " override;" : " {\n return ::TdWindows::ToString(this);\n}") << "\n";
} else {
ss << (is_header_ ? " virtual " : "") << "NativeObject^ "
<< (is_header_ ? "" : gen_class_name(class_name) + "::") << "ToUnmanaged()";
if (is_header_) {
ss << ";\n";
} else {
ss << "{\n return REF_NEW NativeObject(::TdWindows::ToUnmanaged(this).release());\n}\n";
}
}
return ss.str();
}
std::string gen_store_function_end(const std::vector<var_description> &vars, int storer_type) const override {
return "";
}
std::string gen_constructor_begin(int fields_num, const std::string &class_name, bool is_default) const override {
std::stringstream ss;
ss << "\n";
ss << (is_header_ ? " " : gen_class_name(class_name) + "::") << gen_class_name(class_name) << "(";
return ss.str();
}
std::string gen_constructor_parameter(int field_num, const std::string &class_name, const arg &a, bool is_default) const override {
if (is_default) {
return "";
}
std::stringstream ss;
ss << (field_num == 0 ? "" : ", ");
auto field_type = gen_field_type(a);
if (field_type.substr(0, 5) == "Array") {
ss << "CXCONST ";
} else if (field_type.substr(0, 6) != "String" && to_upper(field_type[0]) == field_type[0]) {
field_type = "::TdWindows::" + field_type;
}
ss << field_type << " " << to_camelCase(a.name);
return ss.str();
}
std::string gen_constructor_field_init(int field_num, const std::string &class_name, const arg &a, bool is_default) const override {
if (is_default || is_header_) {
return "";
}
std::stringstream ss;
if (field_num == 0) {
ss << ") {\n";
}
auto field_name = gen_field_name(a.name);
if (field_name == class_name) {
field_name += "Data";
}
ss << " " << field_name << " = " << to_camelCase(a.name) << ";\n";
return ss.str();
}
std::string gen_constructor_end(const tl_combinator *t, int fields_num, bool is_default) const override {
if (is_header_) {
return ");\n";
}
std::stringstream ss;
if (fields_num == 0) {
ss << ") {\n";
}
ss << "}\n";
return ss.str();
}
std::string gen_additional_function(const std::string &function_name, const tl_combinator *t,
bool is_function) const override {
std::stringstream ss;
if (is_header_ && function_name == "ToUnmanaged") {
ss << "};\n";
}
ss << "\n";
if (function_name == "ToUnmanaged") {
gen_to_unmanaged(ss, t);
} else {
gen_from_unmanaged(ss, t);
}
return ss.str();
}
void gen_to_unmanaged(std::stringstream &ss, const tl_combinator *t) const {
auto native_class_name = gen_native_class_name(t->name);
auto class_name = gen_class_name(t->name);
ss << "td::td_api::object_ptr<td::td_api::" << native_class_name << "> ToUnmanaged(" << class_name
<< "^ from)";
if (is_header_) {
ss << ";\n";
return;
}
ss << "{\n"
<< " if (!from) {\n"
<< " return nullptr;\n"
<< " }\n"
<< " return td::td_api::make_object<td::td_api::" << native_class_name << ">(";
bool is_first = true;
for (auto &it : t->args) {
if (is_first) {
is_first = false;
} else {
ss << ", ";
}
auto field_name = gen_field_name(it.name);
if (field_name == class_name) {
field_name += "Data";
}
ss << "ToUnmanaged(from->" << field_name << ")";
}
ss << ");\n}\n";
}
void gen_from_unmanaged(std::stringstream &ss, const tl_combinator *t) const {
auto native_class_name = gen_native_class_name(t->name);
auto class_name = gen_class_name(t->name);
ss << class_name << "^ FromUnmanaged(td::td_api::" << native_class_name << "& from)";
if (is_header_) {
ss << ";\n";
return;
}
ss << "{\n"
<< " return REF_NEW " << class_name << "(";
bool is_first = true;
for (auto &it : t->args) {
if (is_first) {
is_first = false;
} else {
ss << ", ";
}
ss << (gen_field_type(it) == "Array<byte>^" ? "Bytes" : "") << "FromUnmanaged(from." << gen_native_field_name(it.name) << ")";
}
ss << ");\n}\n";
}
std::string gen_array_type_name(const tl_tree_array *arr, const std::string &field_name) const override {
assert(0);
return std::string();
}
std::string gen_var_type_name(void) const override {
assert(0);
return std::string();
}
std::string gen_int_const(const tl_tree *tree_c, const std::vector<var_description> &vars) const override {
assert(0);
return std::string();
}
std::string gen_var_name(const var_description &desc) const override {
assert(0);
return "";
}
std::string gen_parameter_name(int index) const override {
assert(0);
return "";
}
std::string gen_class_alias(const std::string &class_name, const std::string &alias_name) const override {
return "";
}
std::string gen_vars(const tl_combinator *t, const tl_tree_type *result_type,
std::vector<var_description> &vars) const override {
assert(vars.empty());
return "";
}
std::string gen_function_vars(const tl_combinator *t, std::vector<var_description> &vars) const override {
assert(vars.empty());
return "";
}
std::string gen_uni(const tl_tree_type *result_type, std::vector<var_description> &vars,
bool check_negative) const override {
assert(result_type->children.empty());
return "";
}
std::string gen_constructor_id_store(int32_t id, int storer_type) const override {
return "";
}
std::string gen_field_fetch(int field_num, const arg &a, std::vector<var_description> &vars, bool flat,
int parser_type) const override {
return "";
// std::stringstream ss;
// ss << gen_field_name(a.name) << " = from_unmanaged(from->" <<
// gen_native_field_name(a.name) << ");\n"; return ss.str();
}
std::string gen_field_store(const arg &a, std::vector<var_description> &vars, bool flat,
int storer_type) const override {
return "";
// std::stringstream ss;
// ss << "to_unmanaged(" << gen_field_name(a.name) << ")";
// return ss.str();
}
std::string gen_type_fetch(const std::string &field_name, const tl_tree_type *tree_type,
const std::vector<var_description> &vars, int parser_type) const override {
assert(vars.empty());
return "";
}
std::string gen_type_store(const std::string &field_name, const tl_tree_type *tree_type,
const std::vector<var_description> &vars, int storer_type) const override {
return "";
}
std::string gen_var_type_fetch(const arg &a) const override {
assert(0);
return "";
}
std::string gen_get_id(const std::string &class_name, int32_t id, bool is_proxy) const override {
return "";
}
std::string gen_function_result_type(const tl_tree *result) const override {
return "";
}
std::string gen_fetch_function_begin(const std::string &parser_name, const std::string &class_name, int arity,
std::vector<var_description> &vars, int parser_type) const override {
return "";
}
std::string gen_fetch_function_end(int field_num, const std::vector<var_description> &vars,
int parser_type) const override {
return "";
}
std::string gen_fetch_function_result_begin(const std::string &parser_name, const std::string &class_name,
const tl_tree *result) const override {
return "";
}
std::string gen_fetch_function_result_end(void) const override {
return "";
}
std::string gen_fetch_function_result_any_begin(const std::string &parser_name, const std::string &class_name,
bool is_proxy) const override {
return "";
}
std::string gen_fetch_function_result_any_end(bool is_proxy) const override {
return "";
}
std::string gen_fetch_switch_begin(void) const override {
return "";
}
std::string gen_fetch_switch_case(const tl_combinator *t, int arity) const override {
return "";
}
std::string gen_fetch_switch_end(void) const override {
return "";
}
std::string gen_additional_proxy_function_begin(const std::string &function_name, const tl_type *type,
const std::string &name, int arity, bool is_function) const override {
std::stringstream ss;
if (is_header_ && function_name == "ToUnmanaged") {
ss << "};\n";
}
if (type == nullptr) {
return ss.str();
}
auto native_class_name = gen_native_class_name(type->name);
auto class_name = gen_class_name(type->name);
if (function_name == "ToUnmanaged") {
ss << "td::td_api::object_ptr<td::td_api::" << native_class_name << "> ToUnmanaged(" << class_name
<< "^ from)";
if (is_header_) {
ss << ";\n";
return ss.str();
}
ss << "{\n"
<< " if (!from) {\n"
<< " return nullptr;\n"
<< " }\n"
<< " return td::td_api::move_object_as<td::td_api::" << native_class_name << ">(from->ToUnmanaged()->get_object_ptr());\n}\n";
} else {
ss << class_name << "^ FromUnmanaged(td::td_api::" << native_class_name << "& from)";
if (is_header_) {
ss << ";\n";
return ss.str();
}
ss << "{\n";
ss << " CallFromUnmanaged<" << class_name << "^> res;\n";
ss << " downcast_call(from, res);\n";
ss << " return CallFromUnmanagedRes<" << class_name << "^>::res;\n";
ss << "}\n";
}
return ss.str();
}
std::string gen_additional_proxy_function_case(const std::string &function_name, const tl_type *type,
const std::string &class_name, int arity) const override {
return "";
}
std::string gen_additional_proxy_function_case(const std::string &function_name, const tl_type *type,
const tl_combinator *t, int arity, bool is_function) const override {
return "";
}
std::string gen_additional_proxy_function_end(const std::string &function_name, const tl_type *type,
bool is_function) const override {
return "";
}
};
} // namespace tl
} // namespace td

View File

@ -0,0 +1,95 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include "td/telegram/TdWindowsApi.h"
#include "td/telegram/Client.h"
#include "td/utils/port/CxCli.h"
namespace TdWindows {
using namespace CxCli;
public interface class ClientResultHandler {
void OnResult(BaseObject^ object);
};
public ref class Client sealed {
public:
void Send(Function^ function, ClientResultHandler^ handler) {
if (function == nullptr) {
throw REF_NEW NullReferenceException("Function can't be null");
}
std::uint64_t queryId = Increment(currentId);
if (handler != nullptr) {
handlers[queryId] = handler;
}
td::Client::Request request;
request.id = queryId;
request.function = td::td_api::move_object_as<td::td_api::Function>(ToUnmanaged(function)->get_object_ptr());
client->send(std::move(request));
}
BaseObject^ Execute(Function^ function) {
if (function == nullptr) {
throw REF_NEW NullReferenceException("Function can't be null");
}
td::Client::Request request;
request.id = 0;
request.function = td::td_api::move_object_as<td::td_api::Function>(ToUnmanaged(function)->get_object_ptr());
return FromUnmanaged(*client->execute(std::move(request)).object);
}
void SetUpdatesHandler(ClientResultHandler^ handler) {
handlers[0] = handler;
}
void Run() {
while (true) {
auto response = client->receive(10.0);
if (response.object != nullptr) {
ProcessResult(response.id, FromUnmanaged(*response.object));
if (response.object->get_id() == td::td_api::updateAuthorizationState::ID &&
static_cast<td::td_api::updateAuthorizationState &>(*response.object).authorization_state_->get_id() ==
td::td_api::authorizationStateClosed::ID) {
break;
}
}
}
}
static Client^ Create(ClientResultHandler^ updatesHandler) {
return REF_NEW Client(updatesHandler);
}
private:
Client(ClientResultHandler^ updatesHandler) {
client = new td::Client();
handlers[0] = updatesHandler;
}
~Client() {
delete client;
}
std::int64_t currentId = 0;
ConcurrentDictionary<std::uint64_t, ClientResultHandler^> handlers;
td::Client *client = nullptr;
void ProcessResult(std::uint64_t id, BaseObject^ object) {
ClientResultHandler^ handler;
// update handler stays forever
if (id == 0 ? handlers.TryGetValue(id, handler) : handlers.TryRemove(id, handler)) {
// TODO try/catch
handler->OnResult(object);
}
}
};
} // namespace TdWindows

View File

@ -0,0 +1,27 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include "td/telegram/Log.h"
#include "td/utils/port/CxCli.h"
namespace TdWindows {
using namespace CxCli;
public ref class Log sealed {
public:
static void SetFilePath(String^ filePath) {
::td::Log::set_file_path(string_to_unmanaged(filePath));
}
static void SetMaxFileSize(std::int64_t maxFileSize) {
::td::Log::set_max_file_size(maxFileSize);
}
static void SetVerbosityLevel(int verbosityLevel) {
::td::Log::set_verbosity_level(verbosityLevel);
}
};
} // namespace TdWindows

176
td/tl/tl_win_object.h Normal file
View File

@ -0,0 +1,176 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#pragma once
#include "td/utils/misc.h"
#include "td/utils/port/CxCli.h"
#include "td/utils/tl_storers.h"
#include "td/telegram/td_api.h"
#include "td/telegram/td_api.hpp"
namespace TdWindows {
using namespace CxCli;
public ref class NativeObject sealed {
public:
virtual ~NativeObject() {
if (data != nullptr) {
get_object_ptr();
}
}
internal:
explicit NativeObject(td::td_api::BaseObject *fromData) {
data = static_cast<void *>(fromData);
}
td::td_api::object_ptr<td::td_api::BaseObject> get_object_ptr() {
auto res = static_cast<td::td_api::BaseObject *>(data);
data = nullptr;
return td::td_api::object_ptr<td::td_api::BaseObject>(res);
}
void *data;
};
public interface class BaseObject {
public:
virtual NativeObject^ ToUnmanaged();
};
//from unmanaged
inline bool FromUnmanaged(bool val) {
return val;
}
inline int32 FromUnmanaged(int32 val) {
return val;
}
inline int64 FromUnmanaged(int64 val) {
return val;
}
inline float64 FromUnmanaged(float64 val) {
return val;
}
inline String^ FromUnmanaged(const std::string &from) {
return string_from_unmanaged(from);
}
inline auto CLRCALL BytesFromUnmanaged(const std::string &from) {
Array<byte>^ res = REF_NEW Vector<byte>(td::narrow_cast<int>(from.size()));
ArrayIndexType i = 0;
for (auto b : from) {
ArraySet(res, i++, b);
}
return res;
}
template <class FromT>
auto CLRCALL FromUnmanaged(std::vector<FromT> &vec) {
using ToT = decltype(FromUnmanaged(vec[0]));
Array<ToT>^ res = REF_NEW Vector<ToT>(td::narrow_cast<int>(vec.size()));
ArrayIndexType i = 0;
for (auto &from : vec) {
ArraySet(res, i++, FromUnmanaged(from));
}
return res;
}
template <class T>
auto CLRCALL FromUnmanaged(td::td_api::object_ptr<T> &from) -> decltype(FromUnmanaged(*from.get())) {
if (!from) {
return nullptr;
}
return FromUnmanaged(*from.get());
}
template <class ResT>
ref class CallFromUnmanagedRes {
public:
static property ResT res;
};
template <class ResT>
struct CallFromUnmanaged {
template <class T>
void operator()(T &val) const {
CallFromUnmanagedRes<ResT>::res = FromUnmanaged(val);
}
};
inline BaseObject^ FromUnmanaged(td::td_api::Function &from) {
CallFromUnmanaged<BaseObject^> res;
downcast_call(from, res);
return CallFromUnmanagedRes<BaseObject^>::res;
}
inline BaseObject^ FromUnmanaged(td::td_api::Object &from) {
CallFromUnmanaged<BaseObject^> res;
downcast_call(from, res);
return CallFromUnmanagedRes<BaseObject^>::res;
}
// to unmanaged
inline bool ToUnmanaged(bool val) {
return val;
}
inline int32 ToUnmanaged(int32 val) {
return val;
}
inline int64 ToUnmanaged(int64 val) {
return val;
}
inline float64 ToUnmanaged(float64 val) {
return val;
}
inline std::string ToUnmanaged(String ^from) {
return string_to_unmanaged(from);
}
inline std::string ToUnmanaged(Array<byte>^ from) {
if (!from) {
return std::string();
}
ArrayIndexType size = ArraySize(from);
std::string res(size, '\0');
for (ArrayIndexType i = 0; i < size; i++) {
res[i] = static_cast<char>(ArrayGet(from, i));
}
return res;
}
template <class FromT>
auto ToUnmanaged(Array<FromT>^ from) {
std::vector<decltype(ToUnmanaged(ArrayGet(from, 0)))> res;
if (from && ArraySize(from)) {
ArrayIndexType size = ArraySize(from);
res.reserve(size);
for (ArrayIndexType i = 0; i < size; i++) {
res.push_back(ToUnmanaged(ArrayGet(from, i)));
}
}
return res;
}
inline NativeObject^ ToUnmanaged(BaseObject^ from) {
if (!from) {
return REF_NEW NativeObject(nullptr);
}
return from->ToUnmanaged();
}
inline String^ ToString(BaseObject^ from) {
return string_from_unmanaged(td::td_api::to_string(ToUnmanaged(from)->get_object_ptr()));
}
} // namespace TdWindows

View File

@ -7,6 +7,7 @@
#pragma once
#include "td/utils/common.h"
#include "td/utils/port/config.h"
#undef small
#if TD_WINRT