- 종료 직전에 보내는 Event 누락 방지하기 위한 코드 수정 : 큐에 이벤트를 추가하면 +1, 큐에서 읽어와서 Event를 Send하면 -1하는 필드 추가 : 필드가 0이되기를 기다리는 함수 추가(대기 한계 시간 기본값 1500ms) [변경] AptabaseClientBase.cs - EventData에 ipAddredd 할당하는 코드 제거 : 매번 API 호출하면서 속도 지연의 원인이 됨 - aptabase-debug.log 파일 생성하는 코드 제거 : 파일 관리가 안되고 있으므로 제거
163 lines
4.8 KiB
C#
163 lines
4.8 KiB
C#
using Microsoft.Extensions.Logging;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Net;
|
|
using System.Net.Http;
|
|
using System.Net.Http.Json;
|
|
using System.Reflection;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace Aptabase.WPF;
|
|
|
|
internal class AptabaseClientBase : IAsyncDisposable
|
|
{
|
|
protected static readonly TimeSpan SESSION_TIMEOUT = TimeSpan.FromMinutes(60);
|
|
|
|
private static readonly Random _random = new();
|
|
private readonly ILogger? _logger;
|
|
private readonly HttpClient? _http;
|
|
private static readonly HttpClient _ipClient = new();
|
|
private DateTime _lastTouched = DateTime.UtcNow;
|
|
private string _sessionId = NewSessionId();
|
|
private static readonly SystemInfo _sysInfo = new();
|
|
|
|
private static readonly Dictionary<string, string> _hosts = new()
|
|
{
|
|
{ "US", "https://us.aptabase.com" },
|
|
{ "EU", "https://eu.aptabase.com" },
|
|
{ "DEV", "https://localhost:3000" },
|
|
{ "SH", "" },
|
|
};
|
|
|
|
public AptabaseClientBase(string appKey, AptabaseOptions? options, ILogger? logger)
|
|
{
|
|
_logger = logger;
|
|
|
|
var parts = appKey.Split("-");
|
|
|
|
if (parts.Length != 3 || !_hosts.ContainsKey(parts[1]))
|
|
{
|
|
_logger?.LogWarning("The Aptabase App Key {AppKey} is invalid. Tracking will be disabled.", appKey);
|
|
return;
|
|
}
|
|
|
|
var region = parts[1];
|
|
|
|
var baseUrl = GetBaseUrl(parts[1], options);
|
|
|
|
if (baseUrl is null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_sysInfo.IsDebug = options?.IsDebugMode ?? SystemInfo.IsInDebugMode(Assembly.GetExecutingAssembly());
|
|
|
|
_http = region == "DEV" ? new(new LocalHttpsClientHandler()) : new();
|
|
_http.BaseAddress = new Uri(baseUrl);
|
|
|
|
_http.DefaultRequestHeaders.Add("App-Key", appKey);
|
|
}
|
|
|
|
internal async Task TrackEvent(EventData eventData)
|
|
{
|
|
if (_http is null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
RefreshSession();
|
|
|
|
eventData.SessionId = _sessionId;
|
|
eventData.SystemProps = _sysInfo;
|
|
|
|
if (eventData.Props is null)
|
|
eventData.Props = new Dictionary<string, object>();
|
|
|
|
//eventData.Props["ipAddress"] = await GetPublicIpAddress(); 느려서 제외. 필요하면 다른 방법 사용 요망
|
|
|
|
var body = JsonContent.Create(eventData);
|
|
|
|
var response = await _http.PostAsync("/api/v0/event", body);
|
|
|
|
//var logPath = "aptabase-debug.log"; //파일 관리 안되므로 제거. 필요하면 다른 방법 사용 요망
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
{
|
|
if (response.StatusCode >= HttpStatusCode.InternalServerError ||
|
|
response.StatusCode == HttpStatusCode.RequestTimeout ||
|
|
response.StatusCode == HttpStatusCode.TooManyRequests)
|
|
{
|
|
// throw error, should be retried
|
|
response.EnsureSuccessStatusCode();
|
|
}
|
|
|
|
var responseBody = await response.Content.ReadAsStringAsync();
|
|
|
|
_logger?.LogError("Failed to perform TrackEvent due to {StatusCode} and response body {Body}", response.StatusCode, responseBody);
|
|
//File.AppendAllText(logPath, $"{eventData.EventName} Failed to perform TrackEvent due to {response.StatusCode} and response body {responseBody}\n");
|
|
}
|
|
else
|
|
{ var responseBody = await response.Content.ReadAsStringAsync();
|
|
//File.AppendAllText(logPath, $"{eventData.EventName} TrackEvent successful with response body {responseBody}\n");
|
|
}
|
|
}
|
|
|
|
private async Task<string> GetPublicIpAddress()
|
|
{
|
|
try
|
|
{
|
|
return await _ipClient.GetStringAsync("https://api.ipify.org");
|
|
}
|
|
catch
|
|
{
|
|
return "unknown";
|
|
}
|
|
}
|
|
|
|
public virtual ValueTask DisposeAsync()
|
|
{
|
|
_http?.Dispose();
|
|
|
|
return ValueTask.CompletedTask;
|
|
}
|
|
|
|
private void RefreshSession()
|
|
{
|
|
var now = DateTime.UtcNow;
|
|
var timeSince = now.Subtract(_lastTouched);
|
|
|
|
if (timeSince >= SESSION_TIMEOUT)
|
|
{
|
|
_sessionId = NewSessionId();
|
|
}
|
|
|
|
_lastTouched = now;
|
|
}
|
|
|
|
private static string NewSessionId()
|
|
{
|
|
var epochInSeconds = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
|
var random = _random.NextInt64(0, 99999999);
|
|
|
|
return (epochInSeconds * 100000000 + random).ToString();
|
|
}
|
|
|
|
private string? GetBaseUrl(string region, AptabaseOptions? options)
|
|
{
|
|
if (region == "SH")
|
|
{
|
|
if (string.IsNullOrEmpty(options?.Host))
|
|
{
|
|
_logger?.LogWarning("Host parameter must be defined when using Self-Hosted App Key. Tracking will be disabled.");
|
|
|
|
return null;
|
|
}
|
|
|
|
return options.Host;
|
|
}
|
|
|
|
return _hosts[region];
|
|
}
|
|
}
|
|
|