Deleted src/api - this is the old HTTP
This commit is contained in:
parent
46dbc08d4e
commit
029a3ff09b
@ -1,21 +0,0 @@
|
||||
CXX=clang++
|
||||
CFLAGS=-std=c++11 -Wall -O2
|
||||
LDFLAGS=-luv -lhttp_parser ../speedy/r3/.libs/libr3.a -L/usr/local/lib -lpcre
|
||||
# debug only
|
||||
INC=-I../
|
||||
SOURCES=$(wildcard *.cpp)
|
||||
EXECUTABLE=test.out
|
||||
# OBJECTS=$(SOURCES:.cpp=.o)
|
||||
|
||||
all: $(EXECUTABLE)
|
||||
|
||||
$(EXECUTABLE): $(SOURCES)
|
||||
$(CXX) $(CFLAGS) $(SOURCES) -o $(EXECUTABLE) $(INC) $(LDFLAGS)
|
||||
|
||||
# .cpp.o:
|
||||
# $(CXX) $(CFLAGS) $< -o $@ $(LDFLAGS) $(INC)
|
||||
|
||||
.PHONY:
|
||||
clean:
|
||||
rm -f *.out
|
||||
rm -f *.o
|
@ -1,86 +0,0 @@
|
||||
# this script generates the include.hpp file for restful resources
|
||||
import re
|
||||
import os
|
||||
from itertools import chain
|
||||
|
||||
print "generating include.hpp file"
|
||||
|
||||
resource_path = 'resources'
|
||||
template_path = 'resources/include.hpp.template'
|
||||
include_path = 'resources/include.hpp'
|
||||
|
||||
# remove the old version of the file if exists
|
||||
if os.path.isfile(include_path):
|
||||
os.remove(include_path)
|
||||
|
||||
|
||||
class Resource(object):
|
||||
""" represents a restful resource class for speedy """
|
||||
|
||||
def __init__(self, filename, class_name, url):
|
||||
self.filename = filename
|
||||
self.class_name = class_name
|
||||
self.url = url
|
||||
|
||||
|
||||
def scan_resources(filename):
|
||||
|
||||
with open(os.path.join(resource_path, filename)) as f:
|
||||
url_regex = re.compile('#pragma\s+url\s+([^\s]+)\s+')
|
||||
class_name_regex = re.compile('\s*class\s*(\w+)\s*\:')
|
||||
|
||||
lines = f.readlines()
|
||||
pairs = zip(lines, lines[1:])
|
||||
|
||||
for first, second in pairs:
|
||||
url = re.search(url_regex, first)
|
||||
|
||||
if url is None:
|
||||
continue
|
||||
|
||||
class_name = re.search(class_name_regex, second)
|
||||
|
||||
if class_name is None:
|
||||
continue
|
||||
|
||||
yield Resource(filename, class_name.group(1), url.group(1))
|
||||
|
||||
|
||||
def load_resources():
|
||||
resources = chain(*[scan_resources(f) for f in os.listdir(resource_path)
|
||||
if f.endswith('.hpp')])
|
||||
|
||||
return [r for r in resources if r.class_name is not None]
|
||||
|
||||
|
||||
def write_includes(file, resources):
|
||||
for filename in [resource.filename for resource in resources]:
|
||||
print 'writing include for', filename
|
||||
file.write('#include "{}"\n'.format(filename))
|
||||
|
||||
|
||||
def write_inits(file, resources):
|
||||
for class_name, url in [(r.class_name, r.url) for r in resources]:
|
||||
print('writing init for {} -> {}'.format(class_name, url))
|
||||
file.write(' insert<{}>(container, "{}");\n'
|
||||
.format(class_name, url))
|
||||
|
||||
|
||||
def make_include_file():
|
||||
resources = load_resources()
|
||||
|
||||
with open(template_path, 'r') as ftemplate:
|
||||
with open(include_path, 'w') as finclude:
|
||||
for line in ftemplate:
|
||||
if '<INCLUDE>' in line:
|
||||
write_includes(finclude, resources)
|
||||
continue
|
||||
|
||||
if '<INIT>' in line:
|
||||
write_inits(finclude, resources)
|
||||
continue
|
||||
|
||||
finclude.write(line)
|
||||
|
||||
if __name__ == '__main__':
|
||||
make_include_file()
|
1
src/api/resources/.gitignore
vendored
1
src/api/resources/.gitignore
vendored
@ -1 +0,0 @@
|
||||
include.hpp
|
@ -1,150 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "api/restful/resource.hpp"
|
||||
#include "query_engine/query_stripper.hpp"
|
||||
#include "query_engine/query_stripped.hpp"
|
||||
#include "database/db.hpp"
|
||||
#include "utils/hashing/fnv.hpp"
|
||||
#include "threading/task.hpp"
|
||||
#include "storage/model/properties/all.hpp"
|
||||
|
||||
std::vector<std::string> queries {
|
||||
"CREATE (n:Item{id:1}) RETURN n",
|
||||
"MATCH (n:Item{id:1}),(m:Item{id:1}) CREATE (n)-[r:test]->(m) RETURN r",
|
||||
"MATCH (n:Item{id:1}) SET n.prop = 7 RETURN n",
|
||||
"MATCH (n:Item{id:1}) RETURN n",
|
||||
"MATCH (n:Item{id:1})-[r]->(m) RETURN count(r)"
|
||||
};
|
||||
|
||||
#pragma url /transaction/commit
|
||||
class Demo : public Resource<Demo, POST>
|
||||
{
|
||||
public:
|
||||
QueryStripper<int, int, int, int> stripper;
|
||||
std::map<uint64_t, std::function<std::string(const code_args_t&)>> query_f;
|
||||
|
||||
Demo(Task::sptr task, Db::sptr db) :
|
||||
Resource(task, db),
|
||||
stripper(make_query_stripper(TK_INT, TK_FLOAT, TK_STR, TK_BOOL))
|
||||
{
|
||||
std::vector<uint64_t> hashes;
|
||||
|
||||
for(auto& query : queries)
|
||||
{
|
||||
auto strip = stripper.strip(query);
|
||||
auto hash = fnv(strip.query);
|
||||
|
||||
hashes.push_back(hash);
|
||||
}
|
||||
|
||||
query_f[hashes[0]] = [db](const code_args_t& args) {
|
||||
auto& t = db->tx_engine.begin();
|
||||
|
||||
auto v = db->graph.vertices.insert(t);
|
||||
v.property("id", args[0]);
|
||||
|
||||
t.commit();
|
||||
return std::to_string(v.property("id").as<Int32>().value);
|
||||
};
|
||||
|
||||
query_f[hashes[1]] = [db](const code_args_t& args) {
|
||||
return std::string("ALO");
|
||||
auto& t = db->tx_engine.begin();
|
||||
|
||||
auto v1 = db->graph.vertices.find(t, args[0]->as<Int32>().value);
|
||||
|
||||
if(!v1)
|
||||
return t.commit(), std::string("not found");
|
||||
|
||||
auto v2 = db->graph.vertices.find(t, args[1]->as<Int32>().value);
|
||||
|
||||
if(!v2)
|
||||
return t.commit(), std::string("not found");
|
||||
|
||||
auto e = db->graph.edges.insert(t);
|
||||
|
||||
v1.vlist->update(t)->data.out.add(e.vlist);
|
||||
v2.vlist->update(t)->data.in.add(e.vlist);
|
||||
|
||||
e.from(v1.vlist);
|
||||
e.to(v2.vlist);
|
||||
e.edge_type(EdgeType("test"));
|
||||
|
||||
t.commit();
|
||||
return e.edge_type();
|
||||
};
|
||||
|
||||
query_f[hashes[2]] = [db](const code_args_t& args) {
|
||||
auto& t = db->tx_engine.begin();
|
||||
|
||||
auto id = args[0]->as<Int32>();
|
||||
auto v = db->graph.vertices.find(t, id.value);
|
||||
|
||||
if (!v)
|
||||
return t.commit(), std::string("not found");
|
||||
|
||||
v.property("prop", args[1]);
|
||||
|
||||
t.commit();
|
||||
return std::to_string(v.property("id").as<Int32>().value);
|
||||
};
|
||||
|
||||
query_f[hashes[3]] = [db](const code_args_t& args) {
|
||||
auto& t = db->tx_engine.begin();
|
||||
|
||||
auto id = args[0]->as<Int32>();
|
||||
auto v = db->graph.vertices.find(t, id.value);
|
||||
|
||||
t.commit();
|
||||
|
||||
if(!v)
|
||||
return std::string("not found");
|
||||
|
||||
return std::to_string(v.property("id").as<Int32>().value);
|
||||
};
|
||||
|
||||
query_f[hashes[4]] = [db](const code_args_t& args) {
|
||||
auto& t = db->tx_engine.begin();
|
||||
|
||||
auto id = args[0]->as<Int32>();
|
||||
auto v = db->graph.vertices.find(t, id.value);
|
||||
|
||||
t.commit();
|
||||
|
||||
if(!v)
|
||||
return std::string("not found");
|
||||
|
||||
return std::to_string(v.out_degree());
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
int x{0};
|
||||
|
||||
void post(sp::Request& req, sp::Response& res)
|
||||
{
|
||||
task->run([this, &req]() {
|
||||
auto query = req.json["statements"][0]["statement"].GetString();
|
||||
auto strip = stripper.strip(query);
|
||||
auto hash = fnv(strip.query);
|
||||
|
||||
auto it = query_f.find(hash);
|
||||
|
||||
if(it == query_f.end())
|
||||
{
|
||||
std::cout << "Unrecognized query '"
|
||||
<< query << "' with hash "
|
||||
<< hash << "." << std::endl;
|
||||
|
||||
return std::string("Unrecognized Query");
|
||||
}
|
||||
|
||||
return it->second(strip.arguments);
|
||||
},
|
||||
[&req, &res](std::string str) {
|
||||
return res.send(http::Status::Ok, str);
|
||||
});
|
||||
}
|
||||
};
|
@ -1,48 +0,0 @@
|
||||
/** @file include.hpp
|
||||
* @brief Links all restful resources to the application
|
||||
*
|
||||
* This file is autogenerated by the python script link_resources.py
|
||||
*
|
||||
* YOU SHOULD NOT EDIT THIS FILE MANUALLY!
|
||||
*
|
||||
* well, only if you're editing the template file, that's ok :)
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <memory>
|
||||
|
||||
#include "utils/ioc/container.hpp"
|
||||
#include "api/restful/resource.hpp"
|
||||
|
||||
#include "transactions/engine.hpp"
|
||||
#include "threading/task.hpp"
|
||||
#include "speedy/speedy.hpp"
|
||||
|
||||
// for each file in this folder a script will generate an include directive if
|
||||
// this file contains any resources
|
||||
// e.g.
|
||||
// #include "node.hpp"
|
||||
// #include "relationship.hpp"
|
||||
<INCLUDE>
|
||||
|
||||
template <class T>
|
||||
void insert(ioc::Container& container, const std::string& path)
|
||||
{
|
||||
auto app = container.resolve<sp::Speedy>();
|
||||
auto resource = container.singleton<T, Task, Db>();
|
||||
resource->link(*app, path);
|
||||
}
|
||||
|
||||
void init(ioc::Container& container)
|
||||
{
|
||||
// for each resource in a file included above, the script will generate a
|
||||
// linkage command call to the function above
|
||||
// e.g.
|
||||
// insert<CLASS>(PATH);
|
||||
//
|
||||
// insert<Nodes>("/node");
|
||||
// insert<Node>("/node/{id:\\d+}");
|
||||
<INIT>
|
||||
}
|
@ -1,155 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <random>
|
||||
|
||||
#include "debug/log.hpp"
|
||||
#include "mvcc/version_list.hpp"
|
||||
#include "api/response_json.hpp"
|
||||
#include "api/restful/resource.hpp"
|
||||
#include "storage/model/properties/property.hpp"
|
||||
|
||||
#pragma url /node
|
||||
class Nodes : public Resource<Nodes, POST>
|
||||
{
|
||||
public:
|
||||
using Resource::Resource;
|
||||
|
||||
void post(sp::Request& req, sp::Response& res)
|
||||
{
|
||||
task->run([this, &req]() {
|
||||
// create transaction
|
||||
auto& transaction = db->tx_engine.begin();
|
||||
|
||||
// insert a new vertex
|
||||
auto vertex_accessor = db->graph.vertices.insert(transaction);
|
||||
|
||||
auto begin_it = req.json.MemberBegin();
|
||||
auto end_it = req.json.MemberEnd();
|
||||
for(auto it = begin_it; it != end_it; ++it)
|
||||
{
|
||||
vertex_accessor.template property<String>(
|
||||
it->name.GetString(), it->value.GetString()
|
||||
);
|
||||
}
|
||||
|
||||
// commit the transaction
|
||||
transaction.commit();
|
||||
|
||||
return std::move(vertex_accessor);
|
||||
},
|
||||
[&req, &res](VertexAccessor&& vertex_accessor) {
|
||||
return res.send(
|
||||
http::Status::Created,
|
||||
vertex_create_response(vertex_accessor)
|
||||
);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
#pragma url /node/{id:\\d+}
|
||||
class Node : public Resource<Node, GET, PUT, DELETE>
|
||||
{
|
||||
public:
|
||||
using Resource::Resource;
|
||||
|
||||
void get(sp::Request& req, sp::Response& res)
|
||||
{
|
||||
task->run([this, &req]() {
|
||||
// create transaction
|
||||
auto& transaction = db->tx_engine.begin();
|
||||
|
||||
// read id param
|
||||
Id id(std::stoull(req.params[0]));
|
||||
|
||||
// find node
|
||||
auto vertex_accessor = db->graph.vertices.find(transaction, id);
|
||||
|
||||
// commit the transaction
|
||||
transaction.commit();
|
||||
|
||||
return std::move(vertex_accessor);
|
||||
},
|
||||
[&req, &res](VertexAccessor&& vertex_accessor) {
|
||||
if (vertex_accessor.empty()) {
|
||||
return res.send(
|
||||
http::Status::NotFound,
|
||||
"The node was not found"
|
||||
);
|
||||
}
|
||||
return res.send(
|
||||
vertex_create_response(vertex_accessor)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
void put(sp::Request& req, sp::Response& res)
|
||||
{
|
||||
task->run([this, &req]() {
|
||||
// create transaction
|
||||
auto& transaction = db->tx_engine.begin();
|
||||
|
||||
// read id param
|
||||
Id id(std::stoull(req.params[0]));
|
||||
|
||||
// find node
|
||||
auto vertex_accessor = db->graph.vertices.find(transaction, id);
|
||||
|
||||
if (vertex_accessor.empty())
|
||||
return std::move(vertex_accessor);
|
||||
|
||||
auto begin_it = req.json.MemberBegin();
|
||||
auto end_it = req.json.MemberEnd();
|
||||
for(auto it = begin_it; it != end_it; ++it)
|
||||
{
|
||||
vertex_accessor.template property<String>(
|
||||
it->name.GetString(), it->value.GetString()
|
||||
);
|
||||
}
|
||||
|
||||
// commit the transaction
|
||||
transaction.commit();
|
||||
|
||||
return std::move(vertex_accessor);
|
||||
},
|
||||
[&req, &res](VertexAccessor&& vertex_accessor) {
|
||||
if (vertex_accessor.empty()) {
|
||||
return res.send(
|
||||
http::Status::NotFound,
|
||||
"The node was not found"
|
||||
);
|
||||
}
|
||||
return res.send(vertex_create_response(vertex_accessor));
|
||||
});
|
||||
}
|
||||
|
||||
void del(sp::Request& req, sp::Response& res)
|
||||
{
|
||||
task->run([this, &req]() -> bool {
|
||||
// create transaction
|
||||
auto& transaction = db->tx_engine.begin();
|
||||
|
||||
// read id param
|
||||
Id id(std::stoull(req.params[0]));
|
||||
|
||||
auto vertex_accessor = db->graph.vertices.find(transaction, id);
|
||||
|
||||
if (vertex_accessor.empty())
|
||||
return false;
|
||||
|
||||
auto is_deleted = vertex_accessor.remove(transaction);
|
||||
|
||||
// commit the transaction
|
||||
transaction.commit();
|
||||
|
||||
return is_deleted;
|
||||
},
|
||||
// pass something smarter
|
||||
// e.g. enum { NotFound, Deleted, DeletionFaild }
|
||||
[&req, &res](bool is_deleted) {
|
||||
if (is_deleted)
|
||||
return res.send(http::Status::Ok, "The node was deleted");
|
||||
|
||||
return res.send(http::Status::NotFound, "The node was not found");
|
||||
});
|
||||
}
|
||||
};
|
@ -1,15 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "api/restful/resource.hpp"
|
||||
|
||||
#pragma url /ping
|
||||
class Ping : public Resource<Ping, GET>
|
||||
{
|
||||
public:
|
||||
using Resource::Resource;
|
||||
|
||||
void get(sp::Request& req, sp::Response& res)
|
||||
{
|
||||
return res.send(http::Status::NoContent, "");
|
||||
}
|
||||
};
|
@ -1,38 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "api/restful/resource.hpp"
|
||||
|
||||
#pragma url /relationship
|
||||
class Relationships : public Resource<Relationships, POST>
|
||||
{
|
||||
public:
|
||||
using Resource::Resource;
|
||||
|
||||
void post(sp::Request& req, sp::Response& res)
|
||||
{
|
||||
return res.send("POST /db/data/relationship");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#pragma url /relationship/{id:\\d+}
|
||||
class Relationship : public Resource<Relationship, GET>
|
||||
{
|
||||
public:
|
||||
using Resource::Resource;
|
||||
|
||||
void get(sp::Request& req, sp::Response& res)
|
||||
{
|
||||
return res.send("GET /db/data/relationship");
|
||||
}
|
||||
|
||||
void put(sp::Request& req, sp::Response& res)
|
||||
{
|
||||
return res.send("PUT /db/data/relationship");
|
||||
}
|
||||
|
||||
void del(sp::Request& req, sp::Response& res)
|
||||
{
|
||||
return res.send("DELETE /db/data/relationship");
|
||||
}
|
||||
};
|
@ -1,56 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "storage/vertex.hpp"
|
||||
#include "storage/vertex_accessor.hpp"
|
||||
#include "storage/writer/rapidjson_stringwriter.hpp"
|
||||
|
||||
StringBuffer vertex_props_to_buffer(const Vertex* vertex)
|
||||
{
|
||||
// make a string buffer
|
||||
StringBuffer buffer;
|
||||
JsonWriter<StringBuffer> writer(buffer);
|
||||
|
||||
// dump properties in this buffer
|
||||
vertex->data.props.accept(writer);
|
||||
writer.finish();
|
||||
|
||||
// respond to the use with the buffer
|
||||
return buffer;
|
||||
}
|
||||
|
||||
std::string vertex_props_to_string(const Vertex* vertex)
|
||||
{
|
||||
auto buffer = vertex_props_to_buffer(vertex);
|
||||
return std::move(buffer.str());
|
||||
}
|
||||
|
||||
// TODO: clear up naming
|
||||
using RJStringBuffer = rapidjson::StringBuffer;
|
||||
using RJStringWriter = rapidjson::Writer<RJStringBuffer>;
|
||||
using ptr_RJStringWriter = std::shared_ptr<RJStringWriter>;
|
||||
|
||||
std::string vertex_create_response(const VertexAccessor& vertex_accessor)
|
||||
{
|
||||
// make a string buffer
|
||||
RJStringBuffer buffer;
|
||||
ptr_RJStringWriter writer = std::make_shared<RJStringWriter>(buffer);
|
||||
|
||||
writer->StartObject();
|
||||
writer->String("metadata");
|
||||
|
||||
writer->StartObject();
|
||||
writer->String("id");
|
||||
writer->Int64(vertex_accessor.id());
|
||||
writer->EndObject();
|
||||
|
||||
writer->String("data");
|
||||
writer->StartObject();
|
||||
// RapidJsonStringWriter dataBuffer(writer);
|
||||
// auto properties = vertex_accessor.properties();
|
||||
// properties.accept(dataBuffer);
|
||||
writer->EndObject();
|
||||
|
||||
writer->EndObject();
|
||||
|
||||
return std::move(buffer.GetString());
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "api/restful/restful_resource.hpp"
|
||||
|
||||
#include "database/db.hpp"
|
||||
#include "threading/task.hpp"
|
||||
#include "speedy/speedy.hpp"
|
||||
|
||||
|
||||
template <class T, class... Ms>
|
||||
class Resource
|
||||
{
|
||||
public:
|
||||
/** @brief Resource constructor
|
||||
*
|
||||
* List ALL the dependencies here so that ioc can resolve them and store
|
||||
* them to protected members so that derived resources can access them
|
||||
*
|
||||
* @param task shared_ptr to the task dispatching library
|
||||
* @param db shared_ptr to the database instance
|
||||
*/
|
||||
Resource(Task::sptr task, Db::sptr db)
|
||||
: task(task), db(db) {}
|
||||
|
||||
/** @brief Link all resources to an instance of speedy
|
||||
*
|
||||
* link_resources.py generates an include.hpp file which includes and
|
||||
* instantinates all available resources. The include.hpp file also calls
|
||||
* this method to link the resources to speedy for a given path
|
||||
*/
|
||||
void link(sp::Speedy& app, const std::string& path)
|
||||
{
|
||||
// make sure this is called once even if someone actually calls this
|
||||
// function multiple times
|
||||
std::call_once(once_flag, [this, &app, &path]() {
|
||||
Restful<T, Ms...>(static_cast<T&>(*this), app, path);
|
||||
});
|
||||
}
|
||||
|
||||
protected:
|
||||
// all resources have pointers to these instances add everything else
|
||||
// neccessary here as a shared_ptr and also include it in the constructor
|
||||
// and modify the include.hpp.template to include the new dependencies for
|
||||
// resource linking
|
||||
Task::sptr task;
|
||||
Db::sptr db;
|
||||
|
||||
private:
|
||||
std::once_flag once_flag;
|
||||
};
|
@ -1,156 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "speedy/speedy.hpp"
|
||||
#include "utils/crtp.hpp"
|
||||
|
||||
#include "storage/model/properties/traversers/jsonwriter.hpp"
|
||||
|
||||
/** @brief GET handler method for the resource
|
||||
* Contains the code for registering GET handler for a URL to Speedy
|
||||
*/
|
||||
struct GET
|
||||
{
|
||||
/** @brief Links ::get handler to speedy for a given path
|
||||
*
|
||||
* @tparam T Class type containing the required handler
|
||||
* @param app Instance of speedy to register the method to
|
||||
* @param path URL of the resource being registered
|
||||
* @param resource Object containing ::get http::request_cb_t handler
|
||||
*/
|
||||
template <class T>
|
||||
void link(sp::Speedy& app, const std::string& path, T& resource)
|
||||
{
|
||||
using namespace std::placeholders;
|
||||
app.get(path, std::bind(&T::get, std::ref(resource), _1, _2));
|
||||
}
|
||||
};
|
||||
|
||||
/** @brief POST handler method for the resource
|
||||
* Contains the code for registering POST handler for a URL to Speedy
|
||||
*/
|
||||
struct POST
|
||||
{
|
||||
/** @brief Links ::post handler to speedy for a given path
|
||||
*
|
||||
* @tparam T Class type containing the required handler
|
||||
* @param app Instance of speedy to register the method to
|
||||
* @param path URL of the resource being registered
|
||||
* @param resource Object containing ::post http::request_cb_t handler
|
||||
*/
|
||||
template <class T>
|
||||
void link(sp::Speedy& app, const std::string& path, T& resource)
|
||||
{
|
||||
using namespace std::placeholders;
|
||||
app.post(path, std::bind(&T::post, std::ref(resource), _1, _2));
|
||||
}
|
||||
};
|
||||
|
||||
struct PUT
|
||||
{
|
||||
template <class T>
|
||||
void link(sp::Speedy& app, const std::string& path, T& resource)
|
||||
{
|
||||
using namespace std::placeholders;
|
||||
app.put(path, std::bind(&T::put, std::ref(resource), _1, _2));
|
||||
}
|
||||
};
|
||||
|
||||
struct DELETE
|
||||
{
|
||||
template <class T>
|
||||
void link(sp::Speedy& app, const std::string& path, T& resource)
|
||||
{
|
||||
using namespace std::placeholders;
|
||||
app.del(path, std::bind(&T::del, std::ref(resource), _1, _2));
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
/** @brief Registers a method for a path to speedy
|
||||
*
|
||||
* @tparam T Derived class containing the handler of the method
|
||||
* @tparam M A method to register
|
||||
*/
|
||||
template <class T, class M>
|
||||
struct Method : public M
|
||||
{
|
||||
/** Registers a route handler for the resource
|
||||
*
|
||||
* Registers a method handler for M on the given URL
|
||||
*
|
||||
* @param app instance of speedy to register the method to
|
||||
* @param path URL of the resource being registered
|
||||
*/
|
||||
Method(T& resource, sp::Speedy& app, const std::string& path)
|
||||
{
|
||||
M::link(app, path, resource);
|
||||
}
|
||||
};
|
||||
|
||||
/** @brief Generates the Method<T, M> inheritance for each M in Ms
|
||||
*
|
||||
* Implemented inheriting recursively using variadic templates
|
||||
*
|
||||
* @tparam T Derived class containing handlers for each method M in Ms
|
||||
* @tparam Ms... Methods to register
|
||||
*/
|
||||
template <class T, class... Ms>
|
||||
struct Methods;
|
||||
|
||||
/** @brief specialization of the struct Methods<T, Ms...>
|
||||
*
|
||||
* Unrolls one method M and generates a handler for this method by inheriting
|
||||
* from Method<T, M> and generates the rest of the handlers recursively by
|
||||
* inheriting from Methods<T, Ms...> and unrolling one M each time.
|
||||
*
|
||||
* @tparam T Derived class containing handlers for each method M in Ms
|
||||
* @tparam M Unrolled method M for which to generate a handler
|
||||
* @tparam Ms... The rest of the methods
|
||||
*/
|
||||
template <class T, class M, class... Ms>
|
||||
struct Methods<T, M, Ms...> : public Method<T, M>, public Methods<T, Ms...>
|
||||
{
|
||||
Methods(T& resource, sp::Speedy& app, const std::string& path)
|
||||
: Method<T, M>(resource, app, path),
|
||||
Methods<T, Ms...>(resource, app, path) {}
|
||||
};
|
||||
|
||||
/** @brief specialization of the struct Methods<T, Ms...>
|
||||
*
|
||||
* Specializes the recursion termination case containing only one method M
|
||||
*
|
||||
* @tparam T Derived class containing handlers for method M
|
||||
* @tparam M Unrolled method M for which to generate a handler
|
||||
*/
|
||||
template <class T, class M>
|
||||
struct Methods<T, M> : public Method<T, M>
|
||||
{
|
||||
using Method<T, M>::Method;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/** @brief Represents a restful resource
|
||||
*
|
||||
* Automatically registers get, put, post, del... methods inside the derived
|
||||
* class T. Methods are given as a template parameter to the class. Valid
|
||||
* template parameters are classes which implement a function
|
||||
*
|
||||
* void link(sp::Speedy&, const std::string&, T& resource)
|
||||
*
|
||||
* which registers a method you want to use with speedy
|
||||
*
|
||||
* @tparam T Derived class (CRTP)
|
||||
* @tparam Ms... HTTP methods to register for this resource (GET, POST...)
|
||||
*/
|
||||
template <class T, class... Ms>
|
||||
class Restful : public detail::Methods<T, Ms...>
|
||||
{
|
||||
public:
|
||||
Restful(T& resource, sp::Speedy& app, const std::string& path)
|
||||
: detail::Methods<T, Ms...>(resource, app, path) {}
|
||||
};
|
@ -1,19 +0,0 @@
|
||||
#include <iostream>
|
||||
|
||||
#include "speedy/speedy.hpp"
|
||||
#include "resources/include.hpp"
|
||||
|
||||
int main(void)
|
||||
{
|
||||
uv::UvLoop loop;
|
||||
speedy::Speedy app(loop);
|
||||
|
||||
init(app);
|
||||
|
||||
http::Ipv4 ip("0.0.0.0", 3400);
|
||||
app.listen(ip);
|
||||
|
||||
loop.run(uv::UvLoop::Mode::Default);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user