Files
ECAP_Server/module/Local_Server/Data_Source/Data_Source.cpp
T
2026-06-24 09:54:17 +08:00

653 lines
20 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "Data_Source.h"
#include <codecvt>
#include "../server/Global.h"
#include "Database.h"
Psc::serial::Serial* create_serial(const std::string& serial_name, Baud_Rate_Type baud_rate) {
auto serial = new Psc::serial::Serial;
serial->set_serial_name(serial_name);
serial->set_baud_rate(baud_rate);
serial->set_parity(Psc::serial::Parity::NoParity);
serial->set_data_bits(Psc::serial::DataBits::Data8);
serial->set_stop_bits(Psc::serial::StopBits::OneStop);
serial->set_flow_control(Psc::serial::FlowControl::HardwareControl);
serial->set_buffer_byte_size(10 * 1024);
if (!serial->open())
{
std::cerr << "createSerial " + serial_name + ":" + std::to_string(baud_rate) + " 打开串口失败!\n";
Psc::fail_fast();
return nullptr;
} else
{
// std::cerr << "createSerial " + serial_name + ":" + std::to_string(baud_rate) + " 打开串口成功!\n";
}
return serial;
}
std::shared_ptr<Data_Source> create_from_json(const JSON* that_json) {
std::string type = that_json->get_string("type");
std::shared_ptr<Data_Source> ret = create_data_source_from_type(type);
ret->from_json(that_json);
// if (ret->enable)
// {
// ret->open();
// }
return ret;
}
std::shared_ptr<Data_Source> Data_Source::that() {
return shared_from_this();
}
bool Data_Source::registered() const {
auto all_source = Global::instance()->mode_acs.data_source_config.map.list();
for (auto& item : all_source) {
if (item.get() == this) {
return true;
}
}
return false;
}
Psc::JSON Data_Source::get_state() {
Psc::JSON ret = Psc::JSON::object();
ret.append_list(get_custom_state_json().children);
ret.append({"ds: read_speedbyte", read_speed});
ret.append({"ds: value_statisticsbyte", value_statistics});
return ret;
}
Data_Source::Data_Source() {
// parse_format = std::make_shared<Input_Format>();
// 写入到配置文件是懒加载 其他保存时他跟着保存
base_station.handle_when_updated = [this](SSR::HULC_Status_Message msg) {
if (this->update_form_gps) {
lat = msg.get_latitude();
lon = msg.get_longitude();
alt = msg.Alt;
}
};
}
std::string Data_Source::thread_key() const {
//return "Data_Source_Handle_Thread:[" + key + "]";
return key + "_DS_HT";
}
void File_Data_Source::before_handle_msg(std::shared_ptr<SSR::Mode_Msg>& msg) {
auto cur = std::dynamic_pointer_cast<SSR::Mode_Msg>(msg);
if (cur != nullptr) {
auto& pre = last_prase_msg;
if (!pre) {
pre = cur;
return;
}
cur->day_num = pre->day_num;
if (cur->time() < pre->time()) {
++cur->day_num;
}
}
}
std::vector<std::string> readLines(const std::string& path) {
std::vector<std::string> lines;
std::filesystem::path p = std::filesystem::path((const char8_t*)path.c_str());
//std::filesystem::path p = std::filesystem::u8path(path);
std::ifstream istream(p);
if (!istream) {
std::cerr << "读取模拟数据源 readLines 无法打开文件:" << path << std::endl;
Psc::fail_fast();
}
// 将整个文件读入一个字符串
std::stringstream stream;
stream << istream.rdbuf();
// 使用 stringstream 按行分割内容
std::string line;
char ch;
while (stream.get(ch)) {
if (ch == ' ') {
continue;
}
if (ch == '\r' || ch == '\n') {
if (!line.empty()) {
lines.push_back(line);
line.clear();
}
// if (ch == '\r') {
// stream.get(); // 吃掉 \n
// }
// if (ch == '\n') {
// stream.get(); // 吃掉 \n
// }
// 处理 \r\n 组合:如果当前是 \r,下一个是 \n,跳过它
// if (ch == '\r' && stream.peek() == '\n') {
// stream.get(); // 吃掉 \n
// }
} else {
line += ch;
}
if (line.size() == 1000) {
lines.push_back(line);
line.clear();
}
}
// 最后一行如果没有换行符也处理一下
if (!line.empty()) {
lines.push_back(line);
}
std::ostringstream oss;
oss << path + " 总行数:" + std::to_string(lines.size()) + " 有效行数:" + std::to_string(lines.size()) + "\n" << std::flush;
std::cout << oss.str() << std::flush;
return lines;
}
std::string extractID(const std::string& logLine) {
size_t lastSpacePos = logLine.rfind(" "); // 查找最后一个空格
if (lastSpacePos != std::string::npos) {
return logLine.substr(lastSpacePos + 1); // 从最后一个空格之后提取字符串
}
return logLine;
}
time_t convert_to_timestamp(const std::string& str) {
// 创建一个结构体 tm 来存储解析后的时间
std::tm timeStruct = {};
std::istringstream ss(str);
ss >> std::get_time(&timeStruct, "%Y-%m-%d %H:%M:%S");
if (ss.fail()) {
std::cerr << "Failed to parse time" << std::endl;
return -1; // 如果解析失败,返回 -1
}
// 将 tm 转换为 time_t(时间戳)
time_t timestamp = std::mktime(&timeStruct);
if (timestamp == -1) {
std::cerr << "Failed to convert to time_t" << std::endl;
return -1; // 如果转换失败,返回 -1
}
return timestamp;
}
std::tuple<std::string, time_t> extractID2(const std::string& logLine) {
size_t lastSpacePos = logLine.rfind(" "); // 查找最后一个空格
time_t t = convert_to_timestamp(logLine.substr(0, 19));
if (lastSpacePos != std::string::npos) {
return {logLine.substr(lastSpacePos + 1), t}; // 从最后一个空格之后提取字符串
}
return {logLine, t};
}
std::string bin_format(const std::string& hex, time_t t){
std::tm* currentTime = std::localtime(&t);
auto sec = currentTime->tm_hour * 3600 + currentTime->tm_min * 60 + currentTime->tm_sec;
SSR::MLAT_timestamp a(sec, 0);
return create_Binary_Format_memory(hex, 0, &a);
}
std::optional<std::string> File_Data_Source::get_raw_line(int& ret_index) {
if (index == 0 && part_infos.empty())
{
ret_index = -1;
return std::nullopt;
}
std::optional<std::string> log_info = std::nullopt;
if (index == part_infos.size())
{
if (play_mode == Play_Mode::loop)
{
index = 0;
} else
{
if (!have_report_play_back_all_success)
{
std::ostringstream oss;
oss << SSR::get_current_date() << " " << SSR::get_current_time() << " [进程:" << std::this_thread::get_id() << "] " << file_path + " 全部加载成功!\n" << std::flush;
std::cout << oss.str() << std::flush;
have_report_play_back_all_success = true;
}
ret_index = -1;
return std::nullopt;
}
}
ret_index = index + 1;
return part_infos[index++];
}
// 1A 33 1A 1A F1 FB 87 73 7E 7F a8001d81a87543b0a80000
std::string get_true_from_raw_line(Data_Source* ds, File_Data_Type data_type, int index, const std::string& log_info) {
std::string ret;
// 2025-01-06 07:20:17 [info] dc2541e65001401a3119b2dd1c7af67132201
if (data_type == File_Data_Type::BIN) {
return log_info;
}
else if (data_type == File_Data_Type::BIN_Text)
{
auto info = extractID(log_info);
ret = hex2mem(info);
}
else if (data_type == File_Data_Type::AVR)
{
auto [info, time] = extractID2(log_info);
ret = bin_format(info, time);
}
// 1A 33 10 01 A5 31 FB 9A 5D 8D 78 0E 47 99 08 8E 32 B0 08 BE E9 8A E6 1A 32 10 01 AA 14 61 7E 5E 02 E6 0F 38 7D 87 08
// 1A 32 10 01 AD B5 64 F7 63 5D 78 0F 9D BA 93 BA
else if (data_type == File_Data_Type::BIN_Blank_Text)
{
std::string info = log_info;
std::string result = ds->last_char;
ds->last_char = "";
for (char c : info)
{
if (std::isxdigit(c)) { // 会判断字符 c 是否是十六进制数字字符
result += c;
} else if (std::isspace(c)) {
//
} else {
std::ostringstream oss;
oss << "存在非法字符[" << c << "]: value:" << (int)c << " in" << log_info << LOG_POS;
server_logger->c_debug("非法字符:", {}, oss.str());
return "";
}
}
auto size = result.size();
if (size % 2 != 0) {
// 保存最后一个字符
ds->last_char = result.empty() ? "" : std::string(1, result.back());
result.pop_back();
}
ret = hex2mem(result);
}
else if (data_type == File_Data_Type::BIN_Blank_One_Line_With_Escape) {
auto size = log_info.size();
if (size % 2 != 0)
{
return hex2mem(log_info.substr(0, size - 1));
}
return hex2mem(log_info);
}
else if (data_type == File_Data_Type::BIN_Blank_One_Line_No_Escape) {
auto size = log_info.size();
std::string data;
if (size % 2 != 0)
{
data = log_info.substr(0, size - 1);
} else {
data = log_info;
}
return SSR::packet_to_escape_format(hex2mem(data));
}
else if (data_type == File_Data_Type::SIMPLE_BIN_Blank)
{
std::string info = log_info;
std::string result;
for (char c : info)
{
if (c != ' ')
{
result += c;
}
}
// 1 + 1 + 6 + 1 + 2/7/14
// 1a + type time_stamp signal_level data
int size = result.size();
if (size != 2*2 && size != 7*2 && size != 14*2)
{
std::cout << "line_offset:[" << index << "] " << "大小" << size << " 不为偶数,或不为2,7,14 不能转换成二进制格式:" << result << std::endl;
return "";
}
std::string head("\x1a");
std::string type;
std::string time_stamp = "\x11\x22\x33\x44\x55\x66";
std::string signal_level("\xFF");
if (size == 2 * 2)
{
type = R"(1)";
} else if (size == 7 * 2)
{
type = R"(2)";
} else if (size == 14 * 2)
{
type = R"(3)";
}
ret = SSR::packet_to_escape_format(head + type + time_stamp + signal_level + hex2mem(result));
//std::cout << ret.size() << std::endl;
}
else
{
std::cout << "未知的回放类型 " << static_cast<int>(data_type) << std::endl;
Psc::fail_fast();
}
return ret;
}
void File_Data_Source::_close() {
std::lock_guard g(mtx);
index = 0;
part_infos.clear();
}
bool File_Data_Source::_open() {
std::lock_guard g(mtx);
auto path = get_true_file_path();
namespace fs = std::filesystem;
if (!fs::exists(path)) {
state = "文件不存在";
return false;
}
if (data_type == File_Data_Type::BIN) {
part_infos = readBinaryFileAsString(path, 1000);
}
else {
part_infos = readLines(path);
}
state = "已加载" + to_string(part_infos.size()) + "长度数据!";
return true;
}
std::vector<std::string> File_Data_Source::readBinaryFileAsString(const std::string& filepath, size_t part_size) {
// 打开文件(以二进制模式)
std::ifstream file(filepath, std::ios::binary);
if (!file) {
std::cerr << "无法打开文件: " << filepath << std::endl;
return {}; // 文件打开失败,返回空vector
}
// 获取文件大小
file.seekg(0, std::ios::end);
size_t fileSize = file.tellg();
file.seekg(0, std::ios::beg);
// 存储读取的部分
std::vector<std::string> parts;
// 读取文件的每一部分
size_t bytesRead = 0;
while (bytesRead < fileSize) {
// 计算每个部分的长度(最后一部分可能小于part_size)
size_t remaining = fileSize - bytesRead;
size_t currentPartSize = (remaining < part_size) ? remaining : part_size;
// 创建buffer来存储当前部分
std::string buffer(currentPartSize, '\0');
// 读取当前部分
file.read(&buffer[0], currentPartSize);
// 将读取的部分添加到vector
parts.push_back(std::move(buffer));
// 更新已读取字节数
bytesRead += currentPartSize;
}
// 关闭文件
file.close();
return parts;
}
void File_Data_Source::origin_data_transform_mode_data(std::string& mode_data)
{
std::lock_guard g(mtx);
assert(mode_data.size() == 0);
int ret_index = 0;
if (play_mode != Play_Mode::analysis)
{
std::optional<std::string> log_info = get_raw_line(ret_index);
mode_data = log_info.has_value() ? get_true_from_raw_line(this, data_type, ret_index, log_info.value()) : "";
} else
{
int num = 0;
std::string ret;
std::optional<std::string> log_info = get_raw_line(ret_index);
while (log_info.has_value())
{
num++;
auto data = log_info.value();
auto cur = get_true_from_raw_line(this, data_type, ret_index, data);
ret += cur;
// 一定要在这个位置,否则会导致遗漏报文
if (num == 1000) {
break;
}
log_info = get_raw_line(ret_index);
}
// std::cout << "size == " << t.size() << std::endl;
mode_data = ret;
}
}
void File_Data_Source::handle_mode_s(std::shared_ptr<SSR::Mode_S_Msg> msg) {
if (!msg) return;
cache_list.push_back(std::make_shared<Cache_Msg>(std::move(msg)));
if (cache_list.empty()) return;
if (pre_cache == nullptr) {
pre_cache = cache_list.front();
cache_list.pop_front();
SSR::Play_Back_Time_Point& start = player_clock.start_time;
start.day_num = pre_cache->day_num;
start.day_sec = pre_cache->msg->mlat_timestamp.daysec;
}
auto sys_time = player_clock.get_cur_time_point();
while (true) {
if (cache_list.empty()) break;
auto pre = pre_cache;
auto cur = cache_list.front();
cur->day_num = pre->day_num;
if (cur->time() < pre->time()) {
cur->day_num++;
}
cache_list.pop_front();
pre_cache = cur;
Data_Source::handle_mode_s(cur->msg);
if (cur->time() > sys_time) {
break;
}
}
}
void Dll_Data_Source::origin_data_transform_mode_data(std::string& mode_data)
{
auto start = std::chrono::steady_clock::now();
if (read_func_ptr == nullptr) return;
auto buf = reinterpret_cast<char *>(buffer.data());
auto len = read_func_ptr(buf, buffer_size);
vs.update(len);
std::string data(buf, len);
if (data.empty()) {
auto end = std::chrono::steady_clock::now();
auto cost = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
//std::cout << "Dll_Data_Source::read cost: " << cost << " us\n";
return;
}
auto ret = get_true_from_raw_line(this, data_type, -1, data);
auto end = std::chrono::steady_clock::now();
auto cost = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
// std::cout << "Dll_Data_Source::read cost: " << cost << " us\n";
mode_data = ret;
}
bool Shared_Memory_Data_Source::_open() {
sm = std::make_unique<Psc::SM_RingBuffer>();
sm->init(shared_memory_name, shared_memory_size);
return true;
}
void Shared_Memory_Data_Source::_close() {
sm.reset();
}
void Shared_Memory_Data_Source::origin_data_transform_mode_data(std::string& mode_data)
{
auto size = sm->shm.size();
size_t length = size;
std::string data;
data.resize(size);
bool ok = sm->read((uint8_t *)data.data(), length);
if (!ok) {
mode_data = "";
}
if (length != size) {
data.resize(length);
}
if (Global::instance()->console_config.mode_s_console) {
std::cout << "read:" << data << std::endl;
}
auto ret = get_true_from_raw_line(this, data_type, -1, data);
mode_data = ret;
}
void Data_Source_Config::server(Global* g) {
auto& svr = g->svr;
auto& api = g->api;
std::string name = "data_source";
// 返回所有 JSON 数据的 API
svr.Post(api + "get_data_source_connect", [this](HTTP_Param) {
CHECK_JSON_PARAM
HTTP_REQUIRE_VALUE(key, params.try_get_string("key"))
auto t = map.get(key);
JSON ret{nullptr};
if (t.has_value()) {
ret = t.value()->get_all_connect_feed();
}
res->setBody(warp(ret).to_json_string());
});
svr.Post(api + "get_data_source_state", [this](HTTP_Param) {
CHECK_JSON_PARAM
HTTP_REQUIRE_VALUE(key, params.try_get_string("key"))
auto t = map.get(key);
JSON ret{nullptr};
if (t.has_value()) {
ret = t.value()->get_state();
}
res->setBody(warp(ret).to_json_string());
});
svr.Post(api + "get_mode_s_data_source_config", [this](HTTP_Param) {
res->setBody(warp(to_json()).to_json_string());
});
svr.Post(api + svr.update + name, [this, g](HTTP_Param) {
CHECK_JSON_PARAM
HTTP_REQUIRE_VALUE(key, params.try_get_string("key"))
HTTP_REQUIRE_VALUE(ds, map.get(key))
// 直接关闭
ds->enable = false;
ds->close();
ds->from_json(&params);
wake_data_feed_thread();
g->save();
g->mode_acs.source_feed_relation_config.set_need_refresh();
});
svr.Post(api + svr.insert + name, [g, this](HTTP_Param) {
CHECK_JSON_PARAM
HTTP_REQUIRE_VALUE(index, params.try_get_number<int>("index"))
HTTP_REQUIRE_PTR(data, params.get("data"))
HTTP_REQUIRE_VALUE(t, data->try_get_string("type"))
std::cout << params.to_json_string() << std::endl;
std::shared_ptr<Data_Source> ds = create_data_source_from_type(t);
ds->from_json(data);
HTTP_REQUIRE_VALUE(enable, data->try_get_bool("enable"))
(void)enable;
HTTP_REQUIRE_TRUE(map.insert(index, ds), "index")
wake_data_feed_thread();
//std::cout << params.to_json_string() << std::endl;
g->mode_acs.source_feed_relation_config.set_need_refresh();
Config::save();
res->setBody(warp(to_json()).to_json_string());
});
svr.Post(api + svr.remove + name, [g, this](HTTP_Param) {
CHECK_JSON_PARAM
HTTP_REQUIRE_VALUE(index, params.try_get_number<int>("index"))
HTTP_REQUIRE_VALUE(ds, map.try_get(index))
ds->enable = false;
ds->close();
HTTP_REQUIRE_TRUE(map.remove(index), "index")
wake_data_feed_thread();
g->save();
res->setBody(warp(to_json()).to_json_string());
g->mode_acs.source_feed_relation_config.set_need_refresh();
});
svr.Post(api + svr.rise + name, [g, this](HTTP_Param) {
CHECK_JSON_PARAM
HTTP_REQUIRE_VALUE(index, params.try_get_number<int>("index"))
HTTP_REQUIRE_TRUE(map.swap(index, index - 1), "index")
g->save();
res->setBody(warp(to_json()).to_json_string());
g->mode_acs.source_feed_relation_config.set_need_refresh();
});
svr.Post(api + svr.fall + name, [g, this](HTTP_Param) {
CHECK_JSON_PARAM
HTTP_REQUIRE_VALUE(index, params.try_get_number<int>("index"))
HTTP_REQUIRE_TRUE(map.swap(index, index + 1), "index")
g->save();
res->setBody(warp(to_json()).to_json_string());
g->mode_acs.source_feed_relation_config.set_need_refresh();
});
}