Files
LayaNative2.0/Conch/source/conch/JSWrapper/LayaWrap/JSAppCache.cpp
T
helloworldlv 8c228b44cc 同步
2025-06-16 15:53:37 +08:00

510 lines
17 KiB
C++

/**
@file JSAppCache.cpp
@brief
@author James
@version 1.0
@date 2017_11_28
*/
#include "JSAppCache.h"
#include "downloadCache/JCServerFileCache.h"
#include "fileSystem/JCFileSystem.h"
#include "resource/JCFileResManager.h"
#include "util/Log.h"
#include "JSFile.h"
#include "../../JCScriptRuntime.h"
#include "util/JCSimpleCRC.h"
#include "downloadCache/JCFileSource.h"
extern std::string gRedistPath;
#ifdef _DEBUG
#define VERIFY(a,msg) {if(!(a)){LOGE(msg); throw -1;};}
#else
#define VERIFY(a,msg)
#endif
namespace laya
{
char* GlobalTransUrl(void* pData, const char* pUrl)
{
JsAppCache* pCache = (JsAppCache*)pData;
if (pCache)
{
return pCache->getTransedUrl(pUrl);
}
return nullptr;
}
ADDJSCLSINFO(JsAppCache, JSObjNode);
JsAppCache::JsAppCache()
{
//大概估算内部变量
AdjustAmountOfExternalAllocatedMemory( 1024 );
m_bEnableCache=true;
m_pSvFileCache = new JCServerFileCache();
m_pSvFileCache->m_pFuncTransUrl = GlobalTransUrl;
m_pSvFileCache->m_pFuncTransUrlData = this;
m_pSvFileCache->setCachePath((gRedistPath + "appCache").c_str());
if (JCScriptRuntime::s_JSRT->m_pFileResMgr)
{
JCFileResManager* pFileResManager = JCScriptRuntime::s_JSRT->m_pFileResMgr;
//TODO 这段代码有点恶心,日后再整理
//为了刷新的时候,再次设置fileCache,所以要把原来的删除掉
if (pFileResManager->m_pFileCache)
{
delete pFileResManager->m_pFileCache;
pFileResManager->m_pFileCache = NULL;
}
pFileResManager->setFileCache(m_pSvFileCache);
}
}
JsAppCache::JsAppCache(const char* p_pszURL)
{
//大概估算内部变量
AdjustAmountOfExternalAllocatedMemory( 1024 );
m_bEnableCache=true;
m_strURL = p_pszURL;
m_pSvFileCache = new JCServerFileCache();
m_pSvFileCache->m_pFuncTransUrl = GlobalTransUrl;
m_pSvFileCache->m_pFuncTransUrlData = this;
m_pSvFileCache->setCachePath((gRedistPath + "appCache").c_str());
if (JCScriptRuntime::s_JSRT->m_pFileResMgr)
{
JCFileResManager* pFileResManager = JCScriptRuntime::s_JSRT->m_pFileResMgr;
//TODO 这段代码有点恶心,日后再整理
//为了刷新的时候,再次设置fileCache,所以要把原来的删除掉
if (pFileResManager->m_pFileCache)
{
delete pFileResManager->m_pFileCache;
pFileResManager->m_pFileCache = NULL;
}
pFileResManager->setFileCache(m_pSvFileCache);
}
m_pSvFileCache->switchToApp(p_pszURL);
AdjustAmountOfExternalAllocatedMemory( 12+13+128);
JCMemorySurvey::GetInstance()->newClass( "AppCache",12+13+128,this );
}
JsAppCache::~JsAppCache()
{
JCMemorySurvey::GetInstance()->releaseClass( "AppCache",this );
//TODO 这段代码有点恶心,日后再整理
//删除这个svFileCache不能在这删除,因为渲染线程还在运行,所以放到渲染线程删除FileResManager的时候删除了
//但是这个JCAppCache有多个,就会有内存泄露
/*
if (m_pSvFileCache != NULL)
{
delete m_pSvFileCache;
}
*/
m_pSvFileCache = NULL;
}
unsigned int JsAppCache::getCacheSize()
{
return 0;
}
std::string JsAppCache::getCachePath()
{
return m_pSvFileCache->getAppPath();
}
bool JsAppCache::getEnableCache()
{
return m_bEnableCache;
}
void JsAppCache::setEnableCache(bool b )
{
m_bEnableCache = b;
}
void onCheckOKRunInJs(JsAppCache* pobj)
{
pobj->m_funcCheckOK.Call();
}
void onCheckErrorRunInJs(JsAppCache* pobj, const char* pError)
{
pobj->m_funcCheckError.Call();
}
void onCheckOK(JsAppCache* pobj)
{
std::function<void()> pFunction = std::bind(onCheckOKRunInJs,pobj);
//JSConch::GetInstance()->postFuncToJSThread(pFunction);
}
void onCheckError(JsAppCache* pobj)
{
std::function<void()> pFunction = std::bind(onCheckErrorRunInJs,pobj,"");
//JSConch::GetInstance()->postFuncToJSThread(pFunction);
}
void JsAppCache::update( const char* p_pszDccURL, unsigned int p_ulCheckSum, JSValueAsParam p_pFuncCheckOK, JSValueAsParam p_pFuncCheckError )
{
/*
JCDownloadManager* pDown = JCDownloadManager::GetInstance();
if( pDown )
{
m_funcCheckOK = *p_pFuncCheckOK;
m_funcCheckError = *p_pFuncCheckError;
if( !m_bEnableCache )
{
onCheckOK(this);
}
else
{
pDown->m_onWebCheckOK = std::bind( onCheckOK, this );
pDown->m_onWebCheckError = std::bind( onCheckError, this );
pDown->checkWeb(p_pszDccURL, m_strURL.c_str(), p_ulCheckSum );
}
}
*/
}
bool JsAppCache::updateFileForJs(int p_nFileID, unsigned int p_nCheckSum,JSValueAsParam p_pBuffer, bool p_bExtVersion)
{
char* pABPtr = NULL;
int nABLen = 0;
bool isab = extractJSAB(p_pBuffer, pABPtr, nABLen);
if (pABPtr && nABLen > 0)
{
return updateFile(p_nFileID, p_nCheckSum, pABPtr, nABLen, p_bExtVersion);
}
else
{
return false;
}
}
bool JsAppCache::updateFile(int p_nFileID, unsigned int p_ulChkSum,const char* p_pBuffer, int len, bool p_bExtVersion)
{
if (p_pBuffer == NULL || len <= 0)
return false;
if (p_ulChkSum == 0)
{
p_ulChkSum = JCCachedFileSys::getChkSum((char*)p_pBuffer, len);
}
/*
unsigned int localid=0;
if (strstr(p_pszUrl, "http://"))
{
localid = m_pSvFileCache->hashURLFull(p_pszUrl);
}
else
{
localid = m_pSvFileCache->hashURLR(p_pszUrl);
}
*/
if (p_bExtVersion)
{
m_pSvFileCache->updateAFile(p_nFileID, (char*)p_pBuffer, len, p_ulChkSum,
true, 0, false);
return true;
}
else
{
unsigned int chk = 0;
if (m_pSvFileCache->getFileInfo(p_nFileID, chk))
{
if (p_ulChkSum != chk)
{
LOGE("updateFileErr:S:%x R:%x", chk, p_ulChkSum);
return false;
}
m_pSvFileCache->updateAFile(p_nFileID, (char*)p_pBuffer, len, p_ulChkSum,false, 0, false);
return true;
}
LOGE("updateFile error, not in table:%x", p_nFileID);
}
return false;
}
std::string JsAppCache::url2Local(const char* p_pszURL )
{
return "";
}
void JsAppCache::setResourceID(const char* p_pszResource, const char* p_pszVal)
{
return m_pSvFileCache->setResourceID(p_pszResource, p_pszVal);
}
std::string JsAppCache::getResourceID(const char* p_pszResource )
{
return m_pSvFileCache->getResourceID(p_pszResource);
}
void JsAppCache::saveFileTable(const char* p_pszFileContent)
{
m_pSvFileCache->saveFileTable(p_pszFileContent);
}
void JsAppCache::setFileTable(const char* p_pszFileContent)
{
m_pSvFileCache->setFileTables(p_pszFileContent);
}
void JsAppCache::setUrlTransTable(const char* p_pszFileContent,int split)
{
m_pSvFileCache->setUrlTransTable(p_pszFileContent,(char)split);
}
void JsAppCache::setTransUrlToCachedUrl(JSValueAsParam pObj)
{
m_funcTransUrl.set(transUrlFun, this, pObj);
}
char* JsAppCache::getTransedUrl(const char* pUrl)
{
if (!m_funcTransUrl.Empty())
{
char* ret = NULL;
m_funcTransUrl.CallWithReturn(pUrl, ret);
return ret;
}
return nullptr;
}
std::string JsAppCache::loadCachedURL( const char* p_pszUrl )
{
JCFileResManager* pfsMgr = JCScriptRuntime::s_JSRT->m_pFileResMgr;
laya::JCFileRes* res = pfsMgr->getRes(p_pszUrl);
JCBuffer buff;
std::string strOut="";
if( res->loadFromCache(buff,false) && buff.m_pPtr)
{
if (buff.m_nLen >= 3 && ((*(int*)(buff.m_pPtr)) & 0x00ffffff) == 0xbfbbef)
{
strOut.append(buff.m_pPtr+3, buff.m_nLen-3);
}
else
{
strOut.append(buff.m_pPtr, buff.m_nLen);
}
}
else
{
LOGE("JsAppCache::loadCachedURL Error, no cache data.");
}
//LOGE("loadCachedURL:%s,%s", p_pszUrl, strOut.c_str());
return strOut;
}
bool JsAppCache::isFileTableValid()
{
std::string file = m_pSvFileCache->getAppPath()+"/"+"filetable.txt";
JCBuffer buf;
if(!readFileSync(file.c_str(),buf))
return false;
if(buf.m_nLen<=0)
return false;
return true;
}
extern unsigned char* AllocSharedBuffer(int sz, void* pUserData);
bool JsAppCache::isUrlNeedDownload(const char* p_pszFile) {
JCCachedFileSys::fileShell fs;
time_t tm;
unsigned int chksumInFS = 0;
unsigned int id = m_pSvFileCache->getFileID(p_pszFile);
std::string pathstr;
std::string file = m_pSvFileCache->m_FileSys.fileToPath(id, pathstr, false);
// 读取本地缓存中保存的校验值
if (!m_pSvFileCache->loadShell(file.c_str(), fs, tm)) {
JCFileSource* pAssets = m_pSvFileCache->getAssets();
std::string obbPath = m_pSvFileCache->m_FileSys.fileToStr(id, true);
if (pAssets && pAssets->isFileExist(obbPath.c_str())) {
JCSharedBuffer p_BufRet;
int sz;
if (pAssets->loadFileContent(obbPath.c_str(), AllocSharedBuffer, (void*)&p_BufRet, sz)) {
//生成校验码
JCSimpleCRC crc;
crc.process_bytes(p_BufRet.m_pBuffer.get(), sz);
chksumInFS = crc.checksum();
}
else {
return true;
}
}
else {
// 读取缓存失败,要重新下载
return true;
}
}
else {
chksumInFS = fs.chkSum;
}
// 获得dcc表中保存的校验值
unsigned int chksumInDcc;
if (m_pSvFileCache->getFileInfo(id, chksumInDcc)) {
// 两个校验值不相等就需要下载
return chksumInDcc != chksumInFS;
}
else {
// dcc中没有,需要下载
return true;
}
}
//返回的是一个array,元素类型为 {path:string,url:string}
JsValue JsAppCache::getAppList()
{
std::vector <std::string> paths;
std::string path = m_pSvFileCache->getAppPath();
//要去掉 sessionFiles
fs::path full_path(path.c_str());
full_path.remove_filename();
if (fs::exists(full_path))
{
fs::directory_iterator item_begin(full_path);
fs::directory_iterator item_end;
for (; item_begin != item_end; item_begin++)
{
if (fs::is_directory(*item_begin))
{
auto urlid = (*item_begin).path() / "sourceid" / "appurl";
fs::path apppath = (*item_begin).path().filename();
paths.push_back(apppath.generic_string()); //先是实际路径,然后是对应的url,如果没有,对应的url就是""
std::string url = "";
if (fs::exists(urlid))
{
JCBuffer buf;
if (readFileSync(urlid.generic_string().c_str(), buf, JCBuffer::utf8)) {
url = buf.m_pPtr;
paths.push_back(url);
}
}
if(url.length()<=0)
{
paths.push_back("");
}
}
else
{
//文件怎么处理
}
}
}
#ifdef JS_V8
//现在提供的转换不太方便转vector<string>,所以先自己写一个
int size = (int)paths.size();
v8::Isolate* piso = m_isolate;
v8::Local< v8::Context> context = piso->GetCurrentContext();
if (0 == size){
v8::Local<v8::Array> array = v8::Array::New(piso, 0);
return array;
}
else {
v8::Local<Array> array = Array::New(piso, size);
v8::HandleScope sc(m_isolate);
for (int i = 0; i < size/2; i++) {
v8::Local<Object> retobj = v8::Object::New(m_isolate);
std::string& path = paths[i * 2];
std::string& url = paths[i * 2 + 1];
retobj->Set(context, Js_Str(m_isolate, "path"), Js_Str(m_isolate,(const char*)path.c_str()));
if (url.length() > 0)
retobj->Set(context, Js_Str(m_isolate, "url"), Js_Str(m_isolate, (const char*)url.c_str()));
else
retobj->Set(context, Js_Str(m_isolate, "url"), v8::Null(m_isolate));
//array->Set(i, __TransferToJs<const char*>::ToJs(paths[i].c_str()));
array->Set(context, i, retobj);
}
return array;
}
#elif JS_JSVM
int size = (int)paths.size();
AutoHandleScope hs;
auto env = ENV;
JSVM_Status status;
JSVM_Value array;
if (0 == size){
JSVM_API_CALL(status, env, OH_JSVM_CreateArrayWithLength(env, 0, &array));
return array;
}
else {
AutoHandleScope hs;
for (int i = 0; i < size/2; i++) {
JSVM_Value retobj;
JSVM_API_CALL(status, env, OH_JSVM_CreateObject(env, &retobj));
std::string& path = paths[i * 2];
std::string& url = paths[i * 2 + 1];
JSVM_API_CALL(status, env, OH_JSVM_SetProperty(env,retobj,Js_Str("path"),Js_Str((const char*)path.c_str())));
if (url.length() > 0) {
JSVM_API_CALL(status, env, OH_JSVM_SetProperty(env,retobj,Js_Str("url"),Js_Str((const char*)url.c_str())));
}
else {
JSVM_Value null;
JSVM_API_CALL(status, env, OH_JSVM_GetNull(env, &null));
JSVM_API_CALL(status, env, OH_JSVM_SetProperty(env,retobj,Js_Str("url"),null));
}
JSVM_API_CALL(status, env, OH_JSVM_SetElement(env, array, i, retobj));
}
return array;
}
#elif JS_JSC
int size = (int)paths.size();
JSContextRef ctx = __TlsData::GetInstance()->GetCurContext();
if (0 == size){
JSObjectRef array = JSObjectMakeArray(ctx, 0, nullptr, nullptr);
return array;
}
else {
size = size/2;
std::vector<JSValueRef> arguments;
arguments.reserve(size);
for (int i = 0; i < size; i++){
JSObjectRef retobj = JSObjectMake(ctx, nullptr, nullptr);
std::string& path = paths[i * 2];
std::string& url = paths[i * 2 + 1];
JSStringRef jsstrKeyPath = JSStringCreateWithUTF8CString("path");
JSStringRef jsstrKeyUrl = JSStringCreateWithUTF8CString("url");
JSStringRef jsstrValuePath = JSStringCreateWithUTF8CString((const char*)path.c_str());
JSStringRef jsstrValueUrl = JSStringCreateWithUTF8CString((const char*)url.c_str());
JSObjectSetProperty(ctx, retobj, jsstrKeyPath, JSValueMakeString(ctx,jsstrValuePath), kJSPropertyAttributeNone, nullptr);
if (url.length() > 0)
JSObjectSetProperty(ctx, retobj, jsstrKeyUrl, JSValueMakeString(ctx,jsstrValueUrl), kJSPropertyAttributeNone, nullptr);
else
JSObjectSetProperty(ctx, retobj, jsstrKeyUrl, JSValueMakeNull(ctx), kJSPropertyAttributeNone, nullptr);
arguments[i] = retobj;
}
JSObjectRef array= JSObjectMakeArray(ctx, size,&arguments[0], nullptr);
return array;
}
#endif
}
int32_t JsAppCache::getAppSize(const char* appurl)
{
return 0;
}
void JsAppCache::delCurAppCache()
{
m_pSvFileCache->clearAllCachedFile();
}
bool JsAppCache::delAppCache(const char* appurl)
{
m_pSvFileCache->clearAllCachedFile();
return false;
}
void JsAppCache::delAllCache()
{
}
int JsAppCache::hashString(const char* str)
{
return JCCachedFileSys::hashRaw(str);
}
void JsAppCache::exportJS()
{
JSP_CLASS("AppCache", JsAppCache);
JSP_ADD_PROPERTY_RO(cacheSize, JsAppCache, getCacheSize);
JSP_ADD_METHOD("update", JsAppCache::update)
JSP_ADD_METHOD("url2Local", JsAppCache::url2Local);
JSP_ADD_PROPERTY(enableCache, JsAppCache, getEnableCache, setEnableCache);
JSP_ADD_METHOD("getResourceID", JsAppCache::getResourceID);
JSP_ADD_METHOD("setResourceID", JsAppCache::setResourceID);
JSP_ADD_METHOD("saveFileTable", JsAppCache::saveFileTable);
JSP_ADD_METHOD("setFileTable", JsAppCache::setFileTable);
JSP_ADD_METHOD("setUrlTransTable", JsAppCache::setUrlTransTable);
JSP_ADD_METHOD("transUrlToCachedUrl", JsAppCache::setTransUrlToCachedUrl);
JSP_ADD_METHOD("loadCachedURL", JsAppCache::loadCachedURL);
JSP_ADD_METHOD("getCachePath", JsAppCache::getCachePath);
JSP_ADD_METHOD("isFileTableValid", JsAppCache::isFileTableValid); //为了打补丁用的
JSP_ADD_METHOD("getAppList", JsAppCache::getAppList);
JSP_ADD_METHOD("getAppSize", JsAppCache::getAppSize);
JSP_ADD_METHOD("delAppCache", JsAppCache::delAppCache);
JSP_ADD_METHOD("delCurAppCache", JsAppCache::delCurAppCache);
JSP_ADD_METHOD("delAllCache", JsAppCache::delAllCache);
JSP_ADD_METHOD("updateFile", JsAppCache::updateFileForJs);
JSP_ADD_METHOD("hashstr", JsAppCache::hashString);
JSP_ADD_METHOD("isUrlNeedDownload", JsAppCache::isUrlNeedDownload);
JSP_REG_CONSTRUCTOR(JsAppCache, const char *);
JSP_INSTALL_CLASS("AppCache", JsAppCache);
}
}
//------------------------------------------------------------------------------
//-----------------------------END FILE--------------------------------