diff --git a/include/MaaFramework/Utility/MaaBuffer.h b/include/MaaFramework/Utility/MaaBuffer.h index 5f821c132..a7073208b 100644 --- a/include/MaaFramework/Utility/MaaBuffer.h +++ b/include/MaaFramework/Utility/MaaBuffer.h @@ -42,6 +42,8 @@ extern "C" int32_t MAA_FRAMEWORK_API MaaGetRectY(MaaRectHandle handle); int32_t MAA_FRAMEWORK_API MaaGetRectW(MaaRectHandle handle); int32_t MAA_FRAMEWORK_API MaaGetRectH(MaaRectHandle handle); + + MaaBool MAA_FRAMEWORK_API MaaSetRect(MaaRectHandle handle, int32_t x, int32_t y, int32_t w, int32_t h); MaaBool MAA_FRAMEWORK_API MaaSetRectX(MaaRectHandle handle, int32_t value); MaaBool MAA_FRAMEWORK_API MaaSetRectY(MaaRectHandle handle, int32_t value); MaaBool MAA_FRAMEWORK_API MaaSetRectW(MaaRectHandle handle, int32_t value); diff --git a/include/MaaToolKit/ExecAgent/MaaToolKitExecAgent.h b/include/MaaToolKit/ExecAgent/MaaToolKitExecAgent.h new file mode 100644 index 000000000..5566608bb --- /dev/null +++ b/include/MaaToolKit/ExecAgent/MaaToolKitExecAgent.h @@ -0,0 +1,24 @@ +#pragma once + +#include "../MaaToolKitDef.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + MaaBool MAA_TOOLKIT_API MaaToolKitRegisterCustomRecognizerExecutor( // + MaaInstanceHandle handle, MaaStringView recognizer_name, MaaStringView recognizer_exec_path, + MaaStringView recognizer_exec_param_json, MaaToolKitExecAgentArgvTransferMode argv_mode); + MaaBool MAA_TOOLKIT_API MaaToolKitUnregisterCustomRecognizerExecutor( // + MaaInstanceHandle handle, MaaStringView recognizer_name); + + MaaBool MAA_TOOLKIT_API MaaToolKitRegisterCustomActionExecutor( // + MaaInstanceHandle handle, MaaStringView action_name, MaaStringView action_exec_path, + MaaStringView action_exec_param_json, MaaToolKitExecAgentArgvTransferMode argv_mode); + MaaBool MAA_TOOLKIT_API MaaToolKitUnregisterCustomActionExecutor( // + MaaInstanceHandle handle, MaaStringView action_name); + +#ifdef __cplusplus +} +#endif diff --git a/include/MaaToolKit/MaaToolKitAPI.h b/include/MaaToolKit/MaaToolKitAPI.h index 16dc43ba8..15030d904 100644 --- a/include/MaaToolKit/MaaToolKitAPI.h +++ b/include/MaaToolKit/MaaToolKitAPI.h @@ -4,4 +4,5 @@ #include "Config/MaaToolKitConfig.h" #include "Device/MaaToolKitDevice.h" +#include "ExecAgent/MaaToolKitExecAgent.h" #include "Win32/MaaToolKitWin32Window.h" diff --git a/include/MaaToolKit/MaaToolKitDef.h b/include/MaaToolKit/MaaToolKitDef.h index d34bafda5..065d94e2e 100644 --- a/include/MaaToolKit/MaaToolKitDef.h +++ b/include/MaaToolKit/MaaToolKitDef.h @@ -7,3 +7,14 @@ typedef struct MaaToolKitConfigAPI* MaaToolKitConfigHandle; struct MaaToolKitTaskAPI; typedef struct MaaToolKitTaskAPI* MaaToolKitTaskHandle; + +typedef int32_t MaaToolKitExecAgentArgvTransferMode; +enum MaaToolKitExecAgentArgvTransferModeEnum +{ + MaaToolKitExecAgentArgvTransferMode_Text_StdIO = 1, + // MaaToolKitExecAgentArgvTransferMode_Text_FileIO = 2, + MaaToolKitExecAgentArgvTransferMode_Text_Mask = 0xFF, + + MaaToolKitExecAgentArgvTransferMode_Image_FileIO = 1 << 8, + MaaToolKitExecAgentArgvTransferMode_Image_Mask = 0xFF00, +}; diff --git a/sample/cpp/main.cpp b/sample/cpp/main.cpp index 1b1e7091b..2178d504f 100644 --- a/sample/cpp/main.cpp +++ b/sample/cpp/main.cpp @@ -112,12 +112,9 @@ MaaBool my_analyze(MaaSyncContextHandle sync_context, const MaaImageBufferHandle /* Output recognition result */ - // Step 1: output out_box + // Step 1: output box std::array my_box { 0 }; // your result - out_box->x = my_box[0]; - out_box->y = my_box[1]; - out_box->width = my_box[2]; - out_box->height = my_box[3]; + MaaSetRect(out_box, my_box[0], my_box[1], my_box[2], my_box[3]); // Step 2: output anything you want MaaSetString(out_detail, diff --git a/source/MaaAdbControlUnit/API/AdbControlUnitAPI.cpp b/source/MaaAdbControlUnit/API/AdbControlUnitAPI.cpp index 967367412..1e17f17be 100644 --- a/source/MaaAdbControlUnit/API/AdbControlUnitAPI.cpp +++ b/source/MaaAdbControlUnit/API/AdbControlUnitAPI.cpp @@ -6,7 +6,6 @@ #include "Input/MinitouchInput.h" #include "Input/TapInput.h" #include "Manager/ControlUnitMgr.h" -#include "Platform/PlatformFactory.h" #include "Screencap/Encode.h" #include "Screencap/EncodeToFile.h" #include "Screencap/FastestWay.h" @@ -158,13 +157,6 @@ MaaControlUnitHandle MaaAdbControlUnitCreate( // return nullptr; } - auto platform_io = PlatformFactory::create(); - if (!platform_io) { - LogError << "Create platform io failed"; - return nullptr; - } - unit_mgr->set_io(platform_io); - unit_mgr->set_replacement({ { "{ADB}", adb_path }, { "{ADB_SERIAL}", adb_serial }, diff --git a/source/MaaAdbControlUnit/Base/ArgvWrapper.hpp b/source/MaaAdbControlUnit/Base/ArgvWrapper.hpp deleted file mode 100644 index db154a61a..000000000 --- a/source/MaaAdbControlUnit/Base/ArgvWrapper.hpp +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once - -#include -#include - -#include "Utils/StringMisc.hpp" - -MAA_NS_BEGIN - -template -concept CheckArgv = requires(Argv& argv) { - argv.clear(); - argv.reserve(0); - }; - -template -requires IsSomeKindOfStringArray && CheckArgv -struct ArgvWrapper -{ - using value = Argv; - using string = typename Argv::value_type; - using replacement = typename std::map; - - Argv argv; - - bool parse(const json::array& arr); - Argv gen(const std::map& replacement) const; -}; - -template -requires IsSomeKindOfStringArray && CheckArgv -bool ArgvWrapper::parse(const json::array& arr) -{ - if (!MAA_RNS::ranges::all_of(arr, [](const json::value& val) { return val.is_string(); })) { - return false; - } - - argv = arr.to_vector(); - return true; -} - -template -requires IsSomeKindOfStringArray && CheckArgv -Argv ArgvWrapper::gen(const std::map& replacement) const -{ - auto argv_dup = argv; - for (auto& s : argv_dup) { - string_replace_all_(s, replacement); - } - return argv_dup; -} - -// using _Argv = ArgvWrapper>; - -MAA_NS_END diff --git a/source/MaaAdbControlUnit/Base/ProcessArgvGenerator.cpp b/source/MaaAdbControlUnit/Base/ProcessArgvGenerator.cpp new file mode 100644 index 000000000..a0850e095 --- /dev/null +++ b/source/MaaAdbControlUnit/Base/ProcessArgvGenerator.cpp @@ -0,0 +1,49 @@ +#include "ProcessArgvGenerator.h" + +#include "Utils/IOStream/BoostIO.hpp" +#include "Utils/Logger.h" +#include "Utils/Platform.h" + +MAA_CTRL_UNIT_NS_BEGIN + +std::optional ProcessArgvGenerator::create(const json::array& arr) +{ + if (!arr.all()) { + LogError << "array not all string" << VAR(arr); + return std::nullopt; + } + + auto raw = arr.to_vector(); + if (raw.empty()) { + LogError << "array is empty"; + return std::nullopt; + } + + return ProcessArgvGenerator(std::move(raw)); +} +std::optional ProcessArgvGenerator::gen(const Replacement& replacement) const +{ + if (raw_.empty()) { + LogError << "raw is empty"; + return std::nullopt; + } + + auto res = raw_; + for (auto& s : res) { + string_replace_all_(s, replacement); + } + + auto stdpath = MAA_NS::path(res.front()); + auto searched_path = boost::process::search_path(stdpath); + + if (!std::filesystem::exists(searched_path)) { + LogError << "exec path not exits" << VAR(searched_path); + return std::nullopt; + } + + auto args = std::vector(std::make_move_iterator(res.begin() + 1), std::make_move_iterator(res.end())); + + return ProcessArgv { .exec = std::move(searched_path), .args = std::move(args) }; +} + +MAA_CTRL_UNIT_NS_END diff --git a/source/MaaAdbControlUnit/Base/ProcessArgvGenerator.h b/source/MaaAdbControlUnit/Base/ProcessArgvGenerator.h new file mode 100644 index 000000000..aef767260 --- /dev/null +++ b/source/MaaAdbControlUnit/Base/ProcessArgvGenerator.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include +#include + +#include + +#include "Utils/StringMisc.hpp" + +MAA_CTRL_UNIT_NS_BEGIN + +class ProcessArgvGenerator +{ +public: + using Replacement = std::unordered_map; + + struct ProcessArgv + { + std::filesystem::path exec; + std::vector args; + }; + +public: + static std::optional create(const json::array& arr); + + ProcessArgvGenerator() = default; + ProcessArgvGenerator(std::vector raw) : raw_(std::move(raw)) {} + + std::optional gen(const Replacement& replacement) const; + +private: + std::vector raw_; +}; + +MAA_CTRL_UNIT_NS_END diff --git a/source/MaaAdbControlUnit/Base/UnitBase.cpp b/source/MaaAdbControlUnit/Base/UnitBase.cpp index 8cf6d5544..79544588b 100644 --- a/source/MaaAdbControlUnit/Base/UnitBase.cpp +++ b/source/MaaAdbControlUnit/Base/UnitBase.cpp @@ -1,18 +1,11 @@ #include "UnitBase.h" +#include "Utils/IOStream/ChildPipeIOStream.h" #include "Utils/Logger.h" MAA_CTRL_UNIT_NS_BEGIN -void UnitBase::set_io(std::shared_ptr io_ptr) -{ - for (auto child : children_) { - child->set_io(io_ptr); - } - io_ptr_ = io_ptr; -} - -void UnitBase::set_replacement(Argv::replacement argv_replace) +void UnitBase::set_replacement(Replacement argv_replace) { for (auto child : children_) { child->set_replacement(argv_replace); @@ -20,7 +13,7 @@ void UnitBase::set_replacement(Argv::replacement argv_replace) argv_replace_ = std::move(argv_replace); } -void UnitBase::merge_replacement(Argv::replacement argv_replace, bool _override) +void UnitBase::merge_replacement(Replacement argv_replace, bool _override) { for (auto child : children_) { child->merge_replacement(argv_replace, _override); @@ -35,49 +28,41 @@ void UnitBase::merge_replacement(Argv::replacement argv_replace, bool _override) } bool UnitBase::parse_argv(const std::string& key, const json::value& config, const json::array& default_argv, - Argv& argv) + /*out*/ ProcessArgvGenerator& argv) { auto jargv = config.get("command", key, default_argv); - if (!argv.parse(jargv)) { + auto opt = ProcessArgvGenerator::create(jargv); + if (!opt) { LogError << "Parse config failed:" << VAR(key); return false; } + argv = std::move(*opt); return true; } -std::optional UnitBase::command(const Argv::value& cmd, bool recv_by_socket, int64_t timeout) +std::optional UnitBase::startup_and_read_pipe(const ProcessArgv& argv, std::chrono::seconds timeout) { - if (!io_ptr_) { - LogError << "io_ptr is nullptr"; - return std::nullopt; - } - auto start_time = std::chrono::steady_clock::now(); - std::string pipe_data; - std::string sock_data; - int ret = io_ptr_->call_command(cmd, recv_by_socket, pipe_data, sock_data, timeout); + ChildPipeIOStream ios(argv.exec, argv.args); + std::string output = ios.read(timeout); + bool ret = ios.release(); auto duration = duration_since(start_time); - std::string scmd = json::array(cmd).to_string(); - LogDebug << VAR(scmd) << VAR(ret) << VAR(pipe_data.size()) << VAR(sock_data.size()) << VAR(duration); - - if (!pipe_data.empty() && pipe_data.size() < 4096) { - LogDebug << MAA_LOG_NS::separator::newline << "stdout output:" << pipe_data; - } - if (recv_by_socket && !sock_data.empty() && sock_data.size() < 4096) { - LogDebug << MAA_LOG_NS::separator::newline << "socket output:" << sock_data; + LogDebug << VAR(output.size()) << VAR(duration); + if (!output.empty() && output.size() < 4096) { + LogDebug << MAA_LOG_NS::separator::newline << "output:" << output; } - if (ret != 0) { - LogError << "call_command failed" << VAR(cmd) << VAR(ret); + if (!ret) { + LogError << "child return error" << VAR(argv.exec) << VAR(argv.args); return std::nullopt; } - return recv_by_socket ? sock_data : pipe_data; + return output; } MAA_CTRL_UNIT_NS_END diff --git a/source/MaaAdbControlUnit/Base/UnitBase.h b/source/MaaAdbControlUnit/Base/UnitBase.h index 3cb60a48a..fbefc577f 100644 --- a/source/MaaAdbControlUnit/Base/UnitBase.h +++ b/source/MaaAdbControlUnit/Base/UnitBase.h @@ -1,10 +1,11 @@ #pragma once +#include + #include -#include "Base/ArgvWrapper.hpp" +#include "Base/ProcessArgvGenerator.h" #include "ControlUnit/AdbControlUnitAPI.h" -#include "Platform/PlatformIO.h" #include "Screencap/ScreencapHelper.h" MAA_CTRL_UNIT_NS_BEGIN @@ -12,27 +13,27 @@ MAA_CTRL_UNIT_NS_BEGIN class UnitBase { public: - using Argv = ArgvWrapper>; + using Replacement = ProcessArgvGenerator::Replacement; + using ProcessArgv = ProcessArgvGenerator::ProcessArgv; public: virtual ~UnitBase() = default; virtual bool parse(const json::value& config) = 0; - virtual void set_io(std::shared_ptr io_ptr); - virtual void set_replacement(Argv::replacement argv_replace); - virtual void merge_replacement(Argv::replacement argv_replace, bool _override = true); + virtual void set_replacement(Replacement argv_replace); + virtual void merge_replacement(Replacement argv_replace, bool _override = true); protected: static bool parse_argv(const std::string& key, const json::value& config, const json::array& default_argv, - /*out*/ Argv& argv); + /*out*/ ProcessArgvGenerator& argv); - std::optional command(const Argv::value& cmd, bool recv_by_socket = false, int64_t timeout = 20000); + std::optional startup_and_read_pipe(const ProcessArgv& argv, + std::chrono::seconds timeout = std::chrono::seconds(20)); protected: - std::shared_ptr io_ptr_ = nullptr; std::vector> children_; - Argv::replacement argv_replace_; + Replacement argv_replace_; }; class ScreencapBase : public UnitBase diff --git a/source/MaaAdbControlUnit/CMakeLists.txt b/source/MaaAdbControlUnit/CMakeLists.txt index d8b9105cd..117acc924 100644 --- a/source/MaaAdbControlUnit/CMakeLists.txt +++ b/source/MaaAdbControlUnit/CMakeLists.txt @@ -6,7 +6,7 @@ add_library(MaaAdbControlUnit SHARED ${maa_adb_control_unit_src} ${maa_adb_contr target_include_directories(MaaAdbControlUnit PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../include ${CMAKE_CURRENT_SOURCE_DIR}/../../include) -target_link_libraries(MaaAdbControlUnit MaaUtils HeaderOnlyLibraries ${OpenCV_LIBS} ZLIB::ZLIB Boost::system) +target_link_libraries(MaaAdbControlUnit MaaUtils HeaderOnlyLibraries ${OpenCV_LIBS} ZLIB::ZLIB) if(WIN32) target_link_libraries(MaaAdbControlUnit ws2_32) endif() diff --git a/source/MaaAdbControlUnit/General/Activity.cpp b/source/MaaAdbControlUnit/General/Activity.cpp index 8db63a8d3..a0a4361ff 100644 --- a/source/MaaAdbControlUnit/General/Activity.cpp +++ b/source/MaaAdbControlUnit/General/Activity.cpp @@ -22,9 +22,13 @@ bool Activity::start_app(const std::string& intent) LogFunc; merge_replacement({ { "{INTENT}", intent } }); - auto cmd_ret = command(start_app_argv_.gen(argv_replace_)); - return cmd_ret.has_value(); + auto argv_opt = start_app_argv_.gen(argv_replace_); + if (!argv_opt) { + return false; + } + + return startup_and_read_pipe(*argv_opt).has_value(); } bool Activity::stop_app(const std::string& intent) @@ -32,9 +36,12 @@ bool Activity::stop_app(const std::string& intent) LogFunc; merge_replacement({ { "{INTENT}", intent } }); - auto cmd_ret = command(stop_app_argv_.gen(argv_replace_)); + auto argv_opt = stop_app_argv_.gen(argv_replace_); + if (!argv_opt) { + return false; + } - return cmd_ret.has_value(); + return startup_and_read_pipe(*argv_opt).has_value(); } MAA_CTRL_UNIT_NS_END diff --git a/source/MaaAdbControlUnit/General/Activity.h b/source/MaaAdbControlUnit/General/Activity.h index 339db1c7e..1ae451790 100644 --- a/source/MaaAdbControlUnit/General/Activity.h +++ b/source/MaaAdbControlUnit/General/Activity.h @@ -17,8 +17,8 @@ class Activity : public UnitBase bool stop_app(const std::string& intent); private: - Argv start_app_argv_; - Argv stop_app_argv_; + ProcessArgvGenerator start_app_argv_; + ProcessArgvGenerator stop_app_argv_; }; MAA_CTRL_UNIT_NS_END diff --git a/source/MaaAdbControlUnit/General/Connection.cpp b/source/MaaAdbControlUnit/General/Connection.cpp index a39a38853..c7230f83e 100644 --- a/source/MaaAdbControlUnit/General/Connection.cpp +++ b/source/MaaAdbControlUnit/General/Connection.cpp @@ -24,16 +24,20 @@ bool Connection::connect() { LogFunc; - auto cmd_ret = command(connect_argv_.gen(argv_replace_), false, 60LL * 1000); + auto argv_opt = connect_argv_.gen(argv_replace_); + if (!argv_opt) { + return false; + } - if (!cmd_ret) { - LogInfo << "run command failed"; + using namespace std::chrono_literals; + auto output_opt = startup_and_read_pipe(*argv_opt, 60s); + if (!output_opt) { return false; } constexpr std::array kErrorFlag = { "error", "cannot", "refused", "unable to connect" }; for (const auto& flag : kErrorFlag) { - if (cmd_ret->find(flag) != std::string::npos) { + if (output_opt->find(flag) != std::string::npos) { LogInfo << "unable to connect"; return false; } @@ -47,7 +51,13 @@ bool Connection::kill_server() { LogFunc; - return command(kill_server_argv_.gen(argv_replace_), false, 60LL * 1000).has_value(); + auto argv_opt = kill_server_argv_.gen(argv_replace_); + if (!argv_opt) { + return false; + } + + using namespace std::chrono_literals; + return startup_and_read_pipe(*argv_opt, 60s).has_value(); } MAA_CTRL_UNIT_NS_END diff --git a/source/MaaAdbControlUnit/General/Connection.h b/source/MaaAdbControlUnit/General/Connection.h index 81aee545a..f27715175 100644 --- a/source/MaaAdbControlUnit/General/Connection.h +++ b/source/MaaAdbControlUnit/General/Connection.h @@ -17,8 +17,8 @@ class Connection : public UnitBase bool kill_server(); private: - Argv connect_argv_; - Argv kill_server_argv_; + ProcessArgvGenerator connect_argv_; + ProcessArgvGenerator kill_server_argv_; }; MAA_CTRL_UNIT_NS_END diff --git a/source/MaaAdbControlUnit/General/DeviceInfo.cpp b/source/MaaAdbControlUnit/General/DeviceInfo.cpp index 8413284a2..773dfbfb0 100644 --- a/source/MaaAdbControlUnit/General/DeviceInfo.cpp +++ b/source/MaaAdbControlUnit/General/DeviceInfo.cpp @@ -25,13 +25,17 @@ std::optional DeviceInfo::request_uuid() { LogFunc; - auto cmd_ret = command(uuid_argv_.gen(argv_replace_)); + auto argv_opt = uuid_argv_.gen(argv_replace_); + if (!argv_opt) { + return std::nullopt; + } - if (!cmd_ret) { + auto output_opt = startup_and_read_pipe(*argv_opt); + if (!output_opt) { return std::nullopt; } - auto& uuid_str = cmd_ret.value(); + auto& uuid_str = output_opt.value(); std::erase_if(uuid_str, [](char c) { return !std::isdigit(c) && !std::isalpha(c); }); return uuid_str; @@ -41,15 +45,19 @@ std::optional> DeviceInfo::request_resolution() { LogFunc; - auto cmd_ret = command(resolution_argv_.gen(argv_replace_)); + auto argv_opt = resolution_argv_.gen(argv_replace_); + if (!argv_opt) { + return std::nullopt; + } - if (!cmd_ret) { + auto output_opt = startup_and_read_pipe(*argv_opt); + if (!output_opt) { return std::nullopt; } int width = 0, height = 0; - std::istringstream iss(cmd_ret.value()); + std::istringstream iss(output_opt.value()); iss >> width >> height; return std::make_pair(width, height); } @@ -58,13 +66,17 @@ std::optional DeviceInfo::request_orientation() { LogFunc; - auto cmd_ret = command(orientation_argv_.gen(argv_replace_)); + auto argv_opt = orientation_argv_.gen(argv_replace_); + if (!argv_opt) { + return std::nullopt; + } - if (!cmd_ret) { + auto output_opt = startup_and_read_pipe(*argv_opt); + if (!output_opt) { return std::nullopt; } - const auto& s = cmd_ret.value(); + const auto& s = output_opt.value(); if (s.empty()) { return std::nullopt; diff --git a/source/MaaAdbControlUnit/General/DeviceInfo.h b/source/MaaAdbControlUnit/General/DeviceInfo.h index f205a5316..ea51d5c82 100644 --- a/source/MaaAdbControlUnit/General/DeviceInfo.h +++ b/source/MaaAdbControlUnit/General/DeviceInfo.h @@ -18,9 +18,9 @@ class DeviceInfo : public UnitBase std::optional request_orientation(); private: - Argv uuid_argv_; - Argv resolution_argv_; - Argv orientation_argv_; + ProcessArgvGenerator uuid_argv_; + ProcessArgvGenerator resolution_argv_; + ProcessArgvGenerator orientation_argv_; }; MAA_CTRL_UNIT_NS_END diff --git a/source/MaaAdbControlUnit/General/DeviceList.cpp b/source/MaaAdbControlUnit/General/DeviceList.cpp index 53c0d294f..2b050fee6 100644 --- a/source/MaaAdbControlUnit/General/DeviceList.cpp +++ b/source/MaaAdbControlUnit/General/DeviceList.cpp @@ -20,9 +20,13 @@ std::optional> DeviceList::request_devices() { LogFunc; - auto cmd_ret = command(devices_argv_.gen(argv_replace_)); + auto argv_opt = devices_argv_.gen(argv_replace_); + if (!argv_opt) { + return std::nullopt; + } - if (!cmd_ret) { + auto output_opt = startup_and_read_pipe(*argv_opt); + if (!output_opt) { return std::nullopt; } @@ -30,7 +34,7 @@ std::optional> DeviceList::request_devices() // List of devices attached // 127.0.0.1:16384 offline // 127.0.0.1:16416 device - auto devices_str = std::move(cmd_ret).value(); + auto devices_str = std::move(output_opt).value(); auto lines = string_split(devices_str, '\n'); if (lines.empty()) { return {}; diff --git a/source/MaaAdbControlUnit/General/DeviceList.h b/source/MaaAdbControlUnit/General/DeviceList.h index a9d3db4c8..772d79236 100644 --- a/source/MaaAdbControlUnit/General/DeviceList.h +++ b/source/MaaAdbControlUnit/General/DeviceList.h @@ -16,7 +16,7 @@ class DeviceList : public UnitBase std::optional> request_devices(); private: - Argv devices_argv_; + ProcessArgvGenerator devices_argv_; }; MAA_CTRL_UNIT_NS_END diff --git a/source/MaaAdbControlUnit/Input/MaatouchInput.cpp b/source/MaaAdbControlUnit/Input/MaatouchInput.cpp index 55b5432b0..0bbbee00e 100644 --- a/source/MaaAdbControlUnit/Input/MaatouchInput.cpp +++ b/source/MaaAdbControlUnit/Input/MaatouchInput.cpp @@ -41,8 +41,8 @@ bool MaatouchInput::set_wh(int swidth, int sheight, int orientation) { LogFunc << VAR(swidth) << VAR(sheight) << VAR(orientation); - shell_handler_ = invoke_app_->invoke_app(package_name_); - if (!shell_handler_) { + pipe_ios_ = invoke_app_->invoke_app(package_name_); + if (!pipe_ios_) { return false; } @@ -53,7 +53,8 @@ bool MaatouchInput::press_key(int key) { LogInfo << VAR(key); - if (!shell_handler_) { + if (!pipe_ios_) { + LogError << "pipe_ios_ is nullptr"; return false; } @@ -61,15 +62,15 @@ bool MaatouchInput::press_key(int key) static constexpr std::string_view kKeyDownFormat = "k {} d\nc\n"; static constexpr std::string_view kKeyUpFormat = "k {} u\nc\n"; - bool ret = shell_handler_->write(MAA_FMT::format(kKeyDownFormat, key)) && - shell_handler_->write(MAA_FMT::format(kKeyUpFormat, key)); + bool ret = + pipe_ios_->write(MAA_FMT::format(kKeyDownFormat, key)) && pipe_ios_->write(MAA_FMT::format(kKeyUpFormat, key)); if (!ret) { LogError << "failed to write"; return false; } - return ret; + return true; } MAA_CTRL_UNIT_NS_END diff --git a/source/MaaAdbControlUnit/Input/MaatouchInput.h b/source/MaaAdbControlUnit/Input/MaatouchInput.h index 908cb62ff..47f9797ed 100644 --- a/source/MaaAdbControlUnit/Input/MaatouchInput.h +++ b/source/MaaAdbControlUnit/Input/MaatouchInput.h @@ -22,17 +22,12 @@ class MaatouchInput : public MtouchHelper, public KeyInputBase public: // from UnitBase virtual bool parse(const json::value& config) override; - virtual void set_io(std::shared_ptr io_ptr) override - { - TouchInputBase::set_io(io_ptr); - KeyInputBase::set_io(io_ptr); - } - virtual void set_replacement(Argv::replacement argv_replace) override + virtual void set_replacement(UnitBase::Replacement argv_replace) override { TouchInputBase::set_replacement(argv_replace); KeyInputBase::set_replacement(argv_replace); } - virtual void merge_replacement(Argv::replacement argv_replace, bool _override = true) override + virtual void merge_replacement(UnitBase::Replacement argv_replace, bool _override = true) override { TouchInputBase::merge_replacement(argv_replace, _override); KeyInputBase::merge_replacement(argv_replace, _override); diff --git a/source/MaaAdbControlUnit/Input/MinitouchInput.cpp b/source/MaaAdbControlUnit/Input/MinitouchInput.cpp index b5851dbdb..2339c5ef1 100644 --- a/source/MaaAdbControlUnit/Input/MinitouchInput.cpp +++ b/source/MaaAdbControlUnit/Input/MinitouchInput.cpp @@ -63,8 +63,8 @@ bool MinitouchInput::set_wh(int swidth, int sheight, int orientation) // https://github.com/openstf/minitouch#running static const std::string kMinitouchUseStdin = "-i"; - shell_handler_ = invoke_app_->invoke_bin(kMinitouchUseStdin); - if (!shell_handler_) { + pipe_ios_ = invoke_app_->invoke_bin(kMinitouchUseStdin); + if (!pipe_ios_) { return false; } diff --git a/source/MaaAdbControlUnit/Input/MtouchHelper.cpp b/source/MaaAdbControlUnit/Input/MtouchHelper.cpp index 77cb97b32..81a2fb8de 100644 --- a/source/MaaAdbControlUnit/Input/MtouchHelper.cpp +++ b/source/MaaAdbControlUnit/Input/MtouchHelper.cpp @@ -11,43 +11,21 @@ MAA_CTRL_UNIT_NS_BEGIN bool MtouchHelper::read_info(int swidth, int sheight, int orientation) { - auto start_time = std::chrono::steady_clock::now(); - bool timeout = false; - auto check_time = [&]() { - timeout = duration_since(start_time) > std::chrono::seconds(10); - return !timeout; - }; - - std::string prev; - std::string info; - - while (check_time()) { - auto str = prev + shell_handler_->read(5); - LogDebug << "output:" << str; - if (str.empty()) { - std::this_thread::sleep_for(std::chrono::seconds(2)); - continue; - } - auto pos = str.find('^'); - if (pos == std::string::npos) { - continue; - } - auto rpos = str.find('\n', pos); - if (rpos == std::string::npos) { - prev = str; // 也许还得再读点? - continue; - } - - info = str.substr(pos + 1, rpos - pos - 1); - break; - } - if (timeout) { - LogError << "read info timeout"; + if (!pipe_ios_) { + LogError << "pipe_ios_ is nullptr"; return false; } - LogInfo << "info:" << info; - string_trim_(info); + using namespace std::chrono_literals; + std::ignore = pipe_ios_->read_until("^", 5s); + constexpr std::string_view kFlag = "\n"; + std::string info = pipe_ios_->read_until(kFlag, 1s); + + if (!info.ends_with(kFlag)) { + LogError << "failed to read info"; + return false; + } + LogInfo << VAR(info); int contact = 0; int x = 0; @@ -77,8 +55,8 @@ bool MtouchHelper::read_info(int swidth, int sheight, int orientation) bool MtouchHelper::click(int x, int y) { - if (!shell_handler_) { - LogError << "shell handler not ready"; + if (!pipe_ios_) { + LogError << "pipe_ios_ is nullptr"; return false; } @@ -92,20 +70,21 @@ bool MtouchHelper::click(int x, int y) LogInfo << VAR(x) << VAR(y) << VAR(touch_x) << VAR(touch_y); - bool ret = shell_handler_->write(MAA_FMT::format(kDownFormat, 0, touch_x, touch_y, press_)) && - shell_handler_->write(MAA_FMT::format(kUpFormat, 0)); + bool ret = pipe_ios_->write(MAA_FMT::format(kDownFormat, 0, touch_x, touch_y, press_)) && + pipe_ios_->write(MAA_FMT::format(kUpFormat, 0)); if (!ret) { LogError << "failed to write"; return false; } - return ret; + return true; } bool MtouchHelper::swipe(int x1, int y1, int x2, int y2, int duration) { - if (!shell_handler_) { + if (!pipe_ios_) { + LogError << "pipe_ios_ is nullptr"; return false; } @@ -131,7 +110,7 @@ bool MtouchHelper::swipe(int x1, int y1, int x2, int y2, int duration) auto start = std::chrono::steady_clock::now(); auto now = start; bool ret = true; - ret &= shell_handler_->write(MAA_FMT::format(kDownFormat, 0, touch_x1, touch_y1, press_)); + ret &= pipe_ios_->write(MAA_FMT::format(kDownFormat, 0, touch_x1, touch_y1, press_)); if (!ret) { LogError << "write error"; return false; @@ -148,7 +127,7 @@ bool MtouchHelper::swipe(int x1, int y1, int x2, int y2, int duration) std::this_thread::sleep_until(now + delay); now = std::chrono::steady_clock::now(); - ret &= shell_handler_->write(MAA_FMT::format(kMoveFormat, 0, tx, ty, press_)); + ret &= pipe_ios_->write(MAA_FMT::format(kMoveFormat, 0, tx, ty, press_)); if (!ret) { LogWarn << "write error"; } @@ -156,24 +135,24 @@ bool MtouchHelper::swipe(int x1, int y1, int x2, int y2, int duration) std::this_thread::sleep_until(now + delay); now = std::chrono::steady_clock::now(); - ret &= shell_handler_->write(MAA_FMT::format(kMoveFormat, 0, touch_x2, touch_y2, press_)); + ret &= pipe_ios_->write(MAA_FMT::format(kMoveFormat, 0, touch_x2, touch_y2, press_)); std::this_thread::sleep_until(now + delay); now = std::chrono::steady_clock::now(); - ret &= shell_handler_->write(MAA_FMT::format(kUpFormat, 0)); + ret &= pipe_ios_->write(MAA_FMT::format(kUpFormat, 0)); if (!ret) { LogError << "failed to write"; return false; } - return ret; + return true; } bool MtouchHelper::touch_down(int contact, int x, int y, int pressure) { - if (!shell_handler_) { - LogError << "shell handler not ready"; + if (!pipe_ios_) { + LogError << "pipe_ios_ is nullptr"; return false; } @@ -181,20 +160,20 @@ bool MtouchHelper::touch_down(int contact, int x, int y, int pressure) LogInfo << VAR(contact) << VAR(x) << VAR(y) << VAR(touch_x) << VAR(touch_y); - bool ret = shell_handler_->write(MAA_FMT::format(kDownFormat, contact, touch_x, touch_y, pressure)); + bool ret = pipe_ios_->write(MAA_FMT::format(kDownFormat, contact, touch_x, touch_y, pressure)); if (!ret) { LogError << "failed to write"; return false; } - return ret; + return true; } bool MtouchHelper::touch_move(int contact, int x, int y, int pressure) { - if (!shell_handler_) { - LogError << "shell handler not ready"; + if (!pipe_ios_) { + LogError << "pipe_ios_ is nullptr"; return false; } @@ -202,33 +181,33 @@ bool MtouchHelper::touch_move(int contact, int x, int y, int pressure) LogInfo << VAR(contact) << VAR(x) << VAR(y) << VAR(touch_x) << VAR(touch_y); - bool ret = shell_handler_->write(MAA_FMT::format(kMoveFormat, contact, touch_x, touch_y, pressure)); + bool ret = pipe_ios_->write(MAA_FMT::format(kMoveFormat, contact, touch_x, touch_y, pressure)); if (!ret) { LogError << "failed to write"; return false; } - return ret; + return true; } bool MtouchHelper::touch_up(int contact) { - if (!shell_handler_) { - LogError << "shell handler not ready"; + if (!pipe_ios_) { + LogError << "pipe_ios_ is nullptr"; return false; } LogInfo << VAR(contact); - bool ret = shell_handler_->write(MAA_FMT::format(kUpFormat, contact)); + bool ret = pipe_ios_->write(MAA_FMT::format(kUpFormat, contact)); if (!ret) { LogError << "failed to write"; return false; } - return ret; + return true; } MAA_CTRL_UNIT_NS_END diff --git a/source/MaaAdbControlUnit/Input/MtouchHelper.h b/source/MaaAdbControlUnit/Input/MtouchHelper.h index fd86eb91b..8ef31396d 100644 --- a/source/MaaAdbControlUnit/Input/MtouchHelper.h +++ b/source/MaaAdbControlUnit/Input/MtouchHelper.h @@ -3,6 +3,7 @@ #include "Base/UnitBase.h" #include "Invoke/InvokeApp.h" +#include "Utils/IOStream/ChildPipeIOStream.h" MAA_CTRL_UNIT_NS_BEGIN @@ -29,7 +30,7 @@ class MtouchHelper : public TouchInputBase static constexpr std::string_view kMoveFormat = "m {} {} {} {}\nc\n"; static constexpr std::string_view kUpFormat = "u {}\nc\n"; - std::shared_ptr shell_handler_ = nullptr; + std::shared_ptr pipe_ios_ = nullptr; int screen_width_ = 0; int screen_height_ = 0; diff --git a/source/MaaAdbControlUnit/Input/TapInput.cpp b/source/MaaAdbControlUnit/Input/TapInput.cpp index 9920e47ba..918bdf1b1 100644 --- a/source/MaaAdbControlUnit/Input/TapInput.cpp +++ b/source/MaaAdbControlUnit/Input/TapInput.cpp @@ -39,10 +39,13 @@ bool TapTouchInput::click(int x, int y) merge_replacement({ { "{X}", std::to_string(x) }, { "{Y}", std::to_string(y) } }); - LogDebug << VAR(x) << VAR(y); - auto cmd_ret = command(click_argv_.gen(argv_replace_)); + auto argv_opt = click_argv_.gen(argv_replace_); + if (!argv_opt) { + return false; + } - return cmd_ret && cmd_ret->empty(); + auto output_opt = startup_and_read_pipe(*argv_opt); + return output_opt && output_opt->empty(); } bool TapTouchInput::swipe(int x1, int y1, int x2, int y2, int duration) @@ -54,9 +57,15 @@ bool TapTouchInput::swipe(int x1, int y1, int x2, int y2, int duration) { "{X2}", std::to_string(x2) }, { "{Y2}", std::to_string(y2) }, { "{DURATION}", duration ? std::to_string(duration) : std::string() } }); - auto cmd_ret = command(swipe_argv_.gen(argv_replace_)); - return cmd_ret.has_value() && cmd_ret.value().empty(); + auto argv_opt = swipe_argv_.gen(argv_replace_); + if (!argv_opt) { + return false; + } + + using namespace std::chrono_literals; + auto output_opt = startup_and_read_pipe(*argv_opt); + return output_opt && output_opt->empty(); } bool TapTouchInput::touch_down(int contact, int x, int y, int pressure) @@ -91,9 +100,14 @@ bool TapKeyInput::press_key(int key) LogInfo << VAR(key); merge_replacement({ { "{KEY}", std::to_string(key) } }); - auto cmd_ret = command(press_key_argv_.gen(argv_replace_)); - return cmd_ret.has_value() && cmd_ret.value().empty(); + auto argv_opt = press_key_argv_.gen(argv_replace_); + if (!argv_opt) { + return false; + } + + auto output_opt = startup_and_read_pipe(*argv_opt); + return output_opt && output_opt->empty(); } MAA_CTRL_UNIT_NS_END diff --git a/source/MaaAdbControlUnit/Input/TapInput.h b/source/MaaAdbControlUnit/Input/TapInput.h index 7f38dceb2..9805ebf91 100644 --- a/source/MaaAdbControlUnit/Input/TapInput.h +++ b/source/MaaAdbControlUnit/Input/TapInput.h @@ -25,8 +25,8 @@ class TapTouchInput : public TouchInputBase virtual bool touch_up(int contact) override; private: - Argv click_argv_; - Argv swipe_argv_; + ProcessArgvGenerator click_argv_; + ProcessArgvGenerator swipe_argv_; }; class TapKeyInput : public KeyInputBase @@ -41,7 +41,7 @@ class TapKeyInput : public KeyInputBase virtual bool press_key(int key) override; private: - Argv press_key_argv_; + ProcessArgvGenerator press_key_argv_; }; MAA_CTRL_UNIT_NS_END diff --git a/source/MaaAdbControlUnit/Invoke/InvokeApp.cpp b/source/MaaAdbControlUnit/Invoke/InvokeApp.cpp index b046b62c1..b209dad60 100644 --- a/source/MaaAdbControlUnit/Invoke/InvokeApp.cpp +++ b/source/MaaAdbControlUnit/Invoke/InvokeApp.cpp @@ -45,9 +45,10 @@ bool InvokeApp::parse(const json::value& config) bool InvokeApp::init(const std::string& force_temp) { - LogFunc; - tempname_ = force_temp.empty() ? now_filestem() : force_temp; + + LogDebug << VAR(tempname_); + return true; } @@ -55,25 +56,34 @@ std::optional> InvokeApp::abilist() { LogFunc; - auto cmd_ret = command(abilist_argv_.gen(argv_replace_)); + auto argv_opt = abilist_argv_.gen(argv_replace_); + if (!argv_opt) { + return std::nullopt; + } - if (!cmd_ret) { + auto output_opt = startup_and_read_pipe(*argv_opt); + if (!output_opt) { return std::nullopt; } - return string_split(*cmd_ret, ','); + return string_split(*output_opt, ','); } std::optional InvokeApp::sdk() { LogFunc; - auto cmd_ret = command(sdk_argv_.gen(argv_replace_)); + auto argv_opt = sdk_argv_.gen(argv_replace_); + if (!argv_opt) { + return std::nullopt; + } - if (!cmd_ret) { + auto output_opt = startup_and_read_pipe(*argv_opt); + if (!output_opt) { return std::nullopt; } - std::string& ret = *cmd_ret; + + std::string& ret = *output_opt; string_trim_(ret); if (!MAA_RNS::ranges::all_of(ret, [](char c) { return std::isdigit(c); })) { @@ -84,18 +94,18 @@ std::optional InvokeApp::sdk() bool InvokeApp::push(const std::filesystem::path& path) { - LogFunc; - - if (!io_ptr_) { - LogError << "io_ptr is nullptr"; - return false; - } + LogFunc << VAR(path); std::string absolute_path = path_to_crt_string(std::filesystem::absolute(path)); merge_replacement({ { "{BIN_PATH}", absolute_path }, { "{BIN_WORKING_FILE}", tempname_ } }); - auto cmd_ret = command(push_bin_argv_.gen(argv_replace_)); - if (!cmd_ret) { + auto argv_opt = push_bin_argv_.gen(argv_replace_); + if (!argv_opt) { + return false; + } + + auto output_opt = startup_and_read_pipe(*argv_opt); + if (!output_opt) { return false; } @@ -106,60 +116,61 @@ bool InvokeApp::chmod() { LogFunc; - if (!io_ptr_) { - LogError << "io_ptr is nullptr"; + merge_replacement({ { "{BIN_WORKING_FILE}", tempname_ } }); + + auto argv_opt = chmod_bin_argv_.gen(argv_replace_); + if (!argv_opt) { return false; } - merge_replacement({ { "{BIN_WORKING_FILE}", tempname_ } }); - auto cmd_ret = command(chmod_bin_argv_.gen(argv_replace_)); - - if (!cmd_ret) { + auto output_opt = startup_and_read_pipe(*argv_opt); + if (!output_opt) { return false; } return true; } -std::optional InvokeApp::invoke_bin_stdout(const std::string& extra) +std::optional InvokeApp::invoke_bin_and_read_pipe(const std::string& extra) { - LogFunc; + LogFunc << VAR(extra); merge_replacement({ { "{BIN_WORKING_FILE}", tempname_ }, { "{BIN_EXTRA_PARAMS}", extra } }); - LogInfo << invoke_bin_argv_.gen(argv_replace_); - return command(invoke_bin_argv_.gen(argv_replace_)); + + auto argv_opt = invoke_bin_argv_.gen(argv_replace_); + if (!argv_opt) { + return std::nullopt; + } + + return startup_and_read_pipe(*argv_opt); } -std::shared_ptr InvokeApp::invoke_bin(const std::string& extra, bool wants_stderr) +std::shared_ptr InvokeApp::invoke_bin(const std::string& extra) { - LogFunc; + LogFunc << VAR(extra); - if (!io_ptr_) { - LogError << "io_ptr is nullptr"; + merge_replacement({ { "{BIN_WORKING_FILE}", tempname_ }, { "{BIN_EXTRA_PARAMS}", extra } }); + + auto argv_opt = invoke_bin_argv_.gen(argv_replace_); + if (!argv_opt) { return nullptr; } - merge_replacement({ { "{BIN_WORKING_FILE}", tempname_ }, { "{BIN_EXTRA_PARAMS}", extra } }); - LogInfo << invoke_bin_argv_.gen(argv_replace_); - auto cmd_ret = io_ptr_->interactive_shell(invoke_bin_argv_.gen(argv_replace_), wants_stderr); - - return cmd_ret; + return std::make_shared(argv_opt->exec, argv_opt->args); } -std::shared_ptr InvokeApp::invoke_app(const std::string& package) +std::shared_ptr InvokeApp::invoke_app(const std::string& package) { - LogFunc; + LogFunc << VAR(package); - if (!io_ptr_) { - LogError << "io_ptr is nullptr"; + merge_replacement({ { "{APP_WORKING_FILE}", tempname_ }, { "{PACKAGE_NAME}", package } }); + + auto argv_opt = invoke_app_argv_.gen(argv_replace_); + if (!argv_opt) { return nullptr; } - merge_replacement({ { "{APP_WORKING_FILE}", tempname_ }, { "{PACKAGE_NAME}", package } }); - LogInfo << invoke_app_argv_.gen(argv_replace_); - auto cmd_ret = io_ptr_->interactive_shell(invoke_app_argv_.gen(argv_replace_), false); - - return cmd_ret; + return std::make_shared(argv_opt->exec, argv_opt->args); } MAA_CTRL_UNIT_NS_END diff --git a/source/MaaAdbControlUnit/Invoke/InvokeApp.h b/source/MaaAdbControlUnit/Invoke/InvokeApp.h index 5ccdd0b98..7329201e6 100644 --- a/source/MaaAdbControlUnit/Invoke/InvokeApp.h +++ b/source/MaaAdbControlUnit/Invoke/InvokeApp.h @@ -1,6 +1,7 @@ #pragma once #include "Base/UnitBase.h" +#include "Utils/IOStream/ChildPipeIOStream.h" #include @@ -22,17 +23,17 @@ class InvokeApp : public UnitBase bool push(const std::filesystem::path& path); bool chmod(); - std::optional invoke_bin_stdout(const std::string& extra); - std::shared_ptr invoke_bin(const std::string& extra, bool wants_stderr = false); - std::shared_ptr invoke_app(const std::string& package); + std::optional invoke_bin_and_read_pipe(const std::string& extra); + std::shared_ptr invoke_bin(const std::string& extra); + std::shared_ptr invoke_app(const std::string& package); private: - Argv abilist_argv_; - Argv sdk_argv_; - Argv push_bin_argv_; - Argv chmod_bin_argv_; - Argv invoke_bin_argv_; - Argv invoke_app_argv_; + ProcessArgvGenerator abilist_argv_; + ProcessArgvGenerator sdk_argv_; + ProcessArgvGenerator push_bin_argv_; + ProcessArgvGenerator chmod_bin_argv_; + ProcessArgvGenerator invoke_bin_argv_; + ProcessArgvGenerator invoke_app_argv_; std::string tempname_; }; diff --git a/source/MaaAdbControlUnit/Manager/ControlUnitMgr.cpp b/source/MaaAdbControlUnit/Manager/ControlUnitMgr.cpp index 042203d95..ba536e66c 100644 --- a/source/MaaAdbControlUnit/Manager/ControlUnitMgr.cpp +++ b/source/MaaAdbControlUnit/Manager/ControlUnitMgr.cpp @@ -238,25 +238,7 @@ bool ControlUnitMgr::parse(const json::value& config) return ret; } -void ControlUnitMgr::set_io(const std::shared_ptr& io_ptr) -{ - device_list_.set_io(io_ptr); - connection_.set_io(io_ptr); - device_info_.set_io(io_ptr); - activity_.set_io(io_ptr); - - if (touch_input_) { - touch_input_->set_io(io_ptr); - } - if (key_input_) { - key_input_->set_io(io_ptr); - } - if (screencap_) { - screencap_->set_io(io_ptr); - } -} - -void ControlUnitMgr::set_replacement(const std::map& replacement) +void ControlUnitMgr::set_replacement(const UnitBase::Replacement& replacement) { device_list_.set_replacement(replacement); connection_.set_replacement(replacement); diff --git a/source/MaaAdbControlUnit/Manager/ControlUnitMgr.h b/source/MaaAdbControlUnit/Manager/ControlUnitMgr.h index 0e1523710..378ea2c70 100644 --- a/source/MaaAdbControlUnit/Manager/ControlUnitMgr.h +++ b/source/MaaAdbControlUnit/Manager/ControlUnitMgr.h @@ -44,8 +44,7 @@ class ControlUnitMgr : public ControlUnitAPI public: bool parse(const json::value& config); - void set_io(const std::shared_ptr& io_ptr); - void set_replacement(const std::map& replacement); + void set_replacement(const UnitBase::Replacement& replacement); void set_touch_input_obj(std::shared_ptr obj) { touch_input_ = std::move(obj); } void set_key_input_obj(std::shared_ptr obj) { key_input_ = std::move(obj); } diff --git a/source/MaaAdbControlUnit/Platform/BoostIO.cpp b/source/MaaAdbControlUnit/Platform/BoostIO.cpp deleted file mode 100644 index a370087e9..000000000 --- a/source/MaaAdbControlUnit/Platform/BoostIO.cpp +++ /dev/null @@ -1,333 +0,0 @@ -#include "BoostIO.h" - -#include - -#include "Utils/Logger.h" -#include "Utils/Platform.h" - -#ifdef _WIN32 -#define BOOST_CREATE_NO_WINDOW , boost::process::windows::create_no_window -#else -#define BOOST_CREATE_NO_WINDOW -#endif - -MAA_CTRL_UNIT_NS_BEGIN - -BoostIO::BoostIO() : ios_(std::make_shared()), server_sock_(*ios_) -{ - support_socket_ = true; -} - -BoostIO::~BoostIO() {} - -int BoostIO::call_command(const std::vector& cmd, bool recv_by_socket, std::string& pipe_data, - std::string& sock_data, int64_t timeout) -{ - using namespace std::chrono; - - if (cmd.empty()) { - LogError << "cmd is empty"; - return -1; - } - - auto exec = boost::process::search_path(cmd.front()); - if (!std::filesystem::exists(exec)) { - LogError << "path not exists" << VAR(exec) << VAR(cmd.front()); - return -1; - } - auto args = boost::process::args(std::vector(cmd.begin() + 1, cmd.end())); - - boost::process::ipstream pout; - boost::process::child proc(exec, args, boost::process::std_in pout, - boost::process::std_err > boost::process::null BOOST_CREATE_NO_WINDOW); - - const auto start_time = std::chrono::steady_clock::now(); - auto terminate = [&]() -> bool { - return !proc.running() || (timeout && timeout < duration_since(start_time).count()); - }; - - if (recv_by_socket) { - read_sock_data(sock_data, terminate); - } - else { - read_pipe_data(pout, pipe_data, terminate); - } - - while (!terminate()) { - std::this_thread::yield(); - } - - if (proc.running()) { - LogWarn << "terminate" << VAR(exec); - proc.terminate(); - } - else { - proc.wait(); - } - - return proc.exit_code(); -} - -std::optional BoostIO::create_socket(const std::string& local_address) -{ - using namespace boost::asio::ip; - - tcp::endpoint endpoint(tcp::endpoint(address::from_string(local_address), 0)); - - server_sock_.open(endpoint.protocol()); - server_sock_.set_option(tcp::acceptor::reuse_address(true)); - server_sock_.bind(endpoint); - - server_sock_.listen(); - - tcp::endpoint ep = server_sock_.local_endpoint(); - return ep.port(); -} - -void BoostIO::close_socket() noexcept -{ - server_sock_.close(); -} - -std::shared_ptr BoostIO::tcp(const std::string& target, unsigned short port) -{ - using namespace boost::asio::ip; - - if (!ios_) { - LogError << "ios_ is nullptr"; - return nullptr; - } - - tcp::socket socket(*ios_); - - socket.connect(tcp::endpoint(address::from_string(target), port)); - - if (!socket.is_open()) { - LogError << "socket is not opened"; - return nullptr; - } - - return std::make_shared(ios_, std::move(socket)); -} - -std::shared_ptr BoostIO::interactive_shell(const std::vector& cmd, bool want_stderr) -{ - if (cmd.empty()) { - LogError << "cmd is empty"; - return nullptr; - } - - auto pin = std::make_shared(); - auto pout = std::make_shared(); - - std::shared_ptr proc = nullptr; - - auto exec = boost::process::search_path(cmd.front()); - if (!std::filesystem::exists(exec)) { - LogError << "path not exists" << VAR(exec) << VAR(cmd.front()); - return nullptr; - } - auto args = boost::process::args(std::vector(cmd.begin() + 1, cmd.end())); - - if (want_stderr) { - proc = std::make_shared( - exec, args, boost::process::std_in<*pin, boost::process::std_err> * pout BOOST_CREATE_NO_WINDOW); - } - else { - proc = std::make_shared( - exec, args, boost::process::std_in<*pin, boost::process::std_out> * pout BOOST_CREATE_NO_WINDOW); - } - - return std::make_shared(pout, pin, proc); -} - -void BoostIO::read_sock_data(std::string& data, std::function terminate) -{ - constexpr size_t kBufferSize = 128 * 1024; - auto buffer = std::make_unique(kBufferSize); - - auto socket = server_sock_.accept(); - if (!socket.is_open()) { - LogError << "socket is not opened"; - return; - } - boost::system::error_code error; - do { - memset(buffer.get(), 0, kBufferSize); - auto read_num = socket.read_some(boost::asio::mutable_buffer(buffer.get(), kBufferSize), error); - while (error != boost::asio::error::eof && read_num > 0) { - data.insert(data.end(), buffer.get(), buffer.get() + read_num); - read_num = socket.read_some(boost::asio::mutable_buffer(buffer.get(), kBufferSize), error); - } - } while (socket.is_open() && !terminate()); -} - -void BoostIO::read_pipe_data(boost::process::ipstream& pout, std::string& data, std::function terminate) -{ - constexpr size_t kBufferSize = 128 * 1024; - auto buffer = std::make_unique(kBufferSize); - - do { - if (pout.rdbuf()->in_avail() == 0) { - char ch; - pout.read(&ch, 1); - if (pout.gcount() != 1) { - break; - } - data.push_back(ch); - } - - memset(buffer.get(), 0, kBufferSize); - auto read_num = pout.readsome(buffer.get(), kBufferSize); - while (read_num > 0) { - data.insert(data.end(), buffer.get(), buffer.get() + read_num); - read_num = pout.readsome(buffer.get(), kBufferSize); - } - } while (!terminate()); -} - -IOHandlerBoostSocket::~IOHandlerBoostSocket() -{ - sock_.close(); -} - -bool IOHandlerBoostSocket::write(std::string_view data) -{ - if (!sock_.is_open()) { - LogError << "socket is not opened"; - return false; - } - sock_.write_some(boost::asio::buffer(data)); - return true; -} - -std::string IOHandlerBoostSocket::read(unsigned timeout_sec) -{ - auto start_time = std::chrono::steady_clock::now(); - auto check_timeout = [&](const auto& start_time) -> bool { - using namespace std::chrono_literals; - return std::chrono::steady_clock::now() - start_time < timeout_sec * 1s; - }; - - constexpr size_t bufferSize = 4096; - char buffer[bufferSize]; - - std::string result; - - boost::system::error_code error; - while (check_timeout(start_time) && sock_.is_open()) { - auto read_num = sock_.read_some(boost::asio::mutable_buffer(buffer, bufferSize), error); - while (error != boost::asio::error::eof && read_num > 0) { - result.insert(result.end(), buffer, buffer + read_num); - read_num = sock_.read_some(boost::asio::mutable_buffer(buffer, bufferSize), error); - } - break; - } - - return result; -} - -std::string IOHandlerBoostSocket::read(unsigned timeout_sec, size_t expect) -{ - auto start_time = std::chrono::steady_clock::now(); - auto check_timeout = [&](const auto& start_time) -> bool { - using namespace std::chrono_literals; - return std::chrono::steady_clock::now() - start_time < timeout_sec * 1s; - }; - - constexpr size_t kBufferSize = 4096; - char buffer[kBufferSize] = { 0 }; - - std::string result; - - boost::system::error_code error; - while (expect > result.size() && sock_.is_open() && check_timeout(start_time)) { - auto maxi = std::min(kBufferSize, expect - result.size()); - auto read_num = sock_.read_some(boost::asio::mutable_buffer(buffer, maxi), error); - while (error != boost::asio::error::eof && read_num > 0) { - result.insert(result.end(), buffer, buffer + read_num); - maxi = std::min(kBufferSize, expect - result.size()); - read_num = sock_.read_some(boost::asio::mutable_buffer(buffer, maxi), error); - } - } - - return result; -} - -IOHandlerBoostStream::~IOHandlerBoostStream() -{ - if (proc_->running()) { - proc_->terminate(); - } -} - -bool IOHandlerBoostStream::write(std::string_view data) -{ - if (!proc_->running()) { - return false; - } - - // std::cerr << "write " << std::string(data.data(), data.data() + data.size()) << std::endl; - in_->write(data.data(), data.size()); - in_->flush(); - return true; -} - -std::string IOHandlerBoostStream::read(unsigned timeout_sec) -{ - auto start_time = std::chrono::steady_clock::now(); - auto check_timeout = [&](const auto& start_time) -> bool { - using namespace std::chrono_literals; - return std::chrono::steady_clock::now() - start_time < timeout_sec * 1s; - }; - - constexpr size_t kBufferSize = 4096; - char buffer[kBufferSize] = { 0 }; - - std::string result; - - // dirty hack - if (out_->rdbuf()->in_avail() == 0) { - out_->read(buffer, 1); - result.push_back(buffer[0]); - } - - while (check_timeout(start_time)) { - auto read_num = out_->readsome(buffer, kBufferSize); - while (read_num > 0) { - result.insert(result.end(), buffer, buffer + read_num); - read_num = out_->readsome(buffer, kBufferSize); - } - break; - } - - return result; -} - -std::string IOHandlerBoostStream::read(unsigned timeout_sec, size_t expect) -{ - auto start_time = std::chrono::steady_clock::now(); - auto check_timeout = [&](const auto& start_time) -> bool { - using namespace std::chrono_literals; - return std::chrono::steady_clock::now() - start_time < timeout_sec * 1s; - }; - - constexpr size_t bufferSize = 4096; - char buffer[bufferSize]; - - std::string result; - - while (expect > result.size() && check_timeout(start_time)) { - auto maxi = std::min(bufferSize, expect - result.size()); - auto read_num = out_->readsome(buffer, maxi); - while (read_num > 0) { - result.insert(result.end(), buffer, buffer + read_num); - maxi = std::min(bufferSize, expect - result.size()); - read_num = out_->readsome(buffer, maxi); - } - } - - return result; -} - -MAA_CTRL_UNIT_NS_END diff --git a/source/MaaAdbControlUnit/Platform/BoostIO.h b/source/MaaAdbControlUnit/Platform/BoostIO.h deleted file mode 100644 index dc59dee27..000000000 --- a/source/MaaAdbControlUnit/Platform/BoostIO.h +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once - -#include - -#include "PlatformIO.h" -#include "Utils/Boost.hpp" -#include "Utils/NonCopyable.hpp" -#include "Utils/SingletonHolder.hpp" - -MAA_CTRL_UNIT_NS_BEGIN - -class BoostIO : public PlatformIO -{ -public: - BoostIO(); - virtual ~BoostIO() override; - - virtual int call_command(const std::vector& cmd, bool recv_by_socket, std::string& pipe_data, - std::string& sock_data, int64_t timeout) override; - - virtual std::optional create_socket(const std::string& local_address) override; - virtual void close_socket() noexcept override; - - virtual std::shared_ptr tcp(const std::string& target, unsigned short port) override; - virtual std::shared_ptr interactive_shell(const std::vector& cmd, - bool want_stderr) override; - -private: - void read_sock_data(std::string& data, std::function terminate); - void read_pipe_data(boost::process::ipstream& pout, std::string& data, std::function terminate); - - std::shared_ptr ios_; - boost::asio::ip::tcp::acceptor server_sock_; -}; - -class IOHandlerBoostSocket : public IOHandler, NonCopyable -{ -public: - IOHandlerBoostSocket(std::shared_ptr ios, boost::asio::ip::tcp::socket&& socket) - : ios_(ios), sock_(std::move(socket)) - {} - - virtual ~IOHandlerBoostSocket() override; - - virtual bool write(std::string_view data) override; - virtual std::string read(unsigned timeout_sec) override; - virtual std::string read(unsigned timeout_sec, size_t expect) override; - -private: - std::shared_ptr ios_; - boost::asio::ip::tcp::socket sock_; -}; - -class IOHandlerBoostStream : public IOHandler, NonCopyable -{ -public: - IOHandlerBoostStream(std::shared_ptr out, std::shared_ptr in, - std::shared_ptr proc) - : out_(out), in_(in), proc_(proc) - {} - - virtual ~IOHandlerBoostStream() override; - - virtual bool write(std::string_view data) override; - virtual std::string read(unsigned timeout_sec) override; - virtual std::string read(unsigned timeout_sec, size_t expect) override; - -private: - std::shared_ptr out_; - std::shared_ptr in_; - std::shared_ptr proc_; -}; - -MAA_CTRL_UNIT_NS_END diff --git a/source/MaaAdbControlUnit/Platform/PlatformFactory.h b/source/MaaAdbControlUnit/Platform/PlatformFactory.h deleted file mode 100644 index c2ded3a78..000000000 --- a/source/MaaAdbControlUnit/Platform/PlatformFactory.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include "Conf/Conf.h" - -#include "BoostIO.h" - -MAA_CTRL_UNIT_NS_BEGIN - -using NativeIO = BoostIO; - -class PlatformFactory -{ -public: - static std::shared_ptr create() { return std::make_shared(); } -}; - -MAA_CTRL_UNIT_NS_END diff --git a/source/MaaAdbControlUnit/Platform/PlatformIO.h b/source/MaaAdbControlUnit/Platform/PlatformIO.h deleted file mode 100644 index 46121b002..000000000 --- a/source/MaaAdbControlUnit/Platform/PlatformIO.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "Conf/Conf.h" - -MAA_CTRL_UNIT_NS_BEGIN - -class IOHandler; - -class PlatformIO -{ -public: - virtual ~PlatformIO() = default; - - virtual int call_command(const std::vector& cmd, bool recv_by_socket, std::string& pipe_data, - std::string& sock_data, int64_t timeout) = 0; - - virtual std::optional create_socket(const std::string& local_address) = 0; - virtual void close_socket() noexcept = 0; - - virtual std::shared_ptr tcp(const std::string& target, unsigned short port) = 0; - virtual std::shared_ptr interactive_shell(const std::vector& cmd, bool want_stderr) = 0; - - bool support_socket_ = false; -}; - -class IOHandler -{ -public: - virtual ~IOHandler() = default; - - virtual bool write(std::string_view data) = 0; - virtual std::string read(unsigned timeout_sec) = 0; - virtual std::string read(unsigned timeout_sec, size_t expect) = 0; -}; - -MAA_CTRL_UNIT_NS_END diff --git a/source/MaaAdbControlUnit/Screencap/Encode.cpp b/source/MaaAdbControlUnit/Screencap/Encode.cpp index 6b9ce7ab0..d56eee0ba 100644 --- a/source/MaaAdbControlUnit/Screencap/Encode.cpp +++ b/source/MaaAdbControlUnit/Screencap/Encode.cpp @@ -20,19 +20,18 @@ bool ScreencapEncode::init(int swidth, int sheight) std::optional ScreencapEncode::screencap() { - if (!io_ptr_) { - LogError << "io_ptr is nullptr"; + auto argv_opt = screencap_encode_argv_.gen(argv_replace_); + if (!argv_opt) { return std::nullopt; } - auto cmd_ret = command(screencap_encode_argv_.gen(argv_replace_)); - - if (!cmd_ret) { + auto output_opt = startup_and_read_pipe(*argv_opt); + if (!output_opt) { return std::nullopt; } return screencap_helper_.process_data( - cmd_ret.value(), std::bind(&ScreencapHelper::decode_png, &screencap_helper_, std::placeholders::_1)); + *output_opt, std::bind(&ScreencapHelper::decode_png, &screencap_helper_, std::placeholders::_1)); } MAA_CTRL_UNIT_NS_END diff --git a/source/MaaAdbControlUnit/Screencap/Encode.h b/source/MaaAdbControlUnit/Screencap/Encode.h index b60d6b455..0dd167c9d 100644 --- a/source/MaaAdbControlUnit/Screencap/Encode.h +++ b/source/MaaAdbControlUnit/Screencap/Encode.h @@ -21,7 +21,7 @@ class ScreencapEncode : public ScreencapBase virtual std::optional screencap() override; private: - Argv screencap_encode_argv_; + ProcessArgvGenerator screencap_encode_argv_; }; MAA_CTRL_UNIT_NS_END diff --git a/source/MaaAdbControlUnit/Screencap/EncodeToFile.cpp b/source/MaaAdbControlUnit/Screencap/EncodeToFile.cpp index 6adcbedb8..49be17015 100644 --- a/source/MaaAdbControlUnit/Screencap/EncodeToFile.cpp +++ b/source/MaaAdbControlUnit/Screencap/EncodeToFile.cpp @@ -29,27 +29,43 @@ bool ScreencapEncodeToFileAndPull::init(int swidth, int sheight) std::optional ScreencapEncodeToFileAndPull::screencap() { - if (!io_ptr_) { - LogError << "io_ptr is nullptr"; - return std::nullopt; - } - auto dst_path = std::filesystem::temp_directory_path() / now_filestem(); merge_replacement({ { "{TEMP_FILE}", tempname_ }, { "{DST_PATH}", path_to_crt_string(dst_path) } }); - auto cmd_ret = command(screencap_encode_to_file_argv_.gen(argv_replace_)); - if (!cmd_ret) { - return std::nullopt; + { + auto argv_opt = screencap_encode_to_file_argv_.gen(argv_replace_); + if (!argv_opt) { + return std::nullopt; + } + + auto output_opt = startup_and_read_pipe(*argv_opt); + if (!output_opt) { + return std::nullopt; + } + } + + { + auto argv_opt = pull_file_argv_.gen(argv_replace_); + if (!argv_opt) { + return std::nullopt; + } + + auto output_opt = startup_and_read_pipe(*argv_opt); + if (!output_opt) { + return std::nullopt; + } } - cmd_ret = command(pull_file_argv_.gen(argv_replace_)); + auto image = imread(dst_path); + std::filesystem::remove(dst_path); - if (!cmd_ret) { + if (image.empty()) { + LogError << "Failed to read image from" << dst_path; return std::nullopt; } - return imread(dst_path); + return image; } MAA_CTRL_UNIT_NS_END diff --git a/source/MaaAdbControlUnit/Screencap/EncodeToFile.h b/source/MaaAdbControlUnit/Screencap/EncodeToFile.h index 689c5a04f..f6fb4f709 100644 --- a/source/MaaAdbControlUnit/Screencap/EncodeToFile.h +++ b/source/MaaAdbControlUnit/Screencap/EncodeToFile.h @@ -21,8 +21,8 @@ class ScreencapEncodeToFileAndPull : public ScreencapBase virtual std::optional screencap() override; private: - Argv screencap_encode_to_file_argv_; - Argv pull_file_argv_; + ProcessArgvGenerator screencap_encode_to_file_argv_; + ProcessArgvGenerator pull_file_argv_; std::string tempname_; }; diff --git a/source/MaaAdbControlUnit/Screencap/FastestWay.cpp b/source/MaaAdbControlUnit/Screencap/FastestWay.cpp index d9a7d3b78..267a7ef21 100644 --- a/source/MaaAdbControlUnit/Screencap/FastestWay.cpp +++ b/source/MaaAdbControlUnit/Screencap/FastestWay.cpp @@ -115,13 +115,15 @@ bool ScreencapFastestWay::speed_test() // MinicapStream 是直接取数据,只取一次不准 const std::unordered_set kDropFirst = { Method::RawByNetcat, Method::MinicapStream }; - for (auto pair : units_) { + for (auto& pair : units_) { if (kDropFirst.contains(pair.first)) { + LogDebug << "Testing" << pair.first << "drop first"; if (!pair.second->screencap()) { continue; } } + LogDebug << "Testing" << pair.first; auto now = std::chrono::steady_clock::now(); if (pair.second->screencap()) { check(pair.first, now); diff --git a/source/MaaAdbControlUnit/Screencap/Minicap/MinicapBase.cpp b/source/MaaAdbControlUnit/Screencap/Minicap/MinicapBase.cpp index e939e9341..2aa39fe3d 100644 --- a/source/MaaAdbControlUnit/Screencap/Minicap/MinicapBase.cpp +++ b/source/MaaAdbControlUnit/Screencap/Minicap/MinicapBase.cpp @@ -38,29 +38,24 @@ bool MinicapBase::init(int swidth, int sheight) { LogFunc; - if (!io_ptr_) { - LogError << "io_ptr is nullptr"; - return false; - } - if (!binary_->init() || !library_->init("minicap.so")) { return false; } - auto archs = binary_->abilist(); - auto sdk = binary_->sdk(); + auto archs_opt = binary_->abilist(); + auto sdk_opt = binary_->sdk(); - if (!archs || !sdk) { + if (!archs_opt || !sdk_opt) { return false; } - auto arch_iter = MAA_RNS::ranges::find_first_of(*archs, arch_list_); - if (arch_iter == archs->end()) { + auto arch_iter = MAA_RNS::ranges::find_first_of(*archs_opt, arch_list_); + if (arch_iter == archs_opt->end()) { return false; } const std::string& target_arch = *arch_iter; - auto sdk_iter = MAA_RNS::ranges::find_if(sdk_list_, [sdk](int s) { return s <= sdk.value(); }); + auto sdk_iter = MAA_RNS::ranges::find_if(sdk_list_, [sdk_opt](int s) { return s <= sdk_opt.value(); }); if (sdk_iter == sdk_list_.end()) { return false; } diff --git a/source/MaaAdbControlUnit/Screencap/Minicap/MinicapDirect.cpp b/source/MaaAdbControlUnit/Screencap/Minicap/MinicapDirect.cpp index 8464a3cc2..58283996f 100644 --- a/source/MaaAdbControlUnit/Screencap/Minicap/MinicapDirect.cpp +++ b/source/MaaAdbControlUnit/Screencap/Minicap/MinicapDirect.cpp @@ -11,13 +11,14 @@ std::optional MinicapDirect::screencap() int width = screencap_helper_.get_w(); int height = screencap_helper_.get_h(); - auto res = binary_->invoke_bin_stdout(MAA_FMT::format("-P {}x{}@{}x{}/{} -s", width, height, width, height, 0)); + auto res = + binary_->invoke_bin_and_read_pipe(MAA_FMT::format("-P {}x{}@{}x{}/{} -s", width, height, width, height, 0)); if (!res) { return std::nullopt; } return screencap_helper_.process_data( - res.value(), std::bind(&ScreencapHelper::trunc_decode_jpg, &screencap_helper_, std::placeholders::_1)); + *res, std::bind(&ScreencapHelper::trunc_decode_jpg, &screencap_helper_, std::placeholders::_1)); } MAA_CTRL_UNIT_NS_END diff --git a/source/MaaAdbControlUnit/Screencap/Minicap/MinicapStream.cpp b/source/MaaAdbControlUnit/Screencap/Minicap/MinicapStream.cpp index 00fe443d8..0c3f8a14f 100644 --- a/source/MaaAdbControlUnit/Screencap/Minicap/MinicapStream.cpp +++ b/source/MaaAdbControlUnit/Screencap/Minicap/MinicapStream.cpp @@ -20,6 +20,9 @@ bool MinicapStream::parse(const json::value& config) static const json::array kDefaultForwardArgv = { "{ADB}", "-s", "{ADB_SERIAL}", "forward", "tcp:{FOWARD_PORT}", "localabstract:{LOCAL_SOCKET}", }; + static constexpr int kDefaultPort = 1313; + + port_ = config.get("prebuilt", "minicap", "stream", "port", kDefaultPort); return MinicapBase::parse(config) && parse_argv("ForwardSocket", config, kDefaultForwardArgv, forward_argv_); } @@ -32,43 +35,33 @@ bool MinicapStream::init(int swidth, int sheight) return false; } - // TODO: 也许可以允许配置? - merge_replacement({ { "{FOWARD_PORT}", "1313" }, { "{LOCAL_SOCKET}", "minicap" } }); - auto cmd_ret = command(forward_argv_.gen(argv_replace_)); + merge_replacement({ { "{FOWARD_PORT}", std::to_string(port_) }, { "{LOCAL_SOCKET}", "minicap" } }); + + auto argv_opt = forward_argv_.gen(argv_replace_); + if (!argv_opt) { + return false; + } - if (!cmd_ret) { + auto startup_output_opt = startup_and_read_pipe(*argv_opt); + if (!startup_output_opt) { return false; } uint32_t width = screencap_helper_.get_w(); uint32_t height = screencap_helper_.get_h(); - process_handle_ = binary_->invoke_bin(MAA_FMT::format("-P {}x{}@{}x{}/{}", width, height, width, height, 0)); + pipe_ios_ = binary_->invoke_bin(MAA_FMT::format("-P {}x{}@{}x{}/{}", width, height, width, height, 0)); - if (!process_handle_) { - LogError << "invoke screencap failed"; + if (!pipe_ios_) { + LogError << "pipe_ios_ is nullptr"; return false; } - bool ok = false; - - std::string buffer; - constexpr int kMaxTry = 50; - for (int i = 0; i < kMaxTry; ++i) { - auto res = process_handle_->read(5); - if (!res.empty()) { - LogDebug << "minicap stdout:" << res; - buffer.append(res); - } - if (buffer.find("Allocating") != std::string::npos) { - ok = true; - break; - } - using namespace std::chrono_literals; - std::this_thread::sleep_for(100ms); - } - if (!ok) { - LogError << "minicap stdout:" << buffer; + constexpr std::string_view kFlag = "Allocating"; + using namespace std::chrono_literals; + std::string invoke_output = pipe_ios_->read_until(kFlag, 10s); + if (!invoke_output.ends_with(kFlag)) { + LogError << "read_until failed" << VAR(invoke_output); return false; } @@ -79,11 +72,11 @@ bool MinicapStream::init(int swidth, int sheight) local = serial_host.substr(0, shp); } - LogInfo << "minicap try connect to:" << local; + LogInfo << "minicap try to connect" << VAR(local) << VAR(port_); - stream_handle_ = io_ptr_->tcp(local, 1313); - - if (!stream_handle_) { + ClientSockIOFactory io_factory(local, static_cast(port_)); + sock_ios_ = io_factory.connect(); + if (!sock_ios_) { return false; } @@ -92,10 +85,12 @@ bool MinicapStream::init(int swidth, int sheight) // TODO: 解决大端底的情况 MinicapHeader header; - if (!take_out(&header, sizeof(header))) { - LogError << "take_out header failed"; + auto data = read(sizeof(header)); + if (!data) { + LogError << "read header failed"; return false; } + header = *reinterpret_cast(data->data()); LogInfo << VAR(header.version) << VAR(header.size) << VAR(header.pid) << VAR(header.real_width) << VAR(header.real_height) << VAR(header.virt_width) << VAR(header.virt_height) << VAR(header.orientation) @@ -110,8 +105,8 @@ bool MinicapStream::init(int swidth, int sheight) return false; } - if (!take_out(nullptr, header.size - sizeof(header))) { - LogError << "take_out header failed"; + if (!read(header.size - sizeof(header))) { + LogError << "read header failed"; return false; } @@ -131,33 +126,15 @@ std::optional MinicapStream::screencap() return image_.empty() ? std::nullopt : std::make_optional(image_.clone()); } -bool MinicapStream::read_until(std::string& buffer, size_t size) +std::optional MinicapStream::read(size_t count) { - // LogFunc; - - using namespace std::chrono_literals; - auto start = std::chrono::steady_clock::now(); - - while (buffer.size() < size && duration_since(start) < 5s) { - auto ret = stream_handle_->read(2, size - buffer.size()); - buffer += std::move(ret); + if (!sock_ios_) { + LogError << "sock_ios_ is nullptr"; + return std::nullopt; } - return buffer.size() == size; -} - -bool MinicapStream::take_out(void* out, size_t size) -{ - // LogFunc; - - std::string buffer; - if (!read_until(buffer, size)) { - return false; - } - if (out) { - memcpy(out, buffer.data(), size); - } - return true; + using namespace std::chrono_literals; + return sock_ios_->read_some(count, 1s); } void MinicapStream::working_thread() @@ -165,23 +142,24 @@ void MinicapStream::working_thread() LogFunc; while (!quit_) { - uint32_t size = 0; - if (!take_out(&size, 4)) { - LogError << "take_out size failed"; + auto size_opt = read(4); + if (!size_opt) { + LogError << "read size failed"; std::unique_lock locker(mutex_); image_ = cv::Mat(); continue; } + auto size = *reinterpret_cast(size_opt->data()); - std::string buffer; - if (!read_until(buffer, size)) { - LogError << "read_until size failed"; + auto data_opt = read(size); + if (!data_opt) { + LogError << "read data failed"; std::unique_lock locker(mutex_); image_ = cv::Mat(); continue; } - auto img_opt = screencap_helper_.decode_jpg(buffer); + auto img_opt = screencap_helper_.decode_jpg(*data_opt); if (!img_opt || img_opt->empty()) { LogError << "decode jpg failed"; diff --git a/source/MaaAdbControlUnit/Screencap/Minicap/MinicapStream.h b/source/MaaAdbControlUnit/Screencap/Minicap/MinicapStream.h index 324711bf3..cc44be498 100644 --- a/source/MaaAdbControlUnit/Screencap/Minicap/MinicapStream.h +++ b/source/MaaAdbControlUnit/Screencap/Minicap/MinicapStream.h @@ -5,6 +5,9 @@ #include #include +#include "Utils/IOStream/ChildPipeIOStream.h" +#include "Utils/IOStream/SockIOStream.h" + MAA_CTRL_UNIT_NS_BEGIN class MinicapStream : public MinicapBase @@ -23,11 +26,12 @@ class MinicapStream : public MinicapBase virtual std::optional screencap() override; private: - bool read_until(std::string& buffer, size_t size); - bool take_out(void* out, size_t size); + std::optional read(size_t count); + void working_thread(); - Argv forward_argv_; + ProcessArgvGenerator forward_argv_; + int port_ = 0; bool quit_ = true; std::mutex mutex_; @@ -35,8 +39,8 @@ class MinicapStream : public MinicapBase std::condition_variable cond_; std::thread pull_thread_; - std::shared_ptr process_handle_; - std::shared_ptr stream_handle_; + std::shared_ptr pipe_ios_ = nullptr; + std::shared_ptr sock_ios_ = nullptr; }; MAA_CTRL_UNIT_NS_END diff --git a/source/MaaAdbControlUnit/Screencap/RawByNetcat.cpp b/source/MaaAdbControlUnit/Screencap/RawByNetcat.cpp index cdf751018..28ce6516a 100644 --- a/source/MaaAdbControlUnit/Screencap/RawByNetcat.cpp +++ b/source/MaaAdbControlUnit/Screencap/RawByNetcat.cpp @@ -1,5 +1,7 @@ #include "RawByNetcat.h" +#include "Utils/IOStream/ChildPipeIOStream.h" +#include "Utils/IOStream/SockIOStream.h" #include "Utils/Logger.h" MAA_CTRL_UNIT_NS_BEGIN @@ -22,16 +24,11 @@ bool ScreencapRawByNetcat::init(int swidth, int sheight) { LogFunc; - if (!io_ptr_) { - LogError << "io_ptr is nullptr"; + auto addr_opt = request_netcat_address(); + if (!addr_opt) { return false; } - - auto addr = request_netcat_address(); - if (!addr) { - return false; - } - netcat_address_ = addr.value(); + netcat_address_ = std::move(*addr_opt); auto serial_host = argv_replace_["{ADB_SERIAL}"]; auto shp = serial_host.find(':'); @@ -40,63 +37,80 @@ bool ScreencapRawByNetcat::init(int swidth, int sheight) local = serial_host.substr(0, shp); } - auto prt = io_ptr_->create_socket(local); - if (!prt) { - return false; - } - netcat_port_ = prt.value(); + io_factory_ = std::make_shared(local, 0); return set_wh(swidth, sheight); } void ScreencapRawByNetcat::deinit() { - if (netcat_port_ && io_ptr_) { - io_ptr_->close_socket(); - } - + io_factory_ = nullptr; netcat_address_.clear(); - netcat_port_ = 0; } std::optional ScreencapRawByNetcat::screencap() { - if (!io_ptr_) { - LogError << "io_ptr is nullptr"; + if (!io_factory_) { + return std::nullopt; + } + + auto port = io_factory_->port(); + merge_replacement({ { "{NETCAT_ADDRESS}", netcat_address_ }, { "{NETCAT_PORT}", std::to_string(port) } }); + + auto argv_opt = screencap_raw_by_netcat_argv_.gen(argv_replace_); + if (!argv_opt) { return std::nullopt; } + auto start_time = std::chrono::steady_clock::now(); + + auto& argv = *argv_opt; - merge_replacement({ { "{NETCAT_ADDRESS}", netcat_address_ }, { "{NETCAT_PORT}", std::to_string(netcat_port_) } }); - constexpr int kTimeout = 2000; // netcat 能用的时候一般都很快,但连不上的时候会一直卡着,所以超时设短一点 - auto cmd_ret = command(screencap_raw_by_netcat_argv_.gen(argv_replace_), true, kTimeout); + ChildPipeIOStream child(argv.exec, argv.args); - if (!cmd_ret) { + auto ios = io_factory_->accept(); + if (!ios) { + LogError << "accept failed" << VAR(argv.exec) << VAR(argv.args); return std::nullopt; } + using namespace std::chrono_literals; + // netcat 能用的时候一般都很快,但连不上的时候会一直卡着,所以超时设短一点 + std::string output = ios->read(2s); + ios->release(); + + auto duration = duration_since(start_time); + LogDebug << VAR(argv.exec) << VAR(argv.args) << VAR(output.size()) << VAR(duration); + + if (!child.release()) { + LogWarn << "child return error" << VAR(argv.exec) << VAR(argv.args); + } + return screencap_helper_.process_data( - cmd_ret.value(), std::bind(&ScreencapHelper::decode_raw, &screencap_helper_, std::placeholders::_1)); + output, std::bind(&ScreencapHelper::decode_raw, &screencap_helper_, std::placeholders::_1)); } std::optional ScreencapRawByNetcat::request_netcat_address() { LogFunc; - auto cmd_ret = command(netcat_address_argv_.gen(argv_replace_)); + auto argv_opt = netcat_address_argv_.gen(argv_replace_); + if (!argv_opt) { + return std::nullopt; + } - if (!cmd_ret) { + auto output_opt = startup_and_read_pipe(*argv_opt); + if (!output_opt) { return std::nullopt; } - auto ip = cmd_ret.value(); + auto& ip = *output_opt; auto idx = ip.find(' '); - if (idx != std::string::npos) { - return ip.substr(0, idx); - } - else { + if (idx == std::string::npos) { return std::nullopt; } + + return ip.substr(0, idx); } MAA_CTRL_UNIT_NS_END diff --git a/source/MaaAdbControlUnit/Screencap/RawByNetcat.h b/source/MaaAdbControlUnit/Screencap/RawByNetcat.h index bd3c6e9b3..d29875968 100644 --- a/source/MaaAdbControlUnit/Screencap/RawByNetcat.h +++ b/source/MaaAdbControlUnit/Screencap/RawByNetcat.h @@ -3,6 +3,7 @@ #include "Base/UnitBase.h" #include "ScreencapHelper.h" +#include "Utils/IOStream/SockIOStream.h" MAA_CTRL_UNIT_NS_BEGIN @@ -23,11 +24,13 @@ class ScreencapRawByNetcat : public ScreencapBase private: std::optional request_netcat_address(); - Argv screencap_raw_by_netcat_argv_; - Argv netcat_address_argv_; + ProcessArgvGenerator screencap_raw_by_netcat_argv_; + ProcessArgvGenerator netcat_address_argv_; std::string netcat_address_; - uint16_t netcat_port_ = 0; + + std::shared_ptr io_factory_ = nullptr; + std::shared_ptr sock_io_ = nullptr; }; MAA_CTRL_UNIT_NS_END diff --git a/source/MaaAdbControlUnit/Screencap/RawWithGzip.cpp b/source/MaaAdbControlUnit/Screencap/RawWithGzip.cpp index 29206b1f2..d1ce3f674 100644 --- a/source/MaaAdbControlUnit/Screencap/RawWithGzip.cpp +++ b/source/MaaAdbControlUnit/Screencap/RawWithGzip.cpp @@ -20,19 +20,18 @@ bool ScreencapRawWithGzip::init(int swidth, int sheight) std::optional ScreencapRawWithGzip::screencap() { - if (!io_ptr_) { - LogError << "io_ptr is nullptr"; + auto argv_opt = screencap_raw_with_gzip_argv_.gen(argv_replace_); + if (!argv_opt) { return std::nullopt; } - auto cmd_ret = command(screencap_raw_with_gzip_argv_.gen(argv_replace_)); - - if (!cmd_ret) { + auto output_opt = startup_and_read_pipe(*argv_opt); + if (!output_opt) { return std::nullopt; } return screencap_helper_.process_data( - cmd_ret.value(), std::bind(&ScreencapHelper::decode_gzip, &screencap_helper_, std::placeholders::_1)); + *output_opt, std::bind(&ScreencapHelper::decode_gzip, &screencap_helper_, std::placeholders::_1)); } MAA_CTRL_UNIT_NS_END diff --git a/source/MaaAdbControlUnit/Screencap/RawWithGzip.h b/source/MaaAdbControlUnit/Screencap/RawWithGzip.h index c228ab898..1e8920156 100644 --- a/source/MaaAdbControlUnit/Screencap/RawWithGzip.h +++ b/source/MaaAdbControlUnit/Screencap/RawWithGzip.h @@ -21,7 +21,7 @@ class ScreencapRawWithGzip : public ScreencapBase virtual std::optional screencap() override; private: - Argv screencap_raw_with_gzip_argv_; + ProcessArgvGenerator screencap_raw_with_gzip_argv_; }; MAA_CTRL_UNIT_NS_END diff --git a/source/MaaAdbControlUnit/Screencap/ScreencapHelper.cpp b/source/MaaAdbControlUnit/Screencap/ScreencapHelper.cpp index 69df69492..297a0191f 100644 --- a/source/MaaAdbControlUnit/Screencap/ScreencapHelper.cpp +++ b/source/MaaAdbControlUnit/Screencap/ScreencapHelper.cpp @@ -152,10 +152,7 @@ std::optional ScreencapHelper::trunc_decode_jpg(const std::string& buff { auto pos = buffer.find("\xFF\xD8\xFF"); auto truncbuf = buffer.substr(pos); - if (!check_head_tail(truncbuf, "\xFF\xD8\xFF", "\xFF\xD9")) { - return std::nullopt; - } - return decode(truncbuf); + return decode_jpg(truncbuf); } std::optional ScreencapHelper::decode_jpg(const std::string& buffer) diff --git a/source/MaaFramework/API/MaaBuffer.cpp b/source/MaaFramework/API/MaaBuffer.cpp index 2bd5b40ed..2dd8c165b 100644 --- a/source/MaaFramework/API/MaaBuffer.cpp +++ b/source/MaaFramework/API/MaaBuffer.cpp @@ -97,7 +97,7 @@ void MaaDestroyImageBuffer(MaaImageBufferHandle handle) delete handle; } -void* MaaGetImageRawData(MaaImageBufferHandle handle) +MaaImageRawData MaaGetImageRawData(MaaImageBufferHandle handle) { if (!handle) { LogError << "handle is null"; @@ -176,7 +176,7 @@ MaaBool MaaSetImageRawData(MaaImageBufferHandle handle, MaaImageRawData data, in return true; } -uint8_t* MaaGetImageEncoded(MaaImageBufferHandle handle) +MaaImageEncodedData MaaGetImageEncoded(MaaImageBufferHandle handle) { if (!handle) { LogError << "handle is null"; @@ -268,11 +268,25 @@ int32_t MaaGetRectH(MaaRectHandle handle) return handle->height; } +MaaBool MaaSetRect(MaaRectHandle handle, int32_t x, int32_t y, int32_t w, int32_t h) +{ + if (!handle) { + LogError << "handle is null"; + return false; + } + + handle->x = x; + handle->y = y; + handle->width = w; + handle->height = h; + return true; +} + MaaBool MaaSetRectX(MaaRectHandle handle, int32_t value) { if (!handle) { LogError << "handle is null"; - return 0; + return false; } handle->x = value; @@ -283,7 +297,7 @@ MaaBool MaaSetRectY(MaaRectHandle handle, int32_t value) { if (!handle) { LogError << "handle is null"; - return 0; + return false; } handle->y = value; @@ -294,7 +308,7 @@ MaaBool MaaSetRectW(MaaRectHandle handle, int32_t value) { if (!handle) { LogError << "handle is null"; - return 0; + return false; } handle->width = value; @@ -305,7 +319,7 @@ MaaBool MaaSetRectH(MaaRectHandle handle, int32_t value) { if (!handle) { LogError << "handle is null"; - return 0; + return false; } handle->height = value; diff --git a/source/MaaRpc/implement/Utility.cpp b/source/MaaRpc/implement/Utility.cpp index 3779bbf79..9301ba47b 100644 --- a/source/MaaRpc/implement/Utility.cpp +++ b/source/MaaRpc/implement/Utility.cpp @@ -2,20 +2,12 @@ #include "MaaFramework/MaaAPI.h" #include "Macro.h" #include "Utils/Logger.h" - -#include -#include +#include "Utils/Time.hpp" MAA_RPC_NS_BEGIN using namespace ::grpc; -auto uuid_generator = boost::uuids::random_generator(); -std::string make_uuid() -{ - return boost::uuids::to_string(uuid_generator()); -} - void callback_impl(MaaStringView msg, MaaStringView detail, MaaCallbackTransparentArg arg) { ::maarpc::Callback cb; diff --git a/source/MaaRpc/implement/Utility.h b/source/MaaRpc/implement/Utility.h index 6f1f5f2c8..42c239e63 100644 --- a/source/MaaRpc/implement/Utility.h +++ b/source/MaaRpc/implement/Utility.h @@ -2,6 +2,7 @@ #include "AtomicMap.h" #include "MaaFramework/MaaDef.h" +#include "Utils/Uuid.h" #include "generated/utility.grpc.pb.h" #include @@ -38,7 +39,6 @@ class UtilityImpl final : public ::maarpc::Utility::Service AtomicMap> states_; }; -extern std::string make_uuid(); extern void callback_impl(MaaStringView msg, MaaStringView detail, MaaCallbackTransparentArg arg); MAA_RPC_NS_END diff --git a/source/MaaToolKit/API/MaaToolKitExecAgent.cpp b/source/MaaToolKit/API/MaaToolKitExecAgent.cpp new file mode 100644 index 000000000..e2ff5d765 --- /dev/null +++ b/source/MaaToolKit/API/MaaToolKitExecAgent.cpp @@ -0,0 +1,123 @@ +#include "MaaToolKit/ExecAgent/MaaToolKitExecAgent.h" + +#include + +#include + +#include "ExecAgent/ActionExecAgent.h" +#include "ExecAgent/RecognizerExecAgent.h" +#include "Utils/Logger.h" + +using namespace MAA_TOOLKIT_NS; + +enum class ExecutorType +{ + Recognizer, + Action, +}; +std::ostream& operator<<(std::ostream& os, ExecutorType type) +{ + switch (type) { + case ExecutorType::Recognizer: + os << "Recognizer"; + break; + case ExecutorType::Action: + os << "Action"; + break; + } + return os; +} + +MaaBool RegisterExecutor(ExecutorType type, MaaInstanceHandle handle, MaaStringView name, MaaStringView exec_path, + MaaStringView exec_param_json, MaaToolKitExecAgentArgvTransferMode argv_mode) +{ + LogFunc << VAR(type) << VAR_VOIDP(handle) << VAR(name) << VAR(exec_path) << VAR(exec_param_json) << VAR(argv_mode); + + if (!handle) { + LogError << "handle is null"; + return false; + } + if (std::string_view(name).empty()) { + LogError << "name is empty"; + return false; + } + + auto path = MAA_NS::path(exec_path); + + auto params_opt = json::parse(exec_param_json); + if (!params_opt) { + LogError << "exec param json parse failed:" << exec_param_json; + return false; + } + if (!params_opt->is_array() || !params_opt->all()) { + LogError << "exec param json is not array of string:" << exec_param_json; + return false; + } + auto params = params_opt->to_vector(); + + TextTransferMode text_mode = + static_cast(MaaToolKitExecAgentArgvTransferMode_Text_Mask & argv_mode); + ImageTransferMode image_mode = + static_cast((MaaToolKitExecAgentArgvTransferMode_Image_Mask & argv_mode) >> 8); + + switch (type) { + case ExecutorType::Recognizer: + return RecognizerExecAgent::get_instance().register_executor( // + handle, name, std::move(path), std::move(params), text_mode, image_mode); + case ExecutorType::Action: + return ActionExecAgent::get_instance().register_executor( // + handle, name, std::move(path), std::move(params), text_mode, image_mode); + } + + return false; +} + +MaaBool UnregisterExecutor(ExecutorType type, MaaInstanceHandle handle, MaaStringView name) +{ + LogFunc << VAR(type) << VAR_VOIDP(handle) << VAR(name); + + if (!handle) { + LogError << "handle is null"; + return false; + } + if (std::string_view(name).empty()) { + LogError << "name is empty"; + return false; + } + + switch (type) { + case ExecutorType::Recognizer: + return RecognizerExecAgent::get_instance().unregister_executor(handle, name); + + case ExecutorType::Action: + return ActionExecAgent::get_instance().unregister_executor(handle, name); + } + + return false; +} + +MaaBool MaaToolKitRegisterCustomRecognizerExecutor( // + MaaInstanceHandle handle, MaaStringView recognizer_name, MaaStringView recognizer_exec_path, + MaaStringView recognizer_exec_param_json, MaaToolKitExecAgentArgvTransferMode argv_mode) +{ + return RegisterExecutor(ExecutorType::Recognizer, handle, recognizer_name, recognizer_exec_path, + recognizer_exec_param_json, argv_mode); +} + +MaaBool MaaToolKitUnregisterCustomRecognizerExecutor(MaaInstanceHandle handle, MaaStringView recognizer_name) +{ + return UnregisterExecutor(ExecutorType::Recognizer, handle, recognizer_name); +} + +MaaBool MaaToolKitRegisterCustomActionExecutor( // + MaaInstanceHandle handle, MaaStringView action_name, MaaStringView action_exec_path, + MaaStringView action_exec_param_json, MaaToolKitExecAgentArgvTransferMode argv_mode) +{ + return RegisterExecutor(ExecutorType::Action, handle, action_name, action_exec_path, action_exec_param_json, + argv_mode); +} + +MaaBool MaaToolKitUnregisterCustomActionExecutor(MaaInstanceHandle handle, MaaStringView action_name) +{ + return UnregisterExecutor(ExecutorType::Action, handle, action_name); +} diff --git a/source/MaaToolKit/AdbDevice/DeviceMgr.cpp b/source/MaaToolKit/AdbDevice/DeviceMgr.cpp index f93f936f2..fe2e4f163 100644 --- a/source/MaaToolKit/AdbDevice/DeviceMgr.cpp +++ b/source/MaaToolKit/AdbDevice/DeviceMgr.cpp @@ -109,13 +109,7 @@ MaaAdbControllerType DeviceMgr::check_adb_controller_type(const std::filesystem: // TODO: 判断触控方式是否支持 constexpr MaaAdbControllerType kInputType = MaaAdbControllerType_Input_Preset_Maatouch; - -#ifdef MAA_DEBUG - constexpr MaaAdbControllerType kScreencapType = MaaAdbControllerType_Screencap_FastestWay; -#else - // TODO: speed test constexpr MaaAdbControllerType kScreencapType = MaaAdbControllerType_Screencap_FastestWay; -#endif return kInputType | kScreencapType; } diff --git a/source/MaaToolKit/CMakeLists.txt b/source/MaaToolKit/CMakeLists.txt index 1ea6a3dc7..c8d66af9b 100644 --- a/source/MaaToolKit/CMakeLists.txt +++ b/source/MaaToolKit/CMakeLists.txt @@ -13,7 +13,7 @@ target_compile_definitions(MaaToolKit PRIVATE MAA_TOOLKIT_EXPORTS) target_link_libraries( MaaToolKit PUBLIC MaaFramework - PRIVATE MaaUtils LibraryHolder HeaderOnlyLibraries Boost::system) + PRIVATE MaaUtils LibraryHolder HeaderOnlyLibraries Boost::system ${OpenCV_LIBS}) add_dependencies(MaaToolKit MaaFramework MaaUtils LibraryHolder) diff --git a/source/MaaToolKit/ExecAgent/ActionExecAgent.cpp b/source/MaaToolKit/ExecAgent/ActionExecAgent.cpp new file mode 100644 index 000000000..9bddbd908 --- /dev/null +++ b/source/MaaToolKit/ExecAgent/ActionExecAgent.cpp @@ -0,0 +1,81 @@ +#include "ActionExecAgent.h" + +#include + +#include "MaaFramework/MaaAPI.h" +#include "Utils/Logger.h" + +MAA_TOOLKIT_NS_BEGIN + +ActionExecAgent::ActionExecAgent() +{ + custom_action_.run = &ActionExecAgent::maa_api_run; + custom_action_.stop = &ActionExecAgent::maa_api_stop; +} + +bool ActionExecAgent::register_for_maa_inst(MaaInstanceHandle handle, std::string_view name, ExecData& executor) +{ + return MaaRegisterCustomAction(handle, name.data(), &custom_action_, reinterpret_cast(&executor)); +} + +bool ActionExecAgent::unregister_for_maa_inst(MaaInstanceHandle handle, std::string_view name) +{ + return MaaUnregisterCustomAction(handle, name.data()); +} + +bool ActionExecAgent::run(ExecData& data, MaaSyncContextHandle sync_context, std::string_view task_name, + std::string_view custom_action_param, MaaRectHandle cur_box, std::string_view cur_rec_detail) +{ + LogFunc << VAR(data.name) << VAR_VOIDP(sync_context) << VAR(task_name) << VAR(custom_action_param) + << VAR_VOIDP(cur_box) << VAR(cur_rec_detail); + + std::string handle_arg = arg_cvt_.sync_context_to_arg(sync_context); + std::string box_arg = json::array({ cur_box->x, cur_box->y, cur_box->width, cur_box->height }).to_string(); + + std::vector extra_args = { handle_arg, std::string(task_name), std::string(custom_action_param), + box_arg, std::string(cur_rec_detail) }; + std::vector args = data.exec_args; + args.insert(args.end(), std::make_move_iterator(extra_args.begin()), std::make_move_iterator(extra_args.end())); + + auto output_opt = run_executor(data.exec_path, args, data.text_mode, data.image_mode); + if (!output_opt) { + LogError << "run_executor failed" << VAR(data.exec_path) << VAR(data.exec_args); + return false; + } + + return true; +} + +void ActionExecAgent::stop(ExecData& data) +{ + LogFunc << VAR(data.name); + + // TODO +} + +MaaBool ActionExecAgent::maa_api_run(MaaSyncContextHandle sync_context, MaaStringView task_name, + MaaStringView custom_action_param, MaaRectHandle cur_box, + MaaStringView cur_rec_detail, MaaTransparentArg action_arg) +{ + auto* data = static_cast(action_arg); + if (!data) { + LogError << "data is nullptr" << VAR(action_arg); + return false; + } + + return get_instance().run( // + *data, sync_context, task_name, custom_action_param, cur_box, cur_rec_detail); +} + +void ActionExecAgent::maa_api_stop(MaaTransparentArg action_arg) +{ + auto* data = static_cast(action_arg); + if (!data) { + LogError << "data is nullptr" << VAR(action_arg); + return; + } + + get_instance().stop(*data); +} + +MAA_TOOLKIT_NS_END diff --git a/source/MaaToolKit/ExecAgent/ActionExecAgent.h b/source/MaaToolKit/ExecAgent/ActionExecAgent.h new file mode 100644 index 000000000..fda3b65cb --- /dev/null +++ b/source/MaaToolKit/ExecAgent/ActionExecAgent.h @@ -0,0 +1,37 @@ +#pragma once + +#include "Conf/Conf.h" +#include "ExecAgentBase.h" + +#include "MaaFramework/Task/MaaCustomAction.h" +#include "Utils/SingletonHolder.hpp" + +MAA_TOOLKIT_NS_BEGIN + +class ActionExecAgent final : public ExecAgentBase, public SingletonHolder +{ +public: + ActionExecAgent(); + virtual ~ActionExecAgent() = default; + +private: // from ExecAgentBase + virtual bool register_for_maa_inst(MaaInstanceHandle handle, std::string_view name, ExecData& executor) override; + virtual bool unregister_for_maa_inst(MaaInstanceHandle handle, std::string_view name) override; + +private: + bool run(ExecData& data, MaaSyncContextHandle sync_context, std::string_view task_name, + std::string_view custom_action_param, MaaRectHandle cur_box, std::string_view cur_rec_detail); + void stop(ExecData& data); + +private: + // for MaaCustomActionAPI + static MaaBool maa_api_run( // + MaaSyncContextHandle sync_context, MaaStringView task_name, MaaStringView custom_action_param, + MaaRectHandle cur_box, MaaStringView cur_rec_detail, MaaTransparentArg action_arg); + static void maa_api_stop(MaaTransparentArg action_arg); + +private: + MaaCustomActionAPI custom_action_ {}; +}; + +MAA_TOOLKIT_NS_END diff --git a/source/MaaToolKit/ExecAgent/ExecAgentBase.cpp b/source/MaaToolKit/ExecAgent/ExecAgentBase.cpp new file mode 100644 index 000000000..9c8b39910 --- /dev/null +++ b/source/MaaToolKit/ExecAgent/ExecAgentBase.cpp @@ -0,0 +1,92 @@ +#include "ExecAgentBase.h" + +#include "MaaFramework/MaaAPI.h" +#include "Utils/IOStream/ChildPipeIOStream.h" +#include "Utils/Logger.h" + +MAA_TOOLKIT_NS_BEGIN + +bool ExecAgentBase::register_executor(MaaInstanceHandle handle, std::string_view name, std::filesystem::path exec_path, + std::vector exec_args, TextTransferMode text_mode, + ImageTransferMode image_mode) +{ + LogFunc << VAR_VOIDP(handle) << VAR(name) << VAR(exec_path) << VAR(exec_args) << VAR(text_mode) << VAR(image_mode); + + auto [iter, inserted] = exec_data_.insert_or_assign( // + std::string(name), ExecData { + .name = std::string(name), + .exec_path = std::move(exec_path), + .exec_args = std::move(exec_args), + .text_mode = text_mode, + .image_mode = image_mode, + }); + if (!inserted || iter == exec_data_.end()) { + LogError << "insert failed" << VAR(name); + } + + bool registered = register_for_maa_inst(handle, name, iter->second); + if (!registered) { + LogError << "register failed" << VAR(name); + exec_data_.erase(iter); + return false; + } + + return true; +} + +bool ExecAgentBase::unregister_executor(MaaInstanceHandle handle, std::string_view name) +{ + LogFunc << VAR_VOIDP(handle) << VAR(name); + + bool ret = unregister_for_maa_inst(handle, name); + ret &= exec_data_.erase(std::string(name)) > 0; + + return ret; +} + +std::optional ExecAgentBase::run_executor(const std::filesystem::path& exec_path, + const std::vector& exec_args, + TextTransferMode text_mode, ImageTransferMode image_mode) +{ + auto searched_path = boost::process::search_path(exec_path); + if (!std::filesystem::exists(searched_path)) { + LogError << "path not exists" << VAR(searched_path); + return std::nullopt; + } + + ChildPipeIOStream child(searched_path, exec_args); + + switch (text_mode) { + case TextTransferMode::StdIO: + return handle_ipc(child, image_mode); + + case TextTransferMode::FileIO: + LogError << "not implemented"; + return std::nullopt; + + default: + LogError << "not implemented"; + return std::nullopt; + } +} + +std::optional ExecAgentBase::handle_ipc(IOStream& ios, ImageTransferMode image_mode) +{ + std::ignore = image_mode; + + while (ios.is_open()) { + std::string line = ios.read_until("\n"); + LogInfo << "read line:" << line; + + // TODO + } + + if (!ios.release()) { + return std::nullopt; + } + + // TODO + return {}; +} + +MAA_TOOLKIT_NS_END diff --git a/source/MaaToolKit/ExecAgent/ExecAgentBase.h b/source/MaaToolKit/ExecAgent/ExecAgentBase.h new file mode 100644 index 000000000..2856b1d6b --- /dev/null +++ b/source/MaaToolKit/ExecAgent/ExecAgentBase.h @@ -0,0 +1,43 @@ +#pragma once + +#include "Conf/Conf.h" + +#include +#include +#include + +#include "ExecAgent/ExecArgConverter.h" +#include "ExecAgentType.h" +#include "MaaFramework/MaaDef.h" +#include "Utils/IOStream/IOStream.h" + +MAA_TOOLKIT_NS_BEGIN + +class ExecAgentBase +{ +public: + virtual ~ExecAgentBase() = default; + + bool register_executor(MaaInstanceHandle handle, std::string_view name, std::filesystem::path exec_path, + std::vector exec_args, TextTransferMode text_mode, + ImageTransferMode image_mode); + bool unregister_executor(MaaInstanceHandle handle, std::string_view name); + +protected: + virtual bool register_for_maa_inst(MaaInstanceHandle handle, std::string_view name, ExecData& executor) = 0; + virtual bool unregister_for_maa_inst(MaaInstanceHandle handle, std::string_view name) = 0; + + std::optional run_executor(const std::filesystem::path& exec_path, + const std::vector& exec_args, TextTransferMode text_mode, + ImageTransferMode image_mode); + +protected: + std::map exec_data_; + + ExecArgConverter arg_cvt_; + +private: + std::optional handle_ipc(IOStream& ios, ImageTransferMode image_mode); +}; + +MAA_TOOLKIT_NS_END diff --git a/source/MaaToolKit/ExecAgent/ExecAgentType.h b/source/MaaToolKit/ExecAgent/ExecAgentType.h new file mode 100644 index 000000000..f9ff2904e --- /dev/null +++ b/source/MaaToolKit/ExecAgent/ExecAgentType.h @@ -0,0 +1,53 @@ +#pragma once + +#include "Conf/Conf.h" + +#include +#include +#include +#include + +MAA_TOOLKIT_NS_BEGIN + +enum class TextTransferMode +{ + StdIO = 1, + FileIO, +}; +inline std::ostream& operator<<(std::ostream& os, TextTransferMode mode) +{ + switch (mode) { + case TextTransferMode::StdIO: + os << "StdIO"; + break; + case TextTransferMode::FileIO: + os << "FileIO"; + break; + } + return os; +} + +enum class ImageTransferMode +{ + FileIO = 1, +}; +inline std::ostream& operator<<(std::ostream& os, ImageTransferMode mode) +{ + switch (mode) { + case ImageTransferMode::FileIO: + os << "FileIO"; + break; + } + return os; +} + +struct ExecData +{ + std::string name; + std::filesystem::path exec_path; + std::vector exec_args; + TextTransferMode text_mode; + ImageTransferMode image_mode; +}; + +MAA_TOOLKIT_NS_END diff --git a/source/MaaToolKit/ExecAgent/ExecArgConverter.cpp b/source/MaaToolKit/ExecAgent/ExecArgConverter.cpp new file mode 100644 index 000000000..09cc9d869 --- /dev/null +++ b/source/MaaToolKit/ExecAgent/ExecArgConverter.cpp @@ -0,0 +1,49 @@ +#include "ExecArgConverter.h" + +#include "MaaFramework/MaaAPI.h" +#include "Utils/ImageIo.h" +#include "Utils/Logger.h" +#include "Utils/Time.hpp" + +MAA_TOOLKIT_NS_BEGIN + +ExecArgConverter::~ExecArgConverter() +{ + for (const auto& image : images_) { + std::filesystem::remove(image); + } +} + +std::string ExecArgConverter::sync_context_to_arg(MaaSyncContextHandle sync_context) +{ + std::string uuid = std::to_string(reinterpret_cast(sync_context)); + sync_contexts_.insert_or_assign(uuid, sync_context); + return uuid; +} + +std::string ExecArgConverter::image_to_arg(const cv::Mat& image, ImageTransferMode mode) +{ + switch (mode) { + case ImageTransferMode::FileIO: { + auto path = std::filesystem::temp_directory_path() / now_filestem() / ".png"; + imwrite(path, image); + images_.push_back(path); + return path_to_crt_string(path); + } + default: + LogError << "not implemented"; + return {}; + } +} + +MaaSyncContextHandle ExecArgConverter::arg_to_sync_context(const std::string& arg) const +{ + auto it = sync_contexts_.find(arg); + if (it == sync_contexts_.end()) { + LogError << "sync context not found"; + return nullptr; + } + return it->second; +} + +MAA_TOOLKIT_NS_END diff --git a/source/MaaToolKit/ExecAgent/ExecArgConverter.h b/source/MaaToolKit/ExecAgent/ExecArgConverter.h new file mode 100644 index 000000000..f5a2a51fc --- /dev/null +++ b/source/MaaToolKit/ExecAgent/ExecArgConverter.h @@ -0,0 +1,30 @@ +#pragma once + +#include "Conf/Conf.h" + +#include +#include + +#include "ExecAgentType.h" +#include "MaaFramework/MaaDef.h" +#include "Utils/NoWarningCVMat.hpp" + +MAA_TOOLKIT_NS_BEGIN + +class ExecArgConverter +{ +public: + ~ExecArgConverter(); + +public: + std::string sync_context_to_arg(MaaSyncContextHandle sync_context); + std::string image_to_arg(const cv::Mat& image, ImageTransferMode mode); + + MaaSyncContextHandle arg_to_sync_context(const std::string& arg) const; + +private: + std::map sync_contexts_; + std::vector images_; +}; + +MAA_TOOLKIT_NS_END diff --git a/source/MaaToolKit/ExecAgent/RecognizerExecAgent.cpp b/source/MaaToolKit/ExecAgent/RecognizerExecAgent.cpp new file mode 100644 index 000000000..3c3fad1de --- /dev/null +++ b/source/MaaToolKit/ExecAgent/RecognizerExecAgent.cpp @@ -0,0 +1,86 @@ +#include "RecognizerExecAgent.h" + +#include + +#include "MaaFramework/MaaAPI.h" +#include "Utils/ImageIo.h" +#include "Utils/Logger.h" +#include "Utils/Time.hpp" + +MAA_TOOLKIT_NS_BEGIN + +RecognizerExecAgent::RecognizerExecAgent() +{ + custom_recognizer_.analyze = &RecognizerExecAgent::maa_api_analyze; +} + +bool RecognizerExecAgent::register_for_maa_inst(MaaInstanceHandle handle, std::string_view name, ExecData& executor) +{ + return MaaRegisterCustomRecognizer(handle, name.data(), &custom_recognizer_, reinterpret_cast(&executor)); +} + +bool RecognizerExecAgent::unregister_for_maa_inst(MaaInstanceHandle handle, std::string_view name) +{ + return MaaUnregisterCustomRecognizer(handle, name.data()); +} + +std::optional RecognizerExecAgent::analyze( + ExecData& data, MaaSyncContextHandle sync_context, const cv::Mat& image, std::string_view task_name, + std::string_view custom_recognition_param) +{ + LogFunc << VAR(data.name) << VAR_VOIDP(sync_context) << VAR(image.size()) << VAR(task_name) + << VAR(custom_recognition_param); + + std::string handle_arg = arg_cvt_.sync_context_to_arg(sync_context); + std::string image_arg = arg_cvt_.image_to_arg(image, data.image_mode); + + std::vector extra_args = { handle_arg, image_arg, std::string(task_name), + std::string(custom_recognition_param) }; + std::vector args = data.exec_args; + args.insert(args.end(), std::make_move_iterator(extra_args.begin()), std::make_move_iterator(extra_args.end())); + + auto output_opt = run_executor(data.exec_path, args, data.text_mode, data.image_mode); + if (!output_opt) { + LogError << "run_executor failed" << VAR(data.exec_path) << VAR(data.exec_args); + return std::nullopt; + } + + // TODO: parse output to get result + return {}; +} + +MaaBool RecognizerExecAgent::maa_api_analyze( // + MaaSyncContextHandle sync_context, const MaaImageBufferHandle image, MaaStringView task_name, + MaaStringView custom_recognition_param, MaaTransparentArg recognizer_arg, MaaRectHandle out_box, + MaaStringBufferHandle out_detail) +{ + auto* data = static_cast(recognizer_arg); + if (!data) { + LogError << "data is nullptr" << VAR(recognizer_arg); + return false; + } + + void* raw_data = MaaGetImageRawData(image); + int32_t width = MaaGetImageWidth(image); + int32_t height = MaaGetImageHeight(image); + int32_t type = MaaGetImageType(image); + cv::Mat image_mat(height, width, type, raw_data); + + auto result_opt = get_instance().analyze(*data, sync_context, image_mat, task_name, custom_recognition_param); + + if (!result_opt) { + MaaSetRect(out_box, 0, 0, 0, 0); + MaaClearString(out_detail); + return false; + } + + auto& box = result_opt->box; + MaaSetRect(out_box, box.x, box.y, box.width, box.height); + + auto& detail = result_opt->detail; + MaaSetStringEx(out_detail, detail.c_str(), detail.size()); + + return true; +} + +MAA_TOOLKIT_NS_END diff --git a/source/MaaToolKit/ExecAgent/RecognizerExecAgent.h b/source/MaaToolKit/ExecAgent/RecognizerExecAgent.h new file mode 100644 index 000000000..4d6ae5aaf --- /dev/null +++ b/source/MaaToolKit/ExecAgent/RecognizerExecAgent.h @@ -0,0 +1,47 @@ +#pragma once + +#include "Conf/Conf.h" +#include "ExecAgentBase.h" + +#include +#include + +#include "MaaFramework/Task/MaaCustomRecognizer.h" +#include "Utils/NoWarningCVMat.hpp" +#include "Utils/SingletonHolder.hpp" + +MAA_TOOLKIT_NS_BEGIN + +class RecognizerExecAgent final : public ExecAgentBase, public SingletonHolder +{ +public: + RecognizerExecAgent(); + virtual ~RecognizerExecAgent() = default; + +protected: // from ExecAgentBase + virtual bool register_for_maa_inst(MaaInstanceHandle handle, std::string_view name, ExecData& executor) override; + virtual bool unregister_for_maa_inst(MaaInstanceHandle handle, std::string_view name) override; + +private: + struct AnalyzeResult + { + cv::Rect box {}; + std::string detail; + }; + std::optional analyze( // + ExecData& data, MaaSyncContextHandle sync_context, const cv::Mat& image, std::string_view task_name, + std::string_view custom_recognition_param); + +private: + // for MaaCustomRecognizerAPI + static MaaBool maa_api_analyze( // + MaaSyncContextHandle sync_context, const MaaImageBufferHandle image, MaaStringView task_name, + MaaStringView custom_recognition_param, MaaTransparentArg recognizer_arg, + /*out*/ MaaRectHandle out_box, + /*out*/ MaaStringBufferHandle out_detail); + +private: + MaaCustomRecognizerAPI custom_recognizer_ {}; +}; + +MAA_TOOLKIT_NS_END diff --git a/source/MaaUtils/CMakeLists.txt b/source/MaaUtils/CMakeLists.txt index df3420e41..39099f86d 100644 --- a/source/MaaUtils/CMakeLists.txt +++ b/source/MaaUtils/CMakeLists.txt @@ -4,7 +4,7 @@ file(GLOB_RECURSE maa_utils_header ../include/Utils/*) add_library(MaaUtils SHARED ${maa_utils_src} ${maa_utils_header}) target_include_directories(MaaUtils PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../include ${CMAKE_CURRENT_SOURCE_DIR}/../../include) -target_link_libraries(MaaUtils PRIVATE HeaderOnlyLibraries) +target_link_libraries(MaaUtils PRIVATE HeaderOnlyLibraries Boost::system) target_compile_definitions(MaaUtils PRIVATE MAA_UTILS_EXPORTS) install( diff --git a/source/MaaUtils/IOStream/ChildPipeIOStream.cpp b/source/MaaUtils/IOStream/ChildPipeIOStream.cpp new file mode 100644 index 000000000..d00830711 --- /dev/null +++ b/source/MaaUtils/IOStream/ChildPipeIOStream.cpp @@ -0,0 +1,79 @@ +#include "Utils/IOStream/ChildPipeIOStream.h" + +#include "Utils/Logger.h" + +MAA_NS_BEGIN + +ChildPipeIOStream::ChildPipeIOStream(const std::filesystem::path& exec, const std::vector& args) + : child_( // + exec, args, boost::process::std_out > pin_, boost::process::std_err > boost::process::null, + boost::process::std_in < pout_ +#ifdef _WIN32 + , + boost::process::windows::create_no_window +#endif + ) +{ + LogDebug << VAR(exec) << VAR(args); +} + +ChildPipeIOStream::~ChildPipeIOStream() +{ + release(); +} + +bool ChildPipeIOStream::write(std::string_view data) +{ + if (!pout_.good()) { + LogError << "pout is not good"; + return false; + } + + pout_ << data << std::endl; + return true; +} + +bool ChildPipeIOStream::release() +{ + auto start_time = std::chrono::steady_clock::now(); + using namespace std::chrono_literals; + while (child_.running() && duration_since(start_time) < 100ms) { + std::this_thread::yield(); + } + + if (child_.running()) { + child_.terminate(); + } + else { + child_.wait(); + } + + int code = child_.exit_code(); + + if (code != 0) { + LogError << "child exit with" << code; + return false; + } + + return true; +} + +bool ChildPipeIOStream::is_open() const +{ + return !pin_.eof(); +} + +std::string ChildPipeIOStream::read_once(size_t max_count) +{ + constexpr size_t kBufferSize = 128 * 1024; + + if (!buffer_) { + buffer_ = std::make_unique(kBufferSize); + } + + size_t count = std::min(kBufferSize, max_count); + auto read = pin_.read(buffer_.get(), count).gcount(); + return std::string(buffer_.get(), read); +} + +MAA_NS_END diff --git a/source/MaaUtils/IOStream/IOStream.cpp b/source/MaaUtils/IOStream/IOStream.cpp new file mode 100644 index 000000000..f0211716a --- /dev/null +++ b/source/MaaUtils/IOStream/IOStream.cpp @@ -0,0 +1,38 @@ +#include "Utils/IOStream/IOStream.h" + +#include "Utils/Time.hpp" + +MAA_NS_BEGIN + +std::string IOStream::read(duration_t timeout) +{ + return read_some(std::numeric_limits::max(), timeout); +} + +std::string IOStream::read_some(size_t count, duration_t timeout) +{ + auto start_time = std::chrono::steady_clock::now(); + std::string result; + + while (is_open() && result.size() < count && duration_since(start_time) < timeout) { + auto data = read_once(count - result.size()); + result.append(std::move(data)); + } + + return result; +} + +std::string IOStream::read_until(std::string_view delimiter, duration_t timeout) +{ + auto start_time = std::chrono::steady_clock::now(); + std::string result; + + while (is_open() && !result.ends_with(delimiter) && duration_since(start_time) < timeout) { + auto data = read_once(1); + result.append(std::move(data)); + } + + return result; +} + +MAA_NS_END diff --git a/source/MaaUtils/IOStream/SockIOStream.cpp b/source/MaaUtils/IOStream/SockIOStream.cpp new file mode 100644 index 000000000..2c6c1dbd8 --- /dev/null +++ b/source/MaaUtils/IOStream/SockIOStream.cpp @@ -0,0 +1,108 @@ +#include "Utils/IOStream/SockIOStream.h" + +#include "Utils/Logger.h" + +MAA_NS_BEGIN + +ServerSockIOFactory::ServerSockIOFactory(const std::string& address, unsigned short port) : server_acceptor_(io_ctx_) +{ + LogFunc << VAR(address) << VAR(port); + + using namespace boost::asio::ip; + + tcp::endpoint endpoint(address::from_string(address), port); + + server_acceptor_.open(endpoint.protocol()); + server_acceptor_.set_option(tcp::acceptor::reuse_address(true)); + server_acceptor_.bind(endpoint); + + server_acceptor_.listen(); +} + +ServerSockIOFactory::~ServerSockIOFactory() +{ + LogFunc; + + server_acceptor_.close(); +} + +unsigned short ServerSockIOFactory::port() const +{ + return server_acceptor_.local_endpoint().port(); +} + +std::shared_ptr ServerSockIOFactory::accept() +{ + LogFunc; + + boost::asio::ip::tcp::iostream ios; + server_acceptor_.accept(*ios.rdbuf()); + if (ios.eof()) { + LogError << "socket is not opened"; + return nullptr; + } + + return std::make_shared(std::move(ios)); +} + +ClientSockIOFactory::ClientSockIOFactory(const std::string& address, unsigned short port) + : endpoint_(boost::asio::ip::address::from_string(address), port) +{ + LogFunc << VAR(address) << VAR(port); +} + +std::shared_ptr ClientSockIOFactory::connect() +{ + LogFunc; + + boost::asio::ip::tcp::iostream ios(endpoint_); + if (ios.eof()) { + LogError << "socket is not opened"; + return nullptr; + } + return std::make_shared(std::move(ios)); +} + +SockIOStream::SockIOStream(boost::asio::ip::tcp::iostream&& ios) : ios_(std::move(ios)) {} + +SockIOStream::~SockIOStream() +{ + release(); +} + +bool SockIOStream::write(std::string_view data) +{ + if (!ios_.good()) { + LogError << "ios is not good"; + return false; + } + + ios_ << data << std::endl; + return true; +} + +bool SockIOStream::release() +{ + ios_.close(); + return true; +} + +bool SockIOStream::is_open() const +{ + return !ios_.eof(); +} + +std::string SockIOStream::read_once(size_t max_count) +{ + constexpr size_t kBufferSize = 128 * 1024; + + if (!buffer_) { + buffer_ = std::make_unique(kBufferSize); + } + + size_t count = std::min(kBufferSize, max_count); + auto read = ios_.read(buffer_.get(), count).gcount(); + return std::string(buffer_.get(), read); +} + +MAA_NS_END diff --git a/source/MaaUtils/Uuid/Uuid.cpp b/source/MaaUtils/Uuid/Uuid.cpp new file mode 100644 index 000000000..2e0afbbd6 --- /dev/null +++ b/source/MaaUtils/Uuid/Uuid.cpp @@ -0,0 +1,16 @@ +#include "Utils/Uuid.h" + +MAA_SUPPRESS_BOOST_WARNINGS_BEGIN +#include +#include +MAA_SUPPRESS_BOOST_WARNINGS_END + +MAA_NS_BEGIN + +std::string make_uuid() +{ + static boost::uuids::random_generator uuid_generator; + return boost::uuids::to_string(uuid_generator()); +} + +MAA_NS_END diff --git a/source/include/LibraryHolder/LibraryHolder.h b/source/include/LibraryHolder/LibraryHolder.h index 27ed70cd4..b2bb15b6d 100644 --- a/source/include/LibraryHolder/LibraryHolder.h +++ b/source/include/LibraryHolder/LibraryHolder.h @@ -4,8 +4,11 @@ #include #include +#define BOOST_DLL_USE_STD_FS 1 +#include +#include + #include "Conf/Conf.h" -#include "Utils/Boost.hpp" #include "Utils/Logger.h" MAA_NS_BEGIN @@ -57,7 +60,7 @@ inline bool LibraryHolder::load_library(const std::filesystem::path& libname) boost::dll::fs::error_code ec; module_.load(libname, ec, boost::dll::load_mode::append_decorations | boost::dll::load_mode::search_system_folders); - if (ec.value() != boost::system::errc::success) { + if (ec) { auto message = ec.message(); LogError << "Failed to load library" << VAR(libname) << VAR(message); return false; diff --git a/source/include/Utils/Boost.hpp b/source/include/Utils/Boost.hpp deleted file mode 100644 index 0a3b55495..000000000 --- a/source/include/Utils/Boost.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include "Conf/Conf.h" - -#ifdef _WIN32 -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0601 // Win7 -#endif -#endif - -#define BOOST_PROCESS_USE_STD_FS 1 -#define BOOST_DLL_USE_STD_FS 1 - -MAA_SUPPRESS_BOOST_WARNINGS_BEGIN -#include -#include -#ifdef _WIN32 -#include -#endif -#include -#include -#include -#include -MAA_SUPPRESS_BOOST_WARNINGS_END diff --git a/source/include/Utils/IOStream/BoostIO.hpp b/source/include/Utils/IOStream/BoostIO.hpp new file mode 100644 index 000000000..15d621f97 --- /dev/null +++ b/source/include/Utils/IOStream/BoostIO.hpp @@ -0,0 +1,15 @@ +#pragma once + +#ifdef _WIN32 +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0A00 // Win10 +#endif +#endif + +#define BOOST_PROCESS_USE_STD_FS 1 + +#include +#include +#ifdef _WIN32 +#include +#endif diff --git a/source/include/Utils/IOStream/ChildPipeIOStream.h b/source/include/Utils/IOStream/ChildPipeIOStream.h new file mode 100644 index 000000000..0fd125962 --- /dev/null +++ b/source/include/Utils/IOStream/ChildPipeIOStream.h @@ -0,0 +1,34 @@ +#pragma once + +#include + +#include "IOStream.h" +#include "MaaFramework/MaaPort.h" + +MAA_NS_BEGIN + +class MAA_UTILS_API ChildPipeIOStream : public IOStream +{ +public: + ChildPipeIOStream(const std::filesystem::path& exec, const std::vector& args); + + virtual ~ChildPipeIOStream(); + +public: + virtual bool write(std::string_view data) override; + + virtual bool release() override; + virtual bool is_open() const override; + +protected: + virtual std::string read_once(size_t max_count) override; + +private: + boost::process::ipstream pin_; + boost::process::opstream pout_; + boost::process::child child_; + + std::unique_ptr buffer_ = nullptr; +}; + +MAA_NS_END diff --git a/source/include/Utils/IOStream/IOStream.h b/source/include/Utils/IOStream/IOStream.h new file mode 100644 index 000000000..1794f624d --- /dev/null +++ b/source/include/Utils/IOStream/IOStream.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include + +#include "BoostIO.hpp" +#include "MaaFramework/MaaPort.h" +#include "Utils/NonCopyable.hpp" + +MAA_NS_BEGIN + +class MAA_UTILS_API IOStream : public NonCopyButMovable +{ + using duration_t = std::chrono::milliseconds; + +public: + virtual ~IOStream() = default; + +public: + virtual bool write(std::string_view data) = 0; + + virtual std::string read(duration_t timeout = duration_t::max()); + virtual std::string read_some(size_t count, duration_t timeout = duration_t::max()); + virtual std::string read_until(std::string_view delimiter, duration_t timeout = duration_t::max()); + + virtual bool release() = 0; + virtual bool is_open() const = 0; + +protected: + virtual std::string read_once(size_t max_count) = 0; +}; + +MAA_NS_END diff --git a/source/include/Utils/IOStream/SockIOStream.h b/source/include/Utils/IOStream/SockIOStream.h new file mode 100644 index 000000000..f2fbb09c9 --- /dev/null +++ b/source/include/Utils/IOStream/SockIOStream.h @@ -0,0 +1,64 @@ +#pragma once + +#include + +#include "IOStream.h" +#include "MaaFramework/MaaPort.h" +#include "Utils/NonCopyable.hpp" + +MAA_NS_BEGIN + +class MAA_UTILS_API SockIOStream; + +class MAA_UTILS_API ServerSockIOFactory : public NonCopyButMovable +{ +public: + ServerSockIOFactory(const std::string& address, unsigned short port); + ~ServerSockIOFactory(); + + unsigned short port() const; + +public: + std::shared_ptr accept(); + +private: + boost::asio::io_context io_ctx_; + boost::asio::ip::tcp::acceptor server_acceptor_; +}; + +class MAA_UTILS_API ClientSockIOFactory : public NonCopyButMovable +{ +public: + ClientSockIOFactory(const std::string& address, unsigned short port); + ~ClientSockIOFactory() = default; + +public: + std::shared_ptr connect(); + +private: + boost::asio::io_context io_ctx_; + boost::asio::ip::tcp::endpoint endpoint_; +}; + +class MAA_UTILS_API SockIOStream : public IOStream +{ +public: + SockIOStream(boost::asio::ip::tcp::iostream&& ios); + virtual ~SockIOStream() override; + +public: + virtual bool write(std::string_view data) override; + + virtual bool release() override; + virtual bool is_open() const override; + +protected: + virtual std::string read_once(size_t max_count) override; + +private: + boost::asio::ip::tcp::iostream ios_; + + std::unique_ptr buffer_ = nullptr; +}; + +MAA_NS_END diff --git a/source/include/Utils/NonCopyable.hpp b/source/include/Utils/NonCopyable.hpp index 4066ac643..f933398ba 100644 --- a/source/include/Utils/NonCopyable.hpp +++ b/source/include/Utils/NonCopyable.hpp @@ -1,17 +1,31 @@ #pragma once #include "Conf/Conf.h" +#include "MaaFramework/MaaPort.h" MAA_NS_BEGIN -class NonCopyable +class MAA_UTILS_API NonCopyButMovable +{ +public: + NonCopyButMovable(const NonCopyButMovable&) = delete; + NonCopyButMovable(NonCopyButMovable&&) = default; + + NonCopyButMovable& operator=(const NonCopyButMovable&) = delete; + NonCopyButMovable& operator=(NonCopyButMovable&&) = default; + +protected: + NonCopyButMovable() = default; +}; + +class MAA_UTILS_API NonCopyable { public: NonCopyable(const NonCopyable&) = delete; NonCopyable(NonCopyable&&) = delete; - NonCopyable operator=(const NonCopyable&) = delete; - NonCopyable operator=(NonCopyable&&) = delete; + NonCopyable& operator=(const NonCopyable&) = delete; + NonCopyable& operator=(NonCopyable&&) = delete; protected: NonCopyable() = default; diff --git a/source/include/Utils/StringMisc.hpp b/source/include/Utils/StringMisc.hpp index 7f5b7199e..1eae8fcd6 100644 --- a/source/include/Utils/StringMisc.hpp +++ b/source/include/Utils/StringMisc.hpp @@ -43,19 +43,9 @@ inline constexpr void string_replace_all_(StringT& str, string_detail::sv_type -requires IsSomeKindOfString -inline constexpr void string_replace_all_(StringT& str, - std::initializer_list> replace_pairs) -{ - for (auto&& [from, to] : replace_pairs) { - string_replace_all_(str, from, to); - } -} - -template +template requires IsSomeKindOfString -inline constexpr void string_replace_all_(StringT& str, const std::map& replace_map) +inline constexpr void string_replace_all_(StringT& str, const MapT& replace_map) { for (const auto& [from, to] : replace_map) { string_replace_all_(str, from, to); @@ -102,20 +92,9 @@ requires IsSomeKindOfString return result; } -template -requires IsSomeKindOfString -[[nodiscard]] inline constexpr auto string_replace_all( - StringT&& str, std::initializer_list> replace_pairs) -{ - std::decay_t result = std::forward(str); - string_replace_all_(result, replace_pairs); - return result; -} - -template +template requires IsSomeKindOfString -[[nodiscard]] inline constexpr auto string_replace_all(const StringT& str, - const std::map& replace_map) +[[nodiscard]] inline constexpr auto string_replace_all(const StringT& str, const MapT& replace_map) { StringT result = str; string_replace_all_(result, replace_map); diff --git a/source/include/Utils/Time.hpp b/source/include/Utils/Time.hpp index 3c9076b21..b458c9535 100644 --- a/source/include/Utils/Time.hpp +++ b/source/include/Utils/Time.hpp @@ -43,9 +43,10 @@ inline std::string now_filestem() #endif } -inline std::chrono::milliseconds duration_since(const std::chrono::steady_clock::time_point& start_time) +template +inline duration_t duration_since(const std::chrono::steady_clock::time_point& start_time) { - return std::chrono::duration_cast(std::chrono::steady_clock::now() - start_time); + return std::chrono::duration_cast(std::chrono::steady_clock::now() - start_time); } MAA_NS_END diff --git a/source/include/Utils/Uuid.h b/source/include/Utils/Uuid.h new file mode 100644 index 000000000..6ed558e40 --- /dev/null +++ b/source/include/Utils/Uuid.h @@ -0,0 +1,12 @@ +#pragma once + +#include "Conf/Conf.h" +#include "MaaFramework/MaaPort.h" + +#include + +MAA_NS_BEGIN + +std::string MAA_UTILS_API make_uuid(); + +MAA_NS_END