|
@@ -0,0 +1,2748 @@
|
|
|
+#pragma once
|
|
|
+#ifdef WINDOWS_BUILD
|
|
|
+#ifdef MVC_EXPORTS
|
|
|
+#define MVC_API _declspec(dllexport)
|
|
|
+#else
|
|
|
+#define MVC_API _declspec(dllimport)
|
|
|
+#endif
|
|
|
+#elif LINUX_BUILD
|
|
|
+#define MVC_API
|
|
|
+#endif
|
|
|
+//asio2
|
|
|
+#include <asio2/asio2.hpp>
|
|
|
+//robotics
|
|
|
+#include "../robot/robotics/utils.hpp"
|
|
|
+#include "../robot/robotics/json.hpp"
|
|
|
+#include "../robot/robotics/CImg.h"
|
|
|
+
|
|
|
+namespace robotics {
|
|
|
+ namespace v3 {
|
|
|
+ namespace mvc {
|
|
|
+ class web_reflect {
|
|
|
+ public:
|
|
|
+ /**
|
|
|
+ * @brief
|
|
|
+ * @param obj
|
|
|
+ */
|
|
|
+ static std::map<std::string, std::string> get_object_value(rttr::instance obj) {
|
|
|
+ std::map<std::string, std::string> result;
|
|
|
+ auto propertys = obj.get_type().get_properties();
|
|
|
+ for (auto& property : propertys) {
|
|
|
+ std::string propName(property.get_name());
|
|
|
+ rttr::variant propValue = property.get_value(obj);
|
|
|
+ rttr::type propType = property.get_type();
|
|
|
+ if (propType == rttr::type::get<int>()) {
|
|
|
+ result[propName] = std::to_string(propValue.get_value<int>());
|
|
|
+ }
|
|
|
+ else if (propType == rttr::type::get<std::int64_t>()) {
|
|
|
+ result[propName] = std::to_string(propValue.get_value<std::int64_t>());
|
|
|
+ }
|
|
|
+ else if (propType == rttr::type::get<float>()) {
|
|
|
+ result[propName] = v3::utils::format("{:.2f}", propValue.get_value<float>());
|
|
|
+ }
|
|
|
+ else if (propType == rttr::type::get<double>()) {
|
|
|
+ result[propName] = v3::utils::format("{:.2f}", propValue.get_value<double>());
|
|
|
+ }
|
|
|
+ else if (propType == rttr::type::get<long>()) {
|
|
|
+ result[propName] = std::to_string(propValue.get_value<long>());
|
|
|
+ }
|
|
|
+ else if (propType == rttr::type::get<bool>()) {
|
|
|
+ result[propName] = propValue.get_value<bool>() ? "true" : "false";
|
|
|
+ }
|
|
|
+ else if (propType == rttr::type::get<std::string>()) {
|
|
|
+ result[propName] = propValue.get_value<std::string>();
|
|
|
+ }
|
|
|
+ else if (propType == rttr::type::get<v3::datetime>()) {
|
|
|
+ result[propName] = propValue.get_value<v3::datetime>().to_string();
|
|
|
+ }
|
|
|
+ else if (propType == rttr::type::get<std::vector<int>>()) {
|
|
|
+ auto vecValue = propValue.get_value<std::vector<int>>();
|
|
|
+ result[propName] = v3::utils::join(vecValue, ",");
|
|
|
+ }
|
|
|
+ else if (propType == rttr::type::get<std::vector<std::int64_t>>()) {
|
|
|
+ auto vecValue = propValue.get_value<std::vector<std::int64_t>>();
|
|
|
+ result[propName] = v3::utils::join(vecValue, ",");
|
|
|
+ }
|
|
|
+ else if (propType == rttr::type::get<std::vector<float>>()) {
|
|
|
+ auto vecValue = propValue.get_value<std::vector<float>>();
|
|
|
+ result[propName] = v3::utils::join(vecValue, ",");
|
|
|
+ }
|
|
|
+ else if (propType == rttr::type::get<std::vector<double>>()) {
|
|
|
+ auto vecValue = propValue.get_value<std::vector<double>>();
|
|
|
+ result[propName] = v3::utils::join(vecValue, ",");
|
|
|
+ }
|
|
|
+ else if (propType == rttr::type::get<std::vector<long>>()) {
|
|
|
+ auto vecValue = propValue.get_value<std::vector<long>>();
|
|
|
+ result[propName] = v3::utils::join(vecValue, ",");
|
|
|
+ }
|
|
|
+ else if (propType == rttr::type::get<std::vector<bool>>()) {
|
|
|
+ auto vecValue = propValue.get_value<std::vector<bool>>();
|
|
|
+ result[propName] = v3::utils::join(vecValue, ",");
|
|
|
+ }
|
|
|
+ else if (propType == rttr::type::get<std::vector<std::string>>()) {
|
|
|
+ auto vecValue = propValue.get_value<std::vector<std::string>>();
|
|
|
+ result[propName] = v3::utils::join(vecValue, ",");
|
|
|
+ }
|
|
|
+ else if (propType == rttr::type::get<std::vector<v3::datetime>>()) {
|
|
|
+ auto vecValue = propValue.get_value<std::vector<v3::datetime>>();
|
|
|
+ result[propName] = v3::utils::join(vecValue, ",");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief
|
|
|
+ * @param obj
|
|
|
+ * @param values
|
|
|
+ */
|
|
|
+ static void set_object_value(rttr::instance obj, std::map<std::string, std::string>const& 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.contains(name))
|
|
|
+ continue;
|
|
|
+ std::string value = values.find(name)->second;
|
|
|
+ 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 = v3::utils::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 = v3::utils::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 = v3::utils::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 = v3::utils::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 = v3::utils::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 = v3::utils::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 = v3::utils::split(value, ",");
|
|
|
+ property.set_value(obj, vecValue);
|
|
|
+ }
|
|
|
+ else if (type == rttr::type::get<std::vector<v3::datetime>>()) {
|
|
|
+ std::vector<std::string> vec = v3::utils::split(value, ",");
|
|
|
+ std::vector<v3::datetime> vecValue;
|
|
|
+ for (auto vecIt : vec) {
|
|
|
+ vecValue.push_back(v3::datetime(vecIt));
|
|
|
+ }
|
|
|
+ property.set_value(obj, vecValue);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ class cookie_id {
|
|
|
+ public:
|
|
|
+ static std::string get_id() {
|
|
|
+ static std::string g_cookie_id;
|
|
|
+ if (g_cookie_id.empty()) {
|
|
|
+ g_cookie_id = v3::utils::uuid();
|
|
|
+ }
|
|
|
+ return g_cookie_id;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ class cookie {
|
|
|
+ public:
|
|
|
+ cookie() {
|
|
|
+ //name = "SessionId";
|
|
|
+ name = cookie_id::get_id();
|
|
|
+ value = v3::utils::base64_encode(v3::utils::uuid());
|
|
|
+ path = "path=/";
|
|
|
+ time = 30 * 60 * 1000;
|
|
|
+ last_expire_time = v3::datetime::current_time_stamp() + time;
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief cookie名称
|
|
|
+ */
|
|
|
+ std::string name;
|
|
|
+ /**
|
|
|
+ * @brief cookie值
|
|
|
+ */
|
|
|
+ std::string value;
|
|
|
+ /**
|
|
|
+ * @brief cookie路径
|
|
|
+ */
|
|
|
+ std::string path;
|
|
|
+ /**
|
|
|
+ * @brief cookie时间
|
|
|
+ */
|
|
|
+ time_t time = 0;
|
|
|
+ /**
|
|
|
+ * @brief 上次刷新时间
|
|
|
+ */
|
|
|
+ time_t last_expire_time = 0;
|
|
|
+ /**
|
|
|
+ * @brief 对比
|
|
|
+ * @param cookie
|
|
|
+ * @param remove
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ bool compare(std::shared_ptr<cookie> cookie, bool& remove) {
|
|
|
+ bool result = false;
|
|
|
+ remove = false;
|
|
|
+ if (cookie) {
|
|
|
+ result = (name == cookie->name && value == cookie->value);
|
|
|
+ if (result) {
|
|
|
+ time_t current_time = v3::datetime::current_time_stamp();
|
|
|
+ if (last_expire_time < current_time) {
|
|
|
+ remove = true;
|
|
|
+ result = false;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ last_expire_time = v3::datetime::current_time_stamp() + time;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ class cookies {
|
|
|
+ public:
|
|
|
+ /**
|
|
|
+ * @brief 解析
|
|
|
+ * @param cookie_str
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ static std::shared_ptr<cookies> analysis(std::string const& cookie_str) {
|
|
|
+ std::shared_ptr<cookies> result;
|
|
|
+ std::vector<std::string> cookies_tmp = v3::utils::split(cookie_str, ";");
|
|
|
+ for (auto& item : cookies_tmp) {
|
|
|
+ int index = item.find('=');
|
|
|
+ if (index == std::string::npos)
|
|
|
+ continue;
|
|
|
+ std::shared_ptr<cookie> add(new cookie);
|
|
|
+ add->name = item.substr(0, index);
|
|
|
+ add->value = item.substr(index + 1);
|
|
|
+ add->name = v3::utils::trim(add->name);
|
|
|
+ add->value = v3::utils::trim(add->value);
|
|
|
+ if (add->name != "path") {
|
|
|
+ if (!result) {
|
|
|
+ result.reset(new cookies);
|
|
|
+ }
|
|
|
+ result->cookies_.push_back(add);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief 对比
|
|
|
+ * @param value
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ bool compare(std::shared_ptr<cookies> value) {
|
|
|
+ bool result = false;
|
|
|
+ if (!value)
|
|
|
+ return result;
|
|
|
+ for (auto& value_elem : value->cookies_) {
|
|
|
+ for (int i = 0; i < cookies_.size(); ++i) {
|
|
|
+ bool is_remove = false;
|
|
|
+ bool exist = cookies_[i]->compare(value_elem, is_remove);
|
|
|
+ if (is_remove) {
|
|
|
+ cookies_.erase(cookies_.begin() + i);
|
|
|
+ --i;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (exist) {
|
|
|
+ result = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief 数量
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ int count() {
|
|
|
+ return int(cookies_.size());
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief 添加
|
|
|
+ * @param cookie
|
|
|
+ */
|
|
|
+ void add(std::shared_ptr<cookie> cookie) {
|
|
|
+ cookies_.push_back(cookie);
|
|
|
+ }
|
|
|
+ private:
|
|
|
+ std::vector<std::shared_ptr<cookie>> cookies_;
|
|
|
+ };
|
|
|
+
|
|
|
+ struct session {
|
|
|
+ /**
|
|
|
+ * @brief 关闭
|
|
|
+ */
|
|
|
+ bool close = false;
|
|
|
+ /**
|
|
|
+ * @brief
|
|
|
+ */
|
|
|
+ bool authen = false;
|
|
|
+ /**
|
|
|
+ * @brief
|
|
|
+ */
|
|
|
+ std::shared_ptr<cookies> cookies_;
|
|
|
+ /**
|
|
|
+ * @brief
|
|
|
+ */
|
|
|
+ std::map<std::string, std::any> user_data;
|
|
|
+ };
|
|
|
+
|
|
|
+ class MVC_API sessions {
|
|
|
+ public:
|
|
|
+ /**
|
|
|
+ * @brief
|
|
|
+ */
|
|
|
+ static void add_session(std::shared_ptr<session> session) {
|
|
|
+ std::lock_guard<std::mutex> locker(mutex_);
|
|
|
+ sessions_.push_back(session);
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief
|
|
|
+ */
|
|
|
+ static std::shared_ptr<session> get_session(std::string const& cookie_str) {
|
|
|
+ std::shared_ptr<session> result;
|
|
|
+ std::shared_ptr<cookies> cookies = cookies::analysis(cookie_str);
|
|
|
+ {
|
|
|
+ std::lock_guard<std::mutex> locker(mutex_);
|
|
|
+ for (int i = 0; i < sessions_.size(); ++i) {
|
|
|
+ if (sessions_[i]->cookies_->compare(cookies) && !sessions_[i]->close) {
|
|
|
+ result = sessions_[i];
|
|
|
+ }
|
|
|
+ else if (sessions_[i]->cookies_->count() <= 0 || sessions_[i]->close) {
|
|
|
+ sessions_.erase(sessions_.begin() + i);
|
|
|
+ i--;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ private:
|
|
|
+ static std::vector<std::shared_ptr<session>> sessions_;
|
|
|
+ static std::mutex mutex_;
|
|
|
+ };
|
|
|
+
|
|
|
+ enum class captcha_type {
|
|
|
+ /**
|
|
|
+ * @brief 成功
|
|
|
+ */
|
|
|
+ success,
|
|
|
+ /**
|
|
|
+ * @brief 失败
|
|
|
+ */
|
|
|
+ fail,
|
|
|
+ /**
|
|
|
+ * @brief 没有验证码
|
|
|
+ */
|
|
|
+ no
|
|
|
+ };
|
|
|
+
|
|
|
+ struct controller_action;
|
|
|
+
|
|
|
+ class MVC_API http_context {
|
|
|
+ public:
|
|
|
+ class curr {
|
|
|
+ public:
|
|
|
+ /**
|
|
|
+ * @brief 当前context
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ static std::shared_ptr<http_context> current() {
|
|
|
+ return http_context::current();
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief 是否有权限
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ static bool authen() {
|
|
|
+ return current()->authen();
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief 设置权限
|
|
|
+ * @param value
|
|
|
+ */
|
|
|
+ static void set_authen(bool value = true) {
|
|
|
+ current()->set_authen(value);
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief 设置session
|
|
|
+ * @param key
|
|
|
+ * @param value
|
|
|
+ */
|
|
|
+ static void add_session(std::string const& key, std::any const& value) {
|
|
|
+ current()->add_session(key, value);
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief 添加session并设置权限
|
|
|
+ * @param key
|
|
|
+ * @param value
|
|
|
+ */
|
|
|
+ static void add_authen_session(std::string const& key, std::any const& value) {
|
|
|
+ add_session(key, value);
|
|
|
+ set_authen();
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief 获取session
|
|
|
+ * @param key
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ static std::any& session(std::string const& key) {
|
|
|
+ return current()->session(key);
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief 获取session
|
|
|
+ * @tparam _Ret
|
|
|
+ * @param key
|
|
|
+ * @param succ
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ template<typename _Ret>
|
|
|
+ static bool get_session(std::string const& key, _Ret& result) {
|
|
|
+ std::any any_value = current()->session(key);
|
|
|
+ if (any_value.type() != typeid(_Ret)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ result = std::any_cast<_Ret>(any_value);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief 添加cookie
|
|
|
+ * @param timeout
|
|
|
+ */
|
|
|
+ static void add_cookie(int timeout = 30) {
|
|
|
+ current()->add_cookie(timeout);
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief 删除cookie
|
|
|
+ */
|
|
|
+ static void remove_cookie() {
|
|
|
+ current()->remove_cookie();
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief 重置cookie
|
|
|
+ * @param timeout
|
|
|
+ */
|
|
|
+ static void reset_cookie(int timeout = 30) {
|
|
|
+ remove_cookie();
|
|
|
+ add_cookie(timeout);
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief 验证码比较
|
|
|
+ * @param key
|
|
|
+ * @param captcha_code
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ static captcha_type captcha_compare(std::string const& key, std::string const& captcha_code) {
|
|
|
+ std::string value;
|
|
|
+ if (!get_session<std::string>(key, value))
|
|
|
+ return mvc::captcha_type::no;
|
|
|
+ else if (v3::utils::case_insensitive_compare(value, captcha_code))
|
|
|
+ return mvc::captcha_type::success;
|
|
|
+ else
|
|
|
+ return mvc::captcha_type::fail;
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief 验证码比较
|
|
|
+ * @param key
|
|
|
+ * @param captcha_code
|
|
|
+ * @param success
|
|
|
+ * @param message
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ static bool captcha_compare(std::string const& key, std::string const& captcha_code, bool& success, std::string& message) {
|
|
|
+ auto result = captcha_compare(key, captcha_code);
|
|
|
+ if (mvc::captcha_type::no == result) {
|
|
|
+ success = false;
|
|
|
+ message = "验证码不存在!";
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ else if (mvc::captcha_type::fail == result) {
|
|
|
+ success = false;
|
|
|
+ message = "验证码错误!";
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ success = true;
|
|
|
+ message = "成功!";
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+ /**
|
|
|
+ * @brief
|
|
|
+ */
|
|
|
+ static void new_curr_http_context(http::web_request& req, http::web_response& rep) {
|
|
|
+ rep.clear();
|
|
|
+ new http_context(req, rep);
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief
|
|
|
+ */
|
|
|
+ static void remove_curr_http_context() {
|
|
|
+ std::lock_guard<std::mutex> locker(mutex_);
|
|
|
+ http_context_list_.erase(std::this_thread::get_id());
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief
|
|
|
+ * @param route
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ static std::shared_ptr<http_context> current() {
|
|
|
+ std::lock_guard<std::mutex> locker(mutex_);
|
|
|
+ return http_context_list_[std::this_thread::get_id()];
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief
|
|
|
+ */
|
|
|
+ bool authen() {
|
|
|
+ if (current_session_)
|
|
|
+ return current_session_->authen;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief
|
|
|
+ */
|
|
|
+ void set_authen(bool value = true) {
|
|
|
+ if (current_session_)
|
|
|
+ current_session_->authen = value;
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief
|
|
|
+ */
|
|
|
+ void add_session(std::string const& key, std::any const& value) {
|
|
|
+ if (!current_session_)
|
|
|
+ throw std::runtime_error("not cookie!");
|
|
|
+ current_session_->user_data[key] = value;
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief
|
|
|
+ */
|
|
|
+ std::any& session(std::string const& key) {
|
|
|
+ static std::any g_any;
|
|
|
+ if (current_session_) {
|
|
|
+ if (current_session_->user_data.find(key) != current_session_->user_data.end()) {
|
|
|
+ return current_session_->user_data[key];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ g_any = std::any();
|
|
|
+ return g_any;
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief
|
|
|
+ */
|
|
|
+ void add_cookie(int timeout = 30) {
|
|
|
+ std::shared_ptr<cookie> item(new cookie);
|
|
|
+ item->time = timeout * (1000 * 60);
|
|
|
+ item->last_expire_time = v3::datetime::current_time_stamp() + item->time;
|
|
|
+ if (current_session_ && !current_session_->close) {
|
|
|
+ if (!current_session_->cookies_)
|
|
|
+ current_session_->cookies_.reset(new cookies);
|
|
|
+ current_session_->cookies_->add(item);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ current_session_.reset(new mvc::session);
|
|
|
+ current_session_->cookies_.reset(new cookies);
|
|
|
+ current_session_->cookies_->add(item);
|
|
|
+ mvc::sessions::add_session(current_session_);
|
|
|
+ }
|
|
|
+ std::string set_cookie_str;
|
|
|
+ set_cookie_str += item->name;
|
|
|
+ set_cookie_str += "=";
|
|
|
+ set_cookie_str += item->value;
|
|
|
+ set_cookie_str += ";";
|
|
|
+ set_cookie_str += item->path;
|
|
|
+ response.set(http::field::set_cookie, set_cookie_str);
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief
|
|
|
+ */
|
|
|
+ void remove_cookie() {
|
|
|
+ if (current_session_) {
|
|
|
+ current_session_->close = true;
|
|
|
+ }
|
|
|
+ response.set(http::field::set_cookie, "SessionId=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT");
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief
|
|
|
+ */
|
|
|
+ void set_controller_action(std::shared_ptr<controller_action> value) {
|
|
|
+ controller_action_ = value;
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief
|
|
|
+ */
|
|
|
+ std::shared_ptr<controller_action> get_controller_action() {
|
|
|
+ return controller_action_;
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief
|
|
|
+ */
|
|
|
+ http::web_request& request;
|
|
|
+ /**
|
|
|
+ * @brief
|
|
|
+ */
|
|
|
+ http::web_response& response;
|
|
|
+ /**
|
|
|
+ * @brief
|
|
|
+ */
|
|
|
+ std::filesystem::path root_directory;
|
|
|
+ private:
|
|
|
+ http_context(http::web_request& req, http::web_response& rep) :
|
|
|
+ request(req),
|
|
|
+ response(rep),
|
|
|
+ root_directory(rep.get_root_directory()) {
|
|
|
+ if (req.find(http::field::cookie) != req.end()) {
|
|
|
+ current_session_ = sessions::get_session(std::string(req.find(http::field::cookie)->value().begin(), req.find(http::field::cookie)->value().end()));
|
|
|
+ }
|
|
|
+ std::lock_guard<std::mutex> locker(mutex_);
|
|
|
+ http_context_list_[std::this_thread::get_id()].reset(this);
|
|
|
+ }
|
|
|
+ private:
|
|
|
+ std::shared_ptr<mvc::session> current_session_;
|
|
|
+ std::shared_ptr<controller_action> controller_action_;
|
|
|
+ private:
|
|
|
+ static std::mutex mutex_;
|
|
|
+ static std::map<std::thread::id, std::shared_ptr<http_context>> http_context_list_;
|
|
|
+ };
|
|
|
+
|
|
|
+ class http_context_gc {
|
|
|
+ public:
|
|
|
+ http_context_gc(http::web_request& req, http::web_response& rep) {
|
|
|
+ http_context::new_curr_http_context(req, rep);
|
|
|
+ }
|
|
|
+ virtual ~http_context_gc() {
|
|
|
+ http_context::remove_curr_http_context();
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ enum class pseudo_type {
|
|
|
+ NON = 0,
|
|
|
+ MASK,
|
|
|
+ MODEL,
|
|
|
+ FOR,
|
|
|
+ IF,
|
|
|
+ SWITCH,
|
|
|
+ FILE
|
|
|
+ };
|
|
|
+
|
|
|
+ struct class_value {
|
|
|
+ bool is_list = false;
|
|
|
+ std::string class_name;
|
|
|
+ std::vector<std::map<std::string, std::string>> class_value;
|
|
|
+ };
|
|
|
+
|
|
|
+ struct ipseudo_label {
|
|
|
+ ipseudo_label(std::pair<pseudo_type, std::pair<std::string, std::string>> const& value_type) :
|
|
|
+ type(value_type.first),
|
|
|
+ label(value_type.second) {
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief 类型
|
|
|
+ */
|
|
|
+ pseudo_type type;
|
|
|
+ /**
|
|
|
+ * @brief 原始代码
|
|
|
+ */
|
|
|
+ std::string html_code;
|
|
|
+ /**
|
|
|
+ * @brief 临时原始代码
|
|
|
+ */
|
|
|
+ std::string html_code_tmp;
|
|
|
+ /**
|
|
|
+ * @brief 类名
|
|
|
+ */
|
|
|
+ std::string class_name;
|
|
|
+ /**
|
|
|
+ * @brief 标签
|
|
|
+ */
|
|
|
+ std::pair<std::string, std::string> label;
|
|
|
+ /**
|
|
|
+ * @brief 实体类数据列表
|
|
|
+ */
|
|
|
+ std::vector<std::map<std::string, std::string>> class_value_list;
|
|
|
+ /**
|
|
|
+ * @brief 子标签
|
|
|
+ */
|
|
|
+ std::vector<std::shared_ptr<ipseudo_label>> childs;
|
|
|
+ /**
|
|
|
+ * @brief 解析返回html
|
|
|
+ */
|
|
|
+ virtual std::string analysis() = 0;
|
|
|
+ /**
|
|
|
+ * @brief 设置属性值
|
|
|
+ */
|
|
|
+ void set_class_value(std::vector<std::shared_ptr<class_value>>const& value) {
|
|
|
+ for (auto it : childs) {
|
|
|
+ it->set_class_value(value);
|
|
|
+ }
|
|
|
+ for (auto it : value) {
|
|
|
+ if (class_name != it->class_name)
|
|
|
+ continue;
|
|
|
+ if (it->is_list && type == pseudo_type::FOR) {
|
|
|
+ class_value_list = it->class_value;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ else if (!it->is_list) {
|
|
|
+ class_value_list = it->class_value;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief 解析基础信息
|
|
|
+ */
|
|
|
+ virtual void analysis_baseinfo() = 0;
|
|
|
+ protected:
|
|
|
+ std::string extract(std::string const& value, std::pair<std::string, std::string> const& pair, int& index) {
|
|
|
+ std::string result;
|
|
|
+ bool ok = false;
|
|
|
+ int count = 0;
|
|
|
+ for (size_t i = 0; i < value.size(); ++i) {
|
|
|
+ if (i + 1 >= pair.first.size() &&
|
|
|
+ value[i] == pair.first[pair.first.size() - 1] &&
|
|
|
+ value.substr(i - pair.first.size() + 1, pair.first.size()) == pair.first) {
|
|
|
+ count++;
|
|
|
+ if (count == 1) {
|
|
|
+ ok = true;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (ok &&
|
|
|
+ value.size() >= i + pair.second.size() &&
|
|
|
+ value[i] == pair.second[0] &&
|
|
|
+ value.substr(i, pair.second.size()) == pair.second) {
|
|
|
+ count--;
|
|
|
+ if (count == 0) {
|
|
|
+ index = i + 1;
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (ok) {
|
|
|
+ result += value[i];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ index = -1;
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ std::vector<std::string> extractList(std::string const& value, std::pair<std::string, std::string> const& pair) {
|
|
|
+ std::vector<std::string> result;
|
|
|
+ int index = 0;
|
|
|
+ int pos = 0;
|
|
|
+ while (index > -1) {
|
|
|
+ pos += index;
|
|
|
+ std::string ret = extract(value.substr(pos, value.size() - pos), pair, index);
|
|
|
+ if (index != -1)
|
|
|
+ result.push_back(ret);
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ struct pseudo_mask_label : public ipseudo_label {
|
|
|
+ pseudo_mask_label(std::pair<pseudo_type, std::pair<std::string, std::string>>const& value_type) :
|
|
|
+ ipseudo_label(value_type) {
|
|
|
+ }
|
|
|
+ std::string mask_name;
|
|
|
+ virtual std::string analysis()override {
|
|
|
+ for (auto child : childs) {
|
|
|
+ std::string childValue = child->analysis();
|
|
|
+ html_code_tmp = v3::utils::replace(html_code_tmp, child->html_code, childValue);
|
|
|
+ }
|
|
|
+ int index = 0;
|
|
|
+ std::string header = extract(html_code_tmp, { "${mask","}" }, index);
|
|
|
+ header = "${mask" + header + "}";
|
|
|
+ std::string tmp = extract(html_code_tmp, { header,"{/mask}" }, index);
|
|
|
+ return tmp;
|
|
|
+ }
|
|
|
+ virtual void analysis_baseinfo() override {
|
|
|
+ html_code_tmp = html_code;
|
|
|
+ for (auto child : childs) {
|
|
|
+ child->analysis_baseinfo();
|
|
|
+ }
|
|
|
+ //获取mask名称
|
|
|
+ int index = 0;
|
|
|
+ mask_name = extract(html_code, { "name='","'" }, index);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ struct pseudo_model_label : public ipseudo_label {
|
|
|
+ pseudo_model_label(std::pair<pseudo_type, std::pair<std::string, std::string>>const& value_type) :
|
|
|
+ ipseudo_label(value_type) {
|
|
|
+ }
|
|
|
+ virtual std::string analysis()override {
|
|
|
+ for (auto child : childs) {
|
|
|
+ std::string childValue = child->analysis();
|
|
|
+ html_code_tmp = v3::utils::replace(html_code_tmp, child->html_code, childValue);
|
|
|
+ }
|
|
|
+ std::string propName;
|
|
|
+ std::string propValue;
|
|
|
+ std::map<std::string, std::string> mapPropValue;
|
|
|
+ {
|
|
|
+ int index = 0;
|
|
|
+ std::string tmp = extract(html_code_tmp, { "name='","'" }, index);
|
|
|
+ std::string::size_type pos = tmp.find('.');
|
|
|
+ if (pos != std::string::npos) {
|
|
|
+ propName = tmp.substr(pos + 1, tmp.size() - pos - 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //获取值
|
|
|
+ {
|
|
|
+ int index = 0;
|
|
|
+ std::string tmp = extract(html_code_tmp.substr(index, html_code_tmp.size() - index), { "value='[","]'" }, index);
|
|
|
+ //属性值
|
|
|
+ if (tmp == "#value") {
|
|
|
+ propValue = tmp;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ auto values = v3::utils::split(tmp, ",");
|
|
|
+ for (auto value : values) {
|
|
|
+ auto valueItem = v3::utils::split(value, ":");
|
|
|
+ if (valueItem.size() == 2) {
|
|
|
+ if (valueItem[0].size() >= 2 && valueItem[1].size() >= 2 &&
|
|
|
+ valueItem[0][0] == '\'' && valueItem[0][valueItem[0].size() - 1] == '\'' &&
|
|
|
+ valueItem[1][0] == '\'' && valueItem[1][valueItem[1].size() - 1] == '\'') {
|
|
|
+ valueItem[0].erase(valueItem[0].begin());
|
|
|
+ valueItem[0].erase(valueItem[0].begin() + valueItem[0].size() - 1);
|
|
|
+ valueItem[1].erase(valueItem[1].begin());
|
|
|
+ valueItem[1].erase(valueItem[1].begin() + valueItem[1].size() - 1);
|
|
|
+ mapPropValue[valueItem[0]] = valueItem[1];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (propName.empty()) {
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+ //属性值
|
|
|
+ if (!propValue.empty() && !class_value_list.empty()) {
|
|
|
+ if (class_value_list[0].find(propName) != class_value_list[0].end()) {
|
|
|
+ return class_value_list[0][propName];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (!mapPropValue.empty() && !class_value_list.empty()) {
|
|
|
+ if (class_value_list[0].find(propName) != class_value_list[0].end()) {
|
|
|
+ std::string value = class_value_list[0][propName];
|
|
|
+ //选择值
|
|
|
+ if (mapPropValue.find(value) != mapPropValue.end()) {
|
|
|
+ return mapPropValue[value];
|
|
|
+ }
|
|
|
+ //默认值
|
|
|
+ else if (mapPropValue.find("default") != mapPropValue.end()) {
|
|
|
+ if (mapPropValue["default"] == "#value") {
|
|
|
+ return class_value_list[0][propName];
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ return mapPropValue["default"];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+ virtual void analysis_baseinfo() override {
|
|
|
+ html_code_tmp = html_code;
|
|
|
+ for (auto child : childs) {
|
|
|
+ child->analysis_baseinfo();
|
|
|
+ }
|
|
|
+ //获取类名属性名
|
|
|
+ int index = 0;
|
|
|
+ std::string tmp = extract(html_code, { "name='","'" }, index);
|
|
|
+ std::string::size_type pos = tmp.find('.');
|
|
|
+ if (pos != std::string::npos) {
|
|
|
+ class_name = tmp.substr(0, pos);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ struct pseudo_for_label : public ipseudo_label {
|
|
|
+ pseudo_for_label(std::pair<pseudo_type, std::pair<std::string, std::string>> const& value_type) :
|
|
|
+ ipseudo_label(value_type) {
|
|
|
+ }
|
|
|
+ virtual std::string analysis()override {
|
|
|
+ for (auto child : childs) {
|
|
|
+ std::string childValue = child->analysis();
|
|
|
+ html_code_tmp = v3::utils::replace(html_code_tmp, child->html_code, childValue);
|
|
|
+ }
|
|
|
+ std::string resultValue;
|
|
|
+ std::string itemName;
|
|
|
+ std::string forLabel;
|
|
|
+ std::vector<std::string> forItemLabelList;
|
|
|
+ std::map<std::string, std::map<std::string, std::map<std::string, std::string>>> forItemLabelValueList;
|
|
|
+ //获取ITEM名称
|
|
|
+ {
|
|
|
+ int index = 0;
|
|
|
+ itemName = extract(html_code_tmp, { "item='","'" }, index);
|
|
|
+ if (itemName.empty())
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+
|
|
|
+ //提取for标签值
|
|
|
+ {
|
|
|
+ int index = 0;
|
|
|
+ std::string header = extract(html_code_tmp, { "${for","}" }, index);
|
|
|
+ header = "${for" + header + "}";
|
|
|
+ forLabel = extract(html_code_tmp, { header,"{/for}" }, index);
|
|
|
+ }
|
|
|
+
|
|
|
+ //提取foritem标签
|
|
|
+ {
|
|
|
+ forItemLabelList = extractList(forLabel, { "{item","/}" });
|
|
|
+ for (auto& it : forItemLabelList) {
|
|
|
+ it = "{item" + it + "/}";
|
|
|
+ }
|
|
|
+ if (forItemLabelList.empty())
|
|
|
+ return forLabel;
|
|
|
+ }
|
|
|
+
|
|
|
+ //提取foritem参数
|
|
|
+ {
|
|
|
+ int index = 0;
|
|
|
+ std::string header = "name='" + itemName + ".";
|
|
|
+ for (auto it : forItemLabelList) {
|
|
|
+ std::string propName = extract(it, { header,"'" }, index);
|
|
|
+ if (propName.empty())
|
|
|
+ continue;
|
|
|
+ std::string value = extract(it, { "value='[","]'" }, index);
|
|
|
+ if (value.empty())
|
|
|
+ continue;
|
|
|
+ if (value == "#value") {
|
|
|
+ forItemLabelValueList[it][propName][value] = value;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ auto values = v3::utils::split(value, ",");
|
|
|
+ for (auto valueIt : values) {
|
|
|
+ auto valueItem = v3::utils::split(valueIt, "':'");
|
|
|
+ if (valueItem.size() == 2) {
|
|
|
+ valueItem[0] += "'";
|
|
|
+ valueItem[1] = "'" + valueItem[1];
|
|
|
+ if (valueItem[0].size() >= 2 && valueItem[1].size() >= 2 &&
|
|
|
+ valueItem[0][0] == '\'' && valueItem[0][valueItem[0].size() - 1] == '\'' &&
|
|
|
+ valueItem[1][0] == '\'' && valueItem[1][valueItem[1].size() - 1] == '\'') {
|
|
|
+
|
|
|
+ valueItem[0].erase(valueItem[0].begin());
|
|
|
+ valueItem[0].erase(valueItem[0].begin() + valueItem[0].size() - 1);
|
|
|
+
|
|
|
+ valueItem[1].erase(valueItem[1].begin());
|
|
|
+ valueItem[1].erase(valueItem[1].begin() + valueItem[1].size() - 1);
|
|
|
+
|
|
|
+ forItemLabelValueList[it][propName][valueItem[0]] = valueItem[1];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //遍历值
|
|
|
+ {
|
|
|
+ int index = 0;
|
|
|
+ for (auto item : class_value_list) {
|
|
|
+ index++;
|
|
|
+ std::string itemValue = forLabel;
|
|
|
+ for (auto forItem : forItemLabelList) {
|
|
|
+ //没有查找到值赋值为空
|
|
|
+ if (forItemLabelValueList.find(forItem) == forItemLabelValueList.end()) {
|
|
|
+ itemValue = v3::utils::replace(itemValue, forItem, "");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ //查找属性
|
|
|
+ if (forItemLabelValueList[forItem].find("for-index") != forItemLabelValueList[forItem].end()) {
|
|
|
+
|
|
|
+ //默认值
|
|
|
+ if (forItemLabelValueList[forItem]["for-index"].find("#value") != forItemLabelValueList[forItem]["for-index"].end()) {
|
|
|
+
|
|
|
+ itemValue = v3::utils::replace(itemValue, forItem, std::to_string(index));
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ if (forItemLabelValueList[forItem]["for-index"].find(std::to_string(index)) != forItemLabelValueList[forItem]["for-index"].end()) {
|
|
|
+
|
|
|
+ itemValue = v3::utils::replace(itemValue, forItem, forItemLabelValueList[forItem]["for-index"][std::to_string(index)]);
|
|
|
+ }
|
|
|
+ else if (forItemLabelValueList[forItem]["for-index"].find("default") != forItemLabelValueList[forItem]["for-index"].end()) {
|
|
|
+ itemValue = v3::utils::replace(itemValue, forItem, forItemLabelValueList[forItem]["for-index"]["default"]);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ itemValue = v3::utils::replace(itemValue, forItem, "");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ std::string propNameItem;
|
|
|
+ std::map<std::string, std::string> propValueItem;
|
|
|
+ auto childItem = forItemLabelValueList[forItem];
|
|
|
+ for (auto childItemIt : childItem) {
|
|
|
+ propNameItem = childItemIt.first;
|
|
|
+ propValueItem = childItemIt.second;
|
|
|
+ }
|
|
|
+ if (propNameItem.empty()) {
|
|
|
+ itemValue = v3::utils::replace(itemValue, forItem, "");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (item.find(propNameItem) != item.end()) {
|
|
|
+ if (item.find(propNameItem) != item.end()) {
|
|
|
+ if (propValueItem.find("#value") != propValueItem.end()) {
|
|
|
+ itemValue = v3::utils::replace(itemValue, forItem, item[propNameItem]);
|
|
|
+ }
|
|
|
+ else if (propValueItem.find(item[propNameItem]) != propValueItem.end()) {
|
|
|
+ itemValue = v3::utils::replace(itemValue, forItem, propValueItem[item[propNameItem]]);
|
|
|
+ }
|
|
|
+ else if (propValueItem.find("default") != propValueItem.end()) {
|
|
|
+
|
|
|
+ if (propValueItem["default"] == "#value") {
|
|
|
+ itemValue = v3::utils::replace(itemValue, forItem, item[propNameItem]);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ itemValue = v3::utils::replace(itemValue, forItem, propValueItem["default"]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ itemValue = v3::utils::replace(itemValue, forItem, "");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ itemValue = v3::utils::replace(itemValue, forItem, "");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ itemValue = v3::utils::replace(itemValue, forItem, "");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ resultValue += itemValue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return resultValue;
|
|
|
+ }
|
|
|
+ virtual void analysis_baseinfo() override {
|
|
|
+ html_code_tmp = html_code;
|
|
|
+ for (auto child : childs) {
|
|
|
+ child->analysis_baseinfo();
|
|
|
+ }
|
|
|
+ //获取类名属性名
|
|
|
+ int index = 0;
|
|
|
+ class_name = extract(html_code, { "list='","'" }, index);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ struct pseudo_if_label : public ipseudo_label {
|
|
|
+ pseudo_if_label(std::pair<pseudo_type, std::pair<std::string, std::string>> const& value_type) :
|
|
|
+ ipseudo_label(value_type) {
|
|
|
+ }
|
|
|
+ virtual std::string analysis()override {
|
|
|
+ for (auto child : childs) {
|
|
|
+ std::string childValue = child->analysis();
|
|
|
+ html_code_tmp = v3::utils::replace(html_code_tmp, child->html_code, childValue);
|
|
|
+ }
|
|
|
+ std::string propName;
|
|
|
+ std::string propValue;
|
|
|
+ std::string symbol;
|
|
|
+ std::vector<std::string> labelValue;
|
|
|
+ //提取标签内容
|
|
|
+ {
|
|
|
+ labelValue = extractList(html_code_tmp, { "}","{" });
|
|
|
+ if (labelValue.empty())
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+ //判断结构体是否有值
|
|
|
+ {
|
|
|
+ if (class_value_list.empty()) {
|
|
|
+ if (labelValue.size() == 2) {
|
|
|
+ return labelValue[1];
|
|
|
+ }
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //获取类名属性名
|
|
|
+ {
|
|
|
+ int index = 0;
|
|
|
+ std::string tmp = extract(html_code_tmp, { "name='","'" }, index);
|
|
|
+ std::string::size_type pos = tmp.find('.');
|
|
|
+ if (pos != std::string::npos) {
|
|
|
+ propName = tmp.substr(pos + 1, tmp.size() - pos - 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //判断类名
|
|
|
+ {
|
|
|
+ if (propName.empty()) {
|
|
|
+ if (labelValue.size() == 2) {
|
|
|
+ return labelValue[1];
|
|
|
+ }
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //判断属性名称是否存在
|
|
|
+ {
|
|
|
+ if (class_value_list[0].find(propName) == class_value_list[0].end()) {
|
|
|
+ if (labelValue.size() == 2) {
|
|
|
+ return labelValue[1];
|
|
|
+ }
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //提取操作符 逻辑对比值
|
|
|
+ {
|
|
|
+ int index = 0;
|
|
|
+ propValue = extract(html_code_tmp, { "value=='","'" }, index);
|
|
|
+ //==
|
|
|
+ if (propValue.empty()) {
|
|
|
+ propValue = extract(html_code_tmp, { "value!='","'" }, index);
|
|
|
+ //!=
|
|
|
+ if (propValue.empty()) {
|
|
|
+ propValue = extract(html_code_tmp, { "value>='","'" }, index);
|
|
|
+ //>=
|
|
|
+ if (propValue.empty()) {
|
|
|
+ propValue = extract(html_code_tmp, { "value<='","'" }, index);
|
|
|
+ //<=
|
|
|
+ if (propValue.empty()) {
|
|
|
+ if (labelValue.size() == 2) {
|
|
|
+ return labelValue[1];
|
|
|
+ }
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+ else
|
|
|
+ symbol = "<=";
|
|
|
+ }
|
|
|
+ else
|
|
|
+ symbol = ">=";
|
|
|
+ }
|
|
|
+ else
|
|
|
+ symbol = "!=";
|
|
|
+ }
|
|
|
+ else
|
|
|
+ symbol = "==";
|
|
|
+ }
|
|
|
+ //判断
|
|
|
+ {
|
|
|
+ if (symbol == "==" && propValue.compare(class_value_list[0][propName]) == 0) {
|
|
|
+ return labelValue[0];
|
|
|
+ }
|
|
|
+ else if (symbol == "!=" && propValue.compare(class_value_list[0][propName]) != 0) {
|
|
|
+ return labelValue[0];
|
|
|
+ }
|
|
|
+ else if (symbol == ">=" && propValue.compare(class_value_list[0][propName]) >= 0) {
|
|
|
+ return labelValue[0];
|
|
|
+ }
|
|
|
+ else if (symbol == "<=" && propValue.compare(class_value_list[0][propName]) <= 0) {
|
|
|
+ return labelValue[0];
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ if (labelValue.size() == 2)
|
|
|
+ return labelValue[1];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+ virtual void analysis_baseinfo() override {
|
|
|
+ html_code_tmp = html_code;
|
|
|
+ for (auto child : childs) {
|
|
|
+ child->analysis_baseinfo();
|
|
|
+ }
|
|
|
+ //获取类名属性名
|
|
|
+ int index = 0;
|
|
|
+ std::string tmp = extract(html_code, { "name='","'" }, index);
|
|
|
+ std::string::size_type pos = tmp.find('.');
|
|
|
+ if (pos != std::string::npos) {
|
|
|
+ class_name = tmp.substr(0, pos);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ struct pseudo_switch_label : public ipseudo_label {
|
|
|
+ pseudo_switch_label(std::pair<pseudo_type, std::pair<std::string, std::string>> const& value_type) :
|
|
|
+ ipseudo_label(value_type) {
|
|
|
+ }
|
|
|
+ virtual std::string analysis()override {
|
|
|
+ for (auto child : childs) {
|
|
|
+ std::string childValue = child->analysis();
|
|
|
+ html_code_tmp = v3::utils::replace(html_code_tmp, child->html_code, childValue);
|
|
|
+ }
|
|
|
+ std::string propName;
|
|
|
+ std::string labelValueDefault;
|
|
|
+ std::vector<std::string> labelValue;
|
|
|
+
|
|
|
+ //获取类名属性名
|
|
|
+ {
|
|
|
+ int index = 0;
|
|
|
+ std::string tmp = extract(html_code_tmp, { "name='","'" }, index);
|
|
|
+ std::string::size_type pos = tmp.find('.');
|
|
|
+ if (pos != std::string::npos) {
|
|
|
+ propName = tmp.substr(pos + 1, tmp.size() - pos - 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //提取标签内容
|
|
|
+ {
|
|
|
+ int index = 0;
|
|
|
+ labelValue = extractList(html_code_tmp, { "{case","/case}" });
|
|
|
+ labelValueDefault = extract(html_code_tmp, { "{default}","{/default}" }, index);
|
|
|
+ if (labelValue.empty() && labelValueDefault.empty()) {
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+ else if (labelValue.empty() && !labelValueDefault.empty()) {
|
|
|
+ if (labelValueDefault.find("#value") != std::string::npos) {
|
|
|
+ if (class_value_list.empty())
|
|
|
+ return "";
|
|
|
+ if (propName.empty())
|
|
|
+ return "";
|
|
|
+ if (class_value_list[0].find(propName) == class_value_list[0].end())
|
|
|
+ return "";
|
|
|
+ return class_value_list[0][propName];
|
|
|
+ }
|
|
|
+ return labelValueDefault;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //判断属性值
|
|
|
+ {
|
|
|
+ if (class_value_list.empty()) {
|
|
|
+ if (labelValueDefault.empty())
|
|
|
+ return "";
|
|
|
+ if (labelValueDefault.find("#value") != std::string::npos)
|
|
|
+ return "";
|
|
|
+ return labelValueDefault;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (propName.empty()) {
|
|
|
+ if (labelValueDefault.empty())
|
|
|
+ return "";
|
|
|
+ if (labelValueDefault.find("#value") != std::string::npos)
|
|
|
+ return "";
|
|
|
+ return labelValueDefault;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (class_value_list[0].find(propName) == class_value_list[0].end()) {
|
|
|
+ if (labelValueDefault.empty())
|
|
|
+ return "";
|
|
|
+ if (labelValueDefault.find("#value") != std::string::npos)
|
|
|
+ return "";
|
|
|
+ return labelValueDefault;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //遍历值
|
|
|
+ {
|
|
|
+ for (auto it : labelValue) {
|
|
|
+ int index = 0;
|
|
|
+ std::string propValue = extract(it, { "value='","'" }, index);
|
|
|
+ if (class_value_list[0][propName] == propValue) {
|
|
|
+ return extract(it, { "}","{" }, index);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //判断默认值
|
|
|
+ {
|
|
|
+ if (labelValueDefault.empty())
|
|
|
+ return "";
|
|
|
+ if (labelValueDefault.find("#value") != std::string::npos) {
|
|
|
+ return v3::utils::replace(labelValueDefault, "#value", class_value_list[0][propName]);
|
|
|
+ }
|
|
|
+ return labelValueDefault;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ virtual void analysis_baseinfo() override {
|
|
|
+ html_code_tmp = html_code;
|
|
|
+ for (auto child : childs) {
|
|
|
+ child->analysis_baseinfo();
|
|
|
+ }
|
|
|
+ //获取类名属性名
|
|
|
+ int index = 0;
|
|
|
+ std::string tmp = extract(html_code, { "name='","'" }, index);
|
|
|
+ std::string::size_type pos = tmp.find('.');
|
|
|
+ if (pos != std::string::npos) {
|
|
|
+ class_name = tmp.substr(0, pos);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ struct pseudo_file_label : public ipseudo_label {
|
|
|
+ pseudo_file_label(std::pair<pseudo_type, std::pair<std::string, std::string>> const& value_type) :
|
|
|
+ ipseudo_label(value_type) {
|
|
|
+ }
|
|
|
+ virtual std::string analysis()override {
|
|
|
+ for (auto child : childs) {
|
|
|
+ std::string childValue = child->analysis();
|
|
|
+ html_code_tmp = v3::utils::replace(html_code_tmp, child->html_code, childValue);
|
|
|
+ }
|
|
|
+ int index = 0;
|
|
|
+ std::string path_tmp = extract(html_code_tmp, { "path='","'" }, index);
|
|
|
+ std::filesystem::path path = path_tmp;
|
|
|
+ std::filesystem::path filepath;
|
|
|
+ filepath = http_context::current()->response.get_root_directory();
|
|
|
+ filepath.make_preferred();
|
|
|
+ filepath /= path.make_preferred().relative_path();
|
|
|
+ if (filepath.empty())
|
|
|
+ return "";
|
|
|
+ if (std::filesystem::exists(filepath)) {
|
|
|
+ std::ifstream file(filepath, std::ios::in);
|
|
|
+ if (file.is_open()) {
|
|
|
+ return std::string((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+ virtual void analysis_baseinfo() override {
|
|
|
+ html_code_tmp = html_code;
|
|
|
+ for (auto child : childs) {
|
|
|
+ child->analysis_baseinfo();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ struct pseudo_extract_class_value {
|
|
|
+ template<typename ..._Args>
|
|
|
+ static std::vector<std::shared_ptr<class_value>> get_class_value(_Args&&...args) {
|
|
|
+ std::vector<std::shared_ptr<class_value>> result;
|
|
|
+ auto tuple = std::forward_as_tuple(std::forward<_Args>(args)...);
|
|
|
+ v3::utils::for_each(tuple, [&](auto& it) {
|
|
|
+ auto value = serialize(it);
|
|
|
+ result.push_back(value); });
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ private:
|
|
|
+ static std::string get_prop_value(rttr::variant const& value) {
|
|
|
+ std::string result;
|
|
|
+ if (value.get_type() == rttr::type::get<int>()) {
|
|
|
+ result = std::to_string(value.get_value<int>());
|
|
|
+ }
|
|
|
+ else if (value.get_type() == rttr::type::get<std::int64_t>()) {
|
|
|
+ result = std::to_string(value.get_value<std::int64_t>());
|
|
|
+ }
|
|
|
+ else if (value.get_type() == rttr::type::get<float>()) {
|
|
|
+ result = v3::utils::format("{:.2f}", value.get_value<float>());
|
|
|
+ }
|
|
|
+ else if (value.get_type() == rttr::type::get<double>()) {
|
|
|
+ result = v3::utils::format("{:.2f}", value.get_value<double>());
|
|
|
+ }
|
|
|
+ else if (value.get_type() == rttr::type::get<long>()) {
|
|
|
+ result = std::to_string(value.get_value<long>());
|
|
|
+ }
|
|
|
+ else if (value.get_type() == rttr::type::get<bool>()) {
|
|
|
+ if (value.get_value<bool>())
|
|
|
+ result = "true";
|
|
|
+ else
|
|
|
+ result = "false";
|
|
|
+ }
|
|
|
+ else if (value.get_type() == rttr::type::get<std::string>()) {
|
|
|
+ result = value.get_value<std::string>();
|
|
|
+ }
|
|
|
+ else if (value.get_type() == rttr::type::get<v3::datetime>()) {
|
|
|
+ auto t = value.get_value<v3::datetime>();
|
|
|
+ result = t.to_string();
|
|
|
+ }
|
|
|
+ else if (value.get_type() == rttr::type::get<std::vector<int>>()) {
|
|
|
+ auto values = value.get_value<std::vector<int>>();
|
|
|
+ for (int i = 0; i < values.size(); ++i) {
|
|
|
+ if (i + 1 == values.size()) {
|
|
|
+ result += std::to_string(values[i]);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ result += std::to_string(values[i]) + ",";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (value.get_type() == rttr::type::get<std::vector<std::int64_t>>()) {
|
|
|
+ auto values = value.get_value<std::vector<std::int64_t>>();
|
|
|
+ for (int i = 0; i < values.size(); ++i) {
|
|
|
+ if (i + 1 == values.size()) {
|
|
|
+ result += std::to_string(values[i]);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ result += std::to_string(values[i]) + ",";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (value.get_type() == rttr::type::get<std::vector<float>>()) {
|
|
|
+ auto values = value.get_value<std::vector<float>>();
|
|
|
+ for (int i = 0; i < values.size(); ++i) {
|
|
|
+ if (i + 1 == values.size()) {
|
|
|
+ result += v3::utils::format("{:.2f}", values[i]);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ result += v3::utils::format("{:.2f}", values[i]) + ",";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (value.get_type() == rttr::type::get<std::vector<double>>()) {
|
|
|
+ auto values = value.get_value<std::vector<double>>();
|
|
|
+ for (int i = 0; i < values.size(); ++i) {
|
|
|
+ if (i + 1 == values.size()) {
|
|
|
+ result += v3::utils::format("{:.2f}", values[i]);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ result += v3::utils::format("{:.2f}", values[i]) + ",";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (value.get_type() == rttr::type::get<std::vector<long>>()) {
|
|
|
+ auto values = value.get_value<std::vector<long>>();
|
|
|
+ for (int i = 0; i < values.size(); ++i) {
|
|
|
+ if (i + 1 == values.size()) {
|
|
|
+ result += std::to_string(values[i]);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ result += std::to_string(values[i]) + ",";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (value.get_type() == rttr::type::get<std::vector<bool>>()) {
|
|
|
+ auto values = value.get_value<std::vector<bool>>();
|
|
|
+ for (int i = 0; i < values.size(); ++i) {
|
|
|
+ if (i + 1 == values.size()) {
|
|
|
+ result += values[i] ? "true" : "false";
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ result += values[i] ? "true," : "false,";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (value.get_type() == rttr::type::get<std::vector<std::string>>()) {
|
|
|
+ auto values = value.get_value<std::vector<std::string>>();
|
|
|
+ for (int i = 0; i < values.size(); ++i) {
|
|
|
+ if (i + 1 == values.size()) {
|
|
|
+ result += values[i];
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ result += values[i] + ",";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (value.get_type() == rttr::type::get<std::vector<v3::datetime>>()) {
|
|
|
+ auto values = value.get_value<std::vector<v3::datetime>>();
|
|
|
+ for (int i = 0; i < values.size(); ++i) {
|
|
|
+ if (i + 1 == values.size()) {
|
|
|
+ result += values[i].to_string();
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ result += values[i].to_string() + ",";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ template<typename _Type>
|
|
|
+ static std::shared_ptr<class_value> serialize(std::vector<std::shared_ptr<_Type>> const& values) {
|
|
|
+ std::vector<_Type> valueTmp;
|
|
|
+ for (auto it : values) {
|
|
|
+ valueTmp.push_back(*it);
|
|
|
+ }
|
|
|
+ return serialize(valueTmp);
|
|
|
+ }
|
|
|
+ template<typename _Type>
|
|
|
+ static std::shared_ptr<class_value> serialize(std::vector<_Type*> values) {
|
|
|
+ std::vector<_Type> valueTmp;
|
|
|
+ for (auto it : values) {
|
|
|
+ valueTmp.push_back(*it);
|
|
|
+ }
|
|
|
+ return serialize(valueTmp);
|
|
|
+ }
|
|
|
+ template<typename _Type>
|
|
|
+ static std::shared_ptr<class_value> serialize(std::vector<_Type> values) {
|
|
|
+ std::shared_ptr<class_value> result(new class_value);
|
|
|
+ rttr::type type = rttr::type::get<_Type>();
|
|
|
+ std::string className(type.get_name());
|
|
|
+ result->class_name = className;
|
|
|
+ result->is_list = true;
|
|
|
+ for (auto it : values) {
|
|
|
+ std::map<std::string, std::string> elem = web_reflect::get_object_value(it);
|
|
|
+ result->class_value.push_back(elem);
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ template<typename _Type>
|
|
|
+ static std::shared_ptr<class_value> serialize(std::shared_ptr<_Type> value) {
|
|
|
+ return serialize(*value);
|
|
|
+ }
|
|
|
+ template<typename _Type>
|
|
|
+ static std::shared_ptr<class_value> serialize(_Type* value) {
|
|
|
+ return serialize(*value);
|
|
|
+ }
|
|
|
+ template<typename _Type>
|
|
|
+ static std::shared_ptr<class_value> serialize(_Type value) {
|
|
|
+ std::shared_ptr<class_value> result(new class_value);
|
|
|
+ rttr::type type = rttr::type::get<_Type>();
|
|
|
+ std::string className(type.get_name());
|
|
|
+ result->class_name = className;
|
|
|
+ result->is_list = false;
|
|
|
+ std::map<std::string, std::string> elem = web_reflect::get_object_value(value);
|
|
|
+ result->class_value.push_back(elem);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ struct pseudo_extract_label_value {
|
|
|
+ /*
|
|
|
+ * 伪代码结构
|
|
|
+ * 可嵌套 避开关键字 [' }]
|
|
|
+ * ${model name='test_info.userName' value='['${model name='test_info.id' value='[#value]'/}':'启用','false':'禁用'/}
|
|
|
+ *
|
|
|
+ * switch case 中不能存在 #value 属性值 default可以有默认值 可以有固定值
|
|
|
+ * ${switch name='test_info.id'}{case value='1'}<h1>值1</h1>{/case}...{default}<h1>#value</h1>{/default}{/switch}
|
|
|
+ *
|
|
|
+ * if 运算符 == != >= <=
|
|
|
+ * ${if name='test_info.id' value=='100'}<p>判断正确</p>{else}<p>判断错误</p>{/if}
|
|
|
+ *
|
|
|
+ * for for-index 从1开始
|
|
|
+ * ${for item='item' list='test_info'} <td>{item name='item.for-index' value='[#value]'/}</td><td>{item name='item.enable' value='['true':'启用','default':'#value']'/}</td>{/for}
|
|
|
+ *
|
|
|
+ * file path 可以固定 可以嵌套 model设置html路径
|
|
|
+ * ${file path='C:/Users/86158/Desktop/404.html'/}
|
|
|
+ */
|
|
|
+ static std::vector<std::shared_ptr<ipseudo_label>> analysis(std::string const& html) {
|
|
|
+ std::vector<std::shared_ptr<ipseudo_label>> result;
|
|
|
+ std::pair<std::string, std::string> type = { "${mask","{/mask}" };
|
|
|
+ for (size_t i = 0; i < html.size(); ++i) {
|
|
|
+ if (html.size() > i + type.first.size() &&
|
|
|
+ html[i] == type.first[0] &&
|
|
|
+ html.substr(i, type.first.size()) == type.first) {
|
|
|
+
|
|
|
+ std::string retHtml = nounanalysis(html.substr(i, html.size() - i), result);
|
|
|
+ result[result.size() - 1]->html_code;
|
|
|
+ i += retHtml.size();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for (auto it : result) {
|
|
|
+ it->analysis_baseinfo();
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ private:
|
|
|
+ static std::string nounanalysis(std::string const& html, std::vector<std::shared_ptr<ipseudo_label>>& childs, pseudo_type type = pseudo_type::MASK) {
|
|
|
+ static std::map<pseudo_type, std::pair<std::string, std::string>> g_pseudoLabel = {
|
|
|
+ {
|
|
|
+ pseudo_type::MASK,
|
|
|
+ {"${mask","{/mask}"}
|
|
|
+ },
|
|
|
+ {
|
|
|
+ pseudo_type::MODEL,
|
|
|
+ {"${model","/}"}
|
|
|
+ },
|
|
|
+ {
|
|
|
+ pseudo_type::SWITCH,
|
|
|
+ {"${switch","{/switch}"}
|
|
|
+ },
|
|
|
+ {
|
|
|
+ pseudo_type::IF,
|
|
|
+ {"${if","{/if}"}
|
|
|
+ },
|
|
|
+ {
|
|
|
+ pseudo_type::FOR,
|
|
|
+ {"${for","{/for}"}
|
|
|
+ },
|
|
|
+ {
|
|
|
+ pseudo_type::FILE,
|
|
|
+ {"${file","/}"}
|
|
|
+ }
|
|
|
+ };
|
|
|
+ if (!(html.size() > g_pseudoLabel[type].first.size() &&
|
|
|
+ html.substr(0, g_pseudoLabel[type].first.size()) == g_pseudoLabel[type].first)) {
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+ if (type == pseudo_type::MASK)
|
|
|
+ childs.push_back(std::make_shared<pseudo_mask_label>(*g_pseudoLabel.find(type)));
|
|
|
+ else if (type == pseudo_type::MODEL)
|
|
|
+ childs.push_back(std::make_shared<pseudo_model_label>(*g_pseudoLabel.find(type)));
|
|
|
+ else if (type == pseudo_type::FOR)
|
|
|
+ childs.push_back(std::make_shared<pseudo_for_label>(*g_pseudoLabel.find(type)));
|
|
|
+ else if (type == pseudo_type::IF)
|
|
|
+ childs.push_back(std::make_shared<pseudo_if_label>(*g_pseudoLabel.find(type)));
|
|
|
+ else if (type == pseudo_type::SWITCH)
|
|
|
+ childs.push_back(std::make_shared<pseudo_switch_label>(*g_pseudoLabel.find(type)));
|
|
|
+ else if (type == pseudo_type::FILE)
|
|
|
+ childs.push_back(std::make_shared<pseudo_file_label>(*g_pseudoLabel.find(type)));
|
|
|
+ for (std::string::size_type i = 0; i < html.size(); ++i) {
|
|
|
+ for (auto pseudo : g_pseudoLabel) {
|
|
|
+ if (html.size() > i + pseudo.second.first.size() &&
|
|
|
+ html[i] == pseudo.second.first[0] &&
|
|
|
+ html.substr(i, pseudo.second.first.size()) == pseudo.second.first) {
|
|
|
+ if (i == 0) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ std::string retHtml = nounanalysis(html.substr(i, html.size() - i), childs[childs.size() - 1]->childs, pseudo.first);
|
|
|
+ childs[childs.size() - 1]->html_code += retHtml;
|
|
|
+ i += retHtml.size();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (type != pseudo_type::NON) {
|
|
|
+ childs[childs.size() - 1]->html_code += html[i];
|
|
|
+ }
|
|
|
+ if (childs[childs.size() - 1]->html_code.size() > g_pseudoLabel[type].second.size() &&
|
|
|
+ childs[childs.size() - 1]->html_code.substr(childs[childs.size() - 1]->html_code.size() - g_pseudoLabel[type].second.size(), g_pseudoLabel[type].second.size()) == g_pseudoLabel[type].second) {
|
|
|
+ return childs[childs.size() - 1]->html_code;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ enum class from_storage_type {
|
|
|
+ /**
|
|
|
+ * @brief body
|
|
|
+ */
|
|
|
+ BODY = 0,
|
|
|
+ /**
|
|
|
+ * @brief url
|
|
|
+ */
|
|
|
+ QUERY,
|
|
|
+ /**
|
|
|
+ * @brief header
|
|
|
+ */
|
|
|
+ HEADER,
|
|
|
+ /**
|
|
|
+ * @brief url
|
|
|
+ */
|
|
|
+ URL
|
|
|
+ };
|
|
|
+
|
|
|
+ enum class argument_type {
|
|
|
+ Json = 0,
|
|
|
+ Multipart,
|
|
|
+ Int,
|
|
|
+ Int64,
|
|
|
+ Float,
|
|
|
+ Double,
|
|
|
+ Long,
|
|
|
+ Bool_,
|
|
|
+ String,
|
|
|
+ DateTime,
|
|
|
+ Binary,
|
|
|
+ VecJson,
|
|
|
+ VecInt,
|
|
|
+ VecInt64,
|
|
|
+ VecFloat,
|
|
|
+ VecDouble,
|
|
|
+ VecLong,
|
|
|
+ VecBool,
|
|
|
+ VecString,
|
|
|
+ VecDateTime
|
|
|
+ };
|
|
|
+
|
|
|
+ enum class http_method {
|
|
|
+ /**
|
|
|
+ * @brief get
|
|
|
+ */
|
|
|
+ GET = 0,
|
|
|
+ /**
|
|
|
+ * @brief post
|
|
|
+ */
|
|
|
+ POST = 1
|
|
|
+ };
|
|
|
+
|
|
|
+ struct multipart {
|
|
|
+ std::string content_disposition;
|
|
|
+ std::string name;
|
|
|
+ std::vector<std::uint8_t> data;
|
|
|
+ std::string value;
|
|
|
+ std::string content_type;
|
|
|
+ std::string filename;
|
|
|
+ std::string content_transfer_encoding;
|
|
|
+ };
|
|
|
+
|
|
|
+ struct multipart_value {
|
|
|
+ std::vector<multipart> data;
|
|
|
+ template<typename _Type>
|
|
|
+ _Type value() {
|
|
|
+ _Type result;
|
|
|
+ std::map<std::string, std::string> elem;
|
|
|
+ for (auto value : data) {
|
|
|
+ elem[value.name] = value.value;
|
|
|
+ }
|
|
|
+ web_reflect::set_object_value(result, elem);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ struct action_argument {
|
|
|
+ void parameter(http::web_request& request, const rttr::parameter_info& type) {
|
|
|
+ parameter_value_.clear();
|
|
|
+ switch (from_storage_type_) {
|
|
|
+ case from_storage_type::HEADER: analysis_header(request, type); return;
|
|
|
+ case from_storage_type::QUERY: analysis_query(request, type); return;
|
|
|
+ case from_storage_type::BODY: analysis_body(request, type); return;
|
|
|
+ case from_storage_type::URL: analysis_url(request, type); return;
|
|
|
+ }
|
|
|
+ throw std::runtime_error("FormStorageType:错误!");
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief 参数名称
|
|
|
+ */
|
|
|
+ std::string parameter_name_;
|
|
|
+ /**
|
|
|
+ * @brief 参数
|
|
|
+ */
|
|
|
+ rttr::variant parameter_value_;
|
|
|
+ /**
|
|
|
+ * @brief 数据类型
|
|
|
+ */
|
|
|
+ argument_type argument_type_ = argument_type::Binary;
|
|
|
+ /**
|
|
|
+ * @brief 表单存储类型
|
|
|
+ */
|
|
|
+ from_storage_type from_storage_type_ = from_storage_type::QUERY;
|
|
|
+ private:
|
|
|
+ /**
|
|
|
+ * @brief 解析协议头
|
|
|
+ * @param request
|
|
|
+ * @param type
|
|
|
+ */
|
|
|
+ void analysis_header(http::web_request& request, const rttr::parameter_info& type) {
|
|
|
+ std::map<std::string, std::string> headers;
|
|
|
+ for (auto& it : request) {
|
|
|
+ std::string name(it.name_string().begin(), it.name_string().end());
|
|
|
+ std::string value(it.value().begin(), it.value().end());
|
|
|
+ headers[name] = value;
|
|
|
+ }
|
|
|
+ if (headers.find(parameter_name_) == headers.end())
|
|
|
+ throw std::runtime_error("解析协议头参数错误!");
|
|
|
+ convert(headers[parameter_name_], type);
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief 解析url参数
|
|
|
+ * @param request
|
|
|
+ * @param type
|
|
|
+ */
|
|
|
+ void analysis_query(http::web_request& request, const rttr::parameter_info& type) {
|
|
|
+ std::string query(request.query().begin(), request.query().end());
|
|
|
+ std::map<std::string, std::string> querys = v3::utils::split_http_form(query);
|
|
|
+ if (querys.find(parameter_name_) == querys.end())
|
|
|
+ throw std::runtime_error("解析Query参数错误!");
|
|
|
+ convert(querys[parameter_name_], type);
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief 解析BODY
|
|
|
+ * @param request
|
|
|
+ * @param type
|
|
|
+ */
|
|
|
+ void analysis_body(http::web_request& request, const rttr::parameter_info& type) {
|
|
|
+ if (type.get_type() == rttr::type::get<multipart_value>()) {
|
|
|
+ multipart_value parameter;
|
|
|
+ auto multipartValue = request.get_multipart();
|
|
|
+ for (auto it = multipartValue.begin(); it != multipartValue.end(); ++it) {
|
|
|
+ multipart item;
|
|
|
+ item.content_disposition = it->content_disposition();
|
|
|
+ item.name = it->name();
|
|
|
+ auto valueTmp = it->value();
|
|
|
+ item.data.insert(item.data.end(), valueTmp.begin(), valueTmp.end());
|
|
|
+ if (it->filename().empty()) {
|
|
|
+ try {
|
|
|
+ item.value = it->value();
|
|
|
+ }
|
|
|
+ catch (...) {}
|
|
|
+ }
|
|
|
+ item.content_type = it->content_type();
|
|
|
+ item.filename = it->filename();
|
|
|
+ item.content_transfer_encoding = it->content_transfer_encoding();
|
|
|
+ parameter.data.push_back(item);
|
|
|
+ }
|
|
|
+ parameter_value_ = parameter;
|
|
|
+ }
|
|
|
+ else if (parameter_name_.empty()) {
|
|
|
+ convert(std::string(request.body().begin(), request.body().end()), type);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ std::string body(request.body().begin(), request.body().end());
|
|
|
+ std::map<std::string, std::string> bodys = v3::utils::split_http_form(body);
|
|
|
+ if (bodys.find(parameter_name_) == bodys.end())
|
|
|
+ throw std::runtime_error("解析Body参数错误!");
|
|
|
+ convert(bodys[parameter_name_], type);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief url
|
|
|
+ * @param request
|
|
|
+ * @param type
|
|
|
+ */
|
|
|
+ void analysis_url(http::web_request& request, const rttr::parameter_info& type) {
|
|
|
+ std::string query(request.find("http_route_parameter")->value());
|
|
|
+ std::map<std::string, std::string> querys = v3::utils::split_http_form(query);
|
|
|
+ if (querys.find(parameter_name_) == querys.end())
|
|
|
+ throw std::runtime_error("解析Query参数错误!");
|
|
|
+ convert(querys[parameter_name_], type);
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief 数据转换
|
|
|
+ * @param data
|
|
|
+ * @param type
|
|
|
+ */
|
|
|
+ void convert(std::string_view data, const rttr::parameter_info& type) {
|
|
|
+ try {
|
|
|
+ switch (argument_type_) {
|
|
|
+ case argument_type::Json: {
|
|
|
+ parameter_value_ = type.get_type().create();
|
|
|
+ v3::json_convert::deserialize(std::string(data.begin(), data.end()), parameter_value_);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ case argument_type::Multipart: {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ case argument_type::Int: {
|
|
|
+ parameter_value_ = std::atoi(std::string(data.begin(), data.end()).c_str());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ case argument_type::Int64: {
|
|
|
+ parameter_value_ = std::atoll(std::string(data.begin(), data.end()).c_str());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ case argument_type::Float: {
|
|
|
+ parameter_value_ = std::atof(std::string(data.begin(), data.end()).c_str());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ case argument_type::Double: {
|
|
|
+ parameter_value_ = std::atof(std::string(data.begin(), data.end()).c_str());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ case argument_type::Long: {
|
|
|
+ parameter_value_ = std::atol(std::string(data.begin(), data.end()).c_str());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ case argument_type::Bool_: {
|
|
|
+ std::string tmpValue(data.begin(), data.end());
|
|
|
+ parameter_value_ = tmpValue == "1" || tmpValue == "true" || tmpValue == "TRUE" || tmpValue == "True";
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ case argument_type::String: {
|
|
|
+ parameter_value_ = std::string(data.begin(), data.end());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ case argument_type::DateTime: {
|
|
|
+ parameter_value_ = datetime(std::string(data.begin(), data.end()));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ case argument_type::Binary: {
|
|
|
+ parameter_value_ = std::vector<std::uint8_t>(data.begin(), data.end());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ case argument_type::VecInt: {
|
|
|
+ std::vector<std::string> vec = v3::utils::split(std::string(data.begin(), data.end()), ",");
|
|
|
+ std::vector<int> vecValue;
|
|
|
+ for (auto vecIt : vec) {
|
|
|
+ vecValue.push_back(std::atoi(vecIt.c_str()));
|
|
|
+ }
|
|
|
+ parameter_value_ = vecValue;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ case argument_type::VecInt64: {
|
|
|
+ std::vector<std::string> vec = v3::utils::split(std::string(data.begin(), data.end()), ",");
|
|
|
+ std::vector<std::int64_t> vecValue;
|
|
|
+ for (auto vecIt : vec) {
|
|
|
+ vecValue.push_back(std::atoll(vecIt.c_str()));
|
|
|
+ }
|
|
|
+ parameter_value_ = vecValue;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ case argument_type::VecFloat: {
|
|
|
+ std::vector<std::string> vec = v3::utils::split(std::string(data.begin(), data.end()), ",");
|
|
|
+ std::vector<float> vecValue;
|
|
|
+ for (auto vecIt : vec) {
|
|
|
+ vecValue.push_back(std::atof(vecIt.c_str()));
|
|
|
+ }
|
|
|
+ parameter_value_ = vecValue;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ case argument_type::VecDouble: {
|
|
|
+ std::vector<std::string> vec = v3::utils::split(std::string(data.begin(), data.end()), ",");
|
|
|
+ std::vector<double> vecValue;
|
|
|
+ for (auto vecIt : vec) {
|
|
|
+ vecValue.push_back(std::atof(vecIt.c_str()));
|
|
|
+ }
|
|
|
+ parameter_value_ = vecValue;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ case argument_type::VecLong: {
|
|
|
+ std::vector<std::string> vec = v3::utils::split(std::string(data.begin(), data.end()), ",");
|
|
|
+ std::vector<long> vecValue;
|
|
|
+ for (auto vecIt : vec) {
|
|
|
+ vecValue.push_back(std::atol(vecIt.c_str()));
|
|
|
+ }
|
|
|
+ parameter_value_ = vecValue;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ case argument_type::VecBool: {
|
|
|
+ std::vector<std::string> vec = v3::utils::split(std::string(data.begin(), data.end()), ",");
|
|
|
+ std::vector<bool> vecValue;
|
|
|
+ for (auto vecIt : vec) {
|
|
|
+ vecValue.push_back(vecIt == "1" || vecIt == "true" || vecIt == "TRUE" || vecIt == "True");
|
|
|
+ }
|
|
|
+ parameter_value_ = vecValue;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ case argument_type::VecString: {
|
|
|
+ std::vector<std::string> vecValue = v3::utils::split(std::string(data.begin(), data.end()), ",");
|
|
|
+ parameter_value_ = vecValue;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ case argument_type::VecDateTime: {
|
|
|
+ std::vector<std::string> vec = v3::utils::split(std::string(data.begin(), data.end()), ",");
|
|
|
+ std::vector<datetime> vecValue;
|
|
|
+ for (auto vecIt : vec) {
|
|
|
+ vecValue.push_back(datetime(vecIt));
|
|
|
+ }
|
|
|
+ parameter_value_ = vecValue;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (...) {
|
|
|
+ throw std::runtime_error("解析参数错误");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ struct controller;
|
|
|
+
|
|
|
+ struct controller_action {
|
|
|
+ /**
|
|
|
+ * @brief 执行动作
|
|
|
+ * @param request
|
|
|
+ */
|
|
|
+ rttr::variant invoke(http::web_request& request, rttr::variant& variant, rttr::type const& controller_type) {
|
|
|
+ auto http_current_ptr = http_context::current();
|
|
|
+ //判断contentType
|
|
|
+ std::string content_type = "application/x-www-form-urlencoded";
|
|
|
+ if (request.find(http::field::content_type) != request.end()) {
|
|
|
+ content_type = std::string(request.find(http::field::content_type)->value().begin(), request.find(http::field::content_type)->value().end());
|
|
|
+ }
|
|
|
+ if (content_type.find(content_type) == std::string::npos) {
|
|
|
+ throw std::runtime_error("Content-Type:错误!");
|
|
|
+ }
|
|
|
+ //判断method
|
|
|
+ if (!((method == http_method::GET && request.method() == http::verb::get) || (method == http_method::POST && request.method() == http::verb::post))) {
|
|
|
+ throw std::runtime_error("Method:错误!");
|
|
|
+ }
|
|
|
+ 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("Action:错误!");
|
|
|
+ std::vector<rttr::argument> parameters;
|
|
|
+ std::vector<rttr::variant> variantParameters;
|
|
|
+ {
|
|
|
+ std::lock_guard<std::mutex> locker(mux);
|
|
|
+ for (auto& it : find_method[0].get_parameter_infos()) {
|
|
|
+ arguments[it.get_index()]->parameter(request, it);
|
|
|
+ }
|
|
|
+ for (auto& it : arguments) {
|
|
|
+ variantParameters.push_back(it->parameter_value_);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ for (auto& it : variantParameters) {
|
|
|
+ parameters.push_back(it);
|
|
|
+ }
|
|
|
+ return controller_type.invoke(action_name, variant, parameters);
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief 身份验证
|
|
|
+ */
|
|
|
+ bool authen = true;
|
|
|
+ /**
|
|
|
+ * @brief 未登录跳转
|
|
|
+ */
|
|
|
+ std::string authen_jump;
|
|
|
+ /**
|
|
|
+ * @brief 方法名称
|
|
|
+ */
|
|
|
+ std::string action_name;
|
|
|
+ /**
|
|
|
+ * @brief 方式
|
|
|
+ */
|
|
|
+ http_method method = http_method::GET;
|
|
|
+ /**
|
|
|
+ * @brief 数据类型
|
|
|
+ */
|
|
|
+ std::string content_type = "application/x-www-form-urlencoded";
|
|
|
+ /**
|
|
|
+ * @brief 动作类型
|
|
|
+ */
|
|
|
+ std::string action_type;
|
|
|
+ /**
|
|
|
+ * @brief 文件映射
|
|
|
+ */
|
|
|
+ std::string file_mapping;
|
|
|
+ /**
|
|
|
+ * @brief 参数
|
|
|
+ */
|
|
|
+ std::vector<std::shared_ptr<action_argument>> arguments;
|
|
|
+ /**
|
|
|
+ * @brief 控制器
|
|
|
+ */
|
|
|
+ std::shared_ptr<controller> parent;
|
|
|
+ private:
|
|
|
+ /**
|
|
|
+ * @brief 锁
|
|
|
+ */
|
|
|
+ std::mutex mux;
|
|
|
+ };
|
|
|
+
|
|
|
+ struct controller {
|
|
|
+ rttr::variant invoke(http::web_request& request) {
|
|
|
+ std::string key(request.find("http_route_key")->value());
|
|
|
+ if (!actions.contains(key))
|
|
|
+ throw std::runtime_error("Action:不存在!");
|
|
|
+ rttr::type type = rttr::type::get_by_name(controller_name);
|
|
|
+ if (!variant.is_valid())
|
|
|
+ variant = type.create();
|
|
|
+ return actions[key]->invoke(request, variant, type);
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief 控制器名称
|
|
|
+ */
|
|
|
+ std::string controller_name;
|
|
|
+ /**
|
|
|
+ * @brief 动作列表 路由 动作
|
|
|
+ */
|
|
|
+ std::map<std::string, std::shared_ptr<controller_action>> actions;
|
|
|
+ private:
|
|
|
+ /**
|
|
|
+ * @brief 对象
|
|
|
+ */
|
|
|
+ rttr::variant variant;
|
|
|
+ };
|
|
|
+
|
|
|
+ struct mvc_route {
|
|
|
+ bool contains(http::web_request& req) {
|
|
|
+ std::string key;
|
|
|
+ std::string route(req.find("http_route")->value());
|
|
|
+ if (contains(route, key)) {
|
|
|
+ std::size_t index = key.find('<');
|
|
|
+ std::vector<std::string> params;
|
|
|
+ if (std::string::npos != index) {
|
|
|
+ auto keys = v3::utils::split(key.substr(index), "/");
|
|
|
+ auto values = v3::utils::split(route.substr(index), "/");
|
|
|
+ for (int i = 0; i < keys.size() && i < values.size(); ++i) {
|
|
|
+ params.push_back(keys[i].substr(1, keys[i].size() - 2) + "=" + values[i]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ req.insert("http_route_key", key);
|
|
|
+ req.insert("http_route_parameter", v3::utils::join(params, "&"));
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ bool contains(std::string const& route) {
|
|
|
+ std::string key;
|
|
|
+ return contains(route, key);
|
|
|
+ }
|
|
|
+ void add(std::string const& route, std::shared_ptr<controller> value) {
|
|
|
+ routes_[route] = value;
|
|
|
+ }
|
|
|
+ std::shared_ptr<controller>& find(std::string const& route) {
|
|
|
+ std::string key;
|
|
|
+ if (contains(route, key)) {
|
|
|
+ return routes_[key];
|
|
|
+ }
|
|
|
+ throw std::runtime_error("key does not exist");
|
|
|
+ }
|
|
|
+ std::shared_ptr<controller>& operator[](std::string const& route) {
|
|
|
+ return find(route);
|
|
|
+ }
|
|
|
+ std::shared_ptr<controller>& operator[](http::web_request& req) {
|
|
|
+ return find(std::string(req.find("http_route_key")->value()));
|
|
|
+ }
|
|
|
+ private:
|
|
|
+ bool contains(std::string const& route, std::string& result) {
|
|
|
+ if (routes_.contains(route)) {
|
|
|
+ result = route;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ int slash_count = std::count(route.begin(), route.end(), '/');
|
|
|
+ for (auto& [first, second] : routes_) {
|
|
|
+ std::size_t index = first.find('<');
|
|
|
+ if (std::count(first.begin(), first.end(), '/') == slash_count && index != std::string::npos) {
|
|
|
+ if (first.substr(0, index) == route.substr(0, index)) {
|
|
|
+ result = first;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ private:
|
|
|
+ std::map<std::string, std::shared_ptr<controller>> routes_;
|
|
|
+ };
|
|
|
+
|
|
|
+ struct MVC_API ico_controller {
|
|
|
+ /**
|
|
|
+ * @brief 注册
|
|
|
+ */
|
|
|
+ static void attach(std::shared_ptr<controller> controller) {
|
|
|
+ for (auto& [first, second] : controller->actions) {
|
|
|
+ controllers_.add(first, controller);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * @brief
|
|
|
+ * @param url
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ static std::shared_ptr<controller> resolve(http::web_request& req) {
|
|
|
+ if (controllers_.contains(req)) {
|
|
|
+ return controllers_[req];
|
|
|
+ }
|
|
|
+ return nullptr;
|
|
|
+ }
|
|
|
+ private:
|
|
|
+ /**
|
|
|
+ * @brief
|
|
|
+ */
|
|
|
+ static mvc_route controllers_;
|
|
|
+ };
|
|
|
+
|
|
|
+ struct web_base_response {
|
|
|
+ void set_header(std::string_view name, std::string_view value) {
|
|
|
+ auto& response = http_context::current()->response;
|
|
|
+ response.set(name, value);
|
|
|
+ }
|
|
|
+ void set_header(http::field field, std::string_view value) {
|
|
|
+ auto& response = http_context::current()->response;
|
|
|
+ response.set(field, value);
|
|
|
+ }
|
|
|
+ void set_value(std::string_view value) {
|
|
|
+ auto& response = http_context::current()->response;
|
|
|
+ response.body().file().close();
|
|
|
+ response.body().text() = std::move(value);
|
|
|
+ auto const size = response.body().size();
|
|
|
+ response.content_length(size);
|
|
|
+ }
|
|
|
+ void set_value(std::vector<std::uint8_t> const& value) {
|
|
|
+ auto& response = http_context::current()->response;
|
|
|
+ response.body().file().close();
|
|
|
+ response.body().text() = std::string((char*)&value[0], value.size());
|
|
|
+ auto const size = response.body().size();
|
|
|
+ response.content_length(size);
|
|
|
+ }
|
|
|
+ void set_status(http::status status = http::status::ok) {
|
|
|
+ auto& response = http_context::current()->response;
|
|
|
+ response.result(status);
|
|
|
+ }
|
|
|
+ std::filesystem::path get_root_directory() {
|
|
|
+ auto& response = http_context::current()->response;
|
|
|
+ return response.get_root_directory();
|
|
|
+ }
|
|
|
+ http::status get_status() {
|
|
|
+ auto& response = http_context::current()->response;
|
|
|
+ return response.result();
|
|
|
+ }
|
|
|
+ std::string get_value() {
|
|
|
+ auto& response = http_context::current()->response;
|
|
|
+ return response.body().text();
|
|
|
+ }
|
|
|
+ void prepare_payload() {
|
|
|
+ auto& response = http_context::current()->response;
|
|
|
+ response.prepare_payload();
|
|
|
+ }
|
|
|
+ void chunked(bool value) {
|
|
|
+ auto& response = http_context::current()->response;
|
|
|
+ response.chunked(value);
|
|
|
+ }
|
|
|
+ void set_server(std::string_view value = BEAST_VERSION_STRING) {
|
|
|
+ auto& response = http_context::current()->response;
|
|
|
+ response.set(http::field::server, value);
|
|
|
+ }
|
|
|
+ void set_version(int ver = 11) {
|
|
|
+ auto& response = http_context::current()->response;
|
|
|
+ response.version(ver);
|
|
|
+ }
|
|
|
+ void fill_file(std::filesystem::path const& path, http::status status = http::status::ok) {
|
|
|
+ auto& response = http_context::current()->response;
|
|
|
+ if (path.c_str()[0] == '/' || path.c_str()[0] == '\\') {
|
|
|
+ response.fill_file(path, status);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ response.fill_file("/" + path.string(), status);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ void fill_html(std::string const& html, http::status status = http::status::ok) {
|
|
|
+ auto& response = http_context::current()->response;
|
|
|
+ response.fill_html(html, status);
|
|
|
+ }
|
|
|
+ void fill_json(std::string const& json, http::status status = http::status::ok) {
|
|
|
+ auto& response = http_context::current()->response;
|
|
|
+ response.fill_json(json, status);
|
|
|
+ }
|
|
|
+ void fill_page(std::string const& value, http::status status = http::status::ok) {
|
|
|
+ auto& response = http_context::current()->response;
|
|
|
+ response.fill_page(status, value);
|
|
|
+ }
|
|
|
+ void fill_text(std::string const& text, http::status status = http::status::ok) {
|
|
|
+ auto& response = http_context::current()->response;
|
|
|
+ response.fill_text(text, status);
|
|
|
+ }
|
|
|
+ void fill_jump(std::string const& url) {
|
|
|
+ set_header(http::field::content_type, http::extension_to_mimetype("html"));
|
|
|
+ set_header(http::field::location, url);
|
|
|
+ set_status(http::status::found);
|
|
|
+ }
|
|
|
+ void fill_stream(std::vector<std::uint8_t> const& data, std::string const& extension, http::status status = http::status::ok) {
|
|
|
+ set_header("Content-Type", http::extension_to_mimetype(extension));
|
|
|
+ set_value(data);
|
|
|
+ set_status(status);
|
|
|
+ }
|
|
|
+ void fill_download(std::filesystem::path const& path, http::status status = http::status::ok) {
|
|
|
+ set_header(http::field::content_type, "application/octet-stream");
|
|
|
+ set_header(http::field::content_disposition, v3::utils::format("attachment; filename={}", path.filename().string()));
|
|
|
+ }
|
|
|
+ void fill_download(std::filesystem::path const& path, std::string const& filename, http::status status = http::status::ok) {
|
|
|
+ set_header(http::field::content_type, "application/octet-stream");
|
|
|
+ set_header(http::field::content_disposition, v3::utils::format("attachment; filename={}", filename));
|
|
|
+ }
|
|
|
+ void fill_view(http::status status = http::status::ok) {
|
|
|
+ fill_file(get_filename(), status);
|
|
|
+ }
|
|
|
+ std::filesystem::path get_filename() {
|
|
|
+ return mvc::http_context::current()->get_controller_action()->file_mapping;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ struct web_result_response : public web_base_response {};
|
|
|
+
|
|
|
+ struct unknown_response : public web_base_response {
|
|
|
+ unknown_response(std::string const& text) {
|
|
|
+ set_value(text);
|
|
|
+ set_status(http::status::unknown);
|
|
|
+ }
|
|
|
+ virtual ~unknown_response() {
|
|
|
+ }
|
|
|
+ operator web_result_response() {
|
|
|
+ return {};
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ struct jump_response : public web_base_response {
|
|
|
+ jump_response(std::string const& url) {
|
|
|
+ if (!url.empty()) {
|
|
|
+ if (url[0] != '/')
|
|
|
+ fill_jump("/" + url);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ fill_jump(url);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ virtual ~jump_response() {
|
|
|
+ }
|
|
|
+ operator web_result_response() {
|
|
|
+ return {};
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ struct text_response : public web_base_response {
|
|
|
+ text_response(std::string const& text, http::status status = http::status::ok) {
|
|
|
+ fill_text(text, status);
|
|
|
+ }
|
|
|
+ virtual ~text_response() {
|
|
|
+ }
|
|
|
+ operator web_result_response() {
|
|
|
+ return {};
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ struct html_response : public web_base_response {
|
|
|
+ html_response(std::string const& html, http::status status = http::status::ok) {
|
|
|
+ fill_html(html, status);
|
|
|
+ }
|
|
|
+ virtual ~html_response() {
|
|
|
+ }
|
|
|
+ operator web_result_response() {
|
|
|
+ return {};
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ struct file_response : public web_base_response {
|
|
|
+ file_response() {
|
|
|
+ fill_file(get_filename());
|
|
|
+ }
|
|
|
+ file_response(http::status status = http::status::ok) {
|
|
|
+ fill_file(get_filename(), status);
|
|
|
+ }
|
|
|
+ file_response(std::filesystem::path const& path, http::status status = http::status::ok) {
|
|
|
+ fill_file(path, status);
|
|
|
+ }
|
|
|
+ virtual ~file_response() {
|
|
|
+ }
|
|
|
+ operator web_result_response() {
|
|
|
+ return {};
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ struct json_response : public web_base_response {
|
|
|
+ json_response(std::string const& json) {
|
|
|
+ fill_json(json);
|
|
|
+ }
|
|
|
+ json_response(char* json) :
|
|
|
+ json_response(std::string(json)) {
|
|
|
+ }
|
|
|
+ json_response(const char* json) :
|
|
|
+ json_response(std::string(json)) {
|
|
|
+ }
|
|
|
+ template<typename _Type>
|
|
|
+ json_response(_Type const& value) {
|
|
|
+ fill_json(v3::json_convert::serialize(value));
|
|
|
+ }
|
|
|
+ virtual~json_response() {
|
|
|
+ }
|
|
|
+ operator web_result_response() {
|
|
|
+ return {};
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ struct stream_response : public web_base_response {
|
|
|
+ stream_response(std::vector<std::uint8_t> const& data, std::string const& extension, http::status status = http::status::ok) {
|
|
|
+ fill_stream(data, extension, status);
|
|
|
+ }
|
|
|
+ virtual~stream_response() {
|
|
|
+ }
|
|
|
+ operator web_result_response() {
|
|
|
+ return {};
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ struct download_response : public web_base_response {
|
|
|
+ download_response(std::filesystem::path const& path, http::status status = http::status::ok) {
|
|
|
+ fill_download(path, status);
|
|
|
+ }
|
|
|
+ download_response(std::filesystem::path const& path, std::string const& filename, http::status status = http::status::ok) {
|
|
|
+ fill_download(path, filename, status);
|
|
|
+ }
|
|
|
+ virtual~download_response() {
|
|
|
+ }
|
|
|
+ operator web_result_response() {
|
|
|
+ return {};
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ struct view : public web_base_response {
|
|
|
+ virtual ~view() {
|
|
|
+ }
|
|
|
+ view() :
|
|
|
+ web_base_response() {
|
|
|
+ fill_view();
|
|
|
+ }
|
|
|
+ view(std::string const& path) :
|
|
|
+ web_base_response() {
|
|
|
+ fill_file(path);
|
|
|
+ }
|
|
|
+ template<typename ..._Args>
|
|
|
+ view(_Args&& ...args) {
|
|
|
+ std::filesystem::path path = get_filename();
|
|
|
+ std::filesystem::path filepath;
|
|
|
+ filepath = http_context::current()->response.get_root_directory();
|
|
|
+ filepath.make_preferred();
|
|
|
+ filepath /= path.make_preferred().relative_path();
|
|
|
+ std::vector<std::uint8_t> value;
|
|
|
+ std::ifstream file(filepath, std::ios::in | std::ios::binary);
|
|
|
+ if (file.is_open()) {
|
|
|
+ file.seekg(0, std::ios::end);
|
|
|
+ int file_size = file.tellg();
|
|
|
+ file.seekg(0, std::ios::beg);
|
|
|
+ value.resize(file_size);
|
|
|
+ file.read((char*)&value[0], file_size);
|
|
|
+ file.close();
|
|
|
+ }
|
|
|
+ std::string html(value.begin(), value.end());
|
|
|
+ auto label_value_list = pseudo_extract_label_value::analysis(html);
|
|
|
+ if (!label_value_list.empty()) {
|
|
|
+ auto classValueList = pseudo_extract_class_value::get_class_value(std::forward<_Args>(args)...);
|
|
|
+ label_value_list[0]->set_class_value(classValueList);
|
|
|
+ html = label_value_list[0]->analysis();
|
|
|
+ fill_html(html);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ operator web_result_response() {
|
|
|
+ return {};
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ template<int _Width = 100, int _Height = 38, int _Length = 4, int _Line = 2, int _Spot = 200>
|
|
|
+ struct captcha_response : public v3::mvc::web_base_response {
|
|
|
+ captcha_response(std::string const& session_key = "code") :
|
|
|
+ session_key_(session_key) {
|
|
|
+ }
|
|
|
+ virtual ~captcha_response() {
|
|
|
+ }
|
|
|
+ operator v3::mvc::web_result_response() {
|
|
|
+ //验证码
|
|
|
+ std::string captcha_code = generate_captcha_digits();
|
|
|
+ http_context::current()->add_session(session_key_, captcha_code);
|
|
|
+ std::vector<std::uint8_t> img_vec = generate_captcha_image(captcha_code);
|
|
|
+ return v3::mvc::stream_response(img_vec, "bmp");
|
|
|
+ }
|
|
|
+ private:
|
|
|
+ class CImage : public cimg_library::CImg<unsigned char> {
|
|
|
+ public:
|
|
|
+ CImage(const cimg_library::CImg<unsigned char>& img) :
|
|
|
+ cimg_library::CImg<unsigned char>(img) {}
|
|
|
+ cimg_library::CImg<unsigned char>& save_memory_bmp(std::vector<std::uint8_t>& result) {
|
|
|
+ cimg_library::CImg<ucharT> header(54, 1, 1, 1, 0);
|
|
|
+ unsigned char align_buf[4] = {};
|
|
|
+ const unsigned int
|
|
|
+ align = (4 - (3 * _width) % 4) % 4,
|
|
|
+ buf_size = (3 * _width + align) * height(),
|
|
|
+ file_size = 54 + buf_size;
|
|
|
+ header[0] = 'B'; header[1] = 'M';
|
|
|
+ header[0x02] = file_size & 0xFF;
|
|
|
+ header[0x03] = (file_size >> 8) & 0xFF;
|
|
|
+ header[0x04] = (file_size >> 16) & 0xFF;
|
|
|
+ header[0x05] = (file_size >> 24) & 0xFF;
|
|
|
+ header[0x0A] = 0x36;
|
|
|
+ header[0x0E] = 0x28;
|
|
|
+ header[0x12] = _width & 0xFF;
|
|
|
+ header[0x13] = (_width >> 8) & 0xFF;
|
|
|
+ header[0x14] = (_width >> 16) & 0xFF;
|
|
|
+ header[0x15] = (_width >> 24) & 0xFF;
|
|
|
+ header[0x16] = _height & 0xFF;
|
|
|
+ header[0x17] = (_height >> 8) & 0xFF;
|
|
|
+ header[0x18] = (_height >> 16) & 0xFF;
|
|
|
+ header[0x19] = (_height >> 24) & 0xFF;
|
|
|
+ header[0x1A] = 1;
|
|
|
+ header[0x1B] = 0;
|
|
|
+ header[0x1C] = 24;
|
|
|
+ header[0x1D] = 0;
|
|
|
+ header[0x22] = buf_size & 0xFF;
|
|
|
+ header[0x23] = (buf_size >> 8) & 0xFF;
|
|
|
+ header[0x24] = (buf_size >> 16) & 0xFF;
|
|
|
+ header[0x25] = (buf_size >> 24) & 0xFF;
|
|
|
+ header[0x27] = 0x1;
|
|
|
+ header[0x2B] = 0x1;
|
|
|
+ result.insert(result.end(), reinterpret_cast<std::uint8_t*>(header._data), reinterpret_cast<std::uint8_t*>(header._data) + 64);
|
|
|
+ const unsigned char
|
|
|
+ * ptr_r = data(0, _height - 1, 0, 0),
|
|
|
+ * ptr_g = (_spectrum >= 2) ? data(0, _height - 1, 0, 1) : 0,
|
|
|
+ * ptr_b = (_spectrum >= 3) ? data(0, _height - 1, 0, 2) : 0;
|
|
|
+ switch (_spectrum) {
|
|
|
+ case 1: {
|
|
|
+ cimg_forY(*this, y) {
|
|
|
+ cimg_forX(*this, x) {
|
|
|
+ const unsigned char val = (unsigned char)*(ptr_r++);
|
|
|
+ result.push_back(val); result.push_back(val); result.push_back(val);
|
|
|
+ }
|
|
|
+ result.insert(result.end(), reinterpret_cast<std::uint8_t*>(align_buf), reinterpret_cast<std::uint8_t*>(align_buf) + align);
|
|
|
+ ptr_r -= 2 * _width;
|
|
|
+ }
|
|
|
+ } break;
|
|
|
+ case 2: {
|
|
|
+ cimg_forY(*this, y) {
|
|
|
+ cimg_forX(*this, x) {
|
|
|
+ result.push_back(0);
|
|
|
+ result.push_back((unsigned char)(*(ptr_g++)));
|
|
|
+ result.push_back((unsigned char)(*(ptr_r++)));
|
|
|
+ }
|
|
|
+ result.insert(result.end(), reinterpret_cast<std::uint8_t*>(align_buf), reinterpret_cast<std::uint8_t*>(align_buf) + align);
|
|
|
+ ptr_r -= 2 * _width; ptr_g -= 2 * _width;
|
|
|
+ }
|
|
|
+ } break;
|
|
|
+ default: {
|
|
|
+ cimg_forY(*this, y) {
|
|
|
+ cimg_forX(*this, x) {
|
|
|
+ result.push_back((unsigned char)(*(ptr_b++)));
|
|
|
+ result.push_back((unsigned char)(*(ptr_g++)));
|
|
|
+ result.push_back((unsigned char)(*(ptr_r++)));
|
|
|
+ }
|
|
|
+ result.insert(result.end(), reinterpret_cast<std::uint8_t*>(align_buf), reinterpret_cast<std::uint8_t*>(align_buf) + align);
|
|
|
+ ptr_r -= 2 * _width; ptr_g -= 2 * _width; ptr_b -= 2 * _width;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return *this;
|
|
|
+ }
|
|
|
+ };
|
|
|
+ private:
|
|
|
+ //获取验证码
|
|
|
+ std::string generate_captcha_digits() {
|
|
|
+ static const char data_character[] = "23456789abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ\0";
|
|
|
+ int min = 0;
|
|
|
+ int max = std::strlen(data_character) - 1;
|
|
|
+ std::string result;
|
|
|
+ for (int i = 0; i < _Length; ++i) {
|
|
|
+ result += data_character[v3::utils::random(min, max)];
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ //生成随机颜色
|
|
|
+ unsigned char* generate_random_color() {
|
|
|
+ static unsigned char colors[][3] = {
|
|
|
+ {47,79,79 },
|
|
|
+ {105,105,105 },
|
|
|
+ {0,0,128 },
|
|
|
+ {100,149,237 },
|
|
|
+ {72,61,139 },
|
|
|
+ {106,90,205 },
|
|
|
+ {123,104,238 },
|
|
|
+ {132,112,255 },
|
|
|
+ {65,105,225 },
|
|
|
+ {85,107,47 },
|
|
|
+ {107,142,35 },
|
|
|
+ {205,92,92 },
|
|
|
+ {160,82,45 },
|
|
|
+ {178,34,34 },
|
|
|
+ {255,69,0 },
|
|
|
+ {176,48,96 },
|
|
|
+ {160,32,240 },
|
|
|
+ {139,137,137 },
|
|
|
+ {0,139,139 },
|
|
|
+ {139,0,0 },
|
|
|
+ {139,0,139 },
|
|
|
+ {154,50,205 },
|
|
|
+ {238,64,0 },
|
|
|
+ {0,139,69 } };
|
|
|
+ return colors[v3::utils::random(0, sizeof(colors) / sizeof(colors[0]) - 1)];
|
|
|
+ }
|
|
|
+ //生成字体大小,位置
|
|
|
+ std::vector<std::tuple<int, int, int>> generate_font_size() {
|
|
|
+ std::vector<std::tuple<int, int, int>> result;
|
|
|
+ int s_width = _Width / _Length;
|
|
|
+ int s_height = _Height;
|
|
|
+ for (int i = 0; i < _Length; ++i) {
|
|
|
+ int x = 0, y = 0, s = 0;
|
|
|
+ double font_centre_pos = 0.0;
|
|
|
+ if (s_width > s_height) {
|
|
|
+ s = v3::utils::random(double(s_height) - double(s_height) * 0.2, double(s_height) * 1.2);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ s = v3::utils::random(double(s_width) - double(s_width) * 0.2, double(s_width) * 1.2);
|
|
|
+ }
|
|
|
+ font_centre_pos = double(s) * 0.8;
|
|
|
+ x = v3::utils::random(0, double(s_width) - font_centre_pos);
|
|
|
+ y = v3::utils::random(0, double(s_height) - font_centre_pos);
|
|
|
+ result.push_back(std::make_tuple(s, x, y));
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ //验证码图片
|
|
|
+ std::vector<std::uint8_t> generate_captcha_image(std::string const& code) {
|
|
|
+ std::vector<std::uint8_t> result;
|
|
|
+ cimg_library::CImg<unsigned char> image(_Width, _Height, 1, 3, 255); // 创建一个白色背景的图像
|
|
|
+ int s_width = _Width / _Length;
|
|
|
+ int s_height = _Height;
|
|
|
+ std::vector<std::tuple<int, int, int>> font_info = generate_font_size();
|
|
|
+ char c[2] = { 0 };
|
|
|
+ //绘制验证码
|
|
|
+ for (int i = 0; i < _Length; ++i) {
|
|
|
+ c[0] = code[i];
|
|
|
+ image.draw_text(i * s_width + std::get<1>(font_info[i]), std::get<2>(font_info[i]), c, generate_random_color(), 0, 1, std::get<0>(font_info[i])).width();
|
|
|
+ }
|
|
|
+ //绘制干扰线
|
|
|
+ for (int i = 0; i < _Line; ++i) {
|
|
|
+ int x1 = std::rand() % _Width;
|
|
|
+ int y1 = std::rand() % _Height;
|
|
|
+ int x2 = std::rand() % _Width;
|
|
|
+ int y2 = std::rand() % _Height;
|
|
|
+ // 生成随机颜色
|
|
|
+ image.draw_line(x1, y1, x2, y2, generate_random_color());
|
|
|
+ }
|
|
|
+ //绘制干扰点
|
|
|
+ for (int i = 0; i < _Spot; ++i) {
|
|
|
+ int x = std::rand() % _Width;
|
|
|
+ int y = std::rand() % _Height;
|
|
|
+ // 生成随机颜色
|
|
|
+ image.draw_point(x, y, generate_random_color());
|
|
|
+ }
|
|
|
+
|
|
|
+ //扭曲图像
|
|
|
+ cimg_library::CImg<unsigned char> distorted_image(_Width, _Height, 1, 3, 255);
|
|
|
+ cimg_forXY(image, xx, yy) {
|
|
|
+ int new_xx = xx + static_cast<int>(1.32 * sin(2 * 3.14 * yy * 0.045));
|
|
|
+ int new_yy = yy + static_cast<int>(1.42 * sin(2 * 3.14 * xx * 0.062));
|
|
|
+ if (new_xx >= 0 && new_xx < _Width && new_yy >= 0 && new_yy < _Height) {
|
|
|
+ distorted_image(xx, yy, 0, 0) = image(new_xx, new_yy, 0, 0);
|
|
|
+ distorted_image(xx, yy, 0, 1) = image(new_xx, new_yy, 0, 1);
|
|
|
+ distorted_image(xx, yy, 0, 2) = image(new_xx, new_yy, 0, 2);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ CImage(distorted_image).save_memory_bmp(result);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ private:
|
|
|
+ std::string session_key_;
|
|
|
+ };
|
|
|
+
|
|
|
+ class http_server_t {
|
|
|
+ public:
|
|
|
+ http_server_t() {
|
|
|
+ server_.bind<http::verb::post, http::verb::get>(std::string("/*"), &http_server_t::on_base_request, this);
|
|
|
+ }
|
|
|
+ bool start(std::string const& ip, int port) {
|
|
|
+ return server_.start(ip, port);
|
|
|
+ }
|
|
|
+ void stop() {
|
|
|
+ server_.stop();
|
|
|
+ }
|
|
|
+ void set_root_directory(std::filesystem::path const& path) {
|
|
|
+ server_.set_root_directory(path);
|
|
|
+ }
|
|
|
+ protected:
|
|
|
+ virtual void on_request(http::web_request& req, http::web_response& rep) = 0;
|
|
|
+ private:
|
|
|
+ void on_base_request(std::shared_ptr<asio2::http_session>& session_ptr, http::web_request& req, http::web_response& rep) {
|
|
|
+ on_request(req, rep);
|
|
|
+ }
|
|
|
+ private:
|
|
|
+ asio2::http_server server_;
|
|
|
+ };
|
|
|
+
|
|
|
+ class https_server_t {
|
|
|
+ public:
|
|
|
+ https_server_t() {
|
|
|
+ server_.bind<http::verb::post, http::verb::get>("/*", &https_server_t::on_base_request, this);
|
|
|
+ }
|
|
|
+ bool start(std::string const& ip, int port) {
|
|
|
+ return server_.start(ip, port);
|
|
|
+ }
|
|
|
+ void stop() {
|
|
|
+ server_.stop();
|
|
|
+ }
|
|
|
+ void set_root_directory(std::filesystem::path const& path) {
|
|
|
+ server_.set_root_directory(path);
|
|
|
+ }
|
|
|
+ void 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);
|
|
|
+ }
|
|
|
+ protected:
|
|
|
+ virtual void on_request(http::web_request& req, http::web_response& rep) = 0;
|
|
|
+ private:
|
|
|
+ void on_base_request(std::shared_ptr<asio2::https_session>& session_ptr, http::web_request& req, http::web_response& rep) {
|
|
|
+ on_request(req, rep);
|
|
|
+ }
|
|
|
+ private:
|
|
|
+ asio2::https_server server_;
|
|
|
+ };
|
|
|
+
|
|
|
+ template<typename _Before, typename _Err, typename _After, typename _TypeBase>
|
|
|
+ class http_server_base : public _TypeBase {
|
|
|
+ public:
|
|
|
+ http_server_base() :
|
|
|
+ _TypeBase() {
|
|
|
+ }
|
|
|
+ private:
|
|
|
+ virtual void on_request(http::web_request& req, http::web_response& rep)override {
|
|
|
+ http_context_gc http_context(req, rep);
|
|
|
+ try {
|
|
|
+ req.insert("http_route", std::string(req.path()).substr(1));
|
|
|
+ std::shared_ptr<controller> controller = v3::mvc::ico_controller::resolve(req);
|
|
|
+ std::string key(req.find("http_route_key")->value());
|
|
|
+ http_context::current()->set_controller_action((bool)controller ? controller->actions[key] : nullptr);
|
|
|
+ if (before_.before((bool)controller ? controller->actions[key] : nullptr, req, rep)) {
|
|
|
+ rttr::variant variant = controller->invoke(req);
|
|
|
+ if (variant.is_valid()) {
|
|
|
+ auto response = variant.get_value<web_base_response>();
|
|
|
+ response.set_version();
|
|
|
+ response.set_server();
|
|
|
+ response.chunked(true);
|
|
|
+ response.prepare_payload();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //文件
|
|
|
+ else {
|
|
|
+ rep.fill_file(req.path());
|
|
|
+ rep.set(http::field::cache_control, "max-age=31536000");
|
|
|
+ rep.chunked(true);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (unknown_response const&) {
|
|
|
+ }
|
|
|
+ catch (jump_response const&) {
|
|
|
+ }
|
|
|
+ catch (text_response const&) {
|
|
|
+ }
|
|
|
+ catch (html_response const&) {
|
|
|
+ }
|
|
|
+ catch (file_response const&) {
|
|
|
+ }
|
|
|
+ catch (json_response const&) {
|
|
|
+ }
|
|
|
+ catch (std::exception const& ec) {
|
|
|
+ err_.error(ec.what(), req, rep);
|
|
|
+ }
|
|
|
+ catch (...) {
|
|
|
+ err_.error("未知异常", req, rep);
|
|
|
+ }
|
|
|
+ after_.after(req, rep);
|
|
|
+ }
|
|
|
+ private:
|
|
|
+ _Before before_;
|
|
|
+ _Err err_;
|
|
|
+ _After after_;
|
|
|
+ };
|
|
|
+
|
|
|
+ template<typename _Before, typename _Err, typename _After>
|
|
|
+ using http_server = http_server_base<_Before, _Err, _After, http_server_t>;
|
|
|
+
|
|
|
+ template<typename _Before, typename _Err, typename _After>
|
|
|
+ using https_server = http_server_base<_Before, _Err, _After, https_server_t>;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|