diff --git a/Makefile b/Makefile index 2a79dab..895fa40 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ CC = g++ -CFLAGS = -Wall -Wextra -Werror -CFILES = router.cpp path.cpp request.cpp response.cpp -OFILES = router.o path.o request.o response.o -HFILES = router.hpp path.hpp request.hpp response.hpp http.hpp +CFLAGS = -Wall -Wextra -Werror +CFILES = router.cpp path.cpp request.cpp response.cpp tree.cpp +OFILES = router.o path.o request.o response.o tree.o +HFILES = router.hpp path.hpp request.hpp response.hpp http.hpp tree.hpp NAME = libhttpablu.a @@ -12,7 +12,7 @@ $(NAME): ofiles ar rcs $(NAME) $(OFILES) ofiles: - g++ $(CFLAGS) -std=c++20 -O -c $(CFILES) + g++ $(CFLAGS) -std=c++20 -g -O0 -c $(CFILES) clean: rm -f $(OFILES) diff --git a/main.cpp b/main.cpp index 71ec67c..c16ab2b 100644 --- a/main.cpp +++ b/main.cpp @@ -1,5 +1,6 @@ #include "http.hpp" #include "router.hpp" +#include "tree.hpp" using namespace http; @@ -9,36 +10,70 @@ void HelloWorld(Request req, Response *res) { } int main() { - Router router(8181); + Tree t; - // Allow all Methods - router.Handle("/helloWorld", HelloWorld); - - router.Handle("/healthz", [](Request req, Response *res) { - res->SetStatusCode(statuscode::OK); - res->SetPayload(std::vector()); - res->SetContentType("text/plain"); - }); - - // Only allow GET - router.Handle("GET /echo/{name}", [](Request req, Response *res) { - std::string name = req.path.Get("name").value_or("No Name given"); - res->SetPayload("Hello " + name); - res->SetContentType("text/plain"); - }); - - // Only allow POST - router.Handle("POST /echo/{name}", [](Request req, Response *res) { - std::string name = req.path.Get("name").value_or("No Name given"); - res->SetPayload("Hello with Post" + name); - res->SetContentType("text/plain"); - }); - - router.Handle("/", [](Request req, Response *res) { + t.AddPath("/test/dummy", [](Request req, Response *res) { res->SetPayload("Main"); res->SetContentType("text/plain"); }); - router.Start(); - return 0; + t.AddPath("/test/dummy/main", [](Request req, Response *res) { + res->SetPayload("Main"); + res->SetContentType("text/plain"); + }); + + t.AddPath("/test/dummy/main2", [](Request req, Response *res) { + res->SetPayload("Main"); + res->SetContentType("text/plain"); + }); + + t.AddPath("/test/dummy2/main", [](Request req, Response *res) { + res->SetPayload("Main"); + res->SetContentType("text/plain"); + }); + + t.AddPath("/var/main", [](Request req, Response *res) { + res->SetPayload("Main"); + res->SetContentType("text/plain"); + }); + + t.AddPath("/test/dummy2", [](Request req, Response *res) { + res->SetPayload("Main"); + res->SetContentType("text/plain"); + }); + + t.DebugPrint(); + + // Router router(8181); + // + // // Allow all Methods + // router.Handle("/helloWorld", HelloWorld); + // + // router.Handle("/healthz", [](Request req, Response *res) { + // res->SetStatusCode(statuscode::OK); + // res->SetPayload(std::vector()); + // res->SetContentType("text/plain"); + // }); + // + // // Only allow GET + // router.Handle("GET /echo/{name}", [](Request req, Response *res) { + // std::string name = req.path.Get("name").value_or("No Name given"); + // res->SetPayload("Hello " + name); + // res->SetContentType("text/plain"); + // }); + // + // // Only allow POST + // router.Handle("POST /echo/{name}", [](Request req, Response *res) { + // std::string name = req.path.Get("name").value_or("No Name given"); + // res->SetPayload("Hello with Post" + name); + // res->SetContentType("text/plain"); + // }); + // + // router.Handle("/", [](Request req, Response *res) { + // res->SetPayload("Main"); + // res->SetContentType("text/plain"); + // }); + // + // router.Start(); + // return 0; } diff --git a/tree.cpp b/tree.cpp new file mode 100644 index 0000000..1fcb3d2 --- /dev/null +++ b/tree.cpp @@ -0,0 +1,116 @@ +#include "tree.hpp" +#include +#include +#include +#include + +using namespace http; + +std::vector split(std::string s, std::string delimiter) { + size_t pos_start = 0, pos_end, delim_len = delimiter.length(); + std::string token; + std::vector res; + + while ((pos_end = s.find(delimiter, pos_start)) != std::string::npos) { + token = s.substr(pos_start, pos_end - pos_start); + pos_start = pos_end + delim_len; + if (token != "") { + res.push_back(token); + } + } + + token = s.substr(pos_start); + if (token != "") { + res.push_back(token); + } + return res; +} + +Node::Node(std::string sub) { + m_subPath = sub; + m_isDummy = true; + m_isValue = false; + m_function = nullptr; +} + +Node::Node(std::string sub, bool isValue, + std::function func) { + m_subPath = sub; + m_isValue = isValue; + m_function = func; + m_isDummy = false; +} + +void create_dummy_nodes(std::shared_ptr **root, + std::vector rest) { + auto curr = *root; + for (auto next : rest) { + auto dummy = std::make_shared(Node{next}); + (*curr)->m_next.insert_or_assign(next, dummy); + curr = &dummy; + } + root = &curr; +} + +void addNode(std::shared_ptr const &parent, std::string path, + std::vector rest, + std::function func) { + std::shared_ptr curr = parent->m_next[path]; + if (rest.size() == 0) { + if (curr) { + curr->m_isDummy = false; + curr->m_function = func; + } else { + std::shared_ptr leaf = + std::make_shared(Node{path, false, func}); + parent->m_next.insert_or_assign(path, leaf); + } + return; + } + + if (curr) { + auto newPath = rest.front(); + // Ineffiecient, use deque + rest.erase(rest.begin()); + addNode(curr, newPath, rest, func); + } else { + auto newPath = rest.front(); + rest.erase(rest.begin()); + std::shared_ptr leaf = std::make_shared(Node{path}); + parent->m_next.insert_or_assign(path, leaf); + addNode(leaf, newPath, rest, func); + } +} + +void Tree::AddPath(std::string path, + std::function func) { + auto subPaths = split(path, "/"); + + if (subPaths.size() == 0 && m_root == nullptr) { + m_root = std::make_shared(Node{"", false, func}); + return; + } else if (subPaths.size() == 0) { + m_root->m_function = func; + return; + } else if (m_root == nullptr) { + m_root = std::make_shared(Node{""}); + } + + auto newPath = subPaths.front(); + subPaths.erase(subPaths.begin()); + addNode(m_root, newPath, subPaths, func); +} + +void printNode(std::shared_ptr node, size_t depth, size_t max_depth) { + if (depth >= max_depth) { + return; + } + + std::cout << std::string(depth, ' ') << "sub: \"" << node->m_subPath + << "\" IsDummy: " << node->m_isDummy << std::endl; + for (auto &next : node->m_next) { + printNode(next.second, depth + 1, max_depth); + } +} + +void Tree::DebugPrint() { printNode(m_root, 0, 10); } diff --git a/tree.hpp b/tree.hpp new file mode 100644 index 0000000..0759878 --- /dev/null +++ b/tree.hpp @@ -0,0 +1,38 @@ +#ifndef TREE_H +#define TREE_H + +#include "request.hpp" +#include "response.hpp" +#include +#include +#include +#include +namespace http { + +class Node { +public: + bool m_isValue; + bool m_isDummy; + std::string m_subPath; + std::map> m_next; + std::function m_function; + +public: + Node(std::string subPath, bool isValue, + std::function); + Node(std::string subPath); +}; + +class Tree { +private: + std::shared_ptr m_root; + std::string m_method; + size_t depth; + +public: + void AddPath(std::string, std::function); + void DebugPrint(); +}; +} // namespace http + +#endif