#ifndef EQEMU_PLAYER_EVENT_LOGS_H #define EQEMU_PLAYER_EVENT_LOGS_H #include #include #include "../json/json_archive_single_line.h" #include "../servertalk.h" #include "../timer.h" #include "../eqemu_config.h" #include "../repositories/player_event_log_settings_repository.h" #include "../repositories/player_event_logs_repository.h" #include "../repositories/player_event_loot_items_repository.h" #include "../repositories/player_event_merchant_purchase_repository.h" #include "../repositories/player_event_merchant_sell_repository.h" #include "../repositories/player_event_npc_handin_repository.h" #include "../repositories/player_event_npc_handin_entries_repository.h" #include "../repositories/player_event_trade_repository.h" #include "../repositories/player_event_trade_entries_repository.h" #include "../repositories/player_event_speech_repository.h" #include "../repositories/player_event_killed_npc_repository.h" #include "../repositories/player_event_killed_named_npc_repository.h" #include "../repositories/player_event_killed_raid_npc_repository.h" #include "../repositories/player_event_aa_purchase_repository.h" class PlayerEventLogs { public: Database player_event_database{}; void Init(); bool LoadDatabaseConnection(); void ReloadSettings(); void LoadEtlIds(); PlayerEventLogs *SetDatabase(Database *db); bool ValidateDatabaseConnection(); bool IsEventEnabled(PlayerEvent::EventType event); void Process(); // batch queue void AddToQueue(PlayerEventLogsRepository::PlayerEventLogs &logs); // main event record generic function // can ingest any struct event types template std::unique_ptr RecordEvent( PlayerEvent::EventType t, const PlayerEvent::PlayerEvent &p, T e ) { auto n = PlayerEventLogsRepository::NewEntity(); FillPlayerEvent(p, n); n.event_type_id = t; std::stringstream ss; { cereal::JSONOutputArchiveSingleLine ar(ss); e.serialize(ar); } n.event_type_name = PlayerEvent::EventName[t]; n.event_data = Strings::Contains(ss.str(), "noop") ? "{}" : ss.str(); n.created_at = std::time(nullptr); auto c = PlayerEvent::PlayerEventContainer{ .player_event = p, .player_event_log = n }; return BuildPlayerEventPacket(c); } [[nodiscard]] const PlayerEventLogSettingsRepository::PlayerEventLogSettings * GetSettings() const; bool IsEventDiscordEnabled(int32_t event_type_id); std::string GetDiscordWebhookUrlFromEventType(int32_t event_type_id); void LoadPlayerEventSettingsFromQS(const std::vector& settings); static std::string GetDiscordPayloadFromEvent(const PlayerEvent::PlayerEventContainer &e); struct EtlQueues { std::vector loot_items; std::vector merchant_purchase; std::vector merchant_sell; std::vector npc_handin; std::vector npc_handin_entries; std::vector trade; std::vector trade_entries; std::vector speech; std::vector killed_npc; std::vector killed_named_npc; std::vector killed_raid_npc; std::vector aa_purchase; }; static PlayerEventLogs* Instance() { static PlayerEventLogs instance; return &instance; } private: struct EtlSettings { bool enabled; std::string table_name; int64 next_id; }; Database *m_database; // reference to database PlayerEventLogSettingsRepository::PlayerEventLogSettings m_settings[PlayerEvent::EventType::MAX]{}; // batch queue is used to record events in batch std::vector m_record_batch_queue{}; static void FillPlayerEvent(const PlayerEvent::PlayerEvent &p, PlayerEventLogsRepository::PlayerEventLogs &n); static std::unique_ptr BuildPlayerEventPacket(const PlayerEvent::PlayerEventContainer &e); std::map m_etl_settings{}; // timers Timer m_database_ping_timer; // database ping timer Timer m_process_batch_events_timer; // events processing timer Timer m_process_retention_truncation_timer; // timer for truncating events based on retention settings // processing std::mutex m_batch_queue_lock{}; void ProcessBatchQueue(); void ProcessRetentionTruncation(); void SetSettingsDefaults(); public: std::map &GetEtlSettings() { return m_etl_settings;} }; #endif //EQEMU_PLAYER_EVENT_LOGS_H