git_bsmd/SendNSWMessageService/NSWSendService.cs
Daniel Schick 04907e2104 SFTPSession entfernt
stattdessen wird ein open command gesendet. Gleichzeitig wird die Ausgabe nicht mehr
zum Ende gelesen sondern per Events abgefragt. Die Hoffnung ist hier, dass der Prozess nicht
mehr auf dem ReadToEnd() blockiert, wobei das nie bestätigt werden konnte.
2023-07-08 12:20:40 +02:00

340 lines
17 KiB
C#

using bsmd.database;
using bsmd.status;
using log4net;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.ServiceProcess;
using System.Timers;
namespace SendNSWMessageService
{
public partial class NSWSendService : ServiceBase
{
private Timer _timer;
private Timer _filesTimer;
private readonly object _timerlock = new object();
private bool processRunning = false;
private readonly ILog _log = LogManager.GetLogger(typeof(NSWSendService));
public NSWSendService()
{
Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);
InitializeComponent();
System.Net.ServicePointManager.ServerCertificateValidationCallback += (object _, System.Security.Cryptography.X509Certificates.X509Certificate ____,
System.Security.Cryptography.X509Certificates.X509Chain __,
System.Net.Security.SslPolicyErrors ___) =>
{
return true; // **** Immer OK weil wir nur mit einem dedizierten Endpoint reden..
};
}
public void Commandline()
{
// Dieser Modus dient allein dazu, eine separate Instanz "nebenher" laufen zu lassen, ohne
// sie als Service zu installieren. Dies ist sinnvoll um für spezielle HIS Einstellungen Tests zu machen
// ohne den laufenden Betrieb zu stören (hoffentlich!)
this.Init(); // setup timer
this.DoOnce();
while (true)
System.Threading.Thread.Sleep(1000); // sleep until someone kills me :)
}
protected override void OnStart(string[] args)
{
this.EventLog.Source = this.ServiceName;
this.EventLog.Log = "Application";
this.Init();
System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location);
string version = fvi.FileVersion;
this.EventLog.WriteEntry("NSW Send Service started", EventLogEntryType.Information);
_log.InfoFormat("NSW Send Service started. v.{0}", version);
this.DoOnce();
}
private void Init()
{
this._timer = new Timer();
this._timer.Interval = Properties.Settings.Default.SleepSeconds * 1000;
this._timer.Elapsed += _timer_Elapsed;
this._timer.Enabled = true;
this._filesTimer = new Timer();
this._filesTimer.Interval = Properties.Settings.Default.PurgeFilesTimerIntervalHours * 60 * 60 * 1000; // hours to millisecs
this._filesTimer.Elapsed += _filesTimer_Elapsed;
this._filesTimer.Enabled = true;
}
private void _filesTimer_Elapsed(object sender, ElapsedEventArgs e)
{
bsmd.dbh.MessageController.PurgeOldFiles(Properties.Settings.Default.TempFilesMaxAgeDays);
bsmd.hisnord.transmitter.PurgeOldFiles(Properties.Settings.Default.TempFilesMaxAgeDays);
}
public void DoOnce()
{
this._filesTimer_Elapsed(null, null);
this._timer_Elapsed(null, null);
}
private void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
lock (this._timerlock)
{
if (processRunning) return;
else this.processRunning = true;
}
if (DBManager.Instance.Connect(Properties.Settings.Default.ConnectionString))
{
// Datenbank auf zu sendende Objekte überprüfen und laden
List<MessageCore> coresMarkedForSending = DBManager.Instance.GetMessageCoresByStatus(MessageCore.BSMDStatus.TOSEND);
foreach (MessageCore core in coresMarkedForSending)
{
List<Message> messages = DBManager.Instance.GetMessagesForCore(core, DBManager.MessageLoad.ALL);
List<Message> toSendMessageList = new List<Message>();
bool coreSendSucceeded = true;
bool didSendSomething = false;
// Wenn es noch keine Visit-ID gibt können keine Meldeklassen versendet werden. Die Visit/Transit Meldung wird daher dann
// "leer" versendet
if ((core.IsTransit && core.TransitId.IsNullOrEmpty()) || (!core.IsTransit && core.VisitId.IsNullOrEmpty()))
{
foreach (Message message in messages)
{
if (((message.MessageNotificationClass == Message.NotificationClass.VISIT) && (!core.IsTransit)) ||
((message.MessageNotificationClass == Message.NotificationClass.TRANSIT) && (core.IsTransit)))
{
if ((message.InternalStatus == Message.BSMDStatus.UNDEFINED) ||
(message.InternalStatus == Message.BSMDStatus.PREPARE) ||
(message.InternalStatus == Message.BSMDStatus.TOSEND))
{
_log.Debug("Visit/Transit not found, sending VISIT/TRANSIT message");
if (message.HIS == Message.NSWProvider.UNDEFINED)
message.HIS = core.InitialHIS;
if (core.DefaultReportingPartyId.HasValue)
{
message.ReportingPartyId = core.DefaultReportingPartyId; // Referenz umbiegen
if (DBManager.Instance.GetReportingPartyDict().ContainsKey(core.DefaultReportingPartyId.Value)) // geladenes Objekt ersetzen
message.ReportingParty = DBManager.Instance.GetReportingPartyDict()[core.DefaultReportingPartyId.Value];
}
toSendMessageList.Add(message);
}
}
}
}
else
{
// VISIT / TRANSIT Id vorhanden, Daten können übertragen werden
foreach (Message message in messages)
{
// Update 5.10.17: Alles was nicht explizit auf "TOSEND" steht wird nicht verschickt!
if (message.InternalStatus != Message.BSMDStatus.TOSEND) continue;
// "Virtuelle" Meldeklassen (bisher: DK) werden hier nicht versendet!
if (message.MessageNotificationClass == Message.NotificationClass.STO) continue;
// muss zum Go Live wieder einkommentiert werden, da CREWD und PASD vorerst nicht versendet werden
// XXX : TODO herausnehmen
if((message.MessageNotificationClass == Message.NotificationClass.CREWD) ||
(message.MessageNotificationClass == Message.NotificationClass.PASD))
continue;
if ((message.MessageNotificationClass == Message.NotificationClass.VISIT) ||
(message.MessageNotificationClass == Message.NotificationClass.TRANSIT))
continue;
if (!XtraSendLogic.ShouldSendMessage(message))
{
message.InternalStatus = Message.BSMDStatus.SUSPENDED;
message.ChangedBy = ""; // zurücksetzen für Overview
DBManager.Instance.Save(message);
continue;
}
if (core.DefaultReportingPartyId.HasValue)
{
message.ReportingPartyId = core.DefaultReportingPartyId; // Referenz umbiegen
if (DBManager.Instance.GetReportingPartyDict().ContainsKey(core.DefaultReportingPartyId.Value)) // geladenes Objekt ersetzen
message.ReportingParty = DBManager.Instance.GetReportingPartyDict()[core.DefaultReportingPartyId.Value];
}
toSendMessageList.Add(message);
}
}
// nach NotificationClass sortieren
// das ist wichtig für 861,881,882: NOA_NOD vor ATA vor ATD, falls alles gleichzeitig gesendet wird.
toSendMessageList.Sort();
foreach (Message message in toSendMessageList)
{
try
{
bool sendSucceeded = false;
if(message.HIS == Message.NSWProvider.UNDEFINED)
message.HIS = core.InitialHIS;
_log.InfoFormat("Sending {0} message {1} to {2}", message.MessageNotificationClass.ToString(), message.Id, message.HIS.ToString());
// switch über passendes HIS / Schnittstelle
switch (message.HIS)
{
case Message.NSWProvider.DBH:
case Message.NSWProvider.DBH_MAERSK:
sendSucceeded = bsmd.dbh.MessageController.SendMessage(core, message);
if (!sendSucceeded)
message.InternalStatus = Message.BSMDStatus.SEND_FAILED;
else
didSendSomething = true;
break;
case Message.NSWProvider.DAKOSY:
sendSucceeded = bsmd.dakosy.Request.Send(message);
if (!sendSucceeded) message.InternalStatus = Message.BSMDStatus.SEND_FAILED;
else didSendSomething = true;
break;
case Message.NSWProvider.DUDR:
bool? sendResult = bsmd.hisnord.Request.CreateSendFile(core, message);
if (sendResult.HasValue)
{
didSendSomething = true;
sendSucceeded = sendResult.Value;
}
break;
default:
_log.WarnFormat("Initial HIS not specified for message {0}", message.Id);
break;
}
coreSendSucceeded &= sendSucceeded;
if(sendSucceeded)
{
message.ChangedBy = ""; // Leeren nach RS mit CH: Sie möchte das Feld als Indikator "zu versenden" verwenden (ich war dagegen ;-)
message.InternalStatus = Message.BSMDStatus.SENT;
if(message.ReportingPartyId.HasValue && DBManager.Instance.GetReportingPartyDict().ContainsKey(message.ReportingPartyId.Value))
{
bsmd.database.ReportingParty rp = DBManager.Instance.GetReportingPartyDict()[message.ReportingPartyId.Value];
message.SentBy = rp.Logon;
}
}
else
{
message.InternalStatus = Message.BSMDStatus.SEND_FAILED;
}
message.StatusInfo = "";
message.SentAt = DateTime.Now;
DBManager.Instance.DeleteSystemErrors(message);
DBManager.Instance.Save(message);
}
catch (Exception ex)
{
_log.ErrorFormat("SENDING message {0}: {1}", message.Id.ToString(), ex.Message);
}
}
if(!didSendSomething) // bisher nichts passiert, aber auf "TO_SEND", ist das ein Storno?
{
if (core.Cancelled ?? false)
{
switch(core.InitialHIS)
{
case Message.NSWProvider.DUDR:
coreSendSucceeded = bsmd.hisnord.Request.CreateSendFile(core, null) ?? false;
didSendSomething = true;
break;
case Message.NSWProvider.DBH:
case Message.NSWProvider.DBH_MAERSK:
coreSendSucceeded = bsmd.dbh.MessageController.SendCancelCore(core);
break;
default:
_log.WarnFormat("Cancelling for HIS {0} is not supported", core.InitialHIS);
break;
}
}
}
if (didSendSomething)
{
// falls nur eine Nachricht gescheitert ist geht der Core auf SEND_FAILED, sonst FAILURE
core.BSMDStatusInternal = coreSendSucceeded ? MessageCore.BSMDStatus.SENT : MessageCore.BSMDStatus.FAILURE;
}
else
{
core.BSMDStatusInternal = MessageCore.BSMDStatus.PREPARE; // aus irgendwelchen Gründen wurde nichts verschickt -> zurück auf PREPARE
}
DBManager.Instance.Save(core);
}
// external processing for HIS-Nord
if (bsmd.hisnord.transmitter.Transmit())
{
bsmd.hisnord.Request.ReadResponseFiles();
bsmd.hisnord.Response.ReadAnswers();
}
// external processing for dbh
bsmd.dbh.MessageController.SendAndReceive();
foreach (MessageCore core in DBManager.Instance.GetMessageCoresWithNSWStatusFlag())
{
core.QueryNSWStatus = false; // reset flag
Status aStatus = new Status(core);
aStatus.PerformQuery();
}
DBManager.Instance.Disconnect();
}
else
{
// _log.Fatal("database connection failure, stopping service");
this.EventLog.WriteEntry("NSW Send Service DB connection failure", EventLogEntryType.Warning);
// this.Stop();
}
lock (this._timerlock)
{
this.processRunning = false;
}
}
protected override void OnPause()
{
this._timer.Stop();
this._filesTimer.Stop();
}
protected override void OnContinue()
{
this._timer.Start();
this._filesTimer.Start();
}
protected override void OnStop()
{
this._timer.Enabled = false;
this._filesTimer.Enabled = false;
this.EventLog.WriteEntry("NSW Send Service stopped.", EventLogEntryType.Information);
_log.Info("NSW Send Service stopped");
}
}
}