TracksController.cs 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. using molilian.core;
  2. using dodohold.core;
  3. using Microsoft.AspNetCore.Http.Features;
  4. using Microsoft.AspNetCore.Mvc;
  5. using System.Text.Json;
  6. using TencentCloud.Ecm.V20190719.Models;
  7. using YunhuiKit;
  8. namespace molilian.api.Controllers
  9. {
  10. [ApiController]
  11. [Route("[controller]/[action]")]
  12. public class TracksController : ControllerBase
  13. {
  14. protected IHttpContextAccessor _accessor;
  15. public TracksController(IHttpContextAccessor accessor)
  16. {
  17. _accessor = accessor;
  18. }
  19. [HttpGet]
  20. public async Task<ActionResult> Track([FromQuery] string? track_id = null, [FromQuery] string? unique_id = null, [FromQuery] string? scene = "", [FromQuery] string? account_id = null)
  21. {
  22. bool validTrackId = int.TryParse(track_id, out int parsedTrackId) && parsedTrackId > 0;
  23. int parsedAccountId = 0;
  24. bool validAccountId = string.IsNullOrWhiteSpace(account_id) || int.TryParse(account_id, out parsedAccountId);
  25. parsedAccountId = validAccountId ? Math.Max(parsedAccountId, 0) : 0;
  26. string requestUniqueId = unique_id ?? string.Empty;
  27. string requestScene = scene ?? string.Empty;
  28. var link = validTrackId ? await TracksCore.GetLinkByIdAsync(parsedTrackId) : null;
  29. // 隐藏号的曝光/点击不留任何记录
  30. if (await TracksCore.IsHiddenTrackAccountAsync(link, parsedAccountId))
  31. {
  32. return new APIResult(new { success = true, message = "ok" });
  33. }
  34. await WriteTrackRequestTextLogAsync(track_id, unique_id, scene, account_id, parsedTrackId, validTrackId, parsedAccountId, validAccountId);
  35. if (!validTrackId)
  36. {
  37. return new APIResult(new { success = false, message = "miss" });
  38. }
  39. if (link == null)
  40. {
  41. return new APIResult(new { success = false, message = "not found" });
  42. }
  43. string trackScene = TracksCore.ResolveMetricScene(link, requestScene);
  44. var dto = new TrackRequestLogDTO
  45. {
  46. track_id = parsedTrackId,
  47. account_id = parsedAccountId,
  48. event_type = link.event_type,
  49. platform = link.platform,
  50. typename = link.typename,
  51. scene = trackScene,
  52. unique_id = requestUniqueId,
  53. ip = _accessor.HttpContext?.GetUserIp() ?? string.Empty,
  54. user_agent = Request.Headers.UserAgent.ToString(),
  55. referer = Request.Headers.Referer.ToString()
  56. };
  57. _ = TracksCore.LogTrackRequestAsync(dto);
  58. _ = TracksCore.TrackAsync(link, trackScene, parsedAccountId);
  59. return new APIResult(new { success = true, message = "ok" });
  60. }
  61. [HttpPost]
  62. public async Task<ActionResult> Create([FromQuery] string eventType, [FromQuery] string platform = "", [FromQuery] string typename = "", [FromQuery] string scene = "", [FromQuery] string uniqueId = "", [FromQuery] string description = "")
  63. {
  64. if (string.IsNullOrWhiteSpace(typename)) typename = platform;
  65. if (string.IsNullOrWhiteSpace(platform)) platform = typename;
  66. var link = await TracksCore.CreateLinkAsync(eventType, platform, typename, scene, uniqueId, description);
  67. if (link == null)
  68. {
  69. return new APIResult(new { success = false, message = "invalid params or eventType" });
  70. }
  71. //var request = _accessor.HttpContext!.Request;
  72. //string url = $"{request.Scheme}://{request.Host}{link.path}";
  73. return new APIResult(new { success = true, message = "ok", url = link.path });
  74. }
  75. [HttpGet]
  76. public async Task<ActionResult> Daily([FromQuery] int daysAgo = 0, [FromQuery] string reportDate = "", [FromQuery] bool includeToday = true, [FromQuery] bool includeYesterday = true)
  77. {
  78. var dates = new List<DateTime>();
  79. DateTime today = DateTime.Now.Date;
  80. if (!string.IsNullOrWhiteSpace(reportDate) && DateTime.TryParse(reportDate, out var parsed))
  81. {
  82. dates.Add(parsed.Date);
  83. if (includeToday && parsed.Date != today) dates.Add(today);
  84. }
  85. else
  86. {
  87. if (daysAgo > 0)
  88. {
  89. var date = today.AddDays(-daysAgo);
  90. dates.Add(date);
  91. if (includeToday && date != today) dates.Add(today);
  92. }
  93. else
  94. {
  95. dates.Add(today);
  96. if (includeYesterday) dates.Add(today.AddDays(-1));
  97. }
  98. }
  99. int rows = 0;
  100. var reportDates = new List<string>();
  101. var details = new List<object>();
  102. foreach (var date in dates.Distinct())
  103. {
  104. int dateRows = await TracksCore.FlushDailyAsync(date);
  105. rows += dateRows;
  106. reportDates.Add(date.ToString("yyyy-MM-dd"));
  107. details.Add(new { reportDate = date.ToString("yyyy-MM-dd"), rows = dateRows });
  108. }
  109. return new APIResult(new { success = true, message = "ok", rows, reportDates, details });
  110. }
  111. private async Task WriteTrackRequestTextLogAsync(
  112. string? rawTrackId,
  113. string? rawUniqueId,
  114. string? rawScene,
  115. string? rawAccountId,
  116. int parsedTrackId,
  117. bool validTrackId,
  118. int parsedAccountId,
  119. bool validAccountId)
  120. {
  121. try
  122. {
  123. string rawTarget = HttpContext.Features.Get<IHttpRequestFeature>()?.RawTarget ?? $"{Request.Path}{Request.QueryString}";
  124. string rawQuery = string.Empty;
  125. int rawQueryIndex = rawTarget.IndexOf('?');
  126. if (rawQueryIndex >= 0 && rawQueryIndex < rawTarget.Length - 1)
  127. {
  128. rawQuery = rawTarget[(rawQueryIndex + 1)..];
  129. }
  130. var logItem = new
  131. {
  132. time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"),
  133. method = Request.Method,
  134. scheme = Request.Scheme,
  135. host = Request.Host.Value,
  136. path = Request.Path.Value ?? string.Empty,
  137. raw_target = rawTarget,
  138. raw_query = rawQuery,
  139. raw_query_string = Request.QueryString.Value ?? string.Empty,
  140. query = Request.Query.ToDictionary(item => item.Key, item => item.Value.ToArray()),
  141. bound = new
  142. {
  143. track_id = rawTrackId ?? string.Empty,
  144. unique_id = rawUniqueId ?? string.Empty,
  145. scene = rawScene ?? string.Empty,
  146. account_id = rawAccountId ?? string.Empty
  147. },
  148. parsed = new
  149. {
  150. track_id = parsedTrackId,
  151. track_id_valid = validTrackId,
  152. account_id = parsedAccountId,
  153. account_id_valid = validAccountId
  154. },
  155. ip = _accessor.HttpContext?.GetUserIp() ?? string.Empty,
  156. remote_ip = HttpContext.Connection.RemoteIpAddress?.ToString() ?? string.Empty,
  157. x_forwarded_for = Request.Headers["X-Forwarded-For"].ToString(),
  158. x_original_url = Request.Headers["X-Original-URL"].ToString(),
  159. x_rewrite_url = Request.Headers["X-Rewrite-URL"].ToString(),
  160. user_agent = Request.Headers.UserAgent.ToString(),
  161. referer = Request.Headers.Referer.ToString()
  162. };
  163. await new LoggerLibrary("tracks", "track_request")
  164. .Info(JsonSerializer.Serialize(logItem))
  165. .SaveAsync();
  166. }
  167. catch (Exception ex)
  168. {
  169. _ = new LoggerLibrary("tracks", "track_request_error")
  170. .Info(ex.Message, ex.StackTrace)
  171. .SaveAsync();
  172. }
  173. }
  174. }
  175. }