code:priv_dir 返回bad name

本文探讨了在Erlang环境中正确配置代码路径的方法,特别是如何处理标准目录下的ebin和priv目录,确保应用能够顺利加载模块及私有文件。同时讨论了当应用从一个目录移动到另一个目录时可能遇到的问题及其解决办法。

code:priv_dir  返回bad name


如果是在编译的标准目录 ,ebin/  ,src ,priv  等可以

 1、erl -pa ebin 

2、

erl 

执行-- code:add_path(当前完整目录)  


两种方法 都正常获取到 code:priv_dir  


如果 把整个ebin目录拷贝到另一个地方(或是完整拷贝整个工程目录),就不行了,具体原因下次再找....



后记:

后面发现 app_name 拷贝到 app_name1 不能获取;

但是拷贝到 app_name1/app_name  又可以获取了,可能是要求子目录格式也是标准格式:

xxx./app_name/

xxx./app_name/ebin

xxx./app_name/priv


优化这份代码: /****************************************************************************** * Copyright (c) 2025 MeiG Smart Co.Ltd. All Rights Reserved. * * This program is the confidential and proprietary information of MeiG * Smart Co.Ltd. ("Confidential Information"). You shall not disclose such * Confidential Information and shall use it only in accordance with the terms * of the license agreement you entered into with MeiG Smart Co.Ltd. * * Filename: volcano_gpio_app.cpp * * Description: * Meig gpio Daemon App. * * Version: 1.0 * Date: 2025-06-07 * Author: zhanghong * * 1.0 2025-06-07 zhanghong First version ******************************************************************************/ #define __FILE_NAME__ "volcano_gpio_app.cpp" #include <volcano_priv.hpp> #include <thread> #include <iostream> #include <atomic> #include <fcntl.h> #include <unistd.h> #include <linux/input.h> #include <sys/epoll.h> #include <mutex> #include <vector> #include <volcano_gpio_port.hpp> #include <volcano_gpio.hpp> #include <poll.h> #include <pthread.h> #include <cstring> #include <memory> #include <semaphore.h> #include <unordered_map> #include <vector> #include <functional> #include <cstdio> #include <cstdlib> #include <cstdint> #include <string> #include <chrono> #include <condition_variable> #include <algorithm> #include <fstream> #include <sstream> #include <sys/types.h> #include <sys/stat.h> #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <stdint.h> #include <linux/input.h> #include <stdarg.h> #include <syslog.h> namespace volcano { namespace app { namespace gpio { using RequestHandler = std::function<nlohmann::json(const nlohmann::json&)>; auto g_manager_ptr = volcano::port::gpio::Iface::getInstance(); // 获取裸指针 std::atomic<bool> g_running{false}; std::thread g_event_thread; std::mutex g_thread_mutex; Gpio_Status Gpio_Status_Now; int fd_gpio = -1; static volcano_pin_driver_typeDef volcano_pin_table_gpio[] = { {59, MODULE_MCU+54,false}, {61, MODULE_MCU+52,false}, {62, MODULE_MCU+53,false}, {63, MODULE_MCU+55,false}, {71, MODULE_MCU+117,false}, {74, MODULE_MCU+116,false}, {100, MODULE_MCU+129,false}, {102, MODULE_MCU+126,false}, {104, MODULE_MCU+128,false}, {181, MODULE_MCU+50,false}, {249, MODULE_MCU+75,false}, {280, MODULE_MCU+103,false}, {283, MODULE_MCU+78,false}, {297, MODULE_MCU+65,false}, {298, MODULE_MCU+64,false}, {507, MODULE_MCU+48,false}, {508, MODULE_MCU+49,false} }; struct Service { Service(std::shared_ptr<volcano::app::Fmk> fmk) : fmk_(fmk) { keep_run_ = true; fmk_->msg_->register_service_j("volcano_gpio", [this](const nlohmann::json &req) -> nlohmann::json { return this->dispatch_request(req); }); thread_ = std::make_shared<std::thread>([this]() { this->run(); }); }; ~Service() { keep_run_ = false; if (thread_) { thread_->join(); thread_ = nullptr; } fmk_->msg_->unregister_service("volcano_gpio"); }; protected: nlohmann::json dispatch_request(const nlohmann::json &req) { VOLCANO_LOGD("GAO dispatch_request: req=%s", req.dump().c_str()); auto action_map = build_action_map(); auto action_it = req.find("action"); if (action_it != req.end()) { std::string action = action_it->get<std::string>(); auto handler_it = action_map.find(action); if (handler_it != action_map.end()) { return handler_it->second(req); } } return build_error_reply(volcano::err::BadRequest, "Unknown action"); } void run() { int n = 0; while (this->keep_run_) { std::this_thread::sleep_for(std::chrono::seconds(1)); VOLCANO_LOGD("volcano_gpio_app notice callback"); n++; std::string s = "hello world " + std::to_string(n); nlohmann::json notice = {{"n", n}, {"s", s}}; fmk_->msg_->publish_notice_j("volcano_gpio", notice); } }; /* int publicEintStatus(int test) { nlohmann::json eint_info_notice = { {"type", static_cast<int>(VOLCANO_GPIO_CB_TYPE_EINT1)}, {"msg", { {"pin_name", 280}, {"level", test}, }} }; VOLCANO_LOGD("publicEintStatus"); fmk_->msg_->publish_notice_j("volcano_gpio", eint_info_notice); return volcano::err::Ok; } */ int Volcano_gpio_Open(const char* deviceName) { fd_gpio = open(deviceName, O_RDWR); if (fd_gpio < 0) { //LOGI("yangxin : can't open device"); return -1; } Gpio_Status_Now.ReqNum = 0; return 0; } int volcano_ms_gpio_get_number(ENUM_PINNAME pin_name) { uint16_t index = 0; int gpioNumber = 0; for (index = 0; index < ARRAY_SIZE(volcano_pin_table_gpio); index++){ if( volcano_pin_table_gpio[index].pinname == pin_name ){ gpioNumber = volcano_pin_table_gpio[index].pinnumber; } } VOLCANO_LOGD("volcano_ms_gpio_get_number gpioNumber = %d\n",gpioNumber); return gpioNumber; } static void epoll_event_loop_eint() { int fd,i; struct pollfd fds[1]; int ret; struct input_event ev; unsigned int level; int pin; // 打开设备文件 fd = open("/dev/input/event0", O_RDONLY); if (fd < 0) { VOLCANO_LOGD("epoll_event_loop_eint Open"); //return EXIT_FAILURE; } // 准备pollfd结构体 fds[0].fd = fd; fds[0].events = POLLIN; // 等待可读取状态 VOLCANO_LOGD("epoll_event_loop_eint : into wait_inter_event\n"); // 循环使用poll等待事件 while (g_running.load()) { pin = 0; level = 0; // 等待事件,无超时(阻塞) ret = poll(fds, 1, -1); if (ret < 0) { VOLCANO_LOGD("epoll_event_loop_eint Poll"); close(fd); //return EXIT_FAILURE; } // 检查是否有事件 if (fds[0].revents & POLLIN) { // 读取事件 ret = read(fd, &ev, sizeof(struct input_event)); if (ret < 0) { VOLCANO_LOGD("epoll_event_loop_eint Read"); close(fd); //return EXIT_FAILURE; } pin = ev.value >> 1; level = ev.value & 0x1; VOLCANO_LOGD("epoll_event_loop_eint 1111"); for(i=0; i<Gpio_Status_Now.ReqNum; i++){ if(Gpio_Status_Now.Gpio_Init[i].irq_num == (unsigned int)pin && ev.value != 0){ if(Gpio_Status_Now.Gpio_Init[i].callback != NULL) { //Gpio_Status_Now.Gpio_Init[i].callback(()Gpio_Status_Now.Gpio_Init[i].pin,level); //self->publicEintStatus(level); if(Gpio_Status_Now.Gpio_Init[i].callback != NULL) cb_(Gpio_Status_Now.Gpio_Init[i].pin,level); //self->cb(eint_pin_name,level); VOLCANO_LOGD("epoll_event_loop_eint eint"); } break; } } // 处理事件 VOLCANO_LOGD("epoll_event_loop_eint : Event: time %ld.%06ld, type %d, pin %d, level %d\n", ev.time.tv_sec, ev.time.tv_usec, ev.type, pin, level); } } close(fd); //return EXIT_SUCCESS; /* int epoll_fd = epoll_create1(0); if (epoll_fd == -1) { perror("epoll_create1"); return; } int fd = open("/dev/input/event0", O_RDONLY | O_NONBLOCK); if (fd < 0) { perror("open"); close(epoll_fd); return; } struct epoll_event ev; ev.events = EPOLLIN; ev.data.fd = fd; if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) { perror("epoll_ctl"); close(fd); close(epoll_fd); return; } VOLCANO_LOGD("epoll_event_loop_eint"); struct input_event inputEv; while (g_running.load()) { struct epoll_event events[1]; int nfds = epoll_wait(epoll_fd, events, 1, 500); if (nfds > 0 && events[0].data.fd == fd) { ssize_t n = read(fd, &inputEv, sizeof(inputEv)); if (n == sizeof(inputEv) && inputEv.type == EV_MSC && inputEv.code == MSC_RAW) { unsigned int irq_num = inputEv.value >> 1; int level = inputEv.value & 0x1; for (int i = 0; i < Gpio_Status_Now.ReqNum; ++i) { if (Gpio_Status_Now.Gpio_Init[i].irq_num == irq_num && inputEv.value != 0) { self->publicEintStatus(level); VOLCANO_LOGD("epoll_event_loop_eint eint"); break; } } } } VOLCANO_LOGD("epoll_event_loop_eint test"); } VOLCANO_LOGD("epoll_event_loop_eint"); close(fd); close(epoll_fd); */ } nlohmann::json on_volcano_ms_gpio_base_init(const nlohmann::json &req) { try { ENUM_PINNAME pin_name = static_cast<ENUM_PINNAME>(req.at("pin_name").get<int>()); //auto manager = state_machine_.getManager(); //add lock??? if (g_manager_ptr) { int err = g_manager_ptr->mg_volcano_ms_gpio_base_init(pin_name); return {{"ret", err}}; }else{ return {{"ret", volcano::err::InvalidReply}}; } } catch (const std::exception &e) { VOLCANO_LOGE("Invalid request: %s", e.what()); return {{"ret", volcano::err::InvalidReply}}; } } nlohmann::json on_volcano_ms_gpio_init(const nlohmann::json &req) { /* VOLCANO_LOGD("on_volcano_ms_gpio_init: req=%s", req.dump().c_str()); //TODO return {{"ret", volcano::err::Success}}; */ try { ENUM_PINNAME pin_name = static_cast<ENUM_PINNAME>(req.at("pin_name").get<int>()); ENUM_PIN_DIRECTION dir = static_cast<ENUM_PIN_DIRECTION>(req.at("dir").get<int>()); ENUM_PIN_LEVEL level = static_cast<ENUM_PIN_LEVEL>(req.at("level").get<int>()); ENUM_PIN_PULLSEL pullSel = static_cast<ENUM_PIN_PULLSEL>(req.at("pullSel").get<int>()); if (g_manager_ptr) { int err = g_manager_ptr->mg_volcano_ms_gpio_init( pin_name, dir, level, pullSel); return {{"ret", err}}; }else{ return {{"ret", volcano::err::InvalidReply}}; } } catch (const std::exception &e) { VOLCANO_LOGE("Invalid request: %s", e.what()); return {{"ret", volcano::err::InvalidReply}}; } } nlohmann::json on_volcano_ms_gpio_set_direction(const nlohmann::json &req) { try { ENUM_PINNAME pin_name = static_cast<ENUM_PINNAME>(req.at("pin_name").get<int>()); ENUM_PIN_DIRECTION dir = static_cast<ENUM_PIN_DIRECTION>(req.at("dir").get<int>()); if (g_manager_ptr) { int err = g_manager_ptr->mg_volcano_ms_gpio_set_direction( pin_name, dir); return {{"ret", err}}; }else{ return {{"ret", volcano::err::InvalidReply}}; } } catch (const std::exception &e) { VOLCANO_LOGE("Invalid request: %s", e.what()); return {{"ret", volcano::err::InvalidReply}}; } } nlohmann::json on_volcano_ms_gpio_get_direction(const nlohmann::json &req) { try { ENUM_PINNAME pin_name = static_cast<ENUM_PINNAME>(req.at("pin_name").get<int>()); if (g_manager_ptr) { int err = g_manager_ptr->mg_volcano_ms_gpio_get_direction( pin_name); if(err){ VOLCANO_LOGE("on_volcano_ms_gpio_get_direction: in"); }else{ VOLCANO_LOGE("on_volcano_ms_gpio_get_direction: out"); } return {{"ret", err}}; }else{ return {{"ret", volcano::err::InvalidReply}}; } } catch (const std::exception &e) { VOLCANO_LOGE("Invalid request: %s", e.what()); return {{"ret", volcano::err::InvalidReply}}; } } nlohmann::json on_volcano_ms_gpio_set_level(const nlohmann::json &req) { try { ENUM_PINNAME pin_name = static_cast<ENUM_PINNAME>(req.at("pin_name").get<int>()); ENUM_PIN_LEVEL level = static_cast<ENUM_PIN_LEVEL>(req.at("level").get<int>()); if (g_manager_ptr) { int err = g_manager_ptr->mg_volcano_ms_gpio_set_level(pin_name, level); return {{"ret", err}}; }else{ return {{"ret", volcano::err::InvalidReply}}; } } catch (const std::exception &e) { VOLCANO_LOGE("Invalid request: %s", e.what()); return {{"ret", volcano::err::InvalidReply}}; } } nlohmann::json on_volcano_ms_gpio_get_level(const nlohmann::json &req) { try { ENUM_PINNAME pin_name = static_cast<ENUM_PINNAME>(req.at("pin_name").get<int>()); if (g_manager_ptr) { int err = g_manager_ptr->mg_volcano_ms_gpio_get_level(pin_name); VOLCANO_LOGE("volcano_ms_gpio_get_level: %d", err); return {{"ret", err}}; }else{ return {{"ret", volcano::err::InvalidReply}}; } } catch (const std::exception &e) { VOLCANO_LOGE("Invalid request: %s", e.what()); return {{"ret", volcano::err::InvalidReply}}; } } nlohmann::json on_volcano_ms_gpio_set_pull_selection(const nlohmann::json &req) { try { ENUM_PINNAME pin_name = static_cast<ENUM_PINNAME>(req.at("pin_name").get<int>()); ENUM_PIN_PULLSEL pullSel = static_cast<ENUM_PIN_PULLSEL>(req.at("pullSel").get<int>()); if (g_manager_ptr) { int err = g_manager_ptr->mg_volcano_ms_gpio_set_pull_selection(pin_name, pullSel); return {{"ret", err}}; }else{ return {{"ret", volcano::err::InvalidReply}}; } } catch (const std::exception &e) { VOLCANO_LOGE("Invalid request: %s", e.what()); return {{"ret", volcano::err::InvalidReply}}; } } nlohmann::json on_volcano_ms_gpio_get_pull_selection(const nlohmann::json &req) { try { ENUM_PINNAME pin_name = static_cast<ENUM_PINNAME>(req.at("pin_name").get<int>()); if (g_manager_ptr) { int err = g_manager_ptr->mg_volcano_ms_gpio_get_pull_selection(pin_name); return {{"ret", err}}; }else{ return {{"ret", volcano::err::InvalidReply}}; } } catch (const std::exception &e) { VOLCANO_LOGE("Invalid request: %s", e.what()); return {{"ret", volcano::err::InvalidReply}}; } } nlohmann::json on_volcano_ms_gpio_set_awake(const nlohmann::json &req) { try { ENUM_PINNAME pin_name = static_cast<ENUM_PINNAME>(req.at("pin_name").get<int>()); ENUM_PIN_AWAKE en = static_cast<ENUM_PIN_AWAKE>(req.at("en").get<int>()); if (g_manager_ptr) { int err = g_manager_ptr->mg_volcano_ms_gpio_set_awake(pin_name, en); return {{"ret", err}}; }else{ return {{"ret", volcano::err::InvalidReply}}; } } catch (const std::exception &e) { VOLCANO_LOGE("Invalid request: %s", e.what()); return {{"ret", volcano::err::InvalidReply}}; } } nlohmann::json on_volcano_ms_gpio_get_awake(const nlohmann::json &req) { try { ENUM_PINNAME pin_name = static_cast<ENUM_PINNAME>(req.at("pin_name").get<int>()); if (g_manager_ptr) { int err = g_manager_ptr->mg_volcano_ms_gpio_get_awake(pin_name); return {{"ret", err}}; }else{ return {{"ret", volcano::err::InvalidReply}}; } } catch (const std::exception &e) { VOLCANO_LOGE("Invalid request: %s", e.what()); return {{"ret", volcano::err::InvalidReply}}; } } nlohmann::json on_volcano_ms_gpio_uninit(const nlohmann::json &req) { try { ENUM_PINNAME pin_name = static_cast<ENUM_PINNAME>(req.at("pin_name").get<int>()); if (g_manager_ptr) { int err = g_manager_ptr->mg_volcano_ms_gpio_uninit(pin_name); return {{"ret", err}}; }else{ return {{"ret", volcano::err::InvalidReply}}; } } catch (const std::exception &e) { VOLCANO_LOGE("Invalid request: %s", e.what()); return {{"ret", volcano::err::InvalidReply}}; } } void handle_event(ENUM_PINNAME eint_pin_name, int level) { VOLCANO_LOGD("handle_event"); nlohmann::json event_t = { {"eint_pin_name", eint_pin_name}, {"level", level}, }; VOLCANO_LOGD("handle_event"); fmk_->msg_->publish_notice_j("volcano_gpio", event_t); //UNUSED(sim_id); //UNUSED(sim_id); //UNUSED(event); // ¿¿ } nlohmann::json on_volcano_ms_eint_enable(const nlohmann::json &req) { VOLCANO_LOGD("on_volcano_ms_eint_enable: req=%s", req.dump().c_str()); ENUM_PINNAME eint_pin_name = static_cast<ENUM_PINNAME>(req.at("eint_pin_name").get<int>()); ENUM_EINT_TYPE eint_type = static_cast<ENUM_EINT_TYPE>(req.at("eint_type").get<int>()); //volcano_ms_eint_callback eint1_callback = static_cast<volcano_ms_eint_callback>(req.at("eint1_callback").get<int>()); auto cb_ = [this]( ENUM_PINNAME eint_pin_name, int level) { // auto app_cb = [this, agent_callback_id](int sim_id, int port_id, int result) { this->handle_event(eint_pin_name,level); }; if (g_manager_ptr){ int err = g_manager_ptr->mg_volcano_ms_eint_enable(eint_pin_name,eint_type); VOLCANO_LOGD("on_volcano_ms_eint_enable: req=%d", err); } // return {{"ret", err}}; int ret = 0; struct some_ioctl_data user_data; int gpioNumber = 0; uint8_t pin_name = 0; bool existflag = 0; uint8_t i = 0; VOLCANO_LOGD("mg_volcano_ms_eint_enable"); if((eint_type < 0) || (eint_type > 3) ) return {{"ret", volcano::err::Success}};; for (i = 0; i < ARRAY_SIZE(volcano_pin_table_gpio); i++){ if( volcano_pin_table_gpio[i].pinname == eint_pin_name ) existflag = 1; } VOLCANO_LOGD("mg_volcano_ms_eint_enable 1"); if(existflag == 0) return {{"ret", volcano::err::Success}};; gpioNumber = volcano_ms_gpio_get_number(eint_pin_name); pin_name = (uint8_t)gpioNumber; VOLCANO_LOGD("mg_volcano_ms_eint_enable 2"); user_data.value = pin_name << 16 | eint_type << 2; if (fd_gpio < 0){ ret = Volcano_gpio_Open(DEVICE_NAME); if (ret < 0) return {{"ret", volcano::err::Success}}; } ret = ioctl(fd_gpio, GPIO_REQUEST, &user_data); if (ret == -1) { VOLCANO_LOGD("yangxin : gpio:%d Already registered, please release first", pin_name); return {{"ret", volcano::err::Success}}; } if( user_data.ret_val < 0) return {{"ret", volcano::err::Success}}; ret = ioctl(fd_gpio, GPIO_TO_IRQ, &user_data); if (ret == -1) { VOLCANO_LOGD("yangxin : set gpio:%d failed", pin_name); return {{"ret", volcano::err::Success}}; } if( user_data.ret_val < 0) return {{"ret", volcano::err::Success}}; std::lock_guard<std::mutex> lock(g_thread_mutex); if (g_running.load()) { VOLCANO_LOGD("[INFO] epoll thread already running"); //std::cout << "[INFO] epoll thread already running.\n"; //return 0; } g_running.store(true); Gpio_Status_Now.Gpio_Init[Gpio_Status_Now.ReqNum].pin = eint_pin_name; Gpio_Status_Now.Gpio_Init[Gpio_Status_Now.ReqNum].Gpio_InitNum = gpioNumber; //Gpio_Status_Now.Gpio_Init[Gpio_Status_Now.ReqNum].callback = eint1_callback; Gpio_Status_Now.Gpio_Init[Gpio_Status_Now.ReqNum].irq_num = user_data.use_data; Gpio_Status_Now.ReqNum++; g_event_thread = std::thread(epoll_event_loop_eint); //g_event_thread = std::thread(&Service::epoll_event_loop_eint, this); //std::cout << "[INFO] epoll thread started.\n"; //TODO return {{"ret", volcano::err::Success}}; } nlohmann::json on_volcano_ms_eint_disable(const nlohmann::json &req) { VOLCANO_LOGD("on_volcano_ms_eint_disable: req=%s", req.dump().c_str()); std::lock_guard<std::mutex> lock(g_thread_mutex); if (!g_running.load()) { VOLCANO_LOGD("on_volcano_ms_eint_disable 1: req=%s", req.dump().c_str()); } g_running.store(false); if (g_event_thread.joinable()) { g_event_thread.join(); VOLCANO_LOGD("[INFO] epoll thread stopped.\n"); std::cout << "[INFO] epoll thread stopped.\n"; } //TODO return {{"ret", volcano::err::Success}}; } private: std::unordered_map<std::string, RequestHandler> build_action_map() { return { {"volcano_ms_gpio_base_init", [this](const nlohmann::json &req) { return this->on_volcano_ms_gpio_base_init(req); }}, {"volcano_ms_gpio_init", [this](const nlohmann::json &req) { return this->on_volcano_ms_gpio_init(req); }}, {"volcano_ms_gpio_set_direction", [this](const nlohmann::json &req) { return this->on_volcano_ms_gpio_set_direction(req); }}, {"volcano_ms_gpio_get_direction", [this](const nlohmann::json &req) { return this->on_volcano_ms_gpio_get_direction(req); }}, {"volcano_ms_gpio_set_level", [this](const nlohmann::json &req) { return this->on_volcano_ms_gpio_set_level(req); }}, {"volcano_ms_gpio_get_level", [this](const nlohmann::json &req) { return this->on_volcano_ms_gpio_get_level(req); }}, {"volcano_ms_gpio_set_pull_selection", [this](const nlohmann::json &req) { return this->on_volcano_ms_gpio_set_pull_selection(req); }}, {"volcano_ms_gpio_get_pull_selection", [this](const nlohmann::json &req) { return this->on_volcano_ms_gpio_get_pull_selection(req); }}, {"volcano_ms_gpio_set_awake", [this](const nlohmann::json &req) { return this->on_volcano_ms_gpio_set_awake(req); }}, {"volcano_ms_gpio_get_awake", [this](const nlohmann::json &req) { return this->on_volcano_ms_gpio_get_awake(req); }}, {"volcano_ms_gpio_uninit", [this](const nlohmann::json &req) { return this->on_volcano_ms_gpio_uninit(req); }}, {"volcano_ms_eint_enable", [this](const nlohmann::json &req) { return this->on_volcano_ms_eint_enable(req); }}, {"volcano_ms_eint_disable", [this](const nlohmann::json &req) { return this->on_volcano_ms_eint_disable(req); }}, }; } static nlohmann::json build_error_reply(const volcano::err::Code &code, const std::string &msg) { nlohmann::json error_reply = {{"ret", code}, {"msg", msg}}; return error_reply; } std::shared_ptr<volcano::app::Fmk> fmk_; std::shared_ptr<std::thread> thread_; bool keep_run_ = false; //std::function<void(ENUM_PINNAME, int)> cb_; // 存储回调函数 }; static std::shared_ptr<Service> s_service_ = nullptr; static void service_init(std::shared_ptr<volcano::app::Fmk> fmk) { s_service_ = std::make_shared<Service>(fmk); }; static void service_deinit() { s_service_ = nullptr; }; } // namespace gpio } // namespace app } // namespace volcano VOLCANO_APP(volcano::app::gpio::service_init, volcano::app::gpio::service_deinit); 不用管头文件
07-30
服务端代码:bool worker_snapshot_preview_handle(WORKER_CTX *worker_ctx, struct tpsocket_fd *sock, struct list_head *buf) { struct timespec cur_time; clock_gettime(CLOCK_MONOTONIC, &cur_time); MYDEBUG("#### local snapshot producer reached : %ld.%ld\n", cur_time.tv_sec, cur_time.tv_nsec/1000/1000); SNAPSHOT_PREVIEW_PRODUCER *producer; SNAPSHOT_PREVIEW_CONSUMER *local_consumer, *nlocal_consumer; SNAPSHOT_PREVIEW_SERVER *snapshot_preview_server; DEV_INFO *dev_info = NULL; MEDIACENTER_CTX *mediacenter_ctx = worker_ctx->top_ctx; char *dev_id = NULL; if (!worker_ctx || !sock || !buf) { DBG_ERR("arg NULL\n"); return false; } if (!(producer = (SNAPSHOT_PREVIEW_PRODUCER *)snapshot_preview_producer_new(sock, worker_ctx->snapshot_preview_server))) { DBG_ERR("snapshot_preview_producer_new failed\n"); return false; } snapshot_preview_producer_set_content_len(producer, sock->parser.http.length); snapshot_preview_producer_set_dev_ip(producer, sock->addr); list_for_each_entry(dev_info, &mediacenter_ctx->dev_info, list) { if (!strncmp(dev_info->dev_ip, producer->dev_ip, sizeof(dev_info->dev_ip))) { dev_id = dev_info->dev_id; break; } } snapshot_preview_producer_set_dev_id(producer, dev_id); sock->handler.cb = tpsocket_event_snapshot_preview_producer_cb; sock->handler.priv = producer; snapshot_preview_cache_init(producer, producer->content_len); snapshot_preview_start(worker_ctx, producer); /* find local consumer */ snapshot_preview_server = worker_ctx->snapshot_preview_server; list_for_each_entry_safe(local_consumer, nlocal_consumer, &snapshot_preview_server->consumer, list) { if (!strncmp(local_consumer->dev_id, producer->dev_id, LEN_MAX_ID)) { list_del(&local_consumer->list); snapshot_preview_consumer_set_content_len(local_consumer, producer->content_len); list_add_tail(&local_consumer->list, &producer->local_waiting); } } return true; } bool worker_file_log_handle(WORKER_CTX *worker_ctx, struct tpsocket_fd *sock, struct list_head *buf) { // 1. 获取设备MAC地址 char *mac = common_find_key_from_buf(buf, "Device-Mac"); if (!mac || strlen(mac) < 12) { DBG_ERR("Invalid MAC address\n"); return false; } DBG_ERR("mac: %s\n", mac); // 2. MAC格式化处理(冒号转下划线) char processed_mac[18] = {0}; strncpy(processed_mac, mac, sizeof(processed_mac)-1); for (char *p = processed_mac; *p; p++) { if (*p == ':') *p = '_'; } DBG_ERR("processed_mac: %s\n", processed_mac); // 3. 获取文件名 char *filename = common_find_key_from_buf(buf, "FileName"); if (!filename || filename[0] == '\0') { DBG_ERR("Missing filename\n"); return false; } // 4. 创建目标目录 char dirpath[128]; snprintf(dirpath, sizeof(dirpath), "/mnt/sd_card/%s", processed_mac); // 检创建父目录(/mnt/sd_card) if (access("/mnt/sd_card", F_OK) != 0) { if (mkdir("/mnt/sd_card", 0755) != 0) { DBG_ERR("SD card mount failed: %s\n", strerror(errno)); return false; } } // 创建设备目录(/mnt/sd_card/<processed_mac>) if (access(dirpath, F_OK) != 0) { if (mkdir(dirpath, 0755) != 0) { DBG_ERR("Device dir '%s' creation failed: %s\n", dirpath, strerror(errno)); return false; } } // 5. 构建文件路径 char filepath[256]; snprintf(filepath, sizeof(filepath), "%s/%s", dirpath, filename); DBG_ERR("filepath: %s\n", filepath); // 6. 获取内容长度( char *content_length_str = common_find_key_from_buf(buf, "Content-Length"); if (!content_length_str || *content_length_str == '\0') { DBG_ERR("Missing Content-Length header\n"); return false; } size_t content_len = atol(content_length_str); if (content_len <= 0) { DBG_ERR("Invalid content length: %s\n", content_length_str); return false; } FILE *fp = fopen(filepath, "wb"); if (!fp) { DBG_ERR("File open failed: %s\n", strerror(errno)); return false; } char buffer[8192]; size_t remaining = content_len; ssize_t bytes_read = 0; while (remaining > 0) { size_t to_read = (remaining > sizeof(buffer)) ? sizeof(buffer) : remaining; bytes_read = recv(sock->fd.fd, buffer, to_read, 0); DBG_ERR("sock->fd.fd: %d\n", sock->fd.fd); if (bytes_read <= 0) { DBG_ERR("Socket read error: %zd\n", bytes_read); fclose(fp); return false; } if (fwrite(buffer, 1, bytes_read, fp) != bytes_read) { DBG_ERR("File write error: %s\n", strerror(errno)); fclose(fp); return false; } remaining -= bytes_read; } fsync(fileno(fp)); fclose(fp); return true; }客户端代码:# -*- coding: utf-8 -*- import socket import ssl import time import os import logging from urllib.parse import urlparse def send_file(url: str, mac_address: str, file_path: str, chunk_size: int = 8192): """ Send file to server, placing file content in HTTP request body :param url: Server URL (https://host:port/path) :param mac_address: Device MAC address (format: A1:B2:C3:D4:E5:F6) :param file_path: File path to send :param chunk_size: Chunk size for transfer (default: 8KB) :return: Returns True on success, False on failure """ # Parse URL try: parsed_url = urlparse(url) host = parsed_url.hostname port = parsed_url.port or 443 # Default HTTPS port path = parsed_url.path if not host: raise ValueError("Missing host in URL") except Exception as e: logging.error(f"URL parsing failed: {e}") return False # Configure logging logging.basicConfig( level=logging.INFO, format='%(asctime)s [%(levelname)s] %(message)s', handlers=[logging.FileHandler('transfer.log'), logging.StreamHandler()] ) # 1. Prepare file information try: file_size = os.path.getsize(file_path) filename = os.path.basename(file_path) logging.info(f"Preparing to send file to {path}: {file_path} ({file_size} bytes)") except Exception as e: logging.error(f"File loading failed: {e}") return False # 2. Create SSL connection (with retry mechanism) MAX_RETRIES = 3 RETRY_DELAY = 2 # seconds ssl_sock = None for attempt in range(MAX_RETRIES): try: context = ssl.create_default_context() context.check_hostname = False # Can disable hostname verification in test environments context.verify_mode = ssl.CERT_NONE # Can disable certificate verification in test environments # context.load_verify_locations(cafile="/path/to/ca_cert.pem") sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(120) # Set longer timeout ssl_sock = context.wrap_socket(sock, server_hostname=host) ssl_sock.connect((host, port)) logging.info(f"SSL connection established to {host}:{port}") break except Exception as e: if attempt < MAX_RETRIES - 1: logging.warning(f"SSL connection failed ({attempt+1}/{MAX_RETRIES}): {e}, retrying in {RETRY_DELAY} seconds...") time.sleep(RETRY_DELAY) else: logging.error(f"Maximum retries reached: {e}") return False # 3. Build and send HTTP request headers try: # Construct HTTP request headers headers = [ f"POST {path} HTTP/1.1", f"Host: {host}", "Cache-Control: no-cache", "Connection: keep-alive", # Server requires connection closure f"Device-Mac: {mac_address}", # MAC address header required by server f"FileName: {filename}", # Filename header required by server f"Content-Length: {file_size}", # Key: content length "\r\n" # Empty line ends the headers ] header_str = "\r\n".join(headers) logging.debug(f"Request headers:\n{header_str}") ssl_sock.sendall(header_str.encode('utf-8')) except Exception as e: logging.error(f"Request header send error: {e}") if ssl_sock: ssl_sock.close() return False # 4. Send file content (request body) bytes_sent = 0 start_time = time.time() last_progress_update = start_time try: with open(file_path, 'rb') as f: while bytes_sent < file_size: # Read and send data chunk chunk = f.read(chunk_size) if not chunk: break ssl_sock.sendall(chunk) bytes_sent += len(chunk) # Smart progress update (maximum once per second) current_time = time.time() if current_time - last_progress_update > 1.0: progress = bytes_sent / file_size * 100 elapsed = current_time - start_time speed = bytes_sent / (elapsed * 1024) # KB/s logging.info( f"Sending: {bytes_sent}/{file_size} bytes " f"({progress:.1f}%), Speed: {speed:.2f} KB/s" ) last_progress_update = current_time logging.info(f"File transfer completed: {bytes_sent}/{file_size} bytes") except Exception as e: logging.error(f"Transfer interrupted: {e}") if ssl_sock: ssl_sock.close() return False # 5. Receive server response try: response = b"" while True: chunk = ssl_sock.recv(1024) if not chunk: break response += chunk logging.info(f"Server response: {response.decode('utf-8', errors='ignore')}") except Exception as e: logging.error(f"Response receive error: {e}") # 6. Close connection and calculate performance ssl_sock.close() elapsed = time.time() - start_time if bytes_sent == file_size: speed = file_size / (elapsed * 1024) # KB/s logging.info(f"Transfer successful! Time: {elapsed:.2f} seconds, Speed: {speed:.2f} KB/s") return True logging.warning(f"Transfer incomplete: {bytes_sent}/{file_size} bytes") return False if __name__ == "__main__": # Configure server information SERVER_URL = "https://192.168.137.96:21443/log/file_log" # Ensure path matches server TEST_MAC = "A1:B2:C3:D4:E5:F6" # MAC address format TEST_FILE = "test_file.log" # File to send print("="*50) send_file(SERVER_URL, TEST_MAC, TEST_FILE) print("="*50) 服务端错误码:[1014 15:42:55][Error] mediacenter: [worker.c:5933][tpsocket_event_worker_listen_cb] WORKERC: 192.168.137.1:59469 connected [1014 15:42:55][Error] mediacenter: [worker.c:3665][worker_file_log_handle] mac: A1:B2:C3:D4:E5:F6 [1014 15:42:55][Error] mediacenter: [worker.c:3672][worker_file_log_handle] processed_mac: A1_B2_C3_D4_E5_F6 [1014 15:42:55][Error] mediacenter: [worker.c:3700][worker_file_log_handle] filepath: /mnt/sd_card/A1_B2_C3_D4_E5_F6/test_file.log [1014 15:42:55][Error] mediacenter: [worker.c:3726][worker_file_log_handle] Socket read error: -1 客户端错误码:================================================== 2025-10-14 15:42:54,060 [INFO] Preparing to send file to /log/file_log: test_file.log (2097152 bytes) 2025-10-14 15:42:54,235 [INFO] SSL connection established to 192.168.137.96:21443 2025-10-14 15:42:54,239 [ERROR] Transfer interrupted: [WinError 10053] ��������е�������ֹ��һ���ѽ��������ӡ� ==================================================
10-15
服务端报错:mqttCloud: [mqtt_common.c:4835][mqtt_alexa_snap_cer_tmo] mqtt_cloud->alexa_snapshot_cer_retry_cur:32000 [1018 12:29:15][Error] mediacenter: [worker.c:6083][tpsocket_event_worker_listen_cb] WORKERC: 192.168.137.1:53049 connected [tpsocket_buf.c:0972][tpbuf_http_response] tpbuf_http_response_code:404[1018 12:29:17][Error] mqttCloud: [mqtt_matter_device.c:416][mqtt_matter_controller_liveness_check_tmo] controller die[1]!!! [1018 12:29:38][Error] mqttCloud: [mqtt_matter_device.c:416][mqtt_matter_controller_liveness_check_tmo] controller die[2]!!! [1018 12:29:41][Error] mqttCloud: [mqtt_common.c:4771][mqtt_s3_cer_get] mqtt_cloud->mqtt_state:0 [1018 12:29:41][Error] mqttCloud: [mqtt_common.c:4835][mqtt_alexa_snap_cer_tmo] mqtt_cloud->alexa_snapshot_cer_retry_cur:32000 [1018 12:29:49][Error] mqttCloud: [mqtt_matter_device.c:416][mqtt_matter_controller_liveness_check_tmo] controller die[3]!!!服务端代码:bool worker_file_log_handle(WORKER_CTX *worker_ctx, struct tpsocket_fd *sock, struct list_head *buf) { // 1. 获取设备MAC地址 char *mac = common_find_key_from_buf(buf, "Device-Mac"); if (!mac || strlen(mac) < 12) { DBG_ERR("Invalid MAC address\n"); return false; } DBG_ERR("mac: %s\n", mac); // 2. MAC格式化处理(冒号转下划线) char processed_mac[18] = {0}; strncpy(processed_mac, mac, sizeof(processed_mac)-1); for (char *p = processed_mac; *p; p++) { if (*p == ':') *p = '_'; } DBG_ERR("processed_mac: %s\n", processed_mac); // 3. 获取文件名 char *filename = common_find_key_from_buf(buf, "FileName"); if (!filename || filename[0] == '\0') { DBG_ERR("Missing filename\n"); return false; } // 4. 创建目标目录 char dirpath[128]; snprintf(dirpath, sizeof(dirpath), "%s/%s", FILELOG_PATH , processed_mac); // 检创建父目录(/mnt/sd_card) if (access(FILELOG_PATH, F_OK) != 0) { if (mkdir(FILELOG_PATH,0755) != 0) { DBG_ERR("SD card mount failed: %s\n", strerror(errno)); return false; } } // 创建设备目录(/mnt/sd_card/<processed_mac>) if (access(dirpath, F_OK) != 0) { if (mkdir(dirpath, 0755) != 0) { DBG_ERR("Device dir '%s' creation failed: %s\n", dirpath, strerror(errno)); return false; } } // 5. 构建文件路径 char filepath[256]; snprintf(filepath, sizeof(filepath), "%s/log.txt", dirpath); DBG_ERR("filepath: %s\n", filepath); // 6. 获取内容长度( char *content_length_str = common_find_key_from_buf(buf, "Content-Length"); if (!content_length_str || *content_length_str == '\0') { DBG_ERR("Missing Content-Length header\n"); return false; } size_t content_len = atol(content_length_str); if (content_len <= 0) { DBG_ERR("Invalid content length: %s\n", content_length_str); return false; } DBG_ERR("Content-Length: %zu\n", content_len); // 滚动写入核心逻辑 (修复版) FILE *fp = fopen(filepath, "a+"); if (!fp) { /* 错误处理 */ } fseek(fp, 0, SEEK_END); long file_size = ftell(fp); // 处理超大数据特殊情况 if (content_len > MAX_FILELOG_DIR_SIZE) { DBG_ERR("Unable to free sufficient space\n"); const char *resp = "HTTP/1.1 507 Insufficient Storage\r\n\r\n"; struct tpsocket_buf *resp_buf = tpbuf_snprintf(strlen(resp)+1, resp); if (resp_buf) tpsocket_write(sock, resp_buf); return false; } // 循环删除行直到空间足够 while (file_size > 0 && file_size + content_len > MAX_FILELOG_DIR_SIZE) { rewind(fp); long line_start = 0; long line_end = 0; // 增强行定位:逐字符扫描换行符 int ch; while ((ch = fgetc(fp)) != EOF) { line_end = ftell(fp); if (ch == '\n') { // 找到完整行边界 line_start = line_end; // 检查剩余空间 if (file_size - line_start + content_len <= MAX_FILELOG_DIR_SIZE) break; } } // 截断并移位(避免大内存分配) if (line_start > 0) { FILE *temp = tmpfile(); // 创建临时文件 fseek(fp, line_start, SEEK_SET); // 流式复制保留内容 char buffer[1024]; size_t bytes; while ((bytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) { fwrite(buffer, 1, bytes, temp); } // 原子替换原文件 ftruncate(fileno(fp), 0); rewind(fp); rewind(temp); while ((bytes = fread(buffer, 1, sizeof(buffer), temp)) > 0) { fwrite(buffer, 1, bytes, fp); } fclose(temp); file_size = ftell(fp); } else { ftruncate(fileno(fp), 0); file_size = 0; break; } } fclose(fp); //session FileLogSession *session = calloc(1, sizeof(FileLogSession)); if (!session) return false; session->fp = fopen(filepath, "a"); if (!session->fp) { free(session); return false; } session->remaining = content_len; session->total_size = content_len; DBG_ERR("Icontent_len: %d\n", content_len); snprintf(session->filepath,sizeof(session->filepath),"%s",filepath); sock->handler.cb = tpsocket_event_filelog_to_hub; sock->handler.priv = session; return true; } bool worker_file_log_read_handle(WORKER_CTX *worker_ctx, struct tpsocket_fd *sock, struct list_head *buf) { // 1. 仅解析 Device-Mac 参数 char *mac = common_find_key_from_buf(buf, "Device-Mac"); // Offset 和 Follow 参数被忽略 // 2. MAC 验证和格式化 if (!mac || strlen(mac) < 12) { DBG_ERR("Invalid MAC address\n"); const char *resp = "HTTP/1.1 400 Bad Request\r\n\r\n"; struct tpsocket_buf *resp_buf = tpbuf_snprintf(strlen(resp)+1, resp); if (resp_buf) tpsocket_write(sock, resp_buf); return false; } char processed_mac[18] = {0}; strncpy(processed_mac, mac, sizeof(processed_mac)-1); for (char *p = processed_mac; *p; p++) if (*p == ':') *p = '_'; // 3. 构建日志文件路径 char filepath[256]; snprintf(filepath, sizeof(filepath), "%s/%s/log.txt", FILELOG_PATH, processed_mac); // 4. 检查文件是否存在 if (access(filepath, F_OK) != 0) { DBG_ERR("Log file not found: %s\n", filepath); const char *resp = "HTTP/1.1 404 Not Found\r\n\r\n"; struct tpsocket_buf *resp_buf = tpbuf_snprintf(strlen(resp)+1, resp); if (resp_buf) tpsocket_write(sock, resp_buf); return false; } // 5. 打开日志文件 FILE *fp = fopen(filepath, "r"); if (!fp) { DBG_ERR("Failed to open log file: %s\n", strerror(errno)); const char *resp = "HTTP/1.1 500 Internal Error\r\n\r\n"; struct tpsocket_buf *resp_buf = tpbuf_snprintf(strlen(resp)+1, resp); if (resp_buf) tpsocket_write(sock, resp_buf); return false; } // 6. 获取文件大小 (假设最大5MB) struct stat st; if (fstat(fileno(fp), &st) != 0) { DBG_ERR("Failed to get file size: %s\n", strerror(errno)); fclose(fp); const char *resp = "HTTP/1.1 500 Internal Error\r\n\r\n"; struct tpsocket_buf *resp_buf = tpbuf_snprintf(strlen(resp)+1, resp); if (resp_buf) tpsocket_write(sock, resp_buf); return false; } size_t file_size = st.st_size; // 7. 读取整个文件内容 char *content = malloc(file_size + 1); if (!content) { DBG_ERR("Failed to allocate memory for log content\n"); fclose(fp); const char *resp = "HTTP/1.1 507 Insufficient Storage\r\n\r\n"; struct tpsocket_buf *resp_buf = tpbuf_snprintf(strlen(resp)+1, resp); if (resp_buf) tpsocket_write(sock, resp_buf); return false; } size_t bytes_read = fread(content, 1, file_size, fp); content[file_size] = '\0'; // Null-terminate for text safety fclose(fp); if (bytes_read != file_size) { DBG_ERR("Failed to read entire file: expected %zu, got %zu\n", file_size, bytes_read); free(content); const char *resp = "HTTP/1.1 500 Internal Error\r\n\r\n"; struct tpsocket_buf *resp_buf = tpbuf_snprintf(strlen(resp)+1, resp); if (resp_buf) tpsocket_write(sock, resp_buf); return false; } // 8. 构建并发送 HTTP 响应头 char header[512]; int header_len = snprintf(header, sizeof(header), "HTTP/1.1 200 OK\r\n" "Content-Type: text/plain\r\n" "Content-Length: %zu\r\n" "Connection: close\r\n\r\n", file_size); if (header_len < 0 || header_len >= (int)sizeof(header)) { DBG_ERR("Header buffer overflow\n"); free(content); const char *resp = "HTTP/1.1 500 Internal Error\r\n\r\n"; struct tpsocket_buf *resp_buf = tpbuf_snprintf(strlen(resp)+1, resp); if (resp_buf) tpsocket_write(sock, resp_buf); return false; } struct tpsocket_buf *header_buf = tpbuf_snprintf(header_len + 1, header); if (!header_buf) { DBG_ERR("Failed to create header buffer\n"); free(content); return false; } tpsocket_write(sock, header_buf); // 9. 发送日志内容 (假设内容为文本) struct tpsocket_buf *content_buf = tpbuf_snprintf(file_size + 1, "%s", content); if (!content_buf) { DBG_ERR("Failed to create content buffer\n"); free(content); return false; } tpsocket_write(sock, content_buf); free(content); // 释放原始内容内存,tpsocket_buf 自行管理其副本 // 10. 连接在发送后自动关闭 (由 Connection: close 头部控制) return true; }
10-19
POST diagnose_log/set HTTP/1.1 Host: 192.168.137.101 Cache-control: no-cache User-Agent: Camera First-Login: 0 tapo_tag: 31DCA30558E8599A84A377E6B3FDB3FAC1511C2778BAF29F42D91F21EE158469 seq: 746 Device-Mac: 8C902D3F996D Content-Length: 2834 Connection: keep-alive X-If-Encrypt: 1 X-Nonce: ac7f66701c102a5f56a02bcecf6793c4 Content-Type: application/json {"method":"securePassthrough","params":{"request":"F6bRsXD9GbxQ\/v8tsF+\/uo3s\/09JHiW0GNJWvueS6TnSixXb+c\/jcxseW7Y3xAuEzp\/tyZRoz\/hr0BmYJO2P1X5Pr8c9ISQa6o5FhoqAZE64xaz7ShxguFeEgdEbPfk6mbzXiw39TXkwzcb+bJxJnenQmoGIUpSLwNQ2DaJ3MbuRnQGNORqH\/ttnAlKaIoDHXZ2Pl3vaPgbasSzyCxGHIa30tpw57JC9IKpnpokvgnqCOCYLBf1Ow6LDiAl2luXTum8gzLnqfOh8b5Kb4PgU0EaawAkQs6JPMeWMdSd971iLYio2I\/DckzgPwvhllqB4kHjz5noaGOWPYfqYHc\/3hLFV1ZXe+XOVPkWhK0TBbYh\/\/FwLd7yraHLhrVhEX2kHSDcxhEWuLFG2N+7OkOwhKl2xElzbTa6hIShVs2+BF3bro2ag+isfbCnIzXqwN2mVrT9DZVIaTcmjt7gfVmRCs9WZvo2+JPjGMXCeNCKelrr927m+GPRYh9giI\/qkjBDfFyaTXwf5WVcEs66XXDQv66Rl8C67380fqLt3owT\/WqQLPD0cQCWnQ5hlWFlwp3Yv6VBg7U0caFOFOqQzaBeBY5wTuTiMTAOMLWrEOtl8P2aFGhWPOug8oT1QUPFnDyOXOcTyqcY8iDvuZYycvNIKt6Qpvpac3upSrqvs1CWXTXhkIQ4yzI0S4rBgFmp+mAkD4Adaf8r8SVOo97SuasTQihk26a1DGLtVyLhztZ0AvIxMBmRA6PNnmhUJ0C2YaVCJRIs6LL71JCHEvjI4CnynC0vYbZsxNNvqwY\/WMMd95qt1FROgu7tI1LwP60RAEqZxAad\/NEcHPSC5n4LSleECjXgVAsIbY5ONbBFEs5QivPDKlTm1bnzhV5M3dDwUyZynkwYSzXI1yoYnU6VZt8413Pe\/mVqLiaywUOyCGtRedPMNyCDX54O+25GEJTN0LWb2oZh2DpTgCcxpGn6SXhXGaKp3oIoZPgWebIYd7WJfhOmgjv+WvAov7XAbWPNKZ247jFuR70oQeKrljWpg\/p4Y5iqcABuuMQXR3BAcjP1TZAjPdkFjlPye7NBayxBC86FntJ1QFMNv1oGSV+ygta2sJahiPH9VJB+oHozhS6j+x68Ktlw+9Fn8stJIHaXcvdCuEs47kCimaYgtzSvo4T5oYLqGYdEL6eReZwT8YmTe1qYAg1Ubisb6JVf0KQBoGbnWOvmTb3aZFzLrDP24Kl\/XVGBSiCa61PPDXUweregBUllpHoBQfT31Z0fcAZ1Fmxv+uU\/vcfFO1im0mQu4912fuFJ\/Wo4hcPY8XicZ5Pic9qazgoS59K49TtnnKLVoK2aGYkwndeHbmiRLcFwfA2PUn4ngOSZAhnZZaS+zZs0+Q5H+Eqiva95gGhQ\/rjLgtOlqEqQYX6CXMy1wJW9K8GRm5e+NtfOxNAakLUnlv9Z3PKM536cFVgU3qm5KoyxP3NrGOP0a6YFR2l3uvEAAB7NSl4tGkTXe8NF\/GNse8j1fm0P0T9p4J5Y7\/wXpkk5JUmqeLV42uDYm2DAvG6a2Evg2WAI0q5aMigzdzXHveUI0KL4\/LqBFXWCa\/cai0Te3ErV8HP4H9W31iy9CaTwyQccvxHzernSfd6lG9Y1tHp3opV3TtLN3Zpd5K1gNMz3cZo8jOHammK4cVGMagp39HIlQe4aABH9AhpuRixxpD7zXjWMc6bCYODrrij2+GbJU2zozlD1iZ\/faKkAM71HCO\/yKrfUnzAJoIQ5pFKX79uG\/fY5XYVpwJp+7l5H1Jo8kskQjkuxl4liSX6seu8sFYaSIPPwcvn3m\/vmOOAZsHTLPg4yQhZ\/wIkTZtoVxen6M5iVd\/DqIMXSm1iVvi6EYfL8oXR5SBwG42FSKJeheYarrkR8noN2qR\/g1aK7pWs1iQxby7WzFPYqAYbTEvb1o\/5r6wKKZUrR4V8mkJoGAmt8EysOWygg+NikWquOeN8xOnDMplqZOyQKxmahz5TEN60DSgVvwIqCDeKBUjk2K\/Ah4QKyoFp7fogymozW43lk+Z5+lWnoGbGD6j08huAYb0WWDUWA\/SSh6p5JRtp\/FWWQ+TcCMjR0RCiBoTJVOPSOW36KezgWffoYR6filwLhXOa3YgNEawmxavf5f\/fQyh1eyJQRg9v\/pKqmB92kj8qz4zqRw2DZEUSQLPReiJQr0A3uAnjNsB\/Jb8dCKoqUNteHzFHekaRuqnfki4c7\/+hfzH0gvv2lsFmIFsvAXzEhs6fOwO628rjNtZm0NSJXvgXXLqZ6k+i9NgBhODwS11872cE5vWf9RAuPUyd27EmIBTzYSWcFFwrU5idv\/R4pkqv2fBrQumFNDblXPcMpRwa5YjCYAZP\/IeBf6b6ZMS7NdpfdPyggOyMgtEb\/gGRYq4QO+T3PyFuniSyt0xK+e3FtDOiguRmHQimJDHRTdTUQpn+whwbtQTvChrVw4SLQzILD6fnvDoPC17l1E9wmJRbFpSflWnCIHhfKpNH\/IJyhCC7aUjWpHwiAbbpSATw4AEVPbQunbhanp5n+mn\/aOj8b0\/8UOyMa0oU595zWMUGuHrEhEAsirUs8YBdVNgkkTpDdCiuSQ1E8KY4Xp6hnE7idiLtytLlSszqzQT4t82QHsrldfy1CLfKJx8eesTI8OzQW8qKTYLKhbCeaLpC9U0bb8Jiz688jXXbNpX2sllTJuKFWOCes9PL+ZQd1VsN1nADpRigk="}}这是camera发来的报文,帮我解析拿到base64编码的信息。bool tpsocket_event_filelog_to_hub(struct tpsocket_handler *handler, struct list_head *buf, int event) { struct tpsocket_fd *sock = container_of(handler, struct tpsocket_fd, handler); FileLogSession *session = handler->priv; if(!session){ return false; } int decrypt_flag = session->decrypt_flag; struct tpsocket_buf *nbuf = NULL; FILE *fp = session->fp; int remaining = session->remaining; char *filepath = session->filepath; DBG_ERR("sock=%p, event=%s\n", sock, tpsocket_event_name(event)); switch(event) { case TPSOCKET_EVENT_LISTEN: DBG_ERR("TPSOCKET_EVENT_LISTEN: %s:%s Listen\n", sock->addr, sock->port); break; case TPSOCKET_EVENT_SHUTDOWN: DBG_ERR("TPSOCKET_EVENT_LISTEN: %s:%s Shutdown\n", sock->addr, sock->port); break; case TPSOCKET_EVENT_ACCEPT: DBG_ERR("TPSOCKET_EVENT_LISTEN: %s:%s Accepted\n", sock->addr, sock->port); break; case TPSOCKET_EVENT_CONNECTED: DBG_ERR("TPSOCKET_EVENT_LISTEN: %s:%s connected\n", sock->addr, sock->port); break; case TPSOCKET_EVENT_REQ_HEAD: DBG_ERR("TPSOCKET_EVENT_LISTEN: %s Requested path: %s\n", sock->path, sock->parser.http.url); break; case TPSOCKET_EVENT_RSP_HEAD: break; case TPSOCKET_EVENT_SUB_HEAD: break; case TPSOCKET_EVENT_UPGRADE: break; case TPSOCKET_EVENT_STREAM: return true; case TPSOCKET_EVENT_MESSAGE: nbuf = tpsocket_merge_buf(buf); if (!nbuf) { DBG_ERR("Failed to merge buffer\n"); break; } if (!fp) { DBG_ERR("File pointer is NULL, cannot write\n"); break; } unsigned char *input_data = tpbuf_data(nbuf); int input_len = tpbuf_data_len(nbuf); DBG_ERR("input_len:%d", input_len); bool error = false; if (decrypt_flag) { DBG_ERR("+++++++++++++++++++++++++++++"); int decoded_len = tpsocket_base64_decode(input_data, input_len, input_data); if (decoded_len < 0) { DBG_ERR("Base64 decoding failed\n"); error = true; } DBG_ERR("tpsocket_base64_decode\n"); int plain_len = decoded_len; if (remaining > decoded_len) { remaining = decoded_len; DBG_ERR("decode session->remaining:%d\n", remaining); } unsigned char *plain_data = calloc(plain_len, sizeof(unsigned char)); DBG_ERR("plain_data:%s\n", plain_data); work_tapo_log_decrypt(tpbuf_data(nbuf), decoded_len, plain_data, &plain_len); DBG_ERR("plain_len:%d\n",plain_len); // 写入解密后的内容 if (fwrite(plain_data, 1, plain_len, fp) < plain_len) { DBG_ERR("File write error after decryption: %s\n", strerror(errno)); error = true; } else { const char newline = '\n'; if (fwrite(&newline, 1, 1, fp) != 1) { DBG_ERR("Failed to write newline character: %s\n", strerror(errno)); } remaining -= plain_len; } } else { if (fwrite(input_data, 1, input_len, fp) < input_len) { DBG_ERR("File write error: %s\n", strerror(errno)); error = true; } else { const char newline = '\n'; if (fwrite(&newline, 1, 1, fp) != 1) { DBG_ERR("Failed to write newline character: %s\n", strerror(errno)); } remaining -= input_len; } } DBG_ERR("session->remaining: %d\n", remaining); // 传输完成处理 if (remaining <= 0 || error) { if (fp) { fclose(fp); session->fp = NULL; } // char resp[256]; if (error) { // snprintf(resp, sizeof(resp), // "HTTP/1.1 500 Internal Error\r\n" // "Connection: close\r\n" // "{\"error_code\":0}" // "\r\n"); tpsocket_write(sock,tpbuf_snprintf(256, "HTTP/1.1 %d %s\r\n" "Content-Length: %d\r\n" "Cache-Control: no-cache\r\n" "Connection: %s\r\n" "\r\n" "{\"error_code\":0}", 500, "", strlen("{\"error_code\":0}"), "keep-alive")); } else { // snprintf(resp, sizeof(resp), // "HTTP/1.1 200 OK\r\n" // "Content-Type: text/plain\r\n" // "Content-Length: 0\r\n" // "Connection: close\r\n" // "\r\n"); tpsocket_write(sock,tpbuf_snprintf(256, "HTTP/1.1 %d %s\r\n" "Content-Length: %d\r\n" "Cache-Control: no-cache\r\n" "Connection: %s\r\n" "\r\n" "{\"error_code\":0}", 200, "", strlen("{\"error_code\":0}"), "keep-alive")); } // struct tpsocket_buf *resp_buf = tpbuf_snprintf(strlen(resp) + 1, resp); // if (resp_buf) tpsocket_write(sock, resp_buf); // if (error) unlink(filepath); if(session){ free(session); handler->priv = NULL; } // tpsocket_close(sock); } break; case TPSOCKET_EVENT_RESET: break; case TPSOCKET_EVENT_TIMEOUT: break; case TPSOCKET_EVENT_CLOSED: DBG_ERR("TPSOCKET_EVENT_CLOSED\n"); if (session != NULL) { // 异常关闭时清理资源 DBG_ERR("entering TPSOCKET_EVENT_CLOSED\n"); if (session->fp) { fclose(session->fp); session->fp = NULL; } unlink(filepath); free(session); handler->priv = NULL; } break; case TPSOCKET_EVENT_ERROR: default: break; } tpsocket_free_buf(buf, tpsocket_event_name(event), 0); return true; }bool worker_file_log_set_handle(WORKER_CTX *worker_ctx, struct tpsocket_fd *sock, struct list_head *buf) { // 1. 获取设备MAC地址 char *mac = common_find_key_from_buf(buf, "Device-Mac"); if (!mac || strlen(mac) < 12) { DBG_ERR("Invalid MAC address\n"); return false; } DBG_ERR("mac: %s\n", mac); // 2. MAC格式化处理(冒号转下划线) char processed_mac[18] = {0}; strncpy(processed_mac, mac, sizeof(processed_mac)-1); for (char *p = processed_mac; *p; p++) { if (*p == ':') *p = '_'; } DBG_ERR("processed_mac: %s\n", processed_mac); // 3. 创建目标目录 char dirpath[128]; snprintf(dirpath, sizeof(dirpath), "%s/%s", FILELOG_PATH , processed_mac); // 检创建父目录(/mnt/sd_card) if (access(FILELOG_PATH, F_OK) != 0) { if (mkdir(FILELOG_PATH,0755) != 0) { DBG_ERR("SD card mount failed: %s\n", strerror(errno)); return false; } } // 创建设备目录(/mnt/sd_card/<processed_mac>) if (access(dirpath, F_OK) != 0) { if (mkdir(dirpath, 0755) != 0) { DBG_ERR("Device dir '%s' creation failed: %s\n", dirpath, strerror(errno)); return false; } } // 4. 构建文件路径 char filepath[256]; snprintf(filepath, sizeof(filepath), "%s/log.txt", dirpath); DBG_ERR("filepath: %s\n", filepath); // 5. 获取内容长度( char *content_length_str = common_find_key_from_buf(buf, "Content-Length"); if (!content_length_str || *content_length_str == '\0') { DBG_ERR("Missing Content-Length header\n"); return false; } size_t content_len = atol(content_length_str); if (content_len <= 0) { DBG_ERR("Invalid content length: %s\n", content_length_str); return false; } DBG_ERR("Content-Length: %zu\n", content_len); // 滚动写入 FILE *fp = fopen(filepath, "ab+"); if (!fp) { /* 错误处理 */ } fseek(fp, 0, SEEK_END); long file_size = ftell(fp); // 处理超大数据特殊情况 if (content_len > MAX_FILELOG_DIR_SIZE) { DBG_ERR("Unable to free sufficient space\n"); const char *resp = "HTTP/1.1 507 Insufficient Storage\r\n\r\n"; struct tpsocket_buf *resp_buf = tpbuf_snprintf(strlen(resp)+1, resp); if (resp_buf) tpsocket_write(sock, resp_buf); return false; } // 循环删除行直到空间足够 while (file_size > 0 && file_size + content_len > MAX_FILELOG_DIR_SIZE) { rewind(fp); long line_start = 0; long line_end = 0; // 增强行定位:逐字符扫描换行符 int ch; while ((ch = fgetc(fp)) != EOF) { line_end = ftell(fp); if (ch == '\n') { // 找到完整行边界 line_start = line_end; // 检查剩余空间 if (file_size - line_start + content_len <= MAX_FILELOG_DIR_SIZE) break; } } // 截断并移位(避免大内存分配) if (line_start > 0) { FILE *temp = tmpfile(); // 创建临时文件 fseek(fp, line_start, SEEK_SET); // 流式复制保留内容 char buffer[1024]; size_t bytes; while ((bytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) { fwrite(buffer, 1, bytes, temp); } // 原子替换原文件 ftruncate(fileno(fp), 0); rewind(fp); rewind(temp); while ((bytes = fread(buffer, 1, sizeof(buffer), temp)) > 0) { fwrite(buffer, 1, bytes, fp); } fclose(temp); file_size = ftell(fp); } else { ftruncate(fileno(fp), 0); file_size = 0; break; } } // fclose(fp); //session FileLogSession *session = calloc(1, sizeof(FileLogSession)); if (!session) return false; // session->fp = fopen(filepath, "ab"); session->fp = fp; if (!session->fp) { free(session); return false; } session->remaining = content_len; session->total_size = content_len; char *if_encrypt = common_find_key_from_buf(buf, "X-If-Encrypt"); DBG_ERR("if_encrypt:%s\n",if_encrypt); if (if_encrypt) { session->decrypt_flag = atoi(if_encrypt); DBG_ERR("session->decrypt_flagt:%d\n",session->decrypt_flag); char *nonce = NULL; if ((nonce = common_find_key_from_buf(buf, "X-Nonce"))) { DBG_ERR("nonce:%s\n",nonce); work_tapo_log_refresh_nonce(nonce); free(nonce); } } else { session->decrypt_flag = 0; } free(if_encrypt); snprintf(session->filepath,sizeof(session->filepath),"%s",filepath); sock->handler.cb = tpsocket_event_filelog_to_hub; sock->handler.priv = session; return sock->handler.cb; } bool worker_file_log_read_handle(WORKER_CTX *worker_ctx, struct tpsocket_fd *sock, struct list_head *buf) { char *mac = common_find_key_from_buf(buf, "Device-Mac"); if (!mac || strlen(mac) < 12) { DBG_ERR("Invalid MAC address\n"); const char *resp = "HTTP/1.1 400 Bad Request\r\n\r\n"; struct tpsocket_buf *resp_buf = tpbuf_snprintf(strlen(resp)+1, resp); if (resp_buf) tpsocket_write(sock, resp_buf); return false; } DBG_ERR("mac: %s\n", mac); char processed_mac[18] = {0}; strncpy(processed_mac, mac, sizeof(processed_mac)-1); for (char *p = processed_mac; *p; p++) if (*p == ':') *p = '_'; // 1. 构建日志文件路径 char filepath[256]; snprintf(filepath, sizeof(filepath), "%s/%s/log.txt", FILELOG_PATH, processed_mac); DBG_ERR("filepath: %s\n", filepath); // 2. 检查文件是否存在 if (access(filepath, F_OK) != 0) { DBG_ERR("Log file not found: %s\n", filepath); const char *resp = "HTTP/1.1 404 Not Found file\r\n\r\n"; struct tpsocket_buf *resp_buf = tpbuf_snprintf(strlen(resp)+1, resp); if (resp_buf) tpsocket_write(sock, resp_buf); return false; } // 3. 打开日志文件 FILE *fp = fopen(filepath, "rb"); if (!fp) { DBG_ERR("Failed to open log file: %s\n", strerror(errno)); const char *resp = "HTTP/1.1 500 Internal Error\r\n\r\n"; struct tpsocket_buf *resp_buf = tpbuf_snprintf(strlen(resp)+1, resp); if (resp_buf) tpsocket_write(sock, resp_buf); return false; } DBG_ERR("[SUCCESS] File opened successfully\n"); // 4. 获取文件大小 (假设最大5MB) struct stat st; if (fstat(fileno(fp), &st) != 0) { DBG_ERR("Failed to get file size: %s\n", strerror(errno)); fclose(fp); const char *resp = "HTTP/1.1 500 Internal Error\r\n\r\n"; struct tpsocket_buf *resp_buf = tpbuf_snprintf(strlen(resp)+1, resp); if (resp_buf) tpsocket_write(sock, resp_buf); return false; } size_t file_size = st.st_size; DBG_ERR("[DEBUG] File size: %zu bytes\n", file_size); // 5. 读取整个文件内容 char *content = malloc(file_size + 1); if (!content) { DBG_ERR("Failed to allocate memory for log content\n"); fclose(fp); const char *resp = "HTTP/1.1 507 Insufficient Storage\r\n\r\n"; struct tpsocket_buf *resp_buf = tpbuf_snprintf(strlen(resp)+1, resp); if (resp_buf) tpsocket_write(sock, resp_buf); return false; } size_t bytes_read = fread(content, 1, file_size, fp); content[file_size] = '\0'; // Null-terminate for text safety fclose(fp); DBG_ERR("[DEBUG] Bytes read: %zu/%zu\n", bytes_read, file_size); if (bytes_read != file_size) { DBG_ERR("Failed to read entire file: expected %zu, got %zu\n", file_size, bytes_read); free(content); const char *resp = "HTTP/1.1 500 Internal Error\r\n\r\n"; struct tpsocket_buf *resp_buf = tpbuf_snprintf(strlen(resp)+1, resp); if (resp_buf) tpsocket_write(sock, resp_buf); return false; } // 6. 构建并发送 HTTP 响应头 char header[512]; int header_len = snprintf(header, sizeof(header), "HTTP/1.1 200 OK\r\n" "Content-Type: text/plain; charset=utf-8\r\n" "Content-Length: %zu\r\n" "Connection: close\r\n\r\n", file_size); if (header_len < 0 || header_len >= (int)sizeof(header)) { DBG_ERR("Header buffer overflow\n"); free(content); const char *resp = "HTTP/1.1 500 Internal Error\r\n\r\n"; struct tpsocket_buf *resp_buf = tpbuf_snprintf(strlen(resp)+1, resp); if (resp_buf) tpsocket_write(sock, resp_buf); return false; } // 7.创建复合缓冲区:头部 + 内容 struct tpsocket_buf *full_resp = tpbuf_new(header_len + file_size); if (!full_resp) { free(content); DBG_ERR("Failed to create full response buffer\n"); return false; } // 8.按顺序填充数据 memcpy(tpbuf_tail(full_resp), header, header_len); // 头部 tpbuf_put(full_resp, header_len); memcpy(tpbuf_tail(full_resp), content, file_size); // 内容 tpbuf_put(full_resp, file_size); // 9.写入 tpsocket_write_force(sock, full_resp, true); free(content); tpsocket_close(sock); return true; }帮我修改代码,解析请求中的数据再进行处理。
最新发布
11-04
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值