SIGN IN SIGN UP
TarsCloud / Tars UNCLAIMED

Tars is a high-performance RPC framework based on name service and Tars protocol, also integrated administration platform, and implemented hosting-service via flexible schedule.

0 0 21 C++
2017-01-18 16:19:06 +08:00
/**
* Tencent is pleased to support the open source community by making Tars available.
*
* Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
#include "util/tc_file.h"
#include "util/tc_config.h"
#include "util/tc_md5.h"
#include "servant/TarsLogger.h"
#include "PatchImp.h"
#include "PatchCache.h"
#include "PatchServer.h"
extern PatchCache g_PatchCache;
struct LIST
{
LIST(const string& dir, vector<FileInfo> &vf) : _dir(dir), _vf(vf)
{
}
void operator()(const string &file)
{
//普通文件才同步, 连接文件有效
if(tars::TC_File::isFileExistEx(file, S_IFREG))
{
FileInfo fi;
fi.path = file.substr(_dir.length());
fi.size = tars::TC_File::getFileSize(file);
fi.canExec = tars::TC_File::canExecutable(file);
fi.md5 = tars::TC_MD5::md5file(file);
_vf.push_back(fi);
TLOGDEBUG("LIST path:" << fi.path << "|file:" << file << "|size:" << fi.size << "|exec:" << (fi.canExec?"true":"false") << endl);
}
}
string _dir;
vector<FileInfo> &_vf;
};
PatchImp::PatchImp()
: _size(1024*1024)
{
}
void PatchImp::initialize()
{
try
{
_directory = (*g_conf)["/tars<directory>"];
_uploadDirectory = (*g_conf)["/tars<uploadDirectory>"];
_size = TC_Common::toSize(g_conf->get("/tars<size>", "1M"), 1024*1024);
}
catch(exception &ex)
{
TLOGDEBUG("PatchImp::initialize directory must not be empty." << endl);
exit(0);
}
if(!tars::TC_File::isAbsolute(_directory))
{
TLOGDEBUG("PatchImp::initialize directory must be absolute directory path." << endl);
exit(0);
}
TLOGDEBUG("PatchImp::initialize patch dirtectory:" << _directory << "|uploadDirectory:" << _uploadDirectory << "|size:" << _size << endl);
}
/**************************************************************************************************
** 对外接口,普通下载接口
**
**/
int PatchImp::listFileInfo(const string &path, vector<FileInfo> & vf, TarsCurrentPtr current)
{
TLOGDEBUG("PatchImp::listFileInfo ip:" << current->getIp() << "|path:" << path << endl);
string dir = tars::TC_File::simplifyDirectory(_directory + "/" + path);
int ret = __listFileInfo(dir, vf);
stringstream ss;
tars::TarsDisplayer ds(ss);
ds.displaySimple(vf, false);
TLOGDEBUG("PatchImp::listFileInfo ip:" << current->getIp() << "|path:" << path << "|dir:" << dir << "|str:" << ss.str() << endl);
return ret;
}
int PatchImp::download(const string & file, int pos, vector<char> & vb, TarsCurrentPtr current)
{
TLOGDEBUG("PatchImp::download ip:" << current->getIp() << "|file:" << file << "|pos:" << pos << endl);
string path = tars::TC_File::simplifyDirectory(_directory + "/" + file);
int iRet = -1;
if (iRet < 0)
{
iRet = __downloadFromMem (path, pos, vb);
}
if (iRet < 0)
{
iRet = __downloadFromFile(path, pos, vb);
}
return iRet;
}
int PatchImp::preparePatchFile(const string &app, const string &serverName, const string &patchFile, TarsCurrentPtr current)
{
string upfile = _uploadDirectory + "/" + app + "/" + serverName + "/" + patchFile;
string dstDirectory = _directory + "/TARSBatchPatching/" + app + "/" + serverName;
string dstfile = dstDirectory + "/" + app +"." + serverName + ".tgz";
TLOGDEBUG("PatchImp::preparePatchFile upfile:" << upfile << "|dstfile:" << dstfile << endl);
bool succ = TC_File::makeDirRecursive(dstDirectory);
if (!succ)
{
TLOGERROR("PatchImp::preparePatchFile makeDirRecursive path:" << dstDirectory << "|error!" << endl);
return -2;
}
if (!TC_File::isFileExist(upfile))
{
TLOGERROR("PatchImp::preparePatchFile isFileExist file:" << upfile << "|not exist!" << endl);
return -1;
}
TC_File::copyFile(upfile, dstfile, true);
return 0;
}
/**************************************************************************************************
* 发布服务内部使用函数
*/
int PatchImp::__listFileInfo(const string &path, vector<FileInfo> &vf)
{
TLOGDEBUG("PatchImp::__listFileInfo patch:" << path << endl);
if (path.find("..") != string::npos)
{
return -1;
}
if(!tars::TC_File::isFileExistEx(path, S_IFDIR))
{
//是文件
FileInfo fi;
fi.path = tars::TC_File::extractFileName(path);
fi.size = tars::TC_File::getFileSize(path);
fi.canExec = tars::TC_File::canExecutable(path);
fi.md5 = tars::TC_MD5::md5file(path);
vf.push_back(fi);
return 1;
}
else
{
//目录
vector<string> files;
tars::TC_File::listDirectory(path, files, true);
for_each(files.begin(), files.end(), LIST(path, vf));
return 0;
}
return 0;
}
int PatchImp::__downloadFromMem (const string & file, size_t pos, vector<char> & vb)
{
TLOGDEBUG("PatchImp::__downloadFromMem file:" << file << "|pos:" << pos << "|size:" << _size << endl);
pair<char *, size_t> mem;
if (g_PatchCache.load(file, mem) != 0)
{
TLOGERROR("PatchImp::__downloadFromMem file:" << file << "|pos:" << pos << "|LoadFile error" << endl);
return -1;
}
if (pos >= mem.second)
{
TLOGDEBUG("PatchImp::__downloadFromMem file:" << file << "|pos:" << pos << "|to tail ok" << endl);
g_PatchCache.release(file);
return 1;
}
const size_t sizeBuf = mem.second - pos >= _size ? _size : mem.second - pos;
TLOGDEBUG("PatchImp::__downloadFromMem file:" << file << "|pos:" << pos << "|sizeBuf:" << sizeBuf << endl);
vb.resize(sizeBuf);
memcpy((char *)&vb[0], mem.first + pos, sizeBuf);
g_PatchCache.release(file);
return 0;
}
int PatchImp::__downloadFromFile(const string & file, size_t pos, vector<char> & vb)
{
TLOGDEBUG("PatchImp::__downloadFromFile file:" << file << "|pos:" << pos << "|size:" << _size << endl);
FILE * fp = fopen(file.c_str(), "rb");
if (fp == NULL)
{
TLOGERROR("PatchImp::__downloadFromFile file:" << file << "|pos:" << pos << "|open file error:" << strerror(errno) << endl);
return -1;
}
//从指定位置开始读数据
if (fseek(fp, pos, SEEK_SET) == -1)
{
fclose(fp);
TLOGERROR("PatchImp::__downloadFromFile file:" << file << "|pos:" << pos << "|fseek error:" << strerror(errno) << endl);
return -2;
}
//开始读取文件
vb.resize(_size);
size_t r = fread((void*)(&vb[0]), 1, _size, fp);
if (r > 0)
{
//成功读取r字节数据
vb.resize(r);
fclose(fp);
TLOGDEBUG("PatchImp::__downloadFromFile file:" << file << "|pos:" << pos << "|r:" << r << endl);
return 0;
}
else
{
//到文件末尾了
if (feof(fp))
{
fclose(fp);
TLOGDEBUG("PatchImp::__downloadFromFile file:" << file << "|pos:" << pos << "|to tail ok" << endl);
return 1;
}
//读取文件出错了
TLOGERROR("PatchImp::__downloadFromFile file:" << file << "|pos:" << pos << "|r:" << r << "|error:" << strerror(errno) << endl);
fclose(fp);
return -3;
}
}