|
@@ -11,7 +11,7 @@ namespace molilian.core
|
|
|
{
|
|
{
|
|
|
public partial class TracksCore
|
|
public partial class TracksCore
|
|
|
{
|
|
{
|
|
|
- private const string RedisPrefix = ":tracks";
|
|
|
|
|
|
|
+ private const string RedisPrefix = ":tracks_v123";
|
|
|
private const int DailyExpireSeconds = 40 * 86400;
|
|
private const int DailyExpireSeconds = 40 * 86400;
|
|
|
private const int HourlyExpireSeconds = 7 * 86400; // keep a week of hourly buckets
|
|
private const int HourlyExpireSeconds = 7 * 86400; // keep a week of hourly buckets
|
|
|
private const string DefaultDimensionValue = "";
|
|
private const string DefaultDimensionValue = "";
|
|
@@ -21,71 +21,75 @@ namespace molilian.core
|
|
|
/// <summary>
|
|
/// <summary>
|
|
|
/// 生成一个监测链接(仅返回 path,不包含域名),同时落地到 track_links
|
|
/// 生成一个监测链接(仅返回 path,不包含域名),同时落地到 track_links
|
|
|
/// </summary>
|
|
/// </summary>
|
|
|
- public static Task<TrackLinkDTO> CreateLinkAsync(string eventType, string platform, string scene, string uniqueId)
|
|
|
|
|
|
|
+ public static Task<TrackLinkDTO> CreateLinkAsync(string eventType, string typename, string scene, string uniqueId, string description = "", bool forceNew = false)
|
|
|
{
|
|
{
|
|
|
eventType = NormalizeEventType(eventType);
|
|
eventType = NormalizeEventType(eventType);
|
|
|
- platform = Normalize(platform);
|
|
|
|
|
|
|
+ typename = Normalize(typename);
|
|
|
scene = NormalizeOrAll(scene);
|
|
scene = NormalizeOrAll(scene);
|
|
|
uniqueId = NormalizeOrAll(uniqueId);
|
|
uniqueId = NormalizeOrAll(uniqueId);
|
|
|
|
|
+ description = Normalize(description);
|
|
|
|
|
|
|
|
- if (!SupportEventTypes.Contains(eventType) || string.IsNullOrEmpty(platform))
|
|
|
|
|
|
|
+ if (!SupportEventTypes.Contains(eventType))
|
|
|
{
|
|
{
|
|
|
return Task.FromResult<TrackLinkDTO>(null);
|
|
return Task.FromResult<TrackLinkDTO>(null);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- string cacheKey = $"{RedisPrefix}:link:{eventType}:{platform}:{scene}:{uniqueId}";
|
|
|
|
|
- try
|
|
|
|
|
|
|
+ string cacheKey = $"{RedisPrefix}:link:{eventType}:{typename}:{scene}:{uniqueId}";
|
|
|
|
|
+ if (!forceNew)
|
|
|
{
|
|
{
|
|
|
- int cachedId = RedisHelper.Get<int>(cacheKey);
|
|
|
|
|
- if (cachedId > 0)
|
|
|
|
|
|
|
+ try
|
|
|
{
|
|
{
|
|
|
- string cachedPath = BuildPath(eventType, platform, scene, uniqueId);
|
|
|
|
|
- return Task.FromResult(new TrackLinkDTO
|
|
|
|
|
|
|
+ int cachedId = RedisHelper.Get<int>(cacheKey);
|
|
|
|
|
+ if (cachedId > 0)
|
|
|
{
|
|
{
|
|
|
- id = cachedId,
|
|
|
|
|
- event_type = eventType,
|
|
|
|
|
- platform = platform,
|
|
|
|
|
- scene = scene,
|
|
|
|
|
- unique_id = uniqueId,
|
|
|
|
|
- path = cachedPath
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ var cachedLink = RedisHelper.Get<TrackLinkDTO>(GetLinkIdCacheKey(cachedId));
|
|
|
|
|
+ if (cachedLink != null) return Task.FromResult(cachedLink);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ catch
|
|
|
|
|
+ {
|
|
|
|
|
+ // ignore cache errors
|
|
|
}
|
|
}
|
|
|
- }
|
|
|
|
|
- catch
|
|
|
|
|
- {
|
|
|
|
|
- // ignore cache errors
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- string path = BuildPath(eventType, platform, scene, uniqueId);
|
|
|
|
|
try
|
|
try
|
|
|
{
|
|
{
|
|
|
using var conn = DBContext.GetOpenConnection();
|
|
using var conn = DBContext.GetOpenConnection();
|
|
|
- var exist = new DBContext.Table(conn, "track_links")
|
|
|
|
|
- .Get<TrackLinkDTO>("event_type=@event_type AND platform=@platform AND scene=@scene AND unique_id=@unique_id",
|
|
|
|
|
- new { event_type = eventType, platform, scene, unique_id = uniqueId });
|
|
|
|
|
|
|
+ TrackLinkDTO exist = null;
|
|
|
|
|
+ if (!forceNew)
|
|
|
|
|
+ {
|
|
|
|
|
+ exist = new DBContext.Table(conn, "track_links")
|
|
|
|
|
+ .Get<TrackLinkDTO>("event_type=@event_type AND platform=@platform AND scene=@scene AND unique_id=@unique_id",
|
|
|
|
|
+ new { event_type = eventType, platform = typename, scene, unique_id = uniqueId });
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
if (exist != null)
|
|
if (exist != null)
|
|
|
{
|
|
{
|
|
|
- if (string.IsNullOrEmpty(exist.path))
|
|
|
|
|
|
|
+ exist.description = description;
|
|
|
|
|
+ string path = BuildPath(exist.id, eventType);
|
|
|
|
|
+ if (string.IsNullOrEmpty(exist.path) || !exist.path.Contains("track_id"))
|
|
|
{
|
|
{
|
|
|
exist.path = path;
|
|
exist.path = path;
|
|
|
new DBContext.Table(conn, "track_links")
|
|
new DBContext.Table(conn, "track_links")
|
|
|
.Add("path", path)
|
|
.Add("path", path)
|
|
|
|
|
+ .Add("description", description)
|
|
|
.Add("update_time", DateTime.Now)
|
|
.Add("update_time", DateTime.Now)
|
|
|
.Where("id=@id", new { exist.id })
|
|
.Where("id=@id", new { exist.id })
|
|
|
.Update();
|
|
.Update();
|
|
|
}
|
|
}
|
|
|
_ = RedisHelper.Set(cacheKey, exist.id, LinkCacheExpireSeconds);
|
|
_ = RedisHelper.Set(cacheKey, exist.id, LinkCacheExpireSeconds);
|
|
|
|
|
+ _ = RedisHelper.Set(GetLinkIdCacheKey(exist.id), exist, LinkCacheExpireSeconds);
|
|
|
return Task.FromResult(exist);
|
|
return Task.FromResult(exist);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
var item = new TrackLinkDTO
|
|
var item = new TrackLinkDTO
|
|
|
{
|
|
{
|
|
|
event_type = eventType,
|
|
event_type = eventType,
|
|
|
- platform = platform,
|
|
|
|
|
|
|
+ platform = typename,
|
|
|
scene = scene,
|
|
scene = scene,
|
|
|
unique_id = uniqueId,
|
|
unique_id = uniqueId,
|
|
|
- path = path,
|
|
|
|
|
|
|
+ path = string.Empty,
|
|
|
|
|
+ description = description,
|
|
|
create_time = DateTime.Now,
|
|
create_time = DateTime.Now,
|
|
|
update_time = DateTime.Now
|
|
update_time = DateTime.Now
|
|
|
};
|
|
};
|
|
@@ -94,8 +98,16 @@ namespace molilian.core
|
|
|
if (id != null && int.TryParse(id.ToString(), out var linkId))
|
|
if (id != null && int.TryParse(id.ToString(), out var linkId))
|
|
|
{
|
|
{
|
|
|
item.id = linkId;
|
|
item.id = linkId;
|
|
|
|
|
+ item.path = BuildPath(linkId, eventType);
|
|
|
|
|
+ new DBContext.Table(conn, "track_links")
|
|
|
|
|
+ .Add("path", item.path)
|
|
|
|
|
+ .Add("description", description)
|
|
|
|
|
+ .Add("update_time", DateTime.Now)
|
|
|
|
|
+ .Where("id=@id", new { item.id })
|
|
|
|
|
+ .Update();
|
|
|
}
|
|
}
|
|
|
_ = RedisHelper.Set(cacheKey, item.id, LinkCacheExpireSeconds);
|
|
_ = RedisHelper.Set(cacheKey, item.id, LinkCacheExpireSeconds);
|
|
|
|
|
+ _ = RedisHelper.Set(GetLinkIdCacheKey(item.id), item, LinkCacheExpireSeconds);
|
|
|
return Task.FromResult(item);
|
|
return Task.FromResult(item);
|
|
|
}
|
|
}
|
|
|
catch (Exception ex)
|
|
catch (Exception ex)
|
|
@@ -117,7 +129,7 @@ namespace molilian.core
|
|
|
scene = NormalizeOrAll(scene);
|
|
scene = NormalizeOrAll(scene);
|
|
|
uniqueId = NormalizeOrAll(uniqueId);
|
|
uniqueId = NormalizeOrAll(uniqueId);
|
|
|
|
|
|
|
|
- if (!SupportEventTypes.Contains(eventType) || string.IsNullOrEmpty(platform))
|
|
|
|
|
|
|
+ if (!SupportEventTypes.Contains(eventType))
|
|
|
{
|
|
{
|
|
|
return Task.FromResult(false);
|
|
return Task.FromResult(false);
|
|
|
}
|
|
}
|
|
@@ -233,22 +245,51 @@ namespace molilian.core
|
|
|
return rows;
|
|
return rows;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- public static string BuildPath(string eventType, string platform, string scene, string uniqueId)
|
|
|
|
|
|
|
+ public static string BuildPath(int trackId, string eventType)
|
|
|
{
|
|
{
|
|
|
|
|
+ eventType = NormalizeEventType(eventType);
|
|
|
string safeEventType = WebUtility.UrlEncode(eventType);
|
|
string safeEventType = WebUtility.UrlEncode(eventType);
|
|
|
- string safePlatform = WebUtility.UrlEncode(platform);
|
|
|
|
|
- string safeScene = WebUtility.UrlEncode(scene);
|
|
|
|
|
- string safeUniqueId = WebUtility.UrlEncode(uniqueId);
|
|
|
|
|
- return $"https://api.molilian.com/tracks/track?eventType={safeEventType}&platform={safePlatform}&scene={safeScene}&uniqueId={safeUniqueId}";
|
|
|
|
|
|
|
+ return $"https://api.molilian.com/tracks/track?track_id={trackId}&eventType={safeEventType}";
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- public static string GetLinkCacheKey(string eventType, string platform, string scene, string uniqueId)
|
|
|
|
|
|
|
+ public static string GetLinkCacheKey(string eventType, string typename, string scene, string uniqueId)
|
|
|
{
|
|
{
|
|
|
eventType = NormalizeEventType(eventType);
|
|
eventType = NormalizeEventType(eventType);
|
|
|
- platform = Normalize(platform);
|
|
|
|
|
|
|
+ typename = Normalize(typename);
|
|
|
scene = NormalizeOrAll(scene);
|
|
scene = NormalizeOrAll(scene);
|
|
|
uniqueId = NormalizeOrAll(uniqueId);
|
|
uniqueId = NormalizeOrAll(uniqueId);
|
|
|
- return $"{RedisPrefix}:link:{eventType}:{platform}:{scene}:{uniqueId}";
|
|
|
|
|
|
|
+ return $"{RedisPrefix}:link:{eventType}:{typename}:{scene}:{uniqueId}";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public static string GetLinkIdCacheKey(int trackId)
|
|
|
|
|
+ {
|
|
|
|
|
+ return $"{RedisPrefix}:linkid:{trackId}";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public static async Task<TrackLinkDTO> GetLinkByIdAsync(int trackId)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (trackId <= 0) return null;
|
|
|
|
|
+ string cacheKey = GetLinkIdCacheKey(trackId);
|
|
|
|
|
+ try
|
|
|
|
|
+ {
|
|
|
|
|
+ var cached = RedisHelper.Get<TrackLinkDTO>(cacheKey);
|
|
|
|
|
+ if (cached != null) return cached;
|
|
|
|
|
+ }
|
|
|
|
|
+ catch { }
|
|
|
|
|
+
|
|
|
|
|
+ try
|
|
|
|
|
+ {
|
|
|
|
|
+ var item = new DBContext.Table("track_links").Get<TrackLinkDTO>("id=@id", new { id = trackId });
|
|
|
|
|
+ if (item != null)
|
|
|
|
|
+ {
|
|
|
|
|
+ _ = RedisHelper.Set(cacheKey, item, LinkCacheExpireSeconds);
|
|
|
|
|
+ }
|
|
|
|
|
+ return item;
|
|
|
|
|
+ }
|
|
|
|
|
+ catch
|
|
|
|
|
+ {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private static string Normalize(string value)
|
|
private static string Normalize(string value)
|