ãã®çµæãç§ãã¡ã¯èŠåãã®ããããæéã§ãããšå€æãã
#include <restinio/all.hpp> int main() { restinio::run( restinio::on_this_thread() .port(8080) .address("localhost") .request_handler([](auto req) { return req->create_response().set_body("Hello, World!").done(); })); return 0; }
RESTinioã®å®è£ ã§ã¯ãC ++ãã³ãã¬ãŒããç©æ¥µçã«äœ¿çšãããŠããŸããããã«ã€ããŠã¯ãä»æ¥å°ãã話ãããããšæããŸãã
RESTinioã«ã€ããŠã®äžè¬çãªèšè
RESTinioã¯ãBSD-3-CLAUSEã©ã€ã»ã³ã¹ã®äžã§é åžãããå°ããªãªãŒãã³ãœãŒã¹ãããžã§ã¯ãã§ãã RESTinioã¯2017幎ã®æ¥ããç©æ¥µçã«éçºãããŠããŸãã ãã®éãããã€ãã®å ¬éãªãªãŒã¹ãäœæããåŸã ã«RESTinioã«æ©èœãè¿œå ããŸããã ææ°ã®ãªãªãŒã¹ãä»æ¥è¡ãããŸããã ããã¯ãããŒãžã§ã³0.4ã®ãªãªãŒã¹ã§ããããããããå¿ èŠãªæå°éã®æ©èœãå®çŸããŸããã
RESTinioã¯ãããã€ãã®ãµãŒãããŒãã£ã³ã³ããŒãã³ãã䜿çšããŸãã ãããã¯ãŒã¯ãæäœããã«ã¯ãAsioïŒã¹ã¿ã³ãã¢ãã³ããŒãžã§ã³ã®AsioïŒã䜿çšããHTTPãããã³ã«ã®è§£æã«ã¯Node.jsã®http-parserã䜿çšããŸãã ãŸããå éšã§fmtlibã䜿çšãããã¹ãçšã«Catch2ã©ã€ãã©ãªã䜿çšããŸãã
RESTinioã¯ãŸã ããŒãžã§ã³1.0ã«éããŠããªããšããäºå®ã«ãããããããç§ãã¡ã¯RESTinioã®å質ãšå®å®æ§ã«éåžžã«æ³šæããŠããŸãã ããšãã°ãååã¯RESTinioã«åºã¥ããœãªã¥ãŒã·ã§ã³ã䜿çšããŠMail.ruã³ã³ãã¹ãHighloadCupã«åå ããŸãã ã ãã®æ±ºå®ã¯45äœãã決åã«éãã決åã§44äœã«ãªããŸããã ç§ã¯ééã£ãŠãããããããŸãããããã¡ã€ããªã¹ãã®äžã«ã¯ããŠãããŒãµã«HTTPãã¬ãŒã ã¯ãŒã¯ã«åºã¥ããŠæ§ç¯ããã2ã€ãŸãã¯3ã€ã®ãœãªã¥ãŒã·ã§ã³ãããããŸããã§ããã ãããã®1ã€ã¯RESTinioã«åºã¥ããœãªã¥ãŒã·ã§ã³ã§ããããšãå€æããŸãã ã
äžè¬ã«ãããã©ãŒãã³ã¹ã«é¢ããŠèšãã°ãREStinioã®é床ã¯éçºã®æåªå äºé ã§ã¯ãããŸããã§ããã ããã«ãããããããããã©ãŒãã³ã¹ã«æ³šæãæããŸããããããã§ãã䜿ãããããœãªã¥ãŒã·ã§ã³ãååŸããããšãããéèŠã§ããã åæã«ã åæãã³ãããŒã¯ã§ã¯RESTinioã¯ããã»ã©æªãèŠããŸãã ã
ãã ãããã®èšäºã§ã¯ãREStinioã©ã€ãã©ãªèªäœãšãã®æ©èœã«ã€ããŠã¯ããŸã觊ããŸããïŒãã®æ å ±ã®è©³çŽ°ã«ã€ããŠã¯ããã¡ããåç §ããŠãã ããïŒã C ++èšèªã®ãã®ãããªéèŠãªæ©èœããã³ãã¬ãŒããšããŠã©ã®ããã«å®è£ ããã®ãã
ãªããã¿ãŒã³ãªã®ãïŒ
RESTinioã³ãŒãã¯ãã³ãã¬ãŒãã«åºã¥ããŠããŸãã ãããã£ãŠãäžèšã®äŸã§ã¯ããã³ãã¬ãŒãã¯ã©ãã«ã§ããããŸããã衚瀺ãããŠããŸããã
- é¢æ°restinio :: runïŒïŒãã³ãã¬ãŒãå;
- é¢æ°restinio :: on_this_threadïŒïŒãã³ãã¬ãŒãå;
- request_handlerïŒïŒã¡ãœãããå®åã§ãã
- create_responseïŒïŒã¡ãœããããã³ãã¬ãŒãã§ãã
RESTinioããã³ãã¬ãŒããããã»ã©å€ã䜿çšããã®ã¯ãªãã§ããïŒ ããããæãæ·±å»ãªã®ã¯ã次ã®2ã€ã®çç±ã§ãã
ãŸããREStinioãåºãã«ã¹ã¿ãã€ãºã§ããããã«ãããã£ãã®ã§ãã ãããããã®ãããã«ã¹ã¿ãã€ãºã®å®è¡æã®ã³ã¹ãã¯æå°éã«æããããŸãã ããã§ã®ãã³ãã¬ãŒãã¯ãåã«ç«¶äºãè¶ ããŠããããã«æããŸãã
第äºã«ãç§ãã¡ã®äžã«ã¯ãã©ãããã¢ã¬ã¯ãµã³ãã¬ã¹ã¯ã«åãŸããããã§ãã ãããŠãããã¯ãŸã 圱é¿ãåãŒããŠããŸããããã以æ¥å€ãã®ããšãçµéããŠããŸãã
ãŸããç§ãã¡ã¯RESTinioã®ããªãã®éšåããã³ãã¬ãŒãã³ãŒãã§ãããšããäºå®ã®çµæãæ°ã«å ¥ããŸãããã©ã€ãã©ãªã¯ããããŒã®ã¿ã§ããããšãå€æããŸããã çŸåšã®C ++ã§ã¯ãããããŒã®ã¿ã®ã©ã€ãã©ãªãèªåã®ïŒãŸãã¯ä»ã®èª°ãã®ïŒãããžã§ã¯ãã«æ¥ç¶ããæ¹ããã³ã³ãã€ã«ããå¿ èŠããããã®ãããã¯ããã«ç°¡åã§ãã ãã®åç©åã¯ããã«ãã·ã¹ãã ãšäŸåé¢ä¿ç®¡çã·ã¹ãã ãC ++ã§æäŸããŸãã ãããŠããããã®åç©åã®ããããŒã®ã¿ã®ã©ã€ãã©ãªã¯ãã¯ããã«è¯ãæãã§ãã ã³ã³ãã€ã«æéãå¢ãããŠããã«ãéãæããªããã°ãªããªãå Žåã§ããããã¯ãã§ã«å®å šã«ç°ãªãäŒè©±ã®ãããã¯ã§ã...
ç°¡åãªäŸã§ã®ãã³ãã¬ãŒãã®ã«ã¹ã¿ãã€ãº
äžèšã§ããã³ãã¬ãŒãã䜿çšããŠRESTinioãã«ã¹ã¿ãã€ãºã§ãããšè¿°ã¹ãŸããã ããã€ãã®ç°¡åãªäŸã®æå³ã瀺ããŸãããã
ãã£ã³ã¯ãšã³ã³ãŒãã£ã³ã°ã®ã¢ãŒãã§çããåºããŸã
create_responseïŒïŒã¡ãœããã¯å®åçã§ãããšæ¢ã«è¿°ã¹ãŸããã ãã®ã¡ãœããã¯ãHTTPå¿çãçæããã¡ãœããã«ãã£ãŠãã©ã¡ãŒã¿ãŒåãããŸãã ããã©ã«ãã¯restinio_controlled_output_tã§ãã ãã®ã¡ãœããã¯ãContent-Length HTTPããããŒã®å€ãåå¥ã«èšç®ããããã°ã©ããŒãå¿çå šäœãå®å šã«äœæããŠdoneïŒïŒã¡ãœãããåŒã³åºããåŸããœã±ãããžã®å¿çã®æžã蟌ã¿ãéå§ããŸãã
ãã ããRESTINIOã¯ãuser_controlled_output_tããã³chunked_output_tã®ã¡ãœãããããã«ãµããŒãããŠããŸãã ããšãã°ãchunked_output_tã¢ãŒãã䜿çšãããšã次ã®ããã«ãªããŸãã
auto handler = [&](auto req) { auto resp = req->create_response<restinio::chunked_output_t>(); resp .append_header(restinio::http_field::server, "MyApp Embedded Server") .append_header_date_field() .append_header(restinio::http_field::content_type, "text/plain; charset=utf-8"); resp.flush(); // . for(const auto & part : fragments) { resp.append_chunk(make_chunk_from(part)); resp.flush(); // . } return resp.done(); // . };
ç¹ã«ãcreate_responseïŒïŒã¯response_builder_t <Output_Type>ãªããžã§ã¯ããè¿ããŸãããã®ãªããžã§ã¯ãã®ãããªãã¯APIã¯Output_Typeã«äŸåããŠããŸãã ãããã£ãŠãresponse_builder_t <restinio_controlled_output_t>ã«ã¯public flushïŒïŒã¡ãœããããªããresponse_builder_t <user_controlled_output_t>ã®ã¿ã«publicã¡ãœããset_content_lengthïŒïŒããããŸãã
ãã®ã³ã°ããªã³ã«ãã
èšäºã®åé ã§ãæãåçŽãªã·ã³ã°ã«ã¹ã¬ããHTTPãµãŒããŒã玹ä»ããŸããã ããã¯ããã©ãã¯ããã¯ã¹ããšããŠæ©èœãããããã°ã·ãŒã«ã蚺æãã°ã¯ãããŸããã éå§HTTPãµãŒããŒã«ãçºçãããã¹ãŠã®ã¢ã¯ã·ã§ã³ãæšæºåºåã¹ããªãŒã ã«èšé²ãããŸãããã ãããè¡ãã«ã¯ããã³ãã¬ãŒãã䜿çšããã¡ãã£ãšããããªãã¯ãå¿ èŠã§ãã
#include <restinio/all.hpp> int main() { struct my_traits : public restinio::default_single_thread_traits_t { using logger_t = restinio::single_threaded_ostream_logger_t; }; restinio::run( restinio::on_this_thread<my_traits>() .port(8080) .address("localhost") .request_handler([](auto req) { return req->create_response().set_body("Hello, World!").done(); })); return 0; }
ããã§äœãããŸãããïŒ
HTTPãµãŒããŒã«å¯ŸããŠç¬èªã®ç¹æ§ã¯ã©ã¹ãå®çŸ©ããå¿ èŠãªãã¬ãŒã®ã¿ã€ããèšå®ããŸãã 次ã«ãrestinio :: runïŒïŒå ã§HTTPãµãŒããŒãæ§ç¯ãããšãã«RESTinioã«ãã®ã¯ã©ã¹ã®ããããã£ã䜿çšããããã«åŒ·å¶ããŸããã ãã®çµæãrestino :: runïŒïŒå ã«HTTPãµãŒããŒãäœæãããsingle_threaded_ostream_logger_tåã§å®è£ ããããã¬ãŒãä»ããŠãã¹ãŠã®ã€ãã³ãããã°ã«èšé²ãããŸãã
ä¿®æ£ãããäŸãå®è¡ãããµãŒããŒã«åçŽãªèŠæ±ïŒwget localhostïŒ8080ãªã©ïŒãçºè¡ãããšã次ã®ããã«è¡šç€ºãããŸãã
[2017-12-24 12:04:29.612] TRACE: starting server on 127.0.0.1:8080 [2017-12-24 12:04:29.612] INFO: init accept #0 [2017-12-24 12:04:29.612] INFO: server started on 127.0.0.1:8080 [2017-12-24 12:05:00.423] TRACE: accept connection from 127.0.0.1:45930 on socket #0 [2017-12-24 12:05:00.423] TRACE: [connection:1] start connection with 127.0.0.1:45930 [2017-12-24 12:05:00.423] TRACE: [connection:1] start waiting for request [2017-12-24 12:05:00.423] TRACE: [connection:1] continue reading request [2017-12-24 12:05:00.423] TRACE: [connection:1] received 141 bytes [2017-12-24 12:05:00.423] TRACE: [connection:1] request received (#0): GET / [2017-12-24 12:05:00.423] TRACE: [connection:1] append response (#0), flags: { final_parts, connection_keepalive }, bufs count: 2 [2017-12-24 12:05:00.423] TRACE: [connection:1] sending resp data, buf count: 2 [2017-12-24 12:05:00.423] TRACE: [connection:1] start waiting for request [2017-12-24 12:05:00.423] TRACE: [connection:1] continue reading request [2017-12-24 12:05:00.423] TRACE: [connection:1] outgoing data was sent: 76 bytes [2017-12-24 12:05:00.423] TRACE: [connection:1] should keep alive [2017-12-24 12:05:00.423] TRACE: [connection:1] start waiting for request [2017-12-24 12:05:00.423] TRACE: [connection:1] continue reading request [2017-12-24 12:05:00.424] TRACE: [connection:1] EOF and no request, close connection [2017-12-24 12:05:00.424] TRACE: [connection:1] close [2017-12-24 12:05:00.424] TRACE: [connection:1] destructor called [2017-12-24 12:05:16.402] TRACE: closing server on 127.0.0.1:8080 [2017-12-24 12:05:16.402] INFO: server closed on 127.0.0.1:8080
ç§ãã¡ã¯äœãããŸãããïŒ å®éãHTTPãµãŒããŒã®ããããã£ã®1ã€ã®ãã©ã¡ãŒã¿ãŒãä¿®æ£ããè¿œå ã®æ©èœãåãåããŸããã HTTPãµãŒããŒã®ããã©ã«ãããããã£ã䜿çšããæåã®ã±ââãŒã¹ã§ã¯ãããã¯ãŸã£ãããããŸããã§ããã ããã«ããäžè¬ããšã¯ãæ£ç¢ºã«ãäžè¬ããæå³ããŸãã äŸã§èª¬æããŸãããã
RESTinioã³ãŒãã§ã¯ããµãŒããŒæäœã®ãã°ãæ£ãã°ã£ãŠããŸãã ããã§ãèšããŸãããïŒ
void close_impl() { const auto ep = m_acceptor.local_endpoint(); m_logger.trace( [&]{ return fmt::format( "closing server on {}", ep ); } ); m_acceptor.close(); m_logger.info( [&]{ return fmt::format( "server closed on {}", ep ); } ); }
ãã°çšã®ã¡ãã»ãŒãžãçæããã©ã ãé¢æ°ã転éãããã¬ãŒãžã®åŒã³åºãããããŸãã ãã ããrestinio :: null_logger_tããã¬ãŒãšããŠäœ¿çšãããŠããå ŽåïŒããã³ããã¯ããã©ã«ãã§çºçããŸãïŒãtraceïŒïŒãinfoïŒïŒãªã©ã®ã¡ãœããã¯null_logger_tã§äœãããŸããã
class null_logger_t { public: template< typename Message_Builder > constexpr void trace( Message_Builder && ) const {} template< typename Message_Builder > constexpr void info( Message_Builder && ) const {} template< typename Message_Builder > constexpr void warn( Message_Builder && ) const {} ...
ãããã£ãŠãéåžžã®ã³ã³ãã€ã©ã¯ãã¬ãŒãžã®ãã¹ãŠã®åŒã³åºããåã«ã¹ããŒãããã®ã³ã°çšã®ã³ãŒããçæããŸããã ã䜿çšããªã-æ¯æããªãããšããçŽç²ãªåœ¢ã
ãšã¯ã¹ãã¬ã¹ã«ãŒã¿ãŒã®æ£èŠè¡šçŸãšã³ãžã³ã®éžæ
RESTinioã«ãããšã¯ã¹ãã¬ã¹ã«ãŒã¿ãŒã䜿çšãããã³ãã¬ãŒãã«ããã«ã¹ã¿ãã€ãºã®å¥ã®äŸã瀺ããŸãã Express JavaScriptãã¬ãŒã ã¯ãŒã¯ã«åºã¥ããŠRESTinioã§äœæãããExpressã«ãŒã¿ãŒã ãšã¯ã¹ãã¬ã¹ã«ãŒã¿ãŒã䜿çšãããšãURLã䜿çšããŠé©åãªãã³ãã©ãŒãéžæããäœæ¥ãå€§å¹ ã«ç°¡çŽ åãããŸãã ç¹ã«ããã³ãã©ãŒã«å¿ èŠãªãã©ã¡ãŒã¿ãŒãURLå ã§ãä¿è·ããããŠããå Žåã
以äžã«ããšã¯ã¹ãã¬ã¹ã«ãŒã¿ãŒã䜿çšããŠã/ measure /ïŒidããã³/ measure /ïŒyear /ïŒmonth /ïŒdayã®åœ¢åŒã®GETãªã¯ãšã¹ãã®ãã³ãã©ãŒãèšå®ããæ¹æ³ã瀺ãå°ããªäŸã瀺ããŸãã
#include <restinio/all.hpp> using my_router_t = restinio::router::express_router_t<>; auto make_request_handler() { auto router = std::make_unique<my_router_t>(); router->http_get(R"(/measure/:id(\d+))", [](auto req, auto params) { return req->create_response() .set_body( fmt::format("Measure with id={} requested", restinio::cast_to<unsigned long>(params["id"]))) .done(); }); router->http_get(R"(/measures/:year(\d{4})/:month(\d{2})/:day(\d{2}))", [](auto req, auto params) { return req->create_response() .set_body( fmt::format("Request measures for a date: {}.{}.{}", restinio::cast_to<int>(params["year"]), restinio::cast_to<short>(params["month"]), restinio::cast_to<short>(params["day"]))) .done(); }); router->non_matched_request_handler([](auto req) { return req->create_response(404, "Unknown request") .connection_close() .done(); }); return router; } int main() { struct my_traits : public restinio::default_single_thread_traits_t { using request_handler_t = my_router_t; }; restinio::run( restinio::on_this_thread<my_traits>() .port(8080) .address("localhost") .request_handler(make_request_handler())); return 0; }
ãªã¯ãšã¹ãããURLã解æããã«ã¯ããšã¯ã¹ãã¬ã¹ã«ãŒã¿ãŒã«ããçš®ã®æ£èŠè¡šçŸã®å®è£ ãå¿ èŠã§ãã ããã©ã«ãã§ã¯ãstd :: regexã䜿çšãããŸãããçŸæç¹ã§ã¯ãæ®å¿µãªãããåªããããã©ãŒãã³ã¹ãèªãããšã¯ã§ããŸããã ããšãã°ãPCRE / PCRE2ã¯std :: regexãããã¯ããã«é«éã§ãã
ãããã£ãŠãRESTinioã§ã¯ãexpress_router_tã«å¥ã®æ£èŠè¡šçŸå®è£ ãæå®ã§ããŸãã æ¹æ³ãå°ããŸããïŒ æ£ããïŒãã³ãã¬ãŒããã©ã¡ãŒã¿ãŒã䜿çšã ããšãã°ãstd :: regexã®ä»£ããã«PCRE2ã䜿çšããã«ã¯ïŒ
#include <restinio/all.hpp> #include <restinio/router/pcre2_regex_engine.hpp> using my_router_t = restinio::router::express_router_t< restinio::router::pcre2_regex_engine_t<>>;
ããã«ã泚ææ·±ãèªè ã¯ãpcre2_regex_engine_tããã³ãã¬ãŒãã§ããããšã«æ°ä»ããããããŸããã ä»åã¯ãpcre2_regex_engine_tãããã©ã«ãã®ãã©ã¡ãŒã¿ãŒãæã€ã³ã³ãã³ãã§ãã ããããç°¡åã«ä¿®æ£ã§ããŸã...
pcre2_regex_engine_tã¯ãPCRE2ã«åºæã®ç¬èªã®ããããã£ã¯ã©ã¹ã«ãã£ãŠãã©ã¡ãŒã¿ãŒåãããŸãã çŸåšãpcre2_regex_engine_tã®ããããã£ã䜿çšããŠãæ£èŠè¡šçŸãã³ã³ãã€ã«ãããªãã·ã§ã³ãpcre2_matchã®ãªãã·ã§ã³ãããã³max_capture_groupsãªã©ã®éèŠãªãã©ã¡ãŒã¿ãŒãªã©ã®ãã©ã¡ãŒã¿ãŒãèšå®ã§ããŸãã ãã®ãã©ã¡ãŒã¿ãŒã¯ãã¹ããªã³ã°ããæœåºããããã©ã°ã¡ã³ãã®æ倧æ°ã決å®ããŸãã ããã©ã«ãã§ã¯ãmax_capture_groupsã¯20ã§ããããã¯ãpcre2_regex_engine_tãããã«20ãã©ã°ã¡ã³ãã®ã¹ããŒã¹ãå²ãåœãŠãããšãæå³ããŸãã ç§ãã¡ã®å Žåãããã¯å€ãããŸãããªããªã ãã®çãäŸã§ã¯ãURLæååã®èŠçŽ ã®æ倧æ°ã¯3ã§ãã ç¹å®ã®ã±ãŒã¹ã«åºæã®èšå®ãè¡ããŸãããïŒ
#include <restinio/all.hpp> #include <restinio/router/pcre2_regex_engine.hpp> struct my_pcre2_traits : public restinio::router::pcre2_traits_t<> { static constexpr int max_capture_groups = 4; // +1 URL. }; using my_router_t = restinio::router::express_router_t< restinio::router::pcre2_regex_engine_t<my_pcre2_traits>>;
ãããŠãç¹æ§ã«ã€ããŠ
äžèšã§ã¯ãç¹å®ã®ãšã³ãã£ãã£ã®åäœãå¶åŸ¡ããããã«ããããã£ã¯ã©ã¹ïŒã€ãŸããç¹æ§ïŒã䜿çšããäŸããã§ã«ç€ºãããŠããŸãã ããããäžè¬ã«ãREStinioã®HTTPãµãŒããŒã®åäœå šäœã決å®ããã®ã¯ç¹æ§ã§ãã äžèšã®restinio :: runïŒïŒé¢æ°ã®å éšã§ã¯ããã³ãã¬ãŒãã¯ã©ã¹restinio :: http_server_tã®ã€ã³ã¹ã¿ã³ã¹ã®äœæãé ããŸãã ãŸããTraitsãã³ãã¬ãŒããã©ã¡ãŒã¿ãŒã¯ãHTTPãµãŒããŒã®ãã©ã¡ãŒã¿ãŒãå®çŸ©ããã ãã§ãã
倧ããªããããèŠããšã次ã®ååãTraitsã§å®çŸ©ãããŠããã¯ãã§ãã
timer_manager_t ã HTTPãµãŒããŒããµãŒããŒæ¥ç¶ã«é¢é£ããã¿ã€ã ã¢ãŠããã«ãŠã³ãããããã«äœ¿çšããã¿ã€ããå®çŸ©ããŸãã RESTinioã¯ããã©ã«ãã§asio_timer_manager_tã䜿çšããæšæºã®Asioã¿ã€ããŒã¡ã«ããºã ã䜿çšããŸãã SObjectizerã¿ã€ããŒã¡ã«ããºã ã䜿çšããso_timer_manager_tããããŸãã null_timer_manager_tããããŸããããã¯ãŸã£ããäœãããããã³ãããŒã¯ã«åœ¹ç«ã¡ãŸãã
logger_t ã HTTPãµãŒããŒã®å éšã¢ã¯ãã£ããã£ãèšé²ããã¡ã«ããºã ãå®çŸ©ããŸãã ããã©ã«ãã¯null_logger_tãã€ãŸã ããã©ã«ãã§ã¯ãHTTPãµãŒããŒã¯äœãèšé²ããŸããã éåžžã«åçŽãªostream_logger_tãã¬ãŒã®ãã«ã¿ã€ã å®è£ ãããããããã°ã«åœ¹ç«ã¡ãŸãã
request_handler_t ã HTTPèŠæ±ãã³ãã©ãŒã®ã¿ã€ããå®çŸ©ããŸãã ããã©ã«ãã¯default_request_handler_tã§ãããããã¯åãªãstd :: function <request_handling_status_tïŒrequest_handle_tïŒ>ã§ãã ãã ãããã®ã¿ã€ããæŒç®åïŒïŒã«å¿ èŠãªçœ²åãæäŸããå ŽåããŠãŒã¶ãŒã¯å¥ã®ã¿ã€ããæå®ã§ããŸãã ããšãã°ãäžã§èª¬æãããšã¯ã¹ãã¬ã¹ã«ãŒã¿ãŒã¯ãHTTPãµãŒããŒã®Traitsã§request_handler_tãšããŠèšå®ããå¿ èŠãããèŠæ±ãã³ãã©ãŒã®ã¿ã€ããå®çŸ©ããŸãã
strand_t ããããã®ã¿ã€ãã決å®ããŸã ãã«ãã¹ã¬ããã¢ãŒãã§ã®äœæ¥æã«Asioã®ãžãã«ãä¿è·ããããã®ã¹ãã©ã³ãã ããã©ã«ãã§ã¯ãããã¯asio :: strand <asio :: executor>ã§ãããè€æ°ã®äœæ¥ã¹ã¬ããã§HTTPãµãŒããŒãäžåºŠã«å®å šã«å®è¡ã§ããŸãã äŸïŒ
restinio::run( restinio::on_thread_pool(std::thread::hardware_concurrency()) .port(8080) .address("localhost") .request_handler(make_request_handler()));
HTTPãµãŒããŒãã·ã³ã°ã«ã¹ã¬ããã¢ãŒãã§åäœããå ŽåãTraits :: strand_tãrestinio :: noop_strand_tïŒrestinio :: default_single_thread_traits_tã§å®è¡ïŒãšããŠå®çŸ©ããããšã§ãè¿œå ã®ãªãŒããŒããããåé¿ã§ããŸãã
stream_socket_t ã RESTinioãåäœãããœã±ããã®ã¿ã€ããå®çŸ©ããŸãã ããã©ã«ãã§ã¯ãããã¯asio :: ip :: tcp :: socketã§ãã ãã ããHTTPSã䜿çšããã«ã¯ããã®ãã©ã¡ãŒã¿ãŒãrestinio :: tls_socket_tãšããŠèšå®ããå¿ èŠããããŸãã
äžè¬ã«ããã®äžå¿ã§ããäžå€®ã¯ã©ã¹http_server_t-RESTinioã§ããC ++ãã³ãã¬ãŒãã«ããªã·ãŒããŒã¹ã®èšèšãé©çšããŸãã ãããã£ãŠããã®ã¢ãããŒãã®åé¿ãRESTinioã®ä»ã®å€ãã®éšåã«ãèŠãããããšã¯é©ãããšã§ã¯ãããŸããã
ããŠãCRTPã®ãªã3é建ãŠã®å»ºç©ã¯äœã§ããïŒ
3é建ãŠã®ãã³ãã¬ãŒãã¯èšäºã®ã¿ã€ãã«ã§èšåãããŠããŸããããããŸã§ã®ãšããããã³ãã¬ãŒããRESTinioã§ã©ã®çšåºŠåºã䜿çšãããŠãããã«ã€ããŠã®ã¿ã§ããã 3é建ãŠã®å»ºç©èªäœã®äŸã¯ãããŸããã§ããã ãã®çç¥ããªããå¿ èŠããããŸã;ïŒ
C ++ã«ã¯ã CRTPïŒCuriously recurring template patternã®ç¥ ïŒãªã©ã®ããªãããŒãªãã®ããããŸãã ããã§RESTinioã®ãã®ããšã®å©ããåããŠããµãŒããŒãã©ã¡ãŒã¿ã䜿çšããäœæ¥ãå®è£ ããŸããã
HTTPãµãŒããŒãèµ·åããåã«ãããã€ãã®å¿ é ãã©ã¡ãŒã¿ãŒãèšå®ããå¿ èŠããããŸãïŒ+ãªãã·ã§ã³ã®ãã©ã¡ãŒã¿ãŒãèšå®ã§ããŸãïŒã ããšãã°ããã®äŸã§ã¯ãHTTPãµãŒããŒããªãã¹ã³ããããŒããšã¢ãã¬ã¹ããªã¯ãšã¹ãã®ãã³ãã©ãŒãããã³ããŸããŸãªæäœã®ã¿ã€ã ã¢ãŠããèšå®ããŸãã
restinio::run( restinio::on_this_thread() .port(8080) .address("localhost") .request_handler(server_handler()) .read_next_http_message_timelimit(10s) .write_http_response_timelimit(1s) .handle_request_timeout(1s));
å®éãããã§ã¯ç¹ã«è€éãªããšã¯ãããŸãããon_this_threadé¢æ°ã¯server_settingsãªããžã§ã¯ããæ§ç¯ããŠè¿ããŸãããã®ãªããžã§ã¯ãã¯ãsetterã¡ãœãããåŒã³åºãããšã§ããã«å€æŽãããŸãã
ãã ãããç¹ã«è€éãªãã®ã¯äœããªãããšèšããšãon_this_threadããã®ã¿ã€ãã®ã€ã³ã¹ã¿ã³ã¹ãè¿ããããå°ããããã§ãã
template<typename Traits> class run_on_this_thread_settings_t final : public basic_server_settings_t<run_on_this_thread_settings_t<Traits>, Traits> { using base_type_t = basic_server_settings_t< run_on_this_thread_settings_t<Traits>, Traits>; public: using base_type_t::base_type_t; };
ããªãã¡ ãã§ã«CRTPã®è³ããããŸãã ããããbasic_server_settings_tã®å®çŸ©ãèŠããšããã«é¢çœãã§ãã
template<typename Derived, typename Traits> class basic_server_settings_t : public socket_type_dependent_settings_t<Derived, typename Traits::stream_socket_t> { ... };
ããã§ãããŒã¹ã¿ã€ããšããŠäœ¿çšãããå¥ã®ãã³ãã¬ãŒããèŠãããšãã§ããŸãã ããèªäœã§ã¯ãäœãèå³æ·±ããã®ãè¡šããŠããŸããã
template <typename Settings, typename Socket> class socket_type_dependent_settings_t { protected : ~socket_type_dependent_settings_t() = default; };
ãã ããèšå®ãšãœã±ããã®ããŸããŸãªçµã¿åããã«ç¹åããããšãã§ããŸãã ããšãã°ãTLSããµããŒãããã«ã¯ïŒ
template<typename Settings> class socket_type_dependent_settings_t<Settings, tls_socket_t> { protected: ~socket_type_dependent_settings_t() = default; public: socket_type_dependent_settings_t() = default; socket_type_dependent_settings_t(socket_type_dependent_settings_t && ) = default; Settings & tls_context(asio::ssl::context context ) & {...} Settings && tls_context(asio::ssl::context context ) && {...} asio::ssl::context tls_context() {...} ... };
ãããŠãããšãã°ããã®ç¶æ³ã§ããããã¹ãŠããŸãšãããšïŒ
struct my_pcre2_traits : public restinio::router::pcre2_traits_t<> { static constexpr int max_capture_groups = 4; }; using my_router_t = restinio::router::express_router_t< restinio::router::pcre2_regex_engine_t<my_pcre2_traits>>; using my_traits_t = restinio::single_thread_tls_traits_t< restinio::asio_timer_manager_t, restinio::single_threaded_ostream_logger_t, my_router_t>; ... restinio::run( restinio::on_this_thread<my_traits_t>() .address("localhost") .request_handler(server_handler()) .read_next_http_message_timelimit(10s) .write_http_response_timelimit(1s) .handle_request_timeout(1s) .tls_context(std::move(tls_context)));
ãããŠã確ãã«ããã³ãã¬ãŒãã¯ãã³ãã¬ãŒãã®äžã«çœ®ããããã³ãã¬ãŒããé§åããŸãã ã³ã³ãã€ã©ãšã©ãŒã¡ãã»ãŒãžã§ç¹ã«ç®ç«ã€ã®ã¯ã誀ã£ãŠã©ããã«å°å·ããŠããŸã£ãå Žåã§ã...
ãããã«
C ++ããã°ã©ããŒãç·Žç¿ããŠããC ++ãã³ãã¬ãŒãã«å¯Ÿããæ 床ãéåžžã«ç°ãªããšèšã£ãŠããç§ãã¡ãééã£ãŠããããšã¯ãŸããããŸããã誰ããã©ãã§ããã³ãã¬ãŒãã䜿çšããæã 誰ããããã«å¯ŸããŠæåºãšããŠå察ããŠããŸãã éåžžã®ãã©ãŒã©ã /ãªãœãŒã¹åå è ã¯ãç¹ã«C ++éçºã«å°éçã«é¢äžããŠããªããæèŠãæã£ãŠãã人ã®éã§ã¯ãC ++ãã³ãã¬ãŒãã«å¯ŸããŠããã«ææ§ãªæ 床ãæã£ãŠããŸãã ãããã£ãŠã確ãã«ããã®èšäºãèªãã 人ã®å€ãã¯ããããã ãã®äŸ¡å€ã¯ãã£ãã®ãïŒããšããçåãæ±ãã§ãããã
ç§ãã¡ã®æèŠã§ã¯ãã¯ãã ããšãã°ãC ++ã³ãŒãã®ã³ã³ãã€ã«æéã«ã¯ããŸãæ··ä¹±ããŠããŸãããã ã¡ãªã¿ã«ãREStinio + Asioã®ã³ã³ãã€ã«ã¯éåžžã®é床ã§ãã ããã¯ãããã«Catch2ãè¿œå ãããå Žåã§ãããããããšãã³ã³ãã€ã«æéã¯å€§å¹ ã«å¢å ããŸãã ãããŠãç¹ã«å¹Žã ãããã®åãã¡ãã»ãŒãžããŸããŸãå¥å šã«ãªã£ãŠãããããC ++ã³ã³ãã€ã©ããã®ãšã©ãŒã¡ãã»ãŒãžãæããŠããŸããã
ãããã«ãããC ++ã¯éåžžã«ç°ãªãæ¹æ³ã§ããã°ã©ã ãããŠããŸãã ãããŠã誰ãã圌ã«æãåã£ãã¹ã¿ã€ã«ã䜿çšã§ããŸãã çŽç²ã«ãã£ãã·ã¥ãããã©ã€ãã©ãªïŒ mongooseãcivetwebãªã© ïŒãŸãã¯Javaã®ãããªãã¯ã©ã¹ãæã€Cãã§èšè¿°ãããC ++ã©ã€ãã©ãªïŒ POCOãªã©ã§çºçïŒã®ã©ãããŒããéå§ããŸãã ãããŠãC ++ãã³ãã¬ãŒãCROW ã Boost.Beastããã³RESTinioãç©æ¥µçã«äœ¿çšããŠçµäºããŸãã
äžè¬çã«ãçŸä»£ã§ã¯ãRustãGoãDãªã©ã®ç«¶åä»ç€ŸããCïŒãJavaã¯ãã¡ããã®ããšãC ++ã«ã¯å€ãã®æ·±å»ã§å®¢èŠ³çãªå©ç¹ã¯ãªããšããæèŠã«åºå·ããŠããŸãã C ++ãã³ãã¬ãŒãã¯ããããããç¹å®ã®ã¢ããªã±ãŒã·ã§ã³ã§ã®C ++ã®äœ¿çšãæ£åœåã§ãããC ++ã®æ°å°ãªã競äºäžã®å©ç¹ã®1ã€ã§ãã ãããããªããC ++ãã³ãã¬ãŒããæŸæ£ãããã䜿çšãå¶éããããããã€ã³ãã¯äœã§ããïŒ ç§ãã¡ã¯ãã®ãããªæå³ãç解ããŠããªããããåžžèãèš±ãéãç©æ¥µçã«RESTinioå®è£ ã§ãã³ãã¬ãŒãã䜿çšããŸãïŒããã§ã¯ã©ã¡ãåŽããèŠãŠãããã®ã§ããïŒã