/**************************************************************************/ /* aethex_telemetry.cpp */ /**************************************************************************/ /* AeThex Engine */ /* https://aethex.dev */ /**************************************************************************/ #include "aethex_telemetry.h" #include "aethex_cloud.h" #include "core/io/http_client.h" #include "core/os/os.h" #include "core/os/time.h" #include "core/version.h" void AethexTelemetry::_bind_methods() { ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &AethexTelemetry::set_enabled); ClassDB::bind_method(D_METHOD("is_enabled"), &AethexTelemetry::is_enabled); ClassDB::bind_method(D_METHOD("track_event", "event_name", "properties"), &AethexTelemetry::track_event, DEFVAL(Dictionary())); ClassDB::bind_method(D_METHOD("track_screen", "screen_name"), &AethexTelemetry::track_screen); ClassDB::bind_method(D_METHOD("track_error", "error", "stack_trace"), &AethexTelemetry::track_error, DEFVAL("")); ClassDB::bind_method(D_METHOD("report_crash", "message", "stack_trace", "context"), &AethexTelemetry::report_crash, DEFVAL(Dictionary())); ClassDB::bind_method(D_METHOD("flush"), &AethexTelemetry::flush); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled"); } AethexTelemetry::AethexTelemetry() { } AethexTelemetry::~AethexTelemetry() { // Flush remaining events on shutdown if (!event_buffer.is_empty()) { flush(); } } void AethexTelemetry::set_cloud(AethexCloud *p_cloud) { cloud = p_cloud; } void AethexTelemetry::set_enabled(bool p_enabled) { enabled = p_enabled; } bool AethexTelemetry::is_enabled() const { return enabled; } void AethexTelemetry::track_event(const String &p_event_name, const Dictionary &p_properties) { if (!enabled || !cloud) { return; } Dictionary event; event["name"] = p_event_name; event["properties"] = p_properties; event["timestamp"] = Time::get_singleton()->get_datetime_string_from_system(true); event["platform"] = OS::get_singleton()->get_name(); event["engineVersion"] = AETHEX_VERSION_FULL_CONFIG; event_buffer.push_back(event); // Auto-flush if buffer is full if (event_buffer.size() >= buffer_size) { flush(); } } void AethexTelemetry::track_screen(const String &p_screen_name) { Dictionary props; props["screen"] = p_screen_name; track_event("screen_view", props); } void AethexTelemetry::track_error(const String &p_error, const String &p_stack_trace) { Dictionary props; props["error"] = p_error; props["stack_trace"] = p_stack_trace; track_event("error", props); } void AethexTelemetry::report_crash(const String &p_message, const String &p_stack_trace, const Dictionary &p_context) { if (!cloud) { return; } Dictionary data; data["message"] = p_message; data["stackTrace"] = p_stack_trace; data["context"] = p_context; data["platform"] = OS::get_singleton()->get_name(); data["engineVersion"] = AETHEX_VERSION_FULL_CONFIG; data["timestamp"] = Time::get_singleton()->get_datetime_string_from_system(true); // Crash reports are sent immediately, not buffered cloud->make_request("/api/telemetry/crash", HTTPClient::METHOD_POST, data); } void AethexTelemetry::flush() { if (!cloud || event_buffer.is_empty()) { return; } // Send all buffered events for (int i = 0; i < event_buffer.size(); i++) { cloud->make_request("/api/telemetry/event", HTTPClient::METHOD_POST, event_buffer[i]); } event_buffer.clear(); time_since_flush = 0.0; } void AethexTelemetry::process(double p_delta) { if (!enabled) { return; } time_since_flush += p_delta; // Auto-flush periodically if (time_since_flush >= flush_interval && !event_buffer.is_empty()) { flush(); } }