BlobController.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. using Microsoft.AspNetCore.Mvc;
  2. using Microsoft.Extensions.Configuration;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Text;
  6. using System.Text.Json;
  7. using System.Threading.Tasks;
  8. using TEAMModelOS.SDK.Context.Configuration;
  9. using TEAMModelOS.SDK;
  10. using TEAMModelOS.SDK.Helper.Common.JsonHelper;
  11. using TEAMModelOS.SDK.Module.AzureBlob.Configuration;
  12. using TEAMModelOS.SDK.DI;
  13. using System.Net.Http;
  14. using TEAMModelOS.SDK.Helper.Security.ShaHash;
  15. using TEAMModelOS.SDK.Extension;
  16. using System.IdentityModel.Tokens.Jwt;
  17. using Microsoft.AspNetCore.Authorization;
  18. using TEAMModelOS.Filter;
  19. using StackExchange.Redis;
  20. using Azure.Messaging.ServiceBus;
  21. using static TEAMModelOS.SDK.DI.AzureStorageBlobExtensions;
  22. using System.Linq;
  23. namespace TEAMModelOS.Controllers.Core
  24. {
  25. [Route("blob")]
  26. [ApiController]
  27. public class BlobController : ControllerBase
  28. {
  29. private readonly AzureStorageFactory _azureStorage;
  30. private readonly IHttpClientFactory _clientFactory;
  31. private readonly AzureRedisFactory _azureRedis;
  32. private readonly AzureServiceBusFactory _serviceBus;
  33. public BlobController(AzureStorageFactory azureStorage, AzureServiceBusFactory serviceBus, IHttpClientFactory clientFactory, AzureRedisFactory azureRedis)
  34. {
  35. _azureStorage = azureStorage;
  36. _clientFactory = clientFactory;
  37. _serviceBus = serviceBus;
  38. _azureRedis = azureRedis;
  39. }
  40. /// <summary>
  41. /// 获取某个容器的只读权限
  42. /// </summary>
  43. /// <param name="request"></param>
  44. /// <returns></returns>
  45. [HttpPost("sas-r")]
  46. public IActionResult BlobSasR(BlobSas request)
  47. {
  48. ///返回金钥过期时间
  49. // Dictionary<string, object> dict = await azureBlobDBRepository.GetBlobSasUri(request.@params,true);
  50. // dict.Add(d.Key, d.Value);
  51. return Ok(_azureStorage.GetContainerSasUri(request, true));
  52. }
  53. /// <summary>
  54. /// 某个文件的上传SAS rcw权限
  55. /// </summary>
  56. /// <param name="request"></param>
  57. /// <returns></returns>
  58. [HttpPost("sas-rcwld")]
  59. public IActionResult BlobSasRCW(BlobSas request)
  60. {
  61. ///返回金钥过期时间
  62. // Dictionary<string,object> dict= await azureBlobDBRepository.GetBlobSasUri(request.@params,false);
  63. // Dictionary<string, object> dict = ;
  64. //dict.Add(d.Key, d.Value);
  65. return Ok(_azureStorage.GetContainerSasUri(request, false));
  66. }
  67. /// <summary>
  68. /// 删除prefix
  69. ///
  70. /// {"cntr":"","prefix":"res/test"}
  71. /// </summary>
  72. /// <param name="request"></param>
  73. /// <returns></returns>
  74. [HttpPost("delete-prefix")]
  75. [AuthToken(Roles = "teacher,admin")]
  76. public async Task<IActionResult> DeletePrefix(JsonElement json)
  77. {
  78. var (id,_,_,school) = HttpContext.GetAuthTokenInfo();
  79. string blobContainerName = null;
  80. string prefix = null;
  81. if (json.TryGetProperty("cntr", out JsonElement cntr)) {
  82. var cntrs= cntr.ToString();
  83. if (cntrs.Equals(id))
  84. {
  85. blobContainerName = id;
  86. }
  87. else if(cntrs.Equals(school))
  88. {
  89. blobContainerName = school;
  90. }
  91. else
  92. {
  93. return BadRequest("只能删除本人管理的文件夹");
  94. }
  95. }
  96. if (json.TryGetProperty("prefix", out JsonElement prefixjson))
  97. {
  98. prefix = prefixjson.ToString();
  99. }
  100. if (prefix != null && blobContainerName != null)
  101. {
  102. var status = await _azureStorage.GetBlobServiceClient().DelectBlobs(blobContainerName, prefix);
  103. return Ok(new { status });
  104. }
  105. else {
  106. return BadRequest();
  107. }
  108. }
  109. /// <summary>
  110. /// 删除多个Url
  111. ///
  112. /// {"cntr":"","urls":["res/test/1.json","res/test/2.json"]}
  113. /// </summary>
  114. /// <param name="request"></param>
  115. /// <returns></returns>
  116. [HttpPost("delete-blobs")]
  117. [AuthToken(Roles = "teacher,admin")]
  118. public async Task<IActionResult> DeleteBlobs(JsonElement json)
  119. {
  120. var (id, _, _, school) = HttpContext.GetAuthTokenInfo();
  121. string blobContainerName = null;
  122. List<Uri> uris = null;
  123. if (json.TryGetProperty("cntr", out JsonElement cntr))
  124. {
  125. var cntrs = cntr.ToString();
  126. if (cntrs.Equals(id))
  127. {
  128. blobContainerName = id;
  129. }
  130. else if (cntrs.Equals(school))
  131. {
  132. blobContainerName = school;
  133. }
  134. else {
  135. return BadRequest("只能删除本人管理的文件");
  136. }
  137. }
  138. bool flag = true;
  139. if (json.TryGetProperty("urls", out JsonElement urlsjson)) {
  140. uris= urlsjson.ToObject<List<Uri>>();
  141. uris.ForEach(x => {
  142. (string, string) a = BlobUrlString(x.ToString());
  143. string ContainerName = a.Item1;
  144. string BlobName = a.Item2;
  145. if (ContainerName!=blobContainerName) {
  146. flag = false;
  147. }
  148. });
  149. }
  150. if (flag)
  151. {
  152. if (blobContainerName != null && uris != null && uris.Count > 0)
  153. {
  154. var status = await _azureStorage.GetBlobServiceClient().DelectBlobs(blobContainerName, uris);
  155. return Ok(new { status });
  156. }
  157. else
  158. {
  159. return BadRequest();
  160. }
  161. }
  162. else {
  163. return BadRequest("只能删除本人管理的文件");
  164. }
  165. }
  166. /// <summary>
  167. /// 链接只读(读)
  168. /// </summary>
  169. /// <param name="azureBlobSASDto"></param>
  170. /// <returns></returns>
  171. [HttpPost("sas-url-r")]
  172. public IActionResult GetContainerSASRead(JsonElement azureBlobSASDto)
  173. {
  174. azureBlobSASDto.TryGetProperty("url", out JsonElement azureBlobSAS);
  175. //string azureBlobSAS = azureBlobSASDto;
  176. (string, string) a = BlobUrlString(azureBlobSAS.ToString());
  177. string ContainerName = a.Item1;
  178. string BlobName = a.Item2;
  179. bool flg = IsBlobName(BlobName);
  180. if (flg)
  181. {
  182. return Ok(_azureStorage.GetBlobSasUriRead(ContainerName, BlobName));
  183. }
  184. else
  185. {
  186. return BadRequest("文件名错误");
  187. };
  188. }
  189. /// <summary>
  190. /// 获取文件内容
  191. /// </summary>
  192. /// <param name="azureBlobSASDto"></param>
  193. /// <returns></returns>
  194. [HttpPost("get-text")]
  195. public async Task<IActionResult> GetText(JsonElement request)
  196. {
  197. request.TryGetProperty("code", out JsonElement code);
  198. string azureBlobSAS = System.Web.HttpUtility.UrlDecode(code.ToString(), Encoding.UTF8);
  199. (string, string) a = BlobUrlString(azureBlobSAS);
  200. string ContainerName = a.Item1;
  201. string BlobName = a.Item2;
  202. bool flg = IsBlobName(BlobName);
  203. if (flg)
  204. {
  205. //TODO 需驗證
  206. BlobAuth blobAuth= _azureStorage.GetBlobSasUriRead(ContainerName, BlobName);
  207. var response= await _clientFactory.CreateClient().GetAsync(new Uri(blobAuth.url + blobAuth.sas));
  208. response.EnsureSuccessStatusCode();
  209. using var json = await JsonDocument.ParseAsync(await response.Content.ReadAsStreamAsync());
  210. return Ok(json.RootElement);
  211. }
  212. else
  213. {
  214. return BadRequest("文件名错误");
  215. };
  216. }
  217. /// <summary>
  218. /// 测试单个文本内容的上传
  219. /// </summary>
  220. /// <param name="azureBlobSASDto"></param>
  221. /// <returns></returns>
  222. [HttpPost("get-blobsize")]
  223. public async Task<ActionResult> GetBlobsSize(JsonElement request)
  224. {
  225. request.TryGetProperty("containerName", out JsonElement containerName);
  226. request.TryGetProperty("cache", out JsonElement cache);
  227. var name =containerName.GetString();
  228. try {
  229. if (cache.GetBoolean())
  230. {
  231. long blobsize = 0;
  232. RedisValue value = default;
  233. value = _azureRedis.GetRedisClient(8).HashGet($"Blob:Record", name);
  234. if (value != default && !value.IsNullOrEmpty)
  235. {
  236. JsonElement record = value.ToString().ToObject<JsonElement>();
  237. if (record.TryGetInt64(out blobsize))
  238. {
  239. }
  240. }
  241. Dictionary<string, double> catalog = new Dictionary<string, double>();
  242. SortedSetEntry[] Scores = _azureRedis.GetRedisClient(8).SortedSetRangeByScoreWithScores($"Blob:Catalog:{name}");
  243. if (Scores != null )
  244. {
  245. foreach (var score in Scores) {
  246. double val = score.Score;
  247. string key = score.Element.ToString();
  248. catalog.Add(key, val);
  249. }
  250. }
  251. return Ok(new { size = blobsize, catalog= catalog });
  252. }
  253. } catch { }
  254. var client = _azureStorage.GetBlobContainerClient(name);
  255. var size = await client.GetBlobsCatalogSize();
  256. await _azureRedis.GetRedisClient(8).HashSetAsync($"Blob:Record", name, size.Item1);
  257. foreach (var key in size.Item2.Keys) {
  258. await _azureRedis.GetRedisClient(8).SortedSetRemoveAsync($"Blob:Catalog:{name}", key);
  259. await _azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"Blob:Catalog:{name}", key, size.Item2[key].HasValue?size.Item2[key].Value:0);
  260. }
  261. return Ok(new { size = size.Item1, catalog = size.Item2 });
  262. }
  263. /// <summary>
  264. /// 测试单个文本内容的上传
  265. /// {"containerName":"hbcn","urls":["video/xxx.mp4","res/xxx.png"]}
  266. /// </summary>
  267. /// <param name="azureBlobSASDto"></param>
  268. /// <returns></returns>
  269. [HttpPost("check-blobsize")]
  270. public async Task<ActionResult> checkBlobsSize(JsonElement request)
  271. {
  272. request.TryGetProperty("containerName", out JsonElement containerName);
  273. request.TryGetProperty("urls", out JsonElement optUrls);
  274. var name = containerName.GetString();
  275. var urls = optUrls.ToObject<List<string>>();
  276. var client = _azureStorage.GetBlobContainerClient(name);
  277. var urlsSize = await client.GetBlobsSize(urls);
  278. return Ok(new { urlsSize });
  279. }
  280. /*
  281. *
  282. {
  283. "containerName": "hbcn",
  284. "cache": true,
  285. "optUrls": [
  286. {
  287. "url": "video%2F37Z888piCvm9.mp4",
  288. "size": 1000
  289. }
  290. ]
  291. }
  292. */
  293. /// <summary>
  294. /// 测试单个文本内容的上传
  295. /// {"containerName":"hbcn","uploadSize":5000,"optUrls":[{"url":"video/37Z888piCvm9.mp4","size":0},{}]}
  296. /// </summary>
  297. /// <param name="azureBlobSASDto"></param>
  298. /// <returns></returns>
  299. [HttpPost("update-blobsize")]
  300. public async Task<ActionResult> updateBlobsSize(JsonElement request)
  301. {
  302. request.TryGetProperty("containerName", out JsonElement containerName);
  303. request.TryGetProperty("optUrls", out JsonElement optUrls);
  304. var name = containerName.GetString();
  305. var urls = optUrls.ToObject<List<OptUrl>>();
  306. var client = _azureStorage.GetBlobContainerClient(name);
  307. var disSize = urls.Select(x => x.size).Sum();
  308. RedisValue value = default;
  309. long blobSize = 0;
  310. value = _azureRedis.GetRedisClient(8).HashGet($"Blob:Record", name);
  311. if (value != default && !value.IsNullOrEmpty)
  312. {
  313. JsonElement record = value.ToString().ToObject<JsonElement>();
  314. if (record.TryGetInt64(out blobSize))
  315. {
  316. }
  317. }
  318. long? useSize = blobSize + disSize;
  319. await _azureRedis.GetRedisClient(8).HashSetAsync($"Blob:Record", name, useSize);
  320. foreach (var x in urls) {
  321. await _azureRedis.GetRedisClient(8).SortedSetIncrementAsync($"Blob:Catalog:{name}", System.Web.HttpUtility.UrlDecode(x.url, Encoding.UTF8).Split("/")[0], x.size);
  322. }
  323. var messageBlob = new ServiceBusMessage(new {id=Guid.NewGuid().ToString(), progress = "update",name=name}.ToJsonString());
  324. messageBlob.ApplicationProperties.Add("name", "Blob");
  325. await _serviceBus.GetServiceBusClient().SendMessageAsync("active-task", messageBlob);
  326. return Ok(new { size=useSize });
  327. }
  328. private static (string, string) BlobUrlString(string sasUrl)
  329. {
  330. sasUrl = sasUrl.Substring(8);
  331. string[] sasUrls = sasUrl.Split("/");
  332. string ContainerName;
  333. ContainerName = sasUrls[1].Clone().ToString();
  334. string item = sasUrls[0] + "/" + sasUrls[1] + "/";
  335. string blob = sasUrl.Replace(item, "");
  336. return (ContainerName, blob);
  337. }
  338. public static bool IsBlobName(string BlobName)
  339. {
  340. return System.Text.RegularExpressions.Regex.IsMatch(BlobName,
  341. @"(?!((^(con)$)|^(con)\\..*|(^(prn)$)|^(prn)\\..*|(^(aux)$)|^(aux)\\..*|(^(nul)$)|^(nul)\\..*|(^(com)[1-9]$)|^(com)[1-9]\\..*|(^(lpt)[1-9]$)|^(lpt)[1-9]\\..*)|^\\s+|.*\\s$)(^[^\\\\\\:\\<\\>\\*\\?\\\\\\""\\\\|]{1,255}$)");
  342. }
  343. }
  344. }