Compare commits

..

No commits in common. "main" and "v1.5.0" have entirely different histories.
main ... v1.5.0

32 changed files with 487 additions and 37779 deletions

View File

@ -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
View File

@ -6,4 +6,3 @@ cmake-*
compile_commands.json
out
xpbuild
cbuild

3
.gitmodules vendored
View File

@ -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
View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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
View 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": []
}
]
}

View File

@ -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`构建工具。

View File

@ -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

View File

@ -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,7 +1421,7 @@ void TransmClient::judget_down_active()
}
}
std::string TransmClient::variable_handle(const std::string& task_list_path, const std::string& source,
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{};

View File

@ -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

View File

@ -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());

View File

@ -25,11 +25,11 @@ struct CmdParam {
bool null_use{false};
};
class ClientConfig
class CServerConfig
{
public:
ClientConfig();
~ClientConfig();
CServerConfig();
~CServerConfig();
public:
bool baseInit();

View File

@ -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

View File

@ -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()

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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);

View File

@ -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();

View File

@ -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)

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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();
}

View File

@ -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
View 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;
}

View File

@ -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;

View File

@ -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();
}