restructure configer, improve thread safety

This commit is contained in:
MistEO
2021-07-23 23:48:00 +08:00
parent f532cc6c2e
commit 594dc77a2a
10 changed files with 147 additions and 91 deletions

View File

@@ -8,6 +8,7 @@
#include <unordered_map>
#include "AsstDef.h"
#include "Configer.h"
namespace asst {
class WinMacro;
@@ -24,8 +25,8 @@ namespace asst {
void start(const std::string & task);
void stop(bool block = true);
bool setParam(const std::string& type, const std::string& param, const std::string& value);
std::optional<std::string> getParam(const std::string& type, const std::string& param);
bool set_param(const std::string& type, const std::string& param, const std::string& value);
std::optional<std::string> get_param(const std::string& type, const std::string& param);
private:
static void workingProc(Assistance* pThis);
@@ -41,6 +42,8 @@ namespace asst {
bool m_thread_exit = false;
bool m_thread_running = false;
std::vector<std::string> m_next_tasks;
Configer m_configer;
};
}

View File

@@ -52,6 +52,21 @@ namespace asst {
};
return os << _type_name.at(task);
}
enum class AlgorithmType {
JustReturn,
MatchTemplate,
CompareHist
};
static std::ostream& operator<<(std::ostream& os, const AlgorithmType& type)
{
static std::unordered_map<AlgorithmType, std::string> _type_name = {
{AlgorithmType::JustReturn, "JustReturn"},
{AlgorithmType::MatchTemplate, "MatchTemplate"},
{AlgorithmType::CompareHist, "CompareHist"}
};
return os << _type_name.at(type);
}
struct Point
{
@@ -94,6 +109,7 @@ namespace asst {
};
struct SimulatorInfo {
std::string name;
std::vector<HandleInfo> window;
std::vector<HandleInfo> view;
std::vector<HandleInfo> control;

View File

@@ -2,7 +2,6 @@
#include <string>
#include <unordered_map>
#include <vector>
#include <optional>
#include "AsstDef.h"
@@ -12,25 +11,31 @@ namespace asst {
class Configer
{
public:
Configer() = default;
~Configer() = default;
static bool reload();
Configer(const Configer& rhs);
Configer(Configer&& rhs) noexcept;
static std::string m_version;
static Options m_options;
static std::unordered_map<std::string, TaskInfo> m_tasks;
static std::unordered_map<std::string, SimulatorInfo> m_handles;
bool reload(const std::string& filename);
static bool setParam(const std::string& type, const std::string& param, const std::string& value);
static std::optional<std::string> getParam(const std::string& type, const std::string& param);
bool set_param(const std::string& type, const std::string& param, const std::string& value);
std::optional<std::string> get_param(const std::string& type, const std::string& param);
static void clearExecTimes();
void clear_exec_times();
Configer& operator=(const Configer& rhs);
Configer& operator=(Configer&& rhs) noexcept;
constexpr static double DefaultThreshold = 0.9;
constexpr static double DefaultCacheThreshold = 0.9;
private:
Configer() = default;
static std::string m_curDir;
std::string m_version;
Options m_options;
std::unordered_map<std::string, TaskInfo> m_tasks;
std::unordered_map<std::string, SimulatorInfo> m_handles;
private:
};
}

View File

@@ -22,7 +22,7 @@ namespace asst {
bool addImage(const std::string& name, const std::string& path);
// return tuple< algorithmType, suitability, scaled asst::rect>
std::tuple<int, double, asst::Rect> findImage(const cv::Mat& image, const std::string& templ, double threshold = 0.99);
std::tuple<AlgorithmType, double, asst::Rect> findImage(const cv::Mat& image, const std::string& templ, double threshold = 0.99);
void clear_cache();
private:

View File

@@ -11,7 +11,7 @@ namespace asst {
class WinMacro
{
public:
WinMacro(const std::string & simulator_name, HandleType type);
WinMacro(const SimulatorInfo & info, HandleType type);
~WinMacro() = default;
bool captured() const noexcept;
@@ -27,7 +27,7 @@ namespace asst {
private:
bool findHandle();
const std::string m_simulator_name;
const SimulatorInfo m_simulator_info;
const HandleType m_handle_type;
HWND m_handle = NULL;
bool m_is_adb = false;

View File

@@ -12,17 +12,16 @@ Assistance::Assistance()
{
DebugTraceFunction;
Configer::reload();
m_configer.reload(GetResourceDir() + "config.json");
m_pIder = std::make_shared<Identify>();
for (auto&& [name, info] : Configer::m_tasks)
for (auto&& [name, info] : m_configer.m_tasks)
{
m_pIder->addImage(name, GetResourceDir() + info.filename);
}
m_pIder->setUseCache(Configer::m_options.identify_cache);
m_pIder->setUseCache(m_configer.m_options.identify_cache);
m_working_thread = std::thread(workingProc, this);
}
Assistance::~Assistance()
@@ -48,10 +47,10 @@ std::optional<std::string> Assistance::setSimulator(const std::string& simulator
stop();
auto create_handles = [&](const std::string& name) -> bool {
m_pWindow = std::make_shared<WinMacro>(name, HandleType::Window);
m_pView = std::make_shared<WinMacro>(name, HandleType::View);
m_pCtrl = std::make_shared<WinMacro>(name, HandleType::Control);
auto create_handles = [&](const SimulatorInfo& info) -> bool {
m_pWindow = std::make_shared<WinMacro>(info, HandleType::Window);
m_pView = std::make_shared<WinMacro>(info, HandleType::View);
m_pCtrl = std::make_shared<WinMacro>(info, HandleType::Control);
return m_pWindow->captured() && m_pView->captured() && m_pCtrl->captured();
};
@@ -61,9 +60,9 @@ std::optional<std::string> Assistance::setSimulator(const std::string& simulator
std::unique_lock<std::mutex> lock(m_mutex);
if (simulator_name.empty()) {
for (auto&& [name, value] : Configer::m_handles)
for (auto&& [name, info] : m_configer.m_handles)
{
ret = create_handles(name);
ret = create_handles(info);
if (ret) {
cor_name = name;
break;
@@ -71,7 +70,7 @@ std::optional<std::string> Assistance::setSimulator(const std::string& simulator
}
}
else {
ret = create_handles(simulator_name);
ret = create_handles(m_configer.m_handles[simulator_name]);
}
if (ret && m_pWindow->showWindow() && m_pWindow->resizeWindow()) {
m_inited = true;
@@ -94,8 +93,8 @@ void Assistance::start(const std::string& task)
}
std::unique_lock<std::mutex> lock(m_mutex);
m_configer.clear_exec_times();
Configer::clearExecTimes();
m_pIder->clear_cache();
m_next_tasks.clear();
m_next_tasks.emplace_back(task);
@@ -106,31 +105,33 @@ void Assistance::start(const std::string& task)
void Assistance::stop(bool block)
{
DebugTraceFunction;
DebugTrace("Stop |", block);
DebugTrace("Stop |", block ? "block" : "non block");
std::unique_lock<std::mutex> lock;
if (block) { // Íⲿµ÷ÓÃ
lock = std::unique_lock<std::mutex>(m_mutex);
Configer::clearExecTimes();
m_configer.clear_exec_times();
}
m_thread_running = false;
m_next_tasks.clear();
m_pIder->clear_cache();
}
bool Assistance::setParam(const std::string& type, const std::string& param, const std::string& value)
bool Assistance::set_param(const std::string& type, const std::string& param, const std::string& value)
{
DebugTraceFunction;
DebugTrace("SetParam |", type, param, value);
return Configer::setParam(type, param, value);
std::unique_lock<std::mutex> lock(m_mutex);
return m_configer.set_param(type, param, value);
}
std::optional<std::string> Assistance::getParam(const std::string& type, const std::string& param)
std::optional<std::string> Assistance::get_param(const std::string& type, const std::string& param)
{
// DebugTraceFunction;
return Configer::getParam(type, param);
std::unique_lock<std::mutex> lock(m_mutex);
return m_configer.get_param(type, param);
}
void Assistance::workingProc(Assistance* pThis)
@@ -144,14 +145,17 @@ void Assistance::workingProc(Assistance* pThis)
std::string matched_task;
Rect matched_rect;
for (auto&& task_name : pThis->m_next_tasks) {
auto&& task = Configer::m_tasks[task_name];
double threshold = task.threshold;
double threshold = pThis->m_configer.m_tasks[task_name].threshold;
double cache_threshold = pThis->m_configer.m_tasks[task_name].cache_threshold;
auto&& [algorithm, value, rect] = pThis->m_pIder->findImage(curImg, task_name, threshold);
DebugTrace(task_name, "Type:", algorithm, "Value:", value);
if (algorithm == 0 ||
(algorithm == 1 && value >= threshold)
|| (algorithm == 2 && value >= task.cache_threshold)) {
if (algorithm == AlgorithmType::JustReturn ||
(algorithm == AlgorithmType::MatchTemplate && value >= threshold)
|| (algorithm == AlgorithmType::CompareHist && value >= cache_threshold)) {
matched_task = task_name;
matched_rect = rect;
break;
@@ -159,7 +163,7 @@ void Assistance::workingProc(Assistance* pThis)
}
if (!matched_task.empty()) {
auto&& task = Configer::m_tasks[matched_task];
auto&& task = pThis->m_configer.m_tasks[matched_task];
DebugTraceInfo("***Matched***", matched_task, "Type:", task.type);
if (task.pre_delay > 0) {
DebugTrace("PreDelay", task.pre_delay);
@@ -174,9 +178,9 @@ void Assistance::workingProc(Assistance* pThis)
}
if (task.exec_times < task.max_times) {
if ((task.type & TaskType::BasicClick)
&& Configer::m_options.control_delay_upper != 0) {
&& pThis->m_configer.m_options.control_delay_upper != 0) {
static std::default_random_engine rand_engine(std::chrono::system_clock::now().time_since_epoch().count());
static std::uniform_int_distribution<unsigned> rand_uni(Configer::m_options.control_delay_lower, Configer::m_options.control_delay_upper);
static std::uniform_int_distribution<unsigned> rand_uni(pThis->m_configer.m_options.control_delay_lower, pThis->m_configer.m_options.control_delay_upper);
int delay = rand_uni(rand_engine);
DebugTraceInfo("Random Delay", delay, "ms");
bool cv_ret = pThis->m_condvar.wait_for(lock, std::chrono::milliseconds(delay),
@@ -206,8 +210,8 @@ void Assistance::workingProc(Assistance* pThis)
}
++task.exec_times;
for (auto&& reduce : task.reduce_other_times) {
--Configer::m_tasks[reduce].exec_times;
DebugTrace("Reduce exec times", reduce, Configer::m_tasks[reduce].exec_times);
--pThis->m_configer.m_tasks[reduce].exec_times;
DebugTrace("Reduce exec times", reduce, pThis->m_configer.m_tasks[reduce].exec_times);
}
if (task.rear_delay > 0) {
DebugTrace("RearDelay", task.rear_delay);
@@ -216,11 +220,11 @@ void Assistance::workingProc(Assistance* pThis)
[&]() -> bool { return !pThis->m_thread_running; });
if (cv_ret) { continue; }
}
pThis->m_next_tasks = Configer::m_tasks[matched_task].next;
pThis->m_next_tasks = pThis->m_configer.m_tasks[matched_task].next;
}
else {
DebugTraceInfo("Reached limit");
pThis->m_next_tasks = Configer::m_tasks[matched_task].exceeded_next;
pThis->m_next_tasks = pThis->m_configer.m_tasks[matched_task].exceeded_next;
}
std::string nexts_str;
@@ -233,7 +237,7 @@ void Assistance::workingProc(Assistance* pThis)
DebugTrace("Next:", nexts_str);
}
pThis->m_condvar.wait_for(lock,
std::chrono::milliseconds(Configer::m_options.identify_delay),
std::chrono::milliseconds(pThis->m_configer.m_options.identify_delay),
[&]() -> bool { return !pThis->m_thread_running; });
}
else {

View File

@@ -56,7 +56,7 @@ bool AsstSetParam(asst::Assistance* p_asst, const char* type, const char* param,
return false;
}
return p_asst->setParam(type, param, value);
return p_asst->set_param(type, param, value);
}
bool AsstGetParam(asst::Assistance* p_asst, const char* type, const char* param, char * buffer, int buffer_size)
@@ -64,7 +64,7 @@ bool AsstGetParam(asst::Assistance* p_asst, const char* type, const char* param,
if (p_asst == NULL) {
return false;
}
auto ret = p_asst->getParam(type, param);
auto ret = p_asst->get_param(type, param);
if (!ret) {
return false;
}

View File

@@ -3,24 +3,30 @@
#include <fstream>
#include <sstream>
#include <algorithm>
#include <Windows.h>
#include "json.h"
#include "AsstDef.h"
#include "AsstAux.h"
#include "Logger.hpp"
using namespace asst;
std::string Configer::m_curDir;
std::string Configer::m_version;
Options Configer::m_options;
std::unordered_map<std::string, TaskInfo> Configer::m_tasks;
std::unordered_map<std::string, SimulatorInfo> Configer::m_handles;
bool Configer::reload()
Configer::Configer(const Configer& rhs)
: m_version(rhs.m_version),
m_options(rhs.m_options),
m_tasks(rhs.m_tasks),
m_handles(rhs.m_handles)
{
}
Configer::Configer(Configer&& rhs) noexcept
: m_version(std::move(rhs.m_version)),
m_options(std::move(rhs.m_options)),
m_tasks(std::move(rhs.m_tasks)),
m_handles(std::move(rhs.m_handles))
{
}
bool Configer::reload(const std::string& filename)
{
std::string filename = GetResourceDir() + "config.json";
std::ifstream ifs(filename, std::ios::in);
if (!ifs.is_open()) {
return false;
@@ -37,14 +43,15 @@ bool Configer::reload()
auto root = std::move(ret).value();
Configer temp;
try {
m_version = root["version"].as_string();
temp.m_version = root["version"].as_string();
auto options_obj = root["options"].as_object();
m_options.identify_delay = options_obj["identifyDelay"].as_integer();
m_options.identify_cache = options_obj["identifyCache"].as_boolean();
m_options.control_delay_lower = options_obj["controlDelayRange"][0].as_integer();
m_options.control_delay_upper = options_obj["controlDelayRange"][1].as_integer();
temp.m_options.identify_delay = options_obj["identifyDelay"].as_integer();
temp.m_options.identify_cache = options_obj["identifyCache"].as_boolean();
temp.m_options.control_delay_lower = options_obj["controlDelayRange"][0].as_integer();
temp.m_options.control_delay_upper = options_obj["controlDelayRange"][1].as_integer();
auto tasks_obj = root["tasks"].as_object();
for (auto&& [name, task_json] : tasks_obj) {
@@ -120,12 +127,13 @@ bool Configer::reload()
task_info.next.emplace_back(name.as_string());
}
m_tasks.emplace(name, task_info);
temp.m_tasks.emplace(name, task_info);
}
auto handle_obj = root["handle"].as_object();
for (auto&& [name, simulator_json] : handle_obj) {
SimulatorInfo simulator_info;
simulator_info.name = name;
auto window_arr = simulator_json["window"].as_array();
for (auto&& info : window_arr) {
@@ -160,7 +168,7 @@ bool Configer::reload()
simulator_info.x_offset = simulator_json["xOffset"].as_integer();
simulator_info.y_offset = simulator_json["yOffset"].as_integer();
m_handles.emplace(name, simulator_info);
temp.m_handles.emplace(name, simulator_info);
}
}
catch (json::exception& e) {
@@ -168,10 +176,12 @@ bool Configer::reload()
return false;
}
*this = std::move(temp);
return true;
}
bool Configer::setParam(const std::string& type, const std::string& param, const std::string& value)
bool Configer::set_param(const std::string& type, const std::string& param, const std::string& value)
{
if (type == "task.type") {
if (m_tasks.find(param) == m_tasks.cend()) {
@@ -209,7 +219,7 @@ bool Configer::setParam(const std::string& type, const std::string& param, const
return true;
}
std::optional<std::string> Configer::getParam(const std::string& type, const std::string& param)
std::optional<std::string> Configer::get_param(const std::string& type, const std::string& param)
{
if (type == "task.execTimes" && m_tasks.find(param) != m_tasks.cend()) {
return std::to_string(m_tasks.at(param).exec_times);
@@ -217,9 +227,29 @@ std::optional<std::string> Configer::getParam(const std::string& type, const std
return std::nullopt;
}
void Configer::clearExecTimes()
void Configer::clear_exec_times()
{
for (auto&& t : m_tasks) {
t.second.exec_times = 0;
}
}
Configer& asst::Configer::operator=(const Configer& rhs)
{
m_version = rhs.m_version;
m_options = rhs.m_options;
m_tasks = rhs.m_tasks;
m_handles = rhs.m_handles;
return *this;
}
Configer& asst::Configer::operator=(Configer&& rhs) noexcept
{
m_version = std::move(rhs.m_version);
m_options = std::move(rhs.m_options);
m_tasks = std::move(rhs.m_tasks);
m_handles = std::move(rhs.m_handles);
return *this;
}

View File

@@ -68,16 +68,16 @@ std::pair<double, cv::Point> Identify::findImage(const cv::Mat& image, const cv:
return { maxVal, maxLoc };
}
std::tuple<int, double, asst::Rect> Identify::findImage(const Mat& cur, const std::string& templ, double threshold)
std::tuple<AlgorithmType, double, asst::Rect> Identify::findImage(const Mat& cur, const std::string& templ, double threshold)
{
if (m_mat_map.find(templ) == m_mat_map.cend()) {
return { 0, 0, asst::Rect() };
return { AlgorithmType::JustReturn, 0, asst::Rect() };
}
if (m_use_cache && m_cache_map.find(templ) != m_cache_map.cend()) {
auto&& [rect, hist] = m_cache_map.at(templ);
double value = imageHistComp(cur(rect), hist);
return { 2, value, cvRect2Rect(rect).center_zoom(0.8) };
return { AlgorithmType::CompareHist, value, cvRect2Rect(rect).center_zoom(0.8) };
}
else {
auto&& templ_mat = m_mat_map.at(templ);
@@ -88,7 +88,7 @@ std::tuple<int, double, asst::Rect> Identify::findImage(const Mat& cur, const st
m_cache_map.emplace(templ, std::make_pair(raw_rect, image2Hist(cur(raw_rect))));
}
return { 1, value, cvRect2Rect(raw_rect).center_zoom(0.8) };
return { AlgorithmType::MatchTemplate, value, cvRect2Rect(raw_rect).center_zoom(0.8) };
}
}

View File

@@ -8,14 +8,13 @@
#include <stdint.h>
#include <WinUser.h>
#include "Configer.h"
#include "AsstDef.h"
#include "Logger.hpp"
using namespace asst;
WinMacro::WinMacro(const std::string& simulator_name, HandleType type)
: m_simulator_name(simulator_name),
WinMacro::WinMacro(const SimulatorInfo& info, HandleType type)
: m_simulator_info(info),
m_handle_type(type),
m_rand_engine(std::chrono::system_clock::now().time_since_epoch().count())
{
@@ -30,21 +29,20 @@ bool WinMacro::captured() const noexcept
bool WinMacro::findHandle()
{
std::vector<HandleInfo> handle_vec;
auto&& info = Configer::m_handles[m_simulator_name];
switch (m_handle_type) {
case HandleType::Window:
m_width = info.width;
m_height = info.height;
handle_vec = info.window;
m_width = m_simulator_info.width;
m_height = m_simulator_info.height;
handle_vec = m_simulator_info.window;
break;
case HandleType::View:
handle_vec = info.view;
handle_vec = m_simulator_info.view;
break;
case HandleType::Control:
m_is_adb = info.is_adb;
m_x_offset = info.x_offset;
m_y_offset = info.y_offset;
handle_vec = info.control;
m_is_adb = m_simulator_info.is_adb;
m_x_offset = m_simulator_info.x_offset;
m_y_offset = m_simulator_info.y_offset;
handle_vec = m_simulator_info.control;
break;
default:
DebugTraceError("Handle type error!", m_handle_type);
@@ -95,14 +93,14 @@ bool WinMacro::findHandle()
}
size_t pos = adb_dir.find_last_of('\\') + 1;
adb_dir = adb_dir.substr(0, pos);
adb_dir = '"' + StringReplaceAll(info.adb.path, "[EmulatorPath]", adb_dir) + '"';
std::string connect_cmd = adb_dir + info.adb.connect;
adb_dir = '"' + StringReplaceAll(m_simulator_info.adb.path, "[EmulatorPath]", adb_dir) + '"';
std::string connect_cmd = adb_dir + m_simulator_info.adb.connect;
int ret = system(connect_cmd.c_str());
DebugTrace("Call", connect_cmd, "—— ret", ret);
m_click_cmd = adb_dir + info.adb.click;
m_click_cmd = adb_dir + m_simulator_info.adb.click;
}
DebugTrace("Handle:", m_handle, "Name:", m_simulator_name, "Type:", m_handle_type);
DebugTrace("Handle:", m_handle, "Name:", m_simulator_info.name, "Type:", m_handle_type);
if (m_handle != NULL) {
return true;