394 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			394 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using Project;
 | |
| using Project.Device;
 | |
| using System;
 | |
| using System.Collections.Generic;
 | |
| using System.Linq;
 | |
| using System.Management;
 | |
| using System.Net;
 | |
| using System.Net.NetworkInformation;
 | |
| using System.Text;
 | |
| using System.Threading.Tasks;
 | |
| using AR;
 | |
| 
 | |
| /// <summary>
 | |
| /// ============================================================================
 | |
| /// 장비기술 상태 모니터링 관련 클래스
 | |
| /// 이 클래스는 SQLfiletoDB 프로그램과 같이 사용하는 것을 권장합니다.
 | |
| /// 현재 실행 중인 프로그램의 하위 폴더 Status 에 입력된 상태값을 SQL 파일로 기록합니다.
 | |
| /// SQLfiletoDB는 SQL파일을 실제 DB에 기록하는 프로그램입니다.
 | |
| /// ============================================================================
 | |
| /// 작성자 : chi
 | |
| /// 작성일 : 202-06-15
 | |
| /// GIT : (none)
 | |
| /// </summary>
 | |
| public static partial class EEMStatus
 | |
| {
 | |
|     static System.Threading.ManualResetEvent mre = new System.Threading.ManualResetEvent(true);
 | |
|     static string ip = string.Empty;
 | |
|     static string mac = string.Empty;
 | |
|     static DateTime StatusChecktime = DateTime.Now;
 | |
|     static DateTime MonitorChecktime = DateTime.Now.AddYears(-1);
 | |
|     static DateTime FileCheckTime = DateTime.Now;
 | |
|     static string monitorfile = string.Empty;
 | |
|     /// <summary>
 | |
|     /// UpdateStatusSQL 명령이 동작하는 간격이며 기본 180초(=3분)로 되어 있습니다.
 | |
|     /// </summary>
 | |
|     public static int UpdateStatusInterval { get; set; } = 180;
 | |
|     public static int UpdateFileInterval { get; set; } = 3;
 | |
|     static bool queryok = false;
 | |
|     static bool UpdateRun = false;
 | |
| 
 | |
|     public static string IP
 | |
|     {
 | |
|         get
 | |
|         {
 | |
|             if (queryok == false) GetNetworkInfo();
 | |
|             return ip;
 | |
|         }
 | |
|         set { ip = value; }
 | |
|     }
 | |
|     public static string MAC
 | |
|     {
 | |
|         get
 | |
|         {
 | |
|             if (queryok == false) GetNetworkInfo();
 | |
|             return mac;
 | |
|         }
 | |
|         set
 | |
|         {
 | |
|             mac = value;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// <summary>
 | |
|     /// 현재 시스템의 IP/MAC정보를 취득합니다.
 | |
|     /// </summary>
 | |
|     static void GetNetworkInfo()
 | |
|     {
 | |
| 
 | |
|         ip = "";
 | |
|         mac = "";
 | |
|         //      string prgmName = Application.ProductName;
 | |
| 
 | |
|         var nif = NetworkInterface.GetAllNetworkInterfaces();
 | |
|         var host = Dns.GetHostEntry(Dns.GetHostName());
 | |
|         string fullname = System.Net.Dns.GetHostEntry("").HostName;
 | |
|         foreach (IPAddress r in host.AddressList)
 | |
|         {
 | |
|             string str = r.ToString();
 | |
| 
 | |
|             if (str != "" && str.Substring(0, 3) == "10.")
 | |
|             {
 | |
|                 ip = str;
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         string rtn = string.Empty;
 | |
|         ObjectQuery oq = new System.Management.ObjectQuery("SELECT * FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled='TRUE'");
 | |
|         ManagementObjectSearcher query1 = new ManagementObjectSearcher(oq);
 | |
|         foreach (ManagementObject mo in query1.Get())
 | |
|         {
 | |
|             string[] address = (string[])mo["IPAddress"];
 | |
|             if (address[0] == ip && mo["MACAddress"] != null)
 | |
|             {
 | |
|                 mac = mo["MACAddress"].ToString();
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
|         queryok = true;
 | |
|     }
 | |
| 
 | |
|     public static void UpdateStatusSQL(eSMStep status, bool _extrun = false, string remark = "")
 | |
|     {
 | |
|         var tsrun = DateTime.Now - StatusChecktime;
 | |
|         if (tsrun.TotalSeconds >= UpdateStatusInterval)
 | |
|         {
 | |
|             AddStatusSQL(status, "UPDATE", extrun: _extrun);
 | |
|             StatusChecktime = DateTime.Now;
 | |
|         }
 | |
| 
 | |
|         //내부실행모드일때에만 파일을 처리한다
 | |
|         if (_extrun == false)
 | |
|         {
 | |
|             var tsfile = DateTime.Now - FileCheckTime;
 | |
|             if (tsfile.TotalSeconds >= UpdateFileInterval)
 | |
|             {
 | |
|                 if (UpdateRun == false)
 | |
|                 {
 | |
|                     UpdateRun = true;
 | |
|                     Task.Run(() =>
 | |
|                     {
 | |
|                         UpdateFileToDB();
 | |
|                         UpdateRun = false;
 | |
|                     });
 | |
|                 }
 | |
|                 FileCheckTime = DateTime.Now;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// <summary>
 | |
|     /// 상태모니터링 프로그램의 실행파일 명
 | |
|     /// </summary>
 | |
|     static string StatusMonitorFile
 | |
|     {
 | |
|         get
 | |
|         {
 | |
|             if (string.IsNullOrEmpty(monitorfile))
 | |
|                 monitorfile = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Status", "SQLFileToDB.exe");
 | |
|             return monitorfile;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     static System.Diagnostics.Process CheckMonitor()
 | |
|     {
 | |
|         if (System.IO.File.Exists(StatusMonitorFile) == false) return null;
 | |
| 
 | |
|         var prcs = System.Diagnostics.Process.GetProcesses();
 | |
|         return prcs.Where(t => t.ProcessName.ToLower().StartsWith("sqlfiletodb")).FirstOrDefault();
 | |
|     }
 | |
| 
 | |
|     public static bool RunStatusMonitor()
 | |
|     {
 | |
|         //파일이 없으면 실행 불가
 | |
|         if (System.IO.File.Exists(StatusMonitorFile) == false) return false;
 | |
| 
 | |
|         //실행프로세스 검사
 | |
|         var prc = CheckMonitor();
 | |
|         if (prc == null)
 | |
|         {
 | |
|             try
 | |
|             {
 | |
|                 prc = new System.Diagnostics.Process();
 | |
|                 prc.StartInfo = new System.Diagnostics.ProcessStartInfo
 | |
|                 {
 | |
|                     Arguments = string.Empty,
 | |
|                     FileName = StatusMonitorFile,
 | |
|                 };
 | |
|                 prc.Start();
 | |
|             }
 | |
|             catch
 | |
|             {
 | |
|                 return false;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     /// <summary>
 | |
|     /// 작업수량을 입력합니다
 | |
|     /// </summary>
 | |
|     /// <param name="cnt"></param>
 | |
|     /// <returns></returns>
 | |
|     public static string AddStatusCount(int cnt, string remark = "")
 | |
|     {
 | |
|         if (remark.isEmpty()) remark = $"Count Set : {cnt}";
 | |
|         return AddStatusSQL(PUB.sm.Step, remark, count: cnt);
 | |
|     }
 | |
|     /// <summary>
 | |
|     /// 상태메세지를 status 폴더에 기록합니다.
 | |
|     /// </summary>
 | |
|     /// <param name="status">상태머신의 상태값</param>
 | |
|     /// <param name="remark">비고</param>
 | |
|     /// <param name="wdate">기록일시</param>
 | |
|     /// <returns>오류발생시 오류메세지가 반환 됩니다</returns>
 | |
|     public static string AddStatusSQL(eSMStep status, string remark = "", DateTime? wdate = null, bool extrun = false, int? count = null)
 | |
|     {
 | |
|         if (queryok == false || MAC.isEmpty()) GetNetworkInfo();
 | |
|         if (status == eSMStep.CLOSEWAIT || status == eSMStep.CLOSED) return string.Empty;
 | |
| 
 | |
|         if (extrun)
 | |
|         {
 | |
|             //상태모니터링 프로그램을 실행합니다.
 | |
|             var tsMon = DateTime.Now - MonitorChecktime;
 | |
|             if (tsMon.TotalMinutes > 5) RunStatusMonitor();
 | |
|         }
 | |
| 
 | |
|         try
 | |
|         {
 | |
|             var state = 0;
 | |
|             string cntstr = "null";
 | |
|             if (count != null) cntstr = count.ToString();
 | |
|             var alarmid = string.Empty;
 | |
|             var alarmmsg = string.Empty;
 | |
|             if (string.IsNullOrEmpty(remark)) remark = $"STS:{status}";
 | |
| 
 | |
|             if (status == eSMStep.RUN) state = 1;
 | |
|             else if (status == eSMStep.ERROR || status == eSMStep.EMERGENCY)
 | |
|             {
 | |
|                 state = 2;
 | |
|                 alarmid = PUB.Result.ResultErrorCode.ToString();
 | |
|                 alarmmsg = PUB.Result.ResultMessage;
 | |
|             }
 | |
|             else if (status == eSMStep.PAUSE)   //일시중지도 오류코드가 포함된다, 
 | |
|             {
 | |
|                 if (PUB.Result.ResultErrorCode == Project.eECode.USER_STEP || 
 | |
|                     PUB.Result.ResultErrorCode == Project.eECode.USER_STOP || 
 | |
|                     PUB.Result.ResultErrorCode.ToString().StartsWith("MESSAGE"))
 | |
|                 {
 | |
|                     //사용자에의해 멈추는 것은 오류코드를 넣지 않는다.
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     alarmid = PUB.Result.ResultErrorCode.ToString();
 | |
|                     alarmmsg = PUB.Result.ResultMessage;
 | |
|                 }
 | |
|             }
 | |
|             else if (status == eSMStep.INIT) state = 3; //시작
 | |
|             else if (status == eSMStep.CLOSING) state = 4;    //종료
 | |
| 
 | |
|             //length  check
 | |
|             if (alarmid.Length > 10) alarmid = alarmid.Substring(0, 10);
 | |
|             if (remark.Length > 99) remark = remark.Substring(0, 99);
 | |
|             if (alarmmsg.Length > 250) alarmmsg = alarmmsg.Substring(0, 50);
 | |
| 
 | |
|             var mcid = AR.SETTING.Data.MCID;// Project.PUB.setting.MCID;//.Data.MCID;
 | |
|             //var mcid = Project.PUB.setting.MCID;//.Data.MCID;
 | |
|             var path = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Status");
 | |
|             var file = System.IO.Path.Combine(path, $"{DateTime.Now.ToString("HHmmssfff")}_{status}.sql");
 | |
|             var sql = "insert into MCMonitor_Rawdata(Model,status,remark,ip,mac,time,alarmid,alarmmsg,count,version) " +
 | |
|                 " values('{0}','{1}','{2}','{3}','{4}','{5}','{6}','{7}',{8},'{9}')";
 | |
| 
 | |
|             var timestr = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
 | |
|             if (wdate != null) timestr = ((DateTime)wdate).ToString("yyyy-MM-dd HH:mm:ss");
 | |
|             var VersionNumber = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
 | |
|             sql = string.Format(sql, mcid, state, remark.Replace("'", "''"), IP, MAC, timestr, alarmid, alarmmsg, cntstr, VersionNumber);
 | |
|             System.IO.File.WriteAllText(file, sql, System.Text.Encoding.Default);
 | |
| 
 | |
|             ////만들어진지 3분이 지난 파일은 삭제한다.
 | |
|             //var di = new System.IO.DirectoryInfo(path);
 | |
|             //var fi = di.GetFiles("*.sql", System.IO.SearchOption.TopDirectoryOnly).Where(t => t.LastWriteTime < DateTime.Now.AddMinutes(-3)).FirstOrDefault();
 | |
|             //if (fi != null) fi.Delete();
 | |
|             if (state == 4) UpdateFileToDB();
 | |
|             return string.Empty;
 | |
|         }
 | |
|         catch (Exception ex)
 | |
|         {
 | |
|             return ex.Message;
 | |
|         }
 | |
|     }
 | |
| 
 | |
| 
 | |
| 
 | |
|     static void UpdateFileToDB()
 | |
|     {
 | |
|         if (mre.WaitOne(1000) == false) return;
 | |
|         mre.Reset();
 | |
|         var cs = "Data Source=10.131.15.18;Initial Catalog=EE;Persist Security Info=True;User ID=eeuser;Password=Amkor123!";
 | |
|         var path = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Status");
 | |
|         var di = new System.IO.DirectoryInfo(path);
 | |
|         if (di.Exists == false) return;
 | |
|         var file = di.GetFiles("*.sql", System.IO.SearchOption.TopDirectoryOnly)
 | |
|             .Where(t => t.LastWriteTime < DateTime.Now.AddSeconds(-3))
 | |
|             .OrderByDescending(t => t.LastWriteTime).FirstOrDefault();
 | |
| 
 | |
|         if (file == null)
 | |
|         {
 | |
|             mre.Set();
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         //파일을 찾아야한다
 | |
|         // PUB.log.Add($">> {file.FullName}");
 | |
| 
 | |
| 
 | |
| 
 | |
|         try
 | |
|         {
 | |
|             var sql = System.IO.File.ReadAllText(file.FullName, System.Text.Encoding.Default);
 | |
|             if (string.IsNullOrEmpty(sql))
 | |
|             {
 | |
|                 //비어잇다면
 | |
|                 var errpath = System.IO.Path.Combine(di.FullName, "Error");
 | |
|                 var errfile = System.IO.Path.Combine(errpath, file.Name);
 | |
|                 if (System.IO.Directory.Exists(errpath) == false) System.IO.Directory.CreateDirectory(errpath);
 | |
|                 System.IO.File.Move(file.FullName, errfile);// file.MoveTo(errfile);
 | |
|                 // ecnt += 1;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 // var csstr = PUB.setting.ConnectionString;
 | |
|                 // if (string.IsNullOrEmpty(csstr)) csstr = "Data Source=10.131.15.18;Initial Catalog=EE;Persist Security Info=True;User ID=eeuser;Password=Amkor123!";
 | |
|                 var cn = new System.Data.SqlClient.SqlConnection(cs);
 | |
|                 var cmd = new System.Data.SqlClient.SqlCommand(sql, cn);
 | |
|                 cn.Open();
 | |
|                 var cnt = cmd.ExecuteNonQuery();
 | |
|                 //if (cnt == 0) PUB.log.Add($"Result Empty : {sql}");
 | |
|                 cn.Close();
 | |
|                 cnt += 1;
 | |
| 
 | |
|                 var errpath = System.IO.Path.Combine(di.FullName, "Complete");
 | |
|                 var errfile = System.IO.Path.Combine(errpath, file.Name);
 | |
|                 if (System.IO.Directory.Exists(errpath) == false) System.IO.Directory.CreateDirectory(errpath);
 | |
|                 //file.MoveTo(errfile);
 | |
|                 System.IO.File.Move(file.FullName, errfile);
 | |
|             }
 | |
| 
 | |
|         }
 | |
|         catch (Exception ex)
 | |
|         {
 | |
|             if(ex.Message.Contains("deadlocked") == false)
 | |
|             {
 | |
|                 var errpath = System.IO.Path.Combine(di.FullName, "Error");
 | |
|                 var errfile = System.IO.Path.Combine(errpath, file.Name);
 | |
|                 if (System.IO.Directory.Exists(errpath) == false) System.IO.Directory.CreateDirectory(errpath);
 | |
|                 try
 | |
|                 {
 | |
|                     //file.MoveTo(errfile);
 | |
|                     System.IO.File.Move(file.FullName, errfile);
 | |
| 
 | |
|                     //오류내용도  저장한다..
 | |
|                     var errfilename = errfile + "_error.txt";
 | |
|                     System.IO.File.WriteAllText(errfilename, ex.Message, System.Text.Encoding.Default);
 | |
|                 }
 | |
|                 catch (Exception ex2)
 | |
|                 {
 | |
| 
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 Console.WriteLine("Dead lock error ignored");
 | |
|             }
 | |
| 
 | |
|             //ecnt += 1;
 | |
|         }
 | |
| 
 | |
|         //try
 | |
|         //{
 | |
|         //    //생성된지 10일이 넘은 자료는 삭제한다.
 | |
|         //    //시간소비를 피해서 1개의 파일만 작업한다
 | |
|         //    //var sqlfiles = di.GetFiles("*.sql", System.IO.SearchOption.AllDirectories);
 | |
|         //    //총3번의 데이터를 처리한다
 | |
|         //    //var files = sqlfiles.Where(t => t.LastWriteTime < DateTime.Now.AddDays(-10)).Select(t => t.FullName);
 | |
|         //    //int i = 0;
 | |
|         //    //var dellist = files.TakeWhile(t => i++ < 3);
 | |
|         //    //foreach (var delfile in dellist)
 | |
|         //        //System.IO.File.Delete(delfile);
 | |
|         //}
 | |
|         //catch
 | |
|         //{
 | |
| 
 | |
|         //}
 | |
|         mre.Set();
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
| =================================================
 | |
| 변경내역
 | |
| =================================================
 | |
| 230619  chi UpdateFileToDB 에서 폴더가 없다면 return 하도록 함
 | |
| 230615  chi UpdateFiletoDB의 ManualResetEvent적용
 | |
|             Version 항목 추가
 | |
| 230612  chi 프로그램 시작/종료 alarmid항목 추가
 | |
|             완료된 파일 10일간 보존하도록 함
 | |
| 230522  chi extrun 모드 추가(agv용 - SQL파일을 외부 프로그램에서 처리하도록 함)
 | |
| 230617  chi 파일쓰기함수를 Task 로 처리
 | |
|             3분지난데이터 삭제기능 제거
 | |
| 230516  chi initial commit
 | |
| */
 | 
