Implemented Queues and folder monitors.
This commit is contained in:
@@ -248,6 +248,8 @@
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</ApplicationDefinition>
|
||||
<Compile Include="Models\DTO_Base.cs" />
|
||||
<Compile Include="Models\DTO_QueueItem.cs" />
|
||||
<Compile Include="Properties\Resources.es-MX.Designer.cs">
|
||||
<DependentUpon>Resources.es-MX.resx</DependentUpon>
|
||||
<AutoGen>True</AutoGen>
|
||||
@@ -262,7 +264,11 @@
|
||||
<Compile Include="Utils\Auth.cs" />
|
||||
<Compile Include="Utils\BaseModel.cs" />
|
||||
<Compile Include="Utils\BaseViewModel.cs" />
|
||||
<Compile Include="Utils\CIECAMonitor.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Utils\GraphQL.cs" />
|
||||
<Compile Include="Utils\JobProcessingQueue.cs" />
|
||||
<Compile Include="Utils\LoginHelpers.cs" />
|
||||
<Compile Include="Utils\RelayCommand.cs" />
|
||||
<Compile Include="Utils\TrayIcon.cs" />
|
||||
@@ -334,9 +340,7 @@
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Models\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<ItemGroup>
|
||||
<BootstrapperPackage Include=".NETFramework,Version=v4.7.2">
|
||||
<Visible>False</Visible>
|
||||
|
||||
33
BodyshopUploader/Models/DTO_Base.cs
Normal file
33
BodyshopUploader/Models/DTO_Base.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BodyshopUploader.Models
|
||||
{
|
||||
public abstract class DTO_Base : INotifyPropertyChanged
|
||||
{
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] String propertyName = null)
|
||||
{
|
||||
if (object.Equals(storage, value)) return false;
|
||||
|
||||
storage = value;
|
||||
this.OnPropertyChanged(propertyName);
|
||||
return true;
|
||||
}
|
||||
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||
{
|
||||
var eventHandler = this.PropertyChanged;
|
||||
if (eventHandler != null)
|
||||
{
|
||||
eventHandler(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
23
BodyshopUploader/Models/DTO_QueueItem.cs
Normal file
23
BodyshopUploader/Models/DTO_QueueItem.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BodyshopUploader.Models
|
||||
{
|
||||
public class DTO_QueueItem : DTO_Base
|
||||
{
|
||||
public DTO_QueueItem()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private string _filePath;
|
||||
public string FilePath
|
||||
{
|
||||
get { return _filePath; }
|
||||
set { SetProperty(ref _filePath, value); }
|
||||
}
|
||||
}
|
||||
}
|
||||
18
BodyshopUploader/Properties/Resources.Designer.cs
generated
18
BodyshopUploader/Properties/Resources.Designer.cs
generated
@@ -114,6 +114,24 @@ namespace BodyshopUploader.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Start All Monitors.
|
||||
/// </summary>
|
||||
public static string Label_StartAllMonitors {
|
||||
get {
|
||||
return ResourceManager.GetString("Label_StartAllMonitors", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Stop All Monitors.
|
||||
/// </summary>
|
||||
public static string Label_StopAllMonitors {
|
||||
get {
|
||||
return ResourceManager.GetString("Label_StopAllMonitors", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Login.
|
||||
/// </summary>
|
||||
|
||||
@@ -135,6 +135,12 @@
|
||||
<data name="Label_AddMonitoringPath" xml:space="preserve">
|
||||
<value>Add Path</value>
|
||||
</data>
|
||||
<data name="Label_StartAllMonitors" xml:space="preserve">
|
||||
<value>Start All Monitors</value>
|
||||
</data>
|
||||
<data name="Label_StopAllMonitors" xml:space="preserve">
|
||||
<value>Stop All Monitors</value>
|
||||
</data>
|
||||
<data name="Login" xml:space="preserve">
|
||||
<value>Login</value>
|
||||
</data>
|
||||
|
||||
85
BodyshopUploader/Utils/CIECAMonitor.cs
Normal file
85
BodyshopUploader/Utils/CIECAMonitor.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using BodyshopUploader.Models;
|
||||
|
||||
namespace BodyshopUploader.Utils
|
||||
{
|
||||
public class CIECAMonitor : FileSystemWatcher
|
||||
{
|
||||
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
|
||||
|
||||
public CIECAMonitor()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
public CIECAMonitor(String inDirectoryPath)
|
||||
: base(inDirectoryPath)
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
public CIECAMonitor(String inDirectoryPath, string inFilter)
|
||||
: base(inDirectoryPath, inFilter)
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
|
||||
private void Init()
|
||||
{
|
||||
IncludeSubdirectories = false;
|
||||
// Eliminate duplicates when timestamp doesn't change
|
||||
Filter = "*.env";
|
||||
NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite;
|
||||
//NotifyFilter = NotifyFilters.FileName | NotifyFilters.Size; // The default also has NotifyFilters.LastWrite
|
||||
EnableRaisingEvents = true;
|
||||
Created += Watcher_Created;
|
||||
Changed += Watcher_Changed;
|
||||
//Deleted += Watcher_Deleted;
|
||||
//Renamed += Watcher_Renamed;
|
||||
Error += Wathcer_Error;
|
||||
logger.Debug("CIECA Folder watcher started for path: {0}", Path);
|
||||
}
|
||||
|
||||
private void Wathcer_Error(object sender, ErrorEventArgs e)
|
||||
{
|
||||
logger.Error("CIECA monitor encountered an error. Trying to restart. {0}", e.ToString());
|
||||
((FileSystemWatcher)sender).EnableRaisingEvents = true;
|
||||
}
|
||||
|
||||
public void Watcher_Created(object source, FileSystemEventArgs inArgs)
|
||||
{
|
||||
logger.Trace("New CIECA fileset detected | {0}", inArgs.FullPath, inArgs.ChangeType);
|
||||
JobProcessingQueue.Enqueue(new DTO_QueueItem() { FilePath = inArgs.FullPath });
|
||||
}
|
||||
|
||||
public void Watcher_Changed(object sender, FileSystemEventArgs inArgs)
|
||||
{
|
||||
logger.Trace("Updated CIECA fileset detected | {0}", inArgs.FullPath);
|
||||
JobProcessingQueue.Enqueue(new DTO_QueueItem() { FilePath = inArgs.FullPath });
|
||||
}
|
||||
public void Watcher_Deleted(object sender, FileSystemEventArgs inArgs)
|
||||
{
|
||||
}
|
||||
|
||||
public void Watcher_Renamed(object sender, RenamedEventArgs inArgs)
|
||||
{
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
((System.ComponentModel.ISupportInitialize)(this)).BeginInit();
|
||||
//
|
||||
// FolderMonitor
|
||||
//
|
||||
this.IncludeSubdirectories = false;
|
||||
((System.ComponentModel.ISupportInitialize)(this)).EndInit();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
101
BodyshopUploader/Utils/JobProcessingQueue.cs
Normal file
101
BodyshopUploader/Utils/JobProcessingQueue.cs
Normal file
@@ -0,0 +1,101 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using BodyshopUploader.Utils;
|
||||
using BodyshopUploader.Models;
|
||||
|
||||
namespace BodyshopUploader.Utils
|
||||
{
|
||||
public static class JobProcessingQueue
|
||||
{
|
||||
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
|
||||
private static Queue<DTO_QueueItem> _jobs = new Queue<DTO_QueueItem>();
|
||||
private static bool _delegateQueuedOrRunning = false;
|
||||
|
||||
public static void Enqueue(DTO_QueueItem item)
|
||||
{
|
||||
lock (_jobs)
|
||||
{
|
||||
//See if the job is already in the queue based on the file name. If it is, ignore it.
|
||||
if (!(_jobs.Any(_ => _.FilePath == item.FilePath)))
|
||||
{
|
||||
logger.Debug("Adding job to the queue. | {0}", item.FilePath);
|
||||
_jobs.Enqueue(item);
|
||||
if (!_delegateQueuedOrRunning)
|
||||
{
|
||||
_delegateQueuedOrRunning = true;
|
||||
ThreadPool.UnsafeQueueUserWorkItem(ProcessQueuedItems, null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Debug("Ignoring job {0}, it's already in the queue.", item.FilePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ProcessQueuedItems(object ignored)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
DTO_QueueItem item;
|
||||
lock (_jobs)
|
||||
{
|
||||
if (_jobs.Count == 0)
|
||||
{
|
||||
_delegateQueuedOrRunning = false;
|
||||
break;
|
||||
}
|
||||
//Only peek at the first item in the queue so that it does not get added again while it is still getting processed.
|
||||
item = _jobs.Peek();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Thread.Sleep(1000);//Allow a small amount of time to pass before processing the queue item so that any writes can finish.
|
||||
|
||||
DecodeQueueItemJob(item);
|
||||
|
||||
UpsertQueueItem(item);
|
||||
}
|
||||
catch
|
||||
{
|
||||
ThreadPool.UnsafeQueueUserWorkItem(ProcessQueuedItems, null);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void DecodeQueueItemJob(DTO_QueueItem item)
|
||||
{
|
||||
//Process the job.
|
||||
logger.Info("Should process the job here. {0}", item.FilePath);
|
||||
}
|
||||
|
||||
private static void UpsertQueueItem(DTO_QueueItem item)
|
||||
{
|
||||
//Save the job to the DB.
|
||||
logger.Info("Should upsert the job graphqlly here. {0}", item.FilePath);
|
||||
|
||||
_jobs.Dequeue();
|
||||
}
|
||||
|
||||
private static void MoveFile(string FullPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(FullPath) + @"\Processed\");
|
||||
File.Move(FullPath, System.IO.Path.GetDirectoryName(FullPath) + @"\Processed\" + System.IO.Path.GetFileNameWithoutExtension(FullPath) + DateTime.Now.Ticks.ToString() + ".bak");
|
||||
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
logger.Error(Ex, "Can't move file {0} - it's gone!", FullPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,8 +11,10 @@ namespace BodyshopUploader.Utils
|
||||
{
|
||||
public void Execute(object parameter)
|
||||
{
|
||||
new Views.Main().Show();
|
||||
}
|
||||
var m = App.Current.Windows.OfType<Views.Main>().FirstOrDefault();
|
||||
m?.Show();
|
||||
m?.Focus();
|
||||
}
|
||||
|
||||
public bool CanExecute(object parameter)
|
||||
{
|
||||
|
||||
@@ -70,5 +70,37 @@ namespace BodyshopUploader.ViewModels
|
||||
return _removeMonitoringPathCommand;
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand _startFolderMonitorsCommand;
|
||||
public ICommand StartFolderMonitorsCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_startFolderMonitorsCommand == null)
|
||||
{
|
||||
_startFolderMonitorsCommand = new RelayCommand(
|
||||
p => MonitoringPaths.Count > 0,
|
||||
p => StartAllFolderMonitors()
|
||||
);
|
||||
}
|
||||
return _startFolderMonitorsCommand;
|
||||
}
|
||||
}
|
||||
|
||||
private ICommand _stopFolderMonitorsCommand;
|
||||
public ICommand StopFolderMonitorsCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_stopFolderMonitorsCommand == null)
|
||||
{
|
||||
_stopFolderMonitorsCommand = new RelayCommand(
|
||||
p => FolderMonitors.Count > 0,
|
||||
p => StopAllFolderMonitors()
|
||||
);
|
||||
}
|
||||
return _stopFolderMonitorsCommand;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,31 +48,51 @@ namespace BodyshopUploader.ViewModels
|
||||
Properties.Settings.Default.Save();
|
||||
}
|
||||
|
||||
public void StartAllFolderMonitors()
|
||||
{
|
||||
if (FolderMonitors.Count > 0)
|
||||
foreach (var m in FolderMonitors)
|
||||
{
|
||||
m.Dispose();
|
||||
}
|
||||
|
||||
foreach (var p in MonitoringPaths)
|
||||
{
|
||||
//Ensure the directory exists, then start monitoring for CIECA files.
|
||||
System.IO.Directory.CreateDirectory(p);
|
||||
FolderMonitors.Add(new Utils.CIECAMonitor(p));
|
||||
}
|
||||
}
|
||||
|
||||
public void StopAllFolderMonitors()
|
||||
{
|
||||
if (FolderMonitors.Count > 0)
|
||||
foreach (var m in FolderMonitors)
|
||||
{
|
||||
m.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task TestGql()
|
||||
{
|
||||
if (MonitoringPaths == null) MonitoringPaths = new ObservableCollection<string>();
|
||||
MonitoringPaths.Add(@"C:\IMEX");
|
||||
Properties.Settings.Default.MonitoringPaths = MonitoringPaths;
|
||||
Properties.Settings.Default.Save();
|
||||
var r = new GraphQLRequest
|
||||
{
|
||||
Query = @"
|
||||
query {
|
||||
jobs {
|
||||
id
|
||||
est_number
|
||||
ro_number
|
||||
}
|
||||
}
|
||||
"
|
||||
};
|
||||
|
||||
//var r = new GraphQLRequest
|
||||
//{
|
||||
// Query = @"
|
||||
// query {
|
||||
// jobs {
|
||||
// id
|
||||
// est_number
|
||||
// ro_number
|
||||
// }
|
||||
// }
|
||||
// "
|
||||
//};
|
||||
|
||||
//using (var g = Utils.GraphQL.CreateGQLClient())
|
||||
//{
|
||||
// var graphQLResponse = await g.PostAsync(r);
|
||||
// logger.Info(graphQLResponse.Data.jobs);
|
||||
//}
|
||||
using (var g = Utils.GraphQL.CreateGQLClient())
|
||||
{
|
||||
var graphQLResponse = await g.PostAsync(r);
|
||||
logger.Info(graphQLResponse.Data.jobs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,13 @@ namespace BodyshopUploader.ViewModels
|
||||
set { SetProperty(ref _progress, value); }
|
||||
}
|
||||
|
||||
private ObservableCollection<Utils.CIECAMonitor> _folderMonitors = new ObservableCollection<Utils.CIECAMonitor>() ;
|
||||
public ObservableCollection<Utils.CIECAMonitor> FolderMonitors
|
||||
{
|
||||
get { return _folderMonitors; }
|
||||
set { SetProperty(ref _folderMonitors, value); }
|
||||
}
|
||||
|
||||
private ObservableCollection<string> _monitoringPaths = Properties.Settings.Default.MonitoringPaths ;
|
||||
public ObservableCollection<string> MonitoringPaths
|
||||
{
|
||||
|
||||
@@ -20,15 +20,17 @@
|
||||
Background="{DynamicResource MaterialDesignPaper}"
|
||||
FontFamily="{DynamicResource MaterialDesignFont}"
|
||||
Loaded="Window_Loaded"
|
||||
xmlns:util="clr-namespace:BodyshopUploader.Utils">
|
||||
xmlns:util="clr-namespace:BodyshopUploader.Utils"
|
||||
Closing="Window_Closing">
|
||||
<Window.DataContext>
|
||||
<vm:MainViewModel />
|
||||
</Window.DataContext>
|
||||
<Window.Resources>
|
||||
<util:OpenMainWindowCommand x:Key="OpenMainWindowCommand"/>
|
||||
<util:OpenMainWindowCommand x:Key="OpenMainWindowCommand" />
|
||||
</Window.Resources>
|
||||
<StackPanel>
|
||||
<tb:TaskbarIcon IconSource="../favicon.ico"
|
||||
<DockPanel>
|
||||
<tb:TaskbarIcon DockPanel.Dock="Top"
|
||||
IconSource="../favicon.ico"
|
||||
DoubleClickCommand="{StaticResource OpenMainWindowCommand}"
|
||||
PopupActivation="LeftClick"
|
||||
MenuActivation="RightClick"
|
||||
@@ -45,13 +47,15 @@
|
||||
</Border>
|
||||
</tb:TaskbarIcon.TrayPopup>
|
||||
<tb:TaskbarIcon.ContextMenu>
|
||||
<ContextMenu Background="LightCoral">
|
||||
<ContextMenu>
|
||||
<MenuItem Header="First Menu Item" />
|
||||
<MenuItem Header="Second Menu Item" />
|
||||
</ContextMenu>
|
||||
</tb:TaskbarIcon.ContextMenu>
|
||||
</tb:TaskbarIcon>
|
||||
<Button Command="{Binding TestCommand}"
|
||||
|
||||
<Button DockPanel.Dock="Top"
|
||||
Command="{Binding TestCommand}"
|
||||
Content="Test Command" />
|
||||
|
||||
<Button Style="{StaticResource MaterialDesignFloatingActionMiniDarkButton}"
|
||||
@@ -60,8 +64,15 @@
|
||||
<materialDesign:PackIcon Kind="Add"
|
||||
Height="24"
|
||||
Width="24" />
|
||||
</Button>
|
||||
|
||||
</Button>
|
||||
<StackPanel DockPanel.Dock="Right">
|
||||
<Button Command="{Binding StartFolderMonitorsCommand}"
|
||||
Content="{x:Static p:Resources.Label_StartAllMonitors}"/>
|
||||
<Button Command="{Binding StopFolderMonitorsCommand}"
|
||||
Content="{x:Static p:Resources.Label_StopAllMonitors}" />
|
||||
|
||||
</StackPanel>
|
||||
<ItemsControl ItemsSource="{Binding MonitoringPaths}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
@@ -72,12 +83,11 @@
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="{Binding .}" />
|
||||
|
||||
|
||||
<materialDesign:PackIcon Kind="RemoveCircle"
|
||||
Grid.Column="1"
|
||||
Height="16"
|
||||
Width="16" >
|
||||
|
||||
<materialDesign:PackIcon Kind="RemoveCircle"
|
||||
Grid.Column="1"
|
||||
Height="16"
|
||||
Width="16">
|
||||
<materialDesign:PackIcon.InputBindings>
|
||||
<MouseBinding Gesture="LeftClick"
|
||||
Command="{Binding DataContext.RemoveMonitoringPathCommand,
|
||||
@@ -91,5 +101,5 @@
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
</Window>
|
||||
|
||||
@@ -29,5 +29,11 @@ namespace BodyshopUploader.Views
|
||||
{
|
||||
Application.Current.MainWindow = this;
|
||||
}
|
||||
|
||||
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
|
||||
{
|
||||
e.Cancel = true ;
|
||||
this.Hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user