MonitorServicesBus.cs 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787
  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. TeacherTrainChange change = msg.ToObject<TeacherTrainChange>();
  354. if (change.update == null || change.update.Count <= 0 || change.tmdids.IsEmpty())
  355. {
  356. return;
  357. }
  358. var client = _azureCosmos.GetCosmosClient();
  359. string insql = $"where c.id in ({string.Join(",", change.tmdids.Select(x => "'{x}'"))})";
  360. string selsql = $"select value(c) from c {insql} ";
  361. List<TeacherTrain> teacherTrains = new List<TeacherTrain>();
  362. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<TeacherTrain>(queryText: selsql,
  363. requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"TeacherTrain-{change.school}") }))
  364. {
  365. teacherTrains.Add(item);
  366. }
  367. if (change.statistics != 1)
  368. {
  369. List<Task<ItemResponse<TeacherTrain>>> task = new List<Task<ItemResponse<TeacherTrain>>>();
  370. teacherTrains.ForEach(x => {
  371. x.update.UnionWith(change.update);
  372. task.Add(client.GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync<TeacherTrain>(x, x.id, new PartitionKey($"TeacherTrain-{change.school}")));
  373. });
  374. await task.TaskPage(5);
  375. var unchange = change.tmdids.Except(teacherTrains.Select(x => x.id));
  376. if (unchange != null)
  377. {
  378. task.Clear();
  379. unchange.ToList().ForEach(x => {
  380. TeacherTrain teacherTrain = new TeacherTrain
  381. {
  382. pk = "TeacherTrain",
  383. id = x,
  384. code = $"TeacherTrain-{change.school}",
  385. tmdid = x,
  386. school = change.school,
  387. update = new HashSet<string> { StatisticsService.TeacherAility,
  388. StatisticsService.TeacherClass, StatisticsService.OfflineRecord }
  389. };
  390. teacherTrain.update.UnionWith(change.update);
  391. task.Add(client.GetContainer(Constant.TEAMModelOS, "Teacher").CreateItemAsync<TeacherTrain>(teacherTrain, new PartitionKey($"TeacherTrain-{change.school}")));
  392. });
  393. await task.TaskPage(5);
  394. }
  395. }
  396. else
  397. {
  398. Area area = null;
  399. string sql = $"select value(c) from c where c.standard='{change.standard}'";
  400. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Normal").GetItemQueryIterator<Area>(queryText: sql,
  401. requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Base-Area") }))
  402. {
  403. area = item;
  404. }
  405. AreaSetting setting = null;
  406. if (area != null)
  407. {
  408. try
  409. {
  410. //优先找校级
  411. setting = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<AreaSetting>(change.school, new PartitionKey("AreaSetting"));
  412. }
  413. catch (CosmosException)
  414. {
  415. try
  416. {
  417. setting = await client.GetContainer(Constant.TEAMModelOS, "Normal").ReadItemAsync<AreaSetting>(area.id, new PartitionKey("AreaSetting"));
  418. }
  419. catch (CosmosException)
  420. {
  421. setting = null;
  422. }
  423. }
  424. }
  425. if (setting == null)
  426. {
  427. setting = new AreaSetting
  428. {
  429. allTime = 50,
  430. classTime = 5,
  431. submitTime = 15,
  432. onlineTime = 20,
  433. offlineTime = 10,
  434. lessonMinutes = 45,
  435. };
  436. }
  437. List<Task<TeacherTrain>> task = new List<Task<TeacherTrain>>();
  438. teacherTrains.ForEach(x => {
  439. x.update.UnionWith(change.update);
  440. task.Add(StatisticsService.StatisticsTeacher(x, setting, area, client, null));
  441. });
  442. await task.TaskPage(1);
  443. var unchange = change.tmdids.Except(teacherTrains.Select(x => x.id));
  444. if (unchange != null)
  445. {
  446. task.Clear();
  447. unchange.ToList().ForEach(x => {
  448. task.Add(StatisticsService.StatisticsTeacher(new TeacherTrain
  449. {
  450. pk = "TeacherTrain",
  451. id = x,
  452. code = $"TeacherTrain-{change.school}",
  453. tmdid = x,
  454. school = change.school,
  455. update = new HashSet<string> { StatisticsService.TeacherAility,
  456. StatisticsService.TeacherClass, StatisticsService.OfflineRecord }
  457. }, setting, area, client, null));
  458. });
  459. await task.TaskPage(1);
  460. }
  461. }
  462. } catch (Exception ex) {
  463. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-研修数据变更,重新统计-TeacherTrainChange\n{msg}", GroupNames.成都开发測試群組);
  464. }
  465. }
  466. /// <summary>
  467. /// 完善课程变更,StuListChange, originCode是学校编码 则表示名单是学校自定义名单,如果是tmdid则表示醍摩豆的私有名单,scope=school,private。
  468. /// </summary>
  469. /// <data msg>
  470. /// CourseChange
  471. ///// </data>
  472. /// <param name="msg"></param>
  473. /// <returns></returns>
  474. [FunctionName("GroupChange")]
  475. public async Task GroupChange([ServiceBusTrigger("%Azure:ServiceBus:ActiveTask%", "group-change", Connection = "Azure:ServiceBus:ConnectionString")] string msg)
  476. {
  477. var client = _azureCosmos.GetCosmosClient();
  478. try
  479. {
  480. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-名单成员变更-GroupChange\n{msg}", GroupNames.成都开发測試群組);
  481. var jsonMsg = JsonDocument.Parse(msg);
  482. GroupChange groupChange = msg.ToObject<GroupChange>();
  483. //名单变动修改学生课程关联信息
  484. //await StuListService.FixStuCourse(client, stuListChange);
  485. //Vote投票 Survey问卷 Exam评测 Learn学习活动 Homework作业活动
  486. //名单变动修改学生问卷关联信息
  487. await ActivityService.FixActivity(client, _dingDing, groupChange, "Survey");
  488. //名单变动修改学生投票关联信息
  489. await ActivityService.FixActivity(client, _dingDing, groupChange, "Vote");
  490. //名单变动修改学生评测关联信息
  491. await ActivityService.FixActivity(client, _dingDing, groupChange, "Exam");
  492. //名单变动修改学生研修关联信息
  493. await ActivityService.FixActivity(client, _dingDing, groupChange, "Study");
  494. //名单变动修改学生简易评测关联信息
  495. await ActivityService.FixActivity(client, _dingDing, groupChange, "ExamLite");
  496. //TODO学习活动
  497. //await FixActivity(client, stuListChange, "Learn");
  498. //名单变动修改学生作业活动信息
  499. await ActivityService.FixActivity(client, _dingDing, groupChange, "Homework");
  500. if (groupChange.type == null || !groupChange.type.Equals("research") || !groupChange.type.Equals("yxtrain")|| !groupChange.type.Equals("activity"))
  501. {
  502. //课程名单变动修改学生课程关联信息
  503. await ActivityService.FixStuCourse(client, _dingDing, groupChange);
  504. }
  505. }
  506. catch (Exception ex)
  507. {
  508. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-GroupChange-GroupChange\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.成都开发測試群組);
  509. }
  510. }
  511. [FunctionName("ItemCond")]
  512. public async Task ItemCond([ServiceBusTrigger("%Azure:ServiceBus:ItemCondQueue%", Connection = "Azure:ServiceBus:ConnectionString")] string msg)
  513. {
  514. try
  515. {
  516. var client = _azureCosmos.GetCosmosClient();
  517. var jsonMsg = JsonDocument.Parse(msg);
  518. List<ItemCondDto> itemCondDtos = msg.ToObject<List<ItemCondDto>>();
  519. foreach (var itemCondDto in itemCondDtos)
  520. {
  521. if (itemCondDto.scope.Equals("school")) {
  522. ItemCond itemCond = null;
  523. List<ItemInfo> items = new List<ItemInfo>();
  524. 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 ";
  525. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryIterator<ItemInfo>(queryText: queryslt, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Item-{itemCondDto.key}") }))
  526. {
  527. items.Add(item);
  528. }
  529. itemCond = new ItemCond()
  530. {
  531. id = $"{itemCondDto.filed}",
  532. code = $"ItemCond-{itemCondDto.key}",
  533. pk = "ItemCond",
  534. ttl = -1,
  535. count = items.Count,
  536. grades = new List<GradeCount>(),
  537. subjects = new List<SubjectCount>()
  538. };
  539. items.ForEach(z =>
  540. {
  541. ItemService.CountItemCond(z, null, itemCond);
  542. });
  543. await _azureRedis.GetRedisClient(8).HashSetAsync($"ItemCond:{itemCondDto.key}", $"{itemCondDto.filed}", itemCond.ToJsonString());
  544. }
  545. else
  546. {
  547. ItemCond itemCond = null;
  548. List<ItemInfo> items = new List<ItemInfo>();
  549. var queryslt = $"SELECT c.gradeIds,c.subjectId,c.periodId,c.type,c.level,c.field ,c.scope FROM c where c.pid= null ";
  550. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "Teacher").GetItemQueryIterator<ItemInfo>(queryText: queryslt, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Item-{itemCondDto.filed}") }))
  551. {
  552. items.Add(item);
  553. }
  554. itemCond = new ItemCond() { id = $"{itemCondDto.filed}", code = $"ItemCond", pk = "ItemCond", ttl = -1, count = items.Count };
  555. items.ForEach(z =>
  556. {
  557. ItemService.CountItemCond(z, null, itemCond);
  558. });
  559. await _azureRedis.GetRedisClient(8).HashSetAsync($"ItemCond:ItemCond", $"{itemCondDto.filed}", itemCond.ToJsonString());
  560. }
  561. }
  562. }
  563. catch (CosmosException ex )
  564. {
  565. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,ItemCond()\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.醍摩豆服務運維群組);
  566. }
  567. catch (Exception ex)
  568. {
  569. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,ItemCond()\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.醍摩豆服務運維群組);
  570. }
  571. }
  572. //更新產品一覽表
  573. [FunctionName("Product")]
  574. public async Task Product([ServiceBusTrigger("%Azure:ServiceBus:ActiveTask%", "product", Connection = "Azure:ServiceBus:ConnectionString")] string msg, ILogger log)
  575. {
  576. try
  577. {
  578. var jsonMsg = JsonDocument.Parse(msg);
  579. jsonMsg.RootElement.TryGetProperty("method", out JsonElement method);
  580. jsonMsg.RootElement.TryGetProperty("schoolId", out JsonElement schoolId);
  581. jsonMsg.RootElement.TryGetProperty("prodCode", out JsonElement prodCode);
  582. jsonMsg.RootElement.TryGetProperty("prodId", out JsonElement prodId);
  583. var client = _azureCosmos.GetCosmosClient();
  584. string strQuery = string.Empty;
  585. //取得所有學校產品
  586. ////序號
  587. List<SchoolProductSumData> serialsProductSumOrg = new List<SchoolProductSumData>();
  588. strQuery = $"SELECT * FROM c WHERE c.dataType = 'serial'";
  589. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIterator(queryText: strQuery, requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"Product-{schoolId}") }))
  590. {
  591. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  592. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  593. {
  594. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  595. {
  596. SchoolProductSerial serialInfo = obj.ToObject<SchoolProductSerial>();
  597. SchoolProductSumData serialProd = serialsProductSumOrg.Where(sp => sp.prodCode == serialInfo.prodCode).FirstOrDefault();
  598. if(serialProd == null)
  599. {
  600. SchoolProductSumData serialProdAdd = new SchoolProductSumData();
  601. serialProdAdd.prodCode = serialInfo.prodCode;
  602. serialProdAdd.ids.Add(serialInfo.id);
  603. serialProdAdd.avaliable = serialProdAdd.ids.Count;
  604. serialsProductSumOrg.Add(serialProdAdd);
  605. }
  606. else
  607. {
  608. if(!serialProd.ids.Contains(serialInfo.id))
  609. {
  610. serialProd.ids.Add(serialInfo.id);
  611. }
  612. serialProd.avaliable = serialProd.ids.Count;
  613. }
  614. }
  615. }
  616. }
  617. ////服務
  618. List<SchoolProductSumData> servicesProductSumOrg = new List<SchoolProductSumData>();
  619. long timestampToday = DateTimeOffset.UtcNow.AddSeconds(1).ToUnixTimeSeconds(); //比現實時間延遲1秒
  620. strQuery = $"SELECT * FROM c WHERE c.dataType = 'service' AND c.startDate <= {timestampToday} AND {timestampToday} <= c.endDate AND c.ttl < 0"; //在授權期間、ttl < 0 才取
  621. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIterator(queryText: strQuery, requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"Product-{schoolId}") }))
  622. {
  623. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  624. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  625. {
  626. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  627. {
  628. SchoolProductService serviceInfo = obj.ToObject<SchoolProductService>();
  629. SchoolProductSumData serviceProd = servicesProductSumOrg.Where(sp => sp.prodCode == serviceInfo.prodCode).FirstOrDefault();
  630. if (serviceProd == null)
  631. {
  632. SchoolProductSumData serviceProdAdd = new SchoolProductSumData();
  633. serviceProdAdd.prodCode = serviceInfo.prodCode;
  634. serviceProdAdd.avaliable = 0;
  635. serviceProdAdd.ids.Add(serviceInfo.id);
  636. serviceProdAdd.avaliable += serviceInfo.number;
  637. servicesProductSumOrg.Add(serviceProdAdd);
  638. }
  639. else
  640. {
  641. if (!serviceProd.ids.Contains(serviceInfo.id))
  642. {
  643. serviceProd.ids.Add(serviceInfo.id);
  644. serviceProd.avaliable += serviceInfo.number;
  645. }
  646. }
  647. }
  648. }
  649. }
  650. ////服務產品特別對應項
  651. if (servicesProductSumOrg.Count > 0)
  652. {
  653. foreach (SchoolProductSumData servicesProductSumOrgRow in servicesProductSumOrg)
  654. {
  655. //更新學校空間
  656. if (servicesProductSumOrgRow.prodCode.Equals("IPALJ6NY"))
  657. {
  658. School school = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>($"{schoolId}", new PartitionKey("Base"));
  659. school.size = (servicesProductSumOrgRow.avaliable < 1) ? 1 : servicesProductSumOrgRow.avaliable;
  660. await client.GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync<School>(school, $"{schoolId}", new PartitionKey("Base"));
  661. }
  662. }
  663. }
  664. ////硬體
  665. List<SchoolProductSumDataHard> hardsProductSumOrg = new List<SchoolProductSumDataHard>();
  666. strQuery = $"SELECT * FROM c WHERE c.dataType = 'hard'";
  667. await foreach (var item in client.GetContainer(Constant.TEAMModelOS, "School").GetItemQueryStreamIterator(queryText: strQuery, requestOptions: new QueryRequestOptions() { PartitionKey = new Azure.Cosmos.PartitionKey($"Product-{schoolId}") }))
  668. {
  669. using var json = await JsonDocument.ParseAsync(item.ContentStream);
  670. if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
  671. {
  672. foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
  673. {
  674. SchoolProductHard hardInfo = obj.ToObject<SchoolProductHard>();
  675. SchoolProductSumData hardProd = hardsProductSumOrg.Where(sp => sp.prodCode == hardInfo.prodCode).FirstOrDefault();
  676. if (hardProd == null)
  677. {
  678. SchoolProductSumDataHard hardProdAdd = new SchoolProductSumDataHard();
  679. hardProdAdd.prodCode = hardInfo.prodCode;
  680. hardProdAdd.model = hardInfo.model;
  681. hardProdAdd.ids.Add(hardInfo.id);
  682. hardProdAdd.avaliable = hardProdAdd.ids.Count;
  683. hardsProductSumOrg.Add(hardProdAdd);
  684. }
  685. else
  686. {
  687. if (!hardProd.ids.Contains(hardInfo.id))
  688. {
  689. hardProd.ids.Add(hardInfo.id);
  690. }
  691. hardProd.avaliable = hardProd.ids.Count;
  692. }
  693. }
  694. }
  695. }
  696. //更新學校產品一覽表
  697. SchoolProductSum prodSum = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<SchoolProductSum>(schoolId.ToString(), new PartitionKey($"ProductSum"));
  698. prodSum.serial = serialsProductSumOrg;
  699. prodSum.service = servicesProductSumOrg;
  700. prodSum.hard = hardsProductSumOrg;
  701. await client.GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync<SchoolProductSum>(prodSum, prodSum.id, new PartitionKey($"{prodSum.code}"));
  702. }
  703. catch (CosmosException ex)
  704. {
  705. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,Product()\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.醍摩豆服務運維群組);
  706. }
  707. catch (Exception ex)
  708. {
  709. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-ServiceBus,Product()\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.醍摩豆服務運維群組);
  710. }
  711. }
  712. /// <summary>
  713. /// 批量复制文件
  714. /// </summary>
  715. /// <param name="msg"></param>
  716. /// <returns></returns>
  717. [FunctionName("CopyStandardFile")]
  718. public async Task BatchCopyBlob([ServiceBusTrigger("%Azure:ServiceBus:ActiveTask%", "copy-standard-file", Connection = "Azure:ServiceBus:ConnectionString")] string msg)
  719. {
  720. try
  721. {
  722. //await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-Blob复制文件-CopyStandardFile\n{msg}", GroupNames.成都开发測試群組);
  723. var jsonMsg = JsonDocument.Parse(msg);
  724. BatchCopyFile bIBatchCopyFile = msg.ToObject<BatchCopyFile>();
  725. //批量复制文件
  726. var result = await BatchCopyFileService.CopyFile(_dingDing, _azureStorage, bIBatchCopyFile);
  727. if (result == 200)
  728. {
  729. //发送消息实体
  730. Notification notification = new Notification
  731. {
  732. hubName = "hita",
  733. type = "msg",
  734. from = $"ies5:{_option.Location}:private",
  735. to = bIBatchCopyFile.tmdIds,
  736. label = $"{bIBatchCopyFile.codeKey}_finish",
  737. body = new { location = _option.Location, biz = $"{bIBatchCopyFile.codeKey}", tmdid = $"{bIBatchCopyFile.tmdid}", tmdname = $"{bIBatchCopyFile.tmdName}", status = 1, time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() }.ToJsonString(),
  738. expires = DateTimeOffset.UtcNow.AddDays(7).ToUnixTimeSeconds()
  739. };
  740. var url = _configuration.GetValue<string>("HaBookAuth:CoreService:sendnotification");
  741. var clientID = _configuration.GetValue<string>("HaBookAuth:CoreService:clientID");
  742. var clientSecret = _configuration.GetValue<string>("HaBookAuth:CoreService:clientSecret");
  743. var location = _option.Location;
  744. await _notificationService.SendNotification(clientID, clientSecret, location, url, notification); //站内发送消息
  745. }
  746. }
  747. catch (Exception ex)
  748. {
  749. await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-Blob复制文件-CopyStandardFile\n{ex.Message}\n{ex.StackTrace}\n{msg}", GroupNames.醍摩豆服務運維群組);
  750. }
  751. }
  752. }
  753. }