【云备份|| 日志 day6】文件业务处理模块

简介: 【云备份|| 日志 day6】文件业务处理模块

image.png

云备份day6

  • 业务处理

业务处理

云备份项目中 ,业务处理模块是针对客户端的业务请求进行处理,并最终给与响应。而整个过程中包含以下要实现的功能:

  1. 借助网络通信模块httplib库搭建http服务器与客户端进行网络通信
  2. 针对收到的请求进行对应的业务处理并进行响应(文件上传,列表查看,文件下载(包含断点续传))

业务处理模块要对客户端的请求进行处理,那么我们就需要提前定义好客户端与服务端的通信,明确客户端发送什么样的请求,服务端处理后应该给与什么样的响应,而这就是网络通信接口的设计。

HTTP文件上传:

request请求

POST /upload HTTP/1.1
Content-Length:11
Content-Type:multipart/form-data;boundary= ----WebKitFormBoundary+16字节随机字符
------WebKitFormBoundary
Content-Disposition:form-data;filename="a.txt";
hello world
------WebKitFormBoundary--


respons响应

HTTP/1.1 200 OK
Content-Length: 0

HTTP文件列表获取:

request请求

GET /list HTTP/1.1
Content-Length: 0


HTTP/1.1 200 OK

Content-Length:

Content-Type: text/html

<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Page of Download</title>
</head><body>
<h1>Download</h1>
<table><tr>
<td><a href="/download/a.txt"> a.txt </a></td>
<td align="right"> 1994-07-08 03:00 </td>
<td align="right"> 27K </td>
</tr></table></body>

HTTP文件下载:

GET /download/a.txt http/1.1
Content-Length: 0

响应

HTTP/1.1 200 OK
Content-Length: 100000
ETags: "filename-size-mtime一个能够唯一标识文件的数据"
Accept-Ranges: bytes

服务端业务处理模块实现-业务处理类设计

extern cloud::DataManager *_data;
class Service{
private:
int _server_port;
std::string _server_ip;
std::string _url_prefix;
httplib::Server _srv;
public:
static void Upload(const httplib::Request &req, httplib::Response &rsp);
static void List(const httplib::Request &req, httplib::Response &rsp);
static void Download(const httplib::Request &req,httplib::Response &rsp);
public:
Service();
bool RunModule();
}


代码:

class Service{
    private:
      int _server_port;
      std::string _server_ip;
      std::string _download_prefix;
      httplib::Server _server;
    private:
      static void Upload(const httplib::Request &req, httplib::Response &rsp) {
        // post /upload  文件数据在正文中(正文并不全是文件数据)
        auto ret = req.has_file("file");//判断有没有上传的文件区域
        if (ret == false){
          rsp.status = 400;
          return;
        }
        const auto& file = req.get_file_value("file");
        //file.filename//文件名称    file.content//文件数据
        std::string back_dir = Config::GetInstance()->GetBackDir();
        std::string realpath = back_dir + FileUtil(file.filename).FileName();
        FileUtil fu(realpath);
        fu.SetContent(file.content);//将数据写入文件中;
        BackupInfo info;
        info.NewBackupInfo(realpath);//组织备份的文件信息
        _data->Insert(info);//向数据管理模块添加备份的文件信息
        return ;
      }
      static std::string TimetoStr(time_t t) {
        std::string tmp = std::ctime(&t);
        return tmp;
      }
      static void ListShow(const httplib::Request &req, httplib::Response &rsp){
        //1. 获取所有的文件备份信息
        std::vector<BackupInfo> arry;
        _data->GetAll(&arry);
        //2. 根据所有备份信息,组织html文件数据
        std::stringstream ss;
        ss << "<html><head><title>Download</title></head>";
        ss << "<body><h1>Download</h1><table>";
        for (auto &a : arry){
          ss << "<tr>";
          std::string filename = FileUtil(a.real_path).FileName();
          ss << "<td><a href='" << a.url << "'>" << filename << "</a></td>";
          ss << "<td align='right'>" << TimetoStr(a.mtime) << "</td>";
          ss << "<td align='right'>" << a.fsize / 1024 << "k</td>";
          ss << "</tr>";
        }
        ss << "</table></body></html>";
        rsp.body = ss.str();
        rsp.set_header("Content-Type", "text/html");
        rsp.status = 200;
        return ;
      }
      static std::string GetETag(const BackupInfo &info) {
        // etg :  filename-fsize-mtime
        FileUtil fu(info.real_path);
        std::string etag = fu.FileName();
        etag += "-";
        etag += std::to_string(info.fsize);
        etag += "-";
        etag += std::to_string(info.mtime);
        return etag;
      }
      static void Download(const httplib::Request &req, httplib::Response &rsp){
        //1. 获取客户端请求的资源路径path   req.path
        //2. 根据资源路径,获取文件备份信息
        BackupInfo info;
        _data->GetOneByURL(req.path, &info);
        //3. 判断文件是否被压缩,如果被压缩,要先解压缩, 
        if (info.pack_flag == true){
          FileUtil fu(info.pack_path);
          fu.UnCompress(info.real_path);//将文件解压到备份目录下
          //4. 删除压缩包,修改备份信息(已经没有被压缩)
          fu.Remove();
          info.pack_flag = false;
          _data->Update(info);
        }
        bool retrans = false;
        std::string old_etag;
        if (req.has_header("If-Range")) {
          old_etag = req.get_header_value("If-Range");
          //有If-Range字段且,这个字段的值与请求文件的最新etag一致则符合断点续传
          if (old_etag == GetETag(info)) {
            retrans = true;
          }
        }
        //4. 读取文件数据,放入rsp.body中
        FileUtil fu(info.real_path);
        if (retrans == false){
          fu.GetContent(&rsp.body);
          //5. 设置响应头部字段: ETag, Accept-Ranges: bytes
          rsp.set_header("Accept-Ranges", "bytes");
          rsp.set_header("ETag", GetETag(info));
          rsp.set_header("Content-Type", "application/octet-stream");
          rsp.status = 200;
        }else {
          //httplib内部实现了对于区间请求也就是断点续传请求的处理
          //只需要我们用户将文件所有数据读取到rsp.body中,它内部会自动根据请求
          //区间,从body中取出指定区间数据进行响应
          // std::string  range = req.get_header_val("Range"); bytes=start-end
          fu.GetContent(&rsp.body);
          rsp.set_header("Accept-Ranges", "bytes");
          rsp.set_header("ETag", GetETag(info));
          rsp.set_header("Content-Type", "application/octet-stream");
          //rsp.set_header("Content-Range", "bytes start-end/fsize");
          rsp.status = 206;//区间请求响应的是206*****
        }
      }
    public:
      Service(){
        Config *config = Config::GetInstance();
        _server_port = config->GetServerPort();
        _server_ip = config->GetServerIp();
        _download_prefix = config->GetDownloadPrefix();
      }
      bool RunModule() {
        _server.Post("/upload", Upload);
        _server.Get("/listshow", ListShow);
        _server.Get("/", ListShow);
        std::string download_url = _download_prefix + "(.*)";
        _server.Get(download_url, Download);
        _server.listen(_server_ip.c_str(), _server_port);
        return true;
      }
  };


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
26天前
|
Linux Shell
Linux手动清理Linux脚本日志定时清理日志和log文件执行表达式
Linux手动清理Linux脚本日志定时清理日志和log文件执行表达式
78 1
|
1月前
|
Shell Linux C语言
【Shell 命令集合 网络通讯 】Linux 查看系统中的UUCP日志文件 uulog命令 使用指南
【Shell 命令集合 网络通讯 】Linux 查看系统中的UUCP日志文件 uulog命令 使用指南
29 0
|
1月前
|
监控 Shell Linux
【Shell 命令集合 系统管理 】Linux 自动轮转(log rotation)日志文件 logrotate命令 使用指南
【Shell 命令集合 系统管理 】Linux 自动轮转(log rotation)日志文件 logrotate命令 使用指南
51 0
|
1天前
|
Java 数据安全/隐私保护 开发者
【SpringBoot】讲清楚日志文件&&lombok
【SpringBoot】讲清楚日志文件&&lombok
|
8天前
|
运维 Oracle 关系型数据库
Oracle日志文件:数据王国的“记事本”
【4月更文挑战第19天】Oracle日志文件是数据库稳定运行的关键,记录数据变更历史,用于恢复和故障处理。它们协调并发操作,确保数据一致性和完整性。日志文件实时写入操作信息并定期刷新到磁盘,便于数据恢复。然而,日志文件需备份和归档以保证安全性,防止数据丢失。日志文件,数据王国的“记事本”,默默守护数据安全。
|
1月前
|
监控 Shell Linux
【Shell 命令集合 系统管理 】Linux 实时监控日志文件 swatch命令 使用指南
【Shell 命令集合 系统管理 】Linux 实时监控日志文件 swatch命令 使用指南
36 1
|
1月前
|
消息中间件 测试技术 Python
Python使用多线程解析超大日志文件
Python使用多线程解析超大日志文件
24 0
|
1月前
|
存储
Hudi Log日志文件格式分析(一)
Hudi Log日志文件格式分析(一)
27 1
|
1月前
|
缓存 索引
Hudi Log日志文件写入分析(二)
Hudi Log日志文件写入分析(二)
21 1
|
1月前
|
监控 Python
Python生成日志文件
Python生成日志文件
22 0