Changed: Use http cache headers for image cache
--HG-- branch : develophg/compatibility-develop
parent
3d09dd2094
commit
108759952e
@ -0,0 +1,77 @@
|
||||
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
|
||||
// Copyright (C) 2010 Winch Gate Property Limited
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef CL_HTTP_CACHE_H
|
||||
#define CL_HTTP_CACHE_H
|
||||
|
||||
#include "nel/misc/types_nl.h"
|
||||
|
||||
namespace NLGUI
|
||||
{
|
||||
struct CHttpCacheObject
|
||||
{
|
||||
CHttpCacheObject(uint32 expires = 0, const std::string& lastModified = "", const std::string& etag = "")
|
||||
: Expires(expires)
|
||||
, LastModified(lastModified)
|
||||
, Etag(etag){};
|
||||
|
||||
uint32 Expires;
|
||||
std::string LastModified;
|
||||
std::string Etag;
|
||||
|
||||
void serial(NLMISC::IStream& f);
|
||||
};
|
||||
|
||||
/**
|
||||
* Keeping track of downloaded files cache related headers
|
||||
* \author Meelis Mägi (nimetu)
|
||||
* \date 2017
|
||||
*/
|
||||
class CHttpCache
|
||||
{
|
||||
typedef std::map<std::string, CHttpCacheObject> THttpCacheMap;
|
||||
|
||||
public:
|
||||
static CHttpCache* getInstance();
|
||||
static void release();
|
||||
|
||||
public:
|
||||
void setCacheIndex(const std::string& fname);
|
||||
void init();
|
||||
|
||||
CHttpCacheObject lookup(const std::string& fname);
|
||||
void store(const std::string& fname, const CHttpCacheObject& data);
|
||||
|
||||
void flushCache();
|
||||
|
||||
void serial(NLMISC::IStream& f);
|
||||
|
||||
private:
|
||||
CHttpCache();
|
||||
~CHttpCache();
|
||||
|
||||
void pruneCache();
|
||||
|
||||
static CHttpCache* instance;
|
||||
|
||||
THttpCacheMap _List;
|
||||
|
||||
std::string _IndexFilename;
|
||||
bool _Initialized;
|
||||
size_t _MaxObjects;
|
||||
};
|
||||
}
|
||||
#endif
|
@ -0,0 +1,200 @@
|
||||
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
|
||||
// Copyright (C) 2010 Winch Gate Property Limited
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "stdpch.h"
|
||||
#include "nel/gui/http_cache.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace NLMISC;
|
||||
|
||||
#ifdef DEBUG_NEW
|
||||
#define new DEBUG_NEW
|
||||
#endif
|
||||
|
||||
namespace NLGUI
|
||||
{
|
||||
CHttpCache* CHttpCache::instance = NULL;
|
||||
|
||||
CHttpCache* CHttpCache::getInstance()
|
||||
{
|
||||
if (!instance)
|
||||
{
|
||||
instance = new CHttpCache();
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
void CHttpCache::release()
|
||||
{
|
||||
delete instance;
|
||||
instance = NULL;
|
||||
}
|
||||
|
||||
CHttpCache::CHttpCache()
|
||||
: _Initialized(false)
|
||||
, _MaxObjects(100)
|
||||
{ };
|
||||
|
||||
CHttpCache::~CHttpCache()
|
||||
{
|
||||
flushCache();
|
||||
}
|
||||
|
||||
void CHttpCache::setCacheIndex(const std::string& fname)
|
||||
{
|
||||
_IndexFilename = fname;
|
||||
_Initialized = false;
|
||||
}
|
||||
|
||||
CHttpCacheObject CHttpCache::lookup(const std::string& fname)
|
||||
{
|
||||
if (!_Initialized)
|
||||
init();
|
||||
|
||||
if (_List.count(fname) > 0)
|
||||
return _List[fname];
|
||||
|
||||
return CHttpCacheObject();
|
||||
}
|
||||
|
||||
void CHttpCache::store(const std::string& fname, const CHttpCacheObject& data)
|
||||
{
|
||||
if (!_Initialized)
|
||||
init();
|
||||
|
||||
_List[fname] = data;
|
||||
}
|
||||
|
||||
void CHttpCache::init()
|
||||
{
|
||||
if (_Initialized)
|
||||
return;
|
||||
|
||||
_Initialized = true;
|
||||
|
||||
if (_IndexFilename.empty() || !CFile::fileExists(_IndexFilename))
|
||||
return;
|
||||
|
||||
CIFile in;
|
||||
if (!in.open(_IndexFilename)) {
|
||||
nlwarning("Unable to open %s for reading", _IndexFilename.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
serial(in);
|
||||
}
|
||||
|
||||
void CHttpCacheObject::serial(NLMISC::IStream& f)
|
||||
{
|
||||
f.serialVersion(1);
|
||||
f.serial(Expires);
|
||||
f.serial(LastModified);
|
||||
f.serial(Etag);
|
||||
}
|
||||
|
||||
void CHttpCache::serial(NLMISC::IStream& f)
|
||||
{
|
||||
// saved state is ignored when version checks fail
|
||||
try {
|
||||
f.serialVersion(1);
|
||||
|
||||
// CacheIdx
|
||||
f.serialCheck(NELID("hcaC"));
|
||||
f.serialCheck(NELID("xdIe"));
|
||||
|
||||
if (f.isReading())
|
||||
{
|
||||
uint32 numFiles;
|
||||
f.serial(numFiles);
|
||||
|
||||
_List.clear();
|
||||
for (uint k = 0; k < numFiles; ++k)
|
||||
{
|
||||
std::string fname;
|
||||
f.serial(fname);
|
||||
|
||||
CHttpCacheObject obj;
|
||||
obj.serial(f);
|
||||
|
||||
_List[fname] = obj;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32 numFiles = _List.size();
|
||||
f.serial(numFiles);
|
||||
|
||||
for (THttpCacheMap::iterator it = _List.begin(); it != _List.end(); ++it)
|
||||
{
|
||||
std::string fname(it->first);
|
||||
f.serial(fname);
|
||||
|
||||
(*it).second.serial(f);
|
||||
}
|
||||
}
|
||||
} catch (...) {
|
||||
_List.clear();
|
||||
nlwarning("Invalid cache index format (%s)", _IndexFilename.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void CHttpCache::pruneCache()
|
||||
{
|
||||
if (_List.size() < _MaxObjects)
|
||||
return;
|
||||
|
||||
size_t mustDrop = _List.size() - _MaxObjects;
|
||||
|
||||
time_t currentTime;
|
||||
time(¤tTime);
|
||||
|
||||
// if we over object limit, then start removing expired objects
|
||||
// this does not guarantee that max limit is reached
|
||||
for (THttpCacheMap::iterator it = _List.begin(); it != _List.end();) {
|
||||
if (it->second.Expires <= currentTime) {
|
||||
it = _List.erase(it);
|
||||
|
||||
--mustDrop;
|
||||
if (mustDrop == 0)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CHttpCache::flushCache()
|
||||
{
|
||||
if (_IndexFilename.empty())
|
||||
return;
|
||||
|
||||
pruneCache();
|
||||
|
||||
COFile out;
|
||||
if (!out.open(_IndexFilename))
|
||||
{
|
||||
nlwarning("Unable to open %s for writing", _IndexFilename.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
serial(out);
|
||||
out.close();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue