Files
aqhomecontrol/apps/aqhome-react/main.c
2025-03-10 00:02:26 +01:00

357 lines
7.8 KiB
C

/****************************************************************************
* 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 <config.h>
#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 <gwenhywfar/gwenhywfar.h>
#include <gwenhywfar/args.h>
#include <gwenhywfar/logger.h>
#include <gwenhywfar/db.h>
#include <gwenhywfar/debug.h>
#include <gwenhywfar/cgui.h>
#include <gwenhywfar/text.h>
#include <gwenhywfar/testframework.h>
#ifdef HAVE_SIGNAL_H
# include <signal.h>
#endif
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <time.h>
/* ------------------------------------------------------------------------------------------------
* 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);
#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);
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);
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_ERROR(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;
}
}
#if 0
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;
}
#endif
int _diffInSeconds(time_t t1, time_t t0)
{
return t1-t0;
}