diff --git a/Control/Region.cs b/Control/Region.cs index 341764d4..2a0e608f 100644 --- a/Control/Region.cs +++ b/Control/Region.cs @@ -433,9 +433,22 @@ private void ParseOptionsForMediaNode(XmlNode mediaNode, XmlAttributeCollection } } - // Media Types without an update interval should be set to something rather high + // Media Types without an update interval should have a sensible default (xibosignage/xibo#404) + // This means that items which do not provide an update interval will still refresh. if (!updateIntervalProvided) - _options.updateInterval = int.MaxValue; + { + // Special handling for text/webpages because we know they should never have a default update interval applied + if (_options.type == "webpage" || _options.type == "text") + { + // Very high (will expire eventually, but shouldn't cause a routine request for a new resource + _options.updateInterval = int.MaxValue; + } + else + { + // Default to 5 minutes for those items that do not provide an update interval + _options.updateInterval = 5; + } + } } /// @@ -662,6 +675,7 @@ protected override void Dispose(bool disposing) { try { + _media.DurationElapsedEvent -= media_DurationElapsedEvent; _media.Dispose(); _media = null; diff --git a/Forms/OptionForm.cs b/Forms/OptionForm.cs index 237f3ed9..9010a4b1 100644 --- a/Forms/OptionForm.cs +++ b/Forms/OptionForm.cs @@ -49,22 +49,6 @@ public OptionForm() // XMDS completed event xmds1.RegisterDisplayCompleted += new XiboClient.xmds.RegisterDisplayCompletedEventHandler(xmds1_RegisterDisplayCompleted); - - // Library Path - if (ApplicationSettings.Default.LibraryPath == "DEFAULT") - { - Debug.WriteLine("Getting the Library Path", "OptionForm"); - ApplicationSettings.Default.LibraryPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\Xibo Library"; - ApplicationSettings.Default.Save(); - } - - // Computer name if the display name hasnt been set yet - if (ApplicationSettings.Default.DisplayName == "COMPUTERNAME") - { - Debug.WriteLine("Getting the display Name", "OptionForm"); - ApplicationSettings.Default.DisplayName = Environment.MachineName; - ApplicationSettings.Default.Save(); - } // Set global proxy information OptionForm.SetGlobalProxy(); diff --git a/Log/StatLog.cs b/Log/StatLog.cs index a56934e1..ce0fcbe1 100644 --- a/Log/StatLog.cs +++ b/Log/StatLog.cs @@ -150,10 +150,6 @@ public void Flush() // Flush to File FlushToFile(); - // See if there are any records to flush to XMDS - Thread logSubmit = new Thread(new ThreadStart(ProcessQueueToXmds)); - logSubmit.Start(); - Debug.WriteLine(new LogMessage("Flush", String.Format("OUT")), LogType.Audit.ToString()); } @@ -189,80 +185,6 @@ private void FlushToFile() Debug.WriteLine(new LogMessage("FlushToFile", String.Format("OUT")), LogType.Audit.ToString()); } - - /// - /// Send the Stats to XMDS - /// - private void ProcessQueueToXmds() - { - try - { - // If we haven't had a successful connection recently, then don't log - if (ApplicationSettings.Default.XmdsLastConnection.AddSeconds((int)ApplicationSettings.Default.CollectInterval) < DateTime.Now) - return; - - lock (_locker) - { - // Get a list of all the log files waiting to be sent to XMDS. - string[] logFiles = Directory.GetFiles(ApplicationSettings.Default.LibraryPath, "*" + ApplicationSettings.Default.StatsLogFile + "*"); - - // Track processed files - int filesProcessed = 0; - - // Loop through each file - foreach (string fileName in logFiles) - { - // Only process as many files in one go as configured - if (filesProcessed >= ApplicationSettings.Default.MaxLogFileUploads) - break; - - // If we have some, create an XMDS object - using (xmds.xmds logtoXmds = new xmds.xmds()) - { - logtoXmds.Url = ApplicationSettings.Default.XiboClient_xmds_xmds; - - // construct the log message - StringBuilder builder = new StringBuilder(); - builder.Append(""); - - foreach (string entry in File.ReadAllLines(fileName)) - builder.Append(entry); - - builder.Append(""); - - try - { - logtoXmds.SubmitStats(ApplicationSettings.Default.ServerKey, _hardwareKey.Key, builder.ToString()); - - // Delete the file we are on - File.Delete(fileName); - } - catch (WebException webEx) - { - // Increment the quantity of XMDS failures and bail out - ApplicationSettings.Default.IncrementXmdsErrorCount(); - - // Log this message, but dont abort the thread - Trace.WriteLine(new LogMessage("ProcessQueueToXmds", "WebException: " + webEx.Message), LogType.Error.ToString()); - - // Drop out the loop - break; - } - catch (Exception e) - { - Trace.WriteLine(new LogMessage("FlushToXmds", string.Format("Exception when submitting to XMDS: {0}", e.Message)), LogType.Error.ToString()); - } - - filesProcessed++; - } - } - } - } - catch (Exception e) - { - Trace.WriteLine(new LogMessage("FlushToXmds", string.Format("Unknown Exception: {0}", e.Message)), LogType.Error.ToString()); - } - } } class Stat diff --git a/Log/XiboTraceListener.cs b/Log/XiboTraceListener.cs index 9b777311..b33f4595 100644 --- a/Log/XiboTraceListener.cs +++ b/Log/XiboTraceListener.cs @@ -142,81 +142,6 @@ private void FlushToFile() } } - /// - /// Flush the log to XMDS - /// - public void ProcessQueueToXmds() - { - try - { - // If we haven't had a successful connection recently, then don't log - if (ApplicationSettings.Default.XmdsLastConnection.AddSeconds((int)ApplicationSettings.Default.CollectInterval) < DateTime.Now) - return; - - lock (_locker) - { - // Get a list of all the log files waiting to be sent to XMDS. - string[] logFiles = Directory.GetFiles(ApplicationSettings.Default.LibraryPath, "*" + ApplicationSettings.Default.LogLocation + "*"); - - // Track processed files - int filesProcessed = 0; - - // Loop through each file - foreach (string fileName in logFiles) - { - // Only process as many files in one go as configured - if (filesProcessed >= ApplicationSettings.Default.MaxLogFileUploads) - break; - - // If we have some, create an XMDS object - using (xmds.xmds logtoXmds = new xmds.xmds()) - { - logtoXmds.Url = ApplicationSettings.Default.XiboClient_xmds_xmds; - - // construct the log message - StringBuilder builder = new StringBuilder(); - builder.Append(""); - - foreach (string entry in File.ReadAllLines(fileName)) - builder.Append(entry); - - builder.Append(""); - - try - { - logtoXmds.SubmitLog(ApplicationSettings.Default.ServerKey, _hardwareKey.Key, builder.ToString()); - - // Delete the file we are on - File.Delete(fileName); - } - catch (WebException webEx) - { - // Increment the quantity of XMDS failures and bail out - ApplicationSettings.Default.IncrementXmdsErrorCount(); - - // Log this message, but dont abort the thread - Trace.WriteLine(new LogMessage("ProcessQueueToXmds", "WebException: " + webEx.Message), LogType.Error.ToString()); - - // Drop out the loop - break; - } - catch (Exception e) - { - Trace.WriteLine(new LogMessage("ProcessQueueToXmds", string.Format("Exception when submitting to XMDS: {0}", e.Message)), LogType.Error.ToString()); - } - - filesProcessed++; - } - } - } - } - catch (Exception e) - { - // Do nothing - we just have an unknown exception in logging - Trace.WriteLine(new LogMessage("ProcessQueueToXmds", string.Format("Unknown Exception: {0}", e.Message)), LogType.Error.ToString()); - } - } - public override void Write(string message) { AddToCollection(message, LogType.Audit.ToString()); @@ -296,10 +221,6 @@ public override void Flush() return; FlushToFile(); - - // See if there are any records to flush to XMDS - Thread logSubmit = new Thread(new ThreadStart(ProcessQueueToXmds)); - logSubmit.Start(); } } diff --git a/Logic/ApplicationSettings.cs b/Logic/ApplicationSettings.cs index 00432ae4..192ce7c8 100644 --- a/Logic/ApplicationSettings.cs +++ b/Logic/ApplicationSettings.cs @@ -19,6 +19,7 @@ */ using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Linq; using System.Reflection; @@ -36,14 +37,16 @@ public class ApplicationSettings private static string _default = "default"; // Application Specific Settings we want to protect - private string _clientVersion = "1.7.1"; + private string _clientVersion = "1.7.2"; private string _version = "4"; - private int _clientCodeVersion = 105; + private int _clientCodeVersion = 106; public string ClientVersion { get { return _clientVersion; } } public string Version { get { return _version; } } public int ClientCodeVersion { get { return _clientCodeVersion; } } + private static readonly DateTime unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + public static ApplicationSettings Default { get @@ -136,10 +139,14 @@ public object this[string propertyName] public string RequiredFilesFile { get; set; } public string VideoRenderingEngine { get; set; } - public string LibraryPath { get; set; } + private string _libraryPath; + public string LibraryPath { get { return (_libraryPath == "DEFAULT") ? (Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\" + Application.ProductName + " Library") : _libraryPath; } set { _libraryPath = value; } } public string XiboClient_xmds_xmds { get; set; } public string ServerKey { get; set; } - public string DisplayName { get; set; } + + private string _displayName; + public string DisplayName { get { return (_displayName == "COMPUTERNAME") ? Environment.MachineName : _displayName; } set { _displayName = value; } } + public string ServerUri { get; set; } public string ProxyUser { get; set; } public string ProxyPassword { get; set; } @@ -154,6 +161,56 @@ public object this[string propertyName] public string CursorStartPosition { get; set; } public string ClientInformationKeyCode { get; set; } + // Download window + + public long DownloadStartWindow { get; set; } + public long DownloadEndWindow { get; set; } + + public DateTime DownloadStartWindowTime + { + get + { + DateTime now = DateTime.Now; + DateTime start = unixEpoch.AddMilliseconds(DownloadStartWindow); + + // Reset to today + return new DateTime(now.Year, now.Month, now.Day, start.Hour, start.Minute, start.Second); + } + } + + public DateTime DownloadEndWindowTime + { + get + { + DateTime now = DateTime.Now; + DateTime end = unixEpoch.AddMilliseconds(DownloadEndWindow); + + // Reset to today + return new DateTime(now.Year, now.Month, now.Day, end.Hour, end.Minute, end.Second); + } + } + + /// + /// Is the player in the download window + /// + public bool InDownloadWindow + { + get + { + try + { + if (DownloadStartWindow == 0 && DownloadEndWindow == 0) + return true; + + return (DownloadStartWindowTime <= DateTime.Now && DownloadEndWindowTime >= DateTime.Now); + } + catch + { + return true; + } + } + } + public int Licensed { get; set; } public int StatsFlushCount { get; set; } public int CollectInterval { get; set; } @@ -173,7 +230,21 @@ public object this[string propertyName] public bool ClientInfomationCtrlKey { get; set; } public bool UseCefWebBrowser { get; set; } public bool SendCurrentLayoutAsStatusUpdate { get; set; } - public bool ScreenShotRequested { get; set; } + + private bool _screenShotRequested = false; + public bool ScreenShotRequested + { + get + { + return _screenShotRequested; + } + set + { + _screenShotRequested = value; + // Reset the Hash so that the next update is taken into account. + Hash = "0"; + } + } // XMDS Status Flags private DateTime _xmdsLastConnection; diff --git a/Logic/KeyInterceptor.cs b/Logic/KeyInterceptor.cs new file mode 100644 index 00000000..514bcb85 --- /dev/null +++ b/Logic/KeyInterceptor.cs @@ -0,0 +1,59 @@ +using System; +using System.Diagnostics; +using System.Windows.Forms; +using System.Runtime.InteropServices; + +namespace XiboClient +{ + /// + /// Adapted from: http://blogs.msdn.com/b/toub/archive/2006/05/03/589423.aspx + /// + class KeyInterceptor + { + private const int WH_KEYBOARD_LL = 13; + private const int WM_KEYDOWN = 0x0100; + private static LowLevelKeyboardProc _proc = HookCallback; + private static IntPtr _hookId = IntPtr.Zero; + + public static void SetHook() + { + using (Process curProcess = Process.GetCurrentProcess()) + { + using (ProcessModule curModule = curProcess.MainModule) + { + SetWindowsHookEx(WH_KEYBOARD_LL, _proc, GetModuleHandle(curModule.ModuleName), 0); + } + } + } + + public static void UnsetHook() + { + UnhookWindowsHookEx(_hookId); + } + + private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam); + + private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) + { + if (nCode >= 0) + { + KeyStore.Instance.HandleRawKey(wParam, lParam); + } + + return CallNextHookEx(_hookId, nCode, wParam, lParam); + } + + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId); + + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool UnhookWindowsHookEx(IntPtr hhk); + + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam); + + [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern IntPtr GetModuleHandle(string lpModuleName); + } +} \ No newline at end of file diff --git a/Logic/KeyStore.cs b/Logic/KeyStore.cs index 7d4698ff..b5e67891 100644 --- a/Logic/KeyStore.cs +++ b/Logic/KeyStore.cs @@ -31,6 +31,9 @@ class KeyStore : IMessageFilter private bool _shift = false; private bool _control = false; + // The screensaver setting + public bool ScreenSaver { get; set; } + // The definitions private Dictionary _definitions; @@ -80,6 +83,34 @@ public bool PreFilterMessage(ref Message m) return handled; } + /// + /// Handle Raw Keypresses + /// + /// + /// + public void HandleRawKey(IntPtr wParam, IntPtr lParam) + { + bool handled = false; + Keys key = Keys.None; + + if (wParam == (IntPtr)WM_KEYDOWN) + { + key = (Keys)Marshal.ReadInt32(lParam); + handled = HandleModifier(key, false); + } + else if (wParam == (IntPtr)WM_KEYUP) + { + key = (Keys)Marshal.ReadInt32(lParam); + handled = HandleModifier(key, true); + if (false == handled) + { + // If one of the defined keys was pressed then we + // raise an event. + handled = HandleDefinedKey(key); + } + } + } + /// /// Compares a key against the definitions, and raises an event /// if there is a match. @@ -103,6 +134,11 @@ private bool HandleDefinedKey(Keys key) handled = true; } + else if (ScreenSaver) + { + OnKeyPress("ScreenSaver"); + handled = true; + } return handled; } diff --git a/Logic/MouseInterceptor.cs b/Logic/MouseInterceptor.cs new file mode 100644 index 00000000..843c6c29 --- /dev/null +++ b/Logic/MouseInterceptor.cs @@ -0,0 +1,122 @@ +using System; +using System.Diagnostics; +using System.Windows.Forms; +using System.Runtime.InteropServices; +using System.Drawing; + +namespace XiboClient.Logic +{ + public delegate void MouseInterceptorEventHandler(); + + /// + /// Adapted From: http://blogs.msdn.com/b/toub/archive/2006/05/03/589468.aspx + /// + class MouseInterceptor + { + private static LowLevelMouseProc _proc = HookCallback; + private static IntPtr _hookID = IntPtr.Zero; + + private static MouseInterceptor s_instance = null; + // The KeyPressed Event + public event MouseInterceptorEventHandler MouseEvent; + + private static Point _mouseLocation; + + public static IntPtr SetHook() + { + using (Process curProcess = Process.GetCurrentProcess()) + using (ProcessModule curModule = curProcess.MainModule) + { + return SetWindowsHookEx(WH_MOUSE_LL, _proc, GetModuleHandle(curModule.ModuleName), 0); + } + } + + public static void UnsetHook() + { + UnhookWindowsHookEx(_hookID); + } + + private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam); + + private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) + { + if (nCode >= 0) + { + if (MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam || MouseMessages.WM_MOUSEMOVE == (MouseMessages)wParam) + { + MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT)); + Console.WriteLine(hookStruct.pt.x + ", " + hookStruct.pt.y); + + if (Math.Abs(_mouseLocation.X - hookStruct.pt.x) > 5 || Math.Abs(_mouseLocation.Y - hookStruct.pt.y) > 5) + { + if (MouseInterceptor.s_instance != null && MouseInterceptor.s_instance.MouseEvent != null) + MouseInterceptor.s_instance.MouseEvent(); + } + + _mouseLocation = new Point(hookStruct.pt.x, hookStruct.pt.y); + } + } + + return CallNextHookEx(_hookID, nCode, wParam, lParam); + } + + /// + /// Returns the singleton instance. + /// + public static MouseInterceptor Instance + { + get + { + if (null == s_instance) + s_instance = new MouseInterceptor(); + + return s_instance; + } + } + + private const int WH_MOUSE_LL = 14; + + private enum MouseMessages + { + WM_LBUTTONDOWN = 0x0201, + WM_LBUTTONUP = 0x0202, + WM_MOUSEMOVE = 0x0200, + WM_MOUSEWHEEL = 0x020A, + WM_RBUTTONDOWN = 0x0204, + WM_RBUTTONUP = 0x0205 + } + + [StructLayout(LayoutKind.Sequential)] + private struct POINT + { + public int x; + public int y; + } + + [StructLayout(LayoutKind.Sequential)] + private struct MSLLHOOKSTRUCT + { + public POINT pt; + public uint mouseData; + public uint flags; + public uint time; + public IntPtr dwExtraInfo; + } + + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern IntPtr SetWindowsHookEx(int idHook, + LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId); + + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool UnhookWindowsHookEx(IntPtr hhk); + + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, + IntPtr wParam, IntPtr lParam); + + [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern IntPtr GetModuleHandle(string lpModuleName); + + } +} diff --git a/Logic/RequiredFiles.cs b/Logic/RequiredFiles.cs index cb520814..ff985e9e 100644 --- a/Logic/RequiredFiles.cs +++ b/Logic/RequiredFiles.cs @@ -185,8 +185,6 @@ private void SetRequiredFiles() rf.Md5 = attributes["md5"].Value; rf.Size = int.Parse(attributes["size"].Value); - Trace.WriteLine(new LogMessage("RequiredFiles - SetRequiredFiles", "Building required file node for " + rf.Id.ToString()), LogType.Audit.ToString()); - // Does this file already exist in the RF node? We might receive duplicates. bool found = false; diff --git a/Logic/Schedule.cs b/Logic/Schedule.cs index 6e088d2f..b767c8d5 100644 --- a/Logic/Schedule.cs +++ b/Logic/Schedule.cs @@ -77,6 +77,10 @@ class Schedule private LibraryAgent _libraryAgent; Thread _libraryAgentThread; + // Log Agent + private LogAgent _logAgent; + Thread _logAgentThread; + /// /// Client Info Form /// @@ -149,6 +153,11 @@ public Schedule(string scheduleLocation, ref CacheManager cacheManager, ref Clie // Create a thread for the Library Agent to run in - but dont start it up yet. _libraryAgentThread = new Thread(new ThreadStart(_libraryAgent.Run)); _libraryAgentThread.Name = "LibraryAgent"; + + // Log Agent + _logAgent = new LogAgent(); + _logAgentThread = new Thread(new ThreadStart(_logAgent.Run)); + _logAgentThread.Name = "LogAgent"; } /// @@ -170,6 +179,9 @@ public void InitializeComponents() // Start the LibraryAgent thread _libraryAgentThread.Start(); + + // Start the LogAgent thread + _logAgentThread.Start(); } /// @@ -300,6 +312,9 @@ public void Stop() // Stop the LibraryAgent Thread _libraryAgent.Stop(); + + // Stop the LogAgent Thread + _logAgent.Stop(); } } } diff --git a/Logic/ScreenShot.cs b/Logic/ScreenShot.cs index 04b23a30..9d3c2845 100644 --- a/Logic/ScreenShot.cs +++ b/Logic/ScreenShot.cs @@ -14,12 +14,24 @@ class ScreenShot { public static void TakeAndSend() { - Rectangle bounds = Screen.GetBounds(Point.Empty); + Rectangle bounds; + + // Override the default size if necessary + if (ApplicationSettings.Default.SizeX != 0) + { + bounds = new Rectangle((int)ApplicationSettings.Default.OffsetX, (int)ApplicationSettings.Default.OffsetY, (int)ApplicationSettings.Default.SizeX, (int)ApplicationSettings.Default.SizeY); + } + else + { + bounds = new Rectangle(0, 0, SystemInformation.PrimaryMonitorSize.Width, SystemInformation.PrimaryMonitorSize.Height); + } + using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height)) { using (Graphics g = Graphics.FromImage(bitmap)) { - g.CopyFromScreen(Point.Empty, Point.Empty, bounds.Size); + Point p = new Point(bounds.X, bounds.Y); + g.CopyFromScreen(bounds.X, bounds.Y, 0, 0, bounds.Size, CopyPixelOperation.SourceCopy); } using (MemoryStream stream = new MemoryStream()) diff --git a/MainForm.Designer.cs b/MainForm.Designer.cs index 81c6d1ae..60ab8b40 100644 --- a/MainForm.Designer.cs +++ b/MainForm.Designer.cs @@ -47,7 +47,6 @@ private void InitializeComponent() this.WindowState = System.Windows.Forms.FormWindowState.Maximized; this.Load += new System.EventHandler(this.MainForm_Load); this.ResumeLayout(false); - } #endregion diff --git a/MainForm.cs b/MainForm.cs index 21db446c..af7a416a 100644 --- a/MainForm.cs +++ b/MainForm.cs @@ -1,6 +1,6 @@ /* * Xibo - Digitial Signage - http://www.xibo.org.uk - * Copyright (C) 2006-14 Daniel Garner + * Copyright (C) 2006-15 Daniel Garner * * This file is part of Xibo. * @@ -38,6 +38,7 @@ using System.Runtime.InteropServices; using System.Globalization; using Xilium.CefGlue; +using XiboClient.Logic; namespace XiboClient { @@ -49,7 +50,6 @@ public partial class MainForm : Form private int _scheduleId; private int _layoutId; private bool _screenSaver = false; - private Point _mouseLocation; double _layoutWidth; double _layoutHeight; @@ -172,9 +172,6 @@ private void InitializeXibo() _clientInfoForm = new ClientInfo(); _clientInfoForm.Hide(); - // Add a message filter to listen for the i key - Application.AddMessageFilter(KeyStore.Instance); - // Define the hotkey Keys key; try @@ -214,43 +211,15 @@ private void InitializeScreenSaver(bool preview) // Configure some listeners for the mouse (to quit) if (!preview) { - MouseMove += ScreenSaverForm_MouseMove; - MouseDown += ScreenSaverForm_MouseClick; - KeyDown += ScreenSaverForm_KeyPress; - } - } - - private void ScreenSaverForm_MouseMove(object sender, MouseEventArgs e) - { - if (!_screenSaver) - return; + KeyStore.Instance.ScreenSaver = true; - if (!_mouseLocation.IsEmpty) - { - // Terminate if mouse is moved a significant distance - if (Math.Abs(_mouseLocation.X - e.X) > 5 || - Math.Abs(_mouseLocation.Y - e.Y) > 5) - Application.Exit(); + MouseInterceptor.Instance.MouseEvent += Instance_MouseEvent; } - - // Update current mouse location - _mouseLocation = e.Location; } - private void ScreenSaverForm_MouseClick(object sender, MouseEventArgs e) + void Instance_MouseEvent() { - if (!_screenSaver) - return; - - Application.Exit(); - } - - private void ScreenSaverForm_KeyPress(object sender, KeyEventArgs e) - { - if (!_screenSaver) - return; - - Application.Exit(); + Close(); } /// @@ -259,16 +228,25 @@ private void ScreenSaverForm_KeyPress(object sender, KeyEventArgs e) /// void Instance_KeyPress(string name) { - if (name != "ClientInfo") - return; - - // Toggle - if (_clientInfoForm.Visible) - _clientInfoForm.Hide(); - else + Debug.WriteLine("KeyPress " + name); + if (name == "ClientInfo") + { + // Toggle + if (_clientInfoForm.Visible) + _clientInfoForm.Hide(); + else + { + _clientInfoForm.Show(); + _clientInfoForm.BringToFront(); + } + } + else if (name == "ScreenSaver") { - _clientInfoForm.Show(); - _clientInfoForm.BringToFront(); + Debug.WriteLine("Closing due to ScreenSaver key press"); + if (!_screenSaver) + return; + + Close(); } } @@ -322,7 +300,8 @@ private void MainForm_Load(object sender, EventArgs e) Cursor.Hide(); // Move the cursor to the starting place - SetCursorStartPosition(); + if (!_screenSaver) + SetCursorStartPosition(); // Show the splash screen ShowSplashScreen(); diff --git a/Media/CefWebMedia.cs b/Media/CefWebMedia.cs index 11d39db2..869c3105 100644 --- a/Media/CefWebMedia.cs +++ b/Media/CefWebMedia.cs @@ -101,7 +101,7 @@ public override void RenderMedia() private bool HtmlReady() { - // Pull the RSS feed, and put it in a temporary file cache + // Check for cached resource files in the library // We want to check the file exists first if (!File.Exists(_filePath) || _options.updateInterval == 0) return false; @@ -109,8 +109,12 @@ private bool HtmlReady() // It exists - therefore we want to get the last time it was updated DateTime lastWriteDate = File.GetLastWriteTime(_filePath); - if (_options.LayoutModifiedDate.CompareTo(lastWriteDate) > 0 || DateTime.Now.CompareTo(lastWriteDate.AddHours(_options.updateInterval * 1.0 / 60.0)) > 0) + // Compare the last time it was updated to the layout modified time (always refresh when the layout has been modified) + // Also compare to the update interval (refresh if it has not been updated for longer than the update interval) + if (_options.LayoutModifiedDate.CompareTo(lastWriteDate) > 0 || DateTime.Now.CompareTo(lastWriteDate.AddMinutes(_options.updateInterval)) > 0) + { return false; + } else { UpdateCacheIfNecessary(); @@ -172,8 +176,19 @@ private void xmds_GetResourceCompleted(object sender, XiboClient.xmds.GetResourc { Trace.WriteLine(new LogMessage("xmds_GetResource", "Unable to get Resource: " + e.Error.Message), LogType.Error.ToString()); - // Start the timer so that we expire - base.RenderMedia(); + // We have failed to update from XMDS, do we have a cached file we can revert to + if (File.Exists(_filePath)) + { + // Cached file to revert to + UpdateCacheIfNecessary(); + _webView.Browser.GetMainFrame().LoadUrl(_filePath); + } + else + { + // No cache to revert to + // Start the timer so that we expire + base.RenderMedia(); + } } else { diff --git a/Media/IeWebMedia.cs b/Media/IeWebMedia.cs index 17f6b336..6e7c0abf 100644 --- a/Media/IeWebMedia.cs +++ b/Media/IeWebMedia.cs @@ -94,7 +94,7 @@ public override void RenderMedia() private bool HtmlReady() { - // Pull the RSS feed, and put it in a temporary file cache + // Check for cached resource files in the library // We want to check the file exists first if (!File.Exists(_filePath) || _options.updateInterval == 0) return false; @@ -102,8 +102,12 @@ private bool HtmlReady() // It exists - therefore we want to get the last time it was updated DateTime lastWriteDate = File.GetLastWriteTime(_filePath); - if (_options.LayoutModifiedDate.CompareTo(lastWriteDate) > 0 || DateTime.Now.CompareTo(lastWriteDate.AddHours(_options.updateInterval * 1.0 / 60.0)) > 0) + // Compare the last time it was updated to the layout modified time (always refresh when the layout has been modified) + // Also compare to the update interval (refresh if it has not been updated for longer than the update interval) + if (_options.LayoutModifiedDate.CompareTo(lastWriteDate) > 0 || DateTime.Now.CompareTo(lastWriteDate.AddMinutes(_options.updateInterval)) > 0) + { return false; + } else { UpdateCacheIfNecessary(); @@ -165,8 +169,19 @@ private void xmds_GetResourceCompleted(object sender, XiboClient.xmds.GetResourc { Trace.WriteLine(new LogMessage("xmds_GetResource", "Unable to get Resource: " + e.Error.Message), LogType.Error.ToString()); - // Start the timer so that we expire - base.RenderMedia(); + // We have failed to update from XMDS, do we have a cached file we can revert to + if (File.Exists(_filePath)) + { + // Cached file to revert to + UpdateCacheIfNecessary(); + _webBrowser.Navigate(_filePath); + } + else + { + // No cache to revert to + // Start the timer so that we expire + base.RenderMedia(); + } } else { @@ -204,7 +219,7 @@ private void xmds_GetResourceCompleted(object sender, XiboClient.xmds.GetResourc } catch (ObjectDisposedException) { - Trace.WriteLine(new LogMessage("WebMedia", "Retrived the data set, stored the document but the media has already expired."), LogType.Error.ToString()); + Trace.WriteLine(new LogMessage("WebMedia", "Retrived the resource, stored the document but the media has already expired."), LogType.Error.ToString()); } catch (Exception ex) { @@ -268,6 +283,14 @@ protected override void Dispose(bool disposing) // Remove the webbrowser control try { + // Remove the web browser control + Controls.Remove(_webBrowser); + + // Workaround to remove COM object + PerformLayout(); + + // Detatch event and remove + _webBrowser.DocumentCompleted -= _webBrowser_DocumentCompleted; _webBrowser.Dispose(); } catch diff --git a/Media/Video.cs b/Media/Video.cs index 7c47a3d1..b8dfd357 100644 --- a/Media/Video.cs +++ b/Media/Video.cs @@ -1,6 +1,6 @@ /* * Xibo - Digitial Signage - http://www.xibo.org.uk - * Copyright (C) 2006-2012 Daniel Garner + * Copyright (C) 2006-2015 Daniel Garner * * This file is part of Xibo. * @@ -61,6 +61,7 @@ public Video(RegionOptions options) // Capture any video errors _videoPlayer.VideoError += new VideoPlayer.VideoErrored(_videoPlayer_VideoError); + _videoPlayer.VideoEnd += new VideoPlayer.VideoFinished(_videoPlayer_VideoEnd); Controls.Add(_videoPlayer); } @@ -77,9 +78,6 @@ public override void RenderMedia() // Do we need to determine the end time ourselves? if (_duration == 0) { - // Use an event for this. - _videoPlayer.VideoEnd += new VideoPlayer.VideoFinished(_videoPlayer_VideoEnd); - // Set the duration to 1 second Duration = 1; _detectEnd = true; @@ -148,6 +146,10 @@ protected override void Dispose(bool disposing) { try { + // Remove the event handlers + _videoPlayer.VideoError -= _videoPlayer_VideoError; + _videoPlayer.VideoEnd -= _videoPlayer_VideoEnd; + // Stop and Clear _videoPlayer.StopAndClear(); diff --git a/Media/VideoPlayer.cs b/Media/VideoPlayer.cs index fc6b3bc8..a4f0c589 100644 --- a/Media/VideoPlayer.cs +++ b/Media/VideoPlayer.cs @@ -1,6 +1,6 @@ /* * Xibo - Digitial Signage - http://www.xibo.org.uk - * Copyright (C) 2006-2012 Daniel Garner + * Copyright (C) 2006-2015 Daniel Garner * * This file is part of Xibo. * @@ -86,9 +86,6 @@ public void StopAndClear() { try { - GC.WaitForPendingFinalizers(); - GC.Collect(); - if (axWindowsMediaPlayer1 != null) { // Unbind events @@ -97,18 +94,24 @@ public void StopAndClear() // Release resources Marshal.FinalReleaseComObject(axWindowsMediaPlayer1.currentMedia); - axWindowsMediaPlayer1.URL = null; axWindowsMediaPlayer1.close(); + axWindowsMediaPlayer1.URL = null; + axWindowsMediaPlayer1.Dispose(); // Remove the WMP control Controls.Remove(axWindowsMediaPlayer1); + // Workaround to remove the event handlers from the cachedLayoutEventArgs + PerformLayout(); + // Close this form Close(); - //axWindowsMediaPlayer1.Dispose(); axWindowsMediaPlayer1 = null; } + + GC.WaitForPendingFinalizers(); + GC.Collect(); } catch (AccessViolationException) { @@ -134,8 +137,7 @@ void axWindowsMediaPlayer1_ErrorEvent(object sender, EventArgs e) // Raise the event if (VideoError == null) { - // The parent form has been ditached and disposed - StopAndClear(); + Trace.WriteLine(new LogMessage("VideoPlayer - ErrorEvent", "Error event handler is null"), LogType.Audit.ToString()); } else { @@ -153,8 +155,7 @@ void axWMP_PlayStateChange(object sender, AxWMPLib._WMPOCXEvents_PlayStateChange // Raise the event if (VideoEnd == null) { - // The parent form has been ditached and disposed - StopAndClear(); + Trace.WriteLine(new LogMessage("VideoPlayer - Playstate Complete", "Video end handler is null"), LogType.Audit.ToString()); } else { diff --git a/Program.cs b/Program.cs index c5779161..9600d8e4 100644 --- a/Program.cs +++ b/Program.cs @@ -23,6 +23,7 @@ using System.Runtime.InteropServices; using System.Diagnostics; using Xilium.CefGlue; +using XiboClient.Logic; namespace XiboClient { @@ -91,12 +92,20 @@ static int Main(string[] args) // Preview the screen saver case "/p": // args[1] is the handle to the preview window + KeyInterceptor.SetHook(); + MouseInterceptor.SetHook(); RunClient(new IntPtr(long.Parse(args[1]))); + KeyInterceptor.UnsetHook(); + MouseInterceptor.UnsetHook(); break; // Show the screen saver case "/s": + KeyInterceptor.SetHook(); + MouseInterceptor.SetHook(); RunClient(true); + KeyInterceptor.UnsetHook(); + MouseInterceptor.UnsetHook(); break; // Configure the screesaver's settings @@ -107,13 +116,20 @@ static int Main(string[] args) // Show the screen saver default: + KeyInterceptor.SetHook(); + MouseInterceptor.SetHook(); RunClient(true); + KeyInterceptor.UnsetHook(); + MouseInterceptor.UnsetHook(); break; } } } else { + // Add a message filter + Application.AddMessageFilter(KeyStore.Instance); + // No arguments were passed - we run the usual client RunClient(); } diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index 7c7ad949..e896b524 100644 --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -6,11 +6,11 @@ // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("Xibo")] +[assembly: AssemblyTitle("Xibo Open Source Digital Signage")] [assembly: AssemblyDescription("Digital Signage Player")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Xibo Digital Signage")] -[assembly: AssemblyProduct("Xibo Open Source Digital Signage")] +[assembly: AssemblyProduct("Xibo")] [assembly: AssemblyCopyright("Copyright Dan Garner © 2008-2014")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/XiboClient.csproj b/XiboClient.csproj index 5eeaac3c..ca96c04b 100644 --- a/XiboClient.csproj +++ b/XiboClient.csproj @@ -114,7 +114,9 @@ + + @@ -225,6 +227,7 @@ Form + diff --git a/XiboClient.v11.suo b/XiboClient.v11.suo index 9d6af9ad..16ab26eb 100644 Binary files a/XiboClient.v11.suo and b/XiboClient.v11.suo differ diff --git a/XmdsAgents/LogAgent.cs b/XmdsAgents/LogAgent.cs new file mode 100644 index 00000000..46daf08f --- /dev/null +++ b/XmdsAgents/LogAgent.cs @@ -0,0 +1,140 @@ +/* + * Xibo - Digitial Signage - http://www.xibo.org.uk + * Copyright (C) 2006 - 2015 Daniel Garner + * + * This file is part of Xibo. + * + * Xibo is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * Xibo is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Xibo. If not, see . + */ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading; + +namespace XiboClient.XmdsAgents +{ + class LogAgent + { + public static object _locker = new object(); + + // Members to stop the thread + private bool _forceStop = false; + private ManualResetEvent _manualReset = new ManualResetEvent(false); + + /// + /// Stops the thread + /// + public void Stop() + { + _forceStop = true; + _manualReset.Set(); + } + + /// + /// Runs the agent + /// + public void Run() + { + Trace.WriteLine(new LogMessage("LogAgent - Run", "Thread Started"), LogType.Info.ToString()); + + while (!_forceStop) + { + lock (_locker) + { + try + { + // If we are restarting, reset + _manualReset.Reset(); + + HardwareKey key = new HardwareKey(); + + Trace.WriteLine(new LogMessage("RegisterAgent - Run", "Thread Woken and Lock Obtained"), LogType.Info.ToString()); + + using (xmds.xmds xmds = new xmds.xmds()) + { + xmds.Credentials = null; + xmds.Url = ApplicationSettings.Default.XiboClient_xmds_xmds; + xmds.UseDefaultCredentials = false; + + // Log + ProcessFiles(xmds, key.Key, ApplicationSettings.Default.LogLocation); + + // Stat + ProcessFiles(xmds, key.Key, ApplicationSettings.Default.StatsLogFile); + } + } + catch (WebException webEx) + { + // Increment the quantity of XMDS failures and bail out + ApplicationSettings.Default.IncrementXmdsErrorCount(); + + // Log this message, but dont abort the thread + Trace.WriteLine(new LogMessage("LogAgent - Run", "WebException in Run: " + webEx.Message), LogType.Error.ToString()); + } + catch (Exception ex) + { + // Log this message, but dont abort the thread + Trace.WriteLine(new LogMessage("LogAgent - Run", "Exception in Run: " + ex.Message), LogType.Error.ToString()); + } + } + + // Sleep this thread until the next collection interval + _manualReset.WaitOne((int)(ApplicationSettings.Default.CollectInterval * ApplicationSettings.Default.XmdsCollectionIntervalFactor() * 1000)); + } + + Trace.WriteLine(new LogMessage("LogAgent - Run", "Thread Stopped"), LogType.Info.ToString()); + } + + private void ProcessFiles(xmds.xmds xmds, string key, string type) + { + // Get a list of all the log files waiting to be sent to XMDS. + string[] logFiles = Directory.GetFiles(ApplicationSettings.Default.LibraryPath, "*" + type + "*"); + + // Track processed files + int filesProcessed = 0; + + // Loop through each file + foreach (string fileName in logFiles) + { + // Only process as many files in one go as configured + if (filesProcessed >= ApplicationSettings.Default.MaxLogFileUploads) + break; + + // construct the log message + StringBuilder builder = new StringBuilder(); + builder.Append(""); + + foreach (string entry in File.ReadAllLines(fileName)) + builder.Append(entry); + + builder.Append(""); + + if (type == ApplicationSettings.Default.StatsLogFile) + xmds.SubmitStats(ApplicationSettings.Default.ServerKey, key, builder.ToString()); + else + xmds.SubmitLog(ApplicationSettings.Default.ServerKey, key, builder.ToString()); + + // Delete the file we are on + File.Delete(fileName); + + // Increment files processed + filesProcessed++; + } + } + } +} diff --git a/XmdsAgents/RegisterAgent.cs b/XmdsAgents/RegisterAgent.cs index 9b22cf03..40431ffc 100644 --- a/XmdsAgents/RegisterAgent.cs +++ b/XmdsAgents/RegisterAgent.cs @@ -110,6 +110,7 @@ public void Run() public static string ProcessRegisterXml(string xml) { string message = ""; + bool error = false; // Work out if we need to do anything (have the settings changed since the last time) string md5 = Hashes.MD5(xml); @@ -166,12 +167,13 @@ public static string ProcessRegisterXml(string xml) } catch { + error = true; message += "Invalid Configuration Option from CMS [" + node.Name + "]" + Environment.NewLine; } } // Store the MD5 hash and the save - ApplicationSettings.Default.Hash = md5; + ApplicationSettings.Default.Hash = (error) ? "0" : md5; ApplicationSettings.Default.Save(); } else diff --git a/XmdsAgents/RequiredFilesAgent.cs b/XmdsAgents/RequiredFilesAgent.cs index 7aa04fc0..1792a94d 100644 --- a/XmdsAgents/RequiredFilesAgent.cs +++ b/XmdsAgents/RequiredFilesAgent.cs @@ -1,6 +1,6 @@ /* * Xibo - Digitial Signage - http://www.xibo.org.uk - * Copyright (C) 2006 - 2014 Daniel Garner + * Copyright (C) 2006 - 2015 Daniel Garner * * This file is part of Xibo. * @@ -26,6 +26,7 @@ using System.Xml; using XiboClient.Log; using System.Net; +using System.Globalization; /// 17/02/12 Dan Created /// 20/02/12 Dan Added ClientInfo @@ -114,114 +115,121 @@ public void Run() { lock (_locker) { - try + if (ApplicationSettings.Default.InDownloadWindow) { - // If we are restarting, reset - _manualReset.Reset(); - - int filesToDownload = _requiredFiles.FilesDownloading; - - // If we are currently downloading something, we have to wait - if (filesToDownload > 0) + try { - _clientInfoForm.RequiredFilesStatus = string.Format("Waiting: {0} Active Downloads", filesToDownload.ToString()); + // If we are restarting, reset + _manualReset.Reset(); - Trace.WriteLine(new LogMessage("RequiredFilesAgent - Run", "Currently Downloading Files, skipping collect"), LogType.Info.ToString()); - } - else - { - _clientInfoForm.RequiredFilesStatus = "Running: Requesting connection to Xibo Server"; + int filesToDownload = _requiredFiles.FilesDownloading; - using (xmds.xmds xmds = new xmds.xmds()) + // If we are currently downloading something, we have to wait + if (filesToDownload > 0) { - xmds.Credentials = null; - xmds.Url = ApplicationSettings.Default.XiboClient_xmds_xmds; - xmds.UseDefaultCredentials = false; - - // Get required files from XMDS - string requiredFilesXml = xmds.RequiredFiles(ApplicationSettings.Default.ServerKey, _hardwareKey); - - // Set the flag to indicate we have a connection to XMDS - ApplicationSettings.Default.XmdsLastConnection = DateTime.Now; + _clientInfoForm.RequiredFilesStatus = string.Format("Waiting: {0} Active Downloads", filesToDownload.ToString()); - _clientInfoForm.RequiredFilesStatus = "Running: Data received from Xibo Server"; - - // Load the XML file RF call - XmlDocument xml = new XmlDocument(); - xml.LoadXml(requiredFilesXml); - - // Create a required files object and set it to contain the RF returned this tick - _requiredFiles = new RequiredFiles(); - _requiredFiles.CurrentCacheManager = _cacheManager; - _requiredFiles.RequiredFilesXml = xml; - - // List of Threads to start - // TODO: Track these threads so that we can abort them if the application closes - List threadsToStart = new List(); + Trace.WriteLine(new LogMessage("RequiredFilesAgent - Run", "Currently Downloading Files, skipping collect"), LogType.Info.ToString()); + } + else + { + _clientInfoForm.RequiredFilesStatus = "Running: Requesting connection to Xibo Server"; - // Required files now contains a list of files to download (this will be updated by the various worker threads) - foreach (RequiredFile fileToDownload in _requiredFiles.RequiredFileList) + using (xmds.xmds xmds = new xmds.xmds()) { - // Skip downloaded files - if (fileToDownload.Complete) - continue; - - // Spawn a thread to download this file. - FileAgent fileAgent = new FileAgent(); - fileAgent.FileDownloadLimit = _fileDownloadLimit; - fileAgent.HardwareKey = _hardwareKey; - fileAgent.RequiredFiles = _requiredFiles; - fileAgent.RequiredFileId = fileToDownload.Id; - fileAgent.RequiredFileType = fileToDownload.FileType; - fileAgent.OnComplete += new FileAgent.OnCompleteDelegate(fileAgent_OnComplete); - fileAgent.OnPartComplete += new FileAgent.OnPartCompleteDelegate(fileAgent_OnPartComplete); - - // Create the thread and add it to the list of threads to start - Thread thread = new Thread(new ThreadStart(fileAgent.Run)); - thread.Name = "FileAgent_" + fileToDownload.FileType + "_Id_" + fileToDownload.Id.ToString(); - threadsToStart.Add(thread); + xmds.Credentials = null; + xmds.Url = ApplicationSettings.Default.XiboClient_xmds_xmds; + xmds.UseDefaultCredentials = false; + + // Get required files from XMDS + string requiredFilesXml = xmds.RequiredFiles(ApplicationSettings.Default.ServerKey, _hardwareKey); + + // Set the flag to indicate we have a connection to XMDS + ApplicationSettings.Default.XmdsLastConnection = DateTime.Now; + + _clientInfoForm.RequiredFilesStatus = "Running: Data received from Xibo Server"; + + // Load the XML file RF call + XmlDocument xml = new XmlDocument(); + xml.LoadXml(requiredFilesXml); + + // Create a required files object and set it to contain the RF returned this tick + _requiredFiles = new RequiredFiles(); + _requiredFiles.CurrentCacheManager = _cacheManager; + _requiredFiles.RequiredFilesXml = xml; + + // List of Threads to start + // TODO: Track these threads so that we can abort them if the application closes + List threadsToStart = new List(); + + // Required files now contains a list of files to download (this will be updated by the various worker threads) + foreach (RequiredFile fileToDownload in _requiredFiles.RequiredFileList) + { + // Skip downloaded files + if (fileToDownload.Complete) + continue; + + // Spawn a thread to download this file. + FileAgent fileAgent = new FileAgent(); + fileAgent.FileDownloadLimit = _fileDownloadLimit; + fileAgent.HardwareKey = _hardwareKey; + fileAgent.RequiredFiles = _requiredFiles; + fileAgent.RequiredFileId = fileToDownload.Id; + fileAgent.RequiredFileType = fileToDownload.FileType; + fileAgent.OnComplete += new FileAgent.OnCompleteDelegate(fileAgent_OnComplete); + fileAgent.OnPartComplete += new FileAgent.OnPartCompleteDelegate(fileAgent_OnPartComplete); + + // Create the thread and add it to the list of threads to start + Thread thread = new Thread(new ThreadStart(fileAgent.Run)); + thread.Name = "FileAgent_" + fileToDownload.FileType + "_Id_" + fileToDownload.Id.ToString(); + threadsToStart.Add(thread); + } + + // Start the threads after we have built them all - otherwise they will modify the collection we + // are iterating over. + foreach (Thread thread in threadsToStart) + thread.Start(); + + // Report what we are doing back to MediaInventory + _requiredFiles.ReportInventory(); + + // Write Required Files + _requiredFiles.WriteRequiredFiles(); + + // Write the Cache Manager to Disk + _cacheManager.WriteCacheManager(); + + // Set the status on the client info screen + if (threadsToStart.Count == 0) + _clientInfoForm.RequiredFilesStatus = "Sleeping (inside download window)"; + else + _clientInfoForm.RequiredFilesStatus = string.Format("{0} files to download", threadsToStart.Count.ToString()); + + _clientInfoForm.UpdateRequiredFiles(RequiredFilesString()); } - - // Start the threads after we have built them all - otherwise they will modify the collection we - // are iterating over. - foreach (Thread thread in threadsToStart) - thread.Start(); - - // Report what we are doing back to MediaInventory - _requiredFiles.ReportInventory(); - - // Write Required Files - _requiredFiles.WriteRequiredFiles(); - - // Write the Cache Manager to Disk - _cacheManager.WriteCacheManager(); - - // Set the status on the client info screen - if (threadsToStart.Count == 0) - _clientInfoForm.RequiredFilesStatus = "Sleeping"; - else - _clientInfoForm.RequiredFilesStatus = string.Format("{0} files to download", threadsToStart.Count.ToString()); - - _clientInfoForm.UpdateRequiredFiles(RequiredFilesString()); } } - } - catch (WebException webEx) - { - // Increment the quantity of XMDS failures and bail out - ApplicationSettings.Default.IncrementXmdsErrorCount(); + catch (WebException webEx) + { + // Increment the quantity of XMDS failures and bail out + ApplicationSettings.Default.IncrementXmdsErrorCount(); + + // Log this message, but dont abort the thread + Trace.WriteLine(new LogMessage("RequiredFilesAgent - Run", "WebException in Run: " + webEx.Message), LogType.Error.ToString()); - // Log this message, but dont abort the thread - Trace.WriteLine(new LogMessage("RequiredFilesAgent - Run", "WebException in Run: " + webEx.Message), LogType.Error.ToString()); + _clientInfoForm.RequiredFilesStatus = "Error: " + webEx.Message; + } + catch (Exception ex) + { + // Log this message, but dont abort the thread + Trace.WriteLine(new LogMessage("RequiredFilesAgent - Run", "Exception in Run: " + ex.Message), LogType.Error.ToString()); - _clientInfoForm.RequiredFilesStatus = "Error: " + webEx.Message; + _clientInfoForm.RequiredFilesStatus = "Error: " + ex.Message; + } } - catch (Exception ex) + else { - // Log this message, but dont abort the thread - Trace.WriteLine(new LogMessage("RequiredFilesAgent - Run", "Exception in Run: " + ex.Message), LogType.Error.ToString()); - - _clientInfoForm.RequiredFilesStatus = "Error: " + ex.Message; + _clientInfoForm.RequiredFilesStatus = string.Format("Outside Download Window {0} - {1}", ApplicationSettings.Default.DownloadStartWindowTime.ToString("HH:mm", CultureInfo.InvariantCulture), ApplicationSettings.Default.DownloadEndWindowTime.ToString("HH:mm", CultureInfo.InvariantCulture)); } } diff --git a/bin/x86/Release/Xibo.scr b/bin/x86/Release/Xibo.scr index 1c927212..13519de0 100644 Binary files a/bin/x86/Release/Xibo.scr and b/bin/x86/Release/Xibo.scr differ diff --git a/bin/x86/Release/XiboClient.XmlSerializers.dll b/bin/x86/Release/XiboClient.XmlSerializers.dll index 0599934a..e5c38891 100644 Binary files a/bin/x86/Release/XiboClient.XmlSerializers.dll and b/bin/x86/Release/XiboClient.XmlSerializers.dll differ diff --git a/bin/x86/Release/XiboClient.exe b/bin/x86/Release/XiboClient.exe index 2201b1c0..13519de0 100644 Binary files a/bin/x86/Release/XiboClient.exe and b/bin/x86/Release/XiboClient.exe differ diff --git a/bin/x86/Release/XiboClient.pdb b/bin/x86/Release/XiboClient.pdb index 3d5edf40..55f5e965 100644 Binary files a/bin/x86/Release/XiboClient.pdb and b/bin/x86/Release/XiboClient.pdb differ diff --git a/bin/x86/Release/default.config.xml b/bin/x86/Release/default.config.xml index 0afc84b6..cd468504 100644 --- a/bin/x86/Release/default.config.xml +++ b/bin/x86/Release/default.config.xml @@ -45,8 +45,10 @@ true false 0001-01-01T00:00:00 - true + false false false 0 + 0 + 0 \ No newline at end of file diff --git a/default.config.xml b/default.config.xml index 0afc84b6..cd468504 100644 --- a/default.config.xml +++ b/default.config.xml @@ -45,8 +45,10 @@ true false 0001-01-01T00:00:00 - true + false false false 0 + 0 + 0 \ No newline at end of file