using molilian.core; using dodohold.core; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Mvc; using System.Text.Json; using TencentCloud.Ecm.V20190719.Models; using YunhuiKit; namespace molilian.api.Controllers { [ApiController] [Route("[controller]/[action]")] public class TracksController : ControllerBase { protected IHttpContextAccessor _accessor; public TracksController(IHttpContextAccessor accessor) { _accessor = accessor; } [HttpGet] public async Task Track([FromQuery] string? track_id = null, [FromQuery] string? unique_id = null, [FromQuery] string? scene = "", [FromQuery] string? account_id = null) { bool validTrackId = int.TryParse(track_id, out int parsedTrackId) && parsedTrackId > 0; int parsedAccountId = 0; bool validAccountId = string.IsNullOrWhiteSpace(account_id) || int.TryParse(account_id, out parsedAccountId); parsedAccountId = validAccountId ? Math.Max(parsedAccountId, 0) : 0; string requestUniqueId = unique_id ?? string.Empty; string requestScene = scene ?? string.Empty; await WriteTrackRequestTextLogAsync(track_id, unique_id, scene, account_id, parsedTrackId, validTrackId, parsedAccountId, validAccountId); if (!validTrackId) { return new APIResult(new { success = false, message = "miss" }); } var link = await TracksCore.GetLinkByIdAsync(parsedTrackId); if (link == null) { return new APIResult(new { success = false, message = "not found" }); } string trackScene = TracksCore.ResolveMetricScene(link, requestScene); var dto = new TrackRequestLogDTO { track_id = parsedTrackId, account_id = parsedAccountId, event_type = link.event_type, platform = link.platform, typename = link.typename, scene = trackScene, unique_id = requestUniqueId, ip = _accessor.HttpContext?.GetUserIp() ?? string.Empty, user_agent = Request.Headers.UserAgent.ToString(), referer = Request.Headers.Referer.ToString() }; _ = TracksCore.LogTrackRequestAsync(dto); _ = TracksCore.TrackAsync(link, trackScene, parsedAccountId); return new APIResult(new { success = true, message = "ok" }); } [HttpPost] public async Task Create([FromQuery] string eventType, [FromQuery] string platform = "", [FromQuery] string typename = "", [FromQuery] string scene = "", [FromQuery] string uniqueId = "", [FromQuery] string description = "") { if (string.IsNullOrWhiteSpace(typename)) typename = platform; if (string.IsNullOrWhiteSpace(platform)) platform = typename; var link = await TracksCore.CreateLinkAsync(eventType, platform, typename, scene, uniqueId, description); if (link == null) { return new APIResult(new { success = false, message = "invalid params or eventType" }); } //var request = _accessor.HttpContext!.Request; //string url = $"{request.Scheme}://{request.Host}{link.path}"; return new APIResult(new { success = true, message = "ok", url = link.path }); } [HttpGet] public async Task Daily([FromQuery] int daysAgo = 0, [FromQuery] string reportDate = "", [FromQuery] bool includeToday = true, [FromQuery] bool includeYesterday = true) { var dates = new List(); DateTime today = DateTime.Now.Date; if (!string.IsNullOrWhiteSpace(reportDate) && DateTime.TryParse(reportDate, out var parsed)) { dates.Add(parsed.Date); if (includeToday && parsed.Date != today) dates.Add(today); } else { if (daysAgo > 0) { var date = today.AddDays(-daysAgo); dates.Add(date); if (includeToday && date != today) dates.Add(today); } else { dates.Add(today); if (includeYesterday) dates.Add(today.AddDays(-1)); } } int rows = 0; var reportDates = new List(); var details = new List(); foreach (var date in dates.Distinct()) { int dateRows = await TracksCore.FlushDailyAsync(date); rows += dateRows; reportDates.Add(date.ToString("yyyy-MM-dd")); details.Add(new { reportDate = date.ToString("yyyy-MM-dd"), rows = dateRows }); } return new APIResult(new { success = true, message = "ok", rows, reportDates, details }); } private async Task WriteTrackRequestTextLogAsync( string? rawTrackId, string? rawUniqueId, string? rawScene, string? rawAccountId, int parsedTrackId, bool validTrackId, int parsedAccountId, bool validAccountId) { try { string rawTarget = HttpContext.Features.Get()?.RawTarget ?? $"{Request.Path}{Request.QueryString}"; string rawQuery = string.Empty; int rawQueryIndex = rawTarget.IndexOf('?'); if (rawQueryIndex >= 0 && rawQueryIndex < rawTarget.Length - 1) { rawQuery = rawTarget[(rawQueryIndex + 1)..]; } var logItem = new { time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), method = Request.Method, scheme = Request.Scheme, host = Request.Host.Value, path = Request.Path.Value ?? string.Empty, raw_target = rawTarget, raw_query = rawQuery, raw_query_string = Request.QueryString.Value ?? string.Empty, query = Request.Query.ToDictionary(item => item.Key, item => item.Value.ToArray()), bound = new { track_id = rawTrackId ?? string.Empty, unique_id = rawUniqueId ?? string.Empty, scene = rawScene ?? string.Empty, account_id = rawAccountId ?? string.Empty }, parsed = new { track_id = parsedTrackId, track_id_valid = validTrackId, account_id = parsedAccountId, account_id_valid = validAccountId }, ip = _accessor.HttpContext?.GetUserIp() ?? string.Empty, remote_ip = HttpContext.Connection.RemoteIpAddress?.ToString() ?? string.Empty, x_forwarded_for = Request.Headers["X-Forwarded-For"].ToString(), x_original_url = Request.Headers["X-Original-URL"].ToString(), x_rewrite_url = Request.Headers["X-Rewrite-URL"].ToString(), user_agent = Request.Headers.UserAgent.ToString(), referer = Request.Headers.Referer.ToString() }; await new LoggerLibrary("tracks", "track_request") .Info(JsonSerializer.Serialize(logItem)) .SaveAsync(); } catch (Exception ex) { _ = new LoggerLibrary("tracks", "track_request_error") .Info(ex.Message, ex.StackTrace) .SaveAsync(); } } } }