Skip to content

Instantly share code, notes, and snippets.

@tatsuhiro-t
Created October 19, 2015 15:03
Show Gist options
  • Save tatsuhiro-t/d6c8d99ee04ceac932d6 to your computer and use it in GitHub Desktop.
Save tatsuhiro-t/d6c8d99ee04ceac932d6 to your computer and use it in GitHub Desktop.
#include <iostream>
#include <string>
#include <mutex>
#include <thread>
#include <future>
#include <deque>
#include <nghttp2/asio_http2_server.h>
using namespace nghttp2::asio_http2;
using namespace nghttp2::asio_http2::server;
struct Stream : public std::enable_shared_from_this<Stream> {
Stream(uint64_t n, const response &res, boost::asio::io_service &io_service)
: io_service(io_service), n(n), res(res), closed(false) {}
void run_request() {
std::string s;
if (n <= 1) {
s += "[]\n";
} else {
s += "[";
uint64_t i = 2;
for (;;) {
auto to = static_cast<uint64_t>(sqrt(n));
auto m = n;
for (; i <= to && n > 1; ++i) {
while (n % i == 0) {
s += std::to_string(i);
s += ", ";
n /= i;
}
}
if (n == 1) {
break;
}
if (m == n) {
s += std::to_string(n);
s += ", ";
break;
}
}
s.erase(s.size() - 2);
s += "]\n";
}
commit_result(std::move(s));
}
void commit_result(std::string s) {
auto self = shared_from_this();
auto ss = std::make_shared<std::string>(std::move(s));
io_service.post([self, ss]() {
std::lock_guard<std::mutex> lg(self->mu);
if (self->closed) {
return;
}
self->res.write_head(200);
self->res.end(std::move(*ss));
});
}
void set_closed(bool f) {
std::lock_guard<std::mutex> lg(mu);
closed = f;
}
boost::asio::io_service &io_service;
size_t n;
std::mutex mu;
const response &res;
bool closed;
};
struct Queue {
void push(std::shared_ptr<Stream> st) {
std::lock_guard<std::mutex> lg(mu);
q.push_back(st);
cv.notify_all();
}
std::shared_ptr<Stream> pop() {
std::unique_lock<std::mutex> ulk(mu);
cv.wait(ulk, [this]() { return !q.empty(); });
auto res = q.front();
q.pop_front();
return res;
}
std::mutex mu;
std::condition_variable cv;
std::deque<std::shared_ptr<Stream>> q;
};
int main(int argc, char **argv) {
http2 server;
server.num_threads(2);
Queue q;
for (int i = 0; i < 10; ++i) {
auto th = std::thread([&q]() {
for (;;) {
auto st = q.pop();
st->run_request();
}
});
th.detach();
}
server.handle("/fact/", [&q](const request &req, const response &res) {
auto &io_service = res.io_service();
auto &path = req.uri().path;
char *end;
errno = 0;
auto base = path.c_str() + sizeof("/fact/") - 1;
auto n = strtoul(base, &end, 10);
if (errno || base == end || *end || n < 2) {
res.write_head(200);
res.end("invalid input: n must be strictly greater than 1\n");
return;
}
auto st = std::make_shared<Stream>(n, res, io_service);
res.on_close([st](uint32_t error_code) { st->set_closed(true); });
q.push(st);
});
boost::system::error_code ec;
if (server.listen_and_serve(ec, "127.0.0.1", "3000")) {
std::cerr << "error: " << ec.message() << std::endl;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment