[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/expresscpp/expresscpp/master/src/router.cpp [Back]  [Original]

#include "expresscpp/router.hpp"

#include 
#include 

#include "boost/algorithm/string.hpp"
#include "boost/uuid/uuid_generators.hpp"
#include "boost/uuid/uuid_io.hpp"
#include "expresscpp/console.hpp"
#include "expresscpp/impl/utils.hpp"
#include "expresscpp/layer.hpp"

using namespace std::literals;

namespace expresscpp {

Router::Router() {
  Init();
}

Router::Router(std::string_view name) : name_(name) {
  Init();
}

void Router::Init() {
  timestamp_ = std::chrono::system_clock::now();
  uuid_ = boost::uuids::random_generator()();
  Console::Debug(fmt::format("Router \"{}\" created, uuid \"{}\"", name_, boostUUIDToString(uuid_)));
}

std::vector Router::stack() const {
  return stack_;
}

void Router::Use(std::string_view registered_path, handler_wn_t handler) {
  Console::Debug(fmt::format("use \"{}\" registered", registered_path));
  PathToRegExpOptions op{ this->caseSensitive, true,  false};
  auto layer = std::make_shared(registered_path, op, parent_path_, handler);
  stack_.emplace_back(layer);
}

void Router::Use(handler_wn_t handler) {
  Console::Debug(fmt::format("use middleware"));
  PathToRegExpOptions op{ this->caseSensitive,  false, false};
  auto layer = std::make_shared("/", op, parent_path_, handler);
  stack_.emplace_back(layer);
}

void Router::RegisterPath(std::string_view registered_path, const HttpMethod method, handler_wn_t handler) {
  auto route = CreateRoute(registered_path);
  Console::Debug(fmt::format("registering path \"{}\"", registered_path));
  PathToRegExpOptions op;
  auto layer = std::make_shared("/", op, parent_path_, handler);
  layer->SetMethod(method);
  route->methods_.insert(method);
  route->stack_.emplace_back(layer);
}

void Router::Use(std::string_view path, std::shared_ptr router) {
  Console::Debug(fmt::format("adding router to path: \"{}\"", path));
  const auto parent_path = fmt::format("{}{}", parent_path_, path);
  router->SetParentPath(parent_path);
  PathToRegExpOptions op{ this->caseSensitive, true, false};
  auto layer = std::make_shared(path, op, parent_path_,
                                       [router](auto req, auto res, auto /*n*/) { router->HandleRequest(req, res); });
  stack_.emplace_back(layer);
}

void Router::Next(std::shared_ptr req, std::shared_ptr /*res*/, std::shared_ptr err) {
  if (err != nullptr) {
    Console::Error(fmt::format("next error: {}", *err));
    return;
  }
  while (req->match != true && req->idx < stack_.size()) {
    req->current_layer = stack_[req->idx++];
    req->match = req->current_layer->Match(req);
    req->current_route = req->current_layer->GetRoute();

    // no match
    if (req->match == false) {
      Console::Debug(
          fmt::format("no match for path \"{}\", layer \"{}\"", req->getPath(), req->current_layer->GetPath()));
      continue;
    }

    if (!req->current_route) {
      // process non-route handlers normally
      break;
    }

    const auto method = req->getMethod();
    const auto has_method = req->current_route->HasMethod(method);

    // don't even bother matching route
    if (!has_method && method != HttpMethod::Head) {
      req->match = false;
      continue;
    }
  }
}

void Router::HandleRequest(std::shared_ptr req, std::shared_ptr res) {
  assert(req != nullptr);
  assert(res != nullptr);

  Console::Debug(fmt::format("dispatching request path: \"{}\", method \"{}\"", req->getPath(),
                             getHttpMethodName(req->getMethod())));

  // find next matching layer
  req->idx = 0;
  Next(req, res);
  NextRouter next_handler(this, req, res);
  while (req->match == true) {
    req->match = false;
    req->current_layer->HandleRequest(req, res, next_handler);
    // will be reset to true in the next() function if there is another matching layer
  }

  Console::Debug(fmt::format(R"(finished request: "{}", "{}")", getHttpMethodName(req->getMethod()), req->getPath()));
}

void Router::SetParentPath(const std::string& parent_path) {
  for (auto layer : stack_) {
    layer->SetParentPath(parent_path);
  }
  parent_path_ = parent_path;
}

auto Router::GetRouter() {
  Console::Debug("getting a router");
  auto r = std::make_shared();
  return r;
}

auto Router::GetRouter(std::string_view name) {
  Console::Debug(fmt::format("getting a router{}", name));
  auto r = std::make_shared(name);
  return r;
}

std::shared_ptr Router::CreateRoute(const std::string_view registered_path) {
  // create route
  auto r = std::make_shared(registered_path);

  // create layer and add it to the stack
  PathToRegExpOptions op{ this->caseSensitive,  true, true};
  std::shared_ptr l =
      std::make_shared(registered_path, op, parent_path_, [&](auto req, auto res, auto next) {
        Console::Debug("lambda called");
        l->GetRoute()->Dispatch(req, res, next);
      });

  // add route to the layer
  l->SetRoute(r);

  stack_.emplace_back(l);
  return r;
}

std::string_view Router::GetName() const {
  return name_;
}

}  // namespace expresscpp

Web Proxy Viewer  |  New URL  |  Original Page