You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

399 lines
14 KiB

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
  1. #include "extapi_service.hpp"
  2. #include "configs/project_setting.hpp"
  3. #include "iflytop/components/zcanreceiver/zcanreceiverhost.hpp"
  4. #include "iflytop/core/components/stringutils.hpp"
  5. #include "iflytop/core/core.hpp"
  6. #include "version.hpp"
  7. using namespace iflytop;
  8. using namespace core;
  9. using namespace std;
  10. using namespace nlohmann;
  11. #define BIND
  12. namespace iflytop {};
  13. /*******************************************************************************
  14. * TOOLS *
  15. *******************************************************************************/
  16. static void getJsonValFromJson(json j, int &val) {
  17. if (j.is_string()) {
  18. string valstr = j;
  19. val = atoi(valstr.c_str());
  20. } else if (j.is_number()) {
  21. val = j;
  22. } else {
  23. throw std::runtime_error("getJsonValFromJson(int) error");
  24. }
  25. }
  26. template <typename T>
  27. static T jsonGet(json j) {
  28. T val;
  29. getJsonValFromJson(j, val);
  30. return val;
  31. }
  32. void ExtAPIService::dosystem(string order) {
  33. logger->info("do:{}", order);
  34. system(order.c_str());
  35. }
  36. void ExtAPIService::initialize(string can_if_name, int baudrate, bool enablLoopback) {
  37. GET_TO_SERVICE(m_zconfig);
  38. m_zcan_receiver_master.reset(new ZcanReceiverMaster());
  39. m_zcan_receiver_master->initialize(can_if_name, baudrate, enablLoopback);
  40. m_zmodule_device_manager.reset(new ZModuleDeviceManager());
  41. m_zmodule_device_manager->initialize(m_zcan_receiver_master.get());
  42. // m_zmodule_device_manager->registerModule();
  43. for (size_t i = 1; i < 1000; i++) {
  44. m_proxys[i].initialize(i, m_zcan_receiver_master.get());
  45. m_zmodule_device_manager->registerModule(&m_proxys[i]);
  46. }
  47. /**
  48. * @brief CAN通用指令解析器
  49. */
  50. m_zmodule_device_script_cmder_paser.reset(new ZModuleDeviceScriptCmderPaser());
  51. m_zmodule_device_script_cmder_paser->initialize(this, m_zmodule_device_manager.get());
  52. #if 0
  53. m_restfulServer.reset(new RestfulServer());
  54. m_restfulServer->start(20000, 20001, "0.0.0.0");
  55. m_restfulServer->regAPI( //
  56. "/doscript", //
  57. [this](HttpRequestPtr request, shared_ptr<RestfulServer::Context> context, std::shared_ptr<ConnectionState>) {
  58. string script = request->body;
  59. // callcmd(script)
  60. return std::make_shared<HttpResponse>(200, "OK", HttpErrorCode::Ok, WebSocketHttpHeaders(), "hello_world");
  61. });
  62. m_iflytopwsService.reset(new IflytopFrontEndService());
  63. m_iflytopwsService->initialize("0.0.0.0");
  64. m_iflytopwsService->startListen();
  65. #endif
  66. /*******************************************************************************
  67. * *
  68. *******************************************************************************/
  69. /**
  70. *
  71. * protocol: websocket
  72. * port : 19004
  73. * descript:
  74. */
  75. m_script_server.reset(new WebSocketServer(19004, "0.0.0.0"));
  76. m_script_server->setOnConnectionCallback([this](weak_ptr<WebSocket> webSocket, shared_ptr<ConnectionState> connectionState) {
  77. // on new client connected
  78. logger->info("remote ip: {} connect to 19004", connectionState->getRemoteIp());
  79. auto ws = webSocket.lock();
  80. if (!ws) return;
  81. ws->setOnMessageCallback([this, webSocket](const ix::WebSocketMessagePtr &msg) {
  82. if (msg->type == ix::WebSocketMessageType::Message) {
  83. script_server_on_message(webSocket, msg);
  84. }
  85. });
  86. });
  87. m_script_server->listenAndStart();
  88. /*******************************************************************************
  89. * CAN透传服务 *
  90. *******************************************************************************/
  91. /**
  92. *
  93. * protocol: websocket
  94. * port : 19005
  95. * descript: CAN数据
  96. *
  97. */
  98. m_can_passthrough_server.reset(new WebSocketServer(19005, "0.0.0.0"));
  99. m_can_passthrough_server->setOnConnectionCallback([this](weak_ptr<WebSocket> webSocket, shared_ptr<ConnectionState> connectionState) {
  100. logger->info("m_can_passthrough_server on connect remote ip: {}", connectionState->getRemoteIp());
  101. auto ws = webSocket.lock();
  102. if (!ws) return;
  103. ws->setOnMessageCallback([this, webSocket](const ix::WebSocketMessagePtr &msg) {
  104. if (msg->type == ix::WebSocketMessageType::Message) {
  105. logger->info("down can bin -> {}({})", msg->str, msg->wireSize);
  106. vector<uint8_t> rxbyte;
  107. StringUtils().hexStringToBytes(msg->str, "", rxbyte);
  108. m_zcan_receiver_master->sendraw(rxbyte.data(), rxbyte.size());
  109. }
  110. });
  111. });
  112. m_can_passthrough_server->listenAndStart();
  113. m_zcan_receiver_master->regPacketListener([this](int32_t fromboard, zcr_cmd_header_t *packet, int32_t datalen) {
  114. auto clients = m_can_passthrough_server->getClients();
  115. string rx = StringUtils().bytesToString((uint8_t *)packet, datalen);
  116. logger->info("report can bin -< {}({})", rx, datalen);
  117. for (auto &each : clients) {
  118. if (each) each->sendText(rx);
  119. }
  120. });
  121. /*******************************************************************************
  122. * *
  123. *******************************************************************************/
  124. /**
  125. * @brief
  126. */
  127. m_zmodule_device_manager->regOnRegValChangeEvent([this](int32_t moduleid, int32_t regindex, int32_t oldval, int32_t toval) { //
  128. logger->info("on reg change: moduleid:{} REG({}) {} to {}", moduleid, regindex, oldval, toval);
  129. // m_script_server 上报事件
  130. {
  131. auto clients = m_script_server->getClients();
  132. for (auto &each : clients) {
  133. if (each) each->sendText(fmt::format("on reg change: moduleid:{} REG({}) {} to {}", moduleid, regindex, oldval, toval));
  134. }
  135. }
  136. });
  137. };
  138. /*******************************************************************************
  139. * m_script_server *
  140. *******************************************************************************/
  141. void ExtAPIService::script_server_on_message(weak_ptr<WebSocket> webSocket, const ix::WebSocketMessagePtr &msg) {
  142. logger->info("script_server_on_message:\n{}", msg->str);
  143. script_processer_processcmds(
  144. msg->str,
  145. /*******************************************************************************
  146. * PRIVATE_FN_PROCESSER *
  147. *******************************************************************************/
  148. [this, webSocket](string cmd, int32_t paramN, const char **paraV, ICmdParserACK *ack) {
  149. auto ws = webSocket.lock();
  150. if (!ws) return;
  151. /*******************************************************************************
  152. * HELP *
  153. *******************************************************************************/
  154. if (cmd == "help") {
  155. ack->ecode = 0;
  156. string helpinfo;
  157. helpinfo += fmt::format("cmdlist:\n");
  158. for (auto it = m_cmdmap.begin(); it != m_cmdmap.end(); it++) {
  159. // ws->sendText(fmt::format("\t{} {}", it->first, it->second.helpinfo));
  160. helpinfo += fmt::format("\t{} {}\n", it->first, it->second.helpinfo);
  161. }
  162. ws->sendText(helpinfo);
  163. return;
  164. }
  165. if (cmd == "app_scan_moudle") {
  166. ack->ecode = 0;
  167. string helpinfo;
  168. helpinfo += fmt::format("cmdlist:\n");
  169. for (auto it = m_cmdmap.begin(); it != m_cmdmap.end(); it++) {
  170. // ws->sendText(fmt::format("\t{} {}", it->first, it->second.helpinfo));
  171. helpinfo += fmt::format("\t{} {}\n", it->first, it->second.helpinfo);
  172. }
  173. ws->sendText(helpinfo);
  174. return;
  175. }
  176. },
  177. /*******************************************************************************
  178. * ACK_PROCESSER *
  179. *******************************************************************************/
  180. [this, webSocket](string cmd, ICmdParserACK *ack) { //
  181. logger->info("do {},{}({})", cmd, ack->ecode, err::error2str(ack->ecode));
  182. string ackstr;
  183. if (ack->acktype == ICmdParserACK::kAckType_none) {
  184. ackstr += fmt::format("{} -> ecode:{}({})\n", cmd, err::error2str(ack->ecode), ack->ecode);
  185. } else if (ack->acktype == ICmdParserACK::kAckType_int32) {
  186. ackstr += fmt::format("{} -> ecode:{}({})\n", cmd, err::error2str(ack->ecode), ack->ecode);
  187. for (int32_t i = 0; i < ack->getAckInt32Num(); i++) {
  188. ackstr += fmt::format(" ack[{}]{}\n", i, ack->getAckInt32Val(i));
  189. }
  190. } else if (ack->acktype == ICmdParserACK::kAckType_buf) {
  191. ackstr += fmt::format("{} -> ecode:{}({})\n", cmd, err::error2str(ack->ecode), ack->ecode);
  192. ackstr += tools_dumpbuffer(ack->rawdata, ack->rawlen);
  193. } else if (ack->acktype == ICmdParserACK::kAckType_str) {
  194. ackstr += fmt::format("{} -> ecode:{}({})\n", cmd, err::error2str(ack->ecode), ack->ecode);
  195. ackstr = fmt::format(" ackbufstr:{}", string((const char *)ack->rawdata));
  196. }
  197. auto ws = webSocket.lock();
  198. if (ws) ws->sendText(ackstr);
  199. });
  200. }
  201. void ExtAPIService::regfns() {
  202. this->regCMD("", "", 2, [](int32_t paramN, const char **paraV, ICmdParserACK *ack) {
  203. /**
  204. * @brief who call me?
  205. */
  206. });
  207. }
  208. /*******************************************************************************
  209. * *
  210. *******************************************************************************/
  211. void ExtAPIService::regCMD(const char *cmdname, const char *helpinfo, int paraNum, ICmdFunction_t cmdimpl) {
  212. cmd_container_t cmd_container;
  213. cmd_container.cmdname = cmdname;
  214. cmd_container.helpinfo = helpinfo;
  215. cmd_container.paraNum = paraNum;
  216. cmd_container.cmdimpl = cmdimpl;
  217. m_cmdmap[cmdname] = cmd_container;
  218. }
  219. void ExtAPIService::script_processer_processcmds(string script, private_fn_processer_t private_fn_processer, ackprocesser_t ackprocesser) {
  220. /**
  221. * @brief
  222. * script:
  223. * cmd val1 val2 val3
  224. * cmd val1 val2 val3
  225. */
  226. vector<string> cmdlines;
  227. char *strcache = (char *)malloc(script.size() + 1);
  228. strncpy(strcache, script.c_str(), script.size());
  229. int32_t stringlen = script.size();
  230. for (int32_t i = 0; i < stringlen; i++) {
  231. if (strcache[i] == '\n' || strcache[i] == '\r') {
  232. strcache[i] = '\0';
  233. }
  234. }
  235. char *currentstr = nullptr;
  236. for (int32_t i = 0; i < stringlen; i++) {
  237. if (currentstr == nullptr) {
  238. if (strcache[i] != '\0') {
  239. // logger->info("new cmd:{}", &strcache[i]);
  240. currentstr = &strcache[i];
  241. cmdlines.push_back(currentstr);
  242. }
  243. } else {
  244. if (strcache[i] == '\0') {
  245. currentstr = nullptr;
  246. }
  247. }
  248. }
  249. for (auto &cmdline : cmdlines) {
  250. // bool isnote = false;
  251. FnProcessContext cxt;
  252. cxt.private_fn_processer = private_fn_processer;
  253. cxt.ackprocesser = ackprocesser;
  254. // logger->info("do {}", cmdline);
  255. script_processer_callcmd(cmdline, cxt);
  256. if (cxt.breakflag) break;
  257. }
  258. free(strcache);
  259. }
  260. void ExtAPIService::script_processer_callcmd(string cmd, FnProcessContext &cxt) {
  261. char *argv[30] = {0};
  262. int32_t argc = 0;
  263. char cmdcache[1024] = {0};
  264. strncpy(cmdcache, cmd.c_str(), 1023);
  265. // remove note
  266. for (size_t i = 0; i < cmd.length(); i++) {
  267. if (cmdcache[i] == '#') {
  268. cmdcache[i] = '\0';
  269. if (i == 0) {
  270. // is note return;
  271. return;
  272. }
  273. break;
  274. }
  275. }
  276. // logger->info("cmdcache:{}", cmdcache);
  277. for (int32_t i = 0; i < cmd.length(); i++) {
  278. if (cmdcache[i] == '\n' || cmdcache[i] == '\r' || cmdcache[i] == ' ' || cmdcache[i] == 127) {
  279. cmdcache[i] = '\0';
  280. }
  281. }
  282. int j = 0;
  283. for (int i = 0; cmdcache[i] == 0 || i < cmd.length(); i++) {
  284. if (cmdcache[i] != 0 && j == 0) {
  285. argv[argc++] = &cmdcache[i];
  286. j = 1;
  287. continue;
  288. }
  289. if (cmdcache[i] == 0 && j == 1) {
  290. j = 0;
  291. continue;
  292. }
  293. }
  294. logger->info("argc:{}", argc);
  295. for (int i = 0; i < argc; i++) {
  296. logger->info("argv[{}]:{}", i, argv[i]);
  297. }
  298. if (argc == 0) {
  299. return;
  300. }
  301. script_processer_callcmd(cxt, argv[0], argc - 1, (const char **)(argv + 1));
  302. }
  303. void ExtAPIService::script_processer_callcmd(FnProcessContext &cxt, string cmdname, int32_t paramN, const char **paraV) {
  304. std::lock_guard<std::recursive_mutex> lock(m_cmdmaplock_);
  305. auto it = m_cmdmap.find(cmdname);
  306. logger->info("call cmd:{} paramN:{}", cmdname, paramN);
  307. ICmdParserACK ack = {0};
  308. if (it != m_cmdmap.end()) {
  309. cmd_container_t cmd_container = it->second;
  310. if (cmd_container.paraNum != paramN) {
  311. ack.ecode = err::kcmd_param_num_error;
  312. return;
  313. }
  314. if (cmd_container.cmdimpl) {
  315. cmd_container.cmdimpl(paramN, paraV, &ack);
  316. } else {
  317. logger->info("cmd:{} not impl", cmdname);
  318. }
  319. } else {
  320. ack.ecode = err::kcmd_not_found;
  321. if (cxt.private_fn_processer) cxt.private_fn_processer(cmdname, paramN, paraV, &ack);
  322. }
  323. if (cxt.ackprocesser) cxt.ackprocesser(cmdname, &ack);
  324. if (ack.ecode != err::ksucc) cxt.breakflag = true;
  325. }
  326. /*******************************************************************************
  327. * TOOLS *
  328. *******************************************************************************/
  329. string ExtAPIService::tools_dumpbuffer(uint8_t *data, int32_t len) {
  330. int32_t align = 32;
  331. string ret;
  332. for (int32_t i = 0; i < len;) {
  333. for (int32_t j = 0; j < align; j++) {
  334. if (i + j < len) {
  335. ret += fmt::format("{:02X} ", data[i + j]);
  336. } else {
  337. ret += " ";
  338. }
  339. }
  340. ret += "|";
  341. for (int32_t j = 0; j < align; j++) {
  342. if (i + j < len) {
  343. if (isprint(data[i + j])) {
  344. ret += fmt::format("{}", data[i + j]);
  345. } else {
  346. ret += ".";
  347. }
  348. } else {
  349. ret += " ";
  350. }
  351. }
  352. ret += "\n";
  353. }
  354. return ret;
  355. }