diff --git a/aether/aether_app.cpp b/aether/aether_app.cpp index 00ff8031..fa8f9ad4 100644 --- a/aether/aether_app.cpp +++ b/aether/aether_app.cpp @@ -49,34 +49,25 @@ void AetherAppContext::TelemetryInit() { if (!TELE_SINK::Instance().trap()) { # if AE_TELE_LOG_CONSOLE && AE_TELE_LOG_TO_STATISTICS // telemetry to both console and statistics + tele_statistics_trap_is_set = true; auto trap = std::make_shared< - ae::tele::ProxyTrap>>( + ae::tele::ProxyTrap>( std::make_shared(std::cout), - std::make_shared>()); + std::make_shared()); + # elif AE_TELE_LOG_CONSOLE // telemetry to console only auto trap = std::make_shared(std::cout); # elif AE_TELE_LOG_TO_STATISTICS // telemetry to statistics only - auto trap = - std::make_shared>(); + tele_statistics_trap_is_set = true; + auto trap = std::make_shared(); # else // NONE trap is enabled return; # endif TELE_SINK::Instance().SetTrap(trap); } -# if AE_TELE_LOG_TO_STATISTICS - else { - // TODO: is it possible to fix? - // IF AE_TELE_LOG_TO_STATISTICS is defined user are not allowed to set - // custom trap, because it's static_casts in TeleStatistics object - std::cerr - << "Custom trap are not allowed with AE_TELE_LOG_TO_STATISTICS==1\n"; - std::abort(); - } -# endif AE_TELE_ENV(CompileOptions()); AE_TELE_INFO(AetherStarted); @@ -84,6 +75,36 @@ void AetherAppContext::TelemetryInit() { #endif } +void AetherAppContext::TeleStatisticsInit( + TeleStatistics::ptr const& tele_statistics) const { +#if AE_TELE_ENABLED +# if AE_TELE_LOG_TO_STATISTICS + if (!tele_statistics_trap_is_set) { + return; + } + + auto& sink = TELE_SINK::Instance(); + auto trap = sink.trap(); + // !NOTICE it's error if AE_TELE_LOG_TO_STATISTICS is defined to 1 but actual + // trap is set to something different +# if AE_TELE_LOG_CONSOLE && AE_TELE_LOG_TO_STATISTICS + // if proxy trap is used + auto proxy = std::static_pointer_cast< + ae::tele::ProxyTrap>( + trap); + auto const& current_statistics = proxy->second; + tele_statistics->trap()->MergeStatistics(*current_statistics); + proxy->second = tele_statistics->trap(); +# elif AE_TELE_LOG_TO_STATISTICS + auto current_statistics = + std::static_pointer_cast(trap); + tele_statistics->trap()->MergeStatistics(*current_statistics); + sink.SetTrap(tele_statistics->trap()); +# endif +# endif +#endif +} + static Aether::ptr AetherFactory(AetherAppContext const& context) { /** * If it's production or filtration mode, declare and load Aether. @@ -349,6 +370,9 @@ std::unique_ptr AetherApp::Construct(AetherAppContext context) { app->aether_.Save(); #endif // AE_DISTILLATION + // reinit telemetry with tele_statistics object + context.TeleStatisticsInit(app->aether_->tele_statistics); + // save domain from context to the app app->domain_facility_ = std::move(std::move(context).domain_storage_.Resolve()); diff --git a/aether/aether_app.h b/aether/aether_app.h index 9c84f84a..976d3642 100644 --- a/aether/aether_app.h +++ b/aether/aether_app.h @@ -45,9 +45,10 @@ #include "aether/domain_storage/domain_storage_factory.h" namespace ae { +using TeleStatisticsTrap = ae::tele::StatisticsTrap; + class AetherAppContext { friend class AetherApp; - static void TelemetryInit(); public: explicit AetherAppContext() @@ -126,6 +127,9 @@ class AetherAppContext { #endif // AE_DISTILLATION private: + void TelemetryInit(); + void TeleStatisticsInit(TeleStatistics::ptr const& tele_statistics) const; + void InitComponentContext(); ComponentFactory> domain_storage_; @@ -139,6 +143,8 @@ class AetherAppContext { ComponentFactory dns_resolver_; ComponentFactory client_prefab_; ComponentFactory tele_statistics_; + + bool tele_statistics_trap_is_set{false}; }; /** diff --git a/aether/client.cpp b/aether/client.cpp index a23012d6..cd31717d 100644 --- a/aether/client.cpp +++ b/aether/client.cpp @@ -79,6 +79,9 @@ CloudServerConnections& Client::cloud_connection() { // also create telemetry telemetry_ = std::make_unique(*aether_, *cloud_connection_); #endif + + client_cloud_manager_.WithLoaded( + [&](auto const& ccm) { ccm->StartListenForCloudUpdate(); }); } return *cloud_connection_; diff --git a/aether/connection_manager/client_cloud_manager.cpp b/aether/connection_manager/client_cloud_manager.cpp index e5dd3303..5de4863e 100644 --- a/aether/connection_manager/client_cloud_manager.cpp +++ b/aether/connection_manager/client_cloud_manager.cpp @@ -154,17 +154,14 @@ ClientCloudManager::ClientCloudManager(ObjProp prop, ObjPtr aether, [[maybe_unused]] auto const cache_initialized = client_.WithLoaded([&](auto const& obj) { cloud_cache_.emplace(obj->uid(), - client_cloud_manager_internal::CloudCache{ - .version_confirmed = true, - .subject_uid = obj->uid(), - .version = 0, - .cloud = obj->cloud(), - }); + client_cloud_manager_internal::CloudCache{ + .version_confirmed = true, + .subject_uid = obj->uid(), + .version = 0, + .cloud = obj->cloud(), + }); }); assert(cache_initialized && "Client did not load"); - - // init the rest - Init(); } ClientCloudManager::CloudUpdateEvent::Subscriber @@ -175,10 +172,11 @@ ClientCloudManager::cloud_update_event() { GetCloudAction& ClientCloudManager::GetCloud(Uid client_uid) { AE_TELED_DEBUG("Ask cloud for uid: {}", client_uid); - auto aether = Aether::ptr{aether_}.Load(); + auto aether = aether_.Load(); assert(aether && "Aether did not loaded"); - - assert(cloud_actions_ && "Cloud actions did not initiated"); + if (!cloud_actions_) { + cloud_actions_.emplace(*aether); + } auto cached = cloud_cache_.find(client_uid); if ((cached != cloud_cache_.end()) && cached->second.cloud.is_valid()) { @@ -192,7 +190,7 @@ GetCloudAction& ClientCloudManager::GetCloud(Uid client_uid) { } // get from aethernet - auto client = Client::ptr{client_}.Load(); + auto client = client_.Load(); assert(client); auto* action = cloud_actions_->Create( @@ -201,19 +199,13 @@ GetCloudAction& ClientCloudManager::GetCloud(Uid client_uid) { return *action; } -void ClientCloudManager::Init() { - auto aether = Aether::ptr{aether_}.Load(); +void ClientCloudManager::StartListenForCloudUpdate() { + auto aether = aether_.Load(); assert(aether && "Aether must be loaded"); - - cloud_actions_.emplace(*aether); get_servers_pool_.emplace(*aether); - ListenForCloudUpdate(); -} - -void ClientCloudManager::ListenForCloudUpdate() { - auto client = Client::ptr{client_}.Load(); - assert(client != nullptr && "Client does not loaded"); + auto client = client_.Load(); + assert(client && "Client does not loaded"); cloud_update_sub_ = CloudEventListener{ ApiEventSubscriber{[this](ClientApiSafe& client_api, @@ -227,12 +219,11 @@ void ClientCloudManager::ListenForCloudUpdate() { auto ClientCloudManager::MakeServersSender(std::vector const& sids) { using namespace client_cloud_manager_internal; // NOLINT(*using-namespace) - auto aether = Aether::ptr{aether_}; - auto client = Client::ptr{client_}; assert(get_servers_pool_.has_value() && "Get servers pool did not initiated"); - return SplitMissingLoaded(aether, sids) | - LoadMissing(aether, client, *get_servers_pool_) | SortNewServers(sids); + return SplitMissingLoaded(aether_, sids) | + LoadMissing(aether_, client_, *get_servers_pool_) | + SortNewServers(sids); } void ClientCloudManager::CloudConfigs(std::vector const& configs) { @@ -275,7 +266,7 @@ void ClientCloudManager::CloudConfigs(std::vector const& configs) { } void ClientCloudManager::FinalizeCloudConfig(CloudConfig const& conf) { - auto aether = Aether::ptr{aether_}.Load(); + auto aether = aether_.Load(); AE_TELED_DEBUG("Finalize servers for new cloud config [{}]", conf.cloud.sids); // make async waiter for building the new cloud diff --git a/aether/connection_manager/client_cloud_manager.h b/aether/connection_manager/client_cloud_manager.h index 1364e90f..f7b86293 100644 --- a/aether/connection_manager/client_cloud_manager.h +++ b/aether/connection_manager/client_cloud_manager.h @@ -92,15 +92,10 @@ class ClientCloudManager : public Obj { GetCloudAction& GetCloud(Uid client_uid); AE_OBJECT_REFLECT(AE_MMBRS(aether_, client_, cloud_cache_)) - template - void Load(CurrentVersion, Dnv& dnv) { - dnv(base_, aether_, client_, cloud_cache_); - Init(); - } + + void StartListenForCloudUpdate(); private: - void Init(); - void ListenForCloudUpdate(); void CloudConfigs(std::vector const& configs); void FinalizeCloudConfig(CloudConfig const& conf); auto MakeServersSender(std::vector const& sids); diff --git a/aether/domain_storage/spifs_domain_storage.cpp b/aether/domain_storage/spifs_domain_storage.cpp index f98cea17..4ccc6c79 100644 --- a/aether/domain_storage/spifs_domain_storage.cpp +++ b/aether/domain_storage/spifs_domain_storage.cpp @@ -18,6 +18,8 @@ #if defined AE_SPIFS_DOMAIN_STORAGE_ENABLED +# include + # include "sys/stat.h" # include "esp_err.h" @@ -25,26 +27,11 @@ # include "spiffs_config.h" # include "aether-miscpp/crc.h" -# include "aether/mstream.h" -# include "aether/mstream_buffers.h" +# include "aether-miscpp/serialization/binary_archive.h" # include "aether/domain_storage/domain_storage_tele.h" namespace ae { - -class FileWriter : public IDomainStorageWriter { - public: - explicit FileWriter(FILE* f) : file{f} {} - - ~FileWriter() override { fclose(file); } - - void write(void const* data, std::size_t size) override { - fwrite(data, 1, size, file); - } - - FILE* file; -}; - class SpiFsSotorageWriter final : public IDomainStorageWriter { public: explicit SpiFsSotorageWriter(SpiFsDomainStorage& storage, @@ -76,8 +63,15 @@ class SpiFsSotorageWriter final : public IDomainStorageWriter { static_cast(query.version), buffer.size()); } - void write(void const* data, std::size_t size) override { - writer.write(data, size); + seri::SeriResult Write(seri::SizeWriteTag data) override { + auto const size = static_cast(data.size); + return Write(seri::DataTag{size}); + } + + seri::SeriResult Write(seri::DataWriteTag data) override { + auto const* p = static_cast(data.data); + buffer.insert(std::end(buffer), p, p + data.size); + return Ok{seri::good}; } private: @@ -89,29 +83,49 @@ class SpiFsSotorageWriter final : public IDomainStorageWriter { std::string file_path; DomainQuery query; std::vector buffer; - VectorWriter writer{buffer}; }; class SpiFsSotorageReader final : public IDomainStorageReader { public: - explicit SpiFsSotorageReader(FILE* f) : file{f} {} - ~SpiFsSotorageReader() override { fclose(file); } - - void read(void* data, std::size_t size) override { - auto res = fread(data, 1, size, file); - if (res != size) { - printf("read error!\n"); - read_result = ReadResult::kNo; - return; + explicit SpiFsSotorageReader(FILE* f) { + // read all file into buffer + // store actual buffer size in a buff_size + constexpr auto kRead = 256; + std::size_t off = 0; + while (true) { + buffer.resize(off + kRead); + auto res = fread(buffer.data() + off, 1, kRead, f); + off += res; + if (res < kRead) { + break; + } + } + // make buffer actual read size + buffer.resize(off); + + fclose(f); + } + + seri::SeriResult Read(seri::SizeReadTag data) override { + std::uint32_t size{}; + if (auto res = Read(seri::DataTag{size}); !res) { + return res; } - read_result = ReadResult::kYes; + data.size = static_cast(size); + return Ok{seri::good}; } - ReadResult result() const override { return read_result; } - void result(ReadResult res) override { read_result = res; } + seri::SeriResult Read(seri::DataReadTag data) override { + if ((offset + data.size) > buffer.size()) { + return Error{seri::read_eof}; + } + std::memcpy(data.data, buffer.data() + offset, data.size); + offset += data.size; + return Ok{seri::good}; + } - FILE* file; - ReadResult read_result{ReadResult::kYes}; + std::vector buffer; + std::size_t offset{}; }; SpiFsDomainStorage::SpiFsDomainStorage() { @@ -266,26 +280,49 @@ void SpiFsDomainStorage::DeInitFs() { } void SpiFsDomainStorage::InitState() { - auto file = fopen(kObjectMapPath.data(), "r"); - if (!file) { + auto* file = fopen(kObjectMapPath.data(), "r"); + if (file == nullptr) { AE_TELED_DEBUG("File {} does not exists ", kObjectMapPath); return; } - auto file_reader = SpiFsSotorageReader{file}; - imstream is{file_reader}; - is >> object_map_; + constexpr std::size_t kReadSize = 256; + std::vector buffer; + std::size_t off = 0; + while (true) { + buffer.resize(off + kReadSize); + auto res = fread(buffer.data() + off, kReadSize, 1, file); + off += res; + if (res < kReadSize) { + break; + } + } + // resize to actual read size + buffer.resize(off); + + auto bin_archive = + seri::BinaryArchive{seri::BinaryVectorBuffer{buffer}}; + if (!bin_archive.Load(object_map_)) { + AE_TELED_DEBUG("Failed to load object map"); + } } void SpiFsDomainStorage::SyncState() { - auto file = fopen(kObjectMapPath.data(), "w"); - if (!file) { + auto* file = fopen(kObjectMapPath.data(), "w"); + if (file == nullptr) { AE_TELED_ERROR("Failed to open file {} for writing.", kObjectMapPath); return; } - auto file_writer = FileWriter{file}; - omstream os{file_writer}; - os << object_map_; + std::vector buffer; + auto bin_archive = + seri::BinaryArchive{seri::BinaryVectorBuffer{buffer}}; + if (bin_archive.Save(object_map_)) { + fwrite(buffer.data(), 1, buffer.size(), file); + } else { + AE_TELED_DEBUG("Failed to save object map"); + } + + fclose(file); } bool SpiFsDomainStorage::SaveObject(DomainQuery const& query, DataCrc crc) { diff --git a/aether/domain_storage/spifs_domain_storage.h b/aether/domain_storage/spifs_domain_storage.h index d51d44c6..dc01bf6e 100644 --- a/aether/domain_storage/spifs_domain_storage.h +++ b/aether/domain_storage/spifs_domain_storage.h @@ -22,8 +22,8 @@ #if defined ESP_PLATFORM && AE_SUPPORT_SPIFS_FS # define AE_SPIFS_DOMAIN_STORAGE_ENABLED 1 -# include # include +# include # include # include "aether/obj/idomain_storage.h" diff --git a/aether/obj/obj_id.h b/aether/obj/obj_id.h index a7c0923f..3754f806 100644 --- a/aether/obj/obj_id.h +++ b/aether/obj/obj_id.h @@ -21,6 +21,7 @@ #include "aether-miscpp/format/format.h" #include "aether-miscpp/reflect/reflect.h" +#include "aether-miscpp/serialization/serialization.h" namespace ae { @@ -67,6 +68,23 @@ struct Formatter : public Formatter { } }; +namespace seri { +template +struct Serializer { + SeriResult Seri(A& archive, Meta meta) const { + auto const id = meta.value.id(); + return archive.Save(Meta{id, meta.name}); + } + + SeriResult Deseri(A& archive, Meta meta) const { + ObjId::Type id{}; + TRY_RESULT((archive.Load(Meta{id, meta.name}))); + meta.value = ObjId{id}; + return Ok{good}; + } +}; +} // namespace seri + class ObjFlags { public: using Type = std::uint8_t; @@ -106,6 +124,23 @@ struct Formatter : public Formatter { } }; +namespace seri { +template +struct Serializer { + SeriResult Seri(A& archive, Meta meta) const { + ObjFlags::Type const flag = meta.value; + return archive.Save(Meta{flag, meta.name}); + } + + SeriResult Deseri(A& archive, Meta meta) const { + ObjFlags::Type flag{}; + TRY_RESULT((archive.Load(Meta{flag, meta.name}))); + meta.value = ObjFlags{flag}; + return Ok{good}; + } +}; +} // namespace seri + } // namespace ae #endif // AETHER_OBJ_OBJ_ID_H_ */ diff --git a/aether/registration/root_server_select_stream.h b/aether/registration/root_server_select_stream.h index 2a14bd75..6069e254 100644 --- a/aether/registration/root_server_select_stream.h +++ b/aether/registration/root_server_select_stream.h @@ -37,7 +37,7 @@ class Aether; struct RootServerSelectStreamTestAccess; class RootServerSelectStream final : public ByteIStream { public: - static constexpr std::size_t kBufferCapacity = 200; + static constexpr std::size_t kBufferCapacity = 2; using ServerChangedEvent = Event; using CloudErrorEvent = Event; diff --git a/aether/server_connections/client_server_connection.h b/aether/server_connections/client_server_connection.h index cb654899..6996fc8a 100644 --- a/aether/server_connections/client_server_connection.h +++ b/aether/server_connections/client_server_connection.h @@ -37,7 +37,7 @@ class Channel; namespace client_server_connection_internal { class BufferedServerConnection : public ByteIStream { public: - static constexpr std::size_t kBufferCapacity = 200; + static constexpr std::size_t kBufferCapacity = 10; BufferedServerConnection(AeContext const& ae_context, Ptr const& server); diff --git a/aether/tele_statistics.cpp b/aether/tele_statistics.cpp index e46653b9..d91e2f99 100644 --- a/aether/tele_statistics.cpp +++ b/aether/tele_statistics.cpp @@ -16,8 +16,6 @@ #include "aether/tele_statistics.h" -#include "aether/tele.h" - namespace ae { #ifdef AE_DISTILLATION TeleStatistics::TeleStatistics(ObjProp prop) : Obj{prop} {} @@ -25,32 +23,5 @@ TeleStatistics::TeleStatistics(ObjProp prop) : Obj{prop} {} #if AE_TELE_ENABLED && AE_TELE_LOG_TO_STATISTICS auto TeleStatistics::trap() -> std::shared_ptr const& { return trap_; } - -void TeleStatistics::OnLoaded() { - auto& sink = TELE_SINK::Instance(); - auto const& trap = sink.trap(); - if (!trap) { - sink.SetTrap(trap_); - return; - } - // !NOTICE it's error if AE_TELE_LOG_TO_STATISTICS is defined to 1 but actual - // trap is set to something different -# if AE_TELE_LOG_CONSOLE && AE_TELE_LOG_TO_STATISTICS - // if proxy trap is used - auto proxy = std::static_pointer_cast< - ae::tele::ProxyTrap>>( - trap); - auto const& current_statistics = proxy->second; - trap_->MergeStatistics(*current_statistics); - proxy->second = trap_; -# elif AE_TELE_LOG_TO_STATISTICS - auto current_statistics = std::static_pointer_cast< - ae::tele::StatisticsTrap>(trap); - trap_->MergeStatistics(*current_statistics); - sink.SetTrap(trap_); -# endif -} - #endif } // namespace ae diff --git a/aether/tele_statistics.h b/aether/tele_statistics.h index 8b2e8d50..03f5d02e 100644 --- a/aether/tele_statistics.h +++ b/aether/tele_statistics.h @@ -42,7 +42,6 @@ class TeleStatistics : public Obj { template void Load(CurrentVersion, Dnv& dnv) { dnv(base_, *trap_); - OnLoaded(); } template void Save(CurrentVersion, Dnv& dnv) const { @@ -56,7 +55,6 @@ class TeleStatistics : public Obj { std::shared_ptr const& trap(); private: - void OnLoaded(); std::shared_ptr trap_ = std::make_shared(); #endif };