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);
}
}
}