FirmwareUpdateProcedure.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. using AwInitilizer.Assist;
  2. using AwInitilizer.Model;
  3. using Newtonsoft.Json;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Collections.Specialized;
  7. using System.ComponentModel;
  8. using System.Globalization;
  9. using System.IO;
  10. using System.Linq;
  11. using System.Net;
  12. using System.Text;
  13. using System.Threading.Tasks;
  14. using System.Web;
  15. using System.Windows.Ink;
  16. namespace AwInitilizer.Procedure
  17. {
  18. public class FirmwareUpdateProcedure : ProcedureBase
  19. {
  20. internal string Version;
  21. internal string fileName;
  22. internal string module;
  23. //internal int SleepMinuts = 6;
  24. private FirmwareUpdateModel _model;
  25. public FirmwareUpdateProcedure(FirmwareUpdateModel model) :base()
  26. {
  27. _model = model;
  28. Name = string.Format("Firmware {0}", model.Module);
  29. Content = string.Format("Update {0} Firemware and check version matched", model.Module);
  30. Version = model.Version;
  31. fileName = model.FirmwareFileName;
  32. module = model.Module;
  33. }
  34. internal override async Task<bool> Run()
  35. {
  36. var oldVersion = await GetSpecificVersion();
  37. LogPair.Add($"{module}OldVersion", oldVersion);
  38. if (string.IsNullOrEmpty(oldVersion))
  39. {
  40. InfoLog += $"Get {Name} version failed\n";
  41. Logger.Print($"Get {Name} version failed",isError:true);
  42. return false;
  43. }
  44. InfoLog += $"version before update : {oldVersion}\n";
  45. if (oldVersion == Version)
  46. {
  47. Logger.Print("Updated version detected");
  48. }
  49. Logger.Print("Firmware Uploading...");
  50. var uploadResult = await Uploadfiremware(fileName);
  51. LogPair.Add($"{module}Upload", uploadResult.ToString());
  52. if (uploadResult)
  53. {
  54. //wait restart
  55. Logger.Print("Waiting restart..");
  56. bool response = false;
  57. int pollinfCnt = 0;
  58. for (pollinfCnt = 0; pollinfCnt < 14; pollinfCnt++)
  59. {
  60. await Task.Delay(TimeSpan.FromSeconds(30));
  61. response = await ChekCsuBootCompelete();
  62. if (response)
  63. break;
  64. }
  65. //timeout
  66. if(pollinfCnt>=14)
  67. {
  68. Logger.Print("Wait restart timeout",isError:true);
  69. return false;
  70. }
  71. }
  72. else
  73. {
  74. InfoLog += $"Upload {Name} failed\n";
  75. Logger.Print($"Upload {Name} failed", isError: true);
  76. return false;
  77. }
  78. var updatedVersion = await GetSpecificVersion();
  79. LogPair.Add($"{module}NewVersion", updatedVersion);
  80. if (string.IsNullOrEmpty(updatedVersion))
  81. {
  82. InfoLog += $"Get updated {Name} version failed\n";
  83. Logger.Print($"Get updated {Name} version failed", isError: true);
  84. return false;
  85. }
  86. InfoLog += $"Get updated version : {updatedVersion}\n";
  87. if (updatedVersion != Version)
  88. {
  89. InfoLog += $"{Name}:Updated Version mismatched\n";
  90. Logger.Print($"{Name}:Updated Version mismatched", isError: true);
  91. return false;
  92. }
  93. else
  94. {
  95. Logger.Print($"{Name}:updated success");
  96. }
  97. return true;
  98. }
  99. internal virtual async Task<string> GetSpecificVersion()
  100. {
  101. var versions = await GetVersion();
  102. if(!versions.ContainsKey(module))
  103. {
  104. return "";
  105. }
  106. return versions[module];
  107. }
  108. internal async Task<Dictionary<string,string>> GetVersion(bool isConnectTest = false)
  109. {
  110. try
  111. {
  112. using (WebClientTimeout webClient = new WebClientTimeout())
  113. {
  114. NameValueCollection parameters = new NameValueCollection();
  115. parameters.Add("opt", "1");
  116. webClient.QueryString = parameters;
  117. using (Stream stream = await webClient.OpenReadTaskAsync($"https://{ServerIpAddress}/get_query_action.php"))
  118. // 使用 StreamReader 讀取 stream 內的字元
  119. using (StreamReader reader = new StreamReader(stream))
  120. {
  121. // 將 StreamReader 所讀到的字元轉為 string
  122. string request = reader.ReadToEnd();
  123. InfoLog += $"get version response:{request}\n";
  124. var values = JsonConvert.DeserializeObject<Dictionary<string, object>>(request);
  125. var toReturn = new Dictionary<string, string>();
  126. foreach(var pair in values)
  127. {
  128. if (pair.Value is string v)
  129. {
  130. toReturn.Add(pair.Key, v);
  131. }
  132. else if(pair.Value is Newtonsoft.Json.Linq.JArray a)
  133. {
  134. try
  135. {
  136. var versionList = JsonConvert.DeserializeObject<List<string>>(a.ToString());
  137. for (int index = 0; index < versionList.Count; index++)
  138. {
  139. toReturn.Add(string.Format("{0}{1}", pair.Key, index), versionList[index]);
  140. }
  141. }
  142. catch
  143. {
  144. }
  145. }
  146. }
  147. return toReturn;
  148. }
  149. }
  150. }
  151. catch(Exception e)
  152. {
  153. if (!isConnectTest)
  154. {
  155. Logger.Print("Get Version Failed", isError: true);
  156. Logger.Print(e.Message + "", isError: true);
  157. InfoLog += "Get Version Failed\n";
  158. InfoLog += e.Message;
  159. InfoLog += "\n";
  160. }
  161. return null;
  162. }
  163. }
  164. internal async Task<bool> Uploadfiremware(string fileName)
  165. {
  166. try
  167. {
  168. //using (var stream = File.Open(fileName, FileMode.Open))
  169. //{
  170. // UploadFileAsync(
  171. // new NameValueCollection()
  172. // {
  173. // {"fw_tag","iso" }
  174. // },
  175. // new UploadFile()
  176. // {
  177. // Name = "file",
  178. // Filename = Path.GetFileName(fileName),
  179. // Stream = stream
  180. // }
  181. // );
  182. //}
  183. //return true;
  184. using (var stream = File.Open(fileName, FileMode.Open))
  185. {
  186. var response = await UploadFiles(
  187. $"https://{ServerIpAddress}/upgrade_iso_action.php",
  188. new List<UploadFile>() {
  189. new UploadFile()
  190. {
  191. Name="file",
  192. Filename= Path.GetFileName(fileName),
  193. Stream = stream
  194. }
  195. },
  196. new NameValueCollection() {
  197. {"fw_tag","iso" }
  198. }
  199. );
  200. var responseStr = Encoding.ASCII.GetString(response).ToLower();
  201. InfoLog += $"get firmware update response {responseStr}\n";
  202. if (responseStr.Contains("file is uploaded"))
  203. return true;
  204. return false;
  205. }
  206. return true;
  207. //using (WebClient webClient = new WebClient())
  208. //{
  209. // NameValueCollection parameters = new NameValueCollection();
  210. // parameters.Add("fw_tag", "iso");
  211. // webClient.QueryString = parameters;
  212. // var responseBytes = await webClient.UploadFileTaskAsync($"https://{ServerIpAddress}/upgrade_iso_action.php", fileName);
  213. // string responseString = Encoding.ASCII.GetString(responseBytes);
  214. // return true;
  215. //}
  216. }
  217. catch(Exception e)
  218. {
  219. Logger.Print("Upload Firmware Failed", isError: true);
  220. Logger.Print(e.Message + "", isError: true);
  221. InfoLog += "Upload Firmware Failed\n";
  222. InfoLog += e.Message;
  223. InfoLog += "\n";
  224. return false;
  225. }
  226. }
  227. public async Task<byte[]> UploadFiles(string address, IEnumerable<UploadFile> files, NameValueCollection values)
  228. {
  229. var request = (HttpWebRequest) HttpWebRequest.Create(address);
  230. request.KeepAlive = true;
  231. request.Accept = "*/*";
  232. request.Method = "POST";
  233. request.Referer = address;
  234. request.Expect = "";
  235. var boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x", NumberFormatInfo.InvariantInfo);
  236. request.ContentType = "multipart/form-data; boundary=" + boundary;
  237. boundary = "--" + boundary;
  238. using (var requestStream = request.GetRequestStream())
  239. {
  240. // Write the values
  241. foreach (string name in values.Keys)
  242. {
  243. var buffer = Encoding.ASCII.GetBytes(boundary + Environment.NewLine);
  244. requestStream.Write(buffer, 0, buffer.Length);
  245. buffer = Encoding.ASCII.GetBytes(string.Format("Content-Disposition: form-data; name=\"{0}\"{1}{1}", name, Environment.NewLine));
  246. requestStream.Write(buffer, 0, buffer.Length);
  247. buffer = Encoding.UTF8.GetBytes(values[name] + Environment.NewLine);
  248. requestStream.Write(buffer, 0, buffer.Length);
  249. }
  250. // Write the files
  251. foreach (var file in files)
  252. {
  253. var buffer = Encoding.ASCII.GetBytes(boundary + Environment.NewLine);
  254. requestStream.Write(buffer, 0, buffer.Length);
  255. buffer = Encoding.UTF8.GetBytes(string.Format("Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"{2}", file.Name, file.Filename, Environment.NewLine));
  256. requestStream.Write(buffer, 0, buffer.Length);
  257. var ctype = MimeMapping.GetMimeMapping(file.Filename);
  258. buffer = Encoding.ASCII.GetBytes(string.Format("Content-Type: {0}{1}{1}", MimeMapping.GetMimeMapping(file.Filename), Environment.NewLine));
  259. requestStream.Write(buffer, 0, buffer.Length);
  260. file.Stream.CopyTo(requestStream);
  261. buffer = Encoding.ASCII.GetBytes(Environment.NewLine);
  262. requestStream.Write(buffer, 0, buffer.Length);
  263. }
  264. var boundaryBuffer = Encoding.ASCII.GetBytes(boundary + "--");
  265. requestStream.Write(boundaryBuffer, 0, boundaryBuffer.Length);
  266. }
  267. using (var response = await request.GetResponseAsync())
  268. using (var responseStream = response.GetResponseStream())
  269. using (var stream = new MemoryStream())
  270. {
  271. responseStream.CopyTo(stream);
  272. return stream.ToArray();
  273. }
  274. }
  275. [Obsolete]
  276. public void UploadFileAsync(NameValueCollection values, UploadFile file )
  277. {
  278. //to fire events on the calling thread
  279. var _asyncOperation = AsyncOperationManager.CreateOperation(null);
  280. var ms = new MemoryStream();
  281. //make a copy of the input stream in case sb uses disposable stream
  282. file.Stream.CopyTo(ms);
  283. //you cannot set stream position often enough to zero
  284. ms.Position = 0;
  285. Task.Factory.StartNew(() =>
  286. {
  287. try
  288. {
  289. const string contentType = "application/octet-stream";
  290. var request = WebRequest.Create($"https://{ServerIpAddress}/get_query_action.php");
  291. request.Method = "POST";
  292. var boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x", NumberFormatInfo.InvariantInfo);
  293. request.ContentType = "multipart/form-data; boundary=" + boundary;
  294. boundary = "--" + boundary;
  295. var dataStream = new MemoryStream();
  296. byte[] buffer;
  297. // Write the values
  298. foreach (string name in values.Keys)
  299. {
  300. buffer = Encoding.ASCII.GetBytes(boundary + Environment.NewLine);
  301. dataStream.Write(buffer, 0, buffer.Length);
  302. buffer = Encoding.ASCII.GetBytes(string.Format("Content-Disposition: form-data; name=\"{0}\"{1}{1}", name, Environment.NewLine));
  303. dataStream.Write(buffer, 0, buffer.Length);
  304. buffer = Encoding.UTF8.GetBytes(values[name] + Environment.NewLine);
  305. dataStream.Write(buffer, 0, buffer.Length);
  306. }
  307. // Write the file
  308. buffer = Encoding.ASCII.GetBytes(boundary + Environment.NewLine);
  309. dataStream.Write(buffer, 0, buffer.Length);
  310. buffer = Encoding.UTF8.GetBytes($"Content-Disposition: form-data; name=\"{file.Name}\"; filename=\"{file.Filename}\"{Environment.NewLine}");
  311. dataStream.Write(buffer, 0, buffer.Length);
  312. buffer = Encoding.ASCII.GetBytes(string.Format("Content-Type: {0}{1}{1}", MimeMapping.GetMimeMapping(file.Filename), Environment.NewLine));
  313. dataStream.Write(buffer, 0, buffer.Length);
  314. ms.CopyTo(dataStream);
  315. buffer = Encoding.ASCII.GetBytes(Environment.NewLine);
  316. dataStream.Write(buffer, 0, buffer.Length);
  317. buffer = Encoding.ASCII.GetBytes(boundary + "--");
  318. dataStream.Write(buffer, 0, buffer.Length);
  319. dataStream.Position = 0;
  320. //IMPORTANT: set content length to directly write to network socket
  321. request.ContentLength = dataStream.Length;
  322. var requestStream = request.GetRequestStream();
  323. //Write data in chunks and report progress
  324. var size = dataStream.Length;
  325. const int chunkSize = 64 * 1024;
  326. buffer = new byte[chunkSize];
  327. long bytesSent = 0;
  328. int readBytes;
  329. while ((readBytes = dataStream.Read(buffer, 0, buffer.Length)) > 0)
  330. {
  331. requestStream.Write(buffer, 0, readBytes);
  332. bytesSent += readBytes;
  333. var status = "Uploading... " + bytesSent / 1024 + "KB of " + size / 1024 + "KB";
  334. Console.WriteLine(status);
  335. }
  336. //get response
  337. using (var response = request.GetResponse())
  338. using (var responseStream = response.GetResponseStream())
  339. using (var stream = new MemoryStream())
  340. {
  341. // ReSharper disable once PossibleNullReferenceException - exception would get catched anyway
  342. responseStream.CopyTo(stream);
  343. var result = Encoding.Default.GetString(stream.ToArray());
  344. Console.WriteLine(result);
  345. }
  346. }
  347. catch (Exception e )
  348. {
  349. Console.WriteLine(e);
  350. }
  351. }, System.Threading.CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);
  352. }
  353. }
  354. }