Files
2026-07-09 11:27:59 +08:00

566 lines
13 KiB
C++

#include <time.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <signal.h>
#include "debug.h"
#include "ServiceThread.h"
#include "DBInterface.h"
#include "MessageThread.h"
#include "DataBuffers.h"
#include "ResponseManager.h"
#include "EpollThread.h"
#include "INIParser.h"
extern int g_eDebug;
extern int g_iChkStyle;
extern MHTHREADLIST g_lstMessageHandleThreads;
extern CSema* g_pSemaStop;
int g_iSignal = 0;
CSema* g_pSemaService = NULL;
CSema* g_pSemaClientCheck = NULL;
CSema* g_pSemaTimer = NULL;
CUDPMessageReceiveThread * g_pMessageReceiveThread = NULL;
EpollThread* g_pEpollThread = NULL;
CDataBufferManager* g_pDataBuffers = NULL;
CResponseManager* g_pResponses = NULL;
int g_aStyleRecomList[MAX_STYLE_NUM+1];
TQNAITEM g_lstCommonQnA[200];
TNOTICEITEM g_lstPublicNotice[MAX_NOTICE_NUM];
int g_nCommonQnANum = 0, g_nPublicNoticeNum = 0;
TCLIENTVERSION* g_pVersionClient = NULL;
TTESTVERSION* g_pVersionClientTest = NULL;
int g_nClientTypeNum = 0,
g_nClientTestNum = 0;
HANDLE g_hEvClientCheck = NULL;
char g_strStyleFileDir[256] = "";
char g_strWebFileDir[256] = "";
char g_strMusicFileDir[256] = "";
char g_strMusicLocation[8] = "";
char g_strServiceDir[256] = "";
void SignalHandler(int signo)
{
if(signo==SIGTERM || signo==SIGINT || signo==SIGUSR1){
DebugPrint("Terminate by signal: %d", signo);
if(signo==SIGUSR1)
g_iSignal = signo;
if(g_pSemaStop)
g_pSemaStop->ActV();
}
else if(signo==SIGALRM){
if(g_pSemaTimer)
g_pSemaTimer->ActV();
}
}
void CreateLog()
{
time_t t;
struct tm *tm;
time(&t);
tm = localtime(&t);
char szBufPath[256] = "";
sprintf( szBufPath, "%s/log/", g_strServiceDir );
// DebugPrint(szBufPath);
if( chdir(szBufPath) == -1)
mkdir(szBufPath, S_IRWXU|S_IRWXG);
sprintf( szBufPath, "%s%04d-%02d-%02d.log", szBufPath, tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday);
DebugModuleClose();
int iDebug = g_eDebug>0 ? g_eDebug : 1;
DebugModuleInitialize( 0xFFFF, (EDPrintDest)iDebug, szBufPath );
}
#define INI_FILE_NAME "DBService.ini"
#define STR_TESTVERSION_SECTION "TEST_VERSIONS"
#define STR_TESTVERSION "VERSIONS_STRING"
#ifdef _WIN32
#define stat _stat
#endif
time_t g_ftIniModify = 0;
void ReadConfigParams()
{
char szFileName[260] = "";
sprintf( szFileName, "%s/%s", g_strServiceDir, INI_FILE_NAME );
struct stat stFile;
if( stat( szFileName, &stFile )!=0 ){
DebugPrint( "get ini file stat error: %d", errno );
return;
}
if( g_ftIniModify!=stFile.st_mtime ){
if(g_pSemaClientCheck->ActP())
return;
//printf( "retrive config.\n" );
TTESTVERSION aVersion[10];
int num = 0;
INIParser parser;
parser.ReadINI(szFileName);
string szLine = parser.GetValue(STR_TESTVERSION_SECTION, STR_TESTVERSION);
if( !szLine.empty() ){
char szBuf[512] = "";
strcpy(szBuf, szLine.c_str());
char *tokenPtr=strtok( szBuf, "|" );
for( ; tokenPtr!=NULL; num++ ){
int iInner, iMaj, iMin, iMod, iBuil;
sscanf( tokenPtr, "%d,%d.%d.%d", &iInner, &iMaj, &iMin, &iMod );//, &iBuil );
aVersion[num].iClientType = iInner;
aVersion[num].version.majorVersion = iMaj;
aVersion[num].version.minorVersion = iMin;
aVersion[num].version.modifyVersion = iMod;
// aVersion[num].version.buildVersion = iBuil;
tokenPtr = strtok( NULL, "|" );
}
}
parser.Clear();
if( g_nClientTestNum>0 && g_nClientTestNum!=num ){
delete[] g_pVersionClientTest;
g_pVersionClientTest = NULL;
}
g_nClientTestNum = num;
if( num>0 ){
if( !g_pVersionClientTest ){
g_pVersionClientTest = new TTESTVERSION[num];
}
for( int i=0; i<num; i++ ){
TTESTVERSION* pVersion = &(g_pVersionClientTest[i]);
memcpy( pVersion, &aVersion[i], sizeof(TTESTVERSION) );
DebugPrint( "测试版本: %d.%d.%d\t软件内部编号: %d",
pVersion->version.majorVersion, pVersion->version.minorVersion,
pVersion->version.modifyVersion, //pVersion->version.buildVersion, //不设置构建版本
pVersion->iClientType );
}
}
else{
DebugPrint( "No test version." );
}
g_pSemaClientCheck->ActV();
// SetEvent( g_hEvClientCheck );
g_ftIniModify = stFile.st_mtime;
}
else{
DebugPrint( "No config update." );
}
}
void GetStyleRecomList()
{
int tempList[MAX_STYLE_NUM+1];
memset( tempList, 0, sizeof(int)*(MAX_STYLE_NUM+1) );
int num = MAX_STYLE_NUM;
int ret = f_DB_GetRecomStyleIDs( &num, tempList );
if( ret==0 ){
tempList[MAX_STYLE_NUM] = num;
memcpy( g_aStyleRecomList, tempList, sizeof(int)*(MAX_STYLE_NUM+1) );
DebugPrint( "Recommand style num : %d", num );
}
else{
DebugPrint( "DB_GetRecomStyleIDs return %d", ret );
}
}
void GetCommonQnAList()
{
// int dtUpdate = 0;
// for( int i=0; i<g_nCommonQnANum; i++ ){
// if( dtUpdate<g_lstCommonQnA[i].dtUpdate ){
// dtUpdate = g_lstCommonQnA[i].dtUpdate;
// }
// }
// g_nCommonQnANum = f_DB_GetCommonQnA( dtUpdate, g_nCommonQnANum, g_lstCommonQnA );
g_nCommonQnANum = f_DB_GetCommonQnA( 0, g_nCommonQnANum, g_lstCommonQnA );
DebugPrint( "Common QnA num : %d", g_nCommonQnANum );
}
void GetPublicNoticeList()
{
g_nPublicNoticeNum = f_DB_GetNotice( MAX_NOTICE_NUM, g_lstPublicNotice, 0 );
DebugPrint( "Public notice num : %d", g_nPublicNoticeNum );
}
void GetClientUpdateVersion()
{
if( !g_pSemaClientCheck || g_pSemaClientCheck->ActP() ){
return;
}
int nOldTypeNum = g_nClientTypeNum;
g_nClientTypeNum = f_DB_GetClientTypeNumber();
TCLIENTVERSION * pClients = NULL;
if( g_nClientTypeNum>0 ){ //有可用客户端
pClients = new TCLIENTVERSION[g_nClientTypeNum];
if( f_DB_GetClientVersion( pClients, g_nClientTypeNum )<0 ){ //获取客户端信息
delete[] pClients;
pClients = NULL;
}
}
bool bChange = true;
if( g_nClientTypeNum<0 ){
DebugPrint( "获取最新客户端类型数失败!" );
g_nClientTypeNum = nOldTypeNum; //不改变原客户端信息
bChange = false;
}
else if(g_nClientTypeNum>0 && !pClients){
DebugPrint( "获取最新客户端版本信息失败!" );
g_nClientTypeNum = nOldTypeNum; //不改变原客户端信息
bChange = false;
}
else if( g_nClientTypeNum==nOldTypeNum ){ //数量相同则比较是否有改变
bChange = false;
for( int i=0; i<g_nClientTypeNum; i++ ){
TCLIENTVERSION* pOldVersion = &(g_pVersionClient[i]);
TCLIENTVERSION* pNewVersion = &(pClients[i]);
if(memcmp(pOldVersion, pNewVersion, sizeof(TCLIENTVERSION))){
bChange = true;
break;
}
}
}
if(bChange){ //有变化
if(g_pVersionClient) //清理原内存
delete[] g_pVersionClient;
g_pVersionClient = pClients;
for( int i=0; i<g_nClientTypeNum; i++ ){ //打印信息
TCLIENTVERSION* pVersion = &(g_pVersionClient[i]);
DebugPrint( "软件内部编号: %d\n\t最新客户端版本: %d.%d.%d.%04d\n\t发布时间: %d-%d-%d",
pVersion->iClientType,
pVersion->swInfo.version.majorVersion, pVersion->swInfo.version.minorVersion,
pVersion->swInfo.version.modifyVersion, pVersion->swInfo.version.buildVersion,
pVersion->swInfo.tIssueDate>>16, (pVersion->swInfo.tIssueDate&0xFF00)>>8, (pVersion->swInfo.tIssueDate&0xFF));
}
}
else if(pClients){ //无变化清理内存
delete[] pClients;
pClients = NULL;
}
g_pSemaClientCheck->ActV();
}
bool ServiceInit()
{
g_pSemaService = new CSema(NULL, 0);
g_pSemaClientCheck = new CSema(NULL, 1);
g_pSemaTimer = new CSema(NULL, 0);
CreateLog();
//DebugPrint("DebugModuleInitialize success!\n");
//载入数据库访问模块
if( !LoadDB() ){
return FALSE;
}
f_DB_GetPath( g_strStyleFileDir, g_strWebFileDir, g_strMusicFileDir );
DebugPrint( "Style_dir: %s\n\tWeb_dir: %s\n\tMusic_dir: %s", g_strStyleFileDir, g_strWebFileDir, g_strMusicFileDir );
if( strlen(g_strMusicFileDir)>0 ){
char* pos = strstr( g_strMusicFileDir, "File" )+4;
if( pos[0]!='/' && pos[0]!='\\' ){
int num;
sscanf( pos, "%d", &num );
sprintf( g_strMusicLocation, "%d", num );
}
}
/////////////////////////////////////////////////////////////
//修改风格信息专用
if( g_iChkStyle>0 ){
// UpdateStyleInfo();
// ModifyStyleDesc();
return FALSE;
}
/////////////////////////////////////////////////////////////
GetClientUpdateVersion();
memset( g_aStyleRecomList, 0, sizeof(int)*(MAX_STYLE_NUM+1) );
GetStyleRecomList();
ReadConfigParams();
GetCommonQnAList();
GetPublicNoticeList();
//创建数据接收
g_pDataBuffers = new CDataBufferManager;
//创建消息响应管理
g_pResponses = new CResponseManager;
//生成UDP消息接收线程
CUDPSocket * pSocket = new CUDPSocket( LISTEN_PORT );
if( pSocket && pSocket->IsOpen() ){
g_pMessageReceiveThread = new CUDPMessageReceiveThread( 3000, pSocket );
g_pMessageReceiveThread->Resume();
//生成消息处理线程池
for( int i=0; i<20; i++ ){
CMessageHandleThread* pThread = new CMessageHandleThread( 3000, pSocket );
g_lstMessageHandleThreads.push_back( pThread );
}
}
//生成epoll线程
g_pEpollThread = new EpollThread();
g_pEpollThread->Resume();
printf("Composer Service is running...\n");
return true;
}
void ServiceDeInit()
{
printf("Composer Service is stopping...\n");
// if( g_hEvClientCheck ){
// CloseHandle( g_hEvClientCheck );
// }
if( g_pSemaClientCheck ){
delete g_pSemaClientCheck;
g_pSemaClientCheck = NULL;
}
if( g_pSemaTimer ){
delete g_pSemaTimer;
g_pSemaTimer = NULL;
}
if( g_pVersionClient ){
delete[] g_pVersionClient;
g_pVersionClient = NULL;
}
if( g_pMessageReceiveThread ){
g_pMessageReceiveThread->Terminate();
delete g_pMessageReceiveThread;
g_pMessageReceiveThread = NULL;
}
MHTHREADLIST::iterator iMT = g_lstMessageHandleThreads.begin();
while( iMT!=g_lstMessageHandleThreads.end() ){
(*iMT)->Terminate();
// (*iMT)->Resume();
delete (*iMT);
iMT = g_lstMessageHandleThreads.erase( iMT );
}
if( g_pEpollThread ){
g_pEpollThread->Terminate();
}
FreeDB();
if( g_pDataBuffers ){
delete g_pDataBuffers;
g_pDataBuffers = NULL;
}
if( g_pResponses ){
delete g_pResponses;
g_pResponses = NULL;
}
if( g_pEpollThread ){
delete g_pEpollThread;
g_pEpollThread = NULL;
}
DebugModuleClose();
printf( "System unloaded!\n" );
if(g_pSemaService)
g_pSemaService->ActV();
printf("Composer Service stopped.\n");
}
// void CheckProCount()
// {
// //////////////////////////////////////////////////////
// // 统计 PC pro 函数
// #include "MessageHandle.h"
// int n826(0), nOth(0);
// GetProCount(n826, nOth);
// DebugPrint("PC pro使用人数 826 : other = %d : %d", n826, nOth);
// //////////////////////////////////////////////////////
// }
void* OneDaySchedule(void* arg)
{
// CheckProCount();
CreateLog();
GetStyleRecomList();
GetCommonQnAList();
CheckMemoryUsage();
DebugPrint( "OneDaySchedule exit." );
return NULL;
}
int SetTimer(int sec)
{
itimerval value;
value.it_value.tv_sec = sec;
value.it_value.tv_usec = 0;
value.it_interval = value.it_value;
return setitimer(ITIMER_REAL, &value, NULL);
}
int GetTimeCount()
{
time_t t;
struct tm *tm;
time(&t);
tm = localtime(&t);
return tm->tm_hour * 60 * 60 + tm->tm_min * 60 + tm->tm_sec;
}
CServiceThread::CServiceThread():CThread(3000)
{
// getcwd(g_strServiceDir, 256);
if(readlink("/proc/self/exe", g_strServiceDir, 256)>0){
char* p = strrchr(g_strServiceDir,'/');
*p = 0;
}
}
void CServiceThread::Terminate()
{
CThread::Terminate();
if( g_pSemaTimer )
g_pSemaTimer->ActV();
}
void CServiceThread::Main()
{
DWORD timeCount = 0;
if( ServiceInit() ){
timeCount = GetTimeCount();
/* 设置信号的处理方式 */
signal(SIGALRM, SignalHandler);
signal(SIGTERM, SignalHandler);
signal(SIGINT, SignalHandler);
signal(SIGUSR1, SignalHandler);
/* 以系统真实的时间来计算,将送出SIGALRM信号 */
if (SetTimer(1) < 0){
/* 函数调用返回错误 */
DebugPrint("Setitimer Failed : %s", strerror(errno));
Terminate();
}
}
while(!m_bExit){
g_pSemaTimer->ActP();
// if( g_pIOCmpltThread ){
// g_pIOCmpltThread->OnTimer();
// }
if( g_pDataBuffers ){
g_pDataBuffers->OnTimer();
}
if( g_pResponses ){
g_pResponses->OnTimer();
}
if( ++timeCount>=86400 ){ //00:00:00
// if( ++timeCount>=15 ){ //test 10 minutes
// timeCount = 0; //test
timeCount = GetTimeCount();
if( timeCount<3600 ){
#ifdef _WIN32
CreateThread( 0, 0, (LPTHREAD_START_ROUTINE)OnTimerFunc, 0, 0, 0 );
#else
pthread_t tid;
pthread_attr_t attr;
pthread_attr_init (&attr);
pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
pthread_create( &tid, &attr, OneDaySchedule, NULL);
pthread_attr_destroy (&attr);
#endif
}
}
if( ( timeCount & 0x1FF )==0 ){ //0x1FF 512s~9m 定时清除VIP登录记录(10分钟内最多3个设备同时登录)
f_DB_CleanVipLog();
}
if( timeCount>0 && ( timeCount & 0xFFF )==0 //0xFFF 4095s~68m~1h 获取测试版本信息等
&& timeCount < 86000 ){ //23:53:35秒的检测跳过
ReadConfigParams();
GetClientUpdateVersion();
GetPublicNoticeList();
}
// if( ( timeCount & 0x1FFF )==0 ){ //0x1FFF 8191s~136m~2h 获取发布版本信息
// GetClientUpdateVersion();
// GetPublicNoticeList();
// }
}
SetTimer(0);
// CheckProCount();
ServiceDeInit();
DebugPrint("Service main thread exited.");
}