#ifndef MODULE_CALL_H #define MODULE_CALL_H /** * @brief 呼叫模块 * 用户通过WEB呼叫指定人员或者全部人员 * @author 戴月腾 * @date 2018-08-22 */ #include #include #include #include #include #include #include #include "rapidjson/prettywriter.h" #include"module_const.h" #include"module_web.h" #include"ant.h" /** * @brief 呼叫类型 全员 定员 */ enum CALL_CARD_TYPE { /// 全员呼叫 CCT_CALL_ALL = 0, /// 定员 CCT_CALL_APOINT=1, }; /** * @brief 呼叫等级 一般呼叫 紧急呼叫 */ enum CALL_CARD_LEVEL { /// 呼叫等级: 1 一般呼叫 CALL_LEVEL_NORMAL=1, /// 呼叫等级: 2 紧急呼叫 CALL_LEVEL_CRITICAL=2 }; /** * @brief 呼叫状态 */ enum CALL_STATE{ ///无呼叫信息 CALL_NONE = 0, ///呼叫成功 CALL_SUCCESSED = 1, ///呼叫中 CALL_ING = 2, ///呼叫失败 CALL_FAILED = 3, ///呼叫结束 CALL_END=100 }; /** * @brief 呼叫模块 */ class module_call : public i_thread, public singleton_base { private: friend class singleton_base; module_call() { } private: /** * @brief 呼叫卡的信息 */ struct call_card { /// 呼叫卡号 0为全员 uint32_t cardid; int32_t cardtype; /// 分站号 0为全员 int stationid; ///呼叫类型 全员0, 定员1 CALL_CARD_TYPE int call_type_id; /// 呼叫类型:一般1,紧急2 CALL_CARD_LEVEL int call_level_id; /// 呼叫时长,单位分钟 uint32_t call_time_out; int call_time_interval; /// 呼叫开始时间 std::chrono::system_clock::time_point call_time; /// 呼叫状态,正在呼叫、呼叫成功 int call_state; ///呼叫人 std::string user_name; bool is_display = true; bool is_call_all() { return CCT_CALL_ALL == call_type_id; } uint64_t to_id64() { return tool_other::type_id_to_u64(cardtype, cardid); } std::string to_id64_str() { return tool_other::type_id_to_str(cardtype, cardid); } bool is_timeout() { uint32_t seconds = tool_time::elapse_seconds(call_time); return (seconds >= call_time_out*60); } }; typedef std::shared_ptr call_card_ptr; typedef std::map call_card_map; /** * @brief 呼叫用户信息 */ struct call_user { ///呼叫人 std::string user_name; ///呼叫类型 全员0, 定员1 CALL_CARD_TYPE int call_type_id; /// 呼叫等级:一般1,紧急2 CALL_CARD_LEVEL int call_level_id; /// 呼叫时长,单位分钟 uint32_t call_time_out; int call_time_interval; /// 呼叫开始时间 std::chrono::system_clock::time_point call_time; ///呼叫卡列表 call_card_map cards; bool is_timeout() { uint32_t seconds = tool_time::elapse_seconds(call_time); return (seconds >= call_time_out*60); } bool is_call_all() { return CCT_CALL_ALL == call_type_id; } }; typedef std::shared_ptr call_user_ptr; typedef std::map call_user_map; struct call_site { int32_t site_id; ///呼叫类型 全员0, 定员1 CALL_CARD_TYPE int call_type_id; /// 呼叫等级:一般1,紧急2 CALL_CARD_LEVEL int call_level_id; call_card_map cards; bool is_call_all() { return CCT_CALL_ALL == call_type_id; } }; typedef std::shared_ptr call_site_ptr; typedef std::map call_site_map; public: /** * @brief web发给采集:发起呼叫 * @param node_data */ void accept_call(sio::message::ptr const& data); /** * @brief web发给采集:取消呼叫 * @param node_data */ void accept_cancel(sio::message::ptr const& data); /** * @brief 登陆时,采集发送web:请求井下所有呼叫 */ std::string accept_login(); void rev_from_card_resp(std::shared_ptr card_ptr); /** * @brief */ void init(config_file& config) { sleep_ms = std::stoi(config.get("service.send_call_interval","5000")); } private: /** * @brief 采集回复web发起呼叫 * @param arr */ void response_accept_call(const std::vector arr); /** * @brief 采集回复web:取消呼叫 * @param node_data */ void response_accept_cancel(const call_user_ptr user_ptr); void add_cards_to_user(const std::vector& card_vec, call_user_ptr user_ptr); /** * @brief 线程函数 */ void run(); void copy(const call_user_ptr src, call_user_ptr des) { des->call_level_id = src->call_level_id; des->call_time = src->call_time; des->call_time_out = src->call_time_out; des->call_type_id = src->call_type_id; des->user_name = src->user_name; } void copy(const call_card_ptr src, call_card_ptr des) { des->call_level_id = src->call_level_id; des->call_state = src->call_state; des->call_time = src->call_time; des->call_time_out = src->call_time_out; des->cardid = src->cardid; des->cardtype = src->cardtype; des->user_name = src->user_name; des->stationid = src->stationid; des->call_type_id = src->call_type_id; } void copy(const call_user_ptr src, call_card_ptr des) { des->call_level_id = src->call_level_id; //des->call_state = src->call_state; des->call_time = src->call_time; des->call_time_out = src->call_time_out; des->call_time_interval = src->call_time_interval; //des->cardid = src->cardid; des->user_name = src->user_name; des->call_type_id = src->call_type_id; } /** * @brief 获取用户下的所有呼叫卡 * @param user_ptr * @param cardlist * @param out_data */ void get_user_all_call_cards(call_user_ptr& user_ptr, const std::unordered_map>& cardlist, std::vector& out_data); /** * @brief 获取所有的呼叫卡 * @param user_map * @param cardlist * @param out_data */ void get_all_call_cards(call_user_map& user_map, const std::unordered_map>& cardlist, std::vector& out_data) { auto iter_m_map=user_map.begin(); for(;iter_m_map!=user_map.end();++iter_m_map) { get_user_all_call_cards(iter_m_map->second, cardlist, out_data); if(iter_m_map->second->cards.empty())//没有卡了 删除呼叫用户 { user_map.erase(iter_m_map--); } } } /** * @brief 获取所有的呼叫卡 * @param out_data */ void get_all_call_cards(std::vector& out_data) { auto cardlist = card_list::instance()->m_map; { std::lock_guard lock(_mutex); get_all_call_cards(_map, cardlist, out_data); } } /* * @brief * ["fjb", // 发起呼叫人 * "0010000000001", // 呼叫的卡号 * 103, // 分站号 * 23431, // 发起呼叫时间 * 0, // * 0 // 正在呼叫:2/结束呼叫/ * ] */ static void to_node_element(rapidjson::Value& out_elemet, const std::shared_ptr card_ptr, rapidjson::Document::AllocatorType& allocator) { tool_json::push_back(out_elemet, card_ptr->user_name, allocator); tool_json::push_back(out_elemet, card_ptr->to_id64_str(), allocator); out_elemet.PushBack(card_ptr->stationid, allocator); out_elemet.PushBack(card_ptr->call_time_interval, allocator); out_elemet.PushBack(card_ptr->call_type_id, allocator); out_elemet.PushBack(card_ptr->call_state, allocator); } static void to_node_array(rapidjson::Value& out_array, const std::vector> cards, rapidjson::Document::AllocatorType& allocator) { std::vector>::size_type i; for(i=0; iis_display) { continue; } rapidjson::Value node_card(rapidjson::kArrayType); to_node_element(node_card, cards[i], allocator); out_array.PushBack(node_card, allocator); } } /** * @brief 生成所有呼叫卡的json * @param cards * @return */ std::string to_call_card_list_json(std::vector cards); void get_site_map(const std::vector& arr, call_site_map& out_site_map) { auto card_ptr = arr.begin(); for(;card_ptr!=arr.end();++card_ptr) { if((*card_ptr)->stationid<1) { continue; } auto iter = out_site_map.find((*card_ptr)->stationid); if(out_site_map.end()==iter) { call_site_ptr site_ptr(new call_site()); site_ptr->site_id = (*card_ptr)->stationid; site_ptr->call_type_id = (*card_ptr)->call_type_id; site_ptr->call_level_id = (*card_ptr)->call_level_id; out_site_map.insert(std::make_pair(site_ptr->site_id, site_ptr)); iter = out_site_map.find((*card_ptr)->stationid); } if(iter->second->is_call_all()) { continue; } if((*card_ptr)->is_call_all()) { iter->second->call_type_id = (*card_ptr)->call_type_id; iter->second->cards.clear(); continue; } iter->second->cards[(*card_ptr)->cardid]=(*card_ptr); } } ///发呼叫的报文数据给分站 void send_to_sites(call_site_map& site_map) { auto iter_site = site_map.begin(); for(; iter_site != site_map.end(); ++iter_site) { if(iter_site->second->cards.size() > 254) { log_error("呼叫:分站下卡数量过多:分站id=%d, 卡数=%d", iter_site->first, iter_site->second->cards.size()); continue; } std::vector arr; //分站地址 4字节,支持大小分站呼叫协议;added by zhuyf 2018/06/04 //大小分站的全员呼叫,分站id要求4字节全为FF uint32_t anchor_id = (iter_site->second->is_call_all()? 0xffffffff : static_cast(iter_site->first)); memcpy_uint32(arr,anchor_id); //卡数 arr.push_back(static_cast(iter_site->second->cards.size())); //呼叫类型 arr.push_back(static_cast(iter_site->second->call_type_id)); if(!iter_site->second->is_call_all()) { //循环添加卡信息 auto it_card = iter_site->second->cards.begin(); for(; it_card != iter_site->second->cards.end(); ++it_card) { //呼叫类型 arr.push_back(static_cast(it_card->second->call_level_id)); //卡类型 arr.push_back(static_cast(it_card->second->cardtype)); //卡ID长度 int id_len = 4; arr.push_back(static_cast(id_len)); //卡ID memcpy_uint32(arr, it_card->second->cardid); } } auto sit_ptr = sit_list::instance()->get(iter_site->first); if(!sit_ptr || !sit_ptr->m_clt) { log_error("在全局分站列表中找不到分站 或者sit_ptr->m_clt==null:分站id=%d", iter_site->first); continue; } //std::vector arr2 = arr; sit_ptr->m_clt->send(std::move(arr)); //print_test(std::move(arr2), iter_site->first); } } static void print_test(std::vector&& arr, int siteid) { std::string str("呼叫发送的数据帧,分站号="); str.append(std::to_string(siteid)); str.append(":"); char a[4]={0}; for(std::vector::size_type i=0; i(arr[i])); str.append(std::string(a)); } log_info("%s", str.c_str()); } void static memcpy_uint32(std::vector& arr, uint32_t dwSrc) { char bt = HIBYTE(HIWORD(dwSrc)); arr.push_back(bt); bt = LOBYTE(HIWORD(dwSrc)); arr.push_back(bt); bt = HIBYTE(LOWORD(dwSrc)); arr.push_back(bt); bt = LOBYTE(LOWORD(dwSrc)); arr.push_back(bt); } static char HIBYTE(uint16_t dwSrc) { return static_cast(dwSrc>>8); } static char LOBYTE(uint16_t dwSrc) { return static_cast(dwSrc); } static uint16_t HIWORD(uint32_t dwSrc) { return static_cast(dwSrc>>16); } static uint16_t LOWORD(uint32_t dwSrc) { return static_cast(dwSrc); } private: /// 呼叫用户列表 call_user_map _map; }; #endif // MODULE_CALL_H