#include "stdafx.h" #include "etradeclient/browser/async_js_callback_handler.h" #include <string> #include <boost/property_tree/ptree.hpp> #include <boost/algorithm/string.hpp> #include <boost/ptr_container/ptr_map.hpp> #include "etradeclient/boost_patch/property_tree/json_parser.hpp" // WARNIING! Make sure to include our patched version. #include "etradeclient/hardware/hardware_cmd.h" #include "etradeclient/utility/url_regex.h" #include "etradeclient/utility/url_config.h" #include "etradeclient/utility/logging.h" #include "etradeclient/utility/string_converter.h" #include "ETradeClient/utility/win_msg_define.h" #include "ETradeClient/browser/popup_browser_handler.h" namespace HW { namespace PT = boost::property_tree; // Tag & value of the hardware function request & response string in JSON format. static const std::string JSON_TAG_CMD = "command"; static const std::string JSON_TAG_FILEID = "fileId"; static const std::string JSON_TAG_DATA = "data"; static const std::string JSON_TAG_SEQ = "seq"; static const std::string JSON_TAG_ANS = "answer"; static const std::string JSON_TAG_ERROR_CODE = "errorCode"; static const std::string JSON_VAL_CMD_ACTIVATE = "activate"; static const std::string JSON_VAL_CMD_RESET = "reset"; static const std::string JSON_VAL_CMD_READ = "read"; static const std::string JSON_VAL_CMD_WRITE = "write"; static const std::string JSON_VAL_CMD_PRINT = "print"; static const std::string JSON_VAL_ANS_ACTIVATE_ACK = "activate_ack"; static const std::string JSON_VAL_ANS_ACTIVATE_FAILED = "activate_failed"; static const std::string JSON_VAL_ANS_RESET_ACK = "reset_ack"; static const std::string JSON_VAL_ANS_RESET_FAILED = "reset_failed"; static const std::string JSON_VAL_ANS_READ_ACK = "read_ack"; static const std::string JSON_VAL_ANS_READ_FAILED = "read_failed"; static const std::string JSON_VAL_ANS_WRITE_ACK = "write_ack"; static const std::string JSON_VAL_ANS_WRITE_FAILED = "write_failed"; static const std::string JSON_VAL_ANS_PRINT_ACK = "print_ack"; static const std::string JSON_VAL_ANS_PRINT_FAILED = "print_failed"; static const std::string JSON_VAL_FILEID_DILI_CARD = "00"; static const std::string JSON_VAL_FILEID_DILI_CARD_BASIC_INFO = "01"; static const std::string JSON_VAL_FILEID_DILI_CARD_SERVICE_INFO = "02"; // Service info. static const std::string JSON_VAL_FILEID_ID_CARD = "10"; static const std::string JSON_VAL_FILEID_PIN_PAD = "11"; static const std::string JSON_VAL_FILEID_BANK_CARD_NUM = "20"; static const std::string JSON_VAL_FILEID_DILI_CARD_AND_BANK = "30"; static const std::string JSON_VAL_FILEID_ORDER = "40"; static const std::string JSON_VAL_FILEID_DISTRIBUTE = "41"; struct HWRequest { std::string cmd; std::string file_id; std::string data; std::string seq; // The sequence number of the request. }; HWRequest ParseRequest(const std::string& request_json) { PT::ptree ptree; std::stringstream ss; ss << request_json; PT::read_json(ss, ptree); std::string cmd = ptree.get<std::string>(JSON_TAG_CMD); std::string file_id = ptree.get<std::string>(JSON_TAG_FILEID); std::string data; if (cmd.compare(JSON_VAL_CMD_PRINT) == 0 && file_id.compare(JSON_VAL_FILEID_ORDER) == 0) { PT::ptree data_child = ptree.get_child(JSON_TAG_DATA); std::ostringstream os; PT::write_json(os, data_child); CString data_t = str_2_wstr(std::string(os.str())).c_str(); data = CT2A(data_t); } else { data = ptree.get<std::string>(JSON_TAG_DATA); } std::string seq = ptree.get<std::string>(JSON_TAG_SEQ); return{ cmd, file_id, data, seq }; } std::string MakeResultJSON(const std::string& answer, const std::string& file_id, const std::string& error_code, const std::string& seq, const PT::ptree& data) { PT::ptree root; root.put(JSON_TAG_ANS, answer); root.put(JSON_TAG_FILEID, file_id); root.put_child(JSON_TAG_DATA, data); root.put(JSON_TAG_ERROR_CODE, error_code); root.put(JSON_TAG_SEQ, seq); std::stringstream ss; PT::write_json(ss, root, false); return ss.str(); } class HWRequestHandler { typedef boost::ptr_map<std::string, HardwareCmd> HardwareCmdMap; // Key: cmd+file_id. public: HWRequestHandler() { m_hw_cmd_map.insert(JSON_VAL_CMD_READ + JSON_VAL_FILEID_ID_CARD, new ReadIDCardCmd()); m_hw_cmd_map.insert(JSON_VAL_CMD_READ + JSON_VAL_FILEID_PIN_PAD, new ReadPINPadCmd()); m_hw_cmd_map.insert(JSON_VAL_CMD_ACTIVATE + JSON_VAL_FILEID_DILI_CARD, new ActivateDILICardCmd()); m_hw_cmd_map.insert(JSON_VAL_CMD_RESET + JSON_VAL_FILEID_DILI_CARD, new ResetDILICardCmd()); m_hw_cmd_map.insert(JSON_VAL_CMD_READ + JSON_VAL_FILEID_DILI_CARD_BASIC_INFO, new ReadDILICardBasicInfoCmd()); m_hw_cmd_map.insert(JSON_VAL_CMD_READ + JSON_VAL_FILEID_DILI_CARD_SERVICE_INFO, new ReadDILICardServiceInfoCmd()); m_hw_cmd_map.insert(JSON_VAL_CMD_WRITE + JSON_VAL_FILEID_DILI_CARD_SERVICE_INFO, new WriteDILICardServiceInfoCmd()); m_hw_cmd_map.insert(JSON_VAL_CMD_READ + JSON_VAL_FILEID_BANK_CARD_NUM, new ReadBankCardNumCmd()); m_hw_cmd_map.insert(JSON_VAL_CMD_READ + JSON_VAL_FILEID_DILI_CARD_AND_BANK, new ReadDILIAndBankCardNumCmd()); m_hw_cmd_map.insert(JSON_VAL_CMD_PRINT + JSON_VAL_FILEID_ORDER, new StylusPrinterCmd()); m_hw_cmd_map.insert(JSON_VAL_CMD_PRINT + JSON_VAL_FILEID_DISTRIBUTE, new DistributePrinterCmd()); } std::string HandleRequest(const std::string& request_json) { try { static const std::string OK = ""; // TODO maybe improve this use the same variable defined by "HardwareCmd". HWRequest hw_req = ParseRequest(request_json); LOG_TRACE(L"执行硬件调用请求:" + str_2_wstr("[" + hw_req.cmd + "," + hw_req.file_id + "," + hw_req.seq + "]")); HardwareCmd::Reply reply; std::string answer = ""; reply = m_hw_cmd_map.at(hw_req.cmd + hw_req.file_id).Execute(hw_req.data); if (boost::iequals(OK, reply.error_code)) // Succeed. answer = hw_req.cmd + "_ack"; else answer = hw_req.cmd + "_failed"; std::string reply_json = MakeResultJSON(answer, hw_req.file_id, reply.error_code, hw_req.seq, reply.data); LOG_TRACE(L"执行硬件调用结果:" + str_2_wstr("[" + hw_req.cmd + "," + hw_req.file_id + "," + hw_req.seq + "] [" + reply.error_code + "]") + +L"\n"); return reply_json; } catch (std::exception& ex) { LOG_FATAL(L"执行硬件调用请求发生异常,异常信息: " + str_2_wstr(ex.what()) + L"\n"); return ""; } } private: HardwareCmdMap m_hw_cmd_map; }; }; namespace { namespace PT = boost::property_tree; // Tag & value of the hardware function request & response string in JSON format. static const std::string JSON_TAG_CMD = "command"; static const std::string JSON_TAG_FILEID = "fileId"; static const std::string JSON_TAG_DATA = "data"; static const std::string JSON_TAG_SEQ = "seq"; static const std::string JSON_TAG_ANS = "answer"; static const std::string JSON_TAG_ERROR_CODE = "errorCode"; struct JSRequest { std::string cmd; std::string file_id; std::string data; std::string seq; // The sequence number of the request. }; JSRequest ParseRequest(const std::string& request_json) { PT::ptree ptree; std::stringstream ss; ss << request_json; PT::read_json(ss, ptree); std::string cmd = ptree.get<std::string>(JSON_TAG_CMD); std::string file_id = ptree.get<std::string>(JSON_TAG_FILEID); std::string data = ptree.get<std::string>(JSON_TAG_DATA); std::string seq = ptree.get<std::string>(JSON_TAG_SEQ); return{ cmd, file_id, data, seq }; } std::string MakeResultJSON(const std::string& answer, const std::string& file_id, const std::string& error_code, const std::string& seq, const PT::ptree& data = PT::ptree()) { PT::ptree root; root.put(JSON_TAG_ANS, answer); root.put(JSON_TAG_FILEID, file_id); root.put_child(JSON_TAG_DATA, data); root.put(JSON_TAG_ERROR_CODE, error_code); root.put(JSON_TAG_SEQ, seq); std::stringstream ss; PT::write_json(ss, root, false); return ss.str(); } bool IsEqual(const std::string& str1, const std::string& str2) { return 0 == str1.compare(str2); } } namespace UI{ // Tag & value of the hardware function request & response string in JSON format. static const std::string JSON_VAL_CMD_CLOSE_WND = "close_wnd"; static const std::string JSON_VAL_CMD_USER_RELOGIN = "user_relogin"; static const std::string JSON_VAL_CMD_APP_EXIT = "app_exit"; static const std::string JSON_VAL_CMD_APP_RELAUNCH = "app_relauch"; static const std::string JSON_VAL_ANS_ACK = "_ack"; static const std::string JSON_VAL_ANS_FAILED = "_failed"; static const std::string OK = ""; // 操作成功. static const std::string ERR = "601"; // 操作失败. class UIRequestHandler { typedef std::map<std::string, int> UserInterfaceCmdMap; // Key: cmd+file_id. public: UIRequestHandler() { m_ui_cmd_map.insert(std::pair<std::string, int>(JSON_VAL_CMD_CLOSE_WND, WM_CEF_JS_CAMMAND_CLOSE_WND)); m_ui_cmd_map.insert(std::pair<std::string, int>(JSON_VAL_CMD_USER_RELOGIN, WM_CEF_JS_CAMMAND_USER_RELOGIN)); m_ui_cmd_map.insert(std::pair<std::string, int>(JSON_VAL_CMD_APP_EXIT, WM_CEF_JS_CAMMAND_APP_EXIT)); m_ui_cmd_map.insert(std::pair<std::string, int>(JSON_VAL_CMD_APP_RELAUNCH, WM_CEF_JS_CAMMAND_APP_RELAUNCH)); } std::string HandleRequest(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, const CefString& request_json) { JSRequest js_rq = ParseRequest(request_json); try { auto w_hand = ::GetParent(browser->GetHost()->GetWindowHandle()); auto w_message = m_ui_cmd_map.at(js_rq.cmd); ::PostMessage(w_hand, w_message, NULL, NULL); return MakeResultJSON(js_rq.cmd + JSON_VAL_ANS_ACK, js_rq.file_id, OK, js_rq.seq); } catch (std::exception& ex) { LOG_FATAL(L"执行UI调用请求发生异常,异常信息: " + str_2_wstr(ex.what()) + L"\n"); return MakeResultJSON(js_rq.cmd + JSON_VAL_ANS_FAILED, js_rq.file_id, ERR, js_rq.seq); } } private: UserInterfaceCmdMap m_ui_cmd_map; }; } namespace { /*Callback handler for call the hardware function.*/ class Handler : public CefMessageRouterBrowserSide::Handler { public: // This handler function will be called due to 'window.cefQuery' call in web page's JavaScript. virtual bool OnQuery(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, int64 query_id, const CefString& request_json, bool persistent, CefRefPtr<Callback> callback) OVERRIDE { // Only handle the message from our own host. This is an important security check! CefString url_ = frame->GetURL(); if (!CheckHost(url_.ToString())) return false; //callback->Success(m_hw_req_handler.HandleRequest(request_json)); Handing(browser, frame, request_json, callback); return true; } private: bool CheckHost(const std::string& url_) { std::smatch match_res; if (!URLRegex::Parse(url_, match_res)) return false; return 0 == URLConfig::Instance().Host().compare(match_res[3].str()); } private: //HWRequestHandler m_hw_req_handler; virtual void Handing(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, const CefString& request_json, CefRefPtr<Callback> callback) = 0; }; class HWHandle :public Handler { private: void Handing(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, const CefString& request_json, CefRefPtr<Callback> callback) { callback->Success(m_hw_req_handler.HandleRequest(request_json)); } private: HW::HWRequestHandler m_hw_req_handler; }; class UIHandle :public Handler { private: void Handing(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, const CefString& request_json, CefRefPtr<Callback> callback) { callback->Success(m_ui_req_handler.HandleRequest(browser, frame, request_json)); } private: UI::UIRequestHandler m_ui_req_handler; }; } namespace AsyncJSCallbackHandler { // Handler creation. Called from MainViewBrowserHandler. //void Create(MainViewBrowserHandler::MessageHandlerSet& handlers) //{ // //TODO: need exception handling here? return true/false indicator? // handlers.emplace(new HW::Handler()); //} // Handler creation. Called from MainViewBrowserHandler. void HW_Create(MainViewBrowserHandler::MessageHandlerSet& handlers) { //TODO: need exception handling here? return true/false indicator? handlers.emplace(new HWHandle()); } // Handler creation. Called from PopupBrowserHandler(CreateMerchantView). void UI_Create(PopupBrowserHandler::MessageHandlerSet& handlers) { //TODO: need exception handling here? return true/false indicator? handlers.emplace(new UIHandle()); } } // AsyncJSCallbackHandler