Skip to content

Commit

Permalink
Add base for a http cache
Browse files Browse the repository at this point in the history
  • Loading branch information
uNetworkingAB committed Jul 21, 2024
1 parent 8028beb commit 88b15f3
Show file tree
Hide file tree
Showing 10 changed files with 174 additions and 47 deletions.
2 changes: 1 addition & 1 deletion build.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ int main(int argc, char **argv) {
char *CXX = strcpy(calloc(1024, 1), or_else(getenv("CXX"), "g++"));
char *EXEC_SUFFIX = strcpy(calloc(1024, 1), maybe(getenv("EXEC_SUFFIX")));

char *EXAMPLE_FILES[] = {"HelloWorldThreaded", "Http3Server", "Broadcast", "HelloWorld", "Crc32", "ServerName",
char *EXAMPLE_FILES[] = {"CachingApp", "HelloWorldThreaded", "Http3Server", "Broadcast", "HelloWorld", "Crc32", "ServerName",
"EchoServer", "BroadcastingEchoServer", "UpgradeSync", "UpgradeAsync", "ParameterRoutes"};

strcat(CXXFLAGS, " -march=native -O3 -Wpedantic -Wall -Wextra -Wsign-conversion -Wconversion -std=c++20 -Isrc -IuSockets/src");
Expand Down
23 changes: 23 additions & 0 deletions examples/CachingApp.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#include "App.h"
#include <iostream>

int main() {
uWS::App app;

/* Regular, non-cached response */
app.get("/*", [](auto *res, auto */*req*/) {
res->end("Responding without a cache");
}).get("/cached", [](auto *res, auto */*req*/) {
/* A cached response with 13 seconds of lifetime */
std::cout << "Filling cache now" << std::endl;
res->end("This is a response");
}, 13).listen(8080, [](bool success) {
if (success) {
std::cout << "Listening on port 8080" << std::endl;
} else {
std::cerr << "Failed to listen on port 8080" << std::endl;
}
});

app.run();
}
84 changes: 44 additions & 40 deletions src/App.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ namespace uWS {

static_assert(sizeof(struct us_socket_context_options_t) == sizeof(SocketContextOptions), "Mismatching uSockets/uWebSockets ABI");

template <bool SSL>
template <bool SSL, typename BuilderPatternReturnType>
struct TemplatedApp {
private:
/* The app always owns at least one http context, but creates websocket contexts on demand */
Expand All @@ -94,7 +94,7 @@ struct TemplatedApp {
TopicTree<TopicTreeMessage, TopicTreeBigMessage> *topicTree = nullptr;

/* Server name */
TemplatedApp &&addServerName(std::string hostname_pattern, SocketContextOptions options = {}) {
BuilderPatternReturnType &&addServerName(std::string hostname_pattern, SocketContextOptions options = {}) {

/* Do nothing if not even on SSL */
if constexpr (SSL) {
Expand All @@ -104,10 +104,10 @@ struct TemplatedApp {
us_socket_context_add_server_name(SSL, (struct us_socket_context_t *) httpContext, hostname_pattern.c_str(), options, domainRouter);
}

return std::move(*this);
return std::move(static_cast<BuilderPatternReturnType &&>(*this));
}

TemplatedApp &&removeServerName(std::string hostname_pattern) {
BuilderPatternReturnType &&removeServerName(std::string hostname_pattern) {

/* This will do for now, would be better if us_socket_context_remove_server_name returned the user data */
auto *domainRouter = us_socket_context_find_server_name_userdata(SSL, (struct us_socket_context_t *) httpContext, hostname_pattern.c_str());
Expand All @@ -119,7 +119,7 @@ struct TemplatedApp {
return std::move(*this);
}

TemplatedApp &&missingServerName(MoveOnlyFunction<void(const char *hostname)> handler) {
BuilderPatternReturnType &&missingServerName(MoveOnlyFunction<void(const char *hostname)> handler) {

if (!constructorFailed()) {
httpContext->getSocketContextData()->missingServerNameHandler = std::move(handler);
Expand All @@ -141,7 +141,7 @@ struct TemplatedApp {
}

/* Attaches a "filter" function to track socket connections/disconnections */
TemplatedApp &&filter(MoveOnlyFunction<void(HttpResponse<SSL> *, int)> &&filterHandler) {
BuilderPatternReturnType &&filter(MoveOnlyFunction<void(HttpResponse<SSL> *, int)> &&filterHandler) {
httpContext->filter(std::move(filterHandler));

return std::move(*this);
Expand Down Expand Up @@ -259,7 +259,7 @@ struct TemplatedApp {
};

/* Closes all sockets including listen sockets. */
TemplatedApp &&close() {
BuilderPatternReturnType &&close() {
us_socket_context_close(SSL, (struct us_socket_context_t *) httpContext);
for (void *webSocketContext : webSocketContexts) {
us_socket_context_close(SSL, (struct us_socket_context_t *) webSocketContext);
Expand All @@ -269,13 +269,13 @@ struct TemplatedApp {
}

template <typename UserData>
TemplatedApp &&ws(std::string pattern, WebSocketBehavior<UserData> &&behavior) {
BuilderPatternReturnType &&ws(std::string pattern, WebSocketBehavior<UserData> &&behavior) {
/* Don't compile if alignment rules cannot be satisfied */
static_assert(alignof(UserData) <= LIBUS_EXT_ALIGNMENT,
"µWebSockets cannot satisfy UserData alignment requirements. You need to recompile µSockets with LIBUS_EXT_ALIGNMENT adjusted accordingly.");

if (!httpContext) {
return std::move(*this);
return std::move(static_cast<BuilderPatternReturnType &&>(*this));
}

/* Terminate on misleading idleTimeout values */
Expand Down Expand Up @@ -438,11 +438,11 @@ struct TemplatedApp {
req->setYield(true);
}
}, true);
return std::move(*this);
return std::move(static_cast<BuilderPatternReturnType &&>(*this));
}

/* Browse to a server name, changing the router to this domain */
TemplatedApp &&domain(std::string serverName) {
BuilderPatternReturnType &&domain(std::string serverName) {
HttpContextData<SSL> *httpContextData = httpContext->getSocketContextData();

void *domainRouter = us_socket_context_find_server_name_userdata(SSL, (struct us_socket_context_t *) httpContext, serverName.c_str());
Expand All @@ -454,82 +454,82 @@ struct TemplatedApp {
httpContextData->currentRouter = &httpContextData->router;
}

return std::move(*this);
return std::move(static_cast<BuilderPatternReturnType &&>(*this));
}

TemplatedApp &&get(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
BuilderPatternReturnType &&get(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
if (httpContext) {
httpContext->onHttp("GET", pattern, std::move(handler));
}
return std::move(*this);
return std::move(static_cast<BuilderPatternReturnType &&>(*this));
}

TemplatedApp &&post(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
BuilderPatternReturnType &&post(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
if (httpContext) {
httpContext->onHttp("POST", pattern, std::move(handler));
}
return std::move(*this);
return std::move(static_cast<BuilderPatternReturnType &&>(*this));
}

TemplatedApp &&options(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
BuilderPatternReturnType &&options(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
if (httpContext) {
httpContext->onHttp("OPTIONS", pattern, std::move(handler));
}
return std::move(*this);
}

TemplatedApp &&del(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
BuilderPatternReturnType &&del(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
if (httpContext) {
httpContext->onHttp("DELETE", pattern, std::move(handler));
}
return std::move(*this);
}

TemplatedApp &&patch(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
BuilderPatternReturnType &&patch(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
if (httpContext) {
httpContext->onHttp("PATCH", pattern, std::move(handler));
}
return std::move(*this);
}

TemplatedApp &&put(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
BuilderPatternReturnType &&put(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
if (httpContext) {
httpContext->onHttp("PUT", pattern, std::move(handler));
}
return std::move(*this);
}

TemplatedApp &&head(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
BuilderPatternReturnType &&head(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
if (httpContext) {
httpContext->onHttp("HEAD", pattern, std::move(handler));
}
return std::move(*this);
}

TemplatedApp &&connect(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
BuilderPatternReturnType &&connect(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
if (httpContext) {
httpContext->onHttp("CONNECT", pattern, std::move(handler));
}
return std::move(*this);
}

TemplatedApp &&trace(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
BuilderPatternReturnType &&trace(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
if (httpContext) {
httpContext->onHttp("TRACE", pattern, std::move(handler));
}
return std::move(*this);
}

/* This one catches any method */
TemplatedApp &&any(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
BuilderPatternReturnType &&any(std::string pattern, MoveOnlyFunction<void(HttpResponse<SSL> *, HttpRequest *)> &&handler) {
if (httpContext) {
httpContext->onHttp("*", pattern, std::move(handler));
}
return std::move(*this);
return std::move(static_cast<BuilderPatternReturnType &&>(*this));
}

/* Host, port, callback */
TemplatedApp &&listen(std::string host, int port, MoveOnlyFunction<void(us_listen_socket_t *)> &&handler) {
BuilderPatternReturnType &&listen(std::string host, int port, MoveOnlyFunction<void(us_listen_socket_t *)> &&handler) {
if (!host.length()) {
return listen(port, std::move(handler));
}
Expand All @@ -538,7 +538,7 @@ struct TemplatedApp {
}

/* Host, port, options, callback */
TemplatedApp &&listen(std::string host, int port, int options, MoveOnlyFunction<void(us_listen_socket_t *)> &&handler) {
BuilderPatternReturnType &&listen(std::string host, int port, int options, MoveOnlyFunction<void(us_listen_socket_t *)> &&handler) {
if (!host.length()) {
return listen(port, options, std::move(handler));
}
Expand All @@ -547,44 +547,44 @@ struct TemplatedApp {
}

/* Port, callback */
TemplatedApp &&listen(int port, MoveOnlyFunction<void(us_listen_socket_t *)> &&handler) {
BuilderPatternReturnType &&listen(int port, MoveOnlyFunction<void(us_listen_socket_t *)> &&handler) {
handler(httpContext ? httpContext->listen(nullptr, port, 0) : nullptr);
return std::move(*this);
return std::move(static_cast<BuilderPatternReturnType &&>(*this));
}

/* Port, options, callback */
TemplatedApp &&listen(int port, int options, MoveOnlyFunction<void(us_listen_socket_t *)> &&handler) {
BuilderPatternReturnType &&listen(int port, int options, MoveOnlyFunction<void(us_listen_socket_t *)> &&handler) {
handler(httpContext ? httpContext->listen(nullptr, port, options) : nullptr);
return std::move(*this);
}

/* options, callback, path to unix domain socket */
TemplatedApp &&listen(int options, MoveOnlyFunction<void(us_listen_socket_t *)> &&handler, std::string path) {
BuilderPatternReturnType &&listen(int options, MoveOnlyFunction<void(us_listen_socket_t *)> &&handler, std::string path) {
handler(httpContext ? httpContext->listen(path.c_str(), options) : nullptr);
return std::move(*this);
}

/* callback, path to unix domain socket */
TemplatedApp &&listen(MoveOnlyFunction<void(us_listen_socket_t *)> &&handler, std::string path) {
BuilderPatternReturnType &&listen(MoveOnlyFunction<void(us_listen_socket_t *)> &&handler, std::string path) {
handler(httpContext ? httpContext->listen(path.c_str(), 0) : nullptr);
return std::move(*this);
}

/* Register event handler for accepted FD. Can be used together with adoptSocket. */
TemplatedApp &&preOpen(LIBUS_SOCKET_DESCRIPTOR (*handler)(LIBUS_SOCKET_DESCRIPTOR)) {
BuilderPatternReturnType &&preOpen(LIBUS_SOCKET_DESCRIPTOR (*handler)(LIBUS_SOCKET_DESCRIPTOR)) {
httpContext->onPreOpen(handler);
return std::move(*this);
return std::move(static_cast<BuilderPatternReturnType &&>(*this));
}

/* adopt an externally accepted socket */
TemplatedApp &&adoptSocket(LIBUS_SOCKET_DESCRIPTOR accepted_fd) {
BuilderPatternReturnType &&adoptSocket(LIBUS_SOCKET_DESCRIPTOR accepted_fd) {
httpContext->adoptAcceptedSocket(accepted_fd);
return std::move(*this);
return std::move(static_cast<BuilderPatternReturnType &&>(*this));
}

TemplatedApp &&run() {
BuilderPatternReturnType &&run() {
uWS::run();
return std::move(*this);
return std::move(static_cast<BuilderPatternReturnType &&>(*this));
}

Loop *getLoop() {
Expand All @@ -593,9 +593,13 @@ struct TemplatedApp {

};

typedef TemplatedApp<false> App;
typedef TemplatedApp<true> SSLApp;
}

#include "CachingApp.h"

namespace uWS {
typedef uWS::CachingApp App;
typedef uWS::CachingApp SSLApp;
}

#endif // UWS_APP_H
2 changes: 1 addition & 1 deletion src/AsyncSocket.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ struct AsyncSocket {
/* This guy is promiscuous */
template <bool> friend struct HttpContext;
template <bool, bool, typename> friend struct WebSocketContext;
template <bool> friend struct TemplatedApp;
template <bool, typename> friend struct TemplatedApp;
template <bool, typename> friend struct WebSocketContextData;
template <typename, typename> friend struct TopicTree;
template <bool> friend struct HttpResponse;
Expand Down
Loading

0 comments on commit 88b15f3

Please sign in to comment.