using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net.Http; using System.Security.Cryptography; using System.Security.Policy; using System.Text; using System.Threading.Tasks; using static MainForm.ClassFile.XiaomiAPI.XiaomiMqttClient_Extend; using static MainForm.ClassFile.XiaomiAPI_MES.XiaomiMESHttp_StationInbound; namespace MainForm.ClassFile.XiaomiAPI_MES { /// /// 小米MES - 进站接⼝ /// 接口地址: /// 接口方法:UnitConfirmDataSetIn /// public class XiaomiMESHttp_UpLoadFile : XiaomiMESHttp_X5 { #region 变量 /// /// 接口地址 /// protected new static string UpFileUrl { set; get; } = GlobalContext.UpFileUrl; /// /// 接口方法 /// protected new static string Method { set; get; } = "UploadMqtt"; #endregion 变量 /// /// 文件上传到 MES 系统 /// /// 文件路径 /// 文件上传参数 /// MQTT 负载参数 /// (状态码, 结果信息) public static async Task<(int, string)> FileUoladToMes(string wJPath, FileUpload_X5 fileUpload_X5, FileMqttPayload fileMqttPayload) { try { // 基础参数 string url = "http://cm.pre.mi.com/file/x5/file/upload/mqtt"; url = "http://im.pre.mi.com/file/x5/file/upload/mqtt"; //这个之后要加到配置文件config中 string appid = "Auto-Soft"; //这个之后要加到配置文件config中 string appkey = "5984710e-bb38-4806-b94d-7a9a727e3880"; string method = "UploadMqtt"; // 检查文件是否存在 if (!System.IO.File.Exists(wJPath)) { return (-1, "文件不存在"); } // 获取文件信息 FileInfo file = new FileInfo(wJPath); // 构造 body string body = BuildBody(fileUpload_X5, fileMqttPayload); // 计算 sign string sign = GetSign(appid + body + appkey); // MD5 加密 // 构造 header Dictionary header = BuildHeader(url, appid, method, sign); // 构造 data 参数 Dictionary dataParam = new Dictionary { { "header", header }, { "body", body } }; string jsonStr = JsonConvert.SerializeObject(dataParam); // 将 data 参数序列化为 Base64 编码的字符串 string data = Convert.ToBase64String(Encoding.UTF8.GetBytes(jsonStr)); // 调用上传方法 var uploadResult = await UploadFile(url, data, wJPath); // 判断上传结果 if (!string.IsNullOrEmpty(uploadResult) && !uploadResult.StartsWith("异常:") && !uploadResult.StartsWith("HTTP 错误:")) { //删除文件 (bool, string) newResult = DeleteFile(wJPath); if (!newResult.Item1) { return (0, fileUpload_X5.name+newResult.Item2); } return (0, fileUpload_X5.name+"文件上传成功"); } else { return (-2, fileUpload_X5.name+$"文件上传失败: {uploadResult}"); } } catch (Exception ex) { return (-3, fileUpload_X5.name+$"发生异常: {ex.Message}"); } } /// /// 将文件复制到目标文件夹,并删除源文件 /// /// 源文件路径 /// 目标文件夹路径 static string CopyAndDeleteFile(string sourceFilePath, string destinationFolderPath) { try { // 检查目标文件夹是否存在,如果不存在则创建 if (!Directory.Exists(destinationFolderPath)) { Directory.CreateDirectory(destinationFolderPath); } // 构建目标文件的完整路径 string fileName = Path.GetFileName(sourceFilePath); // 获取源文件的文件名 string destinationFilePath = Path.Combine(destinationFolderPath, fileName); // 如果目标文件已存在,则删除已有文件以避免冲突 if (File.Exists(destinationFilePath)) { File.Delete(destinationFilePath); // 删除已有文件 } // 检查文件是否准备好 if (!IsFileReady(sourceFilePath)) { throw new IOException($"文件 {sourceFilePath} 正被其他进程占用,无法进行复制和删除操作。"); } // 复制文件到目标文件夹 File.Copy(sourceFilePath, destinationFilePath); // 删除源文件 File.Delete(sourceFilePath); Console.WriteLine($"文件已从 {sourceFilePath} 成功复制到 {destinationFilePath} 并删除原文件。"); // 返回目标文件路径 return destinationFilePath; } catch (Exception ex) { Console.WriteLine($"文件转移失败: {ex.Message}"); return null; // 或者返回空字符串,根据需求决定 } } /// /// 删除文件 /// /// 文件路径 static (bool,string) DeleteFile(string sourceFilePath) { try { // 构建目标文件的完整路径 string fileName = Path.GetFileName(sourceFilePath); // 获取源文件的文件名 // 检查文件是否准备好 if (!IsFileReady(sourceFilePath)) { throw new IOException($"文件 {sourceFilePath} 正被其他进程占用,无法进行复制和删除操作。"); } // 删除源文件 File.Delete(sourceFilePath); return (true, "文件删除成功!"); } catch (Exception ex) { return (false, "文件删除失败!"+ex.Message); } } public static bool IsFileReady(string filePath) { try { using (FileStream stream = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None)) { stream.Close(); } return true; } catch (IOException) { return false; } } /// /// 文件MD5加密 /// /// /// public static string GetMD5Hex(FileInfo file) { using (MD5 md5 = MD5.Create()) { using (FileStream stream = file.OpenRead()) { byte[] hashBytes = md5.ComputeHash(stream); StringBuilder sb = new StringBuilder(); for (int i = 0; i < hashBytes.Length; i++) { sb.Append(hashBytes[i].ToString("x2")); } return sb.ToString(); } } } /// /// 数据pin接 /// /// /// /// public static string BuildBody(FileUpload_X5 file, FileMqttPayload payload) { Dictionary fileMetadata = new Dictionary(); Dictionary mqttPayLoad = new Dictionary(); mqttPayLoad.Add("factory", payload.factory); mqttPayLoad.Add("project_name", payload.project_name); mqttPayLoad.Add("product_mode", payload.product_mode); mqttPayLoad.Add("line_no", payload.line_no); mqttPayLoad.Add("work_station_no", payload.work_station_no); mqttPayLoad.Add("equipment_no", payload.equipment_no); mqttPayLoad.Add("station_no", payload.station_no); mqttPayLoad.Add("file_id", payload.file_id); mqttPayLoad.Add("file_name", payload.file_name); mqttPayLoad.Add("sn", payload.sn); mqttPayLoad.Add("opt_time", payload.opt_time); mqttPayLoad.Add("file_type", payload.file_type); mqttPayLoad.Add("file_category", payload.file_category); mqttPayLoad.Add("tag", payload.tag); mqttPayLoad.Add("reference_info", Newtonsoft.Json.JsonConvert.SerializeObject(new object[] { new { pass_station_id = payload.pass_station_id } })); fileMetadata.Add("bucket", file.bucket); fileMetadata.Add("name", file.name); fileMetadata.Add("uuid", file.uuid); fileMetadata.Add("md5", file.md5); fileMetadata.Add("uploadCloud", file.uploadCloud); fileMetadata.Add("informMqtt", file.informMqtt); fileMetadata.Add("mqttPayload", Newtonsoft.Json.JsonConvert.SerializeObject(mqttPayLoad)); string body = Newtonsoft.Json.JsonConvert.SerializeObject(fileMetadata); return body; } /// /// 数据头拼接 /// /// /// /// /// /// public static Dictionary BuildHeader(string url, string appid, string method, string sign) { Dictionary header = new Dictionary(); header.Add("appid", appid); header.Add("method", method); header.Add("sign", sign); header.Add("url", url); return header; } public static string GetGuid() { return (System.Guid.NewGuid().ToString("N")); } /// /// 异步文件上传 /// /// 上传地址 /// 文件路径 /// 上传的数据 /// 返回上传结果 public static async Task UploadFile(string url, string data, string imageFile) { using (var httpClient = new HttpClient()) { var formData = new MultipartFormDataContent(); try { // 获取文件名 string filename = Path.GetFileName(imageFile); // 创建 StreamContent 对象 using (var fileStream = File.OpenRead(imageFile)) using (var streamContent = new StreamContent(fileStream)) { // 设置 Content-Type(根据实际文件类型设置) streamContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream"); // 添加文件到 formData formData.Add(streamContent, "file", filename); // 添加其他数据到 formData formData.Add(new StringContent(data), "data"); // 发送 POST 请求 var response = await httpClient.PostAsync(url, formData); if (response.IsSuccessStatusCode) { // 读取响应内容 string result = await response.Content.ReadAsStringAsync(); // 删除图片文件 try { File.Delete(imageFile); } catch (Exception ex) { return $"上传成功,删除图片文件时出错: {ex.Message}"; } return result; // 返回上传成功的响应 } else { return $"HTTP 错误: {response.StatusCode}"; } } } catch (Exception e) { return $"异常: {e.Message}"; } } } /// /// MD5加密 /// /// /// public static string GetSign(string data) { // 实例化一个md5对像 MD5 md5 = MD5.Create(); // MD5加密 byte[] encodingMd5Data = md5.ComputeHash(Encoding.UTF8.GetBytes(data)); // 生成签名字段 string sign = ""; for (int i = 0; i < encodingMd5Data.Length; i++) { // 将得到的字符串使用十六进制类型格式。格式后的字符是小写的字母,如果使用大写(X)则格式后的字符是大写字符 sign += encodingMd5Data[i].ToString("X2"); } return sign; } public class FileUpload_X5 { /// /// ⽂件所属包 /// 必填 /* ${file_category}/${file_type}/${项⽬号}/${⽣ 产阶段}/${运⾏模式}/${过站结果}/${装备编 码}/${sn}/${pass_station_id} • 其中file_category的枚举值为: ◦ IMAGE ◦ TEXT • 若对应字段的值为空,则使⽤默认值 UNKNOWN 注意:⾸位不能出现/,否则会出现路径错误 问题。 如: 正确⽰例 IMAGE/IMAGE/N3/debug/online/PASS/MPA-0001/P320N000006B/382f55e9-c2bb */ /// public string bucket { get; set; } = string.Empty; /// /// 文件名 /// public string name { get; set; } = string.Empty; /// /// 文件唯一标识符 /// public string uuid { get; set; } = string.Empty; /// /// md5 传空 /// public string md5 { get; set; } = string.Empty; /// /// 是否上云 默认true /// public Boolean uploadCloud { get; set; } /// /// 是否通知Mqtt 默认true /// public Boolean informMqtt { get; set; } } public class FileMqttPayload { /// /// 工厂编码 /// public string factory { get; set; } = string.Empty; /// /// 项目号 /// public string project_name { get; set; } = string.Empty; /// /// 生产阶段 /// public string product_mode { get; set; } = string.Empty; /// /// 线体 /// public string line_no { get; set; } = string.Empty; /// /// 工站 /// public string work_station_no { get; set; } = string.Empty; /// /// 装备 /// public string equipment_no { get; set; } = string.Empty; /// /// 工位 /// public string station_no { get; set; } = string.Empty; /// /// 文件ID /// public string file_id { get; set; } = string.Empty; /// /// 文件名 /// public string file_name { get; set; } = string.Empty; /// /// 产品sn /// public string sn { get; set; } = string.Empty; /// /// 文件生成时间 /// public string opt_time { get; set; } = string.Empty; /// /// 文件类型 /// public string file_type { get; set; } = string.Empty; /// /// 文件类别 /// public string file_category { get; set; } = string.Empty; /// /// 自定义标签信息 /// public string tag { get; set; } = string.Empty; /// /// 关联业务信息 /// public string pass_station_id { get; set; } = string.Empty; } } }