Skip to content

Commit

Permalink
refactor: cache manager
Browse files Browse the repository at this point in the history
  • Loading branch information
Serein207 committed Aug 29, 2024
1 parent 365374b commit 8bb5b71
Show file tree
Hide file tree
Showing 6 changed files with 157 additions and 135 deletions.
65 changes: 65 additions & 0 deletions src/Infrastructure/Cache/Cache.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#include <Infrastructure/Cache/Cache.h>
#include <format>

namespace evento {

std::string CacheManager::generateKey(http::verb verb,
urls::url_view url,
const std::initializer_list<urls::param>& params) {
std::string key = std::format("{}|{}", url.data(), static_cast<int>(verb));
for (const auto& param : params) {
key += std::format("|{}={}", param.key, param.value);
}
return key;
}

bool CacheManager::isExpired(const CacheEntry& entry) {
using namespace std::chrono_literals;
return std::chrono::steady_clock::now() - entry.insertTime >= 1h;
}

void CacheManager::insert(const std::string& key, const CacheEntry& entry) {
auto it = _cacheMap.find(key);
if (it != _cacheMap.end()) {
_cacheList.erase(it->second);
currentCacheSize -= it->second->second.size;
}

_cacheList.emplace_front(key, entry);
_cacheMap[key] = _cacheList.begin();
currentCacheSize += entry.size;

while (currentCacheSize > MAX_CACHE_SIZE) {
auto last = _cacheList.end();
--last;
currentCacheSize -= last->second.size;
_cacheMap.erase(last->first);
_cacheList.pop_back();
}
}

std::optional<CacheEntry> CacheManager::get(std::string const& key) {
if (isExpired(_cacheMap[key]->second)) {
currentCacheSize -= _cacheMap[key]->second.size;
_cacheList.erase(_cacheMap[key]);
_cacheMap.erase(key);
return std::nullopt;
}
auto it = _cacheMap.find(key);
if (it == _cacheMap.end()) {
return std::nullopt;
}
return it->second->second;
}

void CacheManager::load() {}

void CacheManager::save() {}

void CacheManager::saveToDisk() {}

std::string CacheManager::generateFilename(urls::url_view url) {
return "";
}

} // namespace evento
54 changes: 54 additions & 0 deletions src/Infrastructure/Cache/Cache.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#pragma once

#include <boost/beast/http.hpp>
#include <boost/url.hpp>
#include <boost/url/url_view.hpp>
#include <chrono>
#include <list>
#include <nlohmann/json.hpp>
#include <optional>
#include <unordered_map>

namespace evento {

namespace beast = boost::beast;
namespace http = beast::http;
namespace urls = boost::urls;

struct CacheEntry {
nlohmann::basic_json<> result;
std::chrono::steady_clock::time_point insertTime;
std::size_t size; //cache size
};

class CacheManager {
public:
CacheManager() { load(); }
~CacheManager() { save(); }

static std::string generateKey(http::verb verb,
urls::url_view url,
const std::initializer_list<urls::param>& params);

static std::string generateFilename(urls::url_view url);

static bool isExpired(const CacheEntry& entry);

void insert(const std::string& key, const CacheEntry& entry);

std::optional<CacheEntry> get(std::string const& key);

static constexpr size_t MAX_CACHE_SIZE = 64 * 1024 * 1024;

private:
void load();
void save();

void saveToDisk();

std::list<std::pair<std::string, CacheEntry>> _cacheList;
std::unordered_map<std::string, decltype(_cacheList.begin())> _cacheMap;
inline static size_t currentCacheSize = 0;
};

} // namespace evento
41 changes: 0 additions & 41 deletions src/Infrastructure/Network/HttpsAccessManager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,10 @@
#include <boost/asio/awaitable.hpp>
#include <boost/asio/ssl/error.hpp>
#include <boost/asio/ssl/stream.hpp>
#include <boost/asio/ssl/stream_base.hpp>
#include <boost/beast/http/dynamic_body.hpp>
#include <boost/beast/http/field.hpp>
#include <boost/beast/http/message.hpp>
#include <boost/beast/http/string_body.hpp>
#include <boost/system/detail/error_code.hpp>
#include <boost/system/system_error.hpp>
#include <boost/url.hpp>
#include <fstream>
#include <sstream>

namespace evento {

Expand All @@ -24,15 +18,6 @@ Task<ResponseResult> HttpsAccessManager::makeReply(std::string host,
http::request<http::string_body> req) {
std::string url = host + std::string(req.target());

// Check cache first
{
std::lock_guard<std::mutex> lock(_cacheMutex);
auto it = _cache.find(url);
if (it != _cache.end()) {
co_return Ok(it->second);
}
}

auto resolver = net::use_awaitable_t<boost::asio::any_io_executor>::as_default_on(
tcp::resolver(co_await net::this_coro::executor));

Expand Down Expand Up @@ -86,37 +71,11 @@ Task<ResponseResult> HttpsAccessManager::makeReply(std::string host,
auto [ec] = co_await stream.async_shutdown(net::as_tuple(net::use_awaitable));
if (!ec || ec == net::error::eof || (ignoreSslError && ec == ssl::error::stream_truncated)) {
// If we get here then the connection is closed gracefully
// Cache the response
{
std::lock_guard<std::mutex> lock(_cacheMutex);
_cache[url] = res;
}

// Generate a unique filename and save the response body to a file
std::string filename = generateFilename(url);
saveToFile(filename, _buffer);

co_return Ok(res);
}

debug(), ec, ec.message();
co_return Err(Error(Error::Network, ec.message()));
}

void HttpsAccessManager::saveToFile(const std::string& filename, const beast::flat_buffer& buffer) {
std::ofstream file(filename, std::ios::binary);
if (file.is_open()) {
file.write(static_cast<const char*>(buffer.data().data()), buffer.size());
file.close();
}
}

std::string HttpsAccessManager::generateFilename(const std::string& url) {
std::hash<std::string> hasher;
std::size_t hash = hasher(url);
std::stringstream ss;
ss << "image_" << hash << ".jpg";
return ss.str();
}

} // namespace evento
16 changes: 0 additions & 16 deletions src/Infrastructure/Network/HttpsAccessManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,10 @@
#include <boost/asio/use_awaitable.hpp>
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/http/dynamic_body.hpp>
#include <boost/beast/http/message.hpp>
#include <boost/beast/http/verb.hpp>
#include <boost/beast/ssl.hpp>
#include <boost/url/url.hpp>
#include <chrono>
#include <functional> // for std::hash
#include <mutex>
#include <string>
#include <unordered_map>

namespace evento {

Expand Down Expand Up @@ -52,16 +46,6 @@ class HttpsAccessManager {
net::ssl::context& _ctx;
std::chrono::seconds _timeout; // respective timeout of ssl handshake & http
beast::flat_buffer _buffer; // http buffer is used for reading and must be persisted

// Cache for storing downloaded images
std::unordered_map<std::string, http::response<http::dynamic_body>> _cache;
std::mutex _cacheMutex;

// Helper function to save response body to a file
void saveToFile(const std::string& filename, const beast::flat_buffer& buffer);

// Helper function to generate a unique filename based on URL
std::string generateFilename(const std::string& url);
};

} // namespace evento
15 changes: 1 addition & 14 deletions src/Infrastructure/Network/NetworkClient.cc
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
#include "NetworkClient.h"
#include <Infrastructure/Network/Api/Evento.hh>
#include <Infrastructure/Network/Api/Github.hh>
#include <Infrastructure/Utils/Debug.h>
#include <boost/url/param.hpp>
#include <boost/url/params_view.hpp>
#include <initializer_list>
#include <memory>
#include <nlohmann/json.hpp>
Expand All @@ -19,7 +17,7 @@ constexpr const char MIME_FORM_URL_ENCODED[] = "application/x-www-form-urlencode

NetworkClient::NetworkClient(net::ssl::context& ctx)
: _ctx(ctx)
, _manager(std::make_unique<HttpsAccessManager>(_ctx, true)) {}
, _httpsAccessManager(std::make_unique<HttpsAccessManager>(_ctx, true)) {}

NetworkClient* NetworkClient::getInstance() {
static ssl::context ctx(ssl::context::sslv23);
Expand Down Expand Up @@ -348,17 +346,6 @@ Task<Result<DepartmentEntityList>> NetworkClient::getDepartmentList() {
co_return Ok(entity);
}

std::string NetworkClient::generateCacheKey(http::verb verb,
const urls::url_view& url,
const std::initializer_list<urls::param>& params) {
std::string key = std::string(url.data(), url.size()) + "|"
+ std::to_string(static_cast<int>(verb));
for (const auto& param : params) {
key += "|" + std::string(param.key) + "=" + std::string(param.value);
}
return key;
}

urls::url NetworkClient::endpoint(std::string_view endpoint) {
return urls::url(EVENTO_API_GATEWAY + endpoint.data());
}
Expand Down
Loading

0 comments on commit 8bb5b71

Please sign in to comment.