RepositoryExtension.Mock.cs 24 KB

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