using BZFAStandardLib;
using Newtonsoft.Json;
using Sunny.UI.Win32;
using System;
using System.Collections.Generic;
using System.Diagnostics;
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 System.Windows.Forms;
using static MainForm.ClassFile.XiaomiAPI.XiaomiMqttClient_Extend;
using static MainForm.ClassFile.XiaomiAPI_MES.XiaomiMESHttp_StationInbound;
using static MainForm.ClassFile.XiaomiAPI_MES.XiaomiMESHttp_StationOutbound.XmMES_StationOutRequest_Body;
using static MainForm.ClassFile.XiaomiClass.MesHelper;
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)
{
string logPath = GlobalContext.MqttFileUpLogDir + "FileInfo" + DateTime.Now.ToString("yyyyMMdd") + ".txt";
try
{
Stopwatch stopwatch1 = new Stopwatch();
// 基础参数
//string url = "http://cm.pre.mi.com/file/x5/file/upload/mqtt";
//url = "http://im.pre.mi.com/file/x5/file/upload/mqtt";
string url = GlobalContext.UpFileUrl;
//这个之后要加到配置文件config中
string appid = GlobalContext.FileAppId;
//这个之后要加到配置文件config中
string appkey = GlobalContext.FileAppKey;
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 }
};
// 将 data 参数序列化为 Base64 编码的字符串
string data = Convert.ToBase64String(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(dataParam)));
FileOperate.NewTxtFile(logPath, DateTime.Now + $"==>【文件提交】开始上传:文件包[{fileUpload_X5.bucket}],文件名[{file.Name}]");
stopwatch1.Start();
// 调用上传方法
var uploadResult = UploadFile(url, file, data).Result;
stopwatch1.Stop();
FileOperate.NewTxtFile(logPath, DateTime.Now+"===>【文件提交】HTTP提交:" + JsonConvert.SerializeObject(dataParam) + "\r\n==>提交结果:" + uploadResult + "");
//获取返回参数
FileUpload_Result fileUpList = JsonConvert.DeserializeObject(uploadResult);
// 判断上传结果
if (!string.IsNullOrEmpty(uploadResult) && !uploadResult.StartsWith("异常:") && !uploadResult.StartsWith("HTTP 错误:"))
{
//附件信息添加到主页面
FileData fileData = new FileData();
fileData.FileName = file.Name;
fileData.FileId = fileUpList.body.uuid;
fileData.Bucket = fileUpList.body.bucket;
Form_Home.fileUploadData.fileData.Add(fileData);
FileOperate.NewTxtFile(logPath, DateTime.Now + $"==>【文件提交】上传结束:文件包[{fileUpload_X5.bucket}],文件名[{file.Name}],耗时[{stopwatch1.ElapsedMilliseconds}]");
return (1, fileUpload_X5.name + $"文件上传成功");
}
else
{
FileOperate.NewTxtFile(logPath, DateTime.Now + $"==>【文件提交】上传失败:文件包[{fileUpload_X5.bucket}],文件名[{file.Name}],耗时[{stopwatch1.ElapsedMilliseconds}]");
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; // 或者返回空字符串,根据需求决定
}
}
///
/// 删除文件
///
/// 文件路径
public 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.reference_info.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, FileInfo file, string data)
{
using (var httpClient = new HttpClient())
{
//httpClient.Timeout = new TimeSpan(80000000);
var formData = new MultipartFormDataContent();
// 添加文件
var fileContent = new StreamContent(file.OpenRead());
formData.Add(fileContent, "file", file.Name);
// 添加数据
formData.Add(new StringContent(data), "data");
try
{
//var response = await httpClient.PostAsync(url, formData);
var response = httpClient.PostAsync(url, formData).Result;
if (response.IsSuccessStatusCode)
{
return await response.Content.ReadAsStringAsync();
}
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 Reference_Info reference_info { get; set; }=new Reference_Info();
}
public class Reference_Info {
public string pass_station_id { get; set; } = string.Empty;
}
///
/// 上传文件-返回参数
///
public struct FileUpload_Result
{
public Header header { get; set; }
public Body body { get; set; }
public struct Header
{
public string code { get; set; }
public string desc { get; set; }
}
public struct Body
{
public string uuid { get; set; }
public string md5 { get; set; }
public string bucket { get; set; }
}
}
///
/// 待上传MES、Iot的文件信息
///
public class FileUpload_FileData
{
public List fileData { get; set; } = new List();
}
public class FileData
{
///
/// ⽂件名称
///
public string FileName { get; set; } = string.Empty;
///
/// ⽂件在⽂件服务器对应的uuid,可以采⽤异步上传,⾃定义uuid,先上传out,然后再异步上传⽂件,提升过站效率
///
public string FileId { get; set; } = string.Empty;
///
/// ⽂件服务器bucket
///
public string Bucket { get; set; } = string.Empty;
}
}
}