Пример #1
0
        public void Run()
        {
            bool success;

            try
            {
                // Get a fresh command from settings
                Command = Command.GetByCode(Code);

                // Run the command.
                success = Command.Run();
            }
            catch (Exception e)
            {
                Trace.WriteLine(new LogMessage("CommandSchedule - Run", "Cannot start Run Command: " + e.Message), LogType.Error.ToString());
                success = false;
            }

            // Notify the state of the command (success or failure)
            using (xmds.xmds statusXmds = new xmds.xmds())
            {
                statusXmds.Url = ApplicationSettings.Default.R23SignageClient_xmds_xmds;
                statusXmds.NotifyStatusAsync(ApplicationSettings.Default.ServerKey, ApplicationSettings.Default.HardwareKey, "{\"lastCommandSuccess\":" + success + "}");
            }
        }
Пример #2
0
        /// <summary>
        /// Runs the agent
        /// </summary>
        public void Run()
        {
            Trace.WriteLine(new LogMessage("RegisterAgent - 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;

                            RegisterAgent.ProcessRegisterXml(xmds.RegisterDisplay(ApplicationSettings.Default.ServerKey, key.Key, ApplicationSettings.Default.DisplayName, "windows", ApplicationSettings.Default.ClientVersion, ApplicationSettings.Default.ClientCodeVersion, Environment.OSVersion.ToString(), key.MacAddress));

                            // Set the flag to indicate we have a connection to XMDS
                            ApplicationSettings.Default.XmdsLastConnection = DateTime.Now;

                            // Do we need to send a screenshot?
                            if (ApplicationSettings.Default.ScreenShotRequested)
                            {
                                ApplicationSettings.Default.ScreenShotRequested = false;
                                ScreenShot.TakeAndSend();
                            }
                        }
                    }
                    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("RegisterAgent - Run", "WebException in Run: " + webEx.Message), LogType.Error.ToString());
                    }
                    catch (Exception ex)
                    {
                        // Log this message, but dont abort the thread
                        Trace.WriteLine(new LogMessage("RegisterAgent - 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("RegisterAgent - Run", "Thread Stopped"), LogType.Info.ToString());
        }
Пример #3
0
        /// <summary>
        /// Runs the agent
        /// </summary>
        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.R23SignageClient_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 static void send(Bitmap bitmap)
        {
            using (MemoryStream stream = new MemoryStream())
            {
                bitmap.Save(stream, ImageFormat.Jpeg);

                byte[] bytes = stream.ToArray();

                using (xmds.xmds screenShotXmds = new xmds.xmds())
                {
                    screenShotXmds.Url = ApplicationSettings.Default.XiboClient_xmds_xmds + "&method=submitScreenshot";
                    screenShotXmds.SubmitScreenShotCompleted += screenShotXmds_SubmitScreenShotCompleted;
                    screenShotXmds.SubmitScreenShotAsync(ApplicationSettings.Default.ServerKey, ApplicationSettings.Default.HardwareKey, bytes);
                }
            }
        }
Пример #5
0
        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("<log>");

                foreach (string entry in File.ReadAllLines(fileName))
                {
                    builder.Append(entry);
                }

                builder.Append("</log>");

                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++;
            }
        }
        private void reportStorage()
        {
            // Use Drive Info
            foreach (DriveInfo drive in DriveInfo.GetDrives())
            {
                if (drive.IsReady && ApplicationSettings.Default.LibraryPath.Contains(drive.RootDirectory.FullName))
                {
                    using (xmds.xmds xmds = new xmds.xmds())
                    {
                        string status = "{\"availableSpace\":\"" + drive.TotalFreeSpace + "\", \"totalSpace\":\"" + drive.TotalSize + "\"}";

                        xmds.Credentials           = null;
                        xmds.Url                   = ApplicationSettings.Default.XiboClient_xmds_xmds;
                        xmds.UseDefaultCredentials = false;
                        xmds.NotifyStatusAsync(ApplicationSettings.Default.ServerKey, ApplicationSettings.Default.HardwareKey, status);
                    }

                    break;
                }
            }
        }
Пример #7
0
        public void notifyStatusToXmds()
        {
            try
            {
                StringBuilder sb = new StringBuilder();
                StringWriter  sw = new StringWriter(sb);

                using (JsonWriter writer = new JsonTextWriter(sw))
                {
                    writer.Formatting = Formatting.None;
                    writer.WriteStartObject();
                    writer.WritePropertyName("lastActivity");
                    writer.WriteValue(DateTime.Now.ToString());
                    writer.WritePropertyName("applicationState");
                    writer.WriteValue(Thread.State.ToString());
                    writer.WritePropertyName("xmdsLastActivity");
                    writer.WriteValue(ApplicationSettings.Default.XmdsLastConnection.ToString());
                    writer.WritePropertyName("scheduleStatus");
                    writer.WriteValue(scheduleStatusLabel.Text);
                    writer.WritePropertyName("requiredFilesStatus");
                    writer.WriteValue(requiredFilesStatus.Text);
                    writer.WritePropertyName("xmrStatus");
                    writer.WriteValue(xmrStatus.Text);
                    writer.WriteEndObject();
                }

                // Notify the state of the command (success or failure)
                using (xmds.xmds statusXmds = new xmds.xmds())
                {
                    statusXmds.Url = ApplicationSettings.Default.XiboClient_xmds_xmds + "&method=notifyStatus";
                    statusXmds.NotifyStatusAsync(ApplicationSettings.Default.ServerKey, ApplicationSettings.Default.HardwareKey, sb.ToString());
                }
            }
            catch (Exception e)
            {
                Trace.WriteLine(new LogMessage("ClientInfo - notifyStatusToXmds", "Failed to notify status to XMDS. e = " + e.Message), LogType.Error.ToString());
            }
        }
        private void reportStorage()
        {
            StringBuilder sb = new StringBuilder();
            StringWriter  sw = new StringWriter(sb);

            using (JsonWriter writer = new JsonTextWriter(sw))
            {
                writer.Formatting = Newtonsoft.Json.Formatting.None;
                writer.WriteStartObject();
                writer.WritePropertyName("deviceName");
                writer.WriteValue(Environment.MachineName);

                // Use Drive Info
                foreach (DriveInfo drive in DriveInfo.GetDrives())
                {
                    if (drive.IsReady && ApplicationSettings.Default.LibraryPath.Contains(drive.RootDirectory.FullName))
                    {
                        writer.WritePropertyName("availableSpace");
                        writer.WriteValue(drive.TotalFreeSpace);
                        writer.WritePropertyName("totalSpace");
                        writer.WriteValue(drive.TotalSize);
                        break;
                    }
                }

                writer.WriteEndObject();

                // Report
                using (xmds.xmds xmds = new xmds.xmds())
                {
                    xmds.Credentials           = null;
                    xmds.Url                   = ApplicationSettings.Default.XiboClient_xmds_xmds + "&method=notifyStatus";
                    xmds.UseDefaultCredentials = false;
                    xmds.NotifyStatusAsync(ApplicationSettings.Default.ServerKey, ApplicationSettings.Default.HardwareKey, sb.ToString());
                }
            }
        }
Пример #9
0
        public static void TakeAndSend()
        {
            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))
                {
                    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())
                {
                    bitmap.Save(stream, ImageFormat.Jpeg);

                    byte[] bytes = stream.ToArray();
                    
                    using (xmds.xmds screenShotXmds = new xmds.xmds())
                    {
                        screenShotXmds.Url = ApplicationSettings.Default.XiboClient_xmds_xmds;
                        screenShotXmds.SubmitScreenShotCompleted += screenShotXmds_SubmitScreenShotCompleted;
                        screenShotXmds.SubmitScreenShotAsync(ApplicationSettings.Default.ServerKey, ApplicationSettings.Default.HardwareKey, bytes);
                    }
                }
            }
        }
Пример #10
0
        public static void TakeAndSend()
        {
            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))
                {
                    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())
                {
                    bitmap.Save(stream, ImageFormat.Jpeg);

                    byte[] bytes = stream.ToArray();

                    using (xmds.xmds screenShotXmds = new xmds.xmds())
                    {
                        screenShotXmds.Url = ApplicationSettings.Default.XiboClient_xmds_xmds;
                        screenShotXmds.SubmitScreenShotCompleted += screenShotXmds_SubmitScreenShotCompleted;
                        screenShotXmds.SubmitScreenShotAsync(ApplicationSettings.Default.ServerKey, ApplicationSettings.Default.HardwareKey, bytes);
                    }
                }
            }
        }
Пример #11
0
        /// <summary>
        /// Adds a media item to the Black list. Adds Locally and to the WebService
        /// </summary>
        /// <param name="id">The Media ID</param>
        /// <param name="type">The BlackListType, either All (to blacklist on all displays) or Single (to blacklist only on this display)</param>
        /// <param name="reason">The reason for the blacklist</param>
        public void Add(string id, BlackListType type, string reason)
        {
            // Do some validation
            if (reason == "")
            {
                reason = "No reason provided";
            }

            int mediaId;

            if (!int.TryParse(id, out mediaId))
            {
                System.Diagnostics.Trace.WriteLine(String.Format("Currently can only append Integer media types. Id {0}", id), "BlackList - Add");
            }

            // Send to the webservice
            xmds1 = new XiboClient.xmds.xmds();
            xmds1.BlackListCompleted += new XiboClient.xmds.BlackListCompletedEventHandler(xmds1_BlackListCompleted);

            xmds1.BlackListAsync(ApplicationSettings.Default.ServerKey, hardwareKey.Key, mediaId, type.ToString(), reason, ApplicationSettings.Default.Version);

            // Add to the local list
            AddLocal(id);
        }
        /// <summary>
        /// Schedule Agent
        /// </summary>
        private void scheduleAgent()
        {
            try
            {
                // If we are restarting, reset
                _manualReset.Reset();

                Trace.WriteLine(new LogMessage("ScheduleAgent - Run", "Thread Woken and Lock Obtained"), LogType.Audit.ToString());

                _clientInfoForm.ScheduleStatus = "Running: Get Data from Xibo Server";

                using (xmds.xmds xmds = new xmds.xmds())
                {
                    xmds.Credentials           = null;
                    xmds.Url                   = ApplicationSettings.Default.XiboClient_xmds_xmds + "&method=schedule";
                    xmds.UseDefaultCredentials = false;

                    string scheduleXml = xmds.Schedule(ApplicationSettings.Default.ServerKey, _hardwareKey);

                    // Set the flag to indicate we have a connection to XMDS
                    ApplicationSettings.Default.XmdsLastConnection = DateTime.Now;

                    _clientInfoForm.ScheduleStatus = "Running: Data Received";

                    // Hash of the result
                    string md5NewSchedule     = Hashes.MD5(scheduleXml);
                    string md5CurrentSchedule = Hashes.MD5(ScheduleManager.GetScheduleXmlString(_scheduleLocation));

                    // Compare the results of the HASH
                    if (md5CurrentSchedule != md5NewSchedule)
                    {
                        Trace.WriteLine(new LogMessage("Schedule Agent - Run", "Received new schedule"));

                        _clientInfoForm.ScheduleStatus = "Running: New Schedule Received";

                        // Write the result to the schedule xml location
                        ScheduleManager.WriteScheduleXmlToDisk(_scheduleLocation, scheduleXml);

                        // Indicate to the schedule manager that it should read the XML file
                        _scheduleManager.RefreshSchedule = true;
                    }

                    _clientInfoForm.ScheduleStatus = "Sleeping";
                }
            }
            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("ScheduleAgent - Run", "WebException in Run: " + webEx.Message), LogType.Info.ToString());

                _clientInfoForm.ScheduleStatus = "Error: " + webEx.Message;
            }
            catch (Exception ex)
            {
                // Log this message, but dont abort the thread
                Trace.WriteLine(new LogMessage("ScheduleAgent - Run", "Exception in Run: " + ex.Message), LogType.Error.ToString());
                _clientInfoForm.ScheduleStatus = "Error. " + ex.Message;
            }
        }
Пример #13
0
        /// <summary>
        /// Runs the agent
        /// </summary>
        public void Run()
        {
            Trace.WriteLine(new LogMessage("ScheduleAgent - Run", "Thread Started"), LogType.Info.ToString());

            while (!_forceStop)
            {
                lock (_locker)
                {
                    try
                    {
                        // If we are restarting, reset
                        _manualReset.Reset();

                        Trace.WriteLine(new LogMessage("ScheduleAgent - Run", "Thread Woken and Lock Obtained"), LogType.Info.ToString());

                        _clientInfoForm.ScheduleStatus = "Running: Get Data from Xibo Server";

                        using (xmds.xmds xmds = new xmds.xmds())
                        {
                            xmds.Credentials = null;
                            xmds.Url = ApplicationSettings.Default.R23SignageClient_xmds_xmds;
                            xmds.UseDefaultCredentials = false;

                            string scheduleXml = xmds.Schedule(ApplicationSettings.Default.ServerKey, _hardwareKey);

                            // Set the flag to indicate we have a connection to XMDS
                            ApplicationSettings.Default.XmdsLastConnection = DateTime.Now;

                            _clientInfoForm.ScheduleStatus = "Running: Data Received";

                            // Hash of the result
                            string md5NewSchedule = Hashes.MD5(scheduleXml);
                            string md5CurrentSchedule = Hashes.MD5(ScheduleManager.GetScheduleXmlString(_scheduleLocation));

                            // Compare the results of the HASH
                            if (md5CurrentSchedule != md5NewSchedule)
                            {
                                Trace.WriteLine(new LogMessage("Schedule Agent - Run", "Received new schedule"));

                                _clientInfoForm.ScheduleStatus = "Running: New Schedule Received";

                                // Write the result to the schedule xml location
                                ScheduleManager.WriteScheduleXmlToDisk(_scheduleLocation, scheduleXml);

                                // Indicate to the schedule manager that it should read the XML file
                                _scheduleManager.RefreshSchedule = true;
                            }

                            _clientInfoForm.ScheduleStatus = "Sleeping";
                        }
                    }
                    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("ScheduleAgent - Run", "WebException in Run: " + webEx.Message), LogType.Error.ToString());

                        _clientInfoForm.ScheduleStatus = "Error: " + webEx.Message;
                    }
                    catch (Exception ex)
                    {
                        // Log this message, but dont abort the thread
                        Trace.WriteLine(new LogMessage("ScheduleAgent - Run", "Exception in Run: " + ex.Message), LogType.Error.ToString());
                        _clientInfoForm.ScheduleStatus = "Error. " + ex.Message;
                    }
                }

                // Sleep this thread until the next collection interval
                _manualReset.WaitOne((int)(ApplicationSettings.Default.CollectInterval * ApplicationSettings.Default.XmdsCollectionIntervalFactor() * 1000));
            }

            Trace.WriteLine(new LogMessage("ScheduleAgent - Run", "Thread Stopped"), LogType.Info.ToString());
        }
Пример #14
0
        /// <summary>
        /// Runs the agent
        /// </summary>
        public void Run()
        {
            Trace.WriteLine(new LogMessage("LogAgent - Run", "Thread Started"), LogType.Info.ToString());

            int retryAfterSeconds = 0;

            while (!_forceStop)
            {
                lock (_locker)
                {
                    try
                    {
                        // If we are restarting, reset
                        _manualReset.Reset();

                        // Reset backOff
                        retryAfterSeconds = 0;

                        HardwareKey key = new HardwareKey();

                        Trace.WriteLine(new LogMessage("RegisterAgent - Run", "Thread Woken and Lock Obtained"), LogType.Audit.ToString());

                        using (xmds.xmds xmds = new xmds.xmds())
                        {
                            xmds.Credentials           = null;
                            xmds.Url                   = ApplicationSettings.Default.XiboClient_xmds_xmds + "&method=submitLog";
                            xmds.UseDefaultCredentials = false;

                            // Log
                            ProcessFiles(xmds, key.Key, ApplicationSettings.Default.LogLocation);
                        }
                    }
                    catch (WebException webEx) when(webEx.Response is HttpWebResponse httpWebResponse && (int)httpWebResponse.StatusCode == 429)
                    {
                        // Get the header for how long we ought to wait
                        retryAfterSeconds = webEx.Response.Headers["Retry-After"] != null?int.Parse(webEx.Response.Headers["Retry-After"]) : 120;

                        // Log it.
                        Trace.WriteLine(new LogMessage("LogAgent", "Run: 429 received, waiting for " + retryAfterSeconds + " seconds."), LogType.Info.ToString());
                    }
                    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.Info.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());
                    }
                }

                if (retryAfterSeconds > 0)
                {
                    // Sleep this thread until we've fulfilled our try after
                    _manualReset.WaitOne(retryAfterSeconds * 1000);
                }
                else
                {
                    // 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());
        }
Пример #15
0
        private void reportStorage()
        {
            // Use Drive Info
            foreach (DriveInfo drive in DriveInfo.GetDrives())
            {
                if (drive.IsReady && ApplicationSettings.Default.LibraryPath.Contains(drive.RootDirectory.FullName))
                {
                    using (xmds.xmds xmds = new xmds.xmds())
                    {
                        string status = "{\"availableSpace\":\"" + drive.TotalFreeSpace + "\", \"totalSpace\":\"" + drive.TotalSize + "\"}";

                        xmds.Credentials = null;
                        xmds.Url = ApplicationSettings.Default.R23SignageClient_xmds_xmds;
                        xmds.UseDefaultCredentials = false;
                        xmds.NotifyStatusAsync(ApplicationSettings.Default.ServerKey, ApplicationSettings.Default.HardwareKey, status);
                    }

                    break;
                }
            }
        }
        /// <summary>
        /// Schedule Agent
        /// </summary>
        private void scheduleAgent()
        {
            try
            {
                if (!ShouldCheckSchedule())
                {
                    ClientInfo.Instance.ScheduleStatus = "Sleeping: last check was not required.";
                    return;
                }

                Trace.WriteLine(new LogMessage("ScheduleAgent - Run", "Thread Woken and Lock Obtained"), LogType.Audit.ToString());

                ClientInfo.Instance.ScheduleStatus = "Running: Get Data from Xibo Server";

                using (xmds.xmds xmds = new xmds.xmds())
                {
                    xmds.Credentials           = null;
                    xmds.Url                   = ApplicationSettings.Default.XiboClient_xmds_xmds + "&method=schedule";
                    xmds.UseDefaultCredentials = false;

                    string scheduleXml = xmds.Schedule(ApplicationSettings.Default.ServerKey, _hardwareKey);

                    // Set the flag to indicate we have a connection to XMDS
                    ApplicationSettings.Default.XmdsLastConnection = DateTime.Now;

                    ClientInfo.Instance.ScheduleStatus = "Running: Data Received";

                    // Calculate and store a CRC32
                    _lastCheckSchedule = Crc32Algorithm.Compute(Encoding.UTF8.GetBytes(scheduleXml)).ToString();

                    // Hash of the result
                    // TODO: we can probably remove this at some point in the future, given later CMS instances output CRC32's to indicate whether
                    // the schedule has changed.
                    string md5NewSchedule     = Hashes.MD5(scheduleXml);
                    string md5CurrentSchedule = Hashes.MD5(ScheduleManager.GetScheduleXmlString(_scheduleLocation));

                    // Compare the results of the HASH
                    if (md5CurrentSchedule != md5NewSchedule)
                    {
                        Trace.WriteLine(new LogMessage("Schedule Agent - Run", "Received new schedule"));

                        ClientInfo.Instance.ScheduleStatus = "Running: New Schedule Received";

                        // Write the result to the schedule xml location
                        ScheduleManager.WriteScheduleXmlToDisk(_scheduleLocation, scheduleXml);

                        // Indicate to the schedule manager that it should read the XML file
                        _scheduleManager.RefreshSchedule = true;
                    }

                    ClientInfo.Instance.ScheduleStatus = "Sleeping";
                }
            }
            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("ScheduleAgent - Run", "WebException in Run: " + webEx.Message), LogType.Info.ToString());

                ClientInfo.Instance.ScheduleStatus = "Error: " + webEx.Message;
            }
            catch (Exception ex)
            {
                // Log this message, but dont abort the thread
                Trace.WriteLine(new LogMessage("ScheduleAgent - Run", "Exception in Run: " + ex.Message), LogType.Error.ToString());
                ClientInfo.Instance.ScheduleStatus = "Error. " + ex.Message;
            }
        }
Пример #17
0
        /// <summary>
        /// Report the timezone to XMDS
        /// </summary>
        private void NotifyStatus()
        {
            StringBuilder sb = new StringBuilder();

            using (StringWriter sw = new StringWriter(sb))
                using (JsonWriter writer = new JsonTextWriter(sw))
                {
                    writer.Formatting = Newtonsoft.Json.Formatting.None;
                    writer.WriteStartObject();
                    writer.WritePropertyName("deviceName");
                    writer.WriteValue(Environment.MachineName);
                    writer.WritePropertyName("width");
                    writer.WriteValue(ClientInfo.Instance.PlayerWidth);
                    writer.WritePropertyName("height");
                    writer.WriteValue(ClientInfo.Instance.PlayerHeight);

                    // GeoLocation
                    if (ClientInfo.Instance.CurrentGeoLocation != null && !ClientInfo.Instance.CurrentGeoLocation.IsUnknown)
                    {
                        writer.WritePropertyName("latitude");
                        writer.WriteValue(ClientInfo.Instance.CurrentGeoLocation.Latitude);
                        writer.WritePropertyName("longitude");
                        writer.WriteValue(ClientInfo.Instance.CurrentGeoLocation.Longitude);
                    }

                    try
                    {
                        // Use Drive Info
                        foreach (DriveInfo drive in DriveInfo.GetDrives())
                        {
                            if (drive.IsReady && ApplicationSettings.Default.LibraryPath.Contains(drive.RootDirectory.FullName))
                            {
                                writer.WritePropertyName("availableSpace");
                                writer.WriteValue(drive.TotalFreeSpace);
                                writer.WritePropertyName("totalSpace");
                                writer.WriteValue(drive.TotalSize);
                                break;
                            }
                        }
                    }
                    catch
                    {
                        Trace.WriteLine(new LogMessage("NotifyStatus", "Unable to get drive info"), LogType.Info.ToString());
                    }


                    // Timezone
                    // we only do the timezone if it is currently empty, otherwise we stick with whatever has been set.
                    if (string.IsNullOrEmpty(ApplicationSettings.Default.DisplayTimeZone))
                    {
                        writer.WritePropertyName("timeZone");
                        writer.WriteValue(WindowsToIana(TimeZone.CurrentTimeZone.StandardName));
                    }

                    // Finish
                    writer.WriteEndObject();

                    // Report
                    using (xmds.xmds xmds = new xmds.xmds())
                    {
                        xmds.Credentials           = null;
                        xmds.Url                   = ApplicationSettings.Default.XiboClient_xmds_xmds + "&method=notifyStatus";
                        xmds.UseDefaultCredentials = false;
                        xmds.NotifyStatusAsync(ApplicationSettings.Default.ServerKey, ApplicationSettings.Default.HardwareKey, sb.ToString());
                    }
                }

            sb.Clear();
        }
Пример #18
0
        /// <summary>
        /// Runs the agent
        /// </summary>
        public void Run()
        {
            Trace.WriteLine(new LogMessage("StatAgent", "Run: Thread Started"), LogType.Info.ToString());

            // Assume no backlog when we first start out.
            bool isBacklog           = false;
            int  retryAfterSeconds   = 0;
            int  countBacklogBatches = 0;
            int  processing          = 0;

            while (!_forceStop)
            {
                lock (_locker)
                {
                    // What is out processing flag?
                    processing = (new Random()).Next(1, 1000);

                    try
                    {
                        // If we are restarting, reset
                        _manualReset.Reset();

                        // Reset backOff
                        retryAfterSeconds = 0;

                        // How many records do we have to send?
                        int recordsReady = StatManager.Instance.TotalReady();

                        // Does this mean we're in a backlog situation?
                        isBacklog = (recordsReady >= 500);

                        // Check to see if we have anything to send
                        if (StatManager.Instance.MarkRecordsForSend(processing, isBacklog))
                        {
                            HardwareKey key = new HardwareKey();

                            Trace.WriteLine(new LogMessage("StatAgent", "Run: Thread Woken and Lock Obtained, Key: " + processing), LogType.Audit.ToString());

                            using (xmds.xmds xmds = new xmds.xmds())
                            {
                                xmds.Credentials           = null;
                                xmds.Url                   = ApplicationSettings.Default.XiboClient_xmds_xmds + "&method=submitStats";
                                xmds.UseDefaultCredentials = false;

                                // Get the starts we've marked to process as XML.
                                xmds.SubmitStats(ApplicationSettings.Default.ServerKey, key.Key, StatManager.Instance.GetXmlForSend(processing));
                            }

                            // Update the last send date to indicate we've just done so
                            StatManager.Instance.LastSendDate = DateTime.Now;

                            // Remove the ones we've just sent
                            StatManager.Instance.DeleteSent(processing);
                        }
                    }
                    catch (WebException webEx) when(webEx.Response is HttpWebResponse httpWebResponse && (int)httpWebResponse.StatusCode == 429)
                    {
                        // We got a backoff, so none of those records are processed.
                        StatManager.Instance.UnmarkRecordsForSend(processing);

                        // Get the header for how long we ought to wait
                        retryAfterSeconds = webEx.Response.Headers["Retry-After"] != null?int.Parse(webEx.Response.Headers["Retry-After"]) : 120;

                        // Log it.
                        Trace.WriteLine(new LogMessage("StatAgent", "Run: 429 received, waiting for " + retryAfterSeconds + " seconds."), LogType.Info.ToString());
                    }
                    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("StatAgent", "Run: WebException in Run: " + webEx.Message), LogType.Info.ToString());

                        // Something went wrong sending those records, set them to be reprocessed
                        StatManager.Instance.UnmarkRecordsForSend(processing);
                    }
                    catch (Exception ex)
                    {
                        // Log this message, but dont abort the thread
                        Trace.WriteLine(new LogMessage("StatAgent", "Run: Exception in Run: " + ex.Message), LogType.Error.ToString());

                        // Something went wrong sending those records, set them to be reprocessed
                        StatManager.Instance.UnmarkRecordsForSend(processing);
                    }
                }

                if (retryAfterSeconds > 0)
                {
                    // Sleep this thread until we've fulfilled our try after
                    _manualReset.WaitOne(retryAfterSeconds * 1000);
                }
                else if (isBacklog)
                {
                    // We've just completed a send in backlog mode, so add to batches.
                    countBacklogBatches++;

                    // How many batches have we sent without a cooldown?
                    if (countBacklogBatches > 2)
                    {
                        // Reset batches
                        countBacklogBatches = 0;

                        // Come back in 30 seconds
                        _manualReset.WaitOne(30000);
                    }
                    else
                    {
                        // Come back much more quickly (10 seconds)
                        _manualReset.WaitOne(10000);
                    }
                }
                else
                {
                    // Reset batches
                    countBacklogBatches = 0;

                    // Sleep this thread until the next collection interval
                    _manualReset.WaitOne((int)(ApplicationSettings.Default.CollectInterval * ApplicationSettings.Default.XmdsCollectionIntervalFactor() * 1000));
                }
            }

            Trace.WriteLine(new LogMessage("StatAgent", "Run: Thread Stopped"), LogType.Info.ToString());
        }
        /// <summary>
        /// Run Thread
        /// </summary>
        public void Run()
        {
            Trace.WriteLine(new LogMessage("RequiredFilesAgent - Run", "Thread Started"), LogType.Info.ToString());

            while (!_forceStop)
            {
                lock (_locker)
                {
                    if (ApplicationSettings.Default.InDownloadWindow)
                    {
                        try
                        {
                            // If we are restarting, reset
                            _manualReset.Reset();

                            int filesToDownload = _requiredFiles.FilesDownloading;

                            // If we are currently downloading something, we have to wait
                            if (filesToDownload > 0)
                            {
                                _clientInfoForm.RequiredFilesStatus = string.Format("Waiting: {0} Active Downloads", filesToDownload.ToString());

                                Trace.WriteLine(new LogMessage("RequiredFilesAgent - Run", "Currently Downloading Files, skipping collect"), LogType.Audit.ToString());
                            }
                            else
                            {
                                _clientInfoForm.RequiredFilesStatus = "Running: Requesting connection to Xibo Server";

                                using (xmds.xmds xmds = new xmds.xmds())
                                {
                                    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 <Thread> threadsToStart = new List <Thread>();

                                    // 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();

                                    // Report the storage usage
                                    reportStorage();

                                    // 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());
                                }
                            }
                        }
                        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.Info.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: " + ex.Message;
                        }
                    }
                    else
                    {
                        _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));
                    }
                }

                // Sleep this thread until the next collection interval
                _manualReset.WaitOne((int)(ApplicationSettings.Default.CollectInterval * ApplicationSettings.Default.XmdsCollectionIntervalFactor() * 1000));
            }

            Trace.WriteLine(new LogMessage("RequiredFilesAgent - Run", "Thread Stopped"), LogType.Info.ToString());
        }
Пример #20
0
        /// <summary>
        /// Runs the agent
        /// </summary>
        public void Run()
        {
            Trace.WriteLine(new LogMessage("FileAgent - Run", "Thread Started"), LogType.Info.ToString());

            // Get the required file id from the list of required files.
            RequiredFile file = _requiredFiles.GetRequiredFile(_requiredFileId, _requiredFileType);

            // Set downloading to be true
            file.Downloading = true;

            // Wait for the Semaphore lock to become available
            _fileDownloadLimit.WaitOne();

            try
            {
                Trace.WriteLine(new LogMessage("FileAgent - Run", "Thread alive and Lock Obtained"), LogType.Info.ToString());

                if (file.FileType == "resource")
                {
                    // Download using GetResource
                    using (xmds.xmds xmds = new xmds.xmds())
                    {
                        xmds.Credentials = null;
                        xmds.Url = Settings.Default.XiboClient_xmds_xmds;
                        xmds.UseDefaultCredentials = true;

                        string result = xmds.GetResource(Settings.Default.ServerKey, Settings.Default.hardwareKey, file.LayoutId, file.RegionId, file.MediaId, Settings.Default.Version);

                        // Write the result to disk
                        using (StreamWriter sw = new StreamWriter(File.Open(Settings.Default.LibraryPath + @"\" + file.Path, FileMode.Create, FileAccess.Write, FileShare.Read)))
                        {
                            sw.Write(result);
                            sw.Close();
                        }

                        // File completed
                        file.Downloading = false;
                        file.Complete = true;
                    }
                }
                else
                {
                    while (!file.Complete)
                    {
                        byte[] getFileReturn;

                        // Call XMDS GetFile
                        using (xmds.xmds xmds = new xmds.xmds())
                        {
                            xmds.Credentials = null;
                            xmds.Url = Settings.Default.XiboClient_xmds_xmds;
                            xmds.UseDefaultCredentials = false;

                            getFileReturn = xmds.GetFile(Settings.Default.ServerKey, _hardwareKey, file.Path, file.FileType, file.ChunkOffset, file.ChunkSize, Settings.Default.Version);
                        }

                        // Set the flag to indicate we have a connection to XMDS
                        Settings.Default.XmdsLastConnection = DateTime.Now;

                        if (file.FileType == "layout")
                        {
                            // Decode this byte[] into a string and stick it in the file.
                            string layoutXml = Encoding.UTF8.GetString(getFileReturn);

                            // Full file is downloaded
                            using (StreamWriter sw = new StreamWriter(File.Open(Settings.Default.LibraryPath + @"\" + file.Path, FileMode.Create, FileAccess.Write, FileShare.Read)))
                            {
                                sw.Write(layoutXml);
                                sw.Close();
                            }

                            file.Complete = true;
                        }
                        else
                        {
                            // Media file
                            // Need to write to the file - in append mode
                            using (FileStream fs = new FileStream(Settings.Default.LibraryPath + @"\" + file.Path, FileMode.Append, FileAccess.Write))
                            {
                                fs.Write(getFileReturn, 0, getFileReturn.Length);
                                fs.Close();
                            }

                            // Increment the offset by the amount we just asked for
                            file.ChunkOffset = file.ChunkOffset + file.ChunkSize;

                            // Has the offset reached the total size?
                            if (file.Size > file.ChunkOffset)
                            {
                                int remaining = file.Size - file.ChunkOffset;

                                // There is still more to come
                                if (remaining < file.ChunkSize)
                                {
                                    // Get the remaining
                                    file.ChunkSize = remaining;
                                }

                                // Part is complete
                                OnPartComplete(file.Id);
                            }
                            else
                            {
                                // File complete
                                file.Complete = true;
                            }
                        }

                        getFileReturn = null;
                    }

                    // File completed
                    file.Downloading = false;

                    // Check MD5
                    string md5 = _requiredFiles.CurrentCacheManager.GetMD5(file.Path);
                    if (file.Md5 == md5)
                    {
                        // Mark it as complete
                        _requiredFiles.MarkComplete(_requiredFileId, file.Md5);

                        // Add it to the cache manager
                        _requiredFiles.CurrentCacheManager.Add(file.Path, file.Md5);

                        Trace.WriteLine(new LogMessage("FileAgent - Run", "File Downloaded Successfully. " + file.Path), LogType.Info.ToString());
                    }
                    else
                    {
                        // Just error - we will pick it up again the next time we download
                        Trace.WriteLine(new LogMessage("FileAgent - Run", "Downloaded file failed MD5 check. Calculated [" + md5 + "] & XMDS [ " + file.Md5 + "] . " + file.Path), LogType.Error.ToString());
                    }
                }

                // Inform the Player thread that a file has been modified.
                OnComplete(file.Id, file.FileType);
            }
            catch (Exception ex)
            {
                // Log this message, but dont abort the thread
                Trace.WriteLine(new LogMessage("FileAgent - Run", "Exception in Run: " + ex.Message), LogType.Error.ToString());

                // Mark as not downloading
                file.Downloading = false;
            }

            // Release the Semaphore
            Trace.WriteLine(new LogMessage("FileAgent - Run", "Releasing Lock"), LogType.Info.ToString());

            _fileDownloadLimit.Release();
        }
Пример #21
0
        public override void RenderMedia(double position)
        {
            if (!string.IsNullOrEmpty(_code))
            {
                // Stored command
                bool success;

                try
                {
                    Command command = Command.GetByCode(_code);
                    success = command.Run();
                }
                catch (Exception e)
                {
                    Trace.WriteLine(new LogMessage("ScheduleManager - Run", "Cannot run Command: " + e.Message), LogType.Error.ToString());
                    success = false;
                }

                // Notify the state of the command (success or failure)
                using (xmds.xmds statusXmds = new xmds.xmds())
                {
                    statusXmds.Url = ApplicationSettings.Default.XiboClient_xmds_xmds + "&method=notifyStatus";
                    statusXmds.NotifyStatusAsync(ApplicationSettings.Default.ServerKey, ApplicationSettings.Default.HardwareKey, "{\"lastCommandSuccess\":" + success + "}");
                }
            }
            else
            {
                // shell command

                // Is this module enabled?
                if (ApplicationSettings.Default.EnableShellCommands)
                {
                    // Check to see if we have an allow list
                    if (!string.IsNullOrEmpty(ApplicationSettings.Default.ShellCommandAllowList))
                    {
                        // Array of allowed commands
                        string[] allowedCommands = ApplicationSettings.Default.ShellCommandAllowList.Split(',');

                        // Check we are allowed to execute the command
                        bool found = false;

                        foreach (string allowedCommand in allowedCommands)
                        {
                            if (_command.StartsWith(allowedCommand))
                            {
                                found = true;
                                ExecuteShellCommand();
                                break;
                            }
                        }

                        if (!found)
                        {
                            Trace.WriteLine(new LogMessage("ShellCommand - RenderMedia", "Shell Commands not in allow list: " + ApplicationSettings.Default.ShellCommandAllowList), LogType.Error.ToString());
                        }
                    }
                    else
                    {
                        // All commands are allowed
                        ExecuteShellCommand();
                    }
                }
                else
                {
                    Trace.WriteLine(new LogMessage("ShellCommand - RenderMedia", "Shell Commands are disabled"), LogType.Error.ToString());
                }
            }

            // All shell commands have a duration of 1
            base.RenderMedia(position);
        }
Пример #22
0
        /// <summary>
        /// Runs the agent
        /// </summary>
        public void Run()
        {
            Trace.WriteLine(new LogMessage("FileAgent - Run", "Thread Started"), LogType.Audit.ToString());

            // Get the required file id from the list of required files.
            RequiredFile file = _requiredFiles.GetRequiredFile(_requiredFileId, _requiredFileType);

            // Set downloading to be true
            file.Downloading = true;

            // Wait for the Semaphore lock to become available
            _fileDownloadLimit.WaitOne();

            try
            {
                Trace.WriteLine(new LogMessage("FileAgent - Run", "Thread alive and Lock Obtained"), LogType.Audit.ToString());

                if (file.FileType == "resource")
                {
                    // Download using XMDS GetResource
                    using (xmds.xmds xmds = new xmds.xmds())
                    {
                        xmds.Credentials           = null;
                        xmds.Url                   = ApplicationSettings.Default.XiboClient_xmds_xmds;
                        xmds.UseDefaultCredentials = true;

                        string result = xmds.GetResource(ApplicationSettings.Default.ServerKey, ApplicationSettings.Default.HardwareKey, file.LayoutId, file.RegionId, file.MediaId);

                        // Write the result to disk
                        using (FileStream fileStream = File.Open(ApplicationSettings.Default.LibraryPath + @"\" + file.SaveAs, FileMode.Create, FileAccess.Write, FileShare.Read))
                        {
                            using (StreamWriter sw = new StreamWriter(fileStream))
                            {
                                sw.Write(result);
                                sw.Close();
                            }
                        }

                        // File completed
                        file.Downloading = false;
                        file.Complete    = true;
                    }
                }
                else if (file.FileType == "media" && file.Http)
                {
                    // Download using HTTP and the rf.Path
                    using (WebClient wc = new WebClient())
                    {
                        wc.DownloadFile(file.Path, ApplicationSettings.Default.LibraryPath + @"\" + file.SaveAs);
                    }

                    // File completed
                    file.Downloading = false;

                    // Check MD5
                    string md5 = _requiredFiles.CurrentCacheManager.GetMD5(file.SaveAs);
                    if (file.Md5 == md5)
                    {
                        // Mark it as complete
                        _requiredFiles.MarkComplete(_requiredFileId, file.Md5);

                        // Add it to the cache manager
                        _requiredFiles.CurrentCacheManager.Add(file.SaveAs, file.Md5);

                        Trace.WriteLine(new LogMessage("FileAgent - Run", "File Downloaded Successfully. " + file.SaveAs), LogType.Info.ToString());
                    }
                    else
                    {
                        // Just error - we will pick it up again the next time we download
                        Trace.WriteLine(new LogMessage("FileAgent - Run", "Downloaded file failed MD5 check. Calculated [" + md5 + "] & XMDS [ " + file.Md5 + "] . " + file.SaveAs), LogType.Info.ToString());
                    }
                }
                else
                {
                    // Download using XMDS GetFile
                    while (!file.Complete)
                    {
                        byte[] getFileReturn;

                        // Call XMDS GetFile
                        using (xmds.xmds xmds = new xmds.xmds())
                        {
                            xmds.Credentials           = null;
                            xmds.Url                   = ApplicationSettings.Default.XiboClient_xmds_xmds;
                            xmds.UseDefaultCredentials = false;

                            getFileReturn = xmds.GetFile(ApplicationSettings.Default.ServerKey, _hardwareKey, file.Id, file.FileType, file.ChunkOffset, file.ChunkSize);
                        }

                        // Set the flag to indicate we have a connection to XMDS
                        ApplicationSettings.Default.XmdsLastConnection = DateTime.Now;

                        if (file.FileType == "layout")
                        {
                            // Decode this byte[] into a string and stick it in the file.
                            string layoutXml = Encoding.UTF8.GetString(getFileReturn);

                            // Full file is downloaded
                            using (FileStream fileStream = File.Open(ApplicationSettings.Default.LibraryPath + @"\" + file.SaveAs, FileMode.Create, FileAccess.Write, FileShare.Read))
                            {
                                using (StreamWriter sw = new StreamWriter(fileStream))
                                {
                                    sw.Write(layoutXml);
                                    sw.Close();
                                }
                            }

                            file.Complete = true;
                        }
                        else
                        {
                            // Media file
                            // Need to write to the file - in append mode
                            using (FileStream fs = new FileStream(ApplicationSettings.Default.LibraryPath + @"\" + file.Path, FileMode.Append, FileAccess.Write))
                            {
                                fs.Write(getFileReturn, 0, getFileReturn.Length);
                                fs.Close();
                            }

                            // Increment the offset by the amount we just asked for
                            file.ChunkOffset = file.ChunkOffset + file.ChunkSize;

                            // Has the offset reached the total size?
                            if (file.Size > file.ChunkOffset)
                            {
                                double remaining = file.Size - file.ChunkOffset;

                                // There is still more to come
                                if (remaining < file.ChunkSize)
                                {
                                    // Get the remaining
                                    file.ChunkSize = remaining;
                                }

                                // Part is complete
                                OnPartComplete(file.Id);
                            }
                            else
                            {
                                // File complete
                                file.Complete = true;
                            }
                        }

                        getFileReturn = null;
                    }

                    // File completed
                    file.Downloading = false;

                    // Check MD5
                    string md5 = _requiredFiles.CurrentCacheManager.GetMD5(file.SaveAs);
                    if (file.Md5 == md5)
                    {
                        // Mark it as complete
                        _requiredFiles.MarkComplete(_requiredFileId, file.Md5);

                        // Add it to the cache manager
                        _requiredFiles.CurrentCacheManager.Add(file.SaveAs, file.Md5);

                        Trace.WriteLine(new LogMessage("FileAgent - Run", "File Downloaded Successfully. " + file.SaveAs), LogType.Info.ToString());
                    }
                    else
                    {
                        // Just error - we will pick it up again the next time we download
                        Trace.WriteLine(new LogMessage("FileAgent - Run", "Downloaded file failed MD5 check. Calculated [" + md5 + "] & XMDS [ " + file.Md5 + "] . " + file.SaveAs), LogType.Info.ToString());
                    }
                }

                // Inform the Player thread that a file has been modified.
                OnComplete(file.Id, file.FileType);
            }
            catch (WebException webEx)
            {
                // Remove from the cache manager
                _requiredFiles.CurrentCacheManager.Remove(file.SaveAs);

                // Log this message, but dont abort the thread
                Trace.WriteLine(new LogMessage("FileAgent - Run", "Web Exception in Run: " + webEx.Message), LogType.Info.ToString());

                // Mark as not downloading
                file.Downloading = false;
            }
            catch (Exception ex)
            {
                // Remove from the cache manager
                _requiredFiles.CurrentCacheManager.Remove(file.SaveAs);

                // Log this message, but dont abort the thread
                Trace.WriteLine(new LogMessage("FileAgent - Run", "Exception in Run: " + ex.Message), LogType.Error.ToString());

                // Mark as not downloading
                file.Downloading = false;
            }

            // Release the Semaphore
            Trace.WriteLine(new LogMessage("FileAgent - Run", "Releasing Lock"), LogType.Audit.ToString());

            _fileDownloadLimit.Release();
        }
Пример #23
0
        /// <summary>
        /// Runs the agent
        /// </summary>
        public void Run()
        {
            Trace.WriteLine(new LogMessage("RegisterAgent - 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 + "&method=registerDisplay";
                            xmds.UseDefaultCredentials = false;

                            // Store the XMR address
                            string xmrAddress = ApplicationSettings.Default.XmrNetworkAddress;

                            RegisterAgent.ProcessRegisterXml(xmds.RegisterDisplay(
                                                                 ApplicationSettings.Default.ServerKey,
                                                                 key.Key,
                                                                 ApplicationSettings.Default.DisplayName,
                                                                 "windows",
                                                                 ApplicationSettings.Default.ClientVersion,
                                                                 ApplicationSettings.Default.ClientCodeVersion,
                                                                 Environment.OSVersion.ToString(),
                                                                 key.MacAddress,
                                                                 key.Channel,
                                                                 key.getXmrPublicKey()));

                            // Set the flag to indicate we have a connection to XMDS
                            ApplicationSettings.Default.XmdsLastConnection = DateTime.Now;

                            // Has the XMR address changed?
                            if (xmrAddress != ApplicationSettings.Default.XmrNetworkAddress)
                            {
                                OnXmrReconfigure();
                            }

                            // Is the timezone empty?
                            if (string.IsNullOrEmpty(ApplicationSettings.Default.DisplayTimeZone))
                            {
                                reportTimezone();
                            }
                        }
                    }
                    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("RegisterAgent - Run", "WebException in Run: " + webEx.Message), LogType.Info.ToString());
                    }
                    catch (Exception ex)
                    {
                        // Log this message, but dont abort the thread
                        Trace.WriteLine(new LogMessage("RegisterAgent - Run", "Exception in Run: " + ex.Message), LogType.Info.ToString());
                    }
                }

                // Sleep this thread until the next collection interval
                _manualReset.WaitOne((int)(ApplicationSettings.Default.CollectInterval * ApplicationSettings.Default.XmdsCollectionIntervalFactor() * 1000));
            }

            Trace.WriteLine(new LogMessage("RegisterAgent - Run", "Thread Stopped"), LogType.Info.ToString());
        }
Пример #24
0
        /// <summary>
        /// Run Thread
        /// </summary>
        public void Run()
        {
            Trace.WriteLine(new LogMessage("RequiredFilesAgent - Run", "Thread Started"), LogType.Info.ToString());

            while (!_forceStop)
            {
                lock (_locker)
                {
                    if (ApplicationSettings.Default.InDownloadWindow)
                    {
                        try
                        {
                            // If we are restarting, reset
                            _manualReset.Reset();

                            int filesToDownload = _requiredFiles.FilesDownloading;

                            // If we are currently downloading something, we have to wait
                            if (filesToDownload > 0)
                            {
                                _clientInfoForm.RequiredFilesStatus = string.Format("Waiting: {0} Active Downloads", filesToDownload.ToString());

                                Trace.WriteLine(new LogMessage("RequiredFilesAgent - Run", "Currently Downloading Files, skipping collect"), LogType.Info.ToString());
                            }
                            else
                            {
                                _clientInfoForm.RequiredFilesStatus = "Running: Requesting connection to Xibo Server";

                                using (xmds.xmds xmds = new xmds.xmds())
                                {
                                    xmds.Credentials = null;
                                    xmds.Url = ApplicationSettings.Default.R23SignageClient_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<Thread> threadsToStart = new List<Thread>();

                                    // 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();

                                    // Report the storage usage
                                    reportStorage();

                                    // 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());
                                }
                            }
                        }
                        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());

                            _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: " + ex.Message;
                        }
                    }
                    else
                    {
                        _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));
                    }
                }

                // Sleep this thread until the next collection interval
                _manualReset.WaitOne((int)(ApplicationSettings.Default.CollectInterval * ApplicationSettings.Default.XmdsCollectionIntervalFactor() * 1000));
            }

            Trace.WriteLine(new LogMessage("RequiredFilesAgent - Run", "Thread Stopped"), LogType.Info.ToString());
        }
Пример #25
0
        /// <summary>
        /// Runs the agent
        /// </summary>
        public void Run()
        {
            Trace.WriteLine(new LogMessage("RegisterAgent - Run", "Thread Started"), LogType.Info.ToString());

            int retryAfterSeconds = 0;

            while (!_forceStop)
            {
                lock (_locker)
                {
                    try
                    {
                        // If we are restarting, reset
                        _manualReset.Reset();

                        // Reset backOff
                        retryAfterSeconds = 0;

                        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 + "&method=registerDisplay";
                            xmds.UseDefaultCredentials = false;

                            // Store the XMR address
                            string xmrAddress = ApplicationSettings.Default.XmrNetworkAddress;

                            RegisterAgent.ProcessRegisterXml(callRegister(xmds, key));

                            // Set the flag to indicate we have a connection to XMDS
                            ApplicationSettings.Default.XmdsLastConnection = DateTime.Now;

                            // Has the XMR address changed?
                            if (xmrAddress != ApplicationSettings.Default.XmrNetworkAddress)
                            {
                                OnXmrReconfigure();
                            }

                            // Notify Status
                            NotifyStatus();

                            // Have we been asked to move CMS instance?
                            // CMS MOVE
                            // --------
                            if (!string.IsNullOrEmpty(ApplicationSettings.Default.NewCmsAddress) &&
                                !string.IsNullOrEmpty(ApplicationSettings.Default.NewCmsKey) &&
                                ApplicationSettings.Default.NewCmsAddress != ApplicationSettings.Default.ServerUri
                                )
                            {
                                // Make a call using the new details, and see if it works.
                                string oldUri = ApplicationSettings.Default.ServerUri;
                                string oldKey = ApplicationSettings.Default.ServerKey;
                                ApplicationSettings.Default.ServerUri = ApplicationSettings.Default.NewCmsAddress;
                                ApplicationSettings.Default.ServerKey = ApplicationSettings.Default.NewCmsKey;

                                Trace.WriteLine(new LogMessage("RegisterAgent - Run", "We have been asked to move to a new CMS. " + ApplicationSettings.Default.NewCmsAddress), LogType.Info.ToString());

                                // Try it and see.
                                try
                                {
                                    xmds.Url = ApplicationSettings.Default.XiboClient_xmds_xmds + "&method=registerDisplay";
                                    string xml = callRegister(xmds, key);

                                    // If that worked (no errors), update our settings
                                    ApplicationSettings.Default.NewCmsAddress = "";
                                    ApplicationSettings.Default.NewCmsKey     = "";
                                    // ServerUri/Key will be updated too.
                                    ApplicationSettings.Default.Save();

                                    ProcessRegisterXml(xml);
                                }
                                catch (Exception e)
                                {
                                    Trace.WriteLine(new LogMessage("RegisterAgent - Run", "Error swapping to new CMS. E = " + e.Message.ToString()), LogType.Error.ToString());

                                    // Switch back to the old values for subsequent tries
                                    ApplicationSettings.Default.ServerUri = oldUri;
                                    ApplicationSettings.Default.ServerKey = oldKey;
                                }
                            }

                            // Have we been asked to switch to HTTPS?
                            // HTTPS MOVE
                            // ----------
                            if (ApplicationSettings.Default.ForceHttps && xmds.Url.ToLowerInvariant().StartsWith("http://"))
                            {
                                Trace.WriteLine(new LogMessage("RegisterAgent - Run", "We have been asked to move to HTTPS from our current HTTP."), LogType.Info.ToString());

                                // Try it and see.
                                try
                                {
                                    string url = ApplicationSettings.Default.XiboClient_xmds_xmds + "&method=registerDisplay";
                                    xmds.Url = url.Replace("http://", "https://");
                                    callRegister(xmds, key);

                                    // If that worked (no errors), update our setting
                                    ApplicationSettings.Default.ServerUri = ApplicationSettings.Default.ServerUri.Replace("http://", "https://");
                                    ApplicationSettings.Default.Save();
                                }
                                catch (Exception e)
                                {
                                    Trace.WriteLine(new LogMessage("RegisterAgent - Run", "Error swapping to HTTPS. E = " + e.Message.ToString()), LogType.Error.ToString());
                                }
                            }
                        }
                    }
                    catch (WebException webEx) when(webEx.Response is HttpWebResponse httpWebResponse && (int)httpWebResponse.StatusCode == 429)
                    {
                        // Get the header for how long we ought to wait
                        retryAfterSeconds = webEx.Response.Headers["Retry-After"] != null?int.Parse(webEx.Response.Headers["Retry-After"]) : 120;

                        // Log it.
                        Trace.WriteLine(new LogMessage("LogAgent", "Run: 429 received, waiting for " + retryAfterSeconds + " seconds."), LogType.Info.ToString());
                    }
                    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("RegisterAgent - Run", "WebException in Run: " + webEx.Message), LogType.Info.ToString());
                    }
                    catch (Exception ex)
                    {
                        // Log this message, but dont abort the thread
                        Trace.WriteLine(new LogMessage("RegisterAgent - Run", "Exception in Run: " + ex.Message), LogType.Info.ToString());
                    }
                }

                if (retryAfterSeconds > 0)
                {
                    // Sleep this thread until we've fulfilled our try after
                    _manualReset.WaitOne(retryAfterSeconds * 1000);
                }
                else
                {
                    // Sleep this thread until the next collection interval
                    _manualReset.WaitOne((int)(ApplicationSettings.Default.CollectInterval * ApplicationSettings.Default.XmdsCollectionIntervalFactor() * 1000));
                }
            }

            Trace.WriteLine(new LogMessage("RegisterAgent - Run", "Thread Stopped"), LogType.Info.ToString());
        }
        /// <summary>
        /// Run Thread
        /// </summary>
        public void Run()
        {
            Trace.WriteLine(new LogMessage("RequiredFilesAgent - Run", "Thread Started"), LogType.Info.ToString());

            int retryAfterSeconds = 0;

            while (!_forceStop)
            {
                // If we are restarting, reset
                _manualReset.Reset();

                // Reset backOff
                retryAfterSeconds = 0;

                lock (_locker)
                {
                    // Run the schedule Agent thread
                    scheduleAgent();

                    if (ApplicationSettings.Default.InDownloadWindow)
                    {
                        try
                        {
                            int filesToDownload = _requiredFiles.FilesDownloading;

                            // If we are currently downloading something, we have to wait
                            if (filesToDownload > 0)
                            {
                                ClientInfo.Instance.RequiredFilesStatus = string.Format("Waiting: {0} Active Downloads", filesToDownload.ToString());

                                Trace.WriteLine(new LogMessage("RequiredFilesAgent - Run", "Currently Downloading Files, skipping collect"), LogType.Audit.ToString());
                            }
                            else if (!ShouldCheckRf())
                            {
                                ClientInfo.Instance.RequiredFilesStatus = "Sleeping: last check was not required.";
                            }
                            else
                            {
                                ClientInfo.Instance.RequiredFilesStatus = "Running: Requesting connection to Xibo Server";

                                using (xmds.xmds xmds = new xmds.xmds())
                                {
                                    xmds.Credentials           = null;
                                    xmds.Url                   = ApplicationSettings.Default.XiboClient_xmds_xmds + "&method=requiredFiles";
                                    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;

                                    ClientInfo.Instance.RequiredFilesStatus = "Running: Data received from Xibo Server";

                                    // Calculate and store a CRC32
                                    _lastCheckRf = Crc32Algorithm.Compute(Encoding.UTF8.GetBytes(requiredFilesXml)).ToString();

                                    // 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.RequiredFilesXml = xml;

                                    // List of Threads to start
                                    // TODO: Track these threads so that we can abort them if the application closes
                                    List <Thread> threadsToStart = new List <Thread>();

                                    // Track available disk space.
                                    long freeSpace = ClientInfo.Instance.GetDriveFreeSpace();

                                    // 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;
                                        }

                                        // Can we fit the file on the drive?
                                        if (freeSpace != -1)
                                        {
                                            if (fileToDownload.Size > freeSpace)
                                            {
                                                Trace.WriteLine(new LogMessage("RequiredFilesAgent", "Run: Not enough free space on disk"), LogType.Error.ToString());
                                                continue;
                                            }

                                            // Decrement this file from the free space
                                            freeSpace -= (long)fileToDownload.Size;
                                        }

                                        // 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.Instance.WriteCacheManager();

                                    // Set the status on the client info screen
                                    if (threadsToStart.Count == 0)
                                    {
                                        ClientInfo.Instance.RequiredFilesStatus = "Sleeping (inside download window)";

                                        // Raise an event to say we've completed
                                        OnFullyProvisioned?.Invoke();
                                    }
                                    else
                                    {
                                        ClientInfo.Instance.RequiredFilesStatus = string.Format("{0} files to download", threadsToStart.Count.ToString());
                                    }

                                    ClientInfo.Instance.UpdateRequiredFiles(RequiredFilesString());
                                }
                            }
                        }
                        catch (WebException webEx) when(webEx.Response is HttpWebResponse httpWebResponse && (int)httpWebResponse.StatusCode == 429)
                        {
                            // Get the header for how long we ought to wait
                            retryAfterSeconds = webEx.Response.Headers["Retry-After"] != null?int.Parse(webEx.Response.Headers["Retry-After"]) : 120;

                            // Log it.
                            Trace.WriteLine(new LogMessage("RequiredFilesAgent", "Run: 429 received, waiting for " + retryAfterSeconds + " seconds."), LogType.Info.ToString());
                        }
                        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.Info.ToString());

                            ClientInfo.Instance.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());

                            ClientInfo.Instance.RequiredFilesStatus = "Error: " + ex.Message;
                        }
                    }
                    else
                    {
                        ClientInfo.Instance.RequiredFilesStatus = string.Format("Outside Download Window {0} - {1}", ApplicationSettings.Default.DownloadStartWindowTime.ToString(), ApplicationSettings.Default.DownloadEndWindowTime.ToString());
                    }
                }

                if (retryAfterSeconds > 0)
                {
                    // Sleep this thread until we've fulfilled our try after
                    _manualReset.WaitOne(retryAfterSeconds * 1000);
                }
                else
                {
                    // Sleep this thread until the next collection interval
                    _manualReset.WaitOne((int)(ApplicationSettings.Default.CollectInterval * ApplicationSettings.Default.XmdsCollectionIntervalFactor() * 1000));
                }
            }

            Trace.WriteLine(new LogMessage("RequiredFilesAgent - Run", "Thread Stopped"), LogType.Info.ToString());
        }