/**************************************************************************** * This file is part of the project AqHome. * AqHome (c) by 2025 Martin Preuss, all rights reserved. * * The license for this file can be found in the file COPYING which you * should have received along with this file. ****************************************************************************/ #ifdef HAVE_CONFIG_H # include #endif #include "./server.h" #include "./net_read.h" #include "aqhome-react/units/u_timer.h" #include "aqhome-react/types/prgrule.h" #include "aqhome-react/types/prgrule-t.h" #include "aqhome/aqhome.h" #include "aqhome/data/path-t.h" #include "aqhome/data/vars-t.h" #include "aqhome/data/vars_dbread-t.h" #include "aqhome/data/vars_dbwrite-t.h" #include #include #include #include #include #include #include #include #ifdef HAVE_SIGNAL_H # include #endif #include #include #include #include #include #include /* ------------------------------------------------------------------------------------------------ * defines * ------------------------------------------------------------------------------------------------ */ #define I18N(msg) msg #define I18S(msg) msg #define FULL_DEBUG #define AQHOME_REACT_READNET_INTERVAL 300 #define AQHOME_REACT_SAVE_INTERVAL 300 #define CONNCLEAN_INTERVAL_IN_SECS 2 #define CONNCHECK_INTERVAL_IN_SECS 10 /* ------------------------------------------------------------------------------------------------ * forward declarations * ------------------------------------------------------------------------------------------------ */ static void _runService(AQH_OBJECT *aqh, AQH_EVENT_LOOP *eventLoop); static int _diffInSeconds(time_t t1, time_t t0); static int _testModules(int argc, char **argv); static int _test(int argc, char **argv); #ifdef HAVE_SIGNAL_H static int _setSignalHandlers(void); static int _setupSigAction(struct sigaction *sa, int sig); static void _signalHandler(int s); static struct sigaction saINT,saTERM, saHUP, saTSTP, saCONT, saPIPE; #endif /* ------------------------------------------------------------------------------------------------ * static vars * ------------------------------------------------------------------------------------------------ */ static int stopService=0; /* ------------------------------------------------------------------------------------------------ * implementations * ------------------------------------------------------------------------------------------------ */ int main(int argc, char **argv) { int rv; AQH_EVENT_LOOP *eventLoop; AQH_OBJECT *aqh; GWEN_GUI *gui; rv=GWEN_Init(); if (rv) { fprintf(stderr, "ERROR: Unable to init Gwen.\n"); return 2; } GWEN_Logger_Open(0, "aqhome-react", 0, GWEN_LoggerType_Console, GWEN_LoggerFacility_User); GWEN_Logger_SetLevel(0, GWEN_LoggerLevel_Warning); //GWEN_Logger_SetLevel(0, GWEN_LoggerLevel_Info); rv=_setSignalHandlers(); if (rv<0) { DBG_INFO(NULL, "here (%d)", rv); return rv; } rv=AQH_Init(); if (rv<0) { DBG_INFO(NULL, "here (%d)", rv); return 2; } gui=GWEN_Gui_CGui_new(); GWEN_Gui_SetGui(gui); if (argc>1) { const char *cmd; cmd=argv[1]; if (cmd && *cmd) { if (strcasecmp(cmd, "unittest")==0) { rv=_testModules(argc, argv); GWEN_Gui_SetGui(NULL); GWEN_Gui_free(gui); return rv; } else if (strcasecmp(cmd, "test")==0) { rv=_test(argc, argv); GWEN_Gui_SetGui(NULL); GWEN_Gui_free(gui); return rv; } } } eventLoop=AQH_EventLoop_new(); aqh=AQH_ReactServer_new(eventLoop); rv=AQH_ReactServer_Init(aqh, argc, argv); if (rv<0) { if (rv==GWEN_ERROR_CLOSE) return 1; DBG_INFO(NULL, "here (%d)", rv); return 2; } _runService(aqh, eventLoop); AQH_ReactServer_Fini(aqh); AQH_Object_free(aqh); AQH_EventLoop_free(eventLoop); GWEN_Gui_SetGui(NULL); GWEN_Gui_free(gui); return 0; } void _runService(AQH_OBJECT *aqh, AQH_EVENT_LOOP *eventLoop) { time_t timeStart; int timeout; time_t timeLastConnCheck; time_t lastFileScanTime; time_t lastSaveTime; timeout=AQH_ReactServer_GetTimeout(aqh); timeStart=time(NULL); timeLastConnCheck=time(NULL); lastFileScanTime=timeStart; lastSaveTime=timeStart; AQH_ReactServer_SetLatestNetworkFileTime(aqh, AQH_ReactServer_GetNewestUnitNetFiletime()); while(!stopService) { time_t now; int rv; AQH_EventLoop_Run(eventLoop, 2000); AQH_ReactServer_HandleBrokerMsgs(aqh); now=time(NULL); if (_diffInSeconds(now, timeLastConnCheck)>CONNCHECK_INTERVAL_IN_SECS) { DBG_INFO(NULL, "Check connections"); AQH_ReactServer_CheckBrokerConnection(aqh); timeLastConnCheck=now; } AQH_ReactServer_ProcessAllUnits(aqh); if (_diffInSeconds(now, lastFileScanTime)>AQHOME_REACT_READNET_INTERVAL) { time_t tNew; time_t t; DBG_INFO(NULL, "Checking network files"); tNew=AQH_ReactServer_GetNewestUnitNetFiletime(); t=AQH_ReactServer_GetLatestNetworkFileTime(aqh); if (tNew && tNew>t) { DBG_INFO(NULL, "Reloading network files"); AQH_ReactServer_ReloadUnitNets(aqh); AQH_ReactServer_SetLatestNetworkFileTime(aqh, tNew); } lastFileScanTime=now; } if (_diffInSeconds(now, lastSaveTime)>AQHOME_REACT_SAVE_INTERVAL) { DBG_INFO(NULL, "Writing var file"); rv=AQH_ReactServer_WriteVarsFile(aqh); if (rv<0) { DBG_INFO(NULL, "Error writing runtime data"); } lastSaveTime=time(NULL); } if (timeout && (_diffInSeconds(now, timeStart)>timeout)) { DBG_INFO(NULL, "Timeout"); break; } } /* while */ } int _setSignalHandlers(void) { #ifdef HAVE_SIGNAL_H int rv; rv=_setupSigAction(&saINT, SIGINT); if (rv) return rv; rv=_setupSigAction(&saTERM, SIGTERM); if (rv) return rv; rv=_setupSigAction(&saHUP, SIGHUP); if (rv) return rv; rv=_setupSigAction(&saPIPE, SIGPIPE); if (rv) return rv; # ifdef SIGTSTP rv=_setupSigAction(&saTSTP, SIGTSTP); if (rv) return rv; # endif # ifdef SIGCONT rv=_setupSigAction(&saCONT, SIGCONT); if (rv) return rv; # endif #endif return 0; } int _setupSigAction(struct sigaction *sa, int sig) { sa->sa_handler=_signalHandler; sigemptyset(&sa->sa_mask); sa->sa_flags=0; if (sigaction(sig, sa, 0)) { DBG_ERROR(NULL, "Could not setup signal handler for signal %d", sig); return GWEN_ERROR_IO; } return 0; } void _signalHandler(int s) { switch(s) { case SIGINT: case SIGTERM: case SIGHUP: DBG_WARN(0, "Received signal %d, stopping service in next loop.",s); stopService=1; break; case SIGPIPE: DBG_WARN(0, "Received PIPE signal"); break; default: DBG_WARN(0, "Unknown signal %d",s); break; } } int _testModules(int argc, char **argv) { GWEN_GUI *gui; GWEN_TEST_FRAMEWORK *tf; int rv; gui=GWEN_Gui_CGui_new(); GWEN_Gui_SetGui(gui); tf=TestFramework_new(); rv=AQHREACT_PrgRule_AddTests(TestFramework_GetModulesRoot(tf)); if (rv<0) { fprintf(stderr, "Adding module \"PrgRule\" failed.\n"); return 2; } rv=AQH_Path_AddTests(TestFramework_GetModulesRoot(tf)); if (rv<0) { fprintf(stderr, "Adding module \"path\" failed.\n"); return 2; } rv=AQH_Vars_AddTests(TestFramework_GetModulesRoot(tf)); if (rv<0) { fprintf(stderr, "Adding module \"vars\" failed.\n"); return 2; } rv=AQH_Vars_DbRead_AddTests(TestFramework_GetModulesRoot(tf)); if (rv<0) { fprintf(stderr, "Adding module \"vars_dbread\" failed.\n"); return 2; } rv=AQH_Vars_DbWrite_AddTests(TestFramework_GetModulesRoot(tf)); if (rv<0) { fprintf(stderr, "Adding module \"vars_dbwrite\" failed.\n"); return 2; } argc--; argv++; rv=TestFramework_Run(tf, argc, argv); if (rv) { fprintf(stderr, "SomeError in tests failed.\n"); GWEN_Gui_SetGui(NULL); GWEN_Gui_free(gui); return 2; } TestFramework_free(tf); GWEN_Gui_SetGui(NULL); GWEN_Gui_free(gui); return 0; } int _test(int argc, char **argv) { if (argc>2) { AQHREACT_PRGRULE_LIST *ruleList; GWEN_Logger_SetLevel(0, GWEN_LoggerLevel_Info); ruleList=AQHREACT_PrgRule_ReadRules(argv[2]); if (ruleList==NULL) { DBG_ERROR(NULL, "Error in rules"); return 2; } DBG_ERROR(NULL, "Rules ok (%d)", AQHREACT_PrgRule_List_GetCount(ruleList)); AQHREACT_PrgRule_List_free(ruleList); return 0; } else { DBG_ERROR(NULL, "No rules"); return 2; } } int _diffInSeconds(time_t t1, time_t t0) { return t1-t0; }