RepositoryExtension.Mock.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. using Elasticsearch.Net;
  2. using JiaZhiQuan.Common.Config;
  3. using JiaZhiQuan.Common.ElasticSearch;
  4. using Microsoft.AspNetCore.JsonPatch.Internal;
  5. using Newtonsoft.Json;
  6. using Newtonsoft.Json.Linq;
  7. using Senparc.Weixin.MP.Containers;
  8. using System;
  9. using System.Collections.Generic;
  10. using System.Data;
  11. using System.Diagnostics;
  12. using System.Dynamic;
  13. using System.Linq;
  14. using System.Net.Http;
  15. using System.Reflection;
  16. using System.Security.Cryptography;
  17. using System.Text;
  18. using System.Threading.Tasks;
  19. using Wicture.DbRESTFul;
  20. using Wicture.DbRESTFul.Cache;
  21. using Wicture.DbRESTFul.Infrastructure.Repository;
  22. namespace JiaZhiQuan.Common
  23. {
  24. public static partial class RepositoryExtension
  25. {
  26. public class MockActionGenerationModel
  27. {
  28. public long targetId { get; set; }
  29. public string action { get; set; }
  30. public string content { get; set; }
  31. public long mockUserId { get; set; }
  32. public DateTime execTime { get; set; }
  33. }
  34. public static List<DateTime> GenerateMockTimes(this DbRESTFulRepository repository, DateTime startMockTime, int hours, int count)
  35. {
  36. var rand = new Random();
  37. var list = new List<DateTime>();
  38. if (hours < 25)
  39. {
  40. var startTicks = startMockTime.Ticks;
  41. var endMockTime = startMockTime.AddHours(hours);
  42. var allSecs = (int)((endMockTime.Ticks - startTicks) / 10000000);
  43. for (var i = 0; i < count; i++)
  44. {
  45. // 给定天内随机,如果在1~6点,则添加16个小时再模拟
  46. var randSecs = rand.Next(allSecs);
  47. var curTime = new DateTime(startTicks + randSecs * 10000000L);
  48. if (curTime.Hour > 1 && curTime.Hour < 6)
  49. {
  50. if (rand.Next(100) < 95)
  51. {
  52. curTime = curTime.AddHours(16);
  53. }
  54. }
  55. list.Add(curTime);
  56. }
  57. return list;
  58. }
  59. else
  60. {
  61. // 按天来随机
  62. var days = Math.Ceiling(hours / 24f);
  63. if (days > 15) days = 15;
  64. var pro = ConfigFromDb.RandomProbabilities[(int)days - 2];
  65. var totalProp = pro.Sum();
  66. // 计算一天的人数数量
  67. var dayCountDic = new Dictionary<int, int>();
  68. for (var idx = 0; idx < count; idx++)
  69. {
  70. var rnum = rand.Next(totalProp + 1);
  71. var tmp = 0;
  72. var curDay = 1;
  73. for (var i = 0; i < pro.Count; i++)
  74. {
  75. if (i == pro.Count - 1 || (rnum >= tmp && rnum <= tmp + pro[i]))
  76. {
  77. curDay = i + 1;
  78. break;
  79. };
  80. tmp += pro[i];
  81. }
  82. if (dayCountDic.ContainsKey(curDay)) dayCountDic[curDay] = dayCountDic[curDay] + 1;
  83. else dayCountDic[curDay] = 1;
  84. }
  85. var index = 0;
  86. foreach (var key in dayCountDic.Keys)
  87. {
  88. var start = startMockTime.AddDays(key - 1);
  89. var end = startMockTime.AddDays(key);
  90. var allSecs = (int)((end.Ticks - start.Ticks) / 10000000);
  91. for (var idx = 0; idx < dayCountDic[key]; idx++)
  92. {
  93. // 给定天内随机,如果在1~6点,则添加16个小时再模拟
  94. var randSecs = rand.Next(allSecs);
  95. var curTime = new DateTime(start.Ticks + randSecs * 10000000L);
  96. if (curTime.Hour > 1 && curTime.Hour < 6)
  97. {
  98. if (rand.Next(100) < 95)
  99. {
  100. curTime = curTime.AddHours(16);
  101. }
  102. }
  103. list.Add(curTime);
  104. index++;
  105. }
  106. }
  107. return list;
  108. }
  109. }
  110. /// <summary>
  111. /// 获取随机用户模拟信息
  112. /// </summary>
  113. /// <param name="modelList">如果不传,则从数据库查手机号大于90000000000的用户</param>
  114. /// <returns></returns>
  115. public async static Task<List<MockActionGenerationModel>> GenerateMockActions(this DbRESTFulRepository repository, DateTime startMockTime, int hours, long targetId, string action, int expectCount, List<MockActionGenerationModel> modelList = null)
  116. {
  117. if (modelList == null)
  118. {
  119. modelList = (await GetMockUserIdsRandom(repository, expectCount, 0))
  120. .Select(e => new MockActionGenerationModel { mockUserId = e }).ToList();
  121. }
  122. var rand = new Random();
  123. if (hours < 25)
  124. {
  125. var startTicks = startMockTime.Ticks;
  126. var endMockTime = startMockTime.AddHours(hours);
  127. var allSecs = (int)((endMockTime.Ticks - startTicks) / 10000000);
  128. foreach (var item in modelList)
  129. {
  130. item.targetId = targetId;
  131. item.action = action;
  132. // 给定天内随机,如果在1~6点,则添加16个小时再模拟
  133. var randSecs = rand.Next(allSecs);
  134. var curTime = new DateTime(startTicks + randSecs * 10000000L);
  135. if (curTime.Hour > 1 && curTime.Hour < 6)
  136. {
  137. if (rand.Next(100) < 95)
  138. {
  139. curTime = curTime.AddHours(16);
  140. }
  141. }
  142. item.execTime = curTime;
  143. }
  144. return modelList;
  145. }
  146. else
  147. {
  148. // 按天来随机
  149. var days = Math.Ceiling(hours / 24f);
  150. if (days > 15) days = 15;
  151. var pro = ConfigFromDb.RandomProbabilities[(int)days - 2];
  152. var totalProp = pro.Sum();
  153. // 计算一天的人数数量
  154. var dayCountDic = new Dictionary<int, int>();
  155. for (var idx = 0; idx < modelList.Count; idx++)
  156. {
  157. var rnum = rand.Next(totalProp + 1);
  158. var tmp = 0;
  159. var curDay = 1;
  160. for (var i = 0; i < pro.Count; i++)
  161. {
  162. if (i == pro.Count - 1 || (rnum >= tmp && rnum <= tmp + pro[i]))
  163. {
  164. curDay = i + 1;
  165. break;
  166. };
  167. tmp += pro[i];
  168. }
  169. if (dayCountDic.ContainsKey(curDay)) dayCountDic[curDay] = dayCountDic[curDay] + 1;
  170. else dayCountDic[curDay] = 1;
  171. }
  172. var index = 0;
  173. foreach(var key in dayCountDic.Keys)
  174. {
  175. var start = startMockTime.AddDays(key - 1);
  176. var end = startMockTime.AddDays(key);
  177. var allSecs = (int)((end.Ticks - start.Ticks) / 10000000);
  178. for (var idx = 0; idx < dayCountDic[key]; idx++)
  179. {
  180. var item = modelList[index];
  181. item.targetId = targetId;
  182. item.action = action;
  183. // 给定天内随机,如果在1~6点,则添加16个小时再模拟
  184. var randSecs = rand.Next(allSecs);
  185. var curTime = new DateTime(start.Ticks + randSecs * 10000000L);
  186. if (curTime.Hour > 1 && curTime.Hour < 6)
  187. {
  188. if (rand.Next(100) < 95)
  189. {
  190. curTime = curTime.AddHours(16);
  191. }
  192. }
  193. item.execTime = curTime;
  194. index++;
  195. }
  196. }
  197. return modelList;
  198. }
  199. }
  200. /// <summary>
  201. /// 给文章添加点赞数量任务
  202. /// </summary>
  203. public static async Task AddMockPostThumbsup(this DbRESTFulRepository repository, DateTime startMockTime, int hours, long postId, int expectCount, IDbConnection conn = null)
  204. {
  205. var postInfo = await repository.QuerySingleOrDefaultAsync<dynamic>($"select id, state, userId, checkCntLevel from n_post where id={postId}", null, conn);
  206. if (postInfo == null || postInfo.state != 1 || "D".Equals(postInfo.checkCntLevel)) return;
  207. var list = await repository.GenerateMockActions(startMockTime, hours, postId, "POST_THUMBSUP", expectCount);
  208. if (list.Count > 0)
  209. {
  210. var time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
  211. var size = 500;
  212. for (var i = 0; i < list.Count; i += size)
  213. {
  214. var leftCount = list.Count - i;
  215. var subList = list.Skip(i).Take(leftCount >= size ? size : leftCount).ToList();
  216. if (subList.Count > 0)
  217. {
  218. await repository.QueryAsync<dynamic>($"insert ignore into n_mock_action_records (targetId, action, content, mockUserId, execTime, createTime) values (@targetId, @action, @content, @mockUserId, @execTime, '{time}')", subList, conn, null, false);
  219. }
  220. }
  221. await repository.QueryAsync<dynamic>("update n_post set mockThumbsupCnt=mockThumbsupCnt+" + list.Count + " where id=" + postId, null, conn, null, false);
  222. }
  223. }
  224. /// <summary>
  225. /// 给文章添加收藏数量任务
  226. /// </summary>
  227. public static async Task AddMockPostCollection(this DbRESTFulRepository repository, DateTime startMockTime, int hours, long postId, int expectCount, IDbConnection conn = null)
  228. {
  229. var postInfo = await repository.QuerySingleOrDefaultAsync<dynamic>($"select id, state, userId, checkCntLevel from n_post where id={postId}", null, conn);
  230. if (postInfo == null || postInfo.state != 1 || "D".Equals(postInfo.checkCntLevel)) return;
  231. var list = await repository.GenerateMockActions(startMockTime, hours, postId, "POST_COLLECTION", expectCount);
  232. if (list.Count > 0)
  233. {
  234. var time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
  235. var size = 500;
  236. for (var i = 0; i < list.Count; i += size)
  237. {
  238. var leftCount = list.Count - i;
  239. var subList = list.Skip(i).Take(leftCount >= size ? size : leftCount).ToList();
  240. if (subList.Count > 0)
  241. {
  242. await repository.QueryAsync<dynamic>($"insert ignore into n_mock_action_records (targetId, action, content, mockUserId, execTime, createTime) values (@targetId, @action, @content, @mockUserId, @execTime, '{time}')", subList, conn, null, false);
  243. }
  244. }
  245. await repository.QueryAsync<dynamic>("update n_post set mockCollectionCnt=mockCollectionCnt+" + list.Count + " where id=" + postId, null, conn, null, false);
  246. }
  247. }
  248. /// <summary>
  249. /// 给文章添加分享数量任务
  250. /// </summary>
  251. public static async Task AddMockPostShare(this DbRESTFulRepository repository, DateTime startMockTime, int hours, long postId, int expectCount, IDbConnection conn = null)
  252. {
  253. var postInfo = await repository.QuerySingleOrDefaultAsync<dynamic>($"select id, state, userId, checkCntLevel from n_post where id={postId}", null, conn);
  254. if (postInfo == null || postInfo.state != 1 || "D".Equals(postInfo.checkCntLevel)) return;
  255. var list = await repository.GenerateMockActions(startMockTime, hours, postId, "POST_SHARE", expectCount);
  256. if (list.Count > 0)
  257. {
  258. var time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
  259. var size = 500;
  260. for (var i = 0; i < list.Count; i += size)
  261. {
  262. var leftCount = list.Count - i;
  263. var subList = list.Skip(i).Take(leftCount >= size ? size : leftCount).ToList();
  264. if (subList.Count > 0)
  265. {
  266. await repository.QueryAsync<dynamic>($"insert ignore into n_mock_action_records (targetId, action, content, mockUserId, execTime, createTime) values (@targetId, @action, @content, @mockUserId, @execTime, '{time}')", subList, conn, null, false);
  267. }
  268. }
  269. await repository.QueryAsync<dynamic>("update n_post set mockShareCnt=mockShareCnt+" + list.Count + " where id=" + postId, null, conn, null, false);
  270. }
  271. }
  272. /// <summary>
  273. /// 按文章添加作者主页访问数量任务
  274. /// </summary>
  275. public static async Task AddMockPostPPVisit(this DbRESTFulRepository repository, DateTime startMockTime, int hours, long postId, int expectCount, IDbConnection conn = null)
  276. {
  277. var postInfo = await repository.QuerySingleOrDefaultAsync<dynamic>($"select id, state, userId, checkCntLevel from n_post where id={postId}", null, conn);
  278. if (postInfo == null || postInfo.state != 1 || "D".Equals(postInfo.checkCntLevel)) return;
  279. var list = await repository.GenerateMockActions(startMockTime, hours, postId, "POST_PPVISIT", expectCount);
  280. if (list.Count > 0)
  281. {
  282. var time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
  283. var size = 500;
  284. for (var i = 0; i < list.Count; i += size)
  285. {
  286. var leftCount = list.Count - i;
  287. var subList = list.Skip(i).Take(leftCount >= size ? size : leftCount).ToList();
  288. if (subList.Count > 0)
  289. {
  290. await repository.QueryAsync<dynamic>($"insert ignore into n_mock_action_records (targetId, action, content, mockUserId, execTime, createTime) values (@targetId, @action, @content, @mockUserId, @execTime, '{time}')", subList, conn, null, false);
  291. }
  292. }
  293. }
  294. }
  295. /// <summary>
  296. /// 按用户添加主页访问数量任务
  297. /// </summary>
  298. public static async Task AddMockUserPPVisit(this DbRESTFulRepository repository, DateTime startMockTime, int hours, long userId, int expectCount, IDbConnection conn = null)
  299. {
  300. var userInfo = await repository.QuerySingleOrDefaultAsync<dynamic>($"select id, state from n_user where id={userId}", null, conn);
  301. if (userInfo == null || userInfo.state != 0) return;
  302. var list = await repository.GenerateMockActions(startMockTime, hours, userId, "USER_PPVISIT", expectCount);
  303. if (list.Count > 0)
  304. {
  305. var time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
  306. var size = 500;
  307. for (var i = 0; i < list.Count; i += size)
  308. {
  309. var leftCount = list.Count - i;
  310. var subList = list.Skip(i).Take(leftCount >= size ? size : leftCount).ToList();
  311. if (subList.Count > 0)
  312. {
  313. await repository.QueryAsync<dynamic>($"insert ignore into n_mock_action_records (targetId, action, content, mockUserId, execTime, createTime) values (@targetId, @action, @content, @mockUserId, @execTime, '{time}')", subList, conn, null, false);
  314. }
  315. }
  316. }
  317. }
  318. /// <summary>
  319. /// 【已废弃】给文章添加评论数量任务
  320. /// </summary>
  321. public static async Task AddMockPostComment(this DbRESTFulRepository repository, DateTime startMockTime, int hours, long postId, int expectCount)
  322. {
  323. await Task.CompletedTask;
  324. // var records = await repository.GenerateMockActions(DateTime.Now, hours, postId, "COMMENT", expectCount);
  325. // if (records.Count == 0) return;
  326. // // 获取模拟评论
  327. // var primaryType = await repository.QuerySingleOrDefaultAsync<int>($"select primaryType from n_post where id={postId}");
  328. // if (primaryType == 0) return;
  329. // var contList = (await repository.QueryAsync<string>($"select `comment`, rand() as rid from n_mock_comment_cnt where primaryType={primaryType} order by rid asc limit " + expectCount)).ToList();
  330. // if (contList.Count == 0) return;
  331. // if (contList.Count < records.Count)
  332. // {
  333. // records = records.Take(contList.Count).ToList();
  334. // }
  335. // for (var i = 0; i < contList.Count; i++)
  336. // {
  337. // records[i].content = contList[i];
  338. // }
  339. // var time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
  340. // await repository.QueryAsync<dynamic>($"insert ignore into n_mock_action_records (targetId, action, content, mockUserId, execTime, createTime) values (@targetId, @action, @content, @mockUserId, @execTime, '{time}')", records, null, null, false);
  341. }
  342. /// <summary>
  343. /// 给某用户添加模拟关注任务
  344. /// </summary>
  345. public static async Task AddMockFocusUser(this DbRESTFulRepository repository, DateTime startMockTime, int hours, long userId, int expectCount, IDbConnection conn = null)
  346. {
  347. var list = (await repository.QueryAsync<MockActionGenerationModel>("select t.id as mockUserId, rand() as rid from (select id from n_user where autoGenerationType=1 and username>='90000000000' and id not in (select uf.fanId from n_user_fan as uf where uf.userId=@userId)) as t order by rid asc limit " + expectCount, new { userId })).ToList();
  348. if (list.Count < expectCount)
  349. {
  350. var count = expectCount - list.Count;
  351. var moreList = (await repository.QueryAsync<MockActionGenerationModel>("select t.id as mockUserId, rand() as rid from (select id from n_user where autoGenerationType=2 and username>='90000000000' and id not in (select uf.fanId from n_user_fan as uf where uf.userId=@userId)) as t order by rid asc limit " + count, new { userId })).ToList();
  352. list.AddRange(moreList);
  353. list.Shuffle();
  354. }
  355. list = await GenerateMockActions(repository, startMockTime, hours, userId, "USER_FOCUS", expectCount, list);
  356. if (list.Count > 0)
  357. {
  358. var time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
  359. var size = 500;
  360. for (var i = 0; i < list.Count; i += size)
  361. {
  362. var leftCount = list.Count - i;
  363. var subList = list.Skip(i).Take(leftCount >= size ? size : leftCount).ToList();
  364. if (subList.Count > 0)
  365. {
  366. await repository.QueryAsync<dynamic>($"insert ignore into n_mock_action_records (targetId, action, content, mockUserId, execTime, createTime) values (@targetId, @action, @content, @mockUserId, @execTime, '{time}')", subList, conn, null, false);
  367. }
  368. }
  369. await repository.QueryAsync<dynamic>($"update n_user set mockFocusCnt=mockFocusCnt+@count where id=@userId", new { count = list.Count, userId }, conn, null, false);
  370. }
  371. }
  372. /// <summary>
  373. /// 给某文章添加模拟阅读任务
  374. /// </summary>
  375. public static async Task AddMockPostRead(this DbRESTFulRepository repository, DateTime startMockTime, int hours, long postId, int count, IDbConnection conn = null)
  376. {
  377. var postInfo = await repository.QuerySingleOrDefaultAsync<dynamic>($"select id, state, userId, checkCntLevel from n_post where id={postId}", null, conn);
  378. if (postInfo == null || postInfo.state != 1 || "D".Equals(postInfo.checkCntLevel)) return;
  379. var records = GenerateMockTimes(repository, startMockTime, hours, count).Select(e => new { readAt = e.ToString("yyyy-MM-dd HH:mm:ss") }).ToList();
  380. // 一次处理500条记录
  381. var size = 500;
  382. for (var i = 0; i < records.Count; i += size)
  383. {
  384. var leftCount = records.Count - i;
  385. var subList = records.Skip(i).Take(leftCount >= size ? size : leftCount).ToList();
  386. if (subList.Count > 0)
  387. {
  388. await repository.QueryAsync<dynamic>($"insert into n_mock_read_action_records(postId, readAt) values ({postId}, @readAt)", subList, conn);
  389. }
  390. }
  391. }
  392. /// <summary>
  393. /// 获取模拟用户
  394. /// </summary>
  395. /// <param name="expectCount">期望获取最多多少个</param>
  396. /// <returns></returns>
  397. public static async Task<List<long>> GetMockUserIdsRandom(this DbRESTFulRepository repository, int expectCount, int minPostCount = 0)
  398. {
  399. if (minPostCount > 0)
  400. {
  401. var userIds = (await repository.QueryAsync<long>("select tt.id from (select t.id, rand() as rid from n_user as t left join n_user_statistic as us on t.id=us.userId where t.autoGenerationType=1 and t.username>='90000000000' and us.post>=@minPostCount order by rid asc limit @expectCount) as tt", new { expectCount, minPostCount })).ToList();
  402. if (userIds.Count < expectCount)
  403. {
  404. var count = expectCount - userIds.Count;
  405. var moreUserIds = (await repository.QueryAsync<long>("select tt.id from (select t.id, rand() as rid from n_user as t left join n_user_statistic as us on t.id=us.userId where t.autoGenerationType=2 and t.username>='90000000000' and us.post>=@minPostCount order by rid asc limit @expectCount) as tt", new { expectCount = count, minPostCount })).ToList();
  406. userIds.AddRange(moreUserIds);
  407. userIds.Shuffle();
  408. }
  409. return userIds;
  410. }
  411. else
  412. {
  413. var userIds = (await repository.QueryAsync<long>("select tt.id from (select t.id, rand() as rid from n_user as t where t.autoGenerationType=1 and t.username>='90000000000' order by rid asc limit @expectCount) as tt", new { expectCount })).ToList();
  414. if (userIds.Count < expectCount)
  415. {
  416. var count = expectCount - userIds.Count;
  417. var moreUserIds = (await repository.QueryAsync<long>("select tt.id from (select t.id, rand() as rid from n_user as t where t.autoGenerationType=2 and t.username>='90000000000' order by rid asc limit @expectCount) as tt", new { expectCount = count })).ToList();
  418. userIds.AddRange(moreUserIds);
  419. userIds.Shuffle();
  420. }
  421. return userIds;
  422. }
  423. }
  424. /// <summary>
  425. /// 获取数据库配置的模拟发文章的用户
  426. /// </summary>
  427. public static async Task<List<long>> GetMockUserIdsRandomByCategoryType(this DbRESTFulRepository repository, int expectCount, int categoryType)
  428. {
  429. return (await repository.QueryAsync<long>($"select tt.userId from (select t.userId, rand() as rid from s_mock_user_post as t where t.categoryType={categoryType} order by rid asc limit {expectCount}) as tt")).ToList();
  430. }
  431. }
  432. }