|
@@ -0,0 +1,1191 @@
|
|
|
+/**
|
|
|
+*
|
|
|
+* @file web_service.hpp
|
|
|
+* @author zxw
|
|
|
+* Copyright 2024, yjrobotics. All rights reserved.
|
|
|
+*
|
|
|
+* robotics
|
|
|
+*
|
|
|
+*/
|
|
|
+#pragma once
|
|
|
+//stl
|
|
|
+#include <iostream>
|
|
|
+//robotics
|
|
|
+#include <robotics/logger.hpp>
|
|
|
+#include <robotics/datetime.hpp>
|
|
|
+//asio
|
|
|
+#include <asio2/asio2.hpp>
|
|
|
+//rttr
|
|
|
+#include <rttr/registration>
|
|
|
+//boost
|
|
|
+#include <boost/foreach.hpp>
|
|
|
+#include <boost/property_tree/ptree.hpp>
|
|
|
+#include <boost/property_tree/xml_parser.hpp>
|
|
|
+
|
|
|
+namespace robotics::v3 {
|
|
|
+ class soap_reflect {
|
|
|
+ public:
|
|
|
+ static void get_object_value(rttr::instance obj, std::map<std::string, std::string>& values) {
|
|
|
+ auto propertys = obj.get_type().get_properties();
|
|
|
+ for (auto& property : propertys) {
|
|
|
+ std::string prop_name(property.get_name());
|
|
|
+ rttr::variant prop_value = property.get_value(obj);
|
|
|
+ rttr::type prop_type = property.get_type();
|
|
|
+ if (prop_type == rttr::type::get<int>()) {
|
|
|
+ values[prop_name] = std::to_string(prop_value.get_value<int>());
|
|
|
+ }
|
|
|
+ else if (prop_type == rttr::type::get<std::int64_t>()) {
|
|
|
+ values[prop_name] = std::to_string(prop_value.get_value<std::int64_t>());
|
|
|
+ }
|
|
|
+ else if (prop_type == rttr::type::get<float>()) {
|
|
|
+ values[prop_name] = format("%1$.2f", prop_value.get_value<float>());
|
|
|
+ }
|
|
|
+ else if (prop_type == rttr::type::get<double>()) {
|
|
|
+ values[prop_name] = format("%1$.2f", prop_value.get_value<double>());
|
|
|
+ }
|
|
|
+ else if (prop_type == rttr::type::get<long>()) {
|
|
|
+ values[prop_name] = std::to_string(prop_value.get_value<long>());
|
|
|
+ }
|
|
|
+ else if (prop_type == rttr::type::get<bool>()) {
|
|
|
+ values[prop_name] = prop_value.get_value<bool>() ? "true" : "false";
|
|
|
+ }
|
|
|
+ else if (prop_type == rttr::type::get<std::string>()) {
|
|
|
+ values[prop_name] = prop_value.get_value<std::string>();
|
|
|
+ }
|
|
|
+ else if (prop_type == rttr::type::get<v3::datetime>()) {
|
|
|
+ values[prop_name] = prop_value.get_value<v3::datetime>().to_string();
|
|
|
+ }
|
|
|
+ else if (prop_type == rttr::type::get<std::vector<int>>()) {
|
|
|
+ auto vecValue = prop_value.get_value<std::vector<int>>();
|
|
|
+ values[prop_name] = join(vecValue, ",");
|
|
|
+ }
|
|
|
+ else if (prop_type == rttr::type::get<std::vector<std::int64_t>>()) {
|
|
|
+ auto vecValue = prop_value.get_value<std::vector<std::int64_t>>();
|
|
|
+ values[prop_name] = join(vecValue, ",");
|
|
|
+ }
|
|
|
+ else if (prop_type == rttr::type::get<std::vector<float>>()) {
|
|
|
+ auto vecValue = prop_value.get_value<std::vector<float>>();
|
|
|
+ values[prop_name] = join(vecValue, ",");
|
|
|
+ }
|
|
|
+ else if (prop_type == rttr::type::get<std::vector<double>>()) {
|
|
|
+ auto vecValue = prop_value.get_value<std::vector<double>>();
|
|
|
+ values[prop_name] = join(vecValue, ",");
|
|
|
+ }
|
|
|
+ else if (prop_type == rttr::type::get<std::vector<long>>()) {
|
|
|
+ auto vecValue = prop_value.get_value<std::vector<long>>();
|
|
|
+ values[prop_name] = join(vecValue, ",");
|
|
|
+ }
|
|
|
+ else if (prop_type == rttr::type::get<std::vector<bool>>()) {
|
|
|
+ auto vecValue = prop_value.get_value<std::vector<bool>>();
|
|
|
+ values[prop_name] = join(vecValue, ",");
|
|
|
+ }
|
|
|
+ else if (prop_type == rttr::type::get<std::vector<std::string>>()) {
|
|
|
+ auto vecValue = prop_value.get_value<std::vector<std::string>>();
|
|
|
+ values[prop_name] = join(vecValue, ",");
|
|
|
+ }
|
|
|
+ else if (prop_type == rttr::type::get<std::vector<v3::datetime>>()) {
|
|
|
+ auto vecValue = prop_value.get_value<std::vector<v3::datetime>>();
|
|
|
+ values[prop_name] = join(vecValue, ",");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ static void set_object_value(rttr::instance obj, std::map<std::string, std::string>& values) {
|
|
|
+ rttr::instance obj1 = obj.get_type().get_raw_type().is_wrapper() ? obj.get_wrapped_instance() : obj;
|
|
|
+ const auto propertys = obj1.get_derived_type().get_properties();
|
|
|
+ for (auto& property : propertys) {
|
|
|
+ auto name = std::string(property.get_name());
|
|
|
+ auto type = property.get_type();
|
|
|
+ if (values.find(name) == values.end())
|
|
|
+ continue;
|
|
|
+ std::string value = values[name];
|
|
|
+ if (type == rttr::type::get<int>()) {
|
|
|
+ property.set_value(obj1, atoi(value.c_str()));
|
|
|
+ }
|
|
|
+ else if (type == rttr::type::get<std::int64_t>()) {
|
|
|
+ property.set_value(obj, std::int64_t(std::atoll(value.c_str())));
|
|
|
+ }
|
|
|
+ else if (type == rttr::type::get<float>()) {
|
|
|
+ property.set_value(obj, float(std::atof(value.c_str())));
|
|
|
+ }
|
|
|
+ else if (type == rttr::type::get<double>()) {
|
|
|
+ property.set_value(obj, double(std::atof(value.c_str())));
|
|
|
+ }
|
|
|
+ else if (type == rttr::type::get<long>()) {
|
|
|
+ property.set_value(obj, long(std::atol(value.c_str())));
|
|
|
+ }
|
|
|
+ else if (type == rttr::type::get<bool>()) {
|
|
|
+ if (value == "1" || value == "true" || value == "TRUE" || value == "True") {
|
|
|
+ property.set_value(obj, true);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ property.set_value(obj, false);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (type == rttr::type::get<std::string>()) {
|
|
|
+ property.set_value(obj, value);
|
|
|
+ }
|
|
|
+ else if (type == rttr::type::get<v3::datetime>()) {
|
|
|
+ property.set_value(obj, v3::datetime(value));
|
|
|
+ }
|
|
|
+ else if (type == rttr::type::get<std::vector<int>>()) {
|
|
|
+ std::vector<std::string> vec = split(value, ",");
|
|
|
+ std::vector<int> vecValue;
|
|
|
+ for (auto vecIt : vec) {
|
|
|
+ vecValue.push_back(std::atoi(vecIt.c_str()));
|
|
|
+ }
|
|
|
+ property.set_value(obj, vecValue);
|
|
|
+ }
|
|
|
+ else if (type == rttr::type::get<std::vector<std::int64_t>>()) {
|
|
|
+ std::vector<std::string> vec = split(value, ",");
|
|
|
+ std::vector<std::int64_t> vecValue;
|
|
|
+ for (auto vecIt : vec) {
|
|
|
+ vecValue.push_back(std::atoll(vecIt.c_str()));
|
|
|
+ }
|
|
|
+ property.set_value(obj, vecValue);
|
|
|
+ }
|
|
|
+ else if (type == rttr::type::get<std::vector<float>>()) {
|
|
|
+ std::vector<std::string> vec = split(value, ",");
|
|
|
+ std::vector<float> vecValue;
|
|
|
+ for (auto vecIt : vec) {
|
|
|
+ vecValue.push_back(std::atof(vecIt.c_str()));
|
|
|
+ }
|
|
|
+ property.set_value(obj, vecValue);
|
|
|
+ }
|
|
|
+ else if (type == rttr::type::get<std::vector<double>>()) {
|
|
|
+ std::vector<std::string> vec = split(value, ",");
|
|
|
+ std::vector<double> vecValue;
|
|
|
+ for (auto vecIt : vec) {
|
|
|
+ vecValue.push_back(std::atof(vecIt.c_str()));
|
|
|
+ }
|
|
|
+ property.set_value(obj, vecValue);
|
|
|
+ }
|
|
|
+ else if (type == rttr::type::get<std::vector<long>>()) {
|
|
|
+ std::vector<std::string> vec = split(value, ",");
|
|
|
+ std::vector<long> vecValue;
|
|
|
+ for (auto vecIt : vec) {
|
|
|
+ vecValue.push_back(std::atol(vecIt.c_str()));
|
|
|
+ }
|
|
|
+ property.set_value(obj, vecValue);
|
|
|
+ }
|
|
|
+ else if (type == rttr::type::get<std::vector<bool>>()) {
|
|
|
+ std::vector<std::string> vec = split(value, ",");
|
|
|
+ std::vector<bool> vecValue;
|
|
|
+ for (auto vecIt : vec) {
|
|
|
+ vecValue.push_back(vecIt == "1" || vecIt == "true" || vecIt == "TRUE" || vecIt == "True");
|
|
|
+ }
|
|
|
+ property.set_value(obj, vecValue);
|
|
|
+ }
|
|
|
+ else if (type == rttr::type::get<std::vector<std::string>>()) {
|
|
|
+ std::vector<std::string> vecValue = split(value, ",");
|
|
|
+ property.set_value(obj, vecValue);
|
|
|
+ }
|
|
|
+ else if (type == rttr::type::get<std::vector<v3::datetime>>()) {
|
|
|
+ std::vector<std::string> vec = split(value, ",");
|
|
|
+ std::vector<v3::datetime> vecValue;
|
|
|
+ for (auto &vecIt : vec) {
|
|
|
+ vecValue.push_back(v3::datetime(vecIt));
|
|
|
+ }
|
|
|
+ property.set_value(obj, vecValue);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ struct soap_response {
|
|
|
+ soap_response(int value) :
|
|
|
+ value_(value) {
|
|
|
+ }
|
|
|
+ soap_response(std::int64_t value) :
|
|
|
+ value_(value) {
|
|
|
+ }
|
|
|
+ soap_response(float value) :
|
|
|
+ value_(value) {
|
|
|
+ }
|
|
|
+ soap_response(double value) :
|
|
|
+ value_(value) {
|
|
|
+ }
|
|
|
+ soap_response(long value) :
|
|
|
+ value_(value) {
|
|
|
+ }
|
|
|
+ soap_response(bool value) :
|
|
|
+ value_(value) {
|
|
|
+ }
|
|
|
+ soap_response(std::string const& value) :
|
|
|
+ value_(value) {
|
|
|
+ }
|
|
|
+ soap_response(v3::datetime const& value) :
|
|
|
+ value_(value) {
|
|
|
+ }
|
|
|
+ soap_response(const char* value) :
|
|
|
+ value_(value) {
|
|
|
+ }
|
|
|
+ soap_response(char* value) :
|
|
|
+ value_(value) {
|
|
|
+ }
|
|
|
+ rttr::variant get_value() {
|
|
|
+ return value_;
|
|
|
+ }
|
|
|
+ template<typename _Type>
|
|
|
+ soap_response(_Type const&value) :
|
|
|
+ value_(value) {
|
|
|
+ }
|
|
|
+ private:
|
|
|
+ rttr::variant value_;
|
|
|
+ };
|
|
|
+
|
|
|
+ struct xml_node_info {
|
|
|
+ std::string node_name; //当前节点名字
|
|
|
+ std::unordered_map<std::string, std::string> xml_attr; //当前节点的属性
|
|
|
+ std::vector<std::string> list_sub_name; //子节点名字
|
|
|
+ std::string parent_name; //父节点 记录了从根节点到上一个节点的名字,用"."隔开
|
|
|
+ std::string value; //当前节点的值
|
|
|
+ };
|
|
|
+
|
|
|
+ class xml_manage {
|
|
|
+ public:
|
|
|
+ void set_xml(std::string xml) {
|
|
|
+ xml_ = xml;
|
|
|
+ }
|
|
|
+ std::vector<xml_node_info> get_xml_node() {
|
|
|
+ xml_parse();
|
|
|
+ return xml_node_list_;
|
|
|
+ }
|
|
|
+ std::string get_xml() {
|
|
|
+ return xml_;
|
|
|
+ }
|
|
|
+ void set_ptree(boost::property_tree::ptree xml) {
|
|
|
+ std::ostringstream os;
|
|
|
+ boost::property_tree::write_xml(os, xml);
|
|
|
+ xml_ = os.str();
|
|
|
+ }
|
|
|
+ private:
|
|
|
+ void xml_parse() {
|
|
|
+ xml_node_list_.clear();
|
|
|
+ std::istringstream s1(xml_);
|
|
|
+ boost::property_tree::ptree pt;
|
|
|
+ boost::property_tree::read_xml(s1, pt);
|
|
|
+ xml_parse(pt, xml_node_list_);
|
|
|
+ }
|
|
|
+ void xml_parse(const boost::property_tree::ptree& pxml, std::vector<xml_node_info>& listNode, std::string strNode = "") {
|
|
|
+ for (const auto& node : pxml) {
|
|
|
+ std::string NodeKey = node.first.data(); //属性或者子节点
|
|
|
+ if (NodeKey == "<xmlattr>") {//判断是否是属性
|
|
|
+ continue; //属性已经在父节点中做了保存
|
|
|
+ }
|
|
|
+ xml_node_info xmlnode;
|
|
|
+ xmlnode.node_name = std::string(node.first.data()); //节点名
|
|
|
+ xmlnode.value = node.second.data(); //值
|
|
|
+ xmlnode.parent_name = strNode; //父节点是外面传入进来的
|
|
|
+ //获取该节点的属性
|
|
|
+ for (const auto& attr : node.second) {
|
|
|
+ std::string strAttr = attr.first.data();
|
|
|
+ if (std::string(strAttr) == "<xmlattr>") {//是属性
|
|
|
+ //获取属性的值
|
|
|
+ for (auto& att : attr.second) {
|
|
|
+ xmlnode.xml_attr[att.first.data()] = att.second.data();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {//节点自身
|
|
|
+ xmlnode.list_sub_name.emplace_back(strAttr); //当前节点的子节点名字
|
|
|
+ }
|
|
|
+ }
|
|
|
+ listNode.emplace_back(xmlnode); //保存当前节点
|
|
|
+ if (!NodeKey.empty()) {//当前节点
|
|
|
+ xmlnode.xml_attr.clear();
|
|
|
+ //获取子节点信息 递归
|
|
|
+ std::string str_parent_name;
|
|
|
+ if (!xmlnode.parent_name.empty()) {
|
|
|
+ str_parent_name += xmlnode.parent_name + "." + xmlnode.node_name;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ str_parent_name = xmlnode.node_name;
|
|
|
+ }
|
|
|
+ //生成父节点 写入XML的时候需要知道父节点
|
|
|
+ xml_parse(node.second, listNode, str_parent_name); //递归遍历
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ private:
|
|
|
+ std::string xml_;
|
|
|
+ std::vector<xml_node_info> xml_node_list_;
|
|
|
+ };
|
|
|
+
|
|
|
+ enum class soap_version {
|
|
|
+ VER1_1,
|
|
|
+ VER1_2
|
|
|
+ };
|
|
|
+
|
|
|
+ struct soap_parameter {
|
|
|
+ std::string method_name;
|
|
|
+ std::map<std::string, rttr::variant> req_parameters;
|
|
|
+ std::map<std::string, bool> req_parameters_namespace;
|
|
|
+ rttr::variant resp_parameter;
|
|
|
+ std::string xmlns_xsi = "http://www.w3.org/2001/XMLSchema-instance";
|
|
|
+ std::string xmlns_xsd = "http://www.w3.org/2001/XMLSchema";
|
|
|
+ std::string xmlns_soap = "http://schemas.xmlsoap.org/soap/envelope/";
|
|
|
+ std::string xmlns_soap12 = "http://www.w3.org/2003/05/soap-envelope";
|
|
|
+ std::string namespace_name;
|
|
|
+ std::string soap_action;
|
|
|
+ soap_version version = soap_version::VER1_1;
|
|
|
+ };
|
|
|
+
|
|
|
+ class soap_err_parser {
|
|
|
+ public:
|
|
|
+ typedef boost::property_tree::ptree xmltree;
|
|
|
+ static std::string get_soap_err(std::string const&type, std::string const& msg, soap_version version = soap_version::VER1_1) {
|
|
|
+ xmltree body;
|
|
|
+ xmltree fault;
|
|
|
+ xmltree envelope;
|
|
|
+ xmltree fault_message;
|
|
|
+ fault_message.add("detail", "");
|
|
|
+ fault_message.add("faultcode", type);
|
|
|
+ fault_message.add("faultstring", msg);
|
|
|
+ fault.add_child("soap:Fault", fault_message);
|
|
|
+ body.add_child("soap:Body", fault);
|
|
|
+ envelope.add_child("soap:Envelope", body);
|
|
|
+ if (version == soap_version::VER1_1) {
|
|
|
+ envelope.add("soap:Envelope.<xmlattr>.xmlns:soap", "http://schemas.xmlsoap.org/soap/envelope/");
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ envelope.add("soap:Envelope.<xmlattr>.xmlns:soap12", "http://www.w3.org/2003/05/soap-envelope");
|
|
|
+ }
|
|
|
+ envelope.add("soap:Envelope.<xmlattr>.xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
|
|
|
+ envelope.add("soap:Envelope.<xmlattr>.xmlns:xsd", "http://www.w3.org/2001/XMLSchema");
|
|
|
+ std::ostringstream os;
|
|
|
+ boost::property_tree::xml_writer_settings<std::string> settings =
|
|
|
+ boost::property_tree::xml_writer_make_settings<std::string>(' ', 4);
|
|
|
+ boost::property_tree::write_xml(os, envelope, settings);
|
|
|
+ return os.str();
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ class soap_server_resp_parser {
|
|
|
+ public:
|
|
|
+ typedef boost::property_tree::ptree xmltree;
|
|
|
+ std::string get_xml(soap_parameter parameter) {
|
|
|
+ add_value(parameter.method_name, parameter.resp_parameter);
|
|
|
+ method_response_.add_child(parameter.method_name + "Response", method_request_);
|
|
|
+ method_response_.add(parameter.method_name + "Response.<xmlattr>.xmlns", parameter.namespace_name);
|
|
|
+ body_.add_child("soap:Body", method_response_);
|
|
|
+ envelope_.add_child("soap:Envelope", body_);
|
|
|
+ if (parameter.version == soap_version::VER1_1) {
|
|
|
+ envelope_.add("soap:Envelope.<xmlattr>.xmlns:soap", parameter.xmlns_soap);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ envelope_.add("soap:Envelope.<xmlattr>.xmlns:soap12", parameter.xmlns_soap12);
|
|
|
+ }
|
|
|
+ envelope_.add("soap:Envelope.<xmlattr>.xmlns:xsi", parameter.xmlns_xsi);
|
|
|
+ envelope_.add("soap:Envelope.<xmlattr>.xmlns:xsd", parameter.xmlns_xsd);
|
|
|
+ std::ostringstream os;
|
|
|
+ boost::property_tree::xml_writer_settings<std::string> settings =
|
|
|
+ boost::property_tree::xml_writer_make_settings<std::string>(' ', 4);
|
|
|
+ boost::property_tree::write_xml(os, envelope_, settings);
|
|
|
+ return os.str();
|
|
|
+ }
|
|
|
+ private:
|
|
|
+ void add_value(std::string const&method_name, rttr::variant value) {
|
|
|
+ if (value.get_type() == rttr::type::get<int>()) {
|
|
|
+ method_request_.put(method_name + "Result", value.get_value<int>());
|
|
|
+ }
|
|
|
+ else if (value.get_type() == rttr::type::get<__int64>()) {
|
|
|
+ method_request_.put(method_name + "Result", value.get_value<__int64>());
|
|
|
+ }
|
|
|
+ else if (value.get_type() == rttr::type::get<float>()) {
|
|
|
+ method_request_.put(method_name + "Result", value.get_value<float>());
|
|
|
+ }
|
|
|
+ else if (value.get_type() == rttr::type::get<double>()) {
|
|
|
+ method_request_.put(method_name + "Result", value.get_value<double>());
|
|
|
+ }
|
|
|
+ else if (value.get_type() == rttr::type::get<long>()) {
|
|
|
+ method_request_.put(method_name + "Result", value.get_value<long>());
|
|
|
+ }
|
|
|
+ else if (value.get_type() == rttr::type::get<bool>()) {
|
|
|
+ method_request_.put(method_name + "Result", value.get_value<bool>() ? "True" : "False");
|
|
|
+ }
|
|
|
+ else if (value.get_type() == rttr::type::get<std::string>()) {
|
|
|
+ method_request_.put(method_name + "Result", value.get_value<std::string>());
|
|
|
+ }
|
|
|
+ else if (value.get_type() == rttr::type::get<const char*>()) {
|
|
|
+ method_request_.put(method_name + "Result", value.get_value<const char*>());
|
|
|
+ }
|
|
|
+ else if (value.get_type() == rttr::type::get<v3::DateTime>()) {
|
|
|
+ method_request_.put(method_name + "Result", value.get_value<v3::DateTime>().getFormatDateTime());
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ std::map<std::string, std::string> property_values;
|
|
|
+ soap_reflect::get_object_value(value, property_values);
|
|
|
+ xmltree propertys;
|
|
|
+ for (auto& it : property_values) {
|
|
|
+ propertys.add(it.first, it.second);
|
|
|
+ }
|
|
|
+ method_request_.add_child(method_name + "Result", propertys);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ private:
|
|
|
+ xmltree body_;
|
|
|
+ xmltree envelope_;
|
|
|
+ xmltree method_request_;
|
|
|
+ xmltree method_response_;
|
|
|
+ };
|
|
|
+
|
|
|
+ class soap_server_req_parser {
|
|
|
+ public:
|
|
|
+ typedef boost::property_tree::ptree xmltree;
|
|
|
+ soap_parameter soap_parser(std::string const&xml) {
|
|
|
+ xml_manage _xml;
|
|
|
+ _xml.set_xml(xml);
|
|
|
+ auto xml_nodes = _xml.get_xml_node();
|
|
|
+ return xml_parser(xml_nodes);
|
|
|
+ }
|
|
|
+ private:
|
|
|
+ soap_parameter xml_parser(std::vector<xml_node_info> const&nodes) {
|
|
|
+ std::string tem_name;
|
|
|
+ std::string soapenv;
|
|
|
+ std::string method_name;
|
|
|
+ std::string namespace_name;
|
|
|
+ std::map<std::string, rttr::variant> _parameter;
|
|
|
+ soap_parameter parameter;
|
|
|
+ std::string envelope = "Envelope";
|
|
|
+ //获取soapenv
|
|
|
+ for (auto& it : nodes) {
|
|
|
+ size_t size = it.node_name.size();
|
|
|
+ if (size > envelope.size() && it.node_name.substr(size - envelope.size(), envelope.size()) == envelope) {
|
|
|
+ soapenv = it.node_name.substr(0, size - envelope.size() - 1);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //获取版本
|
|
|
+ for (auto& it : nodes) {
|
|
|
+ if (it.node_name == soapenv + ":Envelope") {
|
|
|
+ for (auto& attr : it.xml_attr) {
|
|
|
+ if (attr.second == parameter.xmlns_soap) {
|
|
|
+ parameter.version = soap_version::VER1_1;
|
|
|
+ }
|
|
|
+ else if (attr.second == parameter.xmlns_soap12) {
|
|
|
+ parameter.version = soap_version::VER1_2;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //获取命名空间1
|
|
|
+ for (auto& it : nodes) {
|
|
|
+ if (it.parent_name == soapenv + ":Envelope." + soapenv + ":Body") {
|
|
|
+ for (auto& attr : it.xml_attr) {
|
|
|
+ if (attr.first == "xmlns") {
|
|
|
+ namespace_name = attr.second;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //获取命名空间2
|
|
|
+ if (namespace_name.empty()) {
|
|
|
+ for (auto& it : nodes) {
|
|
|
+ if (it.parent_name == soapenv + ":Envelope." + soapenv + ":Body") {
|
|
|
+ size_t size = it.node_name.size();
|
|
|
+ auto values = v3::split(it.node_name, ":");
|
|
|
+ if (values.size() == 2) {
|
|
|
+ for (auto& attr : nodes[0].xml_attr) {
|
|
|
+ if (attr.first == "xmlns:" + values[0]) {
|
|
|
+ namespace_name = attr.second;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //获取方法名称
|
|
|
+ for (auto& it : nodes) {
|
|
|
+ if (it.parent_name == soapenv + ":Envelope." + soapenv + ":Body") {
|
|
|
+ auto values = v3::split(it.node_name, ":");
|
|
|
+
|
|
|
+ if (values.size() == 2) {
|
|
|
+ tem_name = values[0];
|
|
|
+ method_name = values[1];
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ method_name = values[0];
|
|
|
+ }
|
|
|
+
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //获取参数
|
|
|
+ for (auto& it : nodes) {
|
|
|
+ if (it.parent_name == soapenv + ":Envelope." + soapenv + ":Body." +
|
|
|
+ (tem_name.empty() ? method_name : tem_name + ":" + method_name)) {
|
|
|
+
|
|
|
+ if (it.list_sub_name.size() == 0) {
|
|
|
+ auto values = v3::split(it.node_name, ":");
|
|
|
+
|
|
|
+ if (values.size() == 2) {
|
|
|
+ _parameter[values[1]] = it.value;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ _parameter[it.node_name] = it.value;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ std::string value = it.node_name;
|
|
|
+ std::map<std::string, std::string> tmpParameter;
|
|
|
+ for (auto& it1 : nodes) {
|
|
|
+ if (it1.parent_name == soapenv + ":Envelope." + soapenv + ":Body." +
|
|
|
+ (tem_name.empty() ? method_name + "." : tem_name + ":" + method_name + ".") + value) {
|
|
|
+
|
|
|
+ auto values = v3::split(it1.node_name, ":");
|
|
|
+ if (values.size() == 2) {
|
|
|
+ tmpParameter[values[1]] = it1.value;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ tmpParameter[it1.node_name] = it1.value;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ auto values1 = v3::split(it.node_name, ":");
|
|
|
+ if (values1.size() == 2) {
|
|
|
+ _parameter[values1[1]] = tmpParameter;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ _parameter[it.node_name] = tmpParameter;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ parameter.method_name = method_name;
|
|
|
+ parameter.namespace_name = namespace_name;
|
|
|
+ parameter.req_parameters = _parameter;
|
|
|
+ parameter.soap_action = namespace_name + method_name;
|
|
|
+ return parameter;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ class soap_client_req_parser {
|
|
|
+ public:
|
|
|
+ typedef boost::property_tree::ptree xmltree;
|
|
|
+ std::string get_xml(soap_parameter const¶meter) {
|
|
|
+ add_value(parameter.method_name, parameter.req_parameters, parameter.req_parameters_namespace);
|
|
|
+ method_request_.add(parameter.method_name + ".<xmlattr>.xmlns", parameter.namespace_name);
|
|
|
+ body_.add_child("soap:Body", method_request_);
|
|
|
+ envelope_.add_child("soap:Envelope", body_);
|
|
|
+ if (parameter.version == soap_version::VER1_1) {
|
|
|
+ envelope_.add("soap:Envelope.<xmlattr>.xmlns:soap", parameter.xmlns_soap);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ envelope_.add("soap:Envelope.<xmlattr>.xmlns:soap12", parameter.xmlns_soap12);
|
|
|
+ }
|
|
|
+ envelope_.add("soap:Envelope.<xmlattr>.xmlns:xsi", parameter.xmlns_xsi);
|
|
|
+ envelope_.add("soap:Envelope.<xmlattr>.xmlns:xsd", parameter.xmlns_xsd);
|
|
|
+ std::ostringstream os;
|
|
|
+ boost::property_tree::xml_writer_settings<std::string> settings =
|
|
|
+ boost::property_tree::xml_writer_make_settings<std::string>(' ', 4);
|
|
|
+ boost::property_tree::write_xml(os, envelope_, settings);
|
|
|
+ return os.str();
|
|
|
+ }
|
|
|
+ private:
|
|
|
+ void add_value(std::string const&method_name, std::map<std::string, rttr::variant> const& values, std::map<std::string, bool> const& namespaces) {
|
|
|
+ xmltree parameters;
|
|
|
+ for (auto& value : values) {
|
|
|
+ if (value.second.get_type() == rttr::type::get<int>()) {
|
|
|
+ parameters.add(value.first, value.second.get_value<int>());
|
|
|
+ if (namespaces.find(value.first) != namespaces.end() && namespaces[value.first])
|
|
|
+ parameters.add(v3::format("%1%.<xmlattr>.xmlns", value.first), "");
|
|
|
+ }
|
|
|
+ else if (value.second.get_type() == rttr::type::get<std::int64_t>()) {
|
|
|
+ parameters.add(value.first, value.second.get_value<std::int64_t>());
|
|
|
+ if (namespaces.find(value.first) != namespaces.end() && namespaces[value.first])
|
|
|
+ parameters.add(v3::format("%1%.<xmlattr>.xmlns", value.first), "");
|
|
|
+ }
|
|
|
+ else if (value.second.get_type() == rttr::type::get<float>()) {
|
|
|
+ parameters.add(value.first, value.second.get_value<float>());
|
|
|
+ if (namespaces.find(value.first) != namespaces.end() && namespaces[value.first])
|
|
|
+ parameters.add(v3::format("%1%.<xmlattr>.xmlns", value.first), "");
|
|
|
+ }
|
|
|
+ else if (value.second.get_type() == rttr::type::get<double>()) {
|
|
|
+ parameters.add(value.first, value.second.get_value<double>());
|
|
|
+ if (namespaces.find(value.first) != namespaces.end() && namespaces[value.first])
|
|
|
+ parameters.add(v3::format("%1%.<xmlattr>.xmlns", value.first), "");
|
|
|
+ }
|
|
|
+ else if (value.second.get_type() == rttr::type::get<long>()) {
|
|
|
+ parameters.add(value.first, value.second.get_value<long>());
|
|
|
+ if (namespaces.find(value.first) != namespaces.end() && namespaces[value.first])
|
|
|
+ parameters.add(v3::format("%1%.<xmlattr>.xmlns", value.first), "");
|
|
|
+ }
|
|
|
+ else if (value.second.get_type() == rttr::type::get<bool>()) {
|
|
|
+ parameters.add(value.first, value.second.get_value<bool>() ? "True" : "False");
|
|
|
+ if (namespaces.find(value.first) != namespaces.end() && namespaces[value.first])
|
|
|
+ parameters.add(v3::format("%1%.<xmlattr>.xmlns", value.first), "");
|
|
|
+ }
|
|
|
+ else if (value.second.get_type() == rttr::type::get<std::string>()) {
|
|
|
+ parameters.add(value.first, value.second.get_value<std::string>());
|
|
|
+ if (namespaces.find(value.first) != namespaces.end() && namespaces[value.first])
|
|
|
+ parameters.add(v3::format("%1%.<xmlattr>.xmlns", value.first), "");
|
|
|
+ }
|
|
|
+ else if (value.second.get_type() == rttr::type::get<const char*>()) {
|
|
|
+ parameters.add(value.first, value.second.get_value<const char*>());
|
|
|
+ if (namespaces.find(value.first) != namespaces.end() && namespaces[value.first])
|
|
|
+ parameters.add(v3::format("%1%.<xmlattr>.xmlns", value.first), "");
|
|
|
+ }
|
|
|
+ else if (value.second.get_type() == rttr::type::get<v3::datetime>()) {
|
|
|
+ parameters.add(value.first, value.second.get_value<v3::datetime>().to_string());
|
|
|
+ if (namespaces.find(value.first) != namespaces.end() && namespaces[value.first])
|
|
|
+ parameters.add(v3::format("%1%.<xmlattr>.xmlns", value.first), "");
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ std::map<std::string, std::string> property_values;
|
|
|
+ v3::soap_reflect::get_object_value(value.second, property_values);
|
|
|
+ xmltree propertys;
|
|
|
+ for (auto& it : property_values) {
|
|
|
+ propertys.add(it.first, it.second);
|
|
|
+ }
|
|
|
+ parameters.add_child(value.first, propertys);
|
|
|
+ if (namespaces.find(value.first) != namespaces.end() && namespaces[value.first])
|
|
|
+ parameters.add(v3::format("%1%.<xmlattr>.xmlns", value.first), "");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ method_request_.add_child(method_name, parameters);
|
|
|
+ }
|
|
|
+ private:
|
|
|
+ xmltree body_;
|
|
|
+ xmltree envelope_;
|
|
|
+ xmltree method_request_;
|
|
|
+ };
|
|
|
+
|
|
|
+ class soap_client_resp_parser {
|
|
|
+ public:
|
|
|
+ typedef boost::property_tree::ptree xmltree;
|
|
|
+ soap_parameter soap_parser(std::string const&xml) {
|
|
|
+ xml_manage _xml;
|
|
|
+ _xml.set_xml(xml);
|
|
|
+ auto xml_nodes = _xml.get_xml_node();
|
|
|
+ return xml_parser(xml_nodes);
|
|
|
+ }
|
|
|
+ private:
|
|
|
+ soap_parameter xml_parser(std::vector<xml_node_info> nodes) {
|
|
|
+ std::string tem_name;
|
|
|
+ std::string soapenv;
|
|
|
+ std::string method_name;
|
|
|
+ std::string namespace_name;
|
|
|
+ rttr::variant parameter_;
|
|
|
+ soap_parameter parameter;
|
|
|
+ std::string envelope = "Envelope";
|
|
|
+ std::string response = "Response";
|
|
|
+ for (auto& it : nodes) {
|
|
|
+ size_t size = it.node_name.size();
|
|
|
+ if (size > envelope.size() && it.node_name.substr(size - envelope.size(), envelope.size()) == envelope) {
|
|
|
+ soapenv = it.node_name.substr(0, size - envelope.size() - 1);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //获取版本
|
|
|
+ for (auto& it : nodes) {
|
|
|
+ if (it.node_name == soapenv + ":Envelope") {
|
|
|
+ for (auto& attr : it.xml_attr) {
|
|
|
+ if (attr.second == parameter.xmlns_soap) {
|
|
|
+ parameter.version = soap_version::VER1_1;
|
|
|
+ }
|
|
|
+ else if (attr.second == parameter.xmlns_soap12) {
|
|
|
+ parameter.version = soap_version::VER1_2;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //获取命名空间1
|
|
|
+ for (auto& it : nodes) {
|
|
|
+ if (it.parent_name == soapenv + ":Envelope." + soapenv + ":Body") {
|
|
|
+ size_t size = it.node_name.size();
|
|
|
+ if (size > response.size() && it.node_name.substr(size - response.size(), response.size()) == response) {
|
|
|
+ for (auto& attr : it.xml_attr) {
|
|
|
+ if (attr.first == "xmlns") {
|
|
|
+ namespace_name = attr.second;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //获取命名空间2
|
|
|
+ if (namespace_name.empty()) {
|
|
|
+ for (auto& it : nodes) {
|
|
|
+ if (it.parent_name == soapenv + ":Envelope." + soapenv + ":Body") {
|
|
|
+ size_t size = it.node_name.size();
|
|
|
+ if (size > response.size() && it.node_name.substr(size - response.size(), response.size()) == response) {
|
|
|
+ auto values = v3::split(it.node_name, ":");
|
|
|
+ if (values.size() == 2) {
|
|
|
+ for (auto& attr : it.xml_attr) {
|
|
|
+ if (attr.first == "xmlns:" + values[0]) {
|
|
|
+ namespace_name = attr.second;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //获取方法名称
|
|
|
+ for (auto& it : nodes) {
|
|
|
+ if (it.parent_name == soapenv + ":Envelope." + soapenv + ":Body") {
|
|
|
+ size_t size = it.node_name.size();
|
|
|
+ if (size > response.size() && it.node_name.substr(size - response.size(), response.size()) == response) {
|
|
|
+ auto values = v3::split(it.node_name, ":");
|
|
|
+ if (values.size() == 2) {
|
|
|
+ tem_name = values[0];
|
|
|
+ method_name = values[1];
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ method_name = values[0];
|
|
|
+ }
|
|
|
+ if (method_name.size() > response.size()) {
|
|
|
+ method_name.erase(method_name.size() - response.size(), response.size());
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //获取参数
|
|
|
+ for (auto& it : nodes) {
|
|
|
+ if (it.parent_name == soapenv + ":Envelope." + soapenv + ":Body." +
|
|
|
+ (tem_name.empty() ? method_name + "Response" : tem_name + ":" + method_name + "Response") &&
|
|
|
+ it.node_name == (tem_name.empty() ? method_name + "Result" : tem_name + ":" + method_name + "Result")) {
|
|
|
+ if (it.list_sub_name.size() == 0) {
|
|
|
+ parameter_ = it.value;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ parameter_ = std::map<std::string, std::string>();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (it.parent_name == soapenv + ":Envelope." + soapenv + ":Body." +
|
|
|
+ (tem_name.empty() ? method_name + "Response." : tem_name + ":" + method_name + "Response.") +
|
|
|
+ (tem_name.empty() ? method_name + "Result" : tem_name + ":" + method_name + "Result")) {
|
|
|
+ auto tmp_parameter = parameter_.get_value<std::map<std::string, std::string>>();
|
|
|
+ if (tem_name.empty()) {
|
|
|
+ tmp_parameter[it.node_name] = it.value;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ auto values = v3::split(it.node_name, ":");
|
|
|
+ if (values.size() == 2) {
|
|
|
+ tmp_parameter[values[1]] = it.value;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ tmp_parameter[it.node_name] = it.value;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ parameter_ = tmp_parameter;
|
|
|
+ }
|
|
|
+ else if (it.parent_name == soapenv + ":Envelope." + soapenv + ":Body." +
|
|
|
+ (tem_name.empty() ? method_name + "Response" : tem_name + ":" + method_name + "Response") &&
|
|
|
+ it.node_name == "return") {
|
|
|
+ if (it.list_sub_name.size() == 0) {
|
|
|
+ parameter_ = it.value;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ parameter_ = std::map<std::string, std::string>();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (it.parent_name == soapenv + ":Envelope." + soapenv + ":Body." +
|
|
|
+ (tem_name.empty() ? method_name + "Response." : tem_name + ":" + method_name + "Response.return")) {
|
|
|
+ auto tmp_parameter = parameter_.get_value<std::map<std::string, std::string>>();
|
|
|
+ if (tem_name.empty()) {
|
|
|
+ tmp_parameter[it.node_name] = it.value;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ auto values = v3::split(it.node_name, ":");
|
|
|
+ if (values.size() == 2) {
|
|
|
+ tmp_parameter[values[1]] = it.value;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ tmp_parameter[it.node_name] = it.value;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ parameter_ = tmp_parameter;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ parameter.method_name = method_name;
|
|
|
+ parameter.namespace_name = namespace_name;
|
|
|
+ parameter.resp_parameter = parameter_;
|
|
|
+ parameter.soap_action = namespace_name + method_name;
|
|
|
+ return parameter;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ enum class soap_argument_type {
|
|
|
+ Int = 1,
|
|
|
+ Int64,
|
|
|
+ Float,
|
|
|
+ Double,
|
|
|
+ Long,
|
|
|
+ Bool,
|
|
|
+ String,
|
|
|
+ DateTime
|
|
|
+ };
|
|
|
+
|
|
|
+ template<typename _Type>
|
|
|
+ struct soap_variant_value {
|
|
|
+ static _Type get_value(rttr::variant& value) {
|
|
|
+ _Type result;
|
|
|
+ auto map = value.get_value<std::map<std::string, std::string>>();
|
|
|
+ v3::soap_reflect::set_object_value(result, map);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ template<>
|
|
|
+ struct soap_variant_value<int> {
|
|
|
+ static int get_value(rttr::variant& value) {
|
|
|
+ return std::atoi(value.get_value<std::string>().c_str());
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ template<>
|
|
|
+ struct soap_variant_value<std::int64_t> {
|
|
|
+ static std::int64_t get_value(rttr::variant& value) {
|
|
|
+ return std::atoll(value.get_value<std::string>().c_str());
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ template<>
|
|
|
+ struct soap_variant_value<float> {
|
|
|
+ static float get_value(rttr::variant& value) {
|
|
|
+ return std::atof(value.get_value<std::string>().c_str());
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ template<>
|
|
|
+ struct soap_variant_value<double> {
|
|
|
+ static double get_value(rttr::variant& value) {
|
|
|
+ return std::atof(value.get_value<std::string>().c_str());
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ template<>
|
|
|
+ struct soap_variant_value<long> {
|
|
|
+ static long get_value(rttr::variant& value) {
|
|
|
+ return std::atol(value.get_value<std::string>().c_str());
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ template<>
|
|
|
+ struct soap_variant_value<bool> {
|
|
|
+ static bool get_value(rttr::variant& value) {
|
|
|
+ std::string v = value.get_value<std::string>();
|
|
|
+ return v == "true" || v == "True" || v == "TRUE";
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ template<>
|
|
|
+ struct soap_variant_value<std::string> {
|
|
|
+ static std::string get_value(rttr::variant& value) {
|
|
|
+ return value.get_value<std::string>();
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ template<>
|
|
|
+ struct soap_variant_value<v3::datetime> {
|
|
|
+ static v3::datetime get_value(rttr::variant& value) {
|
|
|
+ return v3::datetime(value.get_value<std::string>());
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ class soap_action_argument {
|
|
|
+ public:
|
|
|
+ void parameter(rttr::type type, rttr::variant value) {
|
|
|
+ try {
|
|
|
+ if (rttr::type::get<std::string>() != value.get_type())
|
|
|
+ throw std::runtime_error("parameter error");
|
|
|
+
|
|
|
+ std::string data = value.get_value<std::string>();
|
|
|
+
|
|
|
+ switch (argument_type_) {
|
|
|
+ case soap_argument_type::Int: {
|
|
|
+ parameter_value_ = std::atoi(data.c_str());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ case soap_argument_type::Int64: {
|
|
|
+ parameter_value_ = std::atoll(data.c_str());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ case soap_argument_type::Float: {
|
|
|
+ parameter_value_ = std::atof(data.c_str());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ case soap_argument_type::Double: {
|
|
|
+ parameter_value_ = std::atof(data.c_str());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ case soap_argument_type::Long: {
|
|
|
+ parameter_value_ = std::atol(data.c_str());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ case soap_argument_type::Bool: {
|
|
|
+ std::string tmpValue(data);
|
|
|
+ parameter_value_ = tmpValue == "1" || tmpValue == "true" || tmpValue == "TRUE" || tmpValue == "True";
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ case soap_argument_type::String: {
|
|
|
+ parameter_value_ = std::string(data);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ case soap_argument_type::DateTime: {
|
|
|
+ parameter_value_ = v3::DateTime(data);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (...) {
|
|
|
+ throw std::runtime_error("parameter error");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ std::string parameter_name_;
|
|
|
+ rttr::variant parameter_value_;
|
|
|
+ soap_argument_type argument_type_ = soap_argument_type::String;
|
|
|
+ };
|
|
|
+
|
|
|
+ class soap_controller_action {
|
|
|
+ public:
|
|
|
+ void invoke(http::web_request& request, rttr::variant& variant, rttr::type controller_type, soap_parameter& soap_parameter) {
|
|
|
+ std::vector<rttr::method> find_method;
|
|
|
+ for (auto& it : controller_type.get_methods()) {
|
|
|
+ if (it.get_name() == action_name && it.get_parameter_infos().size() == arguments.size()) {
|
|
|
+ find_method.push_back(it);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (find_method.empty())
|
|
|
+ throw std::runtime_error("method does not exist");
|
|
|
+ std::vector<rttr::argument> parameters;
|
|
|
+ {
|
|
|
+ std::lock_guard<std::mutex> locker(mutex_);
|
|
|
+ for (auto& it : find_method[0].get_parameter_infos()) {
|
|
|
+ std::shared_ptr<soap_action_argument> item = arguments[it.get_index()];
|
|
|
+ if (soap_parameter.req_parameters.find(item->parameter_name_) == soap_parameter.req_parameters.end())
|
|
|
+ throw std::runtime_error("parameter error");
|
|
|
+ item->parameter(it.get_type(), soap_parameter.req_parameters[item->parameter_name_]);
|
|
|
+ }
|
|
|
+ for (auto& it : arguments) {
|
|
|
+ parameters.push_back(it->parameter_value_);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ rttr::variant result = controller_type.invoke(action_name, variant, parameters);
|
|
|
+ soap_parameter.resp_parameter = result.get_value<soap_response>().getValue();
|
|
|
+ }
|
|
|
+ std::string action_name;
|
|
|
+ std::vector<std::shared_ptr<soap_action_argument>> arguments;
|
|
|
+ private:
|
|
|
+ std::mutex mutex_;
|
|
|
+ };
|
|
|
+
|
|
|
+ class soap_controller {
|
|
|
+ public:
|
|
|
+ soap_parameter invoke(http::web_request& request) {
|
|
|
+ soap_parameter soap_parameter = soap_server_req_parser().soap_parser(std::string(request.body().begin(), request.body().end()));
|
|
|
+
|
|
|
+ if (soap_parameter.namespace_name != namespace_name) {
|
|
|
+ throw std::runtime_error("namespace error");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (version != soap_parameter.version) {
|
|
|
+ throw std::runtime_error("version error");
|
|
|
+ }
|
|
|
+
|
|
|
+ rttr::type type = rttr::type::get_by_name(controller_name);
|
|
|
+ if (!variant_.is_valid())
|
|
|
+ variant_ = type.create();
|
|
|
+
|
|
|
+ actions[soap_parameter.method_name]->invoke(request, variant_, type, soap_parameter);
|
|
|
+
|
|
|
+ return soap_parameter;
|
|
|
+ }
|
|
|
+ std::string wsdl;
|
|
|
+ std::string route;
|
|
|
+ std::string namespace_name;
|
|
|
+ std::string controller_name;
|
|
|
+ soap_version version = soap_version::VER1_1;
|
|
|
+ std::map<std::string, std::shared_ptr<soap_controller_action>> actions;
|
|
|
+ private:
|
|
|
+ rttr::variant variant_;
|
|
|
+ std::string response_value_;
|
|
|
+ };
|
|
|
+
|
|
|
+ class soap_ioc_controller {
|
|
|
+ public:
|
|
|
+ static void attach(std::shared_ptr<soap_controller> controller) {
|
|
|
+ if (controllers_.find(controller->route) == controllers_.end()) {
|
|
|
+ controllers_[controller->route] = controller;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ static std::shared_ptr<soap_controller> resolve(std::string const&route) {
|
|
|
+ if (route.empty()) {
|
|
|
+ return nullptr;
|
|
|
+ }
|
|
|
+ if (controllers_.find(route) != controllers_.end()) {
|
|
|
+ return controllers_[route];
|
|
|
+ }
|
|
|
+ return nullptr;
|
|
|
+ }
|
|
|
+ static std::map<std::string, std::shared_ptr<soap_controller>> get_controllers() {
|
|
|
+ return controllers_;
|
|
|
+ }
|
|
|
+ private:
|
|
|
+ static std::map<std::string, std::shared_ptr<soap_controller>> controllers_;
|
|
|
+ };
|
|
|
+
|
|
|
+ class http_web_service {
|
|
|
+ public:
|
|
|
+ http_web_service() {
|
|
|
+ auto conrollers = soap_ioc_controller::get_controllers();
|
|
|
+ for (auto& it : conrollers) {
|
|
|
+ server_.bind<http::verb::post>("/" + it.first, &http_web_service::on_base_request, this);
|
|
|
+ server_.bind<http::verb::get>("/" + it.first, &http_web_service::on_base_wsdl, this);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief 启动
|
|
|
+ * @param host
|
|
|
+ * @param port
|
|
|
+ */
|
|
|
+ void start(std::string host = "0.0.0.0", int port = 80) {
|
|
|
+ _server->start(host, port);
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief 停止
|
|
|
+ */
|
|
|
+ void stop() {
|
|
|
+ _server->stop();
|
|
|
+ }
|
|
|
+ protected:
|
|
|
+ virtual void on_request(http::web_request& req, http::web_response& rep) = 0;
|
|
|
+ virtual void on_wsdl(http::web_request& req, http::web_response& rep) = 0;
|
|
|
+ private:
|
|
|
+ /**
|
|
|
+ * @brief 请求
|
|
|
+ * @param session
|
|
|
+ * @param req
|
|
|
+ * @param rep
|
|
|
+ */
|
|
|
+ void on_base_request(std::shared_ptr<asio2::http_session>& session, http::web_request& req, http::web_response& rep) {
|
|
|
+ on_request(req, rep);
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief wsdl
|
|
|
+ * @param session
|
|
|
+ * @param req
|
|
|
+ * @param rep
|
|
|
+ */
|
|
|
+ void on_base_wsdl(std::shared_ptr<asio2::http_session>& session, http::web_request& req, http::web_response& rep) {
|
|
|
+ on_wsdl(req, rep);
|
|
|
+ }
|
|
|
+ private:
|
|
|
+ asio2::http_server server_;
|
|
|
+ };
|
|
|
+
|
|
|
+ class https_web_service {
|
|
|
+ public:
|
|
|
+ https_web_service() {
|
|
|
+ auto conrollers = soap_ioc_controller::get_controllers();
|
|
|
+ for (auto& it : conrollers) {
|
|
|
+ server_.bind<http::verb::post>("/" + it.first, &https_web_service::on_base_request, this);
|
|
|
+ server_.bind<http::verb::get>("/" + it.first, &https_web_service::on_base_wsdl, this);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief 启动
|
|
|
+ * @param host
|
|
|
+ * @param port
|
|
|
+ */
|
|
|
+ void start(std::string host = "0.0.0.0", int port = 80) {
|
|
|
+ _server->start(host, port);
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief 停止
|
|
|
+ */
|
|
|
+ void stop() {
|
|
|
+ _server->stop();
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief 证书
|
|
|
+ * @param ca_cert_file
|
|
|
+ * @param private_cert_file
|
|
|
+ * @param private_key_file
|
|
|
+ * @param private_password
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ bool set_cert_file(std::string const&ca_cert_file, std::string const& private_cert_file, std::string const& private_key_file, std::string const& private_password) {
|
|
|
+ server_.set_cert_file(ca_cert_file, private_cert_file, private_key_file, private_password);
|
|
|
+ return (bool)asio2::get_last_error();
|
|
|
+ }
|
|
|
+ protected:
|
|
|
+ virtual void on_request(http::web_request& req, http::web_response& rep) = 0;
|
|
|
+ virtual void on_wsdl(http::web_request& req, http::web_response& rep) = 0;
|
|
|
+ private:
|
|
|
+ /**
|
|
|
+ * @brief 请求
|
|
|
+ * @param session
|
|
|
+ * @param req
|
|
|
+ * @param rep
|
|
|
+ */
|
|
|
+ void on_base_request(std::shared_ptr<asio2::https_session>& session, http::web_request& req, http::web_response& rep) {
|
|
|
+ on_request(req, rep);
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief wsdl
|
|
|
+ * @param session
|
|
|
+ * @param req
|
|
|
+ * @param rep
|
|
|
+ */
|
|
|
+ void on_base_wsdl(std::shared_ptr<asio2::https_session>& session, http::web_request& req, http::web_response& rep) {
|
|
|
+ on_wsdl(req, rep);
|
|
|
+ }
|
|
|
+ private:
|
|
|
+ asio2::https_server server_;
|
|
|
+ };
|
|
|
+
|
|
|
+ template<typename _HttpBase>
|
|
|
+ class web_service_base : public _HttpBase {
|
|
|
+ public:
|
|
|
+ web_service_base() :
|
|
|
+ _HttpBase() {
|
|
|
+ }
|
|
|
+ private:
|
|
|
+ /**
|
|
|
+ * @brief
|
|
|
+ * @param req
|
|
|
+ * @param rep
|
|
|
+ */
|
|
|
+ virtual void on_request(http::web_request& req, http::web_response& rep) override {
|
|
|
+ std::shared_ptr<soap_controller> controller = soap_ioc_controller::resolve(req.url().string().substr(1));
|
|
|
+ if (controller) {
|
|
|
+ std::string xml;
|
|
|
+ try {
|
|
|
+ soap_parameter soap_parameter = controller->invoke(req);
|
|
|
+ xml = soap_server_resp_parser().get_xml(soap_parameter);
|
|
|
+ }
|
|
|
+ catch (std::exception const&ec) {
|
|
|
+ xml = soap_err_parser::get_soap_err("soap::client", ec.what());
|
|
|
+ LOG_ERROR << ec;
|
|
|
+ }
|
|
|
+ rep.fill_text(xml, http::status::ok, "text/xml; charset=utf-8");
|
|
|
+ rep.chunked(true);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief
|
|
|
+ * @param req
|
|
|
+ * @param rep
|
|
|
+ */
|
|
|
+ virtual void on_wsdl(http::web_request& req, http::web_response& rep) override {
|
|
|
+ std::shared_ptr<soap_controller> controller = soap_ioc_controller::resolve(req.url().string().substr(1));
|
|
|
+ if (controller) {
|
|
|
+ rep.fill_file(controller->wsdl);
|
|
|
+ rep.chunked(true);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ rep.fill_page(http::status::not_found);
|
|
|
+ rep.chunked(true);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ template<typename _HttpBase>
|
|
|
+ using https_server = web_service_base<_HttpBase>;
|
|
|
+}
|