|
|
#include "extapi_service.hpp"
#include "configs/project_setting.hpp"
#include "iflytop/components/zcanreceiver/zcanreceiverhost.hpp"
#include "iflytop/core/components/stringutils.hpp"
#include "iflytop/core/core.hpp"
#include "version.hpp"
using namespace iflytop; using namespace core; using namespace std; using namespace nlohmann; #define BIND
namespace iflytop {};
/*******************************************************************************
* TOOLS * *******************************************************************************/ static void getJsonValFromJson(json j, int &val) { if (j.is_string()) { string valstr = j; val = atoi(valstr.c_str()); } else if (j.is_number()) { val = j; } else { throw std::runtime_error("getJsonValFromJson(int) error"); } }
template <typename T> static T jsonGet(json j) { T val; getJsonValFromJson(j, val); return val; }
void ExtAPIService::dosystem(string order) { logger->info("do:{}", order); system(order.c_str()); }
void ExtAPIService::initialize(string can_if_name, int baudrate, bool enablLoopback) { GET_TO_SERVICE(m_zconfig);
m_zcan_receiver_master.reset(new ZcanReceiverMaster()); m_zcan_receiver_master->initialize(can_if_name, baudrate, enablLoopback);
m_zmodule_device_manager.reset(new ZModuleDeviceManager()); m_zmodule_device_manager->initialize(m_zcan_receiver_master.get());
// m_zmodule_device_manager->registerModule();
for (size_t i = 1; i < 1000; i++) { m_proxys[i].initialize(i, m_zcan_receiver_master.get()); m_zmodule_device_manager->registerModule(&m_proxys[i]); }
/**
* @brief CAN通用指令解析器 */ m_zmodule_device_script_cmder_paser.reset(new ZModuleDeviceScriptCmderPaser()); m_zmodule_device_script_cmder_paser->initialize(this, m_zmodule_device_manager.get());
#if 0
m_restfulServer.reset(new RestfulServer()); m_restfulServer->start(20000, 20001, "0.0.0.0"); m_restfulServer->regAPI( //
"/doscript", //
[this](HttpRequestPtr request, shared_ptr<RestfulServer::Context> context, std::shared_ptr<ConnectionState>) { string script = request->body; // callcmd(script)
return std::make_shared<HttpResponse>(200, "OK", HttpErrorCode::Ok, WebSocketHttpHeaders(), "hello_world"); }); m_iflytopwsService.reset(new IflytopFrontEndService()); m_iflytopwsService->initialize("0.0.0.0"); m_iflytopwsService->startListen(); #endif
/*******************************************************************************
* 脚本服务 * *******************************************************************************/ /**
* * protocol: websocket * port : 19004 * descript: 命令行脚本服务支持,回执以日志的形式返回 */ m_script_server.reset(new WebSocketServer(19004, "0.0.0.0")); m_script_server->setOnConnectionCallback([this](weak_ptr<WebSocket> webSocket, shared_ptr<ConnectionState> connectionState) { // on new client connected
logger->info("remote ip: {} connect to 19004", connectionState->getRemoteIp()); auto ws = webSocket.lock(); if (!ws) return; ws->setOnMessageCallback([this, webSocket](const ix::WebSocketMessagePtr &msg) { if (msg->type == ix::WebSocketMessageType::Message) { script_server_on_message(webSocket, msg); } }); });
m_script_server->listenAndStart();
/*******************************************************************************
* CAN透传服务 * *******************************************************************************/ /**
* * protocol: websocket * port : 19005 * descript: 直接透传CAN数据,不做任何处理 * */ m_can_passthrough_server.reset(new WebSocketServer(19005, "0.0.0.0")); m_can_passthrough_server->setOnConnectionCallback([this](weak_ptr<WebSocket> webSocket, shared_ptr<ConnectionState> connectionState) { logger->info("m_can_passthrough_server on connect remote ip: {}", connectionState->getRemoteIp()); auto ws = webSocket.lock(); if (!ws) return;
ws->setOnMessageCallback([this, webSocket](const ix::WebSocketMessagePtr &msg) { if (msg->type == ix::WebSocketMessageType::Message) { logger->info("down can bin -> {}({})", msg->str, msg->wireSize); vector<uint8_t> rxbyte; StringUtils().hexStringToBytes(msg->str, "", rxbyte); m_zcan_receiver_master->sendraw(rxbyte.data(), rxbyte.size()); } }); }); m_can_passthrough_server->listenAndStart();
m_zcan_receiver_master->regPacketListener([this](int32_t fromboard, zcr_cmd_header_t *packet, int32_t datalen) { auto clients = m_can_passthrough_server->getClients(); string rx = StringUtils().bytesToString((uint8_t *)packet, datalen); logger->info("report can bin -< {}({})", rx, datalen); for (auto &each : clients) { if (each) each->sendText(rx); } });
/*******************************************************************************
* 事件监听器 * *******************************************************************************/ /**
* @brief 监听事件,并打印 */ m_zmodule_device_manager->regOnRegValChangeEvent([this](int32_t moduleid, int32_t regindex, int32_t oldval, int32_t toval) { //
logger->info("on reg change: moduleid:{} REG({}) {} to {}", moduleid, regindex, oldval, toval);
// m_script_server 上报事件
{ auto clients = m_script_server->getClients(); for (auto &each : clients) { if (each) each->sendText(fmt::format("on reg change: moduleid:{} REG({}) {} to {}", moduleid, regindex, oldval, toval)); } }
}); };
/*******************************************************************************
* m_script_server * *******************************************************************************/
void ExtAPIService::script_server_on_message(weak_ptr<WebSocket> webSocket, const ix::WebSocketMessagePtr &msg) { logger->info("script_server_on_message:\n{}", msg->str); script_processer_processcmds( msg->str, /*******************************************************************************
* PRIVATE_FN_PROCESSER * *******************************************************************************/ [this, webSocket](string cmd, int32_t paramN, const char **paraV, ICmdParserACK *ack) { auto ws = webSocket.lock(); if (!ws) return;
/*******************************************************************************
* HELP * *******************************************************************************/ if (cmd == "help") { ack->ecode = 0; string helpinfo; helpinfo += fmt::format("cmdlist:\n"); for (auto it = m_cmdmap.begin(); it != m_cmdmap.end(); it++) { // ws->sendText(fmt::format("\t{} {}", it->first, it->second.helpinfo));
helpinfo += fmt::format("\t{} {}\n", it->first, it->second.helpinfo); } ws->sendText(helpinfo); return; }
if (cmd == "app_scan_moudle") { ack->ecode = 0; string helpinfo; helpinfo += fmt::format("cmdlist:\n"); for (auto it = m_cmdmap.begin(); it != m_cmdmap.end(); it++) { // ws->sendText(fmt::format("\t{} {}", it->first, it->second.helpinfo));
helpinfo += fmt::format("\t{} {}\n", it->first, it->second.helpinfo); } ws->sendText(helpinfo); return; } }, /*******************************************************************************
* ACK_PROCESSER * *******************************************************************************/ [this, webSocket](string cmd, ICmdParserACK *ack) { //
logger->info("do {},{}({})", cmd, ack->ecode, err::error2str(ack->ecode)); string ackstr; if (ack->acktype == ICmdParserACK::kAckType_none) { ackstr += fmt::format("{} -> ecode:{}({})\n", cmd, err::error2str(ack->ecode), ack->ecode); } else if (ack->acktype == ICmdParserACK::kAckType_int32) { ackstr += fmt::format("{} -> ecode:{}({})\n", cmd, err::error2str(ack->ecode), ack->ecode); for (int32_t i = 0; i < ack->getAckInt32Num(); i++) { ackstr += fmt::format(" ack[{}]{}\n", i, ack->getAckInt32Val(i)); } } else if (ack->acktype == ICmdParserACK::kAckType_buf) { ackstr += fmt::format("{} -> ecode:{}({})\n", cmd, err::error2str(ack->ecode), ack->ecode); ackstr += tools_dumpbuffer(ack->rawdata, ack->rawlen); } else if (ack->acktype == ICmdParserACK::kAckType_str) { ackstr += fmt::format("{} -> ecode:{}({})\n", cmd, err::error2str(ack->ecode), ack->ecode); ackstr = fmt::format(" ackbufstr:{}", string((const char *)ack->rawdata)); } auto ws = webSocket.lock(); if (ws) ws->sendText(ackstr); }); }
void ExtAPIService::regfns() { this->regCMD("", "", 2, [](int32_t paramN, const char **paraV, ICmdParserACK *ack) { /**
* @brief who call me? */ }); } /*******************************************************************************
* 脚本处理方法 * *******************************************************************************/ void ExtAPIService::regCMD(const char *cmdname, const char *helpinfo, int paraNum, ICmdFunction_t cmdimpl) { cmd_container_t cmd_container; cmd_container.cmdname = cmdname; cmd_container.helpinfo = helpinfo; cmd_container.paraNum = paraNum; cmd_container.cmdimpl = cmdimpl; m_cmdmap[cmdname] = cmd_container; }
void ExtAPIService::script_processer_processcmds(string script, private_fn_processer_t private_fn_processer, ackprocesser_t ackprocesser) { /**
* @brief * script: * cmd val1 val2 val3 * cmd val1 val2 val3 */
vector<string> cmdlines; char *strcache = (char *)malloc(script.size() + 1); strncpy(strcache, script.c_str(), script.size()); int32_t stringlen = script.size(); for (int32_t i = 0; i < stringlen; i++) { if (strcache[i] == '\n' || strcache[i] == '\r') { strcache[i] = '\0'; } }
char *currentstr = nullptr; for (int32_t i = 0; i < stringlen; i++) { if (currentstr == nullptr) { if (strcache[i] != '\0') { // logger->info("new cmd:{}", &strcache[i]);
currentstr = &strcache[i]; cmdlines.push_back(currentstr); } } else { if (strcache[i] == '\0') { currentstr = nullptr; } } }
for (auto &cmdline : cmdlines) { // bool isnote = false;
FnProcessContext cxt; cxt.private_fn_processer = private_fn_processer; cxt.ackprocesser = ackprocesser;
// logger->info("do {}", cmdline);
script_processer_callcmd(cmdline, cxt);
if (cxt.breakflag) break; } free(strcache); }
void ExtAPIService::script_processer_callcmd(string cmd, FnProcessContext &cxt) { char *argv[30] = {0}; int32_t argc = 0;
char cmdcache[1024] = {0}; strncpy(cmdcache, cmd.c_str(), 1023);
// remove note
for (size_t i = 0; i < cmd.length(); i++) { if (cmdcache[i] == '#') { cmdcache[i] = '\0'; if (i == 0) { // is note return;
return; } break; } }
// logger->info("cmdcache:{}", cmdcache);
for (int32_t i = 0; i < cmd.length(); i++) { if (cmdcache[i] == '\n' || cmdcache[i] == '\r' || cmdcache[i] == ' ' || cmdcache[i] == 127) { cmdcache[i] = '\0'; } }
int j = 0; for (int i = 0; cmdcache[i] == 0 || i < cmd.length(); i++) { if (cmdcache[i] != 0 && j == 0) { argv[argc++] = &cmdcache[i]; j = 1; continue; }
if (cmdcache[i] == 0 && j == 1) { j = 0; continue; } }
logger->info("argc:{}", argc); for (int i = 0; i < argc; i++) { logger->info("argv[{}]:{}", i, argv[i]); }
if (argc == 0) { return; }
script_processer_callcmd(cxt, argv[0], argc - 1, (const char **)(argv + 1)); } void ExtAPIService::script_processer_callcmd(FnProcessContext &cxt, string cmdname, int32_t paramN, const char **paraV) { std::lock_guard<std::recursive_mutex> lock(m_cmdmaplock_); auto it = m_cmdmap.find(cmdname);
logger->info("call cmd:{} paramN:{}", cmdname, paramN); ICmdParserACK ack = {0}; if (it != m_cmdmap.end()) { cmd_container_t cmd_container = it->second; if (cmd_container.paraNum != paramN) { ack.ecode = err::kcmd_param_num_error; return; } if (cmd_container.cmdimpl) { cmd_container.cmdimpl(paramN, paraV, &ack); } else { logger->info("cmd:{} not impl", cmdname); } } else { ack.ecode = err::kcmd_not_found; if (cxt.private_fn_processer) cxt.private_fn_processer(cmdname, paramN, paraV, &ack); }
if (cxt.ackprocesser) cxt.ackprocesser(cmdname, &ack); if (ack.ecode != err::ksucc) cxt.breakflag = true; } /*******************************************************************************
* TOOLS * *******************************************************************************/ string ExtAPIService::tools_dumpbuffer(uint8_t *data, int32_t len) { int32_t align = 32; string ret;
for (int32_t i = 0; i < len;) { for (int32_t j = 0; j < align; j++) { if (i + j < len) { ret += fmt::format("{:02X} ", data[i + j]); } else { ret += " "; } }
ret += "|";
for (int32_t j = 0; j < align; j++) { if (i + j < len) { if (isprint(data[i + j])) { ret += fmt::format("{}", data[i + j]); } else { ret += "."; } } else { ret += " "; } } ret += "\n"; } return ret; }
|