#pragma once #include #include #include #include #include #include #include namespace rublon { class Status { std::string_view _statusDirPath = "/var/lib/rublon"; std::string_view _statusFilePath = "/var/lib/rublon/install.json"; RapidJSONPMRStackAlloc< 4 * 1024 > _alloc; Document _data; bool _statusUpdated; std::string_view _appVersionKey = "/appVer"; std::string_view _appTypeKey = "/type"; std::string_view _paramSystemName = "/params/os"; std::string_view _paramSSHDUsePamName = "/params/sshd_config/usePam"; public: Status() : _data{&_alloc} { if(not details::exists(_statusFilePath.data())) { log(LogLevel::Info, "application first run, creating status file at %s", _statusFilePath.data()); details::mkdir(_statusDirPath.data()); details::touch(_statusFilePath.data()); } std::ifstream ifs{_statusFilePath.data()}; if(!ifs.is_open()) { /// TODO handle no file error } rapidjson::IStreamWrapper isw{ifs}; _data.ParseStream(isw); } void updateAppVersion(std::string_view newVersion) { RapidJSONPMRStackAlloc< 128 > stackAlloc; auto version = JSONPointer{_appVersionKey.data(), &stackAlloc}.Get(_data); if(not version || version->GetString() != newVersion) { _statusUpdated = true; auto version = Value{newVersion.data(), _data.GetAllocator()}; JSONPointer{_appVersionKey.data(), &stackAlloc}.Set(_data, version); } } void updateSystemVersion(std::string_view system) { RapidJSONPMRStackAlloc< 128 > stackAlloc; auto version = JSONPointer{_paramSystemName.data(), &stackAlloc}.Get(_data); if(not version || version->GetString() != system) { _statusUpdated = true; auto version = Value{system.data(), _data.GetAllocator()}; JSONPointer{_paramSystemName.data(), &stackAlloc}.Set(_data, version); } } bool updated() const { return _statusUpdated; } void save() { if(updated()) { memory::Monotonic_1k_HeapResource tmpResource; RapidJSONPMRAlloc alloc{&tmpResource}; FileWriter s{_statusFilePath}; rapidjson::PrettyWriter< FileWriter, rapidjson::UTF8<>, rapidjson::UTF8<>, RapidJSONPMRAlloc > writer{s, &alloc}; writer.SetIndent(' ', 2); _data.Accept(writer); } } Document & data() { return _data; } }; class CheckApplication { tl::expected< bool, Error > persistStatus(Status & status) const { status.data().RemoveMember("systemToken"); status.save(); return true; } public: template < typename Hander_t > tl::expected< int, Error > call(const CoreHandlerInterface< Hander_t > & coreHandler, std::string_view systemToken) const { memory::Monotonic_1k_HeapResource mr; RapidJSONPMRStackAlloc< 2048 > alloc{}; constexpr std::string_view api = "/api/app/init"; Status status; const auto persist = [&](const auto /*ok*/) { return this->persistStatus(status); }; status.updateAppVersion("2.0.2"); status.updateSystemVersion(details::osName(&mr)); if(status.updated()) { auto & alloc = status.data().GetAllocator(); status.data().AddMember("systemToken", Value{systemToken.data(), alloc}, alloc); return coreHandler.request(alloc, api, status.data()).and_then(persist); } return 0; } }; } // namespace rublon