using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading; using Comal.Classes; using H.Formatters; using H.Pipes; using InABox.Clients; using InABox.Configuration; using InABox.Core; using InABox.Logikal; using Newtonsoft.Json; using Exception = System.Exception; using Process = System.Diagnostics.Process; namespace PRSDesktop; public class LogikalClient : IDisposable { private readonly PipeClient _client; private ConcurrentDictionary Events = new(); private ConcurrentDictionary Responses = new(); private const int DefaultRequestTimeout = 5 * 60 * 1000; // 5 minutes public LogikalSettings Settings { get; set; } public bool Ready { get; private set; } = false; private LogikalErrorResponse NOTLOGGEDIN = new LogikalErrorResponse() { Status = LogikalStatus.NotLoggedIn, Message = "Not Logged In" }; public LogikalClient() { Settings = new GlobalConfiguration().Load(); var _basedirectory = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) ?? ""; var _logikalapp = System.IO.Path.Combine(_basedirectory, "PRSLogikal", "PRSLogikal.exe"); var _info = new ProcessStartInfo(_logikalapp); _info.WindowStyle = ProcessWindowStyle.Minimized; Process.Start(_info); _client = new PipeClient("$logikal", formatter: new NewtonsoftJsonFormatter()); _client.Connected += Client_Connected; _client.Disconnected += Client_Disconnected; _client.MessageReceived += Client_MessageReceived; _client.ExceptionOccurred += Client_ExceptionOccurred; _client.ConnectAsync(); } public void Dispose() { _client.DisposeAsync().AsTask().Wait(); } private void Client_Connected(object? sender, H.Pipes.Args.ConnectionEventArgs e) { Logger.Send(LogType.Information, "", $"Connected to Pipe: {e.Connection.PipeName}"); //Disconnected = false; // Here we will register a Licence "Hit" for the Logikal interface } private void Client_Disconnected(object? sender, H.Pipes.Args.ConnectionEventArgs e) { Logger.Send(LogType.Information, "", $"Disconnected from Pipe: {e.Connection.PipeName}"); foreach (var ev in Events) { Responses.TryAdd(ev.Key, LogikalMessage.Error("Disconnected")); ev.Value.Set(); } //Disconnected = true; } private void Client_ExceptionOccurred(object? sender, H.Pipes.Args.ExceptionEventArgs e) { Logger.Send(LogType.Error, "", $"Exception occured: {e.Exception.Message}"); } private static Dictionary _methods = new Dictionary() { { LogikalMethod.Connect, typeof(LogikalConnectResponse) }, { LogikalMethod.Login, typeof(LogikalLoginResponse) }, { LogikalMethod.Logout, typeof(LogikalLogoutResponse) }, { LogikalMethod.Disconnect, typeof(LogikalDisconnectResponse) }, { LogikalMethod.ProjectCentres, typeof(LogikalProjectCentresResponse) }, { LogikalMethod.Projects, typeof(LogikalProjectsResponse) }, { LogikalMethod.Phases, typeof(LogikalPhasesResponse) }, { LogikalMethod.Elevations, typeof(LogikalElevationsResponse) }, { LogikalMethod.BOM, typeof(LogikalBOMResponse) }, { LogikalMethod.Error, typeof(LogikalErrorResponse) }, }; private LogikalResponse FromMessage(LogikalMessage message) { try { LogikalResponse _result = null; if (_methods.TryGetValue(message.Method, out var _type)) { _result = JsonConvert.DeserializeObject(message.Payload, _type) as LogikalResponse; if (_result != null) return _result; return new LogikalErrorResponse() { Status = LogikalStatus.Error, Message = $"Deserialize Failure: {message.Method}: {message.Payload}" }; } else return new LogikalErrorResponse() { Status = LogikalStatus.Error, Message = $"Invalid Message Method: {message.Method}: {message.Payload}" }; } catch (Exception e) { return new LogikalErrorResponse() { Status = LogikalStatus.Error, Message = $"Exception Deserializing Response: {e.Message}\n{e.StackTrace}" }; } } public LogikalResponse Send(LogikalRequest request, int timeout = DefaultRequestTimeout) { var message = new LogikalMessage() { ID = Guid.NewGuid(), Method = request.Method(), Payload = Serialization.Serialize(request), }; var ev = Queue(message.ID); _client.WriteAsync(message); var result = GetResult(message.ID, ev, timeout); return FromMessage(result); } public ManualResetEventSlim Queue(Guid id) { var ev = new ManualResetEventSlim(); Events[id] = ev; return ev; } public LogikalMessage GetResult(Guid id, ManualResetEventSlim ev, int timeout) { if (Responses.TryRemove(id, out var result)) { Events.TryRemove(id, out ev); return result; } try { if (!ev.Wait(timeout)) { return LogikalMessage.Error("Timeout"); } } catch (Exception e) { Console.WriteLine(e); throw; } Responses.TryRemove(id, out result); Events.TryRemove(id, out ev); return result ?? LogikalMessage.Error("Unknown"); } private void Client_MessageReceived(object? sender, H.Pipes.Args.ConnectionMessageEventArgs e) { if (Events.TryGetValue(e.Message.ID, out var ev)) { Responses[e.Message.ID] = e.Message; ev.Set(); } } ~LogikalClient() { Dispose(); } public LogikalResponse Connect() { Client.Save(new LogikalUsage(),""); Ready = false; var _request = new LogikalConnectRequest() { Path = Settings.Path }; var _result = Send(_request); return _result; } public LogikalResponse Disconnect() { Ready = false; var _request = new LogikalDisconnectRequest(); var _result = Send(_request); return _result; } public LogikalResponse Login() { Ready = false; var _request = new LogikalLoginRequest(); var _result = Send(_request) .Success(r => { Ready = true; }); return _result; } public LogikalResponse Logout() { Ready = false; var _request = new LogikalLogoutRequest(); var _result = Send(_request); return _result; } public LogikalResponse GetProjectCentres() { if (!Ready) return NOTLOGGEDIN; var _request = new LogikalProjectCentresRequest(); var _result = Send(_request); return _result; } public LogikalResponse GetProjects(string jobnumber) { if (!Ready) return NOTLOGGEDIN; var _request = new LogikalProjectsRequest(jobnumber); var _result = Send(_request); return _result; } public LogikalResponse GetProject(Guid projectid) { if (!Ready) return NOTLOGGEDIN; var _request = new LogikalProjectRequest(projectid); var _result = Send(_request); return _result; } public LogikalResponse GetPhases(Guid projectid) { if (!Ready) return NOTLOGGEDIN; var _request = new LogikalPhasesRequest(projectid); var _result = Send(_request); return _result; } public LogikalResponse GetElevations(Guid projectid, string phase) { if (!Ready) return NOTLOGGEDIN; var _request = new LogikalElevationsRequest(projectid, phase); var _result = Send(_request); return _result; } public LogikalResponse GetBillOfMaterials(Guid projectid, Guid[] elevationids, bool excel) { if (!Ready) return NOTLOGGEDIN; var _request = new LogikalBOMRequest( projectid, elevationids, Settings.FinishSQL, Settings.BillOfMaterialsProfileSQL, Settings.BillOfMaterialsComponentSQL, Settings.BillOfMaterialsGlassSQL, Settings.LabourSQL, excel); var _result = Send(_request); return _result; } public LogikalResponse GetElevation(Guid projectid, Guid elevationid, bool excel) { if (!Ready) return NOTLOGGEDIN; var _request = new LogikalElevationRequest( projectid, elevationid, Settings.FinishSQL, Settings.ElevationProfileSQL, Settings.ElevationComponentSQL, Settings.ElevationGlassSQL, Settings.LabourSQL, excel); var _result = Send(_request); return _result; } }