diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore index ed6d1d2..389590d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,12 @@ -# ---> VisualStudio ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. ## -## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +Source/LogDashboard/_Deployment +Source/LogDashboard/Nuget/cache + +Thumbs.db # User-specific files *.rsuser @@ -30,6 +34,7 @@ x86/ bld/ [Bb]in/ [Oo]bj/ +[Oo]ut/ [Ll]og/ [Ll]ogs/ @@ -83,8 +88,6 @@ StyleCopReport.xml *.pgc *.pgd *.rsp -# but not Directory.Build.rsp, as it configures directory-level build defaults -!Directory.Build.rsp *.sbr *.tlb *.tli @@ -93,7 +96,6 @@ StyleCopReport.xml *.tmp_proj *_wpftmp.csproj *.log -*.tlog *.vspscc *.vssscc .builds @@ -196,7 +198,7 @@ publish/ PublishScripts/ # NuGet Packages -*.nupkg +#*.nupkg # NuGet Symbol Packages *.snupkg # The packages folder can be ignored because of Package Restore @@ -297,17 +299,6 @@ node_modules/ # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) *.vbw -# Visual Studio 6 auto-generated project file (contains which files were open etc.) -*.vbp - -# Visual Studio 6 workspace and project file (working project files containing files to include in project) -*.dsw -*.dsp - -# Visual Studio 6 technical files -*.ncb -*.aps - # Visual Studio LightSwitch build output **/*.HTMLClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts @@ -364,9 +355,6 @@ ASALocalRun/ # Local History for Visual Studio .localhistory/ -# Visual Studio History (VSHistory) files -.vshistory/ - # BeatPulse healthcheck temp database healthchecksdb @@ -377,26 +365,4 @@ MigrationBackup/ .ionide/ # Fody - auto-generated XML schema -FodyWeavers.xsd - -# VS Code files for those working on multiple tools -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json -*.code-workspace - -# Local History for Visual Studio Code -.history/ - -# Windows Installer files from build outputs -*.cab -*.msi -*.msix -*.msm -*.msp - -# JetBrains Rider -*.sln.iml - +FodyWeavers.xsd \ No newline at end of file diff --git a/Source/LogDashboard/LogDashboard.UI/App.config b/Source/LogDashboard/LogDashboard.UI/App.config new file mode 100644 index 0000000..2a72a92 --- /dev/null +++ b/Source/LogDashboard/LogDashboard.UI/App.config @@ -0,0 +1,110 @@ + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + 600 + + + 600 + + + 800 + + + 800 + + + 100 + + + 100 + + + 100 + + + 100 + + + + + + + \ No newline at end of file diff --git a/Source/LogDashboard/LogDashboard.UI/App.xaml b/Source/LogDashboard/LogDashboard.UI/App.xaml new file mode 100644 index 0000000..36d2651 --- /dev/null +++ b/Source/LogDashboard/LogDashboard.UI/App.xaml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + diff --git a/Source/LogDashboard/LogDashboard.UI/App.xaml.cs b/Source/LogDashboard/LogDashboard.UI/App.xaml.cs new file mode 100644 index 0000000..54b4d93 --- /dev/null +++ b/Source/LogDashboard/LogDashboard.UI/App.xaml.cs @@ -0,0 +1,221 @@ +//******************************************************************************// +// App.xaml.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using Microsoft.Win32; +using NLog; +using Raytheon.LogDashboard.Helpers; +using System; +using System.Diagnostics; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using System.Windows; +using System.IO; +using Raytheon.LogDashboard.View; +using GalaSoft.MvvmLight.Messaging; +using System.Reflection; + +namespace LogDashboard +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + private static readonly Logger logger = LogManager.GetCurrentClassLogger(); + + public static bool IsManualStartup { get; private set; } = false; + public ResourceDictionary ThemeDictionary => Resources.MergedDictionaries[1]; + + public void ChangeTheme(Uri uri) + { + ThemeDictionary.MergedDictionaries[1] = new ResourceDictionary { Source = uri }; + } + + static Mutex mutex = new Mutex(true, "{8F6F0AC4-B9A1-45fd-A8CF-72F04E6BDE8F}"); + + [STAThread] + protected override void OnStartup(StartupEventArgs e) + { + AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; + Current.DispatcherUnhandledException += Current_DispatcherUnhandledException; + + if(e.Args.Any(x => (x.EndsWith(".txt") || x.EndsWith(".log")) && File.Exists(x))) + { + IsManualStartup = true; + + try + { + if(!mutex.WaitOne(TimeSpan.Zero, true)) + { + Process proc = Process.GetCurrentProcess(); + string processName = proc.ProcessName.Replace(".vshost", ""); + var runningProcess = Process.GetProcesses() + .FirstOrDefault(x => (x.ProcessName == processName || x.ProcessName == proc.ProcessName || x.ProcessName == proc.ProcessName + ".vshost") && x.Id != proc.Id); + + if(runningProcess == null) + { + App app = new App(); + app.InitializeComponent(); + MainWindow window = new MainWindow(); + Raytheon.LogDashboard.View.MainWindow.HandleParameter(e.Args); + app.Run(window); + return; + } + + UnsafeNative.SendMessage(runningProcess.MainWindowHandle, string.Join(" ", e.Args)); + + Environment.Exit(0); + } + } + catch(Exception exception) + { + logger.Warn(exception, "OnStartup check exception (open with arguments)"); + } + } + + string assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + string logDashboardConfigFilePath = Path.Combine(assemblyFolder, "LogDashboard.xml"); + // load settings from configuration file + Raytheon.LogDashboard.Model.Settings.SetInstance(logDashboardConfigFilePath).Load(); + + if(Raytheon.LogDashboard.Model.Settings.Instance.OnlyOneAppInstance) + { + try + { + if(mutex.WaitOne(TimeSpan.Zero, true)) + { + mutex.ReleaseMutex(); + } + else + { + logger.Trace("OnStartup: one instance of Log Viewer already started"); + Messenger.Default.Send("OnStartup: one instance of Log Viewer already started", "DisplayCustomMessage"); + Environment.Exit(0); + } + } + catch(Exception exception) + { + logger.Warn(exception, "OnStartup check exception"); + } + } + + try + { + if(!IsAssociated()) + { + string filePath = Process.GetCurrentProcess().MainModule.FileName; + + SetAssociation(".txt", "LogDashboard", filePath); + SetAssociation(".log", "LogDashboard", filePath); + SetAssociation(".csv", "LogDashboard", filePath); + } + } + catch(Exception exception) + { + logger.Warn(exception, "OnStartup set file association exception"); + } + + base.OnStartup(e); + } + private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) + { + logger.Fatal($"Unhandled exception {e.ExceptionObject as Exception}"); + Environment.Exit(1); + } + + private void Current_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) + { + logger.Fatal($"Unhandled Exception: {e.Exception}"); + Environment.Exit(2); + } + + #region File Association + + private bool IsAssociated() + { + return Registry.CurrentUser.OpenSubKey(@"Software\Classes\LogViewer", false) != null; + } + + [DllImport("Shell32.dll")] + private static extern int SHChangeNotify(int eventId, int flags, IntPtr item1, IntPtr item2); + + private const int SHCNE_ASSOCCHANGED = 0x8000000; + private const int SHCNF_FLUSH = 0x1000; + + private void SetAssociation(string extension, string progId, string applicationFilePath) + { + bool madeChanges = false; + + madeChanges |= SetKeyDefaultValue($@"Software\Classes\{progId}\shell\open\command", "\"" + applicationFilePath + "\" \"%1\""); + madeChanges |= SetProgIdValue($@"Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\{extension}\OpenWithProgids", progId); + + if(madeChanges) + { + SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_FLUSH, IntPtr.Zero, IntPtr.Zero); + } + } + + private bool SetProgIdValue(string path, string progId) + { + using(var key = Registry.CurrentUser.CreateSubKey(path)) + { + if(key.GetValueNames().All(x => x != progId)) + { + key.SetValue(progId, Encoding.Unicode.GetBytes(string.Empty), RegistryValueKind.Binary); + return true; + } + } + return false; + } + + private bool SetKeyDefaultValue(string keyPath, string value) + { + using(var key = Registry.CurrentUser.CreateSubKey(keyPath)) + { + if(key.GetValue(null) as string != value) + { + key.SetValue(null, value); + return true; + } + } + return false; + } + + #endregion + + } +} diff --git a/Source/LogDashboard/LogDashboard.UI/Helpers/UnsafeNative.cs b/Source/LogDashboard/LogDashboard.UI/Helpers/UnsafeNative.cs new file mode 100644 index 0000000..e3f484f --- /dev/null +++ b/Source/LogDashboard/LogDashboard.UI/Helpers/UnsafeNative.cs @@ -0,0 +1,101 @@ +//******************************************************************************// +// UnsafeNative.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// + +// Ignore Spelling: COPYDATA + +using System; +using System.ComponentModel; +using System.Runtime.InteropServices; +using System.Text; + +namespace Raytheon.LogDashboard.Helpers +{ + internal static class UnsafeNative + { + public const int WM_COPYDATA = 0x004A; + + public static string GetMessage(int message, IntPtr lParam) + { + if (message == WM_COPYDATA) + { + try + { + var data = Marshal.PtrToStructure(lParam); + string result = string.Copy(data.lpData); + return result; + } + catch + { + return null; + } + } + + return null; + } + + public static void SendMessage(IntPtr hwnd, string message) + { + byte[] messageBytes = Encoding.Unicode.GetBytes(message); /* ANSII encoding */ + CopyDataStruct data = new CopyDataStruct + { + dwData = IntPtr.Zero, + lpData = message, + cbData = messageBytes.Length + 1 /* +1 because of \0 string termination */ + }; + + if (SendMessage(hwnd, WM_COPYDATA, IntPtr.Zero, ref data) != 0) + { + throw new Win32Exception(Marshal.GetLastWin32Error()); + } + } + + [DllImport("user32.dll")] + public static extern bool SetForegroundWindow(IntPtr hWnd); + + [DllImport("User32.dll", EntryPoint = "SendMessage")] + private static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, ref CopyDataStruct lParam); + + [StructLayout(LayoutKind.Sequential)] + private struct CopyDataStruct + { + public IntPtr dwData; + public int cbData; + + [MarshalAs(UnmanagedType.LPWStr)] + public string lpData; + } + } +} diff --git a/Source/LogDashboard/LogDashboard.UI/LogDashboard.UI.csproj b/Source/LogDashboard/LogDashboard.UI/LogDashboard.UI.csproj new file mode 100644 index 0000000..ab7bc75 --- /dev/null +++ b/Source/LogDashboard/LogDashboard.UI/LogDashboard.UI.csproj @@ -0,0 +1,105 @@ + + + + net48 + Raytheon.LogDashboard + Raytheon.LogDashboard + Raytheon Technologies + Logging Dashboard Application + Specialty Engineering + Raytheon Technologies + 1.3.10 + $(Version) + $(Version) + WinExe + true + Resources\LogDashboard.ico + $(SolutionDir)_Deployment\ + + + + + + + + + PreserveNewest + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + True + Settings.settings + + + True + True + Resource1.resx + + + + + + + + + + ResXFileCodeGenerator + Resource1.Designer.cs + + + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + SettingsSingleFileGenerator + Resources.Designer.cs + + + SettingsSingleFileGenerator + Locals.Designer.cs + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Source/LogDashboard/LogDashboard.UI/Properties/Settings.Designer.cs b/Source/LogDashboard/LogDashboard.UI/Properties/Settings.Designer.cs new file mode 100644 index 0000000..3bb7920 --- /dev/null +++ b/Source/LogDashboard/LogDashboard.UI/Properties/Settings.Designer.cs @@ -0,0 +1,134 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Raytheon.LogDashboard.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.13.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("600")] + public double CurrentWindowHeight { + get { + return ((double)(this["CurrentWindowHeight"])); + } + set { + this["CurrentWindowHeight"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("600")] + public double PreviousWindowHeight { + get { + return ((double)(this["PreviousWindowHeight"])); + } + set { + this["PreviousWindowHeight"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("800")] + public double CurrentWindowWidth { + get { + return ((double)(this["CurrentWindowWidth"])); + } + set { + this["CurrentWindowWidth"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("800")] + public double PreviousWindowWidth { + get { + return ((double)(this["PreviousWindowWidth"])); + } + set { + this["PreviousWindowWidth"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("100")] + public double CurrentWindowLeft { + get { + return ((double)(this["CurrentWindowLeft"])); + } + set { + this["CurrentWindowLeft"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("100")] + public double PreviousWindowLeft { + get { + return ((double)(this["PreviousWindowLeft"])); + } + set { + this["PreviousWindowLeft"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("100")] + public double CurrentWindowTop { + get { + return ((double)(this["CurrentWindowTop"])); + } + set { + this["CurrentWindowTop"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("100")] + public double PreviousWindowTop { + get { + return ((double)(this["PreviousWindowTop"])); + } + set { + this["PreviousWindowTop"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("./LogDashboard.xml")] + public string SettingsPath { + get { + return ((string)(this["SettingsPath"])); + } + set { + this["SettingsPath"] = value; + } + } + } +} diff --git a/Source/LogDashboard/LogDashboard.UI/Properties/Settings.settings b/Source/LogDashboard/LogDashboard.UI/Properties/Settings.settings new file mode 100644 index 0000000..863ea80 --- /dev/null +++ b/Source/LogDashboard/LogDashboard.UI/Properties/Settings.settings @@ -0,0 +1,33 @@ + + + + + + 600 + + + 600 + + + 800 + + + 800 + + + 100 + + + 100 + + + 100 + + + 100 + + + ./LogDashboard.xml + + + \ No newline at end of file diff --git a/Source/LogDashboard/LogDashboard.UI/Resources/LogDashboard.ico b/Source/LogDashboard/LogDashboard.UI/Resources/LogDashboard.ico new file mode 100644 index 0000000..962345b Binary files /dev/null and b/Source/LogDashboard/LogDashboard.UI/Resources/LogDashboard.ico differ diff --git a/Source/LogDashboard/LogDashboard.UI/Resources/Resource1.Designer.cs b/Source/LogDashboard/LogDashboard.UI/Resources/Resource1.Designer.cs new file mode 100644 index 0000000..0538836 --- /dev/null +++ b/Source/LogDashboard/LogDashboard.UI/Resources/Resource1.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Raytheon.LogDashboard.Resources { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resource1 { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resource1() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Raytheon.LogDashboard.Resources.Resource1", typeof(Resource1).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). + /// + internal static System.Drawing.Icon LogDashboard { + get { + object obj = ResourceManager.GetObject("LogDashboard", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + } +} diff --git a/Source/LogDashboard/LogDashboard.UI/Resources/Resource1.resx b/Source/LogDashboard/LogDashboard.UI/Resources/Resource1.resx new file mode 100644 index 0000000..2909ad9 --- /dev/null +++ b/Source/LogDashboard/LogDashboard.UI/Resources/Resource1.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + LogDashboard.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/Source/LogDashboard/LogDashboard.UI/Resources/rt_logo_30h.png b/Source/LogDashboard/LogDashboard.UI/Resources/rt_logo_30h.png new file mode 100644 index 0000000..9bed31a Binary files /dev/null and b/Source/LogDashboard/LogDashboard.UI/Resources/rt_logo_30h.png differ diff --git a/Source/LogDashboard/LogDashboard.UI/View/MainWindow.xaml b/Source/LogDashboard/LogDashboard.UI/View/MainWindow.xaml new file mode 100644 index 0000000..10677ae --- /dev/null +++ b/Source/LogDashboard/LogDashboard.UI/View/MainWindow.xaml @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/LogDashboard/LogDashboard.UI/View/MainWindow.xaml.cs b/Source/LogDashboard/LogDashboard.UI/View/MainWindow.xaml.cs new file mode 100644 index 0000000..e8c0948 --- /dev/null +++ b/Source/LogDashboard/LogDashboard.UI/View/MainWindow.xaml.cs @@ -0,0 +1,212 @@ +//******************************************************************************// +// MainWindow.xaml.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using System; +using System.ComponentModel; +using System.Linq; +using System.Windows; +using System.Windows.Interop; +using System.Windows.Forms; +using NLog; +using Raytheon.LogDashboard.Helpers; +using Raytheon.LogDashboard.ViewModel; +using Application = System.Windows.Application; +using Raytheon.LogDashboard.Resources; +using MahApps.Metro.Controls; +using MahApps.Metro.Controls.Dialogs; +using GalaSoft.MvvmLight.Messaging; +using System.Collections.Generic; + +namespace Raytheon.LogDashboard.View +{ + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow : MetroWindow, IDisposable + { + private static readonly Logger logger = LogManager.GetCurrentClassLogger(); + private NotifyIcon trayIcon; + + public MainWindow() + { + InitializeComponent(); + + Loaded += (s, e) => + { + WindowHandle = new WindowInteropHelper(Application.Current.MainWindow).Handle; + HwndSource.FromHwnd(WindowHandle)?.AddHook(HandleMessages); + }; + } + + /// + /// On Loaded Event + /// + /// + /// + private void MainWindow_OnLoaded(object sender, RoutedEventArgs e) + { + if (AppDomain.CurrentDomain.SetupInformation.ActivationArguments?.ActivationData != null) + { + string[] activationData = AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData; + foreach (var arg in activationData.Where(x => x.EndsWith(".txt") || x.EndsWith(".log") || x.EndsWith(".csv"))) + { + ViewModelLocator.LogDashboard.ImportLogs(arg); + } + return; + } + + List args = Environment.GetCommandLineArgs().Where(x => x.EndsWith(".txt") || x.EndsWith(".log") || x.EndsWith(".csv")).ToList(); + if (args.Any()) + { + ViewModelLocator.LogDashboard.ImportLogs(args.Where(x => x.EndsWith(".txt") || x.EndsWith(".log") || x.EndsWith(".csv"))); + return; + } + } + + #region tray + + protected override void OnStateChanged(EventArgs e) + { + if (WindowState == WindowState.Minimized && Model.Settings.Instance.MinimizeToTray) + { + if (trayIcon == null) + { + trayIcon = new NotifyIcon + { + Icon = Resource1.LogDashboard, + Visible = true, + Text = "Log Viewer" + }; + trayIcon.DoubleClick += delegate + { + Show(); + WindowState = WindowState.Normal; + }; + + trayIcon.ContextMenuStrip = new ContextMenuStrip(); + ToolStripMenuItem openAppMenuItem = new ToolStripMenuItem("Open"); + ToolStripMenuItem exitAppMenuItem = new ToolStripMenuItem("Exit"); + + trayIcon.ContextMenuStrip.Items.AddRange(new ToolStripItem[] { openAppMenuItem, exitAppMenuItem }); + trayIcon.ContextMenuStrip.ItemClicked += TrayIconContextMenuClick; + } + Hide(); + } + + base.OnStateChanged(e); + } + + private void TrayIconContextMenuClick(object sender, ToolStripItemClickedEventArgs e) + { + switch (e.ClickedItem.Text) + { + case "Open": + Show(); + WindowState = WindowState.Normal; + break; + case "Exit": + Close(); + Environment.Exit(0); + break; + } + } + + protected override void OnClosed(EventArgs e) + { + if (trayIcon != null) + { + trayIcon.Visible = false; + trayIcon.Dispose(); + trayIcon.Icon = null; + } + + base.OnClosed(e); + } + + #endregion + + + #region param transfer + + public static IntPtr WindowHandle { get; private set; } + + internal static void HandleParameter(string[] args) + { + if (Application.Current?.MainWindow is MainWindow mainWindow && + args != null && args.Length > 0 && args.All(x => x.EndsWith(".txt") || x.EndsWith(".log") || x.EndsWith(".csv"))) + { + ViewModelLocator.LogDashboard.ImportLogs(args.First()); + } + } + + private static IntPtr HandleMessages(IntPtr handle, int message, IntPtr wParameter, IntPtr lParameter, ref Boolean handled) + { + string data = UnsafeNative.GetMessage(message, lParameter); + + if (data != null) + { + if(Application.Current.MainWindow == null) + { + return IntPtr.Zero; + } + + if(Application.Current.MainWindow.WindowState == WindowState.Minimized) + { + Application.Current.MainWindow.WindowState = WindowState.Normal; + } + + UnsafeNative.SetForegroundWindow(new WindowInteropHelper(Application.Current.MainWindow).Handle); + + string[] args = data.Split(' '); + HandleParameter(args); + handled = true; + } + + return IntPtr.Zero; + } + + #endregion + + public void Dispose() + { + trayIcon?.Dispose(); + } + + private void MetroWindow_Closing(object sender, CancelEventArgs e) + { + ViewModelLocator.LogDashboard.Dispose(); + } + } +} \ No newline at end of file diff --git a/Source/LogDashboard/LogDashboard.UI/ViewModel/MainWindowViewModel.cs b/Source/LogDashboard/LogDashboard.UI/ViewModel/MainWindowViewModel.cs new file mode 100644 index 0000000..661c379 --- /dev/null +++ b/Source/LogDashboard/LogDashboard.UI/ViewModel/MainWindowViewModel.cs @@ -0,0 +1,167 @@ +//******************************************************************************// +// MainWindowViewModel.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using ControlzEx.Theming; +using GalaSoft.MvvmLight; +using GalaSoft.MvvmLight.Messaging; +using MahApps.Metro.Controls.Dialogs; +using System.Windows; +using System.Windows.Media; + +namespace Raytheon.LogDashboard.ViewModel +{ + public class MainWindowViewModel : ViewModelBase + { + protected static LogDashViewModelLocator LocatorInstance; + private IDialogCoordinator _dialogCoordinator; + + public MainWindowViewModel(IDialogCoordinator instance) + { + _dialogCoordinator = instance; + + Messenger.Default.Register(this, "ColorChange", ColorChangeHandler); + Messenger.Default.Register(this, "ThemeChange", ThemeChangeHandler); + + Messenger.Default.Register(this, "DisplayCustomMessage", DisplayCustomMessageHandler); + + LocatorInstance = (Application.Current.Resources["LogDashLocator"] as LogDashViewModelLocator); + } + + private void ThemeChangeHandler(string theme) + { + if(!string.IsNullOrEmpty(theme)) + { + if(theme.Contains("Dark")) + { + ThemeManager.Current.ChangeThemeBaseColor(Application.Current.MainWindow, "Dark"); + } + else + { + ThemeManager.Current.ChangeThemeBaseColor(Application.Current.MainWindow, "Light"); + } + } + } + + private void ColorChangeHandler(string selectedColor) + { + if(!string.IsNullOrEmpty(selectedColor) && Application.Current.MainWindow != null) + { + ThemeManager.Current.ChangeThemeColorScheme(Application.Current.MainWindow, selectedColor); + + Application.Current.Resources["MahApps.Brushes.ToggleSwitch.FillOn"] = ColorConverter.ConvertFromString(selectedColor); + + RaisePropertyChanged(() => IconColor); + } + } + + public SolidColorBrush IconColor + { + get => LocatorInstance.SelectedColorTheme.Color; + } + + public static double PreviousWindowHeight + { + get { return Properties.Settings.Default.PreviousWindowHeight; } + set { Properties.Settings.Default.PreviousWindowHeight = value; } + } + public static double CurrentWindowHeight + { + get { return Properties.Settings.Default.CurrentWindowHeight; } + set + { + Properties.Settings.Default.PreviousWindowHeight = Properties.Settings.Default.CurrentWindowHeight; + Properties.Settings.Default.CurrentWindowHeight = value; + Properties.Settings.Default.Save(); + } + } + + public static double PreviousWindowWidth + { + get { return Properties.Settings.Default.PreviousWindowWidth; } + set { Properties.Settings.Default.PreviousWindowWidth = value; } + } + public static double CurrentWindowWidth + { + get { return Properties.Settings.Default.CurrentWindowWidth; } + set + { + Properties.Settings.Default.PreviousWindowWidth = Properties.Settings.Default.CurrentWindowWidth; + Properties.Settings.Default.CurrentWindowWidth = value; + Properties.Settings.Default.Save(); + } + } + + public static double PreviousWindowLeft + { + get { return Properties.Settings.Default.PreviousWindowLeft; } + set { Properties.Settings.Default.PreviousWindowLeft = value; } + } + public static double CurrentWindowLeft + { + get { return Properties.Settings.Default.CurrentWindowLeft; } + set + { + Properties.Settings.Default.PreviousWindowLeft = Properties.Settings.Default.CurrentWindowLeft; + Properties.Settings.Default.CurrentWindowLeft = value; + Properties.Settings.Default.Save(); + } + } + + public static double PreviousWindowTop + { + get { return Properties.Settings.Default.PreviousWindowTop; } + set { Properties.Settings.Default.PreviousWindowTop = value; } + } + public static double CurrentWindowTop + { + get { return Properties.Settings.Default.CurrentWindowTop; } + set + { + Properties.Settings.Default.PreviousWindowTop = Properties.Settings.Default.CurrentWindowTop; + Properties.Settings.Default.CurrentWindowTop = value; + Properties.Settings.Default.Save(); + } + } + + /// + /// handles custom message with single Okay button + /// + /// + private async void DisplayCustomMessageHandler(string message) + { + await _dialogCoordinator.ShowMessageAsync(this, "Log Dashboard", message).ConfigureAwait(false); + } + } +} diff --git a/Source/LogDashboard/LogDashboard.UI/ViewModel/ViewModelLocator.cs b/Source/LogDashboard/LogDashboard.UI/ViewModel/ViewModelLocator.cs new file mode 100644 index 0000000..cf50c50 --- /dev/null +++ b/Source/LogDashboard/LogDashboard.UI/ViewModel/ViewModelLocator.cs @@ -0,0 +1,58 @@ +//******************************************************************************// +// ViewModelLocator.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// + +// Ignore Spelling: Locator + +using CommonServiceLocator; +using GalaSoft.MvvmLight; +using GalaSoft.MvvmLight.Ioc; +using MahApps.Metro.Controls.Dialogs; + +namespace Raytheon.LogDashboard.ViewModel +{ + public class ViewModelLocator : ViewModelBase + { + public ViewModelLocator() + { + ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default); + + SimpleIoc.Default.Register(() => new MainWindowViewModel(DialogCoordinator.Instance)); + SimpleIoc.Default.Register(); + } + public static MainWindowViewModel Main => ServiceLocator.Current.GetInstance(); + public static LogDashboardViewModel LogDashboard => ServiceLocator.Current.GetInstance(); + } +} diff --git a/Source/LogDashboard/LogDashboard.sln b/Source/LogDashboard/LogDashboard.sln new file mode 100644 index 0000000..dee230a --- /dev/null +++ b/Source/LogDashboard/LogDashboard.sln @@ -0,0 +1,36 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.6.33801.468 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{99AAB3BD-FA07-44B0-AEFE-8C3424A773CC}" + ProjectSection(SolutionItems) = preProject + LogDashboard.sln.licenseheader = LogDashboard.sln.licenseheader + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LogDashboard.UI", "LogDashboard.UI\LogDashboard.UI.csproj", "{AF3B84E0-E237-44F3-9043-26D571F8B31D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LogDashboard", "LogDashboard\LogDashboard.csproj", "{66F98C3C-539E-4A4F-AF39-DF2A62AD1C5C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {AF3B84E0-E237-44F3-9043-26D571F8B31D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AF3B84E0-E237-44F3-9043-26D571F8B31D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AF3B84E0-E237-44F3-9043-26D571F8B31D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AF3B84E0-E237-44F3-9043-26D571F8B31D}.Release|Any CPU.Build.0 = Release|Any CPU + {66F98C3C-539E-4A4F-AF39-DF2A62AD1C5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {66F98C3C-539E-4A4F-AF39-DF2A62AD1C5C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {66F98C3C-539E-4A4F-AF39-DF2A62AD1C5C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {66F98C3C-539E-4A4F-AF39-DF2A62AD1C5C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {2F4122A7-E92D-4788-BD7F-12983BC7718A} + EndGlobalSection +EndGlobal diff --git a/Source/LogDashboard/LogDashboard.sln.licenseheader b/Source/LogDashboard/LogDashboard.sln.licenseheader new file mode 100644 index 0000000..84a9649 --- /dev/null +++ b/Source/LogDashboard/LogDashboard.sln.licenseheader @@ -0,0 +1,79 @@ +extensions: designer.cs generated.cs +extensions: .cs .cpp .h +//******************************************************************************// +// %FileName% +// %CurrentMonth%/%CurrentDay%/%CurrentYear% +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: %UserDisplayName% (%UserName%) +//******************************************************************************// +extensions: .aspx .ascx +<%-- +COPYRIGHT RAYTHEON COMPANY +--%> +extensions: .vb +'Sample license text. +extensions: .xaml .xml .config .xsd + \ No newline at end of file diff --git a/Source/LogDashboard/LogDashboard/Converters/CountToVisibilityConverter.cs b/Source/LogDashboard/LogDashboard/Converters/CountToVisibilityConverter.cs new file mode 100644 index 0000000..2e4697e --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Converters/CountToVisibilityConverter.cs @@ -0,0 +1,59 @@ +//******************************************************************************// +// CountToVisibilityConverter.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using System; +using System.Globalization; +using System.Windows.Data; +using System.Windows; + +namespace Raytheon.LogDashboard.Converters +{ + public class CountToVisibilityConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is int count) + { + return count > 0 ? Visibility.Visible : Visibility.Collapsed; + } + return Visibility.Visible; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Source/LogDashboard/LogDashboard/Converters/DataConverter.cs b/Source/LogDashboard/LogDashboard/Converters/DataConverter.cs new file mode 100644 index 0000000..12b982c --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Converters/DataConverter.cs @@ -0,0 +1,63 @@ +//******************************************************************************// +// DataConverter.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using System; +using System.Globalization; +using System.Windows.Data; + +namespace Raytheon.LogDashboard.Converters +{ + public class DataConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if(value != null && value is DateTime dateValue) + { + string dataFormat = Model.Settings.Instance.DataFormat; + if(string.IsNullOrEmpty(dataFormat)) + { + return dateValue; + } + return dateValue.ToString(Model.Settings.Instance.DataFormat); + } + return value; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Source/LogDashboard/LogDashboard/Converters/LoggerDisplayConverter.cs b/Source/LogDashboard/LogDashboard/Converters/LoggerDisplayConverter.cs new file mode 100644 index 0000000..78b0e22 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Converters/LoggerDisplayConverter.cs @@ -0,0 +1,62 @@ +//******************************************************************************// +// LoggerDisplayConverter.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using System; +using System.Globalization; +using System.Linq; +using System.Windows.Data; + +namespace Raytheon.LogDashboard.Converters +{ + public class LoggerDisplayConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if(value != null && value is string strValue && !string.IsNullOrEmpty(strValue)) + { + if(strValue.Split('.').Length > 0) + { + return strValue.Split('.').Last(); + } + } + return value; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Source/LogDashboard/LogDashboard/Converters/MaxLengthConverter.cs b/Source/LogDashboard/LogDashboard/Converters/MaxLengthConverter.cs new file mode 100644 index 0000000..0b66bab --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Converters/MaxLengthConverter.cs @@ -0,0 +1,74 @@ +//******************************************************************************// +// MaxLengthConverter.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using System; +using System.Globalization; +using System.Windows.Data; + +namespace Raytheon.LogDashboard.Converters +{ + public class MaxLengthConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if(value is string str && !string.IsNullOrEmpty(str) && int.TryParse((string)parameter, out int maxLength)) + { + int indexNewLine = str.IndexOf(Environment.NewLine, StringComparison.Ordinal); + if(indexNewLine != -1 && indexNewLine < maxLength) + { + return str.Substring(0, indexNewLine) + "..."; + } + + int indexN = str.IndexOf('\n'); + if(indexN != -1 && indexN < maxLength) + { + return str.Substring(0, indexN) + "..."; + } + + if(str.Length > maxLength) + { + return str.Substring(0, maxLength) + "..."; + } + return str; + } + return value; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Source/LogDashboard/LogDashboard/Converters/ProgressStateConverter.cs b/Source/LogDashboard/LogDashboard/Converters/ProgressStateConverter.cs new file mode 100644 index 0000000..9b2bbc4 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Converters/ProgressStateConverter.cs @@ -0,0 +1,59 @@ +//******************************************************************************// +// ProgressStateConverter.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using System; +using System.Globalization; +using System.Windows.Data; +using System.Windows.Shell; + +namespace Raytheon.LogDashboard.Converters +{ + class ProgressStateConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is bool val) + { + return val ? TaskbarItemProgressState.Indeterminate : TaskbarItemProgressState.Normal; + } + return value; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/Source/LogDashboard/LogDashboard/Converters/TreeViewLineConverter.cs b/Source/LogDashboard/LogDashboard/Converters/TreeViewLineConverter.cs new file mode 100644 index 0000000..5920f12 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Converters/TreeViewLineConverter.cs @@ -0,0 +1,56 @@ +//******************************************************************************// +// TreeViewLineConverter.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using System; +using System.Windows.Controls; +using System.Windows.Data; + +namespace Raytheon.LogDashboard.Converters +{ + public class TreeViewLineConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + TreeViewItem item = (TreeViewItem)value; + ItemsControl ic = ItemsControl.ItemsControlFromItemContainer(item); + return ic.ItemContainerGenerator.IndexFromContainer(item) == ic.Items.Count - 1; + } + + public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + throw new Exception("The method or operation is not implemented."); + } + } +} diff --git a/Source/LogDashboard/LogDashboard/Helpers/AsyncObservableCollection.cs b/Source/LogDashboard/LogDashboard/Helpers/AsyncObservableCollection.cs new file mode 100644 index 0000000..649e5fc --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Helpers/AsyncObservableCollection.cs @@ -0,0 +1,97 @@ +//******************************************************************************// +// AsyncObservableCollection.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.ComponentModel; +using System.Threading; + +namespace Raytheon.LogDashboard.Helpers +{ + public class AsyncObservableCollection : ObservableCollection + { + private readonly SynchronizationContext synchronizationContext = SynchronizationContext.Current; + + public AsyncObservableCollection() + { + } + + public AsyncObservableCollection(IEnumerable list) + : base(list) + { + } + + protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) + { + if(SynchronizationContext.Current == synchronizationContext) + { + // Execute the CollectionChanged event on the current thread + RaiseCollectionChanged(e); + } + else + { + // Raises the CollectionChanged event on the creator thread + synchronizationContext.Send(RaiseCollectionChanged, e); + } + } + + private void RaiseCollectionChanged(object param) + { + // We are in the creator thread, call the base implementation directly + base.OnCollectionChanged((NotifyCollectionChangedEventArgs)param); + } + + protected override void OnPropertyChanged(PropertyChangedEventArgs e) + { + if(SynchronizationContext.Current == synchronizationContext) + { + // Execute the PropertyChanged event on the current thread + RaisePropertyChanged(e); + } + else + { + // Raises the PropertyChanged event on the creator thread + synchronizationContext.Send(RaisePropertyChanged, e); + } + } + + private void RaisePropertyChanged(object param) + { + // We are in the creator thread, call the base implementation directly + base.OnPropertyChanged((PropertyChangedEventArgs)param); + } + } +} diff --git a/Source/LogDashboard/LogDashboard/Helpers/BindableSelectedItemBehavior.cs b/Source/LogDashboard/LogDashboard/Helpers/BindableSelectedItemBehavior.cs new file mode 100644 index 0000000..87a5ad6 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Helpers/BindableSelectedItemBehavior.cs @@ -0,0 +1,92 @@ +//******************************************************************************// +// BindableSelectedItemBehavior.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using System.Windows.Controls; +using System.Windows; +using System.Windows.Interactivity; + +namespace Raytheon.LogDashboard.Helpers +{ + /// + /// Behavior that makes the + /// + /// System.Windows.Controls.TreeView.SelectedItem + /// + /// bindable. + /// + public class BindableSelectedItemBehavior : Behavior + { + #region SelectedItem Property + + public object SelectedItem + { + get => GetValue(SelectedItemProperty); + set => SetValue(SelectedItemProperty, value); + } + + public static readonly DependencyProperty SelectedItemProperty = + DependencyProperty.Register("SelectedItem", typeof(object), typeof(BindableSelectedItemBehavior), new UIPropertyMetadata(null, OnSelectedItemChanged)); + + private static void OnSelectedItemChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) + { + TreeViewItem item = e.NewValue as TreeViewItem; + item?.SetValue(TreeViewItem.IsSelectedProperty, true); + } + + #endregion + + protected override void OnAttached() + { + base.OnAttached(); + + AssociatedObject.SelectedItemChanged += OnTreeViewSelectedItemChanged; + } + + protected override void OnDetaching() + { + base.OnDetaching(); + + if(AssociatedObject != null) + { + AssociatedObject.SelectedItemChanged -= OnTreeViewSelectedItemChanged; + } + } + + private void OnTreeViewSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs e) + { + SelectedItem = e.NewValue; + } + } +} diff --git a/Source/LogDashboard/LogDashboard/Helpers/EnumerationExtension.cs b/Source/LogDashboard/LogDashboard/Helpers/EnumerationExtension.cs new file mode 100644 index 0000000..23d8793 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Helpers/EnumerationExtension.cs @@ -0,0 +1,102 @@ +//******************************************************************************// +// EnumerationExtension.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using System; +using System.ComponentModel; +using System.Linq; +using System.Windows.Markup; + +namespace Raytheon.LogDashboard.Helpers +{ + public class EnumerationExtension : MarkupExtension + { + private Type _enumType; + + + public EnumerationExtension(Type enumType) + { + EnumType = enumType ?? throw new ArgumentNullException(nameof(enumType)); + } + + public Type EnumType + { + get { return _enumType; } + private set + { + if(_enumType == value) + { + return; + } + + var enumType = Nullable.GetUnderlyingType(value) ?? value; + if(enumType.IsEnum == false) + { + throw new ArgumentException("Type must be an Enum."); + } + + _enumType = value; + } + } + + public override object ProvideValue(IServiceProvider serviceProvider) + { + var enumValues = Enum.GetValues(EnumType); + + return ( + from object enumValue in enumValues + select new EnumerationMember + { + Value = enumValue, + Description = GetDescription(enumValue) + }).ToArray(); + } + + private string GetDescription(object enumValue) + { + return EnumType + .GetField(enumValue.ToString()) + .GetCustomAttributes(typeof(DescriptionAttribute), false) + .FirstOrDefault() is DescriptionAttribute descriptionAttribute + ? descriptionAttribute.Description + : enumValue.ToString(); + } + + public class EnumerationMember + { + public string Description { get; set; } + public object Value { get; set; } + } + } +} diff --git a/Source/LogDashboard/LogDashboard/Helpers/ExtensionMethods.cs b/Source/LogDashboard/LogDashboard/Helpers/ExtensionMethods.cs new file mode 100644 index 0000000..9b0a272 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Helpers/ExtensionMethods.cs @@ -0,0 +1,280 @@ +//******************************************************************************// +// ExtensionMethods.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using Raytheon.LogDashboard.Model; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using System.Windows.Media; + +namespace Raytheon.LogDashboard.Helpers +{ + public static class ExtensionMethods + { + /// + /// Checks whether a FileInfo or DirectoryInfo object is a directory, or intended to be a directory. + /// + /// + /// + public static bool IsDirectory(this FileSystemInfo fileSystemInfo) + { + if(fileSystemInfo == null) + { + return false; + } + + if((int)fileSystemInfo.Attributes != -1) + { + // if attributes are initialized check the directory flag + return fileSystemInfo.Attributes.HasFlag(FileAttributes.Directory); + } + + // If we get here the file probably doesn't exist yet. The best we can do is + // try to judge intent. Because directories can have extensions and files + // can lack them, we can't rely on filename. + // + // We can reasonably assume that if the path doesn't exist yet and + // FileSystemInfo is a DirectoryInfo, a directory is intended. FileInfo can + // make a directory, but it would be a bizarre code path. + + return fileSystemInfo is DirectoryInfo; + } + + public static string FirstCharToUpper(this string input) + { + switch(input) + { + case null: + throw new ArgumentNullException(nameof(input)); + case "": + throw new ArgumentException($"{nameof(input)} cannot be empty", nameof(input)); + default: + return input.First().ToString().ToUpper() + input.Substring(1); + } + } + + public static bool Contains(this string source, string toCheck, StringComparison comp) + { + return source?.IndexOf(toCheck, comp) >= 0; + } + + public static IEnumerable TakeLast(this IEnumerable source, int N) + { + return source.Skip(Math.Max(0, source.Count() - N)); + } + + public static IEnumerable DistinctBy + (this IEnumerable source, Func keySelector) + { + HashSet seenKeys = new HashSet(); + foreach(TSource element in source) + { + if(seenKeys.Add(keySelector(element))) + { + yield return element; + } + } + } + + /// + /// Convert the Brush to a ARGB - Color. + /// + /// your object + /// + /// White = #ffffffff + /// Green = #ff00ff00 + /// + public static string ToARGB(this SolidColorBrush brush) + { + if(brush == null) + { + throw new ArgumentNullException(); + } + + var c = brush.Color; + return $"#{c.A:X2}{c.R:X2}{c.G:X2}{c.B:X2}"; + } + + /// + /// set the current brush to a new color based on the #argb string + /// + /// your object + /// The #ARGB Color + /// the same object as you run the function + public static SolidColorBrush FromARGB(this SolidColorBrush brush, string argb) + { + if(argb.Length != 9) + { + throw new FormatException("we need #aarrggbb as color"); + } + + byte a = Convert.ToByte(int.Parse(argb.Substring(1, 2), NumberStyles.HexNumber)); + byte r = Convert.ToByte(int.Parse(argb.Substring(3, 2), NumberStyles.HexNumber)); + byte g = Convert.ToByte(int.Parse(argb.Substring(5, 2), NumberStyles.HexNumber)); + byte b = Convert.ToByte(int.Parse(argb.Substring(7, 2), NumberStyles.HexNumber)); + Color c = Color.FromArgb(a, r, g, b); + brush.Color = c; + return brush; + } + + public static HashSet ToHashSet(this IEnumerable source, IEqualityComparer comparer = null) + { + return new HashSet(source.ToList(), comparer); + } + + /// + /// returns true if string contains any of the members in search array + /// + /// + /// + /// + /// + public static bool ContainsAnyOf(this String line, string[] search, bool ignoreCase = false) + { + return search.Any(x => ignoreCase ? line.ToUpper().Contains(x.ToUpper()) : line.Contains(x)); + } + + /// + /// returns true if string contains any of the members in search list patterns + /// + /// + /// + /// + /// + public static bool ContainsAnyOfPattern(this string input, string[] patterns, bool ignoreCase = false) + { + foreach(string pattern in patterns) + { + if(Regex.IsMatch(input, pattern, ignoreCase ? RegexOptions.IgnoreCase : RegexOptions.None)) + { + return true; + } + } + return false; + } + + /// + /// does the string begins with regex pattern? + /// + /// + /// + /// + public static bool StartsWithPattern(this string input, string pattern) + { + if(string.IsNullOrEmpty(input)) + { + return false; + } + return Regex.IsMatch(input, $"^{pattern}"); + } + + /// + /// truncates DateTime + /// + /// + /// + /// + public static DateTime Truncate(this DateTime dateTime, TimeSpan timeSpan) + { + if(timeSpan == TimeSpan.Zero) + { + return dateTime; // Or could throw an ArgumentException + } + + if(dateTime == DateTime.MinValue || dateTime == DateTime.MaxValue) + { + return dateTime; // do not modify "guard" values + } + + return dateTime.AddTicks(-(dateTime.Ticks % timeSpan.Ticks)); + } + + /// + /// filters log messages from the main list + /// + /// + /// + /// + /// + /// + /// + /// + public static IEnumerable Filter(this IEnumerable messages, + string text, + bool matchCase, + bool matchWholeWord, + bool useRegularExp, + DashboardLogLevel level = DashboardLogLevel.Trace) + { + IEnumerable searchResult = messages.ToList(); + + if(!matchCase && !matchWholeWord) + { + return searchResult.Where(x => level.HasFlag(x.Level) && + (x.Message.ToUpper().Contains(text, StringComparison.OrdinalIgnoreCase) || + (useRegularExp && Regex.IsMatch(x.Message.ToUpper(), text, RegexOptions.IgnoreCase)))); + } + + if(matchCase && !matchWholeWord) + { + return searchResult.Where(x => level.HasFlag(x.Level) && (x.Message.Contains(text) || (useRegularExp && Regex.IsMatch(x.Message, text)))); + } + + if(matchCase && matchWholeWord) + { + return searchResult.Where(x => level.HasFlag(x.Level) && (x.Message.Contains($" {text} ") || + x.Message.StartsWith($"{text} ") || + x.Message.EndsWith($" {text}") || + (x.Message.StartsWith(text) && x.Message.EndsWith(text)) || + (useRegularExp && Regex.IsMatch(x.Message, text)))); + } + + if(!matchCase && matchWholeWord) + { + return searchResult.Where(x => (level.HasFlag(x.Level) && (x.Message.Contains($" {text} ", StringComparison.OrdinalIgnoreCase) || + x.Message.StartsWith($"{text} ", StringComparison.OrdinalIgnoreCase) || + x.Message.EndsWith($" {text}", StringComparison.OrdinalIgnoreCase) || + (x.Message.StartsWith(text, StringComparison.OrdinalIgnoreCase) && + x.Message.EndsWith(text, StringComparison.OrdinalIgnoreCase)))) || + (useRegularExp && Regex.IsMatch(x.Message.ToUpper(), text, RegexOptions.IgnoreCase))); + } + + return searchResult; + } + } +} diff --git a/Source/LogDashboard/LogDashboard/Helpers/FileWatcher.cs b/Source/LogDashboard/LogDashboard/Helpers/FileWatcher.cs new file mode 100644 index 0000000..c415e6c --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Helpers/FileWatcher.cs @@ -0,0 +1,101 @@ +//******************************************************************************// +// FileWatcher.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using Raytheon.LogDashboard.Model; +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace Raytheon.LogDashboard.Helpers +{ + public class FileWatcher + { + private CancellationTokenSource cancellationToken; + + public string FilePath { get; set; } + + public long Position { get; set; } + + public LogTemplate Template { get; set; } + + public ImportLogFile ImportLogFile { get; set; } + + public event EventHandler FileChanged; + + /// + /// starts watching the file for changes with hard-coded one sec interval + /// + public void StartWatch() + { + cancellationToken = new CancellationTokenSource(); + + Task.Run(() => + { + while(true) + { + if(cancellationToken.Token.IsCancellationRequested) + { + return; + } + + long currentLength; + using(FileStream stream = File.Open(FilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + { + currentLength = stream.Length; + } + + if(currentLength > Position) + { + OnFileChanged(this); + } + + Position = currentLength; + Thread.Sleep(1000); + } + }); + } + + public void StopWatch() + { + cancellationToken.Cancel(); + } + + protected virtual void OnFileChanged(FileWatcher fileWatcher) + { + FileChanged?.Invoke(this, fileWatcher); + } + } +} diff --git a/Source/LogDashboard/LogDashboard/Helpers/SearchableTextControl.cs b/Source/LogDashboard/LogDashboard/Helpers/SearchableTextControl.cs new file mode 100644 index 0000000..0f59114 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Helpers/SearchableTextControl.cs @@ -0,0 +1,255 @@ +//******************************************************************************// +// SearchableTextControl.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// + +// Ignore Spelling: Searchable + +using System.Windows.Controls; +using System.Windows.Documents; +using System.Windows.Media; +using System.Windows; + +namespace Raytheon.LogDashboard.Helpers +{ + public class SearchableTextControl : Control + { + static SearchableTextControl() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(SearchableTextControl), + new FrameworkPropertyMetadata(typeof(SearchableTextControl))); + } + + #region DependencyProperties + + /// + /// Text sandbox which is used to get or set the value from a dependency property. + /// + public string Text + { + get => (string)GetValue(TextProperty); + set => SetValue(TextProperty, value); + } + + + // Real implementation about TextProperty which registers a dependency property with + // the specified property name, property type, owner type, and property metadata. + public static readonly DependencyProperty TextProperty = + DependencyProperty.Register("Text", typeof(string), typeof(SearchableTextControl), + new UIPropertyMetadata(string.Empty, + UpdateControlCallBack)); + + /// + /// HighlightBackground sandbox which is used to get or set the value from a dependency property, + /// if it gets a value,it should be forced to bind to a Brushes type. + /// + public Brush HighlightBackground + { + get => (Brush)GetValue(HighlightBackgroundProperty); + set => SetValue(HighlightBackgroundProperty, value); + } + + + // Real implementation about HighlightBackgroundProperty which registers a dependency property + // with the specified property name, property type, owner type, and property metadata. + public static readonly DependencyProperty HighlightBackgroundProperty = + DependencyProperty.Register("HighlightBackground", typeof(Brush), typeof(SearchableTextControl), + new UIPropertyMetadata(Brushes.Yellow, UpdateControlCallBack)); + + /// + /// HighlightForeground sandbox which is used to get or set the value from a dependency property, + /// if it gets a value,it should be forced to bind to a Brushes type. + /// + public Brush HighlightForeground + { + get => (Brush)GetValue(HighlightForegroundProperty); + set => SetValue(HighlightForegroundProperty, value); + } + + + // Real implementation about HighlightForegroundProperty which registers a dependency property with + // the specified property name, property type, owner type, and property metadata. + public static readonly DependencyProperty HighlightForegroundProperty = + DependencyProperty.Register("HighlightForeground", typeof(Brush), typeof(SearchableTextControl), + new UIPropertyMetadata(Brushes.Black, UpdateControlCallBack)); + + /// + /// IsMatchCase sandbox which is used to get or set the value from a dependency property, + /// if it gets a value,it should be forced to bind to a bool type. + /// + public bool IsMatchCase + { + get => (bool)GetValue(IsMatchCaseProperty); + set => SetValue(IsMatchCaseProperty, value); + } + + // Real implementation about IsMatchCaseProperty which registers a dependency property with + // the specified property name, property type, owner type, and property metadata. + public static readonly DependencyProperty IsMatchCaseProperty = + DependencyProperty.Register("IsMatchCase", typeof(bool), typeof(SearchableTextControl), + new UIPropertyMetadata(true, UpdateControlCallBack)); + + /// + /// IsHighlight sandbox which is used to get or set the value from a dependency property, + /// if it gets a value,it should be forced to bind to a bool type. + /// + public bool IsHighlight + { + get => (bool)GetValue(IsHighlightProperty); + set => SetValue(IsHighlightProperty, value); + } + + // Real implementation about IsHighlightProperty which registers a dependency property with + // the specified property name, property type, owner type, and property metadata. + public static readonly DependencyProperty IsHighlightProperty = + DependencyProperty.Register("IsHighlight", typeof(bool), typeof(SearchableTextControl), + new UIPropertyMetadata(false, UpdateControlCallBack)); + + /// + /// SearchText sandbox which is used to get or set the value from a dependency property, + /// if it gets a value,it should be forced to bind to a string type. + /// + public string SearchText + { + get => (string)GetValue(SearchTextProperty); + set => SetValue(SearchTextProperty, value); + } + + /// + /// Real implementation about SearchTextProperty which registers a dependency property with + /// the specified property name, property type, owner type, and property metadata. + /// + public static readonly DependencyProperty SearchTextProperty = + DependencyProperty.Register("SearchText", typeof(string), typeof(SearchableTextControl), + new UIPropertyMetadata(string.Empty, UpdateControlCallBack)); + + /// + /// Create a call back function which is used to invalidate the rendering of the element, + /// and force a complete new layout pass. + /// One such advanced scenario is if you are creating a PropertyChangedCallback for a + /// dependency property that is not on a Freezable or FrameworkElement derived class that + /// still influences the layout when it changes. + /// + private static void UpdateControlCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + SearchableTextControl obj = d as SearchableTextControl; + obj.InvalidateVisual(); + } + #endregion + + /// + /// override the OnRender method which is used to search for the keyword and highlight + /// it when the operation gets the result. + /// + protected override void OnRender(DrawingContext drawingContext) + { + // Define a TextBlock to hold the search result. + TextBlock displayTextBlock = Template.FindName("PART_TEXT", this) as TextBlock; + + displayTextBlock.TextWrapping = TextWrapping.NoWrap; + + if(string.IsNullOrEmpty(Text)) + { + base.OnRender(drawingContext); + + return; + } + if(!IsHighlight) + { + displayTextBlock.Text = Text; + base.OnRender(drawingContext); + + return; + } + + displayTextBlock.Inlines.Clear(); + string searchstring = IsMatchCase ? SearchText : SearchText.ToUpper(); + + string compareText = IsMatchCase ? Text : Text.ToUpper(); + string displayText = Text; + + Run run; + while(!string.IsNullOrEmpty(searchstring) && compareText.IndexOf(searchstring) >= 0) + { + int position = compareText.IndexOf(searchstring); + run = GenerateRun(displayText.Substring(0, position), false); + + if(run != null) + { + displayTextBlock.Inlines.Add(run); + } + + run = GenerateRun(displayText.Substring(position, searchstring.Length), true); + + if(run != null) + { + displayTextBlock.Inlines.Add(run); + } + + compareText = compareText.Substring(position + searchstring.Length); + displayText = displayText.Substring(position + searchstring.Length); + } + + run = GenerateRun(displayText, false); + + if(run != null) + { + displayTextBlock.Inlines.Add(run); + } + + base.OnRender(drawingContext); + } + + /// + /// Set inline-level flow content element intended to contain a run of formatted or unformatted + /// text into your background and foreground setting. + /// + private Run GenerateRun(string searchedString, bool isHighlight) + { + if(!string.IsNullOrEmpty(searchedString)) + { + Run run = new Run(searchedString) + { + Background = isHighlight ? HighlightBackground : Background, + Foreground = isHighlight ? HighlightForeground : Foreground, + + // Set the source text with the style which is Bold. + FontWeight = isHighlight ? FontWeights.Bold : FontWeights.Normal, + }; + return run; + } + return null; + } + } +} diff --git a/Source/LogDashboard/LogDashboard/Helpers/StringExtensions.cs b/Source/LogDashboard/LogDashboard/Helpers/StringExtensions.cs new file mode 100644 index 0000000..9d96033 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Helpers/StringExtensions.cs @@ -0,0 +1,298 @@ +//******************************************************************************// +// StringExtensions.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using System; +using System.Globalization; +using System.Text.RegularExpressions; + +namespace Raytheon.LogDashboard.Helpers +{ + + public static class StringExtensions + { + /// + /// takes the left of the string from given index + /// + /// + /// + /// + public static string Left(this string value, int maxLength) + { + if(string.IsNullOrEmpty(value)) + { + return string.Empty; + } + + maxLength = Math.Abs(maxLength); + + return (value.Length <= maxLength ? value : value.Substring(0, maxLength)); + } + + /// + /// takes a left of a string from given character + /// + /// + /// + /// + public static string LeftFrom(this string value, char character) + { + if(string.IsNullOrEmpty(value)) + { + return string.Empty; + } + + int index = value.IndexOf(character); + + if(index == -1) + { + return value; + } + + return value.Substring(0, index); + } + + /// + /// takes a left of a string from given string + /// + /// + /// + /// + public static string LeftFrom(this string value, string characters) + { + if(string.IsNullOrEmpty(value)) + { + return string.Empty; + } + + int index = value.IndexOf(characters); + + if(index == -1) + { + return value; + } + + return value.Substring(0, index); + } + + /// + /// takes a left of a string from given regular expression + /// + /// + /// + /// + public static string LeftFromRegex(this string value, string regex) + { + if(string.IsNullOrEmpty(value)) + { + return string.Empty; + } + + Match match = Regex.Match(value, regex); + + if(!match.Success) + { + return value; + } + + return value.Substring(0, match.Index); + } + + /// + /// takes a right of a string from given length + /// + /// + /// + /// + public static string Right(this string value, int length) + { + if(string.IsNullOrEmpty(value)) + { + return string.Empty; + } + + return value.Length <= length ? value : value.Substring(value.Length - length); + } + + /// + /// takes a right of a string from given character + /// + /// + /// + /// + public static string RightFrom(this string value, char character) + { + if(string.IsNullOrEmpty(value)) + { + return string.Empty; + } + + int index = value.LastIndexOf(character); + + if(index == -1) + { + return value; + } + + return value.Substring(index + 1); + } + + /// + /// takes a right of a string from given string including that string + /// + /// + /// + /// + public static string RightFrom(this string value, string characters) + { + if(string.IsNullOrEmpty(value)) + { + return string.Empty; + } + + int index = value.LastIndexOf(characters); + + if(index == -1) + { + return value; + } + + return value.Substring(index); + } + + /// + /// takes a right of a string from given string not including the string + /// + /// + /// + /// + public static string RightAfter(this string value, string characters) + { + if(string.IsNullOrEmpty(value)) + { + return string.Empty; + } + + int index = value.LastIndexOf(characters); + + if(index == -1) + { + return value; + } + + if(value.Length > index + characters.Length) + { + return value.Substring(index + characters.Length); + } + else + { + return string.Empty; + } + } + + + /// + /// takes a right of a string form given regular expression + /// + /// + /// + /// + public static string RightFromRegex(this string value, string regex) + { + if(string.IsNullOrEmpty(value)) + { + return string.Empty; + } + + Match match = Regex.Match(value, regex); + + if(!match.Success) + { + return value; + } + + return value.Substring(match.Index + match.Length); + } + + /// + /// returns the first match of the regular expression + /// + /// + /// + /// + public static string GetFirstMatch(this string input, string pattern) + { + var match = Regex.Match(input, pattern); + return match.Groups[0].Value; + } + + /// + /// reads the next value after provided identifier + /// for example: + /// in the string RESULT=123 and identifier = RESULT this function returns 123 + /// + /// + /// + /// + public static T GetValueAfterIdentifier(this string input, string identifier) => TypeConverter.ChangeType(GetFirstMatch(input, $"(?<={identifier}=)[^ ]+|$")); + + + /// + /// checks for numeric value + /// + /// + /// + public static bool IsNumeric(this string input) + { + if(string.IsNullOrEmpty(input)) + { + return false; + } + + return Regex.IsMatch(input.Trim(), @"^[\d.-]+$"); + } + + /// + /// converts string to Pascal Case + /// + /// + /// + public static string ToPascalCase(this string text) + { + string yourString = text.ToLower().Replace("_", " "); + TextInfo info = CultureInfo.CurrentCulture.TextInfo; + return info.ToTitleCase(yourString).Replace(" ", string.Empty); + } + } +} \ No newline at end of file diff --git a/Source/LogDashboard/LogDashboard/Helpers/TVIExtender.cs b/Source/LogDashboard/LogDashboard/Helpers/TVIExtender.cs new file mode 100644 index 0000000..978eda6 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Helpers/TVIExtender.cs @@ -0,0 +1,136 @@ +//******************************************************************************// +// TVIExtender.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using System.Windows.Controls.Primitives; +using System.Windows.Controls; +using System.Windows; + +namespace Raytheon.LogDashboard.Helpers +{ + public class TVIExtender + { + private TreeViewItem item; + + public static DependencyProperty UseExtenderProperty = + DependencyProperty.RegisterAttached("UseExtender", typeof(bool), typeof(TVIExtender), + new PropertyMetadata(false, OnChangedUseExtender)); + + public static bool GetUseExtender(DependencyObject sender) + { + return (bool)sender.GetValue(UseExtenderProperty); + } + + public static void SetUseExtender(DependencyObject sender, bool useExtender) + { + sender.SetValue(UseExtenderProperty, useExtender); + } + + private static void OnChangedUseExtender(DependencyObject sender, DependencyPropertyChangedEventArgs e) + { + if(sender is TreeViewItem item) + { + if((bool)e.NewValue) + { + if(item.ReadLocalValue(ItemExtenderProperty) == DependencyProperty.UnsetValue) + { + TVIExtender extender = new TVIExtender(item); + item.SetValue(ItemExtenderProperty, extender); + } + } + else + { + if(item.ReadLocalValue(ItemExtenderProperty) != DependencyProperty.UnsetValue) + { + TVIExtender extender = (TVIExtender)item.ReadLocalValue(ItemExtenderProperty); + extender.Detach(); + item.SetValue(ItemExtenderProperty, DependencyProperty.UnsetValue); + } + } + } + } + + public static DependencyProperty ItemExtenderProperty = + DependencyProperty.RegisterAttached("ItemExtender", typeof(TVIExtender), typeof(TVIExtender)); + + public static DependencyProperty IsLastOneProperty = + DependencyProperty.RegisterAttached("IsLastOne", typeof(bool), typeof(TVIExtender)); + + public static bool GetIsLastOne(DependencyObject sender) + { + return (bool)sender.GetValue(IsLastOneProperty); + } + + public static void SetIsLastOne(DependencyObject sender, bool isLastOne) + { + sender.SetValue(IsLastOneProperty, isLastOne); + } + + public TVIExtender(TreeViewItem item) + { + this.item = item; + + ItemsControl ic = ItemsControl.ItemsControlFromItemContainer(this.item); + ic.ItemContainerGenerator.ItemsChanged += OnItemsChangedItemContainerGenerator; + + item.SetValue(IsLastOneProperty, ic.ItemContainerGenerator.IndexFromContainer(this.item) == ic.Items.Count - 1); + } + + private void OnItemsChangedItemContainerGenerator(object sender, ItemsChangedEventArgs e) + { + ItemsControl ic = ItemsControl.ItemsControlFromItemContainer(item); + + if(null != ic) + { + item.SetValue(IsLastOneProperty, ic.ItemContainerGenerator.IndexFromContainer(item) == ic.Items.Count - 1); + } + + } + + private void Detach() + { + if(item != null) + { + ItemsControl ic = ItemsControl.ItemsControlFromItemContainer(item); + if(ic == null) + { + return; + } + + ic.ItemContainerGenerator.ItemsChanged -= OnItemsChangedItemContainerGenerator; + item = null; + } + } + } +} diff --git a/Source/LogDashboard/LogDashboard/Helpers/TypeConverter.cs b/Source/LogDashboard/LogDashboard/Helpers/TypeConverter.cs new file mode 100644 index 0000000..773de1c --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Helpers/TypeConverter.cs @@ -0,0 +1,91 @@ +//******************************************************************************// +// TypeConverter.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using System; +using System.ComponentModel; + +namespace Raytheon.LogDashboard.Helpers +{ + // + // Summary: + // type conversion utility with a special case for enums + public static class TypeConverter + { + // + // Summary: + // special rule for enumeration when converting a type + // + // Parameters: + // value: + // + // Type parameters: + // T: + public static T ChangeType(object value) + { + if(!typeof(T).IsEnum) + { + return (T)ChangeType(typeof(T), value); + } + + return (T)Enum.Parse(typeof(T), value.ToString()); + } + + // + // Summary: + // convert type with TypeDescriptor + // + // Parameters: + // t: + // + // value: + public static object ChangeType(Type t, object value) + { + return TypeDescriptor.GetConverter(t).ConvertFrom(value); + } + + // + // Summary: + // register type with the type descriptor for later conversion + // + // Type parameters: + // T: + // + // TC: + public static void RegisterTypeConverter() where TC : System.ComponentModel.TypeConverter + { + TypeDescriptor.AddAttributes(typeof(T), new TypeConverterAttribute(typeof(TC))); + } + } +} \ No newline at end of file diff --git a/Source/LogDashboard/LogDashboard/Helpers/UnsafeNative.cs b/Source/LogDashboard/LogDashboard/Helpers/UnsafeNative.cs new file mode 100644 index 0000000..18146f1 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Helpers/UnsafeNative.cs @@ -0,0 +1,100 @@ +//******************************************************************************// +// UnsafeNative.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// + +// Ignore Spelling: COPYDATA + +using System; +using System.ComponentModel; +using System.Runtime.InteropServices; +using System.Text; + +namespace Raytheon.LogDashboard.Helpers +{ + internal static class UnsafeNative + { + public const int WM_COPYDATA = 0x004A; + + public static string GetMessage(int message, IntPtr lParam) + { + if(message == WM_COPYDATA) + { + try + { + var data = Marshal.PtrToStructure(lParam); + string result = string.Copy(data.LpData); + return result; + } + catch + { + return null; + } + } + + return null; + } + + public static void SendMessage(IntPtr hwnd, string message) + { + byte[] messageBytes = Encoding.Unicode.GetBytes(message); /* ANSII encoding */ + CopyDataStruct data = new CopyDataStruct + { + DwData = IntPtr.Zero, + LpData = message, + CbData = messageBytes.Length + 1 /* +1 because of \0 string termination */ + }; + + if(SendMessage(hwnd, WM_COPYDATA, IntPtr.Zero, ref data) != 0) + { + throw new Win32Exception(Marshal.GetLastWin32Error()); + } + } + + [DllImport("user32.dll")] + public static extern bool SetForegroundWindow(IntPtr hWnd); + + [DllImport("User32.dll", EntryPoint = "SendMessage")] + private static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, ref CopyDataStruct lParam); + + [StructLayout(LayoutKind.Sequential)] + private struct CopyDataStruct + { + public IntPtr DwData; + public int CbData; + [MarshalAs(UnmanagedType.LPWStr)] + public string LpData; + } + } +} diff --git a/Source/LogDashboard/LogDashboard/LogDashboard.csproj b/Source/LogDashboard/LogDashboard/LogDashboard.csproj new file mode 100644 index 0000000..6fa0853 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/LogDashboard.csproj @@ -0,0 +1,84 @@ + + + + net472;net48 + Raytheon.LogDashboardLib + Raytheon.LogDashboard + Raytheon Technologies + Logging Dashboard Application + Specialty Engineering + Raytheon Technologies + true + 1.3.10 + $(Version) + $(Version) + true + Resources\LogDashboard.ico + True + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + True + Resource1.resx + + + + + + + + + + ResXFileCodeGenerator + Resource1.Designer.cs + + + + + + PreserveNewest + + + + + + \ No newline at end of file diff --git a/Source/LogDashboard/LogDashboard/Model/CheckBoxId.cs b/Source/LogDashboard/LogDashboard/Model/CheckBoxId.cs new file mode 100644 index 0000000..e22c5e2 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Model/CheckBoxId.cs @@ -0,0 +1,44 @@ +//******************************************************************************// +// CheckBoxId.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +// Ignore Spelling: Сheck + +namespace Raytheon.LogDashboard.Model +{ + public struct CheckBoxId + { + public static string CurrentСheckBoxId { get; set; } + } +} diff --git a/Source/LogDashboard/LogDashboard/Model/DashboardLogLevel.cs b/Source/LogDashboard/LogDashboard/Model/DashboardLogLevel.cs new file mode 100644 index 0000000..5db4b47 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Model/DashboardLogLevel.cs @@ -0,0 +1,50 @@ +//******************************************************************************// +// DashboardLogLevel.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using System; + +namespace Raytheon.LogDashboard.Model +{ + [Flags] + public enum DashboardLogLevel + { + Trace = 1 | Debug | Info | Warn | Error | Fatal, + Debug = 2 | Info | Warn | Error | Fatal, + Info = 4 | Warn | Error | Fatal, + Warn = 8 | Error | Fatal, + Error = 16 | Fatal, + Fatal = 32, + } +} diff --git a/Source/LogDashboard/LogDashboard/Model/IgnoredIPAddress.cs b/Source/LogDashboard/LogDashboard/Model/IgnoredIPAddress.cs new file mode 100644 index 0000000..d13873e --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Model/IgnoredIPAddress.cs @@ -0,0 +1,56 @@ +//******************************************************************************// +// IgnoredIPAddress.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using GalaSoft.MvvmLight; + +namespace Raytheon.LogDashboard.Model +{ + public class IgnoredIPAddr : ObservableObject + { + private string ip; + public string IP + { + get => ip; + set { Set(() => IP, ref ip, value); } + } + + private bool isActive = true; + public bool IsActive + { + get => isActive; + set { Set(() => IsActive, ref isActive, value); } + } + } +} diff --git a/Source/LogDashboard/LogDashboard/Model/ImportLogFile.cs b/Source/LogDashboard/LogDashboard/Model/ImportLogFile.cs new file mode 100644 index 0000000..bb35bcb --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Model/ImportLogFile.cs @@ -0,0 +1,52 @@ +//******************************************************************************// +// ImportLogFile.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using GalaSoft.MvvmLight; + +namespace Raytheon.LogDashboard.Model +{ + public class ImportLogFile : ObservableObject + { + public string FileName { get; set; } + public string FilePath { get; set; } + + private double process = 0; + public double Process + { + get => process; + set { Set(() => Process, ref process, value); } + } + } +} diff --git a/Source/LogDashboard/LogDashboard/Model/ImportTemplateParameters.cs b/Source/LogDashboard/LogDashboard/Model/ImportTemplateParameters.cs new file mode 100644 index 0000000..82894b7 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Model/ImportTemplateParameters.cs @@ -0,0 +1,76 @@ +//******************************************************************************// +// ImportTemplateParameters.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +namespace Raytheon.LogDashboard.Model +{ + public enum ImportTemplateParameters + { + // main + level, + logger, + message, + exception, + newline, + oneexception, + var, + + // date and time + date, + longdate, + shortdate, + ticks, + time, + eptstime, + errorloggertime, + + //Call site and stack traces + сallsite, + callsitelinenumber, + stacktrace, + + //Processes, threads and assemblies + threadid, + threadname, + processid, + processinfo, + processname, + processtime, + appdomain, + hostname, + machinename, + + other, + } +} diff --git a/Source/LogDashboard/LogDashboard/Model/LogMessage.cs b/Source/LogDashboard/LogDashboard/Model/LogMessage.cs new file mode 100644 index 0000000..5cf4bc4 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Model/LogMessage.cs @@ -0,0 +1,119 @@ +//******************************************************************************// +// LogMessage.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using GalaSoft.MvvmLight; +using System; +using System.Windows.Media; + +namespace Raytheon.LogDashboard.Model +{ + public class LogMessage : ViewModelBase, ICloneable + { + public LogMessage() + { + toggleMark.Freeze(); + } + + public ulong SequenceNumber { get; set; } + + public DateTime Time { get; set; } + + public DashboardLogLevel Level { get; set; } + + public string Logger { get; set; } = string.Empty; + + public int Thread { get; set; } + + public string ThreadName { get; set; } + + public string Message { get; set; } + + public string ExecutableName { get; set; } + + public string Address { get; set; } + + public int Port { get; set; } + + public string ExceptionString { get; set; } + + public int? ProcessID { get; set; } + + public SolidColorBrush Color { get; set; } + + public string FullPath + { + get + { + if(string.IsNullOrEmpty(ExecutableName)) + { + return Address + "." + Logger; + } + + return Address + "." + ExecutableName + "." + Logger; + } + } + + private SolidColorBrush toggleMark = new SolidColorBrush(Colors.Transparent); + public SolidColorBrush ToggleMark + { + get => toggleMark; + set + { + Set(() => ToggleMark, ref toggleMark, value); + toggleMark.Freeze(); + } + } + + public object Clone() + { + return new LogMessage + { + SequenceNumber = SequenceNumber, + Address = Address, + Port = Port, + ExecutableName = ExecutableName, + Level = Level, + Logger = Logger, + Message = Message, + Thread = Thread, + ThreadName = ThreadName, + Time = Time, + ExceptionString = ExceptionString, + Color = Color, + ProcessID = ProcessID, + }; + } + } +} diff --git a/Source/LogDashboard/LogDashboard/Model/LogTemplate.cs b/Source/LogDashboard/LogDashboard/Model/LogTemplate.cs new file mode 100644 index 0000000..82fc53d --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Model/LogTemplate.cs @@ -0,0 +1,237 @@ +//******************************************************************************// +// LogTemplate.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using GalaSoft.MvvmLight.Messaging; +using Raytheon.LogDashboard.Helpers; +using Raytheon.LogDashboard.ViewModel; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Windows; + +namespace Raytheon.LogDashboard.Model +{ + public enum LogFileType + { + Undefined, + Log4j, + CSV, + EPTS, + ErrorLogger + } + + public class LogTemplate + { + public Dictionary TemplateParameters { get; } = new Dictionary(); + + public string Separator { get; set; } = ";"; + + public string Encoding { get; set; } = "UTF-8"; + + public LogFileType LogFileType { get; set; } + + /// + /// trying to detect template + /// + /// + /// + public bool TryGetLogTemplateByAutoDetect(string firstMessage) + { + if(string.IsNullOrWhiteSpace(firstMessage)) + { + Messenger.Default.Send("An error occurred while trying to automatically match the message template.\nFirst Message is Empty", "DisplayCustomMessage"); + return false; + } + + if(TryDetectTemplate(firstMessage) == LogFileType.Undefined) + { + Messenger.Default.Send("An error occurred while trying to automatically match the message template.\nLog file type is undefined", "DisplayCustomMessage"); + return false; + } + return true; + } + + /// + /// trying to detect template + /// + /// + /// + public LogFileType TryDetectTemplate(string log) + { + LogFileType = LogFileType.Undefined; + + if(log.StartsWith(" otherIndexes = new List(); + + for(int i = 0; i < logSplit.Length; i++) + { + + if(i == dateTimeIndex || i == logLevelIndex || intIndexes.Contains(i)) + { + continue; + } + + if(!string.IsNullOrEmpty(logSplit[i])) + { + otherIndexes.Add(i); + } + } + + if(otherIndexes.Count > 1) + { + TemplateParameters.Add(ImportTemplateParameters.logger, otherIndexes.First()); + } + + TemplateParameters.Add(dataParameter, dateTimeIndex); + TemplateParameters.Add(ImportTemplateParameters.level, logLevelIndex); + + TemplateParameters.Add(ImportTemplateParameters.message, otherIndexes.Last()); + + if(intIndexes.Count > 0) + { + TemplateParameters.Add(ImportTemplateParameters.threadid, intIndexes.Last()); + } + + LogFileType = LogFileType.CSV; + + } + + return LogFileType; + } + + private int GetDateTimeIndex(string[] logSplit, ref ImportTemplateParameters dateTemplateParameter) + { + int index = -1; + for(int i = 0; i < logSplit.Length; i++) + { + string columnString = logSplit[i].Trim(); + + if(DateTime.TryParse(columnString, out DateTime date)) + { + return i; + } + + if(DateTime.TryParseExact(columnString, "MM-dd-y HH:mm:ss.ffff", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime dt)) + { + dateTemplateParameter = ImportTemplateParameters.eptstime; + return i; + } + // legacy Error Logger format + if(DateTime.TryParseExact(columnString, "ddd MMM dd HH:mm:ss yyyy fff\\m\\s", null, DateTimeStyles.None, out dt)) + { + dateTemplateParameter = ImportTemplateParameters.errorloggertime; + return i; + } + + // TODO AK + if(long.TryParse(columnString, out long tickDateTime)) + { + DateTime dateFromTicks = new DateTime(tickDateTime); + dateTemplateParameter = ImportTemplateParameters.ticks; + return i; + } + } + return index; + } + + private List GetIntIndexes(string[] logSplit) + { + List indexes = new List(); + for(int i = 0; i < logSplit.Length; i++) + { + if(logSplit[i].IsNumeric()) + { + indexes.Add(i); + } + } + return indexes; + } + + private int GetLogLevelIndex(string[] logSplit) + { + int index = -1; + for(int i = 0; i < logSplit.Length; i++) + { + string line = logSplit[i]?.Trim(); + if(LogDashboardViewModel.LogTypeArray.Contains(line)) + { + return i; + } + } + return index; + } + } +} diff --git a/Source/LogDashboard/LogDashboard/Model/LogTemplateItem.cs b/Source/LogDashboard/LogDashboard/Model/LogTemplateItem.cs new file mode 100644 index 0000000..93c06a5 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Model/LogTemplateItem.cs @@ -0,0 +1,92 @@ +//******************************************************************************// +// LogTemplateItem.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using System.Windows.Data; +using System.Xml.Serialization; + +namespace Raytheon.LogDashboard.Model +{ + [Serializable] + [DataContract] + public class LogTemplateItem + { + public LogTemplateItemInfo SelectedTemplateParameter { get; set; } + + public LogTemplateItem() + { + List test = new List + { + new LogTemplateItemInfo {Group = "Main", Parameter = ImportTemplateParameters.level}, + new LogTemplateItemInfo {Group = "Main", Parameter = ImportTemplateParameters.logger}, + new LogTemplateItemInfo {Group = "Main", Parameter = ImportTemplateParameters.message}, + new LogTemplateItemInfo {Group = "Main", Parameter = ImportTemplateParameters.exception}, + new LogTemplateItemInfo {Group = "Main", Parameter = ImportTemplateParameters.newline}, + new LogTemplateItemInfo {Group = "Main", Parameter = ImportTemplateParameters.oneexception}, + new LogTemplateItemInfo {Group = "Main", Parameter = ImportTemplateParameters.var}, + + new LogTemplateItemInfo {Group = "Date and Time", Parameter = ImportTemplateParameters.date}, + new LogTemplateItemInfo {Group = "Date and Time", Parameter = ImportTemplateParameters.longdate}, + new LogTemplateItemInfo {Group = "Date and Time", Parameter = ImportTemplateParameters.shortdate}, + new LogTemplateItemInfo {Group = "Date and Time", Parameter = ImportTemplateParameters.ticks}, + new LogTemplateItemInfo {Group = "Date and Time", Parameter = ImportTemplateParameters.time}, + + new LogTemplateItemInfo {Group = "Call Site and Stack Traces", Parameter = ImportTemplateParameters.сallsite}, + new LogTemplateItemInfo {Group = "Call Site and Stack Traces", Parameter = ImportTemplateParameters.callsitelinenumber}, + new LogTemplateItemInfo {Group = "Call Site and Stack Traces", Parameter = ImportTemplateParameters.stacktrace}, + + new LogTemplateItemInfo {Group = "Processes, Threads and Assemblies", Parameter = ImportTemplateParameters.threadid}, + new LogTemplateItemInfo {Group = "Processes, Threads and Assemblies", Parameter = ImportTemplateParameters.threadname}, + new LogTemplateItemInfo {Group = "Processes, Threads and Assemblies", Parameter = ImportTemplateParameters.processid}, + new LogTemplateItemInfo {Group = "Processes, Threads and Assemblies", Parameter = ImportTemplateParameters.processinfo}, + new LogTemplateItemInfo {Group = "Processes, Threads and Assemblies", Parameter = ImportTemplateParameters.processname}, + new LogTemplateItemInfo {Group = "Processes, Threads and Assemblies", Parameter = ImportTemplateParameters.processtime}, + new LogTemplateItemInfo {Group = "Processes, Threads and Assemblies", Parameter = ImportTemplateParameters.appdomain}, + new LogTemplateItemInfo {Group = "Processes, Threads and Assemblies", Parameter = ImportTemplateParameters.hostname}, + new LogTemplateItemInfo {Group = "Processes, Threads and Assemblies", Parameter = ImportTemplateParameters.machinename}, + + new LogTemplateItemInfo {Group = "Other", Parameter = ImportTemplateParameters.other}, + }; + + TemplateItems = new ListCollectionView(test); + TemplateItems.GroupDescriptions.Add(new PropertyGroupDescription("Group")); + } + + [XmlIgnore] + public ListCollectionView TemplateItems { get; set; } + } +} diff --git a/Source/LogDashboard/LogDashboard/Model/LogTemplateItemInfo.cs b/Source/LogDashboard/LogDashboard/Model/LogTemplateItemInfo.cs new file mode 100644 index 0000000..aec1793 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Model/LogTemplateItemInfo.cs @@ -0,0 +1,49 @@ +//******************************************************************************// +// LogTemplateItemInfo.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using System; +using System.Runtime.Serialization; + +namespace Raytheon.LogDashboard.Model +{ + [Serializable] + [DataContract] + public class LogTemplateItemInfo + { + public ImportTemplateParameters Parameter { get; set; } + + public string Group { get; set; } + } +} diff --git a/Source/LogDashboard/LogDashboard/Model/Node.cs b/Source/LogDashboard/LogDashboard/Model/Node.cs new file mode 100644 index 0000000..3271028 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Model/Node.cs @@ -0,0 +1,151 @@ +//******************************************************************************// +// Node.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using GalaSoft.MvvmLight; +using System; +using System.Collections.ObjectModel; +using System.Windows.Media; + +namespace Raytheon.LogDashboard.Model +{ + public class Node : ObservableObject + { + private string text; + private bool? isChecked = true; + private bool isExpanded; + private bool isSelected = false; + private string source = string.Empty; + + public Node() + { + Id = Guid.NewGuid().ToString(); + toggleMark.Freeze(); + } + + public Node(Node parent, string txt) + { + toggleMark.Freeze(); + Id = Guid.NewGuid().ToString(); + Parent = parent; + Text = txt; + + if(Parent != null && parent.Text != "Root") + { + IsExpanded = Parent.IsExpanded; + + Logger = Parent.Logger + "." + Text; + + if(!string.IsNullOrEmpty(Parent.Source)) + { + Source = Parent.Source; + } + } + else + { + Logger = Text; + } + } + + public ObservableCollection Children { get; } = new ObservableCollection(); + + public Node Parent { get; } + + public bool? IsChecked + { + get => isChecked; + set { Set(() => IsChecked, ref isChecked, value); } + } + + public string Text + { + get => text; + set { Set(() => Text, ref text, value); } + } + + public string Logger { get; set; } + public bool IsRoot { get; set; } + + public bool IsExpanded + { + get => isExpanded; + set { Set(() => IsExpanded, ref isExpanded, value); } + } + + private bool isVisible = true; + public bool IsVisible + { + get => isVisible; + set { Set(() => IsVisible, ref isVisible, value); } + } + + public string Source + { + get => source; + set { Set(() => Source, ref source, value); } + } + + private SolidColorBrush toggleMark = new SolidColorBrush(Colors.Transparent); + + public SolidColorBrush ToggleMark + { + get => toggleMark; + set + { + Set(() => ToggleMark, ref toggleMark, value); + toggleMark.Freeze(); + } + } + + public string Id { get; set; } + + private void CheckChildNodes(ObservableCollection itemsChild, bool? isChecked) + { + foreach(Node item in itemsChild) + { + item.IsChecked = isChecked; + if(item.Children.Count != 0) + { + CheckChildNodes(item.Children, isChecked); + } + } + } + + public bool IsSelected + { + get => isSelected; + set { Set(() => IsSelected, ref isSelected, value); } + } + } +} diff --git a/Source/LogDashboard/LogDashboard/Model/Receiver.cs b/Source/LogDashboard/LogDashboard/Model/Receiver.cs new file mode 100644 index 0000000..bc39ef2 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Model/Receiver.cs @@ -0,0 +1,365 @@ +//******************************************************************************// +// Receiver.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using GalaSoft.MvvmLight; +using Raytheon.LogDashboard.Helpers; +using Raytheon.LogDashboard.Parsers; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Runtime.Serialization; +using System.Windows.Media; +using System.Xml.Serialization; + +namespace Raytheon.LogDashboard.Model +{ + public enum ReceiverType + { + [Description("UDP")] + UDP, + [Description("WCF Named Pipes")] + WCF, + [Description("Error Logger")] + ErrorLogger, + [Description("Windows Debug")] + WinDebug + } + + public enum ErrorLoggerType + { + [Description("32 Bit Logger")] + BIT_32, + [Description("64 Bit Logger")] + BIT_64 + } + + [Serializable] + [DataContract] + public class Receiver : ViewModelBase, ICloneable, IDisposable + { + [NonSerialized] + private SolidColorBrush color = new SolidColorBrush(Colors.White); + [DataMember(Name = "ColorString")] + private string colorString; + private int port = 0; + private bool isActive = true; + private string encoding = "UTF-8"; + private IEnumerable receiverNames { get; set; } + + public PacketsParser Parser { get; set; } + + public Receiver(string name, string address, ReceiverType type, IEnumerable receiverNames) + { + Parser = null; + this.receiverNames = receiverNames; + Name = GetUniqueName(name, 0); + Address = address; + ReceiverType = type; + ColorString = "#FFFFFFFF"; + } + + public Receiver(ReceiverSetting receiverSetting) + { + Name = receiverSetting.Name; + ReceiverType = receiverSetting.ReceiverType; + Address = receiverSetting.Address; + Parser = null; + Port = receiverSetting.Port; + IsActive = receiverSetting.IsActive; + Encoding = receiverSetting.Encoding; + ColorString = receiverSetting.ColorString; + IsAddressVisible = receiverSetting.IsAddressVisible; + IsPortVisible = receiverSetting.IsPortVisible; + IsHidden = receiverSetting.IsHidden; + IsAutoSave = receiverSetting.IsAutoSave; + } + + /// + /// sets the parser type plus sets port number for UDP parser + /// + /// + /// + private ReceiverType DeriveTypeFromParser(PacketsParser parser) + { + switch(parser) + { + case UDPPacketsParser udp: + Port = udp.Port; + return ReceiverType.UDP; + case WCFPacketsParser _: + return ReceiverType.WCF; + case ErrorLoggerPacketsParser _: + return ReceiverType.ErrorLogger; + case DebugMonitorParser _: + return ReceiverType.WinDebug; + default: + return ReceiverType.UDP; + } + } + + public bool IsHidden { get; set; } + + private string name; + public string Name + { + get => name; + set { Set(() => Name, ref name, value); } + } + + private ErrorLoggerType errorLoggerType; + public ErrorLoggerType ErrorLoggerType + { + get => errorLoggerType; + set + { + Set(() => ErrorLoggerType, ref errorLoggerType, value); + if(ReceiverType == ReceiverType.ErrorLogger) + { + if(errorLoggerType == ErrorLoggerType.BIT_64) + { + Address = "TsdcSystemSwErrorMailSlot64"; + } + else + { + Address = "TsdcSystemSwErrorMailSlot"; + } + } + + } + } + + private ReceiverType receiverType; + public ReceiverType ReceiverType + { + get => receiverType; + set + { + Set(() => ReceiverType, ref receiverType, value); + IsAddressVisible = ReceiverType == ReceiverType.WCF || ReceiverType == ReceiverType.ErrorLogger; + + if(ReceiverType == ReceiverType.WinDebug) + { + if(string.IsNullOrEmpty(Name)) + { + Name = GetUniqueName("Windows Debug", 0); + } + Address = string.Empty; + Port = 0; + IsPortVisible = false; + IsAddressVisible = false; + IsErrorLogger = false; + IsAutoSave = false; + } + else if(ReceiverType == ReceiverType.UDP) + { + if(string.IsNullOrEmpty(Name)) + { + Name = GetUniqueName("UDP", 0); + } + Address = string.Empty; + IsPortVisible = true; + IsAddressVisible = false; + IsErrorLogger = false; + IsAutoSave = false; + } + else + { + Port = 0; + IsPortVisible = false; + IsAddressVisible = true; + IsErrorLogger = false; + IsAutoSave = false; + } + + if(ReceiverType == ReceiverType.WCF) + { + if(string.IsNullOrEmpty(Name)) + { + Name = GetUniqueName("EPTS", 0); + } + IsErrorLogger = false; + Address = "net.pipe://localhost/EPServer"; + IsAutoSave = false; + } + + if(ReceiverType == ReceiverType.ErrorLogger) + { + if(string.IsNullOrEmpty(Name)) + { + Name = GetUniqueName("Error Logger", 0); + } + IsErrorLogger = true; + Address = "TsdcSystemSwErrorMailSlot"; + IsAutoSave = true; + } + } + } + + /// + /// returns a unique suggestion for the receiver name + /// + /// + /// + /// + private string GetUniqueName(string baseName, int index) + { + if(receiverNames == null) + { + return baseName; + } + string rollingName = index > 1 ? $"{baseName} {index}" : baseName; + while(receiverNames.ToList().Contains(rollingName)) + { + return GetUniqueName(baseName, ++index); + } + return rollingName; + } + + private bool isPortVisible; + public bool IsPortVisible + { + get => isPortVisible; + set { Set(() => IsPortVisible, ref isPortVisible, value); } + } + private bool isErrorLogger; + public bool IsErrorLogger + { + get => isErrorLogger; + set { Set(() => IsErrorLogger, ref isErrorLogger, value); } + } + + public int Port + { + get => port; + set { Set(() => Port, ref port, value); } + } + + [XmlIgnore] + public SolidColorBrush Color + { + get => color; + set + { + colorString = value.ToARGB(); + Set(() => Color, ref color, value); + } + } + + public string ColorString + { + get => colorString; + set + { + if(string.IsNullOrEmpty(value)) + { + value = "#FFFFFFFF"; + } + + color = color.FromARGB(value); + Set(() => ColorString, ref colorString, value); + } + } + + public bool IsActive + { + get => isActive; + set { Set(() => IsActive, ref isActive, value); } + } + + public string Encoding + { + get => encoding; + set { Set(() => Encoding, ref encoding, value); } + } + + private string address; + public string Address + { + get => address; + set { Set(() => Address, ref address, value); } + } + + private bool isAddressVisible; + public bool IsAddressVisible + { + get => isAddressVisible; + set { Set(() => IsAddressVisible, ref isAddressVisible, value); } + } + + private bool isAutoSave; + public bool IsAutoSave + { + get => isAutoSave && Settings.Instance.IsAutoSave; + set + { + Set(() => IsAutoSave, ref isAutoSave, value); + + if(Parser != null) + { + Parser.IsAutoSave = isAutoSave; + } + } + } + + [OnDeserialized] + private void SetValuesOnDeserialized(StreamingContext context) + { + color = color.FromARGB(colorString); + } + + public object Clone() + { + return new Receiver(Name, Address, ReceiverType, receiverNames) + { + ColorString = ColorString, + IsActive = IsActive, + Color = Color, + Port = Port, + Encoding = Encoding, + IsAddressVisible = IsAddressVisible, + IsAutoSave = IsAutoSave, + }; + } + + /// + /// clear the parser + /// + public void Dispose() + { + Parser?.Dispose(); + } + } +} diff --git a/Source/LogDashboard/LogDashboard/Model/ReceiverSetting.cs b/Source/LogDashboard/LogDashboard/Model/ReceiverSetting.cs new file mode 100644 index 0000000..03ee7b8 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Model/ReceiverSetting.cs @@ -0,0 +1,94 @@ +//******************************************************************************// +// ReceiverSetting.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using System.Xml.Serialization; + +namespace Raytheon.LogDashboard.Model +{ + public class ReceiverSetting + { + public ReceiverSetting() + { + } + + public ReceiverSetting(Receiver receiver) + { + Name = receiver.Name; + IsHidden = receiver.IsHidden; + ReceiverType = receiver.ReceiverType; + IsPortVisible = receiver.IsPortVisible; + Port = receiver.Port; + IsAddressVisible = receiver.IsAddressVisible; + Address = receiver.Address; + IsActive = receiver.IsActive; + Encoding = receiver.Encoding; + ColorString = receiver.ColorString; + IsAutoSave = receiver.IsAutoSave; + } + + [XmlElement] + public bool IsHidden { get; set; } + + [XmlElement] + public string Name { get; set; } + + [XmlElement] + public ReceiverType ReceiverType { get; set; } + + [XmlElement] + public bool IsPortVisible { get; set; } + + [XmlElement] + public bool IsAutoSave { get; set; } + + [XmlElement] + public int Port { get; set; } + + [XmlElement] + public bool IsAddressVisible { get; set; } + + [XmlElement] + public string Address { get; set; } + + [XmlElement] + public bool IsActive { get; set; } + + [XmlElement] + public string Encoding { get; set; } + + [XmlElement] + public string ColorString { get; set; } + } +} diff --git a/Source/LogDashboard/LogDashboard/Model/ReleaseNotes.cs b/Source/LogDashboard/LogDashboard/Model/ReleaseNotes.cs new file mode 100644 index 0000000..c24ad68 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Model/ReleaseNotes.cs @@ -0,0 +1,58 @@ +//******************************************************************************// +// ReleaseNotes.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using System.Xml.Serialization; + +namespace Raytheon.LogDashboard.Model +{ + [Serializable] + [DataContract] + public class ReleaseNotes + { + public string Version { get; set; } + + public List NewFeatures { get; set; } = new List(); + + public List ChangedFeatures { get; set; } = new List(); + + public List FixedBugs { get; set; } = new List(); + + [XmlIgnore] + public bool IsExpanded { get; set; } = false; + } +} diff --git a/Source/LogDashboard/LogDashboard/Model/Settings.cs b/Source/LogDashboard/LogDashboard/Model/Settings.cs new file mode 100644 index 0000000..419e1f6 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Model/Settings.cs @@ -0,0 +1,250 @@ +//******************************************************************************// +// Settings.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// + +// Ignore Spelling: Taskbar + +using System; +using System.Collections.Generic; +using System.IO; +using System.Security.Permissions; +using System.Web; +using System.Windows.Media; +using System.Windows; +using NLog; +using Raytheon.Common; +using Raytheon.LogDashboard.ViewModel; +using System.Linq; + +namespace Raytheon.LogDashboard.Model +{ + [Serializable] + [PermissionSet(SecurityAction.Demand, Name = "FullTrust")] + [AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)] + public sealed class Settings + { + private static readonly Logger logger = LogManager.GetCurrentClassLogger(); + private static Settings instance; + private readonly string settingsPath; + private static LogDashViewModelLocator locatorInstance => (Application.Current.Resources["LogDashLocator"] as LogDashViewModelLocator); + + public bool AutoStartInStartup { get; set; } = false; + public bool MinimizeToTray { get; set; } = false; + public bool OnlyOneAppInstance { get; set; } = false; + public bool IsEnabledMaxMessageBufferSize { get; set; } = false; + public int MaxMessageBufferSize { get; set; } = 1000000; + public int DeletedMessagesCount { get; set; } = 100000; + public string DataFormat { get; set; } = "MM/dd/yyyy HH:mm:ss.fff"; + public string FontColor { get; set; } = "#FFFFFFFF"; + + private static List BuildListOfThemes() + { + List> colors = typeof(Colors) + .GetProperties() + .Where(prop => typeof(Color).IsAssignableFrom(prop.PropertyType)) + .Select(prop => new KeyValuePair(prop.Name, (Color)prop.GetValue(null))) + .ToList(); + + List themes = new List(); + + foreach(var color in colors) + { + themes.Add(new ColorTheme { Color = new SolidColorBrush(color.Value), Name = color.Key, ThemeColorString = color.Value.ToString() }); + } + + return themes; + } + public static List ColorThemes { get; } = BuildListOfThemes(); + + public static List Themes { get; } = new List { "BaseLight", "BaseDark" }; + + public ColorTheme CurrentColorTheme { get; set; } + + public string CurrentTheme { get; set; } + + public List Receivers { get; set; } = new List(); + public List IgnoredIPs { get; set; } = new List(); + + /// + /// show column with source + /// + public bool IsShowSourceColumn { get; set; } = false; + + /// + /// show thread column + /// + public bool IsShowThreadColumn { get; set; } = true; + + /// + /// show progress in the taskbar + /// + public bool IsShowTaskbarProgress { get; set; } = true; + + /// + /// highlight message with receiver color + /// + public bool ShowMessageHighlightByReceiverColor { get; set; } = false; + + /// + /// separate logs by port number + /// + public bool IsSeparateIPLoggersByPort { get; set; } = false; + + public bool IsAutoSave { get; set; } + + public bool IsErrorLogger { get; set; } + + public string AutoSaveLocation { get; set; } + + public long AutoSaveMaxSize { get; set; } + + /// + /// indicates if LogDashboard is embedded in another application + /// + public bool EmbeddedMode { get; set; } + + private Settings(string path) + { + settingsPath = !string.IsNullOrEmpty(path) + ? path + : Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "LogDashboard", "LogDashboard.xml"); + } + + public static Settings Instance => instance ?? SetInstance(""); + + public static Settings SetInstance(string path) => instance ?? (instance = new Settings(path)); + + /// + /// using theme + /// + public void ApplyTheme() + { + try + { + Application.Current.Resources.MergedDictionaries[2] = new ResourceDictionary { Source = CurrentColorTheme.ThemeUri }; + } + catch(Exception e) + { + logger.Warn(e, $"An error occurred while ApplyTheme. SelectedTheme - {CurrentColorTheme.Name}"); + } + } + + /// + /// save settings + /// + /// + public bool Save() + { + try + { + ConfigurationFile configurationFile = new ConfigurationFile(settingsPath); + + List receiverSettings = new List(); + foreach(Receiver receiver in Instance.Receivers) + { + receiverSettings.Add(new ReceiverSetting(receiver)); + } + + configurationFile.WriteValue("Base", "AutoStartInStartup", Instance.AutoStartInStartup); + configurationFile.WriteValue("Base", "MinimizeToTray", Instance.MinimizeToTray); + configurationFile.WriteValue("CurrentThemes", "CurrentColorTheme", Instance.CurrentColorTheme); + configurationFile.WriteValue("CurrentThemes", "CurrentTheme", Instance.CurrentTheme); + configurationFile.WriteValue("Base", "DataFormat", Instance.DataFormat); + configurationFile.WriteList("IgnoredIP", "IgnoredIP", Instance.IgnoredIPs); + configurationFile.WriteList("ReceiverList", "Receiver", receiverSettings); + configurationFile.WriteValue("Base", "FontColor", Instance.FontColor); + configurationFile.WriteValue("Base", "OnlyOneAppInstance", Instance.OnlyOneAppInstance); + configurationFile.WriteValue("Base", "IsEnabledMaxMessageBufferSize", Instance.IsEnabledMaxMessageBufferSize); + configurationFile.WriteValue("Base", "MaxMessageBufferSize", Instance.MaxMessageBufferSize); + configurationFile.WriteValue("Base", "DeletedMessagesCount", Instance.DeletedMessagesCount); + configurationFile.WriteValue("Base", "IsShowSourceColumn", Instance.IsShowSourceColumn); + configurationFile.WriteValue("Base", "IsShowThreadColumn", Instance.IsShowThreadColumn); + configurationFile.WriteValue("Base", "IsShowTaskbarProgress", Instance.IsShowTaskbarProgress); + configurationFile.WriteValue("Base", "ShowMessageHighlightByReceiverColor", Instance.ShowMessageHighlightByReceiverColor); + configurationFile.WriteValue("Base", "IsSeparateIPLoggersByPort", Instance.IsSeparateIPLoggersByPort); + configurationFile.WriteValue("Base", "EmbeddedMode", Instance.EmbeddedMode); + configurationFile.WriteValue("Base", "IsAutoSave", Instance.IsAutoSave); + configurationFile.WriteValue("Base", "IsErrorLogger", Instance.IsErrorLogger); + configurationFile.WriteValue("Base", "AutoSaveLocation", Instance.AutoSaveLocation ?? ""); + + return true; + } + catch(Exception e) + { + logger.Warn(e, "An error occurred while Save settings."); + return false; + } + } + + public void Load() + { + IConfigurationFile configurationFile = new ConfigurationFile(settingsPath); + Instance.AutoStartInStartup = configurationFile.ReadValue("Base", "AutoStartInStartup", true); + Instance.MinimizeToTray = configurationFile.ReadValue("Base", "MinimizeToTray", false); + + Instance.CurrentColorTheme = configurationFile.ReadValue("CurrentThemes", "CurrentColorTheme", new ColorTheme { Color = new SolidColorBrush(), Name = "DodgerBlue", ThemeColorString = "#FF1E90FF" }); + + Instance.CurrentTheme = configurationFile.ReadValue("CurrentThemes", "CurrentTheme", "BaseLight"); + + Instance.DataFormat = configurationFile.ReadValue("Base", "DataFormat", "MM/dd/yyyy HH:mm:ss.fff"); + Instance.IgnoredIPs = configurationFile.ReadList("IgnoredIP", "IgnoredIP", new List()); + var receiverSettins = configurationFile.ReadList("ReceiverList", "Receiver", new List + { + new ReceiverSetting { Name = "UDP", ReceiverType = ReceiverType.UDP, Port = 7777, IsActive = true, ColorString = "#00FFFFFF", IsPortVisible = true, Encoding = "UTF-8" } + }); + + foreach(ReceiverSetting receiverSetting in receiverSettins) + { + Instance.Receivers.Add(new Receiver(receiverSetting)); + } + + Instance.FontColor = configurationFile.ReadValue("Base", "FontColor", "#FF1E90FF"); + Instance.OnlyOneAppInstance = configurationFile.ReadValue("Base", "OnlyOneAppInstance", true); + Instance.IsEnabledMaxMessageBufferSize = configurationFile.ReadValue("Base", "IsEnabledMaxMessageBufferSize", false); + Instance.MaxMessageBufferSize = configurationFile.ReadValue("Base", "MaxMessageBufferSize", 1000000); + Instance.DeletedMessagesCount = configurationFile.ReadValue("Base", "DeletedMessagesCount", 100000); + Instance.IsShowSourceColumn = configurationFile.ReadValue("Base", "IsShowSourceColumn", true); + Instance.IsShowThreadColumn = configurationFile.ReadValue("Base", "IsShowThreadColumn", true); + Instance.IsShowTaskbarProgress = configurationFile.ReadValue("Base", "IsShowTaskbarProgress", true); + Instance.ShowMessageHighlightByReceiverColor = configurationFile.ReadValue("Base", "ShowMessageHighlightByReceiverColor", true); + Instance.IsSeparateIPLoggersByPort = configurationFile.ReadValue("Base", "IsSeparateIPLoggersByPort", true); + Instance.EmbeddedMode = configurationFile.ReadValue("Base", "EmbeddedMode", false); + Instance.IsAutoSave = configurationFile.ReadValue("Base", "IsAutoSave", false); + Instance.IsErrorLogger = configurationFile.ReadValue("Base", "IsErrorLogger", false); + Instance.AutoSaveLocation = configurationFile.ReadValue("Base", "AutoSaveLocation", ""); + Instance.AutoSaveMaxSize = configurationFile.ReadValue("Base", "AutoSaveMaxSize", 10 * 1048576); // 10 MG + } + } +} diff --git a/Source/LogDashboard/LogDashboard/Model/Theme.cs b/Source/LogDashboard/LogDashboard/Model/Theme.cs new file mode 100644 index 0000000..f8bf3a4 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Model/Theme.cs @@ -0,0 +1,83 @@ +//******************************************************************************// +// Theme.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using Raytheon.LogDashboard.Helpers; +using System; +using System.Runtime.Serialization; +using System.Windows.Media; +using System.Xml.Serialization; + +namespace Raytheon.LogDashboard.Model +{ + public class ColorTheme + { + [NonSerialized] + private SolidColorBrush themeColor = (SolidColorBrush)new BrushConverter().ConvertFrom("#3F51B5"); + + [DataMember(Name = "ThemeColorString")] + private string themeColorString; + + public string Name { get; set; } + + [XmlIgnore] + public SolidColorBrush Color + { + get => themeColor; + set + { + themeColor = value; + themeColorString = themeColor.ToARGB(); + } + } + + [XmlIgnore] + public Uri ThemeUri => new Uri($"pack://application:,,,/MahApps.Metro;component/Styles/Themes/{Name}.xaml"); + public string ThemeColorString + { + get => themeColorString; + set + { + themeColorString = value; + themeColor = themeColor.FromARGB(themeColorString); + } + } + + [OnDeserialized] + private void SetValuesOnDeserialized(StreamingContext context) + { + themeColor = themeColor.FromARGB(themeColorString); + } + } +} diff --git a/Source/LogDashboard/LogDashboard/Parsers/DebugMonitor.cs b/Source/LogDashboard/LogDashboard/Parsers/DebugMonitor.cs new file mode 100644 index 0000000..78ffe30 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Parsers/DebugMonitor.cs @@ -0,0 +1,428 @@ +//******************************************************************************// +// DebugMonitor.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using System; +using System.Threading; +using System.Runtime.InteropServices; + +namespace Raytheon.LogDashboard.Parsers +{ + /// + /// Delegate used when firing DebugMonitor.OnOutputDebug event + /// + public delegate void OnOutputDebugStringHandler(int pid, string text); + + /// + /// This class captures all strings passed to OutputDebugString when + /// the application is not debugged. + /// + /// + /// This class is a port of Microsoft's Visual Studio's C++ example "dbmon", which + /// can be found at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vcsample98/html/vcsmpdbmon.asp. + /// + /// + /// + /// public static void Main(string[] args) { + /// DebugMonitor.Start(); + /// DebugMonitor.OnOutputDebugString += new OnOutputDebugStringHandler(OnOutputDebugString); + /// Console.WriteLine("Press 'Enter' to exit."); + /// Console.ReadLine(); + /// DebugMonitor.Stop(); + /// } + /// + /// private static void OnOutputDebugString(int pid, string text) { + /// Console.WriteLine(DateTime.Now + ": " + text); + /// } + /// + /// + public static class DebugMonitor + { + #region Win32 API Imports + + [StructLayout(LayoutKind.Sequential)] + private struct SECURITY_DESCRIPTOR + { + public byte revision; + public byte size; + public short control; + public IntPtr owner; + public IntPtr group; + public IntPtr sacl; + public IntPtr dacl; + } + + [StructLayout(LayoutKind.Sequential)] + private struct SECURITY_ATTRIBUTES + { + public int nLength; + public IntPtr lpSecurityDescriptor; + public int bInheritHandle; + } + + [Flags] + private enum PageProtection : uint + { + NoAccess = 0x01, + Readonly = 0x02, + ReadWrite = 0x04, + WriteCopy = 0x08, + Execute = 0x10, + ExecuteRead = 0x20, + ExecuteReadWrite = 0x40, + ExecuteWriteCopy = 0x80, + Guard = 0x100, + NoCache = 0x200, + WriteCombine = 0x400, + } + + + private const int WAIT_OBJECT_0 = 0; + private const uint INFINITE = 0xFFFFFFFF; + private const int ERROR_ALREADY_EXISTS = 183; + + private const uint SECURITY_DESCRIPTOR_REVISION = 1; + + private const uint SECTION_MAP_READ = 0x0004; + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern IntPtr MapViewOfFile(IntPtr hFileMappingObject, uint + dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, + uint dwNumberOfBytesToMap); + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern bool UnmapViewOfFile(IntPtr lpBaseAddress); + + [DllImport("advapi32.dll", SetLastError = true)] + private static extern bool InitializeSecurityDescriptor(ref SECURITY_DESCRIPTOR sd, uint dwRevision); + + [DllImport("advapi32.dll", SetLastError = true)] + private static extern bool SetSecurityDescriptorDacl(ref SECURITY_DESCRIPTOR sd, bool daclPresent, IntPtr dacl, bool daclDefaulted); + + [DllImport("kernel32.dll")] + private static extern IntPtr CreateEvent(ref SECURITY_ATTRIBUTES sa, bool bManualReset, bool bInitialState, string lpName); + + [DllImport("kernel32.dll")] + private static extern bool PulseEvent(IntPtr hEvent); + + [DllImport("kernel32.dll")] + private static extern bool SetEvent(IntPtr hEvent); + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern IntPtr CreateFileMapping(IntPtr hFile, + ref SECURITY_ATTRIBUTES lpFileMappingAttributes, PageProtection flProtect, uint dwMaximumSizeHigh, + uint dwMaximumSizeLow, string lpName); + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern bool CloseHandle(IntPtr hHandle); + + [DllImport("kernel32", SetLastError = true, ExactSpelling = true)] + private static extern Int32 WaitForSingleObject(IntPtr handle, uint milliseconds); + #endregion + + /// + /// Fired if an application calls OutputDebugString + /// + public static event OnOutputDebugStringHandler OnOutputDebugString; + + /// + /// Event handle for slot 'DBWIN_BUFFER_READY' + /// + private static IntPtr m_AckEvent = IntPtr.Zero; + + /// + /// Event handle for slot 'DBWIN_DATA_READY' + /// + private static IntPtr m_ReadyEvent = IntPtr.Zero; + + /// + /// Handle for our shared file + /// + private static IntPtr m_SharedFile = IntPtr.Zero; + + /// + /// Handle for our shared memory + /// + private static IntPtr m_SharedMem = IntPtr.Zero; + + /// + /// Our capturing thread + /// + private static Thread m_Capturer = null; + + /// + /// Our synchronization root + /// + private static object m_SyncRoot = new object(); + + /// + /// Mutex for singleton check + /// + private static Mutex m_Mutex = null; + + /// + /// Starts this debug monitor + /// + public static void Start() + { + lock(m_SyncRoot) + { + if(m_Capturer != null) + { + throw new ApplicationException("This DebugMonitor is already started."); + } + + // Check for supported operating system. Mono (at least with *nix) won't support + // our P/Invoke calls. + if(Environment.OSVersion.ToString().IndexOf("Microsoft") == -1) + { + throw new NotSupportedException("This DebugMonitor is only supported on Microsoft operating systems."); + } + + // Check for multiple instances. As the README.TXT of the msdn + // example notes it is possible to have multiple debug monitors + // listen on OutputDebugString, but the message will be randomly + // distributed among all running instances so this won't be + // such a good idea. + m_Mutex = new Mutex(false, typeof(DebugMonitor).Namespace, out bool createdNew); + if(!createdNew) + { + throw new ApplicationException("There is already an instance of 'DbMon.NET' running."); + } + + SECURITY_DESCRIPTOR sd = new SECURITY_DESCRIPTOR(); + + // Initialize the security descriptor. + if(!InitializeSecurityDescriptor(ref sd, SECURITY_DESCRIPTOR_REVISION)) + { + throw CreateApplicationException("Failed to initializes the security descriptor."); + } + + // Set information in a discretionary access control list + if(!SetSecurityDescriptorDacl(ref sd, true, IntPtr.Zero, false)) + { + throw CreateApplicationException("Failed to initializes the security descriptor"); + } + + SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES(); + + // Create the event for slot 'DBWIN_BUFFER_READY' + m_AckEvent = CreateEvent(ref sa, false, false, "DBWIN_BUFFER_READY"); + if(m_AckEvent == IntPtr.Zero) + { + throw CreateApplicationException("Failed to create event 'DBWIN_BUFFER_READY'"); + } + + // Create the event for slot 'DBWIN_DATA_READY' + m_ReadyEvent = CreateEvent(ref sa, false, false, "DBWIN_DATA_READY"); + if(m_ReadyEvent == IntPtr.Zero) + { + throw CreateApplicationException("Failed to create event 'DBWIN_DATA_READY'"); + } + + // Get a handle to the readable shared memory at slot 'DBWIN_BUFFER'. + m_SharedFile = CreateFileMapping(new IntPtr(-1), ref sa, PageProtection.ReadWrite, 0, 4096, "DBWIN_BUFFER"); + if(m_SharedFile == IntPtr.Zero) + { + throw CreateApplicationException("Failed to create a file mapping to slot 'DBWIN_BUFFER'"); + } + + // Create a view for this file mapping so we can access it + m_SharedMem = MapViewOfFile(m_SharedFile, SECTION_MAP_READ, 0, 0, 512); + if(m_SharedMem == IntPtr.Zero) + { + throw CreateApplicationException("Failed to create a mapping view for slot 'DBWIN_BUFFER'"); + } + + // Start a new thread where we can capture the output + // of OutputDebugString calls so we don't block here. + m_Capturer = new Thread(new ThreadStart(Capture)); + m_Capturer.Start(); + } + } + + /// + /// Captures + /// + private static void Capture() + { + try + { + // Everything after the first DWORD is our debugging text + IntPtr pString = new IntPtr(m_SharedMem.ToInt64() + Marshal.SizeOf(typeof(long))); + + while(true) + { + SetEvent(m_AckEvent); + + int ret = WaitForSingleObject(m_ReadyEvent, INFINITE); + + // if we have no capture set it means that someone + // called 'Stop()' and is now waiting for us to exit + // this endless loop. + if(m_Capturer == null) + { + break; + } + + if(ret == WAIT_OBJECT_0) + { + // The first DWORD of the shared memory buffer contains + // the process ID of the client that sent the debug string. + FireOnOutputDebugString(Marshal.ReadInt32(m_SharedMem), Marshal.PtrToStringAnsi(pString)); + } + } + } + catch + { + throw; + // Cleanup + } + finally + { + Dispose(); + } + } + + private static void FireOnOutputDebugString(int pid, string text) + { + // Raise event if we have any listeners + if(OnOutputDebugString == null) + { + return; + } + +#if !DEBUG + try { +#endif + OnOutputDebugString(pid, text); +#if !DEBUG + } catch (Exception ex) { + Console.WriteLine("An 'OnOutputDebugString' handler failed to execute: " + ex.ToString()); + } +#endif + } + + /// + /// Dispose all resources + /// + private static void Dispose() + { + // Close AckEvent + if(m_AckEvent != IntPtr.Zero) + { + if(!CloseHandle(m_AckEvent)) + { + throw CreateApplicationException("Failed to close handle for 'AckEvent'"); + } + m_AckEvent = IntPtr.Zero; + } + + // Close ReadyEvent + if(m_ReadyEvent != IntPtr.Zero) + { + if(!CloseHandle(m_ReadyEvent)) + { + throw CreateApplicationException("Failed to close handle for 'ReadyEvent'"); + } + m_ReadyEvent = IntPtr.Zero; + } + + // Close SharedFile + if(m_SharedFile != IntPtr.Zero) + { + if(!CloseHandle(m_SharedFile)) + { + throw CreateApplicationException("Failed to close handle for 'SharedFile'"); + } + m_SharedFile = IntPtr.Zero; + } + + + // Unmap SharedMem + if(m_SharedMem != IntPtr.Zero) + { + if(!UnmapViewOfFile(m_SharedMem)) + { + throw CreateApplicationException("Failed to unmap view for slot 'DBWIN_BUFFER'"); + } + m_SharedMem = IntPtr.Zero; + } + + // Close our mutex + if(m_Mutex != null) + { + m_Mutex.Close(); + m_Mutex = null; + } + } + + /// + /// Stops this debug monitor. This call we block the executing thread + /// until this debug monitor is stopped. + /// + public static void Stop() + { + lock(m_SyncRoot) + { + if(m_Capturer == null) + { + throw new ObjectDisposedException("DebugMonitor", "This DebugMonitor is not running."); + } + m_Capturer = null; + + PulseEvent(m_ReadyEvent); + while(m_AckEvent != IntPtr.Zero) + { + } + } + } + + /// + /// Helper to create a new application exception, which has automatically the + /// last win 32 error code appended. + /// + /// text + private static ApplicationException CreateApplicationException(string text) + { + if(text == null || text.Length < 1) + { + throw new ArgumentNullException("text", "'text' may not be empty or null."); + } + + return new ApplicationException(string.Format("{0}. Last Win32 Error was {1}", text, Marshal.GetLastWin32Error())); + } + + } +} diff --git a/Source/LogDashboard/LogDashboard/Parsers/DebugMonitorParser.cs b/Source/LogDashboard/LogDashboard/Parsers/DebugMonitorParser.cs new file mode 100644 index 0000000..7f1b60d --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Parsers/DebugMonitorParser.cs @@ -0,0 +1,140 @@ +//******************************************************************************// +// DebugMonitorParser.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using GalaSoft.MvvmLight.Messaging; +using Raytheon.LogDashboard.Model; +using System; +using System.Collections.Generic; +using System.Net.Sockets; + +namespace Raytheon.LogDashboard.Parsers +{ + public class DebugMonitorParser : PacketsParser + { + private readonly Queue _messages = new Queue(); + + public DebugMonitorParser(string name, bool isAutoSave) + : base(name, isAutoSave) + { + } + + public DebugMonitorParser(string name, string address, bool isAutoSave) + : this(name, isAutoSave) + { + Address = address; + } + + /// + /// initialize WinDebug parser + /// + /// + public override bool Init() + { + try + { + base.Init(); + + DebugMonitor.OnOutputDebugString += DebugMonitor_OnOutputDebugString; + DebugMonitor.Start(); + + IsInitialized = true; + return IsInitialized; + } + catch(SocketException socketException) + { + Logger.Warn(socketException, "An error occurred in DebugMonitorParser initializer."); + IsInitialized = false; + return IsInitialized; + } + catch(Exception e) + { + Logger.Warn(e, "An error occurred in DebugMonitorParser initializer."); + IsInitialized = false; + return IsInitialized; + } + } + + /// + /// gets single message + /// + /// + public override LogMessage GetLog() + { + var log = _messages.Count > 0 ? _messages.Dequeue() : null; + + if(IsAutoSave && log != null) + { + Messenger.Default.Send(log, "PersistLogMessage"); + } + + return log; + } + + private void DebugMonitor_OnOutputDebugString(int pid, string text) + { + DashboardLogLevel level; + if(text.IndexOf("error", StringComparison.OrdinalIgnoreCase) >= 0) + { + level = DashboardLogLevel.Error; + } + else if(text.IndexOf("warning", StringComparison.OrdinalIgnoreCase) >= 0) + { + level = DashboardLogLevel.Warn; + } + else + { + level = DashboardLogLevel.Debug; + } + + _messages.Enqueue(new LogMessage + { + ProcessID = pid, + Thread = pid, + Logger = Name, + Address = Environment.MachineName, + Message = text, + Level = level, + Time = DateTime.Now + }); + } + + public override void Dispose() + { + base.Dispose(); + + DebugMonitor.Stop(); + } + } +} diff --git a/Source/LogDashboard/LogDashboard/Parsers/ErrorLoggerPacketsParser.cs b/Source/LogDashboard/LogDashboard/Parsers/ErrorLoggerPacketsParser.cs new file mode 100644 index 0000000..c90467d --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Parsers/ErrorLoggerPacketsParser.cs @@ -0,0 +1,209 @@ +//******************************************************************************// +// ErrorLoggerPacketsParser.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using GalaSoft.MvvmLight.Messaging; +using Raytheon.LogDashboard.Model; +using System; +using System.Diagnostics; +using System.Globalization; +using System.Linq; +using System.Threading; + +namespace Raytheon.LogDashboard.Parsers +{ + /// + /// \\\\.\\mailslot\\TsdcSystemSwErrorMailSlot + /// \\\\.\\mailslot\\TsdcSystemSwErrorMailSlot64 + /// + public class ErrorLoggerPacketsParser : PacketsParser + { + private MailslotServer mailslotServer { get; set; } + private Mutex _mutex; + + public ErrorLoggerPacketsParser(string name, bool isAutoSave) + : base(name, isAutoSave) + { } + + public ErrorLoggerPacketsParser(string name, string address, bool isAutoSave) + : this(name, isAutoSave) + { + Address = address; + } + + /// + /// + /// + /// + public override LogMessage GetLog() + { + string msg = mailslotServer.GetNextMessage(); + + if(msg != null) + { + return ParseString(msg); + } + + return null; + } + + private LogMessage ParseString(string inputString) + { + int index = 0; + string[] fields = new string[4]; + for(int i = 0; i < 3; i++) + { + int nextIndex = inputString.IndexOf(',', index); + if(nextIndex == -1) + { + throw new ArgumentException("Input string is not in the correct format."); + } + fields[i] = inputString.Substring(index, nextIndex - index).Trim(); + index = nextIndex + 1; + } + fields[3] = inputString.Substring(index).Trim(); + + LogMessage msg = new LogMessage + { + Logger = Name, + Address = Address, + Time = ParseDate(fields[1]), + Level = GetLevel(fields[2]), + Message = fields[3] + }; + + if(IsAutoSave && msg != null) + { + Messenger.Default.Send(msg, "PersistLogMessage"); + } + + return msg; + } + + private DateTime ParseDate(string data) + { + if(DateTime.TryParseExact(data, "ddd MMM dd HH:mm:ss yyyy fff'ms'", null, DateTimeStyles.AssumeLocal, out DateTime dateTime)) + { + return dateTime; + } + else + { + return DateTime.Now; + } + } + + private DashboardLogLevel GetLevel(string level) + { + switch(level) + { + case "LOG_INFO_VERBOSE": + return DashboardLogLevel.Trace; + case "LOG_INFORMATION": + return DashboardLogLevel.Info; + case "LOG_WARNING": + return DashboardLogLevel.Warn; + case "LOG_DEBUG": + return DashboardLogLevel.Debug; + case "LOG_ERROR": + return DashboardLogLevel.Error; + + default: + return DashboardLogLevel.Error; + } + } + + /// + /// + /// + /// + public override bool Init() + { + base.Init(); + + string strMutex = !string.IsNullOrEmpty(Address) && Address.Trim().EndsWith("64") ? + "ErrorLoggerMutex_F1BB29A5-0AFC-45e9-A725-C302DF7EB3CF_64" : + "ErrorLoggerMutex_F1BB29A5-0AFC-45e9-A725-C302DF7EB3CF"; + + _mutex = new Mutex(true, strMutex, out bool createdNew); + + if(!createdNew) + { + Process[] errorLoggerProcesses = Process.GetProcessesByName("ErrorLogger"); + if(errorLoggerProcesses.Any()) + { + Process er = errorLoggerProcesses.First(); + + Messenger.Default.Send("Detected ErrorLogger instance running. Please close ErrorLogger or disable the Error Logger receiver.", "DisplayCustomMessage"); + + _mutex = new Mutex(true, strMutex, out createdNew); + } + } + + if(!createdNew) + { + Logger.Error($"Error initializing Mailslot {Address}\nOnly one instance of ErrorLogger is allowed"); + + IsInitialized = false; + return false; + } + + try + { + mailslotServer = new MailslotServer(Address); + } + catch(Exception ex) + { + Logger.Error($"Error initializing Mailslot {Address}\n{ex.Message}"); + + IsInitialized = false; + return false; + } + + IsInitialized = true; + return IsInitialized; + } + + /// + /// + /// + public override void Dispose() + { + base.Dispose(); + + mailslotServer?.Dispose(); + + _mutex?.Dispose(); + } + } +} diff --git a/Source/LogDashboard/LogDashboard/Parsers/Mailslot.cs b/Source/LogDashboard/LogDashboard/Parsers/Mailslot.cs new file mode 100644 index 0000000..a559dcf --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Parsers/Mailslot.cs @@ -0,0 +1,148 @@ +//******************************************************************************// +// Mailslot.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using Microsoft.Win32.SafeHandles; +using System; +using System.ComponentModel; +using System.Runtime.ConstrainedExecution; +using System.Runtime.InteropServices; +using System.Security.Permissions; +using System.Security; +using System.Text; + +namespace Raytheon.LogDashboard.Parsers +{ + [SuppressUnmanagedCodeSecurity] + public static class Mailslot + { + public const int MailslotNoMessage = -1; + + [HostProtection(SecurityAction.LinkDemand, MayLeakOnAbort = true)] + [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] + public sealed class SafeMailslotHandle : SafeHandleZeroOrMinusOneIsInvalid + { + private SafeMailslotHandle() + : base(true) + { } + + public SafeMailslotHandle(IntPtr preexistingHandle, bool ownsHandle) + : base(ownsHandle) + { + SetHandle(preexistingHandle); + } + + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool CloseHandle(IntPtr handle); + + protected override bool ReleaseHandle() + { + return CloseHandle(base.handle); + } + } + + [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] + public static extern SafeMailslotHandle CreateMailslot(string mailslotName, + uint nMaxMessageSize, int lReadTimeout, + IntPtr securityAttributes); + + + [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetMailslotInfo(SafeMailslotHandle hMailslot, + IntPtr lpMaxMessageSize, + out int lpNextSize, out int lpMessageCount, + IntPtr lpReadTimeout); + + + [DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool ReadFile(SafeMailslotHandle handle, + byte[] bytes, int numBytesToRead, + out int numBytesRead, + IntPtr overlapped); + } + + public class MailslotServer : IDisposable + { + private Mailslot.SafeMailslotHandle _handle; + + public MailslotServer(string name) + { + _handle = Mailslot.CreateMailslot(@"\\.\mailslot\" + name, 0, 0, IntPtr.Zero); + if(_handle.IsInvalid) + { + throw new Win32Exception(); + } + } + + public string GetNextMessage() + { + if(_handle == null) + { + return null; + } + + if(!Mailslot.GetMailslotInfo(_handle, IntPtr.Zero, out int messageBytes, out _, IntPtr.Zero)) + { + throw new Win32Exception(); + } + + if(messageBytes == Mailslot.MailslotNoMessage) + { + return null; + } + + byte[] bBuffer = new byte[messageBytes]; + + if(!Mailslot.ReadFile(_handle, bBuffer, messageBytes, out int bytesRead, IntPtr.Zero) || bytesRead == 0) + { + throw new Win32Exception(); + } + + return Encoding.ASCII.GetString(bBuffer); + } + + public void Dispose() + { + if(_handle != null) + { + _handle.Close(); + _handle = null; + } + } + } +} diff --git a/Source/LogDashboard/LogDashboard/Parsers/PacketsParser.cs b/Source/LogDashboard/LogDashboard/Parsers/PacketsParser.cs new file mode 100644 index 0000000..03439b2 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Parsers/PacketsParser.cs @@ -0,0 +1,104 @@ +//******************************************************************************// +// PacketsParser.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using NLog; +using Raytheon.LogDashboard.Model; +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using System.Text; +using System.Threading; +using System.Xml; + +namespace Raytheon.LogDashboard.Parsers +{ + [Serializable] + [DataContract] + public abstract class PacketsParser : IDisposable + { + protected static readonly Logger Logger = LogManager.GetCurrentClassLogger(); + + protected readonly XmlParserContext XmlContext; + protected readonly Encoding Encoding = Encoding.ASCII; + + public string Address { get; protected set; } + + public bool IsInitialized { get; protected set; } + public List IgnoredIPs { get; set; } + + public string Name { get; set; } + + public CancellationTokenSource CancellationToken { get; set; } + + public bool IsAutoSave { get; set; } + + public PacketsParser(string name, bool isAutoSave) + { + Name = name; + + XmlContext = CreateContext(); + IgnoredIPs = Settings.Instance.IgnoredIPs; + IsAutoSave = isAutoSave; + } + + public virtual bool Init() + { + CancellationToken = new CancellationTokenSource(); + return true; + } + + public abstract LogMessage GetLog(); + + protected XmlParserContext CreateContext() + { + NameTable nt = new NameTable(); + XmlNamespaceManager nsmanager = new XmlNamespaceManager(nt); + nsmanager.AddNamespace("log4j", "http://jakarta.apache.org/log4j/"); + nsmanager.AddNamespace("nlog", "http://nlog-project.org"); + return new XmlParserContext(nt, nsmanager, "elem", XmlSpace.None, Encoding.UTF8); + } + + protected DateTime UnixTimeStampToDateTime(long unixTimeStamp) + { + return new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(unixTimeStamp); + } + + public virtual void Dispose() + { + CancellationToken?.Cancel(); + IsInitialized = false; + } + } +} diff --git a/Source/LogDashboard/LogDashboard/Parsers/UDPPacketsParser.cs b/Source/LogDashboard/LogDashboard/Parsers/UDPPacketsParser.cs new file mode 100644 index 0000000..3b423c8 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Parsers/UDPPacketsParser.cs @@ -0,0 +1,236 @@ +//******************************************************************************// +// UDPPacketsParser.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using Raytheon.LogDashboard.Model; +using System; +using System.Linq; +using System.Net.Sockets; +using System.Net; +using System.Xml; +using Raytheon.LogDashboard.Helpers; +using Settings = Raytheon.LogDashboard.Model.Settings; +using GalaSoft.MvvmLight.Messaging; + +namespace Raytheon.LogDashboard.Parsers +{ + public class UDPPacketsParser : PacketsParser + { + private UdpClient udpClient; + private IPEndPoint remoteIpEndPoint; + + public int Port { get; set; } + + public UDPPacketsParser(string name, bool isAutoSave) + : base(name, isAutoSave) + { + } + + public UDPPacketsParser(string name, string address, int port, bool isAutoSave) + : this(name, isAutoSave) + { + Address = address; + Port = port; + } + + /// + /// initialize UDP parser + /// + /// + public override bool Init() + { + try + { + base.Init(); + udpClient = new UdpClient(Port); + remoteIpEndPoint = new IPEndPoint(IPAddress.Any, Port); + IsInitialized = true; + return IsInitialized; + } + catch(SocketException socketException) + { + Logger.Warn(socketException, "An error occurred in UDPPacketsParser ctor."); + Messenger.Default.Send($"Port {Port} is busy!", "DisplayCustomMessage"); + + IsInitialized = false; + return IsInitialized; + } + catch(Exception e) + { + Logger.Warn(e, "An error occurred in UDPPacketsParser ctor."); + Messenger.Default.Send($"An error occurred while connect to port {Port}.\n{e.Message}", "DisplayCustomMessage"); + IsInitialized = false; + return IsInitialized; + } + } + + /// + /// read individual message + /// + /// + public override LogMessage GetLog() + { + LogMessage log = null; + string incomingLog = string.Empty; + + if(udpClient == null) + { + return null; + } + + try + { + // getting bytes + byte[] receiveBytes = udpClient.Receive(ref remoteIpEndPoint); + if(IgnoredIPs.Any(x => x.IsActive && x.IP.Contains(remoteIpEndPoint.Address.ToString()))) + { + return null; + } + + // converting bytes to string + incomingLog = Encoding.GetString(receiveBytes); + + log = ReadXmlLog(incomingLog); + log.Address = Settings.Instance.IsSeparateIPLoggersByPort ? $"{remoteIpEndPoint.Address}:{Port}" : remoteIpEndPoint.Address.ToString(); + log.Port = Port; + } + catch(SocketException) + { + return null; + } + catch(Exception e) + { + log = new LogMessage + { + Logger = "UDP Logger", + Address = Settings.Instance.IsSeparateIPLoggersByPort ? $"{remoteIpEndPoint.Address}:{Port}" : remoteIpEndPoint.Address.ToString(), + Thread = -1, + Message = $"An error occurred while parsing log: {incomingLog}. {Environment.NewLine} Exception: {e}", + Time = DateTime.Now, + Level = DashboardLogLevel.Error, + ExecutableName = "LogDashboard" + }; + + Logger.Warn(e, "An error occurred while parsing log."); + } + + if(IsAutoSave) + { + Messenger.Default.Send(log, "PersistLogMessage"); + } + return log; + } + + /// + /// reads XML log in log4j format + /// + /// + /// + /// + private LogMessage ReadXmlLog(string xmlFragment) + { + LogMessage log = new LogMessage(); + + using(XmlReader reader = new XmlTextReader(xmlFragment, XmlNodeType.Element, XmlContext) { WhitespaceHandling = WhitespaceHandling.Significant }) + { + reader.Read(); + if(reader.MoveToContent() != XmlNodeType.Element || reader.Name != "log4j:event") + { + throw new Exception("The Log Event is not a valid log4j Xml block."); + } + + log.Logger = reader.GetAttribute("logger"); + log.Level = (DashboardLogLevel)Enum.Parse(typeof(DashboardLogLevel), reader.GetAttribute("level").ToLower().FirstCharToUpper()); + log.Thread = int.Parse(reader.GetAttribute("thread")); + + if(long.TryParse(reader.GetAttribute("timestamp"), out long timeStamp)) + { + log.Time = UnixTimeStampToDateTime(timeStamp).ToLocalTime(); + } + + int eventDepth = reader.Depth; + reader.Read(); + while(reader.Depth > eventDepth) + { + if(reader.MoveToContent() == XmlNodeType.Element) + { + switch(reader.Name) + { + case "log4j:message": + log.Message = reader.ReadString(); + break; + + case "log4j:throwable": + log.Message += Environment.NewLine + reader.ReadString(); + break; + case "log4j:properties": + reader.Read(); + while(reader.MoveToContent() == XmlNodeType.Element + && reader.Name == "log4j:data") + { + string name = reader.GetAttribute("name"); + string value = reader.GetAttribute("value"); + if(!string.IsNullOrEmpty(name) && name == "log4japp" && !string.IsNullOrEmpty(value) && value.Contains(".exe")) + { + log.ExecutableName = value.Substring(0, value.IndexOf(".exe", StringComparison.Ordinal)); + } + + reader.Read(); + } + + break; + } + } + reader.Read(); + } + } + return log; + } + + public override void Dispose() + { + base.Dispose(); + try + { + udpClient?.Close(); + udpClient?.Dispose(); + udpClient = null; + } + catch(Exception e) + { + Logger.Warn(e, "Dispose error"); + } + } + } +} diff --git a/Source/LogDashboard/LogDashboard/Parsers/WCFPacketsParser.cs b/Source/LogDashboard/LogDashboard/Parsers/WCFPacketsParser.cs new file mode 100644 index 0000000..524bc09 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Parsers/WCFPacketsParser.cs @@ -0,0 +1,174 @@ +//******************************************************************************// +// WCFPacketsParser.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using Raytheon.LogDashboard.Model; +using System; +using System.Net.Sockets; +using Raytheon.LogDashboard.Service; +using GalaSoft.MvvmLight.Messaging; +using System.Collections.Generic; +using NLog; +using System.Linq; + +namespace Raytheon.LogDashboard.Parsers +{ + public class WCFPacketsParser : PacketsParser + { + private ITRSInfoServiceHost _serviceHost; + private readonly Queue _messages = new Queue(); + + public WCFPacketsParser(string name, bool isAutoSave) + : base(name, isAutoSave) + { + } + public WCFPacketsParser(string name, string address, bool isAutoSave) + : this(name, isAutoSave) + { + Address = address; + } + + /// + /// initialize WCF packet receiver / parser + /// + /// + public override bool Init() + { + try + { + base.Init(); + + if(!string.IsNullOrEmpty(Address)) + { + _serviceHost = new TRSInfoServiceHost(); + _serviceHost.StartHost(Address); + } + + Messenger.Default.Register>(this, "WCFMessage", MessageReceivedHandler); + Messenger.Default.Register(this, "AddProcessingText", AddProcessingTextHandler); + + IsInitialized = true; + return IsInitialized; + } + catch(SocketException socketException) + { + Logger.Warn(socketException, "An error occurred in WCFPacketsParser initializer."); + IsInitialized = false; + return IsInitialized; + } + catch(Exception e) + { + Logger.Warn(e, "An error occurred in WCFPacketsParser initializer."); + IsInitialized = false; + return IsInitialized; + } + } + + private void AddProcessingTextHandler(LogEventInfo info) + { + var threadIdProperty = info.Properties.FirstOrDefault(p => p.Key.ToString() == "ThreadId"); + int threadId = threadIdProperty.Key != null ? (int)threadIdProperty.Value : 0; + + LogMessage logMessage = new LogMessage + { + Logger = info.LoggerName, + ThreadName = info.LoggerName, + Address = string.IsNullOrEmpty(Address) ? Environment.MachineName : Address, + Message = info.Message, + Time = info.TimeStamp, + Thread = threadId, + Level = FromNLogLevelToDashboardLevel(info.Level.ToString()), + ExecutableName = "LogDashboard" + }; + _messages.Enqueue(logMessage); + } + + public static DashboardLogLevel FromNLogLevelToDashboardLevel(string level) + { + switch(level.ToUpper()) + { + case "INFOPOPUP": + case "INFO": + return Model.DashboardLogLevel.Info; + case "DEBUGPOPUP": + case "DEBUG": + return Model.DashboardLogLevel.Debug; + case "TRACE": + return Model.DashboardLogLevel.Trace; + case "ERROR": + return Model.DashboardLogLevel.Error; + case "WARN": + return Model.DashboardLogLevel.Warn; + case "FATAL": + case "CRITICAL": + return Model.DashboardLogLevel.Fatal; + default: + return Model.DashboardLogLevel.Error; + } + } + + private void MessageReceivedHandler(NotificationMessage message) + { + LogMessage logMessage = message?.Content; + if(logMessage == null) + { + return; + } + logMessage.Address = Address; + _messages.Enqueue(logMessage); + } + + public override LogMessage GetLog() + { + var log = _messages.Count > 0 ? _messages.Dequeue() : null; + + if(IsAutoSave && log != null) + { + Messenger.Default.Send(log, "PersistLogMessage"); + } + + return log; + } + + public override void Dispose() + { + base.Dispose(); + _serviceHost?.StopHost(); + + Messenger.Default.Unregister>(this, "WCFMessage", MessageReceivedHandler); + Messenger.Default.Unregister(this, "AddProcessingText", AddProcessingTextHandler); + } + + } +} diff --git a/Source/LogDashboard/LogDashboard/ReleaseNotes.xml b/Source/LogDashboard/LogDashboard/ReleaseNotes.xml new file mode 100644 index 0000000..07d3e25 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/ReleaseNotes.xml @@ -0,0 +1,110 @@ + + + + + 1.4.1 + + Support for dynamically changing file location based on the Error Logger settings + New toggle switch for monitoring Error Logger ini file for the current file location + + + Removed the dependency on EP.DataContracts package. + When writing log files based on the Error Logger location, use the same methods for naming files, start with the base name first and rename with the date stamp only when file reach maximum file length. + + + Parsing of the log files with 3 columns + Fix for the dialog when importing multiple log file of different types + + + + + 1.3.9 + + Added support for persisting log records into a rolling file based on a file size + Added support for parsing Error Logger csv files + Added identification for the Error Logger running. If Error Logger detected, display informational message to the user + + + + + Fixed a bug for displaying error messages as a Metro dialog + + + + + 1.3.6 + + - Updated the default icon + + + Added drop-down control for selecting 32 bit and 64 bit Error Logger + + + Error Logger initialization with the correct mutex when running 64 bit version + + + + + 1.3.5 + + - Added support Dark mode + - Added full system color support + - Added embedded mode so that it can be hosted inside other applications like EPTS + + + Windows Debug parser to display machine name as a source + + + Error Logger parser is checking for null handle avoiding exception when MailSlot failed to initialize + + + + + 1.3.2 + + - Added support for parsing EPTS log files + + + - removed normalization for the new line character when parsing xml (log4j format) + + + fixed a bug in EPTS log file parser for skipping first and last lines + stopping and starting receivers was not picking up the enabled receivers from the list + overwriting custom receiver name with the default name after saving in configuration + + + + + 1.0.2 + + - Added new ErrorLogger receiver capable of reading from Mailslot + - Added new WinDebug receiver based on Microsoft's 'dbmon' example + + + - Moved LogDashboard to separate DLL + - Packaged LogDashboardCtrl as a package to be reused + + + + + + + 1.0.0 + + - Default Receiver is UDP listening on port 7777 + Define your target in NLog.config as type=Chainsaw and address=udp://127.0.0.1:7777 + + - Ability to import log4j format files + - Track file changes after importing the file + - Fast sorting and filtering capabilities + - Sorting and filtering based on the namespace from tree view + - Sorting and filtering based on time stamps + + + - Nothing Yet + + + - Nothing Yet + + + \ No newline at end of file diff --git a/Source/LogDashboard/LogDashboard/Resources/LogDashboard.ico b/Source/LogDashboard/LogDashboard/Resources/LogDashboard.ico new file mode 100644 index 0000000..962345b Binary files /dev/null and b/Source/LogDashboard/LogDashboard/Resources/LogDashboard.ico differ diff --git a/Source/LogDashboard/LogDashboard/Resources/Resource1.Designer.cs b/Source/LogDashboard/LogDashboard/Resources/Resource1.Designer.cs new file mode 100644 index 0000000..0538836 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Resources/Resource1.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Raytheon.LogDashboard.Resources { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resource1 { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resource1() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Raytheon.LogDashboard.Resources.Resource1", typeof(Resource1).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). + /// + internal static System.Drawing.Icon LogDashboard { + get { + object obj = ResourceManager.GetObject("LogDashboard", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + } +} diff --git a/Source/LogDashboard/LogDashboard/Resources/Resource1.resx b/Source/LogDashboard/LogDashboard/Resources/Resource1.resx new file mode 100644 index 0000000..2909ad9 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Resources/Resource1.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + LogDashboard.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/Source/LogDashboard/LogDashboard/Resources/Settings.png b/Source/LogDashboard/LogDashboard/Resources/Settings.png new file mode 100644 index 0000000..76327a6 Binary files /dev/null and b/Source/LogDashboard/LogDashboard/Resources/Settings.png differ diff --git a/Source/LogDashboard/LogDashboard/Service/ITRSInfoServiceHost.cs b/Source/LogDashboard/LogDashboard/Service/ITRSInfoServiceHost.cs new file mode 100644 index 0000000..12670ef --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Service/ITRSInfoServiceHost.cs @@ -0,0 +1,51 @@ +//******************************************************************************// +// ITRSInfoServiceHost.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// + +namespace Raytheon.LogDashboard.Service +{ + public interface ITRSInfoServiceHost + { + /// + /// The implementer of this interface will start the service host WCF or Named Pipes + /// + void StartHost(string address); + + /// + /// The implementer of this interface will stop the service host WCF or Named Pipes + /// + void StopHost(); + } +} diff --git a/Source/LogDashboard/LogDashboard/Service/ITestInfoService.cs b/Source/LogDashboard/LogDashboard/Service/ITestInfoService.cs new file mode 100644 index 0000000..ab38561 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Service/ITestInfoService.cs @@ -0,0 +1,101 @@ +//******************************************************************************// +// ITestInfoService.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using System.Collections.Generic; +using System.ServiceModel; + +namespace Raytheon.LogDashboard.Service +{ + [ServiceContract(CallbackContract = typeof(ISubscriptionCallback))] + public interface ITestInfoService + { + [OperationContract] + void ProcessScannedData(string barcodeData); + + [OperationContract(IsOneWay = true)] + void SubscribeToDataEntry(string keyName); + + [OperationContract(IsOneWay = true)] + void UnsubscribeFromDataEntry(string keyName); + + [OperationContract] + void SetParseProfile(string parseProfilePath); + + [OperationContract] + IDictionary GetStoredScanData(); + + [OperationContract] + bool IsAlive(); + + [OperationContract] + void MoveWindowToFront(); + + [OperationContract(IsOneWay = true)] + void ReportMessage(string message); + + [OperationContract(IsOneWay = true)] + void LogMessage(string level, string message); + } + + [ServiceContract(CallbackContract = typeof(IOperatorInterfaceCallback))] + public interface IOperatorInterface + { + [OperationContract(IsOneWay = true)] + void Handshake(string caller); + + [OperationContract(IsOneWay = true)] + void MenuCommand(string command); + } + + [ServiceContract] + public interface ISubscriptionCallback + { + [OperationContract(IsOneWay = true)] + void Notify(); + + [OperationContract(IsOneWay = true)] + void NotifyScan(Dictionary data); + } + + [ServiceContract] + public interface IOperatorInterfaceCallback + { + [OperationContract(IsOneWay = true)] + void CallMethod(string methodName, string parameter); + + [OperationContract] + bool IsSequenceRunning(); + } +} \ No newline at end of file diff --git a/Source/LogDashboard/LogDashboard/Service/TRSInfoServiceHost.cs b/Source/LogDashboard/LogDashboard/Service/TRSInfoServiceHost.cs new file mode 100644 index 0000000..eca6639 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Service/TRSInfoServiceHost.cs @@ -0,0 +1,68 @@ +//******************************************************************************// +// TRSInfoServiceHost.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using NLog; +using System; +using System.ServiceModel; + +namespace Raytheon.LogDashboard.Service +{ + public class TRSInfoServiceHost : ITRSInfoServiceHost + { + static ServiceHost _host; + readonly ILogger _log = LogManager.GetCurrentClassLogger(); + + public void StartHost(string address) + { + _log.Info("Starting TRS Info Service"); + try + { + _host = new ServiceHost(typeof(TestInfoService), new Uri[] { new Uri(address) }); + _host.AddServiceEndpoint(typeof(ITestInfoService), new NetNamedPipeBinding(), address); + _host.Open(); + } + catch(Exception ex) + { + _log.Error(ex, "Unable to start service host TRS Service, please check configuration"); + } + } + + public void StopHost() + { + _log.Info("Stopping TRS Info Service"); + _host.Close(); + } + } +} diff --git a/Source/LogDashboard/LogDashboard/Service/TestInfoService.cs b/Source/LogDashboard/LogDashboard/Service/TestInfoService.cs new file mode 100644 index 0000000..2542cab --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Service/TestInfoService.cs @@ -0,0 +1,180 @@ +//******************************************************************************// +// TestInfoService.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// + +// Ignore Spelling: Unsubscribe + +using System; +using System.Collections.Generic; +using System.ServiceModel; +using GalaSoft.MvvmLight.Messaging; +using NLog; +using Raytheon.LogDashboard.Parsers; + +namespace Raytheon.LogDashboard.Service +{ + [ServiceBehavior(Name = "TestInfoService", + Namespace = "http://epts.data.us.ray.com/EPTS/TRS", + InstanceContextMode = InstanceContextMode.PerSession, + ConcurrencyMode = ConcurrencyMode.Multiple)] + public class TestInfoService : ITestInfoService + { + /// + /// Logger + /// + private readonly ILogger _log = LogManager.GetCurrentClassLogger(); + + /// + /// Used to set the parse profile path to be used when parsing scan data + /// + /// + public void SetParseProfile(string parseProfilePath) + { + _log.Debug($"Setting Parse Profile for path: {parseProfilePath}"); + } + + /// + /// Used to subscribe to the Data Entry Accept event + /// The name of the client's pipeServer is provided for Data Entry to be able to call out to it + /// + /// + public void SubscribeToDataEntry(string keyName) + { + _log.Debug($"Subscribing to Data Entry with key: {keyName}"); + } + + /// + /// Unsubscripted from data entry. + /// + /// Name of the key. + /// + public void UnsubscribeFromDataEntry(string keyName) + { + _log.Debug($"Unsubscribing from Data Entry with key: {keyName}"); + } + + /// + /// Used to retrieve accepted data + /// This will continue to return the previous scan entry until a new scan is accepted in the UI + /// + /// + public IDictionary GetStoredScanData() + { + _log.Debug("Getting Stored Scan Data"); + return null; + } + + /// + /// BCCapture will call this method via WCF + /// // + /// Parse the string that BCCapture passes. + /// Determine if it is DES data scan or RSS scan + /// If DES data scan + /// Call Message.Send.Default + /// Else (RSS scan) + /// Create a new Test Session + /// + /// + public void ProcessScannedData(string scannedData) + { + _log.Debug($"Received Scan Data {scannedData}"); + } + + + /// + /// A call that lets the client end check to see if the endpoint is available. + /// + /// + public bool IsAlive() + { + return true; + } + + /// + /// Used to move the TRS window to active/ to front + /// + public void MoveWindowToFront() + { + _log.Debug("Move Window to the Front call"); + } + + /// + /// will process messages submitted by texPrint + /// + /// + public void ReportMessage(string message) + { + _log.Debug("Report Message call"); + } + + /// + /// Logs the message via local log4net. + /// + /// The level. + /// The message. + public void LogMessage(string level, string message) + { + Messenger.Default.Send(new NotificationMessage(new Model.LogMessage + { + Level = WCFPacketsParser.FromNLogLevelToDashboardLevel(level), + Address = "EPTS", + Logger = "EPTS", + Message = message, + Time = DateTime.Now, + }, + level), "WCFMessage"); + } + + /// + /// Handshake with Common Operator Interface. + /// + /// The caller. + /// + public void Handshake(string caller) + { + _log.Debug($"Handshake Message Received from caller: {caller}"); + } + + /// + /// Menus the command. + /// + /// The command. + /// + public void MenuCommand(string command) + { + _log.Debug($"Menu Command Received command: {command}"); + } + } +} \ No newline at end of file diff --git a/Source/LogDashboard/LogDashboard/Styles/DrawingImages.xaml b/Source/LogDashboard/LogDashboard/Styles/DrawingImages.xaml new file mode 100644 index 0000000..832bca7 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Styles/DrawingImages.xaml @@ -0,0 +1,644 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Source/LogDashboard/LogDashboard/Styles/Styles.xaml b/Source/LogDashboard/LogDashboard/Styles/Styles.xaml new file mode 100644 index 0000000..4bf1b55 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Styles/Styles.xaml @@ -0,0 +1,1325 @@ + + + + + + + + + + + + + + + True + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Source/LogDashboard/LogDashboard/Validators/IPValidation.cs b/Source/LogDashboard/LogDashboard/Validators/IPValidation.cs new file mode 100644 index 0000000..39f6834 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Validators/IPValidation.cs @@ -0,0 +1,67 @@ +//******************************************************************************// +// IPValidation.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// + +// Ignore Spelling: Validators + +using System.Globalization; +using System.Linq; +using System.Net; +using System.Windows.Controls; + +namespace Raytheon.LogDashboard.Validators +{ + public class IPValidation : ValidationRule + { + public override ValidationResult Validate(object value, CultureInfo cultureInfo) + { + if(value is string str && ValidateIPv4(str)) + { + return new ValidationResult(true, null); + } + return new ValidationResult(false, "Invalid IP Address!"); + } + + private bool ValidateIPv4(string ipString) + { + if(ipString.Count(c => c == '.') != 3) + { + return false; + } + + return IPAddress.TryParse(ipString, out IPAddress address); + } + } +} diff --git a/Source/LogDashboard/LogDashboard/Validators/PortNumberValidation.cs b/Source/LogDashboard/LogDashboard/Validators/PortNumberValidation.cs new file mode 100644 index 0000000..df1ca18 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/Validators/PortNumberValidation.cs @@ -0,0 +1,83 @@ +//******************************************************************************// +// PortNumberValidation.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// + +// Ignore Spelling: Validators + +using System; +using System.Globalization; +using System.Text.RegularExpressions; +using System.Windows.Controls; + +namespace Raytheon.LogDashboard.Validators +{ + public class PortNumberValidation : ValidationRule + { + public override ValidationResult Validate(object value, CultureInfo cultureInfo) + { + if(value is string str && IsPort(str)) + { + return new ValidationResult(true, null); + } + return new ValidationResult(false, "Invalid port number!"); + } + + private bool IsPort(string value) + { + if(string.IsNullOrEmpty(value)) + { + return false; + } + + Regex numeric = new Regex(@"^[0-9]+$", RegexOptions.Compiled | RegexOptions.IgnoreCase); + + if(numeric.IsMatch(value)) + { + try + { + if(Convert.ToInt32(value) < 65536) + { + return true; + } + } + catch(OverflowException) + { + } + } + + return false; + } + } +} diff --git a/Source/LogDashboard/LogDashboard/View/ImportLogsProcessDialog.xaml b/Source/LogDashboard/LogDashboard/View/ImportLogsProcessDialog.xaml new file mode 100644 index 0000000..ab1e573 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/View/ImportLogsProcessDialog.xaml @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/LogDashboard/LogDashboard/View/LogDashboardCtrl.xaml.cs b/Source/LogDashboard/LogDashboard/View/LogDashboardCtrl.xaml.cs new file mode 100644 index 0000000..c0ddb34 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/View/LogDashboardCtrl.xaml.cs @@ -0,0 +1,292 @@ +//******************************************************************************// +// LogDashboardCtrl.xaml.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using Raytheon.LogDashboard.ViewModel; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Deployment.Application; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; + +namespace Raytheon.LogDashboard.View +{ + /// + /// Interaction logic for LogDashboardCtrl.xaml + /// + public partial class LogDashboardCtrl + { + public static IntPtr WindowHandle { get; private set; } + + public LogDashboardCtrl() + { + InitializeComponent(); + + AutoScrollButton.ToolTip = "Enable Auto Scroll"; + } + + private void MetroContentControl_Loaded(object sender, RoutedEventArgs e) + { + if (AppDomain.CurrentDomain.SetupInformation.ActivationArguments?.ActivationData != null) + { + string[] activationData = AppDomain.CurrentDomain.SetupInformation.ActivationArguments.ActivationData; + foreach (var arg in activationData.Where(x => x.EndsWith(".txt") || x.EndsWith(".log"))) + { + ((LogDashboardViewModel)DataContext).ImportLogs(arg); + } + return; + } + + List args = Environment.GetCommandLineArgs().Where(x => x.EndsWith(".txt") || x.EndsWith(".log")).ToList(); + + if (args.Any()) + { + ((LogDashboardViewModel)DataContext).ImportLogs(args.Where(x => x.EndsWith(".txt") || x.EndsWith(".log"))); + return; + } + + DisplayChangeLog(); + + } + + private void OnSelectionChanged(object sender, SelectionChangedEventArgs e) + { + if(AutoScrollEnabled && LogsListView.Items.Count > 0) + { + AutoScrollEnabled = false; + } + + Task.Run(() => + { + Application.Current.Dispatcher.Invoke(() => + { + LogsListView.ScrollIntoView(LogsListView.SelectedItem); + //TODO + //LoggersTreeView.BringIntoView(); + }); + }); + } + + #region Logging scroll + + private bool autoScrollEnabled = true; + protected bool AutoScrollEnabled + { + get => autoScrollEnabled; + set + { + autoScrollEnabled = value; + if (autoScrollEnabled) + { + AutoScrollButton.Opacity = 0.5; + AutoScrollButton.ToolTip = "Disable Auto Scroll"; + } + else + { + AutoScrollButton.ToolTip = "Enable Auto Scroll"; + AutoScrollButton.Opacity = 1; + } + } + } + + private void OnScrollToTopButtonClick(object sender, RoutedEventArgs e) + { + if (LogsListView.Items.Count > 0) + { + LogsListView.ScrollIntoView(LogsListView.Items[0]); + } + } + + private void OnAutoScrollToBottomButtonClick(object sender, RoutedEventArgs e) + { + if (AutoScrollEnabled) + { + AutoScrollEnabled = false; + } + else + { + if (LogsListView.Items.Count > 0) + { + LogsListView.ScrollIntoView(LogsListView.Items[LogsListView.Items.Count - 1]); + } + + AutoScrollEnabled = true; + } + } + + private void OnScrollToBottomButtonClick(object sender, RoutedEventArgs e) + { + if (LogsListView.Items.Count > 0) + { + LogsListView.ScrollIntoView(LogsListView.Items[LogsListView.Items.Count - 1]); + } + } + + private void LogsListView_OnScrollChanged(object sender, ScrollChangedEventArgs e) + { + if (AutoScrollEnabled && LogsListView.Items.Count > 0 && e.VerticalChange < 0) + { + AutoScrollEnabled = false; + } + + if (AutoScrollEnabled && LogsListView.Items.Count > 0) + { + LogsListView.ScrollIntoView(LogsListView.Items[LogsListView.Items.Count - 1]); + } + } + + #endregion + + #region table sorting + + GridViewColumnHeader lastHeaderClicked = null; + ListSortDirection lastDirection = ListSortDirection.Ascending; + + private void GridViewColumnHeaderClickedHandler(object sender, RoutedEventArgs e) + { + GridViewColumnHeader headerClicked = e.OriginalSource as GridViewColumnHeader; + + if (headerClicked != null && (string)headerClicked.Content == "Message") + { + return; + } + + if (headerClicked != null) + { + if (headerClicked.Role != GridViewColumnHeaderRole.Padding) + { + ListSortDirection direction; + if (headerClicked != lastHeaderClicked) + { + direction = ListSortDirection.Ascending; + } + else + { + direction = lastDirection == ListSortDirection.Ascending + ? ListSortDirection.Descending + : ListSortDirection.Ascending; + } + + Binding columnBinding = headerClicked.Column.DisplayMemberBinding as Binding; + string sortBy = columnBinding?.Path.Path ?? headerClicked.Column.Header as string; + + Sort(sortBy, direction); + + if (direction == ListSortDirection.Ascending) + { + headerClicked.Column.HeaderTemplate = Resources["HeaderTemplateArrowUp"] as DataTemplate; + } + else + { + headerClicked.Column.HeaderTemplate = Resources["HeaderTemplateArrowDown"] as DataTemplate; + } + + // Remove arrow from previously sorted header + if (lastHeaderClicked != null && lastHeaderClicked != headerClicked) + { + lastHeaderClicked.Column.HeaderTemplate = null; + } + + lastHeaderClicked = headerClicked; + lastDirection = direction; + } + } + } + + private void Sort(string sortBy, ListSortDirection direction) + { + ICollectionView dataView = CollectionViewSource.GetDefaultView(LogsListView.ItemsSource); + + dataView.SortDescriptions.Clear(); + SortDescription sd = new SortDescription(sortBy, direction); + dataView.SortDescriptions.Add(sd); + dataView.Refresh(); + } + + #endregion + + #region Drag and Drop + + private void LogsListView_OnDragOver(object sender, DragEventArgs e) + { + string file = ((string[])e.Data.GetData(DataFormats.FileDrop))?.FirstOrDefault( + x => Path.GetExtension(x) == ".txt" || + Path.GetExtension(x) == ".log" || + Path.GetExtension(x) == ".csv"); + + e.Effects = file != null ? DragDropEffects.Copy : DragDropEffects.None; + e.Handled = true; + } + + private void LogsListView_OnDrop(object sender, DragEventArgs e) + { + e.Effects = DragDropEffects.Copy; + if (e.Data.GetDataPresent(DataFormats.FileDrop)) + { + string[] files = (string[])e.Data.GetData(DataFormats.FileDrop); + if (files != null && files.Any()) + { + var logFiles = files.Where(x => Path.GetExtension(x) == ".txt" || + Path.GetExtension(x) == ".log" || + Path.GetExtension(x) == ".csv"); + if (logFiles.Any()) + { + ((LogDashboardViewModel)DataContext).ImportLogs(logFiles); + } + } + } + } + + #endregion + + private void DisplayChangeLog() + { + if (!ApplicationDeployment.IsNetworkDeployed || !ApplicationDeployment.CurrentDeployment.IsFirstRun) + { + return; + } + + ReleaseNotesDialog releaseNotesDialog = new ReleaseNotesDialog + { + WindowStartupLocation = WindowStartupLocation.CenterOwner + }; + releaseNotesDialog.ShowDialog(); + } + } +} diff --git a/Source/LogDashboard/LogDashboard/View/LogImportTemplateDialog.xaml b/Source/LogDashboard/LogDashboard/View/LogImportTemplateDialog.xaml new file mode 100644 index 0000000..cf3c3e8 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/View/LogImportTemplateDialog.xaml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/LogDashboard/LogDashboard/View/SearchResult.xaml.cs b/Source/LogDashboard/LogDashboard/View/SearchResult.xaml.cs new file mode 100644 index 0000000..6a7bdf7 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/View/SearchResult.xaml.cs @@ -0,0 +1,150 @@ +//******************************************************************************// +// SearchResult.xaml.cs +// 12/4/2023 +// +// RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION +// PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS +// AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. DISCLOSURE TO +// UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO +// RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS +// CONTENTS SHALL BE FURNISHED OR DISCLOSED TO OR COPIED OR USED BY PERSONS +// OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF RAYTHEON +// COMPANY. +// +// THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT +// +// UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. +// +// WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE +// EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED +// BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION +// 120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION +// 730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER +// OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER +// LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS +// BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT +// APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL +// PENALTIES. +// +// DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 : +// FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R, +// INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS +// DESTROY BY ANY METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR +// RECONSTRUCTION OF THE DOCUMENT. +// POC: Alex Kravchenko (1118268) +//******************************************************************************// +using Raytheon.LogDashboard.Model; +using Raytheon.LogDashboard.ViewModel; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Input; + +namespace Raytheon.LogDashboard.View +{ + /// + /// Interaction logic for SearchResult.xaml + /// + public partial class SearchResult + { + public event EventHandler ShowLogEvent; + + public SearchResult(List searchResult, string searchText, bool isMatchCase) + { + InitializeComponent(); + var dataContext = new SearchResultViewModel + { + SearchResult = new ObservableCollection(searchResult), + HighlightSearchText = searchText, + IsMatchCase = isMatchCase + }; + DataContext = dataContext; + } + + #region Sorting + + GridViewColumnHeader lastHeaderClicked = null; + ListSortDirection lastDirection = ListSortDirection.Ascending; + + private void GridViewColumnHeaderClickedHandler(object sender, RoutedEventArgs e) + { + var headerClicked = e.OriginalSource as GridViewColumnHeader; + + if (headerClicked != null) + { + if (headerClicked.Role != GridViewColumnHeaderRole.Padding) + { + ListSortDirection direction; + if (headerClicked != lastHeaderClicked) + { + direction = ListSortDirection.Ascending; + } + else + { + direction = lastDirection == ListSortDirection.Ascending ? ListSortDirection.Descending : ListSortDirection.Ascending; + } + + var columnBinding = headerClicked.Column.DisplayMemberBinding as Binding; + var sortBy = columnBinding?.Path.Path ?? headerClicked.Column.Header as string; + + Sort(sortBy, direction); + + if (direction == ListSortDirection.Ascending) + { + headerClicked.Column.HeaderTemplate = + Resources["HeaderTemplateArrowUp"] as DataTemplate; + } + else + { + headerClicked.Column.HeaderTemplate = + Resources["HeaderTemplateArrowDown"] as DataTemplate; + } + + // Remove arrow from previously sorted header + if (lastHeaderClicked != null && lastHeaderClicked != headerClicked) + { + lastHeaderClicked.Column.HeaderTemplate = null; + } + + lastHeaderClicked = headerClicked; + lastDirection = direction; + } + } + } + + private void Sort(string sortBy, ListSortDirection direction) + { + ICollectionView dataView = CollectionViewSource.GetDefaultView(FoundResultListView.ItemsSource); + + dataView.SortDescriptions.Clear(); + SortDescription sd = new SortDescription(sortBy, direction); + dataView.SortDescriptions.Add(sd); + dataView.Refresh(); + } + + #endregion + + + protected virtual void OnShowLogEvent(LogMessage e) + { + ShowLogEvent?.Invoke(this, e); + } + + private void ShowMessageInMainWindowClick(object sender, RoutedEventArgs e) + { + OnShowLogEvent((LogMessage)FoundResultListView.SelectedItem); + } + + private void ListViewItem_MouseDoubleClick(object sender, MouseButtonEventArgs e) + { + if (sender is ListViewItem item && item.Content is LogMessage logMessage) + { + OnShowLogEvent(logMessage); + } + } + } +} diff --git a/Source/LogDashboard/LogDashboard/View/SelectTimeIntervalDialog.xaml b/Source/LogDashboard/LogDashboard/View/SelectTimeIntervalDialog.xaml new file mode 100644 index 0000000..7fa0b76 --- /dev/null +++ b/Source/LogDashboard/LogDashboard/View/SelectTimeIntervalDialog.xaml @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +