/// <summary> /// FileAgent OnComplete /// </summary> /// <param name="fileId"></param> void fileAgent_OnComplete(int fileId, string fileType) { // Notify the player thread using another event (chained events? bad idea?) Trace.WriteLine(new LogMessage("RequiredFilesAgent - fileAgent_OnComplete", "FileId finished downloading" + fileId.ToString())); // Get the required file associated with this ID RequiredFile rf = _requiredFiles.GetRequiredFile(fileId, fileType); // Set the status on the client info screen if (_requiredFiles.FilesDownloading == 0) { _clientInfoForm.RequiredFilesStatus = "Sleeping"; } else { _clientInfoForm.RequiredFilesStatus = string.Format("{0} files to download", _requiredFiles.FilesDownloading.ToString()); } // Update the RequiredFiles TextBox _clientInfoForm.UpdateRequiredFiles(RequiredFilesString()); // Write the Cache Manager to Disk _cacheManager.WriteCacheManager(); if (rf.FileType == "layout") { // Raise an event to say it is completed OnComplete(rf.Path); } }
public static IEnumerable<RequiredFile> GetRequiredFiles(CompilerContext context, string script) { var matches = Regex.Matches(script, RequireMatchPattern, RegexOptions.Multiline | RegexOptions.IgnoreCase); var result = new List<RequiredFile>(); foreach (Match match in matches) { var location = match.Groups["requiredFile"].Value.Trim(); var protocolString = match.Groups["protocol"].Value ?? string.Empty; var isEmbedded = location.EndsWith("`") && location.StartsWith("`"); location = isEmbedded ? location.Substring(1, location.Length - 2) : location; var file = new RequiredFile { IsEmbedded = isEmbedded, Location = location, Protocol = FileProtocol.LocalFile, RegexMatch = match, Context = context }; if (!string.IsNullOrEmpty(protocolString)) { FileProtocol protocol; Enum.TryParse<FileProtocol>(protocolString.Replace("://", string.Empty), true, out protocol); file.Protocol = protocol; } if (file.Protocol == FileProtocol.LocalFile) if (!new FileInfo(file.Location).Exists) file.Location = Path.Combine(context.WorkingDirectory, file.Location); result.Add(file); } return result; }
/// <summary> /// Run Thread /// </summary> public void Run() { Trace.WriteLine(new LogMessage("LibraryAgent - Run", "Thread Started"), LogType.Info.ToString()); while (!_forceStop) { lock (_locker) { try { // If we are restarting, reset _manualReset.Reset(); // Only do something if enabled if (!ApplicationSettings.Default.EnableExpiredFileDeletion) { return; } // Get required files from disk _requiredFiles = RequiredFiles.LoadFromDisk(); // Build a list of files in the library DirectoryInfo directory = new DirectoryInfo(ApplicationSettings.Default.LibraryPath); // Check each one and see if it is in required files foreach (FileInfo fileInfo in directory.GetFiles()) { // Delete files that were accessed over N days ago try { RequiredFile file = _requiredFiles.GetRequiredFile(fileInfo.Name); } catch { // Not a required file if (fileInfo.LastAccessTime < DateTime.Now.AddDays(ApplicationSettings.Default.LibraryAgentInterval * -1)) { Trace.WriteLine(new LogMessage("LibraryAgent - Run", "Deleting old file: " + fileInfo.Name), LogType.Info.ToString()); File.Delete(fileInfo.FullName); } } } } catch (Exception ex) { // Log this message, but dont abort the thread Trace.WriteLine(new LogMessage("LibraryAgent - Run", "Exception in Run: " + ex.Message), LogType.Error.ToString()); } } // Sleep this thread for 5 minutes _manualReset.WaitOne(900 * 1000); } Trace.WriteLine(new LogMessage("LibraryAgent - Run", "Thread Stopped"), LogType.Info.ToString()); }
/// <summary> /// FileAgent OnComplete /// </summary> /// <param name="fileId"></param> void fileAgent_OnComplete(int fileId, string fileType) { // Notify the player thread using another event (chained events? bad idea?) Trace.WriteLine(new LogMessage("RequiredFilesAgent - fileAgent_OnComplete", "FileId finished downloading" + fileId.ToString())); // Get the required file associated with this ID RequiredFile rf = _requiredFiles.GetRequiredFile(fileId, fileType); // Set the status on the client info screen if (_requiredFiles.FilesDownloading == 0) { _clientInfoForm.RequiredFilesStatus = "Sleeping"; // If we are the last download thread to complete, then we should report media inventory and raise an event to say we've got everything _requiredFiles.ReportInventory(); // Raise an event to say we've completed if (OnFullyProvisioned != null) { OnFullyProvisioned(); } } else { _clientInfoForm.RequiredFilesStatus = string.Format("{0} files to download", _requiredFiles.FilesDownloading.ToString()); } // Update the RequiredFiles TextBox _clientInfoForm.UpdateRequiredFiles(RequiredFilesString()); // Write the Cache Manager to Disk _cacheManager.WriteCacheManager(); if (rf.FileType == "layout") { // Raise an event to say it is completed if (OnComplete != null) { OnComplete(rf.SaveAs); } } }
/// <summary> /// Run Thread /// </summary> public void Run() { Trace.WriteLine(new LogMessage("LibraryAgent - Run", "Thread Started"), LogType.Info.ToString()); while (!_forceStop) { lock (_locker) { try { // If we are restarting, reset _manualReset.Reset(); // Only do something if enabled if (!ApplicationSettings.Default.EnableExpiredFileDeletion) { Trace.WriteLine(new LogMessage("LibraryAgent - Run", "Expired File Deletion Disabled"), LogType.Audit.ToString()); return; } // Test Date DateTime testDate = DateTime.Now.AddDays(ApplicationSettings.Default.LibraryAgentInterval * -1); // Get required files from disk _requiredFiles = RequiredFiles.LoadFromDisk(); Trace.WriteLine(new LogMessage("LibraryAgent - Run", "Number of required files = " + _requiredFiles.RequiredFileList.Count), LogType.Audit.ToString()); // Build a list of files in the library DirectoryInfo directory = new DirectoryInfo(ApplicationSettings.Default.LibraryPath); // Check each one and see if it is in required files foreach (FileInfo fileInfo in directory.GetFiles()) { // Never delete certain system files // Also do not delete log/stat files as they are managed by their respective agents if (_persistentFiles.Contains(fileInfo.Name) || fileInfo.Name.Contains(ApplicationSettings.Default.LogLocation) || fileInfo.Name.Contains(ApplicationSettings.Default.StatsLogFile) ) { continue; } // Delete files that were accessed over N days ago try { RequiredFile file = _requiredFiles.GetRequiredFile(fileInfo.Name); } catch { // It is a bad idea to log in here - it can cause a build up of log files. //Debug.WriteLine(new LogMessage("LibraryAgent - Run", fileInfo.Name + " is not in Required Files, testing last accessed date [" + fileInfo.LastAccessTime + "] is earlier than " + testDate), LogType.Audit.ToString()); // Not a required file if (fileInfo.LastAccessTime < testDate) { Trace.WriteLine(new LogMessage("LibraryAgent - Run", "Deleting old file: " + fileInfo.Name), LogType.Info.ToString()); File.Delete(fileInfo.FullName); // Is this a HTZ file? if (fileInfo.Extension.ToLower() == ".htz") { // Also delete the extracted version of this file string pathToPackageFolder = Path.Combine(ApplicationSettings.Default.LibraryPath, "package_" + fileInfo.Name.Replace(fileInfo.Extension, "")); if (Directory.Exists(pathToPackageFolder)) { Directory.Delete(pathToPackageFolder, true); } } } } } } catch (Exception ex) { // Log this message, but dont abort the thread Trace.WriteLine(new LogMessage("LibraryAgent - Run", "Exception in Run: " + ex.Message), LogType.Error.ToString()); } } // Sleep this thread for 15 minutes _manualReset.WaitOne(2700 * 1000); } Trace.WriteLine(new LogMessage("LibraryAgent - Run", "Thread Stopped"), LogType.Info.ToString()); }
/// <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(); }
/// <summary> /// Set required files from the XML document /// </summary> private void SetRequiredFiles() { // Itterate through the RF XML and populate the RF collection XmlNodeList fileNodes = _requiredFilesXml.SelectNodes("/files/file"); foreach (XmlNode file in fileNodes) { RequiredFile rf = new RequiredFile(); XmlAttributeCollection attributes = file.Attributes; rf.FileType = attributes["type"].Value; rf.Downloading = false; rf.Complete = false; rf.LastChecked = DateTime.Now; rf.ChunkOffset = 0; rf.ChunkSize = 0; // Fill in some information that we already know if (rf.FileType == "media") { rf.Id = int.Parse(attributes["id"].Value); rf.Path = attributes["path"].Value; rf.SaveAs = (attributes["saveAs"] == null || string.IsNullOrEmpty(attributes["saveAs"].Value)) ? rf.Path : attributes["saveAs"].Value; rf.Http = (attributes["download"].Value == "http"); rf.ChunkSize = 512000; } else if (rf.FileType == "layout") { rf.Id = int.Parse(attributes["id"].Value); rf.Path = attributes["path"].Value; rf.Http = (attributes["download"].Value == "http"); if (rf.Http) { rf.SaveAs = attributes["saveAs"].Value; } else { rf.Path = rf.Path + ".xlf"; rf.SaveAs = rf.Path; } rf.ChunkSize = rf.Size; } else if (rf.FileType == "resource") { // Do something special here. Check to see if the resource file already exists otherwise add to RF try { // Set the ID to be some random number rf.Id = int.Parse(attributes["id"].Value); rf.LayoutId = int.Parse(attributes["layoutid"].Value); rf.RegionId = attributes["regionid"].Value; rf.MediaId = attributes["mediaid"].Value; rf.Path = rf.MediaId + ".htm"; rf.SaveAs = rf.Path; // Set the size to something arbitary rf.Size = 10000; // Check to see if this has already been downloaded if (File.Exists(ApplicationSettings.Default.LibraryPath + @"\" + rf.MediaId + ".htm")) { // Has it expired? int updated = 0; try { updated = int.Parse(attributes["updated"].Value); } catch (Exception) { } DateTime updatedDt = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); updatedDt = updatedDt.AddSeconds(updated); if (File.GetLastWriteTimeUtc(ApplicationSettings.Default.LibraryPath + @"\" + rf.MediaId + ".htm") > updatedDt) { rf.Complete = true; } } // Add to the Rf Node RequiredFileList.Add(rf); continue; } catch { // Forget about this resource continue; } } else { continue; } // This stuff only executes for Layout/Files items rf.Md5 = attributes["md5"].Value; rf.Size = double.Parse(attributes["size"].Value); // Does this file already exist in the RF node? We might receive duplicates. bool found = false; foreach (RequiredFile existingRf in RequiredFileList) { if (existingRf.Id == rf.Id && existingRf.FileType == rf.FileType) { found = true; break; } } if (found) { Trace.WriteLine(new LogMessage("RequiredFiles - SetRequiredFiles", "Duplicate file detected, ignoring. FileId = " + rf.Id), LogType.Audit.ToString()); continue; } // Does this file exist? if (File.Exists(ApplicationSettings.Default.LibraryPath + @"\" + rf.SaveAs)) { // Compare MD5 of the file we currently have, to what we should have if (rf.Md5 != _cacheManager.GetMD5(rf.SaveAs)) { Trace.WriteLine(new LogMessage("RequiredFiles - SetRequiredFiles", "MD5 different for existing file: " + rf.SaveAs), LogType.Info.ToString()); // They are different _cacheManager.Remove(rf.SaveAs); // TODO: Resume the file download under certain conditions. Make sure its not bigger than it should be. // Make sure it is fairly fresh FileInfo info = new FileInfo(ApplicationSettings.Default.LibraryPath + @"\" + rf.SaveAs); if (info.Length < rf.Size && info.LastWriteTime > DateTime.Now.AddDays(-1)) { // Continue the file rf.ChunkOffset = (int)info.Length; } else { // Delete the old file as it is wrong try { File.Delete(ApplicationSettings.Default.LibraryPath + @"\" + rf.SaveAs); } catch (Exception ex) { Trace.WriteLine(new LogMessage("CompareAndCollect", "Unable to delete incorrect file because: " + ex.Message)); } } } else { // The MD5 is equal - we already have an up to date version of this file. rf.Complete = true; _cacheManager.Add(rf.SaveAs, rf.Md5); } } else { // File does not exist, therefore remove it from the cache manager (on the off chance that it is in there for some reason) _cacheManager.Remove(rf.SaveAs); } RequiredFileList.Add(rf); } }