using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using Tango.Core; using Tango.Core.DI; using Tango.FSE.BL; using Tango.FSE.Common; using Tango.FSE.Common.Connection; using Tango.FSE.Common.HotFolder; using Tango.FSE.Common.Notifications; using Tango.FSE.Common.RemoteJobUpload; using Tango.PPC.Shared.RemoteJobUpload; using Tango.Settings; namespace Tango.FSE.UI.HotFolder { [TangoCreateWhenRegistered] public class DefaultHotFolderService : FSEExtendedObject, IHotFolderService { private Thread _watchThread; private class FailedItem { public String File { get; set; } public int Count { get; set; } } private bool _enabled; public bool Enabled { get { return _enabled; } set { _enabled = value; RaisePropertyChangedAuto(); RaisePropertyChanged(nameof(IsActive)); } } private String _hotFolderPath; public String HotFolderPath { get { return _hotFolderPath; } set { _hotFolderPath = value; RaisePropertyChangedAuto(); } } private bool _isActive; public bool IsActive { get { return _isActive && _enabled; } private set { _isActive = value; RaisePropertyChangedAuto(); } } [TangoInject] private IRemoteJobUploadProvider RemoteJobUploadProvider { get; set; } private IMachineProvider MachineProvider { get; set; } [TangoInject] private INotificationProvider NotificationProvider { get; set; } public SynchronizedObservableCollection Items { get; private set; } public DefaultHotFolderService(IMachineProvider machineProvider) { Items = new SynchronizedObservableCollection(); bool testData = false; if (testData) { HotFolderItem item1 = new HotFolderItem("C:\\HotFolder\\file1.csv"); item1.Status = HotFolderItemStatus.Pending; Items.Add(item1); HotFolderItem item2 = new HotFolderItem("C:\\HotFolder\\file2.csv"); item2.Status = HotFolderItemStatus.Uploading; Items.Add(item2); HotFolderItem item3 = new HotFolderItem("C:\\HotFolder\\file3.csv"); item3.Status = HotFolderItemStatus.Completed; Items.Add(item3); HotFolderItem item4 = new HotFolderItem("C:\\HotFolder\\file4.csv"); item4.Status = HotFolderItemStatus.Failed; item4.Message = "Error some error with some message I don't know."; Items.Add(item4); HotFolderItem item5 = new HotFolderItem("C:\\HotFolder\\file5.csv"); item5.Status = HotFolderItemStatus.CompletedWithError; item5.Message = "Can't delete file after completion.\nPlease remove manually."; Items.Add(item5); } MachineProvider = machineProvider; var settings = SettingsManager.Default.GetOrCreate(); Enabled = settings.EnableHotFolder; String defaultPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Twine", "Tango", "Hot Folder", BuildProvider.Build.ToDescription()); HotFolderPath = settings.HotFolderPath.IsNotNullOrEmpty() ? settings.HotFolderPath : defaultPath; MachineProvider.MachineConnected += MachineProvider_MachineConnected; } private void MachineProvider_MachineConnected(object sender, MachineConnectedEventArgs e) { if (MachineProvider.ConnectionType.IsRemote()) { try { if (!Directory.Exists(HotFolderPath)) { Directory.CreateDirectory(HotFolderPath); } _watchThread = new Thread(WatchThreadLoop); _watchThread.IsBackground = true; _watchThread.Start(); } catch (Exception ex) { LogManager.Log(ex, $"Error initializing hot folder at '{HotFolderPath}'."); NotificationProvider.PushSnackbarItem(MessageType.Error, "Hot Folder", true, "Error initializing hot folder"); } } } private void WatchThreadLoop() { while (MachineProvider.IsConnected) { try { Thread.Sleep(5000); if (Enabled && MachineProvider.IsConnected && Directory.Exists(HotFolderPath)) { IsActive = true; var files = Directory.GetFiles(HotFolderPath).ToList(); String machineHotFolder = Path.Combine(HotFolderPath, MachineProvider.Machine.SerialNumber); try { Directory.CreateDirectory(machineHotFolder); } catch (Exception ex) { LogManager.Log(ex, $"Error creating folder {MachineProvider.Machine.SerialNumber} inside hot folder."); } if (Directory.Exists(machineHotFolder)) { files.AddRange(Directory.GetFiles(machineHotFolder)); } foreach (var file in files) { if (!MachineProvider.IsConnected) break; bool upload = false; String extension = Path.GetExtension(file).ToLower(); String fileName = Path.GetFileName(file); if (extension == ".csv") upload = true; if (upload) { HotFolderItem hotFolderItem = Items.FirstOrDefault(x => x.FilePath == file); if (hotFolderItem == null || hotFolderItem.Status != HotFolderItemStatus.Pending && hotFolderItem.Status != HotFolderItemStatus.Failed) { LogManager.Log($"Found new hot folder item '{fileName}'. Uploading..."); hotFolderItem = new HotFolderItem(file); hotFolderItem.Status = HotFolderItemStatus.Uploading; Items.Insert(0, hotFolderItem); } else if (hotFolderItem.Status == HotFolderItemStatus.Pending) { LogManager.Log($"Retrying hot folder item '{fileName}'. Uploading..."); hotFolderItem.Status = HotFolderItemStatus.Uploading; } else { continue; } var snackItem = NotificationProvider.PushProgressSnackbar("Hot Folder", $"Uploading '{fileName}' to machine '{MachineProvider.Machine.SerialNumber}'..."); try { RemoteJobUploadProvider.UploadJob(file, RemoteJobUploadType.CSV).GetAwaiter().GetResult(); LogManager.Log($"Success uploading hot folder item '{fileName}'."); snackItem.ProgressCompleted($"'{fileName}' uploaded successfully.", TimeSpan.FromSeconds(10)); hotFolderItem.Status = HotFolderItemStatus.Completed; try { File.Delete(file); } catch (Exception ex) { LogManager.Log(ex, $"Error deleting file '{fileName}' after upload from hot folder."); NotificationProvider.PushSnackbarItem(MessageType.Error, "Hot Folder", true, $"$Error deleting '{fileName}' from hot folder."); hotFolderItem.Status = HotFolderItemStatus.CompletedWithError; hotFolderItem.Message = "Error deleting file after completion."; } } catch (Exception ex) { LogManager.Log(ex, $"Error uploading hot folder item '{fileName}'."); snackItem.ProgressFailed($"'{fileName}' upload failed.\n{ex.Message}", TimeSpan.FromSeconds(10)); hotFolderItem.Status = HotFolderItemStatus.Failed; hotFolderItem.Message = ex.Message; } } } } else { IsActive = false; } } catch (Exception ex) { LogManager.Log(ex, "Error occurred on hot folder service watch loop."); } } IsActive = false; } public void RetryFailedItem(HotFolderItem item) { if (item != null) item.Status = HotFolderItemStatus.Pending; } } }