feat: implement MoloApp plans 01-15 with integration
Full C++23 framework tree: runtime, observability, security, data, app, realtime, supervisor, clients, CLI, example plus enterprise tenancy, audit, operability, governance, supplychain. Postgres via docker compose for tests.
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
#include "Router.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "Caps.hpp"
|
||||
|
||||
namespace molo::example::fw {
|
||||
|
||||
namespace {
|
||||
|
||||
std::vector<std::string> split_path(std::string_view path) {
|
||||
std::vector<std::string> segs;
|
||||
std::string cur;
|
||||
for (char c : path) {
|
||||
if (c == '/') {
|
||||
if (!cur.empty()) {
|
||||
segs.push_back(cur);
|
||||
cur.clear();
|
||||
}
|
||||
} else {
|
||||
cur.push_back(c);
|
||||
}
|
||||
}
|
||||
if (!cur.empty()) segs.push_back(cur);
|
||||
return segs;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool match_pattern(std::string_view pattern, std::string_view path,
|
||||
std::map<std::string, std::string>& params) {
|
||||
auto want = split_path(pattern);
|
||||
auto got = split_path(path);
|
||||
if (want.size() != got.size()) return false;
|
||||
for (std::size_t i = 0; i < want.size(); ++i) {
|
||||
const std::string& w = want[i];
|
||||
if (w.size() >= 2 && w.front() == '{' && w.back() == '}') {
|
||||
params[w.substr(1, w.size() - 2)] = url_decode(got[i]);
|
||||
} else if (w != got[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Router::add(std::vector<Method> methods, std::string pattern,
|
||||
std::string name, Handler handler) {
|
||||
if (routes_.size() >= caps::kMaxRouteCount)
|
||||
throw std::length_error("route cap exceeded");
|
||||
for (const auto& r : routes_) {
|
||||
if (r.name == name)
|
||||
throw std::runtime_error("duplicate route name: " + name);
|
||||
}
|
||||
routes_.push_back(
|
||||
Route{std::move(methods), std::move(pattern), std::move(name),
|
||||
std::move(handler)});
|
||||
}
|
||||
|
||||
void Router::get(std::string pattern, std::string name, Handler handler) {
|
||||
add({Method::Get}, std::move(pattern), std::move(name), std::move(handler));
|
||||
}
|
||||
|
||||
void Router::post(std::string pattern, std::string name, Handler handler) {
|
||||
add({Method::Post}, std::move(pattern), std::move(name), std::move(handler));
|
||||
}
|
||||
|
||||
void Router::put(std::string pattern, std::string name, Handler handler) {
|
||||
add({Method::Put}, std::move(pattern), std::move(name), std::move(handler));
|
||||
}
|
||||
|
||||
void Router::patch(std::string pattern, std::string name, Handler handler) {
|
||||
add({Method::Patch}, std::move(pattern), std::move(name), std::move(handler));
|
||||
}
|
||||
|
||||
void Router::del(std::string pattern, std::string name, Handler handler) {
|
||||
add({Method::Delete}, std::move(pattern), std::move(name),
|
||||
std::move(handler));
|
||||
}
|
||||
|
||||
void Router::options(std::string pattern, std::string name, Handler handler) {
|
||||
add({Method::Options}, std::move(pattern), std::move(name),
|
||||
std::move(handler));
|
||||
}
|
||||
|
||||
void Router::any(std::vector<Method> methods, std::string pattern,
|
||||
std::string name, Handler handler) {
|
||||
add(std::move(methods), std::move(pattern), std::move(name),
|
||||
std::move(handler));
|
||||
}
|
||||
|
||||
void Router::include_router(const std::string& prefix, const Router& other,
|
||||
const std::string& name_prefix) {
|
||||
for (const auto& r : other.routes_) {
|
||||
std::string pattern = prefix;
|
||||
if (!r.pattern.empty() && r.pattern != "/") {
|
||||
if (pattern.empty() || pattern.back() != '/') pattern += "/";
|
||||
std::string sub = r.pattern;
|
||||
if (!sub.empty() && sub.front() == '/') sub.erase(sub.begin());
|
||||
pattern += sub;
|
||||
}
|
||||
if (pattern.empty()) pattern = "/";
|
||||
std::string name = name_prefix.empty() ? r.name : name_prefix + r.name;
|
||||
add(r.methods, pattern, name, r.handler);
|
||||
}
|
||||
}
|
||||
|
||||
bool Router::match(Request& req, Handler& out) const {
|
||||
for (const auto& r : routes_) {
|
||||
bool method_ok = false;
|
||||
for (Method m : r.methods) {
|
||||
if (m == req.method) {
|
||||
method_ok = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!method_ok) continue;
|
||||
std::map<std::string, std::string> params;
|
||||
if (match_pattern(r.pattern, req.path, params)) {
|
||||
for (auto& [k, v] : params) req.path_params[k] = v;
|
||||
out = r.handler;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::vector<Route>& Router::routes() const { return routes_; }
|
||||
|
||||
} // namespace molo::example::fw
|
||||
Reference in New Issue
Block a user