Commit 20cb334d authored by octal's avatar octal

Improved client API

parent e673be32
...@@ -10,37 +10,35 @@ ...@@ -10,37 +10,35 @@
#include <atomic> #include <atomic>
using namespace Net; using namespace Net;
using namespace Net::Http;
int main(int argc, char *argv[]) {
if (argc < 2) {
std::cerr << "Usage: http_client host [page]" << std::endl;
return 1;
}
std::string host = argv[1];
std::string page;
if (argc == 3)
page = argv[2];
else
page = "/";
Experimental::Client client(host);
int main() {
Http::Experimental::Client client("http://supnetwork.org:9080");
auto opts = Http::Experimental::Client::options() auto opts = Http::Experimental::Client::options()
.threads(1) .threads(1)
.maxConnections(64); .maxConnections(64);
client.init(opts);
auto resp = client.get(page).cookie(Cookie("FOO", "bar")).send();
using namespace Net::Http; resp.then([](Response response) {
std::cout << "Response code = " << response.code() << std::endl;
std::cout << "Response body = " << response.body() << std::endl;
}, Async::NoExcept);
constexpr size_t Requests = 10000; std::this_thread::sleep_for(std::chrono::seconds(1));
std::atomic<int> responsesReceived(0);
client.init(opts);
for (int i = 0; i < Requests; ++i) {
client.get(client
.request("/ping")
.cookie(Cookie("FOO", "bar")))
.then([&](const Http::Response& response) {
responsesReceived.fetch_add(1);
//std::cout << "code = " << response.code() << std::endl;
//std::cout << "body = " << response.body() << std::endl;
}, Async::NoExcept);
const auto count = i + 1;
if (count % 10 == 0)
std::cout << "Sent " << count << " requests" << std::endl;
}
for (;;) {
std::this_thread::sleep_for(std::chrono::seconds(1));
auto count = responsesReceived.load();
std::cout << "Received " << count << " responses" << std::endl;
if (count == Requests) break;
}
client.shutdown(); client.shutdown();
} }
...@@ -240,9 +240,51 @@ namespace Default { ...@@ -240,9 +240,51 @@ namespace Default {
constexpr bool KeepAlive = true; constexpr bool KeepAlive = true;
} }
class Client;
class RequestBuilder {
public:
friend class Client;
RequestBuilder& method(Method method);
RequestBuilder& resource(std::string val);
RequestBuilder& params(const Uri::Query& query);
RequestBuilder& header(const std::shared_ptr<Header::Header>& header);
template<typename H, typename... Args>
typename
std::enable_if<
Header::IsHeader<H>::value, RequestBuilder&
>::type
header(Args&& ...args) {
return header(std::make_shared<H>(std::forward<Args>(args)...));
}
RequestBuilder& cookie(const Cookie& cookie);
RequestBuilder& body(std::string val);
RequestBuilder& timeout(std::chrono::milliseconds value);
Async::Promise<Response> send();
private:
RequestBuilder(Client* const client)
: client_(client)
, timeout_(std::chrono::milliseconds(0))
{ }
Client* const client_;
Request request_;
std::chrono::milliseconds timeout_;
};
class Client { class Client {
public: public:
friend class RequestBuilder;
struct Options { struct Options {
friend class Client; friend class Client;
...@@ -267,20 +309,10 @@ public: ...@@ -267,20 +309,10 @@ public:
static Options options(); static Options options();
void init(const Options& options); void init(const Options& options);
RequestBuilder request(std::string resource); RequestBuilder get(std::string resource);
RequestBuilder post(std::string resource);
Async::Promise<Response> get( RequestBuilder put(std::string resource);
const Http::Request& request, RequestBuilder del(std::string resource);
std::chrono::milliseconds timeout = std::chrono::milliseconds(0));
Async::Promise<Response> post(
const Http::Request& req,
std::chrono::milliseconds timeout = std::chrono::milliseconds(0));
Async::Promise<Response> put(
const Http::Request& req,
std::chrono::milliseconds timeout = std::chrono::milliseconds(0));
Async::Promise<Response> del(
const Http::Request& req,
std::chrono::milliseconds timeout = std::chrono::milliseconds(0));
void shutdown(); void shutdown();
...@@ -297,9 +329,10 @@ private: ...@@ -297,9 +329,10 @@ private:
std::atomic<uint64_t> ioIndex; std::atomic<uint64_t> ioIndex;
Queue<Connection::RequestData> requestsQueue; Queue<Connection::RequestData> requestsQueue;
RequestBuilder prepareRequest(std::string resource, Http::Method method);
Async::Promise<Response> doRequest( Async::Promise<Response> doRequest(
const Http::Request& req, Http::Request req,
Http::Method method,
std::chrono::milliseconds timeout); std::chrono::milliseconds timeout);
void processRequestQueue(); void processRequestQueue();
......
...@@ -37,6 +37,7 @@ namespace Private { ...@@ -37,6 +37,7 @@ namespace Private {
namespace Experimental { namespace Experimental {
class Client; class Client;
class RequestBuilder;
} }
template< class CharT, class Traits> template< class CharT, class Traits>
...@@ -93,7 +94,6 @@ namespace Uri { ...@@ -93,7 +94,6 @@ namespace Uri {
}; };
} // namespace Uri } // namespace Uri
class RequestBuilder;
// 5. Request // 5. Request
class Request : public Message { class Request : public Message {
...@@ -101,7 +101,7 @@ public: ...@@ -101,7 +101,7 @@ public:
friend class Private::RequestLineStep; friend class Private::RequestLineStep;
friend class Private::Parser<Http::Request>; friend class Private::Parser<Http::Request>;
friend class RequestBuilder; friend class Experimental::RequestBuilder;
// @Todo: try to remove the need for friend-ness here // @Todo: try to remove the need for friend-ness here
friend class Experimental::Client; friend class Experimental::Client;
...@@ -155,32 +155,6 @@ private: ...@@ -155,32 +155,6 @@ private:
#endif #endif
}; };
class RequestBuilder {
public:
RequestBuilder& method(Method method);
RequestBuilder& resource(std::string val);
RequestBuilder& params(const Uri::Query& query);
RequestBuilder& header(const std::shared_ptr<Header::Header>& header);
template<typename H, typename... Args>
typename
std::enable_if<
Header::IsHeader<H>::value, RequestBuilder&
>::type
header(Args&& ...args) {
return header(std::make_shared<H>(std::forward<Args>(args)...));
}
RequestBuilder& cookie(const Cookie& cookie);
RequestBuilder& body(std::string val);
const Request& request() const { return request_; }
operator Request() const { return request_; }
private:
Request request_;
};
class Handler; class Handler;
class ResponseWriter; class ResponseWriter;
......
...@@ -570,6 +570,47 @@ ConnectionPool::availableCount() const { ...@@ -570,6 +570,47 @@ ConnectionPool::availableCount() const {
return connections.size() - usedCount.load(); return connections.size() - usedCount.load();
} }
RequestBuilder&
RequestBuilder::method(Method method)
{
request_.method_ = method;
return *this;
}
RequestBuilder&
RequestBuilder::resource(std::string val) {
request_.resource_ = std::move(val);
return *this;
}
RequestBuilder&
RequestBuilder::params(const Uri::Query& params) {
request_.query_ = params;
return *this;
}
RequestBuilder&
RequestBuilder::header(const std::shared_ptr<Header::Header>& header) {
request_.headers_.add(header);
return *this;
}
RequestBuilder&
RequestBuilder::cookie(const Cookie& cookie) {
request_.cookies_.add(cookie);
return *this;
}
RequestBuilder&
RequestBuilder::body(std::string val) {
request_.body_ = std::move(val);
}
Async::Promise<Response>
RequestBuilder::send() {
return client_->doRequest(std::move(request_), timeout_);
}
Client::Options& Client::Options&
Client::Options::threads(int val) { Client::Options::threads(int val) {
if (val > 1) { if (val > 1) {
...@@ -642,47 +683,46 @@ Client::shutdown() { ...@@ -642,47 +683,46 @@ Client::shutdown() {
} }
RequestBuilder RequestBuilder
Client::request(std::string val) { Client::get(std::string resource)
RequestBuilder builder; {
builder.resource(std::move(val)); return prepareRequest(std::move(resource), Http::Method::Get);
return builder;
} }
Async::Promise<Http::Response> RequestBuilder
Client::get(const Http::Request& request, std::chrono::milliseconds timeout) Client::post(std::string resource)
{ {
return doRequest(request, Http::Method::Get, timeout); return prepareRequest(std::move(resource), Http::Method::Post);
} }
Async::Promise<Http::Response> RequestBuilder
Client::post(const Http::Request& request, std::chrono::milliseconds timeout) Client::put(std::string resource)
{ {
return doRequest(request, Http::Method::Post, timeout); return prepareRequest(std::move(resource), Http::Method::Put);
} }
Async::Promise<Http::Response> RequestBuilder
Client::put(const Http::Request& request, std::chrono::milliseconds timeout) Client::del(std::string resource)
{ {
return doRequest(request, Http::Method::Put, timeout); return prepareRequest(std::move(resource), Http::Method::Delete);
} }
Async::Promise<Http::Response> RequestBuilder
Client::del(const Http::Request& request, std::chrono::milliseconds timeout) Client::prepareRequest(std::string resource, Http::Method method)
{ {
return doRequest(request, Http::Method::Delete, timeout); RequestBuilder builder(this);
builder
.resource(std::move(resource))
.method(method);
return builder;
} }
Async::Promise<Response> Async::Promise<Response>
Client::doRequest( Client::doRequest(
const Http::Request& request, Http::Request request,
Http::Method method,
std::chrono::milliseconds timeout) std::chrono::milliseconds timeout)
{ {
unsafe { request.headers_.remove<Header::UserAgent>();
auto &req = const_cast<Http::Request &>(request);
req.method_ = method;
req.headers_.remove<Header::UserAgent>();
}
auto conn = pool.pickConnection(); auto conn = pool.pickConnection();
if (conn == nullptr) { if (conn == nullptr) {
......
...@@ -559,41 +559,6 @@ Request::peer() const { ...@@ -559,41 +559,6 @@ Request::peer() const {
} }
#endif #endif
RequestBuilder&
RequestBuilder::method(Method method)
{
request_.method_ = method;
return *this;
}
RequestBuilder&
RequestBuilder::resource(std::string val) {
request_.resource_ = std::move(val);
return *this;
}
RequestBuilder&
RequestBuilder::params(const Uri::Query& params) {
request_.query_ = params;
return *this;
}
RequestBuilder&
RequestBuilder::header(const std::shared_ptr<Header::Header>& header) {
request_.headers_.add(header);
return *this;
}
RequestBuilder&
RequestBuilder::cookie(const Cookie& cookie) {
request_.cookies_.add(cookie);
return *this;
}
RequestBuilder&
RequestBuilder::body(std::string val) {
request_.body_ = std::move(val);
}
ResponseStream::ResponseStream( ResponseStream::ResponseStream(
Message&& other, Message&& other,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment