2
0

3 Sitoutukset fa1018e925 ... c664af1279

Tekijä SHA1 Viesti Päivämäärä
  dodo hold c664af1279 fix(转链日志): 避免日志类型初始化失败 1 viikko sitten
  dodo hold 0c45b173a1 feat(淘宝账号池): 增加账号级 QPS 限制 1 viikko sitten
  dodo hold 17a212d4db 0820 2 viikkoa sitten

+ 4 - 2
molilian.api/Controllers/admin/TaobaoController.cs

@@ -101,8 +101,10 @@ namespace molilian.api.Controllers
                            .Update();
                     log.SaveAsync();
                     break;
-                case "time_range":
-                    int.TryParse(val, out int iVal);
+                case "time_range":
+                case "qps_limit":
+                    int.TryParse(val, out int iVal);
+                    if ("qps_limit".Equals(name) && iVal < 0) iVal = 0;
                     result = new DBContext.Table("tk_pool")
                            .Add(name, iVal)
                            .Add("last_time", DateTime.Now)

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 0 - 0
molilian.api/Properties/PublishProfiles/latest.pubxml.user


+ 5 - 6
molilian.core/Core/log/base.cs

@@ -11,12 +11,11 @@ namespace molilian.core
     public partial class TkLogCore
     {
 
-        public static bool save_dailys_log = false;
-
-        static TkLogCore()
-        {
-            int flag = RedisHelper.Get<int>("turn:save_dailys_log");
-            if (flag == 1) save_dailys_log = true;
+        public static bool save_dailys_log = false;
+
+        internal static void InitializeSaveDailyLogFlag()
+        {
+            save_dailys_log = RedisHelper.Get<int>("turn:save_dailys_log") == 1;
         }
         private static readonly SemaphoreSlim semaphore = new SemaphoreSlim(10, 10);
         private const int StatsHourlyExpireSeconds = 7 * 86400;

+ 59 - 49
molilian.core/Core/taoke/TkPoolCore.cs

@@ -1,6 +1,6 @@
 using dodohold.core;
-using Org.BouncyCastle.Bcpg.OpenPgp;
-using YunhuiKit;
+using Org.BouncyCastle.Bcpg.OpenPgp;
+using YunhuiKit;
 
 
 namespace molilian.core
@@ -22,7 +22,7 @@ namespace molilian.core
             _end_point = Environment.GetEnvironmentVariable("EndPoint");
         }
 
-        private static SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
+        private static SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
 
         private static IEnumerable<TkPoolDTO> _cached;
         private static IEnumerable<TkPoolDTO> _all_cached;
@@ -61,12 +61,12 @@ namespace molilian.core
             }
             return null;
         }
-        public static async Task<TkPoolDTO> GetOneAsync(TkAction action, bool isTaobaoUrl, string riskStrategy, int launchScene, string parse_type = "", string strategy_id = "")
+        public static async Task<TkPoolDTO> GetOneAsync(TkAction action, bool isTaobaoUrl, string riskStrategy, int launchScene, string parse_type = "", string strategy_id = "")
         {
             var list = await ListAsync().ConfigureAwait(false);
-            if (!list.Any())
-                return null;
-
+            if (!list.Any())
+                return null;
+
             // 获取所有账号(包括离线账号)
             var allAccounts = await AllListAsync().ConfigureAwait(false);
             if (allAccounts == null)
@@ -127,9 +127,9 @@ namespace molilian.core
 
             if (filteredList.Count == 0) return null;
 
-            // 1. 筛选出有可用端点的账号池,并计算权重
-            var weightedAccounts = new List<(TkPoolDTO account, int weight)>();
-            var random = new Random(Guid.NewGuid().GetHashCode()); // 避免重复种子问题
+            // 1. 筛选出有可用端点的账号池,并计算权重
+            var weightedAccounts = new List<(TkPoolDTO account, int weight)>();
+            var random = new Random(Guid.NewGuid().GetHashCode()); // 避免重复种子问题
 
             foreach (var item in filteredList)
             {
@@ -146,45 +146,55 @@ namespace molilian.core
                     .Where(e => !TkEndpointManager.IsEndpointSuspended(item.id, e.endpoint)) // 直接检查端点对象
                     .ToList();
 
-                if (availableEndpoints.Count == 0) continue;
-
-                // 计算账号权重(基于剩余调用量)
-                int weight = availableEndpoints.Sum(e =>
-                    e.hourly_calls_limit <= 0 ? 3600 : e.hourly_calls_limit - e.current_hourly_calls);
-
-                weightedAccounts.Add((item, weight));
-            }
-
-            if (weightedAccounts.Count == 0) return null;
-
-            // 2. 加权随机选择
-            int totalWeight = weightedAccounts.Sum(x => x.weight);
-            int randomNumber = random.Next(0, totalWeight);
-
-            foreach (var (account, weight) in weightedAccounts)
-            {
-                if (randomNumber < weight)
-                {
-                    if (await FilterNodesAsync(account, action).ConfigureAwait(false))
-                        return account;
-                    break; // 如果过滤失败,跳出当前循环
-                }
-                randomNumber -= weight;
-            }
-
-            // 3. 如果加权选择失败,回退到简单随机选择
-            var fallbackCandidates = weightedAccounts
-                .OrderBy(_ => random.Next())
-                .Select(x => x.account);
-
-            foreach (var account in fallbackCandidates)
-            {
-                if (await FilterNodesAsync(account, action).ConfigureAwait(false))
-                    return account;
-            }
-            return null;
-        }
-
+                if (availableEndpoints.Count == 0) continue;
+
+                // 计算账号权重(基于剩余调用量)
+                int weight = availableEndpoints.Sum(e =>
+                    e.hourly_calls_limit <= 0 ? 3600 : e.hourly_calls_limit - e.current_hourly_calls);
+
+                weightedAccounts.Add((item, weight));
+            }
+
+            if (weightedAccounts.Count == 0) return null;
+
+            // 2. 保留原有加权随机选择,选中账号超出 QPS 时继续尝试其他账号
+            int totalWeight = weightedAccounts.Sum(x => x.weight);
+            int randomNumber = random.Next(0, totalWeight);
+
+            foreach (var (account, weight) in weightedAccounts)
+            {
+                if (randomNumber < weight)
+                {
+                    if (await FilterNodesAsync(account, action).ConfigureAwait(false) && TryAcquireQps(account))
+                        return account;
+                    break;
+                }
+                randomNumber -= weight;
+            }
+
+            // 3. 选中账号不可用或超过 QPS 时,回退尝试其他候选账号
+            var fallbackCandidates = weightedAccounts
+                .OrderBy(_ => random.Next())
+                .Select(x => x.account);
+
+            foreach (var account in fallbackCandidates)
+            {
+                if (await FilterNodesAsync(account, action).ConfigureAwait(false) && TryAcquireQps(account))
+                    return account;
+            }
+            return null;
+        }
+
+        private static bool TryAcquireQps(TkPoolDTO account)
+        {
+            if (account == null) return false;
+
+            return SpecialBusinessRateLimiter.TryAcquire(
+                $"tk_pool_qps:{account.id}",
+                account.qps_limit,
+                TimeSpan.FromSeconds(1));
+        }
+
         private static async Task<bool> FilterNodesAsync(TkPoolDTO item, TkAction action)
         {
             if (!PassesFastAccountChecks(item, action)) return false;

+ 4 - 3
molilian.core/DTO/alimama/TkPoolDTO.cs

@@ -33,9 +33,10 @@
 
         public int daily_calls_limit { get; set; } = 0;
         public int current_hourly_calls { get; set; } = 0;
-        public int hourly_calls_limit { get; set; } = 0;
-        public int current_daily_calls { get; set; } = 0;
-        public int time_range { get; set; } = 0;
+        public int hourly_calls_limit { get; set; } = 0;
+        public int current_daily_calls { get; set; } = 0;
+        public int time_range { get; set; } = 0;
+        public int qps_limit { get; set; } = 0;
 
 
         public decimal draw_balance { get; set; } = 0;

+ 19 - 4
molilian.core/Plus/Alimama/parse.cs

@@ -252,6 +252,14 @@ namespace molilian.core
                     item.exposeTracks = TracksCore.BuildBrwSimilarPath(TrackType.Expose, result, item, i);
                     item.pic = NormalizeAlicdnImageUrl(item.pic);
                 }
+
+                DateTime now = DateTime.Now;
+                if (now < new DateTime(2026, 8, 22))
+                {
+                    _ = new LoggerLibrary("AlimamaPlus", "PromotionImageCount")
+                        .Info(now.ToString("yyyy-MM-dd HH:mm:ss.fff"), i.ToString())
+                        .SaveAsync();
+                }
             }
 
             result.pic = NormalizeAlicdnImageUrl(result.pic);
@@ -306,8 +314,10 @@ namespace molilian.core
             {
                 return items.Count > 0 ? items.Skip(1).ToList() : [];
             }
+
             string requestUrl = "https://similar.molilian.com/api/unsafePromotionQuery";
-            string targetPic = pic.StartsWith("//") ? $"https:{pic}" : pic;
+            string targetPic = NormalizeAlicdnImageUrl(pic.StartsWith("//") ? $"https:{pic}" : pic, 1200);
+
             object postData = new
             {
                 url = targetPic,
@@ -365,9 +375,13 @@ namespace molilian.core
             return [];
         }
 
-        private static string NormalizeAlicdnImageUrl(string pic)
+        private static string NormalizeAlicdnImageUrl(string pic, int size = 400)
         {
-            const string formatSuffix = "_400x400q90.jpg_.webp";
+            string formatSuffix = size switch
+            {
+                1200 => "_1200x1200q90.jpg_.webp",
+                _ => "_400x400q90.jpg_.webp"
+            };
 
             if (string.IsNullOrWhiteSpace(pic))
             {
@@ -379,7 +393,7 @@ namespace molilian.core
                 return pic;
             }
 
-            if (pic.Contains(formatSuffix, StringComparison.OrdinalIgnoreCase))
+            if (Regex.IsMatch(pic, @"_\d+x\d+q\d+\.jpg_\.webp(?:[?#].*)?$", RegexOptions.IgnoreCase))
             {
                 return pic;
             }
@@ -793,6 +807,7 @@ namespace molilian.core
                 case "tbpush":
                 case "brwsimilar":
                 case "icon":
+                case "req":
                     if (IsDigitsOnly(content))
                     {
                         content = $"https://item.taobao.com/item.htm?id={content}";

+ 3 - 1
molilian.core/Plus/pdd/PddUnionPlus.cs

@@ -220,8 +220,10 @@ namespace molilian.core
         {
             switch (request.RiskStrategy)
             {
-                case "icon":
                 case "tbpush":
+                case "brwsimilar":
+                case "icon":
+                case "req":
                     if (AlimamaPlus.IsDigitsOnly(request.Content))
                     {
                         request.Content = $"https://mobile.yangkeduo.com/goods.html?goods_id={request.Content}";

+ 4 - 3
molilian.core/middleware/CustomToken.cs

@@ -44,9 +44,10 @@ namespace molilian.core
                 var connstr = Environment.GetEnvironmentVariable("RedisConfig") ?? throw new ArgumentNullException("找不到对应的RedisConfig配置!");
                 RedisKit.InitializeAsync(connstr);
 
-                //初始化Redis
-                RedisUtility.Init();
-            }
+                //初始化Redis
+                RedisUtility.Init();
+                TkLogCore.InitializeSaveDailyLogFlag();
+            }
             catch (Exception ex)
             {
                 var endPoint = Environment.GetEnvironmentVariable("EndPoint");

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä