ResumableContext.cs 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. /*
  2. * Copyright (C) Alibaba Cloud Computing
  3. * All rights reserved.
  4. *
  5. * 版权所有 (C)阿里云计算有限公司
  6. */
  7. using System;
  8. using System.Collections.Generic;
  9. using System.IO;
  10. using System.Text;
  11. using System.Threading;
  12. namespace Aliyun.OSS
  13. {
  14. internal class ResumablePartContext
  15. {
  16. protected static readonly char TokenSeparator = '_';
  17. public int PartId { get; set; }
  18. public long Position { get; set; }
  19. public long Length { get; set; }
  20. public PartETag PartETag { get; set; }
  21. public bool IsCompleted { get; set; }
  22. public bool FromString(string value)
  23. {
  24. if (string.IsNullOrEmpty(value))
  25. {
  26. return false;
  27. }
  28. var tokens = value.Split(TokenSeparator);
  29. if (tokens.Length != 6)
  30. {
  31. return false;
  32. }
  33. int partId;
  34. if (!int.TryParse(tokens[0], out partId) || partId <= 0)
  35. {
  36. return false;
  37. }
  38. PartId = partId;
  39. long position;
  40. if (!long.TryParse(tokens[1], out position) || position < 0)
  41. {
  42. return false;
  43. }
  44. Position = position;
  45. long length;
  46. if (!long.TryParse(tokens[2], out length) || Length < 0)
  47. {
  48. return false;
  49. }
  50. Length = length;
  51. bool isCompleted;
  52. if (!bool.TryParse(tokens[3], out isCompleted))
  53. {
  54. return false;
  55. }
  56. IsCompleted = isCompleted;
  57. int partNum;
  58. if (int.TryParse(tokens[4], out partNum) && partNum > 0 && !string.IsNullOrEmpty(tokens[5]))
  59. {
  60. PartETag = new PartETag(partNum, tokens[5]);
  61. }
  62. return true;
  63. }
  64. override public string ToString()
  65. {
  66. string result = PartId.ToString() + TokenSeparator + Position.ToString() + TokenSeparator
  67. + Length.ToString() + TokenSeparator + IsCompleted.ToString() + TokenSeparator;
  68. if (PartETag != null)
  69. {
  70. result += PartETag.PartNumber.ToString() + TokenSeparator + PartETag.ETag;
  71. } else
  72. {
  73. result += TokenSeparator;
  74. }
  75. return result;
  76. }
  77. }
  78. internal class ResumableContext
  79. {
  80. protected static readonly char ContextSeparator = ':';
  81. protected static readonly char PartContextSeparator = ',';
  82. public string BucketName { get; protected set; }
  83. public string Key { get; protected set; }
  84. public List<ResumablePartContext> PartContextList { get; set; }
  85. public string UploadId { get; set; }
  86. public string ContentMd5 { get; set; }
  87. public string CheckpointFile
  88. {
  89. get
  90. {
  91. return GenerateCheckpointFile();
  92. }
  93. }
  94. public string CheckpointDir { get; protected set; }
  95. public void Clear()
  96. {
  97. if (!string.IsNullOrEmpty(CheckpointFile) && File.Exists(CheckpointFile))
  98. {
  99. File.Delete(CheckpointFile);
  100. }
  101. }
  102. public bool Load()
  103. {
  104. if (!string.IsNullOrEmpty(CheckpointFile) && File.Exists(CheckpointFile))
  105. {
  106. var content = File.ReadAllText(CheckpointFile);
  107. return FromString(content);
  108. }
  109. return false;
  110. }
  111. public void Dump()
  112. {
  113. if (!string.IsNullOrEmpty(CheckpointFile))
  114. {
  115. string serialize = ToString();
  116. if (!string.IsNullOrEmpty(serialize))
  117. {
  118. File.WriteAllText(CheckpointFile, serialize);
  119. }
  120. }
  121. }
  122. virtual public bool FromString(string value)
  123. {
  124. var tokens = value.Split(ContextSeparator);
  125. if (tokens.Length != 3)
  126. {
  127. return false;
  128. }
  129. UploadId = tokens[0];
  130. ContentMd5 = tokens[1];
  131. var partStr = tokens[2];
  132. var partTokens = partStr.Split(PartContextSeparator);
  133. if (partTokens.Length <= 1)
  134. {
  135. return false;
  136. }
  137. PartContextList = PartContextList ?? new List<ResumablePartContext>();
  138. for (int i = 0; i < partTokens.Length; i++)
  139. {
  140. var partContext = new ResumablePartContext();
  141. if (!partContext.FromString(partTokens[i]))
  142. {
  143. return false;
  144. }
  145. PartContextList.Add(partContext);
  146. }
  147. return true;
  148. }
  149. override public string ToString()
  150. {
  151. string result = string.Empty;
  152. if (string.IsNullOrEmpty(UploadId))
  153. {
  154. return string.Empty;
  155. }
  156. result += UploadId.ToString() + ContextSeparator;
  157. if (string.IsNullOrEmpty(ContentMd5))
  158. {
  159. return string.Empty;
  160. }
  161. result += ContentMd5.ToString() + ContextSeparator;
  162. if (PartContextList.Count == 0)
  163. {
  164. return string.Empty;
  165. }
  166. foreach (var part in PartContextList)
  167. {
  168. string partStr = part.ToString();
  169. if (string.IsNullOrEmpty(partStr))
  170. {
  171. return string.Empty;
  172. }
  173. result += partStr + PartContextSeparator;
  174. }
  175. if (result.EndsWith(new string(PartContextSeparator, 1)))
  176. {
  177. result = result.Substring(0, result.Length - 1);
  178. }
  179. return result;
  180. }
  181. public ResumableContext(string bucketName, string key, string checkpointDir)
  182. {
  183. BucketName = bucketName;
  184. Key = key;
  185. if (!string.IsNullOrEmpty(checkpointDir))
  186. {
  187. CheckpointDir = checkpointDir;
  188. }
  189. }
  190. virtual protected string GenerateCheckpointFile()
  191. {
  192. return CheckpointDir + Path.PathSeparator + Base64(BucketName) + "_" + Base64(Key);
  193. }
  194. protected string Base64(string str)
  195. {
  196. var bytes = Encoding.UTF8.GetBytes(str);
  197. return Convert.ToBase64String(bytes);
  198. }
  199. }
  200. internal class ResumableCopyContext : ResumableContext
  201. {
  202. public string SourceBucketName { get; private set; }
  203. public string SourceKey { get; private set; }
  204. override protected string GenerateCheckpointFile()
  205. {
  206. return base.CheckpointDir + Path.PathSeparator + Base64(SourceBucketName) + "_" + Base64(SourceKey) + "_"
  207. + Base64(BucketName) + "_" + Base64(Key);
  208. }
  209. public ResumableCopyContext (string sourceBucketName, string sourceKey, string destBucketName,
  210. string destKey, string checkpointDir)
  211. : base(destBucketName, destKey, checkpointDir)
  212. {
  213. SourceBucketName = sourceBucketName;
  214. SourceKey = sourceKey;
  215. }
  216. }
  217. }