Skip to content

Commit

Permalink
feat: PiCli configurator, and init interactor
Browse files Browse the repository at this point in the history
  • Loading branch information
MistEO committed Feb 6, 2024
1 parent bff478d commit 237caa2
Show file tree
Hide file tree
Showing 7 changed files with 314 additions and 30 deletions.
76 changes: 60 additions & 16 deletions source/MaaProjectInterfaceCli/configurator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,29 @@
#include <ranges>

#include "ProjectInterface/Parser.h"
#include "Utils/Logger.h"
#include "Utils/Platform.h"

using namespace MAA_PROJECT_INTERFACE_NS;

bool Configurator::load(const std::filesystem::path& project_dir)
{
LogFunc << VAR(project_dir);

auto data_opt = Parser::parse_interface(project_dir / kInterfaceFilename);
if (!data_opt) {
LogError << "Failed to parse interface.json";
return false;
}
data_ = *data_opt;
if (data_.resource.empty()) {
LogError << "Resource is empty";
return false;
}

Configuration config;
auto cfg_json_opt = json::open(project_dir / kConfigFilename);
if (cfg_json_opt) {
if (auto cfg_opt = Parser::parse_config(*cfg_json_opt)) {
config = *cfg_opt;
}
if (auto cfg_opt = Parser::parse_config(project_dir / kConfigFilename)) {
config = *cfg_opt;
}

project_dir_ = project_dir;
Expand All @@ -31,29 +37,67 @@ void Configurator::save()
std::ofstream(project_dir_ / kInterfaceFilename) << config_.to_json();
}

void Configurator::check_config()
std::optional<RuntimeParam> Configurator::generate_runtime() const
{
RuntimeParam runtime;

auto resource_iter =
std::ranges::find_if(data_.resource, [&](const auto& resource) { return resource.name == config_.resource; });

if (resource_iter == data_.resource.end()) {
select_resource();
LogWarn << "Resource not found";
return std::nullopt;
}
else {
runtime_.resource_path = resource_iter->path;

runtime.resource_path = resource_iter->path;

for (const auto& config_task : config_.task) {
auto task_opt = generate_runtime_task(config_task);
if (!task_opt) {
LogWarn << "Task not found, ignore" << VAR(config_task.name);
continue;
}
runtime.task.emplace_back(*std::move(task_opt));
}

for (const auto& config_task : config_.task) {}
runtime.executor = data_.executor;

runtime_.executor = data_.executor;
LogTrace << VAR(runtime);
return runtime;
}

void Configurator::select_resource()
std::optional<RuntimeParam::Task> Configurator::generate_runtime_task(const Configuration::Task& config_task) const
{
Resource res;
auto data_iter = std::ranges::find_if(data_.entry, [&](const auto& task) { return task.name == config_task.name; });
if (data_iter == data_.entry.end()) {
LogWarn << "Task not found, remove" << VAR(config_task.name);
return std::nullopt;
}
const Entry& data_entry = *data_iter;

RuntimeParam::Task result { .entry = data_entry.name, .param = data_entry.param };

for (const auto& [config_option, config_option_value] : config_task.option) {
auto data_option_iter =
std::ranges::find_if(data_entry.options, [&](const auto& opt) { return opt.name == config_option; });
if (data_option_iter == data_entry.options.end()) {
LogWarn << "Option not found, remove" << VAR(config_task.name) << VAR(config_option);
return std::nullopt;
}
const Option& data_option = *data_option_iter;

// TODO
auto case_iter =
std::ranges::find_if(data_option.cases, [&](const auto& c) { return c.name == config_option_value; });
if (case_iter == data_option.cases.end()) {
LogWarn << "Case not found, remove" << VAR(config_task.name) << VAR(config_option)
<< VAR(config_option_value);
return std::nullopt;
}
const Option::Case& data_case = *case_iter;

// data_case first, duplicate keys will be overwritten by data_case.param
result.param = data_case.param | std::move(result.param);
}

config_.resource = res.name;
runtime_.resource_path = res.path;
return result;
}
12 changes: 8 additions & 4 deletions source/MaaProjectInterfaceCli/configurator.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,19 @@ class Configurator
bool load(const std::filesystem::path& project_dir);
void save();

void check_config();
void select_resource();
std::optional<MAA_PROJECT_INTERFACE_NS::RuntimeParam> generate_runtime() const;

const auto& get_runtime() const { return runtime_; }
const auto& interface_data() const { return data_; }

const auto& configuration() const { return config_; }
auto& configuration() { return config_; }

private:
std::optional<MAA_PROJECT_INTERFACE_NS::RuntimeParam::Task> generate_runtime_task(
const MAA_PROJECT_INTERFACE_NS::Configuration::Task& config_task) const;

std::filesystem::path project_dir_;

MAA_PROJECT_INTERFACE_NS::InterfaceData data_;
MAA_PROJECT_INTERFACE_NS::Configuration config_;
MAA_PROJECT_INTERFACE_NS::RuntimeParam runtime_;
};
185 changes: 185 additions & 0 deletions source/MaaProjectInterfaceCli/interactor.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
#include "interactor.h"

#include <unordered_set>

#include "Utils/Logger.h"
#include "Utils/Platform.h"

// return [1, size]
int input(size_t size)
{
std::cout << std::format("Please Input [1-{}]:", size);
int value = 0;

while (true) {
std::cin >> value;
if (value > 0 && value <= size) {
break;
}
std::cout << std::format("Invalid value, please Input [1-{}]:", size);
}

return value;
}

void Interactor::interact_for_first_time_use()
{
select_resource();
add_task();
interact();
}

void Interactor::interact()
{
while (true) {
interact_once();
}
}

void Interactor::interact_once()
{
std::cout << "\n\n\n";
std::cout << "### Current configuration ###\n\n";
std::cout << "Resource:\n\n";
std::cout << "\t" << config_.configuration().resource << "\n\n";
std::cout << "Tasks:\n\n";
for (const auto& task : config_.configuration().task) {
std::cout << "\t- " << task.name << "\n";
for (const auto& [key, value] : task.option) {
std::cout << "\t\t- " << key << ": " << value << "\n";
}
}

std::cout << "### Select action ###\n\n";
std::cout << "\t1. Run tasks\n";
std::cout << "\t2. Select resource\n";
std::cout << "\t3. Add task\n";
std::cout << "\t4. Edit task\n";
std::cout << "\t5. Remove task\n";
std::cout << "\t6. Move task\n";

int action = input(6);

switch (action) {
case 1:
// run_tasks();
break;
case 2:
select_resource();
break;
case 3:
add_task();
break;
case 4:
edit_task();
break;
case 5:
remove_task();
break;
case 6:
move_task();
break;
}
}

void Interactor::select_resource()
{
using namespace MAA_PROJECT_INTERFACE_NS;

const auto& all_resources = config_.interface_data().resource;
if (all_resources.empty()) {
LogError << "Resource is empty";
return;
}

int index = 0;
if (all_resources.size() != 1) {
std::cout << "\n\n\n";
std::cout << "### Select resource ###\n\n";
for (size_t i = 0; i < all_resources.size(); ++i) {
std::cout << std::format("\t{}. {}\n", i + 1, all_resources[i].name);
}
index = input(all_resources.size()) - 1;
}
else {
std::cout << "\n\n\n";
std::cout << "### Only one resource, use it ###\n\n";
index = 0;
}
const Resource& resource = all_resources[index];

config_.configuration().resource = resource.name;
config_.save();
}

void Interactor::add_task()
{
using namespace MAA_PROJECT_INTERFACE_NS;

const auto& all_tasks = config_.interface_data().entry;
if (all_tasks.empty()) {
LogError << "Task is empty";
return;
}

std::cout << "\n\n\n";
std::cout << "### Add task ###\n\n";
for (size_t i = 0; i < all_tasks.size(); ++i) {
std::cout << std::format("\t{}. {}\n", i + 1, all_tasks[i].name);
}
int task_index = input(all_tasks.size()) - 1;
const Entry& task = all_tasks[task_index];

std::unordered_map<std::string, std::string> option_map;
for (const Option& opt : task.options) {
if (!opt.default_case.empty()) {
option_map.emplace(opt.name, opt.default_case);
continue;
}
std::cout << std::format("\n\n\n## Input option for \"{}\" ##\n\n", opt.name);
for (size_t i = 0; i < opt.cases.size(); ++i) {
std::cout << std::format("\t{}. {}\n", i + 1, opt.cases[i]);
}
int case_index = input(opt.cases.size()) - 1;
option_map.emplace(opt.name, opt.cases[case_index]);
}

config_.configuration().task.emplace_back(
Configuration::Task { .name = task.name, .option = std::move(option_map) });
config_.save();
}

void Interactor::edit_task()
{
using namespace MAA_PROJECT_INTERFACE_NS;

const auto& all_tasks = config_.configuration().task;
if (all_tasks.empty()) {
LogError << "Task is empty";
return;
}

std::cout << "\n\n\n";
std::cout << "### Edit task ###\n\n";
for (size_t i = 0; i < all_tasks.size(); ++i) {
std::cout << std::format("\t{}. {}\n", i + 1, all_tasks[i].name);
}
int task_index = input(all_tasks.size()) - 1;

Configuration::Task& task = config_.configuration().task[task_index];

const auto& all_tasks_in_interface = config_.interface_data().entry;
auto task_in_interface =
std::ranges::find_if(all_tasks_in_interface, [&](const auto& entry) { return entry.name == task.name; });

if (task_in_interface == all_tasks_in_interface.end()) {
LogError << "Task not found in interface" << VAR(task.name);
return;
}

// TODO
}

void Interactor::remove_task() {}

void Interactor::move_task() {}
23 changes: 23 additions & 0 deletions source/MaaProjectInterfaceCli/interactor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#pragma once

#include "configurator.h"

class Interactor
{
public:
const auto& configurator() const { return config_; }
auto& configurator() { return config_; }

void interact_for_first_time_use();
void interact();

private:
void interact_once();
void select_resource();
void add_task();
void edit_task();
void remove_task();
void move_task();

Configurator config_;
};
Loading

0 comments on commit 237caa2

Please sign in to comment.