FirmwareUpdateProcedure.cs 19 KB

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