using System; using System.Collections.Generic; using System.Globalization; using System.Threading.Tasks; using Unity.Services.Core.Configuration.Internal; using Unity.Services.Core.Environments.Internal; using Unity.Services.Core.Scheduler.Internal; using UnityEngine; namespace Unity.Services.Core.Telemetry.Internal { /// /// Handles common logic between all instances. /// class DiagnosticsHandler : TelemetryHandler { class SendState { public DiagnosticsHandler Self; public CachedPayload Payload; } public DiagnosticsHandler( TelemetryConfig config, CachedPayload cache, IActionScheduler scheduler, ICachePersister cachePersister, TelemetrySender sender) : base(config, cache, scheduler, cachePersister, sender) {} internal override void SendPersistedCache(CachedPayload persistedCache) { var sendAsync = m_Sender.SendAsync(persistedCache.Payload); m_CachePersister.Delete(); var localState = new SendState { Self = this, Payload = new CachedPayload { TimeOfOccurenceTicks = persistedCache.TimeOfOccurenceTicks, Payload = persistedCache.Payload, }, }; sendAsync.ContinueWith(OnSendAsyncCompleted, localState, TaskContinuationOptions.ExecuteSynchronously); } static void OnSendAsyncCompleted(Task sendOperation, object state) { if (!(state is SendState castState)) { throw new ArgumentException("The given state is invalid."); } switch (sendOperation.Status) { case TaskStatus.Canceled: case TaskStatus.Faulted: { castState.Self.ThreadSafeCache(castState.Payload); break; } case TaskStatus.RanToCompletion: { break; } default: throw new ArgumentOutOfRangeException( nameof(sendOperation.Status), "Can't continue without the send operation being completed."); } } void ThreadSafeCache(CachedPayload payload) { lock (Lock) { Cache.AddRangeFrom(payload); } } internal override void FetchSpecificCommonTags(ICloudProjectId cloudProjectId, IEnvironments environments) { var commonTags = Cache.Payload.DiagnosticsCommonTags; commonTags.Clear(); commonTags[TagKeys.ApplicationVersion] = Application.version; commonTags[TagKeys.ProductName] = Application.productName; commonTags[TagKeys.CloudProjectId] = cloudProjectId.GetCloudProjectId(); commonTags[TagKeys.EnvironmentName] = environments.Current; commonTags[TagKeys.ApplicationGenuine] = Application.genuineCheckAvailable ? Application.genuine.ToString(CultureInfo.InvariantCulture) : "unavailable"; commonTags[TagKeys.InternetReachability] = Application.internetReachability.ToString(); } internal override void SendCachedPayload() { if (Cache.IsEmpty()) return; var sendAsync = m_Sender.SendAsync(Cache.Payload); var localState = new SendState { Self = this, Payload = new CachedPayload { TimeOfOccurenceTicks = Cache.TimeOfOccurenceTicks, Payload = new DiagnosticsPayload { Diagnostics = new List(Cache.Payload.Diagnostics), CommonTags = new Dictionary(Cache.Payload.CommonTags), DiagnosticsCommonTags = new Dictionary(Cache.Payload.DiagnosticsCommonTags), }, }, }; Cache.TimeOfOccurenceTicks = 0; Cache.Payload.Diagnostics.Clear(); if (m_CachePersister.CanPersist) { m_CachePersister.Delete(); } sendAsync.ContinueWith(OnSendAsyncCompleted, localState, TaskContinuationOptions.ExecuteSynchronously); } } }