Server API rework.
parent
a65294aeec
commit
a3cab444dc
@ -0,0 +1,39 @@
|
||||
// A general HTTP server serving static files.
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "webcc/logger.h"
|
||||
#include "webcc/server.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void Help(const char* argv0) {
|
||||
std::cout << "Usage: " << argv0 << " <port> <doc_root>" << std::endl;
|
||||
std::cout << " E.g.," << std::endl;
|
||||
std::cout << " " << argv0 << " 8080 D:/www" << std::endl;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc < 3) {
|
||||
Help(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
WEBCC_LOG_INIT("", webcc::LOG_CONSOLE);
|
||||
|
||||
std::uint16_t port = static_cast<std::uint16_t>(std::atoi(argv[1]));
|
||||
std::string doc_root = argv[2];
|
||||
|
||||
try {
|
||||
webcc::Server server(port, 1, doc_root);
|
||||
|
||||
server.Run();
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
#include "webcc/service.h"
|
||||
|
||||
#include "webcc/logger.h"
|
||||
|
||||
namespace webcc {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
ResponsePtr ListService::Handle(RequestPtr request, const UrlArgs& args) {
|
||||
if (request->method() == methods::kGet) {
|
||||
return Get(UrlQuery(request->url().query()));
|
||||
}
|
||||
|
||||
if (request->method() == methods::kPost) {
|
||||
return Post(request);
|
||||
}
|
||||
|
||||
return ResponsePtr();
|
||||
}
|
||||
|
||||
ResponsePtr ListService::Get(const UrlQuery& query) {
|
||||
return ResponsePtr();
|
||||
}
|
||||
|
||||
ResponsePtr ListService::Post(RequestPtr request) {
|
||||
return ResponsePtr();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
ResponsePtr DetailService::Handle(RequestPtr request, const UrlArgs& args) {
|
||||
if (request->method() == methods::kGet) {
|
||||
return Get(args, UrlQuery(request->url().query()));
|
||||
}
|
||||
|
||||
if (request->method() == methods::kPut) {
|
||||
return Put(request, args);
|
||||
}
|
||||
|
||||
if (request->method() == methods::kPatch) {
|
||||
return Patch(request, args);
|
||||
}
|
||||
|
||||
if (request->method() == methods::kDelete) {
|
||||
return Delete(args);
|
||||
}
|
||||
|
||||
return ResponsePtr();
|
||||
}
|
||||
|
||||
ResponsePtr DetailService::Get(const UrlArgs& args, const UrlQuery& query) {
|
||||
return ResponsePtr();
|
||||
}
|
||||
|
||||
ResponsePtr DetailService::Put(RequestPtr request, const UrlArgs& args) {
|
||||
return ResponsePtr();
|
||||
}
|
||||
|
||||
ResponsePtr DetailService::Patch(RequestPtr request, const UrlArgs& args) {
|
||||
return ResponsePtr();
|
||||
}
|
||||
|
||||
ResponsePtr DetailService::Delete(const UrlArgs& args) {
|
||||
return ResponsePtr();
|
||||
}
|
||||
|
||||
} // namespace webcc
|
@ -1,73 +0,0 @@
|
||||
#ifndef WEBCC_SERVICE_H_
|
||||
#define WEBCC_SERVICE_H_
|
||||
|
||||
// NOTE:
|
||||
// The design of RestListService and RestDetailService is very similar to
|
||||
// XxxListView and XxxDetailView in Python Django Rest Framework.
|
||||
// Deriving from them instead of RestService can simplify your own REST services
|
||||
// a lot. But if you find the filtered parameters cannot meet your needs, feel
|
||||
// free to derive from RestService directly.
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "webcc/globals.h"
|
||||
#include "webcc/request.h"
|
||||
#include "webcc/response.h"
|
||||
#include "webcc/response_builder.h"
|
||||
#include "webcc/url.h"
|
||||
|
||||
namespace webcc {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Regex sub-matches of the URL (usually resource ID's).
|
||||
// Could also be considered as arguments, so named as UrlArgs.
|
||||
using UrlArgs = std::vector<std::string>;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Base class for your service.
|
||||
class Service {
|
||||
public:
|
||||
virtual ~Service() = default;
|
||||
|
||||
// Handle request, return response.
|
||||
virtual ResponsePtr Handle(RequestPtr request, const UrlArgs& args) = 0;
|
||||
};
|
||||
|
||||
using ServicePtr = std::shared_ptr<Service>;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
class ListService : public Service {
|
||||
public:
|
||||
ResponsePtr Handle(RequestPtr request, const UrlArgs& args) override;
|
||||
|
||||
protected:
|
||||
virtual ResponsePtr Get(const UrlQuery& query);
|
||||
|
||||
virtual ResponsePtr Post(RequestPtr request);
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
class DetailService : public Service {
|
||||
public:
|
||||
ResponsePtr Handle(RequestPtr request, const UrlArgs& args) override;
|
||||
|
||||
protected:
|
||||
virtual ResponsePtr Get(const UrlArgs& args, const UrlQuery& query);
|
||||
|
||||
virtual ResponsePtr Put(RequestPtr request, const UrlArgs& args);
|
||||
|
||||
virtual ResponsePtr Patch(RequestPtr request, const UrlArgs& args);
|
||||
|
||||
virtual ResponsePtr Delete(const UrlArgs& args);
|
||||
};
|
||||
|
||||
} // namespace webcc
|
||||
|
||||
#endif // WEBCC_SERVICE_H_
|
@ -1,59 +0,0 @@
|
||||
#include "webcc/service_manager.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "webcc/logger.h"
|
||||
|
||||
namespace webcc {
|
||||
|
||||
bool ServiceManager::Add(ServicePtr service, const std::string& url,
|
||||
bool is_regex) {
|
||||
assert(service);
|
||||
|
||||
Item item(service, url, is_regex);
|
||||
|
||||
if (!is_regex) {
|
||||
items_.push_back(std::move(item));
|
||||
return true;
|
||||
}
|
||||
|
||||
std::regex::flag_type flags = std::regex::ECMAScript | std::regex::icase;
|
||||
|
||||
try {
|
||||
// Compile the regex.
|
||||
item.url_regex.assign(url, flags);
|
||||
items_.push_back(std::move(item));
|
||||
return true;
|
||||
} catch (const std::regex_error& e) {
|
||||
LOG_ERRO("URL is not a valid regular expression: %s", e.what());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ServicePtr ServiceManager::Get(const std::string& url, UrlArgs* args) {
|
||||
assert(args != nullptr);
|
||||
|
||||
for (Item& item : items_) {
|
||||
if (item.is_regex) {
|
||||
std::smatch match;
|
||||
|
||||
if (std::regex_match(url, match, item.url_regex)) {
|
||||
// Any sub-matches?
|
||||
// NOTE: Start from 1 because match[0] is the whole string itself.
|
||||
for (size_t i = 1; i < match.size(); ++i) {
|
||||
args->push_back(match[i].str());
|
||||
}
|
||||
|
||||
return item.service;
|
||||
}
|
||||
} else {
|
||||
if (item.url == url) {
|
||||
return item.service;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ServicePtr();
|
||||
}
|
||||
|
||||
} // namespace webcc
|
@ -1,66 +0,0 @@
|
||||
#ifndef WEBCC_SERVICE_MANAGER_H_
|
||||
#define WEBCC_SERVICE_MANAGER_H_
|
||||
|
||||
#include <regex> // NOLINT
|
||||
#include <string>
|
||||
#include <utility> // for move()
|
||||
#include <vector>
|
||||
|
||||
#include "webcc/service.h"
|
||||
|
||||
namespace webcc {
|
||||
|
||||
class ServiceManager {
|
||||
public:
|
||||
ServiceManager() = default;
|
||||
|
||||
ServiceManager(const ServiceManager&) = delete;
|
||||
ServiceManager& operator=(const ServiceManager&) = delete;
|
||||
|
||||
// Add a service and bind it with the given URL.
|
||||
// The |url| should start with "/" and will be treated as a regular expression
|
||||
// if |regex| is true.
|
||||
// Examples: "/instances", "/instances/(\\d+)".
|
||||
bool Add(ServicePtr service, const std::string& url, bool is_regex);
|
||||
|
||||
// The |matches| is only available when the |url| bound to the service is a
|
||||
// regular expression and has sub-expressions.
|
||||
// E.g., the URL bound to the service is "/instances/(\\d+)", now match
|
||||
// "/instances/12345" against it, you will get one match of "12345".
|
||||
ServicePtr Get(const std::string& url, UrlArgs* args);
|
||||
|
||||
private:
|
||||
class Item {
|
||||
public:
|
||||
Item(ServicePtr _service, const std::string& _url, bool _is_regex)
|
||||
: service(_service), url(_url), is_regex(_is_regex) {
|
||||
}
|
||||
|
||||
Item(const Item&) = default;
|
||||
Item& operator=(const Item&) = default;
|
||||
|
||||
Item(Item&& rhs)
|
||||
: service(rhs.service),
|
||||
url(std::move(rhs.url)),
|
||||
is_regex(rhs.is_regex),
|
||||
url_regex(std::move(rhs.url_regex)) {
|
||||
}
|
||||
|
||||
ServicePtr service;
|
||||
|
||||
// URL string, e.g., "/instances/(\\d+)".
|
||||
std::string url;
|
||||
|
||||
// If the URL is a regular expression or not.
|
||||
bool is_regex;
|
||||
|
||||
// Compiled regex for URL string.
|
||||
std::regex url_regex;
|
||||
};
|
||||
|
||||
std::vector<Item> items_;
|
||||
};
|
||||
|
||||
} // namespace webcc
|
||||
|
||||
#endif // WEBCC_SERVICE_MANAGER_H_
|
@ -0,0 +1,43 @@
|
||||
#include "webcc/view.h"
|
||||
|
||||
namespace webcc {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
//ResponsePtr DetailView::Handle(RequestPtr request, const UrlArgs& args) {
|
||||
// if (request->method() == methods::kGet) {
|
||||
// return Get(args, UrlQuery(request->url().query()));
|
||||
// }
|
||||
//
|
||||
// if (request->method() == methods::kPut) {
|
||||
// return Put(request, args);
|
||||
// }
|
||||
//
|
||||
// if (request->method() == methods::kPatch) {
|
||||
// return Patch(request, args);
|
||||
// }
|
||||
//
|
||||
// if (request->method() == methods::kDelete) {
|
||||
// return Delete(args);
|
||||
// }
|
||||
//
|
||||
// return ResponsePtr();
|
||||
//}
|
||||
//
|
||||
//ResponsePtr DetailView::Get(const UrlArgs& args, const UrlQuery& query) {
|
||||
// return ResponsePtr();
|
||||
//}
|
||||
//
|
||||
//ResponsePtr DetailView::Put(RequestPtr request, const UrlArgs& args) {
|
||||
// return ResponsePtr();
|
||||
//}
|
||||
//
|
||||
//ResponsePtr DetailView::Patch(RequestPtr request, const UrlArgs& args) {
|
||||
// return ResponsePtr();
|
||||
//}
|
||||
//
|
||||
//ResponsePtr DetailView::Delete(const UrlArgs& args) {
|
||||
// return ResponsePtr();
|
||||
//}
|
||||
|
||||
} // namespace webcc
|
@ -0,0 +1,22 @@
|
||||
#ifndef WEBCC_VIEW_H_
|
||||
#define WEBCC_VIEW_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "webcc/request.h"
|
||||
#include "webcc/response.h"
|
||||
|
||||
namespace webcc {
|
||||
|
||||
class View {
|
||||
public:
|
||||
virtual ~View() = default;
|
||||
|
||||
virtual ResponsePtr Handle(RequestPtr request) = 0;
|
||||
};
|
||||
|
||||
using ViewPtr = std::shared_ptr<View>;
|
||||
|
||||
} // namespace webcc
|
||||
|
||||
#endif // WEBCC_VIEW_H_
|
Loading…
Reference in New Issue