173 lines
4.5 KiB
C#
173 lines
4.5 KiB
C#
using MAX.Core.DependencyInjection;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Store.ImageCache.Dtos;
|
|
using Store.ImageCache.Entities;
|
|
using Store.ImageCache.Mapper;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
|
|
namespace Store.ImageCache.Services
|
|
{
|
|
public class ImageCacheService : ISingletonDependency
|
|
{
|
|
private const int Md5Length = 32;
|
|
private const int PlatformUrlMaxLength = 1000;
|
|
|
|
private readonly IFreeSql _freeSql;
|
|
private ImageCacheMapper mapper;
|
|
public ImageCacheService([FromKeyedServices("ImageCacheConnection")] IFreeSql freeSql)
|
|
{
|
|
mapper = new ImageCacheMapper();
|
|
if (freeSql == null)
|
|
{
|
|
throw new ArgumentNullException("freeSql");
|
|
}
|
|
|
|
_freeSql = freeSql;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 按 MD5 查询图片缓存;platform 为空时返回该 MD5 在所有平台的缓存。
|
|
/// </summary>
|
|
public ImageCacheDto GetByMd5(string sourceUrlMd5, byte? platform = null)
|
|
{
|
|
var md5 = NormalizeMd5(sourceUrlMd5);
|
|
return GetByMd5sInternal(new List<string> { md5 }, platform).FirstOrDefault();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 批量按 MD5 查询图片缓存。MD5 会按首字符分组,只查询对应的 images_0 到 images_f 分表。
|
|
/// </summary>
|
|
public List<ImageCacheDto> GetByMd5s(IEnumerable<string> sourceUrlMd5s, byte? platform = null)
|
|
{
|
|
return GetByMd5sInternal(NormalizeMd5s(sourceUrlMd5s), platform);
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// 按 MD5 和平台直接修改平台图片 URL,未找到时返回 false。
|
|
/// </summary>
|
|
public bool AddOrUpdate(string sourceUrlMd5, byte platform, string platformUrl)
|
|
{
|
|
var md5 = NormalizeMd5(sourceUrlMd5);
|
|
ValidatePlatformUrl(platformUrl);
|
|
var tableName = GetTableName(md5[0]);
|
|
var existing = _freeSql.Select<ImageCacheEntity>()
|
|
.AsTable((type, oldName) => tableName)
|
|
.Where(a => a.source_url_md5 == sourceUrlMd5 && a.platform == platform)
|
|
.First();
|
|
|
|
var now = DateTime.Now;
|
|
if (existing != null)
|
|
{
|
|
var affected = _freeSql.Update<ImageCacheEntity>()
|
|
.AsTable(tableName)
|
|
.Set(a => a.platform_url, platformUrl)
|
|
.Set(a => a.update_time, now)
|
|
.Where(a => a.source_url_md5 == md5 && a.platform == platform)
|
|
.ExecuteAffrows();
|
|
return affected > 0;
|
|
}
|
|
else
|
|
{
|
|
ImageCacheEntity imageCache = new ImageCacheEntity();
|
|
imageCache.id = 0;
|
|
imageCache.source_url_md5 = md5;
|
|
imageCache.platform = platform;
|
|
imageCache.platform_url = platformUrl;
|
|
imageCache.create_time = now;
|
|
imageCache.update_time = now;
|
|
imageCache.id = _freeSql.Insert(imageCache)
|
|
.AsTable(tableName)
|
|
.ExecuteIdentity();
|
|
return imageCache.id > 0;
|
|
}
|
|
}
|
|
|
|
private List<ImageCacheDto> GetByMd5sInternal(List<string> md5s, byte? platform)
|
|
{
|
|
var result = new List<ImageCacheDto>();
|
|
if (md5s.Count == 0)
|
|
{
|
|
return result;
|
|
}
|
|
|
|
foreach (var shard in md5s.GroupBy(a => a[0]))
|
|
{
|
|
var tableName = GetTableName(shard.Key);
|
|
var md5sInTable = shard.ToList();
|
|
var query = _freeSql.Select<ImageCacheEntity>()
|
|
.AsTable((type, oldName) => tableName)
|
|
.Where(a => md5sInTable.Contains(a.source_url_md5));
|
|
|
|
if (platform.HasValue)
|
|
{
|
|
var platformValue = platform.Value;
|
|
query = query.Where(a => a.platform == platformValue);
|
|
}
|
|
result.AddRange(query.ToList().Select(mapper.ToDto));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private List<string> NormalizeMd5s(IEnumerable<string> sourceUrlMd5s)
|
|
{
|
|
if (sourceUrlMd5s == null)
|
|
{
|
|
throw new ArgumentNullException("sourceUrlMd5s");
|
|
}
|
|
|
|
var result = new List<string>();
|
|
foreach (var sourceUrlMd5 in sourceUrlMd5s)
|
|
{
|
|
var md5 = NormalizeMd5(sourceUrlMd5);
|
|
if (!result.Contains(md5))
|
|
{
|
|
result.Add(md5);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private string NormalizeMd5(string sourceUrlMd5)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(sourceUrlMd5))
|
|
{
|
|
throw new ArgumentException("MD5 不能为空", "sourceUrlMd5");
|
|
}
|
|
|
|
var md5 = sourceUrlMd5.Trim().ToLowerInvariant();
|
|
if (md5.Length != Md5Length || md5.Any(a => !Uri.IsHexDigit(a)))
|
|
{
|
|
throw new ArgumentException("MD5 必须是 32 位十六进制字符串", "sourceUrlMd5");
|
|
}
|
|
|
|
return md5;
|
|
}
|
|
|
|
private string GetTableName(char shard)
|
|
{
|
|
return "images_" + shard;
|
|
}
|
|
|
|
|
|
|
|
private void ValidatePlatformUrl(string platformUrl)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(platformUrl))
|
|
{
|
|
throw new ArgumentException("平台图片 URL 不能为空", "platformUrl");
|
|
}
|
|
|
|
if (platformUrl.Length > PlatformUrlMaxLength)
|
|
{
|
|
throw new ArgumentException("平台图片 URL 长度不能超过 1000", "platformUrl");
|
|
}
|
|
}
|
|
}
|
|
}
|