mirror of
https://github.com/danog/pif-tdpony.git
synced 2024-11-26 20:04:48 +01:00
Finished writing the extension
This commit is contained in:
parent
05396d0221
commit
370300234f
@ -5,6 +5,6 @@ project(TdExample VERSION 1.0 LANGUAGES CXX)
|
||||
|
||||
add_subdirectory(td)
|
||||
|
||||
add_executable(main main.cpp)
|
||||
target_link_libraries(main PRIVATE Td::TdStatic)
|
||||
set_property(TARGET main PROPERTY CXX_STANDARD 14)
|
||||
add_library(phptd SHARED main.cpp)
|
||||
target_link_libraries(phptd PRIVATE Td::TdJsonStatic phpcpp)
|
||||
set_property(TARGET phptd PROPERTY CXX_STANDARD 14)
|
||||
|
113
exception.cpp
113
exception.cpp
@ -1,113 +0,0 @@
|
||||
#include <phpcpp.h>
|
||||
|
||||
|
||||
class PHPCPP_EXPORT Exception : public std::exception
|
||||
{
|
||||
protected:
|
||||
/**
|
||||
* The exception message
|
||||
* @var char*
|
||||
*/
|
||||
std::string _message;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param message The exception message
|
||||
*/
|
||||
Exception(std::string message) : _message(std::move(message)) {}
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~Exception() = default;
|
||||
|
||||
/**
|
||||
* Overridden what method
|
||||
* @return const char *
|
||||
*/
|
||||
virtual const char *what() const _NOEXCEPT override
|
||||
{
|
||||
return _message.c_str();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the message of the exception.
|
||||
* @return &string
|
||||
*/
|
||||
const std::string &message() const throw()
|
||||
{
|
||||
return _message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the exception code
|
||||
*
|
||||
* @note This only works if the exception was originally
|
||||
* thrown in PHP userland. If the native() member
|
||||
* function returns true, this function will not
|
||||
* be able to correctly provide the filename.
|
||||
*
|
||||
* @return The exception code
|
||||
*/
|
||||
virtual long int code() const _NOEXCEPT
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the filename the exception was thrown in
|
||||
*
|
||||
* @note This only works if the exception was originally
|
||||
* thrown in PHP userland. If the native() member
|
||||
* function returns true, this function will not
|
||||
* be able to correctly provide the filename.
|
||||
*
|
||||
* @return The filename the exception was thrown in
|
||||
*/
|
||||
virtual const std::string& file() const _NOEXCEPT
|
||||
{
|
||||
// we don't know the file the exception is from
|
||||
static std::string file{ "<filename unknown>" };
|
||||
|
||||
// return the missing filename
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the line at which the exception was thrown
|
||||
*
|
||||
* @note This only works if the exception was originally
|
||||
* thrown in PHP userland. If the native() member
|
||||
* function returns true, this function will not
|
||||
* be able to correctly provide the line number.
|
||||
*
|
||||
* @return The line number the exception was thrown at
|
||||
*/
|
||||
virtual long int line() const _NOEXCEPT
|
||||
{
|
||||
// we don't know the file the exception is from
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this a native exception (one that was thrown from C++ code)
|
||||
* @return bool
|
||||
*/
|
||||
virtual bool native() const
|
||||
{
|
||||
// yes, it is native
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Report this error as a fatal error
|
||||
* @return bool
|
||||
*/
|
||||
virtual bool report() const
|
||||
{
|
||||
// this is not done here
|
||||
return false;
|
||||
}
|
||||
};
|
320
main.cpp
320
main.cpp
@ -4,13 +4,12 @@
|
||||
// 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/Client.h>
|
||||
#include <td/telegram/ClientJson.h>
|
||||
#include <tdutils/td/utils/Slice.h>
|
||||
#include <td/telegram/Log.h>
|
||||
|
||||
#include <phpcpp.h>
|
||||
#include "exception.cpp"
|
||||
|
||||
#include <exception>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
@ -22,264 +21,86 @@
|
||||
|
||||
class API : public Php::Base {
|
||||
public:
|
||||
API() = default;
|
||||
virtual ~API() = default;
|
||||
|
||||
void __construct() {
|
||||
initTdlib();
|
||||
}
|
||||
void __wakeup() {
|
||||
initTdlib();
|
||||
Php::Value self(this);
|
||||
if (self["tdlibParameters"]) client_->send(toSlice(self["tdlibParameters"]));
|
||||
}
|
||||
void __destruct() {
|
||||
deinitTdlib();
|
||||
}
|
||||
|
||||
void initTdlib() {
|
||||
client_ = std::make_unique<td::Client>();
|
||||
client_ = std::make_unique<td::ClientJson>();
|
||||
}
|
||||
void deinitTdlib() {
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
while (true) {
|
||||
if (need_restart_) {
|
||||
restart();
|
||||
} else if (!are_authorized_) {
|
||||
process_response(client_->receive(10));
|
||||
} else {
|
||||
std::cerr
|
||||
<< "Enter action [q] quit [u] check for updates and request results [c] show chats [m <id> <text>] send message [l] logout: "
|
||||
<< std::endl;
|
||||
std::string line;
|
||||
std::getline(std::cin, line);
|
||||
std::istringstream ss(line);
|
||||
std::string action;
|
||||
if (!(ss >> action)) {
|
||||
continue;
|
||||
}
|
||||
if (action == "q") {
|
||||
return;
|
||||
}
|
||||
if (action == "u") {
|
||||
std::cerr << "Checking for updates..." << std::endl;
|
||||
while (true) {
|
||||
auto response = client_->receive(0);
|
||||
if (response.object) {
|
||||
process_response(std::move(response));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (action == "l") {
|
||||
std::cerr << "Logging out..." << std::endl;
|
||||
send_query(td::api::make_object<td::api::logOut>(), {});
|
||||
} else if (action == "m") {
|
||||
std::int64_t chat_id;
|
||||
ss >> chat_id;
|
||||
ss.get();
|
||||
std::string text;
|
||||
std::getline(ss, text);
|
||||
|
||||
std::cerr << "Sending message to chat " << chat_id << "..." << std::endl;
|
||||
auto send_message = td::api::make_object<td::api::sendMessage>();
|
||||
send_message->chat_id_ = chat_id;
|
||||
auto message_content = td::api::make_object<td::api::inputMessageText>();
|
||||
message_content->text_ = std::move(text);
|
||||
send_message->input_message_content_ = std::move(message_content);
|
||||
|
||||
send_query(std::move(send_message), {});
|
||||
} else if (action == "c") {
|
||||
std::cerr << "Loading chat list..." << std::endl;
|
||||
send_query(td::api::make_object<td::api::getChats>(std::numeric_limits<std::int64_t>::max(), 0, 20),
|
||||
[this](Object object) {
|
||||
if (object->get_id() == td::api::error::ID) {
|
||||
return;
|
||||
}
|
||||
auto chats = td::move_tl_object_as<td::api::chats>(object);
|
||||
for (auto chat_id : chats->chat_ids_) {
|
||||
std::cerr << "[id:" << chat_id << "] [title:" << chat_title_[chat_id] << "]" << std::endl;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
void send(Php::Parameters ¶ms) {
|
||||
Php::Value value = params[0];
|
||||
if (value.get("@type") == "setTdlibParameters") {
|
||||
Php::Value self(this);
|
||||
self["tdlibParameters"] = value;
|
||||
}
|
||||
client_->send(toSlice(value));
|
||||
}
|
||||
|
||||
Php::Value receive(Php::Parameters ¶ms) {
|
||||
auto slice = client_->receive(params[0]);
|
||||
if (slice.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
Php::Value result = Php::call("json_decode", slice.c_str(), true);
|
||||
Php::Value self(this);
|
||||
return result;
|
||||
}
|
||||
|
||||
Php::Value execute(Php::Parameters ¶ms) {
|
||||
Php::Value value = params[0];
|
||||
if (value.get("@type") == "setTdlibParameters") {
|
||||
Php::Value self(this);
|
||||
self["tdlibParameters"] = value;
|
||||
}
|
||||
auto slice = client_->execute(toSlice(value));
|
||||
if (slice.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
return Php::call("json_decode", slice.c_str(), true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private:
|
||||
using Object = td::api::object_ptr<td::api::Object>;
|
||||
std::unique_ptr<td::Client> client_;
|
||||
|
||||
td::api::object_ptr<td::api::AuthorizationState> authorization_state_;
|
||||
bool are_authorized_{false};
|
||||
bool need_restart_{false};
|
||||
std::uint64_t current_query_id_{0};
|
||||
std::uint64_t authentication_query_id_{0};
|
||||
|
||||
std::map<std::uint64_t, std::function<void(Object)>> handlers_;
|
||||
|
||||
std::map<std::int32_t, td::api::object_ptr<td::api::user>> users_;
|
||||
|
||||
std::map<std::int64_t, std::string> chat_title_;
|
||||
|
||||
void restart() {
|
||||
client_.reset();
|
||||
*this = API();
|
||||
std::unique_ptr<td::ClientJson> client_;
|
||||
td::Slice toSlice(Php::Value value) {
|
||||
std::string str = Php::call("json_encode", value);
|
||||
return td::Slice(str);
|
||||
}
|
||||
|
||||
void send_query(td::api::object_ptr<td::api::Function> f, std::function<void(Object)> handler) {
|
||||
auto query_id = next_query_id();
|
||||
if (handler) {
|
||||
handlers_.emplace(query_id, std::move(handler));
|
||||
}
|
||||
client_->send({query_id, std::move(f)});
|
||||
}
|
||||
|
||||
void process_response(td::Client::Response response) {
|
||||
if (!response.object) {
|
||||
return;
|
||||
}
|
||||
//std::cerr << response.id << " " << to_string(response.object) << std::endl;
|
||||
if (response.id == 0) {
|
||||
return process_update(std::move(response.object));
|
||||
}
|
||||
auto it = handlers_.find(response.id);
|
||||
if (it != handlers_.end()) {
|
||||
it->second(std::move(response.object));
|
||||
}
|
||||
}
|
||||
|
||||
std::string get_user_name(std::int32_t user_id) {
|
||||
auto it = users_.find(user_id);
|
||||
if (it == users_.end()) {
|
||||
return "unknown user";
|
||||
}
|
||||
return it->second->first_name_ + " " + it->second->last_name_;
|
||||
}
|
||||
|
||||
void process_update(td::api::object_ptr<td::api::Object> update) {
|
||||
td::api::downcast_call(
|
||||
*update, overloaded(
|
||||
[this](td::api::updateAuthorizationState &update_authorization_state) {
|
||||
authorization_state_ = std::move(update_authorization_state.authorization_state_);
|
||||
on_authorization_state_update();
|
||||
},
|
||||
[this](td::api::updateNewChat &update_new_chat) {
|
||||
chat_title_[update_new_chat.chat_->id_] = update_new_chat.chat_->title_;
|
||||
},
|
||||
[this](td::api::updateChatTitle &update_chat_title) {
|
||||
chat_title_[update_chat_title.chat_id_] = update_chat_title.title_;
|
||||
},
|
||||
[this](td::api::updateUser &update_user) {
|
||||
auto user_id = update_user.user_->id_;
|
||||
users_[user_id] = std::move(update_user.user_);
|
||||
},
|
||||
[this](td::api::updateNewMessage &update_new_message) {
|
||||
auto chat_id = update_new_message.message_->chat_id_;
|
||||
auto sender_user_name = get_user_name(update_new_message.message_->sender_user_id_);
|
||||
std::string text;
|
||||
if (update_new_message.message_->content_->get_id() == td::api::messageText::ID) {
|
||||
text = static_cast<td::api::messageText &>(*update_new_message.message_->content_).text_;
|
||||
}
|
||||
std::cerr << "Got message: [chat_id:" << chat_id << "] [from:" << sender_user_name << "] ["
|
||||
<< text << "]" << std::endl;
|
||||
},
|
||||
[](auto &update) {}));
|
||||
}
|
||||
|
||||
auto create_authentication_query_handler() {
|
||||
return [this, id = authentication_query_id_](Object object) {
|
||||
if (id == authentication_query_id_) {
|
||||
check_authentication_error(std::move(object));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void on_authorization_state_update() {
|
||||
authentication_query_id_++;
|
||||
td::api::downcast_call(
|
||||
*authorization_state_,
|
||||
overloaded(
|
||||
[this](td::api::authorizationStateReady &) {
|
||||
are_authorized_ = true;
|
||||
std::cerr << "Got authorization" << std::endl;
|
||||
},
|
||||
[this](td::api::authorizationStateLoggingOut &) {
|
||||
are_authorized_ = false;
|
||||
std::cerr << "Logging out" << std::endl;
|
||||
},
|
||||
[this](td::api::authorizationStateClosing &) { std::cerr << "Closing" << std::endl; },
|
||||
[this](td::api::authorizationStateClosed &) {
|
||||
are_authorized_ = false;
|
||||
need_restart_ = true;
|
||||
std::cerr << "Terminated" << std::endl;
|
||||
},
|
||||
[this](td::api::authorizationStateWaitCode &wait_code) {
|
||||
std::string first_name;
|
||||
std::string last_name;
|
||||
if (!wait_code.is_registered_) {
|
||||
std::cerr << "Enter your first name: ";
|
||||
std::cin >> first_name;
|
||||
std::cerr << "Enter your last name: ";
|
||||
std::cin >> last_name;
|
||||
}
|
||||
std::cerr << "Enter authentication code: ";
|
||||
std::string code;
|
||||
std::cin >> code;
|
||||
send_query(td::api::make_object<td::api::checkAuthenticationCode>(code, first_name, last_name),
|
||||
create_authentication_query_handler());
|
||||
},
|
||||
[this](td::api::authorizationStateWaitPassword &) {
|
||||
std::cerr << "Enter authentication password: ";
|
||||
std::string password;
|
||||
std::cin >> password;
|
||||
send_query(td::api::make_object<td::api::checkAuthenticationPassword>(password),
|
||||
create_authentication_query_handler());
|
||||
},
|
||||
[this](td::api::authorizationStateWaitPhoneNumber &) {
|
||||
std::cerr << "Enter phone number: ";
|
||||
std::string phone_number;
|
||||
std::cin >> phone_number;
|
||||
send_query(td::api::make_object<td::api::setAuthenticationPhoneNumber>(
|
||||
phone_number, false /*allow_flash_calls*/, false /*is_current_phone_number*/),
|
||||
create_authentication_query_handler());
|
||||
},
|
||||
[this](td::api::authorizationStateWaitEncryptionKey &) {
|
||||
std::cerr << "Enter encryption key or DESTROY: ";
|
||||
std::string key;
|
||||
std::getline(std::cin, key);
|
||||
if (key == "DESTROY") {
|
||||
send_query(td::api::make_object<td::api::destroy>(), create_authentication_query_handler());
|
||||
} else {
|
||||
send_query(td::api::make_object<td::api::checkDatabaseEncryptionKey>(std::move(key)),
|
||||
create_authentication_query_handler());
|
||||
}
|
||||
},
|
||||
[this](td::api::authorizationStateWaitTdlibParameters &) {
|
||||
auto parameters = td::api::make_object<td::api::tdlibParameters>();
|
||||
parameters->use_message_database_ = true;
|
||||
parameters->use_secret_chats_ = true;
|
||||
parameters->api_id_ = 94575;
|
||||
parameters->api_hash_ = "a3406de8d171bb422bb6ddf3bbd800e2";
|
||||
parameters->system_language_code_ = "en";
|
||||
parameters->device_model_ = "Desktop";
|
||||
parameters->system_version_ = "Unknown";
|
||||
parameters->application_version_ = "1.0";
|
||||
parameters->enable_storage_optimizer_ = true;
|
||||
send_query(td::api::make_object<td::api::setTdlibParameters>(std::move(parameters)),
|
||||
create_authentication_query_handler());
|
||||
}));
|
||||
}
|
||||
|
||||
void check_authentication_error(Object object) {
|
||||
if (object->get_id() == td::api::error::ID) {
|
||||
auto error = td::move_tl_object_as<td::api::error>(object);
|
||||
std::cerr << "Error: " << to_string(error);
|
||||
on_authorization_state_update();
|
||||
}
|
||||
}
|
||||
|
||||
std::uint64_t next_query_id() {
|
||||
return ++current_query_id_;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class Logging : public Php::Base
|
||||
{
|
||||
public:
|
||||
Logging() = default;
|
||||
virtual ~Logging() = default;
|
||||
|
||||
static Php::Value set_file_path(Php::Parameters ¶ms) {
|
||||
return td::Log::set_file_path(params[0]);
|
||||
}
|
||||
static void set_max_file_size(Php::Parameters ¶ms) {
|
||||
td::Log::set_max_file_size(params[0]);
|
||||
}
|
||||
static void set_verbosity_level(Php::Parameters ¶ms) {
|
||||
td::Log::set_verbosity_level(params[0]);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
extern "C" {
|
||||
@ -300,9 +121,12 @@ extern "C" {
|
||||
// description of the class so that PHP knows which methods are accessible
|
||||
Php::Class<API> api("API");
|
||||
|
||||
api.method<&API::__construct>("__construct", Php::Public | Php::Final);
|
||||
api.method<&API::__wakeup>("__wakeup", Php::Public | Php::Final);
|
||||
api.method<&API::__sleep>("__sleep", Php::Public | Php::Final);
|
||||
api.method<&API::__construct>("__construct", Php::Public | Php::Final, {});
|
||||
api.method<&API::__wakeup>("__wakeup", Php::Public | Php::Final, {});
|
||||
api.method<&API::__destruct>("__destruct", Php::Public | Php::Final, {});
|
||||
api.method<&API::send>("send", Php::Public | Php::Final);
|
||||
api.method<&API::receive>("receive", Php::Public | Php::Final);
|
||||
api.method<&API::execute>("execute", Php::Public | Php::Final);
|
||||
|
||||
api.property("settings", 0, Php::Public);
|
||||
|
||||
@ -312,10 +136,14 @@ extern "C" {
|
||||
Php::Namespace MadelineProto("MadelineProto");
|
||||
Php::Namespace X("X");
|
||||
|
||||
Php::Class<Exception> exception("Exception");
|
||||
Php::Class<Logging> logging("Logging");
|
||||
|
||||
logging.method<&Logging::set_file_path>("set_file_path", Php::Public, {Php::ByVal("file_path", Php::Type::String)});
|
||||
logging.method<&Logging::set_max_file_size>("set_max_file_size", Php::Public, {Php::ByVal("set_max_file_size", Php::Type::Numeric)});
|
||||
logging.method<&Logging::set_verbosity_level>("set_verbosity_level", Php::Public, {Php::ByVal("verbosity_level", Php::Type::Numeric)});
|
||||
|
||||
X.add(std::move(exception));
|
||||
X.add(std::move(api));
|
||||
X.add(std::move(logging));
|
||||
MadelineProto.add(std::move(X));
|
||||
danog.add(std::move(MadelineProto));
|
||||
extension.add(std::move(danog));
|
||||
|
2
td
2
td
@ -1 +1 @@
|
||||
Subproject commit 9813b0128bd7d236167071cc7a2e3e25c1d82a45
|
||||
Subproject commit 6c706f45e7a73c936b9f2f267785092c8a73348f
|
Loading…
Reference in New Issue
Block a user