Revision 0c02aa65

b/trunk/Pithos.Client.WPF/App.xaml.cs
18 18
    {
19 19
        public App()
20 20
        {
21
            var extensionController = new ShellExtensionController();
21
            //var extensionController = new ShellExtensionController();
22 22
            //extensionController.RegisterExtensions();
23 23
            
24 24

  
b/trunk/Pithos.Client.WPF/Configuration/PithosSettings.cs
18 18
    using System.Text;
19 19

  
20 20
    [Export(typeof(IPithosSettings))]
21
    [Export]
21 22
    public class PithosSettings :  IPithosSettings
22 23
    {
23 24
        public bool UseDefaultProxy
......
112 113
            set { Settings.Default.ExtensionsActivated = value; }
113 114
        }
114 115

  
116
        public bool ShowDesktopNotifications
117
        {
118
            get { return Settings.Default.ShowDesktopNotifications; }
119
            set { Settings.Default.ShowDesktopNotifications = value; }
120
        }
115 121
/*
116 122
        public override IEnumerable<string> GetDynamicMemberNames()
117 123
        {
b/trunk/Pithos.Client.WPF/Pithos.Client.WPF.csproj
117 117
      <DependentUpon>FilePropertiesView.xaml</DependentUpon>
118 118
    </Compile>
119 119
    <Compile Include="FilePropertiesViewModel.cs" />
120
    <Compile Include="Notification.cs" />
121
    <Compile Include="PithosAccount.cs" />
120 122
    <Compile Include="PithosCommand.cs" />
121 123
    <Compile Include="PreferencesView.xaml.cs">
122 124
      <DependentUpon>PreferencesView.xaml</DependentUpon>
123 125
    </Compile>
124 126
    <Compile Include="PreferencesViewModel.cs" />
125
    <Compile Include="ShellExtensionController.cs" />
126 127
    <Compile Include="TaskbarViewModel.cs" />
127 128
    <Page Include="FilePropertiesView.xaml">
128 129
      <SubType>Designer</SubType>
......
188 189
    <Resource Include="Images\TrayInSynch.ico" />
189 190
  </ItemGroup>
190 191
  <ItemGroup>
192
    <ProjectReference Include="..\Libraries\ParallelExtensionsExtras\ParallelExtensionsExtras.csproj">
193
      <Project>{C45218F8-09E7-4F57-85BC-5D8D2AC736A3}</Project>
194
      <Name>ParallelExtensionsExtras</Name>
195
    </ProjectReference>
191 196
    <ProjectReference Include="..\NotifyIconWpf\NotifyIconWpf.csproj">
192 197
      <Project>{7AC63864-7638-41C4-969C-D3197EF2BED9}</Project>
193 198
      <Name>NotifyIconWpf</Name>
......
204 209
      <Project>{C8E2BC8B-C7F1-4222-855C-4B04A57FFDFD}</Project>
205 210
      <Name>Pithos.Network</Name>
206 211
    </ProjectReference>
207
    <ProjectReference Include="..\Pithos.ShellExtensions\Pithos.ShellExtensions.csproj">
208
      <Project>{240B432F-1030-4623-BCC3-FF351D6C1B63}</Project>
209
      <Name>Pithos.ShellExtensions</Name>
210
    </ProjectReference>
211 212
  </ItemGroup>
212 213
  <ItemGroup>
213 214
    <Resource Include="Images\Accounts.png" />
b/trunk/Pithos.Client.WPF/PreferencesView.xaml
102 102
                            </ListBox.ItemTemplate>
103 103
                        </ListBox>
104 104
                        <StackPanel Orientation="Horizontal" Grid.Row="1">
105
                            <Button Name="AddAccount" Content="Add" Style="{StaticResource ButtonStyle}" Width="50"/>
106
                            <Button Name="RemoveAccount" Content="Remove" Style="{StaticResource ButtonStyle}" Width="50"/>
105
                            <Button Name="AddPithosAccount" Content="Add" Style="{StaticResource ButtonStyle}" Width="50"/>
106
                            <Button Name="RemoveAccount" Content="Remove" Style="{StaticResource ButtonStyle}" Width="50"/>                            
107 107
                        </StackPanel>
108 108
                    </Grid>
109
                        <GroupBox Header="Account" Padding="5" Margin="5" Height="190" HorizontalAlignment="Stretch" VerticalAlignment="Top" Width="272">
110
                        <Grid>
109
                    <GroupBox Header="Account" Padding="5" Margin="5" Height="190" HorizontalAlignment="Stretch" VerticalAlignment="Top" Width="272">
110
                            <Grid>
111 111
                            <Grid.ColumnDefinitions>
112 112
                                <ColumnDefinition Width="Auto"/>
113 113
                                <ColumnDefinition Width="91*"/>
......
129 129
                            <Button Name="SelectSyncFolders" Content="Selective Sync" Width="Auto" HorizontalAlignment="Left" Style="{StaticResource ButtonStyle}" Grid.Column="1" Grid.Row="4"/>
130 130
                            
131 131
                        </Grid>
132
                        
132 133
                    </GroupBox>
134
                    
133 135
                </StackPanel>
134 136
            </TabItem>
135 137
            <TabItem VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch">
b/trunk/Pithos.Client.WPF/PreferencesView.xaml.cs
10 10
using System.Windows.Media;
11 11
using System.Windows.Media.Imaging;
12 12
using System.Windows.Shapes;
13
using Caliburn.Micro;
14
using Hardcodet.Wpf.TaskbarNotification;
13 15

  
14 16
namespace Pithos.Client.WPF
15 17
{
......
37 39
        {
38 40
            this.Show();
39 41
            this.Topmost = true;
42

  
43
            
40 44
        }
45

  
41 46
    }
42 47
}
b/trunk/Pithos.Client.WPF/PreferencesViewModel.cs
16 16
using System.Windows;
17 17
using System.Windows.Forms;
18 18
using Caliburn.Micro;
19
using Hardcodet.Wpf.TaskbarNotification;
19 20
using Pithos.Client.WPF.Configuration;
20 21
using Pithos.Core;
21 22
using Pithos.Interfaces;
22
using Pithos.ShellExtensions;
23

  
23 24
using Screen = Caliburn.Micro.Screen;
24 25

  
25 26
namespace Pithos.Client.WPF
......
28 29
    using System.Collections.Generic;
29 30
    using System.Linq;
30 31
    using System.Text;
32
    using System.Threading.Tasks;
31 33

  
32 34
    /// <summary>
33 35
    /// TODO: Update summary.
34 36
    /// </summary>
35 37
    [Export(typeof(IShell))]
36
    public class PreferencesViewModel : Screen, IShell
38
    public class PreferencesViewModel : Screen, IShell, IHandle<Notification>
37 39
    {
38
        
40
        private IEventAggregator _events;
39 41

  
40 42

  
41
        public IPithosSettings Settings { get; set; }
43
        public PithosSettings Settings { get; set; }
42 44

  
43 45

  
44 46
        public PithosMonitor Monitor { get; private set; }
45 47

  
46 48
        public TaskbarViewModel Taskbar { get; set; }
47 49

  
48
        ShellExtensionController _extensionController=new ShellExtensionController();
50
        //ShellExtensionController _extensionController=new ShellExtensionController();
49 51

  
50 52
        [ImportingConstructor]
51
        public PreferencesViewModel(TaskbarViewModel taskbar, IPithosSettings settings, PithosMonitor monitor)
53
        public PreferencesViewModel(IEventAggregator events, TaskbarViewModel taskbar, PithosSettings settings, PithosMonitor monitor)
52 54
        {
55
            _events = events;
56
            _events.Subscribe(this);
57

  
53 58
            DisplayName = "Pithos Preferences";
54 59

  
55 60
            Taskbar=taskbar;
......
65 70
                                      new FileEntry{FileName="Moo",FullPath=@"e:\Pithos\moo"}   ,
66 71
                                      new FileEntry{FileName="Mee",FullPath=@"e:\Pithos\mee"}   
67 72
                                     });
68
            Taskbar.StatusMessage = "In Synch";
69
            Taskbar.UpdateStatus();
73
            Taskbar.StatusMessage = "In Synch";            
70 74
        }
71 75

  
72 76
        protected override void OnViewAttached(object view, object context)
......
81 85
        {
82 86
            var window = (Window)view;
83 87
            window.Hide();
84

  
88
            Taskbar.UpdateStatus();
85 89
            base.OnViewLoaded(view);
86 90
        }
87 91

  
......
189 193
            NotifyOfPropertyChange(()=>Settings);
190 194
        }
191 195

  
196
        public void AddPithosAccount()
197
       {
198
           var task=PithosAccount.RetrieveCredentialsAsync(Settings.PithosSite)
199
               .ContinueWith(t=>
200
                   {                       
201
                       var credentials=t.Result;
202
                       var account = Settings.Accounts.FirstOrDefault(act => act.AccountName == credentials.UserName);
203
                       if (account == null)
204
                       {
205
                           account=new AccountSettings{
206
                               AccountName=credentials.UserName,
207
                               ApiKey=credentials.Password,
208
                               UsePithos=true
209
                           };
210
                           Settings.Accounts.Add(account);
211
                       }
212
                       else
213
                       {
214
                           account.ApiKey=credentials.Password;
215
                       }
216
                       SelectedAccountIndex= Settings.Accounts.IndexOf(account);
217
                       NotifyOfPropertyChange(()=>Settings);
218
                   });
219
            ((Task)task).WaitWithPumping();
220
       }
221

  
192 222
        public void RemoveAccount()
193 223
        {
194 224
            Settings.Accounts.RemoveAll(account => account.AccountName == CurrentAccount.AccountName);
......
215 245

  
216 246
                Settings.ExtensionsActivated = value;
217 247

  
218
                if (value)
219
                    _extensionController.RegisterExtensions();
220
                else
221
                {
222
                    _extensionController.UnregisterExtensions();
223
                }
248
                //if (value)
249
                //    _extensionController.RegisterExtensions();
250
                //else
251
                //{
252
                //    _extensionController.UnregisterExtensions();
253
                //}
224 254
                NotifyOfPropertyChange(() => ExtensionsActivated);
225 255
            }
226 256
        }
......
244 274
                //    _selectedAccountIndex = value;
245 275
                //else
246 276
                //    _selectedAccountIndex = 0;
277
                _selectedAccountIndex = value;
247 278
                NotifyOfPropertyChange(() => CurrentAccount);
248 279
                NotifyOfPropertyChange(() => CanRemoveAccount);
249 280
                NotifyOfPropertyChange(()=>SelectedAccountIndex);
......
267 298
        }
268 299

  
269 300

  
301
        public void Handle(Notification notification)
302
        {
303
            if (!Settings.ShowDesktopNotifications)
304
                return;
305
            BalloonIcon icon = BalloonIcon.None;
306
            switch (notification.Level)
307
            {
308
                case TraceLevel.Error:
309
                    icon = BalloonIcon.Error;
310
                    break;
311
                case TraceLevel.Info:
312
                case TraceLevel.Verbose:
313
                    icon = BalloonIcon.Info;
314
                    break;
315
                case TraceLevel.Warning:
316
                    icon = BalloonIcon.Warning;
317
                    break;
318
                default:
319
                    icon = BalloonIcon.None;
320
                    break;
321
            }
322

  
323
            var tv = (PreferencesView)this.GetView();
324
            tv.TaskbarView.ShowBalloonTip(notification.Title, notification.Message, icon);
325
        }
326

  
270 327
    }
271 328
}
b/trunk/Pithos.Client.WPF/ShellExtensionController.cs
8 8
using System.IO;
9 9
using System.IO.IsolatedStorage;
10 10
using System.Runtime.Serialization;
11
using Pithos.ShellExtensions;
11

  
12 12

  
13 13
namespace Pithos.Client.WPF
14 14
{
b/trunk/Pithos.Client.WPF/TaskbarViewModel.cs
7 7
using System.ComponentModel.Composition;
8 8
using System.Diagnostics;
9 9
using System.IO;
10
using System.Threading.Tasks;
10 11
using System.Windows;
11 12
using Caliburn.Micro;
12 13
using Pithos.Client.WPF.Properties;
......
24 25
    /// TODO: Update summary.
25 26
    /// </summary>
26 27
    [Export]
27
    public class TaskbarViewModel:ViewAware
28
    public class TaskbarViewModel:ViewAware,IStatusNotification
28 29
    {
29 30
        private IStatusChecker _statusChecker;
31
        private IEventAggregator _events;
30 32

  
31 33
        public PithosMonitor Monitor { get; private set; }
32 34

  
......
35 37
        public IScreen Parent { get; set; }
36 38

  
37 39
        [ImportingConstructor]
38
        public TaskbarViewModel(IStatusChecker statusChecker,PithosMonitor monitor,IPithosSettings settings)
40
        public TaskbarViewModel(IEventAggregator events, IStatusChecker statusChecker,PithosMonitor monitor,IPithosSettings settings)
39 41
        {
40 42
            OpenPithosFolderCommand = new PithosCommand(OpenPithosFolder);
41 43
            _statusChecker = statusChecker;
44
            _events = events;            
42 45
            Settings = settings;
43 46
            Monitor = monitor;
47
            Monitor.StatusNotification = this;
48

  
49
            
44 50

  
45 51
            var account=settings.Accounts.FirstOrDefault(act => act.IsActive);
46 52
            if (account != null)
......
167 173
                StatusIcon = String.Format(@"Images/{0}.ico", info.IconName);
168 174
                StatusMessage = String.Format("Pithos 1.0\r\n{0}", info.StatusText);
169 175
            }
176

  
177
            var tv=this.GetView();
178
            _events.Publish(new Notification { Title = "Start", Message = "Start Monitoring", Level = TraceLevel.Info});
170 179
            if (!String.IsNullOrWhiteSpace(Monitor.UserName) &&
171 180
                !String.IsNullOrWhiteSpace(Monitor.ApiKey))
172
                try
173
                {
174
                    Monitor.Start();
175
                }
176
                catch (Exception exc)
177
                {
178
                    MessageBox.Show("An exception occured. Can't start monitoring");
179
                }
181
                Task.Factory.StartNew(() => 
182
                    Monitor.Start())
183
                    .ContinueWith(t =>{
184
                        if (t.IsFaulted)
185
                        {
186
                            
187
                            var message= String.Format("An exception occured. Can't start monitoring\n{0}",t.Exception);
188
                            _events.Publish(new Notification { Title = "Error",Message=message,Level= TraceLevel.Error });
189
                            MessageBox.Show(message);
190
                        }
191
                    });                
192
        }
193

  
194
       
195

  
196
        public void NotifyChange(string status, TraceLevel level=TraceLevel.Info)
197
        {
198
            this.StatusMessage = status;
199
            
200
            _events.Publish(new Notification { Title = "Pithos", Message = status, Level = level });
180 201
        }
181 202
    }
182 203
}
b/trunk/Pithos.Core/FileHashMap.cs
1
using System.Collections.Generic;
2

  
3
public class FileHashMap
4
{
5
    public byte[] Hash { get; set; }
6
    public IEnumerable<byte[]> Hashes { get; set; }
7
}
b/trunk/Pithos.Core/FileState.cs
4 4
// </copyright>
5 5
// -----------------------------------------------------------------------
6 6

  
7
using System.Threading.Tasks;
7 8
using Castle.ActiveRecord;
8 9
using Castle.ActiveRecord.Framework;
9 10
using Pithos.Interfaces;
......
47 48
            get { return _tags; }   
48 49
            set { _tags=value;}
49 50
        }
50
       
51

  
52
        [HasMany(Cascade = ManyRelationCascadeEnum.AllDeleteOrphan, Lazy = true)]
53
        public IList<FileHash> Hashes { get; set; }
54

  
55
        public FileState()
56
        {
57
            
58
        }
59

  
60
        private static int BLOCK_SIZE = 4194304;
61

  
62
        public static Task<FileState> CreateForAsync(string filePath)
63
        {
64
            var fileState = new FileState
65
                                {
66
                                    FilePath = filePath, 
67
                                    OverlayStatus = FileOverlayStatus.Unversioned, 
68
                                    FileStatus = FileStatus.Created
69
                                };
70
            
71
            
72
            return Task.Factory.StartNew(()=> {
73
                    fileState.Checksum = Signature.CalculateHash(fileState.FilePath);
74
                })
75
                .ContinueWith(_=> Signature.CalculateBlockHashesAsync(filePath, BLOCK_SIZE)).Unwrap()
76
                .ContinueWith(t =>
77
                {
78
                    fileState.Hashes = t.Result;
79
                }).ContinueWith(t =>
80
                {
81
                    fileState.HashmapHash = Signature.CalculateHashmapHash(fileState.Hashes);
82
                }).ContinueWith(t=> fileState);
83
            //return fileState;
84
        }
85

  
86
        public byte[] HashmapHash { get; set; }
51 87
    }
52 88

  
53 89
    [ActiveRecord]
......
63 99
        public FileState FileState { get; set; }
64 100

  
65 101
    }
102
    
103
    [ActiveRecord]
104
    public class FileHash : ActiveRecordLinqBase<FileHash>
105
    {
106
        [PrimaryKey]
107
        public string FilePath { get; set; }
108

  
109
        [Property]
110
        public byte[] Value { get; set; }        
111

  
112
        [BelongsTo("FilePath")]
113
        public FileState FileState { get; set; }
114

  
115
    }
66 116

  
67 117

  
68 118
}
b/trunk/Pithos.Core/Pithos.Core.csproj
127 127
    <Reference Include="System.Xml" />
128 128
  </ItemGroup>
129 129
  <ItemGroup>
130
    <Compile Include="FileHashMap.cs" />
130 131
    <Compile Include="FileState.cs" />
131 132
    <Compile Include="IStatusService.cs" />
132 133
    <Compile Include="JobQueue.cs" />
b/trunk/Pithos.Core/PithosMonitor.cs
40 40
        [Import]
41 41
        public ICloudClient CloudListeningClient { get; set; }
42 42

  
43
        public IStatusNotification StatusNotification { get; set; }
44

  
43 45
        public string UserName { get; set; }
44 46
        public string ApiKey { get; set; }
45 47

  
......
57 59
                if (value)
58 60
                {
59 61
                    StatusKeeper.SetPithosStatus(PithosStatus.SyncPaused);
62
                    StatusNotification.NotifyChange("Paused");
60 63
                }
61 64
                else
62 65
                {
63 66
                    StatusKeeper.SetPithosStatus(PithosStatus.InSynch);
67
                    StatusNotification.NotifyChange("In Synch");
64 68
                }
65 69
            }
66 70
        }
......
77 81

  
78 82
        public void Start()
79 83
        {
80

  
84
            StatusNotification.NotifyChange("Starting");
81 85
            if (_cancellationSource != null)
82 86
            {
83 87
                if (!_cancellationSource.IsCancellationRequested)
......
135 139

  
136 140
        private void IndexLocalFiles(string path)
137 141
        {
138
            Trace.TraceInformation("[START] Inxed Local");
142
            StatusNotification.NotifyChange("Indexing Local Files",TraceLevel.Info);
143
            Trace.TraceInformation("[START] Index Local");
139 144
            try
140 145
            {
141 146
                var files =
......
157 162

  
158 163
        private void RestartInterruptedFiles()
159 164
        {
165
            StatusNotification.NotifyChange("Restart processing interrupted files", TraceLevel.Verbose);
160 166
            var interruptedStates = new[] { FileOverlayStatus.Unversioned, FileOverlayStatus.Modified };
161 167
            var filesQuery = from state in FileState.Queryable
162 168
                             where interruptedStates.Contains(state.OverlayStatus)
......
350 356

  
351 357
                                      var uniques =
352 358
                                          onlyLocal.Union(onlyRemote).Union(commonObjects)
353
                                              .Except(_networkActions,new LocalFileComparer());
354
                                      
359
                                              .Except(_networkActions,new LocalFileComparer());                                      
360

  
355 361
                                      _networkActions.AddFromEnumerable(uniques, false);
356 362

  
363
                                      StatusNotification.NotifyChange(String.Format("Processing {0} files", _networkActions.Count));
364

  
357 365
                                      Trace.TraceInformation("[LISTENER] End Processing");
358 366
                                      
359 367
                                  }
......
734 742

  
735 743

  
736 744
    }
745

  
746
    public interface IStatusNotification
747
    {        
748
        void NotifyChange(string status,TraceLevel level=TraceLevel.Info);
749
    }
737 750
}
b/trunk/Pithos.Core/Signature.cs
1
using System;
2
using System.Collections;
3
using System.Collections.Concurrent;
4
using System.Collections.Generic;
1 5
using System.IO;
2 6
using System.Security.Cryptography;
3 7
using System.Text;
8
using System.Threading.Tasks;
9
using System.Linq;
10
using Pithos.Core;
4 11

  
5 12
public static class Signature
6 13
{
......
18 25
        }
19 26
        return hash;
20 27
    }
28

  
29
    /*public static FileHashMap CalculateHashMap(string path, int blockSize)
30
    {
31
        CalculateBlockHashes(path, blockSize)
32
            .ContinueWith(blockTask =>
33
                              {
34
                                  var hashes = blockTask.Result;
35
                                  var hashMapHash = CalculateHashmapHash(hashes);
36
                                  return new FileHashMap {Hash = hashMapHash, Hashes = hashes};
37
                              });
38
    }*/
39

  
40
    public static Task<IList<FileHash>> CalculateBlockHashesAsync(string path, int blockSize)
41
    {
42
        var hashMap = new ConcurrentQueue<FileHash>();
43
        var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 4096, true);
44
        
45
            return stream.ReadBuffersAsync(blockSize, (buffer, read) =>
46
            {
47
                using (var hasher = SHA256.Create())
48
                {
49
                    var hash = hasher.ComputeHash(buffer, 0, read);
50
                    hashMap.Enqueue(new FileHash{FilePath=path,Value=hash});
51
                }
52
            }).ContinueWith(t=>
53
                                {
54
                                    stream.Close();
55
                                    return (IList<FileHash>)hashMap.ToList();
56
                                });                
57
    }
58
    //I'd rather return an enumerable of hash calculation tasks, each of which can
59
    //be use to further store the hashes to storage without first creating the list of hashes
60

  
61
    /* //Or I could pass an action object, just like ReadBuffers does
62
     Task.Factory.Iterate(HashMapIterator(stream, blockSize,hashMap.Enqueue))
63
         .ContinueWith(t=>
64
                           {
65
                               SHA256.Create();
66
                           });*/
67
            
68

  
69

  
70
    public static byte[] CalculateHashmapHash(IList<FileHash> hashMap )
71
    {
72
        using (var stream = new MemoryStream())
73
        using(var hasher=SHA256.Create())
74
        {
75
            foreach (var hash in hashMap)
76
            {
77
                stream.Write(hash.Value, 0, hash.Value.Length);
78
            }
79
            return hasher.ComputeHash(stream);
80
        }
81
    }
82

  
83
    public static IEnumerable<byte[]> HashMapLinq(string path, int blockSize)
84
    {
85
        using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 4096, true))
86
        {
87

  
88
            var query = from block in stream.GetIterator(blockSize).AsParallel().AsOrdered()
89
                        select block;  
90
            
91
            return query;
92
        }
93
    }
94
    
95
    public class Block
96
    {
97
        public int Offset { get; set; }
98
        public byte[] Data { get; set; }
99
    }
100

  
101
    public static IEnumerable<byte[]> GetIterator(this Stream stream,int blockSize)
102
    {        
103
        var buffer = new byte[blockSize];
104
        while(true)
105
        {            
106
            stream.Read(buffer, 0, buffer.Length);            
107
            yield return buffer;
108
        }
109
    }
110

  
111

  
112

  
113
    private static IEnumerable<Task> HashMapIterator(Stream input, int bufferSize,Action<byte[]> hashAvailable )
114
    {
115
        // Create a buffer that will be used over and over
116
        var buffer = new byte[bufferSize];
117

  
118
        using (var hasher = SHA256.Create())
119
        {
120
            // Until there's no more data
121
            while (true)
122
            {
123
                // Asynchronously read a buffer and yield until the operation completes
124
                var readTask = input.ReadAsync(buffer, 0, buffer.Length);
125
                yield return readTask;
126

  
127
                // If there's no more data in the stream, we're done.
128
                if (readTask.Result <= 0) break;
129

  
130
                // Otherwise, hand the data off to the delegate
131
                var hashTask = Task.Factory.StartNew(() => hasher.ComputeHash(buffer, 0, readTask.Result));
132
                yield return hashTask;
133
                hashAvailable(hashTask.Result);
134
            }
135
        }
136
    }
137

  
21 138
}
b/trunk/Pithos.Core/StatusKeeper.cs
79 79

  
80 80
        public IEnumerable<string> StoreUnversionedFiles(ParallelQuery<string> paths)
81 81
        {            
82
            var existingFiles = from state in  FileState.Queryable
83
                                    select state.FilePath;
84

  
85
            var newFiles = (from file in paths.Except(existingFiles.AsParallel())
86
                            select new FileState
87
                                       {
88
                                           FilePath = file,
89
                                           OverlayStatus = FileOverlayStatus.Unversioned,
90
                                           FileStatus=FileStatus.Created,     
91
                                           Checksum=Signature.CalculateHash(file)
92
                                       }
93
                           );
82
            var existingFiles = (from state in  FileState.Queryable
83
                                    select state.FilePath).ToList();
84

  
85
            var newFiles = paths.Except(existingFiles.AsParallel());//(from file in paths.Except(existingFiles.AsParallel())
86
                            //select FileState.FromPathAsync(file)
87
                           //);
94 88
            
95
            //var files=new ConcurrentBag<string>();
96
            newFiles.ForAll(state=> _statusUpdateQueue.Add(state.Save));
89
            //var files=new ConcurrentBag<string>();            
90
            newFiles.ForAll(file=>  
91
                FileState.CreateForAsync(file)
92
                .ContinueWith(state=>_statusUpdateQueue.Add(state.Result.Save)));
97 93

  
98
            return newFiles.Select(state => state.FilePath);// files.GetConsumingEnumerable();
94
            return newFiles;//.Select(state => state);// files.GetConsumingEnumerable();
99 95

  
100 96
        }
101 97

  
......
147 143

  
148 144

  
149 145
        ConcurrentDictionary<string,NetworkState> _networkState=new ConcurrentDictionary<string, NetworkState>();
146
        private int BLOCK_SIZE = 4194304;
150 147

  
151 148
        public void SetNetworkState(string path,NetworkState state)
152 149
        {
b/trunk/Pithos.Network/PithosClient.cs
66 66
        protected override WebRequest GetWebRequest(Uri address)
67 67
        {
68 68
            TimedOut = false;
69
            HttpWebRequest request = base.GetWebRequest(address) as HttpWebRequest;
69
            var webRequest = base.GetWebRequest(address);
70
            var request = webRequest as HttpWebRequest;
70 71
            request.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
71 72
            if(Timeout>0)
72 73
                request.Timeout = Timeout;
......
278 279
                throw new WebException(String.Format("{0} with code {1} - {2}", message, StatusCode, StatusDescription));
279 280
        }
280 281

  
281
        /*private Func<T> Retry<T>(Func< T> original, int retryCount)
282
        {
283
            return () =>
284
            {
285
                while (true)
286
                {
287
                    try
288
                    {
289
                        return original();
290
                    }
291
                    catch (WebException e)
292
                    {
293
                        var statusCode = ((HttpWebResponse)e.Response).StatusCode;
294
                        this.StatusCode = statusCode;
295

  
296
                        switch (e.Status)
297
                        {
298
                            case WebExceptionStatus.Timeout:
299 282

  
300
                                TimedOut = true;
301
                                if (retryCount == 0)
302
                                {
303
                                    Trace.TraceError("[ERROR] Timed out too many times. {0}\n", e);
304
                                    throw new RetryException("Timed out too many times.", e);
305
                                }
306
                                retryCount--;
307
                                Trace.TraceError(
308
                                    "[RETRY] Timed out after {0} ms. Will retry {1} more times\n{2}", Timeout,
309
                                    retryCount, e);
310

  
311
                                break;
312
                            case WebExceptionStatus.ProtocolError:
313
                                switch (statusCode)
314
                                {
315
                                    case HttpStatusCode.NotFound:
316
                                        {
317
                                            return default(T);
318
                                        }
319
                                    case HttpStatusCode.ServiceUnavailable:
320
                                        {
321

  
322
                                            TimedOut = false;
323
                                            if (retryCount == 0)
324
                                            {
325
                                                Trace.TraceError("[ERROR] Failed too many times. {0}\n", e);
326
                                                throw new RetryException("Failed too many times.", e);
327
                                            }
328
                                            retryCount--;
329
                                            Trace.TraceError(
330
                                                "[RETRY] Failed due to 503. Will retry {0} more times\n{1}", retryCount, e);
331
                                            break;
332
                                        }
333
                                    default:
334
                                        throw;
335
                                }
336
                                break;
337
                            default:
338
                                throw;
339
                        }
340
                    }
341
                }
342
            };
343
        }*/
344
        
345
        private Task<T> Retry<T>(Func< T> original, int retryCount)
283
        private Task<T> Retry<T>(Func<T> original, int retryCount, TaskCompletionSource<T> tcs = null)
346 284
        {
347
            return Task.Factory.StartNew(() => original()).ContinueWith(_original =>
285
            if (tcs == null)
286
                tcs = new TaskCompletionSource<T>();
287
            Task.Factory.StartNew(original).ContinueWith(_original =>
348 288
                {
349
                    if(_original.IsFaulted )
289
                    if (!_original.IsFaulted)
290
                        tcs.SetFromTask(_original);
291
                    else 
350 292
                    {
351 293
                        var e = _original.Exception.InnerException;
352
                        if (e is WebException)
294
                        var we = (e as WebException);
295
                        if (we==null)
296
                            tcs.SetException(e);
297
                        else
353 298
                        {
354
                            var we = (e as WebException);
355

  
356
                            var statusCode = HttpStatusCode.RequestTimeout;
357
                            if (we.Response != null)
358
                            {                                
359
                                statusCode = ((HttpWebResponse) we.Response).StatusCode;
360
                                this.StatusCode = statusCode;
361
                            }
362

  
363
                            if (we.Status==WebExceptionStatus.Timeout || 
364
                                (we.Status==WebExceptionStatus.ProtocolError && statusCode==HttpStatusCode.ServiceUnavailable))
299
                            var statusCode = GetStatusCode(we);
300

  
301
                            //Return null for 404
302
                            if (statusCode == HttpStatusCode.NotFound)
303
                                tcs.SetResult(default(T));
304
                            //Retry for timeouts and service unavailable
305
                            else if (we.Status == WebExceptionStatus.Timeout ||
306
                                (we.Status == WebExceptionStatus.ProtocolError && statusCode == HttpStatusCode.ServiceUnavailable))
365 307
                            {
366 308
                                TimedOut = true;
367 309
                                if (retryCount == 0)
368 310
                                {
369 311
                                    Trace.TraceError("[ERROR] Timed out too many times. {0}\n", e);
370
                                    throw new RetryException("Timed out too many times.", e);
312
                                    tcs.SetException(new RetryException("Timed out too many times.", e));                                    
313
                                }
314
                                else
315
                                {
316
                                    Trace.TraceError(
317
                                        "[RETRY] Timed out after {0} ms. Will retry {1} more times\n{2}", Timeout,
318
                                        retryCount, e);
319
                                    Retry(original, retryCount - 1, tcs);
371 320
                                }
372
                                Trace.TraceError(
373
                                    "[RETRY] Timed out after {0} ms. Will retry {1} more times\n{2}", Timeout,
374
                                    retryCount, e);
375
                                return Retry(original, retryCount - 1);
376 321
                            }
377

  
378
                            if (statusCode==HttpStatusCode.NotFound)
379
                                return Task<T>.Factory.StartNew(() => default(T));                            
322
                            else
323
                                tcs.SetException(e);
380 324
                        }
381
                        throw e;
382
                    }
383
                    else                    
384
                        return Task<T>.Factory.StartNew(() => _original.Result);
385
                }).Unwrap();
325
                    };
326
                });
327
            return tcs.Task;
386 328
        }
387 329

  
388
       
330
        private HttpStatusCode GetStatusCode(WebException we)
331
        {
332
            var statusCode = HttpStatusCode.RequestTimeout;
333
            if (we.Response != null)
334
            {
335
                statusCode = ((HttpWebResponse) we.Response).StatusCode;
336
                this.StatusCode = statusCode;
337
            }
338
            return statusCode;
339
        }
389 340
    }
390 341

  
391 342
    public class RetryException:Exception
b/trunk/Pithos.sln
49 49
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
50 50
		{240B432F-1030-4623-BCC3-FF351D6C1B63}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
51 51
		{240B432F-1030-4623-BCC3-FF351D6C1B63}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
52
		{240B432F-1030-4623-BCC3-FF351D6C1B63}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
53 52
		{240B432F-1030-4623-BCC3-FF351D6C1B63}.Debug|x86.ActiveCfg = Debug|Any CPU
54 53
		{240B432F-1030-4623-BCC3-FF351D6C1B63}.Release|Any CPU.ActiveCfg = Release|Any CPU
55 54
		{240B432F-1030-4623-BCC3-FF351D6C1B63}.Release|Any CPU.Build.0 = Release|Any CPU

Also available in: Unified diff