MonitorServicesBus.cs 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Text.Json;
  5. using System.Threading.Tasks;
  6. using Azure.Cosmos;
  7. using Azure.Messaging.ServiceBus;
  8. using Microsoft.Azure.WebJobs;
  9. using Microsoft.Azure.WebJobs.Host;
  10. using Microsoft.Extensions.Logging;
  11. using StackExchange.Redis;
  12. using TEAMModelOS.SDK.DI;
  13. using TEAMModelOS.SDK.Extension;
  14. using TEAMModelOS.SDK;
  15. using TEAMModelOS.SDK.Models;
  16. using TEAMModelOS.SDK.Models.Cosmos;
  17. using TEAMModelOS.SDK.Models.Cosmos.Common;
  18. using TEAMModelOS.Services.Common;
  19. using System.Linq;
  20. using TEAMModelOS.SDK.Models.Service;
  21. using TEAMModelOS.SDK.Models.Cosmos.BI;
  22. using TEAMModelOS.Models;
  23. using Microsoft.Extensions.Options;
  24. using Microsoft.Extensions.Configuration;
  25. using HTEXLib.COMM.Helpers;
  26. namespace TEAMModelFunction
  27. {
  28. public class MonitorServicesBus
  29. {
  30. private readonly AzureCosmosFactory _azureCosmos;
  31. private readonly DingDing _dingDing;
  32. private readonly AzureStorageFactory _azureStorage;
  33. private readonly AzureRedisFactory _azureRedis;
  34. private readonly AzureServiceBusFactory _serviceBus;
  35. private readonly Option _option;
  36. private readonly NotificationService _notificationService;
  37. private readonly IConfiguration _configuration;
  38. public MonitorServicesBus(AzureCosmosFactory azureCosmos, DingDing dingDing, AzureStorageFactory azureStorage, AzureRedisFactory azureRedis, AzureServiceBusFactory serviceBus, IOptionsSnapshot<Option> option, NotificationService notificationService, IConfiguration configuration)
  39. {
  40. _azureCosmos = azureCosmos;
  41. _dingDing = dingDing;
  42. _azureStorage = azureStorage;
  43. _azureRedis = azureRedis;
  44. _serviceBus = serviceBus;
  45. _option = option?.Value;
  46. _notificationService = notificationService;
  47. _configuration = configuration;
  48. }
  49. [FunctionName("Exam")]
  50. public async Task Exam([ServiceBusTrigger("%Azure:ServiceBus:ActiveTask%", "exam", Connection = "Azure:ServiceBus:ConnectionString")] string msg)
  51. {
  52. try
  53. {
  54. var json = JsonDocument.Parse(msg);
  55. json.RootElement.TryGetProperty("id", out JsonElement id);
  56. json.RootElement.TryGetProperty("progress", out JsonElement progress);
  57. json.RootElement.TryGetProperty("code", out JsonElement code);
  58. //Dictionary<string, object> keyValuePairs = mySbMsg.ToObject<Dictionary<string, object>>();
  59. var client = _azureCosmos.GetCosmosClient();
  60. ExamInfo exam = await client.GetContainer(Constant.TEAMModelOS, "Common").ReadItemAsync<ExamInfo>(id.ToString(), new PartitionKey($"{code}"));
  61. exam.progress = progress.ToString();
  62. await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(exam, id.ToString(), new PartitionKey($"{code}"));
  63. }
  64. catch (CosmosException)
  65. {
  66. }
  67. catch (Exception ex)
  68. {
  69. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,ExamBus()\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.醍摩豆服務運維群組);
  70. }
  71. }
  72. [FunctionName("Vote")]
  73. public async Task Vote([ServiceBusTrigger("%Azure:ServiceBus:ActiveTask%", "vote", Connection = "Azure:ServiceBus:ConnectionString")] string msg)
  74. {
  75. try
  76. {
  77. var jsonMsg = JsonDocument.Parse(msg);
  78. jsonMsg.RootElement.TryGetProperty("id", out JsonElement id);
  79. jsonMsg.RootElement.TryGetProperty("progress", out JsonElement progress);
  80. jsonMsg.RootElement.TryGetProperty("code", out JsonElement code);
  81. var client = _azureCosmos.GetCosmosClient();
  82. Vote vote = await client.GetContainer(Constant.TEAMModelOS, "Common").ReadItemAsync<Vote>(id.ToString(), new PartitionKey($"{code}"));
  83. vote.progress = progress.ToString();
  84. await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(vote, id.ToString(), new PartitionKey($"{code}"));
  85. }
  86. catch (CosmosException)
  87. {
  88. }
  89. catch (Exception ex)
  90. {
  91. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,VoteBus()\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.醍摩豆服務運維群組);
  92. }
  93. }
  94. [FunctionName("Correct")]
  95. public async Task Correct([ServiceBusTrigger("%Azure:ServiceBus:ActiveTask%", "correct", Connection = "Azure:ServiceBus:ConnectionString")] string msg)
  96. {
  97. try
  98. {
  99. var jsonMsg = JsonDocument.Parse(msg);
  100. jsonMsg.RootElement.TryGetProperty("id", out JsonElement id);
  101. jsonMsg.RootElement.TryGetProperty("progress", out JsonElement progress);
  102. jsonMsg.RootElement.TryGetProperty("code", out JsonElement code);
  103. var client = _azureCosmos.GetCosmosClient();
  104. Correct correct = await client.GetContainer(Constant.TEAMModelOS, "Common").ReadItemAsync<Correct>(id.ToString(), new PartitionKey($"{code}"));
  105. correct.progress = progress.ToString();
  106. await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(correct, id.ToString(), new PartitionKey($"{code}"));
  107. }
  108. catch (CosmosException)
  109. {
  110. }
  111. catch (Exception ex)
  112. {
  113. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,Correct()\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.醍摩豆服務運維群組);
  114. }
  115. }
  116. [FunctionName("Survey")]
  117. public async Task Survey([ServiceBusTrigger("%Azure:ServiceBus:ActiveTask%", "survey", Connection = "Azure:ServiceBus:ConnectionString")] string msg)
  118. {
  119. try
  120. {
  121. var jsonMsg = JsonDocument.Parse(msg);
  122. jsonMsg.RootElement.TryGetProperty("id", out JsonElement id);
  123. jsonMsg.RootElement.TryGetProperty("progress", out JsonElement progress);
  124. jsonMsg.RootElement.TryGetProperty("code", out JsonElement code);
  125. //Dictionary<string, object> keyValuePairs = mySbMsg.ToObject<Dictionary<string, object>>();
  126. var client = _azureCosmos.GetCosmosClient();
  127. Survey survey = await client.GetContainer(Constant.TEAMModelOS, "Common").ReadItemAsync<Survey>(id.ToString(), new PartitionKey($"{code}"));
  128. survey.progress = progress.ToString();
  129. await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(survey, id.ToString(), new PartitionKey($"{code}"));
  130. }
  131. catch (CosmosException)
  132. {
  133. }
  134. catch (Exception ex)
  135. {
  136. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,SurveyBus()\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.醍摩豆服務運維群組);
  137. }
  138. }
  139. [FunctionName("Homework")]
  140. public async Task Homework([ServiceBusTrigger("%Azure:ServiceBus:ActiveTask%", "homework", Connection = "Azure:ServiceBus:ConnectionString")] string msg)
  141. {
  142. try
  143. {
  144. var jsonMsg = JsonDocument.Parse(msg);
  145. jsonMsg.RootElement.TryGetProperty("id", out JsonElement id);
  146. jsonMsg.RootElement.TryGetProperty("progress", out JsonElement progress);
  147. jsonMsg.RootElement.TryGetProperty("code", out JsonElement code);
  148. var client = _azureCosmos.GetCosmosClient();
  149. Homework homework = await client.GetContainer(Constant.TEAMModelOS, "Common").ReadItemAsync<Homework>(id.ToString(), new PartitionKey($"{code}"));
  150. homework.progress = progress.ToString();
  151. await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(homework, id.ToString(), new PartitionKey($"{code}"));
  152. }
  153. catch (CosmosException ) {
  154. }
  155. catch (Exception ex)
  156. {
  157. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,Homework()\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.醍摩豆服務運維群組);
  158. }
  159. }
  160. [FunctionName("Study")]
  161. public async Task Study([ServiceBusTrigger("%Azure:ServiceBus:ActiveTask%", "study", Connection = "Azure:ServiceBus:ConnectionString")] string msg)
  162. {
  163. try
  164. {
  165. var jsonMsg = JsonDocument.Parse(msg);
  166. jsonMsg.RootElement.TryGetProperty("id", out JsonElement id);
  167. jsonMsg.RootElement.TryGetProperty("progress", out JsonElement progress);
  168. jsonMsg.RootElement.TryGetProperty("code", out JsonElement code);
  169. var client = _azureCosmos.GetCosmosClient();
  170. Study study = await client.GetContainer(Constant.TEAMModelOS, "Common").ReadItemAsync<Study>(id.ToString(), new PartitionKey($"{code}"));
  171. study.progress = progress.ToString();
  172. await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(study, id.ToString(), new PartitionKey($"{code}"));
  173. }
  174. catch (CosmosException)
  175. {
  176. }
  177. catch (Exception ex)
  178. {
  179. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,Study()\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.醍摩豆服務運維群組);
  180. }
  181. }
  182. [FunctionName("ExamLite")]
  183. public async Task ExamLite([ServiceBusTrigger("%Azure:ServiceBus:ActiveTask%", "examlite", Connection = "Azure:ServiceBus:ConnectionString")] string msg)
  184. {
  185. try
  186. {
  187. var jsonMsg = JsonDocument.Parse(msg);
  188. jsonMsg.RootElement.TryGetProperty("id", out JsonElement id);
  189. jsonMsg.RootElement.TryGetProperty("progress", out JsonElement progress);
  190. jsonMsg.RootElement.TryGetProperty("code", out JsonElement code);
  191. var client = _azureCosmos.GetCosmosClient();
  192. ExamLite lite = await client.GetContainer(Constant.TEAMModelOS, "Common").ReadItemAsync<ExamLite>(id.ToString(), new PartitionKey($"{code}"));
  193. lite.progress = progress.ToString();
  194. await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(lite, id.ToString(), new PartitionKey($"{code}"));
  195. }
  196. catch (CosmosException)
  197. {
  198. }
  199. catch (Exception ex)
  200. {
  201. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,ExamLite()\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.醍摩豆服務運維群組);
  202. }
  203. }
  204. [FunctionName("Blob")]
  205. public async Task Blob([ServiceBusTrigger("%Azure:ServiceBus:ActiveTask%", "blob", Connection = "Azure:ServiceBus:ConnectionString")] string msg) {
  206. try
  207. {
  208. //11 await _dingDing.SendBotMsg($"ServiceBus,Blob(){msg}", GroupNames.醍摩豆服務運維群組);
  209. var jsonMsg = JsonDocument.Parse(msg);
  210. if(jsonMsg.RootElement.TryGetProperty("name", out JsonElement name)&& name.ValueKind==JsonValueKind.String)
  211. {
  212. var client = _azureStorage.GetBlobContainerClient($"{name}");
  213. var size = await client.GetBlobsCatalogSize();
  214. await _azureRedis.GetRedisClient(8).HashSetAsync($"Blob:Record", new RedisValue($"{name}"), new RedisValue($"{long.Parse($"{size.Item1}")}"));
  215. foreach (var key in size.Item2.Keys)
  216. {
  217. await _azureRedis.GetRedisClient(8).SortedSetRemoveAsync($"Blob:Catalog:{name}", key);
  218. await _azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"Blob:Catalog:{name}", key, size.Item2[key].HasValue ? size.Item2[key].Value : 0);
  219. }
  220. //await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,Blob() 容器:{name}使用:{size.Item1},文件分类:{size.Item2.ToJsonString()}",
  221. // GroupNames.成都开发測試群組);
  222. }
  223. }
  224. catch (Exception ex)
  225. {
  226. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,Blob()\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.醍摩豆服務運維群組);
  227. }
  228. }
  229. /// <summary>
  230. /// 根据容器的根目录刷新redis并获取redis的最新使用情况
  231. /// </summary>
  232. /// <param name="msg"></param>
  233. /// <returns></returns>
  234. [FunctionName("BlobRoot")]
  235. public async Task BlobRoot([ServiceBusTrigger("%Azure:ServiceBus:ActiveTask%", "blobroot", Connection = "Azure:ServiceBus:ConnectionString")] string msg)
  236. {
  237. try
  238. {
  239. var jsonMsg = JsonDocument.Parse(msg);
  240. if (jsonMsg.RootElement.TryGetProperty("name", out JsonElement _name) && _name.ValueKind == JsonValueKind.String
  241. && jsonMsg.RootElement.TryGetProperty("root", out JsonElement root) && root.ValueKind == JsonValueKind.String)
  242. {
  243. //await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,Blob() 容器:触发变更,{jsonMsg.ToJsonString()}",
  244. // GroupNames.成都开发測試群組);
  245. List<Dictionary<string, double?>> list = new List<Dictionary<string, double?>>();
  246. string[] uls = System.Web.HttpUtility.UrlDecode($"{root}", Encoding.UTF8).Split("/");
  247. string u = !string.IsNullOrEmpty(uls[0]) ? uls[0] : uls[1];
  248. string name = $"{_name}";
  249. string lockKey = $"Blob:Lock:{name}:{u}";
  250. bool exist= await _azureRedis.GetRedisClient(8).KeyExistsAsync(lockKey);
  251. if (!exist)
  252. { ///key不存在则正常进行计算
  253. bool condition = false;
  254. TimeSpan timeSpan = new TimeSpan(DateTimeOffset.UtcNow.AddMinutes(5).Ticks);
  255. timeSpan = timeSpan - new TimeSpan(DateTimeOffset.UtcNow.Ticks);
  256. //准备处理Blob刷新时间
  257. long action = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
  258. await _azureRedis.GetRedisClient(8).StringSetAsync(lockKey, action, expiry: timeSpan);
  259. await RefreshBlob(name, u);
  260. //将action 与Redis最新的时间进行比较,如果
  261. var rds = await CheckLockKey(lockKey, action);
  262. condition = rds.condition;
  263. exist = rds.exist;
  264. if (condition || !exist) {
  265. await RefreshBlob(name, u);
  266. }
  267. //使用 CancellationToken
  268. //while (condition || !exist)
  269. //{
  270. //}
  271. }
  272. else {
  273. ///key存在则,则刷新key对应的值
  274. TimeSpan timeSpan = new TimeSpan(DateTimeOffset.UtcNow.AddMinutes(5).Ticks);
  275. timeSpan = timeSpan - new TimeSpan(DateTimeOffset.UtcNow.Ticks);
  276. long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
  277. await _azureRedis.GetRedisClient(8).StringSetAsync(lockKey, now, expiry: timeSpan);
  278. }
  279. //await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,Blob() 容器:{name}使用:{u},文件分类:{list.ToJsonString()}",
  280. // GroupNames.成都开发測試群組);
  281. }
  282. }
  283. catch (Exception ex)
  284. {
  285. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,Blob()\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.醍摩豆服務運維群組);
  286. }
  287. }
  288. private async Task<(bool condition,bool exist)> CheckLockKey(string lockKey,long nowTime) {
  289. //Redis的最新时间
  290. long newestTime = 0;
  291. RedisValue value = await _azureRedis.GetRedisClient(8).StringGetAsync(lockKey);
  292. if (value != default && !value.IsNullOrEmpty)
  293. {
  294. JsonElement record = value.ToString().ToObject<JsonElement>();
  295. if (record.TryGetInt64(out newestTime))
  296. {
  297. }
  298. }
  299. //说明key已经不存在
  300. if (newestTime == 0)
  301. {
  302. return (false, true);
  303. }
  304. //说明key存在
  305. else {
  306. //说明Redis记录了最新的时间戳
  307. if (nowTime != newestTime)
  308. {
  309. return (true, false);
  310. }
  311. //时间相同,没有被再次记录最新的时间戳
  312. else
  313. {
  314. await _azureRedis.GetRedisClient(8).KeyDeleteAsync(lockKey);
  315. return (false, true);
  316. }
  317. }
  318. }
  319. private async Task RefreshBlob(string name ,string u) {
  320. long statr = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
  321. var client = _azureStorage.GetBlobContainerClient(name);
  322. var size = await client.GetBlobsSize(u);
  323. await _azureRedis.GetRedisClient(8).SortedSetRemoveAsync($"Blob:Catalog:{name}", u);
  324. await _azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"Blob:Catalog:{name}", u, size.HasValue ? size.Value : 0);
  325. var scores = await _azureRedis.GetRedisClient(8).SortedSetRangeByRankWithScoresAsync($"Blob:Catalog:{name}");
  326. double blobsize = 0;
  327. if (scores != default && scores != null)
  328. {
  329. foreach (var score in scores)
  330. {
  331. blobsize = blobsize + score.Score;
  332. }
  333. }
  334. await _azureRedis.GetRedisClient(8).HashSetAsync($"Blob:Record", new RedisValue(name), new RedisValue($"{blobsize}"));
  335. long end = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
  336. long dis = (end - statr)/1000;
  337. long timeout = 10;
  338. if (dis> timeout) {
  339. await _dingDing.SendBotMsg($"ServiceBus,RefreshBlob:空间计算已经超过{timeout}秒\n容器名:{name}\n文件夹:{u}\n计算时长:{dis}", GroupNames.醍摩豆服務運維群組);
  340. }
  341. }
  342. /// <summary>
  343. /// 完善课程变更,StuListChange, originCode是学校编码 则表示名单是学校自定义名单,如果是tmdid则表示醍摩豆的私有名单,scope=school,private。
  344. /// </summary>
  345. /// <data msg>
  346. /// CourseChange
  347. ///// </data>
  348. /// <param name="msg"></param>
  349. /// <returns></returns>
  350. [FunctionName("TeacherTrainChange")]
  351. public async Task TeacherTrainChange([ServiceBusTrigger("%Azure:ServiceBus:ActiveTask%", "teacher-train-change", Connection = "Azure:ServiceBus:ConnectionString")] string msg) {
  352. try {
  353. await _dingDing.SendBotMsg($"{msg}", GroupNames.成都开发測試群組);
  354. TeacherTrainChange change = msg.ToObject<TeacherTrainChange>();
  355. if (change.update == null || change.update.Count <= 0 || change.tmdids.IsEmpty())
  356. {
  357. return;
  358. }
  359. var client = _azureCosmos.GetCosmosClient();
  360. string insql = $"where c.id in ({string.Join(",", change.tmdids.Select(x => $"'{x}'"))})";
  361. string selsql = $"select value(c) from c {insql} ";
  362. List<TeacherTrain> teacherTrains = new List<TeacherTrain>();
  363. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<TeacherTrain>(queryText: selsql,
  364. requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"TeacherTrain-{change.school}") }))
  365. {
  366. teacherTrains.Add(item);
  367. }
  368. if (change.statistics != 1)
  369. {
  370. List<Task<ItemResponse<TeacherTrain>>> task = new List<Task<ItemResponse<TeacherTrain>>>();
  371. teacherTrains.ForEach(x => {
  372. x.update.UnionWith(change.update);
  373. task.Add(client.GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync<TeacherTrain>(x, x.id, new PartitionKey($"TeacherTrain-{change.school}")));
  374. });
  375. await task.TaskPage(5);
  376. var unchange = change.tmdids.Except(teacherTrains.Select(x => x.id));
  377. if (unchange != null)
  378. {
  379. task.Clear();
  380. unchange.ToList().ForEach(x => {
  381. TeacherTrain teacherTrain = new TeacherTrain
  382. {
  383. pk = "TeacherTrain",
  384. id = x,
  385. code = $"TeacherTrain-{change.school}",
  386. tmdid = x,
  387. school = change.school,
  388. update = new HashSet<string> { StatisticsService.TeacherAility,
  389. StatisticsService.TeacherClass, StatisticsService.OfflineRecord }
  390. };
  391. teacherTrain.update.UnionWith(change.update);
  392. task.Add(client.GetContainer(Constant.TEAMModelOS, "Teacher").UpsertItemAsync<TeacherTrain>(teacherTrain, new PartitionKey($"TeacherTrain-{change.school}")));
  393. });
  394. await task.TaskPage(1);
  395. }
  396. }
  397. else
  398. {
  399. Area area = null;
  400. string sql = $"select value(c) from c where c.standard='{change.standard}'";
  401. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Normal").GetItemQueryIterator<Area>(queryText: sql,
  402. requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base-Area") }))
  403. {
  404. area = item;
  405. }
  406. AreaSetting setting = null;
  407. if (area != null)
  408. {
  409. try
  410. {
  411. //优先找校级
  412. setting = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<AreaSetting>(change.school, new PartitionKey("AreaSetting"));
  413. }
  414. catch (CosmosException)
  415. {
  416. try
  417. {
  418. setting = await client.GetContainer(Constant.TEAMModelOS, "Normal").ReadItemAsync<AreaSetting>(area.id, new PartitionKey("AreaSetting"));
  419. }
  420. catch (CosmosException)
  421. {
  422. setting = null;
  423. }
  424. }
  425. }
  426. if (setting == null)
  427. {
  428. setting = new AreaSetting
  429. {
  430. allTime = 50,
  431. classTime = 5,
  432. submitTime = 15,
  433. onlineTime = 20,
  434. offlineTime = 10,
  435. lessonMinutes = 45,
  436. };
  437. }
  438. List<Task<TeacherTrain>> task = new List<Task<TeacherTrain>>();
  439. teacherTrains.ForEach(x => {
  440. x.update.UnionWith(change.update);
  441. task.Add(StatisticsService.StatisticsTeacher(x, setting, area, client, null));
  442. });
  443. await task.TaskPage(1);
  444. var unchange = change.tmdids.Except(teacherTrains.Select(x => x.id));
  445. if (unchange != null)
  446. {
  447. task.Clear();
  448. unchange.ToList().ForEach(x => {
  449. task.Add(StatisticsService.StatisticsTeacher(new TeacherTrain
  450. {
  451. pk = "TeacherTrain",
  452. id = x,
  453. code = $"TeacherTrain-{change.school}",
  454. tmdid = x,
  455. school = change.school,
  456. update = new HashSet<string> { StatisticsService.TeacherAility,
  457. StatisticsService.TeacherClass, StatisticsService.OfflineRecord }
  458. }, setting, area, client, null));
  459. });
  460. await task.TaskPage(1);
  461. }
  462. }
  463. } catch (Exception ex) {
  464. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-研修数据变更,重新统计-TeacherTrainChange\n{msg}\n{ex.Message}\n{ex.StackTrace}", GroupNames.成都开发測試群組);
  465. }
  466. }
  467. /// <summary>
  468. /// 完善课程变更,StuListChange, originCode是学校编码 则表示名单是学校自定义名单,如果是tmdid则表示醍摩豆的私有名单,scope=school,private。
  469. /// </summary>
  470. /// <data msg>
  471. /// CourseChange
  472. ///// </data>
  473. /// <param name="msg"></param>
  474. /// <returns></returns>
  475. [FunctionName("GroupChange")]
  476. public async Task GroupChange([ServiceBusTrigger("%Azure:ServiceBus:ActiveTask%", "group-change", Connection = "Azure:ServiceBus:ConnectionString")] string msg)
  477. {
  478. var client = _azureCosmos.GetCosmosClient();
  479. try
  480. {
  481. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-名单成员变更-GroupChange\n{msg}", GroupNames.成都开发測試群組);
  482. var jsonMsg = JsonDocument.Parse(msg);
  483. GroupChange groupChange = msg.ToObject<GroupChange>();
  484. //名单变动修改学生课程关联信息
  485. //await StuListService.FixStuCourse(client, stuListChange);
  486. //Vote投票 Survey问卷 Exam评测 Learn学习活动 Homework作业活动
  487. //名单变动修改学生问卷关联信息
  488. await ActivityService.FixActivity(client, _dingDing, groupChange, "Survey");
  489. //名单变动修改学生投票关联信息
  490. await ActivityService.FixActivity(client, _dingDing, groupChange, "Vote");
  491. //名单变动修改学生评测关联信息
  492. await ActivityService.FixActivity(client, _dingDing, groupChange, "Exam");
  493. //名单变动修改学生研修关联信息
  494. await ActivityService.FixActivity(client, _dingDing, groupChange, "Study");
  495. //名单变动修改学生简易评测关联信息
  496. await ActivityService.FixActivity(client, _dingDing, groupChange, "ExamLite");
  497. //TODO学习活动
  498. //await FixActivity(client, stuListChange, "Learn");
  499. //名单变动修改学生作业活动信息
  500. await ActivityService.FixActivity(client, _dingDing, groupChange, "Homework");
  501. if (groupChange.type == null || !groupChange.type.Equals("research") || !groupChange.type.Equals("yxtrain")|| !groupChange.type.Equals("activity"))
  502. {
  503. //课程名单变动修改学生课程关联信息
  504. await ActivityService.FixStuCourse(client, _dingDing, groupChange);
  505. }
  506. }
  507. catch (Exception ex)
  508. {
  509. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-GroupChange-GroupChange\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.成都开发測試群組);
  510. }
  511. }
  512. [FunctionName("ItemCond")]
  513. public async Task ItemCond([ServiceBusTrigger("%Azure:ServiceBus:ItemCondQueue%", Connection = "Azure:ServiceBus:ConnectionString")] string msg)
  514. {
  515. try
  516. {
  517. var client = _azureCosmos.GetCosmosClient();
  518. var jsonMsg = JsonDocument.Parse(msg);
  519. List<ItemCondDto> itemCondDtos = msg.ToObject<List<ItemCondDto>>();
  520. foreach (var itemCondDto in itemCondDtos)
  521. {
  522. if (itemCondDto.scope.Equals("school")) {
  523. ItemCond itemCond = null;
  524. List<ItemInfo> items = new List<ItemInfo>();
  525. var queryslt = $"SELECT c.gradeIds,c.subjectId,c.periodId,c.type,c.level,c.field ,c.scope FROM c where c.periodId='{itemCondDto.filed}' and c.pid= null ";
  526. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<ItemInfo>(queryText: queryslt, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Item-{itemCondDto.key}") }))
  527. {
  528. items.Add(item);
  529. }
  530. itemCond = new ItemCond()
  531. {
  532. id = $"{itemCondDto.filed}",
  533. code = $"ItemCond-{itemCondDto.key}",
  534. pk = "ItemCond",
  535. ttl = -1,
  536. count = items.Count,
  537. grades = new List<GradeCount>(),
  538. subjects = new List<SubjectCount>()
  539. };
  540. items.ForEach(z =>
  541. {
  542. ItemService.CountItemCond(z, null, itemCond);
  543. });
  544. await _azureRedis.GetRedisClient(8).HashSetAsync($"ItemCond:{itemCondDto.key}", $"{itemCondDto.filed}", itemCond.ToJsonString());
  545. }
  546. else
  547. {
  548. ItemCond itemCond = null;
  549. List<ItemInfo> items = new List<ItemInfo>();
  550. var queryslt = $"SELECT c.gradeIds,c.subjectId,c.periodId,c.type,c.level,c.field ,c.scope FROM c where c.pid= null ";
  551. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<ItemInfo>(queryText: queryslt, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Item-{itemCondDto.filed}") }))
  552. {
  553. items.Add(item);
  554. }
  555. itemCond = new ItemCond() { id = $"{itemCondDto.filed}", code = $"ItemCond", pk = "ItemCond", ttl = -1, count = items.Count };
  556. items.ForEach(z =>
  557. {
  558. ItemService.CountItemCond(z, null, itemCond);
  559. });
  560. await _azureRedis.GetRedisClient(8).HashSetAsync($"ItemCond:ItemCond", $"{itemCondDto.filed}", itemCond.ToJsonString());
  561. }
  562. }
  563. }
  564. catch (CosmosException ex )
  565. {
  566. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,ItemCond()\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.醍摩豆服務運維群組);
  567. }
  568. catch (Exception ex)
  569. {
  570. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,ItemCond()\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.醍摩豆服務運維群組);
  571. }
  572. }
  573. //更新產品一覽表
  574. [FunctionName("Product")]
  575. public async Task Product([ServiceBusTrigger("%Azure:ServiceBus:ActiveTask%", "product", Connection = "Azure:ServiceBus:ConnectionString")] string msg, ILogger log)
  576. {
  577. try
  578. {
  579. var jsonMsg = JsonDocument.Parse(msg);
  580. jsonMsg.RootElement.TryGetProperty("method", out JsonElement method);
  581. jsonMsg.RootElement.TryGetProperty("schoolId", out JsonElement schoolId);
  582. jsonMsg.RootElement.TryGetProperty("prodCode", out JsonElement prodCode);
  583. jsonMsg.RootElement.TryGetProperty("prodId", out JsonElement prodId);
  584. var client = _azureCosmos.GetCosmosClient();
  585. string strQuery = string.Empty;
  586. //取得所有學校產品
  587. ////序號
  588. List<SchoolProductSumData> serialsProductSumOrg = new List<SchoolProductSumData>();
  589. strQuery = $"SELECT * FROM c WHERE c.dataType = 'serial'";
  590. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIterator(queryText: strQuery, requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"Product-{schoolId}") }))
  591. {
  592. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  593. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  594. {
  595. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  596. {
  597. SchoolProductSerial serialInfo = obj.ToObject<SchoolProductSerial>();
  598. SchoolProductSumData serialProd = serialsProductSumOrg.Where(sp => sp.prodCode == serialInfo.prodCode).FirstOrDefault();
  599. if(serialProd == null)
  600. {
  601. SchoolProductSumData serialProdAdd = new SchoolProductSumData();
  602. serialProdAdd.prodCode = serialInfo.prodCode;
  603. serialProdAdd.ids.Add(serialInfo.id);
  604. serialProdAdd.avaliable = serialProdAdd.ids.Count;
  605. serialsProductSumOrg.Add(serialProdAdd);
  606. }
  607. else
  608. {
  609. if(!serialProd.ids.Contains(serialInfo.id))
  610. {
  611. serialProd.ids.Add(serialInfo.id);
  612. }
  613. serialProd.avaliable = serialProd.ids.Count;
  614. }
  615. }
  616. }
  617. }
  618. ////服務
  619. List<SchoolProductSumData> servicesProductSumOrg = new List<SchoolProductSumData>();
  620. long timestampToday = DateTimeOffset.UtcNow.AddSeconds(1).ToUnixTimeSeconds(); //比現實時間延遲1秒
  621. strQuery = $"SELECT * FROM c WHERE c.dataType = 'service' AND c.startDate <= {timestampToday} AND {timestampToday} <= c.endDate AND c.ttl < 0"; //在授權期間、ttl < 0 才取
  622. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIterator(queryText: strQuery, requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"Product-{schoolId}") }))
  623. {
  624. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  625. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  626. {
  627. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  628. {
  629. SchoolProductService serviceInfo = obj.ToObject<SchoolProductService>();
  630. SchoolProductSumData serviceProd = servicesProductSumOrg.Where(sp => sp.prodCode == serviceInfo.prodCode).FirstOrDefault();
  631. if (serviceProd == null)
  632. {
  633. SchoolProductSumData serviceProdAdd = new SchoolProductSumData();
  634. serviceProdAdd.prodCode = serviceInfo.prodCode;
  635. serviceProdAdd.avaliable = 0;
  636. serviceProdAdd.ids.Add(serviceInfo.id);
  637. serviceProdAdd.avaliable += serviceInfo.number;
  638. servicesProductSumOrg.Add(serviceProdAdd);
  639. }
  640. else
  641. {
  642. if (!serviceProd.ids.Contains(serviceInfo.id))
  643. {
  644. serviceProd.ids.Add(serviceInfo.id);
  645. serviceProd.avaliable += serviceInfo.number;
  646. }
  647. }
  648. }
  649. }
  650. }
  651. ////服務產品特別對應項
  652. if (servicesProductSumOrg.Count > 0)
  653. {
  654. foreach (SchoolProductSumData servicesProductSumOrgRow in servicesProductSumOrg)
  655. {
  656. //更新學校空間
  657. if (servicesProductSumOrgRow.prodCode.Equals("IPALJ6NY"))
  658. {
  659. School school = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>($"{schoolId}", new PartitionKey("Base"));
  660. school.size = (servicesProductSumOrgRow.avaliable < 1) ? 1 : servicesProductSumOrgRow.avaliable;
  661. await client.GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync<School>(school, $"{schoolId}", new PartitionKey("Base"));
  662. }
  663. }
  664. }
  665. ////硬體
  666. List<SchoolProductSumDataHard> hardsProductSumOrg = new List<SchoolProductSumDataHard>();
  667. strQuery = $"SELECT * FROM c WHERE c.dataType = 'hard'";
  668. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIterator(queryText: strQuery, requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"Product-{schoolId}") }))
  669. {
  670. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  671. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  672. {
  673. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  674. {
  675. SchoolProductHard hardInfo = obj.ToObject<SchoolProductHard>();
  676. SchoolProductSumData hardProd = hardsProductSumOrg.Where(sp => sp.prodCode == hardInfo.prodCode).FirstOrDefault();
  677. if (hardProd == null)
  678. {
  679. SchoolProductSumDataHard hardProdAdd = new SchoolProductSumDataHard();
  680. hardProdAdd.prodCode = hardInfo.prodCode;
  681. hardProdAdd.model = hardInfo.model;
  682. hardProdAdd.ids.Add(hardInfo.id);
  683. hardProdAdd.avaliable = hardProdAdd.ids.Count;
  684. hardsProductSumOrg.Add(hardProdAdd);
  685. }
  686. else
  687. {
  688. if (!hardProd.ids.Contains(hardInfo.id))
  689. {
  690. hardProd.ids.Add(hardInfo.id);
  691. }
  692. hardProd.avaliable = hardProd.ids.Count;
  693. }
  694. }
  695. }
  696. }
  697. //更新學校產品一覽表
  698. SchoolProductSum prodSum = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<SchoolProductSum>(schoolId.ToString(), new PartitionKey($"ProductSum"));
  699. prodSum.serial = serialsProductSumOrg;
  700. prodSum.service = servicesProductSumOrg;
  701. prodSum.hard = hardsProductSumOrg;
  702. await client.GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync<SchoolProductSum>(prodSum, prodSum.id, new PartitionKey($"{prodSum.code}"));
  703. }
  704. catch (CosmosException ex)
  705. {
  706. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,Product()\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.醍摩豆服務運維群組);
  707. }
  708. catch (Exception ex)
  709. {
  710. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,Product()\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.醍摩豆服務運維群組);
  711. }
  712. }
  713. /// <summary>
  714. /// 批量复制文件
  715. /// </summary>
  716. /// <param name="msg"></param>
  717. /// <returns></returns>
  718. [FunctionName("CopyStandardFile")]
  719. public async Task BatchCopyBlob([ServiceBusTrigger("%Azure:ServiceBus:ActiveTask%", "copy-standard-file", Connection = "Azure:ServiceBus:ConnectionString")] string msg)
  720. {
  721. try
  722. {
  723. //await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-Blob复制文件-CopyStandardFile\n{msg}", GroupNames.成都开发測試群組);
  724. var jsonMsg = JsonDocument.Parse(msg);
  725. BatchCopyFile bIBatchCopyFile = msg.ToObject<BatchCopyFile>();
  726. //批量复制文件
  727. var result = await BatchCopyFileService.CopyFile(_dingDing, _azureStorage, bIBatchCopyFile);
  728. if (result == 200)
  729. {
  730. //发送消息实体
  731. Notification notification = new Notification
  732. {
  733. hubName = "hita",
  734. type = "msg",
  735. from = $"ies5:{_option.Location}:private",
  736. to = bIBatchCopyFile.tmdIds,
  737. label = $"{bIBatchCopyFile.codeKey}_finish",
  738. body = new { location = _option.Location, biz = $"{bIBatchCopyFile.codeKey}", tmdid = $"{bIBatchCopyFile.tmdid}", tmdname = $"{bIBatchCopyFile.tmdName}", status = 1, time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() }.ToJsonString(),
  739. expires = DateTimeOffset.UtcNow.AddDays(7).ToUnixTimeSeconds()
  740. };
  741. var url = _configuration.GetValue<string>("HaBookAuth:CoreService:sendnotification");
  742. var clientID = _configuration.GetValue<string>("HaBookAuth:CoreService:clientID");
  743. var clientSecret = _configuration.GetValue<string>("HaBookAuth:CoreService:clientSecret");
  744. var location = _option.Location;
  745. await _notificationService.SendNotification(clientID, clientSecret, location, url, notification); //站内发送消息
  746. }
  747. }
  748. catch (Exception ex)
  749. {
  750. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-Blob复制文件-CopyStandardFile\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.醍摩豆服務運維群組);
  751. }
  752. }
  753. }
  754. }