2025-01-06 16:25:39 +08:00
|
|
|
#include <CLI11.hpp>
|
2024-12-16 09:40:57 +08:00
|
|
|
#include <iostream>
|
2025-02-18 23:33:21 +08:00
|
|
|
#include <of_util.h>
|
2025-01-06 16:25:39 +08:00
|
|
|
#include <regex>
|
2024-12-11 08:44:14 +08:00
|
|
|
|
2025-03-01 03:49:40 +08:00
|
|
|
#include "client.h"
|
|
|
|
#include "config.h"
|
|
|
|
#include "version.h"
|
|
|
|
|
2025-01-21 14:47:42 +08:00
|
|
|
#ifdef _WIN32
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <io.h>
|
|
|
|
#include <windows.h>
|
|
|
|
#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
|
|
|
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
2025-04-16 22:19:49 +08:00
|
|
|
#if defined(GRAB_CRASH)
|
|
|
|
#ifdef USE_BOOST
|
|
|
|
#include <boost/filesystem.hpp>
|
|
|
|
namespace fs = boost::filesystem;
|
|
|
|
#else
|
|
|
|
#include <filesystem>
|
|
|
|
namespace fs = std::filesystem;
|
|
|
|
#endif
|
|
|
|
#include <crashelper.h>
|
|
|
|
#endif
|
|
|
|
|
2025-04-12 22:51:06 +08:00
|
|
|
std::shared_ptr<ClientConfig> g_Config = nullptr;
|
2025-01-06 18:59:11 +08:00
|
|
|
int parse_cmd(int argc, char** argv, CmdParam& param)
|
2024-12-16 09:40:57 +08:00
|
|
|
{
|
2025-04-16 22:19:49 +08:00
|
|
|
std::string intro(fmt::format("tsc cmd introduce, version: {}\nopensource: {}", VERSION_NUM, VERSION_URL));
|
2025-01-06 16:25:39 +08:00
|
|
|
CLI::App app(intro);
|
|
|
|
|
2025-03-28 12:01:35 +08:00
|
|
|
app.add_option("-u, --use", param.use_config, "使用服务器地址组(值为使用--show中显示的序号)");
|
2025-03-28 11:00:13 +08:00
|
|
|
app.add_option("-a, --append", param.appendValue, "添加服务器地址组(地址格式:127.0.0.1:9898:注释)");
|
2025-01-06 16:25:39 +08:00
|
|
|
app.add_flag("-s, --show", param.showValue, "查看服务器地址组");
|
|
|
|
app.add_option("-r, --remove", param.removeValue, "移除服务器地址组(值为使用--show中显示的序号)");
|
2025-03-28 11:00:13 +08:00
|
|
|
app.add_flag("-d, --direct", param.direct_use, "添加服务器时直接使用此服务器。");
|
2025-03-28 12:01:35 +08:00
|
|
|
app.add_flag("-l, --last", param.last_use, "直接使用之前最后一次使用的服务器。");
|
2025-03-28 12:20:58 +08:00
|
|
|
app.add_flag("-n, --null", param.null_use, "先运行在选择服务器。");
|
2025-04-07 11:49:13 +08:00
|
|
|
app.add_option("-c, --connect", param.connectValue, "直连服务器((地址格式:127.0.0.1:9898)。");
|
2025-01-06 18:59:11 +08:00
|
|
|
|
|
|
|
if (argc == 1) {
|
|
|
|
std::cout << app.help() << std::endl;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
// 这里的 CLI11_PARSE 在程序没有输入或者仅输入--help(-h)时,会直接返回,后面代码都不会执行。
|
|
|
|
// 当有自定义的参数被输入时,后面代码会执行。
|
2025-01-06 16:25:39 +08:00
|
|
|
try {
|
|
|
|
CLI11_PARSE(app, argc, argv);
|
|
|
|
} catch (const CLI::ParseError& e) {
|
2025-01-06 18:59:11 +08:00
|
|
|
return app.exit(e);
|
2025-01-06 16:25:39 +08:00
|
|
|
}
|
2025-01-06 18:59:11 +08:00
|
|
|
param.parsed = true;
|
|
|
|
return 0;
|
2024-12-16 09:40:57 +08:00
|
|
|
}
|
|
|
|
|
2025-03-28 12:20:58 +08:00
|
|
|
bool select_server(const std::vector<TransmSet>& sets, std::string& ip, long& port)
|
|
|
|
{
|
|
|
|
TLOGI("Please Select a Server:");
|
|
|
|
if (sets.empty()) {
|
|
|
|
TLOGE("No servers available to select.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// 打印所有服务器选项(带编号)
|
|
|
|
for (size_t i = 0; i < sets.size(); ++i) {
|
|
|
|
const auto& server = sets[i];
|
|
|
|
if (server.comment.empty()) {
|
|
|
|
TLOGI("[{}] {}:{}", i + 1, server.ip, server.port);
|
|
|
|
} else {
|
|
|
|
TLOGI("[{}] {}:{} ({})", i + 1, server.ip, server.port, server.comment);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
TLOGW("Enter server number (or 'exit' to cancel): ");
|
|
|
|
std::string input;
|
|
|
|
std::getline(std::cin, input);
|
|
|
|
|
|
|
|
// 检查是否输入了退出命令
|
|
|
|
if (input == "exit" || input == "quit" || input == "q") {
|
|
|
|
TLOGD("User canceled server selection.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 检查输入是否为空或非数字
|
|
|
|
if (input.empty() || !std::all_of(input.begin(), input.end(), ::isdigit)) {
|
|
|
|
TLOGE("Invalid input '{}'. Please enter a valid number or 'exit'.", input);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 转换为数字
|
|
|
|
int choice = std::stoi(input);
|
|
|
|
|
|
|
|
// 检查数字是否在有效范围内
|
|
|
|
if (choice < 1 || choice > static_cast<int>(sets.size())) {
|
|
|
|
TLOGE("Invalid choice '{}'. Please select a number between 1 and {}.", choice, sets.size());
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 选择成功,返回对应的 IP 和端口
|
|
|
|
const auto& selected = sets[choice - 1];
|
|
|
|
ip = selected.ip;
|
|
|
|
port = selected.port;
|
|
|
|
TLOGI("Selected server: {}:{} ({})", ip, port, selected.comment);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-03-28 11:00:13 +08:00
|
|
|
bool exec_cmd(CmdParam& param, bool& run)
|
2024-12-16 09:40:57 +08:00
|
|
|
{
|
2025-01-06 16:25:39 +08:00
|
|
|
run = false;
|
|
|
|
// 如果是展示
|
|
|
|
if (param.showValue) {
|
|
|
|
std::vector<TransmSet> set;
|
|
|
|
if (!g_Config->read_ini(set)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
for (const auto& item : set) {
|
2025-03-28 11:00:13 +08:00
|
|
|
TLOGI("{} => {}:{} {}", item.group, item.ip, item.port, item.comment);
|
2025-01-06 16:25:39 +08:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (param.use_config != -1) {
|
|
|
|
run = true;
|
|
|
|
return true;
|
2024-12-16 09:40:57 +08:00
|
|
|
}
|
2025-01-06 16:25:39 +08:00
|
|
|
if (!param.appendValue.empty() && !param.removeValue.empty()) {
|
2025-03-01 03:49:40 +08:00
|
|
|
TLOGW("append and remove can't simultaneous operate!");
|
2024-12-16 09:40:57 +08:00
|
|
|
return false;
|
|
|
|
}
|
2025-01-06 16:25:39 +08:00
|
|
|
if (!param.appendValue.empty()) {
|
2025-03-28 11:00:13 +08:00
|
|
|
std::regex pattern(R"((\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):(\d+)(?::(.*))?)");
|
|
|
|
std::smatch matches;
|
|
|
|
std::string ip, port, comment;
|
|
|
|
if (std::regex_match(param.appendValue, matches, pattern)) {
|
|
|
|
ip = matches[1].str();
|
|
|
|
port = matches[2].str();
|
|
|
|
comment = matches.size() > 3 ? matches[3].str() : "default";
|
2025-01-06 16:25:39 +08:00
|
|
|
}
|
2025-03-28 11:00:13 +08:00
|
|
|
auto id = g_Config->append_ini(ip, std::stol(port), comment);
|
|
|
|
if (id < 0) {
|
2025-03-01 03:49:40 +08:00
|
|
|
TLOGW("add {}:{} failed.", ip, port);
|
2025-01-06 16:25:39 +08:00
|
|
|
return false;
|
|
|
|
}
|
2025-03-01 03:49:40 +08:00
|
|
|
TLOGI("add {}:{} success.", ip, port);
|
2025-03-28 11:00:13 +08:00
|
|
|
param.use_config = id;
|
2025-01-06 16:25:39 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (!param.removeValue.empty()) {
|
|
|
|
if (!g_Config->remove_ini(std::stol(param.removeValue))) {
|
2025-03-01 03:49:40 +08:00
|
|
|
TLOGW("remove config num=[{}] failed, please check!", param.removeValue);
|
2025-01-06 16:25:39 +08:00
|
|
|
return false;
|
|
|
|
}
|
2025-03-01 03:49:40 +08:00
|
|
|
TLOGI("remove config num=[{}] success!", param.removeValue);
|
2025-01-06 16:25:39 +08:00
|
|
|
return true;
|
|
|
|
}
|
2025-03-28 12:20:58 +08:00
|
|
|
if (param.last_use || param.null_use) {
|
2025-03-28 12:01:35 +08:00
|
|
|
return true;
|
|
|
|
}
|
2025-03-01 03:49:40 +08:00
|
|
|
TLOGW("not matched!", param.removeValue);
|
2025-01-06 16:25:39 +08:00
|
|
|
return false;
|
2024-12-16 09:40:57 +08:00
|
|
|
}
|
2024-12-11 10:22:14 +08:00
|
|
|
|
2024-12-16 09:40:57 +08:00
|
|
|
int main(int argc, char* argv[])
|
2024-12-11 08:44:14 +08:00
|
|
|
{
|
2025-04-16 22:19:49 +08:00
|
|
|
#if defined(GRAB_CRASH)
|
|
|
|
auto config_dir = COfPath::get_config_dir("transm", true);
|
|
|
|
auto err = fs::path(config_dir).append("errs").string();
|
|
|
|
backward::SetDumpFileSavePath(err);
|
|
|
|
backward::SetDumpLogSavePath(err);
|
|
|
|
CRASHELPER_MARK_ENTRY();
|
|
|
|
#endif
|
2025-04-13 13:22:35 +08:00
|
|
|
|
2025-01-21 14:47:42 +08:00
|
|
|
#ifdef _WIN32
|
|
|
|
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
|
|
DWORD mode;
|
|
|
|
GetConsoleMode(hConsole, &mode);
|
|
|
|
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
|
|
|
SetConsoleMode(hConsole, mode);
|
|
|
|
#endif
|
|
|
|
|
2025-03-01 03:49:40 +08:00
|
|
|
std::shared_ptr<int> deleter(new int(), [](int* p) {
|
|
|
|
fc_recovery_color();
|
|
|
|
delete p;
|
|
|
|
});
|
|
|
|
|
2025-04-12 22:51:06 +08:00
|
|
|
g_Config = std::make_shared<ClientConfig>();
|
2025-01-06 16:25:39 +08:00
|
|
|
if (!g_Config->baseInit()) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool run = false;
|
|
|
|
CmdParam param;
|
2025-01-06 18:59:11 +08:00
|
|
|
parse_cmd(argc, argv, param);
|
|
|
|
if (!param.parsed) {
|
2025-01-06 16:25:39 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2025-03-28 12:01:35 +08:00
|
|
|
std::string ip;
|
|
|
|
long port{};
|
2025-03-28 12:20:58 +08:00
|
|
|
|
2025-04-07 11:49:13 +08:00
|
|
|
if (!param.connectValue.empty()) {
|
|
|
|
std::regex pattern(R"((\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):(\d+))");
|
|
|
|
std::smatch matches;
|
|
|
|
|
|
|
|
if (std::regex_match(param.connectValue, matches, pattern) && matches.size() == 3) {
|
|
|
|
ip = matches[1].str();
|
|
|
|
port = std::stol(matches[2].str());
|
|
|
|
run = true;
|
|
|
|
} else {
|
|
|
|
TLOGE("Invalid connect value [{}]", param.connectValue);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else if (!exec_cmd(param, run)) {
|
|
|
|
TLOGW("exec_cmd failed!");
|
2025-03-28 12:20:58 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2025-04-07 11:49:13 +08:00
|
|
|
if (!run && !param.direct_use && !param.last_use && !param.null_use) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ip.empty()) {
|
|
|
|
std::vector<TransmSet> sets;
|
|
|
|
if (!g_Config->read_ini(sets)) {
|
2025-03-28 12:01:35 +08:00
|
|
|
return -1;
|
|
|
|
}
|
2025-04-07 11:49:13 +08:00
|
|
|
|
|
|
|
if (param.null_use) {
|
|
|
|
if (!select_server(sets, ip, port)) {
|
2025-03-28 12:20:58 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
2025-04-07 11:49:13 +08:00
|
|
|
if (param.last_use) {
|
|
|
|
if (!g_Config->get_last_use(ip, port)) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
TransmSet use;
|
|
|
|
if (!g_Config->get_ini(sets, param.use_config, use)) {
|
|
|
|
TLOGW("Not found config by num:[{}]", param.use_config);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
ip = use.ip;
|
|
|
|
port = use.port;
|
2025-03-28 12:20:58 +08:00
|
|
|
}
|
2025-03-28 12:01:35 +08:00
|
|
|
}
|
2025-04-07 11:49:13 +08:00
|
|
|
g_Config->save_last_use(ip, port);
|
2024-12-16 09:40:57 +08:00
|
|
|
}
|
2025-03-01 03:49:40 +08:00
|
|
|
TLOGI("Build At {} {} under {} on {}", __DATE__, __TIME__, VERSION_GIT_COMMIT, VERSION_GIT_BRANCH);
|
2025-03-28 12:01:35 +08:00
|
|
|
TLOGI("use ip => [{}], port => [{}]", ip, port);
|
2025-04-13 00:08:50 +08:00
|
|
|
std::shared_ptr<TransmClient> client = std::make_shared<TransmClient>();
|
|
|
|
client->run(ip, std::to_string(port), g_Config->get_config_dir());
|
2025-03-01 03:49:40 +08:00
|
|
|
TLOGI("exit ==========");
|
2024-12-11 08:44:14 +08:00
|
|
|
return 0;
|
|
|
|
}
|