Files
LayaNative2.0/Conch/source/common/downloadCache/JCServerFileCache.h
T
2020-11-11 16:17:13 +08:00

334 lines
13 KiB
C++

/**
@file JCServerFileCache.h
@brief
@author guo
@version 1.0
@date 2016_5_11
*/
#ifndef __JCServerFileCache_H__
#define __JCServerFileCache_H__
#include <functional>
#include <thread>
#include <mutex>
#include "../buffer/JCBuffer.h"
#include <string>
#include <map>
#define CURCACHEFILEVER 2
namespace laya
{
class JCFileTable;
class JCFileSource;
class JCResStateDispatcher;
/**
* @brief 用特殊目录和格式管理的文件缓存。
* 设置一个目录path,然后会把所有的文件都保存在这个目录下。
* path随时可以换。
* 文件以id来查找。字符串也可以?
* 文件都带一个壳,保存了校验码。
* 壳可以与实际文件可以分离。
* 可以更新每个文件。
*/
class JCCachedFileSys {
public:
typedef unsigned int typeFile;
typedef unsigned int typeChkSum;
//每个文件的头
struct fileShell{
enum {
magic_filid = 0x7788eeff,
};
fileShell(){
magicNum=magic_filid;
version = CURCACHEFILEVER;
headSize = sizeof(fileShell);
hashtype = ready = link = linkPackID = padd1= chkSum =0;
linkSameFile = 1;
reserved[0]=reserved[1]=reserved[2]=reserved[3]=0;
linkFile=0;
extfile = 0;
}
int magicNum;
int version:8;
unsigned int headSize:8;
unsigned int hashtype:3; //0 simplecrc 1 crc 2:BKDR ; 3:MD5
unsigned int ready:1; //1表示已经完成了,内容也是正确的。0表示还没有内容
unsigned int link:1; //1表示是一个链接。
unsigned int linkPackID:3; //使用哪个外部包
unsigned int linkSameFile:1; //1表示链接的文件时同名的。否则,就要使用下面的linkFile;
unsigned int extfile : 1; //实际文件内容在一个外部文件中,即头和文件体是分开的。主要是为了满足有的库需要直接访问文件。
unsigned int extVersionMgr : 1; //使用外部版本管理,版本號只是一個int,佔用chkSum
unsigned int tmpFile : 1; //临时文件。为1的时候,expiredTime有效
unsigned int withprocess : 1; //临时文件,但是进程中不允许删除,一般是资源文件。
int padd1:3;
typeChkSum chkSum;
int reserved[4];
int linkFile;
int svETag; //ETag的hash
time_t expiredTime; //过期时间
};
JCCachedFileSys();
static typeChkSum hashRaw( const char* p_pszStr );
void setCachePath(const char* p_pszPath);
/** @brief 从缓存中加载一个文件。
* @param p_nFileID
* @param p_nChkSum 这个=0 表示不用进行校验
* @return
* 如果从cache或者包中都找不到文件,则返回false,否则返回true,并设置文件内容和校验码
* 可能会导致创建链接文件。对于不存在的不会创建壳。
*/
bool load(typeFile p_nFileID, typeChkSum& p_nChkSum, JCSharedBuffer& p_BufRet );
/** @brief 更新cache中的一个资源。不做校验码的检查。检查需要在外面做
* @param[in] p_nFileID
* @param[in] p_pBuff
* @param[in] p_nLen
* @param[in] p_nChkSum 这个值必须外部提供。此函数只是直接与头的记录进行比较。
* @param[in] p_bExtVersion 外部提供的版本号,如果为true,则 p_nChkSum就是版本号
* @param[in] p_tmExpiredTm 过期时间。只对临时文件有效
* @param[in] p_bWithProcess 进程内不允许删除。
* @return 如果保存成功。返回本地路径。否则返回"";
*/
std::string updateAFile(typeFile p_nFileID, char* p_pBuff, int p_nLen, typeChkSum p_nChkSum,
bool p_bExtVersion, time_t p_tmExpiredTm, bool p_bWithProcess);
/** @brief 删除cache中的文件资源
* @param p_nFileID
*/
void delFromCache( typeFile p_nFileID );
static typeChkSum getChkSum( char* p_pBuff, int p_nLen );
/** @brief 从缓存目录中读取资源。
* 基本上相当于简单包装了的 readFileSync
* @param p_pszFile
* @param p_BufRet[out] 是文件内容,不含壳信息。
* @return 如果缓存中没有,就返回false。
*/
bool load(const char* p_pszFile, JCSharedBuffer& p_BufRet, fileShell& p_nFs ,time_t& p_tmLastModify);
/*
加载缓存的文件的信息。不实际加载文件。通常用来判断是否需要更新。
*/
bool loadShell(const char* p_pszFile, fileShell& p_nFs, time_t& p_tmLastModify);
std::string fileToPath(typeFile p_nFile, std::string& p_strPath, bool p_bCreateDir);
bool createLink( const char* p_pszFile, typeChkSum p_nChkSum);
//转成字符串。
std::string fileToStr(typeFile, bool bHex );
//创建一个壳。还没有实际内容
bool createShell(typeFile p_nFileID, typeChkSum p_nChkSum);
//返回整个cache的大小。
long size();
//这个主要是为了效率,减少目录是否存在的判断。
bool hasDir(unsigned char dir) {
int pos = dir / 8;
int off = dir % 8;
return (m_HasDir[pos] >> off)&1;
}
void setHasDir(unsigned char dir) {
int pos = dir / 8;
int off = dir % 8;
m_HasDir[pos] |= (1 << off);
}
protected:
typedef std::recursive_mutex _mutex_t;
_mutex_t m_lockFileRW;
std::string m_strCacheFilesPath;
unsigned char m_HasDir[32]; //最多有256個目錄。每個bit表示一個。
};
class JCServerFileCache{
public:
typedef std::function<void(int,int)> funcOnUpdateProgress; //更新过程
typedef std::function<void(void)> funcOnUpdateOK; //所有资源更新完成后的回调
/*
绝对地址的URL转换函数,为了能多个url对应一个cache入口
返回0表示放弃转换。
不允许直接修改原始url内存。
*/
typedef char* (*FUN_TRANSLATEURL)(void* pUserData, const char*);
public:
JCServerFileCache();
~JCServerFileCache();
void saveFileTable(const char* p_pszFileContent);
/** @brief 设置所有app的缓存根目录
* @param p_pszCachePath [in] 文件缓存的目录。是绝对路径。
*/
void setCachePath(const char* p_pszCachePath );
/** @brief 得到当前应用的缓存目录。最后没有/
*/
std::string getAppPath();
std::string getDccFile() { return getAppPath() + "/" + "filetable.txt"; };
/** @brief 切换到某个url的缓存。
* 大约相当于把url映射到一个本地path上
* 每个process只允许调用一次。
* @param p_pszWebBase [in] 是index.html所在网络目录,例如 http://jx.laya8.com/game1/
*/
void switchToApp(const char* p_pszWebBase);
/** @brief 设置资源对象。提供访问文件的接口。
*/
void setAssets(JCFileSource* pAssets );
JCFileSource* getAssets(){ return m_pAssets;}
/** @brief 计算相对路径的hash
* 注意url必须是一个相对路径,前面可以有 / 或者没有
*/
JCCachedFileSys::typeChkSum hashURLR(const char* p_pszURL );
/** @brief 从cache中加载一个文件。
* 如果cache中没有则尝试从资源包中加载。
* 如果在资源包中存在,会创建一个链接文件。
* 如果是需要管理的文件,并且需要下载,则先创建壳,然后再下载。
* @param p_nFileID [in]
* @param p_nChkSum [in] 为0表示不用进行校验。
* @param p_BufRet [out] 返回的内容
* @param p_bUseVersion [in] 检查版本号
* @return true则存在,并且p_BufRet会有文件内容。否则返回 false
*/
bool load(JCCachedFileSys::typeFile p_nFileID, JCCachedFileSys::typeChkSum& p_nChkSum, JCSharedBuffer& p_BufRet ,bool p_bUseVersion, bool doCheckSum);
/** @brief load一个文件。如果有dcc,就会把加载的内容进行dcc校验,否则就直接从缓存中加载。如果缓存中没有,就返回false。
* 这个函数实际上最终会调用上面的load函数
* @param[in] nFileID 文件的本地id。
* @param[out] buff 返回的buffer
* @param[in] doCheckSum 是否进行版本号或者校验码的验证
* @return 加载成功就返回true,否则返回false
*/
bool load(unsigned int nFileID, JCBuffer& buff, bool doCheckSum=true);
/*
加载缓存的文件的信息。不实际加载文件。通常用来判断是否需要更新。
*/
bool loadShell(const char* p_pszFile, JCCachedFileSys::fileShell& p_nFs, time_t& p_tmLastModify);
/**
* @brief 从缓存中加载指定版本号的某个文件。
* @param[in] p_nFileID 文件id
* @param[in] p_nVersion 版本号
* @param[out] p_BufRet 返回的文件内容
* @return 如果文件存在,并且版本符合,就返回true,并且p_BufRet有返回内容
*/
//bool loadByVersion(unsigned int p_nFileID, int p_nVersion, JCSharedBuffer& p_BufRet);
//删除cache中的文件资源
void delFromCache( JCCachedFileSys::typeFile p_nFileID ){ m_FileSys.delFromCache(p_nFileID);}
/** @brief 根据p_pTable来更新所有的内容。这样以后就不用再需要fileTable了
* 如果用索引表的方法(不用分散文件),必须用这种方式
* 系统资源也用这种方法更新。
* @param p_pTable 如果为空,则直接使用自己的 fileTable 来更新
*/
void updateAll( JCFileTable* p_pTable, funcOnUpdateOK p_OnUpdateOK);
/** @brief 获得某个文件的校验码。
* @return 如果没有管理这个文件,返回false
*/
bool getFileInfo(unsigned int p_nFileID, unsigned int& p_nChkSum );
void setResourceID(const char* p_pszResource, const char* p_pszVal);
std::string getResourceID(const char* p_pszResource );
/** @brief
* 删除本url的所有的缓存文件。包括session文件。
* 这个函数可能很危险,不要暴露出去。
* @return
*/
void clearAllCachedFile();
/** @brief 文件下载完成。 更新文件的缓存。
* @param[in] p_nFileID 文件ID。
* @param[in] p_pBuff
* @param[in] p_nLen
* @param[in] p_nChkSum 校验值。外部设置的,只是要求这个函数保存,并不要求检验。
* @return 如果成功的话,返回本地目录。否则返回"";
*/
std::string updateAFile(JCCachedFileSys::typeFile p_nFileID, char* p_pBuff, int p_nLen,
JCCachedFileSys::typeChkSum p_nChkSum, bool p_bExtVersion, time_t p_tmExpiredTm,
bool p_bWithProcess) {
return m_FileSys.updateAFile(p_nFileID, p_pBuff, p_nLen, p_nChkSum, p_bExtVersion,
p_tmExpiredTm, p_bWithProcess);
}
/**
* @brief 重新加载app目录下的dcc文件。一般是在更新dcc之后调用。
* @return 创建的dcc中的文件的个数。
*/
int reloadDccFile();
/**
获得一个url的fileid。
如果有转换表需要先转换一下
*/
unsigned int getFileID(const char* Url);
//protected:
//这个函数要小心。要避免线程问题。本来是私有的。为了方便改成public了
/** @brief 根据字符串设置dcc信息。
注意只有开始的时候才能调用这个,当正常使用的时候,不允许设置,否则应该加锁
外部不允许调用这个函数。否则不知道怎么处理。
* @param[in] p_pszFiles
* @return 返回文件的个数。
*/
int setFileTables( const char* p_pszFiles );
/**
设置url转换表。必须是相对路径。必须以/开头
*/
void setUrlTransTable(const char* p_pszTable, char split);
protected:
//从资源包中读取。返回内容和chksum,如果false则表示没有这个文件
bool _loadFromAssets(JCCachedFileSys::typeFile p_nFileID, JCSharedBuffer& p_BufRet, JCCachedFileSys::typeChkSum& p_nChkSum, bool p_bGetChkSum=true );
//为了统一的解密加的,上面的那个只是统一入口
bool __load(JCCachedFileSys::typeFile p_nFileID, JCCachedFileSys::typeChkSum& p_nChkSum, JCSharedBuffer& p_BufRet, bool p_bUseVersion, bool doCheckSum);
protected:
time_t m_tmCacheMgrCreateTime;
JCFileTable* m_pFileTable;
std::string m_strCachePath;
std::string m_strWebBase;
std::string m_strCacheFilesPath;//在m_strCachePath下面的files中
std::string m_strAppPath; //这是一个相对路径
JCFileSource* m_pAssets;
std::map<unsigned int, std::string> m_UrlTrans;
public://config
JCCachedFileSys m_FileSys;
enum SessionFileCacheType {
CT_UseHeaderInfo=0,
CT_ValidInCurProcess,
CT_AllwaysReload
};
/*
* 是否根据header中的参数来决定是否缓存。
* 如果是false,则临时文件都是
*/
static SessionFileCacheType s_bSessionCacheType ;
FUN_TRANSLATEURL m_pFuncTransUrl = nullptr;
void* m_pFuncTransUrlData = nullptr;
};
}
#endif //__JCServerFileCache_H__