Skip to content

Commit

Permalink
Fully working basic cache
Browse files Browse the repository at this point in the history
  • Loading branch information
uNetworkingAB committed Jul 22, 2024
1 parent a5ef598 commit d044f27
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 38 deletions.
8 changes: 4 additions & 4 deletions examples/CachingApp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ int main() {
uWS::App app;

/* Regular, non-cached response */
app.get("/*", [](auto *res, auto */*req*/) {
app.get("/not-cached", [](auto *res, auto */*req*/) {
res->end("Responding without a cache");
}).get("/cached", [](auto *res, auto */*req*/) {
/* A cached response with 13 seconds of lifetime */
}).get("/*", [](auto *res, auto */*req*/) {
/* A cached response with 5 seconds of lifetime */
std::cout << "Filling cache now" << std::endl;
res->end("This is a response");
}, 13).listen(8080, [](bool success) {
}, 5).listen(8080, [](bool success) {
if (success) {
std::cout << "Listening on port 8080" << std::endl;
} else {
Expand Down
4 changes: 2 additions & 2 deletions src/App.h
Original file line number Diff line number Diff line change
Expand Up @@ -598,8 +598,8 @@ struct TemplatedApp {
#include "CachingApp.h"

namespace uWS {
typedef uWS::CachingApp App;
typedef uWS::CachingApp SSLApp;
typedef uWS::CachingApp<false> App;
typedef uWS::CachingApp<true> SSLApp;
}

#endif // UWS_APP_H
71 changes: 42 additions & 29 deletions src/CachingApp.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,41 +21,48 @@ struct StringViewEqual {
}
};

typedef std::unordered_map<std::string_view, std::string,
StringViewHash,
StringViewEqual> CacheType;


class CachingHttpResponse {
public:
CachingHttpResponse(uWS::HttpResponse<false> *res, CacheType &cache, const std::string_view &cacheKey)
: res(res), cache(cache), cacheKey(cacheKey) {}
CachingHttpResponse(uWS::HttpResponse<false> *res)
: res(res) {}

void write(std::string_view data) {
buffer.append(data);
}

void end(std::string_view data = "") {
buffer.append(data);
cache[cacheKey] = buffer;

// end for all queued up sockets also
res->end(buffer);

created = time(0);
}

private:
uWS::HttpResponse<false>* res;
CacheType &cache;
std::string cacheKey;
std::string buffer;
public:
uWS::HttpResponse<false>* res; // should be a vector of waiting sockets


std::string buffer; // body
time_t created;
};

typedef std::unordered_map<std::string_view, CachingHttpResponse *,
StringViewHash,
StringViewEqual> CacheType;

// we can also derive from H3app later on
struct CachingApp : public uWS::TemplatedApp<false, CachingApp> {
template <bool SSL>
struct CachingApp : public uWS::TemplatedApp<SSL, CachingApp<SSL>> {
public:
CachingApp(SocketContextOptions options = {}) : uWS::TemplatedApp<false, CachingApp>(options) {}
CachingApp(SocketContextOptions options = {}) : uWS::TemplatedApp<SSL, CachingApp<SSL>>(options) {}

using uWS::TemplatedApp<false, CachingApp>::get;
using uWS::TemplatedApp<SSL, CachingApp<SSL>>::get;

CachingApp(const CachingApp &other) = delete;
CachingApp(CachingApp &&other) : uWS::TemplatedApp<false, CachingApp>(std::move(other)) {
CachingApp(CachingApp<SSL> &&other) : uWS::TemplatedApp<SSL, CachingApp<SSL>>(std::move(other)) {
// also move the cache
}

Expand All @@ -64,27 +71,33 @@ struct CachingApp : public uWS::TemplatedApp<false, CachingApp> {
}

// variant 1: only taking URL into account
CachingApp& get(const std::string& url, std::function<void(CachingHttpResponse*, uWS::HttpRequest*)> handler, unsigned int /*secondsToExpiry*/) {
((uWS::TemplatedApp<false, CachingApp> *)this)->get(url, [this, handler](auto* res, auto* req) {
CachingApp& get(const std::string& url, std::function<void(CachingHttpResponse*, uWS::HttpRequest*)> handler, unsigned int secondsToExpiry) {
((uWS::TemplatedApp<SSL, CachingApp<SSL>> *)this)->get(url, [this, handler, secondsToExpiry](auto* res, auto* req) {
/* We need to know the cache key and the time of now */
std::string_view cache_key = req->getFullUrl();
time_t now = static_cast<LoopData *>(us_loop_ext((us_loop_t *)uWS::Loop::get()))->cacheTimepoint;

// whenever a cache is to be used, its timestamp is checked against
// the one timestamp driven by the server
// CachedApp::updateTimestamp() will be called by the server timer

// Loop::get()::getTimestamp()
auto it = cache.find(cache_key);
if (it != cache.end()) {

if (cache.find(cache_key) != cache.end()) {
res->end(cache[cache_key]); // tryEnd!
} else {
if (it->second->created + secondsToExpiry > now) {
res->end(it->second->buffer); // tryEnd!
return;
}

// om CacheNode har HttpRequest, status, headers, body - kan CacheNode användas som CachedHttpResponse
// Cache blir unorderd_map<string_view, unique_ptr<CacheNode>> cache;
/* We are no longer valid, delete old cache and fall through to create a new entry */
delete it->second;

CachingHttpResponse cachingRes(res, cache, cache_key); // res kan inte vara stackallokerad
// is the cache completed? if not, add yourself to the waiting list of sockets to that cache

handler(&cachingRes, req);
// if the cache completed? ok, is it still valid? use it
}

// immediately take the place in the cache
CachingHttpResponse *cachingRes;
cache[cache_key] = (cachingRes = new CachingHttpResponse(res));

handler(cachingRes, req);
});
return *this;
}
Expand Down
7 changes: 4 additions & 3 deletions src/LoopData.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,13 @@ struct alignas(16) LoopData {
}

void updateDate() {
time_t now = time(0);
cacheTimepoint = time(0);
struct tm tstruct = {};
#ifdef _WIN32
/* Micro, fucking soft never follows spec. */
gmtime_s(&tstruct, &now);
gmtime_s(&tstruct, &cacheTimepoint);
#else
gmtime_r(&now, &tstruct);
gmtime_r(&cacheTimepoint, &tstruct);
#endif
static const char wday_name[][4] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
Expand All @@ -87,6 +87,7 @@ struct alignas(16) LoopData {
}

char date[32];
time_t cacheTimepoint = 0;

/* Be silent */
bool noMark = false;
Expand Down

0 comments on commit d044f27

Please sign in to comment.