//#include "stdafx.h" #include "SpBase.h" #include "SpHelper.h" #include "CustMngrAuth_UserErrorCode.h" #include "CustMngrAuthFSM.h" #include #include #include #include #include #include #include #include #include #include #include "path.h" using namespace std; #define _ATL_NO_AUTOMATIC_NAMESPACE //#include const int UPDATEINTERNAL = 10*60*1000; //query data from branch server internal, 10min const int CONNECTINTERNAL = 30*1000; //connect branch server internal, 30s const int FINGERNUM = 8; //suuport max register finger num class CCustMngrAuthEntity; //Init void CCustMngrAuthFSM::s0_on_entry() { LOG_FUNCTION(); FSMEvent *pEvt = new FSMEvent(USER_EVT_INIT); PostEventFIFO(pEvt); } void CCustMngrAuthFSM::s0_on_exit() { LOG_FUNCTION(); } unsigned int CCustMngrAuthFSM::s0_on_event(FSMEvent* pEvt) { LOG_FUNCTION(); Dbg("s0 evt %d", pEvt->iEvt); switch (pEvt->iEvt) { case USER_EVT_INIT: { InitTask* task = new InitTask(this); GetEntityBase()->GetFunction()->PostThreadPoolTask(task); pEvt->SetHandled(); return 0; } break; default: break; } return 0; } //Initializing void CCustMngrAuthFSM::s1_on_entry() { LOG_FUNCTION(); } void CCustMngrAuthFSM::s1_on_exit() { LOG_FUNCTION(); } unsigned int CCustMngrAuthFSM::s1_on_event(FSMEvent* pEvt) { LOG_FUNCTION(); Dbg("s1 evt %d", pEvt->iEvt); switch (pEvt->iEvt) { case USER_EVT_INIT_FINISHED: pEvt->SetHandled(); return pEvt->param1; default: break; } return 0; } //Idle void CCustMngrAuthFSM::s2_on_entry() { LOG_FUNCTION(); } void CCustMngrAuthFSM::s2_on_exit() { LOG_FUNCTION(); } unsigned int CCustMngrAuthFSM::s2_on_event(FSMEvent* pEvt) { Dbg("s2 evt(%d)", pEvt->iEvt); int ret = 0; switch (pEvt->iEvt) { case USER_EVT_AUTHORIZE_START: { pEvt->SetHandled(); Dbg("start to authorize"); AuthorizeStartEvent *ase = dynamic_cast(pEvt); if (ase->ctx->Req.TimeLimit <= 0) { LOG_TRACE("ERROR: receive timelimit lessequal than zero. ctx->Answer(error_Param)"); AuthorizeFinishedEvent *e = new AuthorizeFinishedEvent(); e->ctx = ase->ctx; e->param1 = Error_Param; this->PostEventFIFO(e); break; } m_TimeLimit = (ase->ctx->Req.TimeLimit - 3) * 1000; //状态机流程会耗一些时间,这里要比前端传过来的时间小一些,及时返回给前端 ErrorCodeEnum eErr; m_bCancelAuthorize = false; //打开USB eErr = SwitchUSB(true); if (eErr != Error_Succeed) Dbg("open usb failed with eErr(0x%x)", eErr); else{ Dbg("open usb successfully."); m_ctx = ase->ctx; } //起指纹匹配线程 MatchFingerPrintTask *mTask = new MatchFingerPrintTask(this); mTask->ctx = ase->ctx; GetEntityBase()->GetFunction()->PostThreadPoolTask(mTask); } break; case USER_EVT_COLLECTFINGERPRINT_START: { CollectFingerPrintStartEvent *cfpe = dynamic_cast(pEvt); CollectFingerPrintTask *ftask = new CollectFingerPrintTask(this); ftask->ctx = cfpe->ctx; GetEntityBase()->GetFunction()->PostThreadPoolTask(ftask); Dbg("collect_finger_print task posted"); pEvt->SetHandled(); } break; case USER_EVT_SAVEFINGERPRINT_START: { pEvt->SetHandled(); SaveFingerPrintStartEvent *sfpe = dynamic_cast(pEvt); SaveFingerPrintTask *sTask = new SaveFingerPrintTask(this); sTask->ctx = sfpe->ctx; GetEntityBase()->GetFunction()->PostThreadPoolTask(sTask); Dbg("save_finger_print task posted"); } break; case USER_EVT_CHECKUKEY: { pEvt->SetHandled(); SwitchUSB(true); } break; default: break; } return 0; } void CCustMngrAuthFSM::s3_on_entry() { LOG_FUNCTION(); ScheduleTimer(1, m_TimeLimit); Dbg("Timer Set %dms", m_TimeLimit); } void CCustMngrAuthFSM::s3_on_exit() { LOG_FUNCTION(); CancelTimer(1); Dbg("Timer Canceled"); } unsigned int CCustMngrAuthFSM::s3_on_event(FSMEvent* pEvt) { Dbg("s3 evt %d, %d", pEvt->iEvt, pEvt->param1); switch (pEvt->iEvt) { case USER_EVT_HOLDON: { HoldOnEvent *hoe = dynamic_cast(pEvt); Dbg(" Cancel old timer(1) and rescheduling timer(1)"); CancelTimer(1); Dbg("Timer1 canceled"); if (hoe->ctx == NULL) Dbg("HoldOnEvent->ctx is NULL"); Dbg("HoldOn with MoreTime: %d second", hoe->ctx->Req.MoreTime); int moreTime = hoe->ctx->Req.MoreTime * 1000; Dbg("Adding more time: %d", moreTime); ScheduleTimer(1, (moreTime > 0) ? moreTime : m_TimeLimit); pEvt->SetHandled(); } break; case EVT_TIMER: { Dbg("Hit Timer"); pEvt->SetHandled(); m_bAuthorizeTimeout = true; m_bCancelAuthorize = true; CancelAuthorize(); //SwitchUSB(false); } break; case USER_EVT_AUTHORIZE_FINISHED: { pEvt->SetHandled(); ErrorCodeEnum eErr; AuthorizeFinishedEvent *afe = dynamic_cast(pEvt); Dbg("Checking m_authCtx and answer ctx"); if(m_csMachineType.Compare("RVC.PAD", true)) { //非PAD才去关闭U口 SwitchUSB(false); } if (afe->param1 == 0) { Dbg("authorize finished with param1 as 0"); if (m_authCtx.eAuthByWhich == AuthByUkey) { Dbg("m_authCtx.eAuthByWhich == AuthByUkey"); if (m_pFingerPrint != NULL && !m_pFingerPrint->QuerySessionClosed()) { Dbg("Invoke cancel match."); m_pFingerPrint->CancelMatch(); } afe->ctx->Ans.WayofAuth = AuthByUkey; afe->ctx->Ans.UkeyID = m_authCtx.UkeyID; afe->ctx->Answer(Error_Succeed); } else if (m_authCtx.eAuthByWhich == AuthByFngPrnt) { Dbg("m_authCtx.eAuthByWhich == AuthByFngPrnt"); afe->ctx->Ans.WayofAuth = AuthByFngPrnt; afe->ctx->Ans.CustomerID = m_authCtx.CustomerID; afe->ctx->Answer(Error_Succeed); } } else { Dbg("authorize finished with param1 as %d", afe->param1); afe->ctx->Answer((ErrorCodeEnum)afe->param1); } if (m_pFingerPrint != NULL && !m_pFingerPrint->QuerySessionClosed()) { m_bCancelAuthorize = true; //m_pFingerPrint->CancelMatch(); m_pFingerPrint->GetFunction()->CloseSession(); m_pFingerPrint->SafeDelete(); m_pFingerPrint=NULL; Dbg("M_pFingerPrint disconnected."); } m_authCtx.eAuthByWhich = AuthByNone; m_authCtx.CustomerID = ""; m_authCtx.UkeyID = ""; m_ctx = NULL; } break; case USER_EVT_AUTHORIZE_CANCEL: { pEvt->SetHandled(); m_bCancelAuthorize = true; CancelAuthorize(); } break; default: break; } return 0; } void CCustMngrAuthFSM::s4_on_entry() { LOG_FUNCTION(); } void CCustMngrAuthFSM::s4_on_exit() { LOG_FUNCTION(); } unsigned int CCustMngrAuthFSM::s4_on_event(FSMEvent* pEvt) { Dbg("s4 evt %d, %d", pEvt->iEvt, pEvt->param1); int ret = 0; switch (pEvt->iEvt) { case USER_EVT_COLLECTFINGERPRINT_FINISHED: pEvt->SetHandled(); break; case USER_EVT_COLLECTFINGERPRINT_CANCEL: { pEvt->SetHandled(); if (m_pFingerPrint != NULL && !m_pFingerPrint->QuerySessionClosed()) m_pFingerPrint->CancelRegister(); } break; case USER_EVT_SAVEFINGERPRINT_FINISHED: pEvt->SetHandled(); break; case USER_EVT_CHECKUKEY_FINISHED: { pEvt->SetHandled(); if (m_csMachineType.Compare("RVC.PAD", true)) { SwitchUSB(false); } } break; default: break; } return 0; } void CCustMngrAuthFSM::s5_on_entry() { LOG_FUNCTION(); } void CCustMngrAuthFSM::s5_on_exit() { LOG_FUNCTION(); } unsigned int CCustMngrAuthFSM::s5_on_event(FSMEvent* pEvt) { Dbg("s5 evt %d, %d", pEvt->iEvt, pEvt->param1); return 0; } ErrorCodeEnum CCustMngrAuthFSM::OnInit() { LOG_FUNCTION(); m_authCtx.eAuthByWhich = AuthByNone; CSystemStaticInfo staticInfo; m_pEntity->GetFunction()->GetSystemStaticInfo(staticInfo); m_TerminalID = staticInfo.strTerminalID; m_csMachineType = staticInfo.strMachineType; return Error_Succeed; } ErrorCodeEnum CCustMngrAuthFSM::OnExit() { LOG_FUNCTION(); FSMImpl::OnExit(); return Error_Succeed; } int CCustMngrAuthFSM::Initial() { STR_FINGERINFO = "FingerInfo"; ErrorCodeEnum eErr = GetEntityBase()->GetFunction()->GetPath("RunInfo", m_runInfoPath); if(eErr != Error_Succeed){ Dbg("get runinfo path failed."); LogError(Severity_High, Error_DevLoadFileFailed, LOG_ERR_CUSTMNGRAUTH_GET_RUNINFO_PATH_FAILED_Init, "get runinfo path failed while init"); return 1; } FeatureUpdateTask *pTask = new FeatureUpdateTask(this); GetEntityBase()->GetFunction()->PostThreadPoolTask(pTask); return 0; } string CCustMngrAuthFSM::ClearStringSpaceHeadTail(string& line) { if(line.empty()){ return line; } line.erase(0, line.find_first_not_of(" ")); line.erase(line.find_last_not_of(" ") + 1); return line; } bool CCustMngrAuthFSM::ReadDataIntoMemory(bool& bHasData) { LOG_FUNCTION(); CSmartPointer spConfig; ErrorCodeEnum eErr; CSimpleStringA strPath; CSimpleStringA runInfoFile; runInfoFile = CSimpleStringA::Format("%s" SPLIT_SLASH_STR "runcfg" SPLIT_SLASH_STR "CustMngrAuth.ini" , (const char*)m_runInfoPath); ifstream inFile(runInfoFile); string line; int customerNum = 0; Dbg("read data timer start..."); SYSTEMTIME urlStartTime, urlEndTime; GetLocalTime(&urlStartTime); DWORD dwStart = GetTickCount(); while(getline(inFile, line)){ if(line.length() <= 0){ continue; } string tempLine = ClearStringSpaceHeadTail(line); if(!tempLine.compare("[UpdateTime]") || string::npos != tempLine.find("UpdateTime") || !tempLine.compare("[LatestTime]") || string::npos != tempLine.find("LatestTime") || !tempLine.compare("[FingerInfo]") || !tempLine.compare("[FaceInfo]") || string::npos != tempLine.find("FaceInfo1") || string::npos != tempLine.find("FaceInfo2")){ continue; } string::size_type pos = tempLine.find("="); if(pos != 16){ continue; } string keys = tempLine.substr(0, pos); string values = tempLine.substr(pos+1); Json::Reader reader; Json::Value root; if (reader.parse((const char*)values.c_str(), root)){ customerNum++; FeatureData *fd = new FeatureData(); fd->FingerIDArray.Init(FINGERNUM); fd->FingerIDLenArray.Init(FINGERNUM); for (int i = 0; i < FINGERNUM; ++i){ char index[20]; _snprintf_s(index, 10, "FingerID%d", i+1); fd->FingerIDArray[i] = root.isMember(index) ? CSimpleStringA(root[index].asCString()) : ""; fd->FingerIDLenArray[i] = root.isMember(index) ? fd->FingerIDArray[i].GetLength() : 0; } //首次读取到内存,m_featureData为空,不用考虑其中已存在该key值 m_featureData[CSimpleStringA(keys.c_str())] = fd; //Dbg("CustomerID=%s success.", keys.c_str()); }else{ Dbg("Error: parse jsonFingerInfo failed."); LogWarn(Severity_High, Error_Unexpect, LOG_ERR_CUSTMNGRAUTH_AUTHORIZATION_READFEAT_FAILED, "Read fingerprint feature json failed."); return false; } } Dbg("Total CustomerNum:%d in local file.", customerNum); DWORD dwEnd = GetTickCount(); GetLocalTime(&urlEndTime); auto urlDuration = getDuration(urlStartTime, urlEndTime); LogWarn(Severity_High, Error_Debug, LOG_ERR_CUSTMNGRAUTH_READ_INTO_MEMORY_TIME, generateAlarmJson("CustMngrAuth", formatTime(urlStartTime).c_str(), urlDuration).GetData()); Dbg("read data timer end..."); Dbg("cost time:%dms", (dwEnd - dwStart)) ; bHasData = true; return true; } void CCustMngrAuthFSM::TransDataFromServer(CAutoArray &dataArray, CSimpleStringA latestTime, bool& bResumeTrans, bool bIsFirstTimeQueryData) { LOG_FUNCTION(); int transTime = 0; char currAgent[16]=""; char branchID[16]=""; while(bResumeTrans){ transTime++; if (bIsFirstTimeQueryData) m_pConnection->SendFeatReq(currAgent, branchID); else m_pConnection->SendFeatReq(currAgent, branchID, (const char*)latestTime); ResetEvent(m_pConnection->hPkgAnswer); DWORD dw = WaitForSingleObject(m_pConnection->hPkgAnswer, 20000); //10->20 20200430@liuwentao switch(dw) { case WAIT_FAILED: Dbg("WAIT_FAILED!"); break; case WAIT_TIMEOUT: Dbg("WAIT_TIMEOUT"); case WAIT_OBJECT_0: Dbg("WAIT_OBJECT_0"); break; } ResetEvent(m_pConnection->hPkgAnswer); if (m_pConnection->m_reply == NULL){ Dbg("m_reply still null after hPkgAnswer handled"); break; }else{ if (m_pConnection->getErrMsg){ Dbg("get error message, check dbg log"); break; } if (m_pConnection->m_reply->ResultCode == 2){ Dbg("remote server uninitialized yet, unable to excute query"); break; }else{ if (m_pConnection->m_reply->ResultCode == 0){ Dbg("All package downloaded from branch server."); bResumeTrans = false; } memcpy(currAgent, m_pConnection->m_reply->CurrentAgent, 16); memcpy(branchID, m_pConnection->m_reply->BranchID, 16); CSimpleStringA jbuf(m_pConnection->m_reply->Data, m_pConnection->m_jsonLen); dataArray.Append(&jbuf,0,1); } } } } bool CCustMngrAuthFSM::BackupFile(CSimpleStringA srcFile, CSimpleStringA dstFile) { bool backupResult = true; fstream fileExist; ifstream inFile; ofstream outFile; fileExist.open((const char*)srcFile, ios::in); if(!fileExist){ fileExist.close(); return true; } fileExist.close(); inFile.open((const char*)srcFile); if (inFile.fail()){ Dbg("Open CustMngrAuth.ini failed"); inFile.close(); return false; } outFile.open((const char*)dstFile); if (outFile.fail()){ Dbg("Open CustMngrAuth_bak.ini failed."); backupResult = false; }else{ outFile << inFile.rdbuf(); } inFile.close(); outFile.close(); return backupResult; } void CCustMngrAuthFSM::FeatureUpdate() { LOG_FUNCTION(); //when start entity, read data into memory bool bHasData = false; bool bReadResult = ReadDataIntoMemory(bHasData); if (bReadResult && bHasData) { Dbg("Read feature data into memory success."); }else if (bReadResult && !bHasData) { Dbg("Has no data in local file."); }else{ Dbg("Read feature data into memory failed, wait next read."); } int tWait = UPDATEINTERNAL; int connectFailedTimes = 0; ErrorCodeEnum eErr; while(1){ CSmartPointer spConfig; CAutoArray transArray; m_pConnection = new FeatureUpdateConn(m_pEntity, this); //connect branch server if (m_pConnection->ConnectFromCentralSetting() && m_pConnection->IsConnectionOK()){ connectFailedTimes = 0; tWait = UPDATEINTERNAL; bool resumeTrans = true; bool isFirstTimeQueryData = false; EnterCriticalSection(&m_cs);//临时锁一下运行时,防止在写入 eErr = GetEntityBase()->GetFunction()->OpenConfig(Config_Run, spConfig); if (eErr != Error_Succeed){ Dbg("Open runcfg file failed before query data."); LogError(Severity_High, Error_Unexpect, LOG_ERR_CUSTMNGRAUTH_OPEN_RUNINFO_FAILED_UPDATE, "open runcfg failed before query data."); LeaveCriticalSection(&m_cs); goto Err; } CSimpleStringA latestTime(""), updateTime("");//latestTime表示最上一次传来的最新时间,updateTime表示更新日期(是否要做全量清除更新) spConfig->ReadConfigValue("LatestTime", "LatestTime", latestTime); spConfig->ReadConfigValue("UpdateTime", "UpdateTime", updateTime); LeaveCriticalSection(&m_cs); //query current time CSimpleStringA newTime = GetCurrentDate(); //当前日期大于文件中日期时,需要做全量更新 if (updateTime.GetLength() <= 0 || (updateTime.GetLength() > 0 && CompareTime(newTime, updateTime) > 0) || latestTime.GetLength() <= 0){ isFirstTimeQueryData = true; } //多次续传从分行服务获取数据(增量更新时,大于latestTime的才传下来) TransDataFromServer(transArray, latestTime, resumeTrans, isFirstTimeQueryData); if(resumeTrans){ Dbg("ERROR: The last update of feature ended with resumetrans as true, might be timeout or some errors happened"); //存在有时因分行服务升级导致连接断开,更新数据失败,暂时对业务无影响 //LogError(Severity_High, Error_Unexpect, LOG_ERR_CUSTMNGRAUTH_FEATUPDATE_DOWNLOAD_FAILED, "Transmission of fingerprint feature failed."); goto Err; } if (transArray.GetCount() <= 0){ Dbg("query no data from branchServer.(exact no data or the sql was deleted)"); //LogWarn(Severity_High, Error_Unexpect, LOG_ERR_CUSTMNGRAUTH_FEATUPDATE_DOWNLOAD_FAILED, "query no data from branchServer."); goto Err; } //续传成功结束,解析jbuf数组并写入本地 Dbg("Transmission finished successfully. Ready to decode json data and write into runcfg"); //写入文件前,先判断是否已存在CustMngrAuth.ini文件,若不存在则直接写入,若存在,则先备份该文件 CSimpleStringA srcFile(true); CSimpleStringA backupFile(true); srcFile = CSimpleStringA::Format("%s" SPLIT_SLASH_STR "runcfg" SPLIT_SLASH_STR "CustMngrAuth.ini" , (const char*)m_runInfoPath); backupFile = CSimpleStringA::Format("%s" SPLIT_SLASH_STR "runcfg" SPLIT_SLASH_STR "CustMngrAuth_bak.ini" , (const char*)m_runInfoPath); EnterCriticalSection(&m_cs); if(!BackupFile(srcFile, backupFile)){ Dbg("Backup runinfo file failed."); } if (isFirstTimeQueryData){ //首次更新,需清除数据,全量写入,并更新时间 ofstream fileOut((const char*)srcFile, ios::trunc); fileOut.close(); } eErr = GetEntityBase()->GetFunction()->OpenConfig(Config_Run, spConfig); if (eErr != Error_Succeed){ RecoverFile(srcFile, backupFile);//有失败情况,恢复原文件 //LogError(Severity_High, Error_DevLoadFileFailed, LOG_ERR_CUSTMNGRAUTH_OPEN_RUNINFO__FAILED, "Open runinfo file failed."); Dbg("ERROR: Open runcfg failed with %d", eErr); LeaveCriticalSection(&m_cs); goto Err; } spConfig->WriteConfigValue("UpdateTime", "UpdateTime", (const char*)newTime); if (isFirstTimeQueryData){ //首次全量更新或存量无LatestTime字段 spConfig->WriteConfigValue("LatestTime", "LatestTime", ""); } map tempFeature;//如果是全量更新,需要更新后全量传给m_featureData CSimpleStringA maxUpdateTime = latestTime; for(int transTime = 0; transTime < transArray.GetCount(); ++transTime){ Json::Value root; Json::Reader reader; Json::FastWriter writer; CSimpleStringA transBuffer = transArray[transTime];//一次传输受大小限制,只能有3~4条 //Dbg("transBuffer=%s", transBuffer.GetData()); if (reader.parse((const char*)transBuffer, root)){ for (int i = 0; i < (int)root.size(); ++i){ Json::Value jsonFingerInfo; FeatureData *fd = new FeatureData(); fd->FingerIDArray.Init(FINGERNUM); fd->FingerIDLenArray.Init(FINGERNUM); for(int fingerIndex = 0; fingerIndex < FINGERNUM; ++fingerIndex){ char FingerID[20];//运行时文件是"FingerID" char fingerId[20];//分行服务是"fingerId" 二者不一致,历史遗留 _snprintf_s(FingerID, 10, "FingerID%d", fingerIndex+1); _snprintf_s(fingerId, 10, "fingerId%d", fingerIndex+1); jsonFingerInfo[FingerID] = root[i][fingerId].asCString(); fd->FingerIDArray[fingerIndex] = CSimpleStringA(root[i][fingerId].asCString()); fd->FingerIDLenArray[fingerIndex] = fd->FingerIDArray[fingerIndex].GetLength(); } //插入临时map if(tempFeature.find(CSimpleStringA(root[i]["customerID"].asCString())) == tempFeature.end()){//不存在,直接插入 tempFeature[CSimpleStringA(root[i]["customerID"].asCString())] = fd; }else{//已存在,需要释放原有内存 auto tempFD = tempFeature[CSimpleStringA(root[i]["customerID"].asCString())]; tempFeature[CSimpleStringA(root[i]["customerID"].asCString())] = fd; if(tempFD){ delete tempFD; tempFD = NULL; } } CSimpleStringA tempMaxUpdateTime = CSimpleStringA(root[i]["updateTime"].asCString()); maxUpdateTime = GetMaxTime(maxUpdateTime, tempMaxUpdateTime); int fingerDataState = root[i]["state"].asCString()[0] - '0'; if (fingerDataState == 0){ CSimpleStringA jsonFingerStr(writer.write(jsonFingerInfo).c_str()); int jlen = jsonFingerStr.GetLength()-1; char *jstr = new char[jlen+1]; memcpy(jstr, jsonFingerStr.GetData(), jlen); jstr[jlen]= '\0'; //不做这步处理的话runcfg里faceinfo节不同customerID间没有换行,fingerinfo节本来有,但以防万一也做同样处理。 eErr = spConfig->WriteConfigValue(STR_FINGERINFO, root[i]["customerID"].asCString(), jstr); delete []jstr; if (eErr != Error_Succeed){ //如果写入失败,则将原文件恢复 RecoverFile(srcFile, backupFile); LeaveCriticalSection(&m_cs); goto Err; } }else if (fingerDataState == 2){ Dbg("state(2): customer %s is currently unavailable.", root[i]["customerID"].asCString()); spConfig->WriteConfigValue(STR_FINGERINFO, root[i]["customerID"].asCString(), ""); }else{ Dbg("ERROR: unexpectedly customer(%s)'s state is either 0 or 2", root[i]["customerID"].asCString()); } } }else{ Dbg("ERROR: fail to parse transArray[%d]!", transTime); //LogError(Severity_High, Error_Unexpect, LOG_ERR_CUSTMNGRAUTH_FEATUPDATE_WRITE_FAILED, "Failed to write fingerprint feature into runcfg."); LeaveCriticalSection(&m_cs); goto Err; } } //数据写完,将最新时间更新到本地 if (maxUpdateTime.GetLength() > 0){ spConfig->WriteConfigValue("LatestTime", "LatestTime", (const char*)maxUpdateTime); } Dbg("updateNum=%d", tempFeature.size()); //更新数据到内存 UpdateDataIntoMemory(tempFeature, isFirstTimeQueryData); LeaveCriticalSection(&m_cs); }else{ Dbg("ERROR: Fail to connect remote server! Try again in %d mm.", CONNECTINTERNAL); connectFailedTimes++; Dbg("connect time = %d", connectFailedTimes); if(connectFailedTimes >= 60){//如果一直连不上,则30分钟抛一次告警 LogWarn(Severity_High, Error_Unexpect, LOG_ERR_CUSTMNGRAUTH_FEATUPDATE_CONNECT_FAILED, "Connect branch server failed."); connectFailedTimes = 0; } tWait = CONNECTINTERNAL; } Err: if(m_pConnection){ m_pConnection->Close(); m_pConnection->DecRefCount(); m_pConnection = NULL; } Dbg("Feature-update processed, wait until next"); //等待tWait时间后,进行下一次请求更新 if (WaitForSingleObject(hStopUpdate, tWait) == WAIT_OBJECT_0) break; } } void CCustMngrAuthFSM::UpdateDataIntoMemory(map tempFeature, bool bIsFirstTimeQueryData) { //如果不是第一次更新,则只覆盖新增/修改数据 if(!bIsFirstTimeQueryData){ for(auto it = tempFeature.begin(); it != tempFeature.end(); ++it){ if(m_featureData.find(it->first) == m_featureData.end()){//没有这个key,直接插入 m_featureData[it->first] = it->second; }else{//已存在该key,释放旧有的内存 auto tempFD = m_featureData[it->first]; m_featureData[it->first] = it->second; if(tempFD != NULL){ delete tempFD; tempFD = NULL; } } } }else{//如果是全量更新,需要先将内存数据清理掉,内存中有可能存在已离职人员 DWORD dwStart = GetTickCount(); for(auto iter = m_featureData.begin(); iter != m_featureData.end();){ auto fd = iter->second; if(fd){ delete fd; fd = NULL; m_featureData.erase(iter++); } } m_featureData.insert(tempFeature.begin(), tempFeature.end()); DWORD dwEnd = GetTickCount(); Dbg("copy data to memory time:%dms", dwEnd - dwStart); } } ErrorCodeEnum CCustMngrAuthFSM::MatchFingerPrint(SpReqAnsContext::Pointer ctx, bool& bStopAuthorize) { //只有取消、超时、成功匹配、侦听到ukey插入触发这里的取消这些情况下才会终止授权,否则就算遇到异常退出本方法,也要继续等待直到超时或ukey或取消。 LOG_FUNCTION(); ErrorCodeEnum eErr; m_pFingerPrint = new FingerPrintService_ClientBase(m_pEntity); eErr = m_pFingerPrint->Connect(); if (eErr != Error_Succeed){ Dbg("ERROR: connect to fingerprint entity failed!"); m_pFingerPrint->SafeDelete(); m_pFingerPrint=NULL; return Error_Unexpect; //TODO::give one other errCode } EnterCriticalSection(&m_cs); //loop invoke match, only when have one match,stop;otherwise, continue loop FingerPrintService_Match_Req matchReq; FingerPrintService_Match_Ans matchAns; CAutoArray tempFeatureArray; //临时存放指纹数据,用于给入参赋值 CAutoArray tempFeatureLenArray; int totalCustomerID = m_featureData.size(); int totalTemplate = totalCustomerID * FINGERNUM; if (totalCustomerID <= 0){ Dbg("No FingerPrint data in local file or read local file failed."); LeaveCriticalSection(&m_cs); return Error_NoTarget; } tempFeatureArray.Init(totalTemplate); tempFeatureLenArray.Init(totalTemplate); vector fingerCount;//存放CustomerID及其对应指纹个数(非空指纹) Dbg("begin copy feature to reqParams"); int i = 0, j = 0; DWORD dwStart = GetTickCount(); int count = 0; //实际不为空的指纹模板总个数 for (auto it = m_featureData.begin(); it != m_featureData.end(); ++it){ int countPerCust = 0;//统计每个CustomerID不为空指纹个数 TemplateInfo ti; memset(&ti, 0, sizeof(ti)); ti.CustomerID = it->first; ti.TemplateNum = 0; for(int index = 0; index < FINGERNUM; ++index){// if(index >= it->second->FingerIDArray.GetCount()){//旧版本可能只有2个 break; } if(it->second->FingerIDArray[index].GetLength() <= 0){ continue; } tempFeatureArray[count] = it->second->FingerIDArray[index]; tempFeatureLenArray[count] = it->second->FingerIDLenArray[index]; ti.TemplateNum = ti.TemplateNum + 1; ++count; } if(ti.TemplateNum > 0){ fingerCount.push_back(ti); } } LeaveCriticalSection(&m_cs); Dbg("num of template not empty:%d", count); matchReq.templateNum = count; matchReq.templates.Init(count); matchReq.templateLen.Init(count); for(int i = 0; i < count; ++i){ matchReq.templates[i] = tempFeatureArray[i]; matchReq.templateLen[i] = tempFeatureLenArray[i]; } DWORD dwEnd = GetTickCount(); Dbg("copy data to match req, cost time:%dms", dwEnd - dwStart); Dbg("end copy feature to reqParams"); Dbg("templateNum: %d", matchReq.templateNum); while (true){ if (m_pFingerPrint == NULL || m_pFingerPrint->QuerySessionClosed()){ Dbg("m_pFingerPrint is NULL or connection closed."); return Error_Unexpect; } std::this_thread::sleep_for(std::chrono::milliseconds(100)); //Sleep(100);//如果指纹仪返回及时,这里可以考虑去掉 DWORD startMatch, endMatch; startMatch = GetTickCount(); Dbg("begin next invoke match."); eErr = m_pFingerPrint->Match(matchReq, matchAns, 20000); endMatch = GetTickCount(); Dbg("MatchTime:%d", endMatch - startMatch); if (m_bCancelAuthorize || eErr == Error_Cancel){ bStopAuthorize = true; Dbg("m_bCancelAuthorize=true or m_pFingerPrint->Match return Error_Cancel, closing authorization task and setting m_bCancelAuthorize=false"); m_bCancelAuthorize = false; if (m_bAuthorizeTimeout){ m_bAuthorizeTimeout = false; return Error_TimeOut; } return Error_Cancel; }else if (eErr == Error_Unexpect || eErr == Error_TimeOut){//调用指纹仪接口失败,但可以立即进行下一次授权 Dbg("#################### Invoke Match Error %d ######################", eErr); BroadcastGetFinger(2);//调用match出错 }else if (eErr == Error_Succeed){//指纹仪成功返回匹配结果数组 Dbg("#################### Match Result Received And Analyzing ######################"); int resTemplateNum = matchAns.result.GetCount(); if (resTemplateNum != count){ Dbg("Ans match result template num is not equale to the Req's "); continue; } int matchIndex = -1;//匹配的CustomerID对应的下标 int matchCount = 0;//匹配的CustomerID个数 int m = 0; int fingerNum = fingerCount[m].TemplateNum; for(int i = 0; i < resTemplateNum; i += fingerNum){ //单人有多指纹匹配不报错(可能多个指纹都用同一个手指注册的) //Dbg("i=%d", i); int oneCustMatchResult = 0; fingerNum = fingerCount[m].TemplateNum; for(int j = 0; j < fingerNum; ++j){ oneCustMatchResult += matchAns.result[i+j]; } //Dbg("oneCustMatcnResult=%d", oneCustMatchResult); if(oneCustMatchResult > 0){//同一个CustomerID的指纹如果有多个匹配,算作一个 matchCount++; matchIndex = m; } if(matchCount > 1){//有多个CustomerID的指纹都匹配上,则是多匹配 break; } m++; } int matchResult = matchCount;//0:no match; 1:just one match; 2: muti match if (m_bCancelAuthorize){ bStopAuthorize = true; Dbg("m_bCancelAuthorize=true, closing authorization task and setting m_bCancelAuthorize=false"); m_bCancelAuthorize = false; if (m_bAuthorizeTimeout){ m_bAuthorizeTimeout = false; return Error_TimeOut; }else return Error_Cancel; } //根据返回匹配结果数组,判断发送指纹授权失败提示广播还是授权结果广播 switch (matchResult) { case 0: { Dbg("MatchResult: 0| no match"); BroadcastGetFinger(0); } break; case 1: { Dbg("MatchResult: 1| one and only one match, authorize done."); Dbg("Match Finger(CustomerID=%s)", (const char*)fingerCount[matchIndex].CustomerID); m_authCtx.eAuthByWhich = AuthByFngPrnt; m_authCtx.CustomerID = fingerCount[matchIndex].CustomerID; bStopAuthorize = true; return Error_Succeed; } break; case 2: { Dbg("MatchResult: 2| two and more matches. be alerted"); BroadcastGetFinger(1); } break; default:break; } }else{//指纹仪match返回其他错误(eg:Error_NotInit,Error_Param),不再调用指纹仪实体的match Dbg("Invoke Match Error %d, Stopping FingerPrint-Authorization", eErr); return Error_Unexpect; } } } ErrorCodeEnum CCustMngrAuthFSM::WaitForUkey(ErrorCodeEnum eErr) { int status = (eErr == Error_NoTarget) ? 4: 3;//与朱毅约定,4表示本地无指纹数据,3表示指纹仪实体异常,前端给予提示 BroadcastGetFinger(status); while(1){ std::this_thread::sleep_for(std::chrono::milliseconds(300)); //Sleep(300); if (m_bCancelAuthorize){ m_bCancelAuthorize = false; if (m_bAuthorizeTimeout){ m_bAuthorizeTimeout = false; return Error_TimeOut; }else return Error_Cancel; } } } void CCustMngrAuthFSM::CancelAuthorize() { Dbg("Invoke m_pFingerPrint->CancelMatch()"); if (m_pFingerPrint != NULL && !m_pFingerPrint->QuerySessionClosed()) m_pFingerPrint->CancelMatch(); } void CCustMngrAuthFSM::BroadcastPressFinger(int times, bool bPressFinger) { if(bPressFinger){ PressFinger pfEvt;// pfEvt.FingerNo = 1;//maybe no use,control by @zhuyi pfEvt.Times = times; SpSendBroadcast(m_pEntity->GetFunction(), SP_MSG_OF(PressFinger), SP_MSG_SIG_OF(PressFinger), pfEvt); }else{ LiftFinger lfEvt; lfEvt.FingerNo = 1; lfEvt.Times = times; SpSendBroadcast(m_pEntity->GetFunction(), SP_MSG_OF(LiftFinger), SP_MSG_SIG_OF(LiftFinger), lfEvt); } } void CCustMngrAuthFSM::BroadcastGetFinger(int status) { GetFinger evt; evt.Status = status; SpSendBroadcast(GetEntityBase()->GetFunction(), SP_MSG_OF(GetFinger),SP_MSG_SIG_OF(GetFinger),evt); } ErrorCodeEnum CCustMngrAuthFSM::CollectFingerPrint(SpReqAnsContext::Pointer ctx, DWORD& dwUserErrCode) { LOG_FUNCTION(); ErrorCodeEnum eErr; m_pFingerPrint = new FingerPrintService_ClientBase(GetEntityBase()); eErr = m_pFingerPrint->Connect(); if (eErr!= Error_Succeed) { m_pFingerPrint->SafeDelete(); m_pFingerPrint = NULL; return Error_NoTarget; } //need to collect for 3 times const int NUM_COLLECT = 3; ctx->Ans.FingerImgs.Init(NUM_COLLECT); CAutoArray imgPaths; CSimpleStringA strPath; imgPaths.Init(NUM_COLLECT); m_pEntity->GetFunction()->GetPath("Dep", strPath); int getImgNum = 0; for(int i = 0; i < NUM_COLLECT; ++i){ if (i) { std::this_thread::sleep_for(std::chrono::milliseconds(2000)); //Sleep(2 * 1000);//internal for 2s between two times(actually finger entity cannot detect finger lift or not) } BroadcastPressFinger(i+1, true);//press finger FingerPrintService_GetImageAndFeature_Req gifReq; FingerPrintService_GetImageAndFeature_Ans gifAns; gifReq.times = i+1;//the num from 1 start , 1/2/3 if (m_pFingerPrint == NULL || m_pFingerPrint->QuerySessionClosed()){ Dbg("m_pFingerPrint is NULL or connection closed."); return Error_NoTarget; } eErr = m_pFingerPrint->GetImageAndFeature(gifReq, gifAns, 16000, dwUserErrCode);//fingerprint entity loop duration is 15s if (eErr == Error_Succeed){ getImgNum += 1; BroadcastPressFinger(i+1, false);//lift finger CBlob data; CSimpleStringA tempFullPath; tempFullPath = CSimpleStringA::Format("%s" SPLIT_SLASH_STR "%s" , (const char*)strPath, (const char*)gifAns.imageName); eErr = GetImgBlob(data, tempFullPath); if (eErr != Error_Succeed){ Dbg("Failed to load finger image."); break; } switch(i) { case 0: ctx->Ans.FingerImg1 = data; break; case 1: ctx->Ans.FingerImg2 = data; break; case 2: ctx->Ans.FingerImg3 = data; break; } ctx->Ans.FingerImgs[i] = data; imgPaths[i] = gifAns.imageName; } else { Dbg("failed to collect fingerprint %th times, also failed to generate template failed."); break; } //third times, get th template success if (i == (NUM_COLLECT-1)){ ctx->Ans.feature = gifAns.feature; } } //delete bmp files in dep for (int j = 0; j < getImgNum; ++j) { CSimpleStringA tempFullPath(true); tempFullPath = CSimpleStringA::Format("%s" SPLIT_SLASH_STR "%s" , (const char*)strPath, (const char*)imgPaths[j]); if(remove((const char*)tempFullPath) == 0) Dbg("finger image %s deleted!", (const char*)tempFullPath); else Dbg("fail to delete image %s!", (const char*)tempFullPath); } if (eErr == Error_Succeed){ Dbg("Register FingerPrint successfully."); return Error_Succeed; }else{ Dbg("Register FingerPrint failed!"); return Error_Unexpect; } } ErrorCodeEnum CCustMngrAuthFSM::SaveFingerPrint(SpReqAnsContext::Pointer ctx) { LOG_FUNCTION(); EnterCriticalSection(&m_cs); CSmartPointer spConfig; Json::FastWriter writer; ErrorCodeEnum eErr; eErr = GetEntityBase()->GetFunction()->OpenConfig(Config_Run, spConfig); if (eErr != Error_Succeed){ Dbg("ERROR: open config failed! eErr: %d", eErr); LogError(Severity_High, Error_DevLoadFileFailed, LOG_ERR_CUSTMNGRAUTH_OPEN_RUNINFO_FAILED_SAVEFINGERPRINT, "open runinfo file failed while save data to local."); LeaveCriticalSection(&m_cs); return Error_Unexpect; } Dbg("open Config_Run succeed, prepare to write feature data."); Json::Value fingerInfo; int fingerIDNum = ctx->Req.FingerIdList.GetCount(); FeatureData *fd = new FeatureData(); Dbg("FingerIDNum=%d", fingerIDNum); fd->FingerIDArray.Init(fingerIDNum); fd->FingerIDLenArray.Init(fingerIDNum); for (int i = 0; i < fingerIDNum; ++i){ char a[20]={0}; _snprintf_s(a, 10,"FingerID%d", ctx->Req.FingerIdList[i]); Dbg("writing %s",a); fingerInfo[a] = (const char*)ctx->Req.FPFeatureList[i]; fd->FingerIDArray[i] = ctx->Req.FPFeatureList[i]; fd->FingerIDLenArray[i] = fd->FingerIDArray[i].GetLength(); } if(m_featureData.find(ctx->Req.CustomerID) == m_featureData.end()){//不存在,直接插入 m_featureData[ctx->Req.CustomerID] = fd; }else{ auto tempFD = m_featureData[ctx->Req.CustomerID]; m_featureData[ctx->Req.CustomerID] = fd; if(tempFD){ delete tempFD; tempFD = NULL; } } Dbg("jsonvalue for fingerinfo created, writing config value......"); eErr = spConfig->WriteConfigValue(STR_FINGERINFO, (const char*)ctx->Req.CustomerID, writer.write(fingerInfo).c_str()); Dbg("spConfig->WriteConfigValue done"); if (eErr != Error_Succeed){ Dbg("write data into runinfo failed when commit."); LogError(Severity_High, Error_DevLoadFileFailed, LOG_ERR_CUSTMNGRAUTH_REGISTER_WRITE_RUNINFO_FAILED, "write data into runinfo failed when commit."); LeaveCriticalSection(&m_cs); return Error_Unexpect; } Dbg("write data into runinfo success when commit."); LeaveCriticalSection(&m_cs); return eErr; } ErrorCodeEnum CCustMngrAuthFSM::SwitchUSB(bool bOpen) { LOG_FUNCTION(); ErrorCodeEnum eErr; //connect devicecontrol and open usb Dbg("connecting DeviceControl"); m_pDeviceControl = new DeviceControlService_ClientBase(GetEntityBase()); if(m_pDeviceControl != NULL){ eErr = m_pDeviceControl->Connect(); if (eErr != Error_Succeed){ Dbg("m_pDeviceControl connect failed with eErr %x0x", eErr); }else{ if(bOpen) Dbg("Open USB"); else Dbg("Close USB"); DeviceControlService_USB_Req usbReq; DeviceControlService_USB_Ans usbAns; usbReq.open = bOpen;//open or close usb eErr = m_pDeviceControl->USB(usbReq, usbAns, 2000); if (eErr != Error_Succeed) Dbg("Open/Close usb failed."); else Dbg("Open/Close usb success."); m_pDeviceControl->GetFunction()->CloseSession(); } m_pDeviceControl->SafeDelete(); m_pDeviceControl = NULL; return eErr; }else{ Dbg("DeviceControl is null."); return Error_Unexpect; } } ErrorCodeEnum CCustMngrAuthFSM::GetImgBlob(CBlob &data, CSimpleStringA imgPath) { Dbg("########Openning imgpath: %s", (const char*)imgPath); ErrorCodeEnum eErr; FILE *fp = fopen(imgPath, "rb"); if (fp) { Dbg("fopen succeed."); fseek(fp, 0, SEEK_END); long flen = ftell(fp); fseek(fp, 0, SEEK_SET); data.Alloc(flen); fread(data.m_pData, 1, flen, fp); fclose(fp); eErr = Error_Succeed; }else{ Dbg("fopen %s failed!", (LPCSTR)imgPath); eErr = Error_IO; } return eErr; } int CCustMngrAuthFSM::CompareTime(CSimpleStringA time1, CSimpleStringA time2) { //这里只比较是否是同一天 if (time1.GetLength() > 0 && time2.GetLength() > 0) { int year1 = atoi((const char*)time1.SubString(0, 4)); int month1 = atoi((const char*)time1.SubString(4, 2)); int day1 = atoi((const char*)time1.SubString(6, 2)); int year2 = atoi((const char*)time2.SubString(0, 4)); int month2 = atoi((const char*)time2.SubString(4, 2)); int day2 = atoi((const char*)time2.SubString(6, 2)); int temp1 = year1 * 10000 + month1 * 100 + day1; int temp2 = year2 * 10000 + month2 * 100 + day2; if (temp1 > temp2) { return 1; } else if(temp1 < temp2) { return -1; } else { return 0; } } return 0; } int CCustMngrAuthFSM::RecoverFile(CSimpleStringA nowFileName, CSimpleStringA backupFileName) { ofstream fileOut((const char*)nowFileName, ios::trunc); ifstream fileIn((const char*)backupFileName); if (!(fileOut.fail() || fileIn.fail())) { fileOut << fileIn.rdbuf(); fileOut.close(); fileIn.close(); return 0; } fileOut.close(); fileIn.close(); return -1; } CSimpleStringA CCustMngrAuthFSM::GetCurrentDate() { time_t curTime = time(NULL); tm* p = localtime(&curTime); char cTime[100]; sprintf(cTime, "%d%02d%02d", p->tm_year+1900, p->tm_mon+1, p->tm_mday); CSimpleStringA curDate(cTime); return curDate; } CSimpleStringA CCustMngrAuthFSM::GetMaxTime(CSimpleStringA maxTime, CSimpleStringA tempTime) { if (tempTime.GetLength() > 0){ if (maxTime.GetLength() <= 0){ maxTime = tempTime; }else{ int compareResult = CompareUpdateTime((const char*)maxTime, (const char*)tempTime); if (compareResult == 0){ maxTime = tempTime; } } } return maxTime; } int CCustMngrAuthFSM::CompareUpdateTime(const char* time1, const char* time2) { int year1, month1, day1, hour1, minute1, second1; int year2, month2, day2, hour2, minute2, second2; sscanf(time1, "%d-%d-%d %d:%d:%d", &year1, &month1, &day1, &hour1, &minute1, &second1); sscanf(time2, "%d-%d-%d %d:%d:%d", &year2, &month2, &day2, &hour2, &minute2, &second2); int tm1 = year1 * 10000 + month1 * 100 + day1; int tm2 = year2 * 10000 + month2 * 100 + day2; if(tm1 != tm2) return (tm1 > tm2) ? 1 : 0; tm1 = hour1 * 3600 + minute1 * 60 + second1; tm2 = hour2 * 3600 + minute2 * 60 + second2; if(tm1 != tm2) return (tm1 > tm2) ? 1 : 0; return 2; } int CCustMngrAuthFSM::getDuration(SYSTEMTIME time1, SYSTEMTIME time2) { ULARGE_INTEGER fTime1;/*FILETIME*/ ULARGE_INTEGER fTime2;/*FILETIME*/ SystemTimeToFileTime(&time1, (FILETIME*)&fTime1); SystemTimeToFileTime(&time2, (FILETIME*)&fTime2); unsigned __int64 dft = fTime2.QuadPart - fTime1.QuadPart; return dft / 10000; } std::string CCustMngrAuthFSM::formatTime(SYSTEMTIME time) { char tBuf[1024] = ""; sprintf(tBuf, "%04u-%02u-%02u %02u:%02u:%02u:%03u", time.wYear, time.wMonth, time.wDay, time.wHour, time.wMinute, time.wSecond, time.wMilliseconds); return tBuf; } CSimpleString CCustMngrAuthFSM::generateAlarmJson(CSimpleString entityName, CSimpleString startTime, int cost) { return CSimpleString::Format("[{\"name\":\"%s\",\"time\":\"%s\",\"cost\":%d}]", entityName.GetData(), startTime.GetData(), cost); }