UnionParseCore.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  1. using Microsoft.AspNetCore.Http;
  2. using Microsoft.AspNetCore.Mvc.Controllers;
  3. using Microsoft.AspNetCore.Mvc.Filters;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using System.Text;
  8. using dodohold.core;
  9. using Spire.Pdf.Exporting.XPS.Schema;
  10. using System.Xml.Linq;
  11. using System.Net;
  12. using TencentCloud.Mrs.V20200910.Models;
  13. using Microsoft.AspNetCore.Mvc;
  14. using Microsoft.AspNetCore.Authentication;
  15. using Spire.Pdf.Graphics;
  16. using Google.Protobuf.WellKnownTypes;
  17. using TencentCloud.Tcm.V20210413.Models;
  18. using System.Diagnostics;
  19. using System.Threading;
  20. using TencentCloud.Soe.V20180724.Models;
  21. using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
  22. using System.Runtime.Intrinsics.Arm;
  23. using ZstdSharp.Unsafe;
  24. using System.Text.RegularExpressions;
  25. namespace molilian.core
  26. {
  27. public partial class UnionParseCore
  28. {
  29. public static async Task<ActionResult> UnionParseAsync(string content, string channel, string ip, string oaid, int accountid = 0)
  30. {
  31. content = content.Trim();
  32. return channel switch
  33. {
  34. "wemeet" => await WemeetParseAsync(content, ip, oaid),
  35. "bdpan" => PanParse(content, ip, oaid),
  36. "jd" => await JdParseAsync(content, ip, oaid, accountid),
  37. "dy" => await DyParseAsync(content, ip, oaid),
  38. _ => await TaobaoParseAsync(content, ip, oaid, accountid),
  39. };
  40. }
  41. public static async Task<APIResult> WemeetParseAsync(string content, string ip, string oaid)
  42. {
  43. var result = ToolParsePlus.GetFormattedObject(TkChannelEnum.wemeet, content, ip, oaid);
  44. content = content.UrlDecode();
  45. result.rawContent = content;
  46. try
  47. {
  48. result = await ToolParsePlus.WemeetParseAsync(content, result);
  49. }
  50. catch (Exception ex)
  51. {
  52. _ = new LoggerLibrary("unionParse", "wemeet_error")
  53. .Info(ip, oaid)
  54. .Info(content)
  55. .Info(ex.Message, ex.StackTrace)
  56. .SaveAsync();
  57. NotifyCore.Notify(new NifyMessage
  58. {
  59. message = $"【转链异常Wemeet】\n{content}\n\n{ex.Message}\n{ex.StackTrace}",
  60. priority = NifyMessagePriority.high,
  61. tags = ["red_circle"]
  62. });
  63. result.success = false;
  64. result.message = "内部错误";
  65. result.reason = "转链接口异常";
  66. }
  67. _ = TkLogCore.ParseLogAsync(result);
  68. return new APIResult(new
  69. {
  70. result.success,
  71. result.message,
  72. channel = result?.channel.ToString(),
  73. result.shortLinkurl,
  74. result.deeplink_url,
  75. result.itemName,
  76. }, result.success ? APIResultCodeEnum.OK : APIResultCodeEnum.NotAcceptable);
  77. }
  78. public static APIResult PanParse(string content, string ip, string oaid)
  79. {
  80. var result = ToolParsePlus.GetFormattedObject(TkChannelEnum.bdpan, content, ip, oaid);
  81. content = content.UrlDecode();
  82. result.rawContent = content;
  83. try
  84. {
  85. ToolParsePlus.PanParse(content, ref result);
  86. }
  87. catch (Exception ex)
  88. {
  89. _ = new LoggerLibrary("unionParse", "pan_error")
  90. .Info(ip, oaid)
  91. .Info(content)
  92. .Info(ex.Message, ex.StackTrace)
  93. .SaveAsync();
  94. NotifyCore.Notify(new NifyMessage
  95. {
  96. message = $"【转链异常Pan】\n{content}\n\n{ex.Message}\n{ex.StackTrace}",
  97. priority = NifyMessagePriority.high,
  98. tags = ["red_circle"]
  99. });
  100. result.success = false;
  101. result.message = "内部错误";
  102. result.reason = "转链接口异常";
  103. }
  104. _ = TkLogCore.ParseLogAsync(result);
  105. return new APIResult(new
  106. {
  107. result.success,
  108. result.message,
  109. channel = result?.channel.ToString(),
  110. result.shortLinkurl,
  111. result.deeplink_url,
  112. result.itemName,
  113. }, !string.IsNullOrEmpty(result.deeplink_url) ? APIResultCodeEnum.OK : APIResultCodeEnum.NotAcceptable);
  114. }
  115. private static APIResult TaobaoParseOutput(TkDataDTO result, Dictionary<string, long> swData, object info, APIResultCodeEnum code = APIResultCodeEnum.OK)
  116. {
  117. if (result.elapsedTime > 2000)
  118. {
  119. LoggerLibrary log = new("debug", "stopwatch");
  120. foreach ((var key, var value) in swData)
  121. {
  122. log.Info($"{key}\t{value}");
  123. }
  124. log.SaveAsync();
  125. }
  126. return new APIResult(info, code);
  127. }
  128. public static async Task<APIResult> TaobaoParseAsync(string content,
  129. string ip = "", string oaid = "",
  130. int accountid = 0)
  131. {
  132. AlimamaPlus alimama = null;
  133. //content = content.UrlDecode();
  134. content = content[..Math.Min(1000, content.Length)];
  135. var result = AlimamaPlus.GetFormattedObject(content, ip, oaid);
  136. Dictionary<string, long> swData = new();
  137. swData.Add("StartNew", 0);
  138. Stopwatch stopwatch = Stopwatch.StartNew();
  139. result.rawContent = content;
  140. try
  141. {
  142. string reason = string.Empty;
  143. var config = TkConfigCore.Get();
  144. var arr = config.tk_whitelist_regular.Split('\n')
  145. .Where(line => !string.IsNullOrWhiteSpace(line))
  146. .ToList();
  147. var arr2 = config.tk_blacklist_regular.Split('\n')
  148. .Where(line => !string.IsNullOrWhiteSpace(line))
  149. .ToList();
  150. var arr3 = config.multi_token_regular.Split('\n')
  151. .Where(line => !string.IsNullOrWhiteSpace(line))
  152. .ToList();
  153. bool is_tao_url = !string.IsNullOrEmpty(result.shortLinkurl);
  154. bool is_tao_token = AlimamaPlus.MatchRegexes(content, arr);
  155. bool is_other = AlimamaPlus.MatchOtherInfo(content, arr2);
  156. //============================== 放弃转链-初步筛选1 ==============================
  157. if (!is_tao_url && !is_tao_token || is_other)
  158. {
  159. //没有链接都放弃
  160. result.success = false;
  161. result.message = "放弃转链";
  162. result.reason = "初步筛选1";
  163. result.subCode = TkSubCodeEnum.Prelim1;
  164. result.itemName = "";
  165. result.deeplink_url = "";
  166. _ = TkLogCore.ParseLogAsync(result);
  167. return TaobaoParseOutput(result, swData, new
  168. {
  169. result.success,
  170. result.message,
  171. result.content,
  172. result.itemName,
  173. result.deeplink_url,
  174. });
  175. }
  176. bool is_multi_token = AlimamaPlus.MatchMultiToken(content, arr3);
  177. //============================== 放弃转链-初步筛选1.5 ==============================
  178. if (is_multi_token)
  179. {
  180. //没有链接都放弃
  181. result.success = false;
  182. result.message = "放弃转链";
  183. result.reason = "初步筛选1.5";
  184. result.subCode = TkSubCodeEnum.Prelim1_5;
  185. result.itemName = "";
  186. result.deeplink_url = "";
  187. _ = TkLogCore.ParseLogAsync(result);
  188. return TaobaoParseOutput(result, swData, new
  189. {
  190. result.success,
  191. result.message,
  192. result.content,
  193. result.itemName,
  194. result.deeplink_url,
  195. });
  196. }
  197. //============================== 放弃转链-初步筛选2 ==============================
  198. bool is_aff_link = false;
  199. if (!string.IsNullOrEmpty(result.shortLinkurl)) is_aff_link = AlimamaPlus.IsAffLink(result.shortLinkurl);
  200. if ((!is_tao_url && is_tao_token) || is_aff_link)
  201. {
  202. //没有短链接都放弃
  203. result.success = false;
  204. result.message = "放弃转链";
  205. result.reason = "初步筛选2";
  206. result.subCode = TkSubCodeEnum.Prelim2;
  207. result.itemName = "点击打开淘宝APP";
  208. _ = TkLogCore.ParseLogAsync(result);
  209. return TaobaoParseOutput(result, swData, new
  210. {
  211. result.success,
  212. result.message,
  213. result.content,
  214. result.itemName,
  215. result.deeplink_url,
  216. });
  217. }
  218. //那就初步筛选3 有tb.cn 并且有 or 手淘发现
  219. string pattern = @"^(?!【淘宝】).*https?:\/\/m\.tb\.cn.*(?:手淘发现|手淘搜索)";
  220. bool isMatch = Regex.IsMatch(content, pattern);
  221. if (isMatch)
  222. {
  223. result.success = false;
  224. result.message = "放弃转链";
  225. result.reason = "初步筛选3";
  226. result.subCode = TkSubCodeEnum.Prelim3;
  227. result.itemName = "点击打开淘宝APP";
  228. _ = TkLogCore.ParseLogAsync(result);
  229. return TaobaoParseOutput(result, swData, new
  230. {
  231. result.success,
  232. result.message,
  233. result.content,
  234. result.itemName,
  235. result.deeplink_url,
  236. });
  237. }
  238. //============================== 放弃转链-地区过滤 ==============================
  239. bool is_ignore2 = AlimamaPlus.ShouldIgnoreRequest(ip, oaid, out reason);
  240. if (is_ignore2)
  241. {
  242. result.success = false;
  243. result.message = "放弃转链";
  244. result.itemName = "点击打开淘宝APP";
  245. result.reason = reason;
  246. result.subCode = TkSubCodeEnum.TrafficCtrl;
  247. _ = TkLogCore.ParseLogAsync(result);
  248. return TaobaoParseOutput(result, swData, new
  249. {
  250. result.success,
  251. result.message,
  252. result.content,
  253. result.itemName,
  254. result.deeplink_url,
  255. });
  256. }
  257. //============================== 放弃转链-没有匹配账号 ==============================
  258. TkPoolDTO? account = accountid > 0 ?
  259. TkPoolCore.GetOne(accountid) :
  260. TkPoolCore.GetOne(TkPoolCore.TkAction.parse);
  261. if (account == null)
  262. {
  263. result.success = false;
  264. result.message = "放弃转链";
  265. result.reason = "没有匹配账号";
  266. result.subCode = TkSubCodeEnum.Other;
  267. result.itemName = "点击打开淘宝APP";
  268. _ = TkLogCore.ParseLogAsync(result);
  269. return TaobaoParseOutput(result, swData, new
  270. {
  271. result.success,
  272. result.message,
  273. result.content,
  274. result.couponAmount,
  275. result.taoToken,
  276. result.shortLinkurl,
  277. result.deeplink_url,
  278. });
  279. }
  280. result.accountId = account.id;
  281. result.accountName = account.company;
  282. alimama = new AlimamaPlus(account);
  283. int timeout = alimama._config.rt_max;
  284. #if DEBUG
  285. timeout = 10000;
  286. #endif
  287. using var cts = new CancellationTokenSource();
  288. cts.CancelAfter(timeout);
  289. var requestTask = Task.Run(() => alimama.UnionParse2Async(content, result, cts.Token, swData), cts.Token);
  290. var delayTask = Task.Delay(timeout, cts.Token);
  291. var completedTask = await Task.WhenAny(requestTask, delayTask);
  292. if (completedTask == requestTask)
  293. {
  294. result = await requestTask;
  295. }
  296. else
  297. {
  298. //============================== 放弃转链-请求超时 ==============================
  299. cts.Cancel();
  300. result.success = false;
  301. result.message = "放弃转链";
  302. result.reason = "请求超时";
  303. result.subCode = TkSubCodeEnum.Other;
  304. result.itemName = "点击打开淘宝APP";
  305. }
  306. result.accountName = account.company;
  307. //result = await alimama.UnionParse2Async(content, result);
  308. }
  309. catch (Exception ex)
  310. {
  311. //============================== 放弃转链-请求超时 ==============================
  312. if (ex.Message.Contains("was canceled"))
  313. {
  314. result.success = false;
  315. result.message = "放弃转链";
  316. result.reason = "请求超时";
  317. result.subCode = TkSubCodeEnum.Other;
  318. result.itemName = "点击打开淘宝APP";
  319. }
  320. else
  321. {
  322. //============================== 转链接口异常 ==============================
  323. _ = new LoggerLibrary("unionParse", "tb_error")
  324. .Info(ip, oaid)
  325. .Info(content)
  326. .Info(ex.Message, ex.StackTrace)
  327. .SaveAsync();
  328. NotifyCore.Notify(new NifyMessage
  329. {
  330. message = $"【转链异常TB】\n{content}\n\n{ex.Message}\n{ex.StackTrace}",
  331. priority = NifyMessagePriority.high,
  332. tags = ["red_circle"]
  333. });
  334. result.success = false;
  335. result.subCode = TkSubCodeEnum.Other;
  336. result.message = "转链接口异常";
  337. result.itemName = "点击打开淘宝APP";
  338. }
  339. }
  340. _ = TkLogCore.ParseLogAsync(result, alimama);
  341. return TaobaoParseOutput(result, swData, new
  342. {
  343. result.success,
  344. result.message,
  345. link_type = result.link_type.ToString(),
  346. channel = result?.channel.ToString(),
  347. result.channel_type,
  348. result.itemId,
  349. result.itemName,
  350. result.pic,
  351. result.promotionPrice,
  352. result.couponAmount,
  353. result.couponEffectiveStartTime,
  354. result?.couponEffectiveEndTime,
  355. result.shortLinkurl,
  356. result.deeplink_url,
  357. result.content,
  358. result.taoToken,
  359. });
  360. }
  361. private static APIResult JdParseOutput(JdDataDTO result, APIResultCodeEnum code = APIResultCodeEnum.OK)
  362. {
  363. return new APIResult(new
  364. {
  365. result.success,
  366. result.message,
  367. link_type = result.link_type.ToString(),
  368. channel = result?.channel.ToString(),
  369. result.channel_type,
  370. result.itemId,
  371. result.itemName,
  372. result.shortLinkurl,
  373. result.deeplink_url,
  374. }, code);
  375. }
  376. public static async Task<APIResult> JdParseAsync(string content, string ip, string oaid,
  377. int accountid = 0, CancellationToken cancellationToken = default)
  378. {
  379. var result = JdUnionPlus.GetFormattedObject(content, ip, oaid);
  380. content = content.UrlDecode();
  381. result.rawContent = content;
  382. bool IfExceptional = false;
  383. try
  384. {
  385. var config = TkConfigCore.Get();
  386. //============================== 放弃转链-地区过滤 ==============================
  387. if (accountid == 0 && JdUnionPlus.ShouldIgnoreRequest(config, ip, oaid, out string reason))
  388. {
  389. result.success = false;
  390. result.message = "放弃转链";
  391. result.reason = reason;
  392. _ = TkLogCore.ParseLogAsync(result);
  393. return JdParseOutput(result);
  394. }
  395. // bool is_ignore2 = JdUnionPlus.FlowControlIgnoreRequest(config, out reason);
  396. //#if DEBUG
  397. // is_ignore2 = false;
  398. //#endif
  399. // if (accountid == 0 && is_ignore2)
  400. // {
  401. // result.success = false;
  402. // result.message = "放弃转链";
  403. // result.reason = reason;
  404. // _ = TkLogCore.ParseLogAsync(result);
  405. // return JdParseOutput(result);
  406. // }
  407. var account = accountid > 0 ? JdPoolCore.GetOne(accountid, JdPoolCore.JdAction.parse) : JdPoolCore.GetOne(JdPoolCore.JdAction.parse);
  408. if (account == null)
  409. {
  410. result.success = false;
  411. result.message = "放弃转链";
  412. result.reason = "没有匹配账号";
  413. _ = TkLogCore.ParseLogAsync(result);
  414. return JdParseOutput(result);
  415. }
  416. result.accountId = account.id;
  417. result.accountName = account.name;
  418. var plus = new JdUnionPlus(account);
  419. result = await plus.JdParseAsync(content, result, cancellationToken);
  420. }
  421. catch (Exception ex)
  422. {
  423. if (ex.Message.Contains("was canceled"))
  424. {
  425. result.success = false;
  426. result.message = "放弃转链";
  427. result.reason = "请求超时";
  428. }
  429. else
  430. {
  431. IfExceptional = true;
  432. _ = new LoggerLibrary("unionParse", "jd_error")
  433. .Info(ip, oaid)
  434. .Info(content)
  435. .Info(ex.Message, ex.StackTrace)
  436. .SaveAsync();
  437. NotifyCore.Notify(new NifyMessage
  438. {
  439. message = $"【转链异常JD】\n{content}\n\n{ex.Message}\n{ex.StackTrace}",
  440. priority = NifyMessagePriority.high,
  441. tags = ["red_circle"]
  442. });
  443. result.success = false;
  444. result.message = "内部错误";
  445. result.reason = "转链接口异常";
  446. }
  447. }
  448. _ = TkLogCore.ParseLogAsync(result);
  449. return JdParseOutput(result, IfExceptional ? APIResultCodeEnum.NotAcceptable : APIResultCodeEnum.OK);
  450. }
  451. public static async Task<APIResult> DyParseAsync(string content, string ip, string oaid, CancellationToken cancellationToken = default)
  452. {
  453. var result = DyUnionPlus.GetFormattedObject(content, ip, oaid);
  454. content = content.UrlDecode();
  455. result.rawContent = content;
  456. bool IfExceptional = false;
  457. try
  458. {
  459. // 2024-06-19 联盟业务下线
  460. result.success = false;
  461. result.message = "放弃转链";
  462. result.reason = "联盟下线";
  463. _ = TkLogCore.ParseLogAsync(result);
  464. return new APIResult(result);
  465. if (DyUnionPlus.ShouldIgnoreRequest(ip, oaid, out string reason))
  466. {
  467. result.success = false;
  468. result.message = "放弃转链";
  469. result.reason = reason;
  470. _ = TkLogCore.ParseLogAsync(result);
  471. return new APIResult(result);
  472. }
  473. var account = PangolinPoolCore.GetOne();
  474. if (account == null)
  475. {
  476. result.success = false;
  477. result.message = "放弃转链";
  478. result.reason = "没有匹配账号";
  479. _ = TkLogCore.ParseLogAsync(result);
  480. return new APIResult(result);
  481. }
  482. result = await DyUnionPlus.DyParseAsync(account, content, result, cancellationToken);
  483. }
  484. catch (Exception ex)
  485. {
  486. if (ex.Message.Contains("was canceled"))
  487. {
  488. result.success = false;
  489. result.message = "放弃转链";
  490. result.reason = "请求超时";
  491. }
  492. else
  493. {
  494. IfExceptional = true;
  495. _ = new LoggerLibrary("unionParse", "dy_error")
  496. .Info(ip, oaid)
  497. .Info(content)
  498. .Info(ex.Message, ex.StackTrace)
  499. .SaveAsync();
  500. NotifyCore.Notify(new NifyMessage
  501. {
  502. message = $"【转链异常DY】\n{content}\n\n{ex.Message}\n{ex.StackTrace}",
  503. priority = NifyMessagePriority.high,
  504. tags = ["red_circle"]
  505. });
  506. result.success = false;
  507. result.message = "内部错误";
  508. result.reason = "转链接口异常";
  509. }
  510. }
  511. _ = TkLogCore.ParseLogAsync(result);
  512. return new APIResult(new
  513. {
  514. result.success,
  515. result.message,
  516. link_type = result.link_type.ToString(),
  517. channel = result?.channel.ToString(),
  518. content = result?.rawContent.ToString(),
  519. taoToken = result?.taoToken.ToString(),
  520. result.channel_type,
  521. result.itemName,
  522. result.shortLinkurl,
  523. result.deeplink_url,
  524. }, IfExceptional ? APIResultCodeEnum.NotAcceptable : APIResultCodeEnum.OK);
  525. }
  526. }
  527. }