【lesson8】云备份服务端完整版代码

作者 : admin 本文共16785个字,预计阅读时间需要42分钟 发布时间: 2024-06-17 共1人阅读

文章目录

  • util.hpp
  • config.hpp
  • hot.hpp
  • data.hpp
  • server.hpp
  • server.cc
  • Makefile
  • cloud.conf

util.hpp

#pragma once
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "bundle.h"
namespace cloud
{
namespace fs = std::experimental::filesystem;
class fileUtil
{
public:
fileUtil(std::string filename)
:_filename(filename)
{}
bool Remove()
{
if(exists() == false)
{
return true;
}
remove(_filename.c_str());
return true;
}
size_t fileSize()
{
struct stat st;
int ret = stat(_filename.c_str(), &st);
if(ret == -1)
{
std::cout << strerror(errno) << std::endl;
return 0;
}
return st.st_size;
}
time_t lastModifyTime()
{
struct stat st;
int ret = stat(_filename.c_str(), &st);
if(ret == -1)
{
std::cout << strerror(errno) << std::endl;
return -1;
}
return st.st_mtime;
}
time_t lastAccessTime()
{
struct stat st;
int ret = stat(_filename.c_str(), &st);
if(ret == -1)
{
std::cout << strerror(errno) << std::endl;
return -1;
}
return st.st_atime;
}
std::string fileName()
{
size_t pos = _filename.find_last_of("/");
if(pos == std::string::npos)
{
return _filename;
}
return _filename.substr(pos + 1);
}
bool setContent(const std::string &body)
{
std::ofstream ofs;
ofs.open(_filename, std::ios::binary);
if(ofs.is_open() == false)
{
std::cout << "setContent open failed
";
return false;
}
ofs.write(&body[0], body.size());
if(ofs.good() == false)
{
std::cout << "setContent write failed
";
ofs.close();
return false;
}
ofs.close();
return true;
}
bool getPosLen(std::string *body, size_t pos, size_t len)
{
std::ifstream ifs;
if(pos + len > fileSize())
{
std::cout << "getPosLen failed
";
return false;
}
ifs.open(_filename, std::ios::binary);
if(ifs.is_open() == false)
{
std::cout << "getPosLen open failed
";
return false;
}
body->resize(len - pos);
ifs.read(&(*body)[0], len);
if(ifs.good() == false)
{
std::cout << "getPosLen read failed
";
ifs.close();
return false;
}
ifs.close();
return true;
}
bool getContent(std::string *body)
{
size_t n = fileSize();
return getPosLen(body, 0, n);
}
bool exists()
{
return fs::exists(_filename);
}
bool createDirectory()
{
if(exists())
return true;
return fs::create_directories(_filename);
}
bool getDirectory(std::vector<std::string> *arry)
{
for(const fs::directory_entry& entry : fs::directory_iterator{_filename})
{
if(fs::is_directory(entry))
continue;
arry->push_back(fs::path(entry).relative_path().string());
}
return true;
}
bool compress(const std::string &packname)
{
std::string body;
getContent(&body);
std::string buffer = bundle::pack(bundle::LZIP, body);
std::ofstream ofs;
ofs.open(packname, std::ios::binary);
if(ofs.is_open() == false)
{
std::cout << "compress open failed
";
return false;
}
ofs.write(&buffer[0], buffer.size());
if(ofs.good() == false)
{
std::cout << "compress write failed
";
ofs.close();
return false;
}
ofs.close();
return true;
}
bool uncompress(const std::string &filename)
{
std::string body;
getContent(&body);
std::string buffer = bundle::unpack(body);
std::ofstream ofs;
ofs.open(filename, std::ios::binary);
if(ofs.is_open() == false)
{
std::cout << "uncompress open failed
";
return false;
}
ofs.write(&buffer[0], buffer.size());
if(ofs.good() == false)
{
std::cout << "uncompress write failed
";
ofs.close();
return false;
}
ofs.close();
return true;
}
private:
std::string _filename;
};
class JsonUtil
{
public:
static bool Serialize(const Json::Value &root, std::string *str)
{
Json::StreamWriterBuilder swb;
std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());
std::stringstream ss;
int ret = sw->write(root, &ss);
if(ret != 0)
{
std::cout << "Serialize failed" << std::endl;
return false;
}
*str = ss.str();
return true;
}
static bool UnSerialize(const std::string &str, Json::Value *root)
{
Json::CharReaderBuilder crb;
std::unique_ptr<Json::CharReader> cr(crb.newCharReader());
std::string errs;
bool ret = cr->parse(str.c_str(), str.c_str() + str.size(), root, &errs);
if(ret == false)
{
std::cout << "UnSerialize failed " << errs << std::endl;
return false;
}
return true;
}
};
}

config.hpp

#pragma once
#include 
#include "util.hpp"
namespace cloud
{
#define CONFIG_FILE "./cloud.conf"
class Config
{
private:
Config()
{
ReadConfigFile();
}
bool ReadConfigFile()
{
fileUtil fu(CONFIG_FILE);
std::string body; 
bool ret = fu.getContent(&body);
if(ret == false)
{
std::cout << "ReadConfigFile getContent faile" << std::endl;
}
Json::Value root;
ret = cloud::JsonUtil::UnSerialize(body, &root);
if(ret == false)
{
std::cout << "ReadConfigFile UnSerialize faile" << std::endl;
}
_hot_time = root["hot_time"].asInt();
_server_port = root["server_port"].asInt();
_server_ip = root["server_ip"].asString();
_download_prefix = root["download_prefix"].asString();
_packfile_suffix = root["packfile_suffix"].asString();
_pack_dir = root["pack_dir"].asString();
_back_dir = root["back_dir"].asString();
_backup_file = root["backup_file"].asString();
}
public:
static Config* getIstance()
{
if(_instance == nullptr)
{
_mtx.lock();
if(_instance == nullptr)
{
_instance = new Config();
}
_mtx.unlock();
}
return _instance;
}
int getHotTime()
{
return _hot_time;
}
int getServerPort()
{
return _server_port;
}
std::string getServerIp()
{
return _server_ip;
}
std::string getDownloadPrefix()
{
return _download_prefix;
}
std::string getPackfileSuffix()
{
return _packfile_suffix;
}
std::string getPackDir()
{
return _pack_dir;
}
std::string getBackDir()
{
return _back_dir;
}
std::string getBackupFile()
{
return _backup_file;
}
private:
static Config* _instance;
static std::mutex _mtx;
private:
int _hot_time;
int _server_port;
std::string _server_ip;
std::string _download_prefix;
std::string _packfile_suffix;
std::string _pack_dir;
std::string _back_dir;
std::string _backup_file;
};
Config* Config::_instance = nullptr;
std::mutex Config::_mtx;
} // namespace cloud

hot.hpp

#pragma once
#include 
#include 
#include "data.hpp"
extern cloud::dataManager *_data;
namespace cloud
{
class HotManager
{
private:
//非热点文件返回否, 热点文件返回真
bool hotJuge(const std::string& filename)
{
fileUtil fu(filename);
time_t last_atime = fu.lastAccessTime();
time_t cur_time = time(nullptr);
if(cur_time - last_atime > _hot_time)
{
return false;
}
return true;
}
public:
HotManager()
{
Config* f = Config::getIstance();
_back_dir = f->getBackDir();
_pack_dir = f->getPackDir();
_packfile_suffix = f->getPackfileSuffix();
_hot_time = f->getHotTime();
fileUtil fu1(_back_dir);
fileUtil fu2(_pack_dir);
fu1.createDirectory();
fu2.createDirectory();
}
bool runMoudle()
{
while(true)
{
//std::cout << -1 << std::endl;
fileUtil fu(_back_dir);
std::vector<std::string> arry;
fu.getDirectory(&arry);
for(auto& e : arry)
{
if(hotJuge(e))
{
continue;
}
BackupInfo info;
bool ret = _data->getBifoByRealPath(e, &info);
if(ret == false)
{
std::cout << "runMoudle faile" << std::endl;
info.NewBackupInfo(e);
}
fileUtil fu(e);
fu.compress(info.pack_path);
fu.Remove();
info.pack_flag = true;
_data->update(info);
}
usleep(1000);
}
return true;
}
private:
std::string _back_dir;
std::string _pack_dir;
std::string _packfile_suffix;
int _hot_time;
};
}

data.hpp

#pragma once
#include 
#include 
#include "util.hpp"
#include "config.hpp"
namespace cloud
{
struct BackupInfo
{
bool pack_flag;
size_t file_size;
time_t modify_time;
time_t access_time;
std::string real_path;
std::string pack_path;
std::string url;
bool NewBackupInfo(const std::string& filepath)
{
//std::cout << filepath << std::endl;
fileUtil fu(filepath);
if(fu.exists() == false)
{
std::cout << "NewBackupInfo fail" << std::endl;
return false;
}
pack_flag = false;
//std::cout << fu.fileSize() << std::endl;
file_size = fu.fileSize();
modify_time = fu.lastModifyTime();
access_time = fu.lastAccessTime();
real_path = filepath;
Config* f = Config::getIstance();
std::string packdir = f->getPackDir();
std::string packfile_suffix = f->getPackfileSuffix();
pack_path = packdir + fu.fileName() + packfile_suffix;
std::string download_prefix = f->getDownloadPrefix();
url = download_prefix + fu.fileName();
return true;
}
};
class dataManager
{
public:
dataManager()
{
_backup_file = Config::getIstance()->getBackupFile();
pthread_rwlock_init(&_rwlock, nullptr);
initLoad();
}
bool initLoad()//初始化程序运行时从文件读取数据
{
fileUtil fu(_backup_file);
if(fu.exists() == false)
{
return true;
}
std::string body;
bool ret = fu.getContent(&body);
if(ret == false)
{
std::cout << "InitLoad getContent failed" << std::endl;
return false;
}
Json::Value root;
ret = JsonUtil::UnSerialize(body, &root);
if(ret == false)
{
std::cout << "InitLoad getContent failed" << std::endl;
return false;
}
for(int i = 0; i < root.size(); i++)
{
BackupInfo info;
info.pack_flag = root[i]["pack_flag"].asBool();
info.file_size = root[i]["file_size"].asInt64();
info.modify_time = root[i]["modify_time"].asInt64();
info.access_time = root[i]["access_time"].asInt64();
info.real_path = root[i]["real_path"].asString();
info.pack_path = root[i]["pack_path"].asString();
info.url = root[i]["url"].asString();
//_table[info.url] = info;
insert(info);
} 
return true;
}
bool storage() //每次有信息改变则需要持久化存储一次
{
Json::Value root;
for(auto& e : _table)
{
Json::Value tmp;
tmp["pack_flag"] = e.second.pack_flag;
tmp["file_size"] = (Json::Int64)e.second.file_size;
tmp["modify_time"] = (Json::Int64)e.second.modify_time;
tmp["access_time"] = (Json::Int64)e.second.access_time;
tmp["real_path"] = e.second.real_path;
tmp["pack_path"] = e.second.pack_path;
tmp["url"] = e.second.url;
root.append(tmp);
}
std::string body;
bool ret = JsonUtil::Serialize(root, &body);
if(ret == false)
{
std::cout << "Storage Serialize faile" << std::endl;
return false;
}
fileUtil fu(_backup_file);
ret = fu.setContent(body);
if(ret == false)
{
std::cout << "Storage setContent faile" << std::endl;
return false;
}
return true;
}
bool insert(const BackupInfo& Info)
{
pthread_rwlock_wrlock(&_rwlock);
_table[Info.url] = Info;
pthread_rwlock_unlock(&_rwlock);
storage();
return true;
}
bool update(const BackupInfo& Info)
{
pthread_rwlock_wrlock(&_rwlock);
_table[Info.url] = Info;
pthread_rwlock_unlock(&_rwlock);
storage();
return true;
}
bool getBifoByUrl(const std::string& url, BackupInfo* Info)
{
//问题这个应该是读者模式锁还是写者模式锁呢?
pthread_rwlock_wrlock(&_rwlock);
auto ret = _table.find(url);
if(ret == _table.end())
{
pthread_rwlock_unlock(&_rwlock);
return false;
}
*Info = ret->second;
pthread_rwlock_unlock(&_rwlock);
return true;
}
bool getBifoByRealPath(const std::string& realPath, BackupInfo* Info)
{
pthread_rwlock_wrlock(&_rwlock);
for(auto& e : _table)
{
if(e.second.real_path == realPath)
{
*Info = e.second;
pthread_rwlock_unlock(&_rwlock);
return true;
}
}
pthread_rwlock_unlock(&_rwlock);
return false;
}
bool getAll(std::vector<BackupInfo> *arry)
{
pthread_rwlock_wrlock(&_rwlock);
for(auto& e : _table)
{
arry->push_back(e.second);
}
pthread_rwlock_unlock(&_rwlock);
return true;
}
~dataManager()
{
pthread_rwlock_destroy(&_rwlock);
}
private:
std::string _backup_file;
pthread_rwlock_t _rwlock;
std::unordered_map<std::string, BackupInfo> _table;
};
}

server.hpp

#pragma once
#include "data.hpp"
#include "httplib.h"
extern cloud::dataManager *_data;
namespace cloud
{
class serevr
{
private:
static void upLoad(const httplib::Request& rq, const httplib::Response& rp)
{
bool ret = rq.has_file("file");
if(ret == false)
{
return ;
}
const auto& file = rq.get_file_value("file");
std::string real_path = _back_dir + fileUtil(file.filename).fileName();
fileUtil fu(real_path);
fu.setContent(file.content);
BackupInfo info;
info.NewBackupInfo(real_path);
_data->insert(info);
return;
}
static std::string timeToString(time_t t)
{
return std::ctime(&t);
}
static void listShow(const httplib::Request& rq, httplib::Response& rp)
{
std::vector<BackupInfo> arry;
_data->getAll(&arry);
std::stringstream ss;
ss << "Download";
ss << " 

Download

";for(auto& e : arry){ ss <<""; std::string filename =fileUtil(e.real_path).fileName(); ss <<""; ss <<""; ss <<""; ss <<"";} ss <<"
<< e.url << "'>" << filename << " "; ss << timeToString(e.modify_time); ss << " "; ss << e.file_size / 1024 << "K"; ss << "
"
; rp.body = ss.str(); rp.set_header("Content-Type", "text/html"); rp.status = 200; } static std::string getETagInfo(const BackupInfo& info) { std::string etag; etag += fileUtil(info.real_path).fileName(); etag += "-"; etag += std::to_string(info.file_size); etag += "-"; etag += std::to_string(info.modify_time); return etag; } static void downLoad(const httplib::Request& rq, httplib::Response& rp) { std::string url = rq.path; //std::cout << url << std::endl; BackupInfo info; _data->getBifoByUrl(url, &info); //std::cout << info.real_path << std::endl; if(info.pack_flag == true) { //解压文件 fileUtil fu(info.pack_path); fu.uncompress(info.real_path); //删除压缩文件, 并修改BackupInfo信息 fu.Remove(); info.pack_flag = false; _data->insert(info); } // if(rq.has_header("If-Range")) // std::cout << "hello" << std::endl; // else // std::cout << "no" << std::endl; // for(auto& e : rp.headers) // { // std::cout << e.second << std::endl; // } fileUtil fu(info.real_path); fu.getContent(&rp.body); rp.set_header("Accept-Ranges", "bytes"); rp.set_header("ETag", getETagInfo(info)); rp.set_header("Content-Type", "application/octet-stream"); //rp.status = 200; if(rq.has_header("If-Range") && rq.get_header_value("If-Range") == getETagInfo(info)) { rp.status = 206; //std::cout << rp.status << std::endl; } else { rp.status = 200; } } public: serevr() { Config* cnf = Config::getIstance(); _server_port = cnf->getServerPort(); _server_ip = cnf->getServerIp(); _download_prefix = cnf->getDownloadPrefix(); _back_dir = cnf->getBackDir(); } bool RunModule() { _server.Post("/upload",upLoad); _server.Get("/listshow", listShow); _server.Get("/", listShow); std::string url = _download_prefix + "(.*)"; _server.Get(url,downLoad); _server.listen("0.0.0.0", _server_port); return true; } private: int _server_port; std::string _server_ip; std::string _download_prefix; static std::string _back_dir; httplib::Server _server; }; std::string serevr::_back_dir; }

server.cc

#include "util.hpp"
#include "config.hpp"
#include "data.hpp"
#include "hot.hpp"
#include "server.hpp"
#include 
cloud::dataManager *_data;
void server()
{
cloud::serevr s;
s.RunModule();
}
void hot()
{
cloud::HotManager h;
h.runMoudle();
}
int main(int argc, char *argv[])
{
// if(argc != 2)
// {
//     std::cout << argv[0] << " filepath newfilename" << std::endl;
//     exit(1);
// }
// std::string name = argv[1];
// cloud::fileUtil f(name);
// std::cout << f.fileSize() << std::endl;
// std::cout << f.lastModifyTime() << std::endl;
// std::cout << f.lastAccessTime() << std::endl;
// std::cout << f.fileName() << std::endl;
// std::string buffer;
// f.getContent(&buffer);
// name = argv[2];
// cloud::fileUtil f2(name);
// f2.setContent(buffer);
// std::string name = argv[1];
// cloud::fileUtil f(name);
// f.compress(name += ".lz");
// f.uncompress(name += ".backup");
// cloud::fileUtil f(name);
// f.createDirectory();
// std::vector arry;
// f.getDirectory(&arry);
// for(auto& e : arry)
// {
//     std::cout << e << std::endl;
// }
// const char* name = "xiaolion";
// int age = 18;
// int score[] = {100, 98, 89};
// Json::Value root;
// root["name"] = name;
// root["age"] = age;
// root["socre"].append(score[0]);
// root["socre"].append(score[1]);
// root["socre"].append(score[2]);
// std::string str;
// cloud::JsonUtil::Serialize(root, &str);
// std::cout << str << std::endl;
// Json::Value val;
// cloud::JsonUtil::UnSerialize(str, &val);
// std::cout << val["name"].asString() << std::endl;
// std::cout << val["age"].asInt() << std::endl;
// std::cout << val["socre"][0].asInt() << std::endl;
// std::cout << val["socre"][1].asInt() << std::endl;
// std::cout << val["socre"][2].asInt() << std::endl;
// cloud::Config* f = cloud::Config::getIstance();
// std::cout <getHotTime() << std::endl;
// std::cout <getServerPort() << std::endl;
// std::cout <getServerIp() << std::endl;
// std::cout <getDownloadPrefix() << std::endl;
// std::cout <getPackfileSuffix() << std::endl;
// std::cout <getPackDir() << std::endl;
// std::cout <getBackDir() << std::endl;
// std::cout <getBackupFile() << std::endl;
// cloud::BackupInfo f;
// f.NewBackupInfo(argv[1]);
// cloud::fileUtil f1(argv[1]);
// std::cout << f1.fileSize() << std::endl;
// std::cout << argv[1] << std::endl;
// std::cout << f.pack_flag << std::endl;
// std::cout << f.file_size << std::endl;
// std::cout << f.modify_time << std::endl;
// std::cout << f.access_time << std::endl;
// std::cout << f.real_path << std::endl;
// std::cout << f.pack_path << std::endl;
// std::cout << f.url << std::endl;
// cloud::dataManager d;
// d.insert(f);
// f.pack_flag = true;
// d.update(f);
// cloud::BackupInfo tmp;
// d.getBifoByRealPath(argv[1], &tmp);
// std::cout << tmp.pack_flag << std::endl;
// std::cout << tmp.file_size << std::endl;
// std::cout << tmp.modify_time << std::endl;
// std::cout << tmp.access_time << std::endl;
// std::cout << tmp.real_path << std::endl;
// std::cout << tmp.pack_path << std::endl;
// std::cout << tmp.url << std::endl;
// cloud::BackupInfo tmp2;
// d.getBifoByUrl(f.url, &tmp2);
// std::cout << tmp2.pack_flag << std::endl;
// std::cout << tmp2.file_size << std::endl;
// std::cout << tmp2.modify_time << std::endl;
// std::cout << tmp2.access_time << std::endl;
// std::cout << tmp2.real_path << std::endl;
// std::cout << tmp2.pack_path << std::endl;
// std::cout << tmp2.url << std::endl;
// std::vector arry;
// d.getAll(&arry);
// for(auto& e : arry)
// {
//     std::cout << e.pack_flag << std::endl;
//     std::cout << e.file_size << std::endl;
//     std::cout << e.modify_time << std::endl;
//     std::cout << e.access_time << std::endl;
//     std::cout << e.real_path << std::endl;
//     std::cout << e.pack_path << std::endl;
//     std::cout << e.url << std::endl;
// }
// cloud::BackupInfo f;
// f.NewBackupInfo(argv[1]);
// cloud::dataManager d;
// d.insert(f);
// cloud::dataManager d;
// std::vector arry;
// d.getAll(&arry);
// for(auto& e : arry)
// {
//     std::cout << e.pack_flag << std::endl;
//     std::cout << e.file_size << std::endl;
//     std::cout << e.modify_time << std::endl;
//     std::cout << e.access_time << std::endl;
//     std::cout << e.real_path << std::endl;
//     std::cout << e.pack_path << std::endl;
//     std::cout << e.url << std::endl;
// }
//_data = new cloud::dataManager();
// cloud::HotManager ht;
// ht.runMoudle();
// cloud::serevr srv;
// srv.RunModule();
// httplib::Server _server;
// _server.Post("/upload", upLoad);
// _server.Get("/listshow", listShow);
// _server.Get("/", listShow);
// _server.Get("/", downLoad);
// _server.listen("", 8080);
_data = new cloud::dataManager();
std::thread thread_hot(hot);
std::thread thread_server(server);
thread_hot.join();
thread_server.join();
return 0;
}

Makefile

.PHONY:util
cloudServer:cloudServer.cc
g++ -o $@ $^ -L./lib -lpthread -lstdc++fs -ljsoncpp -lbundle

cloud.conf

{
"hot_time" : 30,
"server_port" : 8080,
"server_ip" : "-.-.-.-",
"download_prefix" : "/download/",
"packfile_suffix" : ".lz",
"pack_dir" : "./packdir/",
"back_dir" : "./backdir/",
"backup_file" : "./cloud.dat"
}
本站无任何商业行为
个人在线分享 » 【lesson8】云备份服务端完整版代码
E-->