Kaynağa Gözat

0320 增加push报告

dodo hold 1 yıl önce
ebeveyn
işleme
b16fb68e96

+ 26 - 1
molilian.api/Controllers/public/TaskController.cs

@@ -12,6 +12,7 @@ using System.Security.Cryptography;
 using System.Threading;
 using TencentCloud.Batch.V20170312.Models;
 using Org.BouncyCastle.Bcpg.OpenPgp;
+using Microsoft.VisualBasic;
 
 namespace molilian.api.Controllers
 {
@@ -27,6 +28,28 @@ namespace molilian.api.Controllers
         }
 
 
+        [HttpGet]
+        public async Task<ActionResult> FillPushReortData(DateTime date = default)
+        {
+            PushDataReportCore core = new();
+            if (date == default) date = DateTime.Now.AddDays(-1);
+
+            int count = await core.FillData(date);
+            return new APIResult(new { success = true, count });
+        }
+
+
+        [HttpGet]
+        public async Task<ActionResult> PushReportData(int repush = 0, DateTime date = default)
+        {
+            PushDataReportCore core = new();
+            if (date == default) date = DateTime.Now.AddDays(-1);
+
+            int count = await core.PushReportData(date, repush == 1);
+            return new APIResult(new { success = true, count });
+        }
+
+
 
         [HttpGet]
         public async Task<ActionResult> GetRawItemIdTask(int limit = 100)
@@ -524,6 +547,9 @@ namespace molilian.api.Controllers
             {
                 foreach (var account in list)
                 {
+#if DEBUG
+                    if (account.id != 38) continue;
+#endif
                     try
                     {
                         account.current_daily_calls = await RiskControlCore.GetAllNodesCallsAsync(TkChannelEnum.tb, account.id, DateTime.Now.ToString("yyyyMMdd"));
@@ -548,7 +574,6 @@ namespace molilian.api.Controllers
                     }
 
                     if (!account.enable_sync_order) continue;
-                    if (account.is_hide) continue;
                     try
                     {
                         var alimama = new AlimamaPlus(account);

+ 1 - 1
molilian.api/Controllers/public/TestController.cs

@@ -15,6 +15,7 @@ using System.Text.RegularExpressions;
 using System.Text;
 using TencentCloud.Oceanus.V20190422.Models;
 using YunhuiKit;
+using TencentCloud.Cdn.V20180606.Models;
 
 namespace molilian.api.Controllers
 {
@@ -40,7 +41,6 @@ namespace molilian.api.Controllers
 
         }
 
-
         [HttpGet]
         public async Task<ActionResult> ChangePublicIp(int id)
         {

Dosya farkı çok büyük olduğundan ihmal edildi
+ 0 - 0
molilian.api/Properties/PublishProfiles/latest.pubxml.user


+ 411 - 0
molilian.core/Core/PushDataReport/Enum.cs

@@ -0,0 +1,411 @@
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc.Controllers;
+using Microsoft.AspNetCore.Mvc.Filters;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using dodohold.core;
+using System.Xml.Linq;
+using YunhuiKit;
+using System.Text.Json;
+using COSXML.Network;
+
+
+namespace molilian.core.PushDataReport;
+
+public class ResponseDTO
+{
+    public int code { get; set; } = 0;
+    public string message { get; set; } = string.Empty;
+    public string requestId { get; set; } = string.Empty;
+}
+
+public enum PlatformEnum
+{
+    /// <summary>
+    /// 未知
+    /// </summary>
+    Unknown = 0,
+
+    /// <summary>
+    /// 淘宝
+    /// </summary>
+    Taobao = 1,
+
+    /// <summary>
+    /// 抖音
+    /// </summary>
+    Douyin = 2,
+
+    /// <summary>
+    /// 天猫
+    /// </summary>
+    Tmall = 4,
+
+    /// <summary>
+    /// 百度网盘
+    /// </summary>
+    BaiduNetdisk = 7,
+
+    /// <summary>
+    /// 腾讯会议
+    /// </summary>
+    TencentMeeting = 8,
+
+    /// <summary>
+    /// 拼多多
+    /// </summary>
+    Pinduoduo = 9,
+
+    /// <summary>
+    /// 拼多多H5
+    /// </summary>
+    PinduoduoH5 = 10,
+
+    /// <summary>
+    /// 支付宝
+    /// </summary>
+    Alipay = 11,
+
+    /// <summary>
+    /// 快手
+    /// </summary>
+    Kuaishou = 12,
+
+    /// <summary>
+    /// 京东
+    /// </summary>
+    JD = 13,
+
+    /// <summary>
+    /// 安居客
+    /// </summary>
+    Anjuke = 27,
+
+    /// <summary>
+    /// 抖音商城
+    /// </summary>
+    DouyinMall = 28,
+
+    /// <summary>
+    /// 番茄畅听音乐版
+    /// </summary>
+    FanqieMusic = 29,
+
+    /// <summary>
+    /// 唯品会
+    /// </summary>
+    Vipshop = 30,
+
+    /// <summary>
+    /// 京东金融
+    /// </summary>
+    JDFinance = 32,
+
+    /// <summary>
+    /// 爱奇艺极速版
+    /// </summary>
+    IqiyiLite = 33,
+
+    /// <summary>
+    /// 安逸花
+    /// </summary>
+    Anyihua = 34,
+
+    /// <summary>
+    /// 同程旅行
+    /// </summary>
+    TongchengTravel = 35,
+
+    /// <summary>
+    /// 河马剧场
+    /// </summary>
+    HemaTheater = 36,
+
+    /// <summary>
+    /// BOSS直聘
+    /// </summary>
+    BossZhipin = 37,
+
+    /// <summary>
+    /// 喜马拉雅
+    /// </summary>
+    Ximalaya = 38,
+
+    /// <summary>
+    /// QQ浏览器
+    /// </summary>
+    QQBrowser = 39,
+
+    /// <summary>
+    /// 咪咕视频
+    /// </summary>
+    MiguVideo = 40,
+
+    /// <summary>
+    /// 飞猪旅行
+    /// </summary>
+    Fliggy = 41,
+
+    /// <summary>
+    /// 途虎养车
+    /// </summary>
+    Tuhu = 42,
+
+    /// <summary>
+    /// 桔多多
+    /// </summary>
+    Juduoduo = 43,
+
+    /// <summary>
+    /// Keep
+    /// </summary>
+    Keep = 44,
+
+    /// <summary>
+    /// 百度文库
+    /// </summary>
+    BaiduWenku = 45,
+
+    /// <summary>
+    /// TT语音
+    /// </summary>
+    TTVoice = 46,
+
+    /// <summary>
+    /// 通义
+    /// </summary>
+    Tongyi = 47,
+
+    /// <summary>
+    /// 起点读书
+    /// </summary>
+    Qidian = 48,
+
+    /// <summary>
+    /// 搜狐新闻
+    /// </summary>
+    SohuNews = 49,
+
+    /// <summary>
+    /// YY
+    /// </summary>
+    YY = 50,
+
+    /// <summary>
+    /// 腾讯新闻
+    /// </summary>
+    TencentNews = 52,
+
+    /// <summary>
+    /// 网易云音乐
+    /// </summary>
+    NetEaseMusic = 53,
+
+    /// <summary>
+    /// QQ音乐
+    /// </summary>
+    QQMusic = 54,
+
+    /// <summary>
+    /// 酷狗音乐
+    /// </summary>
+    KugouMusic = 55,
+
+    /// <summary>
+    /// 全民K歌
+    /// </summary>
+    QuanminKge = 56,
+
+    /// <summary>
+    /// 识货
+    /// </summary>
+    Shihuo = 57,
+
+    /// <summary>
+    /// 酷我音乐
+    /// </summary>
+    KuwoMusic = 58,
+
+    /// <summary>
+    /// 微博
+    /// </summary>
+    Weibo = 59,
+
+    /// <summary>
+    /// 转转
+    /// </summary>
+    Zhuanzhuan = 60,
+
+    /// <summary>
+    /// 快手极速版
+    /// </summary>
+    KuaishouLite = 61,
+
+    /// <summary>
+    /// 抖音极速版
+    /// </summary>
+    DouyinLite = 62,
+
+    /// <summary>
+    /// 百度极速版
+    /// </summary>
+    BaiduLite = 63,
+
+    /// <summary>
+    /// 搜狐视频
+    /// </summary>
+    SohuVideo = 64,
+
+    /// <summary>
+    /// 酷安
+    /// </summary>
+    Coolapk = 65,
+
+    /// <summary>
+    /// 好看视频
+    /// </summary>
+    HaokanVideo = 66,
+
+    /// <summary>
+    /// 大众点评
+    /// </summary>
+    Dianping = 67,
+
+    /// <summary>
+    /// 虎牙直播
+    /// </summary>
+    Huya = 68,
+
+    /// <summary>
+    /// 番茄免费小说
+    /// </summary>
+    FanqieNovel = 101,
+
+    /// <summary>
+    /// 红果免费短剧
+    /// </summary>
+    HongguoDrama = 102,
+
+    /// <summary>
+    /// 阿里巴巴
+    /// </summary>
+    Alibaba = 103,
+
+    /// <summary>
+    /// 百度
+    /// </summary>
+    Baidu = 104,
+
+    /// <summary>
+    /// 番茄畅听
+    /// </summary>
+    FanqieAudio = 105,
+
+    /// <summary>
+    /// 小红书
+    /// </summary>
+    Xiaohongshu = 106,
+
+    /// <summary>
+    /// 美团
+    /// </summary>
+    Meituan = 107,
+
+    /// <summary>
+    /// 西瓜视频
+    /// </summary>
+    XiguaVideo = 108,
+
+    /// <summary>
+    /// 抖音火山版
+    /// </summary>
+    DouyinHuoshan = 109,
+
+    /// <summary>
+    /// 饿了么
+    /// </summary>
+    Eleme = 110,
+
+    /// <summary>
+    /// 优酷视频
+    /// </summary>
+    Youku = 111,
+
+    /// <summary>
+    /// 今日头条
+    /// </summary>
+    Toutiao = 112,
+
+    /// <summary>
+    /// 得物
+    /// </summary>
+    Dewu = 113,
+
+    /// <summary>
+    /// 七猫免费小说
+    /// </summary>
+    QimaoNovel = 114,
+
+    /// <summary>
+    /// 夸克
+    /// </summary>
+    Quark = 115,
+
+    /// <summary>
+    /// 悟空浏览器
+    /// </summary>
+    WukongBrowser = 116,
+
+    /// <summary>
+    /// 豆包
+    /// </summary>
+    Doubao = 117,
+
+    /// <summary>
+    /// 懂车帝
+    /// </summary>
+    Dongchedi = 118,
+
+    /// <summary>
+    /// 腾讯视频
+    /// </summary>
+    TencentVideo = 119,
+
+    /// <summary>
+    /// 哔哩哔哩
+    /// </summary>
+    Bilibili = 120,
+
+    /// <summary>
+    /// 头条搜索极速版
+    /// </summary>
+    ToutiaoSearchLite = 121,
+
+    /// <summary>
+    /// 爱奇艺
+    /// </summary>
+    Iqiyi = 122,
+
+    /// <summary>
+    /// 闲鱼
+    /// </summary>
+    Xianyu = 123,
+
+    /// <summary>
+    /// 携程旅行
+    /// </summary>
+    Ctrip = 124,
+
+    /// <summary>
+    /// Soul
+    /// </summary>
+    Soul = 125,
+
+    /// <summary>
+    /// UC浏览器
+    /// </summary>
+    UCBrowser = 126
+}
+

+ 225 - 0
molilian.core/Core/PushDataReport/PushDataReportCore.cs

@@ -0,0 +1,225 @@
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc.Controllers;
+using Microsoft.AspNetCore.Mvc.Filters;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using dodohold.core;
+using Dataoke;
+using Google.Protobuf.WellKnownTypes;
+using System.Xml.Linq;
+using Mysqlx.Crud;
+using ZstdSharp.Unsafe;
+using YunhuiKit;
+using COSXML.Network;
+using System.Threading.Channels;
+using TencentCloud.Apm.V20210622.Models;
+using static QRCoder.PayloadGenerator;
+using TencentCloud.Tcm.V20210413.Models;
+using TencentCloud.Tione.V20211111.Models;
+using TencentCloud.Cdn.V20180606.Models;
+using static molilian.core.ApiReportCore;
+using molilian.core.PushDataReport;
+using Org.BouncyCastle.Asn1.Ocsp;
+
+
+namespace molilian.core
+{
+
+    public partial class PushDataReportCore
+    {
+        private PushDataReportPush plus;
+        public PushDataReportCore()
+        {
+            plus = new PushDataReportPush();
+        }
+        public bool FillReportData(DateTime date)
+        {
+            return true;
+        }
+
+        public async Task<int> FillData(DateTime reportDatetime)
+        {
+            int count = 0;
+            count += await FillToolData(reportDatetime);
+            count += await FillParseData(reportDatetime);
+            count += await FillDeeplinkData(reportDatetime);
+            return count;
+        }
+        public async Task<int> FillParseData(DateTime reportDatetime)
+        {
+            var conn = DBContext.GetOpenConnection();
+            try
+            {
+                var platform_list = new List<DeeplinkParseRuleDTO>()
+                {
+                    new() { channel_id = 0,  push_channel_id = 1, channel_name = "tb" },
+                    new() { channel_id = 1, push_channel_id = 13, channel_name = "jd" },
+                    new() { channel_id = 3,  push_channel_id = 9, channel_name = "pdd" }
+                };
+
+
+                int data_type = 1; //转链数据
+                int count = 0;
+                foreach (var p in platform_list)
+                {
+                    int platform = p.channel_id;
+                    string filter = "`is_show`=@is_show AND data_type=@data_type AND platform=@platform AND report_date=@report_date";
+
+                    string orderBy = "report_date DESC";
+
+                    var list = new DBContext.Table("api_call_report_dailys")
+                                .Where(filter, new { is_show = true, platform, data_type, report_date = reportDatetime.Date })
+                                .Order(orderBy)
+                                .Select<RecordDTO>().ToList();
+
+                    foreach (var data in list)
+                    {
+                        //描述:0:全分销类型;-1:各分销类型,1:goods 2: live 3:video 4: profile 5: unknown
+
+                        //int[] distributiontype_list = [1, 2, 3, 4, 5, 6, 7];
+
+                        //foreach (var distribution in distributiontype_list)
+                        {
+                            int distribution = 0;
+                            var item = new PushDataReportDTO();
+                            item.report_date = reportDatetime.Date;
+                            item.platform = p.push_channel_id;
+                            item.platform_name = p.channel_name;
+                            item.type = data_type;
+                            item.distribution = distribution;
+                            item.req_count = data.total_count;
+                            item.dp_transition_succ_count = data.success_count;
+                            item.click_count = data.uclk_pv;
+                            item.click_user_count = data.uclk_uv;
+                            item.order_count = data.eff_ord_num;
+                            item.order_user_count = data.pay_ord_uv;
+                            item.Gmv = data.eff_ord_amt;
+                            item.income = data.eff_tk_disp_tfee;
+                            conn.Replace<PushDataReportDTO>(item);
+                            count++;
+                        }
+                    }
+                }
+                return count;
+            }
+            catch (Exception ex)
+            {
+                //暂时不记录日志
+                return 0;
+            }
+        }
+
+        public async Task<int> FillToolData(DateTime reportDatetime)
+        {
+            var conn = DBContext.GetOpenConnection();
+            try
+            {
+                var list = new List<DeeplinkParseRuleDTO>()
+                {
+                    new() { push_channel_id = 7, channel_name = "bdpan" },
+                    new() { push_channel_id = 8, channel_name = "wemeet" }
+                };
+
+                int count = 0;
+                foreach (var deeplink in list)
+                {
+                    string accountName = $"{deeplink.channel_name}";
+                    int all_total = await TkLogCore.GetTotalAsync($":parse_total:{deeplink.channel_name}:{reportDatetime:yyyyMMdd}");
+                    int success_total = await TkLogCore.GetTotalAsync($":parse_total:{deeplink.channel_name}:success:{reportDatetime:yyyyMMdd}");
+
+                    var item = new PushDataReportDTO();
+                    item.report_date = reportDatetime.Date;
+                    item.platform = deeplink.push_channel_id;
+                    item.platform_name = deeplink.channel_name;
+                    item.req_count = all_total;
+                    item.dp_transition_succ_count = success_total;
+                    conn.Replace<PushDataReportDTO>(item);
+                    count++;
+                }
+                return count;
+            }
+            catch (Exception ex)
+            {
+                //暂时不记录日志
+                return 0;
+            }
+        }
+
+        public async Task<int> FillDeeplinkData(DateTime reportDatetime)
+        {
+
+            var list = DeeplinkParseRuleCore.List();
+            var conn = DBContext.GetOpenConnection();
+            try
+            {
+                int count = 0;
+                foreach (var deeplink in list)
+                {
+                    if (deeplink.push_channel_id == 0) continue;
+
+                    string[] flags = ["none", "home", "success", "fail"];
+                    int all_total = 0;
+                    int success_total = 0;
+                    foreach (var dp_flag in flags)
+                    {
+                        string accountName = $"dp_{dp_flag}:{deeplink.channel_name}";
+                        all_total += await TkLogCore.GetTotalAsync($":parse_total:{accountName}:{reportDatetime:yyyyMMdd}");
+                        if ("success".Equals(dp_flag))
+                        {
+                            success_total = await TkLogCore.GetTotalAsync($":parse_total:{accountName}:success:{reportDatetime:yyyyMMdd}");
+                        }
+                    }
+
+                    var item = new PushDataReportDTO();
+                    item.report_date = reportDatetime.Date;
+                    item.platform = deeplink.push_channel_id;
+                    item.platform_name = deeplink.channel_name;
+                    item.req_count = all_total;
+                    item.dp_transition_succ_count = success_total;
+                    conn.Replace<PushDataReportDTO>(item);
+                    count++;
+                }
+                return count;
+            }
+            catch (Exception ex)
+            {
+                //暂时不记录日志
+                return 0;
+            }
+        }
+
+
+        public async Task<int> PushReportData(DateTime report_date, bool repush = false, CancellationToken cancellationToken = default)
+        {
+            string filter = "report_date=@report_date";
+            if (!repush)
+            {
+                filter += " AND status=@status";
+            }
+
+            var list = new DBContext.Table("push_data_report")
+                .Where(filter, new { report_date = report_date.Date, status = 0 })
+                .Select<PushDataReportDTO>();
+
+            int count = 0;
+            foreach (var item in list)
+            {
+                count++;
+                item.request_id = Guid.NewGuid().ToString();
+                var response = await plus.PushReportData(item, cancellationToken);
+
+                bool status = response.code == 200;
+
+                new DBContext.Table("push_data_report")
+                    .Add("status", status)
+                    .Add("request_id", item.request_id)
+                    .Add("update_time", DateTime.Now)
+                    .Where("id=@id", new { id = item.Id })
+                    .Update();
+            }
+            return count;
+        }
+    }
+}

+ 174 - 0
molilian.core/Core/PushDataReport/PushDataReportDTO.cs

@@ -0,0 +1,174 @@
+using dodohold.core;
+using System;
+using System.ComponentModel;
+using System.Text.Json.Serialization;
+
+namespace molilian.core.PushDataReport;
+public class Response
+{
+    public int code { get; set; } = 0;
+    public string message { get; set; } = string.Empty;
+    public string requestId { get; set; } = string.Empty;
+}
+
+[Table("push_data_report")]
+public class PushDataReportDTO
+{
+    /// <summary>
+    /// 主键ID
+    /// </summary>
+    [JsonIgnore]
+    [Key]
+    public long Id { get; set; }
+
+    /// <summary>
+    /// 报告日期
+    /// </summary>
+
+    [JsonPropertyName("datetime")]
+    [JsonConverter(typeof(YunhuiKit.DateOnlyConverter))] // 自定义日期转换器
+    public DateTime report_date { get; set; } = DateTime.Now.Date;
+
+    /// <summary>
+    /// 是否结算数据
+    /// </summary>
+    [JsonPropertyName("settlement")]
+    public bool is_settlement { get; set; } = false;
+
+    /// <summary>
+    /// 投放场景
+    /// </summary>
+    public int type { get; set; } = 1;
+
+
+    /// <summary>
+    /// 子场景
+    /// </summary>
+    /// </summary>
+    [JsonPropertyName("subType")]
+    public int sub_type { get; set; } = 100000;
+
+    /// <summary>
+    /// 平台
+    /// </summary>
+    public int platform { get; set; } = 0;
+
+    [JsonIgnore]
+    [JsonPropertyName("platformName")]
+    public string platform_name { get; set; } = string.Empty;
+
+    /// <summary>
+    /// 分销类型(0:未知,1:商品,2:直播,3:视频等)
+    /// </summary>
+    public int distribution { get; set; } = 0;
+
+    /// <summary>
+    /// 请求量
+    /// </summary>
+    [JsonConverter(typeof(YunhuiKit.LongToStringConverter))]
+    [JsonPropertyName("reqCount")]
+    public long req_count { get; set; } = 0;
+
+    /// <summary>
+    /// DP转链成功数
+    /// </summary>
+    [JsonConverter(typeof(YunhuiKit.LongToStringConverter))]
+    [JsonPropertyName("dpTransitionSuccCount")]
+    public long dp_transition_succ_count { get; set; } = 0;
+
+    /// <summary>
+    /// 商业转链成功数
+    /// </summary>
+    [JsonConverter(typeof(YunhuiKit.LongToStringConverter))]
+    [JsonPropertyName("transitionSuccCount")]
+    public long transition_succ_count { get; set; } = 0;
+
+    /// <summary>
+    /// 曝光PV
+    /// </summary>
+    [JsonConverter(typeof(YunhuiKit.LongToStringConverter))]
+    [JsonPropertyName("exposeCount")]
+    public long expose_count { get; set; } = 0;
+
+    /// <summary>
+    /// 曝光UV
+    /// </summary>
+    [JsonConverter(typeof(YunhuiKit.LongToStringConverter))]
+    [JsonPropertyName("exposeUserCount")]
+    public long expose_user_count { get; set; } = 0;
+
+    /// <summary>
+    /// 点击PV
+    /// </summary>  
+    [JsonConverter(typeof(YunhuiKit.LongToStringConverter))]
+    [JsonPropertyName("clickCount")]
+    public long click_count { get; set; } = 0;
+
+    /// <summary>
+    /// 点击UV
+    /// </summary>
+    [JsonConverter(typeof(YunhuiKit.LongToStringConverter))]
+    [JsonPropertyName("clickUserCount")]
+    public long click_user_count { get; set; } = 0;
+
+    /// <summary>
+    /// 唤端PV
+    /// </summary>
+    [JsonConverter(typeof(YunhuiKit.LongToStringConverter))]
+    [JsonPropertyName("appOpenCount")]
+    public long app_open_count { get; set; } = 0;
+
+    /// <summary>
+    /// 唤端UV
+    /// </summary>
+    [JsonConverter(typeof(YunhuiKit.LongToStringConverter))]
+    [JsonPropertyName("appOpenUserCount")]
+    public long app_open_user_count { get; set; } = 0;
+
+    /// <summary>
+    /// 订单PV
+    /// </summary>
+    [JsonConverter(typeof(YunhuiKit.LongToStringConverter))]
+    [JsonPropertyName("orderCount")]
+    public long order_count { get; set; } = 0;
+
+    /// <summary>
+    /// 订单UV
+    /// </summary>
+    [JsonConverter(typeof(YunhuiKit.LongToStringConverter))]
+    [JsonPropertyName("orderUserCount")]
+    public long order_user_count { get; set; } = 0;
+
+    /// <summary>
+    /// GMV(元)
+    /// </summary>
+    [JsonConverter(typeof(YunhuiKit.DecimalToStringConverter))]
+    public decimal Gmv { get; set; } = 0;
+
+    /// <summary>
+    /// 预估收入(元)
+    /// </summary>
+    [JsonConverter(typeof(YunhuiKit.DecimalToStringConverter))]
+    public decimal income { get; set; } = 0;
+
+    /// <summary>
+    /// 请求唯一标识
+    /// </summary> 
+    [JsonPropertyName("requestId")]
+    public string request_id { get; set; } = string.Empty;
+
+    /// <summary>
+    /// 创建时间
+    /// </summary>
+    [JsonIgnore]
+    public DateTime create_time { get; set; } = DateTime.Now;
+
+    /// <summary>
+    /// 更新时间
+    /// </summary>
+    [JsonIgnore]
+    public DateTime update_time { get; set; } = DateTime.Now;
+
+    [JsonIgnore]
+    public int status { get; set; } = 0;
+}

+ 109 - 0
molilian.core/Core/PushDataReport/PushDataReportPush.cs

@@ -0,0 +1,109 @@
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc.Controllers;
+using Microsoft.AspNetCore.Mvc.Filters;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using dodohold.core;
+using System.Xml.Linq;
+using YunhuiKit;
+using System.Text.Json;
+using COSXML.Network;
+
+using molilian.core.PushDataReport;
+
+namespace molilian.core
+{
+
+    public class PushDataReportPush
+    {
+        private string _url = "https://adx.ads.heytapmobi.com";
+        private string _app_key = "mll";
+        private string _app_secret = "fHTPd7RK7OnpIv7zGvPgL2Wv8P3pDYfW";
+        public PushDataReportPush()
+        {
+#if DEBUG
+            _url = "http://adx-ads-test.wanyol.com";
+#endif
+        }
+
+        public PushDataReportPush(string url, string app_key, string app_secret)
+        {
+#if DEBUG
+            _url = "http://adx-ads-test.wanyol.com";
+#endif
+            _url = url;
+            _app_key = app_key;
+            _app_secret = app_secret;
+        }
+
+        public async Task<ResponseDTO> PushReportData(PushDataReportDTO item, CancellationToken cancellationToken = default)
+        {
+            try
+            {
+                var options = new JsonSerializerOptions
+                {
+                    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
+                    WriteIndented = true
+                };
+                string json = JsonSerializer.Serialize(item, options);
+
+
+                var root = await Request("/cps/data/report", json, cancellationToken);
+                var response = root.GetRawText().Convert2Object<ResponseDTO>();
+                return response;
+            }
+            catch (Exception ex)
+            {
+                return new ResponseDTO
+                {
+                    code = 500,
+                    message = ex.Message
+                };
+            }
+        }
+
+        public async Task<JsonElement> Request(string action, string post, CancellationToken cancellationToken = default)
+        {
+            string url = $"{_url}{action}";
+
+            long ts = DateTime.Now.Convert2UnixTimestamp(true);
+            string sign = $"{_app_key}{_app_secret}{ts}".ToSHA1();
+            string token = $"{_app_key}:{ts}:{sign}".ToBase64();
+
+            try
+            {
+                WebClientUtility client = new WebClientUtility();
+                client.SetContentType("application/json");
+                client.SetHeaders(new Dictionary<string, string> { { "Authorization", $"Bearer {token}" } });
+                client.Post(post);
+                var response = await client.RequestAsync(url, "POST", cancellationToken);
+
+                if (!response.Successed)
+                {
+                    throw response.ResponseException;
+                }
+                var body = response.Body();
+
+                await new LoggerLibrary("push_report")
+                    .Info(action, post)
+                    .Info(body)
+                    .SaveAsync();
+
+                var root = body.Convert2JsonElement();
+                return root;
+            }
+            catch (Exception ex)
+            {
+                await new LoggerLibrary("push_report", "error")
+                    .Info(action, post)
+                    .Info(ex.Message, ex.StackTrace)
+                    .SaveAsync();
+                throw;
+            }
+        }
+
+
+    }
+}

+ 61 - 17
molilian.core/Core/jd/JdPoolCore.cs

@@ -161,39 +161,83 @@ namespace molilian.core
         public static async Task<IEnumerable<JdPoolDTO>> ListAsync(bool force = false)
         {
             if (!force && _cached != null) return _cached;
-
             try
             {
-                await _semaphore.WaitAsync(); // 异步等待锁
+                await _semaphore.WaitAsync();
+
+                // 如果缓存存在且未强制刷新,直接返回
+                if (!force && _cached != null) return _cached;
 
                 string cache_key = $"cache:jd_pool";
-                var list = await RedisKit.GetAsync<IEnumerable<JdPoolDTO>>(cache_key);
+                IEnumerable<JdPoolDTO>? list = null;
 
-                if (force || list == null)
+                // 尝试从Redis获取数据
+                try
                 {
-                    list = new DBContext.Table("jd_pool")
-                        .Where("status=@status", new { status = 1 })
-                        .Select<JdPoolDTO>();
+                    list = await RedisKit.GetAsync<IEnumerable<JdPoolDTO>>(cache_key);
+                }
+                catch (Exception ex)
+                {
+                    // 记录Redis错误
+                    _ = new LoggerLibrary("JdPool", "Redis").Info(ex.Message, ex.StackTrace).SaveAsync();
+                }
 
-                    if (list != null)
+                // 如果Redis获取失败或需要强制刷新
+                if (force || list == null)
+                {
+                    try
                     {
-                        foreach (var item in list)
+                        list = new DBContext.Table("jd_pool")
+                            .Where("status=@status", new { status = 1 })
+                            .Select<JdPoolDTO>();
+
+                        if (list != null && list.Any())
                         {
-                            _ = RiskControlCore.SetCallsAsync(TkChannelEnum.jd, item.id,
-                                DateTime.Now.ToString("yyyyMMddHH"), item.current_hourly_calls);
-                            _ = RiskControlCore.SetCallsAsync(TkChannelEnum.jd, item.id,
-                                DateTime.Now.ToString("yyyyMMdd"), item.current_daily_calls);
+                            // 更新计数器
+                            foreach (var item in list)
+                            {
+                                try
+                                {
+                                    await RiskControlCore.SetCallsAsync(TkChannelEnum.jd, item.id,
+                                        DateTime.Now.ToString("yyyyMMddHH"), item.current_hourly_calls);
+                                    await RiskControlCore.SetCallsAsync(TkChannelEnum.jd, item.id,
+                                        DateTime.Now.ToString("yyyyMMdd"), item.current_daily_calls);
+                                }
+                                catch (Exception ex)
+                                {
+                                    // 记录计数器更新错误
+                                    _ = new LoggerLibrary("JdPool", "Counter").Info(ex.Message, ex.StackTrace).SaveAsync();
+                                }
+                            }
+
+                            // 尝试更新Redis缓存
+                            try
+                            {
+                                await RedisKit.SetAsync(cache_key, list, 30 * 86400);
+                            }
+                            catch (Exception ex)
+                            {
+                                // 记录Redis更新错误
+                                _ = new LoggerLibrary("JdPool", "Redis").Info(ex.Message, ex.StackTrace).SaveAsync();
+                            }
                         }
-                        await RedisKit.SetAsync(cache_key, list, 30 * 86400);
                     }
-                }
+                    catch (Exception ex)
+                    {
+                        // 记录数据库查询错误
+                        _ = new LoggerLibrary("JdPool", "Database").Info(ex.Message, ex.StackTrace).SaveAsync();
 
+                        // 如果数据库查询失败但缓存还在,继续使用缓存
+                        if (_cached != null) return _cached;
+                        throw; // 如果没有任何可用数据,则抛出异常
+                    }
+                }
                 _cached = list;
-                return list;
+                return list ?? [];
             }
             finally
             {
-                _semaphore.Release(); // 确保释放锁
+                _semaphore.Release();
             }
         }
 

+ 1 - 0
molilian.core/Core/log/base.cs

@@ -383,6 +383,7 @@ namespace molilian.core
             }
 
             await SaveParseAccountCacheAsync("all", success, message, reason);
+            await SaveParseAccountCacheAsync($"dp_channel:{channel}", success, message, reason);
             await SaveParseAccountCacheAsync($"{channel}", success, message, reason);
             await SaveParseAccountCacheAsync($"{accountName}", success, message, reason);
             if (accountId != 0)

+ 85 - 13
molilian.core/Core/tool/DeeplinkParseCore.cs

@@ -7,6 +7,7 @@ using Sayaka.Common;
 using Spire.Pdf.Annotations;
 using Spire.Pdf.Exporting.XPS.Schema;
 using System.Security.Cryptography;
+using System.Text.Json;
 using System.Text.RegularExpressions;
 using System.Web;
 using System.Xml.Linq;
@@ -227,7 +228,7 @@ namespace molilian.core
                     {
                         foreach (var resource in rule.resources)
                         {
-                            Dictionary<string, string> resResult = await ResourceProcessing(match, resource);
+                            Dictionary<string, string> resResult = await ResourceProcessing(match, resource, rule.replacements);
                             foreach (var e in resResult)
                             {
                                 if (deeplink.Contains(e.Key))
@@ -258,7 +259,7 @@ namespace molilian.core
                                     }
                                     break;
                             }
-                            ReplaceProcessing(val, i, ref deeplink, ref prompt_text);
+                            ReplaceProcessing(val, i, rule.replacements, ref deeplink, ref prompt_text);
                         }
 
                         if (rule.replace != null && rule.replace.Count > 0)
@@ -313,7 +314,7 @@ namespace molilian.core
         /// <param name="i"></param>
         /// <param name="deeplink"></param>
         /// <param name="prompt_text"></param>
-        private static void ReplaceProcessing(string word, int i, ref string deeplink, ref string prompt_text)
+        private static void ReplaceProcessing(string word, int i, List<ReplacementRule> replacements, ref string deeplink, ref string prompt_text)
         {
             if (deeplink.Contains("{url:"))
             {
@@ -391,9 +392,60 @@ namespace molilian.core
             }
             deeplink = deeplink.Replace($"{{{i - 1}}}", word);
             prompt_text = prompt_text.Replace($"{{{i - 1}}}", word);
+
+
+            // 新增 <<>> 格式处理
+            if (replacements != null)
+            {
+                deeplink = Regex.Replace(deeplink, @"<<(\w+):([^>]+)>>", match =>
+                {
+                    var ruleName = match.Groups[1].Value;
+                    var value = match.Groups[2].Value;
+
+                    // 查找并应用替换规则
+                    var rule = replacements.FirstOrDefault(r => r.Name == ruleName);
+                    if (rule != null)
+                    {
+                        foreach (var r in rule.Rules)
+                        {
+                            if (r.When.Evaluate(value))
+                            {
+                                return r.Then;
+                            }
+                        }
+                        return rule.Default;
+                    }
+                    return value;
+                });
+
+                prompt_text = Regex.Replace(prompt_text, @"<<(\w+):([^>]+)>>", match =>
+                {
+                    var ruleName = match.Groups[1].Value;
+                    var value = match.Groups[2].Value;
+
+                    // 查找并应用替换规则
+                    var rule = replacements.FirstOrDefault(r => r.Name == ruleName);
+                    if (rule != null)
+                    {
+                        foreach (var r in rule.Rules)
+                        {
+                            if (r.When.Evaluate(value))
+                            {
+                                return r.Then;
+                            }
+                        }
+                        return rule.Default;
+                    }
+                    return value;
+                });
+            }
+
+            // 最后处理普通的索引替换
+            deeplink = deeplink.Replace($"{{{i - 1}}}", word);
+            prompt_text = prompt_text.Replace($"{{{i - 1}}}", word);
         }
 
-        private static async Task<Dictionary<string, string>> ResourceProcessing(Match baseMatch, DeeplinkResources resource)
+        private static async Task<Dictionary<string, string>> ResourceProcessing(Match baseMatch, DeeplinkResources resource, List<ReplacementRule> replacements)
         {
             Dictionary<string, string> result = new Dictionary<string, string>();
             string url = resource.url_pattern;
@@ -401,7 +453,7 @@ namespace molilian.core
             for (var i = 1; i < baseMatch.Groups.Count; i++)
             {
                 string val = baseMatch.Groups[i].Value;
-                ReplaceProcessing(val, i, ref url, ref prompt_text);
+                ReplaceProcessing(val, i, replacements, ref url, ref prompt_text);
             }
 
             string content = string.Empty;
@@ -425,6 +477,7 @@ namespace molilian.core
                         }
                         break;
                     case UrlAction.Body:
+                    case UrlAction.JsonBody:
                         {
                             var response = await new WebClientUtility
                             {
@@ -449,19 +502,38 @@ namespace molilian.core
 
             if (string.IsNullOrEmpty(content)) { return result; }
 
-            for (int i = 0; i < resource.pattern.Count; i++)
+
+            try
             {
-                string val = string.Empty;
-                var regex = new Regex(resource.pattern[i]);
-                var match = regex.Match(content);
-                if (match.Success)
+                JsonElement root = default;
+                if (UrlAction.JsonBody.Equals(resource.url_action))
                 {
-                    val = match.Groups[1].Value;
+                    root = content.Convert2JsonElement();
                 }
 
-                string key = $"{{{i}@{resource.name}}}";
-                result.Add(key, val);
+                for (int i = 0; i < resource.pattern.Count; i++)
+                {
+                    string val = string.Empty;
+
+                    if (UrlAction.JsonBody.Equals(resource.url_action))
+                    {
+                        val = root.PathRead(resource.pattern[i], string.Empty);
+                    }
+                    else
+                    {
+                        var regex = new Regex(resource.pattern[i]);
+                        var match = regex.Match(content);
+                        if (match.Success)
+                        {
+                            val = match.Groups[1].Value;
+                        }
+                    }
+
+                    string key = $"{{{i}@{resource.name}}}";
+                    result.Add(key, val);
+                }
             }
+            catch (Exception ex) { }
             return result;
         }
 

+ 54 - 2
molilian.core/DTO/deeplink/DeeplinkParseRuleDTO.cs

@@ -3,11 +3,50 @@ using Spire.Pdf.Exporting.XPS.Schema;
 
 namespace molilian.core
 {
+
+    public class ReplacementRule
+    {
+        public class Rule
+        {
+            public class Condition
+            {
+                public string Value { get; set; }
+                public string Operator { get; set; } = "equals";
+
+                public bool Evaluate(string input)
+                {
+                    return Operator switch
+                    {
+                        "equals" => input == Value,
+                        "contains" => input.Contains(Value),
+                        "startsWith" => input.StartsWith(Value),
+                        "endsWith" => input.EndsWith(Value),
+                        _ => false
+                    };
+                }
+            }
+            public Condition When { get; set; }
+            public string Then { get; set; }
+        }
+        public string Name { get; set; }
+        public List<Rule> Rules { get; set; }
+        public string Default { get; set; }
+
+        internal object FirstOrDefault(Func<object, bool> value)
+        {
+            throw new NotImplementedException();
+        }
+    }
+
+
+
+
     public enum UrlAction
     {
         None = 0,
         Redirect = 1,
         Body = 2,
+        JsonBody = 3,
     }
 
     public class DeeplinkParseRule
@@ -23,9 +62,22 @@ namespace molilian.core
         public bool enable { get; set; } = true;
         public List<DeeplinkParseRule> childs { get; set; } = new();
         public List<DeeplinkResources> resources { get; set; } = new();
+        public List<ReplacementRule> replacements { get; set; } = new();
     }
 
-
+    /// <summary>
+    /// "resources": [
+	///	{
+	///		"name": "info",
+	///		"url_pattern": "https://api.my.tv.sohu.com/forward/api/h5/getForwardInfo?callback=jsonpx1730973492613_41_1&forward_id={1}",
+	///		"url_action": 2,
+	///		"pattern": [
+    ///           "{\"commentDigg\":{\"id\":\"(\\d+)\"",
+    ///           "\"comment_id\":\"(\\d+)\""
+    ///        ]
+    /// }
+	/// ] 
+    /// </summary>
     public class DeeplinkResources
     {
         public string name { get; set; } = string.Empty;
@@ -36,13 +88,13 @@ namespace molilian.core
     }
 
 
-
     [Table("deeplink_parse_rule")]
     public class DeeplinkParseRuleDTO
     {
         [Key]
         public int id { get; set; }
         public int channel_id { get; set; } = 0;
+        public int push_channel_id { get; set; } = 0;
         public string channel_name { get; set; } = string.Empty;
         public string name { get; set; } = string.Empty;
         public string logo { get; set; } = string.Empty;

+ 1 - 1
molilian.core/Plus/Alimama/parse.cs

@@ -186,7 +186,7 @@ namespace molilian.core
 #endif
             while (try_count == 0 || try_count <= _config.tk_parse_retry_count)
             {
-                if (try_count > 3) break;
+                if (try_count >= 3) break;
                 result = await alimamaParseAsync(result.content, result, cancellationToken);
                 if (!"该链接不支持转化,请更换链接尝试".Equals(result.message)) break;
                 try_count++;

+ 11 - 6
molilian.core/Plus/Alimama/parse_2.cs

@@ -431,6 +431,8 @@ namespace molilian.core
 
             //============================== 放弃转链-其他推广链接 ==============================
             string url = GetLink(content);
+            result.shortLinkurl = url;
+
             if (!string.IsNullOrEmpty(url))
             {
                 bool is_aff = IsAffLink(url);
@@ -441,7 +443,7 @@ namespace molilian.core
                     result.reason = "其他推广链接";
                     result.subCode = TkSubCodeEnum.OtherPromo;
                     result.link_type = LinkTypeEnum.other_aff;
-                    result.shortLinkurl = url;
+                    //result.shortLinkurl = url;
                     return result;
                 }
 
@@ -451,7 +453,7 @@ namespace molilian.core
                     result.success = true;
                     result.content = resultText;
                     result.link_type = LinkTypeEnum.goods;
-                    result.shortLinkurl = resultText;
+                    //result.shortLinkurl = resultText;
                     return result;
                 }
 
@@ -495,7 +497,7 @@ namespace molilian.core
                         result.reason = "其他推广链接";
                         result.subCode = TkSubCodeEnum.OtherPromo;
                         result.link_type = LinkTypeEnum.other_aff;
-                        result.shortLinkurl = url;
+                        //result.shortLinkurl = url;
                         return result;
                     }
 
@@ -505,7 +507,7 @@ namespace molilian.core
                         result.success = true;
                         result.content = desiredUrl;
                         result.link_type = LinkTypeEnum.goods;
-                        result.shortLinkurl = desiredUrl;
+                        //result.shortLinkurl = desiredUrl;
                         return result;
                     }
                     result.link_type = GetLinkType(desiredUrl);
@@ -831,8 +833,11 @@ namespace molilian.core
                 result.couponEffectiveEndTime = couponEffectiveEndTime;
                 result.couponEffectiveStartTime = couponEffectiveStartTime;
                 result.taoToken = taoToken;
-                result.shortLinkurl = shortLinkurl;
-                result.deeplink_url = deeplink_url;
+                if (!string.IsNullOrEmpty(shortLinkurl))
+                {
+                    result.shortLinkurl = shortLinkurl;
+                    result.deeplink_url = deeplink_url;
+                }
                 result.mktId = mktId;
 
                 result.itemId = itemId;

+ 1 - 1
molilian.core/molilian.core.csproj

@@ -25,7 +25,7 @@
     <PackageReference Include="IP2Region.Net" Version="2.0.2" />
     <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0" />
     <PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.5.0" />
-    <PackageReference Include="YunhuiKit" Version="0.0.31" />
+    <PackageReference Include="YunhuiKit" Version="0.0.34" />
   </ItemGroup>
 
   <ItemGroup>

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor