UnionParseCore.cs 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944
  1. using dodohold.core;
  2. using Microsoft.AspNetCore.Mvc;
  3. using System.Diagnostics;
  4. using System.Text.RegularExpressions;
  5. namespace molilian.core
  6. {
  7. public partial class UnionParseCore
  8. {
  9. public static async Task<ActionResult> UnionParseAsync(string content, string channel, int commerceType, string ip, string oaid, string riskStrategy, int launchScene, int accountid = 0, string clickId = "")
  10. {
  11. content = content.Trim();
  12. return channel switch
  13. {
  14. "wemeet" => await WemeetParseAsync(content, ip, oaid),
  15. "bdpan" => PanParse(content, ip, oaid),
  16. "jd" => await JdParseAsync(content, commerceType, ip, oaid, riskStrategy, launchScene, accountid, clickId),
  17. "ks" => await KsParseAsync(content, commerceType, ip, oaid, accountid),
  18. "dy" => await DyParseAsync(content, commerceType, ip, oaid),
  19. "pdd" => await PddParseAsync(content, commerceType, ip, oaid, accountid),
  20. "tb" => await TaobaoParseAsync(content, commerceType, ip, oaid, riskStrategy, launchScene, accountid),
  21. _ => await DeeplinkParseCore.ParseAsync(content, channel, ip, oaid),
  22. };
  23. }
  24. //return await DeeplinkParseCore.ParseAsync(content, channel, ip, oaid);
  25. public static async Task<APIResult> WemeetParseAsync(string content, string ip, string oaid)
  26. {
  27. var result = ToolParsePlus.GetFormattedObject(TkChannelEnum.wemeet, content, ip, oaid);
  28. content = content.UrlDecode();
  29. result.rawContent = content;
  30. try
  31. {
  32. result = await ToolParsePlus.WemeetParseAsync(content, result);
  33. }
  34. catch (Exception ex)
  35. {
  36. _ = new LoggerLibrary("unionParse", "wemeet_error")
  37. .Info(ip, oaid)
  38. .Info(content)
  39. .Info(ex.Message, ex.StackTrace)
  40. .SaveAsync();
  41. NotifyCore.Notify(new NifyMessage
  42. {
  43. message = $"【转链异常Wemeet】\n{content}\n\n{ex.Message}\n{ex.StackTrace}",
  44. priority = NifyMessagePriority.high,
  45. tags = ["red_circle"]
  46. });
  47. result.success = false;
  48. result.message = "内部错误";
  49. result.reason = "转链接口异常";
  50. }
  51. _ = TkLogCore.ParseLogAsync(result);
  52. return new APIResult(new
  53. {
  54. result.success,
  55. result.message,
  56. channel = result?.channel.ToString(),
  57. result.shortLinkurl,
  58. result.deeplink_url,
  59. result.itemName,
  60. }, result.success ? APIResultCodeEnum.OK : APIResultCodeEnum.NotAcceptable);
  61. }
  62. public static APIResult PanParse(string content, string ip, string oaid)
  63. {
  64. var result = ToolParsePlus.GetFormattedObject(TkChannelEnum.bdpan, content, ip, oaid);
  65. content = content.UrlDecode();
  66. result.rawContent = content;
  67. try
  68. {
  69. ToolParsePlus.PanParse(content, ref result);
  70. }
  71. catch (Exception ex)
  72. {
  73. _ = new LoggerLibrary("unionParse", "pan_error")
  74. .Info(ip, oaid)
  75. .Info(content)
  76. .Info(ex.Message, ex.StackTrace)
  77. .SaveAsync();
  78. NotifyCore.Notify(new NifyMessage
  79. {
  80. message = $"【转链异常Pan】\n{content}\n\n{ex.Message}\n{ex.StackTrace}",
  81. priority = NifyMessagePriority.high,
  82. tags = ["red_circle"]
  83. });
  84. result.success = false;
  85. result.message = "内部错误";
  86. result.reason = "转链接口异常";
  87. }
  88. _ = TkLogCore.ParseLogAsync(result);
  89. return new APIResult(new
  90. {
  91. result.success,
  92. result.message,
  93. channel = result?.channel.ToString(),
  94. result.shortLinkurl,
  95. result.deeplink_url,
  96. result.itemName,
  97. }, !string.IsNullOrEmpty(result.deeplink_url) ? APIResultCodeEnum.OK : APIResultCodeEnum.NotAcceptable);
  98. }
  99. private static APIResult TaobaoParseOutput(TkDataDTO result, Dictionary<string, long> swData, object info, APIResultCodeEnum code = APIResultCodeEnum.OK)
  100. {
  101. if (result.elapsedTime > 2000)
  102. {
  103. LoggerLibrary log = new("debug", "stopwatch");
  104. foreach ((var key, var value) in swData)
  105. {
  106. log.Info($"{key}\t{value}");
  107. }
  108. log.SaveAsync();
  109. }
  110. return new APIResult(info, code);
  111. }
  112. public static async Task<APIResult> TaobaoParseAsync(string content, int commerceType,
  113. string ip = "", string oaid = "", string riskStrategy = "", int launchScene = 0,
  114. int accountid = 0)
  115. {
  116. bool other_aff = false;
  117. AlimamaPlus alimama = null;
  118. //content = content.UrlDecode();
  119. content = content[..Math.Min(1000, content.Length)];
  120. var result = AlimamaPlus.GetFormattedObject(content, ip, oaid);
  121. result.riskStrategy = riskStrategy;
  122. result.launchScene = launchScene;
  123. Dictionary<string, long> swData = new();
  124. swData.Add("StartNew", 0);
  125. Stopwatch stopwatch = Stopwatch.StartNew();
  126. result.rawContent = content;
  127. try
  128. {
  129. string reason = string.Empty;
  130. var config = TkConfigCore.Get();
  131. var arr = config.tk_whitelist_regular.Split('\n')
  132. .Where(line => !string.IsNullOrWhiteSpace(line))
  133. .ToList();
  134. var arr2 = config.tk_blacklist_regular.Split('\n')
  135. .Where(line => !string.IsNullOrWhiteSpace(line))
  136. .ToList();
  137. var arr3 = config.multi_token_regular.Split('\n')
  138. .Where(line => !string.IsNullOrWhiteSpace(line))
  139. .ToList();
  140. bool is_tao_url = !string.IsNullOrEmpty(result.shortLinkurl);
  141. bool is_tao_token = AlimamaPlus.MatchRegexes(content, arr);
  142. bool is_other = AlimamaPlus.MatchOtherInfo(content, arr2);
  143. //============================== 放弃转链-初步筛选1 ==============================
  144. if (!is_tao_url && !is_tao_token || is_other)
  145. {
  146. //没有链接都放弃
  147. result.success = false;
  148. result.message = "放弃转链";
  149. result.reason = "初步筛选1";
  150. result.subCode = TkSubCodeEnum.Prelim1;
  151. result.itemName = "";
  152. result.deeplink_url = "";
  153. _ = TkLogCore.ParseLogAsync(result);
  154. return TaobaoParseOutput(result, swData, new
  155. {
  156. result.success,
  157. result.commercial,
  158. result.message,
  159. result.content,
  160. result.itemName,
  161. other_aff,
  162. result.deeplink_url,
  163. });
  164. }
  165. bool is_multi_token = AlimamaPlus.MatchMultiToken(content, arr3);
  166. //============================== 放弃转链-初步筛选1.5 ==============================
  167. if (is_multi_token)
  168. {
  169. //没有链接都放弃
  170. result.success = false;
  171. result.message = "放弃转链";
  172. result.reason = "初步筛选1.5";
  173. result.subCode = TkSubCodeEnum.Prelim1_5;
  174. result.itemName = "";
  175. result.deeplink_url = "";
  176. _ = TkLogCore.ParseLogAsync(result);
  177. return TaobaoParseOutput(result, swData, new
  178. {
  179. result.success,
  180. result.commercial,
  181. result.message,
  182. result.content,
  183. result.itemName,
  184. other_aff,
  185. result.deeplink_url,
  186. });
  187. }
  188. //============================== 放弃转链-初步筛选2 ==============================
  189. bool is_aff_link = false;
  190. if (!string.IsNullOrEmpty(result.shortLinkurl)) is_aff_link = AlimamaPlus.IsAffLink(result.shortLinkurl);
  191. if (!is_tao_url && is_tao_token)
  192. {
  193. //淘宝口令
  194. result.success = false;
  195. result.message = "放弃转链";
  196. result.reason = "初步筛选2";
  197. result.subCode = TkSubCodeEnum.Prelim2;
  198. result.itemName = "点击打开淘宝APP";
  199. _ = TkLogCore.ParseLogAsync(result);
  200. //20241229 特例
  201. //if ("bj".Equals(EndPointCore.CurrentEndPoint))
  202. //{
  203. // string ruleKey = $"tmp_rules2:tb:{DateTime.Now:yyyyMMdd}";
  204. // var count = RedisHelper.Get<int>(ruleKey);
  205. // var now = DateTime.Now;
  206. // if (now > new DateTime(2024, 12, 19) && now <= new DateTime(2024, 12, 22) && now.Hour >= 7 && count < 1000)
  207. // {
  208. // result.deeplink_url = "tbopen://m.taobao.com/tbopen/index.html?source=auto&action=ali.open.nav&module=h5&bootImage=0&afc_route=1&bc_fl_src=growth_dhh_2200803434968_100-1930985-1595034112&dpa_Inid=159503411212096&dpa_material_id=530637422585&dpa_material_type=1&dpa_source_code=12096&force_no_smb=true&h5Url=https%3A%2F%2Fs.m.taobao.com%2Fh5%3Ffrom%3Dcustoms%26g_channelSrp%3Ddhhdpa_1232552832%26dpa_material_type%3D1%26ut_sk%3Dsearch%26spm%3Da2141.mb819t211c7%26sLaunch%3D0%26sKeep%3D1%26sModuleName%3Dsearch%26spm_back_up%3Da2141.mb819t211c7%26bc_fl_src%3Dgrowth_dhh_2200803434968_100-1930985-1595034112%26dpa_Inid%3D159503411212096%26dpa_material_id%3D530637422585%26dpa_material_type%3D1%26dpa_source_code%3D12096%26force_no_smb%3Dtrue%26itemIds%3D530637422585%26slk_actid%3D100000000207%26spm%3D2014.ugdhh.2200803434968.100-1930985-1595034112%26wh_biz%3Dtm&itemIds=530637422585&slk_actid=100000000207&spm=2014.ugdhh.2200803434968.100-1930985-1595034112&wh_biz=tm";
  209. // RedisHelper.IncrBy(ruleKey);
  210. // RedisHelper.Expire(ruleKey, 86400 * 1);
  211. // }
  212. //}
  213. other_aff = true;
  214. return TaobaoParseOutput(result, swData, new
  215. {
  216. result.success,
  217. result.commercial,
  218. result.message,
  219. result.content,
  220. result.itemName,
  221. other_aff,
  222. result.deeplink_url,
  223. });
  224. }
  225. if ((!is_tao_url && is_tao_token) || is_aff_link)
  226. {
  227. //没有短链接都放弃
  228. result.success = false;
  229. result.message = "放弃转链";
  230. result.reason = "初步筛选2";
  231. result.subCode = TkSubCodeEnum.Prelim2;
  232. result.itemName = "点击打开淘宝APP";
  233. _ = TkLogCore.ParseLogAsync(result);
  234. //20241229 特例
  235. //if ("bj".Equals(EndPointCore.CurrentEndPoint))
  236. //{
  237. // string ruleKey = $"tmp_rules2:tb:{DateTime.Now:yyyyMMdd}";
  238. // var count = RedisHelper.Get<int>(ruleKey);
  239. // var now = DateTime.Now;
  240. // if (now > new DateTime(2024, 12, 19) && now <= new DateTime(2024, 12, 22) && now.Hour >= 7 && count < 1000)
  241. // {
  242. // result.deeplink_url = "tbopen://m.taobao.com/tbopen/index.html?source=auto&action=ali.open.nav&module=h5&bootImage=0&afc_route=1&bc_fl_src=growth_dhh_2200803434968_100-1930985-1595034112&dpa_Inid=159503411212096&dpa_material_id=530637422585&dpa_material_type=1&dpa_source_code=12096&force_no_smb=true&h5Url=https%3A%2F%2Fs.m.taobao.com%2Fh5%3Ffrom%3Dcustoms%26g_channelSrp%3Ddhhdpa_1232552832%26dpa_material_type%3D1%26ut_sk%3Dsearch%26spm%3Da2141.mb819t211c7%26sLaunch%3D0%26sKeep%3D1%26sModuleName%3Dsearch%26spm_back_up%3Da2141.mb819t211c7%26bc_fl_src%3Dgrowth_dhh_2200803434968_100-1930985-1595034112%26dpa_Inid%3D159503411212096%26dpa_material_id%3D530637422585%26dpa_material_type%3D1%26dpa_source_code%3D12096%26force_no_smb%3Dtrue%26itemIds%3D530637422585%26slk_actid%3D100000000207%26spm%3D2014.ugdhh.2200803434968.100-1930985-1595034112%26wh_biz%3Dtm&itemIds=530637422585&slk_actid=100000000207&spm=2014.ugdhh.2200803434968.100-1930985-1595034112&wh_biz=tm";
  243. // RedisHelper.IncrBy(ruleKey);
  244. // RedisHelper.Expire(ruleKey, 86400 * 1);
  245. // }
  246. //}
  247. other_aff = true;
  248. return TaobaoParseOutput(result, swData, new
  249. {
  250. result.success,
  251. result.commercial,
  252. result.message,
  253. result.content,
  254. result.itemName,
  255. other_aff,
  256. result.deeplink_url,
  257. });
  258. }
  259. //那就初步筛选3 有tb.cn 并且有 or 手淘发现
  260. string pattern = @"^(?!【淘宝】).*https?:\/\/m\.tb\.cn.*(?:手淘发现|手淘搜索)";
  261. bool isMatch = Regex.IsMatch(content, pattern);
  262. if (isMatch)
  263. {
  264. result.success = false;
  265. result.message = "放弃转链";
  266. result.reason = "初步筛选3";
  267. result.subCode = TkSubCodeEnum.Prelim3;
  268. result.itemName = "点击打开淘宝APP";
  269. _ = TkLogCore.ParseLogAsync(result);
  270. return TaobaoParseOutput(result, swData, new
  271. {
  272. result.success,
  273. result.commercial,
  274. result.message,
  275. result.content,
  276. result.itemName,
  277. other_aff,
  278. result.deeplink_url,
  279. });
  280. }
  281. //============================== 放弃转链-地区过滤 ==============================
  282. bool is_ignore2 = AlimamaPlus.ShouldIgnoreRequest(ip, oaid, riskStrategy, launchScene, out reason);
  283. if (is_ignore2)
  284. {
  285. result.success = false;
  286. result.message = "放弃转链";
  287. result.itemName = "点击打开淘宝APP";
  288. result.reason = reason;
  289. result.subCode = TkSubCodeEnum.TrafficCtrl;
  290. _ = TkLogCore.ParseLogAsync(result);
  291. return TaobaoParseOutput(result, swData, new
  292. {
  293. result.success,
  294. result.commercial,
  295. result.message,
  296. result.content,
  297. result.itemName,
  298. other_aff,
  299. result.deeplink_url,
  300. });
  301. }
  302. (bool isTaobaoUrl, string url) = AlimamaPlus.IsTaobaoUrl(content);
  303. //============================== 放弃转链-没有匹配账号 ==============================
  304. TkPoolDTO? account = accountid > 0 ?
  305. await TkPoolCore.GetOneAsync(accountid) :
  306. await TkPoolCore.GetOneAsync(TkPoolCore.TkAction.parse, isTaobaoUrl, riskStrategy, launchScene);
  307. if (account == null)
  308. {
  309. result.success = false;
  310. result.message = "放弃转链";
  311. result.reason = "没有匹配账号";
  312. result.subCode = TkSubCodeEnum.Other;
  313. result.itemName = "点击打开淘宝APP";
  314. _ = TkLogCore.ParseLogAsync(result);
  315. return TaobaoParseOutput(result, swData, new
  316. {
  317. result.success,
  318. result.commercial,
  319. result.message,
  320. result.content,
  321. result.couponAmount,
  322. result.taoToken,
  323. result.shortLinkurl,
  324. other_aff,
  325. result.deeplink_url,
  326. });
  327. }
  328. result.accountId = account.id;
  329. result.accountName = account.company;
  330. alimama = new AlimamaPlus(account);
  331. int timeout = alimama._config.rt_max;
  332. #if DEBUG
  333. timeout = 10000;
  334. #endif
  335. using var cts = new CancellationTokenSource();
  336. cts.CancelAfter(timeout);
  337. var requestTask = Task.Run(() => alimama.UnionParseAsync(ip, oaid, content, commerceType, result, isTaobaoUrl, riskStrategy, launchScene, cts.Token, swData), cts.Token);
  338. var delayTask = Task.Delay(timeout, cts.Token);
  339. var completedTask = await Task.WhenAny(requestTask, delayTask);
  340. if (completedTask == requestTask)
  341. {
  342. result = await requestTask;
  343. }
  344. else
  345. {
  346. //============================== 放弃转链-请求超时 ==============================
  347. cts.Cancel();
  348. result.success = false;
  349. result.message = "放弃转链";
  350. result.reason = "请求超时";
  351. result.subCode = TkSubCodeEnum.Other;
  352. result.itemName = "点击打开淘宝APP";
  353. }
  354. result.accountName = account.company;
  355. //result = await alimama.UnionParse2Async(content, result);
  356. }
  357. catch (Exception ex)
  358. {
  359. //============================== 放弃转链-请求超时 ==============================
  360. if (ex.Message.Contains("was canceled"))
  361. {
  362. result.success = false;
  363. result.message = "放弃转链";
  364. result.reason = "请求超时";
  365. result.subCode = TkSubCodeEnum.Other;
  366. result.itemName = "点击打开淘宝APP";
  367. }
  368. else
  369. {
  370. //============================== 转链接口异常 ==============================
  371. _ = new LoggerLibrary("unionParse", "tb_error")
  372. .Info(ip, oaid)
  373. .Info(content)
  374. .Info(ex.Message, ex.StackTrace)
  375. .SaveAsync();
  376. NotifyCore.Notify(new NifyMessage
  377. {
  378. message = $"【转链异常TB】\n{content}\n\n{ex.Message}\n{ex.StackTrace}",
  379. priority = NifyMessagePriority.high,
  380. tags = ["red_circle"]
  381. });
  382. result.success = false;
  383. result.subCode = TkSubCodeEnum.Other;
  384. result.message = "转链接口异常";
  385. result.itemName = "点击打开淘宝APP";
  386. }
  387. }
  388. _ = TkLogCore.ParseLogAsync(result, alimama);
  389. switch (result.reason)
  390. {
  391. case "其他推广链接":
  392. //case "排除淘口令":
  393. case "纯口令 没链接":
  394. other_aff = true;
  395. break;
  396. }
  397. return TaobaoParseOutput(result, swData, new
  398. {
  399. result.success,
  400. result.commercial,
  401. result.message,
  402. link_type = result.link_type.ToString(),
  403. channel = result?.channel.ToString(),
  404. result.channel_type,
  405. result.itemId,
  406. result.itemName,
  407. result.pic,
  408. result.promotionPrice,
  409. result.couponAmount,
  410. result.couponEffectiveStartTime,
  411. result?.couponEffectiveEndTime,
  412. result.shortLinkurl,
  413. result.deeplink_url,
  414. result.riskStrategy,
  415. result.launchScene,
  416. result.content,
  417. result.taoToken,
  418. other_aff,
  419. });
  420. }
  421. private static APIResult JdParseOutput(JdDataDTO result, APIResultCodeEnum code = APIResultCodeEnum.OK)
  422. {
  423. return new APIResult(new
  424. {
  425. result.success,
  426. result.commercial,
  427. result.message,
  428. link_type = result.link_type.ToString(),
  429. channel = result?.channel.ToString(),
  430. result.channel_type,
  431. result.itemId,
  432. result.itemName,
  433. result.shortLinkurl,
  434. result.deeplink_url,
  435. result.riskStrategy,
  436. result.launchScene,
  437. }, code);
  438. }
  439. public static async Task<APIResult> JdParseAsync(string content, int commerceType, string ip, string oaid,
  440. string riskStrategy = "", int launchScene = 0,
  441. int accountid = 0, string clickId = "", CancellationToken cancellationToken = default)
  442. {
  443. var config = TkConfigCore.Get();
  444. var result = JdUnionPlus.GetFormattedObject(content, ip, oaid, clickId);
  445. content = content.UrlDecode();
  446. result.rawContent = content;
  447. result.riskStrategy = riskStrategy;
  448. result.launchScene = launchScene;
  449. bool IfExceptional = false;
  450. try
  451. {
  452. if (!string.IsNullOrEmpty(config.jd_blacklist_regular))
  453. {
  454. var blacklist = config.jd_blacklist_regular.Split('\n')
  455. .Where(line => !string.IsNullOrWhiteSpace(line))
  456. .ToList();
  457. bool anyMatch = false;
  458. foreach (string pattern in blacklist)
  459. {
  460. if (Regex.IsMatch(content, pattern, RegexOptions.IgnoreCase)) anyMatch = true;
  461. }
  462. if (anyMatch)
  463. {
  464. result.success = false;
  465. result.deeplink_url = string.Empty;
  466. result.message = "放弃转链";
  467. result.reason = "规则排除";
  468. _ = TkLogCore.ParseLogAsync(result);
  469. return JdParseOutput(result);
  470. }
  471. }
  472. string out_url = null;
  473. string itemId = null;
  474. //============================== 放弃转链-地区过滤 ==============================
  475. if (!TestParseCore.InWhitelist(result.ip, result.oaid) && accountid == 0 && JdUnionPlus.ShouldIgnoreRequest(config, ip, oaid, riskStrategy, launchScene, out string reason))
  476. {
  477. result.link_type = JdUnionPlus.GetLinkType(result.shortLinkurl, out out_url, out itemId);
  478. result.deeplink_url = result.link_type switch
  479. {
  480. LinkTypeEnum.other_aff or
  481. LinkTypeEnum.live or
  482. LinkTypeEnum.video or
  483. LinkTypeEnum.profile or
  484. LinkTypeEnum.goods => JdUnionPlus.GetDefaultStyleDeeplink(result.shortLinkurl),
  485. _ => JdUnionPlus.GetDefaultStyleDeeplink(result.shortLinkurl),
  486. };
  487. //if (result.link_type == LinkTypeEnum.other_aff)
  488. //{
  489. // //20241204 特例
  490. // if ("bj".Equals(EndPointCore.CurrentEndPoint))
  491. // {
  492. // string ruleKey = $"tmp_rules1:jd:{DateTime.Now:yyyyMMdd}";
  493. // var count = RedisHelper.Get<int>(ruleKey);
  494. // if (DateTime.Now < DateTime.Parse("2024-12-07") && count < 500)
  495. // {
  496. // result.deeplink_url = "openapp.jdmobile://virtual?params=%7B%22des%22%3A%22union%22%2C%22category%22%3A%22jump%22%2C%22url%22%3A%22https%3A%2F%2Fu.jd.com%2FugInesd%3Fe%3DCPS-11417-__ZLDEVICE__-CPS-wkfG72%22%7D&backurl=__back_url__";
  497. // RedisHelper.IncrBy(ruleKey);
  498. // RedisHelper.Expire(ruleKey, 86400 * 1);
  499. // }
  500. // }
  501. //}
  502. result.success = false;
  503. result.message = "放弃转链";
  504. result.reason = reason;
  505. _ = TkLogCore.ParseLogAsync(result);
  506. return JdParseOutput(result);
  507. }
  508. // bool is_ignore2 = JdUnionPlus.FlowControlIgnoreRequest(config, out reason);
  509. //#if DEBUG
  510. // is_ignore2 = false;
  511. //#endif
  512. // if (accountid == 0 && is_ignore2)
  513. // {
  514. // result.success = false;
  515. // result.message = "放弃转链";
  516. // result.reason = reason;
  517. // _ = TkLogCore.ParseLogAsync(result);
  518. // return JdParseOutput(result);
  519. // }
  520. result.shortLinkurl = JdUnionPlus.GetLink(content);
  521. result.content = result.shortLinkurl;
  522. result.link_type = JdUnionPlus.GetLinkType(result.shortLinkurl, out out_url, out itemId);
  523. bool is_numeric = result.shortLinkurl.Contains(itemId);
  524. var account = accountid > 0 ? await JdPoolCore.GetOneAsync(accountid, JdPoolCore.JdAction.parse) : await JdPoolCore.GetOneAsync(JdPoolCore.JdAction.parse, riskStrategy, launchScene, is_numeric);
  525. if (account == null)
  526. {
  527. result.success = false;
  528. result.message = "放弃转链";
  529. result.reason = "没有匹配账号";
  530. result.deeplink_url = result.link_type switch
  531. {
  532. LinkTypeEnum.other_aff or LinkTypeEnum.goods => JdUnionPlus.GetDefaultStyleDeeplink(result.shortLinkurl),
  533. _ => JdUnionPlus.GetDefaultStyleDeeplink(result.shortLinkurl),
  534. };
  535. _ = TkLogCore.ParseLogAsync(result);
  536. return JdParseOutput(result);
  537. }
  538. result.accountId = account.id;
  539. result.accountName = account.name;
  540. var plus = new JdUnionPlus(account);
  541. result = await plus.JdParseAsync(content, commerceType, clickId, result, cancellationToken);
  542. }
  543. catch (Exception ex)
  544. {
  545. if (ex.Message.Contains("was canceled"))
  546. {
  547. result.success = false;
  548. result.message = "放弃转链";
  549. result.reason = "请求超时";
  550. }
  551. else
  552. {
  553. IfExceptional = true;
  554. _ = new LoggerLibrary("unionParse", "jd_error")
  555. .Info(ip, oaid)
  556. .Info(content)
  557. .Info(ex.Message, ex.StackTrace)
  558. .SaveAsync();
  559. NotifyCore.Notify(new NifyMessage
  560. {
  561. message = $"【转链异常JD】\n{content}\n\n{ex.Message}\n{ex.StackTrace}",
  562. priority = NifyMessagePriority.high,
  563. tags = ["red_circle"]
  564. });
  565. result.success = false;
  566. result.message = "内部错误";
  567. result.reason = "转链接口异常";
  568. }
  569. result.deeplink_url = result.link_type switch
  570. {
  571. LinkTypeEnum.other_aff or LinkTypeEnum.goods => JdUnionPlus.GetDefaultStyleDeeplink(result.shortLinkurl),
  572. _ => JdUnionPlus.GetDefaultStyleDeeplink(result.shortLinkurl),
  573. };
  574. }
  575. _ = TkLogCore.ParseLogAsync(result);
  576. return JdParseOutput(result, IfExceptional ? APIResultCodeEnum.NotAcceptable : APIResultCodeEnum.OK);
  577. }
  578. public static async Task<APIResult> DyParseAsync(string content, int commerceType, string ip, string oaid, CancellationToken cancellationToken = default)
  579. {
  580. var result = DyUnionPlus.GetFormattedObject(content, ip, oaid);
  581. content = content.UrlDecode();
  582. result.rawContent = content;
  583. bool IfExceptional = false;
  584. try
  585. {
  586. #if DEBUG
  587. #else
  588. // 2024-06-19 联盟业务下线
  589. result.success = false;
  590. result.message = "放弃转链";
  591. result.reason = "联盟下线";
  592. _ = TkLogCore.ParseLogAsync(result);
  593. return new APIResult(result);
  594. #endif
  595. if (DyUnionPlus.ShouldIgnoreRequest(ip, oaid, out string reason))
  596. {
  597. result.success = false;
  598. result.message = "放弃转链";
  599. result.reason = reason;
  600. _ = TkLogCore.ParseLogAsync(result);
  601. return new APIResult(result);
  602. }
  603. var account = PangolinPoolCore.GetOne();
  604. if (account == null)
  605. {
  606. result.success = false;
  607. result.message = "放弃转链";
  608. result.reason = "没有匹配账号";
  609. _ = TkLogCore.ParseLogAsync(result);
  610. return new APIResult(result);
  611. }
  612. result = await DyUnionPlus.DyParseAsync(account, content, commerceType, result, cancellationToken);
  613. }
  614. catch (Exception ex)
  615. {
  616. if (ex.Message.Contains("was canceled"))
  617. {
  618. result.success = false;
  619. result.message = "放弃转链";
  620. result.reason = "请求超时";
  621. }
  622. else
  623. {
  624. IfExceptional = true;
  625. _ = new LoggerLibrary("unionParse", "dy_error")
  626. .Info(ip, oaid)
  627. .Info(content)
  628. .Info(ex.Message, ex.StackTrace)
  629. .SaveAsync();
  630. NotifyCore.Notify(new NifyMessage
  631. {
  632. message = $"【转链异常DY】\n{content}\n\n{ex.Message}\n{ex.StackTrace}",
  633. priority = NifyMessagePriority.high,
  634. tags = ["red_circle"]
  635. });
  636. result.success = false;
  637. result.message = "内部错误";
  638. result.reason = "转链接口异常";
  639. }
  640. }
  641. _ = TkLogCore.ParseLogAsync(result);
  642. return new APIResult(new
  643. {
  644. result.success,
  645. result.message,
  646. link_type = result.link_type.ToString(),
  647. channel = result?.channel.ToString(),
  648. content = result?.rawContent.ToString(),
  649. taoToken = result?.taoToken.ToString(),
  650. result.channel_type,
  651. result.itemName,
  652. result.shortLinkurl,
  653. result.deeplink_url,
  654. }, IfExceptional ? APIResultCodeEnum.NotAcceptable : APIResultCodeEnum.OK);
  655. }
  656. public static async Task<APIResult> PddParseAsync(string content, int commerceType, string ip, string oaid,
  657. int accountid = 0, CancellationToken cancellationToken = default)
  658. {
  659. var result = PddUnionPlus.GetFormattedObject(content, ip, oaid);
  660. content = content.UrlDecode();
  661. result.rawContent = content;
  662. bool IfExceptional = false;
  663. try
  664. {
  665. var config = TkConfigCore.Get();
  666. if (!string.IsNullOrEmpty(config.pdd_blacklist_regular))
  667. {
  668. var blacklist = config.pdd_blacklist_regular.Split('\n')
  669. .Where(line => !string.IsNullOrWhiteSpace(line))
  670. .ToList();
  671. bool anyMatch = false;
  672. foreach (string pattern in blacklist)
  673. {
  674. if (Regex.IsMatch(content, pattern, RegexOptions.IgnoreCase)) anyMatch = true;
  675. }
  676. if (anyMatch)
  677. {
  678. result.success = false;
  679. result.deeplink_url = string.Empty;
  680. result.message = "放弃转链";
  681. result.reason = "规则排除";
  682. _ = TkLogCore.ParseLogAsync(result);
  683. return PddParseOutput(result);
  684. }
  685. }
  686. //============================== 放弃转链-地区过滤 ==============================
  687. if (accountid == 0 && PddUnionPlus.ShouldIgnoreRequest(config, ip, oaid, out string reason))
  688. {
  689. result.success = false;
  690. result.message = "放弃转链";
  691. result.reason = reason;
  692. result.deeplink_url = PddUnionPlus.GetDeeplink(result.rawContent);
  693. _ = TkLogCore.ParseLogAsync(result);
  694. return PddParseOutput(result);
  695. }
  696. var account = PddPoolCore.GetOne(PddUnionWorkMode.All, accountid);
  697. if (account == null)
  698. {
  699. result.success = false;
  700. result.message = "放弃转链";
  701. result.reason = "没有匹配账号";
  702. result.deeplink_url = PddUnionPlus.GetDeeplink(result.rawContent);
  703. _ = TkLogCore.ParseLogAsync(result);
  704. return PddParseOutput(result);
  705. }
  706. result.accountId = account.id;
  707. result.accountName = account.name;
  708. var plus = new PddUnionPlus(account);
  709. result = await plus.PddParseAsync(content, commerceType, result, cancellationToken);
  710. }
  711. catch (Exception ex)
  712. {
  713. if (ex.Message.Contains("was canceled"))
  714. {
  715. result.success = false;
  716. result.message = "放弃转链";
  717. result.reason = "请求超时";
  718. }
  719. else
  720. {
  721. IfExceptional = true;
  722. _ = new LoggerLibrary("unionParse", "pdd_error")
  723. .Info(ip, oaid)
  724. .Info(content)
  725. .Info(ex.Message, ex.StackTrace)
  726. .SaveAsync();
  727. NotifyCore.Notify(new NifyMessage
  728. {
  729. message = $"【转链异常PDD】\n{content}\n\n{ex.Message}\n{ex.StackTrace}",
  730. priority = NifyMessagePriority.high,
  731. tags = ["red_circle"]
  732. });
  733. result.success = false;
  734. result.message = "内部错误";
  735. result.reason = "转链接口异常";
  736. }
  737. }
  738. _ = TkLogCore.ParseLogAsync(result);
  739. return PddParseOutput(result, IfExceptional ? APIResultCodeEnum.NotAcceptable : APIResultCodeEnum.OK);
  740. }
  741. private static APIResult PddParseOutput(PddDataDTO result, APIResultCodeEnum code = APIResultCodeEnum.OK)
  742. {
  743. return new APIResult(new
  744. {
  745. result.success,
  746. result.message,
  747. link_type = result.link_type.ToString(),
  748. channel = result?.channel.ToString(),
  749. result.itemId,
  750. result.itemName,
  751. result.shortLinkurl,
  752. result.deeplink_url,
  753. }, code);
  754. }
  755. public static async Task<APIResult> KsParseAsync(string content, int commerceType, string ip, string oaid,
  756. int accountid = 0, CancellationToken cancellationToken = default)
  757. {
  758. var result = KsUnionPlus.GetFormattedObject(content, ip, oaid);
  759. content = content.UrlDecode();
  760. result.rawContent = content;
  761. bool IfExceptional = false;
  762. try
  763. {
  764. var config = TkConfigCore.Get();
  765. if (!string.IsNullOrEmpty(config.ks_blacklist_regular))
  766. {
  767. var blacklist = config.ks_blacklist_regular.Split('\n')
  768. .Where(line => !string.IsNullOrWhiteSpace(line))
  769. .ToList();
  770. bool anyMatch = false;
  771. foreach (string pattern in blacklist)
  772. {
  773. if (Regex.IsMatch(content, pattern, RegexOptions.IgnoreCase)) anyMatch = true;
  774. }
  775. if (anyMatch)
  776. {
  777. result.success = false;
  778. result.deeplink_url = string.Empty;
  779. result.message = "放弃转链";
  780. result.reason = "规则排除";
  781. _ = TkLogCore.ParseLogAsync(result);
  782. return KsParseOutput(result);
  783. }
  784. }
  785. //============================== 放弃转链-地区过滤 ==============================
  786. if (accountid == 0 && KsUnionPlus.ShouldIgnoreRequest(config, ip, oaid, out string reason))
  787. {
  788. result.success = false;
  789. result.message = "放弃转链";
  790. result.reason = reason;
  791. result.deeplink_url = KsUnionPlus.GetDeeplink(string.Empty, LinkTypeEnum.baseDomain);
  792. _ = TkLogCore.ParseLogAsync(result);
  793. return KsParseOutput(result);
  794. }
  795. var account = accountid > 0 ? KsPoolCore.GetOne(accountid, KsPoolCore.KsAction.parse) : KsPoolCore.GetOne(KsPoolCore.KsAction.parse);
  796. if (account == null)
  797. {
  798. result.success = false;
  799. result.message = "放弃转链";
  800. result.reason = "没有匹配账号";
  801. result.deeplink_url = KsUnionPlus.GetDeeplink(string.Empty, LinkTypeEnum.baseDomain);
  802. _ = TkLogCore.ParseLogAsync(result);
  803. return KsParseOutput(result);
  804. }
  805. result.accountId = account.id;
  806. result.accountName = account.name;
  807. var plus = new KsUnionPlus(account);
  808. result = await plus.KsParseAsync(content, commerceType, result, cancellationToken);
  809. }
  810. catch (Exception ex)
  811. {
  812. if (ex.Message.Contains("was canceled"))
  813. {
  814. result.success = false;
  815. result.message = "放弃转链";
  816. result.reason = "请求超时";
  817. }
  818. else
  819. {
  820. IfExceptional = true;
  821. _ = new LoggerLibrary("unionParse", "jd_error")
  822. .Info(ip, oaid)
  823. .Info(content)
  824. .Info(ex.Message, ex.StackTrace)
  825. .SaveAsync();
  826. NotifyCore.Notify(new NifyMessage
  827. {
  828. message = $"【转链异常JD】\n{content}\n\n{ex.Message}\n{ex.StackTrace}",
  829. priority = NifyMessagePriority.high,
  830. tags = ["red_circle"]
  831. });
  832. result.success = false;
  833. result.message = "内部错误";
  834. result.reason = "转链接口异常";
  835. }
  836. result.deeplink_url = KsUnionPlus.GetDeeplink(string.Empty, LinkTypeEnum.baseDomain);
  837. }
  838. _ = TkLogCore.ParseLogAsync(result);
  839. return KsParseOutput(result, IfExceptional ? APIResultCodeEnum.NotAcceptable : APIResultCodeEnum.OK);
  840. }
  841. private static APIResult KsParseOutput(KsDataDTO result, APIResultCodeEnum code = APIResultCodeEnum.OK)
  842. {
  843. return new APIResult(new
  844. {
  845. result.success,
  846. result.message,
  847. link_type = result.link_type.ToString(),
  848. channel = result?.channel.ToString(),
  849. result.itemId,
  850. result.itemName,
  851. result.shortLinkurl,
  852. result.deeplink_url,
  853. }, code);
  854. }
  855. }
  856. }