PracticeDev/study_cpp/P2P-Share/p2pserver.cpp

154 lines
4.1 KiB
C++

#include<iostream>
#include<unistd.h>
#include<boost/filesystem.hpp>
#include<stdio.h>
#include "httplib.h"
#define SHARD_PATH "SHARD"
#define LOG(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)
using namespace httplib;
namespace bf = boost::filesystem;
class P2PServer
{
private:
Server _server;
private:
static void GetHostPair(const Request& req,Response& rsp)
{
rsp.status =200;
return;
}
static void GetFileList(const Request& req,Response& rsp)
{
bf::directory_iterator it_begin(SHARD_PATH);
bf::directory_iterator it_end;
std::stringstream body;
// body<<"<html><body>";
for(;it_begin!=it_end;it_begin++){
if(bf::is_directory(it_begin->status())){
continue;
}
std::string name = it_begin->path().filename().string();
rsp.body+=name+"\n";
// body << "<h4><a href='/list/"<< name <<"'>";
// body << name;
// body <<"</a></h4>";
//rsp.body+=name;
}
// body<<"</body></html>";
// rsp.body = body.str();
rsp.set_header("Content-Type","text/html");//渲染
rsp.status = 200;
}
static void GetFileData(const Request& req,Response& rsp)
{
//a.txt->Dowanload/a.txt
bf::path path(req.path); //生成一个path对象
std::stringstream name;
name<< SHARD_PATH << "/" << path.filename().string();
if(!bf::exists(name.str())){
rsp.status = 404;
return;
}
if(bf::is_directory(name.str())){
rsp.status = 403;
return;
}
int64_t fsize = bf::file_size(name.str());
if(req.method == "HEAD"){
rsp.status = 200;
std::string len = std::to_string(fsize);
rsp.set_header("Content-Length", len.c_str());
return;
}
else{
if(!req.has_header("Range")){
rsp.status = 400;
return;
}
std::string range_val;
range_val = req.get_header_value("Range");
int64_t start, rlen;
bool ret = RangeParse(range_val, start, rlen);
if(ret == false){
rsp.status = 400;
return;
}
std::cerr << "body.resize: " << rlen << "\n";
rsp.body.resize(rlen);
std::ifstream file(name.str(),std::ios::binary);
if(!file.is_open())
{
std::cerr<<"open file"<<name.str()<<"failed\n";
rsp.status = 404;
return;
}
file.seekg(start, std::ios::beg);
file.read(&rsp.body[0],rlen); //写到body里了
if(!file.good()){
std::cerr<<"read file"<<name.str()<<"body error\n";
rsp.status = 500;
return;
}
file.close();
rsp.status = 206;
rsp.set_header("Content-Type","application/octet-stream");//二进制流
std::cerr << "file range: " << range_val;
std::cerr << "download success\n";
}
}
static bool RangeParse(std::string &range_val, int64_t &start, \
int64_t &len){
size_t pos1 = range_val.find("=");
size_t pos2 = range_val.find("-");
if(pos1 == std::string::npos ||
pos2 == std::string::npos){
std::cerr << "range " << range_val << " format error\n";
return false;
}
int64_t end;
std::string rstart;
std::string rend;
rstart = range_val.substr(pos1 + 1, pos2 - pos1 - 1);
rend = range_val.substr(pos2 + 1);
std::stringstream tmp;
tmp << rstart;
tmp >> start;
tmp.clear();
tmp << rend;
tmp >> end;
len = end - start + 1;
return true;
}
public:
P2PServer(){
if(!bf::exists(SHARD_PATH)){
bf::create_directory(SHARD_PATH);
}
}
bool Start(uint16_t port){
_server.Get("/hostpair",GetHostPair);
_server.Get("/list",GetFileList);
_server.Get("/list/(.*)",GetFileData);
_server.listen("0.0.0.0",port);
}
};
int main()
{
P2PServer srv;
srv.Start(9000);
return 0;
}