Compare commits
2 Commits
eea5eee933
...
3ded526713
Author | SHA1 | Date | |
---|---|---|---|
3ded526713 | |||
f6e7596367 |
@ -1,6 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(transm VERSION 1.4.0 LANGUAGES CXX)
|
||||
project(transm VERSION 1.4.1 LANGUAGES CXX)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
|
98
README.md
98
README.md
@ -8,35 +8,32 @@
|
||||
|
||||
**注**:使用安装包的用户,如果想变更安装位置的话,请先卸载旧版本(原位置更新最新版不用卸载)。
|
||||
|
||||
# 一、简要介绍
|
||||
# 一、说明
|
||||
|
||||
| 主要功能序号 | 简介 |
|
||||
| ------------ | ------------------------------------------------------------ |
|
||||
| 1 | A端提交文件列表到服务端,B端可以从服务端查阅有哪些客户端提交的哪些任务,自行选择下载。 |
|
||||
| 2 | A端可以提交一个下载任务文件给B端,B端会自动下载列表中的文件(可用作更新远端文件)。 |
|
||||
| 3 | A端可以直接给B端发送文件(v1.3.1及其以后版本)。
|
||||
**注意:** 当前说明文档仅针对`v1.4.1`及其以后的版本,此前的版本需要检出对应`tag`的`README.md`或者下载对应发布版本的源码,然后解压其中的`README.md`。
|
||||
|
||||
服务端程序支持任意个客户端相互之间**同时连接**和**同时传输**文件,吞吐瓶颈在服务端主机网络上。
|
||||
|
||||
- `tss`和`tsc`均为命令行端程序,无GUI。
|
||||
|
||||
- `tsc`从`tss`下载文件的时候,如果本地有已存在则会被**覆盖**(注意)。
|
||||
|
||||
- 介绍所指的客户端`A`、`B`是泛指,实际服务端程序支持任意个客户端相互之间**同时连接**和**同时传输**文件,吞吐瓶颈在服务端主机网络上。
|
||||
|
||||
## 一些特点(基于最新版本)
|
||||
|
||||
- 通配符传输。
|
||||
- 终端自动文件补全。
|
||||
- 自动更新远程文件。
|
||||
- 多客户端可以同时互相收发文件。
|
||||
- 自动检测对方掉线。
|
||||
- 服务端自我安全防御(若部署到云端防止常规攻击)。
|
||||
- 广泛的平台支持。
|
||||
- 服务端仅转发数据,不存储数据。
|
||||
- 终端自动文件补全。
|
||||
- 自动检测对方掉线。
|
||||
- 极小的、单个文件。
|
||||
- 干净,不会在客户机环境到处遗留临时文件。
|
||||
- 支持相对路径处理。
|
||||
- 单端可以操作下载发送。
|
||||
- 支持单客户端操作收发本地文件。
|
||||
- 多客户端可以同时互相收发文件。
|
||||
- 服务端仅转发数据,不存储数据。
|
||||
- 运行时无其他三方二进制库依赖。
|
||||
- 临时公网传输,无需使用三方需要登陆软件。
|
||||
- `Linux`到`Linux`文件传输保留原权限。
|
||||
- 干净,不会在客户机环境到处遗留临时文件。
|
||||
- 临时公网传输,无需使用三方需要登陆软件。
|
||||
- 服务端自我安全防御(若部署到云端防止常规攻击)。
|
||||
- 支持拒绝同时操作同设备同路径文件,防止文件内容丢失。
|
||||
|
||||
# 二、使用说明
|
||||
|
||||
@ -44,76 +41,31 @@
|
||||
|
||||
- 对于服务端程序`tss`,绑定默认绑定`0.0.0.0`的`9898`端口,如果需要修改端口,使用参数启动,示例:`tss 9898`。
|
||||
- 对于客户端程序`tsc`,请使用`tsc --help`查看使用方式。
|
||||
- `Up`指令后面的文件名路径,如果是非全路径(即相对路径),程序会自动拼接到当前`tsc`工作目录(如`Up dira/test.txt`也是可以的)。
|
||||
|
||||
## 2.命令使用(截图可能过时,但使用方式大致如此)
|
||||
## 2.使用
|
||||
|
||||
### 2.1 客户端 tsc 简介
|
||||
`tsc`连接到服务端`tss`后,可以输入`h`查看所有指令的具体介绍。
|
||||
|
||||

|
||||
|
||||
### 2.2 功能一简介
|
||||
## 3.介绍补充
|
||||
|
||||

|
||||
- 需要传入存储路径的指令,如果未填写,默认`tsc`当前工作目录。
|
||||
- `任务文件`格式统一为`UTF-8`编码。
|
||||
- 支持相对路径处理。
|
||||
- `UpTask`和`DownTask`指令`任务文件`格式完全一致,均为左文件,右目录,尽管是下载别人文件。
|
||||
|
||||
### 2.3 功能二简介
|
||||
|
||||

|
||||
|
||||
### 3.1 Get功能
|
||||
|
||||
`v1.2.3`版本起(含),当某个客户端的列表文件数量过多时,只展示部分(会显示总数量)。
|
||||
|
||||
### 3.2 Up功能
|
||||
|
||||
`v1.2.3`版本起(含),`up`后路径支持`?`和`*`通配符:
|
||||
|
||||
```shell
|
||||
up /home/zhang/png/cloud*.png|/home/zhang/download/202?-*.exe
|
||||
```
|
||||
|
||||
### 3.3 Down功能
|
||||
|
||||
`v1.2.3`版本起(含),支持传入下载位置(默认命令所在目录):
|
||||
|
||||
```shell
|
||||
down 1 dira/dirb
|
||||
down 1 ../download
|
||||
down 2 /home/zhang/document
|
||||
```
|
||||
|
||||
### 3.4 Update功能
|
||||
|
||||
命令格式为:`Update 客户端标号 列表文件`
|
||||
|
||||
`Update`的提交的列表文件格式为`txt`,内容为每一行格式是`A|B`,其中`A`为提交端的文件路径,`B`为要放到下载端的哪个目录 **(下载端必须存在这个目录,否则下载端拒绝自动下载)**。
|
||||
|
||||
示例执行:`Update 1 task.txt`,其中`task.txt`内容示例如下:
|
||||
|
||||
```txt
|
||||
D:/文件/abc.zip|/home/zhangsan/downlaod
|
||||
D:/截图/Ni.jpg|/home/zhangsan/picture
|
||||
```
|
||||
|
||||
#### update新增(一)
|
||||
|
||||
`v1.2.1`版本起(含),`task.txt`支持以下变量:
|
||||
具体`任务文件`内容格式如下(左侧发送端,右侧接受端),内容支持变量:
|
||||
|
||||
- ${HOME},用户目录(发送端接收端均支持)。
|
||||
- ${CURRENT},任务文件所在目录(即`task.txt`所在目录,该变量仅支持发送端,也就是`|`左侧,因为接收端没有任务文件所在路径)
|
||||
- ${CURRENT},任务文件所在目录(该变量仅支持发送端,也就是`|`左侧,因为接收端没有任务文件所在路径)
|
||||
|
||||
```txt
|
||||
${HOME}/截图/Ni.jpg|${HOME}/dira
|
||||
${CURRENT}/xxx.zip|D:\
|
||||
```
|
||||
|
||||
**NOTE**: `列表文件`的格式为`UTF-8`编码。
|
||||
|
||||
# 注意
|
||||
|
||||
- 如果两个`tsc`客户端在同一台机器上同时收发同一个文件将导致文件丢失损坏(如果收发操作的是同一个文件)。
|
||||
|
||||
# 编译
|
||||
# 三、编译
|
||||
|
||||
当前项目支持`cmake`构建工具。
|
||||
|
||||
|
@ -50,6 +50,78 @@ CClient::~CClient()
|
||||
}
|
||||
}
|
||||
|
||||
void CClient::print_help(bool detail)
|
||||
{
|
||||
TLOGI("version: {}", VERSION_NUM);
|
||||
TLOGI("opensource: {}", VERSION_URL);
|
||||
TLOGW("SupportCmd ==>");
|
||||
|
||||
if (!detail) {
|
||||
TLOGW("Get|Who|Where|Ls|Sub|Fetch|Up|Down|UpTask|DownTask");
|
||||
TLOGI("You can use 'h' to show cmd's detail.");
|
||||
TLOGI("You can use 'end' or 'ctrl-c' to exit.");
|
||||
return;
|
||||
}
|
||||
|
||||
constexpr char* sp = "==================================================";
|
||||
TLOGI("{}", sp);
|
||||
TLOGW("#Get#");
|
||||
TLOGI(" des: Get all clients on server.");
|
||||
TLOGI(" cmd: Get get g G");
|
||||
TLOGI(" arg: NULL");
|
||||
TLOGI("{}", sp);
|
||||
TLOGW("#Who#");
|
||||
TLOGI(" des: Show current client's ID.");
|
||||
TLOGI(" cmd: Who who");
|
||||
TLOGI(" arg: NULL");
|
||||
TLOGI("{}", sp);
|
||||
TLOGW("#Where#");
|
||||
TLOGI(" des: Show current client's work dir.");
|
||||
TLOGI(" cmd: Where where wh");
|
||||
TLOGI(" arg: NULL");
|
||||
TLOGI("{}", sp);
|
||||
TLOGW("#Ls#");
|
||||
TLOGI(" des: List one client's all files and folders.");
|
||||
TLOGI(" cmd: Ls ls");
|
||||
TLOGI(" arg: @id @dir");
|
||||
TLOGI("{}", sp);
|
||||
TLOGW("#Sub#");
|
||||
TLOGI(" des: Submit local file's list on the server.");
|
||||
TLOGI(" cmd: Sub sub");
|
||||
TLOGI(" arg: @files(Separated by | if multi)");
|
||||
TLOGI("{}", sp);
|
||||
TLOGW("#Fetch#");
|
||||
TLOGI(" des: Fetch one client's submited files.");
|
||||
TLOGI(" cmd: Fetch fetch");
|
||||
TLOGI(" arg: @id @savedir");
|
||||
TLOGI("{}", sp);
|
||||
TLOGW("#Clear#");
|
||||
TLOGI(" des: clear submited list.");
|
||||
TLOGI(" cmd: Clear clear c C");
|
||||
TLOGI(" arg: NULL");
|
||||
TLOGI("{}", sp);
|
||||
TLOGW("#Up#");
|
||||
TLOGI(" des: Upload local files to one client directly.");
|
||||
TLOGI(" cmd: Up up");
|
||||
TLOGI(" arg: @id @files(Sep by | if multi) @savedir");
|
||||
TLOGI("{}", sp);
|
||||
TLOGW("#Down#");
|
||||
TLOGI(" des: Down one client's files directly.");
|
||||
TLOGI(" cmd: Down down");
|
||||
TLOGI(" arg: @id @files(Sep by | if multi) @savedir(opt)");
|
||||
TLOGI("{}", sp);
|
||||
TLOGW("#UpTask#");
|
||||
TLOGI(" des: Down one client's files directly.");
|
||||
TLOGI(" cmd: UpTask uptask ut");
|
||||
TLOGI(" arg: @id @taskfile(UTF-8)");
|
||||
TLOGI("{}", sp);
|
||||
TLOGW("#DownTask#");
|
||||
TLOGI(" des: Down one client's files directly.");
|
||||
TLOGI(" cmd: DownTask downtask dt");
|
||||
TLOGI(" arg: @id @taskfile(UTF-8)");
|
||||
TLOGI("{}", sp);
|
||||
}
|
||||
|
||||
void CClient::run(const std::string& ip, const std::string& port, const std::string& config_dir)
|
||||
{
|
||||
fs::path fp(config_dir);
|
||||
@ -80,16 +152,13 @@ void CClient::run(const std::string& ip, const std::string& port, const std::str
|
||||
std::thread thread([&]() { io_context_.run(); });
|
||||
th_down_active_ = std::thread([&]() { judget_down_active(); });
|
||||
|
||||
get_id();
|
||||
if (ip == "127.0.0.1") {
|
||||
get_task_list();
|
||||
}
|
||||
|
||||
TLOGI("version: {}", VERSION_NUM);
|
||||
TLOGI("opensource: {}", VERSION_URL);
|
||||
TLOGW("SupportCmd ==>");
|
||||
TLOGW("Get|Up|Down|Cancel|Update|Who|Where|Ls|Req");
|
||||
print_help(false);
|
||||
fc_append('|');
|
||||
get_id();
|
||||
|
||||
if (ip == "127.0.0.1") {
|
||||
get_clients();
|
||||
}
|
||||
|
||||
while (1) {
|
||||
char* readline = fc_readline();
|
||||
@ -104,6 +173,12 @@ void CClient::run(const std::string& ip, const std::string& port, const std::str
|
||||
fc_free(readline);
|
||||
std::cout << "" << std::endl;
|
||||
cmd_input = ofen::COfStr::trim(cmd_input);
|
||||
|
||||
if (cmd_input == "help" || cmd_input == "h") {
|
||||
print_help(true);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cmd_input == "end" || cmd_input == "End") {
|
||||
th_run_ = false;
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
@ -119,11 +194,11 @@ void CClient::run(const std::string& ip, const std::string& port, const std::str
|
||||
continue;
|
||||
}
|
||||
if (cmd_input == "Get" || cmd_input == "get" || cmd_input == "g" || cmd_input == "G") {
|
||||
get_task_list();
|
||||
get_clients();
|
||||
continue;
|
||||
}
|
||||
if (cmd_input == "Cancel" || cmd_input == "cancel" || cmd_input == "c" || cmd_input == "C") {
|
||||
cancel_task();
|
||||
if (cmd_input == "Clear" || cmd_input == "clear" || cmd_input == "c" || cmd_input == "C") {
|
||||
cmd_clear_submited();
|
||||
continue;
|
||||
}
|
||||
auto vec = COfStr::split(cmd_input, " ");
|
||||
@ -135,28 +210,32 @@ void CClient::run(const std::string& ip, const std::string& port, const std::str
|
||||
std::string scmd = param.substr(0, param.find_first_of(" "));
|
||||
param.erase(0, param.find_first_of(" ") + 1);
|
||||
|
||||
if (scmd == "Update" || scmd == "update") {
|
||||
request_update_list(param);
|
||||
if (scmd == "UpTask" || scmd == "uptask" || scmd == "ut") {
|
||||
cmd_sub_task(param, true);
|
||||
continue;
|
||||
}
|
||||
if (scmd == "Send" || scmd == "send") {
|
||||
send_files(param);
|
||||
continue;
|
||||
}
|
||||
if (scmd == "Down" || scmd == "down") {
|
||||
down_task(param);
|
||||
if (scmd == "DownTask" || scmd == "downtask" || scmd == "dt") {
|
||||
cmd_sub_task(param, false);
|
||||
continue;
|
||||
}
|
||||
if (scmd == "Up" || scmd == "up") {
|
||||
up_task(param);
|
||||
cmd_upload_files(param);
|
||||
continue;
|
||||
}
|
||||
if (scmd == "Fetch" || scmd == "fetch") {
|
||||
cmd_fetch_files(param);
|
||||
continue;
|
||||
}
|
||||
if (scmd == "Sub" || scmd == "sub") {
|
||||
cmd_sub_list(param);
|
||||
continue;
|
||||
}
|
||||
if (scmd == "Ls" || scmd == "ls") {
|
||||
require_dir_files(param);
|
||||
cmd_ls(param);
|
||||
continue;
|
||||
}
|
||||
if (scmd == "Req" || scmd == "req") {
|
||||
down_req_list(param);
|
||||
if (scmd == "Down" || scmd == "down") {
|
||||
cmd_down_list(param);
|
||||
continue;
|
||||
}
|
||||
TLOGE("No matched cmd, May be param size incorrect.");
|
||||
@ -166,14 +245,14 @@ void CClient::run(const std::string& ip, const std::string& port, const std::str
|
||||
TLOGI("{} exit.", __FUNCTION__);
|
||||
}
|
||||
|
||||
bool CClient::get_task_list()
|
||||
bool CClient::get_clients()
|
||||
{
|
||||
std::shared_ptr<CFrameBuffer> buf = std::make_shared<CFrameBuffer>();
|
||||
buf->type_ = TYPE_GET_LIST;
|
||||
return send_frame(buf.get());
|
||||
}
|
||||
|
||||
bool CClient::down_task(const std::string& param)
|
||||
bool CClient::cmd_fetch_files(const std::string& param)
|
||||
{
|
||||
if (downloading_) {
|
||||
TLOGW("Have Task Downloading, Please wait.....");
|
||||
@ -218,7 +297,7 @@ bool CClient::down_task(const std::string& param)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CClient::up_task(const std::string& param)
|
||||
bool CClient::cmd_sub_list(const std::string& param)
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
@ -270,7 +349,7 @@ bool CClient::up_task(const std::string& param)
|
||||
return send_frame(buf.get());
|
||||
}
|
||||
|
||||
bool CClient::cancel_task()
|
||||
bool CClient::cmd_clear_submited()
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
@ -286,7 +365,7 @@ bool CClient::cancel_task()
|
||||
return send_frame(buf.get());
|
||||
}
|
||||
|
||||
bool CClient::send_files(const std::string& param)
|
||||
bool CClient::cmd_upload_files(const std::string& param)
|
||||
{
|
||||
auto tvec = COfStr::split(param, " ");
|
||||
if (tvec.size() < 3) {
|
||||
@ -338,7 +417,7 @@ bool CClient::send_files(const std::string& param)
|
||||
return false;
|
||||
}
|
||||
|
||||
auto handel_ret = handle_user_select(mre);
|
||||
auto handel_ret = handle_user_select(mre, true);
|
||||
if (handel_ret.empty()) {
|
||||
TLOGE("handle_user_select not pass, abort action!");
|
||||
return false;
|
||||
@ -470,7 +549,7 @@ void CClient::report_trans_ret(TransState state, const std::string& key)
|
||||
|
||||
功能为,请求某个客户端,更新我所列出的文件,右侧是远端需要存储的目录(必须存在,不存在则不理会)
|
||||
*/
|
||||
bool CClient::request_update_list(const std::string& param)
|
||||
bool CClient::cmd_sub_task(const std::string& param, bool is_send)
|
||||
{
|
||||
auto tvec = COfStr::split(param, " ");
|
||||
if (tvec.size() < 2) {
|
||||
@ -490,20 +569,19 @@ bool CClient::request_update_list(const std::string& param)
|
||||
}
|
||||
|
||||
const auto& sr = clients_[index];
|
||||
bool local_trans = false;
|
||||
if (sr->id == own_id_) {
|
||||
TLOGW("local_trans path handle mode!!!");
|
||||
local_trans = true;
|
||||
}
|
||||
|
||||
// 读取list文件
|
||||
std::string list_file_full = COfPath::to_full(list_file);
|
||||
|
||||
if (fs::is_directory(list_file_full)) {
|
||||
TLOGE("{} is a directory, only support file.", list_file_full);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool local_trans = false;
|
||||
if (sr->uuid == uuid_) {
|
||||
TLOGW("local_trans path handle mode!!!");
|
||||
local_trans = true;
|
||||
}
|
||||
|
||||
std::ifstream in(list_file_full);
|
||||
if (!in.is_open()) {
|
||||
TLOGE("Can't Open File:{}", list_file_full);
|
||||
@ -515,6 +593,7 @@ bool CClient::request_update_list(const std::string& param)
|
||||
in.close();
|
||||
|
||||
#if defined(_WIN32)
|
||||
// 从文件中读取的内容还是要手动转码一下。
|
||||
content = CCodec::u8_to_ansi(content);
|
||||
#endif
|
||||
|
||||
@ -533,27 +612,17 @@ bool CClient::request_update_list(const std::string& param)
|
||||
if (v.size() >= 2) {
|
||||
auto pr = variable_handle(list_file_full, v[0], true);
|
||||
pr = COfPath::standardize(pr);
|
||||
if (!fs::exists(pr)) {
|
||||
if (is_send && !fs::exists(pr)) {
|
||||
TLOGE("file {} not exist.", pr);
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
TLOGI("--->check pass {}:{}", line, pr);
|
||||
auto sec = v[1];
|
||||
if (local_trans) {
|
||||
sec = variable_handle(list_file_full, v[1], true);
|
||||
sec = COfPath::standardize(sec);
|
||||
if (!fs::is_directory(sec) || !fs::exists(sec)) {
|
||||
TLOGE("not directory or {} not exist.", pr);
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
if (COfPath::is_same_dir(pr, sec)) {
|
||||
TLOGE("Local Trans Can't Transfer {} to {}", pr, sec);
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
if (is_send) {
|
||||
TLOGI("--->check pass {}:{}", line, pr);
|
||||
}
|
||||
auto sec = v[1];
|
||||
sec = variable_handle(list_file_full, sec, local_trans);
|
||||
sec = COfPath::standardize(sec);
|
||||
mre[line++] = pr + "|" + sec;
|
||||
continue;
|
||||
}
|
||||
@ -566,7 +635,7 @@ bool CClient::request_update_list(const std::string& param)
|
||||
return false;
|
||||
}
|
||||
|
||||
auto handel_ret = handle_user_select(mre);
|
||||
auto handel_ret = handle_user_select(mre, is_send);
|
||||
if (handel_ret.empty()) {
|
||||
TLOGE("handle_user_select not pass, abort action!");
|
||||
return false;
|
||||
@ -574,7 +643,12 @@ bool CClient::request_update_list(const std::string& param)
|
||||
|
||||
list_file_ = list_file_full;
|
||||
std::shared_ptr<CFrameBuffer> buf = std::make_shared<CFrameBuffer>();
|
||||
buf->type_ = TYPE_REQUEST_UPDATE_LIST;
|
||||
|
||||
if (is_send) {
|
||||
buf->type_ = TYPE_REQUEST_UPDATE_LIST;
|
||||
} else {
|
||||
buf->type_ = TYPE_REQUEST_DOWN_UPDATE_LIST;
|
||||
}
|
||||
CMessageInfo msg_info;
|
||||
msg_info.str = handel_ret;
|
||||
serialize(msg_info, &buf->data_, buf->len_);
|
||||
@ -587,7 +661,7 @@ bool CClient::request_update_list(const std::string& param)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CClient::check_update_list(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;
|
||||
@ -665,7 +739,7 @@ bool CClient::get_dir_files(const std::string& dir, std::string& out, std::strin
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CClient::require_dir_files(const std::string& param)
|
||||
bool CClient::cmd_ls(const std::string& param)
|
||||
{
|
||||
auto tvec = COfStr::split(param, " ");
|
||||
if (tvec.size() < 2) {
|
||||
@ -695,7 +769,7 @@ bool CClient::require_dir_files(const std::string& param)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CClient::down_req_list(const std::string& param)
|
||||
bool CClient::cmd_down_list(const std::string& param)
|
||||
{
|
||||
auto tvec = COfStr::split(param, " ");
|
||||
if (tvec.size() < 2) {
|
||||
@ -796,6 +870,45 @@ std::vector<std::string> CClient::load_line_his()
|
||||
return history;
|
||||
}
|
||||
|
||||
std::string CClient::variable_and_reverse_files(const std::string& source)
|
||||
{
|
||||
auto vec = COfStr::split(source, "\n");
|
||||
std::string result;
|
||||
bool valid = true;
|
||||
for (const auto& item : vec) {
|
||||
auto rl = COfStr::trim(item);
|
||||
if (rl.empty()) {
|
||||
continue;
|
||||
}
|
||||
auto vi = COfStr::split(rl, "|");
|
||||
if (vi.size() != 2) {
|
||||
TLOGE("Size not 2 {}", item);
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
auto pr = variable_handle("", vi[1], false);
|
||||
if (!fs::exists(pr)) {
|
||||
valid = false;
|
||||
TLOGE("Not exist {}", pr);
|
||||
break;
|
||||
}
|
||||
TLOGI("---> check pass {}", pr);
|
||||
|
||||
fs::path ppr(pr);
|
||||
fs::path pvi(vi[0]);
|
||||
|
||||
auto lp = ppr.append(pvi.filename().string()).string();
|
||||
auto rp = pvi.parent_path().string();
|
||||
|
||||
auto line = lp + "|" + rp;
|
||||
result = result + line + "\n";
|
||||
}
|
||||
if (!valid) {
|
||||
return "";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CClient::save_uuid()
|
||||
{
|
||||
fs::path uuid_path(uuid_path_);
|
||||
@ -1058,6 +1171,23 @@ void CClient::handle_frame(CFrameBuffer* buf)
|
||||
report_trans_ret(TRANS_FAILED);
|
||||
break;
|
||||
}
|
||||
case TYPE_REQUEST_DOWN_UPDATE_LIST: {
|
||||
CMessageInfo msg_info;
|
||||
if (!deserialize(buf->data_, buf->len_, msg_info)) {
|
||||
TLOGE("{} GetList deserialize failed.", __LINE__);
|
||||
break;
|
||||
}
|
||||
delete[] buf->data_;
|
||||
msg_info.str = variable_and_reverse_files(msg_info.str);
|
||||
serialize(msg_info, &buf->data_, buf->len_);
|
||||
std::swap(buf->tid_, buf->fid_);
|
||||
buf->type_ = TYPE_REQUEST_UPDATE_LIST;
|
||||
if (!send_frame(buf)) {
|
||||
TLOGE("Send Failed {}.", __LINE__);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
};
|
||||
case TYPE_REQUEST_UPDATE_LIST: {
|
||||
std::map<std::string, std::string> files;
|
||||
if (down_ && down_->trans_state_ == TRANS_REDAY) {
|
||||
@ -1069,7 +1199,7 @@ void CClient::handle_frame(CFrameBuffer* buf)
|
||||
TLOGE("{} GetList deserialize failed.", __LINE__);
|
||||
break;
|
||||
}
|
||||
if (check_update_list(msg_info.str, files)) {
|
||||
if (variable_and_parse_files(msg_info.str, files)) {
|
||||
buf->type_ = TYPE_CONFIRM_UPDATE_LIST;
|
||||
} else {
|
||||
buf->type_ = TYPE_UNCONFIRM_UPDATE_LIST;
|
||||
@ -1240,16 +1370,19 @@ void CClient::judget_down_active()
|
||||
}
|
||||
|
||||
std::string CClient::variable_handle(const std::string& task_list_path, const std::string& source,
|
||||
bool is_send)
|
||||
bool is_local)
|
||||
{
|
||||
std::string result(source);
|
||||
// 支持的变量如下:
|
||||
// ${HOME} 用户目录(发送端接收端均支持)
|
||||
// ${CURRENT} 任务文件所在目录(该变量仅支持发送端,因为接收端没有任务文件所在路径)
|
||||
if (source.find("${HOME}") != std::string::npos) {
|
||||
if (is_local && source.find("${HOME}") != std::string::npos) {
|
||||
result = COfStr::replace(result, "${HOME}", COfPath::get_home());
|
||||
}
|
||||
if (is_send && source.find("${CURRENT}") != std::string::npos) {
|
||||
if (is_local && source.find("${CURRENT}") != std::string::npos) {
|
||||
if (task_list_path.empty()) {
|
||||
return result;
|
||||
}
|
||||
fs::path p(task_list_path);
|
||||
std::string list_dir = p.parent_path().string();
|
||||
result = COfStr::replace(result, "${CURRENT}", list_dir);
|
||||
@ -1257,14 +1390,25 @@ std::string CClient::variable_handle(const std::string& task_list_path, const st
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string CClient::handle_user_select(const std::unordered_map<int, std::string>& source)
|
||||
std::string CClient::handle_user_select(const std::unordered_map<int, std::string>& source, bool is_send)
|
||||
{
|
||||
std::string handled_content{};
|
||||
std::string input{};
|
||||
|
||||
if (!is_send) {
|
||||
handled_content.clear(); // 清空之前的内容
|
||||
for (const auto& pair : source) {
|
||||
handled_content.append(pair.second + "\n");
|
||||
}
|
||||
return handled_content;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
TLOGI("numbers by space, or '0' use all, 'end' to quit: ");
|
||||
std::getline(std::cin, input);
|
||||
// std::getline(std::cin, input);
|
||||
char* readline = fc_readline();
|
||||
input = std::string(readline);
|
||||
fc_free(readline);
|
||||
|
||||
if (input == "end") {
|
||||
handled_content.clear();
|
||||
|
@ -48,35 +48,37 @@ public:
|
||||
void run(const std::string& ip, const std::string& port, const std::string& config_dir);
|
||||
|
||||
public:
|
||||
bool get_task_list();
|
||||
bool down_task(const std::string& param);
|
||||
bool up_task(const std::string& param);
|
||||
bool cancel_task();
|
||||
bool send_files(const std::string& param);
|
||||
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 request_update_list(const std::string& param);
|
||||
bool check_update_list(const std::string& content, std::map<std::string, std::string>& files);
|
||||
bool cmd_sub_task(const std::string& param, bool is_send);
|
||||
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);
|
||||
bool require_dir_files(const std::string& param);
|
||||
bool down_req_list(const std::string& param);
|
||||
bool cmd_ls(const std::string& param);
|
||||
bool cmd_down_list(const std::string& param);
|
||||
|
||||
private:
|
||||
bool send_frame(CFrameBuffer* buf);
|
||||
void save_line_his(const std::string& input);
|
||||
std::vector<std::string> load_line_his();
|
||||
std::string variable_and_reverse_files(const std::string& source);
|
||||
bool save_uuid();
|
||||
std::string read_uuid();
|
||||
void get_id();
|
||||
void print_help(bool detail);
|
||||
|
||||
private:
|
||||
void handle_frame(CFrameBuffer* buf);
|
||||
void send_file_data_th(const char* keys);
|
||||
void hearts();
|
||||
void judget_down_active();
|
||||
std::string variable_handle(const std::string& task_list_path, const std::string& source, bool is_send);
|
||||
std::string handle_user_select(const std::unordered_map<int, std::string>& source);
|
||||
std::string variable_handle(const std::string& task_list_path, const std::string& source, bool is_local);
|
||||
std::string handle_user_select(const std::unordered_map<int, std::string>& source, bool is_send);
|
||||
|
||||
private:
|
||||
std::mutex mutex_;
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit c477dad67e171aecf9fb5b8ce361119bf459ff8f
|
||||
Subproject commit 4b6612cc63f21b4d092a0b5731ceb7f817f20d23
|
BIN
img/func1.png
BIN
img/func1.png
Binary file not shown.
Before Width: | Height: | Size: 796 KiB |
BIN
img/func2.png
BIN
img/func2.png
Binary file not shown.
Before Width: | Height: | Size: 1.1 MiB |
BIN
img/tsc_use.png
BIN
img/tsc_use.png
Binary file not shown.
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 578 KiB |
@ -29,6 +29,7 @@ enum FrameType : int16_t {
|
||||
TYPE_OFFLINE,
|
||||
TYPE_JUDGE_ACTIVE,
|
||||
TYPE_REQUEST_UPDATE_LIST,
|
||||
TYPE_REQUEST_DOWN_UPDATE_LIST,
|
||||
TYPE_CONFIRM_UPDATE_LIST,
|
||||
TYPE_UNCONFIRM_UPDATE_LIST,
|
||||
TYPE_DONE_UPDATE_LIST,
|
||||
@ -106,7 +107,7 @@ 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), "[%Y-%m-%d %H:%M:%S") << "." << std::setfill('0')
|
||||
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();
|
||||
|
Loading…
x
Reference in New Issue
Block a user