using Models; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using ProductionControl.Utils; using SqlSugar; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; namespace ProductionControl { public class WebService { private HttpListener svcHttpListener; public Action LogEvent; Service.OrderService svcOrder = new Service.OrderService(); private void logEvent(string msg, WarningEnum warn = WarningEnum.Normal) { LogEvent?.Invoke(warn,msg); } public void start() { try { if (Config.LocalHttpPort > 0) { //logEvent("Web服务启动..."); this.svcHttpListener = new HttpListener(); List lstIp = HttpUtil.getLocalIPList(); //logEvent($"Web服务已启动,运行于端口:{Config.LocalHttpPort.ToString()}, 监听Ip:{string.Join("|", lstIp)}"); //if (!string.IsNullOrWhiteSpace(Config.LocalIp) && lstIp.FindIndex(m => m.Contains(Config.LocalIp)) >= 0)//没指定IP/指定的不对 //{ // lstIp.Clear(); // lstIp.Add(Config.LocalIp); //} //lstIp.Clear(); if (lstIp.Count < 1) { lstIp.Add(Config.LocalIp); lstIp.Add("127.0.0.1"); } logEvent($"Web服务已启动,运行于端口:{Config.LocalHttpPort.ToString()}, 监听Ip:{string.Join("|", lstIp)}"); for (int i = 0; i < lstIp.Count; i++) this.svcHttpListener.Prefixes.Add("http://" + lstIp[i] + ":" + Config.LocalHttpPort.ToString() + "/"); this.svcHttpListener.Start(); //logEvent($"Web服务已启动,运行于端口:{Config.LocalHttpPort.ToString()}, 监听Ip:{string.Join("|", lstIp)}"); //this.svcHttpListener.GetContext().Response.AppendHeader("Access-Control-Allow-Origin", "*");//后台跨域请求,通常设置为配置文件 //this.svcHttpListener.GetContext().Response.AppendHeader("Access-Control-Allow-Credentials", "true"); //后台跨域请求 this.svcHttpListener.BeginGetContext(new AsyncCallback(this.GetContextCallBack), this.svcHttpListener); } //------WEB Socket //if (Config.localIp != "" && Config.localSocketPort > 0) //{ // logEvent( "WebSocket服务启动..."); // this.wssv = new WebSocketServer(Config.localSocketPort); // this.wssv.AddWebSocketService("/socket1"); // this.wssv.Start(); // logEvent( "WebSocket服务已启动。"); //} } catch (Exception ex) { logEvent("Web服务启动失败,ex="+ex.Message); } } public void stop() { logEvent( "正在停止WEB服务..."); try { if (this.svcHttpListener != null && this.svcHttpListener.IsListening) { this.svcHttpListener.Stop(); this.svcHttpListener.Close(); this.logEvent("Web服务已停止!"); } //if (this.svcWebSocket != null && this.svcWebSocket.IsListening) //{ // this.svcWebSocket.Stop(); // this.svcWebSocket = null; // this.AddTextEvent("WebSocket", "WebSocket服务已停止!"); //} } catch (Exception ex) { logEvent("Web服务停止失败,ex=" + ex.Message); } } // private void GetContextCallBack(IAsyncResult ar) { this.svcHttpListener = (ar.AsyncState as HttpListener); HttpListenerContext httpListenerContext; try { httpListenerContext = this.svcHttpListener.EndGetContext(ar); //httpListenerContext.Response.AppendHeader("Access-Control-Allow-Origin", "*");//后台跨域请求,通常设置为配置文件 //httpListenerContext.Response.AppendHeader("Access-Control-Allow-Credentials", "true"); //后台跨域请求 //httpListenerContext.Response.AppendHeader("Access-Control-Allow-Methods", "GET,POST"); httpListenerContext.Response.AddHeader("Access-Control-Allow-Origin", "*"); httpListenerContext.Response.AddHeader("Access-Control-Allow-Headers", "*"); httpListenerContext.Response.AddHeader("Access-Control-Allow-Methods", "*"); this.svcHttpListener.BeginGetContext(new AsyncCallback(this.GetContextCallBack), this.svcHttpListener); } catch (Exception ex) { logEvent( "ex:" + ex.StackTrace); return; } // string sessionId = Convert.ToInt32(DateTime.Now.ToString("mmssfff")).ToString();//.ToString("X"); string reqHttpMethod = httpListenerContext.Request.HttpMethod; string reqUrl = httpListenerContext.Request.RawUrl; string reqData = ""; try { this.logEvent( $"{sessionId} / 收到请求:{reqHttpMethod} To Url:{reqUrl}"); reqData = HttpUtil.getPostData(httpListenerContext.Request); this.logEvent( $"{sessionId} / 请求数据:{reqData}"); var subUrls = reqUrl.Trim(new char[] { '/' }).Split(new char[] { '/' }); if (subUrls[0].ToLower() == "static") { #region //string InputStream = ""; //上传的数据 //using (var streamReader = new StreamReader(httpListenerContext.Request.InputStream)) // InputStream = streamReader.ReadToEnd(); string filePath = Config.appBasePath; foreach (var sub in subUrls) filePath += "\\" + sub; if (!File.Exists(filePath)) filePath = filePath + "\\index.html"; if (!File.Exists(filePath)) { httpListenerContext.Response.ContentLength64 = 0; httpListenerContext.Response.StatusCode = 404; httpListenerContext.Response.Abort(); } else { httpListenerContext.Response.StatusCode = 200; string exeName = Path.GetExtension(filePath); httpListenerContext.Response.ContentType = HttpUtil.GetContentType(exeName); FileStream fileStream = new System.IO.FileStream(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read, FileShare.ReadWrite); int byteLength = (int)fileStream.Length; byte[] fileBytes = new byte[byteLength]; fileStream.Read(fileBytes, 0, byteLength); fileStream.Close(); fileStream.Dispose(); httpListenerContext.Response.ContentLength64 = byteLength; httpListenerContext.Response.OutputStream.Write(fileBytes, 0, byteLength); //httpListenerContext.Response.OutputStream.Close(); } #endregion return; } if (reqData == null) throw new Exception("请求数据不可为空!"); httpListenerContext.Response.StatusCode = 200; JObject joReqData = JObject.Parse(reqData); string respText; JObject result = new JObject(); string sourceSessionId; switch (subUrls[0].ToLower()) { case "static": //上面已处理 break; case "test": HttpUtil.writeToHttpContext_text(httpListenerContext.Response, "测试回应!"); break; case "api": switch (subUrls[1].ToLower()) { case "query_table": #region //if (httpListenerContext.Request.HttpMethod != "POST") // goto case "http_error"; result = getTableList(joReqData); respText = JsonConvert.SerializeObject(result); this.logEvent($"{sessionId} / 返回:{(respText.Length > 30 ?respText.Substring(0,30):respText)}"); if (!HttpUtil.writeToHttpContext_json(httpListenerContext.Response, respText)) this.logEvent($"{sessionId} / http返回时连接已断开!"); #endregion break; case "update_table"://insert+update #region //if (httpListenerContext.Request.HttpMethod != "POST") // goto case "http_error"; result = updateTableList(joReqData); respText = JsonConvert.SerializeObject(result); this.logEvent($"{sessionId} / 返回:{(respText.Length > 30 ?respText.Substring(0,30):respText)}"); if (!HttpUtil.writeToHttpContext_json(httpListenerContext.Response, respText)) this.logEvent($"{sessionId} / http返回时连接已断开!"); #endregion break; case "delete_table": #region //if (httpListenerContext.Request.HttpMethod != "POST") // goto case "http_error"; result = delTableList(joReqData); respText = JsonConvert.SerializeObject(result); this.logEvent($"{sessionId} / 返回:{(respText.Length > 30 ? respText.Substring(0, 30) : respText)}"); if (!HttpUtil.writeToHttpContext_json(httpListenerContext.Response, respText)) this.logEvent($"{sessionId} / http返回时连接已断开!"); #endregion break; case "getreport_qualified": #region //if (httpListenerContext.Request.HttpMethod != "POST") // goto case "http_error"; result = getReport_Qualified(joReqData); respText = JsonConvert.SerializeObject(result); this.logEvent($"{sessionId} / 返回:{(respText.Length > 30 ? respText.Substring(0, 30) : respText)}"); if (!HttpUtil.writeToHttpContext_json(httpListenerContext.Response, respText)) this.logEvent($"{sessionId} / http返回时连接已断开!"); #endregion break; case "getchart_qualified_rate"://图表:日月季年 合格率 #region //if (httpListenerContext.Request.HttpMethod != "POST") // goto case "http_error"; result = GetChart_Qualified_Rate(joReqData); respText = JsonConvert.SerializeObject(result); this.logEvent($"{sessionId} / 返回:{(respText.Length > 30 ? respText.Substring(0, 30) : respText)}"); if (!HttpUtil.writeToHttpContext_json(httpListenerContext.Response, respText)) this.logEvent($"{sessionId} / http返回时连接已断开!"); #endregion break; case "getchart_qualified_date"://图表:合格率分析 #region //if (httpListenerContext.Request.HttpMethod != "POST") // goto case "http_error"; result = GetChart_Qualified_Date(joReqData); respText = JsonConvert.SerializeObject(result); this.logEvent($"{sessionId} / 返回:{(respText.Length > 30 ? respText.Substring(0, 30) : respText)}"); if (!HttpUtil.writeToHttpContext_json(httpListenerContext.Response, respText)) this.logEvent($"{sessionId} / http返回时连接已断开!"); #endregion break; case "getchart_defects_date"://图表:按日期统计各缺陷数 #region //if (httpListenerContext.Request.HttpMethod != "POST") // goto case "http_error"; result = GetReport_Defects_Date(joReqData); respText = JsonConvert.SerializeObject(result); this.logEvent($"{sessionId} / 返回:{(respText.Length > 30 ? respText.Substring(0, 30) : respText)}"); if (!HttpUtil.writeToHttpContext_json(httpListenerContext.Response, respText)) this.logEvent($"{sessionId} / http返回时连接已断开!"); #endregion break; case "getchart_defects_total"://图表:缺陷总数 #region //if (httpListenerContext.Request.HttpMethod != "POST") // goto case "http_error"; result = GetReport_Defects_Total(joReqData); respText = JsonConvert.SerializeObject(result); this.logEvent($"{sessionId} / 返回:{(respText.Length > 30 ? respText.Substring(0, 30) : respText)}"); if (!HttpUtil.writeToHttpContext_json(httpListenerContext.Response, respText)) this.logEvent($"{sessionId} / http返回时连接已断开!"); #endregion break; //修复台 case "get_defect_from_sn"://读取缺陷文件名列表和JSON数组 #region //if (httpListenerContext.Request.HttpMethod != "POST") // goto case "http_error"; result = getDefectFromSN(joReqData); respText = JsonConvert.SerializeObject(result); this.logEvent($"{sessionId} / 返回:{(respText.Length > 30 ? respText.Substring(0, 30) : respText)}"); if (!HttpUtil.writeToHttpContext_json(httpListenerContext.Response, respText)) this.logEvent($"{sessionId} / http返回时连接已断开!"); #endregion break; case "get_defect_pic"://读取缺陷文件base64 #region //if (httpListenerContext.Request.HttpMethod != "POST") // goto case "http_error"; result = getDefectBmpBase64(joReqData); respText = JsonConvert.SerializeObject(result); this.logEvent($"{sessionId} / 返回BaseLen:{(respText.Length > 30 ? respText.Substring(0, 30) : respText)}"); if (!HttpUtil.writeToHttpContext_json(httpListenerContext.Response, respText)) this.logEvent($"{sessionId} / http返回时连接已断开!"); #endregion break; default: HttpUtil.writeToHttpContext_text(httpListenerContext.Response, "未知请求!"); break; } break; case "http_error": result.Add("code", -1); result.Add("msg", "不支持的请求协议!"); respText = JsonConvert.SerializeObject(result); this.logEvent( $"{sessionId} / 返回:{respText}" ); if (!HttpUtil.writeToHttpContext_json(httpListenerContext.Response, respText)) { this.logEvent( $"{sessionId} / http返回时连接已断开!" ); //this.logEvent( id + " /http连接已断开," + (string.IsNullOrWhiteSpace(callback_url) ? "无法返回结果!" : "通过回调返回" + callback_url), 1); //if (callback_url != null && callback_url != "") // HttpUtil.post(callback_url, respText); } break; case "url_error": result.Add("code", -2); result.Add("msg", "URL地址错误!"); respText = JsonConvert.SerializeObject(result); this.logEvent( $"{sessionId} / 返回:{respText}" ); if (!HttpUtil.writeToHttpContext_json(httpListenerContext.Response, respText)) { this.logEvent( $"{sessionId} / http返回时连接已断开!" ); //this.logEvent( id + " /http连接已断开," + (string.IsNullOrWhiteSpace(callback_url) ? "无法返回结果!" : "通过回调返回" + callback_url), 1); //if (callback_url != null && callback_url != "") // HttpUtil.post(callback_url, respText); } break; case "param_error": result.Add("code", -3); result.Add("msg", "参数错误!"); respText = JsonConvert.SerializeObject(result); this.logEvent( $"{sessionId} / 返回:{respText}" ); if (!HttpUtil.writeToHttpContext_json(httpListenerContext.Response, respText)) { this.logEvent( $"{sessionId} / http返回时连接已断开!" ); //this.logEvent( id + " /http连接已断开," + (string.IsNullOrWhiteSpace(callback_url) ? "无法返回结果!" : "通过回调返回" + callback_url), 1); //if (callback_url != null && callback_url != "") // HttpUtil.post(callback_url, respText); } break; default: HttpUtil.writeToHttpContext_text(httpListenerContext.Response, "未知请求!"); break; } } catch (Exception ex) { this.logEvent( $"{sessionId} / 异常:{ex.Message}\r\n{ex.StackTrace}" ); httpListenerContext.Response.StatusCode = 500; } finally { try { httpListenerContext.Response.OutputStream.Close();//客户端断开时会异常 } catch { } } } //---- private JObject getTableList(JObject req) { JObject res = new JObject(); try { string model, fields = "", domain = "", order = ""; int pageNum = 0, pageSize = 0, totalCount = 0; model = req.Value("model"); if (req.ContainsKey("fields")) fields = req.Value("fields"); if (req.ContainsKey("domain")) domain = req.Value("domain").ToString(); if (req.ContainsKey("order")) order = req.Value("order"); if (req.ContainsKey("pageNum")) pageNum = req.Value("pageNum"); if (req.ContainsKey("pageSize")) pageSize = req.Value("pageSize"); //创建表达式 var exp1 = Expressionable.Create() //.AndIF((int)cobProductList.SelectedValue > 0, it => it.ProductId == (int)cobProductList.SelectedValue) //.AndIF((int)cobStepList.SelectedValue > 0, it => it.StepId == (int)cobStepList.SelectedValue) //.AndIF(dateTimePicker1.Checked, it => it.CreateTime >= dateTimePicker1.Value) //.AndIF(dateTimePicker2.Checked, it => it.CreateTime < dateTimePicker2.Value) .ToExpression();//注意 这一句 不能少 var list = svcOrder.GetList(model, fields, domain, order, pageNum, pageSize, ref totalCount); //var list = svcOrder.GetListNav(pageNum, pageSize, ref totalCount, exp1); res.Add("code", 200); res.Add("data", JArray.FromObject(list)); res.Add("totalCount", totalCount); } catch (Exception ex) { res.Add("code", -9); res.Add("data", ex.Message); } return res; } private JObject delTableList(JObject req) { JObject res = new JObject(); try { string model = req.Value("model"); string domain = req.Value("domain").ToString(); //var idArr = req.Value("idList"); //List ids = new List(); //foreach (int id in idArr) ids.Add(id); int result = svcOrder.DeleteList(model, domain); res.Add("code", 200); res.Add("data", result); } catch (Exception ex) { res.Add("code", -9); res.Add("data", ex.Message); } return res; } private JObject updateTableList(JObject req) { JObject res = new JObject(); try { string model = req.Value("model"); var list = req.Value("datas"); string[] updateColumns = null; if (req.ContainsKey("columns")) updateColumns = req.Value("columns").ToObject>().ToArray(); int result = svcOrder.UpdateableList(model, list.ToString(), updateColumns); res.Add("code", 200); res.Add("data", result); } catch (Exception ex) { res.Add("code", -9); res.Add("data", ex.Message); } return res; } private JObject getReport_Qualified(JObject req) { JObject res = new JObject(); try { string domain = "", order = ""; int pageNum = 0, pageSize = 0, totalCount = 0; if (req.ContainsKey("domain")) domain = req.Value("domain").ToString(); if (req.ContainsKey("order")) order = req.Value("order"); if (req.ContainsKey("pageNum")) pageNum = req.Value("pageNum"); if (req.ContainsKey("pageSize")) pageSize = req.Value("pageSize"); //创建表达式 var list = svcOrder.GetReport_Qualified( domain, order, pageNum, pageSize, ref totalCount); res.Add("code", 200); res.Add("data", list); res.Add("totalCount", totalCount); } catch (Exception ex) { res.Add("code", -9); res.Add("data", ex.Message); } return res; } /// /// 获取缺陷数据 /// /// /// {文件名:[["4","3.9","-0.8","dk","0.39"],["index","X","Y","缺陷类型","缺陷的置信度"],...]} private JObject getDefectFromSN(JObject req) { JObject res = new JObject(); try { string date = req.Value("date"); string sn = req.Value("sn"); JObject data = new JObject(); string path, key; string[] files; //文件名格式:$"Size_SN{order.SN}_I{res.index}_X{res.Defects_X}_Y{res.Defects_Y}_.....json/bmp //--缺陷 path = $"{Config.Defect_Compress_SavePath}\\{date}\\{sn}\\"; if (Directory.Exists(path)) { files = Directory.GetFiles(path, $"Defect_SN{sn}_*.json", SearchOption.TopDirectoryOnly); //对文件名中的数字(index)进行大小排序 files = files.OrderBy(s => int.Parse(Path.GetFileNameWithoutExtension(s).Split('_')[2].Substring(1))).ToArray(); foreach (string file in files) { key = Path.GetFileNameWithoutExtension(file); if (File.Exists(path + key + ".bmp")) data.Add(key, JArray.Parse(File.ReadAllText(file))); } } //2024-3-5 先传输比对,再传输缺陷 ,取消 //--比对 path = $"{Config.SizeBmp_Zoom_Image_SavePath}\\{date}\\{sn}\\"; if (Directory.Exists(path)) { files = Directory.GetFiles(path, $"Size_SN{sn}_*.json", SearchOption.TopDirectoryOnly); //对文件名中的数字(index)进行大小排序 files = files.OrderBy(s => int.Parse(Path.GetFileNameWithoutExtension(s).Split('_')[2].Substring(1))).ToArray(); foreach (string file in files) { key = Path.GetFileNameWithoutExtension(file); if (File.Exists(path + key + ".bmp")) data.Add(key, JArray.Parse(File.ReadAllText(file))); } } res.Add("code", 200); res.Add("data", data); } catch (Exception ex) { res.Add("code", -9); res.Add("data", ex.Message); } return res; } private JObject getDefectBmpBase64(JObject req) { JObject res = new JObject(); try { string date = req.Value("date"); string sn = req.Value("sn"); string file_name = req.Value("file_name"); string file_path; //--缺陷 if (file_name.ToLower().IndexOf("defect") == 0) { file_path = $"{Config.Defect_Compress_SavePath}\\{date}\\{sn}\\{file_name}.bmp"; if (!File.Exists(file_path)) throw new Exception(file_name + " 缺陷文件不存在!"); res.Add("code", 200); res.Add("data", Convert.ToBase64String(File.ReadAllBytes(file_path))); } //--比对 else if (file_name.ToLower().IndexOf("size") == 0) { file_path = $"{Config.SizeBmp_Zoom_Image_SavePath}\\{date}\\{sn}\\{file_name}.bmp"; if (!File.Exists(file_path)) throw new Exception(file_name + " 比对文件不存在!"); res.Add("code", 200); res.Add("data", Convert.ToBase64String(File.ReadAllBytes(file_path))); } else throw new Exception($"文件类型错误:file_name={file_name}"); } catch (Exception ex) { res.Add("code", -9); res.Add("data", ex.Message); } return res; } private JObject GetChart_Qualified_Rate(JObject req) { JObject res = new JObject(); try { var list = svcOrder.GetReport_Qualified_Total(); res.Add("code", 200); res.Add("data", JArray.FromObject(list)); } catch (Exception ex) { res.Add("code", -9); res.Add("data", ex.Message); } return res; } private JObject GetReport_Defects_Date(JObject req) { JObject res = new JObject(); try { string domain = "", order = ""; int pageNum = 0, pageSize = 0, totalCount = 0; if (req.ContainsKey("domain")) domain = req.Value("domain").ToString(); if (req.ContainsKey("order")) order = req.Value("order"); if (req.ContainsKey("pageNum")) pageNum = req.Value("pageNum"); if (req.ContainsKey("pageSize")) pageSize = req.Value("pageSize"); //创建表达式 var list = svcOrder.GetReport_Defects_Date(domain, order, pageNum, pageSize, ref totalCount); res.Add("code", 200); res.Add("data", list); } catch (Exception ex) { res.Add("code", -9); res.Add("data", ex.Message); } return res; } private JObject GetReport_Defects_Total(JObject req) { JObject res = new JObject(); try { string domain = "", order = ""; if (req.ContainsKey("domain")) domain = req.Value("domain").ToString(); var list = svcOrder.GetReport_Defects_Total(domain); res.Add("code", 200); res.Add("data", list); } catch (Exception ex) { res.Add("code", -9); res.Add("data", ex.Message); } return res; } private JObject GetChart_Qualified_Date(JObject req) { JObject res = new JObject(); try { string domain = "", order = ""; int pageNum = 0, pageSize = 0, totalCount = 0; if (req.ContainsKey("domain")) domain = req.Value("domain").ToString(); if (req.ContainsKey("order")) order = req.Value("order"); if (req.ContainsKey("pageNum")) pageNum = req.Value("pageNum"); if (req.ContainsKey("pageSize")) pageSize = req.Value("pageSize"); //创建表达式 var list = svcOrder.GetReport_Qualified_Date( domain, order, pageNum, pageSize, ref totalCount); res.Add("code", 200); res.Add("data", list); res.Add("totalCount", totalCount); } catch (Exception ex) { res.Add("code", -9); res.Add("data", ex.Message); } return res; } } }