fixed speedy

This commit is contained in:
Dominik Tomičević 2015-10-07 02:24:21 +02:00
parent 61241ba039
commit 71dad5a6af
4 changed files with 172 additions and 147 deletions

127
speedy/r3.hpp Normal file
View File

@ -0,0 +1,127 @@
#ifndef MEMGRAPH_SPEEDY_R3_HPP
#define MEMGRAPH_SPEEDY_R3_HPP
#include <list>
#include <cassert>
#include "http/http.hpp"
namespace r3 {
#include "r3_include.h"
}
namespace speedy
{
class R3
{
public:
enum Method : int
{
GET = METHOD_GET,
POST = METHOD_POST,
PUT = METHOD_PUT,
DELETE = METHOD_DELETE,
HEAD = METHOD_HEAD
};
static Method to_r3_method(http::Method method)
{
switch (method)
{
case http::Method::GET: return Method::GET;
case http::Method::POST: return Method::POST;
case http::Method::PUT: return Method::PUT;
case http::Method::DELETE: return Method::DELETE;
case http::Method::HEAD: return Method::HEAD;
}
}
private:
class MatchEntry
{
public:
MatchEntry(Method method, const std::string& path)
{
entry = r3::match_entry_createl(path.c_str(), path.size());
entry->request_method = method;
}
~MatchEntry()
{
r3::match_entry_free(entry);
}
operator r3::match_entry*()
{
return entry;
}
private:
r3::match_entry* entry;
r3::route* route;
};
public:
class Route
{
public:
Route(r3::route* route) : route(route) {}
bool exists() const
{
return route != nullptr;
}
void operator()(http::Request& req, http::Response& res)
{
assert(route != nullptr);
auto cb = reinterpret_cast<http::request_cb_t*>(route->data);
cb->operator()(req, res);
}
private:
r3::route* route;
};
R3(size_t capacity)
{
root = r3::r3_tree_create(capacity);
}
~R3()
{
r3::r3_tree_free(root);
}
R3(R3&) = delete;
R3(R3&& other)
{
this->root = other.root;
other.root = nullptr;
}
void insert(Method method, const std::string& path, http::request_cb_t cb)
{
routes.push_back(cb);
r3::r3_tree_insert_routel(root, method, path.c_str(), path.size(),
&routes.back());
}
Route match(Method method, const std::string& path)
{
auto entry = MatchEntry(method, path);
return Route(r3::r3_tree_match_route(root, entry));
}
private:
std::list<http::request_cb_t> routes;
r3::node* root;
};
}
#endif

View File

@ -7,68 +7,61 @@
* @author Dominik Tomicevic (domko)
* @author Marko Budiselic (buda)
*/
#ifndef MEMGRAPH_SPEEDY_HPP
#define MEMGRAPH_SPEEDY_HPP
#ifndef MEMGRAPH_SPEEDY_SPEEDY_HPP
#define MEMGRAPH_SPEEDY_SPEEDY_HPP
#include <vector>
#include "io/uv/uv.hpp"
#include "http/http.hpp"
#include "r3_include.h"
#include "r3.hpp"
namespace speedy
{
typedef unsigned int uint;
class Speedy
{
private:
/*
* http server instance that contains all logic related
* to the http protocol
*/
http::HttpServer server;
/*
* ip address of the server
*/
http::Ipv4 ip;
/*
* root node of r3 decision tree
*/
node *n;
/*
* callbacks container
*/
std::vector<http::request_cb_t> callbacks;
/** @brief Store a http callback.
*
* Every callback for now has receiving method and path (url).
* So, the implementation of this method saves callback for
* the method and the path.
*
* @param method int http defined method
* @param path std::string path (url)
* @param callback http::request_cb_t callback which will be called
* on a http request
*/
void store_callback(int method,
const std::string &path,
http::request_cb_t callback);
public:
Speedy(uv::UvLoop& loop, const http::Ipv4& ip);
void get(const std::string &path, http::request_cb_t callback);
void post(const std::string &path, http::request_cb_t callback);
void put(const std::string &path, http::request_cb_t callback);
void del(const std::string &path, http::request_cb_t callback);
void listen();
Speedy(uv::UvLoop& loop) : server(loop), router(100) {}
Speedy(Speedy&) = delete;
Speedy(Speedy&&) = delete;
void get(const std::string& path, http::request_cb_t cb)
{
router.insert(R3::Method::GET, path, cb);
}
void post(const std::string& path, http::request_cb_t cb)
{
router.insert(R3::Method::POST, path, cb);
}
void put(const std::string& path, http::request_cb_t cb)
{
router.insert(R3::Method::PUT, path, cb);
}
void del(const std::string& path, http::request_cb_t cb)
{
router.insert(R3::Method::DELETE, path, cb);
}
void listen(const http::Ipv4& ip)
{
server.listen(ip, [this](http::Request& req, http::Response& res) {
auto route = router.match(R3::to_r3_method(req.method), req.url);
if(!route.exists())
return res.send(http::Status::NotFound, "Resource not found");
route(req, res);
});
}
private:
http::HttpServer server;
R3 router;
};
}
#include "speedy.inl"
#endif

View File

@ -1,95 +0,0 @@
#ifndef MEMGRAPH_SPEEDY_INL
#define MEMGRAPH_SPEEDY_INL
#include "speedy.hpp"
#include <http_parser.h>
namespace speedy
{
int r3_request_method(http::Method method)
{
switch (method) {
case http::Method::GET: return METHOD_GET;
case http::Method::POST: return METHOD_POST;
case http::Method::PUT: return METHOD_PUT;
case http::Method::DELETE: return METHOD_DELETE;
case http::Method::HEAD: return METHOD_HEAD;
}
}
// TODO: better implementation
Speedy::Speedy(uv::UvLoop& loop, const http::Ipv4& ip) : server(loop), ip(ip)
{
n = r3_tree_create(100);
}
void Speedy::store_callback(int method,
const std::string &path,
http::request_cb_t callback)
{
callbacks.push_back(callback);
void *ptr = malloc(sizeof(uint));
*((uint *)ptr) = callbacks.size() - 1;
r3_tree_insert_routel(n, method, path.c_str(), path.size(), ptr);
}
void Speedy::get(const std::string &path, http::request_cb_t callback)
{
store_callback(METHOD_GET, path, callback);
// TODO: something like this
// this solution doesn't work, currenlty I don't know why
// callbacks.push_back(callback)
// r3_tree_insert_pathl(n, path.c_str(), path.size(), &callbacks.back());
}
void Speedy::post(const std::string &path, http::request_cb_t callback)
{
store_callback(METHOD_POST, path, callback);
}
void Speedy::put(const std::string &path, http::request_cb_t callback)
{
store_callback(METHOD_PUT, path, callback);
}
void Speedy::del(const std::string &path, http::request_cb_t callback)
{
store_callback(METHOD_DELETE, path, callback);
}
void Speedy::listen()
{
char *errstr = NULL;
int err = r3_tree_compile(n, &errstr);
if (err) {
std::cout << "R3 compile error" << std::endl;
}
server.listen(ip, [this](http::Request& req, http::Response& res) {
auto url = req.url;
auto c_url = url.c_str();
match_entry *entry = match_entry_create(c_url);
entry->request_method = r3_request_method(req.method);
route *r = r3_tree_match_route(this->n, entry);
match_entry_free(entry);
if (r) {
int index = *((int *)r->data);
auto callback = this->callbacks[index];
callback(req, res);
// TODO: and something like this
// auto callback = *reinterpret_cast<http::request_cb_t*>(n->data);
// callback(req, res);
} else {
res.send("Not found");
}
});
std::cout << "Server is UP" << std::endl;
}
}
#endif

View File

@ -32,7 +32,7 @@ int main(void)
// speedy init
uv::UvLoop loop;
http::Ipv4 ip("0.0.0.0", 3400);
speedy::Speedy app(loop, ip);
speedy::Speedy app(loop);
// GET methods
app.get(test_url_1, test_callback);
@ -60,7 +60,7 @@ int main(void)
test_delete(test_callback, app);
// app run
app.listen();
app.listen(ip);
loop.run(uv::UvLoop::Mode::Default);
return 0;