Compare commits
No commits in common. "main" and "v1.5.0" have entirely different histories.
@ -11,7 +11,13 @@ ReflowComments: true
|
||||
SpacesBeforeTrailingComments: 3
|
||||
TabWidth: 4
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ColumnLimit: 130
|
||||
ColumnLimit: 110
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
AllowShortEnumsOnASingleLine: false
|
||||
IncludeBlocks: Regroup
|
||||
IncludeCategories:
|
||||
- Regex: '^<.*>'
|
||||
Priority: 1
|
||||
- Regex: '^".*"'
|
||||
Priority: 2
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -6,4 +6,3 @@ cmake-*
|
||||
compile_commands.json
|
||||
out
|
||||
xpbuild
|
||||
cbuild
|
||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -6,6 +6,3 @@
|
||||
path = filecomplete
|
||||
url = https://www.sinxmiao.cn/taynpg/filecomplete
|
||||
branch = main
|
||||
[submodule "crashelper"]
|
||||
path = crashelper
|
||||
url = https://www.sinxmiao.cn/taynpg/crashelper
|
||||
|
88
.vscode/settings.json
vendored
88
.vscode/settings.json
vendored
@ -1,8 +1,10 @@
|
||||
{
|
||||
"files.autoSave": "onFocusChange",
|
||||
"editor.fontSize": 13,
|
||||
"editor.fontFamily": "'Monaspace Krypton Light', 'Monaspace Krypton Light', 'Monaspace Krypton Light'",
|
||||
"terminal.integrated.fontFamily": "Monaspace Krypton Light",
|
||||
"editor.fontSize": 14,
|
||||
"editor.fontFamily": "'Source Code Pro', 'Source Code Pro', 'Source Code Pro'",
|
||||
"terminal.integrated.fontFamily": "Source Code Pro",
|
||||
"editor.fontLigatures": true,
|
||||
//"C_Cpp.default.configurationProvider": "tboox.xmake-vscode",
|
||||
"cmake.configureOnOpen": true,
|
||||
"cmake.debugConfig": {
|
||||
"console": "integratedTerminal",
|
||||
@ -17,20 +19,24 @@
|
||||
"ignoreFailures": true
|
||||
}
|
||||
],
|
||||
"visualizerFile": "${workspaceRoot}/.vscode/qt5.natvis",
|
||||
"args": [
|
||||
"9999"
|
||||
"-u", "0"
|
||||
]
|
||||
},
|
||||
"cmake.environment": {
|
||||
"PATH": "${env:PATH};"
|
||||
},
|
||||
"cmake.configureArgs": [
|
||||
"-Wno-dev",
|
||||
"-DGRAB_CRASH=ON"
|
||||
"-DCMAKE_PREFIX_PATH:STRING=C:/dev/wxwigets",
|
||||
"-DUSE_GUI=ON",
|
||||
"-DUSE_TRANSM_TEST=ON"
|
||||
],
|
||||
"cmake.configureSettings": {
|
||||
//"CMAKE_TOOLCHAIN_FILE": "${env:VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
|
||||
},
|
||||
"cmake.options.statusBarVisibility": "visible",
|
||||
"cmake.generator": "Ninja",
|
||||
"C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools",
|
||||
"C_Cpp.default.compileCommands": "${workspaceRoot}/build/compile_commands.json",
|
||||
"C_Cpp.default.cppStandard": "c++17",
|
||||
"editor.inlayHints.enabled": "off",
|
||||
"editor.unicodeHighlight.allowedLocales": {
|
||||
"ja": true,
|
||||
@ -38,27 +44,22 @@
|
||||
"zh-hans": true
|
||||
},
|
||||
"files.associations": {
|
||||
".clang-tidy": "yaml",
|
||||
"filesystem": "cpp",
|
||||
"regex": "cpp",
|
||||
"functional": "cpp",
|
||||
"xstring": "cpp",
|
||||
"vector": "cpp",
|
||||
"string": "cpp",
|
||||
"algorithm": "cpp",
|
||||
"any": "cpp",
|
||||
"array": "cpp",
|
||||
"atomic": "cpp",
|
||||
"bit": "cpp",
|
||||
"bitset": "cpp",
|
||||
"cctype": "cpp",
|
||||
"charconv": "cpp",
|
||||
"chrono": "cpp",
|
||||
"cinttypes": "cpp",
|
||||
"clocale": "cpp",
|
||||
"cmath": "cpp",
|
||||
"codecvt": "cpp",
|
||||
"compare": "cpp",
|
||||
"complex": "cpp",
|
||||
"concepts": "cpp",
|
||||
"condition_variable": "cpp",
|
||||
"coroutine": "cpp",
|
||||
"csignal": "cpp",
|
||||
"cstdarg": "cpp",
|
||||
"cstddef": "cpp",
|
||||
@ -68,13 +69,13 @@
|
||||
"cstring": "cpp",
|
||||
"ctime": "cpp",
|
||||
"cwchar": "cpp",
|
||||
"cwctype": "cpp",
|
||||
"deque": "cpp",
|
||||
"exception": "cpp",
|
||||
"expected": "cpp",
|
||||
"resumable": "cpp",
|
||||
"format": "cpp",
|
||||
"filesystem": "cpp",
|
||||
"forward_list": "cpp",
|
||||
"fstream": "cpp",
|
||||
"functional": "cpp",
|
||||
"future": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"iomanip": "cpp",
|
||||
@ -98,22 +99,21 @@
|
||||
"ratio": "cpp",
|
||||
"set": "cpp",
|
||||
"shared_mutex": "cpp",
|
||||
"source_location": "cpp",
|
||||
"sstream": "cpp",
|
||||
"stack": "cpp",
|
||||
"stdexcept": "cpp",
|
||||
"stop_token": "cpp",
|
||||
"streambuf": "cpp",
|
||||
"string": "cpp",
|
||||
"string_view": "cpp",
|
||||
"strstream": "cpp",
|
||||
"system_error": "cpp",
|
||||
"thread": "cpp",
|
||||
"tuple": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"typeindex": "cpp",
|
||||
"typeinfo": "cpp",
|
||||
"unordered_map": "cpp",
|
||||
"utility": "cpp",
|
||||
"valarray": "cpp",
|
||||
"variant": "cpp",
|
||||
"vector": "cpp",
|
||||
"xfacet": "cpp",
|
||||
"xhash": "cpp",
|
||||
"xiosbase": "cpp",
|
||||
@ -125,9 +125,39 @@
|
||||
"xlocnum": "cpp",
|
||||
"xloctime": "cpp",
|
||||
"xmemory": "cpp",
|
||||
"xstring": "cpp",
|
||||
"xmemory0": "cpp",
|
||||
"xstddef": "cpp",
|
||||
"xtr1common": "cpp",
|
||||
"xtree": "cpp",
|
||||
"xutility": "cpp"
|
||||
}
|
||||
"xutility": "cpp",
|
||||
"qbytearray": "cpp",
|
||||
"*.ipp": "cpp",
|
||||
"xthread": "cpp",
|
||||
"*.tcc": "cpp",
|
||||
"regex": "cpp",
|
||||
"bit": "cpp",
|
||||
"memory_resource": "cpp",
|
||||
"source_location": "cpp",
|
||||
"charconv": "cpp",
|
||||
"compare": "cpp",
|
||||
"concepts": "cpp",
|
||||
"coroutine": "cpp",
|
||||
"format": "cpp",
|
||||
"stop_token": "cpp",
|
||||
"expected": "cpp",
|
||||
"numbers": "cpp",
|
||||
"semaphore": "cpp",
|
||||
"span": "cpp",
|
||||
"text_encoding": "cpp",
|
||||
"*.in": "cpp",
|
||||
"hash_map": "cpp",
|
||||
"stdfloat": "cpp",
|
||||
"unordered_set": "cpp",
|
||||
"cfenv": "cpp",
|
||||
"cassert": "cpp",
|
||||
"version": "cpp",
|
||||
"resumable": "cpp"
|
||||
},
|
||||
"makefile.configureOnOpen": false,
|
||||
"C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools"
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
10497
3rd/httplib.h
10497
3rd/httplib.h
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(transm VERSION 1.5.2 LANGUAGES CXX)
|
||||
project(transm VERSION 1.5.0 LANGUAGES CXX)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
@ -11,7 +11,6 @@ set(PROJECT_URL "https://www.sinxmiao.cn/taynpg/transm")
|
||||
set(COMPILER_ID ${CMAKE_CXX_COMPILER_ID})
|
||||
if(MSVC)
|
||||
add_compile_options(/source-charset:utf-8)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_SYSTEM_NAME MATCHES "Windows")
|
||||
@ -46,12 +45,6 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY
|
||||
${PROJECT_BINARY_DIR}/bin/${CMAKE_BUILD_TYPE}/
|
||||
)
|
||||
|
||||
if (DEFINED GRAB_CRASH)
|
||||
message(STATUS "GRAB_CRASH ${GRAB_CRASH}")
|
||||
add_subdirectory(crashelper/crashelper)
|
||||
add_definitions(-DGRAB_CRASH)
|
||||
endif()
|
||||
|
||||
add_definitions(-DFMT_HEADER_ONLY)
|
||||
include_directories(3rd)
|
||||
include_directories(.)
|
||||
@ -64,16 +57,8 @@ add_subdirectory(client)
|
||||
add_subdirectory(filecomplete)
|
||||
add_subdirectory(tinyaes)
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_SYSTEM_NAME MATCHES "Windows")
|
||||
message(STATUS "tss-http can't support mingw, will not compile.")
|
||||
else()
|
||||
add_subdirectory(http-server)
|
||||
endif()
|
||||
|
||||
if (DEFINED USE_TRANSM_TEST)
|
||||
message(STATUS "USE USE_TRANSM_TEST ${USE_TRANSM_TEST}")
|
||||
add_definitions(-DUSE_TRANSM_TEST)
|
||||
include(CTest)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
||||
@ -98,12 +83,6 @@ message(STATUS "VERSION_GIT_HASH: ${VERSION_GIT_HASH}")
|
||||
install(TARGETS tsc DESTINATION bin)
|
||||
install(TARGETS tss DESTINATION bin)
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_SYSTEM_NAME MATCHES "Windows")
|
||||
message(STATUS "tss-http can't support mingw, will not pack.")
|
||||
else()
|
||||
install(TARGETS tss-http DESTINATION bin)
|
||||
endif()
|
||||
|
||||
if (DEFINED USE_BOOST)
|
||||
install(FILES ${MINGW32_DLLS} DESTINATION bin)
|
||||
endif()
|
||||
|
63
CMakeSettings.json
Normal file
63
CMakeSettings.json
Normal file
@ -0,0 +1,63 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "x64 Local Debug",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "Debug",
|
||||
"inheritEnvironments": [ "msvc_x64_x64" ],
|
||||
"buildRoot": "${projectDir}\\out\\build\\${name}",
|
||||
"installRoot": "${projectDir}\\out\\install\\${name}",
|
||||
"cmakeCommandArgs": "",
|
||||
"buildCommandArgs": "",
|
||||
"ctestCommandArgs": ""
|
||||
},
|
||||
{
|
||||
"name": "x64 Local Release",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "Release",
|
||||
"inheritEnvironments": [ "msvc_x64_x64" ],
|
||||
"buildRoot": "${projectDir}\\out\\build\\${name}",
|
||||
"installRoot": "${projectDir}\\out\\install\\${name}"
|
||||
},
|
||||
{
|
||||
"name": "x64 Linux Debug",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "Debug",
|
||||
"cmakeExecutable": "cmake",
|
||||
"remoteCopySourcesExclusionList": [ ".vs", "out" ],
|
||||
"cmakeCommandArgs": "",
|
||||
"buildCommandArgs": "",
|
||||
"ctestCommandArgs": "",
|
||||
"inheritEnvironments": [ "linux_x64" ],
|
||||
"remoteMachineName": "${defaultRemoteMachineName}",
|
||||
"remoteCMakeListsRoot": "$HOME/vs/${projectDirName}/${workspaceHash}/src",
|
||||
"remoteBuildRoot": "$HOME/vs/${projectDirName}/${workspaceHash}/out/build/${name}",
|
||||
"remoteInstallRoot": "$HOME/vs/${projectDirName}/${workspaceHash}/out/install/${name}",
|
||||
"remoteCopySources": true,
|
||||
"rsyncCommandArgs": "-t --delete",
|
||||
"remoteCopyBuildOutput": false,
|
||||
"remoteCopySourcesMethod": "rsync",
|
||||
"variables": []
|
||||
},
|
||||
{
|
||||
"name": "x64 Linux Release",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "Release",
|
||||
"cmakeExecutable": "cmake",
|
||||
"remoteCopySourcesExclusionList": [ ".vs", "out" ],
|
||||
"cmakeCommandArgs": "",
|
||||
"buildCommandArgs": "",
|
||||
"ctestCommandArgs": "",
|
||||
"inheritEnvironments": [ "linux_x64" ],
|
||||
"remoteMachineName": "${defaultRemoteMachineName}",
|
||||
"remoteCMakeListsRoot": "$HOME/vs/${projectDirName}/${workspaceHash}/src",
|
||||
"remoteBuildRoot": "$HOME/vs/${projectDirName}/${workspaceHash}/out/build/${name}",
|
||||
"remoteInstallRoot": "$HOME/vs/${projectDirName}/${workspaceHash}/out/install/${name}",
|
||||
"remoteCopySources": true,
|
||||
"rsyncCommandArgs": "-t --delete",
|
||||
"remoteCopyBuildOutput": false,
|
||||
"remoteCopySourcesMethod": "rsync",
|
||||
"variables": []
|
||||
}
|
||||
]
|
||||
}
|
10
README.md
10
README.md
@ -18,9 +18,7 @@
|
||||
|
||||
## 一些特点(基于最新版本)
|
||||
|
||||
- 易编译。
|
||||
- 通配符传输。
|
||||
- 公网传输支持加密。
|
||||
- 广泛的平台支持。
|
||||
- 终端自动文件补全。
|
||||
- 自动检测对方掉线。
|
||||
@ -42,7 +40,7 @@
|
||||
## 1.程序启动
|
||||
|
||||
- 对于服务端程序`tss`,绑定默认绑定`0.0.0.0`的`9898`端口,如果需要修改端口,使用参数启动,示例:`tss 9898`。
|
||||
- 对于客户端程序`tsc`,请使用`tsc --help`查看如何启动。
|
||||
- 对于客户端程序`tsc`,请使用`tsc --help`查看使用方式。
|
||||
|
||||
## 2.使用
|
||||
|
||||
@ -96,12 +94,6 @@ Data verification: PASSED
|
||||
*/
|
||||
```
|
||||
|
||||
- `v1.5.2`及其以后的代码版本:新增了`tss-http`服务端,简单用于某些时候,客户机上没有`tsc`和`tss`程序时,通过`http`协议传输文件。
|
||||
|
||||
> 关于`tss-http`编译:不支持`mingw`编译,因此`win8`及以下没有此程序支持。
|
||||
|
||||
> 示例启动:`tss-http 8080 D:/files`(参数为端口、根目录)。
|
||||
|
||||
# 三、编译
|
||||
|
||||
当前项目支持`cmake`构建工具。
|
||||
|
@ -24,10 +24,6 @@ if(DEFINED USE_BOOST)
|
||||
target_link_directories(tsc PRIVATE ${MBOOST_LIB_DIR})
|
||||
target_link_libraries(tsc PRIVATE ${MBOOST_LIBS})
|
||||
endif()
|
||||
if (DEFINED GRAB_CRASH)
|
||||
message(STATUS "tsc link crashelper")
|
||||
target_link_libraries(tsc PRIVATE crashelper)
|
||||
endif()
|
||||
if(UNIX)
|
||||
execute_process(
|
||||
COMMAND uname -a
|
||||
|
@ -15,13 +15,13 @@ namespace fs = boost::filesystem;
|
||||
namespace fs = std::filesystem;
|
||||
#endif
|
||||
|
||||
TransmClient::TransmClient() : msg_info_("")
|
||||
CClient::CClient() : msg_info_("")
|
||||
{
|
||||
client_ = std::make_shared<CTcpClient>(io_context_);
|
||||
sleep_.set_timeout(5000);
|
||||
}
|
||||
|
||||
TransmClient::~TransmClient()
|
||||
CClient::~CClient()
|
||||
{
|
||||
th_run_ = false;
|
||||
sleep_.contiune();
|
||||
@ -48,12 +48,9 @@ TransmClient::~TransmClient()
|
||||
if (hearts_.joinable()) {
|
||||
hearts_.join();
|
||||
}
|
||||
if (context_th_.joinable()) {
|
||||
context_th_.join();
|
||||
}
|
||||
}
|
||||
|
||||
void TransmClient::print_help(bool detail)
|
||||
void CClient::print_help(bool detail)
|
||||
{
|
||||
TLOGI("version: {}", VERSION_NUM);
|
||||
TLOGI("opensource: {}", VERSION_URL);
|
||||
@ -126,7 +123,16 @@ void TransmClient::print_help(bool detail)
|
||||
TLOGI("{}", sp);
|
||||
}
|
||||
|
||||
bool TransmClient::base_init(const std::string& ip, const std::string& port, const std::string& config_dir)
|
||||
void CClient::free_buf_manual(CFrameBuffer* buf)
|
||||
{
|
||||
if (buf == nullptr) {
|
||||
return;
|
||||
}
|
||||
delete buf->data_;
|
||||
buf->data_ = nullptr;
|
||||
}
|
||||
|
||||
void CClient::run(const std::string& ip, const std::string& port, const std::string& config_dir)
|
||||
{
|
||||
fs::path fp(config_dir);
|
||||
config_path_ = fp.append("history.txt").string();
|
||||
@ -137,7 +143,7 @@ bool TransmClient::base_init(const std::string& ip, const std::string& port, con
|
||||
uuid_ = read_uuid();
|
||||
if (uuid_.empty()) {
|
||||
TLOGE("uuid is empty!");
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
auto his = load_line_his();
|
||||
@ -148,21 +154,13 @@ bool TransmClient::base_init(const std::string& ip, const std::string& port, con
|
||||
th_run_ = true;
|
||||
if (!client_->connect(ip, port)) {
|
||||
TLOGI("{} connect err.", __FUNCTION__);
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
client_->register_func([&](CFrameBuffer* buf) { handle_frame(buf); });
|
||||
client_->async_recv();
|
||||
hearts_ = std::thread([&]() { hearts(); });
|
||||
context_th_ = std::thread([&]() { io_context_.run(); });
|
||||
std::thread thread([&]() { io_context_.run(); });
|
||||
th_down_active_ = std::thread([&]() { judget_down_active(); });
|
||||
return true;
|
||||
}
|
||||
|
||||
void TransmClient::run(const std::string& ip, const std::string& port, const std::string& config_dir)
|
||||
{
|
||||
if (!base_init(ip, port, config_dir)) {
|
||||
return;
|
||||
}
|
||||
|
||||
print_help(false);
|
||||
fc_append('|');
|
||||
@ -270,62 +268,18 @@ void TransmClient::run(const std::string& ip, const std::string& port, const std
|
||||
TLOGE("No matched cmd, May be param size incorrect.");
|
||||
}
|
||||
client_->disconnect();
|
||||
thread.join();
|
||||
TLOGI("{} exit.", __FUNCTION__);
|
||||
}
|
||||
|
||||
#ifdef USE_TRANSM_TEST
|
||||
bool TransmClient::connect_for_test(const std::string& ip, const std::string& port,
|
||||
const std::string& config_dir)
|
||||
{
|
||||
if (!base_init(ip, port, config_dir)) {
|
||||
return false;
|
||||
}
|
||||
get_clients();
|
||||
get_id();
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string TransmClient::test_get_own_id() const
|
||||
{
|
||||
return own_id_;
|
||||
}
|
||||
|
||||
void TransmClient::set_task_state(TaskState state)
|
||||
{
|
||||
task_state_ = state;
|
||||
}
|
||||
|
||||
TransmClient::TaskState TransmClient::get_task_state() const
|
||||
{
|
||||
return task_state_;
|
||||
}
|
||||
|
||||
void TransmClient::disconnect_for_test()
|
||||
{
|
||||
client_->disconnect();
|
||||
}
|
||||
|
||||
int TransmClient::test_index_by_id(const std::string& id)
|
||||
{
|
||||
int ret = -1;
|
||||
for (const auto& item : clients_) {
|
||||
if (item.second->id == id) {
|
||||
ret = item.first;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool TransmClient::get_clients()
|
||||
bool CClient::get_clients()
|
||||
{
|
||||
std::shared_ptr<CFrameBuffer> buf = std::make_shared<CFrameBuffer>();
|
||||
buf->type_ = TYPE_GET_LIST;
|
||||
return send_frame(buf.get());
|
||||
}
|
||||
|
||||
bool TransmClient::cmd_fetch_files(const std::string& param)
|
||||
bool CClient::cmd_fetch_files(const std::string& param)
|
||||
{
|
||||
if (downloading_) {
|
||||
TLOGW("Have Task Downloading, Please wait.....");
|
||||
@ -361,25 +315,16 @@ bool TransmClient::cmd_fetch_files(const std::string& param)
|
||||
}
|
||||
|
||||
// 开始传输文件
|
||||
bool ret = true;
|
||||
for (const auto& item : vec) {
|
||||
if (!down_one_file(id, item, relative_path)) {
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
}
|
||||
#ifdef USE_TRANSM_TEST
|
||||
if (ret) {
|
||||
task_state_ = TaskState::TASK_STATE_DONE;
|
||||
} else {
|
||||
task_state_ = TaskState::TASK_STATE_ERROR;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TransmClient::cmd_sub_list(const std::string& param)
|
||||
bool CClient::cmd_sub_list(const std::string& param)
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
@ -431,7 +376,7 @@ bool TransmClient::cmd_sub_list(const std::string& param)
|
||||
return send_frame(buf.get());
|
||||
}
|
||||
|
||||
bool TransmClient::cmd_clear_submited()
|
||||
bool CClient::cmd_clear_submited()
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
@ -447,7 +392,7 @@ bool TransmClient::cmd_clear_submited()
|
||||
return send_frame(buf.get());
|
||||
}
|
||||
|
||||
bool TransmClient::cmd_upload_files(const std::string& param)
|
||||
bool CClient::cmd_upload_files(const std::string& param)
|
||||
{
|
||||
auto tvec = COfStr::split(param, " ");
|
||||
if (tvec.size() < 3) {
|
||||
@ -520,7 +465,7 @@ bool TransmClient::cmd_upload_files(const std::string& param)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TransmClient::down_one_file(int remote_id, const std::string& file, const std::string& local_dir)
|
||||
bool CClient::down_one_file(int remote_id, const std::string& file, const std::string& local_dir)
|
||||
{
|
||||
std::string ret_id{};
|
||||
std::string ret_uuid{};
|
||||
@ -605,7 +550,7 @@ bool TransmClient::down_one_file(int remote_id, const std::string& file, const s
|
||||
}
|
||||
}
|
||||
|
||||
void TransmClient::report_trans_ret(TransState state, const std::string& key)
|
||||
void CClient::report_trans_ret(TransState state, const std::string& key)
|
||||
{
|
||||
std::shared_ptr<TransInfomation> t = nullptr;
|
||||
if (key.empty()) {
|
||||
@ -638,7 +583,7 @@ void TransmClient::report_trans_ret(TransState state, const std::string& key)
|
||||
|
||||
功能为,请求某个客户端,更新我所列出的文件,右侧是远端需要存储的目录(必须存在,不存在则不理会)
|
||||
*/
|
||||
bool TransmClient::cmd_sub_task(const std::string& param, bool is_send)
|
||||
bool CClient::cmd_sub_task(const std::string& param, bool is_send)
|
||||
{
|
||||
auto tvec = COfStr::split(param, " ");
|
||||
if (tvec.size() < 2) {
|
||||
@ -724,11 +669,7 @@ bool TransmClient::cmd_sub_task(const std::string& param, bool is_send)
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef USE_TRANSM_TEST
|
||||
auto handel_ret = handle_user_select(mre, false);
|
||||
#else
|
||||
auto handel_ret = handle_user_select(mre, is_send);
|
||||
#endif
|
||||
if (handel_ret.empty()) {
|
||||
TLOGE("handle_user_select not pass, abort action!");
|
||||
return false;
|
||||
@ -754,8 +695,7 @@ bool TransmClient::cmd_sub_task(const std::string& param, bool is_send)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TransmClient::variable_and_parse_files(const std::string& content,
|
||||
std::map<std::string, std::string>& files)
|
||||
bool CClient::variable_and_parse_files(const std::string& content, std::map<std::string, std::string>& files)
|
||||
{
|
||||
auto vec = COfStr::split(content, "\n");
|
||||
bool valid = true;
|
||||
@ -781,7 +721,7 @@ bool TransmClient::variable_and_parse_files(const std::string& content,
|
||||
return valid;
|
||||
}
|
||||
|
||||
bool TransmClient::down_update_file(const std::map<std::string, std::string>& files)
|
||||
bool CClient::down_update_file(const std::map<std::string, std::string>& files)
|
||||
{
|
||||
std::shared_ptr<CFrameBuffer> buf = std::make_shared<CFrameBuffer>();
|
||||
buf->tid_ = list_server_id_;
|
||||
@ -813,7 +753,7 @@ bool TransmClient::down_update_file(const std::map<std::string, std::string>& fi
|
||||
return suc;
|
||||
}
|
||||
|
||||
bool TransmClient::get_dir_files(const std::string& dir, std::string& out, std::string& error)
|
||||
bool CClient::get_dir_files(const std::string& dir, std::string& out, std::string& error)
|
||||
{
|
||||
fs::path p(dir);
|
||||
out.clear();
|
||||
@ -833,7 +773,7 @@ bool TransmClient::get_dir_files(const std::string& dir, std::string& out, std::
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TransmClient::cmd_ls(const std::string& param)
|
||||
bool CClient::cmd_ls(const std::string& param)
|
||||
{
|
||||
auto tvec = COfStr::split(param, " ");
|
||||
if (tvec.size() < 2) {
|
||||
@ -853,8 +793,8 @@ bool TransmClient::cmd_ls(const std::string& param)
|
||||
buf->type_ = TYPE_GET_DIRFILES;
|
||||
CMessageInfo msg_info(own_id_);
|
||||
msg_info.str = path;
|
||||
buf->tid_ = sr->id;
|
||||
serialize(msg_info, &buf->data_, buf->len_);
|
||||
buf->tid_ = sr->id;
|
||||
|
||||
if (!send_frame(buf.get())) {
|
||||
TLOGE("Send Failed {}", __LINE__);
|
||||
@ -863,7 +803,7 @@ bool TransmClient::cmd_ls(const std::string& param)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TransmClient::cmd_down_list(const std::string& param)
|
||||
bool CClient::cmd_down_list(const std::string& param)
|
||||
{
|
||||
auto tvec = COfStr::split(param, " ");
|
||||
if (tvec.size() < 2) {
|
||||
@ -899,7 +839,7 @@ bool TransmClient::cmd_down_list(const std::string& param)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TransmClient::send_frame(CFrameBuffer* buf)
|
||||
bool CClient::send_frame(CFrameBuffer* buf)
|
||||
{
|
||||
char* out_buf{};
|
||||
int out_len{};
|
||||
@ -916,7 +856,7 @@ bool TransmClient::send_frame(CFrameBuffer* buf)
|
||||
return true;
|
||||
}
|
||||
|
||||
void TransmClient::save_line_his(const std::string& input)
|
||||
void CClient::save_line_his(const std::string& input)
|
||||
{
|
||||
if (input.empty()) {
|
||||
return;
|
||||
@ -945,7 +885,7 @@ void TransmClient::save_line_his(const std::string& input)
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> TransmClient::load_line_his()
|
||||
std::vector<std::string> CClient::load_line_his()
|
||||
{
|
||||
std::vector<std::string> history;
|
||||
if (!fs::exists(config_path_)) {
|
||||
@ -964,7 +904,7 @@ std::vector<std::string> TransmClient::load_line_his()
|
||||
return history;
|
||||
}
|
||||
|
||||
std::string TransmClient::variable_and_reverse_files(const std::string& source)
|
||||
std::string CClient::variable_and_reverse_files(const std::string& source)
|
||||
{
|
||||
auto vec = COfStr::split(source, "\n");
|
||||
std::string result;
|
||||
@ -1003,7 +943,7 @@ std::string TransmClient::variable_and_reverse_files(const std::string& source)
|
||||
return result;
|
||||
}
|
||||
|
||||
bool TransmClient::save_uuid()
|
||||
bool CClient::save_uuid()
|
||||
{
|
||||
fs::path uuid_path(uuid_path_);
|
||||
if (fs::exists(uuid_path)) {
|
||||
@ -1022,7 +962,7 @@ bool TransmClient::save_uuid()
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string TransmClient::read_uuid()
|
||||
std::string CClient::read_uuid()
|
||||
{
|
||||
fs::path uuid_path(uuid_path_);
|
||||
if (!fs::exists(uuid_path)) {
|
||||
@ -1039,7 +979,7 @@ std::string TransmClient::read_uuid()
|
||||
return uuid;
|
||||
}
|
||||
|
||||
void TransmClient::get_id()
|
||||
void CClient::get_id()
|
||||
{
|
||||
auto* bf = new CFrameBuffer();
|
||||
bf->type_ = TYPE_GET_ID;
|
||||
@ -1050,7 +990,7 @@ void TransmClient::get_id()
|
||||
delete bf;
|
||||
}
|
||||
|
||||
void TransmClient::handle_frame(CFrameBuffer* buf)
|
||||
void CClient::handle_frame(CFrameBuffer* buf)
|
||||
{
|
||||
if (buf == nullptr) {
|
||||
TLOGE("{} nullptr.", __FUNCTION__);
|
||||
@ -1154,12 +1094,13 @@ void TransmClient::handle_frame(CFrameBuffer* buf)
|
||||
if (!get_dir_files(msg_info.str, out, err)) {
|
||||
TLOGE("Get Dir Files Failed. {}", err);
|
||||
buf->type_ = TYPE_GET_DIRFILES_FAILED;
|
||||
delete[] buf->data_;
|
||||
msg_info.str = err;
|
||||
} else {
|
||||
buf->type_ = TYPE_GET_DIRFILES_DONE;
|
||||
delete[] buf->data_;
|
||||
msg_info.str = out;
|
||||
}
|
||||
msg_info.id = buf->tid_;
|
||||
serialize(msg_info, &buf->data_, buf->len_);
|
||||
std::swap(buf->tid_, buf->fid_);
|
||||
if (!send_frame(buf)) {
|
||||
@ -1275,10 +1216,9 @@ void TransmClient::handle_frame(CFrameBuffer* buf)
|
||||
TLOGE("{} GetList deserialize failed.", __LINE__);
|
||||
break;
|
||||
}
|
||||
delete[] buf->data_;
|
||||
msg_info.str = variable_and_reverse_files(msg_info.str);
|
||||
msg_info.id = buf->tid_;
|
||||
serialize(msg_info, &buf->data_, buf->len_);
|
||||
|
||||
std::swap(buf->tid_, buf->fid_);
|
||||
buf->type_ = TYPE_REQUEST_UPDATE_LIST;
|
||||
if (!send_frame(buf)) {
|
||||
@ -1288,12 +1228,12 @@ void TransmClient::handle_frame(CFrameBuffer* buf)
|
||||
break;
|
||||
};
|
||||
case TYPE_REQUEST_UPDATE_LIST: {
|
||||
CMessageInfo msg_info(buf->fid_);
|
||||
std::map<std::string, std::string> files;
|
||||
if (down_ && down_->trans_state_ == TRANS_REDAY) {
|
||||
TLOGW("Update Busy......, Ignore {}", buf->fid_);
|
||||
buf->type_ = TYPE_BUSY_UPDATE_LIST;
|
||||
} else {
|
||||
CMessageInfo msg_info(buf->fid_);
|
||||
if (!deserialize(buf->data_, buf->len_, msg_info)) {
|
||||
TLOGE("{} GetList deserialize failed.", __LINE__);
|
||||
break;
|
||||
@ -1305,8 +1245,6 @@ void TransmClient::handle_frame(CFrameBuffer* buf)
|
||||
buf->type_ = TYPE_UNCONFIRM_UPDATE_LIST;
|
||||
}
|
||||
}
|
||||
msg_info.id = buf->tid_;
|
||||
serialize(msg_info, &buf->data_, buf->len_);
|
||||
std::swap(buf->tid_, buf->fid_);
|
||||
if (!send_frame(buf)) {
|
||||
TLOGE("Send Failed {}.", __LINE__);
|
||||
@ -1329,16 +1267,10 @@ void TransmClient::handle_frame(CFrameBuffer* buf)
|
||||
}
|
||||
case TYPE_UNCONFIRM_UPDATE_LIST: {
|
||||
TLOGE("remote {} check {} not passed!", buf->fid_, list_file_);
|
||||
#ifdef USE_TRANSM_TEST
|
||||
task_state_ = TaskState::TASK_STATE_ERROR;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case TYPE_DONE_UPDATE_LIST: {
|
||||
TLOGI("remote {} do task {} success!", buf->fid_, list_file_);
|
||||
#ifdef USE_TRANSM_TEST
|
||||
task_state_ = TaskState::TASK_STATE_DONE;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case TYPE_FAILED_UPDATE_LIST: {
|
||||
@ -1376,7 +1308,7 @@ void TransmClient::handle_frame(CFrameBuffer* buf)
|
||||
}
|
||||
}
|
||||
|
||||
void TransmClient::send_file_data_th(const char* keys)
|
||||
void CClient::send_file_data_th(const char* keys)
|
||||
{
|
||||
std::string str_key(keys);
|
||||
std::shared_ptr<TransInfomation> t = nullptr;
|
||||
@ -1400,11 +1332,9 @@ void TransmClient::send_file_data_th(const char* keys)
|
||||
// ********************************************************
|
||||
|
||||
// seekg 用于读,seekp 用于写。
|
||||
// t->file_.seekg(0, std::ios::end);
|
||||
// long long size = t->file_.tellg();
|
||||
// t->file_.seekg(0, std::ios::beg);
|
||||
|
||||
auto size = fs::file_size(t->cur_file_);
|
||||
t->file_.seekg(0, std::ios::end);
|
||||
long long size = t->file_.tellg();
|
||||
t->file_.seekg(0, std::ios::beg);
|
||||
buf->type_ = TYPE_FILE_INFO;
|
||||
std::string str_size = std::to_string(size);
|
||||
|
||||
@ -1429,9 +1359,7 @@ void TransmClient::send_file_data_th(const char* keys)
|
||||
return;
|
||||
}
|
||||
|
||||
delete[] buf->data_;
|
||||
buf->data_ = nullptr;
|
||||
|
||||
free_buf_manual(buf.get());
|
||||
buf->type_ = TYPE_TRANS_FILE;
|
||||
buf->mark_ = 1;
|
||||
|
||||
@ -1448,7 +1376,7 @@ void TransmClient::send_file_data_th(const char* keys)
|
||||
cur_send_size = t->file_.gcount();
|
||||
msg_info.data.resize(cur_send_size);
|
||||
send_size += cur_send_size;
|
||||
serialize(msg_info, &buf->data_, buf->len_, true);
|
||||
serialize(msg_info, &buf->data_, buf->len_);
|
||||
if (!send_frame(buf.get())) {
|
||||
report_trans_ret(TRANS_FAILED, str_key);
|
||||
TLOGE("Stop Trans {} To {} failed.", t->cur_file_, str_key);
|
||||
@ -1464,7 +1392,7 @@ void TransmClient::send_file_data_th(const char* keys)
|
||||
TLOGD("Trans File {} To {} Done !!!, {}", t->cur_file_, str_key, send_size);
|
||||
}
|
||||
|
||||
void TransmClient::hearts()
|
||||
void CClient::hearts()
|
||||
{
|
||||
std::shared_ptr<CFrameBuffer> buf = std::make_shared<CFrameBuffer>();
|
||||
buf->type_ = TYPE_HEARTS;
|
||||
@ -1477,7 +1405,7 @@ void TransmClient::hearts()
|
||||
}
|
||||
}
|
||||
|
||||
void TransmClient::judget_down_active()
|
||||
void CClient::judget_down_active()
|
||||
{
|
||||
std::shared_ptr<CFrameBuffer> buf = std::make_shared<CFrameBuffer>();
|
||||
buf->type_ = TYPE_JUDGE_ACTIVE;
|
||||
@ -1493,8 +1421,8 @@ void TransmClient::judget_down_active()
|
||||
}
|
||||
}
|
||||
|
||||
std::string TransmClient::variable_handle(const std::string& task_list_path, const std::string& source,
|
||||
bool is_local)
|
||||
std::string CClient::variable_handle(const std::string& task_list_path, const std::string& source,
|
||||
bool is_local)
|
||||
{
|
||||
std::string result(source);
|
||||
// 支持的变量如下:
|
||||
@ -1514,7 +1442,7 @@ std::string TransmClient::variable_handle(const std::string& task_list_path, con
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string TransmClient::handle_user_select(const std::unordered_map<int, std::string>& source, bool is_send)
|
||||
std::string CClient::handle_user_select(const std::unordered_map<int, std::string>& source, bool is_send)
|
||||
{
|
||||
std::string handled_content{};
|
||||
std::string input{};
|
||||
|
@ -38,29 +38,29 @@ struct TransInfomation {
|
||||
};
|
||||
|
||||
constexpr int down_check_wait = 100; // millsec
|
||||
class TransmClient
|
||||
class CClient
|
||||
{
|
||||
public:
|
||||
TransmClient();
|
||||
~TransmClient();
|
||||
CClient();
|
||||
~CClient();
|
||||
|
||||
public:
|
||||
void run(const std::string& ip, const std::string& port, const std::string& config_dir);
|
||||
|
||||
public:
|
||||
bool get_clients();
|
||||
bool cmd_fetch_files(const std::string& param);
|
||||
bool cmd_sub_list(const std::string& param);
|
||||
bool cmd_clear_submited();
|
||||
bool cmd_upload_files(const std::string& param);
|
||||
bool down_one_file(int remote_id, const std::string& file, const std::string& local_dir = "");
|
||||
void report_trans_ret(TransState state, const std::string& key = "");
|
||||
bool cmd_sub_task(const std::string& param, bool is_send);
|
||||
bool cmd_ls(const std::string& param);
|
||||
bool cmd_down_list(const std::string& param);
|
||||
|
||||
private:
|
||||
bool variable_and_parse_files(const std::string& content, std::map<std::string, std::string>& files);
|
||||
bool down_update_file(const std::map<std::string, std::string>& files);
|
||||
bool get_dir_files(const std::string& dir, std::string& out, std::string& error);
|
||||
void report_trans_ret(TransState state, const std::string& key = "");
|
||||
bool down_one_file(int remote_id, const std::string& file, const std::string& local_dir = "");
|
||||
bool cmd_ls(const std::string& param);
|
||||
bool cmd_down_list(const std::string& param);
|
||||
|
||||
private:
|
||||
bool send_frame(CFrameBuffer* buf);
|
||||
@ -71,7 +71,7 @@ private:
|
||||
std::string read_uuid();
|
||||
void get_id();
|
||||
void print_help(bool detail);
|
||||
bool base_init(const std::string& ip, const std::string& port, const std::string& config_dir);
|
||||
void free_buf_manual(CFrameBuffer* buf);
|
||||
|
||||
private:
|
||||
void handle_frame(CFrameBuffer* buf);
|
||||
@ -97,7 +97,6 @@ private:
|
||||
std::shared_ptr<TransInfomation> down_;
|
||||
std::vector<std::thread> ths_;
|
||||
std::map<std::string, std::shared_ptr<TransInfomation>> up_;
|
||||
std::thread context_th_;
|
||||
std::thread th_down_active_;
|
||||
long long cur_file_size_{};
|
||||
long long cur_down_size_{};
|
||||
@ -111,27 +110,6 @@ private:
|
||||
std::string config_path_{};
|
||||
std::string uuid_path_{};
|
||||
std::string uuid_{};
|
||||
|
||||
#ifdef USE_TRANSM_TEST
|
||||
public:
|
||||
enum TaskState {
|
||||
TASK_STATE_IDLE,
|
||||
TASK_STATE_RUNNING,
|
||||
TASK_STATE_DONE,
|
||||
TASK_STATE_ERROR
|
||||
};
|
||||
|
||||
public:
|
||||
bool connect_for_test(const std::string& ip, const std::string& port, const std::string& config_dir);
|
||||
void disconnect_for_test();
|
||||
int test_index_by_id(const std::string& id);
|
||||
std::string test_get_own_id() const;
|
||||
void set_task_state(TaskState state);
|
||||
TaskState get_task_state() const;
|
||||
|
||||
private:
|
||||
TaskState task_state_{};
|
||||
#endif
|
||||
};
|
||||
|
||||
class CFileOpr
|
||||
|
@ -10,13 +10,13 @@ namespace fs = boost::filesystem;
|
||||
namespace fs = std::filesystem;
|
||||
#endif
|
||||
|
||||
ClientConfig::ClientConfig()
|
||||
CServerConfig::CServerConfig()
|
||||
{
|
||||
}
|
||||
|
||||
ClientConfig::~ClientConfig() = default;
|
||||
CServerConfig::~CServerConfig() = default;
|
||||
|
||||
bool ClientConfig::baseInit()
|
||||
bool CServerConfig::baseInit()
|
||||
{
|
||||
fs::path tpath(COfPath::get_config_dir("transm", true));
|
||||
config_dir_ = tpath.string();
|
||||
@ -33,7 +33,7 @@ bool ClientConfig::baseInit()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ClientConfig::read_ini(std::vector<TransmSet>& set)
|
||||
bool CServerConfig::read_ini(std::vector<TransmSet>& set)
|
||||
{
|
||||
assert(init_ == true);
|
||||
long groups = ini_handle_.GetLongValue("BASE", "GROUPS");
|
||||
@ -59,7 +59,7 @@ bool ClientConfig::read_ini(std::vector<TransmSet>& set)
|
||||
return true;
|
||||
}
|
||||
|
||||
long ClientConfig::have_ini(const std::vector<TransmSet>& set, const std::string& ip, long port)
|
||||
long CServerConfig::have_ini(const std::vector<TransmSet>& set, const std::string& ip, long port)
|
||||
{
|
||||
long id = -1;
|
||||
for (const auto& item : set) {
|
||||
@ -71,7 +71,7 @@ long ClientConfig::have_ini(const std::vector<TransmSet>& set, const std::string
|
||||
return id;
|
||||
}
|
||||
|
||||
bool ClientConfig::write_ini(const std::vector<TransmSet>& set)
|
||||
bool CServerConfig::write_ini(const std::vector<TransmSet>& set)
|
||||
{
|
||||
assert(init_ == true);
|
||||
for (size_t start = 0; start < set.size(); ++start) {
|
||||
@ -84,7 +84,7 @@ bool ClientConfig::write_ini(const std::vector<TransmSet>& set)
|
||||
return true;
|
||||
}
|
||||
|
||||
long ClientConfig::append_ini(const std::string& ip, long port, const std::string& comment)
|
||||
long CServerConfig::append_ini(const std::string& ip, long port, const std::string& comment)
|
||||
{
|
||||
assert(init_ == true);
|
||||
long id = -1;
|
||||
@ -109,7 +109,7 @@ long ClientConfig::append_ini(const std::string& ip, long port, const std::strin
|
||||
return id;
|
||||
}
|
||||
|
||||
bool ClientConfig::remove_ini(long num)
|
||||
bool CServerConfig::remove_ini(long num)
|
||||
{
|
||||
assert(init_ == true);
|
||||
std::vector<TransmSet> set;
|
||||
@ -124,7 +124,7 @@ bool ClientConfig::remove_ini(long num)
|
||||
return write_ini(set);
|
||||
}
|
||||
|
||||
bool ClientConfig::get_ini(const std::vector<TransmSet>& set, long num, TransmSet& use)
|
||||
bool CServerConfig::get_ini(const std::vector<TransmSet>& set, long num, TransmSet& use)
|
||||
{
|
||||
bool find = false;
|
||||
for (const auto& item : set) {
|
||||
@ -137,12 +137,12 @@ bool ClientConfig::get_ini(const std::vector<TransmSet>& set, long num, TransmSe
|
||||
return find;
|
||||
}
|
||||
|
||||
std::string ClientConfig::get_config_dir() const
|
||||
std::string CServerConfig::get_config_dir() const
|
||||
{
|
||||
return config_dir_;
|
||||
}
|
||||
|
||||
bool ClientConfig::save_last_use(const std::string& ip, long port)
|
||||
bool CServerConfig::save_last_use(const std::string& ip, long port)
|
||||
{
|
||||
assert(init_ == true);
|
||||
ini_handle_.SetValue("Base", "LastUseIP", ip.c_str());
|
||||
@ -151,7 +151,7 @@ bool ClientConfig::save_last_use(const std::string& ip, long port)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ClientConfig::get_last_use(std::string& ip, long& port)
|
||||
bool CServerConfig::get_last_use(std::string& ip, long& port)
|
||||
{
|
||||
assert(init_ == true);
|
||||
if (!ini_handle_.KeyExists("Base", "LastUseIP") || !ini_handle_.KeyExists("Base", "LastUsePort")) {
|
||||
@ -163,7 +163,7 @@ bool ClientConfig::get_last_use(std::string& ip, long& port)
|
||||
return true;
|
||||
}
|
||||
|
||||
void ClientConfig::gen_default_ini(const std::string& path)
|
||||
void CServerConfig::gen_default_ini(const std::string& path)
|
||||
{
|
||||
TLOGW("Gen Default Setting Ini in [{}].", path);
|
||||
ini_handle_.LoadFile(path.c_str());
|
||||
|
@ -25,11 +25,11 @@ struct CmdParam {
|
||||
bool null_use{false};
|
||||
};
|
||||
|
||||
class ClientConfig
|
||||
class CServerConfig
|
||||
{
|
||||
public:
|
||||
ClientConfig();
|
||||
~ClientConfig();
|
||||
CServerConfig();
|
||||
~CServerConfig();
|
||||
|
||||
public:
|
||||
bool baseInit();
|
||||
|
@ -16,21 +16,11 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
std::shared_ptr<ClientConfig> g_Config = nullptr;
|
||||
std::shared_ptr<CServerConfig> g_Config = nullptr;
|
||||
int parse_cmd(int argc, char** argv, CmdParam& param)
|
||||
{
|
||||
std::string intro(fmt::format("tsc cmd introduce, version: {}\nopensource: {}", VERSION_NUM, VERSION_URL));
|
||||
std::string intro(
|
||||
fmt::format("tsc cmd introduce, version: {}\nopensource: {}", VERSION_NUM, VERSION_URL));
|
||||
CLI::App app(intro);
|
||||
|
||||
app.add_option("-u, --use", param.use_config, "使用服务器地址组(值为使用--show中显示的序号)");
|
||||
@ -166,14 +156,6 @@ bool exec_cmd(CmdParam& param, bool& run)
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
#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
|
||||
|
||||
#ifdef _WIN32
|
||||
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
DWORD mode;
|
||||
@ -187,7 +169,7 @@ int main(int argc, char* argv[])
|
||||
delete p;
|
||||
});
|
||||
|
||||
g_Config = std::make_shared<ClientConfig>();
|
||||
g_Config = std::make_shared<CServerConfig>();
|
||||
if (!g_Config->baseInit()) {
|
||||
return -1;
|
||||
}
|
||||
@ -252,8 +234,8 @@ int main(int argc, char* argv[])
|
||||
}
|
||||
TLOGI("Build At {} {} under {} on {}", __DATE__, __TIME__, VERSION_GIT_COMMIT, VERSION_GIT_BRANCH);
|
||||
TLOGI("use ip => [{}], port => [{}]", ip, port);
|
||||
std::shared_ptr<TransmClient> client = std::make_shared<TransmClient>();
|
||||
client->run(ip, std::to_string(port), g_Config->get_config_dir());
|
||||
CClient client;
|
||||
client.run(ip, std::to_string(port), g_Config->get_config_dir());
|
||||
TLOGI("exit ==========");
|
||||
return 0;
|
||||
}
|
@ -1 +0,0 @@
|
||||
Subproject commit 2cf72f3e5c5313527b5d1442017caf06d51a3c02
|
@ -1,26 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(tss-http LANGUAGES CXX)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
if (MSVC)
|
||||
add_compile_options(/source-charset:utf-8)
|
||||
endif()
|
||||
|
||||
add_executable(tss-http main.cpp)
|
||||
if (UNIX)
|
||||
target_link_libraries(tss-http PRIVATE pthread)
|
||||
endif()
|
||||
|
||||
if(UNIX)
|
||||
execute_process(
|
||||
COMMAND uname -a
|
||||
OUTPUT_VARIABLE UNAME_OUT
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
if(UNAME_OUT MATCHES "alpine" OR UNAME_OUT MATCHES "Alpine")
|
||||
message(STATUS "tss-http on musl static link")
|
||||
target_link_libraries(tss-http PRIVATE -static;-static-libstdc++)
|
||||
endif()
|
||||
endif()
|
@ -1,264 +0,0 @@
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <httplib.h>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
#ifdef _WIN32
|
||||
std::string u8_to_ansi(const std::string& str)
|
||||
{
|
||||
int wideCharLen = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, nullptr, 0);
|
||||
if (wideCharLen <= 0) {
|
||||
return "";
|
||||
}
|
||||
std::wstring wideStr(wideCharLen, L'\0');
|
||||
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, &wideStr[0], wideCharLen);
|
||||
int gbkLen = WideCharToMultiByte(CP_ACP, 0, wideStr.c_str(), -1, nullptr, 0, nullptr, nullptr);
|
||||
if (gbkLen <= 0) {
|
||||
return "";
|
||||
}
|
||||
std::string gbkStr(gbkLen, '\0');
|
||||
WideCharToMultiByte(CP_ACP, 0, wideStr.c_str(), -1, &gbkStr[0], gbkLen, nullptr, nullptr);
|
||||
|
||||
gbkStr.resize(gbkLen - 1);
|
||||
return gbkStr;
|
||||
}
|
||||
std::string ansi_to_u8(const std::string& str)
|
||||
{
|
||||
int wideCharLen = MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, nullptr, 0);
|
||||
if (wideCharLen <= 0) {
|
||||
return "";
|
||||
}
|
||||
std::wstring wideStr(wideCharLen, L'\0');
|
||||
MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, &wideStr[0], wideCharLen);
|
||||
|
||||
int utf8Len = WideCharToMultiByte(CP_UTF8, 0, wideStr.c_str(), -1, nullptr, 0, nullptr, nullptr);
|
||||
if (utf8Len <= 0) {
|
||||
return "";
|
||||
}
|
||||
std::string utf8Str(utf8Len, '\0');
|
||||
WideCharToMultiByte(CP_UTF8, 0, wideStr.c_str(), -1, &utf8Str[0], utf8Len, nullptr, nullptr);
|
||||
|
||||
utf8Str.resize(utf8Len - 1);
|
||||
return utf8Str;
|
||||
}
|
||||
#endif
|
||||
|
||||
// 生成文件列表的HTML页面
|
||||
std::string generate_file_list(const std::string& base_path, const std::string& current_path)
|
||||
{
|
||||
fs::path full_path = fs::path(base_path) / current_path;
|
||||
|
||||
std::string html = R"(
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>File Browser</title>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; margin: 20px; }
|
||||
h1 { color: #333; }
|
||||
.path { color: #666; margin-bottom: 20px; }
|
||||
ul { list-style-type: none; padding: 0; }
|
||||
li { margin: 8px 0; }
|
||||
a { text-decoration: none; color: #0066cc; }
|
||||
a:hover { text-decoration: underline; }
|
||||
.file::before { content: "\1F4C4 "; }
|
||||
.dir::before { content: "\1F4C1 "; }
|
||||
.parent::before { content: "\2B06 "; }
|
||||
.size { color: #888; font-size: 0.9em; margin-left: 10px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>File Browser</h1>
|
||||
<div class="path">Current path: /)" +
|
||||
current_path + R"(</div>
|
||||
<ul>
|
||||
)";
|
||||
|
||||
// 添加返回上一级链接(如果不是根目录)
|
||||
if (current_path != "") {
|
||||
fs::path parent_path = fs::path(current_path).parent_path();
|
||||
std::string parent_link = parent_path.empty() ? "" : parent_path.string();
|
||||
html += R"(<li class="parent"><a href="/browse/)" + parent_link + R"(">..</a></li>)";
|
||||
}
|
||||
|
||||
// 遍历目录下的文件和子目录
|
||||
for (const auto& entry : fs::directory_iterator(full_path)) {
|
||||
std::string filename = entry.path().filename().string();
|
||||
std::string new_path = (fs::path(current_path) / filename).string();
|
||||
|
||||
if (entry.is_directory()) {
|
||||
html += R"(<li class="dir"><a href="/browse/)" + new_path + R"(">)" + filename + R"(/</a></li>)";
|
||||
} else {
|
||||
// 获取文件大小并转换为MB
|
||||
uintmax_t file_size = entry.file_size();
|
||||
double size_mb = file_size / (1024.0 * 1024.0);
|
||||
char size_str[20];
|
||||
snprintf(size_str, sizeof(size_str), "%.4f MB", size_mb);
|
||||
|
||||
html += R"(<li class="file"><a href="/download/)" + new_path + R"(">)" + filename + R"(</a><span class="size">)" +
|
||||
size_str + R"(</span></li>)";
|
||||
}
|
||||
}
|
||||
|
||||
html += R"(
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
)";
|
||||
|
||||
#ifdef _WIN32
|
||||
html = ansi_to_u8(html);
|
||||
#endif
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc != 3) {
|
||||
std::cout << "Usage: " << argv[0] << " <port> <base_dir>" << std::endl;
|
||||
return -2;
|
||||
}
|
||||
|
||||
const std::string base_dir(argv[2]); // 基础文件目录
|
||||
if (!fs::exists(base_dir)) {
|
||||
std::cout << "Base directory does not exist: " << base_dir << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int port = std::stoi(argv[1]);
|
||||
httplib::Server server;
|
||||
// 确保基础目录存在
|
||||
if (!fs::exists(base_dir)) {
|
||||
fs::create_directory(base_dir);
|
||||
}
|
||||
|
||||
// 文件浏览路由
|
||||
server.Get("/browse(.*)", [&base_dir](const httplib::Request& req, httplib::Response& res) {
|
||||
std::string path = req.matches[1].str();
|
||||
#ifdef _WIN32
|
||||
path = u8_to_ansi(path);
|
||||
#endif
|
||||
// 移除开头的斜杠
|
||||
if (!path.empty() && path[0] == '/') {
|
||||
path = path.substr(1);
|
||||
}
|
||||
|
||||
// 安全检查:防止目录遍历攻击
|
||||
if (path.find("..") != std::string::npos) {
|
||||
res.set_content("Invalid path", "text/plain");
|
||||
res.status = 400;
|
||||
return;
|
||||
}
|
||||
|
||||
fs::path full_path = fs::path(base_dir) / path;
|
||||
|
||||
if (!fs::exists(full_path)) {
|
||||
res.set_content("Path not found", "text/plain");
|
||||
res.status = 404;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fs::is_directory(full_path)) {
|
||||
res.set_content("Not a directory", "text/plain");
|
||||
res.status = 400;
|
||||
return;
|
||||
}
|
||||
res.set_header("Content-Type", "text/html; charset=utf-8");
|
||||
res.set_content(generate_file_list(base_dir, path), "text/html; charset=utf-8");
|
||||
});
|
||||
|
||||
// 文件下载路由
|
||||
server.Get("/download/(.*)", [&base_dir](const httplib::Request& req, httplib::Response& res) {
|
||||
std::string path = req.matches[1];
|
||||
|
||||
#ifdef _WIN32
|
||||
path = u8_to_ansi(path);
|
||||
#endif
|
||||
// 安全检查:防止目录遍历攻击
|
||||
if (path.find("..") != std::string::npos) {
|
||||
res.set_content("Invalid path", "text/plain");
|
||||
res.status = 400;
|
||||
return;
|
||||
}
|
||||
|
||||
fs::path file_path = fs::path(base_dir) / path;
|
||||
|
||||
if (!fs::exists(file_path)) {
|
||||
res.set_content("File not found", "text/plain");
|
||||
res.status = 404;
|
||||
return;
|
||||
}
|
||||
|
||||
if (fs::is_directory(file_path)) {
|
||||
res.set_content("Cannot download directory", "text/plain");
|
||||
res.status = 400;
|
||||
return;
|
||||
}
|
||||
|
||||
// 设置响应头,触发浏览器下载
|
||||
res.set_header("Content-Type", "application/octet-stream");
|
||||
res.set_header("Content-Disposition", "attachment; filename=" + file_path.filename().string());
|
||||
|
||||
auto file = std::make_shared<std::ifstream>(file_path, std::ios::binary);
|
||||
if (!*file) {
|
||||
res.status = 500;
|
||||
res.set_content("Failed to open file", "text/plain");
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取文件大小
|
||||
const size_t file_size = fs::file_size(file_path);
|
||||
|
||||
// 定义分块回调(严格匹配 ContentProvider 签名)
|
||||
auto provider = [file](size_t offset, size_t length, httplib::DataSink& sink) {
|
||||
file->seekg(offset);
|
||||
const size_t chunk_size = std::min<size_t>(1024 * 1024, length); // 64KB或剩余长度
|
||||
std::vector<char> buffer(chunk_size);
|
||||
|
||||
size_t remaining = length;
|
||||
while (remaining > 0 && sink.is_writable() && *file) {
|
||||
size_t read_size = std::min(buffer.size(), remaining);
|
||||
file->read(buffer.data(), read_size);
|
||||
size_t bytes_read = file->gcount();
|
||||
|
||||
if (bytes_read > 0) {
|
||||
sink.write(buffer.data(), bytes_read);
|
||||
remaining -= bytes_read;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
// 定义资源清理回调
|
||||
auto releaser = [file](bool /*success*/) { file->close(); };
|
||||
|
||||
// 调用 set_content_provider
|
||||
res.set_content_provider(file_size, // 文件总大小
|
||||
"application/octet-stream", // MIME类型
|
||||
provider, // 数据提供回调
|
||||
releaser // 资源清理回调
|
||||
);
|
||||
});
|
||||
|
||||
// 根目录重定向到/browse
|
||||
server.Get("/", [](const httplib::Request& req, httplib::Response& res) { res.set_redirect("/browse"); });
|
||||
|
||||
std::cout << "Server running at http://localhost:" << port << std::endl;
|
||||
std::cout << "Access the root path to browse files.\n";
|
||||
if (!server.listen("0.0.0.0", port)) {
|
||||
std::cerr << "Failed to start server\n";
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -23,9 +23,6 @@ endif()
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_SYSTEM_NAME MATCHES "Windows")
|
||||
target_link_libraries(tss PRIVATE ws2_32 wsock32)
|
||||
endif()
|
||||
if (DEFINED GRAB_CRASH)
|
||||
target_link_libraries(tss PRIVATE crashelper)
|
||||
endif()
|
||||
if(UNIX)
|
||||
execute_process(
|
||||
COMMAND uname -a
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
#include "server.h"
|
||||
#include "version.h"
|
||||
#include <of_path.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <fcntl.h>
|
||||
@ -14,19 +13,7 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(GRAB_CRASH)
|
||||
#include <crashelper.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_BOOST
|
||||
#include <boost/filesystem.hpp>
|
||||
namespace fs = boost::filesystem;
|
||||
#else
|
||||
#include <filesystem>
|
||||
namespace fs = std::filesystem;
|
||||
#endif
|
||||
|
||||
void msignal_handler(int signal)
|
||||
void signal_handler(int signal)
|
||||
{
|
||||
if (signal == SIGINT) {
|
||||
fc_recovery_color();
|
||||
@ -36,14 +23,7 @@ void msignal_handler(int signal)
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
#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();
|
||||
sh.register_user_sig_handler([](int sig) { msignal_handler(sig); });
|
||||
#endif
|
||||
std::signal(SIGINT, signal_handler);
|
||||
|
||||
#ifdef _WIN32
|
||||
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
@ -68,7 +48,7 @@ int main(int argc, char* argv[])
|
||||
TLOGI("Use Port:{}", port);
|
||||
}
|
||||
asio::io_context io_context;
|
||||
TransmServer server(io_context);
|
||||
CTcpServer server(io_context);
|
||||
if (!server.start(port)) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -7,13 +7,13 @@
|
||||
using namespace ofen;
|
||||
constexpr int check_idle_percycle = 1000 * 30; // 毫秒
|
||||
constexpr int remove_after_time = 60; // 秒
|
||||
TransmServer::TransmServer(asio::io_context& io_context) : io_context_(io_context), acceptor_(io_context)
|
||||
CTcpServer::CTcpServer(asio::io_context& io_context) : io_context_(io_context), acceptor_(io_context)
|
||||
{
|
||||
th_run_ = true;
|
||||
sleep_.set_timeout(check_idle_percycle);
|
||||
}
|
||||
|
||||
TransmServer::~TransmServer()
|
||||
CTcpServer::~CTcpServer()
|
||||
{
|
||||
th_run_ = false;
|
||||
sleep_.contiune();
|
||||
@ -22,7 +22,7 @@ TransmServer::~TransmServer()
|
||||
}
|
||||
}
|
||||
|
||||
bool TransmServer::start(unsigned short port)
|
||||
bool CTcpServer::start(unsigned short port)
|
||||
{
|
||||
asio::ip::tcp::resolver resolver(io_context_);
|
||||
asio::ip::tcp::resolver::query query(asio::ip::host_name(), "");
|
||||
@ -63,7 +63,7 @@ bool TransmServer::start(unsigned short port)
|
||||
return true;
|
||||
}
|
||||
|
||||
void TransmServer::stop()
|
||||
void CTcpServer::stop()
|
||||
{
|
||||
acceptor_.close();
|
||||
std::unique_lock<std::shared_mutex> lock(cli_mut_);
|
||||
@ -75,14 +75,14 @@ void TransmServer::stop()
|
||||
client_threads_.clear();
|
||||
}
|
||||
|
||||
void TransmServer::get_client_list(CMessageInfo& msg_info)
|
||||
void CTcpServer::get_client_list(CMessageInfo& msg_info)
|
||||
{
|
||||
struct TmpInfo {
|
||||
std::string id;
|
||||
std::string online_time;
|
||||
std::string uuid;
|
||||
std::string task;
|
||||
uint64_t timestamp{};
|
||||
uint64_t timestamp;
|
||||
};
|
||||
std::vector<TmpInfo> vec;
|
||||
std::string msg;
|
||||
@ -101,7 +101,8 @@ void TransmServer::get_client_list(CMessageInfo& msg_info)
|
||||
}
|
||||
|
||||
// 排序 vec 根据 client->timestamp
|
||||
std::sort(vec.begin(), vec.end(), [](const TmpInfo& a, const TmpInfo& b) { return a.timestamp < b.timestamp; });
|
||||
std::sort(vec.begin(), vec.end(),
|
||||
[](const TmpInfo& a, const TmpInfo& b) { return a.timestamp < b.timestamp; });
|
||||
|
||||
int index = 1;
|
||||
for (const auto& item : vec) {
|
||||
@ -116,7 +117,7 @@ void TransmServer::get_client_list(CMessageInfo& msg_info)
|
||||
msg_info.str = msg;
|
||||
}
|
||||
|
||||
void TransmServer::trans_data(CFrameBuffer* buf)
|
||||
void CTcpServer::trans_data(CFrameBuffer* buf)
|
||||
{
|
||||
std::shared_ptr<ClientCache> fcli = nullptr;
|
||||
std::shared_ptr<ClientCache> tcli = nullptr;
|
||||
@ -189,7 +190,8 @@ void TransmServer::trans_data(CFrameBuffer* buf)
|
||||
}
|
||||
}
|
||||
|
||||
bool TransmServer::check_double(CFrameBuffer* buf, std::shared_ptr<ClientCache>& fcli, std::shared_ptr<ClientCache>& tcli)
|
||||
bool CTcpServer::check_double(CFrameBuffer* buf, std::shared_ptr<ClientCache>& fcli,
|
||||
std::shared_ptr<ClientCache>& tcli)
|
||||
{
|
||||
std::shared_lock<std::shared_mutex> lock(cli_mut_);
|
||||
if (client_map_.count(buf->fid_)) {
|
||||
@ -218,7 +220,7 @@ bool TransmServer::check_double(CFrameBuffer* buf, std::shared_ptr<ClientCache>&
|
||||
return true;
|
||||
}
|
||||
|
||||
void TransmServer::accept_client()
|
||||
void CTcpServer::accept_client()
|
||||
{
|
||||
auto socket = std::make_shared<asio::ip::tcp::socket>(io_context_);
|
||||
acceptor_.async_accept(*socket, [this, socket](const asio::error_code& error) {
|
||||
@ -246,14 +248,15 @@ void TransmServer::accept_client()
|
||||
if (!can) {
|
||||
std::this_thread::sleep_for(std::chrono::minutes(1));
|
||||
} else {
|
||||
client_threads_[client_key] = std::thread(&TransmServer::th_client, this, socket, client_key);
|
||||
client_threads_[client_key] = std::thread(&CTcpServer::th_client, this, socket, client_key);
|
||||
}
|
||||
}
|
||||
accept_client();
|
||||
});
|
||||
}
|
||||
|
||||
void TransmServer::th_client(const std::shared_ptr<asio::ip::tcp::socket>& socket, const std::string& client_key)
|
||||
void CTcpServer::th_client(const std::shared_ptr<asio::ip::tcp::socket>& socket,
|
||||
const std::string& client_key)
|
||||
{
|
||||
std::shared_ptr<int> deleter(new int(0), [&](int* p) {
|
||||
std::unique_lock<std::shared_mutex> lock(cli_mut_);
|
||||
@ -327,7 +330,7 @@ void TransmServer::th_client(const std::shared_ptr<asio::ip::tcp::socket>& socke
|
||||
}
|
||||
}
|
||||
|
||||
bool TransmServer::send_frame(const std::shared_ptr<asio::ip::tcp::socket>& socket, CFrameBuffer* buf)
|
||||
bool CTcpServer::send_frame(const std::shared_ptr<asio::ip::tcp::socket>& socket, CFrameBuffer* buf)
|
||||
{
|
||||
char* out_buf{};
|
||||
int out_len{};
|
||||
@ -341,20 +344,21 @@ bool TransmServer::send_frame(const std::shared_ptr<asio::ip::tcp::socket>& sock
|
||||
}
|
||||
try {
|
||||
if (!socket->send(asio::buffer(out_buf, out_len))) {
|
||||
TLOGE("{} send failed, buf type:{}, fid:{}, tid:{}", __FUNCTION__, static_cast<int>(buf->type_), buf->fid_,
|
||||
buf->tid_);
|
||||
TLOGE("{} send failed, buf type:{}, fid:{}, tid:{}", __FUNCTION__, static_cast<int>(buf->type_),
|
||||
buf->fid_, buf->tid_);
|
||||
delete[] out_buf;
|
||||
return false;
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
TLOGE("send failed, type:{}, fid:{}, tid:{}, mark:{}", static_cast<int>(buf->type_), buf->fid_, buf->tid_, buf->mark_);
|
||||
TLOGE("send failed, type:{}, fid:{}, tid:{}, mark:{}", static_cast<int>(buf->type_), buf->fid_,
|
||||
buf->tid_, buf->mark_);
|
||||
}
|
||||
|
||||
delete[] out_buf;
|
||||
return true;
|
||||
}
|
||||
|
||||
void TransmServer::monitor_idle()
|
||||
void CTcpServer::monitor_idle()
|
||||
{
|
||||
while (th_run_) {
|
||||
sleep_.sleep();
|
||||
@ -365,7 +369,9 @@ void TransmServer::monitor_idle()
|
||||
std::unique_lock<std::shared_mutex> lock(cli_mut_);
|
||||
for (auto& item : client_map_) {
|
||||
auto now = std::chrono::high_resolution_clock::now();
|
||||
auto duration = std::chrono::duration_cast<std::chrono::seconds>(now - item.second->last_active_time_).count();
|
||||
auto duration =
|
||||
std::chrono::duration_cast<std::chrono::seconds>(now - item.second->last_active_time_)
|
||||
.count();
|
||||
if (duration >= remove_after_time) {
|
||||
TLOGW("OnLine Time [{}] sec, Proactively disconnect:{}", duration, item.first);
|
||||
remove_vec.push_back(item.first);
|
||||
|
@ -13,22 +13,22 @@ using namespace ofen;
|
||||
using high_c = std::chrono::time_point<std::chrono::high_resolution_clock>;
|
||||
struct ClientCache {
|
||||
std::shared_ptr<asio::ip::tcp::socket> socket_;
|
||||
CMutBuffer buffer_;
|
||||
CMutBuffer buffer_{};
|
||||
std::array<char, g_BuffSize> tmp_buf_{};
|
||||
std::string task_;
|
||||
std::string uuid;
|
||||
std::string task_time_;
|
||||
std::string online_time_;
|
||||
std::string task_{};
|
||||
std::string uuid{};
|
||||
std::string task_time_{};
|
||||
std::string online_time_{};
|
||||
uint64_t timestamp{};
|
||||
high_c last_active_time_;
|
||||
FrameType cur_type_{TYPE_DEFAULT};
|
||||
};
|
||||
|
||||
class TransmServer
|
||||
class CTcpServer
|
||||
{
|
||||
public:
|
||||
explicit TransmServer(asio::io_context& io_context);
|
||||
~TransmServer();
|
||||
CTcpServer(asio::io_context& io_context);
|
||||
~CTcpServer();
|
||||
|
||||
public:
|
||||
bool start(unsigned short port);
|
||||
@ -39,7 +39,8 @@ private:
|
||||
|
||||
private:
|
||||
void trans_data(CFrameBuffer* buf);
|
||||
bool check_double(CFrameBuffer* buf, std::shared_ptr<ClientCache>& fcli, std::shared_ptr<ClientCache>& tcli);
|
||||
bool check_double(CFrameBuffer* buf, std::shared_ptr<ClientCache>& fcli,
|
||||
std::shared_ptr<ClientCache>& tcli);
|
||||
|
||||
private:
|
||||
void accept_client();
|
||||
|
@ -1,42 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(transm_test LANGUAGES CXX)
|
||||
project(test LANGUAGES CXX)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
set(TEST_SOURCES
|
||||
../3rd/catch_amalgamated.cpp
|
||||
assistant.h
|
||||
assistant.cxx
|
||||
)
|
||||
|
||||
set(TRANSM_TEST_SOURCES
|
||||
../3rd/catch_amalgamated.cpp
|
||||
../client/client.cpp
|
||||
../client/client.h
|
||||
../client/config.cpp
|
||||
../client/config.h
|
||||
../util/util.h
|
||||
../server/server.cpp
|
||||
../server/server.h
|
||||
../net/net_base.h
|
||||
assistant.h
|
||||
assistant.cxx
|
||||
)
|
||||
|
||||
add_executable(encry_correct_test EncryptCorrect.cxx ${TEST_SOURCES})
|
||||
add_executable(encry_speed_test EncryptSpeed.cxx ${TEST_SOURCES})
|
||||
target_link_libraries(encry_correct_test PRIVATE tinyaes trans_util)
|
||||
target_link_libraries(encry_speed_test PRIVATE tinyaes trans_util)
|
||||
add_executable(transm_cmd_test Cmd.cxx ${TRANSM_TEST_SOURCES})
|
||||
target_link_libraries(transm_cmd_test PRIVATE trans_net trans_util)
|
||||
|
||||
if (UNIX)
|
||||
target_link_libraries(encry_speed_test PRIVATE pthread)
|
||||
target_link_libraries(encry_correct_test PRIVATE pthread)
|
||||
target_link_libraries(transm_cmd_test PRIVATE pthread)
|
||||
endif()
|
||||
|
||||
enable_testing()
|
||||
add_test(NAME EncryCorrectTest COMMAND encry_correct_test)
|
||||
add_test(NAME EncrySpeedTest COMMAND encry_speed_test -s)
|
||||
add_test(NAME CmdTest COMMAND transm_cmd_test)
|
||||
add_executable(test main.cxx)
|
||||
target_link_libraries(test PRIVATE tinyaes trans_util)
|
228
test/Cmd.cxx
228
test/Cmd.cxx
@ -1,228 +0,0 @@
|
||||
#include <catch_amalgamated.hpp>
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
|
||||
#include "../client/client.h"
|
||||
#include "../client/config.h"
|
||||
#include "../server/server.h"
|
||||
#include "../util/util.h"
|
||||
#include "assistant.h"
|
||||
|
||||
std::shared_ptr<TransmServer> server;
|
||||
std::shared_ptr<TransmClient> clientA;
|
||||
std::shared_ptr<TransmClient> clientB;
|
||||
std::shared_ptr<ClientConfig> config;
|
||||
|
||||
asio::io_context server_context;
|
||||
|
||||
constexpr auto ip = "127.0.0.1";
|
||||
constexpr unsigned short port = 9897;
|
||||
bool server_suc = false;
|
||||
constexpr unsigned int max_wait = 3000;
|
||||
constexpr unsigned int wait_interval = 100;
|
||||
|
||||
std::string str_id_a;
|
||||
int ida_in_b = -1;
|
||||
std::thread server_th;
|
||||
|
||||
std::string test_filea = "filea.dat";
|
||||
std::string test_fileb = "fileb.dat";
|
||||
std::string test_sub_dir = "test_sub";
|
||||
std::string test_task_file = "test_task.txt";
|
||||
|
||||
bool test_ls();
|
||||
bool random_ralated_files();
|
||||
bool test_up_task(bool encrypt);
|
||||
|
||||
void server_run()
|
||||
{
|
||||
server = std::make_shared<TransmServer>(server_context);
|
||||
if (!server->start(port)) {
|
||||
server_suc = false;
|
||||
return;
|
||||
}
|
||||
server_suc = true;
|
||||
server_context.run();
|
||||
}
|
||||
|
||||
bool base_connect()
|
||||
{
|
||||
config = std::make_shared<ClientConfig>();
|
||||
if (!config->baseInit()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
server_th = std::thread(server_run);
|
||||
if (value_wait<bool>([]() -> bool { return server_suc; }, true, std::equal_to<bool>(), max_wait,
|
||||
wait_interval) == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
clientA = std::make_shared<TransmClient>();
|
||||
if (clientA->connect_for_test(ip, std::to_string(port), config->get_config_dir()) == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
clientB = std::make_shared<TransmClient>();
|
||||
if (clientB->connect_for_test(ip, std::to_string(port), config->get_config_dir()) == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (value_wait<std::string>([]() -> std::string { return clientA->test_get_own_id(); }, std::string(),
|
||||
std::not_equal_to<std::string>(), max_wait, wait_interval) == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (value_wait<std::string>([]() -> std::string { return clientB->test_get_own_id(); }, std::string(),
|
||||
std::not_equal_to<std::string>(), max_wait, wait_interval) == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
str_id_a = clientA->test_get_own_id();
|
||||
std::cout << "clientA id: " << str_id_a << std::endl;
|
||||
if (value_wait<int>([]() -> int { return clientB->test_index_by_id(str_id_a); }, -1,
|
||||
std::not_equal_to<int>(), max_wait, wait_interval) == false) {
|
||||
return false;
|
||||
}
|
||||
ida_in_b = clientB->test_index_by_id(str_id_a);
|
||||
std::cout << "clientA index In B: " << ida_in_b << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool main_test()
|
||||
{
|
||||
ON_SCOPE_EXIT
|
||||
{
|
||||
fc_recovery_color();
|
||||
};
|
||||
|
||||
if (!base_connect()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<int> deleter(new int(), [](int* p) {
|
||||
if (clientA) {
|
||||
clientA->disconnect_for_test();
|
||||
}
|
||||
if (clientB) {
|
||||
clientB->disconnect_for_test();
|
||||
}
|
||||
if (server) {
|
||||
server->stop();
|
||||
}
|
||||
server_context.stop();
|
||||
if (server_th.joinable()) {
|
||||
server_th.join();
|
||||
}
|
||||
delete p;
|
||||
});
|
||||
|
||||
if (!test_ls()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!random_ralated_files()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!test_up_task(true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!test_up_task(false)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::seconds(10));
|
||||
return true;
|
||||
}
|
||||
|
||||
// 测试 Ls
|
||||
bool test_ls()
|
||||
{
|
||||
std::string cmd = std::to_string(ida_in_b) + " .";
|
||||
if (!clientB->cmd_ls(cmd)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_up_task(bool encrypt)
|
||||
{
|
||||
std::string cmd = std::to_string(ida_in_b) + " " + test_task_file;
|
||||
|
||||
auto fas = test_filea;
|
||||
auto fat = test_sub_dir + "/" + test_filea;
|
||||
auto fbs = test_fileb;
|
||||
auto fbt = test_sub_dir + "/" + test_fileb;
|
||||
|
||||
ON_SCOPE_EXIT
|
||||
{
|
||||
if (fs::exists(fat)) {
|
||||
fs::remove(fat);
|
||||
}
|
||||
if (fs::exists(fbt)) {
|
||||
fs::remove(fbt);
|
||||
}
|
||||
};
|
||||
|
||||
set_encrypt(encrypt);
|
||||
clientB->set_task_state(TransmClient::TaskState::TASK_STATE_IDLE);
|
||||
if (!clientB->cmd_sub_task(cmd, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (value_wait<TransmClient::TaskState>(
|
||||
[&]() -> TransmClient::TaskState { return clientB->get_task_state(); },
|
||||
TransmClient::TaskState::TASK_STATE_IDLE, std::not_equal_to<TransmClient::TaskState>(),
|
||||
max_wait * 2, wait_interval) == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto r = clientB->get_task_state();
|
||||
if (r != TransmClient::TaskState::TASK_STATE_DONE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_equal_filecontent(fas, fat)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_equal_filecontent(fbs, fbt)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::cout << "****** up task done encrypt:" << encrypt << " ******" << std::endl;
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool random_ralated_files()
|
||||
{
|
||||
if (!random_file("filea.dat", 1024 * 1024 * 10)) {
|
||||
return false;
|
||||
}
|
||||
if (!random_file("fileb.dat", 1024 * 1024 * 10)) {
|
||||
return false;
|
||||
}
|
||||
if (fs::exists(test_sub_dir)) {
|
||||
fs::remove_all(test_sub_dir);
|
||||
}
|
||||
fs::create_directories(test_sub_dir);
|
||||
if (fs::exists(test_task_file)) {
|
||||
fs::remove(test_task_file);
|
||||
}
|
||||
std::ofstream ofs(test_task_file);
|
||||
ofs << "${CURRENT}/" << test_filea << "|" << test_sub_dir + "/" << std::endl;
|
||||
ofs << test_fileb << "|" << test_sub_dir + "/" << std::endl;
|
||||
ofs.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST_CASE("transm cmd part", "[cmd]")
|
||||
{
|
||||
SECTION("correctness of cmd")
|
||||
{
|
||||
REQUIRE(main_test() == true);
|
||||
}
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
#include <aes.hpp>
|
||||
#include <catch_amalgamated.hpp>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <util.h>
|
||||
|
||||
bool correctness_test()
|
||||
{
|
||||
std::string key = "demokey";
|
||||
uint8_t ik[32]{};
|
||||
hash(key.c_str(), ik);
|
||||
|
||||
int offset = 16;
|
||||
char* msg = new char[256]{};
|
||||
std::shared_ptr<int> deleter(new int(), [msg](int* p) {
|
||||
delete p;
|
||||
delete[] msg;
|
||||
});
|
||||
|
||||
char source[] = "hello world";
|
||||
memset(msg, 0, 256);
|
||||
auto len = std::snprintf(msg + offset, 256 - offset, "%s", source);
|
||||
if (!encrypt(ik, (uint8_t*)msg, len + offset)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t ik2[32]{};
|
||||
hash(key.c_str(), ik2);
|
||||
if (!decrypt(ik2, (uint8_t*)msg, len + offset)) {
|
||||
return false;
|
||||
}
|
||||
return std::memcmp(source, msg + offset, len) == 0;
|
||||
}
|
||||
|
||||
TEST_CASE("transm encry part", "[encry]")
|
||||
{
|
||||
SECTION("correctness of encryption")
|
||||
{
|
||||
REQUIRE(correctness_test() == true);
|
||||
}
|
||||
}
|
@ -1,185 +0,0 @@
|
||||
#include <aes.hpp>
|
||||
#include <catch_amalgamated.hpp>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <util.h>
|
||||
|
||||
#include "assistant.h"
|
||||
|
||||
const size_t BLOCK_SIZE = 102400; // 100KB块大小
|
||||
const size_t IV_SIZE = 16; // 随机值大小
|
||||
|
||||
struct SpeedRet {
|
||||
std::string mode;
|
||||
long long file_size;
|
||||
long long encry_speed;
|
||||
long long decry_speed;
|
||||
bool verify;
|
||||
};
|
||||
|
||||
bool test_speed(SpeedRet& ret)
|
||||
{
|
||||
std::string test_file("1.dat");
|
||||
if (!random_file(test_file, 1024 * 1024 * 10)) {
|
||||
std::cerr << "Failed to create test file" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
ret.decry_speed = 0;
|
||||
ret.encry_speed = 0;
|
||||
ret.mode = "";
|
||||
ret.verify = false;
|
||||
|
||||
std::shared_ptr<int> deleter(new int(1), [test_file](int* p) {
|
||||
delete p;
|
||||
if (fs::exists(test_file)) {
|
||||
fs::remove(test_file);
|
||||
}
|
||||
});
|
||||
|
||||
if (!fs::exists(test_file)) {
|
||||
std::cerr << "Input file not found: " << test_file << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t file_size = fs::file_size(test_file);
|
||||
ret.file_size = file_size / (1024 * 1024);
|
||||
if (file_size == 0) {
|
||||
std::cerr << "Input file is empty" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string key = "test_speed_key";
|
||||
uint8_t ik[32]{};
|
||||
hash(key.c_str(), ik);
|
||||
|
||||
fs::path decrypted_path = fs::path(test_file).replace_filename(
|
||||
fs::path(test_file).stem().string() + "_decrypted" + fs::path(test_file).extension().string());
|
||||
|
||||
std::ofstream decrypted_file(decrypted_path, std::ios::binary);
|
||||
if (!decrypted_file) {
|
||||
std::cerr << "Failed to create decrypted file" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::ifstream in_file(test_file, std::ios::binary);
|
||||
if (!in_file) {
|
||||
std::cerr << "Failed to open input file" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 测试数据缓冲区(额外预留16字节空间)
|
||||
std::vector<uint8_t> original_block(BLOCK_SIZE);
|
||||
std::vector<uint8_t> processing_block(BLOCK_SIZE + IV_SIZE); // 加密/解密处理缓冲区
|
||||
|
||||
size_t total_bytes = 0;
|
||||
size_t blocks_processed = 0;
|
||||
bool verification_passed = true;
|
||||
|
||||
auto total_encrypt_time = std::chrono::microseconds(0);
|
||||
auto total_decrypt_time = std::chrono::microseconds(0);
|
||||
|
||||
while (in_file) {
|
||||
in_file.read(reinterpret_cast<char*>(original_block.data()), BLOCK_SIZE - IV_SIZE);
|
||||
size_t bytes_read = in_file.gcount();
|
||||
if (bytes_read == 0)
|
||||
break;
|
||||
|
||||
memcpy(processing_block.data() + IV_SIZE, original_block.data(), bytes_read);
|
||||
auto start_encrypt = std::chrono::high_resolution_clock::now();
|
||||
if (!encrypt(ik, processing_block.data(), bytes_read + IV_SIZE)) {
|
||||
std::cerr << "Encryption failed at block " << blocks_processed << std::endl;
|
||||
verification_passed = false;
|
||||
break;
|
||||
}
|
||||
auto end_encrypt = std::chrono::high_resolution_clock::now();
|
||||
total_encrypt_time +=
|
||||
std::chrono::duration_cast<std::chrono::microseconds>(end_encrypt - start_encrypt);
|
||||
|
||||
auto start_decrypt = std::chrono::high_resolution_clock::now();
|
||||
if (!decrypt(ik, processing_block.data(), bytes_read + IV_SIZE)) {
|
||||
std::cerr << "Decryption failed at block " << blocks_processed << std::endl;
|
||||
verification_passed = false;
|
||||
break;
|
||||
}
|
||||
auto end_decrypt = std::chrono::high_resolution_clock::now();
|
||||
total_decrypt_time +=
|
||||
std::chrono::duration_cast<std::chrono::microseconds>(end_decrypt - start_decrypt);
|
||||
|
||||
if (memcmp(original_block.data(), processing_block.data() + IV_SIZE, bytes_read) != 0) {
|
||||
std::cerr << "Data mismatch at block " << blocks_processed << std::endl;
|
||||
verification_passed = false;
|
||||
break;
|
||||
}
|
||||
|
||||
decrypted_file.write(reinterpret_cast<const char*>(processing_block.data() + IV_SIZE), bytes_read);
|
||||
total_bytes += bytes_read;
|
||||
blocks_processed++;
|
||||
}
|
||||
|
||||
in_file.close();
|
||||
decrypted_file.close();
|
||||
|
||||
#if !defined(NDEBUG) || defined(_DEBUG) || defined(DEBUG)
|
||||
// Debug 模式
|
||||
ret.mode = "Debug";
|
||||
#else
|
||||
// Release 模式
|
||||
ret.mode = "Release";
|
||||
#endif
|
||||
|
||||
// 计算吞吐量(只计算有效数据部分)
|
||||
double encrypt_throughput =
|
||||
(double)total_bytes / (1024 * 1024) / (total_encrypt_time.count() / 1000000.0);
|
||||
double decrypt_throughput =
|
||||
(double)total_bytes / (1024 * 1024) / (total_decrypt_time.count() / 1000000.0);
|
||||
|
||||
ret.encry_speed = encrypt_throughput;
|
||||
ret.decry_speed = decrypt_throughput;
|
||||
ret.verify = verification_passed;
|
||||
|
||||
fs::remove(decrypted_path);
|
||||
return verification_passed;
|
||||
}
|
||||
|
||||
bool correctness_test()
|
||||
{
|
||||
std::string key = "demokey";
|
||||
uint8_t ik[32]{};
|
||||
hash(key.c_str(), ik);
|
||||
|
||||
int offset = 16;
|
||||
char* msg = new char[256]{};
|
||||
std::shared_ptr<int> deleter(new int(), [msg](int* p) {
|
||||
delete p;
|
||||
delete[] msg;
|
||||
});
|
||||
|
||||
char source[] = "hello world";
|
||||
memset(msg, 0, 256);
|
||||
auto len = std::snprintf(msg + offset, 256 - offset, "%s", source);
|
||||
if (!encrypt(ik, (uint8_t*)msg, len + offset)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t ik2[32]{};
|
||||
hash(key.c_str(), ik2);
|
||||
if (!decrypt(ik2, (uint8_t*)msg, len + offset)) {
|
||||
return false;
|
||||
}
|
||||
return std::memcmp(source, msg + offset, len) == 0;
|
||||
}
|
||||
|
||||
TEST_CASE("transm encry part", "[encry]")
|
||||
{
|
||||
SECTION("speed of encryption")
|
||||
{
|
||||
SpeedRet ret{};
|
||||
auto r = test_speed(ret);
|
||||
UNSCOPED_INFO("Encryption mode: " << ret.mode << "");
|
||||
UNSCOPED_INFO("FileSize: " << ret.file_size << " MB");
|
||||
UNSCOPED_INFO("Encryption speed: " << ret.encry_speed << " MB/s");
|
||||
UNSCOPED_INFO("Decryption speed: " << ret.decry_speed << " MB/s");
|
||||
REQUIRE(r == true);
|
||||
}
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
#include "assistant.h"
|
||||
|
||||
bool random_file(const std::string& file, size_t size)
|
||||
{
|
||||
if (file.empty() || size == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::ofstream ofs(file, std::ios::binary | std::ios::trunc);
|
||||
if (!ofs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::random_device rd;
|
||||
std::mt19937_64 gen(rd());
|
||||
std::uniform_int_distribution<int> dis(0, 255);
|
||||
|
||||
const size_t buffer_size = 4096;
|
||||
std::vector<unsigned char> buffer(buffer_size);
|
||||
|
||||
for (size_t remaining = size; remaining > 0;) {
|
||||
size_t chunk = std::min(remaining, buffer_size);
|
||||
|
||||
for (size_t i = 0; i < chunk; ++i) {
|
||||
buffer[i] = static_cast<unsigned char>(dis(gen));
|
||||
}
|
||||
if (!ofs.write(reinterpret_cast<const char*>(buffer.data()), chunk)) {
|
||||
return false;
|
||||
}
|
||||
remaining -= chunk;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 比较两个文件的内容是否完全相同
|
||||
*
|
||||
* @param filea 第一个文件路径
|
||||
* @param fileb 第二个文件路径
|
||||
* @return true 如果文件内容完全相同
|
||||
* @return false 如果文件内容不同或无法读取文件
|
||||
*/
|
||||
bool is_equal_filecontent(const std::string& filea, const std::string& fileb)
|
||||
{
|
||||
std::ifstream stream_a(filea, std::ios::binary);
|
||||
std::ifstream stream_b(fileb, std::ios::binary);
|
||||
|
||||
if (!stream_a.is_open() || !stream_b.is_open()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto size_a = fs::file_size(filea);
|
||||
auto size_b = fs::file_size(fileb);
|
||||
if (size_a != size_b) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t buffer_size = 4096; // 4KB 缓冲区
|
||||
char buffer_a[buffer_size];
|
||||
char buffer_b[buffer_size];
|
||||
|
||||
while (stream_a.good() && stream_b.good()) {
|
||||
|
||||
stream_a.read(buffer_a, buffer_size);
|
||||
stream_b.read(buffer_b, buffer_size);
|
||||
|
||||
if (stream_a.gcount() != stream_b.gcount()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!std::equal(buffer_a, buffer_a + stream_a.gcount(), buffer_b)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return !stream_a.bad() && !stream_b.bad();
|
||||
}
|
109
test/assistant.h
109
test/assistant.h
@ -1,109 +0,0 @@
|
||||
#ifndef ASSISTANT_H
|
||||
#define ASSISTANT_H
|
||||
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#ifdef USE_BOOST
|
||||
#include <boost/filesystem.hpp>
|
||||
namespace fs = boost::filesystem;
|
||||
#else
|
||||
#include <filesystem>
|
||||
namespace fs = std::filesystem;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief 比较两个文件的内容是否完全相同
|
||||
*
|
||||
* @param filea 第一个文件路径
|
||||
* @param fileb 第二个文件路径
|
||||
* @return true 如果文件内容完全相同
|
||||
* @return false 如果文件内容不同或无法读取文件
|
||||
*/
|
||||
bool is_equal_filecontent(const std::string& filea, const std::string& fileb);
|
||||
bool random_file(const std::string& file, size_t size);
|
||||
|
||||
/**
|
||||
* @brief 等待变量的值达到预期值
|
||||
*
|
||||
* @tparam T 变量类型
|
||||
* @tparam Compare 比较器类型
|
||||
* @param value 变量的引用
|
||||
* @param expected 预期值
|
||||
* @param comparator 比较函数 (默认为 std::equal_to)
|
||||
* @param timeout_ms 超时时间(毫秒),0表示无限等待
|
||||
* @param interval_ms 检查间隔(毫秒)
|
||||
* @return true 变量值符合预期
|
||||
* @return false 超时或条件不满足
|
||||
*/
|
||||
template <typename T, typename Compare = std::equal_to<T>>
|
||||
bool value_wait(const std::function<T()>& value_ref, const T& expected, Compare comparator = Compare(),
|
||||
unsigned long timeout_ms = 0, unsigned long interval_ms = 100)
|
||||
{
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
|
||||
while (true) {
|
||||
|
||||
T value = value_ref();
|
||||
if (comparator(value, expected)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (timeout_ms > 0) {
|
||||
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::steady_clock::now() - start)
|
||||
.count();
|
||||
|
||||
if (elapsed >= timeout_ms) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(interval_ms));
|
||||
}
|
||||
}
|
||||
|
||||
class ScopeExit
|
||||
{
|
||||
public:
|
||||
ScopeExit() = default;
|
||||
template <typename F> ScopeExit(F&& f) : func_(std::forward<F>(f))
|
||||
{
|
||||
}
|
||||
ScopeExit(const ScopeExit&) = delete;
|
||||
ScopeExit& operator=(const ScopeExit&) = delete;
|
||||
ScopeExit(ScopeExit&& other) noexcept : func_(std::move(other.func_))
|
||||
{
|
||||
other.func_ = nullptr;
|
||||
}
|
||||
ScopeExit& operator=(ScopeExit&& other) noexcept
|
||||
{
|
||||
if (this != &other) {
|
||||
if (func_)
|
||||
func_();
|
||||
func_ = std::move(other.func_);
|
||||
other.func_ = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
~ScopeExit()
|
||||
{
|
||||
if (func_)
|
||||
func_();
|
||||
}
|
||||
void dismiss() noexcept
|
||||
{
|
||||
func_ = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<void()> func_;
|
||||
};
|
||||
|
||||
#define _SCOPE_EXIT_CONCAT(a, b) a##b
|
||||
#define _MAKE_ON_SCOPE_EXIT(line) ScopeExit _SCOPE_EXIT_CONCAT(exit_defer_, line) = [&]()
|
||||
#define ON_SCOPE_EXIT _MAKE_ON_SCOPE_EXIT(__LINE__)
|
||||
|
||||
#endif // ASSISTANT_H
|
198
test/main.cxx
Normal file
198
test/main.cxx
Normal file
@ -0,0 +1,198 @@
|
||||
#include <aes.hpp>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <util.h>
|
||||
|
||||
#ifdef USE_BOOST
|
||||
#include <boost/filesystem.hpp>
|
||||
namespace fs = boost::filesystem;
|
||||
#else
|
||||
#include <filesystem>
|
||||
namespace fs = std::filesystem;
|
||||
#endif
|
||||
|
||||
const size_t BLOCK_SIZE = 102400; // 100KB块大小
|
||||
const size_t IV_SIZE = 16; // 随机值大小
|
||||
|
||||
/*
|
||||
测试环境:
|
||||
Microsoft Windows 10 Professional (x64) Build 19045.5608 (22H2)
|
||||
13th Gen Intel(R) Core(TM) i5-13500H 3200.0 MHz
|
||||
Debug模式 tinyaes 加密解密测试速度:
|
||||
=========================================
|
||||
File size: 630239232 bytes (601.043 MB)
|
||||
Effective block size: 102384 bytes
|
||||
IV size: 16 bytes
|
||||
Blocks processed: 6156
|
||||
Total encryption time: 41887336 μs (14.349 MB/s)
|
||||
Total decryption time: 41822620 μs (14.3712 MB/s)
|
||||
Decrypted file: "D:\\1_decrypted.iso"
|
||||
Data verification: PASSED
|
||||
=========================================
|
||||
Release模式 tinyaes 加密解密测试速度:
|
||||
=========================================
|
||||
File size: 630239232 bytes (601.043 MB)
|
||||
Effective block size: 102384 bytes
|
||||
IV size: 16 bytes
|
||||
Blocks processed: 6156
|
||||
Total encryption time: 8367460 μs (71.831 MB/s)
|
||||
Total decryption time: 8150036 μs (73.7473 MB/s)
|
||||
Decrypted file: "D:\\1_decrypted.iso"
|
||||
Data verification: PASSED
|
||||
=========================================
|
||||
*/
|
||||
|
||||
void test_speed(const char* input_file)
|
||||
{
|
||||
// 检查输入文件
|
||||
if (!fs::exists(input_file)) {
|
||||
std::cerr << "Input file not found: " << input_file << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
size_t file_size = fs::file_size(input_file);
|
||||
if (file_size == 0) {
|
||||
std::cerr << "Input file is empty" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// 准备密钥
|
||||
std::string key = "test_speed_key";
|
||||
uint8_t ik[32]{};
|
||||
hash(key.c_str(), ik);
|
||||
|
||||
// 准备解密后的输出文件
|
||||
fs::path decrypted_path = fs::path(input_file)
|
||||
.replace_filename(fs::path(input_file).stem().string() + "_decrypted" +
|
||||
fs::path(input_file).extension().string());
|
||||
|
||||
std::ofstream decrypted_file(decrypted_path, std::ios::binary);
|
||||
if (!decrypted_file) {
|
||||
std::cerr << "Failed to create decrypted file" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// 打开输入文件
|
||||
std::ifstream in_file(input_file, std::ios::binary);
|
||||
if (!in_file) {
|
||||
std::cerr << "Failed to open input file" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// 测试数据缓冲区(额外预留16字节空间)
|
||||
std::vector<uint8_t> original_block(BLOCK_SIZE);
|
||||
std::vector<uint8_t> processing_block(BLOCK_SIZE + IV_SIZE); // 加密/解密处理缓冲区
|
||||
|
||||
size_t total_bytes = 0;
|
||||
size_t blocks_processed = 0;
|
||||
bool verification_passed = true;
|
||||
|
||||
// 计时变量
|
||||
auto total_encrypt_time = std::chrono::microseconds(0);
|
||||
auto total_decrypt_time = std::chrono::microseconds(0);
|
||||
|
||||
while (in_file) {
|
||||
// 读取原始数据块(注意实际读取量比BLOCK_SIZE少16字节)
|
||||
in_file.read(reinterpret_cast<char*>(original_block.data()), BLOCK_SIZE - IV_SIZE);
|
||||
size_t bytes_read = in_file.gcount();
|
||||
if (bytes_read == 0)
|
||||
break;
|
||||
|
||||
// 准备加密缓冲区(前16字节留给随机值)
|
||||
memcpy(processing_block.data() + IV_SIZE, original_block.data(), bytes_read);
|
||||
|
||||
// 加密计时
|
||||
auto start_encrypt = std::chrono::high_resolution_clock::now();
|
||||
if (!encrypt(ik, processing_block.data(), bytes_read + IV_SIZE)) {
|
||||
std::cerr << "Encryption failed at block " << blocks_processed << std::endl;
|
||||
verification_passed = false;
|
||||
break;
|
||||
}
|
||||
auto end_encrypt = std::chrono::high_resolution_clock::now();
|
||||
total_encrypt_time +=
|
||||
std::chrono::duration_cast<std::chrono::microseconds>(end_encrypt - start_encrypt);
|
||||
|
||||
// 解密计时(使用加密后的数据)
|
||||
auto start_decrypt = std::chrono::high_resolution_clock::now();
|
||||
if (!decrypt(ik, processing_block.data(), bytes_read + IV_SIZE)) {
|
||||
std::cerr << "Decryption failed at block " << blocks_processed << std::endl;
|
||||
verification_passed = false;
|
||||
break;
|
||||
}
|
||||
auto end_decrypt = std::chrono::high_resolution_clock::now();
|
||||
total_decrypt_time +=
|
||||
std::chrono::duration_cast<std::chrono::microseconds>(end_decrypt - start_decrypt);
|
||||
|
||||
// 验证解密结果(比较解密后的数据部分)
|
||||
if (memcmp(original_block.data(), processing_block.data() + IV_SIZE, bytes_read) != 0) {
|
||||
std::cerr << "Data mismatch at block " << blocks_processed << std::endl;
|
||||
verification_passed = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// 写入解密后的数据(只写入有效数据部分)
|
||||
decrypted_file.write(reinterpret_cast<const char*>(processing_block.data() + IV_SIZE), bytes_read);
|
||||
|
||||
total_bytes += bytes_read;
|
||||
blocks_processed++;
|
||||
}
|
||||
|
||||
// 关闭文件
|
||||
in_file.close();
|
||||
decrypted_file.close();
|
||||
|
||||
// 计算吞吐量(只计算有效数据部分)
|
||||
double encrypt_throughput =
|
||||
(double)total_bytes / (1024 * 1024) / (total_encrypt_time.count() / 1000000.0);
|
||||
double decrypt_throughput =
|
||||
(double)total_bytes / (1024 * 1024) / (total_decrypt_time.count() / 1000000.0);
|
||||
|
||||
// 输出结果
|
||||
std::cout << "\nOptimized Block Encryption/Decryption Test\n";
|
||||
std::cout << "=========================================\n";
|
||||
std::cout << "File size: " << file_size << " bytes (" << (double)file_size / (1024 * 1024) << " MB)\n";
|
||||
std::cout << "Effective block size: " << (BLOCK_SIZE - IV_SIZE) << " bytes\n";
|
||||
std::cout << "IV size: " << IV_SIZE << " bytes\n";
|
||||
std::cout << "Blocks processed: " << blocks_processed << "\n";
|
||||
std::cout << "Total encryption time: " << total_encrypt_time.count() << " μs (" << encrypt_throughput
|
||||
<< " MB/s)\n";
|
||||
std::cout << "Total decryption time: " << total_decrypt_time.count() << " μs (" << decrypt_throughput
|
||||
<< " MB/s)\n";
|
||||
std::cout << "Decrypted file: " << decrypted_path << "\n";
|
||||
std::cout << "Data verification: " << (verification_passed ? "PASSED" : "FAILED") << "\n";
|
||||
std::cout << "=========================================\n";
|
||||
|
||||
// 如果验证失败,删除可能不正确的解密文件
|
||||
if (!verification_passed) {
|
||||
fs::remove(decrypted_path);
|
||||
}
|
||||
}
|
||||
|
||||
void base_test()
|
||||
{
|
||||
std::string key = "sss";
|
||||
uint8_t ik[32]{};
|
||||
hash(key.c_str(), ik);
|
||||
|
||||
int offset = 16;
|
||||
char* msg = new char[256]{};
|
||||
memset(msg, 0, 256);
|
||||
auto len = std::snprintf(msg + offset, 256 - offset, "%s", "hello world");
|
||||
std::cout << encrypt(ik, (uint8_t*)msg, len + offset) << std::endl;
|
||||
std::cout << msg + offset << std::endl;
|
||||
|
||||
uint8_t ik2[32]{};
|
||||
hash(key.c_str(), ik2);
|
||||
|
||||
std::cout << decrypt(ik2, (uint8_t*)msg, len + offset) << std::endl;
|
||||
|
||||
std::cout << msg + offset << std::endl;
|
||||
delete[] msg;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_speed("D:\\1.iso");
|
||||
|
||||
return 0;
|
||||
}
|
@ -134,7 +134,7 @@ CFrameBuffer::~CFrameBuffer()
|
||||
len_ = 0;
|
||||
}
|
||||
|
||||
void serialize(CMessageInfo& msg_info, char** out_buf, int& len, bool reuse_mem)
|
||||
void serialize(CMessageInfo& msg_info, char** out_buf, int& len)
|
||||
{
|
||||
auto& info = msg_info;
|
||||
info.id = localtou8(info.id);
|
||||
@ -144,21 +144,14 @@ void serialize(CMessageInfo& msg_info, char** out_buf, int& len, bool reuse_mem)
|
||||
// 计算总长度
|
||||
len = sizeof(int) * 4 + info.id.size() + info.uuid.size() + info.str.size() + info.data.size() + kz + 1;
|
||||
|
||||
// 《这里为了效率》,
|
||||
// 认为如果 *out_buf 不为空,则直接使用,且长度符合要求
|
||||
// 调用方负责确保内存够用性(len <= 可用最大空间长度)和内存可用性。
|
||||
// 即,如果调用方及高频率调用 serialize, 且每次 len <= 已分配空间就复用内存,完了再释放。
|
||||
// 《这里为了效率》,认为如果 *out_buf 不为空,则直接使用,且长度符合要求
|
||||
// 调用方负责确保内存够用性(len小于最大长度)和可用性。
|
||||
// 即,如果调用方及高频率调用 serialize, 且每次 len 固定就复用内存,完了再释放。
|
||||
// 低频率或者 len 不固定时,每次都释放内存,并置 nullptr。
|
||||
if (*out_buf) {
|
||||
if (!reuse_mem) {
|
||||
delete[] *out_buf;
|
||||
*out_buf = new char[len]; // 分配内存(调用方负责释放)
|
||||
}
|
||||
} else {
|
||||
*out_buf = new char[len];
|
||||
if (*out_buf == nullptr) {
|
||||
*out_buf = new char[len]{}; // 分配内存(调用方负责释放)
|
||||
}
|
||||
|
||||
std::memset(*out_buf, 0x0, kz + 1);
|
||||
char* ptr = *out_buf + kz + 1;
|
||||
|
||||
// 序列化 cmd
|
||||
@ -188,15 +181,15 @@ void serialize(CMessageInfo& msg_info, char** out_buf, int& len, bool reuse_mem)
|
||||
ptr += sizeof(int);
|
||||
memcpy(ptr, info.data.data(), o_size);
|
||||
|
||||
char* mark = *out_buf;
|
||||
char* c = *out_buf;
|
||||
if (!use_encrypt) {
|
||||
mark[0] = 0x00;
|
||||
c[0] = 0x00;
|
||||
return;
|
||||
}
|
||||
uint8_t ik[32]{};
|
||||
hash(msg_info.id.c_str(), ik);
|
||||
encrypt(ik, (uint8_t*)(*out_buf + 1), len - 1);
|
||||
mark[0] = 0x01;
|
||||
encrypt(ik, (uint8_t*)(*out_buf + 1), len);
|
||||
c[0] = 0x01;
|
||||
}
|
||||
|
||||
bool deserialize(char* data, int len, CMessageInfo& msg_info)
|
||||
@ -207,13 +200,13 @@ bool deserialize(char* data, int len, CMessageInfo& msg_info)
|
||||
|
||||
auto& info = msg_info;
|
||||
char* ptr = data + kz + 1;
|
||||
uint8_t mark = data[0];
|
||||
uint8_t ie = data[0];
|
||||
int remaining = len;
|
||||
|
||||
if (mark != 0x00) {
|
||||
if (ie != 0x00) {
|
||||
uint8_t ik[32]{};
|
||||
hash(msg_info.id.c_str(), ik);
|
||||
if (!decrypt(ik, (uint8_t*)(data + 1), len - 1)) {
|
||||
if (!decrypt(ik, (uint8_t*)(data + 1), len)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -319,15 +312,9 @@ void hash(const char* data, uint8_t k[32])
|
||||
|
||||
void rdm(uint8_t* o, size_t size)
|
||||
{
|
||||
/*
|
||||
需要加密安全:坚持用random_device(慢)
|
||||
需要性能:用 mt19937 + uniform_int_distribution
|
||||
*/
|
||||
std::random_device rd;
|
||||
// std::mt19937 gen(rd());
|
||||
std::mt19937_64 gen(rd());
|
||||
std::uniform_int_distribution<int> dist(0, 255);
|
||||
std::generate(o, o + size, [&]() { return static_cast<uint8_t>(dist(gen)); });
|
||||
std::generate(o, o + size, [&]() { return static_cast<uint8_t>(dist(rd)); });
|
||||
}
|
||||
|
||||
bool encrypt(const uint8_t* k, uint8_t* m, size_t len)
|
||||
@ -340,7 +327,7 @@ bool encrypt(const uint8_t* k, uint8_t* m, size_t len)
|
||||
rdm(nonce, sizeof(nonce) - 4);
|
||||
memcpy(m, nonce, kz);
|
||||
|
||||
struct AES_ctx ctx{};
|
||||
struct AES_ctx ctx;
|
||||
AES_init_ctx_iv(&ctx, k, nonce);
|
||||
AES_CTR_xcrypt_buffer(&ctx, m + kz, len - kz);
|
||||
return true;
|
||||
@ -355,7 +342,7 @@ bool decrypt(const uint8_t* k, uint8_t* m, size_t len)
|
||||
uint8_t nonce[kz]{};
|
||||
memcpy(nonce, m, kz);
|
||||
|
||||
struct AES_ctx ctx{};
|
||||
struct AES_ctx ctx;
|
||||
AES_init_ctx_iv(&ctx, k, nonce);
|
||||
AES_CTR_xcrypt_buffer(&ctx, m + kz, len - kz);
|
||||
return true;
|
||||
|
24
util/util.h
24
util/util.h
@ -44,7 +44,7 @@ enum FrameType : int16_t {
|
||||
|
||||
// 此结构体成员顺序不可变动,涉及到序列化反序列化。
|
||||
struct CMessageInfo {
|
||||
explicit CMessageInfo(const std::string& id);
|
||||
CMessageInfo(const std::string& id);
|
||||
CMessageInfo(const CMessageInfo& info);
|
||||
CMessageInfo& operator=(const CMessageInfo& info);
|
||||
std::string id;
|
||||
@ -53,7 +53,7 @@ struct CMessageInfo {
|
||||
std::string data;
|
||||
};
|
||||
|
||||
void serialize(CMessageInfo& msg_info, char** out_buf, int& len, bool reuse_mem = false);
|
||||
void serialize(CMessageInfo& msg_info, char** out_buf, int& len);
|
||||
bool deserialize(char* data, int len, CMessageInfo& msg_info);
|
||||
std::string u8tolocal(const std::string& str);
|
||||
std::string localtou8(const std::string& str);
|
||||
@ -72,8 +72,8 @@ public:
|
||||
~CFrameBuffer();
|
||||
|
||||
public:
|
||||
std::string fid_;
|
||||
std::string tid_;
|
||||
std::string fid_{};
|
||||
std::string tid_{};
|
||||
|
||||
public:
|
||||
FrameType type_{};
|
||||
@ -113,8 +113,8 @@ inline std::string now_str()
|
||||
auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;
|
||||
|
||||
std::ostringstream timestamp;
|
||||
timestamp << std::put_time(std::localtime(&time_t_now), "[%m-%d %H:%M:%S") << "." << std::setfill('0') << std::setw(3)
|
||||
<< milliseconds.count() << "] ";
|
||||
timestamp << std::put_time(std::localtime(&time_t_now), "[%m-%d %H:%M:%S") << "." << std::setfill('0')
|
||||
<< std::setw(3) << milliseconds.count() << "] ";
|
||||
|
||||
return timestamp.str();
|
||||
}
|
||||
@ -122,27 +122,31 @@ inline std::string now_str()
|
||||
template <typename... Args> void TLOGI(const std::string& format, Args&&... args)
|
||||
{
|
||||
fc_lock_print();
|
||||
std::cout << ConsoleColor::Green << fmt::format(now_str() + format, std::forward<Args>(args)...) << std::endl;
|
||||
std::cout << ConsoleColor::Green << fmt::format(now_str() + format, std::forward<Args>(args)...)
|
||||
<< std::endl;
|
||||
fc_unlock_print();
|
||||
}
|
||||
|
||||
template <typename... Args> void TLOGW(const std::string& format, Args&&... args)
|
||||
{
|
||||
fc_lock_print();
|
||||
std::cout << ConsoleColor::Yellow << fmt::format(now_str() + format, std::forward<Args>(args)...) << std::endl;
|
||||
std::cout << ConsoleColor::Yellow << fmt::format(now_str() + format, std::forward<Args>(args)...)
|
||||
<< std::endl;
|
||||
fc_unlock_print();
|
||||
}
|
||||
|
||||
template <typename... Args> void TLOGE(const std::string& format, Args&&... args)
|
||||
{
|
||||
fc_lock_print();
|
||||
std::cout << ConsoleColor::Red << fmt::format(now_str() + format, std::forward<Args>(args)...) << std::endl;
|
||||
std::cout << ConsoleColor::Red << fmt::format(now_str() + format, std::forward<Args>(args)...)
|
||||
<< std::endl;
|
||||
fc_unlock_print();
|
||||
}
|
||||
|
||||
template <typename... Args> void TLOGD(const std::string& format, Args&&... args)
|
||||
{
|
||||
fc_lock_print();
|
||||
std::cout << ConsoleColor::Cyan << fmt::format(now_str() + format, std::forward<Args>(args)...) << std::endl;
|
||||
std::cout << ConsoleColor::Cyan << fmt::format(now_str() + format, std::forward<Args>(args)...)
|
||||
<< std::endl;
|
||||
fc_unlock_print();
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user