WebSocketClient.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. #include "HttpMessage.h"
  2. #include "libhv_bindings.hpp"
  3. #include "pocketpy/pocketpy.h"
  4. #include "http/client/WebSocketClient.h"
  5. struct libhv_WebSocketClient {
  6. hv::WebSocketClient ws;
  7. libhv_MQ<std::pair<WsMessageType, std::string>> mq;
  8. libhv_WebSocketClient() {
  9. ws.onopen = [this]() {
  10. mq.push({WsMessageType::onopen, ""});
  11. };
  12. ws.onclose = [this]() {
  13. mq.push({WsMessageType::onclose, ""});
  14. };
  15. ws.onmessage = [this](const std::string& msg) {
  16. mq.push({WsMessageType::onmessage, msg});
  17. };
  18. // reconnect: 1,2,4,8,10,10,10...
  19. reconn_setting_t reconn;
  20. reconn_setting_init(&reconn);
  21. reconn.min_delay = 1000;
  22. reconn.max_delay = 10000;
  23. reconn.delay_policy = 2;
  24. ws.setReconnect(&reconn);
  25. }
  26. };
  27. py_Type libhv_register_WebSocketClient(py_GlobalRef mod) {
  28. py_Type type = py_newtype("WebSocketClient", tp_object, mod, [](void* ud) {
  29. libhv_WebSocketClient* self = (libhv_WebSocketClient*)ud;
  30. self->~libhv_WebSocketClient();
  31. });
  32. py_bindmagic(type, __new__, [](int argc, py_Ref argv) {
  33. PY_CHECK_ARGC(1);
  34. libhv_WebSocketClient* self = (libhv_WebSocketClient*)
  35. py_newobject(py_retval(), py_totype(argv), 0, sizeof(libhv_WebSocketClient));
  36. new (self) libhv_WebSocketClient();
  37. return true;
  38. });
  39. py_bindmethod(type, "open", [](int argc, py_Ref argv) {
  40. libhv_WebSocketClient* self = (libhv_WebSocketClient*)py_touserdata(argv);
  41. PY_CHECK_ARG_TYPE(1, tp_str);
  42. const char* url = py_tostr(py_arg(1));
  43. http_headers headers = DefaultHeaders;
  44. if(argc == 2) {
  45. // open(self, url)
  46. } else if(argc == 3) {
  47. // open(self, url, headers)
  48. if(!py_checktype(py_arg(2), tp_dict)) return false;
  49. bool ok = py_dict_apply(
  50. py_arg(2),
  51. [](py_Ref key, py_Ref value, void* ctx) {
  52. http_headers* p_headers = (http_headers*)ctx;
  53. if(!py_checkstr(key)) return false;
  54. if(!py_checkstr(value)) return false;
  55. p_headers->operator[] (py_tostr(key)) = py_tostr(value);
  56. return true;
  57. },
  58. &headers);
  59. if(!ok) return false;
  60. } else {
  61. return TypeError("open() takes 2 or 3 arguments");
  62. }
  63. int code = self->ws.open(url, headers);
  64. py_newint(py_retval(), code);
  65. return true;
  66. });
  67. py_bindmethod(type, "close", [](int argc, py_Ref argv) {
  68. PY_CHECK_ARGC(1);
  69. libhv_WebSocketClient* self = (libhv_WebSocketClient*)py_touserdata(argv);
  70. int code = self->ws.close();
  71. py_newint(py_retval(), code);
  72. return true;
  73. });
  74. py_bindmethod(type, "send", [](int argc, py_Ref argv) {
  75. PY_CHECK_ARGC(2);
  76. libhv_WebSocketClient* self = (libhv_WebSocketClient*)py_touserdata(argv);
  77. PY_CHECK_ARG_TYPE(1, tp_str);
  78. const char* msg = py_tostr(py_arg(1));
  79. int code = self->ws.send(msg);
  80. py_newint(py_retval(), code);
  81. return true;
  82. });
  83. py_bindmethod(type, "recv", [](int argc, py_Ref argv) {
  84. PY_CHECK_ARGC(1);
  85. libhv_WebSocketClient* self = (libhv_WebSocketClient*)py_touserdata(py_arg(0));
  86. std::pair<WsMessageType, std::string> mq_msg;
  87. if(!self->mq.pop(&mq_msg)) {
  88. py_newnone(py_retval());
  89. return true;
  90. } else {
  91. py_Ref p = py_newtuple(py_retval(), 2);
  92. switch(mq_msg.first) {
  93. case WsMessageType::onopen: {
  94. py_newstr(py_offset(p, 0), "onopen");
  95. py_newnone(py_offset(p, 1));
  96. break;
  97. }
  98. case WsMessageType::onclose: {
  99. py_newstr(py_offset(p, 0), "onclose");
  100. py_newnone(py_offset(p, 1));
  101. break;
  102. }
  103. case WsMessageType::onmessage: {
  104. py_newstr(py_offset(p, 0), "onmessage");
  105. py_newstrv(py_offset(p, 1), {mq_msg.second.data(), (int)mq_msg.second.size()});
  106. break;
  107. }
  108. }
  109. return true;
  110. }
  111. });
  112. return type;
  113. }