using AwInitilizer.Assist; using AwInitilizer.Model; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; using System.Globalization; using System.IO; using System.Linq; using System.Net; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Web; using System.Windows.Ink; namespace AwInitilizer.Procedure { public class FirmwareUpdateProcedure : ProcedureBase { internal string Version; internal string fileName; internal string module; //internal int SleepMinuts = 6; private FirmwareUpdateModel _model; public FirmwareUpdateProcedure(FirmwareUpdateModel model) :base() { _model = model; Name = string.Format("Firmware {0}", model.Module); Content = string.Format("Update {0} Firemware and check version matched", model.Module); Version = model.Version; fileName = model.FirmwareFileName; module = model.Module; } internal override async Task Run() { var oldVersion = await GetSpecificVersion(); LogPair.Add($"{module}OldVersion", oldVersion); if (string.IsNullOrEmpty(oldVersion)) { InfoLog += $"Get {Name} version failed\n"; Logger.Print($"Get {Name} version failed",isError:true); return false; } InfoLog += $"version before update : {oldVersion}\n"; if (oldVersion == Version) { Logger.Print("Updated version detected"); } Logger.Print("Firmware Uploading..."); var uploadResult = await Uploadfiremware(fileName); LogPair.Add($"{module}Upload", uploadResult.ToString()); if (uploadResult) { //wait restart Logger.Print("Waiting restart.."); bool response = false; int pollinfCnt = 0; for (pollinfCnt = 0; pollinfCnt < 14; pollinfCnt++) { await Task.Delay(TimeSpan.FromSeconds(30)); response = await CheckAllIdel(); if (response) break; } //timeout if(pollinfCnt>=14) { Logger.Print("Wait restart timeout",isError:true); return false; } } else { InfoLog += $"Upload {Name} failed\n"; Logger.Print($"Upload {Name} failed", isError: true); return false; } var updatedVersion = await GetSpecificVersion(); LogPair.Add($"{module}NewVersion", updatedVersion); if (string.IsNullOrEmpty(updatedVersion)) { InfoLog += $"Get updated {Name} version failed\n"; Logger.Print($"Get updated {Name} version failed", isError: true); return false; } InfoLog += $"Get updated version : {updatedVersion}\n"; if (updatedVersion != Version) { InfoLog += $"{Name}:Updated Version mismatched\n"; Logger.Print($"{Name}:Updated Version mismatched", isError: true); return false; } else { Logger.Print($"{Name}:updated success"); } return true; } internal virtual async Task GetSpecificVersion() { var versions = await GetVersion(); if(!versions.ContainsKey(module)) { return ""; } return versions[module]; } internal async Task> GetVersion(bool isConnectTest = false) { try { using (WebClientTimeout webClient = new WebClientTimeout()) { NameValueCollection parameters = new NameValueCollection(); parameters.Add("opt", "1"); webClient.QueryString = parameters; using (Stream stream = await webClient.OpenReadTaskAsync($"https://{ServerIpAddress}/get_query_action.php")) // 使用 StreamReader 讀取 stream 內的字元 using (StreamReader reader = new StreamReader(stream)) { // 將 StreamReader 所讀到的字元轉為 string string request = reader.ReadToEnd(); InfoLog += $"get version response:{request}\n"; var values = JsonConvert.DeserializeObject>(request); var toReturn = new Dictionary(); foreach(var pair in values) { if (pair.Value is string v) { toReturn.Add(pair.Key, v); } else if(pair.Value is Newtonsoft.Json.Linq.JArray a) { try { var versionList = JsonConvert.DeserializeObject>(a.ToString()); for (int index = 0; index < versionList.Count; index++) { toReturn.Add(string.Format("{0}{1}", pair.Key, index), versionList[index]); } } catch { } } } return toReturn; } } } catch(Exception e) { if (!isConnectTest) { Logger.Print("Get Version Failed", isError: true); Logger.Print(e.Message + "", isError: true); InfoLog += "Get Version Failed\n"; InfoLog += e.Message; InfoLog += "\n"; } return null; } } private async Task CheckAllIdel() { try { using (WebClient webClient = new WebClient()) { NameValueCollection parameters = new NameValueCollection(); parameters.Add("opt", "2"); webClient.QueryString = parameters; using (Stream stream = await webClient.OpenReadTaskAsync($"https://{ServerIpAddress}/get_query_action.php")) // 使用 StreamReader 讀取 stream 內的字元 using (StreamReader reader = new StreamReader(stream)) { // 將 StreamReader 所讀到的字元轉為 string string request = reader.ReadToEnd(); InfoLog += $"get status respons:\n{request}\n"; LogPair.Add($"EvseStatus", request); Regex rx = new Regex("(SystemStatus)\\\": (\\d)"); var matches = rx.Matches(request); bool isAllPassed = true; for (int matchIndex = 0; matchIndex < matches.Count; matchIndex++) { var match = matches[matchIndex]; if (match.Groups.Count != 3) { InfoLog += $"Connector {matchIndex} status string mismatched\n"; Logger.Print($"Connector {matchIndex} status string mismatched", isError: true); isAllPassed = false; } else { if (match.Groups[2].Value != "1") { InfoLog += $"Connector {matchIndex} status not Idel\n"; Logger.Print($"Connector {matchIndex} status not Idel", isError: true); isAllPassed = false; } } } return isAllPassed; } } return true; } catch (Exception e) { return false; } } internal async Task Uploadfiremware(string fileName) { try { //using (var stream = File.Open(fileName, FileMode.Open)) //{ // UploadFileAsync( // new NameValueCollection() // { // {"fw_tag","iso" } // }, // new UploadFile() // { // Name = "file", // Filename = Path.GetFileName(fileName), // Stream = stream // } // ); //} //return true; using (var stream = File.Open(fileName, FileMode.Open)) { var response = await UploadFiles( $"https://{ServerIpAddress}/upgrade_iso_action.php", new List() { new UploadFile() { Name="file", Filename= Path.GetFileName(fileName), Stream = stream } }, new NameValueCollection() { {"fw_tag","iso" } } ); var responseStr = Encoding.ASCII.GetString(response).ToLower(); InfoLog += $"get firmware update response {responseStr}\n"; if (responseStr.Contains("file is uploaded")) return true; return false; } return true; //using (WebClient webClient = new WebClient()) //{ // NameValueCollection parameters = new NameValueCollection(); // parameters.Add("fw_tag", "iso"); // webClient.QueryString = parameters; // var responseBytes = await webClient.UploadFileTaskAsync($"https://{ServerIpAddress}/upgrade_iso_action.php", fileName); // string responseString = Encoding.ASCII.GetString(responseBytes); // return true; //} } catch(Exception e) { Logger.Print("Upload Firmware Failed", isError: true); Logger.Print(e.Message + "", isError: true); InfoLog += "Upload Firmware Failed\n"; InfoLog += e.Message; InfoLog += "\n"; return false; } } public async Task UploadFiles(string address, IEnumerable files, NameValueCollection values) { var request = (HttpWebRequest) HttpWebRequest.Create(address); request.KeepAlive = true; request.Accept = "*/*"; request.Method = "POST"; request.Referer = address; request.Expect = ""; var boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x", NumberFormatInfo.InvariantInfo); request.ContentType = "multipart/form-data; boundary=" + boundary; boundary = "--" + boundary; using (var requestStream = request.GetRequestStream()) { // Write the values foreach (string name in values.Keys) { var buffer = Encoding.ASCII.GetBytes(boundary + Environment.NewLine); requestStream.Write(buffer, 0, buffer.Length); buffer = Encoding.ASCII.GetBytes(string.Format("Content-Disposition: form-data; name=\"{0}\"{1}{1}", name, Environment.NewLine)); requestStream.Write(buffer, 0, buffer.Length); buffer = Encoding.UTF8.GetBytes(values[name] + Environment.NewLine); requestStream.Write(buffer, 0, buffer.Length); } // Write the files foreach (var file in files) { var buffer = Encoding.ASCII.GetBytes(boundary + Environment.NewLine); requestStream.Write(buffer, 0, buffer.Length); buffer = Encoding.UTF8.GetBytes(string.Format("Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"{2}", file.Name, file.Filename, Environment.NewLine)); requestStream.Write(buffer, 0, buffer.Length); var ctype = MimeMapping.GetMimeMapping(file.Filename); buffer = Encoding.ASCII.GetBytes(string.Format("Content-Type: {0}{1}{1}", MimeMapping.GetMimeMapping(file.Filename), Environment.NewLine)); requestStream.Write(buffer, 0, buffer.Length); file.Stream.CopyTo(requestStream); buffer = Encoding.ASCII.GetBytes(Environment.NewLine); requestStream.Write(buffer, 0, buffer.Length); } var boundaryBuffer = Encoding.ASCII.GetBytes(boundary + "--"); requestStream.Write(boundaryBuffer, 0, boundaryBuffer.Length); } using (var response = await request.GetResponseAsync()) using (var responseStream = response.GetResponseStream()) using (var stream = new MemoryStream()) { responseStream.CopyTo(stream); return stream.ToArray(); } } [Obsolete] public void UploadFileAsync(NameValueCollection values, UploadFile file ) { //to fire events on the calling thread var _asyncOperation = AsyncOperationManager.CreateOperation(null); var ms = new MemoryStream(); //make a copy of the input stream in case sb uses disposable stream file.Stream.CopyTo(ms); //you cannot set stream position often enough to zero ms.Position = 0; Task.Factory.StartNew(() => { try { const string contentType = "application/octet-stream"; var request = WebRequest.Create($"https://{ServerIpAddress}/get_query_action.php"); request.Method = "POST"; var boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x", NumberFormatInfo.InvariantInfo); request.ContentType = "multipart/form-data; boundary=" + boundary; boundary = "--" + boundary; var dataStream = new MemoryStream(); byte[] buffer; // Write the values foreach (string name in values.Keys) { buffer = Encoding.ASCII.GetBytes(boundary + Environment.NewLine); dataStream.Write(buffer, 0, buffer.Length); buffer = Encoding.ASCII.GetBytes(string.Format("Content-Disposition: form-data; name=\"{0}\"{1}{1}", name, Environment.NewLine)); dataStream.Write(buffer, 0, buffer.Length); buffer = Encoding.UTF8.GetBytes(values[name] + Environment.NewLine); dataStream.Write(buffer, 0, buffer.Length); } // Write the file buffer = Encoding.ASCII.GetBytes(boundary + Environment.NewLine); dataStream.Write(buffer, 0, buffer.Length); buffer = Encoding.UTF8.GetBytes($"Content-Disposition: form-data; name=\"{file.Name}\"; filename=\"{file.Filename}\"{Environment.NewLine}"); dataStream.Write(buffer, 0, buffer.Length); buffer = Encoding.ASCII.GetBytes(string.Format("Content-Type: {0}{1}{1}", MimeMapping.GetMimeMapping(file.Filename), Environment.NewLine)); dataStream.Write(buffer, 0, buffer.Length); ms.CopyTo(dataStream); buffer = Encoding.ASCII.GetBytes(Environment.NewLine); dataStream.Write(buffer, 0, buffer.Length); buffer = Encoding.ASCII.GetBytes(boundary + "--"); dataStream.Write(buffer, 0, buffer.Length); dataStream.Position = 0; //IMPORTANT: set content length to directly write to network socket request.ContentLength = dataStream.Length; var requestStream = request.GetRequestStream(); //Write data in chunks and report progress var size = dataStream.Length; const int chunkSize = 64 * 1024; buffer = new byte[chunkSize]; long bytesSent = 0; int readBytes; while ((readBytes = dataStream.Read(buffer, 0, buffer.Length)) > 0) { requestStream.Write(buffer, 0, readBytes); bytesSent += readBytes; var status = "Uploading... " + bytesSent / 1024 + "KB of " + size / 1024 + "KB"; Console.WriteLine(status); } //get response using (var response = request.GetResponse()) using (var responseStream = response.GetResponseStream()) using (var stream = new MemoryStream()) { // ReSharper disable once PossibleNullReferenceException - exception would get catched anyway responseStream.CopyTo(stream); var result = Encoding.Default.GetString(stream.ToArray()); Console.WriteLine(result); } } catch (Exception e ) { Console.WriteLine(e); } }, System.Threading.CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default); } } }