public AppBootstrapper()
{
- ConfigureLogging();
+ log4net.Config.XmlConfigurator.Configure();
LogManager.GetLog = type => new log4netLogger(type);
}
- private static void ConfigureLogging()
- {
- var patternLayout = new PatternLayout();
- patternLayout.ConversionPattern = "%logger (%property{myContext}) [%level]- %message%newline";
- patternLayout.ActivateOptions();
- var appender = new TraceAppender { Layout = patternLayout };
- appender.AddFilter(new LevelRangeFilter{LevelMin=log4net.Core.Level.Info,LevelMax=log4net.Core.Level.Fatal});
- appender.ActivateOptions();
-
- BasicConfigurator.Configure(appender);
- }
-
/// <summary>
/// By default, we are configured to use MEF
/// </summary>
catalog.Catalogs.Add(new AssemblyCatalog(type.Assembly));
}
-
-
-
container = new CompositionContainer(catalog);
var batch = new CompositionBatch();
batch.AddExportedValue(catalog);
-
-
-
-
container.Compose(batch);
}
</Compile>
<Compile Include="PreferencesViewModel.cs" />
<Compile Include="TaskbarViewModel.cs" />
+ <Compile Include="Wpf32Window.cs" />
<Page Include="FilePropertiesView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
// </copyright>
// -----------------------------------------------------------------------
+using Pithos.Network;
+using log4net;
+
namespace Pithos.Client.WPF
{
using System;
/// </summary>
public static class PithosAccount
{
+ private static readonly ILog Log = LogManager.GetLogger(typeof(PithosAccount));
+
/// <summary>
/// Asynchronously retrieves PITHOS credentials
/// </summary>
HttpListener listener = new HttpListener();
listener.Prefixes.Add(listenerUrl);
- Trace.TraceInformation("[RETRIEVE] Listening at {0}", listenerUrl);
+ Log.InfoFormat("[RETRIEVE] Listening at {0}", listenerUrl);
listener.Start();
{
if (tc.IsFaulted)
{
- Trace.TraceError("[RETRIEVE][ERROR] Receive connection {0}", tc.Exception);
+ Log.Error("[RETRIEVE][ERROR] Receive connection {0}", tc.Exception);
throw tc.Exception;
}
else
var context = tc.Result;
var request = context.Request;
- Trace.TraceInformation("[RETRIEVE] Got Connection {0}", request.RawUrl);
+ Log.InfoFormat("[RETRIEVE] Got Connection {0}", request.RawUrl);
var query = request.QueryString;
var userName = query["user"];
var token = query["token"];
- Trace.TraceInformation("[RETRIEVE] Credentials retrieved user:{0} token:{1}", userName, token);
+ Log.InfoFormat("[RETRIEVE] Credentials retrieved user:{0} token:{1}", userName, token);
Respond(context);
return new NetworkCredential(userName, token);
uriBuilder.Query="next=" + listenerUrl;
var retrieveUri = uriBuilder.Uri;
- Trace.TraceInformation("[RETRIEVE] Open Browser at {0}", retrieveUri);
+ Log.InfoFormat("[RETRIEVE] Open Browser at {0}", retrieveUri);
Process.Start(retrieveUri.ToString());
return task;
stream.Write(outBuffer, 0, outBuffer.Length);
}
- Trace.TraceInformation("[RETRIEVE] Responded");
+ Log.InfoFormat("[RETRIEVE] Responded");
}
/// <summary>
/// Locates a free local port
xmlns:tb="clr-namespace:Hardcodet.Wpf.TaskbarNotification;assembly=Hardcodet.Wpf.TaskbarNotification"
xmlns:cal="http://www.caliburnproject.org"
x:Name="TheView"
- Title="Pithos Preferences" Height="382" Width="445"
+ Title="Pithos Preferences" Height="381" Width="548"
ShowInTaskbar="true"
WindowStartupLocation="CenterScreen"
Icon="/Pithos.Client.WPF;component/Images/Tray.ico"
<TextBlock Text="Accounts"/>
</StackPanel>
</TabItem.Header>
- <StackPanel Orientation="Horizontal" VerticalAlignment="Stretch" >
- <Grid Margin="5,10,5,5">
+ <Grid VerticalAlignment="Stretch" >
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="Auto"/>
+ <ColumnDefinition Width="*"/>
+ </Grid.ColumnDefinitions>
+ <Grid Margin="5,10,5,5" Column="0" Width="150">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<Button Name="RemoveAccount" Content="Remove" Style="{StaticResource ButtonStyle}" Width="50"/>
</StackPanel>
</Grid>
- <GroupBox Header="Account" Padding="5" Margin="5" Height="190" HorizontalAlignment="Stretch" VerticalAlignment="Top" Width="272">
+ <GroupBox Header="Account" Padding="5" Margin="5" Height="231" HorizontalAlignment="Stretch" VerticalAlignment="Top" Grid.Column="1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
+ <RowDefinition Height="Auto"/>
<RowDefinition />
</Grid.RowDefinitions>
<Label Content="Account" Grid.Column="0" Grid.Row="0" Margin="0,5" HorizontalAlignment="Left"/>
<TextBox Name="CurrentAccount_AccountName" Grid.Column="1" Grid.Row="0" Margin="5"/>
<Label Content="API Key" Grid.Column="0" Grid.Row="1" Margin="0,5" HorizontalAlignment="Left"/>
<TextBox Name="CurrentAccount_ApiKey" Grid.Column="1" Grid.Row="1" Margin="5"/>
- <CheckBox Name="CurrentAccount_IsActive" Content="Account is Active" Grid.Column="1" Grid.Row="2" Margin="5"/>
- <CheckBox Name="CurrentAccount_UsePithos" Content="Use Pithos Extensions" Grid.Column="1" Grid.Row="3" Margin="5"/>
- <Button Name="SelectSyncFolders" Content="Selective Sync" Width="Auto" HorizontalAlignment="Left" Style="{StaticResource ButtonStyle}" Grid.Column="1" Grid.Row="4"/>
+ <Label Content="Folder" Grid.Column="0" Grid.Row="2" Margin="0,5" HorizontalAlignment="Left"/>
+ <Grid Grid.Row="2" Grid.Column="1" >
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="*"/>
+ <ColumnDefinition Width="Auto"/>
+ </Grid.ColumnDefinitions>
+ <TextBox Name="CurrentAccount_RootPath" Margin="5" HorizontalAlignment="Stretch" Grid.Column="0"/>
+ <Button Name="MoveAccountFolder" Content="Move ..." Width="60" Height="30" Grid.Column="1" />
+ </Grid>
+ <CheckBox Name="CurrentAccount_IsActive" Content="Account is Active" Grid.Column="1" Grid.Row="3" Margin="5"/>
+ <CheckBox Name="CurrentAccount_UsePithos" Content="Use Pithos Extensions" Grid.Column="1" Grid.Row="4" Margin="5"/>
+ <Button Name="SelectSyncFolders" Content="Selective Sync" Width="Auto" HorizontalAlignment="Left" Style="{StaticResource ButtonStyle}" Grid.Column="1" Grid.Row="5"/>
</Grid>
</GroupBox>
- </StackPanel>
+ </Grid>
</TabItem>
<TabItem VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch">
<TabItem.Header>
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
+using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
}
+
}
}
using System.Runtime.Serialization;
using System.Windows;
using System.Windows.Forms;
+using System.Windows.Interop;
using Caliburn.Micro;
using Hardcodet.Wpf.TaskbarNotification;
using Pithos.Client.WPF.Configuration;
using Pithos.Core;
using Pithos.Interfaces;
-
+using IWin32Window = System.Windows.Forms.IWin32Window;
using Screen = Caliburn.Micro.Screen;
namespace Pithos.Client.WPF
private IEventAggregator _events;
- public PithosSettings Settings { get; set; }
+ private PithosSettings _settings;
+ public PithosSettings Settings
+ {
+ get { return _settings; }
+ set
+ {
+ _settings = value;
+ foreach (var account in _settings.Accounts.Where(account=>account.IsActive))
+ {
+ if (String.IsNullOrWhiteSpace(account.RootPath))
+ {
+ account.RootPath = _settings.PithosPath;
+ _settings.Save();
+ }
+ }
+ NotifyOfPropertyChange(()=>Settings);
+ }
+ }
- public PithosMonitor Monitor { get; private set; }
+ private Dictionary<string,PithosMonitor> _monitors=new Dictionary<string, PithosMonitor>();
+ public Dictionary<string, PithosMonitor> Monitors
+ {
+ get { return _monitors; }
+ }
private TaskbarViewModel _taskbar;
public TaskbarViewModel Taskbar
//ShellExtensionController _extensionController=new ShellExtensionController();
[ImportingConstructor]
- public PreferencesViewModel(IEventAggregator events, TaskbarViewModel taskbar, PithosSettings settings, PithosMonitor monitor)
+ public PreferencesViewModel(IEventAggregator events, TaskbarViewModel taskbar, PithosSettings settings)
{
_events = events;
_events.Subscribe(this);
Taskbar=taskbar;
Taskbar.Parent = this;
- Settings=settings;
- Monitor=monitor;
+ Settings=settings;
Taskbar.UsageMessage = "Using 15% of 50 GB";
if (String.IsNullOrWhiteSpace(activeAccount.AccountName))
return;
- Monitor.ApiKey = activeAccount.ApiKey;
- Monitor.UserName = activeAccount.AccountName;
- Monitor.UsePithos = activeAccount.UsePithos;
+ var monitor = Monitors[activeAccount.AccountName];
+ monitor.ApiKey = activeAccount.ApiKey;
+ monitor.UserName = activeAccount.AccountName;
+ monitor.UsePithos = activeAccount.UsePithos;
- Monitor.Start();
+ monitor.Start();
}
public void ChangePithosFolder()
return Settings.Accounts[SelectedAccountIndex];
return null;
}
-/*
- set
- {
- _currentAccount = value;
- }
-*/
+
}
tv.TaskbarView.ShowBalloonTip(notification.Title, notification.Message, icon);
}
+
+ public void MoveAccountFolder()
+ {
+
+ using (var dlg = new FolderBrowserDialog())
+ {
+ var currentFolder = CurrentAccount.RootPath;
+ dlg.SelectedPath = currentFolder;
+ //Ask the user to select a folder
+ //Note: We need a parent window here, which we retrieve with GetView
+ var view = (Window)GetView();
+ if (DialogResult.OK != dlg.ShowDialog(new Wpf32Window(view)))
+ return;
+
+ var newPath= dlg.SelectedPath;
+ //Find the account's monitor and stop it
+ var monitor = Monitors[CurrentAccount.AccountName];
+ monitor.Stop();
+
+ var oldPath = monitor.RootPath;
+ //The old directory may not exist eg. if we create an account for the first time
+ if (Directory.Exists(oldPath))
+ {
+ //If it does, do the move
+ Directory.Move(oldPath, newPath);
+ //We also need to change the path of the existing file states
+ monitor.MoveFileStates(oldPath, newPath);
+ }
+ //Replace the old rootpath with the new
+ CurrentAccount.RootPath = newPath;
+ //TODO: This will save all settings changes. Too coarse grained, need to fix at a later date
+ Settings.Save();
+ //And start the monitor on the new RootPath
+ monitor.RootPath = newPath;
+ monitor.Start();
+ //Finally, notify that the Settings, CurrentAccount have changed
+ NotifyOfPropertyChange(() => CurrentAccount);
+ NotifyOfPropertyChange(() => Settings);
+
+ }
+ }
}
}
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows;
+using System.Windows.Interop;
+using IWin32Window = System.Windows.Forms.IWin32Window;
+
+
+namespace Pithos.Client.WPF
+{
+ public class Wpf32Window : IWin32Window
+ {
+ public IntPtr Handle { get; private set; }
+
+ public Wpf32Window(Window wpfWindow)
+ {
+ Handle = new WindowInteropHelper(wpfWindow).Handle;
+ }
+ }
+}
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<section name="Pithos.Client.WPF.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</sectionGroup>
+ <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
</setting>
</Pithos.Client.WPF.Properties.Settings>
</applicationSettings>
+ <log4net>
+ <appender name="TraceAppender" type="log4net.Appender.TraceAppender" >
+ <layout type="log4net.Layout.PatternLayout">
+ <conversionPattern value="%logger (%property{myContext}) [%level]- %message%newline" />
+ </layout>
+ <filter type="log4net.Filter.LevelRangeFilter">
+ <levelMin value="DEBUG" />
+ <levelMax value="FATAL" />
+ <acceptOnMatch value="false" />
+ </filter>
+ <filter type="log4net.Filter.LoggerMatchFilter">
+ <loggerToMatch value="NHibernate" />
+ <acceptOnMatch value="false" />
+ </filter>
+ <filter type="log4net.Filter.LoggerMatchFilter">
+ <loggerToMatch value="Caliburn" />
+ <acceptOnMatch value="false" />
+ </filter>
+ </appender>
+ <root>
+ <level value="DEBUG" />
+ <appender-ref ref="TraceAppender" />
+ </root>
+ </log4net>
</configuration>
\ No newline at end of file
public string BlockHash { get; set; }
public int BlockSize { get; set; }
+ public void ChangeRoots(string oldPath, string newPath)
+ {
+ throw new NotImplementedException();
+ }
private PithosStatus _pithosStatus = PithosStatus.InSynch;
</PropertyGroup>
<ItemGroup>
<Reference Include="Castle.ActiveRecord, Version=3.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL" />
+ <Reference Include="Castle.Core">
+ <HintPath>..\Libraries\Castle.Core.dll</HintPath>
+ </Reference>
<Reference Include="nunit.framework, Version=2.5.10.11092, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">
<HintPath>..\packages\NUnit.2.5.10.11092\lib\nunit.framework.dll</HintPath>
</Reference>
using System;
+using System.Linq;
+using Castle.ActiveRecord;
using NUnit.Framework;
+using Pithos.Core.Agents;
using Pithos.Interfaces;
namespace Pithos.Core.Test
}
+
}
}
}
- //Constructor for downloading files
- public CloudAction(CloudActionType action, ObjectInfo cloudFile)
+
+ }
+
+ public class CloudDownloadAction:CloudAction
+ {
+ public CloudDownloadAction(ObjectInfo cloudFile)
+ :base(CloudActionType.DownloadUnconditional)
+ {
+ CloudFile = cloudFile;
+ }
+
+ }
+ public class CloudDeleteAction:CloudAction
+ {
+ public CloudDeleteAction(string fileName, FileState fileState)
+ : this(new ObjectInfo { Name = fileName },fileState)
+ {
+ }
+
+ public CloudDeleteAction(ObjectInfo cloudFile, FileState fileState)
+ : base(CloudActionType.DeleteCloud)
{
- Action = action;
CloudFile = cloudFile;
+ FileState = fileState;
}
+ }
- }
+ public class CloudUploadAction:CloudAction
+ {
+ public CloudUploadAction(FileInfo fileInfo, FileState state, int blockSize, string algorithm)
+ : base(CloudActionType.UploadUnconditional,fileInfo,ObjectInfo.Empty,state,blockSize,algorithm)
+ {
+ }
+ }
public class CloudMoveAction:CloudAction
{
using System.Threading.Tasks;
using Pithos.Interfaces;
using Pithos.Network;
+using log4net;
+using log4net.Core;
namespace Pithos.Core.Agents
{
public string RootPath { get; private set; }
+ private static readonly ILog Log = LogManager.GetLogger("FileAgent");
public void Start(string rootPath)
{
var process=message.Then(Process,inbox.CancellationToken);
inbox.LoopAsync(process,loop,ex=>
- Trace.TraceError("[ERROR] File Event Processing:\r{0}", ex));
+ Log.ErrorFormat("[ERROR] File Event Processing:\r{0}", ex));
};
loop();
});
{
if (File.Exists(state.Path))
{
- Trace.TraceWarning("File access error occured, retrying {0}\n{1}", state.Path, exc);
+ Log.WarnFormat("File access error occured, retrying {0}\n{1}", state.Path, exc);
_agent.Post(state);
}
else
{
- Trace.TraceWarning("File {0} does not exist. Will be ignored\n{1}", state.Path, exc);
+ Log.WarnFormat("File {0} does not exist. Will be ignored\n{1}", state.Path, exc);
}
}
catch (Exception exc)
{
- Trace.TraceWarning("Error occured while indexing{0. The file will be skipped}\n{1}", state.Path, exc);
+ Log.WarnFormat("Error occured while indexing{0. The file will be skipped}\n{1}", state.Path, exc);
}
return CompletedTask<object>.Default;
}
public int BlockSize { get; set; }
public string BlockHash { get; set; }
- private static readonly ILog Log = LogManager.GetLogger(typeof(NetworkAgent));
+ private static readonly ILog Log = LogManager.GetLogger("NetworkAgent");
public void Start(string pithosContainer, string trashContainer, int blockSize, string blockHash)
throw new ArgumentNullException("action");
Contract.EndContractBlock();
- using (log4net.LogicalThreadContext.Stacks["NETWORK"].Push("PROCESS"))
+ using (log4net.ThreadContext.Stacks["NETWORK"].Push("PROCESS"))
{
Log.InfoFormat("[ACTION] Start Processing {0}:{1}->{2}", action.Action, action.LocalFile,
action.CloudFile.Name);
{
throw;
}
- catch (System.IO.FileNotFoundException exc)
+ catch (FileNotFoundException exc)
{
Log.ErrorFormat("{0} : {1} -> {2} failed because the file was not found.\n Rescheduling a delete",
action.Action, action.LocalFile, action.CloudFile, exc);
- Post(new CloudAction(CloudActionType.DeleteCloud,action.CloudFile));
+ Post(new CloudDeleteAction(action.CloudFile,action.FileState));
}
catch (Exception exc)
{
throw new ArgumentNullException("action");
Contract.EndContractBlock();
- Trace.TraceInformation("[ACTION] Start Processing {0}:{1}->{2}", action.Action, action.LocalFile, action.CloudFile.Name);
+ Log.InfoFormat("[ACTION] Start Processing {0}:{1}->{2}", action.Action, action.LocalFile, action.CloudFile.Name);
try
{
RenameCloudFile(action.OldFileName, action.NewPath, action.NewFileName);
- Trace.TraceInformation("[ACTION] End Processing {0}:{1}->{2}", action.Action, action.LocalFile, action.CloudFile.Name);
+ Log.InfoFormat("[ACTION] End Processing {0}:{1}->{2}", action.Action, action.LocalFile, action.CloudFile.Name);
}
catch (OperationCanceledException)
{
}
catch (Exception exc)
{
- Trace.TraceError("[REQUEUE] {0} : {1} -> {2} due to exception\r\n{3}",
+ Log.ErrorFormat("[REQUEUE] {0} : {1} -> {2} due to exception\r\n{3}",
action.Action, action.OldFileName, action.NewFileName, exc);
_agent.Post(action);
throw new ArgumentNullException(accountPath);
Contract.EndContractBlock();
- using (log4net.LogicalThreadContext.Stacks["SCHEDULE"].Push("Retrieve Remote"))
+ using (log4net.ThreadContext.Stacks["SCHEDULE"].Push("Retrieve Remote"))
{
Log.Info("[LISTENER] Scheduled");
ProcessRemoteFiles(accountPath, since);
return;
}
- using (log4net.LogicalThreadContext.Stacks["SCHEDULE"].Push("Process Results"))
+ using (log4net.ThreadContext.Stacks["SCHEDULE"].Push("Process Results"))
{
var remoteObjects = ((Task<IList<ObjectInfo>>) task.Result[0]).Result;
var trashObjects = ((Task<IList<ObjectInfo>>) task.Result[1]).Result;
if (fileStatus != FileStatus.Deleted)
{
//Remote files should be downloaded
- yield return new CloudAction(CloudActionType.DownloadUnconditional, objectInfo);
+ yield return new CloudDownloadAction(objectInfo);
}
}
}
throw new ArgumentException("The fileName should not be rooted","fileName");
Contract.EndContractBlock();
- using ( log4net.LogicalThreadContext.Stacks["DeleteCloudFile"].Push("Delete"))
+ using ( log4net.ThreadContext.Stacks["DeleteCloudFile"].Push("Delete"))
{
var info = FileAgent.GetFileInfo(fileName);
var path = info.FullName.ToLower();
throw new ArgumentNullException("topHash");
Contract.EndContractBlock();
- var upload = Task.Factory.Iterate(UploadIterator(account,container,fileInfo, hash, topHash));
+ var upload = Task.Factory.Iterate(UploadIterator(account,container,fileInfo, hash.ToLower(), topHash.ToLower()));
upload.Wait();
}
//Even if GetObjectInfo times out, we can proceed with the upload
var info = CloudClient.GetObjectInfo(account, container, url);
+ var cloudHash = info.Hash.ToLower();
//If the file hashes match, abort the upload
- if (hash.Equals(info.Hash, StringComparison.InvariantCultureIgnoreCase) ||
- topHash.Equals(info.Hash, StringComparison.InvariantCultureIgnoreCase))
+ if (hash == cloudHash || topHash ==cloudHash)
{
//but store any metadata changes
this.StatusKeeper.StoreInfo(fullFileName, info);
private Agent<Action> _persistenceAgent;
- private static readonly ILog log = LogManager.GetLogger(typeof(StatusAgent));
+ private static readonly ILog Log = LogManager.GetLogger("StatusAgent");
public StatusAgent()
{
var connectionString = String.Format(@"Data Source={0}\pithos.db;Version=3", pithosDbPath);
properties.Add("connection.connection_string", connectionString);
- var source = new InPlaceConfigurationSource();
-
+ var source = new InPlaceConfigurationSource();
source.Add(typeof (ActiveRecordBase), properties);
+ source.SetDebugFlag(false);
return source;
}
}
catch (Exception ex)
{
- Trace.TraceError("[ERROR] STATE \n{0}",ex);
+ Log.ErrorFormat("[ERROR] STATE \n{0}",ex);
}
queue.DoAsync(loop);
});
public string BlockHash { get; set; }
public int BlockSize { get; set; }
+ public void ChangeRoots(string oldPath, string newPath)
+ {
+ if (String.IsNullOrWhiteSpace(oldPath))
+ throw new ArgumentNullException("oldPath");
+ if (!Path.IsPathRooted(oldPath))
+ throw new ArgumentException("oldPath must be an absolute path", "oldPath");
+ if (string.IsNullOrWhiteSpace(newPath))
+ throw new ArgumentNullException("newPath");
+ if (!Path.IsPathRooted(newPath))
+ throw new ArgumentException("newPath must be an absolute path", "newPath");
+ Contract.EndContractBlock();
+
+ FileState.ChangeRootPath(oldPath,newPath);
+
+ }
private PithosStatus _pithosStatus=PithosStatus.InSynch;
}
catch (Exception exc)
{
- Trace.TraceError(exc.ToString());
+ Log.ErrorFormat(exc.ToString());
return defaultValue;
}
}
var state = FileState.FindByFilePath(filePath);
if (state == null)
{
- Trace.TraceWarning("[NOFILE] Unable to set status for {0}.", filePath);
+ Log.WarnFormat("[NOFILE] Unable to set status for {0}.", filePath);
return;
}
setter(state);
var state = FileState.Find(stateID);
if (state == null)
{
- Trace.TraceWarning("[NOFILE] Unable to set status for {0}.", stateID);
+ Log.WarnFormat("[NOFILE] Unable to set status for {0}.", stateID);
return;
}
setter(state);
}
catch (Exception exc)
{
- Trace.TraceError(exc.ToString());
+ Log.ErrorFormat(exc.ToString());
return FileOverlayStatus.Unversioned;
}
}
if (state == null)
{
- Trace.TraceWarning("[NOFILE] Unable to set status for {0}.", oldPath);
+ Log.WarnFormat("[NOFILE] Unable to set status for {0}.", oldPath);
return;
}
//NOTE: This will cause problems if path is used as a key in relationships
var state = FileState.FindByFilePath(path);
if (state == null)
{
- Trace.TraceWarning("[NOFILE] Unable to set checkesum for {0}.", path);
+ Log.WarnFormat("[NOFILE] Unable to set checkesum for {0}.", path);
return;
}
state.Checksum = checksum;
using System.Text;
using System.Threading.Tasks;
using Pithos.Interfaces;
+using log4net;
namespace Pithos.Core.Agents
{
[Import]
public NetworkAgent NetworkAgent { get; set; }
+ private static readonly ILog Log = LogManager.GetLogger("WorkflowAgent");
+
public void Start()
{
_agent = Agent<WorkflowState>.Start(inbox =>
var message = inbox.Receive();
var process = message.Then(Process, inbox.CancellationToken);
inbox.LoopAsync(process,loop,ex=>
- Trace.TraceError("[ERROR] Synch for {0}:\r{1}", message.Result.FileName, ex));
+ Log.ErrorFormat("[ERROR] Synch for {0}:\r{1}", message.Result.FileName, ex));
};
loop();
});
private Task<object> Process(WorkflowState state)
{
- if (state.Skip)
- return CompletedTask<object>.Default;
- string path = state.Path.ToLower();
-
- //Bypass deleted files, unless the status is Deleted
- if (!File.Exists(path) && state.Status != FileStatus.Deleted)
+ using (log4net.ThreadContext.Stacks["Workflow"].Push("Process"))
{
- state.Skip = true;
- this.StatusKeeper.ClearFileStatus(path);
- return CompletedTask<object>.Default;
- }
- var fileState = FileState.FindByFilePath(path);
- var blockHash = NetworkAgent.BlockHash;
- var blockSize = NetworkAgent.BlockSize;
- var info = new FileInfo(path);
+ if (Log.IsDebugEnabled) Log.DebugFormat("State {0} {1} {2}", state.FileName,state.Status,state.TriggeringChange);
- switch (state.Status)
- {
- case FileStatus.Created:
- case FileStatus.Modified:
- NetworkAgent.Post(new CloudAction(CloudActionType.UploadUnconditional, info, ObjectInfo.Empty, fileState,blockSize,blockHash));
- break;
- case FileStatus.Deleted:
- string fileName = info.AsRelativeUrlTo(NetworkAgent.FileAgent.RootPath);
- NetworkAgent.Post(new CloudAction(CloudActionType.DeleteCloud, null, new ObjectInfo { Name = fileName }, fileState, blockSize, blockHash));
- break;
- case FileStatus.Renamed:
- NetworkAgent.Post(new CloudMoveAction(CloudActionType.RenameCloud, state.OldFileName, state.OldPath, state.FileName, state.Path));
- break;
- }
+ if (state.Skip)
+ {
+ if (Log.IsDebugEnabled) Log.DebugFormat("Skipping {0}",state.FileName);
+
+ return CompletedTask<object>.Default;
+ }
+ string path = state.Path.ToLower();
+
+ //Bypass deleted files, unless the status is Deleted
+ if (!File.Exists(path) && state.Status != FileStatus.Deleted)
+ {
+ state.Skip = true;
+ this.StatusKeeper.ClearFileStatus(path);
+
+ if (Log.IsDebugEnabled) Log.DebugFormat("Skipped missing {0}", state.FileName);
+
+ return CompletedTask<object>.Default;
+ }
+ var fileState = FileState.FindByFilePath(path);
+ var blockHash = NetworkAgent.BlockHash;
+ var blockSize = NetworkAgent.BlockSize;
+ var info = new FileInfo(path);
+
+ switch (state.Status)
+ {
+ case FileStatus.Created:
+ case FileStatus.Modified:
+ NetworkAgent.Post(new CloudUploadAction(info, fileState, blockSize, blockHash));
+ break;
+ case FileStatus.Deleted:
+ string fileName = info.AsRelativeUrlTo(NetworkAgent.FileAgent.RootPath);
+ NetworkAgent.Post(new CloudDeleteAction(fileName, fileState));
+ break;
+ case FileStatus.Renamed:
+ NetworkAgent.Post(new CloudMoveAction(CloudActionType.RenameCloud, state.OldFileName,
+ state.OldPath, state.FileName, state.Path));
+ break;
+ }
- return CompletedTask<object>.Default;
+ return CompletedTask<object>.Default;
+ }
}
public void RestartInterruptedFiles()
{
- StatusNotification.NotifyChange("Restart processing interrupted files", TraceLevel.Verbose);
-
- var pendingEntries = from state in FileState.Queryable
- where state.FileStatus != FileStatus.Unchanged &&
- !state.FilePath.StartsWith(FragmentsPath.ToLower()) &&
- !state.FilePath.EndsWith(".ignore")
- select state;
-
- var validEntries = from state in pendingEntries
- select new WorkflowState
- {
- Path = state.FilePath.ToLower(),
- FileName = Path.GetFileName(state.FilePath).ToLower(),
- Hash = state.Checksum,
- Status = state.OverlayStatus == FileOverlayStatus.Unversioned ?
- FileStatus.Created :
- state.FileStatus,
- TriggeringChange = state.OverlayStatus == FileOverlayStatus.Unversioned ?
- WatcherChangeTypes.Created :
- WatcherChangeTypes.Changed
- };
- foreach (var entry in validEntries)
- {
- Post(entry);
- }
+ StatusNotification.NotifyChange("Restart processing interrupted files", TraceLevel.Verbose);
+ using (log4net.ThreadContext.Stacks["Workflow"].Push("Restart"))
+ {
+ if (Log.IsDebugEnabled)
+ Log.Debug("Starting interrupted files");
+
+ var pendingEntries = from state in FileState.Queryable
+ where state.FileStatus != FileStatus.Unchanged &&
+ !state.FilePath.StartsWith(FragmentsPath.ToLower()) &&
+ !state.FilePath.EndsWith(".ignore")
+ select state;
+ if (Log.IsDebugEnabled)
+ Log.DebugFormat("Found {0} interrupted files",pendingEntries.Count());
+
+ var validEntries = from state in pendingEntries
+ select new WorkflowState
+ {
+ Path = state.FilePath.ToLower(),
+ FileName = Path.GetFileName(state.FilePath).ToLower(),
+ Hash = state.Checksum,
+ Status = state.OverlayStatus == FileOverlayStatus.Unversioned
+ ? FileStatus.Created
+ : state.FileStatus,
+ TriggeringChange =
+ state.OverlayStatus == FileOverlayStatus.Unversioned
+ ? WatcherChangeTypes.Created
+ : WatcherChangeTypes.Changed
+ };
+ foreach (var entry in validEntries)
+ {
+ Post(entry);
+ }
+ }
}
public void Post(WorkflowState workflowState)
{
+ if (Log.IsDebugEnabled)
+ Log.DebugFormat("Posted {0} {1} {2}", workflowState.Path, workflowState.Status, workflowState.TriggeringChange);
_agent.Post(workflowState);
}
}
}
+ public static void ChangeRootPath(string oldPath,string newPath)
+ {
+ if (String.IsNullOrWhiteSpace(oldPath))
+ throw new ArgumentNullException("oldPath");
+ if (!Path.IsPathRooted(oldPath))
+ throw new ArgumentException("oldPath must be an absolute path", "oldPath");
+ if (string.IsNullOrWhiteSpace(newPath))
+ throw new ArgumentNullException("newPath");
+ if (!Path.IsPathRooted(newPath))
+ throw new ArgumentException("newPath must be an absolute path", "newPath");
+ Contract.EndContractBlock();
+
+ //Ensure the paths end with the same character
+ if (!oldPath.EndsWith("\\"))
+ oldPath = oldPath + "\\";
+ if (!newPath.EndsWith("\\"))
+ newPath = newPath + "\\";
+
+ using (new TransactionScope())
+ {
+ Execute((session, instance) =>
+ {
+ const string hqlUpdate =
+ "update FileState set FilePath = replace(FilePath,:oldPath,:newPath) where FilePath like :oldPath || '%' ";
+ var result=session.CreateQuery(hqlUpdate)
+ .SetString("oldPath", oldPath.ToLower())
+ .SetString("newPath", newPath.ToLower())
+ .ExecuteUpdate();
+ return null;
+ }, null);
+ }
+ }
+
public static Task<FileState> CreateForAsync(string filePath,int blockSize,string algorithm)
{
if (blockSize <= 0)
string BlockHash { get; set; }
int BlockSize { get; set; }
+ void ChangeRoots(string oldPath, string newPath);
}
[ContractClassFor(typeof(IStatusKeeper))]
public abstract string BlockHash { get; set; }
public abstract int BlockSize { get; set; }
+ public void ChangeRoots(string oldPath, string newPath)
+ {
+ Contract.Requires(!String.IsNullOrWhiteSpace(oldPath));
+ Contract.Requires(Path.IsPathRooted(oldPath));
+ Contract.Requires(!string.IsNullOrWhiteSpace(newPath));
+ Contract.Requires(Path.IsPathRooted(newPath));
+ }
}
}
using Pithos.Interfaces;
using System.ServiceModel;
using Pithos.Network;
+using log4net;
namespace Pithos.Core
{
private ServiceHost _statusService { get; set; }
+ private static readonly ILog Log = LogManager.GetLogger(typeof(PithosMonitor));
+
public bool Pause
{
private void IndexLocalFiles(string path)
{
StatusNotification.NotifyChange("Indexing Local Files",TraceLevel.Info);
- Trace.TraceInformation("[START] Index Local");
- try
+ using (log4net.ThreadContext.Stacks["Monitor"].Push("Indexing local files"))
{
- var fragmentsPath=Path.Combine(RootPath, FragmentsFolder);
- var directory = new DirectoryInfo(path);
- var files =
- from file in directory.EnumerateFiles("*", SearchOption.AllDirectories)
- where !file.FullName.StartsWith(fragmentsPath,StringComparison.InvariantCultureIgnoreCase) &&
- !file.Extension.Equals("ignore",StringComparison.InvariantCultureIgnoreCase)
- select file;
- StatusKeeper.ProcessExistingFiles(files);
-
- }
- catch (Exception exc)
- {
- Trace.TraceError("[ERROR] Index Local - {0}", exc);
- }
- finally
- {
- Trace.TraceInformation("[END] Inxed Local");
+ Log.Info("START");
+ try
+ {
+ var fragmentsPath = Path.Combine(RootPath, FragmentsFolder);
+ var directory = new DirectoryInfo(path);
+ var files =
+ from file in directory.EnumerateFiles("*", SearchOption.AllDirectories)
+ where !file.FullName.StartsWith(fragmentsPath, StringComparison.InvariantCultureIgnoreCase) &&
+ !file.Extension.Equals("ignore", StringComparison.InvariantCultureIgnoreCase)
+ select file;
+ StatusKeeper.ProcessExistingFiles(files);
+
+ }
+ catch (Exception exc)
+ {
+ Log.Error("[ERROR]", exc);
+ }
+ finally
+ {
+ Log.Info("[END]");
+ }
}
}
var info = Directory.CreateDirectory(folder);
info.Attributes |= FileAttributes.Hidden;
- Trace.TraceInformation("Created Fragments Folder: {0}", folder);
+ Log.InfoFormat("Created Fragments Folder: {0}", folder);
}
return folder;
}
}
+ public void MoveFileStates(string oldPath, string newPath)
+ {
+ if (String.IsNullOrWhiteSpace(oldPath))
+ throw new ArgumentNullException("oldPath");
+ if (!Path.IsPathRooted(oldPath))
+ throw new ArgumentException("oldPath must be an absolute path","oldPath");
+ if (string.IsNullOrWhiteSpace(newPath))
+ throw new ArgumentNullException("newPath");
+ if (!Path.IsPathRooted(newPath))
+ throw new ArgumentException("newPath must be an absolute path","newPath");
+ Contract.EndContractBlock();
+
+ StatusKeeper.ChangeRoots(oldPath, newPath);
+ }
}
public interface IStatusNotification
using System.Threading.Tasks;
using Newtonsoft.Json;
using Pithos.Interfaces;
+using log4net;
using WebHeaderCollection = System.Net.WebHeaderCollection;
namespace Pithos.Network
private bool _authenticated = false;
- //
+ private static readonly ILog Log = LogManager.GetLogger("CloudFilesClient");
+
+
public void Authenticate(string userName,string apiKey)
{
if (String.IsNullOrWhiteSpace(userName))
Contract.Ensures(_baseClient != null);
Contract.EndContractBlock();
- Trace.TraceInformation("[AUTHENTICATE] Start for {0}", userName);
+ Log.InfoFormat("[AUTHENTICATE] Start for {0}", userName);
if (_authenticated)
return;
Contract.Assume(_baseClient.Headers!=null);
_baseClient.Headers.Add("X-Auth-Token", Token);
- Trace.TraceInformation("[AUTHENTICATE] End for {0}", userName);
+ Log.InfoFormat("[AUTHENTICATE] End for {0}", userName);
}
public IList<ShareAccountInfo> ListSharingAccounts(DateTime? since=null)
{
- Trace.TraceInformation("[START] ListSharingAccounts");
-
- using (var client = new RestClient(_baseClient))
+ using (log4net.ThreadContext.Stacks["Share"].Push("List Accounts"))
{
- client.Parameters.Clear();
- client.Parameters.Add("format", "json");
- client.IfModifiedSince = since;
+ if (Log.IsDebugEnabled) Log.DebugFormat("START");
- //Extract the username from the base address
- client.BaseAddress = RootAddressUri.AbsoluteUri;
-
- var content = client.DownloadStringWithRetry(@"", 3);
+ using (var client = new RestClient(_baseClient))
+ {
+ client.Parameters.Clear();
+ client.Parameters.Add("format", "json");
+ client.IfModifiedSince = since;
- client.AssertStatusOK("ListSharingAccounts failed");
+ //Extract the username from the base address
+ client.BaseAddress = RootAddressUri.AbsoluteUri;
- //If the result is empty, return an empty list,
- var infos = String.IsNullOrWhiteSpace(content)
- ? new List<ShareAccountInfo>()
- //Otherwise deserialize the account list into a list of ShareAccountInfos
- : JsonConvert.DeserializeObject<IList<ShareAccountInfo>>(content);
+ var content = client.DownloadStringWithRetry(@"", 3);
- Trace.TraceInformation("[END] ListSharingAccounts");
- return infos;
+ client.AssertStatusOK("ListSharingAccounts failed");
+
+ //If the result is empty, return an empty list,
+ var infos = String.IsNullOrWhiteSpace(content)
+ ? new List<ShareAccountInfo>()
+ //Otherwise deserialize the account list into a list of ShareAccountInfos
+ : JsonConvert.DeserializeObject<IList<ShareAccountInfo>>(content);
+
+ Log.DebugFormat("END");
+ return infos;
+ }
}
}
public IList<ObjectInfo> ListSharedObjects(DateTime? since = null)
{
- Trace.TraceInformation("[START] ListSharedObjects");
-
- var objects=new List<ObjectInfo>();
- var accounts=ListSharingAccounts(since);
- foreach (var account in accounts)
+ using (log4net.ThreadContext.Stacks["Share"].Push("List Objects"))
{
- var containers=ListContainers(account.name);
- foreach (var container in containers)
+ if (Log.IsDebugEnabled) Log.DebugFormat("START");
+
+ var objects = new List<ObjectInfo>();
+ var accounts = ListSharingAccounts(since);
+ foreach (var account in accounts)
{
- var containerObjects=ListObjects(account.name, container.Name, account.last_modified);
- objects.AddRange(containerObjects);
+ var containers = ListContainers(account.name);
+ foreach (var container in containers)
+ {
+ var containerObjects = ListObjects(account.name, container.Name, account.last_modified);
+ objects.AddRange(containerObjects);
+ }
}
+ if (Log.IsDebugEnabled) Log.DebugFormat("END");
+ return objects;
}
- return objects;
}
public void ShareObject(string account, string container, string objectName, string shareTo, bool read, bool write)
throw new ArgumentNullException("shareTo");
Contract.EndContractBlock();
- using (var client = new RestClient(_baseClient))
+ using (log4net.ThreadContext.Stacks["Share"].Push("Share Object"))
{
-
- client.BaseAddress = GetAccountUrl(account);
+ if (Log.IsDebugEnabled) Log.DebugFormat("START");
+
+ using (var client = new RestClient(_baseClient))
+ {
- client.Parameters.Clear();
- client.Parameters.Add("format", "json");
+ client.BaseAddress = GetAccountUrl(account);
- string permission = "";
- if (write)
- permission = String.Format("write={0}", shareTo);
- else if (read)
- permission=String.Format("read={0}", shareTo);
- client.Headers.Add("X-Object-Sharing",permission);
-
- var content = client.DownloadStringWithRetry(container, 3);
+ client.Parameters.Clear();
+ client.Parameters.Add("format", "json");
+
+ string permission = "";
+ if (write)
+ permission = String.Format("write={0}", shareTo);
+ else if (read)
+ permission = String.Format("read={0}", shareTo);
+ client.Headers.Add("X-Object-Sharing", permission);
- client.AssertStatusOK("ShareObject failed");
+ var content = client.DownloadStringWithRetry(container, 3);
- //If the result is empty, return an empty list,
- var infos = String.IsNullOrWhiteSpace(content)
- ? new List<ObjectInfo>()
- //Otherwise deserialize the object list into a list of ObjectInfos
- : JsonConvert.DeserializeObject<IList<ObjectInfo>>(content);
+ client.AssertStatusOK("ShareObject failed");
- Trace.TraceInformation("[END] ListObjects");
+ //If the result is empty, return an empty list,
+ var infos = String.IsNullOrWhiteSpace(content)
+ ? new List<ObjectInfo>()
+ //Otherwise deserialize the object list into a list of ObjectInfos
+ : JsonConvert.DeserializeObject<IList<ObjectInfo>>(content);
+
+ if (Log.IsDebugEnabled) Log.DebugFormat("END");
+ }
}
-
+
}
throw new ArgumentNullException("container");
Contract.EndContractBlock();
- Trace.TraceInformation("[START] ListObjects");
-
- using (var client = new RestClient(_baseClient))
+ using (log4net.ThreadContext.Stacks["Objects"].Push("List"))
{
- if (!String.IsNullOrWhiteSpace(account))
- client.BaseAddress = GetAccountUrl(account);
+ if (Log.IsDebugEnabled) Log.DebugFormat("START");
- client.Parameters.Clear();
- client.Parameters.Add("format", "json");
- client.IfModifiedSince = since;
- var content = client.DownloadStringWithRetry(container, 3);
+ using (var client = new RestClient(_baseClient))
+ {
+ if (!String.IsNullOrWhiteSpace(account))
+ client.BaseAddress = GetAccountUrl(account);
- client.AssertStatusOK("ListObjects failed");
+ client.Parameters.Clear();
+ client.Parameters.Add("format", "json");
+ client.IfModifiedSince = since;
+ var content = client.DownloadStringWithRetry(container, 3);
- //If the result is empty, return an empty list,
- var infos=String.IsNullOrWhiteSpace(content)
- ? new List<ObjectInfo>()
- //Otherwise deserialize the object list into a list of ObjectInfos
- : JsonConvert.DeserializeObject<IList<ObjectInfo>>(content);
+ client.AssertStatusOK("ListObjects failed");
- foreach (var info in infos)
- {
- info.Container = container;
- info.Account = account;
+ //If the result is empty, return an empty list,
+ var infos = String.IsNullOrWhiteSpace(content)
+ ? new List<ObjectInfo>()
+ //Otherwise deserialize the object list into a list of ObjectInfos
+ : JsonConvert.DeserializeObject<IList<ObjectInfo>>(content);
+
+ foreach (var info in infos)
+ {
+ info.Container = container;
+ info.Account = account;
+ }
+ if (Log.IsDebugEnabled) Log.DebugFormat("START");
+ return infos;
}
- Trace.TraceInformation("[END] ListObjects");
- return infos;
}
}
throw new ArgumentNullException("folder");
Contract.EndContractBlock();
- Trace.TraceInformation("[START] ListObjects");
-
- using (var client = new RestClient(_baseClient))
+ using (log4net.ThreadContext.Stacks["Objects"].Push("List"))
{
- if (!String.IsNullOrWhiteSpace(account))
- client.BaseAddress = GetAccountUrl(account);
+ if (Log.IsDebugEnabled) Log.DebugFormat("START");
- client.Parameters.Clear();
- client.Parameters.Add("format", "json");
- client.Parameters.Add("path", folder);
- client.IfModifiedSince = since;
- var content = client.DownloadStringWithRetry(container, 3);
- client.AssertStatusOK("ListObjects failed");
+ using (var client = new RestClient(_baseClient))
+ {
+ if (!String.IsNullOrWhiteSpace(account))
+ client.BaseAddress = GetAccountUrl(account);
- var infos = JsonConvert.DeserializeObject<IList<ObjectInfo>>(content);
+ client.Parameters.Clear();
+ client.Parameters.Add("format", "json");
+ client.Parameters.Add("path", folder);
+ client.IfModifiedSince = since;
+ var content = client.DownloadStringWithRetry(container, 3);
+ client.AssertStatusOK("ListObjects failed");
- Trace.TraceInformation("[END] ListObjects");
- return infos;
+ var infos = JsonConvert.DeserializeObject<IList<ObjectInfo>>(content);
+
+ if (Log.IsDebugEnabled) Log.DebugFormat("END");
+ return infos;
+ }
}
}
throw new ArgumentNullException("container", "The container property can't be empty");
Contract.EndContractBlock();
- using (var client = new RestClient(_baseClient))
+ using (log4net.ThreadContext.Stacks["Containters"].Push("Exists"))
{
- if (!String.IsNullOrWhiteSpace(account))
- client.BaseAddress = GetAccountUrl(account);
+ if (Log.IsDebugEnabled) Log.DebugFormat("START");
- client.Parameters.Clear();
- client.Head(container, 3);
-
- switch (client.StatusCode)
+ using (var client = new RestClient(_baseClient))
{
- case HttpStatusCode.OK:
- case HttpStatusCode.NoContent:
- return true;
- case HttpStatusCode.NotFound:
- return false;
- default:
- throw CreateWebException("ContainerExists", client.StatusCode);
+ if (!String.IsNullOrWhiteSpace(account))
+ client.BaseAddress = GetAccountUrl(account);
+
+ client.Parameters.Clear();
+ client.Head(container, 3);
+
+ bool result;
+ switch (client.StatusCode)
+ {
+ case HttpStatusCode.OK:
+ case HttpStatusCode.NoContent:
+ result=true;
+ break;
+ case HttpStatusCode.NotFound:
+ result=false;
+ break;
+ default:
+ throw CreateWebException("ContainerExists", client.StatusCode);
+ }
+ if (Log.IsDebugEnabled) Log.DebugFormat("END");
+
+ return result;
}
+
}
}
throw new ArgumentNullException("objectName", "The objectName property can't be empty");
Contract.EndContractBlock();
- using (var client = new RestClient(_baseClient))
- {
- if (!String.IsNullOrWhiteSpace(account))
- client.BaseAddress = GetAccountUrl(account);
- try
+ using (log4net.ThreadContext.Stacks["Objects"].Push("GetObjectInfo"))
+ {
+
+ using (var client = new RestClient(_baseClient))
{
- client.Parameters.Clear();
+ if (!String.IsNullOrWhiteSpace(account))
+ client.BaseAddress = GetAccountUrl(account);
+ try
+ {
+ client.Parameters.Clear();
- client.Head(container + "/" + objectName, 3);
+ client.Head(container + "/" + objectName, 3);
- if (client.TimedOut)
- return ObjectInfo.Empty;
+ if (client.TimedOut)
+ return ObjectInfo.Empty;
- switch (client.StatusCode)
+ switch (client.StatusCode)
+ {
+ case HttpStatusCode.OK:
+ case HttpStatusCode.NoContent:
+ var keys = client.ResponseHeaders.AllKeys.AsQueryable();
+ var tags = (from key in keys
+ where key.StartsWith("X-Object-Meta-")
+ let name = key.Substring(14)
+ select new {Name = name, Value = client.ResponseHeaders[name]})
+ .ToDictionary(t => t.Name, t => t.Value);
+ var extensions = (from key in keys
+ where key.StartsWith("X-Object-") && !key.StartsWith("X-Object-Meta-")
+ select new {Name = key, Value = client.ResponseHeaders[key]})
+ .ToDictionary(t => t.Name, t => t.Value);
+ var info = new ObjectInfo
+ {
+ Name = objectName,
+ Hash = client.GetHeaderValue("ETag"),
+ Content_Type = client.GetHeaderValue("Content-Type"),
+ Tags = tags,
+ Last_Modified = client.LastModified,
+ Extensions = extensions
+ };
+ return info;
+ case HttpStatusCode.NotFound:
+ return ObjectInfo.Empty;
+ default:
+ throw new WebException(
+ String.Format("[FAIL] GetObjectInfo for {0} failed with unexpected status code {1}",
+ objectName, client.StatusCode));
+ }
+
+ }
+ catch (RetryException)
{
- case HttpStatusCode.OK:
- case HttpStatusCode.NoContent:
- var keys = client.ResponseHeaders.AllKeys.AsQueryable();
- var tags = (from key in keys
- where key.StartsWith("X-Object-Meta-")
- let name = key.Substring(14)
- select new {Name = name, Value = client.ResponseHeaders[name]})
- .ToDictionary(t => t.Name, t => t.Value);
- var extensions = (from key in keys
- where key.StartsWith("X-Object-") && !key.StartsWith("X-Object-Meta-")
- select new {Name = key, Value = client.ResponseHeaders[key]})
- .ToDictionary(t => t.Name, t => t.Value);
- var info = new ObjectInfo
- {
- Name = objectName,
- Hash = client.GetHeaderValue("ETag"),
- Content_Type = client.GetHeaderValue("Content-Type"),
- Tags = tags,
- Last_Modified = client.LastModified,
- Extensions = extensions
- };
- return info;
- case HttpStatusCode.NotFound:
- return ObjectInfo.Empty;
- default:
- throw new WebException(
- String.Format("[FAIL] GetObjectInfo for {0} failed with unexpected status code {1}",
- objectName, client.StatusCode));
+ Log.WarnFormat("[RETRY FAIL] GetObjectInfo for {0} failed.");
+ return ObjectInfo.Empty;
}
-
- }
- catch(RetryException)
- {
- Trace.TraceWarning("[RETRY FAIL] GetObjectInfo for {0} failed.");
- return ObjectInfo.Empty;
- }
- catch(WebException e)
- {
- Trace.TraceError(
- String.Format("[FAIL] GetObjectInfo for {0} failed with unexpected status code {1}",
- objectName, client.StatusCode), e);
- throw;
- }
+ catch (WebException e)
+ {
+ Log.Error(
+ String.Format("[FAIL] GetObjectInfo for {0} failed with unexpected status code {1}",
+ objectName, client.StatusCode), e);
+ throw;
+ }
+ }
}
}
var uri = builder.Uri;
//Download progress is reported to the Trace log
- Trace.TraceInformation("[GET] START {0}", objectName);
+ Log.InfoFormat("[GET] START {0}", objectName);
client.DownloadProgressChanged += (sender, args) =>
- Trace.TraceInformation("[GET PROGRESS] {0} {1}% {2} of {3}",
+ Log.InfoFormat("[GET PROGRESS] {0} {1}% {2} of {3}",
fileName, args.ProgressPercentage,
args.BytesReceived,
args.TotalBytesToReceive);
//And report failure or completion
if (download.IsFaulted)
{
- Trace.TraceError("[GET] FAIL for {0} with \r{1}", objectName,
+ Log.ErrorFormat("[GET] FAIL for {0} with \r{1}", objectName,
download.Exception);
}
else
{
- Trace.TraceInformation("[GET] END {0}", objectName);
+ Log.InfoFormat("[GET] END {0}", objectName);
}
});
}
catch (Exception exc)
{
- Trace.TraceError("[GET] END {0} with {1}", objectName, exc);
+ Log.ErrorFormat("[GET] END {0} with {1}", objectName, exc);
throw;
}
//Any other status code is unexpected but there was no exception. We can probably continue processing
else
{
- Trace.TraceWarning("Unexcpected status code when putting map: {0} - {1}",client.StatusCode,client.StatusDescription);
+ Log.WarnFormat("Unexcpected status code when putting map: {0} - {1}",client.StatusCode,client.StatusDescription);
}
return empty;
});
client.Headers[HttpRequestHeader.ContentType] = "application/octet-stream";
- Trace.TraceInformation("[BLOCK POST] START");
+ Log.InfoFormat("[BLOCK POST] START");
client.UploadProgressChanged += (sender, args) =>
- Trace.TraceInformation("[BLOCK POST PROGRESS] {0}% {1} of {2}",
+ Log.InfoFormat("[BLOCK POST PROGRESS] {0}% {1} of {2}",
args.ProgressPercentage, args.BytesSent,
args.TotalBytesToSend);
client.UploadFileCompleted += (sender, args) =>
- Trace.TraceInformation("[BLOCK POST PROGRESS] Completed ");
+ Log.InfoFormat("[BLOCK POST PROGRESS] Completed ");
//Send the block
if (upload.IsFaulted)
{
var exception = upload.Exception.InnerException;
- Trace.TraceError("[BLOCK POST] FAIL with \r{0}", exception);
+ Log.ErrorFormat("[BLOCK POST] FAIL with \r{0}", exception);
throw exception;
}
- Trace.TraceInformation("[BLOCK POST] END");
+ Log.InfoFormat("[BLOCK POST] END");
});
return uploadTask;
}
//And report failure or completion
if (download.IsFaulted)
{
- Trace.TraceError("[GET HASH] FAIL for {0} with \r{1}", objectName,
+ Log.ErrorFormat("[GET HASH] FAIL for {0} with \r{1}", objectName,
download.Exception);
throw download.Exception;
}
//The server will return an empty string if the file is empty
var json = download.Result;
var treeHash = TreeHash.Parse(json);
- Trace.TraceInformation("[GET HASH] END {0}", objectName);
+ Log.InfoFormat("[GET HASH] END {0}", objectName);
return treeHash;
});
}
catch (Exception exc)
{
- Trace.TraceError("[GET HASH] END {0} with {1}", objectName, exc);
+ Log.ErrorFormat("[GET HASH] END {0} with {1}", objectName, exc);
throw;
}
client.Headers.Add("ETag", etag);
- Trace.TraceInformation("[PUT] START {0}", objectName);
+ Log.InfoFormat("[PUT] START {0}", objectName);
client.UploadProgressChanged += (sender, args) =>
{
- Trace.TraceInformation("[PUT PROGRESS] {0} {1}% {2} of {3}", fileName, args.ProgressPercentage, args.BytesSent, args.TotalBytesToSend);
+ using (log4net.ThreadContext.Stacks["PUT"].Push("Progress"))
+ {
+ Log.InfoFormat("{0} {1}% {2} of {3}", fileName, args.ProgressPercentage,
+ args.BytesSent, args.TotalBytesToSend);
+ }
};
client.UploadFileCompleted += (sender, args) =>
{
- Trace.TraceInformation("[PUT PROGRESS] Completed {0}", fileName);
+ using (log4net.ThreadContext.Stacks["PUT"].Push("Progress"))
+ {
+ Log.InfoFormat("Completed {0}", fileName);
+ }
};
return client.UploadFileTask(uri, "PUT", fileName)
.ContinueWith(upload=>
if (upload.IsFaulted)
{
var exc = upload.Exception.InnerException;
- Trace.TraceError("[PUT] FAIL for {0} with \r{1}",objectName,exc);
+ Log.ErrorFormat("[PUT] FAIL for {0} with \r{1}",objectName,exc);
throw exc;
}
else
- Trace.TraceInformation("[PUT] END {0}", objectName);
+ Log.InfoFormat("[PUT] END {0}", objectName);
});
}
catch (Exception exc)
{
- Trace.TraceError("[PUT] END {0} with {1}", objectName, exc);
+ Log.ErrorFormat("[PUT] END {0} with {1}", objectName, exc);
throw;
}
<CodeContractsAnalysisWarningLevel>2</CodeContractsAnalysisWarningLevel>
</PropertyGroup>
<ItemGroup>
+ <Reference Include="log4net">
+ <HintPath>..\Libraries\log4net.dll</HintPath>
+ </Reference>
<Reference Include="System" />
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Core" />
using System.Net;
using System.Runtime.Serialization;
using System.Threading.Tasks;
+using log4net;
namespace Pithos.Network
{
}
}
+ private static readonly ILog Log = LogManager.GetLogger("RestClient");
+
+
[ContractInvariantMethod]
private void Invariants()
{
protected override WebResponse GetWebResponse(WebRequest request, IAsyncResult result)
{
- var response = (HttpWebResponse) base.GetWebResponse(request, result);
- StatusCode=response.StatusCode;
- StatusDescription=response.StatusDescription;
- return response;
+ return ProcessResponse(()=>base.GetWebResponse(request, result));
}
- private readonly List<HttpStatusCode> _allowedStatusCodes=new List<HttpStatusCode>{HttpStatusCode.NotModified};
- public List<HttpStatusCode> AllowedStatusCodes
+ protected override WebResponse GetWebResponse(WebRequest request)
{
- get
- {
- return _allowedStatusCodes;
- }
+ return ProcessResponse(() => base.GetWebResponse(request));
}
- protected override WebResponse GetWebResponse(WebRequest request)
+ private WebResponse ProcessResponse(Func<WebResponse> getResponse)
{
try
- {
- var response = (HttpWebResponse)base.GetWebResponse(request);
+ {
+ var response = (HttpWebResponse)getResponse();
StatusCode = response.StatusCode;
- LastModified=response.LastModified;
- StatusDescription = response.StatusDescription;
+ LastModified = response.LastModified;
+ StatusDescription = response.StatusDescription;
return response;
}
catch (WebException exc)
- {
- if (exc.Response!=null)
+ {
+ if (exc.Response != null)
{
var response = (exc.Response as HttpWebResponse);
if (AllowedStatusCodes.Contains(response.StatusCode))
if (exc.Response.ContentLength > 0)
{
string content = GetContent(exc.Response);
- Trace.TraceError(content);
+ Log.ErrorFormat(content);
}
}
throw;
}
}
+ private readonly List<HttpStatusCode> _allowedStatusCodes=new List<HttpStatusCode>{HttpStatusCode.NotModified};
+ public List<HttpStatusCode> AllowedStatusCodes
+ {
+ get
+ {
+ return _allowedStatusCodes;
+ }
+ }
+
public DateTime LastModified { get; private set; }
private static string GetContent(WebResponse webResponse)
var exc = ex.InnerException;
if (exc is RetryException)
{
- Trace.TraceError("[{0}] RETRY FAILED for {1} after {2} retries",method,address,retries);
+ Log.ErrorFormat("[{0}] RETRY FAILED for {1} after {2} retries",method,address,retries);
}
else
{
- Trace.TraceError("[{0}] FAILED for {1} with \n{2}", method, address, exc);
+ Log.ErrorFormat("[{0}] FAILED for {1} with \n{2}", method, address, exc);
}
throw;
}
catch(Exception ex)
{
- Trace.TraceError("[{0}] FAILED for {1} with \n{2}", method, address, ex);
+ Log.ErrorFormat("[{0}] FAILED for {1} with \n{2}", method, address, ex);
throw;
}
}
private static void TraceStart(string method, string actualAddress)
{
- Trace.WriteLine(String.Format("[{0}] {1} {2}", method, DateTime.Now, actualAddress));
+ Log.InfoFormat("[{0}] {1} {2}", method, DateTime.Now, actualAddress);
}
private string GetActualAddress(string address)
TimedOut = true;
if (retryCount == 0)
{
- Trace.TraceError("[ERROR] Timed out too many times. \n{0}\n",e);
+ Log.ErrorFormat("[ERROR] Timed out too many times. \n{0}\n",e);
tcs.SetException(new RetryException("Timed out too many times.", e));
}
else
{
- Trace.TraceError(
+ Log.ErrorFormat(
"[RETRY] Timed out after {0} ms. Will retry {1} more times\n{2}", Timeout,
retryCount, e);
Retry(original, retryCount - 1, tcs);
}
catch (Exception exc)
{
- Trace.TraceError("Composition Error: {0}",exc);
+ Log.ErrorFormat("Composition Error: {0}",exc);
throw;
}
}
if (!NativeMethods.InsertMenu(hMenu, idCmdFirst, MF.MF_SEPARATOR | MF.MF_BYPOSITION, 0, String.Empty))
{
- Trace.TraceError("Error adding separator 1\r\n{0}", Marshal.GetLastWin32Error());
+ Log.ErrorFormat("Error adding separator 1\r\n{0}", Marshal.GetLastWin32Error());
return Marshal.GetHRForLastWin32Error();
}
sep.fType = MFT.MFT_SEPARATOR;*/
if (!NativeMethods.InsertMenu(hMenu, (uint)_items.Values.Count + idCmdFirst+1,MF.MF_SEPARATOR|MF.MF_BYPOSITION, 0, String.Empty))
{
- Trace.TraceError("Error adding separator 1\r\n{0}", Marshal.GetLastWin32Error());
+ Log.ErrorFormat("Error adding separator 1\r\n{0}", Marshal.GetLastWin32Error());
return Marshal.GetHRForLastWin32Error();
}
catch (Exception ex)
{
//Log and rethrow
- Trace.TraceError("Failed to unregister overlay {0}:{1} with error {2}",iconName,type.GUID,ex.Message);
+ Log.ErrorFormat("Failed to unregister overlay {0}:{1} with error {2}",iconName,type.GUID,ex.Message);
throw;
}
}
}
catch (Exception exc)
{
- Trace.TraceError("[ERROR] while loading settings:\r{0}",exc);
+ Log.ErrorFormat("[ERROR] while loading settings:\r{0}",exc);
_settings = new Lazy<IPithosSettings>(LoadSettings);
}
return null;
}
catch (Exception exc)
{
- Trace.TraceError("[ERROR] retrieving overlay status for {0}:\r{1}",path,exc);
+ Log.ErrorFormat("[ERROR] retrieving overlay status for {0}:\r{1}",path,exc);
return FileOverlayStatus.Unversioned;
}
}