重覆盖
This commit is contained in:
@@ -1,72 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(archery_netcore CXX)
|
||||
|
||||
set(CMAKE_SYSTEM_NAME Linux)
|
||||
set(CMAKE_SYSTEM_PROCESSOR riscv64)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
if(NOT DEFINED PY_INCLUDE_DIR)
|
||||
message(FATAL_ERROR "PY_INCLUDE_DIR not set")
|
||||
endif()
|
||||
if(NOT DEFINED PY_LIB)
|
||||
message(FATAL_ERROR "PY_LIB not set")
|
||||
endif()
|
||||
if(NOT DEFINED PY_EXT_SUFFIX)
|
||||
message(FATAL_ERROR "PY_EXT_SUFFIX not set")
|
||||
endif()
|
||||
if(NOT DEFINED MAIXCDK_PATH)
|
||||
message(FATAL_ERROR "MAIXCDK_PATH not set (need components/3rd_party/pybind11)")
|
||||
endif()
|
||||
|
||||
add_library(archery_netcore MODULE
|
||||
archery_netcore.cpp
|
||||
native_logger.cpp
|
||||
utils.cpp
|
||||
decrypt_ota_file.cpp
|
||||
msg_handler.cpp
|
||||
tcp_ssl_password.cpp
|
||||
)
|
||||
|
||||
target_include_directories(archery_netcore PRIVATE
|
||||
"${PY_INCLUDE_DIR}"
|
||||
"${MAIXCDK_PATH}/components/3rd_party/pybind11/pybind11/include"
|
||||
"${MAIXCDK_PATH}/components/3rd_party/openssl/include"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/third_party" # 添加 nlohmann/json 路径
|
||||
)
|
||||
|
||||
# 尽量减少 .so 体积并增加逆向成本
|
||||
target_compile_options(archery_netcore PRIVATE
|
||||
-Os
|
||||
-ffunction-sections
|
||||
-fdata-sections
|
||||
-fvisibility=hidden
|
||||
-fvisibility-inlines-hidden
|
||||
)
|
||||
target_link_options(archery_netcore PRIVATE
|
||||
-Wl,--gc-sections
|
||||
-Wl,-s
|
||||
)
|
||||
|
||||
set_target_properties(archery_netcore PROPERTIES
|
||||
PREFIX ""
|
||||
SUFFIX "${PY_EXT_SUFFIX}"
|
||||
)
|
||||
|
||||
# OpenSSL (for AES-256-GCM decrypt)
|
||||
# 使用 MaixCDK 提供的 OpenSSL 库(在 so/maixcam 目录下)
|
||||
set(OPENSSL_LIB_DIR "${MAIXCDK_PATH}/components/3rd_party/openssl/so/maixcam")
|
||||
if(EXISTS "${OPENSSL_LIB_DIR}/libcrypto.so")
|
||||
target_link_directories(archery_netcore PRIVATE "${OPENSSL_LIB_DIR}")
|
||||
target_link_libraries(archery_netcore PRIVATE "${PY_LIB}" crypto ssl)
|
||||
message(STATUS "Using OpenSSL from MaixCDK: ${OPENSSL_LIB_DIR}")
|
||||
else()
|
||||
# Fallback: 尝试 find_package 或系统库
|
||||
find_package(OpenSSL QUIET)
|
||||
if(OpenSSL_FOUND)
|
||||
target_link_libraries(archery_netcore PRIVATE "${PY_LIB}" OpenSSL::Crypto OpenSSL::SSL)
|
||||
else()
|
||||
message(WARNING "OpenSSL not found in MaixCDK, trying system libraries (may fail)")
|
||||
target_link_libraries(archery_netcore PRIVATE "${PY_LIB}" crypto ssl)
|
||||
endif()
|
||||
endif()
|
||||
@@ -1,117 +0,0 @@
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h> // 支持 std::vector, std::map 等
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <array>
|
||||
|
||||
#include "msg_handler.hpp"
|
||||
#include "native_logger.hpp"
|
||||
#include "decrypt_ota_file.hpp"
|
||||
#include "utils.hpp"
|
||||
#include "tcp_ssl_password.hpp"
|
||||
|
||||
namespace py = pybind11;
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace {
|
||||
// 配置项
|
||||
const std::string _cfg_server_ip = "www.shelingxingqiu.com";
|
||||
const int _cfg_server_port = 50005;
|
||||
const std::string _cfg_device_id_file = "/device_key";
|
||||
|
||||
|
||||
}
|
||||
|
||||
// 定义获取配置的函数
|
||||
py::dict get_config() {
|
||||
py::dict config;
|
||||
config["SERVER_IP"] = _cfg_server_ip;
|
||||
config["SERVER_PORT"] = _cfg_server_port;
|
||||
return config;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
PYBIND11_MODULE(archery_netcore, m) {
|
||||
m.doc() = "Archery net core (native, pybind11).";
|
||||
|
||||
// Optional: configure native logger from Python.
|
||||
// Default log file: /maixapp/apps/t11/netcore.log
|
||||
m.def("set_log_file", [](const std::string& path) { netcore::set_log_file(path); }, py::arg("path"));
|
||||
m.def("set_log_level", [](int level) {
|
||||
if (level < 0) level = 0;
|
||||
if (level > 3) level = 3;
|
||||
netcore::set_log_level(static_cast<netcore::LogLevel>(level));
|
||||
}, py::arg("level"));
|
||||
m.def("log_test", [](const std::string& msg) {
|
||||
netcore::log_info(std::string("log_test: ") + msg);
|
||||
}, py::arg("msg"));
|
||||
|
||||
m.def("make_packet", &netcore::make_packet,
|
||||
"Pack TCP packet: header (len+type+checksum) + JSON body",
|
||||
py::arg("msg_type"), py::arg("body_dict"));
|
||||
|
||||
m.def("parse_packet", &netcore::parse_packet,
|
||||
"Parse TCP packet, return (msg_type, body_dict)");
|
||||
|
||||
m.def("get_config", &get_config, "Get system configuration");
|
||||
|
||||
m.def(
|
||||
"calculate_tcp_ssl_password",
|
||||
&netcore::calculate_tcp_ssl_password,
|
||||
"Calculate TCP SSL password: hex(md5(hex(md5(device_id)) + iccid))",
|
||||
py::arg("device_id"),
|
||||
py::arg("iccid")
|
||||
);
|
||||
|
||||
m.def(
|
||||
"decrypt_ota_file",
|
||||
[](const std::string& input_path, const std::string& output_zip_path) {
|
||||
netcore::log_info(std::string("decrypt_ota_file in=") + input_path + " out=" + output_zip_path);
|
||||
return netcore::decrypt_ota_file_impl(input_path, output_zip_path);
|
||||
},
|
||||
py::arg("input_path"),
|
||||
py::arg("output_zip_path"),
|
||||
"Decrypt OTA encrypted file (MAGIC|nonce|ciphertext|tag) to plaintext zip."
|
||||
);
|
||||
|
||||
// Minimal demo: return actions for inner_cmd=41 (manual trigger + ack)
|
||||
m.def("actions_for_inner_cmd", [](int inner_cmd) {
|
||||
py::list actions;
|
||||
|
||||
if (inner_cmd == 41) {
|
||||
// 1) set manual trigger flag
|
||||
{
|
||||
py::dict a;
|
||||
a["type"] = "SET_FLAG";
|
||||
py::dict args;
|
||||
args["name"] = "manual_trigger_flag";
|
||||
args["value"] = true;
|
||||
a["args"] = args;
|
||||
actions.append(a);
|
||||
}
|
||||
|
||||
// 2) enqueue trigger_ack
|
||||
{
|
||||
py::dict a;
|
||||
a["type"] = "ENQUEUE";
|
||||
py::dict args;
|
||||
args["msg_type"] = 2;
|
||||
args["high"] = false;
|
||||
py::dict body;
|
||||
body["result"] = "trigger_ack";
|
||||
args["body"] = body;
|
||||
a["args"] = args;
|
||||
actions.append(a);
|
||||
}
|
||||
}
|
||||
|
||||
return actions;
|
||||
});
|
||||
}
|
||||
@@ -1,155 +0,0 @@
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
#include <openssl/evp.h>
|
||||
#include "native_logger.hpp"
|
||||
|
||||
namespace netcore{
|
||||
|
||||
// OTA AEAD format: MAGIC(7) | nonce(12) | ciphertext(N) | tag(16)
|
||||
constexpr const char* kOtaMagic = "AROTAE1";
|
||||
constexpr size_t kOtaMagicLen = 7;
|
||||
constexpr size_t kGcmNonceLen = 12;
|
||||
constexpr size_t kGcmTagLen = 16;
|
||||
constexpr size_t kHeaderLen = kOtaMagicLen + kGcmNonceLen;
|
||||
// 分块解密,避免整包读入导致 RAM 峰值约为「文件大小×2」(小内存设备易 OOM)
|
||||
constexpr size_t kDecryptChunk = 65536;
|
||||
|
||||
static std::array<uint8_t, 32> ota_key_bytes() {
|
||||
static const std::array<uint8_t, 32> a = {
|
||||
0x92,0x99,0x4d,0x06,0x6f,0xb6,0xa6,0x3d,0x85,0x08,0xbe,0x73,0x5e,0x73,0x4d,0x8a,
|
||||
0x53,0x88,0xe6,0x99,0xfc,0x10,0x29,0xb9,0x16,0x9b,0xe7,0x0c,0x65,0x21,0x1c,0xce
|
||||
};
|
||||
static const std::array<uint8_t, 32> b = {
|
||||
0xcf,0x60,0xa2,0xc2,0x32,0x7a,0x61,0xb0,0x4c,0x8e,0x8a,0x62,0x31,0xc7,0x82,0xff,
|
||||
0xec,0xac,0xa1,0x04,0x2a,0x4d,0xaa,0xf2,0xb0,0x5b,0x39,0x2b,0xf4,0xb3,0xad,0xad
|
||||
};
|
||||
std::array<uint8_t, 32> k{};
|
||||
for (size_t i = 0; i < k.size(); i++) k[i] = static_cast<uint8_t>(a[i] ^ b[i]);
|
||||
return k;
|
||||
}
|
||||
|
||||
bool decrypt_ota_file_impl(const std::string& input_path, const std::string& output_zip_path) {
|
||||
std::ifstream ifs(input_path, std::ios::binary);
|
||||
if (!ifs) {
|
||||
netcore::log_error(std::string("decrypt_ota_file: open in failed: ") + input_path);
|
||||
return false;
|
||||
}
|
||||
ifs.seekg(0, std::ios::end);
|
||||
const std::streampos szp = ifs.tellg();
|
||||
if (szp <= 0) {
|
||||
netcore::log_error("decrypt_ota_file: empty input");
|
||||
return false;
|
||||
}
|
||||
const uint64_t file_size = static_cast<uint64_t>(szp);
|
||||
const size_t min_len = kHeaderLen + kGcmTagLen + 1;
|
||||
if (file_size < min_len) {
|
||||
netcore::log_error("decrypt_ota_file: too short");
|
||||
return false;
|
||||
}
|
||||
const uint64_t ciphertext_len = file_size - kHeaderLen - kGcmTagLen;
|
||||
|
||||
ifs.seekg(0, std::ios::beg);
|
||||
std::array<uint8_t, kHeaderLen> header{};
|
||||
ifs.read(reinterpret_cast<char*>(header.data()), static_cast<std::streamsize>(kHeaderLen));
|
||||
if (ifs.gcount() != static_cast<std::streamsize>(kHeaderLen)) {
|
||||
netcore::log_error("decrypt_ota_file: read header failed");
|
||||
return false;
|
||||
}
|
||||
if (!std::equal(header.begin(), header.begin() + kOtaMagicLen,
|
||||
reinterpret_cast<const uint8_t*>(kOtaMagic))) {
|
||||
netcore::log_error("decrypt_ota_file: bad magic");
|
||||
return false;
|
||||
}
|
||||
const uint8_t* nonce = header.data() + kOtaMagicLen;
|
||||
|
||||
std::ofstream ofs(output_zip_path, std::ios::binary | std::ios::trunc);
|
||||
if (!ofs) {
|
||||
netcore::log_error(std::string("decrypt_ota_file: open out failed: ") + output_zip_path);
|
||||
return false;
|
||||
}
|
||||
|
||||
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
|
||||
if (!ctx) {
|
||||
netcore::log_error("decrypt_ota_file: EVP_CIPHER_CTX_new failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ok = false;
|
||||
auto key = ota_key_bytes();
|
||||
std::vector<uint8_t> chunk_in(kDecryptChunk);
|
||||
std::vector<uint8_t> chunk_out(kDecryptChunk + EVP_MAX_BLOCK_LENGTH);
|
||||
|
||||
do {
|
||||
if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), nullptr, nullptr, nullptr)) {
|
||||
netcore::log_error("decrypt_ota_file: DecryptInit failed");
|
||||
break;
|
||||
}
|
||||
if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, static_cast<int>(kGcmNonceLen), nullptr)) {
|
||||
netcore::log_error("decrypt_ota_file: set ivlen failed");
|
||||
break;
|
||||
}
|
||||
if (1 != EVP_DecryptInit_ex(ctx, nullptr, nullptr, key.data(), nonce)) {
|
||||
netcore::log_error("decrypt_ota_file: set key/iv failed");
|
||||
break;
|
||||
}
|
||||
|
||||
uint64_t remaining = ciphertext_len;
|
||||
while (remaining > 0) {
|
||||
const size_t n = static_cast<size_t>(std::min<uint64_t>(remaining, kDecryptChunk));
|
||||
ifs.read(reinterpret_cast<char*>(chunk_in.data()), static_cast<std::streamsize>(n));
|
||||
if (ifs.gcount() != static_cast<std::streamsize>(n)) {
|
||||
netcore::log_error("decrypt_ota_file: read ciphertext chunk failed");
|
||||
goto cleanup_ctx;
|
||||
}
|
||||
int outl = 0;
|
||||
if (1 != EVP_DecryptUpdate(ctx, chunk_out.data(), &outl,
|
||||
chunk_in.data(), static_cast<int>(n))) {
|
||||
netcore::log_error("decrypt_ota_file: update failed");
|
||||
goto cleanup_ctx;
|
||||
}
|
||||
if (outl > 0) {
|
||||
ofs.write(reinterpret_cast<const char*>(chunk_out.data()), outl);
|
||||
if (!ofs) {
|
||||
netcore::log_error("decrypt_ota_file: write plaintext failed");
|
||||
goto cleanup_ctx;
|
||||
}
|
||||
}
|
||||
remaining -= n;
|
||||
}
|
||||
|
||||
std::array<uint8_t, kGcmTagLen> tag{};
|
||||
ifs.read(reinterpret_cast<char*>(tag.data()), static_cast<std::streamsize>(kGcmTagLen));
|
||||
if (ifs.gcount() != static_cast<std::streamsize>(kGcmTagLen)) {
|
||||
netcore::log_error("decrypt_ota_file: read tag failed");
|
||||
break;
|
||||
}
|
||||
if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, static_cast<int>(kGcmTagLen), tag.data())) {
|
||||
netcore::log_error("decrypt_ota_file: set tag failed");
|
||||
break;
|
||||
}
|
||||
|
||||
int outl2 = 0;
|
||||
if (1 != EVP_DecryptFinal_ex(ctx, chunk_out.data(), &outl2)) {
|
||||
netcore::log_error("decrypt_ota_file: final failed (auth tag mismatch?)");
|
||||
break;
|
||||
}
|
||||
if (outl2 > 0) {
|
||||
ofs.write(reinterpret_cast<const char*>(chunk_out.data()), outl2);
|
||||
if (!ofs) {
|
||||
netcore::log_error("decrypt_ota_file: write final failed");
|
||||
break;
|
||||
}
|
||||
}
|
||||
ok = true;
|
||||
} while (false);
|
||||
|
||||
cleanup_ctx:
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
return ok;
|
||||
}
|
||||
} // namespace netcore
|
||||
@@ -1,7 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace netcore{
|
||||
bool decrypt_ota_file_impl(const std::string& input_path, const std::string& output_zip_path);
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include "native_logger.hpp"
|
||||
#include "msg_handler.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
namespace py = pybind11;
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace netcore {
|
||||
// 打包 TCP 数据包
|
||||
py::bytes make_packet(int msg_type, py::dict body_dict) {
|
||||
netcore::log_debug(std::string("make_packet msg_type=") + std::to_string(msg_type));
|
||||
// 1) 将 py::dict 转为 JSON 字符串
|
||||
json j = netcore::py_dict_to_json(body_dict);
|
||||
std::string body_str = j.dump();
|
||||
|
||||
// 2) 计算 body_len 和 checksum
|
||||
uint32_t body_len = body_str.size();
|
||||
uint32_t checksum = body_len + msg_type;
|
||||
|
||||
// 3) 打包头部(大端序)
|
||||
std::vector<uint8_t> packet;
|
||||
packet.reserve(12 + body_len);
|
||||
|
||||
// body_len (big-endian, 4 bytes)
|
||||
packet.push_back((body_len >> 24) & 0xFF);
|
||||
packet.push_back((body_len >> 16) & 0xFF);
|
||||
packet.push_back((body_len >> 8) & 0xFF);
|
||||
packet.push_back(body_len & 0xFF);
|
||||
|
||||
// msg_type (big-endian, 4 bytes)
|
||||
packet.push_back((msg_type >> 24) & 0xFF);
|
||||
packet.push_back((msg_type >> 16) & 0xFF);
|
||||
packet.push_back((msg_type >> 8) & 0xFF);
|
||||
packet.push_back(msg_type & 0xFF);
|
||||
|
||||
// checksum (big-endian, 4 bytes)
|
||||
packet.push_back((checksum >> 24) & 0xFF);
|
||||
packet.push_back((checksum >> 16) & 0xFF);
|
||||
packet.push_back((checksum >> 8) & 0xFF);
|
||||
packet.push_back(checksum & 0xFF);
|
||||
|
||||
// 4) 追加 body
|
||||
packet.insert(packet.end(), body_str.begin(), body_str.end());
|
||||
|
||||
netcore::log_debug(std::string("make_packet done bytes=") + std::to_string(packet.size()));
|
||||
return py::bytes(reinterpret_cast<const char*>(packet.data()), packet.size());
|
||||
}
|
||||
|
||||
// 解析 TCP 数据包
|
||||
py::tuple parse_packet(py::bytes data) {
|
||||
// 1) 转换为 bytes view
|
||||
py::buffer_info buf = py::buffer(data).request();
|
||||
if (buf.size < 12) {
|
||||
netcore::log_error(std::string("parse_packet too_short len=") + std::to_string(buf.size));
|
||||
return py::make_tuple(py::none(), py::none());
|
||||
}
|
||||
|
||||
const uint8_t* ptr = static_cast<const uint8_t*>(buf.ptr);
|
||||
|
||||
// 2) 解析头部(大端序)
|
||||
uint32_t body_len = (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3];
|
||||
uint32_t msg_type = (ptr[4] << 24) | (ptr[5] << 16) | (ptr[6] << 8) | ptr[7];
|
||||
uint32_t checksum = (ptr[8] << 24) | (ptr[9] << 16) | (ptr[10] << 8) | ptr[11];
|
||||
|
||||
// 3) 校验 checksum(可选,你现有代码不强制校验)
|
||||
// if (checksum != (body_len + msg_type)) {
|
||||
// return py::make_tuple(py::none(), py::none());
|
||||
// }
|
||||
|
||||
// 4) 检查长度
|
||||
uint32_t expected_len = 12 + body_len;
|
||||
if (buf.size < expected_len) {
|
||||
// 半包
|
||||
netcore::log_warn(std::string("parse_packet incomplete got=") + std::to_string(buf.size) +
|
||||
" expected=" + std::to_string(expected_len));
|
||||
return py::make_tuple(py::none(), py::none());
|
||||
}
|
||||
|
||||
// 5) 防御性检查:如果 data 比预期长,说明可能有粘包
|
||||
// (只解析第一个包,忽略多余数据)
|
||||
if (buf.size > expected_len) {
|
||||
netcore::log_warn(std::string("parse_packet concat got=") + std::to_string(buf.size) +
|
||||
" expected=" + std::to_string(expected_len) +
|
||||
" body_len=" + std::to_string(body_len) +
|
||||
" msg_type=" + std::to_string(msg_type));
|
||||
}
|
||||
|
||||
// 6) 提取 body 并解析 JSON
|
||||
std::string body_str(reinterpret_cast<const char*>(ptr + 12), body_len);
|
||||
|
||||
try {
|
||||
json j = json::parse(body_str);
|
||||
py::dict body_dict = netcore::json_to_py_dict(j);
|
||||
return py::make_tuple(py::int_(msg_type), body_dict);
|
||||
} catch (const json::parse_error& e) {
|
||||
// JSON 解析失败,返回 raw(兼容你现有的逻辑)
|
||||
netcore::log_error(std::string("parse_packet json_parse_error: ") + e.what());
|
||||
py::dict raw_dict;
|
||||
raw_dict["raw"] = body_str;
|
||||
return py::make_tuple(py::int_(msg_type), raw_dict);
|
||||
} catch (const std::exception& e) {
|
||||
netcore::log_error(std::string("parse_packet json_parse_error: ") + e.what());
|
||||
py::dict raw_dict;
|
||||
raw_dict["raw"] = body_str;
|
||||
return py::make_tuple(py::int_(msg_type), raw_dict);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h> // 支持 std::vector, std::map 等
|
||||
|
||||
namespace py = pybind11;
|
||||
|
||||
namespace netcore {
|
||||
|
||||
// 打包 TCP 数据包
|
||||
py::bytes make_packet(int msg_type, py::dict body_dict);
|
||||
// 解包 TCP 数据包
|
||||
py::tuple parse_packet(py::bytes data);
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
#include "native_logger.hpp"
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace netcore {
|
||||
|
||||
static std::mutex g_mu;
|
||||
static int g_fd = -1;
|
||||
static std::string g_path = "netcore.log";
|
||||
static LogLevel g_level = LogLevel::kDebug; //LogLevel::kInfo;
|
||||
|
||||
static const char* level_name(LogLevel lvl) {
|
||||
switch (lvl) {
|
||||
case LogLevel::kError: return "E";
|
||||
case LogLevel::kWarn: return "W";
|
||||
case LogLevel::kInfo: return "I";
|
||||
case LogLevel::kDebug: return "D";
|
||||
default: return "?";
|
||||
}
|
||||
}
|
||||
|
||||
static void ensure_open_locked() {
|
||||
if (g_path.empty()) return;
|
||||
if (g_fd >= 0) return;
|
||||
g_fd = ::open(g_path.c_str(), O_CREAT | O_WRONLY | O_APPEND, 0644);
|
||||
}
|
||||
|
||||
void set_log_file(const std::string& path) {
|
||||
std::lock_guard<std::mutex> lk(g_mu);
|
||||
g_path = path;
|
||||
if (g_fd >= 0) {
|
||||
::close(g_fd);
|
||||
g_fd = -1;
|
||||
}
|
||||
ensure_open_locked();
|
||||
}
|
||||
|
||||
void set_log_level(LogLevel level) {
|
||||
std::lock_guard<std::mutex> lk(g_mu);
|
||||
g_level = level;
|
||||
}
|
||||
|
||||
void log(LogLevel level, const std::string& msg) {
|
||||
std::lock_guard<std::mutex> lk(g_mu);
|
||||
if (static_cast<int>(level) > static_cast<int>(g_level)) return;
|
||||
if (g_path.empty()) return;
|
||||
|
||||
ensure_open_locked();
|
||||
if (g_fd < 0) {
|
||||
// Last resort: stderr (avoid any Python APIs)
|
||||
::write(STDERR_FILENO, msg.c_str(), msg.size());
|
||||
::write(STDERR_FILENO, "\n", 1);
|
||||
return;
|
||||
}
|
||||
|
||||
// Timestamp: epoch milliseconds (simple and cheap)
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
// long long ms = (long long)ts.tv_sec * 1000LL + ts.tv_nsec / 1000000LL;
|
||||
// 1. 将秒数转换为本地时间结构体 struct tm
|
||||
struct tm *tm_info = localtime(&ts.tv_sec);
|
||||
|
||||
// 2. 准备一个缓冲区来存储时间字符串
|
||||
char buffer[30];
|
||||
|
||||
// 3. 格式化秒的部分
|
||||
// 格式: 年-月-日 时:分:秒
|
||||
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", tm_info);
|
||||
|
||||
// 4. 计算毫秒部分并追加到字符串中
|
||||
// ts.tv_nsec 是纳秒,除以 1,000,000 得到毫秒
|
||||
char ms_buffer[8];
|
||||
snprintf(ms_buffer, sizeof(ms_buffer), ".%03ld", ts.tv_nsec / 1000000);
|
||||
|
||||
// Build one line to keep writes atomic-ish
|
||||
char head[256];
|
||||
int n = ::snprintf(head, sizeof(head), "[%s%s] [%s] ", buffer, ms_buffer, level_name(level));
|
||||
if (n < 0) n = 0;
|
||||
|
||||
::write(g_fd, head, (size_t)n);
|
||||
::write(g_fd, msg.c_str(), msg.size());
|
||||
::write(g_fd, "\n", 1);
|
||||
}
|
||||
|
||||
void log_debug(const std::string& msg) { log(LogLevel::kDebug, msg); }
|
||||
void log_info (const std::string& msg) { log(LogLevel::kInfo, msg); }
|
||||
void log_warn (const std::string& msg) { log(LogLevel::kWarn, msg); }
|
||||
void log_error(const std::string& msg) { log(LogLevel::kError, msg); }
|
||||
|
||||
} // namespace netcore
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace netcore {
|
||||
|
||||
enum class LogLevel : int {
|
||||
kError = 0,
|
||||
kWarn = 1,
|
||||
kInfo = 2,
|
||||
kDebug = 3,
|
||||
};
|
||||
|
||||
// Set log file path. If empty, logging is disabled.
|
||||
void set_log_file(const std::string& path);
|
||||
|
||||
// Set minimum log level to write (default: kInfo).
|
||||
void set_log_level(LogLevel level);
|
||||
|
||||
// Log helpers (thread-safe, never calls into Python).
|
||||
void log(LogLevel level, const std::string& msg);
|
||||
void log_debug(const std::string& msg);
|
||||
void log_info(const std::string& msg);
|
||||
void log_warn(const std::string& msg);
|
||||
void log_error(const std::string& msg);
|
||||
|
||||
} // namespace netcore
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
#include "tcp_ssl_password.hpp"
|
||||
|
||||
#include <openssl/md5.h>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
namespace netcore {
|
||||
|
||||
static std::string md5_hex(const std::string& input) {
|
||||
MD5_CTX ctx;
|
||||
MD5_Init(&ctx);
|
||||
MD5_Update(&ctx, input.data(), input.size());
|
||||
|
||||
unsigned char digest[MD5_DIGEST_LENGTH];
|
||||
MD5_Final(digest, &ctx);
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << std::hex << std::setfill('0');
|
||||
for (int i = 0; i < MD5_DIGEST_LENGTH; ++i) {
|
||||
oss << std::setw(2) << static_cast<unsigned int>(digest[i]);
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string calculate_tcp_ssl_password(const std::string& device_id, const std::string& iccid) {
|
||||
std::string md5_device_hex = md5_hex(device_id);
|
||||
if (!iccid.empty()) {
|
||||
md5_device_hex += iccid;
|
||||
}
|
||||
return md5_hex(md5_device_hex);
|
||||
}
|
||||
|
||||
} // namespace netcore
|
||||
@@ -1,7 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace netcore {
|
||||
std::string calculate_tcp_ssl_password(const std::string& device_id, const std::string& iccid);
|
||||
}
|
||||
-24765
File diff suppressed because it is too large
Load Diff
@@ -1,95 +0,0 @@
|
||||
#include <fstream>
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include "utils.hpp"
|
||||
|
||||
namespace netcore {
|
||||
// 辅助函数:将 py::dict 转为 nlohmann::json
|
||||
json py_dict_to_json(py::dict d) {
|
||||
json j;
|
||||
for (auto item : d) {
|
||||
std::string key = py::str(item.first);
|
||||
py::object val = py::reinterpret_borrow<py::object>(item.second);
|
||||
|
||||
if (py::isinstance<py::dict>(val)) {
|
||||
j[key] = py_dict_to_json(py::cast<py::dict>(val));
|
||||
} else if (py::isinstance<py::list>(val)) {
|
||||
py::list py_list = py::cast<py::list>(val);
|
||||
json arr = json::array();
|
||||
for (auto elem : py_list) {
|
||||
py::object elem_obj = py::reinterpret_borrow<py::object>(elem);
|
||||
if (py::isinstance<py::dict>(elem_obj)) {
|
||||
arr.push_back(py_dict_to_json(py::cast<py::dict>(elem_obj)));
|
||||
} else if (py::isinstance<py::int_>(elem_obj)) {
|
||||
arr.push_back(py::cast<int64_t>(elem_obj));
|
||||
} else if (py::isinstance<py::float_>(elem_obj)) {
|
||||
arr.push_back(py::cast<double>(elem_obj));
|
||||
} else {
|
||||
arr.push_back(py::str(elem_obj));
|
||||
}
|
||||
}
|
||||
j[key] = arr;
|
||||
} else if (py::isinstance<py::int_>(val)) {
|
||||
j[key] = py::cast<int64_t>(val);
|
||||
} else if (py::isinstance<py::float_>(val)) {
|
||||
j[key] = py::cast<double>(val);
|
||||
} else if (py::isinstance<py::bool_>(val)) {
|
||||
j[key] = py::cast<bool>(val);
|
||||
} else if (val.is_none()) {
|
||||
j[key] = nullptr;
|
||||
} else {
|
||||
j[key] = py::str(val);
|
||||
}
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
// 辅助函数:将 nlohmann::json 转为 py::dict
|
||||
py::dict json_to_py_dict(const json& j) {
|
||||
py::dict d;
|
||||
if (j.is_object()) {
|
||||
for (auto& item : j.items()) {
|
||||
std::string key = item.key();
|
||||
json val = item.value();
|
||||
|
||||
if (val.is_object()) {
|
||||
d[py::str(key)] = json_to_py_dict(val);
|
||||
} else if (val.is_array()) {
|
||||
py::list py_list;
|
||||
for (auto& elem : val) {
|
||||
if (elem.is_object()) {
|
||||
py_list.append(json_to_py_dict(elem));
|
||||
} else if (elem.is_number_integer()) {
|
||||
py_list.append(py::int_(elem.get<int64_t>()));
|
||||
} else if (elem.is_number_float()) {
|
||||
py_list.append(py::float_(elem.get<double>()));
|
||||
} else if (elem.is_boolean()) {
|
||||
py_list.append(py::bool_(elem.get<bool>()));
|
||||
} else if (elem.is_null()) {
|
||||
py_list.append(py::none());
|
||||
} else {
|
||||
py_list.append(py::str(elem.get<std::string>()));
|
||||
}
|
||||
}
|
||||
d[py::str(key)] = py_list;
|
||||
} else if (val.is_number_integer()) {
|
||||
d[py::str(key)] = py::int_(val.get<int64_t>());
|
||||
} else if (val.is_number_float()) {
|
||||
d[py::str(key)] = py::float_(val.get<double>());
|
||||
} else if (val.is_boolean()) {
|
||||
d[py::str(key)] = py::bool_(val.get<bool>());
|
||||
} else if (val.is_null()) {
|
||||
d[py::str(key)] = py::none();
|
||||
} else {
|
||||
d[py::str(key)] = py::str(val.get<std::string>());
|
||||
}
|
||||
}
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h> // 支持 std::vector, std::map 等
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace py = pybind11;
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace netcore {
|
||||
|
||||
json py_dict_to_json(py::dict d);
|
||||
py::dict json_to_py_dict(const json& j);
|
||||
}
|
||||
Reference in New Issue
Block a user