PackageManager.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. using Force.Crc32;
  2. using PackageInterface;
  3. using System;
  4. using System.Collections.Concurrent;
  5. using System.Diagnostics;
  6. using System.IO;
  7. using System.IO.Compression;
  8. using System.Linq;
  9. using System.Threading.Tasks;
  10. namespace PackageServer
  11. {
  12. enum PackageTaskState
  13. {
  14. Running,
  15. Transfering,
  16. Executing,
  17. Closed,
  18. }
  19. class PackageTask
  20. {
  21. private uint _transferHashCode;
  22. private string _transferFolder;
  23. private string _packageFolder;
  24. private string _transferFilePath;
  25. private Stream _transferStream;
  26. private Process _runningProcess;
  27. public string Id { get; }
  28. public string Version { get; }
  29. public PackageTaskState State { get; private set; }
  30. public PackageTask(string version, string transferFolder, string packageFolder)
  31. {
  32. _transferFolder = transferFolder;
  33. _packageFolder = packageFolder;
  34. Id = Guid.NewGuid().ToString("N");
  35. Version = version;
  36. State = PackageTaskState.Running;
  37. }
  38. public void StartTransfer(uint hashCode)
  39. {
  40. if(!Directory.Exists(_transferFolder))
  41. {
  42. Directory.CreateDirectory(_transferFolder);
  43. }
  44. //Clean the package folder
  45. if(Directory.Exists(_packageFolder))
  46. {
  47. Directory.Delete(_packageFolder, true);
  48. }
  49. if(!Directory.Exists(_packageFolder))
  50. {
  51. Directory.CreateDirectory(_packageFolder);
  52. }
  53. _transferHashCode = hashCode;
  54. _transferFilePath = Path.Combine(_transferFolder, Guid.NewGuid().ToString("N") + ".zip");
  55. _transferStream = File.Open(_transferFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
  56. State = PackageTaskState.Transfering;
  57. }
  58. public void AddTransferData(byte[] data)
  59. {
  60. try
  61. {
  62. _transferStream.Write(data);
  63. }
  64. catch
  65. {
  66. Close();
  67. throw;
  68. }
  69. }
  70. public void EndTransfer()
  71. {
  72. try
  73. {
  74. _transferStream.Flush();
  75. _transferStream.Dispose();
  76. var zipData = File.ReadAllBytes(_transferFilePath);
  77. //check hash code.
  78. var hashCode = Crc32Algorithm.Compute(zipData);
  79. if (hashCode != _transferHashCode)
  80. {
  81. throw new InvalidDataException("Transfer hash code is not right.");
  82. }
  83. //Extract to package folder.
  84. ZipFile.ExtractToDirectory(_transferFilePath, _packageFolder, true);
  85. if (File.Exists(_transferFilePath))
  86. {
  87. File.Delete(_transferFilePath);
  88. }
  89. State = PackageTaskState.Running;
  90. }
  91. catch
  92. {
  93. Close();
  94. throw;
  95. }
  96. }
  97. public void Execute(string fileName)
  98. {
  99. try
  100. {
  101. //Execute bat file or exe file.
  102. var filePath = Path.Combine(_packageFolder, fileName);
  103. if (!File.Exists(filePath))
  104. {
  105. throw new InvalidDataException("The file is not exist.");
  106. }
  107. _runningProcess = Process.Start(new ProcessStartInfo() { FileName = filePath, Arguments=Version, UseShellExecute = true, WorkingDirectory = _packageFolder });
  108. State = PackageTaskState.Executing;
  109. Task.Run(() =>
  110. {
  111. _runningProcess.WaitForExit();
  112. State = PackageTaskState.Running;
  113. });
  114. }
  115. catch
  116. {
  117. Close();
  118. throw;
  119. }
  120. }
  121. public void Close()
  122. {
  123. if(_transferStream != null)
  124. {
  125. _transferStream.Dispose();
  126. _transferStream = null;
  127. }
  128. if(File.Exists(_transferFilePath))
  129. {
  130. File.Delete(_transferFilePath);
  131. }
  132. State = PackageTaskState.Closed;
  133. }
  134. /// <summary>
  135. /// Kill means force kill the running task.
  136. /// </summary>
  137. public void Kill()
  138. {
  139. if (_runningProcess != null)
  140. {
  141. _runningProcess.Kill();
  142. }
  143. Close();
  144. State = PackageTaskState.Closed;
  145. }
  146. }
  147. class Packager
  148. {
  149. private string _packagerFolder;
  150. private string _transferFolder;
  151. private string _packageFolder;
  152. public string Id { get; }
  153. public string ProjectName { get; }
  154. public PackageTask CurrentTask { get; private set; }
  155. public Packager(string projectName)
  156. {
  157. Id = Guid.NewGuid().ToString("N");
  158. ProjectName = projectName;
  159. _packagerFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Packages", ProjectName);
  160. if(!Directory.Exists(_packagerFolder))
  161. {
  162. Directory.CreateDirectory(_packagerFolder);
  163. }
  164. _transferFolder = Path.Combine(_packagerFolder, "Transfer");
  165. if(!Directory.Exists(_transferFolder))
  166. {
  167. Directory.CreateDirectory(_transferFolder);
  168. }
  169. _packageFolder = Path.Combine(_packagerFolder, "Dist");
  170. if(!Directory.Exists(_packageFolder))
  171. {
  172. Directory.CreateDirectory(_packageFolder);
  173. }
  174. }
  175. public void StartPackage(string version)
  176. {
  177. if (CurrentTask != null)
  178. {
  179. CurrentTask.Kill();
  180. CurrentTask = null;
  181. }
  182. CurrentTask = new PackageTask(version, _transferFolder, _packageFolder);
  183. }
  184. public void EndPackage()
  185. {
  186. if (CurrentTask != null)
  187. {
  188. CurrentTask.Close();
  189. CurrentTask = null;
  190. }
  191. }
  192. public void KillTask()
  193. {
  194. if(CurrentTask != null)
  195. {
  196. CurrentTask.Kill();
  197. CurrentTask = null;
  198. }
  199. }
  200. }
  201. class PackageManager : IPackageManager
  202. {
  203. private readonly ConcurrentDictionary<string, Packager> _packagers = new ConcurrentDictionary<string,Packager>();
  204. public void EndPackage(string packagerId, string taskId)
  205. {
  206. if (_packagers.TryGetValue(packagerId, out var packager))
  207. {
  208. var task = packager.CurrentTask;
  209. if (task == null)
  210. {
  211. throw new InvalidOperationException("No task is running.");
  212. }
  213. if (packager.CurrentTask.Id != taskId)
  214. {
  215. throw new InvalidOperationException("The task is not current running task.");
  216. }
  217. packager.EndPackage();
  218. }
  219. else
  220. {
  221. throw new InvalidOperationException("Packager does not exist.");
  222. }
  223. }
  224. public void EndTransfer(string packagerId, string taskId)
  225. {
  226. if (_packagers.TryGetValue(packagerId, out var packager))
  227. {
  228. var task = packager.CurrentTask;
  229. if (task == null)
  230. {
  231. throw new InvalidOperationException("No task is running.");
  232. }
  233. if (packager.CurrentTask.Id != taskId)
  234. {
  235. throw new InvalidOperationException("The task is not current running task.");
  236. }
  237. packager.CurrentTask.EndTransfer();
  238. }
  239. else
  240. {
  241. throw new InvalidOperationException("Packager does not exist.");
  242. }
  243. }
  244. public void Execute(string packagerId, string taskId, string fileName)
  245. {
  246. if (_packagers.TryGetValue(packagerId, out var packager))
  247. {
  248. var task = packager.CurrentTask;
  249. if (task == null)
  250. {
  251. throw new InvalidOperationException("No task is running.");
  252. }
  253. if (packager.CurrentTask.Id != taskId)
  254. {
  255. throw new InvalidOperationException("The task is not current running task.");
  256. }
  257. packager.CurrentTask.Execute(fileName);
  258. }
  259. else
  260. {
  261. throw new InvalidOperationException("Packager does not exist.");
  262. }
  263. }
  264. public string GetOrCreatePackager(string projectName)
  265. {
  266. var packager = _packagers.Values.FirstOrDefault(x => x.ProjectName == projectName);
  267. if(packager == null)
  268. {
  269. packager = new Packager(projectName);
  270. _packagers.TryAdd(packager.Id, packager);
  271. }
  272. return packager.Id;
  273. }
  274. public string GetPackageTaskState(string packagerId, string taskId)
  275. {
  276. if (_packagers.TryGetValue(packagerId, out var packager))
  277. {
  278. var task = packager.CurrentTask;
  279. if (task == null)
  280. {
  281. throw new InvalidOperationException("No task is running.");
  282. }
  283. if (packager.CurrentTask.Id != taskId)
  284. {
  285. throw new InvalidOperationException("The task is not current running task.");
  286. }
  287. return packager.CurrentTask.State.ToString();
  288. }
  289. else
  290. {
  291. throw new InvalidOperationException("Packager does not exist.");
  292. }
  293. }
  294. public void KillPackager(string packagerId)
  295. {
  296. if (_packagers.TryGetValue(packagerId, out var packager))
  297. {
  298. packager.KillTask();
  299. _packagers.TryRemove(packager.ProjectName, out _);
  300. }
  301. else
  302. {
  303. throw new InvalidOperationException("Packager does not exist.");
  304. }
  305. }
  306. public void KillPackageTask(string packagerId, string taskId)
  307. {
  308. if (_packagers.TryGetValue(packagerId, out var packager))
  309. {
  310. var task = packager.CurrentTask;
  311. if (task == null)
  312. {
  313. throw new InvalidOperationException("No task is running.");
  314. }
  315. if (packager.CurrentTask.Id != taskId)
  316. {
  317. throw new InvalidOperationException("The task is not current running task.");
  318. }
  319. packager.KillTask();
  320. }
  321. else
  322. {
  323. throw new InvalidOperationException("Packager does not exist.");
  324. }
  325. }
  326. public string StartPackageTask(string packagerId, string version)
  327. {
  328. if(_packagers.TryGetValue(packagerId, out var packager))
  329. {
  330. packager.StartPackage(version);
  331. return packager.CurrentTask.Id;
  332. }
  333. else
  334. {
  335. throw new InvalidOperationException("Packager does not exist.");
  336. }
  337. }
  338. public void StartTransfer(string packagerId, string taskId, uint hashCode)
  339. {
  340. if (_packagers.TryGetValue(packagerId, out var packager))
  341. {
  342. var task = packager.CurrentTask;
  343. if(task == null)
  344. {
  345. throw new InvalidOperationException("No task is running.");
  346. }
  347. if(packager.CurrentTask.Id != taskId)
  348. {
  349. throw new InvalidOperationException("The task is not current running task.");
  350. }
  351. packager.CurrentTask.StartTransfer(hashCode);
  352. }
  353. else
  354. {
  355. throw new InvalidOperationException("Packager does not exist.");
  356. }
  357. }
  358. public void TransferData(string packagerId, string taskId, byte[] data)
  359. {
  360. if (_packagers.TryGetValue(packagerId, out var packager))
  361. {
  362. var task = packager.CurrentTask;
  363. if (task == null)
  364. {
  365. throw new InvalidOperationException("No task is running.");
  366. }
  367. if (packager.CurrentTask.Id != taskId)
  368. {
  369. throw new InvalidOperationException("The task is not current running task.");
  370. }
  371. packager.CurrentTask.AddTransferData(data);
  372. }
  373. else
  374. {
  375. throw new InvalidOperationException("Packager does not exist.");
  376. }
  377. }
  378. }
  379. }