diff --git a/Log.cs b/Log.cs index d97dc18..9a15df4 100644 --- a/Log.cs +++ b/Log.cs @@ -2,22 +2,26 @@ { internal class Log { + private static object obj = new object(); public static void Logger(string str) { - string outdir = Environment.CurrentDirectory + @"\logs\"; - if (!Directory.Exists(outdir)) Directory.CreateDirectory(outdir); - string filename = $"{DateTime.Now.Day}_{DateTime.Now.Month}_{DateTime.Now.Year}_SendNotify"; - - foreach (FileInfo file in new DirectoryInfo(outdir).GetFiles()) + lock (obj) { - if (Convert.ToDateTime(file.LastWriteTime) < DateTime.Now.AddDays(-30)) - file.Delete(); - } + string outdir = Environment.CurrentDirectory + @"\logs\"; + if (!Directory.Exists(outdir)) Directory.CreateDirectory(outdir); + string filename = $"{DateTime.Now.Day}_{DateTime.Now.Month}_{DateTime.Now.Year}_SendNotify"; - using (FileStream aFile = new FileStream($@"{outdir}\{filename}.log", FileMode.Append, FileAccess.Write)) - using (StreamWriter sw = new StreamWriter(aFile)) - { - sw.WriteLine(DateTime.Now + " - " + str); + foreach (FileInfo file in new DirectoryInfo(outdir).GetFiles()) + { + if (Convert.ToDateTime(file.LastWriteTime) < DateTime.Now.AddDays(-30)) + file.Delete(); + } + + using (FileStream aFile = new FileStream($@"{outdir}\{filename}.log", FileMode.Append, FileAccess.Write)) + using (StreamWriter sw = new StreamWriter(aFile)) + { + sw.WriteLine(DateTime.Now + " - " + str); + } } } } diff --git a/Program.cs b/Program.cs index 2aa0382..10749d4 100644 --- a/Program.cs +++ b/Program.cs @@ -1,6 +1,7 @@ using Microsoft.Data.SqlClient; using Oracle.ManagedDataAccess.Client; using SendNotify; +using System; using System.Net; using System.Net.Http.Json; using System.Text; @@ -8,18 +9,26 @@ using System.Text; internal class Program { private static DateTime lastDate = DateTime.MinValue; - - + private static DateTime startProgramDT = DateTime.MinValue; + public static bool statusRemovingBillets = false; + private static CancellationTokenSource? removalCts; + private static object removalLock = new object(); + private static void Main(string[] args) { + startProgramDT = DateTime.Now; + var RemovingBillets = new RemovingBillets(); + while (true) { string? gotifyUrl = null; string? appToken_izhstal = null; + string? clientToken_izhstal = null; string? proxyUrl = null; string? proxyUsername = null; string? proxyPassword = null; string? checkNow = null; + int targetPriority = -1; var config = File.ReadAllLines("config.txt"); @@ -37,23 +46,52 @@ internal class Program proxyPassword = line.Substring("proxy_password=".Length); else if (line.StartsWith("check_now=")) checkNow = line.Substring("check_now=".Length); + else if (line.StartsWith("client_token_izhstal=")) + clientToken_izhstal = line.Substring("client_token_izhstal=".Length); + else if (line.StartsWith("target_priority=")) + int.TryParse(line.Substring("target_priority=".Length), out targetPriority); } - if (gotifyUrl == null || appToken_izhstal == null || proxyUrl == null || proxyUsername == null || proxyPassword == null || checkNow == null) + if (gotifyUrl == null || appToken_izhstal == null || proxyUrl == null || proxyUsername == null || + proxyPassword == null || checkNow == null || clientToken_izhstal == null || targetPriority == -1) { Console.WriteLine("Ошибка: не все параметры указаны в config.txt"); Log.Logger("Ошибка: не все параметры указаны в config.txt"); - } else { NotifyPollingAsync(gotifyUrl, appToken_izhstal, proxyUrl, proxyUsername, proxyPassword, checkNow); - } + var result = ReceiveMessagesAsync(gotifyUrl, clientToken_izhstal, proxyUrl, proxyUsername, proxyPassword, targetPriority).Result; + if (result.status && result.msg.Date > startProgramDT) + { + if (result.msg.Title == "L2_REM") + { + lock (removalLock) + { + if (result.msg.Message == "ON" && !statusRemovingBillets) + { + removalCts = new CancellationTokenSource(); + Task.Run(() => RemovingBillets.StartRemovalProcess(removalCts.Token)); + statusRemovingBillets = true; + Log.Logger("Удаление заготовок: ЗАПУЩЕНО"); + } + else if (result.msg.Message == "OFF" && statusRemovingBillets) + { + removalCts?.Cancel(); + statusRemovingBillets = false; + Log.Logger("Удаление заготовок: ОСТАНОВЛЕНО"); + } + } + } + } + } Thread.Sleep(60000); } } + + private static async void NotifyPollingAsync(string url, string token, string proxyUrl, string proxyUsername, string proxyPassword, string checkNow) { #region test msg to check @@ -213,7 +251,8 @@ internal class Program try { - HttpResponseMessage response = await client.PostAsync(url, content); + var requestUrl = $"{url}/message"; + HttpResponseMessage response = await client.PostAsync(requestUrl, content); if (response.IsSuccessStatusCode) { @@ -238,5 +277,74 @@ internal class Program } } } -} - \ No newline at end of file + private static async Task<(bool status, GotifyMessage msg)> ReceiveMessagesAsync( + string url, + string token, + string proxyUrl, + string proxyUsername, + string proxyPassword, + int targetPriority) + { + var proxy = new WebProxy(new Uri(proxyUrl)) + { + Credentials = new NetworkCredential(proxyUsername, proxyPassword, "MECHEL") + }; + + var handler = new HttpClientHandler() + { + Proxy = proxy, + UseProxy = true, + PreAuthenticate = true, + UseDefaultCredentials = false + }; + + using (var client = new HttpClient(handler)) + { + client.DefaultRequestHeaders.Add("X-Gotify-Key", token); + var requestUrl = $"{url}/message?limit=100"; + + try + { + var response = await client.GetAsync(requestUrl); + if (response.IsSuccessStatusCode) + { + var messages = await response.Content.ReadFromJsonAsync(); + + var filtered = messages.Messages? + .Where(m => m.Priority == targetPriority) + .OrderByDescending(m => m.Date) + .ToList(); + + if (filtered?.Count > 0) + { + var lastMsg = filtered.First(); + return (true, lastMsg); + } + return (false, null); + } + + Console.WriteLine($"Ошибка HTTP: {response.StatusCode}"); + return (false, null); + } + catch (Exception ex) + { + Console.WriteLine($"Ошибка: {ex.Message}"); + Log.Logger($"Ошибка получения сообщений: {ex.Message}"); + return (false, null); + } + } + } + + public class GotifyMessagesResponse + { + public required List Messages { get; set; } + } + + public class GotifyMessage + { + public string? Title { get; set; } + public string? Message { get; set; } + public int Priority { get; set; } + public DateTime Date { get; set; } + } +} \ No newline at end of file diff --git a/RemovingBillets.cs b/RemovingBillets.cs new file mode 100644 index 0000000..6ebab46 --- /dev/null +++ b/RemovingBillets.cs @@ -0,0 +1,140 @@ +using Oracle.ManagedDataAccess.Client; +using SendNotify; +using System.Data; + +public class RemovingBillets +{ + private static readonly object _syncRoot = new object(); + private static bool _isProcessActive = false; + private static DateTime _lastCheckTime = DateTime.MinValue; + + public static async Task StartRemovalProcess(CancellationToken ct) + { + lock (_syncRoot) + { + if (_isProcessActive) + { + Log.Logger("Процесс удаления уже запущен"); + return; + } + _isProcessActive = true; + } + + Log.Logger("Процесс удаления: СТАРТ"); + + try + { + using (var periodicTimer = new PeriodicTimer(TimeSpan.FromSeconds(5))) + { + while (await periodicTimer.WaitForNextTickAsync(ct)) + { + if (ct.IsCancellationRequested) + break; + + try + { + var result = await CheckAndSendAlerts(ct); + + if (!result) + { + Log.Logger("Нет заготовок для удаления - остановка"); + break; + } + + _lastCheckTime = DateTime.Now; + } + catch (Exception ex) when (ex is not OperationCanceledException) + { + Log.Logger($"Ошибка в процессе удаления: {ex.Message}"); + } + } + } + } + catch (OperationCanceledException) + { + Log.Logger("Процесс удаления: ОСТАНОВЛЕН ПО ТРЕБОВАНИЮ"); + } + finally + { + lock (_syncRoot) + { + _isProcessActive = false; + } + Program.statusRemovingBillets = false; + Log.Logger("Процесс удаления: ФИНАЛИЗАЦИЯ"); + } + } + + private static async Task CheckAndSendAlerts(CancellationToken ct) + { + const string oracleConn = "User Id=main;Password=main;Data Source=10.14.18.50:1521/izl2;"; + + try + { + using var conn = new OracleConnection(oracleConn); + await conn.OpenAsync(ct); + + var products = await GetTrackedProducts(conn, ct); + if (!products.Any()) return false; + + foreach (var product in products) + { + ct.ThrowIfCancellationRequested(); + await SendToRoll(product.ProductId, conn, ct); + Thread.Sleep(5000); + } + + return true; + } + catch + { + throw; + } + } + + private static async Task> GetTrackedProducts(OracleConnection conn, CancellationToken ct) + { + var result = new List(); + + using var cmd = conn.CreateCommand(); + cmd.CommandText = @" + SELECT + product_id, + DISCHARGING_DATI + FROM V_TRACKING_MILL + WHERE DISCHARGING_DATI > :last_check"; + + cmd.Parameters.Add("last_check", OracleDbType.Date).Value = _lastCheckTime; + + using var reader = await cmd.ExecuteReaderAsync(ct); + while (await reader.ReadAsync(ct)) + { + result.Add(new ProductInfo + { + ProductId = reader.GetInt32(0), + CreatedDate = reader.GetDateTime(1) + }); + } + + return result; + } + + private static async Task SendToRoll(int productId, OracleConnection conn, CancellationToken ct) + { + using var cmd = conn.CreateCommand(); + cmd.CommandText = "dbms_alert.signal"; + cmd.CommandType = CommandType.StoredProcedure; + + cmd.Parameters.Add(new OracleParameter("name", "UI_ALERT_IZH")); + cmd.Parameters.Add(new OracleParameter("message", $"send_finish_mill {productId}")); + + await cmd.ExecuteNonQueryAsync(ct); + Log.Logger($"Отправлен сигнал удаления для ID: {productId}"); + } +} + +public class ProductInfo +{ + public int ProductId { get; set; } + public DateTime CreatedDate { get; set; } +} \ No newline at end of file diff --git a/config.txt b/config.txt index a2496b7..7f74251 100644 --- a/config.txt +++ b/config.txt @@ -1,6 +1,8 @@ -gotify_url=https://gtf.mysrvhateapple.duckdns.org/message +gotify_url=https://gtf.mysrvhateapple.duckdns.org app_token_izhstal=A6i4cMWOMSikvsR proxy_url=http://10.14.0.14:3128 proxy_username=KhasanovAM proxy_password=Prokatka49! -check_now=no \ No newline at end of file +check_now=no +client_token_izhstal=C3r-LxgBxnxyMH. +target_priority=7 \ No newline at end of file