Revision 4d301e8e

b/trunk/Pithos.Client.WPF/FilePropertiesView.xaml
1
<UserControl x:Class="Pithos.Client.WPF.FilePropertiesView"
2
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
5
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
6
             mc:Ignorable="d" 
7
             d:DesignHeight="300" d:DesignWidth="300">
8
    <Grid>
9
            
10
    </Grid>
11
</UserControl>
b/trunk/Pithos.Client.WPF/FilePropertiesView.xaml.cs
1
using System;
2
using System.Collections.Generic;
3
using System.Linq;
4
using System.Text;
5
using System.Windows;
6
using System.Windows.Controls;
7
using System.Windows.Data;
8
using System.Windows.Documents;
9
using System.Windows.Input;
10
using System.Windows.Media;
11
using System.Windows.Media.Imaging;
12
using System.Windows.Navigation;
13
using System.Windows.Shapes;
14

  
15
namespace Pithos.Client.WPF
16
{
17
    /// <summary>
18
    /// Interaction logic for FilePropertiesView.xaml
19
    /// </summary>
20
    public partial class FilePropertiesView : UserControl
21
    {
22
        public FilePropertiesView()
23
        {
24
            InitializeComponent();
25
        }
26
    }
27
}
b/trunk/Pithos.Client.WPF/FilePropertiesViewModel.cs
1
// -----------------------------------------------------------------------
2
// <copyright file="FilePropertiesViewModel.cs" company="Microsoft">
3
// TODO: Update copyright text.
4
// </copyright>
5
// -----------------------------------------------------------------------
6

  
7
using System.ComponentModel.Composition;
8
using Caliburn.Micro;
9

  
10
namespace Pithos.Client.WPF
11
{
12
    using System;
13
    using System.Collections.Generic;
14
    using System.Linq;
15
    using System.Text;
16

  
17
    /// <summary>
18
    /// TODO: Update summary.
19
    /// </summary>
20
    [Export(typeof(FilePropertiesViewModel))]
21
    public class FilePropertiesViewModel : Screen, IShell
22
    {
23
    }
24
}
b/trunk/Pithos.Client.WPF/Pithos.Client.WPF.csproj
110 110
    <Compile Include="Caliburn\Micro\Logging\DebugLogger.cs" />
111 111
    <Compile Include="Configuration\PithosSettings.cs" />
112 112
    <Compile Include="FileEntry.cs" />
113
    <Compile Include="FilePropertiesView.xaml.cs">
114
      <DependentUpon>FilePropertiesView.xaml</DependentUpon>
115
    </Compile>
116
    <Compile Include="FilePropertiesViewModel.cs" />
113 117
    <Compile Include="PithosCommand.cs" />
114 118
    <Compile Include="PreferencesView.xaml.cs">
115 119
      <DependentUpon>PreferencesView.xaml</DependentUpon>
......
117 121
    <Compile Include="PreferencesViewModel.cs" />
118 122
    <Compile Include="ShellExtensionController.cs" />
119 123
    <Compile Include="TaskbarViewModel.cs" />
124
    <Page Include="FilePropertiesView.xaml">
125
      <SubType>Designer</SubType>
126
      <Generator>MSBuild:Compile</Generator>
127
    </Page>
120 128
    <Page Include="MainWindow.xaml">
121 129
      <Generator>MSBuild:Compile</Generator>
122 130
      <SubType>Designer</SubType>
b/trunk/Pithos.Core/PithosMonitor.cs
331 331
                                      
332 332
                                      var onlyLocal = from localFile in pithosDir.EnumerateFiles()
333 333
                                                      where !remoteFiles.Contains(localFile.Name.ToLower()) 
334
                                                      select new ListenerAction(CloudActionType.UploadUnconditional, localFile,null);
334
                                                      select new ListenerAction(CloudActionType.UploadUnconditional, localFile,ObjectInfo.Empty);
335 335

  
336 336

  
337 337

  
......
340 340

  
341 341
                                      var onlyRemote = from upFile in remoteObjects
342 342
                                                       where !localNames.Contains(upFile.Name.ToLower())
343
                                                       select new ListenerAction(CloudActionType.DownloadUnconditional,null,upFile);
343
                                                       select new ListenerAction(CloudActionType.DownloadUnconditional,new FileInfo(""), upFile);
344 344

  
345 345

  
346 346
                                      var commonObjects = from  upFile in remoteObjects
......
385 385
                    switch (action.Action)
386 386
                    {
387 387
                        case CloudActionType.UploadUnconditional:
388

  
389 388
                            UploadCloudFile(localFile.Name,localFile.Length,localFile.FullName,action.LocalHash.Value);
390 389
                            break;
391 390
                        case CloudActionType.DownloadUnconditional:
......
552 551

  
553 552
        private void DownloadCloudFile(string container, string fileName, string localPath)
554 553
        {
554
            var state = StatusKeeper.GetNetworkState(fileName);
555
            //Abort if the file is already being uploaded or downloaded
556
            if (state != NetworkState.None)
557
                return;
558

  
555 559
            StatusKeeper.SetNetworkState(localPath,NetworkState.Downloading);
556 560
            CloudClient.GetObject(container, fileName, localPath)
557 561
            .ContinueWith(t=>
......
566 570
        private void UploadCloudFile(string fileName, long fileSize, string path,string hash)
567 571
        {
568 572
            Contract.Requires(!Path.IsPathRooted(fileName));
573
            var state=StatusKeeper.GetNetworkState(fileName);
574
            //Abort if the file is already being uploaded or downloaded
575
            if (state != NetworkState.None)
576
                return;
569 577

  
570 578
            StatusKeeper.SetNetworkState(fileName,NetworkState.Uploading);
571 579
            
......
584 592
                {
585 593
                    this.StatusKeeper.StoreInfo(path,info);
586 594
                }
587
            }
588
            )
595
            })
589 596
            .ContinueWith(t => 
590 597
                this.StatusKeeper.SetFileState(path, FileStatus.Unchanged, FileOverlayStatus.Normal))
591 598
                .ContinueWith(t=>
b/trunk/Pithos.Core/StatusService.cs
29 29
        [Import]
30 30
        public IStatusChecker Checker { get; set; }
31 31

  
32
        [Import]
33
        public PithosMonitor Monitor { get; set; }
34

  
32 35
        public StatusService()
33 36
        {
34 37
            IoC.BuildUp(this);
......
46 49
            return Checker.GetFileOverlayStatus(filePath);
47 50
        }
48 51

  
52
        public void DisplayProperties(string filePath)
53
        {
54
            //Monitor.
55
        }
56

  
49 57
        public PithosSettingsData GetSettings()
50 58
        {
51 59
            var data = new PithosSettingsData(Settings);
b/trunk/Pithos.Network/CloudFilesClient.cs
9 9
using System.Security.Cryptography;
10 10
using System.Text;
11 11
using System.Threading.Tasks;
12
using Hammock;
13
using Hammock.Caching;
14
using Hammock.Retries;
15
using Hammock.Serialization;
16
using Hammock.Tasks;
17
using Hammock.Web;
18 12
using Newtonsoft.Json;
19 13
using Pithos.Interfaces;
14
using WebHeaderCollection = System.Net.WebHeaderCollection;
20 15

  
21 16
namespace Pithos.Network
22 17
{
......
24 19
    public class CloudFilesClient:ICloudClient
25 20
    {
26 21

  
27
        private RestClient _client;
22
        private PithosClient _client;
28 23
        private readonly TimeSpan _shortTimeout = TimeSpan.FromSeconds(10);
29
        private readonly int _retries = 5;
30
        private RetryPolicy _retryPolicy;
24
        private readonly int _retries = 5;        
31 25
        public string ApiKey { get; set; }
32 26
        public string UserName { get; set; }
33 27
        public Uri StorageUrl { get; set; }
......
63 57
            UserName = userName;
64 58
            ApiKey = apiKey;
65 59
            
66
            var proxy = Proxy != null ? Proxy.ToString() : null;
67 60
            if (UsePithos)
68 61
            {
69 62
                Token = ApiKey;
......
74 67
            {
75 68

  
76 69
                string authUrl = String.Format("{0}/{1}", AuthenticationUrl, VersionPath);
77
                var authClient = new RestClient {Path = authUrl, Proxy = proxy};                
70
                var authClient = new PithosClient{BaseAddress= authUrl};
71
                if (Proxy != null)
72
                    authClient.Proxy = new WebProxy(Proxy);
78 73

  
79
                authClient.AddHeader("X-Auth-User", UserName);
80
                authClient.AddHeader("X-Auth-Key", ApiKey);
74
                authClient.Headers.Add("X-Auth-User", UserName);
75
                authClient.Headers.Add("X-Auth-Key", ApiKey);
81 76

  
82
                var response = authClient.Request();
77
                var response = authClient.DownloadStringWithRetry("",3);
83 78

  
84
                ThrowIfNotStatusOK(response, "Authentication failed");
79
                authClient.AssertStatusOK("Authentication failed");
85 80

  
86
                var keys = response.Headers.AllKeys.AsQueryable();
81
                //var keys = authClient.ResponseHeaders.AllKeys.AsQueryable();
87 82

  
88
                string storageUrl = GetHeaderValue("X-Storage-Url", response, keys);
83
                string storageUrl = authClient.GetHeaderValue("X-Storage-Url");
89 84
                if (String.IsNullOrWhiteSpace(storageUrl))
90 85
                    throw new InvalidOperationException("Failed to obtain storage url");
91 86
                StorageUrl = new Uri(storageUrl);
92 87

  
93
                var token = GetHeaderValue("X-Auth-Token", response, keys);
88
                var token = authClient.GetHeaderValue("X-Auth-Token");
94 89
                if (String.IsNullOrWhiteSpace(token))
95 90
                    throw new InvalidOperationException("Failed to obtain token url");
96 91
                Token = token;
97 92
            }
98 93

  
99
            _retryPolicy = new RetryPolicy { RetryCount = _retries };
100
            _retryPolicy.RetryConditions.Add(new TimeoutRetryCondition());
94
            /*_retryPolicy = new RetryPolicy { RetryCount = _retries };
95
            _retryPolicy.RetryConditions.Add(new TimeoutRetryCondition());*/
101 96

  
102
            _client = new RestClient { Authority = StorageUrl.AbsoluteUri, Path = UserName, Proxy = proxy };
103
            _client.FileProgress += OnFileProgress;
97
            _client = new PithosClient{
98
                BaseAddress  = StorageUrl.AbsoluteUri,                
99
                Timeout=10000,
100
                Retries=3};
101
            if (Proxy!=null)
102
                _client.Proxy = new WebProxy(Proxy);
103
            //_client.FileProgress += OnFileProgress;
104 104
            
105
            _client.AddHeader("X-Auth-Token", Token);
105
            _client.Headers.Add("X-Auth-Token", Token);
106 106
            /*if (UsePithos)
107 107
            {
108 108
                _client.AddHeader("X-Auth-User", UserName);
......
112 112
            Trace.TraceInformation("[AUTHENTICATE] End for {0}", userName);
113 113
        }
114 114

  
115
        private void OnFileProgress(object sender, FileProgressEventArgs e)
115
       /* private void OnFileProgress(object sender, FileProgressEventArgs e)
116 116
        {
117 117
            Trace.TraceInformation("[PROGRESS] {0} {1:p} {2} of {3}",e.FileName,(double)e.BytesWritten/e.TotalBytes, e.BytesWritten,e.TotalBytes);            
118
        }
118
        }*/
119 119

  
120 120
        public IList<ContainerInfo> ListContainers()
121 121
        {                        
......
123 123
            //appends a / unless a Path is specified.
124 124
            
125 125
            //Create a request with a complete path
126
            var request = new RestRequest { Path = StorageUrl.ToString(), RetryPolicy = _retryPolicy,Timeout = _shortTimeout };
127
            request.AddParameter("format","json");
126
            //var request = new RestRequest { Path = StorageUrl.ToString(), RetryPolicy = _retryPolicy,Timeout = _shortTimeout };
127
            //request.AddParameter("format","json");
128 128
            //Create a client clone
129

  
130
            /*var url = String.Join("/", new[] { _client.Authority, StorageUrl.ToString() });
131
            var builder=new UriBuilder(url);
132
            builder.Query = "format=json";
133
           
134
            var client= new PithosClient(_client){Timeout=10};   */         
135
            var content=_client.DownloadStringWithRetry("",3);
136
            _client.Parameters.Clear();
137
            _client.Parameters.Add("format", "json");
138
            _client.AssertStatusOK("List Containers failed");
139

  
140
            if (_client.StatusCode==HttpStatusCode.NoContent)
141
                return new List<ContainerInfo>();
142
            var infos = JsonConvert.DeserializeObject<IList<ContainerInfo>>(content);
143
            return infos;
144

  
145

  
146
/*
129 147
            var client = new RestClient{Proxy=Proxy.ToString()};
130 148
            foreach (var header in _client.GetAllHeaders())
131 149
            {
132 150
                client.AddHeader(header.Name,header.Value);
133
            }            
151
            }
152

  
153
            
154

  
155

  
134 156

  
135 157
            var response = client.Request(request);
136 158

  
......
142 164

  
143 165
            var infos=JsonConvert.DeserializeObject<IList<ContainerInfo>>(response.Content);
144 166
            
145
            return infos;
167
            return infos;*/
146 168
        }
147 169

  
148 170
        public IList<ObjectInfo> ListObjects(string container)
......
152 174

  
153 175
            Trace.TraceInformation("[START] ListObjects");
154 176

  
155
            var request = new RestRequest { Path = container, RetryPolicy = _retryPolicy, Timeout = TimeSpan.FromMinutes(1) };
156
            request.AddParameter("format", "json");
157
            var response = _client.Request(request);
158
            
159
            var infos = InfosFromContent(response);
177
            //var request = new RestRequest { Path = container, RetryPolicy = _retryPolicy, Timeout = TimeSpan.FromMinutes(1) };
178
            //request.AddParameter("format", "json");
179
            //var response = _client.Request(request);
180

  
181

  
182
/*
183
            var url = String.Join("/", new[] { _client.Authority, container });
184
            var builder = new UriBuilder(url) {Query = "format=json"};
185

  
186
            var client = new PithosClient(_client) { Timeout = 60000 };
187
*/
188
            _client.Parameters.Clear();
189
            _client.Parameters.Add("format", "json");
190
            var content = _client.DownloadStringWithRetry(container, 3);
191

  
192
            _client.AssertStatusOK("ListObjects failed");
193

  
194
            var infos = JsonConvert.DeserializeObject<IList<ObjectInfo>>(content);
160 195

  
161 196
            Trace.TraceInformation("[END] ListObjects");
162 197
            return infos;
......
171 206

  
172 207
            Trace.TraceInformation("[START] ListObjects");
173 208

  
174
            var request = new RestRequest { Path = container,RetryPolicy = _retryPolicy, Timeout = TimeSpan.FromMinutes(1) };
209
           /* var request = new RestRequest { Path = container,RetryPolicy = _retryPolicy, Timeout = TimeSpan.FromMinutes(1) };
175 210
            request.AddParameter("format", "json");
176
            request.AddParameter("path", folder);
177
            var response = _client.Request(request);
211
            request.AddParameter("path", folder);*/
212
            
213
            _client.Parameters.Clear();
214
            _client.Parameters.Add("format", "json");
215
            _client.Parameters.Add("path", folder);
216
            var content = _client.DownloadStringWithRetry(container, 3);
217
            _client.AssertStatusOK("ListObjects failed");
218

  
219
            var infos = JsonConvert.DeserializeObject<IList<ObjectInfo>>(content);
220

  
221
           /* var response = _client.Request(request);
178 222
            
179
            var infos = InfosFromContent(response);
223
            var infos = InfosFromContent(response);*/
180 224

  
181 225
            Trace.TraceInformation("[END] ListObjects");
182 226
            return infos;
183 227
        }
184 228

  
185
        private static IList<ObjectInfo> InfosFromContent(RestResponse response)
229
 /*       private static IList<ObjectInfo> InfosFromContent(RestResponse response)
186 230
        {
187 231
            if (response.TimedOut)
188 232
                return new List<ObjectInfo>();
......
204 248
            var infos = JsonConvert.DeserializeObject<IList<ObjectInfo>>(response.Content);
205 249
            return infos;
206 250
        }
207

  
251
*/
208 252
        public bool ContainerExists(string container)
209 253
        {
210 254
            if (String.IsNullOrWhiteSpace(container))
211 255
                throw new ArgumentNullException("container", "The container property can't be empty");
212 256

  
213
            var request = new RestRequest { Path = container, Method = WebMethod.Head, RetryPolicy = _retryPolicy,Timeout = _shortTimeout };
214
            var response = _client.Request(request);
257
            _client.Parameters.Clear();
258
            _client.Head(container,3);
259
            //var request = new RestRequest { Path = container, Method = WebMethod.Head, RetryPolicy = _retryPolicy,Timeout = _shortTimeout };            
260
            //var response = _client.Request(request);
215 261

  
216
            switch(response.StatusCode)
262
            switch (_client.StatusCode)
217 263
            {
218 264
                case HttpStatusCode.OK:
219 265
                case HttpStatusCode.NoContent:
......
221 267
                case HttpStatusCode.NotFound:
222 268
                    return false;          
223 269
                default:
224
                    throw CreateWebException("ContainerExists",response.StatusCode);
270
                    throw CreateWebException("ContainerExists", _client.StatusCode);
225 271
            }
226 272
        }
227 273

  
......
233 279
                throw new ArgumentNullException("objectName", "The objectName property can't be empty");
234 280

  
235 281

  
282
/*
236 283
            var request = new RestRequest { Path = container + "/" + objectName, Method = WebMethod.Head,RetryPolicy = _retryPolicy, Timeout = _shortTimeout };
237 284
            var response = _client.Request(request);
285
*/
286
            _client.Parameters.Clear();
287
            _client.Head(container + "/" + objectName, 3);
238 288

  
239
            switch (response.StatusCode)
289
            switch (_client.StatusCode)
240 290
            {
241 291
                case HttpStatusCode.OK:
242 292
                case HttpStatusCode.NoContent:
......
244 294
                case HttpStatusCode.NotFound:
245 295
                    return false;
246 296
                default:
247
                    throw CreateWebException("ObjectExists",response.StatusCode);
297
                    throw CreateWebException("ObjectExists", _client.StatusCode);
248 298
            }
249 299
            
250 300
        }
......
257 307
                throw new ArgumentNullException("objectName", "The objectName property can't be empty");
258 308

  
259 309

  
310
/*
260 311
            var request = new RestRequest { Path = container + "/" + objectName, Method = WebMethod.Head, RetryPolicy = _retryPolicy,Timeout = _shortTimeout };
261 312
            var response = _client.Request(request);
313
*/
314
            try
315
            {
316
                _client.Parameters.Clear();
262 317

  
263
            if (response.TimedOut)
264
                return ObjectInfo.Empty;
318
                _client.Head(container + "/" + objectName, 3);
265 319

  
266
            switch (response.StatusCode)
267
            {
268
                case HttpStatusCode.OK:
269
                case HttpStatusCode.NoContent:
270
                    var keys = response.Headers.AllKeys.AsQueryable();
271
                    var tags=(from key in keys
272
                             where key.StartsWith("X-Object-Meta-")
273
                             let name=key.Substring(14)
274
                             select new {Name=name,Value=response.Headers[name]})
275
                             .ToDictionary(t=>t.Name,t=>t.Value);
276
                    var extensions = (from key in keys
277
                                      where key.StartsWith("X-Object-") && !key.StartsWith("X-Object-Meta-")
278
                                      let name = key.Substring(9)
279
                                      select new { Name = name, Value = response.Headers[name] })
280
                             .ToDictionary(t => t.Name, t => t.Value);
281
                    return new ObjectInfo
282
                               {
283
                                   Name = objectName,
284
                                   Bytes = long.Parse(GetHeaderValue("Content-Length", response, keys)),
285
                                   Hash = GetHeaderValue("ETag", response, keys),
286
                                   Content_Type = GetHeaderValue("Content-Type", response, keys),
287
                                   Tags=tags,
288
                                   Extensions=extensions
289
                               };
290
                case HttpStatusCode.NotFound:
320
                if (_client.TimedOut)
291 321
                    return ObjectInfo.Empty;
292
                default:
293
                    if (request.RetryState.RepeatCount > 0)
294
                    {
295
                        Trace.TraceWarning("[RETRY FAIL] GetObjectInfo for {0} failed after {1} retries",
296
                                                      objectName, request.RetryState.RepeatCount);
322

  
323
                switch (_client.StatusCode)
324
                {
325
                    case HttpStatusCode.OK:
326
                    case HttpStatusCode.NoContent:
327
                        var keys = _client.ResponseHeaders.AllKeys.AsQueryable();
328
                        var tags = (from key in keys
329
                                    where key.StartsWith("X-Object-Meta-")
330
                                    let name = key.Substring(14)
331
                                    select new { Name = name, Value = _client.ResponseHeaders[name] })
332
                            .ToDictionary(t => t.Name, t => t.Value);
333
                        var extensions = (from key in keys
334
                                          where key.StartsWith("X-Object-") && !key.StartsWith("X-Object-Meta-")
335
                                          let name = key.Substring(9)
336
                                          select new { Name = name, Value = _client.ResponseHeaders[name] })
337
                            .ToDictionary(t => t.Name, t => t.Value);
338
                        return new ObjectInfo
339
                                   {
340
                                       Name = objectName,
341
                                       Bytes =
342
                                           long.Parse(_client.GetHeaderValue("Content-Length")),
343
                                       Hash = _client.GetHeaderValue("ETag"),
344
                                       Content_Type = _client.GetHeaderValue("Content-Type"),
345
                                       Tags = tags,
346
                                       Extensions = extensions
347
                                   };
348
                    case HttpStatusCode.NotFound:
297 349
                        return ObjectInfo.Empty;
298
                    }
299
                    if (response.InnerException != null)
300
                        throw new WebException(String.Format("[FAIL] GetObjectInfo for {0} failed with unexpected status code {1}", objectName, response.StatusCode), response.InnerException);
301
                    throw new WebException(String.Format("[FAIL] GetObjectInfo for {0} failed with unexpected status code {1}", objectName, response.StatusCode));
350
                    default:
351
                        throw new WebException(
352
                            String.Format("[FAIL] GetObjectInfo for {0} failed with unexpected status code {1}",
353
                                          objectName, _client.StatusCode));
354
                }
302 355
            }
356
            catch (RetryException e)
357
            {
358
                Trace.TraceWarning("[RETRY FAIL] GetObjectInfo for {0} failed.");
359
                return ObjectInfo.Empty;
360
            }
361
            catch (WebException e)
362
            {                
363
                Trace.TraceError(String.Format("[FAIL] GetObjectInfo for {0} failed with unexpected status code {1}",
364
                                              objectName, _client.StatusCode), e);
365
                throw;
366
            }
367
            
303 368
        }
304 369

  
305 370
        public void CreateFolder(string container, string folder)
......
310 375
                throw new ArgumentNullException("folder", "The folder property can't be empty");
311 376

  
312 377
            var folderUrl=String.Format("{0}/{1}",container,folder);
378
/*
313 379
            var request = new RestRequest { Path = folderUrl, Method = WebMethod.Put, RetryPolicy = _retryPolicy,Timeout = _shortTimeout };
314 380
            request.AddHeader("Content-Type", @"application/directory");
315 381
            request.AddHeader("Content-Length", "0");
382
*/
383
            
384
            _client.Parameters.Clear();
385
            _client.Headers.Add("Content-Type", @"application/directory");
386
            _client.Headers.Add("Content-Length", "0");
387
            _client.PutWithRetry(folderUrl,3);
316 388

  
317
            var response = _client.Request(request);
318

  
319
            if (response.StatusCode != HttpStatusCode.Created && response.StatusCode != HttpStatusCode.Accepted)
320
                throw CreateWebException("CreateFolder", response.StatusCode);
389
            if (_client.StatusCode != HttpStatusCode.Created && _client.StatusCode != HttpStatusCode.Accepted)
390
                throw CreateWebException("CreateFolder", _client.StatusCode);
321 391

  
322 392
        }
323 393

  
......
326 396
            if (String.IsNullOrWhiteSpace(container))
327 397
                throw new ArgumentNullException("container", "The container property can't be empty");
328 398

  
399
/*
329 400
            var request = new RestRequest { Path = container, Method = WebMethod.Head, RetryPolicy = _retryPolicy,Timeout = _shortTimeout };
330 401
            var response = _client.Request(request);
331

  
332
            switch(response.StatusCode)
402
*/
403
            _client.Head(container);
404
            switch (_client.StatusCode)
333 405
            {
334 406
                case HttpStatusCode.NoContent:
335
                    var keys = response.Headers.AllKeys.AsQueryable();
336 407
                    var containerInfo = new ContainerInfo
337 408
                                            {
338 409
                                                Name = container,
339
                                                Count =long.Parse(GetHeaderValue("X-Container-Object-Count", response, keys)),
340
                                                Bytes =long.Parse(GetHeaderValue("X-Container-Bytes-Used", response, keys))
410
                                                Count =long.Parse(_client.GetHeaderValue("X-Container-Object-Count")),
411
                                                Bytes = long.Parse(_client.GetHeaderValue("X-Container-Bytes-Used"))
341 412
                                            };
342 413
                    return containerInfo;
343 414
                case HttpStatusCode.NotFound:
344 415
                    return ContainerInfo.Empty;                    
345 416
                default:
346
                    throw CreateWebException("GetContainerInfo", response.StatusCode);
417
                    throw CreateWebException("GetContainerInfo", _client.StatusCode);
347 418
            }
348 419
        }
349 420

  
......
352 423
            if (String.IsNullOrWhiteSpace(container))
353 424
                throw new ArgumentNullException("container", "The container property can't be empty");
354 425

  
355
            var request = new RestRequest { Path = container, Method = WebMethod.Put, RetryPolicy = _retryPolicy,Timeout = _shortTimeout };
356
            
426
/*
427
            var request = new RestRequest { Path = container, Method = WebMethod.Put, RetryPolicy = _retryPolicy,Timeout = _shortTimeout };            
357 428
            var response = _client.Request(request);
358

  
429
*/
430
            _client.PutWithRetry(container,3);
359 431
            var expectedCodes = new[]{HttpStatusCode.Created ,HttpStatusCode.Accepted , HttpStatusCode.OK};
360
            if (!expectedCodes.Contains(response.StatusCode))
361
                throw CreateWebException("CreateContainer", response.StatusCode);
432
            if (!expectedCodes.Contains(_client.StatusCode))
433
                throw CreateWebException("CreateContainer", _client.StatusCode);
362 434
        }
363 435

  
364 436
        public void DeleteContainer(string container)
......
366 438
            if (String.IsNullOrWhiteSpace(container))
367 439
                throw new ArgumentNullException("container", "The container property can't be empty");
368 440

  
441
/*
369 442
            var request = new RestRequest { Path = container, Method = WebMethod.Delete, RetryPolicy = _retryPolicy,Timeout = _shortTimeout };
370 443
            var response = _client.Request(request);
371

  
444
*/
445
            _client.DeleteWithRetry(container,3);
372 446
            var expectedCodes = new[] { HttpStatusCode.NotFound, HttpStatusCode.NoContent};
373
            if (!expectedCodes.Contains(response.StatusCode))
374
                throw CreateWebException("DeleteContainer", response.StatusCode);
447
            if (!expectedCodes.Contains(_client.StatusCode))
448
                throw CreateWebException("DeleteContainer", _client.StatusCode);
375 449

  
376 450
        }
377 451

  
......
389 463
                throw new ArgumentNullException("container", "The container property can't be empty");
390 464
            if (String.IsNullOrWhiteSpace(objectName))
391 465
                throw new ArgumentNullException("objectName", "The objectName property can't be empty");
392

  
393
            var request = new RestRequest {Path = container + "/" + objectName, Method = WebMethod.Get};
394 466
            /*
395
                        if (DownloadPercentLimit > 0)
396
                            request.TaskOptions = new TaskOptions<int> { RateLimitPercent = DownloadPercentLimit };
397
            */
467
           var request = new RestRequest {Path = container + "/" + objectName, Method = WebMethod.Get};
468
           
469
                       if (DownloadPercentLimit > 0)
470
                           request.TaskOptions = new TaskOptions<int> { RateLimitPercent = DownloadPercentLimit };
471
           */
398 472
            try
399 473
            {
400
                var url = String.Join("/", new[] {_client.Authority, container, objectName});
474
                var url = String.Join("/", _client.BaseAddress, container, objectName);
401 475
                var uri = new Uri(url);
402 476

  
403
                var client = new WebClient();
404
                if (!String.IsNullOrWhiteSpace(_client.Proxy))
477
                var client = new PithosClient(_client){Timeout=0};
478
               /* if (!String.IsNullOrWhiteSpace(_client.Proxy))
405 479
                    client.Proxy = new WebProxy(_client.Proxy);
406 480

  
407
                CopyHeaders(_client, client);
481
                CopyHeaders(_client, client);*/
408 482

  
409 483
                Trace.TraceInformation("[GET] START {0}", objectName);
410 484
                client.DownloadProgressChanged += (sender, args) => 
......
413 487
                                    args.BytesReceived,
414 488
                                    args.TotalBytesToReceive);
415 489
                
416
                return client.DownloadFileTask(uri, fileName)
490
                return _client.DownloadFileTask(uri, fileName)
417 491
                    .ContinueWith(download =>
418 492
                                      {
419 493
                                          client.Dispose();
......
461 535
            
462 536
            try
463 537
            {
464
                var url = String.Join("/",new[]{_client.Authority,container,objectName});
538
                var url = String.Join("/",_client.BaseAddress,container,objectName);
465 539
                var uri = new Uri(url);
466 540

  
467
                var client = new WebClient();                
541
                var client = new PithosClient(_client){Timeout=0};           
468 542
                string etag = hash ?? CalculateHash(fileName);
469 543

  
470 544
                client.Headers.Add("Content-Type", "application/octet-stream");
471 545
                client.Headers.Add("ETag", etag);
472 546

  
547
/*
473 548
                if(!String.IsNullOrWhiteSpace(_client.Proxy))
474 549
                    client.Proxy = new WebProxy(_client.Proxy);
475 550

  
476 551
                CopyHeaders(_client, client);
552
*/
477 553

  
478 554
                Trace.TraceInformation("[PUT] START {0}", objectName);
479 555
                client.UploadProgressChanged += (sender, args) =>
......
502 578

  
503 579
        }
504 580
       
505

  
581
/*
506 582
        /// <summary>
507 583
        /// Copies headers from a Hammock RestClient to a WebClient
508 584
        /// </summary>
......
521 597
            {
522 598
                target.Headers.Add(header.Name, header.Value);
523 599
            }
524
        }
600
        }*/
601

  
602
       /* /// <summary>
603
        /// Copies headers from a Hammock RestClient to a WebClient
604
        /// </summary>
605
        /// <param name="source">The RestClient from which the headers are copied</param>
606
        /// <param name="target">The WebClient to which the headers are copied</param>
607
        private static void CopyHeaders(RestClient source, WebRequest target)
608
        {
609
            Contract.Requires(source!=null,"source can't be null");
610
            Contract.Requires(target != null, "target can't be null");
611
            if (source == null)
612
                throw new ArgumentNullException("source", "source can't be null");
613
            if (source == null)
614
                throw new ArgumentNullException("target", "target can't be null");
525 615

  
616
            foreach (var header in source.GetAllHeaders())
617
            {
618
                target.Headers.Add(header.Name, header.Value);
619
            }
620
        }*/
621

  
622
        
526 623
        private static string CalculateHash(string fileName)
527 624
        {
528 625
            string hash;
......
544 641
            if (String.IsNullOrWhiteSpace(objectName))
545 642
                throw new ArgumentNullException("objectName", "The objectName property can't be empty");
546 643

  
644
/*
547 645
            var request = new RestRequest { Path = container + "/" + objectName, Method = WebMethod.Delete, RetryPolicy = _retryPolicy,Timeout = _shortTimeout };
548 646
            var response = _client.Request(request);
647
*/
648
            _client.DeleteWithRetry(container + "/" + objectName,3);
549 649

  
550 650
            var expectedCodes = new[] { HttpStatusCode.NotFound, HttpStatusCode.NoContent };
551
            if (!expectedCodes.Contains(response.StatusCode))
552
                throw CreateWebException("DeleteObject", response.StatusCode);
651
            if (!expectedCodes.Contains(_client.StatusCode))
652
                throw CreateWebException("DeleteObject", _client.StatusCode);
553 653
   
554 654
        }
555 655

  
......
567 667
            var targetUrl = targetContainer + "/" + newObjectName;
568 668
            var sourceUrl = String.Format("/{0}/{1}", sourceContainer, oldObjectName);
569 669

  
670
/*
570 671
            var request = new RestRequest { Path = targetUrl, Method = WebMethod.Put };
571 672
            request.AddHeader("X-Copy-From",sourceUrl);
572 673
            request.AddPostContent(new byte[]{});
573 674
            var response = _client.Request(request);
675
*/
574 676

  
677
            var client = new PithosClient(_client);
678
            client.Headers.Add("X-Copy-From", sourceUrl);
679
            client.PutWithRetry(targetUrl,3);
575 680

  
576 681
            var expectedCodes = new[] { HttpStatusCode.OK ,HttpStatusCode.NoContent ,HttpStatusCode.Created };
577
            if (expectedCodes.Contains(response.StatusCode))
682
            if (expectedCodes.Contains(client.StatusCode))
578 683
            {
579 684
                this.DeleteObject(sourceContainer,oldObjectName);
580 685
            }                
581 686
            else
582
                throw CreateWebException("MoveObject", response.StatusCode);
687
                throw CreateWebException("MoveObject", client.StatusCode);
583 688
        }
584 689

  
585
        private string GetHeaderValue(string headerName, RestResponse response, IQueryable<string> keys)
690
      
691

  
692
        /*private string GetHeaderValue(string headerName, WebHeaderCollection headers, IQueryable<string> keys)
586 693
        {
587 694
            if (keys.Any(key => key == headerName))
588
                return response.Headers[headerName];
695
                return headers[headerName];
589 696
            else
590
                throw new WebException(String.Format("The {0}  header is missing",headerName));
697
                throw new WebException(String.Format("The {0}  header is missing", headerName));
698
        }*/
699

  
700
       /* private static void ThrowIfNotStatusOK(RestResponse response, string message)
701
        {
702
            int status = (int)response.StatusCode;
703
            ThrowIfNotStatusOK(status, message);
591 704
        }
592 705

  
593
        private static void ThrowIfNotStatusOK(RestResponse response, string message)
706
        private static void ThrowIfNotStatusOK(HttpWebResponse response, string message)
594 707
        {
595 708
            int status = (int)response.StatusCode;
596
            if (status < 200 || status >= 300)
597
                throw new WebException(String.Format("{0} with code {1}",message, status));
709
            ThrowIfNotStatusOK(status, message);
598 710
        }
599 711

  
712
        private static void ThrowIfNotStatusOK(int status, string message)
713
        {
714
            if (status < 200 || status >= 300)
715
                throw new WebException(String.Format("{0} with code {1}", message, status));
716
        }
717
        */
600 718
        private static WebException CreateWebException(string operation, HttpStatusCode statusCode)
601 719
        {
602 720
            return new WebException(String.Format("{0} failed with unexpected status code {1}", operation, statusCode));
603 721
        }
604 722

  
723
       /* public static Func<T> Retry<T>(Func<int,T> original, int retryCount,int timeout)
724
        {
725
            return () =>
726
            {
727
                while (true)
728
                {
729
                    try
730
                    {
731
                        return original(timeout);
732
                    }
733
                    catch (WebException e)
734
                    {
735
                        if (e.Status == WebExceptionStatus.Timeout)
736
                        {
737
                            if (retryCount == 0)
738
                            {
739
                                throw;
740
                            }
741
                            retryCount--;
742
                        }
743
                        else
744
                        {
745
                            throw;
746
                        }
747
                    }
748
                    catch (Exception e)
749
                    {                                   
750
                            throw;                        
751
                    }
752
                }
753
            };
754
        } */
755

  
756

  
605 757
    }
606 758
}
b/trunk/Pithos.Network/Pithos.Network.csproj
78 78
    <AssemblyOriginatorKeyFile>pithos.snk</AssemblyOriginatorKeyFile>
79 79
  </PropertyGroup>
80 80
  <ItemGroup>
81
    <Reference Include="Hammock.ClientProfile, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c148cfba29ed1a4d, processorArchitecture=MSIL">
82
      <HintPath>..\packages\Hammock.1.2.6\lib\net40-client\Hammock.ClientProfile.dll</HintPath>
83
    </Reference>
84 81
    <Reference Include="System" />
85 82
    <Reference Include="System.ComponentModel.Composition" />
86 83
    <Reference Include="System.Core" />
......
91 88
  </ItemGroup>
92 89
  <ItemGroup>
93 90
    <Compile Include="CloudFilesClient.cs" />
91
    <Compile Include="PithosClient.cs">
92
      <SubType>Component</SubType>
93
    </Compile>
94 94
    <Compile Include="Properties\AssemblyInfo.cs" />
95
    <Compile Include="TimeoutRetryCondition.cs" />
96 95
  </ItemGroup>
97 96
  <ItemGroup>
98 97
    <ProjectReference Include="..\Libraries\Json40r2\Source\Src\Newtonsoft.Json\Newtonsoft.Json.csproj">
......
109 108
    </ProjectReference>
110 109
  </ItemGroup>
111 110
  <ItemGroup>
112
    <None Include="packages.config" />
113 111
    <None Include="pithos.snk" />
114 112
  </ItemGroup>
115 113
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
b/trunk/Pithos.Network/PithosClient.cs
1
// -----------------------------------------------------------------------
2
// <copyright file="PithosClient.cs" company="Microsoft">
3
// TODO: Update copyright text.
4
// </copyright>
5
// -----------------------------------------------------------------------
6

  
7
using System.Collections.Specialized;
8
using System.Diagnostics;
9
using System.Diagnostics.Contracts;
10
using System.Net;
11
using System.Runtime.Serialization;
12

  
13
namespace Pithos.Network
14
{
15
    using System;
16
    using System.Collections.Generic;
17
    using System.Linq;
18
    using System.Text;
19

  
20
    /// <summary>
21
    /// TODO: Update summary.
22
    /// </summary>
23
    public class PithosClient:WebClient
24
    {
25
        public int Timeout { get; set; }
26

  
27
        public bool TimedOut { get; set; }
28

  
29
        public HttpStatusCode StatusCode { get; private set; }
30

  
31
        public string StatusDescription { get; set; }
32

  
33

  
34
        public int Retries { get; set; }
35

  
36
        private readonly Dictionary<string, string> _parameters=new Dictionary<string, string>();
37
        public Dictionary<string, string> Parameters
38
        {
39
            get { return _parameters; }            
40
        }
41

  
42
        public PithosClient():base()
43
        {
44
            
45
        }
46

  
47
        /*public PithosClient(RestClient restClient)
48
            :base()
49
        {
50
            CopyHeaders(restClient);
51
        }*/
52

  
53
        public PithosClient(PithosClient other)
54
            : base()
55
        {
56
            CopyHeaders(other);
57
            Timeout = other.Timeout;
58
            Retries = other.Retries;
59
            BaseAddress = other.BaseAddress;
60
            
61

  
62
            foreach (var parameter in other.Parameters)
63
            {
64
                Parameters.Add(parameter.Key,parameter.Value);
65
            }
66

  
67
            this.Proxy = other.Proxy;
68
        }
69

  
70
        protected override WebRequest GetWebRequest(Uri address)
71
        {
72
            TimedOut = false;
73
            HttpWebRequest request = base.GetWebRequest(address) as HttpWebRequest;
74
            request.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
75
            if(Timeout>0)
76
                request.Timeout = Timeout;
77
            return request; 
78
        }
79

  
80
        protected override WebResponse GetWebResponse(WebRequest request, IAsyncResult result)
81
        {
82
            var response = (HttpWebResponse) base.GetWebResponse(request, result);
83
            StatusCode=response.StatusCode;
84
            StatusDescription=response.StatusDescription;
85
            return response;
86
        }
87

  
88

  
89

  
90
        protected override WebResponse GetWebResponse(WebRequest request)
91
        {
92
            var response = (HttpWebResponse)base.GetWebResponse(request);
93
            StatusCode = response.StatusCode;
94
            StatusDescription = response.StatusDescription;
95
            return response;
96
        }
97

  
98
        public string DownloadStringWithRetry(string address,int retries=0)
99
        {
100
            if (address == null)
101
                throw new ArgumentNullException("address");
102

  
103
            var actualAddress = GetActualAddress(address);
104

  
105
            var actualRetries = (retries == 0) ? Retries : retries;
106
            var func = Retry(() =>
107
            {
108
                var uriString = String.Join("/", BaseAddress, actualAddress);
109
                var content = base.DownloadString(uriString);
110

  
111
                if (StatusCode == HttpStatusCode.NoContent)
112
                    return String.Empty;
113
                return content;
114

  
115
            }, actualRetries);
116

  
117
            var result = func();
118
            return result;
119
        }
120

  
121
        public void Head(string address,int retries=0)
122
        {
123
            RetryWithoutContent(address, retries, "HEAD");
124
        }
125

  
126
        public void PutWithRetry(string address, int retries = 0)
127
        {
128
            RetryWithoutContent(address, retries, "PUT");
129
        }
130

  
131
        public void DeleteWithRetry(string address,int retries=0)
132
        {
133
            RetryWithoutContent(address, retries, "DELETE");
134
        }
135

  
136
        public string GetHeaderValue(string headerName)
137
        {
138
            var values=this.ResponseHeaders.GetValues(headerName);
139
            if (values == null)
140
                throw new WebException(String.Format("The {0}  header is missing", headerName));
141
            else
142
                return values[0];
143
        }
144

  
145
        private void RetryWithoutContent(string address, int retries, string method)
146
        {
147
            if (address == null)
148
                throw new ArgumentNullException("address");
149

  
150
            var actualAddress = GetActualAddress(address);
151

  
152
            var actualRetries = (retries == 0) ? Retries : retries;
153
            var func = Retry(() =>
154
            {
155
                var uriString = String.Join("/",BaseAddress ,actualAddress);
156
                var uri = new Uri(uriString);
157
                var request =  GetWebRequest(uri);
158
                request.Method = method;
159
                if (ResponseHeaders!=null)
160
                    ResponseHeaders.Clear();
161

  
162

  
163
                //CopyHeaders(this.Headers,request.Headers);
164

  
165
                var response = (HttpWebResponse)GetWebResponse(request);
166
                StatusCode = response.StatusCode;
167
                StatusDescription = response.StatusDescription;                
168
                
169
                //CopyHeaders(response.Headers,this.ResponseHeaders);
170

  
171
                return 0;
172
            }, actualRetries);
173

  
174
            func();
175
        }
176

  
177
        private string GetActualAddress(string address)
178
        {
179
            if (Parameters.Count == 0)
180
                return address;
181
            var addressBuilder=new StringBuilder(address);            
182

  
183
            bool isFirst = true;
184
            foreach (var parameter in Parameters)
185
            {
186
                if(isFirst)
187
                    addressBuilder.AppendFormat("?{0}={1}", parameter.Key, parameter.Value);
188
                else
189
                    addressBuilder.AppendFormat("&{0}={1}", parameter.Key, parameter.Value);
190
                isFirst = false;
191
            }
192
            return addressBuilder.ToString();
193
        }
194

  
195
        public string DownloadStringWithRetry(Uri address,int retries=0)
196
        {
197
            if (address == null)
198
                throw new ArgumentNullException("address");
199

  
200
            var actualRetries = (retries == 0) ? Retries : retries;            
201
            var func = Retry(() =>
202
            {
203
                var content = base.DownloadString(address);
204

  
205
                if (StatusCode == HttpStatusCode.NoContent)
206
                    return String.Empty;
207
                return content;
208

  
209
            }, actualRetries);
210

  
211
            var result = func();
212
            return result;
213
        }
214

  
215
      /*  /// <summary>
216
        /// Copies headers from a Hammock RestClient to a WebClient
217
        /// </summary>
218
        /// <param name="source">The RestClient from which the headers are copied</param>
219
        /// <param name="target">The WebClient to which the headers are copied</param>
220
        private void CopyHeaders(RestClient source)
221
        {
222
            Contract.Requires(source != null, "source can't be null");
223
            if (source == null)
224
                throw new ArgumentNullException("source", "source can't be null");
225
            if (source == null)
226
                throw new ArgumentNullException("target", "target can't be null");
227

  
228
            foreach (var header in source.GetAllHeaders())
229
            {
230
                Headers.Add(header.Name, header.Value);
231
            }
232
        } 
233
        */
234
        /// <summary>
235
        /// Copies headers from a Hammock RestClient to a WebClient
236
        /// </summary>
237
        /// <param name="source">The PithosClient from which the headers are copied</param>
238
        public void CopyHeaders(PithosClient source)
239
        {
240
            Contract.Requires(source != null, "source can't be null");
241
            if (source == null)
242
                throw new ArgumentNullException("source", "source can't be null");
243
            CopyHeaders(source.Headers,Headers);
244
        }
245
        
246
        /// <summary>
247
        /// Copies headers from a Hammock RestClient to a WebClient
248
        /// </summary>
249
        /// <param name="source">The RestClient from which the headers are copied</param>
250
        /// <param name="target">The WebClient to which the headers are copied</param>
251
        public static void CopyHeaders(WebHeaderCollection source,WebHeaderCollection target)
252
        {
253
            Contract.Requires(source != null, "source can't be null");
254
            Contract.Requires(target != null, "target can't be null");
255
            if (source == null)
256
                throw new ArgumentNullException("source", "source can't be null");
257
            if (target == null)
258
                throw new ArgumentNullException("target", "target can't be null");
259
            for (int i = 0; i < source.Count; i++)
260
            {
261
                target.Add(source.GetKey(i), source[i]);
262
            }            
263
        }
264

  
265
        public void AssertStatusOK(string message)
266
        {
267
            if (StatusCode >= HttpStatusCode.BadRequest)
268
                throw new WebException(String.Format("{0} with code {1} - {2}", message, StatusCode, StatusDescription));
269
        }
270

  
271
        private Func<T> Retry<T>(Func< T> original, int retryCount)
272
        {
273
            return () =>
274
            {
275
                while (true)
276
                {
277
                    try
278
                    {
279
                        return original();
280
                    }
281
                    catch (WebException e)
282
                    {
283
                        var statusCode = ((HttpWebResponse)e.Response).StatusCode;
284
                        this.StatusCode = statusCode;
285

  
286
                        switch (e.Status)
287
                        {
288
                            case WebExceptionStatus.Timeout:
289

  
290
                                TimedOut = true;
291
                                if (retryCount == 0)
292
                                {
293
                                    Trace.TraceError("[ERROR] Timed out too many times. {0}\n", e);
294
                                    throw new RetryException("Timed out too many times.", e);
295
                                }
296
                                retryCount--;
297
                                Trace.TraceError(
298
                                    "[RETRY] Timed out after {0} ms. Will retry {1} more times\n{2}", Timeout,
299
                                    retryCount, e);
300

  
301
                                break;
302
                            case WebExceptionStatus.ProtocolError:
303
                                switch (statusCode)
304
                                {
305
                                    case HttpStatusCode.NotFound:
306
                                        {
307
                                            return default(T);
308
                                        }
309
                                    case HttpStatusCode.ServiceUnavailable:
310
                                        {
311

  
312
                                            TimedOut = false;
313
                                            if (retryCount == 0)
314
                                            {
315
                                                Trace.TraceError("[ERROR] Failed too many times. {0}\n", e);
316
                                                throw new RetryException("Failed too many times.", e);
317
                                            }
318
                                            retryCount--;
319
                                            Trace.TraceError(
320
                                                "[RETRY] Failed due to 503. Will retry {0} more times\n{1}", retryCount, e);
321
                                            break;
322
                                        }
323
                                    default:
324
                                        throw;
325
                                }
326
                                break;
327
                            default:
328
                                throw;
329
                        }
330
                    }
331
                }
332
            };
333
        }
334

  
335
       
336
    }
337

  
338
    public class RetryException:Exception
339
    {
340
        public RetryException()
341
            :base()
342
        {
343
            
344
        }
345

  
346
        public RetryException(string message)
347
            :base(message)
348
        {
349
            
350
        }
351

  
352
        public RetryException(string message,Exception innerException)
353
            :base(message,innerException)
354
        {
355
            
356
        }
357

  
358
        public RetryException(SerializationInfo info,StreamingContext context)
359
            :base(info,context)
360
        {
361
            
362
        }
363
    }
364
}
/dev/null
1
<?xml version="1.0" encoding="utf-8"?>
2
<packages>
3
  <package id="Hammock" version="1.2.6" />
4
</packages>
b/trunk/Pithos.Setup.x64/Pithos.Setup.x64.vdproj
466 466
        "Entry"
467 467
        {
468 468
        "MsmKey" = "8:_E573D8AD1AAEB39255958325DA5EDBD5"
469
        "OwnerKey" = "8:_BAA515E0FCDE402CBF2A6FF3D94A0B83"
470
        "MsmSig" = "8:_UNDEFINED"
471
        }
472
        "Entry"
473
        {
474
        "MsmKey" = "8:_E573D8AD1AAEB39255958325DA5EDBD5"
475 469
        "OwnerKey" = "8:_1082D2B1D4BC998D946F5A9AADC3F5BE"
476 470
        "MsmSig" = "8:_UNDEFINED"
477 471
        }
......
1494 1488
        "Name" = "8:Microsoft Visual Studio"
1495 1489
        "ProductName" = "8:Pithos"
1496 1490
        "ProductCode" = "8:{6DF108D9-D8FB-4438-9B83-A06A272FF56D}"
1497
        "PackageCode" = "8:{FE169482-E9D7-4D7B-BD3D-0101348C3EBF}"
1491
        "PackageCode" = "8:{E35A6485-B3CF-43D5-B0E2-7A4E75CD36F3}"
1498 1492
        "UpgradeCode" = "8:{9D7BB283-458F-4124-A847-E42AFC9D5514}"
1499 1493
        "AspNetVersion" = "8:4.0.30319.0"
1500 1494
        "RestartWWWService" = "11:FALSE"
b/trunk/Pithos.ShellExtensions/Menus/FileContextMenu.cs
30 30

  
31 31
        public FileContextMenu()
32 32
        {                        
33
           /* _gotoBitmap = GetBitmapPtr(Resources.MenuGoToPithos);
34
            _versionBitmap = GetBitmapPtr(Resources.MenuHistory);*/
33
            _gotoBitmap = GetBitmapPtr(Resources.MenuGoToPithos);
34
            _versionBitmap = GetBitmapPtr(Resources.MenuHistory);
35 35

  
36 36

  
37 37
            
......
42 42
                                            Verb = "gotoPithos",
43 43
                                             VerbCanonicalName = "PITHOSGoTo",
44 44
                                              VerbHelpText = "Go to Pithos",
45
                                               MenuDisplayId = 0,
45
                                               MenuDisplayId = 1,
46 46
                                               MenuCommand=OnGotoPithos,
47 47
                                               DisplayFlags=DisplayFlags.All,
48 48
                                               MenuBitmap = _gotoBitmap
......
52 52
                                            Verb = "prevVersions",
53 53
                                             VerbCanonicalName = "PITHOSPrevVersions",
54 54
                                              VerbHelpText = "Go to Pithos and display previous versions",
55
                                               MenuDisplayId = 1,
55
                                               MenuDisplayId = 2,
56 56
                                               MenuCommand=OnVerbDisplayFileName,
57 57
                                               DisplayFlags=DisplayFlags.File,
58 58
                                               MenuBitmap=_versionBitmap
......
341 341

  
342 342
            Debug.WriteLine(String.Format("Item Flags {0}", itemType), LogCategories.ShellMenu);
343 343

  
344
            if (!NativeMethods.InsertMenu(hMenu, idCmdFirst, MF.MF_SEPARATOR | MF.MF_BYPOSITION, 0, String.Empty))
345
            {
346
                Trace.TraceError("Error adding separator 1\r\n{0}", Marshal.GetLastWin32Error());
347
                return Marshal.GetHRForLastWin32Error();
348
            }
349

  
344 350
            foreach (var menuItem in _items.Values)
345 351
            {
346 352
                Debug.WriteLine(String.Format("Menu Flags {0}", menuItem.DisplayFlags), LogCategories.ShellMenu);
......
362 368

  
363 369
            Debug.Write("Adding Separator 1", LogCategories.ShellMenu);
364 370
            // Add a separator.
365
            MENUITEMINFO sep = new MENUITEMINFO();
371
           /* MENUITEMINFO sep = new MENUITEMINFO();
366 372
            sep.cbSize = (uint)Marshal.SizeOf(sep);
367 373
            sep.fMask = MIIM.MIIM_TYPE;
368
            sep.fType = MFT.MFT_SEPARATOR;
369
            if (!NativeMethods.InsertMenuItem(hMenu, iMenu, true, ref sep))
374
            sep.fType = MFT.MFT_SEPARATOR;*/
375
            if (!NativeMethods.InsertMenu(hMenu, (uint)_items.Values.Count + idCmdFirst+1,MF.MF_SEPARATOR|MF.MF_BYPOSITION, 0, String.Empty))
370 376
            {
371 377
                Trace.TraceError("Error adding separator 1\r\n{0}", Marshal.GetLastWin32Error());
372 378
                return Marshal.GetHRForLastWin32Error();
b/trunk/Pithos.ShellExtensions/Menus/MenuItem.cs
23 23
        {
24 24
            var mii = new MENUITEMINFO();
25 25
            mii.cbSize = (uint)Marshal.SizeOf(mii);
26
            mii.fMask = MIIM.MIIM_ID | MIIM.MIIM_TYPE | MIIM.MIIM_STATE;
26
            mii.fMask = MIIM.MIIM_BITMAP| MIIM.MIIM_STRING | MIIM.MIIM_FTYPE | MIIM.MIIM_ID | MIIM.MIIM_STATE;
27
            //mii.fMask = MIIM.MIIM_ID | MIIM.MIIM_TYPE | MIIM.MIIM_STATE;
27 28
            mii.wID = idCmdFirst + MenuDisplayId;
28 29
            mii.fType = MFT.MFT_STRING;
29 30
            mii.dwTypeData = MenuText;
30 31
            mii.fState = MFS.MFS_ENABLED;
31 32

  
32
           /* if (MenuBitmap != IntPtr.Zero)
33
            if (MenuBitmap != IntPtr.Zero)
33 34
            {
34 35
                mii.fMask|=  MIIM.MIIM_BITMAP;
35 36
                mii.hbmpItem = MenuBitmap;
36
            }*/
37
            }
37 38

  
38 39
            return mii;
39 40
        }
b/trunk/Pithos.ShellExtensions/Properties/Resources.Designer.cs
59 59
                resourceCulture = value;
60 60
            }
61 61
        }
62
        
63
        internal static System.Drawing.Bitmap MenuGoToPithos {
64
            get {
65
                object obj = ResourceManager.GetObject("MenuGoToPithos", resourceCulture);
66
                return ((System.Drawing.Bitmap)(obj));
67
            }
68
        }
69
        
70
        internal static System.Drawing.Bitmap MenuHistory {
71
            get {
72
                object obj = ResourceManager.GetObject("MenuHistory", resourceCulture);
73
                return ((System.Drawing.Bitmap)(obj));
74
            }
75
        }
62 76
    }
63 77
}
b/trunk/Pithos.ShellExtensions/Properties/Resources.resx
112 112
    <value>2.0</value>
113 113
  </resheader>
114 114
  <resheader name="reader">
115
    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
115
    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
116 116
  </resheader>
117 117
  <resheader name="writer">
118
    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
118
    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
119 119
  </resheader>
120
  <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
121
  <data name="MenuGoToPithos" type="System.Resources.ResXFileRef, System.Windows.Forms">
122
    <value>..\Resources\MenuGoToPithos.bmp;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
123
  </data>
124
  <data name="MenuHistory" type="System.Resources.ResXFileRef, System.Windows.Forms">
125
    <value>..\Resources\MenuHistory.bmp;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
126
  </data>
120 127
</root>
b/trunk/Pithos.ShellExtensions/ShellExtLib.cs
692 692
        MIIM_BITMAP = 0x00000080,
693 693
        MIIM_FTYPE = 0x00000100
694 694
    }
695

  
695
    [Flags]
696 696
    internal enum MFT : uint
697 697
    {
698 698
        MFT_STRING = 0x00000000,
......
706 706
        MFT_RIGHTJUSTIFY = 0x00004000
707 707
    }
708 708

  
709
    [Flags]
709 710
    internal enum MFS : uint
710 711
    {
711 712
        MFS_ENABLED = 0x00000000,
......
718 719
        MFS_DEFAULT = 0x00001000
719 720
    }
720 721

  
722
    [Flags]
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff