mirror of
https://github.com/Relintai/rcpp_framework.git
synced 2024-11-14 04:57:21 +01:00
Added my web app implementation to the drogon module. Just renamed it and made it compile.
This commit is contained in:
parent
9e0621daf0
commit
c4c9d34e35
@ -5,6 +5,7 @@ Import("env")
|
||||
|
||||
env_mod.core_sources = []
|
||||
|
||||
env_mod.add_source_files(env_mod.core_sources, "*.cpp")
|
||||
env_mod.add_source_files(env_mod.core_sources, "drogon/lib/src/*.cc")
|
||||
env_mod.add_source_files(env_mod.core_sources, "drogon/lib/inc/http/*.cc")
|
||||
env_mod.add_source_files(env_mod.core_sources, "drogon/lib/src/ssl_funcs/*.cc")
|
||||
|
13
modules/drogon/handler_instance.cpp
Normal file
13
modules/drogon/handler_instance.cpp
Normal file
@ -0,0 +1,13 @@
|
||||
#include "handler_instance.h"
|
||||
|
||||
#include "request.h"
|
||||
#include "core/object.h"
|
||||
|
||||
DHandlerInstance::DHandlerInstance() {
|
||||
instance = nullptr;
|
||||
}
|
||||
|
||||
DHandlerInstance::DHandlerInstance(std::function<void(Object *, DRequest *)> p_handler_func, Object *p_instance) {
|
||||
handler_func = p_handler_func;
|
||||
instance = p_instance;
|
||||
}
|
17
modules/drogon/handler_instance.h
Normal file
17
modules/drogon/handler_instance.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef DHANDLER_INSTANCE_H
|
||||
#define DHANDLER_INSTANCE_H
|
||||
|
||||
#include <functional>
|
||||
|
||||
class Object;
|
||||
class DRequest;
|
||||
|
||||
struct DHandlerInstance {
|
||||
std::function<void(Object *, DRequest *)> handler_func;
|
||||
Object *instance;
|
||||
|
||||
DHandlerInstance();
|
||||
DHandlerInstance(std::function<void(Object *, DRequest *)> p_handler_func, Object *p_instance = nullptr);
|
||||
};
|
||||
|
||||
#endif
|
309
modules/drogon/request.cpp
Normal file
309
modules/drogon/request.cpp
Normal file
@ -0,0 +1,309 @@
|
||||
#include "request.h"
|
||||
|
||||
#include "web_application.h"
|
||||
|
||||
void DRequest::compile_body() {
|
||||
compiled_body.reserve(body.size() + head.size() + 13 + 14 + 15);
|
||||
|
||||
//13
|
||||
compiled_body += "<html>"
|
||||
"<head>";
|
||||
|
||||
compiled_body += head;
|
||||
|
||||
//14
|
||||
compiled_body += "</head>"
|
||||
"<body>";
|
||||
|
||||
compiled_body += body;
|
||||
compiled_body += footer;
|
||||
|
||||
//15
|
||||
compiled_body += "</body>"
|
||||
"</html>";
|
||||
|
||||
response->setBody(compiled_body);
|
||||
}
|
||||
|
||||
void DRequest::compile_and_send_body() {
|
||||
compile_body();
|
||||
send();
|
||||
}
|
||||
|
||||
void DRequest::next_stage() {
|
||||
if (current_middleware_index == (*middleware_stack).size()) {
|
||||
handler_instance.handler_func(handler_instance.instance, this);
|
||||
return;
|
||||
}
|
||||
|
||||
const DHandlerInstance &hi = (*middleware_stack)[current_middleware_index++];
|
||||
|
||||
hi.handler_func(hi.instance, this);
|
||||
}
|
||||
|
||||
void DRequest::send() {
|
||||
//if (connection_closed) {
|
||||
// DRequestPool::return_request(this);
|
||||
// return;
|
||||
//}
|
||||
|
||||
if (http_parser->isKeepAlive()) {
|
||||
response->addHeadValue("Connection", "Keep-Alive");
|
||||
|
||||
std::string result = response->getResult();
|
||||
|
||||
session->send(result.c_str(), result.size());
|
||||
} else {
|
||||
response->addHeadValue("Connection", "Close");
|
||||
|
||||
std::string result = response->getResult();
|
||||
|
||||
HttpSession::Ptr lsession = session;
|
||||
|
||||
session->send(result.c_str(), result.size(), [lsession]() { lsession->postShutdown(); });
|
||||
}
|
||||
|
||||
DRequestPool::return_request(this);
|
||||
}
|
||||
|
||||
void DRequest::send_file(const std::string &p_file_path) {
|
||||
//if (connection_closed) {
|
||||
// DRequestPool::return_request(this);
|
||||
// return;
|
||||
//}
|
||||
|
||||
file_path = p_file_path;
|
||||
|
||||
FILE *f = fopen(file_path.c_str(), "rb");
|
||||
|
||||
if (!f) {
|
||||
printf("send_file: Error: Download: file doesn't exists! %s\n", file_path.c_str());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
file_size = ftell(f);
|
||||
fclose(f);
|
||||
|
||||
response->addHeadValue("Connection", "Close");
|
||||
std::string result = "HTTP/1.1 200 OK\r\nConnection: Close\r\n\r\n";
|
||||
|
||||
application->register_request_update(this);
|
||||
|
||||
session->send(result.c_str(), result.size(), [this]() { this->_file_chunk_sent(); });
|
||||
}
|
||||
|
||||
void DRequest::send_error(int error_code) {
|
||||
application->send_error(error_code, this);
|
||||
}
|
||||
|
||||
void DRequest::reset() {
|
||||
application = nullptr;
|
||||
http_parser = nullptr;
|
||||
session = nullptr;
|
||||
current_middleware_index = 0;
|
||||
middleware_stack = nullptr;
|
||||
_path_stack.clear();
|
||||
_path_stack_pointer = 0;
|
||||
file_size = 0;
|
||||
current_file_progress = 0;
|
||||
connection_closed = false;
|
||||
|
||||
head.clear();
|
||||
body.clear();
|
||||
footer.clear();
|
||||
compiled_body.clear();
|
||||
|
||||
if (response)
|
||||
delete response;
|
||||
|
||||
response = new HttpResponse();
|
||||
}
|
||||
|
||||
void DRequest::setup_url_stack() {
|
||||
std::string path = http_parser->getPath();
|
||||
|
||||
size_t pos = 0;
|
||||
std::string st;
|
||||
while ((pos = path.find("/")) != std::string::npos) {
|
||||
st = path.substr(0, pos);
|
||||
|
||||
if (st.size() != 0)
|
||||
_path_stack.push_back(st);
|
||||
|
||||
path.erase(0, pos + 1);
|
||||
}
|
||||
|
||||
if (path.size() != 0)
|
||||
_path_stack.push_back(path);
|
||||
}
|
||||
|
||||
std::string DRequest::get_path() const {
|
||||
std::string path = "";
|
||||
|
||||
for (uint32_t i = _path_stack_pointer; i < _path_stack.size(); ++i) {
|
||||
path += _path_stack[i];
|
||||
path += "/";
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
const std::string &DRequest::get_path_full() const {
|
||||
return http_parser->getPath();
|
||||
}
|
||||
|
||||
const std::string &DRequest::get_path_segment(const uint32_t i) const {
|
||||
return _path_stack[i];
|
||||
}
|
||||
|
||||
const std::string &DRequest::get_current_path_segment() const {
|
||||
if (_path_stack_pointer >= _path_stack.size()) {
|
||||
//for convenience
|
||||
static const std::string e_str = "";
|
||||
return e_str;
|
||||
}
|
||||
|
||||
return _path_stack[_path_stack_pointer];
|
||||
}
|
||||
|
||||
uint32_t DRequest::get_path_segment_count() const {
|
||||
return _path_stack.size();
|
||||
}
|
||||
|
||||
uint32_t DRequest::get_current_segment_index() const {
|
||||
return _path_stack_pointer;
|
||||
}
|
||||
|
||||
uint32_t DRequest::get_remaining_segment_count() const {
|
||||
if (_path_stack_pointer > _path_stack.size()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _path_stack.size() - _path_stack_pointer;
|
||||
}
|
||||
|
||||
void DRequest::pop_path() {
|
||||
_path_stack_pointer -= 1;
|
||||
}
|
||||
|
||||
void DRequest::push_path() {
|
||||
_path_stack_pointer += 1;
|
||||
}
|
||||
|
||||
void DRequest::update() {
|
||||
if (file_next) {
|
||||
file_next = false;
|
||||
_progress_send_file();
|
||||
}
|
||||
}
|
||||
|
||||
DRequest::DRequest() {
|
||||
response = nullptr;
|
||||
|
||||
//This value will need benchmarks, 2 MB seems to be just as fast for me as 4 MB, but 1MB is slower
|
||||
//It is a tradeoff on server memory though, as every active download will consume this amount of memory
|
||||
//where the file is bigger than this number
|
||||
file_chunk_size = 1 << 21; //2MB
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
DRequest::~DRequest() {
|
||||
delete response;
|
||||
}
|
||||
|
||||
void DRequest::_progress_send_file() {
|
||||
if (connection_closed) {
|
||||
DRequestPool::return_request(this);
|
||||
return;
|
||||
}
|
||||
|
||||
if (current_file_progress >= file_size) {
|
||||
session->postShutdown();
|
||||
|
||||
DRequestPool::return_request(this);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
FILE *f = fopen(file_path.c_str(), "rb");
|
||||
|
||||
if (!f) {
|
||||
printf("Error: Download: In progress file doesn't exists anymore! %s\n", file_path.c_str());
|
||||
|
||||
application->unregister_request_update(this);
|
||||
|
||||
session->postShutdown();
|
||||
|
||||
DRequestPool::return_request(this);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
fseek(f, current_file_progress, SEEK_SET);
|
||||
|
||||
long nfp = current_file_progress + file_chunk_size;
|
||||
|
||||
long csize = file_chunk_size;
|
||||
if (nfp >= file_size) {
|
||||
csize = (file_size - current_file_progress);
|
||||
}
|
||||
|
||||
body.resize(csize);
|
||||
|
||||
fread(&body[0], 1, csize, f);
|
||||
fclose(f);
|
||||
|
||||
current_file_progress = nfp;
|
||||
|
||||
session->send(body.c_str(), body.size(), [this]() { this->_file_chunk_sent(); });
|
||||
}
|
||||
|
||||
void DRequest::_file_chunk_sent() {
|
||||
file_next = true;
|
||||
}
|
||||
|
||||
DRequest *DRequestPool::get_request() {
|
||||
_mutex.lock();
|
||||
|
||||
DRequest *request;
|
||||
|
||||
if (_requests.size() == 0) {
|
||||
_mutex.unlock();
|
||||
|
||||
request = new DRequest();
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
request = _requests[_requests.size() - 1];
|
||||
_requests.pop_back();
|
||||
|
||||
_mutex.unlock();
|
||||
|
||||
request->reset();
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
void DRequestPool::return_request(DRequest *request) {
|
||||
_mutex.lock();
|
||||
_requests.push_back(request);
|
||||
_mutex.unlock();
|
||||
}
|
||||
|
||||
DRequestPool::DRequestPool() {
|
||||
}
|
||||
|
||||
DRequestPool::~DRequestPool() {
|
||||
for (uint32_t i = 0; i < _requests.size(); ++i) {
|
||||
delete _requests[i];
|
||||
}
|
||||
|
||||
_requests.clear();
|
||||
}
|
||||
|
||||
std::mutex DRequestPool::_mutex;
|
||||
std::vector<DRequest *> DRequestPool::_requests;
|
83
modules/drogon/request.h
Normal file
83
modules/drogon/request.h
Normal file
@ -0,0 +1,83 @@
|
||||
#ifndef DREQUEST_H
|
||||
#define REQUEST_H
|
||||
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#include <brynet/net/http/HttpFormat.hpp>
|
||||
#include <brynet/net/http/HttpService.hpp>
|
||||
|
||||
#include "handler_instance.h"
|
||||
|
||||
class DWebApplication;
|
||||
|
||||
class DRequest {
|
||||
public:
|
||||
HTTPParser::Ptr http_parser;
|
||||
HttpSession::Ptr session;
|
||||
HttpResponse *response;
|
||||
DWebApplication *application;
|
||||
|
||||
uint32_t current_middleware_index;
|
||||
DHandlerInstance handler_instance;
|
||||
std::vector<DHandlerInstance> *middleware_stack;
|
||||
|
||||
std::string head;
|
||||
std::string body;
|
||||
std::string footer;
|
||||
std::string compiled_body;
|
||||
|
||||
std::string file_path;
|
||||
long file_size;
|
||||
long current_file_progress;
|
||||
long file_chunk_size;
|
||||
bool file_next;
|
||||
|
||||
bool connection_closed;
|
||||
|
||||
void compile_body();
|
||||
void compile_and_send_body();
|
||||
void next_stage();
|
||||
void send();
|
||||
void send_file(const std::string &p_file_path);
|
||||
void send_error(int error_code);
|
||||
void reset();
|
||||
|
||||
void setup_url_stack();
|
||||
std::string get_path() const;
|
||||
const std::string &get_path_full() const;
|
||||
const std::string &get_path_segment(const uint32_t i) const;
|
||||
const std::string &get_current_path_segment() const;
|
||||
uint32_t get_path_segment_count() const;
|
||||
uint32_t get_current_segment_index() const;
|
||||
uint32_t get_remaining_segment_count() const;
|
||||
void pop_path();
|
||||
void push_path();
|
||||
|
||||
void update();
|
||||
|
||||
DRequest();
|
||||
~DRequest();
|
||||
|
||||
protected:
|
||||
void _progress_send_file();
|
||||
void _file_chunk_sent();
|
||||
|
||||
std::vector<std::string> _path_stack;
|
||||
uint32_t _path_stack_pointer;
|
||||
};
|
||||
|
||||
class DRequestPool {
|
||||
public:
|
||||
static DRequest *get_request();
|
||||
static void return_request(DRequest *request);
|
||||
|
||||
DRequestPool();
|
||||
~DRequestPool();
|
||||
|
||||
protected:
|
||||
static std::mutex _mutex;
|
||||
static std::vector<DRequest *> _requests;
|
||||
};
|
||||
|
||||
#endif
|
140
modules/drogon/web_application.cpp
Normal file
140
modules/drogon/web_application.cpp
Normal file
@ -0,0 +1,140 @@
|
||||
#include "web_application.h"
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
#include "request.h"
|
||||
|
||||
#include "core/file_cache.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void DWebApplication::load_settings() {
|
||||
}
|
||||
|
||||
void DWebApplication::setup_routes() {
|
||||
default_error_handler_func = DWebApplication::default_fallback_error_handler;
|
||||
|
||||
error_handler_map[404] = DWebApplication::default_404_error_handler;
|
||||
}
|
||||
|
||||
void DWebApplication::setup_middleware() {
|
||||
middlewares.push_back(DHandlerInstance([this](Object *instance, DRequest *request){ this->default_routing_middleware(instance, request); }));
|
||||
}
|
||||
|
||||
void DWebApplication::default_routing_middleware(Object *instance, DRequest *request) {
|
||||
std::string path = request->http_parser->getPath();
|
||||
|
||||
if (FileCache::get_singleton()->wwwroot_has_file(path)) {
|
||||
send_file(path, request);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
DHandlerInstance handler_data;
|
||||
|
||||
//std::function<void(Object *, Request *)> func;
|
||||
|
||||
//if (path == "/") {
|
||||
if (request->get_path_segment_count() == 0) {
|
||||
//quick shortcut
|
||||
handler_data = index_func;
|
||||
} else {
|
||||
const std::string main_route = request->get_current_path_segment();
|
||||
|
||||
handler_data = main_route_map[main_route];
|
||||
|
||||
request->push_path();
|
||||
}
|
||||
|
||||
if (!handler_data.handler_func) {
|
||||
send_error(404, request);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
request->handler_instance = handler_data;
|
||||
request->next_stage();
|
||||
}
|
||||
|
||||
void DWebApplication::default_fallback_error_handler(int error_code, DRequest *request) {
|
||||
request->response->setBody(default_generic_error_body);
|
||||
request->send();
|
||||
}
|
||||
|
||||
void DWebApplication::default_404_error_handler(int error_code, DRequest *request) {
|
||||
request->response->setBody(default_error_404_body);
|
||||
request->send();
|
||||
}
|
||||
|
||||
void DWebApplication::handle_request(DRequest *request) {
|
||||
request->middleware_stack = &middlewares;
|
||||
|
||||
//note that middlewares handle the routing -> DWebApplication::default_routing_middleware by default
|
||||
request->next_stage();
|
||||
}
|
||||
|
||||
void DWebApplication::send_error(int error_code, DRequest *request) {
|
||||
std::function<void(int, DRequest *)> func = error_handler_map[error_code];
|
||||
|
||||
if (!func) {
|
||||
default_error_handler_func(error_code, request);
|
||||
return;
|
||||
}
|
||||
|
||||
func(error_code, request);
|
||||
}
|
||||
|
||||
void DWebApplication::send_file(const std::string &path, DRequest *request) {
|
||||
std::string fp = FileCache::get_singleton()->wwwroot + path;
|
||||
|
||||
request->send_file(fp);
|
||||
}
|
||||
|
||||
void DWebApplication::migrate() {
|
||||
}
|
||||
|
||||
void DWebApplication::register_request_update(DRequest *request) {
|
||||
std::lock_guard<std::mutex> lock(_update_registered_requests_mutex);
|
||||
|
||||
_update_registered_requests.push_back(request);
|
||||
}
|
||||
void DWebApplication::unregister_request_update(DRequest *request) {
|
||||
std::lock_guard<std::mutex> lock(_update_registered_requests_mutex);
|
||||
|
||||
std::size_t s = _update_registered_requests.size();
|
||||
for (std::size_t i = 0; i < s; ++i) {
|
||||
DRequest *r = _update_registered_requests[i];
|
||||
|
||||
if (r == request) {
|
||||
_update_registered_requests[i] = _update_registered_requests[s - 1];
|
||||
|
||||
_update_registered_requests.pop_back();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DWebApplication::update() {
|
||||
for (std::size_t i = 0; i < _update_registered_requests.size(); ++i) {
|
||||
DRequest *r = _update_registered_requests[i];
|
||||
|
||||
r->update();
|
||||
}
|
||||
}
|
||||
|
||||
DWebApplication::DWebApplication() {
|
||||
}
|
||||
|
||||
DWebApplication::~DWebApplication() {
|
||||
main_route_map.clear();
|
||||
error_handler_map.clear();
|
||||
middlewares.clear();
|
||||
}
|
||||
|
||||
std::string DWebApplication::default_error_404_body = "<html><body>404 :(</body></html>";
|
||||
std::string DWebApplication::default_generic_error_body = "<html><body>Internal server error! :(</body></html>";
|
56
modules/drogon/web_application.h
Normal file
56
modules/drogon/web_application.h
Normal file
@ -0,0 +1,56 @@
|
||||
#ifndef DWEB_APPLICATION_H
|
||||
#define WEB_APPLICATION_H
|
||||
|
||||
#include "core/object.h"
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include "handler_instance.h"
|
||||
|
||||
class DRequest;
|
||||
|
||||
class DWebApplication {
|
||||
public:
|
||||
static std::string default_error_404_body;
|
||||
static std::string default_generic_error_body;
|
||||
|
||||
void handle_request(DRequest *request);
|
||||
void send_error(int error_code, DRequest *request);
|
||||
void send_file(const std::string &path, DRequest *request);
|
||||
|
||||
static void default_fallback_error_handler(int error_code, DRequest *request);
|
||||
static void default_404_error_handler(int error_code, DRequest *request);
|
||||
|
||||
virtual void load_settings();
|
||||
virtual void setup_routes();
|
||||
virtual void setup_middleware();
|
||||
|
||||
void default_routing_middleware(Object *instance, DRequest *request);
|
||||
|
||||
virtual void migrate();
|
||||
|
||||
void register_request_update(DRequest *request);
|
||||
void unregister_request_update(DRequest *request);
|
||||
void update();
|
||||
|
||||
DWebApplication();
|
||||
virtual ~DWebApplication();
|
||||
|
||||
public:
|
||||
DHandlerInstance index_func;
|
||||
std::map<std::string, DHandlerInstance> main_route_map;
|
||||
std::vector<DHandlerInstance> middlewares;
|
||||
|
||||
std::map<int, std::function<void(int, DRequest *)> > error_handler_map;
|
||||
std::function<void(int, DRequest *)> default_error_handler_func;
|
||||
|
||||
protected:
|
||||
std::mutex _update_registered_requests_mutex;
|
||||
std::vector<DRequest *> _update_registered_requests;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user