using Elasticsearch.Net; using JiaZhiQuan.Common.Config; using JiaZhiQuan.Common.ElasticSearch; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Senparc.Weixin.MP.Containers; using System; using System.Collections.Generic; using System.Data; using System.Diagnostics; using System.Dynamic; using System.Linq; using System.Net.Http; using System.Reflection; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; using Wicture.DbRESTFul; using Wicture.DbRESTFul.Cache; using Wicture.DbRESTFul.Infrastructure.Repository; namespace JiaZhiQuan.Common { public static partial class RepositoryExtension { public class MockActionGenerationModel { public long targetId { get; set; } public string action { get; set; } public string content { get; set; } public long mockUserId { get; set; } public DateTime execTime { get; set; } } public static List GenerateMockTimes(this DbRESTFulRepository repository, DateTime startMockTime, int hours, int count) { var rand = new Random(); var list = new List(); if (hours < 25) { var startTicks = startMockTime.Ticks; var endMockTime = startMockTime.AddHours(hours); var allSecs = (int)((endMockTime.Ticks - startTicks) / 10000000); for (var i = 0; i < count; i++) { // 给定天内随机,如果在1~6点,则添加16个小时再模拟 var randSecs = rand.Next(allSecs); var curTime = new DateTime(startTicks + randSecs * 10000000L); if (curTime.Hour > 1 && curTime.Hour < 6) { if (rand.Next(100) < 95) { curTime = curTime.AddHours(16); } } list.Add(curTime); } return list; } else { // 按天来随机 var days = Math.Ceiling(hours / 24f); if (days > 15) days = 15; var pro = ConfigFromDb.RandomProbabilities[(int)days - 2]; var totalProp = pro.Sum(); // 计算一天的人数数量 var dayCountDic = new Dictionary(); for (var idx = 0; idx < count; idx++) { var rnum = rand.Next(totalProp + 1); var tmp = 0; var curDay = 1; for (var i = 0; i < pro.Count; i++) { if (i == pro.Count - 1 || (rnum >= tmp && rnum <= tmp + pro[i])) { curDay = i + 1; break; }; tmp += pro[i]; } if (dayCountDic.ContainsKey(curDay)) dayCountDic[curDay] = dayCountDic[curDay] + 1; else dayCountDic[curDay] = 1; } var index = 0; foreach (var key in dayCountDic.Keys) { var start = startMockTime.AddDays(key - 1); var end = startMockTime.AddDays(key); var allSecs = (int)((end.Ticks - start.Ticks) / 10000000); for (var idx = 0; idx < dayCountDic[key]; idx++) { // 给定天内随机,如果在1~6点,则添加16个小时再模拟 var randSecs = rand.Next(allSecs); var curTime = new DateTime(start.Ticks + randSecs * 10000000L); if (curTime.Hour > 1 && curTime.Hour < 6) { if (rand.Next(100) < 95) { curTime = curTime.AddHours(16); } } list.Add(curTime); index++; } } return list; } } /// /// 获取随机用户模拟信息 /// /// 如果不传,则从数据库查手机号大于90000000000的用户 /// public async static Task> GenerateMockActions(this DbRESTFulRepository repository, DateTime startMockTime, int hours, long targetId, string action, int expectCount, List modelList = null) { if (modelList == null) { modelList = (await GetMockUserIdsRandom(repository, expectCount, 0)) .Select(e => new MockActionGenerationModel { mockUserId = e }).ToList(); } var rand = new Random(); if (hours < 25) { var startTicks = startMockTime.Ticks; var endMockTime = startMockTime.AddHours(hours); var allSecs = (int)((endMockTime.Ticks - startTicks) / 10000000); foreach (var item in modelList) { item.targetId = targetId; item.action = action; // 给定天内随机,如果在1~6点,则添加16个小时再模拟 var randSecs = rand.Next(allSecs); var curTime = new DateTime(startTicks + randSecs * 10000000L); if (curTime.Hour > 1 && curTime.Hour < 6) { if (rand.Next(100) < 95) { curTime = curTime.AddHours(16); } } item.execTime = curTime; } return modelList; } else { // 按天来随机 var days = Math.Ceiling(hours / 24f); if (days > 15) days = 15; var pro = ConfigFromDb.RandomProbabilities[(int)days - 2]; var totalProp = pro.Sum(); // 计算一天的人数数量 var dayCountDic = new Dictionary(); for (var idx = 0; idx < modelList.Count; idx++) { var rnum = rand.Next(totalProp + 1); var tmp = 0; var curDay = 1; for (var i = 0; i < pro.Count; i++) { if (i == pro.Count - 1 || (rnum >= tmp && rnum <= tmp + pro[i])) { curDay = i + 1; break; }; tmp += pro[i]; } if (dayCountDic.ContainsKey(curDay)) dayCountDic[curDay] = dayCountDic[curDay] + 1; else dayCountDic[curDay] = 1; } var index = 0; foreach(var key in dayCountDic.Keys) { var start = startMockTime.AddDays(key - 1); var end = startMockTime.AddDays(key); var allSecs = (int)((end.Ticks - start.Ticks) / 10000000); for (var idx = 0; idx < dayCountDic[key]; idx++) { var item = modelList[index]; item.targetId = targetId; item.action = action; // 给定天内随机,如果在1~6点,则添加16个小时再模拟 var randSecs = rand.Next(allSecs); var curTime = new DateTime(start.Ticks + randSecs * 10000000L); if (curTime.Hour > 1 && curTime.Hour < 6) { if (rand.Next(100) < 95) { curTime = curTime.AddHours(16); } } item.execTime = curTime; index++; } } return modelList; } } /// /// 给文章添加点赞数量任务 /// public static async Task AddMockPostThumbsup(this DbRESTFulRepository repository, DateTime startMockTime, int hours, long postId, int expectCount, IDbConnection conn = null) { var postInfo = await repository.QuerySingleOrDefaultAsync($"select id, state, userId, checkCntLevel from n_post where id={postId}", null, conn); if (postInfo == null || postInfo.state != 1 || "D".Equals(postInfo.checkCntLevel)) return; var list = await repository.GenerateMockActions(startMockTime, hours, postId, "POST_THUMBSUP", expectCount); if (list.Count > 0) { var time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); var size = 500; for (var i = 0; i < list.Count; i += size) { var leftCount = list.Count - i; var subList = list.Skip(i).Take(leftCount >= size ? size : leftCount).ToList(); if (subList.Count > 0) { await repository.QueryAsync($"insert ignore into n_mock_action_records (targetId, action, content, mockUserId, execTime, createTime) values (@targetId, @action, @content, @mockUserId, @execTime, '{time}')", subList, conn, null, false); } } await repository.QueryAsync("update n_post set mockThumbsupCnt=mockThumbsupCnt+" + list.Count + " where id=" + postId, null, conn, null, false); } } /// /// 给文章添加收藏数量任务 /// public static async Task AddMockPostCollection(this DbRESTFulRepository repository, DateTime startMockTime, int hours, long postId, int expectCount, IDbConnection conn = null) { var postInfo = await repository.QuerySingleOrDefaultAsync($"select id, state, userId, checkCntLevel from n_post where id={postId}", null, conn); if (postInfo == null || postInfo.state != 1 || "D".Equals(postInfo.checkCntLevel)) return; var list = await repository.GenerateMockActions(startMockTime, hours, postId, "POST_COLLECTION", expectCount); if (list.Count > 0) { var time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); var size = 500; for (var i = 0; i < list.Count; i += size) { var leftCount = list.Count - i; var subList = list.Skip(i).Take(leftCount >= size ? size : leftCount).ToList(); if (subList.Count > 0) { await repository.QueryAsync($"insert ignore into n_mock_action_records (targetId, action, content, mockUserId, execTime, createTime) values (@targetId, @action, @content, @mockUserId, @execTime, '{time}')", subList, conn, null, false); } } await repository.QueryAsync("update n_post set mockCollectionCnt=mockCollectionCnt+" + list.Count + " where id=" + postId, null, conn, null, false); } } /// /// 给文章添加分享数量任务 /// public static async Task AddMockPostShare(this DbRESTFulRepository repository, DateTime startMockTime, int hours, long postId, int expectCount, IDbConnection conn = null) { var postInfo = await repository.QuerySingleOrDefaultAsync($"select id, state, userId, checkCntLevel from n_post where id={postId}", null, conn); if (postInfo == null || postInfo.state != 1 || "D".Equals(postInfo.checkCntLevel)) return; var list = await repository.GenerateMockActions(startMockTime, hours, postId, "POST_SHARE", expectCount); if (list.Count > 0) { var time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); var size = 500; for (var i = 0; i < list.Count; i += size) { var leftCount = list.Count - i; var subList = list.Skip(i).Take(leftCount >= size ? size : leftCount).ToList(); if (subList.Count > 0) { await repository.QueryAsync($"insert ignore into n_mock_action_records (targetId, action, content, mockUserId, execTime, createTime) values (@targetId, @action, @content, @mockUserId, @execTime, '{time}')", subList, conn, null, false); } } await repository.QueryAsync("update n_post set mockShareCnt=mockShareCnt+" + list.Count + " where id=" + postId, null, conn, null, false); } } /// /// 按文章添加作者主页访问数量任务 /// public static async Task AddMockPostPPVisit(this DbRESTFulRepository repository, DateTime startMockTime, int hours, long postId, int expectCount, IDbConnection conn = null) { var postInfo = await repository.QuerySingleOrDefaultAsync($"select id, state, userId, checkCntLevel from n_post where id={postId}", null, conn); if (postInfo == null || postInfo.state != 1 || "D".Equals(postInfo.checkCntLevel)) return; var list = await repository.GenerateMockActions(startMockTime, hours, postId, "POST_PPVISIT", expectCount); if (list.Count > 0) { var time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); var size = 500; for (var i = 0; i < list.Count; i += size) { var leftCount = list.Count - i; var subList = list.Skip(i).Take(leftCount >= size ? size : leftCount).ToList(); if (subList.Count > 0) { await repository.QueryAsync($"insert ignore into n_mock_action_records (targetId, action, content, mockUserId, execTime, createTime) values (@targetId, @action, @content, @mockUserId, @execTime, '{time}')", subList, conn, null, false); } } } } /// /// 按用户添加主页访问数量任务 /// public static async Task AddMockUserPPVisit(this DbRESTFulRepository repository, DateTime startMockTime, int hours, long userId, int expectCount, IDbConnection conn = null) { var userInfo = await repository.QuerySingleOrDefaultAsync($"select id, state from n_user where id={userId}", null, conn); if (userInfo == null || userInfo.state != 0) return; var list = await repository.GenerateMockActions(startMockTime, hours, userId, "USER_PPVISIT", expectCount); if (list.Count > 0) { var time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); var size = 500; for (var i = 0; i < list.Count; i += size) { var leftCount = list.Count - i; var subList = list.Skip(i).Take(leftCount >= size ? size : leftCount).ToList(); if (subList.Count > 0) { await repository.QueryAsync($"insert ignore into n_mock_action_records (targetId, action, content, mockUserId, execTime, createTime) values (@targetId, @action, @content, @mockUserId, @execTime, '{time}')", subList, conn, null, false); } } } } /// /// 【已废弃】给文章添加评论数量任务 /// public static async Task AddMockPostComment(this DbRESTFulRepository repository, DateTime startMockTime, int hours, long postId, int expectCount) { await Task.CompletedTask; // var records = await repository.GenerateMockActions(DateTime.Now, hours, postId, "COMMENT", expectCount); // if (records.Count == 0) return; // // 获取模拟评论 // var primaryType = await repository.QuerySingleOrDefaultAsync($"select primaryType from n_post where id={postId}"); // if (primaryType == 0) return; // var contList = (await repository.QueryAsync($"select `comment`, rand() as rid from n_mock_comment_cnt where primaryType={primaryType} order by rid asc limit " + expectCount)).ToList(); // if (contList.Count == 0) return; // if (contList.Count < records.Count) // { // records = records.Take(contList.Count).ToList(); // } // for (var i = 0; i < contList.Count; i++) // { // records[i].content = contList[i]; // } // var time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); // await repository.QueryAsync($"insert ignore into n_mock_action_records (targetId, action, content, mockUserId, execTime, createTime) values (@targetId, @action, @content, @mockUserId, @execTime, '{time}')", records, null, null, false); } /// /// 给某用户添加模拟关注任务 /// public static async Task AddMockFocusUser(this DbRESTFulRepository repository, DateTime startMockTime, int hours, long userId, int expectCount, IDbConnection conn = null) { var list = (await repository.QueryAsync("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(); if (list.Count < expectCount) { var count = expectCount - list.Count; var moreList = (await repository.QueryAsync("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(); list.AddRange(moreList); list.Shuffle(); } list = await GenerateMockActions(repository, startMockTime, hours, userId, "USER_FOCUS", expectCount, list); if (list.Count > 0) { var time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); var size = 500; for (var i = 0; i < list.Count; i += size) { var leftCount = list.Count - i; var subList = list.Skip(i).Take(leftCount >= size ? size : leftCount).ToList(); if (subList.Count > 0) { await repository.QueryAsync($"insert ignore into n_mock_action_records (targetId, action, content, mockUserId, execTime, createTime) values (@targetId, @action, @content, @mockUserId, @execTime, '{time}')", subList, conn, null, false); } } await repository.QueryAsync($"update n_user set mockFocusCnt=mockFocusCnt+@count where id=@userId", new { count = list.Count, userId }, conn, null, false); } } /// /// 给某文章添加模拟阅读任务 /// public static async Task AddMockPostRead(this DbRESTFulRepository repository, DateTime startMockTime, int hours, long postId, int count, IDbConnection conn = null) { var postInfo = await repository.QuerySingleOrDefaultAsync($"select id, state, userId, checkCntLevel from n_post where id={postId}", null, conn); if (postInfo == null || postInfo.state != 1 || "D".Equals(postInfo.checkCntLevel)) return; var records = GenerateMockTimes(repository, startMockTime, hours, count).Select(e => new { readAt = e.ToString("yyyy-MM-dd HH:mm:ss") }).ToList(); // 一次处理500条记录 var size = 500; for (var i = 0; i < records.Count; i += size) { var leftCount = records.Count - i; var subList = records.Skip(i).Take(leftCount >= size ? size : leftCount).ToList(); if (subList.Count > 0) { await repository.QueryAsync($"insert into n_mock_read_action_records(postId, readAt) values ({postId}, @readAt)", subList, conn); } } } /// /// 获取模拟用户 /// /// 期望获取最多多少个 /// public static async Task> GetMockUserIdsRandom(this DbRESTFulRepository repository, int expectCount, int minPostCount = 0) { if (minPostCount > 0) { var userIds = (await repository.QueryAsync("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(); if (userIds.Count < expectCount) { var count = expectCount - userIds.Count; var moreUserIds = (await repository.QueryAsync("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(); userIds.AddRange(moreUserIds); userIds.Shuffle(); } return userIds; } else { var userIds = (await repository.QueryAsync("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(); if (userIds.Count < expectCount) { var count = expectCount - userIds.Count; var moreUserIds = (await repository.QueryAsync("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(); userIds.AddRange(moreUserIds); userIds.Shuffle(); } return userIds; } } /// /// 获取数据库配置的模拟发文章的用户 /// public static async Task> GetMockUserIdsRandomByCategoryType(this DbRESTFulRepository repository, int expectCount, int categoryType) { return (await repository.QueryAsync($"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(); } } }