Skip to content

Commit d044f27

Browse files
committed
Fully working basic cache
1 parent a5ef598 commit d044f27

4 files changed

Lines changed: 52 additions & 38 deletions

File tree

examples/CachingApp.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ int main() {
55
uWS::App app;
66

77
/* Regular, non-cached response */
8-
app.get("/*", [](auto *res, auto */*req*/) {
8+
app.get("/not-cached", [](auto *res, auto */*req*/) {
99
res->end("Responding without a cache");
10-
}).get("/cached", [](auto *res, auto */*req*/) {
11-
/* A cached response with 13 seconds of lifetime */
10+
}).get("/*", [](auto *res, auto */*req*/) {
11+
/* A cached response with 5 seconds of lifetime */
1212
std::cout << "Filling cache now" << std::endl;
1313
res->end("This is a response");
14-
}, 13).listen(8080, [](bool success) {
14+
}, 5).listen(8080, [](bool success) {
1515
if (success) {
1616
std::cout << "Listening on port 8080" << std::endl;
1717
} else {

src/App.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -598,8 +598,8 @@ struct TemplatedApp {
598598
#include "CachingApp.h"
599599

600600
namespace uWS {
601-
typedef uWS::CachingApp App;
602-
typedef uWS::CachingApp SSLApp;
601+
typedef uWS::CachingApp<false> App;
602+
typedef uWS::CachingApp<true> SSLApp;
603603
}
604604

605605
#endif // UWS_APP_H

src/CachingApp.h

Lines changed: 42 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -21,41 +21,48 @@ struct StringViewEqual {
2121
}
2222
};
2323

24-
typedef std::unordered_map<std::string_view, std::string,
25-
StringViewHash,
26-
StringViewEqual> CacheType;
24+
2725

2826
class CachingHttpResponse {
2927
public:
30-
CachingHttpResponse(uWS::HttpResponse<false> *res, CacheType &cache, const std::string_view &cacheKey)
31-
: res(res), cache(cache), cacheKey(cacheKey) {}
28+
CachingHttpResponse(uWS::HttpResponse<false> *res)
29+
: res(res) {}
3230

3331
void write(std::string_view data) {
3432
buffer.append(data);
3533
}
3634

3735
void end(std::string_view data = "") {
3836
buffer.append(data);
39-
cache[cacheKey] = buffer;
37+
38+
// end for all queued up sockets also
4039
res->end(buffer);
40+
41+
created = time(0);
4142
}
4243

43-
private:
44-
uWS::HttpResponse<false>* res;
45-
CacheType &cache;
46-
std::string cacheKey;
47-
std::string buffer;
44+
public:
45+
uWS::HttpResponse<false>* res; // should be a vector of waiting sockets
46+
47+
48+
std::string buffer; // body
49+
time_t created;
4850
};
4951

52+
typedef std::unordered_map<std::string_view, CachingHttpResponse *,
53+
StringViewHash,
54+
StringViewEqual> CacheType;
55+
5056
// we can also derive from H3app later on
51-
struct CachingApp : public uWS::TemplatedApp<false, CachingApp> {
57+
template <bool SSL>
58+
struct CachingApp : public uWS::TemplatedApp<SSL, CachingApp<SSL>> {
5259
public:
53-
CachingApp(SocketContextOptions options = {}) : uWS::TemplatedApp<false, CachingApp>(options) {}
60+
CachingApp(SocketContextOptions options = {}) : uWS::TemplatedApp<SSL, CachingApp<SSL>>(options) {}
5461

55-
using uWS::TemplatedApp<false, CachingApp>::get;
62+
using uWS::TemplatedApp<SSL, CachingApp<SSL>>::get;
5663

5764
CachingApp(const CachingApp &other) = delete;
58-
CachingApp(CachingApp &&other) : uWS::TemplatedApp<false, CachingApp>(std::move(other)) {
65+
CachingApp(CachingApp<SSL> &&other) : uWS::TemplatedApp<SSL, CachingApp<SSL>>(std::move(other)) {
5966
// also move the cache
6067
}
6168

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

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

71-
// whenever a cache is to be used, its timestamp is checked against
72-
// the one timestamp driven by the server
73-
// CachedApp::updateTimestamp() will be called by the server timer
74-
75-
// Loop::get()::getTimestamp()
80+
auto it = cache.find(cache_key);
81+
if (it != cache.end()) {
7682

77-
if (cache.find(cache_key) != cache.end()) {
78-
res->end(cache[cache_key]); // tryEnd!
79-
} else {
83+
if (it->second->created + secondsToExpiry > now) {
84+
res->end(it->second->buffer); // tryEnd!
85+
return;
86+
}
8087

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

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

86-
handler(&cachingRes, req);
93+
// if the cache completed? ok, is it still valid? use it
8794
}
95+
96+
// immediately take the place in the cache
97+
CachingHttpResponse *cachingRes;
98+
cache[cache_key] = (cachingRes = new CachingHttpResponse(res));
99+
100+
handler(cachingRes, req);
88101
});
89102
return *this;
90103
}

src/LoopData.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,13 @@ struct alignas(16) LoopData {
6161
}
6262

6363
void updateDate() {
64-
time_t now = time(0);
64+
cacheTimepoint = time(0);
6565
struct tm tstruct = {};
6666
#ifdef _WIN32
6767
/* Micro, fucking soft never follows spec. */
68-
gmtime_s(&tstruct, &now);
68+
gmtime_s(&tstruct, &cacheTimepoint);
6969
#else
70-
gmtime_r(&now, &tstruct);
70+
gmtime_r(&cacheTimepoint, &tstruct);
7171
#endif
7272
static const char wday_name[][4] = {
7373
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
@@ -87,6 +87,7 @@ struct alignas(16) LoopData {
8787
}
8888

8989
char date[32];
90+
time_t cacheTimepoint = 0;
9091

9192
/* Be silent */
9293
bool noMark = false;

0 commit comments

Comments
 (0)