Update.cs 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.IO.Compression;
  5. using System.Net.Http;
  6. using System.Text.RegularExpressions;
  7. using System.Threading.Tasks;
  8. using Update.Utils;
  9. namespace Update.Services
  10. {
  11. public static class Update
  12. {
  13. public delegate void DeleUpdateProgress(string step, int nowP, int maxP);
  14. public delegate void DeleAfterUpdateProgress(bool ok, string error);
  15. private static readonly string DEFAULT_DOWNLOAD_PATH = Path.Combine(Environment.CurrentDirectory, "tmp");
  16. private static readonly List<string> IGNORE_PATHS = new List<string>()
  17. {
  18. "update"
  19. };
  20. public struct UpdateInfo
  21. {
  22. public string MD5 { get; set; }
  23. public double Version { get; set; }
  24. }
  25. public static async Task UpdateApplication(string url, string targetPath, DeleUpdateProgress updateProgress, DeleAfterUpdateProgress afterUpdateProgress, string tmpPath = null)
  26. {
  27. await Task.Factory.StartNew(async () =>
  28. {
  29. int maxSteps = 7, step = 1;
  30. if (string.IsNullOrEmpty(tmpPath))
  31. {
  32. tmpPath = DEFAULT_DOWNLOAD_PATH;
  33. }
  34. string localFile = Path.Combine(tmpPath, Path.GetFileName(url));
  35. string uncompressPath = Path.Combine(tmpPath, "tmp");
  36. void clearCache()
  37. {
  38. Task.Run(async () => { await ClearCache(uncompressPath, localFile); });
  39. }
  40. //await ClearTempPath(uncompressPath);
  41. updateProgress("获取更新参数", step++, maxSteps);
  42. UpdateInfo info = await GetUpdateInfo(url);
  43. if (info.Version < 1 || string.IsNullOrEmpty(info.MD5))
  44. {
  45. AfterUpdateProgressEvent(afterUpdateProgress, false, "获取更新参数失败!", clearCache);
  46. return;
  47. }
  48. updateProgress("下载", step++, maxSteps);
  49. if (!await Download(url, localFile))
  50. {
  51. AfterUpdateProgressEvent(afterUpdateProgress, false, "下载失败!", clearCache);
  52. return;
  53. }
  54. updateProgress("校验", step++, maxSteps);
  55. if (!CheckFileMd5(localFile, info.MD5))
  56. {
  57. AfterUpdateProgressEvent(afterUpdateProgress, false, "校验失败!", clearCache);
  58. return;
  59. }
  60. updateProgress("解压", step++, maxSteps);
  61. if (!await UnCompress(localFile, uncompressPath))
  62. {
  63. AfterUpdateProgressEvent(afterUpdateProgress, false, "解压失败!", clearCache);
  64. return;
  65. }
  66. updateProgress("更新", step++, maxSteps);
  67. if (!await CopyDirectory(uncompressPath, targetPath))
  68. {
  69. updateProgress("更新失败", step, maxSteps);
  70. AfterUpdateProgressEvent(afterUpdateProgress, false, "更新失败!", clearCache);
  71. return;
  72. }
  73. updateProgress("清理缓存", step++, maxSteps);
  74. if (!await ClearCache(uncompressPath, localFile))
  75. {
  76. updateProgress("清理缓存失败", step, maxSteps);
  77. AfterUpdateProgressEvent(afterUpdateProgress, true, "更新完成,清理缓存失败!", null);
  78. }
  79. else
  80. {
  81. updateProgress("更新完成", step++, maxSteps);
  82. AfterUpdateProgressEvent(afterUpdateProgress, true, "更新完成!", null);
  83. }
  84. });
  85. }
  86. private static void AfterUpdateProgressEvent(DeleAfterUpdateProgress afterUpdateProgress, bool res, string error, Action task)
  87. {
  88. afterUpdateProgress.Invoke(res, error);
  89. task?.Invoke();
  90. }
  91. private static async Task<UpdateInfo> GetUpdateInfo(string url)
  92. {
  93. UpdateInfo info = new UpdateInfo();
  94. try
  95. {
  96. url = Regex.Replace(url, "\\.[^.]{2,5}$", ".txt", RegexOptions.IgnoreCase);
  97. HttpResponseMessage response = await Http.Fetch(new Http.Request(url, Http.Method.Get));
  98. if (response.IsSuccessStatusCode)
  99. {
  100. string txt = await response.Content.ReadAsStringAsync();
  101. info = Utils.Json.Decode<UpdateInfo>(txt);
  102. }
  103. }
  104. catch
  105. {
  106. }
  107. return info;
  108. }
  109. private static bool CheckFileMd5(string localFileName, string md5)
  110. {
  111. return FileExtensions.FileMd5(localFileName) == md5;
  112. }
  113. private static async Task<bool> ClearTempPath(string targetPath)
  114. {
  115. try
  116. {
  117. await Task.Run(() =>
  118. {
  119. DirectoryInfo di = new DirectoryInfo(targetPath);
  120. if (di.Exists)
  121. {
  122. di.Delete(true);
  123. }
  124. FileExtensions.CheckDirectory(targetPath, true);
  125. });
  126. return true;
  127. }
  128. catch
  129. {
  130. return false;
  131. }
  132. }
  133. private static async Task<bool> Download(string url, string localFilename)
  134. {
  135. try
  136. {
  137. HttpResponseMessage response = await Utils.Http.Fetch(new Utils.Http.Request(url, Utils.Http.Method.Get));
  138. if (response != null && response.IsSuccessStatusCode)
  139. {
  140. var bytes = await response.Content.ReadAsByteArrayAsync();
  141. FileExtensions.WriteBytes(localFilename, bytes);
  142. }
  143. return true;
  144. }
  145. catch
  146. {
  147. return false;
  148. }
  149. }
  150. private static async Task<bool> UnCompress(string localFilename, string targetPath)
  151. {
  152. bool r = false;
  153. try
  154. {
  155. r = await Task.Run(async () =>
  156. {
  157. bool res = await ClearTempPath(targetPath);
  158. if (res)
  159. {
  160. ZipFile.ExtractToDirectory(localFilename, targetPath);
  161. res = true;
  162. }
  163. return res;
  164. });
  165. }
  166. catch
  167. {
  168. }
  169. return r;
  170. }
  171. private static async Task<bool> CopyDirectory(string srcPath, string dstPath)
  172. {
  173. bool copyDirectory(string sp, string dp)
  174. {
  175. string np;
  176. try
  177. {
  178. DirectoryInfo dir = new DirectoryInfo(sp);
  179. FileSystemInfo[] fileinfo = dir.GetFileSystemInfos(); //获取目录下(不包含子目录)的文件和子目录
  180. foreach (FileSystemInfo i in fileinfo)
  181. {
  182. np = Path.Combine(dp, i.Name);
  183. if (i is DirectoryInfo) //判断是否文件夹
  184. {
  185. if (!Directory.Exists(np))
  186. {
  187. Directory.CreateDirectory(np); //目标目录下不存在此文件夹即创建子文件夹
  188. }
  189. if (!IsIgnoreDirectory(i.FullName, srcPath))
  190. {
  191. // 判断是否是忽略目录
  192. copyDirectory(i.FullName, np); //递归调用复制子文件夹
  193. }
  194. }
  195. else
  196. {
  197. File.Copy(i.FullName, np, true); //不是文件夹即复制文件,true表示可以覆盖同名文件
  198. }
  199. }
  200. return true;
  201. }
  202. catch
  203. {
  204. return false;
  205. }
  206. }
  207. return await Task.Run(() => { return copyDirectory(srcPath, dstPath); });
  208. }
  209. private static bool IsIgnoreDirectory(string p, string srcRootPath)
  210. {
  211. bool res = false;
  212. Uri a = new Uri(p), b;
  213. foreach (string s in IGNORE_PATHS)
  214. {
  215. b = new Uri(Path.Combine(srcRootPath, s));
  216. res = a == b;
  217. if (res)
  218. {
  219. break;
  220. }
  221. }
  222. return res;
  223. }
  224. private static async Task<bool> ClearCache(string cachePath, string cacheUpdateFile)
  225. {
  226. bool res = false;
  227. await Task.Run(() =>
  228. {
  229. try
  230. {
  231. DirectoryInfo di = new DirectoryInfo(cachePath);
  232. if (di.Exists)
  233. {
  234. di.Delete(true);
  235. }
  236. if (File.Exists(cacheUpdateFile))
  237. {
  238. File.Delete(cacheUpdateFile);
  239. }
  240. res = true;
  241. }
  242. catch { }
  243. });
  244. return res;
  245. }
  246. }
  247. }