#include "vendor_base.h" #include "vendor_global.h" #include #include #include #include #include namespace vendor { LongOpts::LongOpts(const MyOpt opts[], const int size) { myOpt = opts; sizeOpt = size; } void LongOpts::GetOptions(option *opts, std::string &shorts) { for (int i = 0; i < sizeOpt; i++) { // printf("val: %d(%c) ", myOpt[i].val, myOpt[i].val); opts[i].name = strdup(myOpt[i].name); opts[i].has_arg = myOpt[i].has_arg; opts[i].flag = NULL; opts[i].val = myOpt[i].val; if (myOpt[i].val == 0) { continue; } if (myOpt[i].has_arg == no_argument) { shorts.push_back(static_cast(myOpt[i].val)); } else if (myOpt[i].has_arg == required_argument) { shorts.push_back(static_cast(myOpt[i].val)); shorts.push_back(':'); } else { shorts.push_back(static_cast(myOpt[i].val)); } } } MyOpt LongOpts::GetOption(char ch, int index) { if (ch == 0) { return myOpt[index]; } for (int i = 0; i < sizeOpt; i++) { if (myOpt[i].val == ch) { return myOpt[i]; } } return myOpt[0]; } VendorBase::VendorBase() { HTELINK_LOG_ENABLE(true); uvLoop_ = uv_default_loop(); if (uvLoop_ == nullptr) { HTELINK_LOG_ERR("event new failed, %s", strerror(errno)); } } VendorBase::~VendorBase() { if (uvLoop_ == nullptr) { return; } for (auto sig : uvSignals_) { uv_close(reinterpret_cast(sig), nullptr); delete sig; } uvSignals_.clear(); uv_loop_close(uvLoop_); Exit(SIGINT); } void VendorBase::ListenSignal(int signal) { uv_signal_t *uvSigal = new uv_signal_t; uv_signal_init(uvLoop_, uvSigal); uvSigal->data = this; uv_signal_start(uvSigal, VendorBase::SignalHandler, signal); uvSignals_.push_back(reinterpret_cast(uvSigal)); } int VendorBase::Exec() { HTELINK_LOG_INFO("register event..."); // 注册信号事件 ListenSignal(SIGSEGV); ListenSignal(SIGFPE); ListenSignal(SIGINT); ListenSignal(SIGTERM); #ifndef WIN32 ListenSignal(SIGTSTP); signal(SIGPIPE, SIG_IGN); #endif AppendTimerEvent(10 * 60 * 1000, [] { /* move files if disk full */ utils::check_disk_log(VENDOR_LOG_PATH); }); uv_work_t workReq; workReq.data = this; uv_queue_work( uvLoop_, &workReq, [](uv_work_t *req) { VendorBase *vb = reinterpret_cast(req->data); HTELINK_LOG_INFO("start to Run"); vb->Run(); }, [](uv_work_t *req, int status) {}); HTELINK_LOG_INFO("start to deamon..."); return uv_run(uvLoop_, UV_RUN_DEFAULT); } void VendorBase::Exit(int signal) { Stop(signal); if (uvLoop_ == nullptr) { return; } uv_stop(uvLoop_); } uv_handle_t *VendorBase::AppendEvent(int fd, int ev, VendorIf *vif) { uv_async_t *async = new uv_async_t; uv_async_cb asyncCb = [](uv_async_t *handle) { VendorIf *vif = static_cast(handle->data); if (vif) { vif->OnEvent(nullptr); } }; uv_async_init(uvLoop_, async, asyncCb); async->data = vif; uv_async_send(async); uvSignals_.push_back(reinterpret_cast(async)); return (uv_handle_t *)async; } uv_handle_t *VendorBase::AppendTimerEvent(int millionsecs, VendorIf *vif) { uv_timer_t *timerReq = new uv_timer_t; uv_timer_init(uvLoop_, timerReq); timerReq->data = vif; uv_timer_cb timerCb = [](uv_timer_t *handle) { VendorIf *vif = static_cast(handle->data); if (vif) { vif->OnTimer(nullptr); } }; uv_timer_start(timerReq, timerCb, millionsecs, 1); uvSignals_.push_back(reinterpret_cast(timerReq)); return (uv_handle_t *)(timerReq); } uv_handle_t *VendorBase::AppendTimerEvent( int millionsecs, std::function timerFunc) { class VendorTimerIf : public VendorIf { public: VendorTimerIf(std::function timerFunc) { timerFunc_ = timerFunc; } virtual void OnEvent(void *args) {} virtual void OnTimer(void *args) { timerFunc_(); } virtual void OnShot(void *args) {} private: std::function timerFunc_; }; // 存在内存泄露问题,待更好的方案 return AppendTimerEvent(millionsecs, new VendorTimerIf(timerFunc)); } void VendorBase::StopEvent(uv_handle_t *handle) { if (handle == nullptr) { return; } if (handle->type == UV_TIMER) { uv_timer_stop((uv_timer_t *)handle); } else { uv_close(handle, nullptr); } delete handle; } void VendorBase::SignalHandler(uv_signal_t *handle, int signum) { void *l_buffer[1024]; char **l_ptrace; int signal = signum; VendorBase *vendorBase = static_cast(handle->data); if (vendorBase) { vendorBase->Exit(signal); } HTELINK_LOG_ERR("\r\n=========>>>catch signal %d, pid: %ld <<<=========", signal, getpid()); HTELINK_LOG_ERR("Dump stack start..."); #ifndef WIN32 int size = backtrace(l_buffer, 1024); l_ptrace = backtrace_symbols(l_buffer, size); if (NULL == l_ptrace) { HTELINK_LOG_ERR("backtrace_symbols"); exit(signal); } for (int i = 0; i < size; i++) { HTELINK_LOG_ERR(" [%02d] %s", i, l_ptrace[i]); } HTELINK_LOG_ERR("Dump stack end..."); free(l_ptrace); #endif abort(); } int32_t VendorBase::ParseOptionArgs(VendorBase *vendor, int argc, char *argv[]) { int longindex = 0; std::string shorts; struct option longopts[vendor->GetOptSize()]; LongOpts longOpts(vendor->GetOpts(), vendor->GetOptSize()); longOpts.GetOptions(longopts, shorts); int ch; while ((ch = getopt_long(argc, argv, shorts.c_str(), longopts, &longindex)) != -1) { MyOpt myOpt = longOpts.GetOption(ch, longindex); printf("longindex :%d, opt %d(%c), name:%s , optarg :%s\n", longindex, myOpt.val, myOpt.val, myOpt.name, optarg == nullptr ? "nullptr" : optarg); if (strcmp(myOpt.name, "help") == 0) { MyOpt *myOpts = vendor->GetOpts(); printf("Usage: %s [OPTION] -l URL\n\nOPTIONS:\n", vendor->Name().c_str()); for (int i = 1; i < vendor->GetOptSize(); i++) { if (myOpts[i].val == 0) { printf("--%s: %s\n", myOpts[i].name, myOpts[i].desc); } else { printf("-%c, --%s: %s\n", myOpts[i].val, myOpts[i].name, myOpts[i].desc); } } return -1; } if (vendor->ParseCmdline(myOpt.name, optarg == nullptr ? "" : optarg) != 0) { printf("parse failed!!!\n"); return -1; } } return 0; } }; // namespace vendor