HttpServer.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. #include "HttpMessage.h"
  2. #include "WebSocketChannel.h"
  3. #include "libhv_bindings.hpp"
  4. #include "http/server/WebSocketServer.h"
  5. #include "pocketpy.h"
  6. struct libhv_HttpServer {
  7. hv::HttpService http_service;
  8. hv::WebSocketService ws_service;
  9. hv::WebSocketServer server;
  10. libhv_MQ<std::pair<HttpContextPtr, std::atomic<int>>*> mq;
  11. struct WsMessage {
  12. WsMessageType type;
  13. hv::WebSocketChannel* channel;
  14. HttpRequestPtr request;
  15. std::string body;
  16. };
  17. libhv_MQ<WsMessage> ws_mq;
  18. };
  19. static bool libhv_HttpServer__new__(int argc, py_Ref argv) {
  20. libhv_HttpServer* self =
  21. (libhv_HttpServer*)py_newobject(py_retval(), py_totype(argv), 0, sizeof(libhv_HttpServer));
  22. new (self) libhv_HttpServer();
  23. return true;
  24. }
  25. static bool libhv_HttpServer__init__(int argc, py_Ref argv) {
  26. PY_CHECK_ARGC(3);
  27. libhv_HttpServer* self = (libhv_HttpServer*)py_touserdata(py_arg(0));
  28. PY_CHECK_ARG_TYPE(1, tp_str);
  29. PY_CHECK_ARG_TYPE(2, tp_int);
  30. const char* host = py_tostr(py_arg(1));
  31. int port = py_toint(py_arg(2));
  32. self->server.setHost(host);
  33. self->server.setPort(port);
  34. // http
  35. self->http_service.AllowCORS();
  36. http_ctx_handler internal_handler = [self](const HttpContextPtr& ctx) {
  37. std::pair<HttpContextPtr, std::atomic<int>> msg(ctx, 0);
  38. self->mq.push(&msg);
  39. int code;
  40. do {
  41. code = msg.second.load();
  42. } while(code == 0);
  43. return code;
  44. };
  45. self->http_service.Any("*", internal_handler);
  46. self->server.registerHttpService(&self->http_service);
  47. // websocket
  48. self->ws_service.onopen = [self](const WebSocketChannelPtr& channel,
  49. const HttpRequestPtr& req) {
  50. self->ws_mq.push({WsMessageType::onopen, channel.get(), req, ""});
  51. };
  52. self->ws_service.onmessage = [self](const WebSocketChannelPtr& channel,
  53. const std::string& msg) {
  54. self->ws_mq.push({WsMessageType::onmessage, channel.get(), nullptr, msg});
  55. };
  56. self->ws_service.onclose = [self](const WebSocketChannelPtr& channel) {
  57. self->ws_mq.push({WsMessageType::onclose, channel.get(), nullptr, ""});
  58. };
  59. self->server.registerWebSocketService(&self->ws_service);
  60. py_newnone(py_retval());
  61. return true;
  62. }
  63. static bool libhv_HttpServer_dispatch(int argc, py_Ref argv) {
  64. PY_CHECK_ARGC(2);
  65. libhv_HttpServer* self = (libhv_HttpServer*)py_touserdata(py_arg(0));
  66. py_Ref callable = py_arg(1);
  67. if(!py_callable(callable)) return TypeError("dispatcher must be callable");
  68. std::pair<HttpContextPtr, std::atomic<int>>* mq_msg;
  69. if(!self->mq.pop(&mq_msg)) {
  70. py_newbool(py_retval(), false);
  71. return true;
  72. } else {
  73. HttpContextPtr ctx = mq_msg->first;
  74. libhv_HttpRequest_create(py_retval(), ctx->request);
  75. // call dispatcher
  76. if(!py_call(callable, 1, py_retval())) return false;
  77. py_Ref object;
  78. int status_code = 200;
  79. if(py_istuple(py_retval())) {
  80. int length = py_tuple_len(py_retval());
  81. if(length == 2 || length == 3) {
  82. // "Hello, world!", 200
  83. object = py_tuple_getitem(py_retval(), 0);
  84. py_ItemRef status_code_object = py_tuple_getitem(py_retval(), 1);
  85. if(!py_checkint(status_code_object)) return false;
  86. status_code = py_toint(status_code_object);
  87. if(length == 3) {
  88. // "Hello, world!", 200, {"Content-Type": "text/plain"}
  89. py_ItemRef headers_object = py_tuple_getitem(py_retval(), 2);
  90. if(!py_checktype(headers_object, tp_dict)) return false;
  91. bool ok = py_dict_apply(
  92. headers_object,
  93. [](py_Ref key, py_Ref value, void* ctx_) {
  94. if(!py_checkstr(key) || !py_checkstr(value)) return false;
  95. ((hv::HttpContext*)ctx_)
  96. ->response->SetHeader(py_tostr(key), py_tostr(value));
  97. return true;
  98. },
  99. ctx.get());
  100. if(!ok) return false;
  101. }
  102. } else {
  103. return TypeError("dispatcher return tuple must have 2 or 3 elements");
  104. }
  105. } else {
  106. // "Hello, world!"
  107. object = py_retval();
  108. }
  109. switch(py_typeof(object)) {
  110. case tp_bytes: {
  111. int size;
  112. unsigned char* buf = py_tobytes(object, &size);
  113. ctx->response->Data(buf, size, false);
  114. break;
  115. }
  116. case tp_str: {
  117. c11_sv sv = py_tosv(object);
  118. ctx->response->String(std::string(sv.data, sv.size));
  119. break;
  120. }
  121. case tp_NoneType: {
  122. break;
  123. }
  124. default: {
  125. if(!py_json_dumps(object, 0)) return false;
  126. c11_sv sv = py_tosv(py_retval());
  127. ctx->response->String(std::string(sv.data, sv.size));
  128. ctx->response->SetContentType(APPLICATION_JSON);
  129. break;
  130. }
  131. }
  132. mq_msg->second.store(status_code);
  133. }
  134. py_newbool(py_retval(), true);
  135. return true;
  136. }
  137. static bool libhv_HttpServer_start(int argc, py_Ref argv) {
  138. PY_CHECK_ARGC(1);
  139. libhv_HttpServer* self = (libhv_HttpServer*)py_touserdata(py_arg(0));
  140. int code = self->server.start();
  141. py_newint(py_retval(), code);
  142. return true;
  143. }
  144. static bool libhv_HttpServer_stop(int argc, py_Ref argv) {
  145. PY_CHECK_ARGC(1);
  146. libhv_HttpServer* self = (libhv_HttpServer*)py_touserdata(py_arg(0));
  147. int code = self->server.stop();
  148. py_newint(py_retval(), code);
  149. return true;
  150. }
  151. static bool libhv_HttpServer_ws_set_ping_interval(int argc, py_Ref argv) {
  152. PY_CHECK_ARGC(2);
  153. libhv_HttpServer* self = (libhv_HttpServer*)py_touserdata(py_arg(0));
  154. PY_CHECK_ARG_TYPE(1, tp_int);
  155. int interval = py_toint(py_arg(1));
  156. self->ws_service.setPingInterval(interval);
  157. py_newnone(py_retval());
  158. return true;
  159. }
  160. static bool libhv_HttpServer_ws_close(int argc, py_Ref argv) {
  161. PY_CHECK_ARGC(2);
  162. libhv_HttpServer* self = (libhv_HttpServer*)py_touserdata(py_arg(0));
  163. PY_CHECK_ARG_TYPE(1, tp_int);
  164. py_i64 channel = py_toint(py_arg(1));
  165. int code = reinterpret_cast<hv::WebSocketChannel*>(channel)->close();
  166. py_newint(py_retval(), code);
  167. return true;
  168. }
  169. static bool libhv_HttpServer_ws_send(int argc, py_Ref argv) {
  170. PY_CHECK_ARGC(3);
  171. libhv_HttpServer* self = (libhv_HttpServer*)py_touserdata(py_arg(0));
  172. PY_CHECK_ARG_TYPE(1, tp_int);
  173. PY_CHECK_ARG_TYPE(2, tp_str);
  174. py_i64 channel = py_toint(py_arg(1));
  175. const char* msg = py_tostr(py_arg(2));
  176. hv::WebSocketChannel* p_channel = reinterpret_cast<hv::WebSocketChannel*>(channel);
  177. int code = p_channel->send(msg);
  178. py_newint(py_retval(), code);
  179. return true;
  180. }
  181. static bool libhv_HttpServer_ws_recv(int argc, py_Ref argv) {
  182. PY_CHECK_ARGC(1);
  183. libhv_HttpServer* self = (libhv_HttpServer*)py_touserdata(py_arg(0));
  184. libhv_HttpServer::WsMessage msg;
  185. if(!self->ws_mq.pop(&msg)) {
  186. py_newnone(py_retval());
  187. return true;
  188. }
  189. py_Ref data = py_newtuple(py_retval(), 2);
  190. switch(msg.type) {
  191. case WsMessageType::onopen: {
  192. // "onopen", (channel, request)
  193. assert(msg.request != nullptr);
  194. py_newstr(py_offset(data, 0), "onopen");
  195. py_Ref p = py_newtuple(py_offset(data, 1), 2);
  196. py_newint(py_offset(p, 0), (py_i64)msg.channel);
  197. libhv_HttpRequest_create(py_offset(p, 1), msg.request);
  198. break;
  199. }
  200. case WsMessageType::onclose: {
  201. // "onclose", channel
  202. py_newstr(py_offset(data, 0), "onclose");
  203. py_newint(py_offset(data, 1), (py_i64)msg.channel);
  204. break;
  205. }
  206. case WsMessageType::onmessage: {
  207. // "onmessage", (channel, body)
  208. py_newstr(py_offset(data, 0), "onmessage");
  209. py_Ref p = py_newtuple(py_offset(data, 1), 2);
  210. py_newint(py_offset(p, 0), (py_i64)msg.channel);
  211. c11_sv sv;
  212. sv.data = msg.body.data();
  213. sv.size = msg.body.size();
  214. py_newstrv(py_offset(p, 1), sv);
  215. break;
  216. }
  217. }
  218. return true;
  219. }
  220. py_Type libhv_register_HttpServer(py_GlobalRef mod) {
  221. py_Type type = py_newtype("HttpServer", tp_object, mod, [](void* ud) {
  222. libhv_HttpServer* self = (libhv_HttpServer*)ud;
  223. self->~libhv_HttpServer();
  224. });
  225. py_bindmagic(type, __new__, libhv_HttpServer__new__);
  226. py_bindmagic(type, __init__, libhv_HttpServer__init__);
  227. py_bindmethod(type, "start", libhv_HttpServer_start);
  228. py_bindmethod(type, "stop", libhv_HttpServer_stop);
  229. py_bindmethod(type, "dispatch", libhv_HttpServer_dispatch);
  230. py_bindmethod(type, "ws_set_ping_interval", libhv_HttpServer_ws_set_ping_interval);
  231. py_bindmethod(type, "ws_close", libhv_HttpServer_ws_close);
  232. py_bindmethod(type, "ws_send", libhv_HttpServer_ws_send);
  233. py_bindmethod(type, "ws_recv", libhv_HttpServer_ws_recv);
  234. return type;
  235. }