#ifndef HEALTHMANAGER_ENTITY_BOOT_STRUCT_H #define HEALTHMANAGER_ENTITY_BOOT_STRUCT_H #include #include #include #include #include #include "iniutil.h" #include "SpBase.h" #define ISSUCCEEDED(hr) ((hr) == Error_Succeed) #define FAILURED(hr) (!(ISSUCCEEDED(hr))) enum EntityBootType { IgnoreResult, VerifyInAsync, VerifyInSync }; enum EntityBootStep { NotInit, CoreBoot, SafeLoad, IEBrowser, Operating, NotConfigInit, NotConfigSecond }; struct EntityBootInfo { CSimpleStringA entityName; CSimpleStringA cmdLine; EntityBootType bootType; ErrorCodeEnum bootResult; EntityBootInfo(const char* name, EntityBootType type) :entityName(name) , bootType(type) , bootResult(Error_NotInit) { } }; struct StartEntityOperation; struct BootStep { CSimpleStringA strSectionName; std::vector< EntityBootInfo> entityList; BootStep() :strSectionName(true) {} BootStep(const char* stepName) :strSectionName(stepName) {} virtual ~BootStep() {} static ErrorCodeEnum WaitForAsyncEntitStartOperation(std::vector& entityList); ErrorCodeEnum LoadConfig(const CSimpleStringA& configPath) { array_header_t* keys = inifile_read_section_key_all(configPath, strSectionName); if (!keys || array_empty(keys)) { return Error_NotExist; } entityList.clear(); for (size_t i = 0; i < keys->nelts; ++i) { char* entityName = ARRAY_IDX(keys, i, char*); int bootType = inifile_read_int(configPath, strSectionName, entityName, 0); DbgWithLink(LOG_LEVEL_DEBUG, LOG_TYPE_SYSTEM)("boot type info: %s=%d", entityName, bootType); EntityBootInfo entityBootInfo{ entityName, static_cast(bootType) }; entityList.push_back(entityBootInfo); } toolkit_array_free2(keys); return Error_Succeed; } bool HasEntity() const { return(!entityList.empty()); } ErrorCodeEnum StartStartupEntities(CEntityBase* pTrigger); }; struct CoreBootStep : public BootStep { CoreBootStep(const CSimpleStringA& sectionPosix) :BootStep(CSimpleStringA("CoreBoot.") + sectionPosix) { } }; struct SafeLoadStep : public BootStep { SafeLoadStep(const CSimpleStringA& sectionPosix) :BootStep(CSimpleStringA("SafeLoad.") + sectionPosix) { } }; struct BrowserShowStep : public BootStep { BrowserShowStep(const CSimpleStringA& sectionPosix) :BootStep(CSimpleStringA("IEBrowser.") + sectionPosix + ".Url") { } }; struct OperatingStep : public BootStep { OperatingStep(const CSimpleStringA& sectionPosix) : BootStep(CSimpleStringA("Operating.") + sectionPosix) { } }; struct TerminalDeployStep : public BootStep { TerminalDeployStep(const CSimpleStringA& noUsed) : BootStep(CSimpleStringA("TerminalDeploy")) { } }; struct TerminalDeploySecondStep : public BootStep { TerminalDeploySecondStep(const CSimpleStringA& sectionPosix) : BootStep(CSimpleStringA("TerminalDeploySec.") + sectionPosix) { } }; struct TerminalDeployThirdStep : public BootStep { TerminalDeployThirdStep(const CSimpleStringA& sectionPosix) : BootStep(CSimpleStringA("TerminalDeployTrd.") + sectionPosix) { } }; struct StartEntityBaseContext : public IReleasable { CEntityBase* theEntity; virtual bool IsFinished(ErrorCodeEnum* retrieveResult) const { return true; } StartEntityBaseContext(CEntityBase* pEntity) :theEntity(pEntity) {} virtual ~StartEntityBaseContext() {} ErrorCodeEnum StartEntity(const char* entityName, const char* cmdLine, CSmartPointer& spWait) { CSmartPointer pFuncPrivilege = theEntity->GetFunction() .ConvertCase(); ErrorCodeEnum result = pFuncPrivilege->StartEntity(entityName, cmdLine, spWait); return result; } virtual ErrorCodeEnum BootEntity(const EntityBootInfo* entityInfo) { return Error_NotImpl; } }; struct StartEntitySyncContenxt : public StartEntityBaseContext { using StartEntityBaseContext::StartEntityBaseContext; ErrorCodeEnum BootEntity(const EntityBootInfo* entityInfo) { ErrorCodeEnum result(Error_Succeed); CSmartPointer spWait; result = StartEntity(entityInfo->entityName, entityInfo->cmdLine, spWait); if (ISSUCCEEDED(result) && spWait != nullptr) { result = spWait->WaitAnswer(60 * 1000); } return result; } }; struct StartEntityOperation; struct StartEntityAsyncContenxt : public StartEntityBaseContext, public ICallbackListener { enum FinishedState { Pending, End } theFinishedState; StartEntityAsyncContenxt(CEntityBase* pEntity) : StartEntityBaseContext(pEntity) , theFinishedState(End) , asyncResult(Error_NotInit) { } virtual bool IsFinished(ErrorCodeEnum* retrieveResult) const { if (retrieveResult) { *retrieveResult = asyncResult; } return (theFinishedState == End); } ErrorCodeEnum BootEntity(const EntityBootInfo* entityInfo) { LOG_FUNCTION(); ErrorCodeEnum result(Error_Succeed); CSmartPointer spWait; theFinishedState = Pending; result = StartEntity(entityInfo->entityName, entityInfo->cmdLine, spWait); if (ISSUCCEEDED(result) && spWait != nullptr) { spWait->SetCallback(this, nullptr); result = Error_Pending; } else { theFinishedState = End; DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM)("return directly: %s", SpStrError(result)); } asyncResult = result; return result; } void OnAnswer(CSmartPointer pAsynWaitSp) { LOG_FUNCTION(); asyncResult = pAsynWaitSp->AsyncGetAnswer(); theFinishedState = End; } ErrorCodeEnum asyncResult; }; struct StartEntityOperation { StartEntityOperation(CEntityBase* pEntity, EntityBootInfo& entityInfo) :entInfo(entityInfo) { switch (entityInfo.bootType) { case VerifyInAsync: theContext = std::make_shared(pEntity); break; case VerifyInSync: theContext = std::make_shared(pEntity); break; default: theContext = std::make_shared(pEntity); break; } } bool IsDone() { return theContext->IsFinished(&entInfo.bootResult); } ErrorCodeEnum StartEntity() { ErrorCodeEnum result = theContext->BootEntity(&entInfo); entInfo.bootResult = result; return result; } std::shared_ptr< StartEntityBaseContext> theContext; EntityBootInfo& entInfo; }; ErrorCodeEnum BootStep::WaitForAsyncEntitStartOperation(std::vector& entityList) { LOG_FUNCTION(); ErrorCodeEnum result = Error_Succeed; for (; !entityList.empty();) { auto finishedInstance = find_if(entityList.begin(), entityList.end() , [](StartEntityOperation* operation) { return operation->IsDone(); }); if (finishedInstance != entityList.end()) { StartEntityOperation* operation = *finishedInstance; entityList.erase(finishedInstance); auto& entity = operation->entInfo; if (FAILURED(entity.bootResult)) { result = entity.bootResult; } delete operation; } else { std::this_thread::sleep_for(std::chrono::milliseconds(100)); } } return result; } ErrorCodeEnum BootStep::StartStartupEntities(CEntityBase* pTrigger) { ErrorCodeEnum result = Error_Succeed; if (HasEntity()) { std::vector pendingEntiList; for (auto& entity : entityList) { StartEntityOperation* startOperat = new StartEntityOperation(pTrigger, entity); DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("to start entity: %s ...", entity.entityName.GetData()); result = startOperat->StartEntity(); if (!startOperat->IsDone()) { pendingEntiList.push_back(startOperat); } else { if (ISSUCCEEDED(result)) { DbgWithLink(LOG_LEVEL_INFO, LOG_TYPE_SYSTEM)("start entity: %s successfully :)", entity.entityName.GetData()); } else { DbgWithLink(LOG_LEVEL_WARN, LOG_TYPE_SYSTEM)("start entity: %s failed :( EC: %s", entity.entityName.GetData(), SpStrError(result)); } delete startOperat; if (FAILURED(result)) { break; } } } if (!pendingEntiList.empty()) { result = WaitForAsyncEntitStartOperation(pendingEntiList); } [](std::vector < StartEntityOperation*>& entities) { for (auto& entity : entities) { delete entity; } }(pendingEntiList); } return result; } #endif