Revision 3c43ec9b
b/trunk/Libraries/ParallelExtensionsExtras/ParallelExtensionsExtras.csproj | ||
---|---|---|
13 | 13 |
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion> |
14 | 14 |
<FileAlignment>512</FileAlignment> |
15 | 15 |
<CodeContractsAssemblyMode>1</CodeContractsAssemblyMode> |
16 |
<TargetFrameworkProfile>Client</TargetFrameworkProfile> |
|
16 | 17 |
</PropertyGroup> |
17 | 18 |
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> |
18 | 19 |
<DebugSymbols>true</DebugSymbols> |
b/trunk/Pithos.Client.WPF/PreferencesView.xaml | ||
---|---|---|
106 | 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="160" HorizontalAlignment="Stretch" VerticalAlignment="Top" Width="272">
|
|
109 |
<GroupBox Header="Account" Padding="5" Margin="5" Height="190" HorizontalAlignment="Stretch" VerticalAlignment="Top" Width="272">
|
|
110 | 110 |
<Grid> |
111 | 111 |
<Grid.ColumnDefinitions> |
112 | 112 |
<ColumnDefinition Width="Auto"/> |
... | ... | |
117 | 117 |
<RowDefinition Height="Auto"/> |
118 | 118 |
<RowDefinition Height="Auto"/> |
119 | 119 |
<RowDefinition Height="Auto"/> |
120 |
<RowDefinition Height="Auto"/> |
|
120 | 121 |
<RowDefinition /> |
121 | 122 |
</Grid.RowDefinitions> |
122 | 123 |
<Label Content="Account" Grid.Column="0" Grid.Row="0" Margin="0,5" HorizontalAlignment="Left"/> |
... | ... | |
124 | 125 |
<Label Content="API Key" Grid.Column="0" Grid.Row="1" Margin="0,5" HorizontalAlignment="Left"/> |
125 | 126 |
<TextBox Name="CurrentAccount_ApiKey" Grid.Column="1" Grid.Row="1" Margin="5"/> |
126 | 127 |
<CheckBox Name="CurrentAccount_IsActive" Content="Account is Active" Grid.Column="1" Grid.Row="2" Margin="5"/> |
127 |
<Button Name="SelectSyncFolders" Content="Selective Sync" Width="Auto" HorizontalAlignment="Left" Style="{StaticResource ButtonStyle}" Grid.Column="1" Grid.Row="3"/> |
|
128 |
<CheckBox Name="CurrentAccount_UsePithos" Content="Use Pithos Extensions" Grid.Column="1" Grid.Row="3" Margin="5"/> |
|
129 |
<Button Name="SelectSyncFolders" Content="Selective Sync" Width="Auto" HorizontalAlignment="Left" Style="{StaticResource ButtonStyle}" Grid.Column="1" Grid.Row="4"/> |
|
128 | 130 |
|
129 | 131 |
</Grid> |
130 | 132 |
</GroupBox> |
b/trunk/Pithos.Client.WPF/Properties/Settings.Designer.cs | ||
---|---|---|
203 | 203 |
} |
204 | 204 |
} |
205 | 205 |
|
206 |
[global::System.Configuration.ApplicationScopedSettingAttribute()] |
|
207 |
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] |
|
208 |
[global::System.Configuration.DefaultSettingValueAttribute("http://pithos.dev.grnet.gr/pithos.html")] |
|
209 |
public string PithosSite { |
|
210 |
get { |
|
211 |
return ((string)(this["PithosSite"])); |
|
212 |
} |
|
213 |
} |
|
214 |
|
|
206 | 215 |
[global::System.Configuration.UserScopedSettingAttribute()] |
207 | 216 |
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] |
208 |
[global::System.Configuration.DefaultSettingValueAttribute(@"<?xml version=""1.0"" encoding=""utf-16""?> |
|
209 |
<ArrayOfAccountSettings xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema""> |
|
210 |
<AccountSettings> |
|
211 |
<AccountName>pkanavos</AccountName> |
|
212 |
<ApiKey>9d3cb7b231e96f72ebe96af1c6cd5112</ApiKey> |
|
213 |
<IsActive>true</IsActive> |
|
214 |
<SelectiveFolders /> |
|
215 |
</AccountSettings> |
|
216 |
</ArrayOfAccountSettings>")] |
|
217 |
[global::System.Configuration.DefaultSettingValueAttribute("\r\n <ArrayOfAccountSettings xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-i" + |
|
218 |
"nstance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">\r\n <AccountSett" + |
|
219 |
"ings>\r\n </AccountSettings>\r\n </ArrayOfAccountSettings>\r\n " + |
|
220 |
" ")] |
|
217 | 221 |
public global::Pithos.Interfaces.AccountsCollection Accounts { |
218 | 222 |
get { |
219 | 223 |
return ((global::Pithos.Interfaces.AccountsCollection)(this["Accounts"])); |
... | ... | |
222 | 226 |
this["Accounts"] = value; |
223 | 227 |
} |
224 | 228 |
} |
225 |
|
|
226 |
[global::System.Configuration.ApplicationScopedSettingAttribute()] |
|
227 |
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] |
|
228 |
[global::System.Configuration.DefaultSettingValueAttribute("http://pithos.dev.grnet.gr/pithos.html")] |
|
229 |
public string PithosSite { |
|
230 |
get { |
|
231 |
return ((string)(this["PithosSite"])); |
|
232 |
} |
|
233 |
} |
|
234 | 229 |
} |
235 | 230 |
} |
b/trunk/Pithos.Client.WPF/Properties/Settings.settings | ||
---|---|---|
47 | 47 |
<Setting Name="UseManualProxy" Type="System.Boolean" Scope="User"> |
48 | 48 |
<Value Profile="(Default)">False</Value> |
49 | 49 |
</Setting> |
50 |
<Setting Name="Accounts" Type="Pithos.Interfaces.AccountsCollection" Scope="User"> |
|
51 |
<Value Profile="(Default)"><?xml version="1.0" encoding="utf-16"?> |
|
52 |
<ArrayOfAccountSettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> |
|
53 |
<AccountSettings> |
|
54 |
<AccountName>pkanavos</AccountName> |
|
55 |
<ApiKey>9d3cb7b231e96f72ebe96af1c6cd5112</ApiKey> |
|
56 |
<IsActive>true</IsActive> |
|
57 |
<SelectiveFolders /> |
|
58 |
</AccountSettings> |
|
59 |
</ArrayOfAccountSettings></Value> |
|
60 |
</Setting> |
|
61 | 50 |
<Setting Name="PithosSite" Type="System.String" Scope="Application"> |
62 | 51 |
<Value Profile="(Default)">http://pithos.dev.grnet.gr/pithos.html</Value> |
63 | 52 |
</Setting> |
53 |
<Setting Name="Accounts" Type="Pithos.Interfaces.AccountsCollection" Scope="User"> |
|
54 |
<Value Profile="(Default)"> |
|
55 |
<ArrayOfAccountSettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> |
|
56 |
<AccountSettings> |
|
57 |
</AccountSettings> |
|
58 |
</ArrayOfAccountSettings> |
|
59 |
</Value> |
|
60 |
</Setting> |
|
64 | 61 |
</Settings> |
65 | 62 |
</SettingsFile> |
b/trunk/Pithos.Client.WPF/TaskbarViewModel.cs | ||
---|---|---|
47 | 47 |
{ |
48 | 48 |
Monitor.UserName = account.AccountName; |
49 | 49 |
Monitor.ApiKey = account.ApiKey; |
50 |
Monitor.UsePithos = account.UsePithos; |
|
50 | 51 |
Monitor.RootPath = Path.Combine(Settings.PithosPath, account.RootPath??""); |
51 | 52 |
} |
52 | 53 |
|
b/trunk/Pithos.Client.WPF/app.config | ||
---|---|---|
71 | 71 |
<setting name="UseManualProxy" serializeAs="String"> |
72 | 72 |
<value>False</value> |
73 | 73 |
</setting> |
74 |
<setting name="Accounts" serializeAs="Xml"> |
|
75 |
<value> |
|
76 |
<ArrayOfAccountSettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|
77 |
xmlns:xsd="http://www.w3.org/2001/XMLSchema"> |
|
78 |
<AccountSettings> |
|
79 |
<AccountName>pkanavos</AccountName> |
|
80 |
<ApiKey>9d3cb7b231e96f72ebe96af1c6cd5112</ApiKey> |
|
81 |
<IsActive>true</IsActive> |
|
82 |
<SelectiveFolders /> |
|
83 |
</AccountSettings> |
|
84 |
</ArrayOfAccountSettings> |
|
85 |
</value> |
|
86 |
</setting> |
|
87 | 74 |
</Pithos.Client.WPF.Properties.Settings> |
88 | 75 |
</userSettings> |
89 | 76 |
<connectionStrings> |
b/trunk/Pithos.Core.Test/MockStatusKeeper.cs | ||
---|---|---|
4 | 4 |
using System.Diagnostics.Contracts; |
5 | 5 |
using System.Linq; |
6 | 6 |
using System.Text; |
7 |
using System.Threading; |
|
7 | 8 |
using Pithos.Interfaces; |
8 | 9 |
|
9 | 10 |
namespace Pithos.Core.Test |
... | ... | |
116 | 117 |
return NetworkState.None; |
117 | 118 |
} |
118 | 119 |
|
120 |
public void StartProcessing(CancellationToken token) |
|
121 |
{ |
|
122 |
|
|
123 |
} |
|
124 |
|
|
119 | 125 |
|
120 | 126 |
private PithosStatus _pithosStatus = PithosStatus.InSynch; |
121 | 127 |
public void SetPithosStatus(PithosStatus status) |
b/trunk/Pithos.Core.Test/StatusCheckerTest.cs | ||
---|---|---|
14 | 14 |
var files = new[] {Tuple.Create(@"e:\pithos\0File1.txt", FileOverlayStatus.Normal), |
15 | 15 |
Tuple.Create(@"e:\pithos\0File2.txt", FileOverlayStatus.Conflict), |
16 | 16 |
Tuple.Create(@"e:\pithos\0File3.txt", FileOverlayStatus.Modified), |
17 |
Tuple.Create(@"e:\pithos\0File4.txt", FileOverlayStatus.Synch)
|
|
17 |
Tuple.Create(@"e:\pithos\0File4.txt", FileOverlayStatus.Modified)
|
|
18 | 18 |
}; |
19 | 19 |
|
20 | 20 |
var checker = new InMemStatusChecker(); |
... | ... | |
39 | 39 |
var files = new[] {Tuple.Create(@"e:\pithos\0File1.txt", FileOverlayStatus.Normal), |
40 | 40 |
Tuple.Create(@"e:\pithos\0File2.txt", FileOverlayStatus.Conflict), |
41 | 41 |
Tuple.Create(@"e:\pithos\0File3.txt", FileOverlayStatus.Modified), |
42 |
Tuple.Create(@"e:\pithos\0File4.txt", FileOverlayStatus.Synch)
|
|
42 |
Tuple.Create(@"e:\pithos\0File4.txt", FileOverlayStatus.Modified)
|
|
43 | 43 |
}; |
44 | 44 |
|
45 | 45 |
var checker = new InMemStatusChecker(); |
... | ... | |
65 | 65 |
Tuple.Create(@"e:\pithos\0File1.txt", FileOverlayStatus.Normal), |
66 | 66 |
Tuple.Create(@"e:\pithos\0File2.txt", FileOverlayStatus.Conflict), |
67 | 67 |
Tuple.Create(@"e:\pithos\0File3.txt", FileOverlayStatus.Modified), |
68 |
Tuple.Create(@"e:\pithos\0File4.txt", FileOverlayStatus.Synch)
|
|
68 |
Tuple.Create(@"e:\pithos\0File4.txt", FileOverlayStatus.Modified)
|
|
69 | 69 |
}; |
70 | 70 |
|
71 | 71 |
var checker = new InMemStatusChecker(); |
b/trunk/Pithos.Core/FileState.cs | ||
---|---|---|
22 | 22 |
public class FileState:ActiveRecordLinqBase<FileState> |
23 | 23 |
{ |
24 | 24 |
private string _filePath; |
25 |
private IList<FileTag> _tags=new List<FileTag>(); |
|
26 |
|
|
25 | 27 |
|
26 | 28 |
[PrimaryKey] |
27 | 29 |
public string FilePath |
... | ... | |
39 | 41 |
[Property] |
40 | 42 |
public string Checksum { get; set; } |
41 | 43 |
|
44 |
[HasMany(Cascade=ManyRelationCascadeEnum.AllDeleteOrphan,Lazy=true)] |
|
45 |
public IList<FileTag> Tags |
|
46 |
{ |
|
47 |
get { return _tags; } |
|
48 |
set { _tags=value;} |
|
49 |
} |
|
50 |
|
|
42 | 51 |
} |
43 | 52 |
|
44 |
|
|
53 |
[ActiveRecord] |
|
54 |
public class FileTag : ActiveRecordLinqBase<FileTag> |
|
55 |
{ |
|
56 |
[PrimaryKey] |
|
57 |
public string FilePath { get; set; } |
|
58 |
|
|
59 |
[Property] |
|
60 |
public string Value { get; set; } |
|
61 |
|
|
62 |
[BelongsTo("FilePath")] |
|
63 |
public FileState FileState { get; set; } |
|
64 |
|
|
65 |
} |
|
66 |
|
|
67 |
|
|
45 | 68 |
} |
b/trunk/Pithos.Core/IStatusKeeper.cs | ||
---|---|---|
3 | 3 |
using System.Diagnostics.Contracts; |
4 | 4 |
using System.IO; |
5 | 5 |
using System.Linq; |
6 |
using System.Threading; |
|
6 | 7 |
using Pithos.Interfaces; |
7 | 8 |
|
8 | 9 |
namespace Pithos.Core |
... | ... | |
26 | 27 |
void SetStatus(string path, Action<FileState> setter); |
27 | 28 |
void SetNetworkState(string fileName, NetworkState uploading); |
28 | 29 |
NetworkState GetNetworkState(string fileName); |
30 |
|
|
31 |
void StartProcessing(CancellationToken token); |
|
32 |
|
|
29 | 33 |
} |
30 | 34 |
|
31 | 35 |
[ContractClassFor(typeof(IStatusKeeper))] |
... | ... | |
130 | 134 |
public void SetPithosStatus(PithosStatus status) |
131 | 135 |
{ |
132 | 136 |
} |
137 |
|
|
138 |
public void StartProcessing(CancellationToken token) |
|
139 |
{ |
|
140 |
Contract.Requires(token != null, "token can't be empty"); |
|
141 |
} |
|
142 |
|
|
133 | 143 |
} |
134 | 144 |
} |
b/trunk/Pithos.Core/InMemStatusChecker.cs | ||
---|---|---|
4 | 4 |
using System.ComponentModel.Composition; |
5 | 5 |
using System.Diagnostics.Contracts; |
6 | 6 |
using System.Linq; |
7 |
using System.Threading; |
|
7 | 8 |
using Pithos.Interfaces; |
8 | 9 |
|
9 | 10 |
namespace Pithos.Core |
... | ... | |
100 | 101 |
return NetworkState.None; |
101 | 102 |
} |
102 | 103 |
|
104 |
public void StartProcessing(CancellationToken token) |
|
105 |
{ |
|
106 |
|
|
107 |
} |
|
108 |
|
|
103 | 109 |
public void SetFileOverlayStatus(string path, FileOverlayStatus overlayStatus) |
104 | 110 |
{ |
105 | 111 |
_overlayCache[path] = overlayStatus; |
b/trunk/Pithos.Core/Pithos.Core.csproj | ||
---|---|---|
13 | 13 |
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion> |
14 | 14 |
<FileAlignment>512</FileAlignment> |
15 | 15 |
<CodeContractsAssemblyMode>1</CodeContractsAssemblyMode> |
16 |
<TargetFrameworkProfile>Client</TargetFrameworkProfile> |
|
16 | 17 |
</PropertyGroup> |
17 | 18 |
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> |
18 | 19 |
<DebugSymbols>true</DebugSymbols> |
b/trunk/Pithos.Core/PithosMonitor.cs | ||
---|---|---|
22 | 22 |
[Export(typeof(PithosMonitor))] |
23 | 23 |
public class PithosMonitor:IDisposable |
24 | 24 |
{ |
25 |
private const string PithosContainer = "pithos"; |
|
26 |
private const string TrashContainer = "trash"; |
|
27 |
|
|
25 | 28 |
[Import] |
26 | 29 |
public IPithosSettings Settings{get;set;} |
27 | 30 |
|
... | ... | |
84 | 87 |
|
85 | 88 |
var proxyUri = ProxyFromSettings(); |
86 | 89 |
CloudClient.Proxy = proxyUri; |
87 |
//CloudClient.UsePithos = true; |
|
90 |
CloudClient.UsePithos = this.UsePithos; |
|
91 |
EnsurePithosContainers(); |
|
92 |
StatusKeeper.StartProcessing(_cancellationSource.Token); |
|
88 | 93 |
IndexLocalFiles(RootPath); |
89 | 94 |
StartMonitoringFiles(RootPath); |
90 | 95 |
|
... | ... | |
93 | 98 |
StartNetwork(); |
94 | 99 |
} |
95 | 100 |
|
101 |
private void EnsurePithosContainers() |
|
102 |
{ |
|
103 |
CloudClient.UsePithos = this.UsePithos; |
|
104 |
CloudClient.Authenticate(UserName, ApiKey); |
|
105 |
|
|
106 |
var pithosContainers = new[] {PithosContainer, TrashContainer}; |
|
107 |
foreach (var container in pithosContainers) |
|
108 |
{ |
|
109 |
if (!CloudClient.ContainerExists(container)) |
|
110 |
CloudClient.CreateContainer(container); |
|
111 |
} |
|
112 |
} |
|
113 |
|
|
96 | 114 |
private Uri ProxyFromSettings() |
97 | 115 |
{ |
98 | 116 |
if (Settings.UseManualProxy) |
... | ... | |
136 | 154 |
|
137 | 155 |
private void RestartInterruptedFiles() |
138 | 156 |
{ |
139 |
var interruptedStates = new[] { FileOverlayStatus.Unversioned, FileOverlayStatus.Synch };
|
|
157 |
var interruptedStates = new[] { FileOverlayStatus.Unversioned, FileOverlayStatus.Modified };
|
|
140 | 158 |
var filesQuery = from state in FileState.Queryable |
141 | 159 |
where interruptedStates.Contains(state.OverlayStatus) |
142 | 160 |
select new WorkflowState |
... | ... | |
205 | 223 |
|
206 | 224 |
try |
207 | 225 |
{ |
208 |
CloudClient.UsePithos = false;
|
|
226 |
CloudClient.UsePithos = this.UsePithos;
|
|
209 | 227 |
CloudClient.Authenticate(UserName, ApiKey); |
210 | 228 |
|
211 | 229 |
StartListening(RootPath); |
... | ... | |
219 | 237 |
} |
220 | 238 |
} |
221 | 239 |
|
240 |
public bool UsePithos { get; set; } |
|
241 |
|
|
222 | 242 |
internal enum CloudActionType |
223 | 243 |
{ |
224 | 244 |
Upload=0, |
... | ... | |
289 | 309 |
{ |
290 | 310 |
Trace.TraceInformation("[LISTENER] Scheduled"); |
291 | 311 |
return Task.Factory.StartNewDelayed(10000) |
292 |
.ContinueWith(t=>CloudClient.ListObjects("PITHOS"))
|
|
312 |
.ContinueWith(t=>CloudClient.ListObjects(PithosContainer))
|
|
293 | 313 |
.ContinueWith(task => |
294 | 314 |
{ |
295 | 315 |
Trace.TraceInformation("[LISTENER] Start Processing"); |
... | ... | |
351 | 371 |
{ |
352 | 372 |
foreach(var action in _networkActions.GetConsumingEnumerable()) |
353 | 373 |
{ |
354 |
Trace.TraceInformation("[ACTION] Start Processing {0}:{1}->{2}",action.Action,action.LocalFile,action.CloudFile); |
|
374 |
Trace.TraceInformation("[ACTION] Start Processing {0}:{1}->{2}",action.Action,action.LocalFile,action.CloudFile.Name);
|
|
355 | 375 |
var localFile = action.LocalFile; |
356 | 376 |
var cloudFile = action.CloudFile; |
357 | 377 |
var downloadPath = (cloudFile == null)? String.Empty |
... | ... | |
365 | 385 |
UploadCloudFile(localFile.Name,localFile.Length,localFile.FullName,action.LocalHash.Value); |
366 | 386 |
break; |
367 | 387 |
case CloudActionType.DownloadUnconditional: |
368 |
DownloadCloudFile("PITHOS",cloudFile.Name,downloadPath);
|
|
388 |
DownloadCloudFile(PithosContainer,cloudFile.Name,downloadPath);
|
|
369 | 389 |
break; |
370 | 390 |
case CloudActionType.Download: |
371 | 391 |
if (File.Exists(downloadPath)) |
... | ... | |
380 | 400 |
StatusKeeper.SetFileOverlayStatus(downloadPath,FileOverlayStatus.Conflict); |
381 | 401 |
} |
382 | 402 |
else |
383 |
DownloadCloudFile("PITHOS",action.CloudFile.Name,downloadPath);
|
|
403 |
DownloadCloudFile(PithosContainer,action.CloudFile.Name,downloadPath);
|
|
384 | 404 |
} |
385 | 405 |
} |
386 | 406 |
else |
387 |
DownloadCloudFile("PITHOS",action.CloudFile.Name,downloadPath);
|
|
407 |
DownloadCloudFile(PithosContainer,action.CloudFile.Name,downloadPath);
|
|
388 | 408 |
break; |
389 | 409 |
} |
390 |
Trace.TraceInformation("[ACTION] End Processing {0}:{1}->{2}", action.Action, action.LocalFile, action.CloudFile); |
|
410 |
Trace.TraceInformation("[ACTION] End Processing {0}:{1}->{2}", action.Action, action.LocalFile, action.CloudFile.Name);
|
|
391 | 411 |
} |
392 | 412 |
catch (Exception exc) |
393 | 413 |
{ |
... | ... | |
496 | 516 |
|
497 | 517 |
private void RenameCloudFile(WorkflowState state) |
498 | 518 |
{ |
499 |
this.StatusKeeper.SetFileOverlayStatus(state.Path, FileOverlayStatus.Synch);
|
|
519 |
this.StatusKeeper.SetFileOverlayStatus(state.Path, FileOverlayStatus.Modified);
|
|
500 | 520 |
|
501 | 521 |
|
502 | 522 |
|
503 |
CloudClient.MoveObject("PITHOS", state.OldFileName, state.FileName);
|
|
523 |
CloudClient.MoveObject(PithosContainer, state.OldFileName,PithosContainer, state.FileName);
|
|
504 | 524 |
|
505 | 525 |
this.StatusKeeper.SetFileStatus(state.Path, FileStatus.Unchanged); |
506 | 526 |
this.StatusKeeper.SetFileOverlayStatus(state.Path, FileOverlayStatus.Normal); |
... | ... | |
511 | 531 |
{ |
512 | 532 |
Contract.Requires(!Path.IsPathRooted(fileName)); |
513 | 533 |
|
514 |
this.StatusKeeper.SetFileOverlayStatus(fileName, FileOverlayStatus.Synch); |
|
515 |
CloudClient.DeleteObject("PITHOS", fileName); |
|
534 |
this.StatusKeeper.SetFileOverlayStatus(fileName, FileOverlayStatus.Modified); |
|
535 |
|
|
536 |
CloudClient.MoveObject(PithosContainer,fileName,TrashContainer,fileName); |
|
516 | 537 |
this.StatusKeeper.ClearFileStatus(fileName); |
517 | 538 |
this.StatusKeeper.RemoveFileOverlayStatus(fileName); |
518 | 539 |
} |
... | ... | |
537 | 558 |
StatusKeeper.SetNetworkState(fileName,NetworkState.Uploading); |
538 | 559 |
|
539 | 560 |
//Even if GetObjectInfo times out, we can proceed with the upload |
540 |
var info = CloudClient.GetObjectInfo("PITHOS", fileName);
|
|
561 |
var info = CloudClient.GetObjectInfo(PithosContainer, fileName);
|
|
541 | 562 |
Task.Factory.StartNew(() => |
542 | 563 |
{ |
543 | 564 |
if (hash != info.Hash) |
544 | 565 |
{ |
545 | 566 |
Task.Factory.StartNew(() => |
546 |
this.StatusKeeper.SetFileOverlayStatus(path, FileOverlayStatus.Synch))
|
|
567 |
this.StatusKeeper.SetFileOverlayStatus(path, FileOverlayStatus.Modified))
|
|
547 | 568 |
.ContinueWith(t => |
548 |
CloudClient.PutObject("PITHOS", fileName, path, hash));
|
|
569 |
CloudClient.PutObject(PithosContainer, fileName, path, hash));
|
|
549 | 570 |
} |
550 | 571 |
else |
551 | 572 |
{ |
b/trunk/Pithos.Core/StatusKeeper.cs | ||
---|---|---|
1 | 1 |
using System; |
2 |
using System.Collections; |
|
2 | 3 |
using System.Collections.Concurrent; |
3 | 4 |
using System.Collections.Generic; |
4 | 5 |
using System.ComponentModel.Composition; |
... | ... | |
12 | 13 |
using System.Threading; |
13 | 14 |
using System.Threading.Tasks; |
14 | 15 |
using Castle.ActiveRecord; |
15 |
using Castle.ActiveRecord.Framework; |
|
16 | 16 |
using Castle.ActiveRecord.Framework.Config; |
17 | 17 |
using Pithos.Interfaces; |
18 | 18 |
|
... | ... | |
24 | 24 |
[System.ComponentModel.Composition.Import] |
25 | 25 |
public IPithosSettings Settings { get; set; } |
26 | 26 |
|
27 |
private BlockingCollection<Action> _statusUpdateQueue = new BlockingCollection<Action>(); |
|
28 |
//private readonly CancellationToken _cancel=new CancellationToken(); |
|
27 |
private BlockingCollection<Action> _statusUpdateQueue = new BlockingCollection<Action>(); |
|
29 | 28 |
|
30 | 29 |
public StatusKeeper() |
31 |
{ |
|
32 |
var source = new XmlConfigurationSource("DbConfig.xml"); |
|
33 |
ActiveRecordStarter.Initialize(source,typeof(FileState)); |
|
30 |
{ |
|
31 |
var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); |
|
32 |
var pithosDbPath = Path.Combine(appDataPath , "Pithos"); |
|
33 |
|
|
34 |
var source = GetConfiguration(pithosDbPath); |
|
35 |
ActiveRecordStarter.Initialize(source,typeof(FileState),typeof(FileTag)); |
|
34 | 36 |
|
35 |
if (!File.Exists("pithos.db"))
|
|
37 |
if (!File.Exists(Path.Combine(pithosDbPath ,"pithos.db")))
|
|
36 | 38 |
ActiveRecordStarter.CreateSchema(); |
37 | 39 |
|
38 |
Task.Factory.StartNew(ProcessUpdates); |
|
40 |
} |
|
41 |
|
|
42 |
private static InPlaceConfigurationSource GetConfiguration(string pithosDbPath) |
|
43 |
{ |
|
44 |
var properties = new Dictionary<string, string> |
|
45 |
{ |
|
46 |
{"connection.driver_class", "NHibernate.Driver.SQLite20Driver"}, |
|
47 |
{"dialect", "NHibernate.Dialect.SQLiteDialect"}, |
|
48 |
{"connection.provider", "NHibernate.Connection.DriverConnectionProvider"}, |
|
49 |
{ |
|
50 |
"proxyfactory.factory_class", |
|
51 |
"NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle" |
|
52 |
}, |
|
53 |
}; |
|
54 |
|
|
55 |
var connectionString = String.Format(@"Data Source={0}\pithos.db;Version=3", pithosDbPath); |
|
56 |
properties.Add("connection.connection_string", connectionString); |
|
57 |
|
|
58 |
var source = new InPlaceConfigurationSource(); |
|
59 |
|
|
60 |
source.Add(typeof (ActiveRecordBase), properties); |
|
61 |
return source; |
|
62 |
} |
|
63 |
|
|
64 |
public void StartProcessing(CancellationToken token) |
|
65 |
{ |
|
66 |
Task.Factory.StartNew(ProcessUpdates,token); |
|
39 | 67 |
} |
40 | 68 |
|
41 | 69 |
public void ProcessUpdates() |
... | ... | |
48 | 76 |
|
49 | 77 |
public void Stop() |
50 | 78 |
{ |
51 |
_statusUpdateQueue.CompleteAdding(); |
|
79 |
_statusUpdateQueue.CompleteAdding();
|
|
52 | 80 |
} |
53 | 81 |
|
54 | 82 |
|
... | ... | |
142 | 170 |
return NetworkState.None; |
143 | 171 |
} |
144 | 172 |
|
145 |
|
|
146 | 173 |
public T GetStatus<T>(string path,Func<FileState,T> getter,T defaultValue ) |
147 | 174 |
{ |
148 | 175 |
|
... | ... | |
236 | 263 |
SetStatus(path,s=>s.OverlayStatus=overlayStatus); |
237 | 264 |
} |
238 | 265 |
|
239 |
/* private static void InnerSetOverlayStatus(string path, FileOverlayStatus overlayStatus) |
|
240 |
{ |
|
241 |
var filePath = path.ToLower(); |
|
242 |
var state = FileState.TryFind(filePath); |
|
243 |
if (state != null) |
|
244 |
{ |
|
245 |
state.OverlayStatus = overlayStatus; |
|
246 |
state.Update(); |
|
247 |
} |
|
248 |
else |
|
249 |
{ |
|
250 |
state = new FileState |
|
251 |
{FilePath = filePath, OverlayStatus = overlayStatus}; |
|
252 |
state.Save(); |
|
253 |
} |
|
254 |
}*/ |
|
255 |
|
|
256 | 266 |
public void RemoveFileOverlayStatus(string path) |
257 | 267 |
{ |
258 | 268 |
_statusUpdateQueue.Add(() => |
... | ... | |
306 | 316 |
state.FilePath = path.ToLower(); |
307 | 317 |
state.Checksum = objectInfo.Hash; |
308 | 318 |
state.FileStatus = FileStatus.Unchanged; |
309 |
state.OverlayStatus = FileOverlayStatus.Normal; |
|
319 |
state.OverlayStatus = FileOverlayStatus.Normal; |
|
320 |
foreach (var tag in objectInfo.Tags) |
|
321 |
{ |
|
322 |
state.Tags.Add(new FileTag |
|
323 |
{ |
|
324 |
FilePath=state.FilePath, |
|
325 |
FileState=state, |
|
326 |
Value=tag.Value |
|
327 |
}); |
|
328 |
} |
|
310 | 329 |
|
311 | 330 |
state.Save(); |
312 | 331 |
|
b/trunk/Pithos.Interfaces/AccountSettings.cs | ||
---|---|---|
24 | 24 |
|
25 | 25 |
public bool IsActive { get; set; } |
26 | 26 |
|
27 |
public bool UsePithos { get; set; } |
|
28 |
|
|
27 | 29 |
public string RootPath { get; set; } |
28 | 30 |
|
29 | 31 |
private StringCollection _selectiveFolders = new StringCollection(); |
b/trunk/Pithos.Interfaces/ICloudClient.cs | ||
---|---|---|
1 | 1 |
using System; |
2 | 2 |
using System.Collections.Generic; |
3 | 3 |
using System.Diagnostics.Contracts; |
4 |
using System.IO; |
|
5 | 4 |
using System.Linq; |
6 | 5 |
using System.Text; |
7 | 6 |
using System.Threading.Tasks; |
... | ... | |
33 | 32 |
Task GetObject(string container, string objectName, string fileName); |
34 | 33 |
Task PutObject(string container, string objectName, string fileName, string hash = null); |
35 | 34 |
void DeleteObject(string container, string objectName); |
36 |
void MoveObject(string container, string oldObjectName, string newObjectName);
|
|
35 |
void MoveObject(string sourceContainer, string oldObjectName, string targetContainer,string newObjectName);
|
|
37 | 36 |
bool ObjectExists(string container,string objectName); |
38 | 37 |
ObjectInfo GetObjectInfo(string container, string objectName); |
39 | 38 |
void CreateFolder(string container, string folder); |
... | ... | |
156 | 155 |
Contract.Requires(!String.IsNullOrWhiteSpace(objectName)); |
157 | 156 |
} |
158 | 157 |
|
159 |
public void MoveObject(string container, string oldObjectName, string newObjectName)
|
|
158 |
public void MoveObject(string sourceContainer, string oldObjectName, string targetContainer,string newObjectName)
|
|
160 | 159 |
{ |
161 | 160 |
Contract.Requires(!String.IsNullOrWhiteSpace(Token)); |
162 | 161 |
Contract.Requires(StorageUrl!=null); |
163 |
Contract.Requires(!String.IsNullOrWhiteSpace(container));
|
|
162 |
Contract.Requires(!String.IsNullOrWhiteSpace(sourceContainer));
|
|
164 | 163 |
Contract.Requires(!String.IsNullOrWhiteSpace(oldObjectName)); |
164 |
Contract.Requires(!String.IsNullOrWhiteSpace(targetContainer)); |
|
165 | 165 |
Contract.Requires(!String.IsNullOrWhiteSpace(newObjectName)); |
166 | 166 |
} |
167 | 167 |
|
... | ... | |
202 | 202 |
|
203 | 203 |
public static ContainerInfo Empty=new ContainerInfo(); |
204 | 204 |
} |
205 |
|
|
206 |
public class ObjectInfo |
|
207 |
{ |
|
208 |
public string Name { get; set; } |
|
209 |
public string Hash { get; set; } |
|
210 |
public long Bytes { get; set; } |
|
211 |
public string Content_Type { get; set; } |
|
212 |
public DateTime Last_Modified { get; set; } |
|
213 |
|
|
214 |
private Dictionary<string, string> _tags=new Dictionary<string, string>(); |
|
215 |
public Dictionary<string, string> Tags |
|
216 |
{ |
|
217 |
get { return _tags; } |
|
218 |
set { _tags = value; } |
|
219 |
} |
|
220 |
|
|
221 |
public Stream Stream { get; set; } |
|
222 |
|
|
223 |
public static ObjectInfo Empty=new ObjectInfo {Name=String.Empty,Hash=String.Empty,Bytes=0,Content_Type=String.Empty,Last_Modified=DateTime.MinValue}; |
|
224 |
} |
|
225 | 205 |
} |
b/trunk/Pithos.Interfaces/IStatusChecker.cs | ||
---|---|---|
3 | 3 |
using System.Diagnostics.Contracts; |
4 | 4 |
using System.Linq; |
5 | 5 |
using System.Text; |
6 |
using System.Threading; |
|
6 | 7 |
|
7 | 8 |
namespace Pithos.Interfaces |
8 | 9 |
{ |
... | ... | |
29 | 30 |
{ |
30 | 31 |
return default(PithosStatus); |
31 | 32 |
} |
33 |
|
|
32 | 34 |
} |
33 | 35 |
|
34 | 36 |
public enum FileOverlayStatus |
... | ... | |
37 | 39 |
Unversioned=-1, |
38 | 40 |
Normal=0, |
39 | 41 |
Modified=1, |
40 |
Conflict=2, |
|
41 |
Synch=3 |
|
42 |
Conflict=2 |
|
42 | 43 |
} |
43 | 44 |
|
44 | 45 |
public enum PithosStatus |
b/trunk/Pithos.Interfaces/ObjectInfo.cs | ||
---|---|---|
1 |
using System; |
|
2 |
using System.Collections.Generic; |
|
3 |
using System.IO; |
|
4 |
|
|
5 |
namespace Pithos.Interfaces |
|
6 |
{ |
|
7 |
public class ObjectInfo |
|
8 |
{ |
|
9 |
public string Name { get; set; } |
|
10 |
public string Hash { get; set; } |
|
11 |
public long Bytes { get; set; } |
|
12 |
public string Content_Type { get; set; } |
|
13 |
public DateTime Last_Modified { get; set; } |
|
14 |
|
|
15 |
private Dictionary<string, string> _tags=new Dictionary<string, string>(); |
|
16 |
public Dictionary<string, string> Tags |
|
17 |
{ |
|
18 |
get { return _tags; } |
|
19 |
set { _tags = value; } |
|
20 |
} |
|
21 |
|
|
22 |
private Dictionary<string, string> _extensions=new Dictionary<string, string>(); |
|
23 |
public Dictionary<string, string> Extensions |
|
24 |
{ |
|
25 |
get { return _extensions; } |
|
26 |
set { _extensions = value; } |
|
27 |
} |
|
28 |
|
|
29 |
|
|
30 |
|
|
31 |
public Stream Stream { get; set; } |
|
32 |
|
|
33 |
public static ObjectInfo Empty=new ObjectInfo {Name=String.Empty,Hash=String.Empty,Bytes=0,Content_Type=String.Empty,Last_Modified=DateTime.MinValue}; |
|
34 |
} |
|
35 |
} |
b/trunk/Pithos.Interfaces/Pithos.Interfaces.csproj | ||
---|---|---|
13 | 13 |
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion> |
14 | 14 |
<FileAlignment>512</FileAlignment> |
15 | 15 |
<CodeContractsAssemblyMode>1</CodeContractsAssemblyMode> |
16 |
<TargetFrameworkProfile>Client</TargetFrameworkProfile> |
|
16 | 17 |
</PropertyGroup> |
17 | 18 |
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> |
18 | 19 |
<DebugSymbols>true</DebugSymbols> |
... | ... | |
92 | 93 |
<Compile Include="ICloudClient.cs" /> |
93 | 94 |
<Compile Include="IPithosSettings.cs" /> |
94 | 95 |
<Compile Include="IStatusChecker.cs" /> |
96 |
<Compile Include="ObjectInfo.cs" /> |
|
95 | 97 |
<Compile Include="PithosSettingsData.cs" /> |
96 | 98 |
<Compile Include="Properties\AssemblyInfo.cs" /> |
97 | 99 |
<Compile Include="Properties\Settings.Designer.cs"> |
b/trunk/Pithos.Interfaces/Properties/Settings.Designer.cs | ||
---|---|---|
22 | 22 |
return defaultInstance; |
23 | 23 |
} |
24 | 24 |
} |
25 |
|
|
26 |
[global::System.Configuration.UserScopedSettingAttribute()] |
|
27 |
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] |
|
28 |
[global::System.Configuration.DefaultSettingValueAttribute("")] |
|
29 |
public string Setting { |
|
30 |
get { |
|
31 |
return ((string)(this["Setting"])); |
|
32 |
} |
|
33 |
set { |
|
34 |
this["Setting"] = value; |
|
35 |
} |
|
36 |
} |
|
37 | 25 |
} |
38 | 26 |
} |
b/trunk/Pithos.Interfaces/app.config | ||
---|---|---|
1 |
<?xml version="1.0" encoding="utf-8" ?>
|
|
1 |
<?xml version="1.0"?>
|
|
2 | 2 |
<configuration> |
3 |
</configuration> |
|
3 |
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0,Profile=Client"/></startup></configuration> |
b/trunk/Pithos.Network.Test/NetworkOpsTest.cs | ||
---|---|---|
284 | 284 |
|
285 | 285 |
Assert.IsTrue(client.ObjectExists("Shares",info.Name),"File Created"); |
286 | 286 |
|
287 |
client.MoveObject("Shares",info.Name,"smoo.pdf"); |
|
287 |
client.MoveObject("Shares",info.Name,"Shares","smoo.pdf");
|
|
288 | 288 |
Assert.IsFalse(client.ObjectExists("Shares", info.Name),"Original File Deleted"); |
289 | 289 |
Assert.IsTrue(client.ObjectExists("Shares", "smoo.pdf"), "Target File Created"); |
290 | 290 |
|
b/trunk/Pithos.Network/CloudFilesClient.cs | ||
---|---|---|
24 | 24 |
public class CloudFilesClient:ICloudClient |
25 | 25 |
{ |
26 | 26 |
string _rackSpaceAuthUrl = "https://auth.api.rackspacecloud.com"; |
27 |
private string _pithosAuthUrl = "https://pithos.grnet.gr"; |
|
27 |
private string _pithosAuthUrl = "https://pithos.dev.grnet.gr";
|
|
28 | 28 |
|
29 | 29 |
private RestClient _client; |
30 | 30 |
private readonly TimeSpan _shortTimeout = TimeSpan.FromSeconds(10); |
... | ... | |
51 | 51 |
|
52 | 52 |
public bool UsePithos { get; set; } |
53 | 53 |
|
54 |
private bool _authenticated = false; |
|
55 |
|
|
54 | 56 |
public void Authenticate(string userName,string apiKey) |
55 | 57 |
{ |
56 | 58 |
Trace.TraceInformation("[AUTHENTICATE] Start for {0}", userName); |
... | ... | |
59 | 61 |
if (String.IsNullOrWhiteSpace(apiKey)) |
60 | 62 |
throw new ArgumentNullException("apiKey", "The apiKey property can't be empty"); |
61 | 63 |
|
64 |
if (_authenticated) |
|
65 |
return; |
|
66 |
|
|
62 | 67 |
UserName = userName; |
63 | 68 |
ApiKey = apiKey; |
64 | 69 |
|
65 | 70 |
var proxy = Proxy != null ? Proxy.ToString() : null; |
66 | 71 |
if (UsePithos) |
67 | 72 |
{ |
68 |
Token = "0000";
|
|
73 |
Token = ApiKey;
|
|
69 | 74 |
string storageUrl = String.Format("{0}/{1}/{2}", AuthUrl, VersionPath, UserName); |
70 | 75 |
StorageUrl = new Uri(storageUrl); |
71 | 76 |
} |
... | ... | |
214 | 219 |
|
215 | 220 |
switch(response.StatusCode) |
216 | 221 |
{ |
222 |
case HttpStatusCode.OK: |
|
217 | 223 |
case HttpStatusCode.NoContent: |
218 | 224 |
return true; |
219 | 225 |
case HttpStatusCode.NotFound: |
220 |
return false;
|
|
226 |
return false; |
|
221 | 227 |
default: |
222 |
throw new WebException(String.Format("ContainerExists failed with unexpected status code {0}",response.StatusCode));
|
|
228 |
throw CreateWebException("ContainerExists",response.StatusCode);
|
|
223 | 229 |
} |
224 | 230 |
} |
225 | 231 |
|
... | ... | |
242 | 248 |
case HttpStatusCode.NotFound: |
243 | 249 |
return false; |
244 | 250 |
default: |
245 |
throw new WebException(String.Format("ObjectExists failed with unexpected status code {0}", response.StatusCode));
|
|
251 |
throw CreateWebException("ObjectExists",response.StatusCode);
|
|
246 | 252 |
} |
247 | 253 |
|
248 | 254 |
} |
... | ... | |
271 | 277 |
let name=key.Substring(14) |
272 | 278 |
select new {Name=name,Value=response.Headers[name]}) |
273 | 279 |
.ToDictionary(t=>t.Name,t=>t.Value); |
280 |
var extensions = (from key in keys |
|
281 |
where key.StartsWith("X-Object-") && !key.StartsWith("X-Object-Meta-") |
|
282 |
let name = key.Substring(9) |
|
283 |
select new { Name = name, Value = response.Headers[name] }) |
|
284 |
.ToDictionary(t => t.Name, t => t.Value); |
|
274 | 285 |
return new ObjectInfo |
275 | 286 |
{ |
276 | 287 |
Name = objectName, |
277 | 288 |
Bytes = long.Parse(GetHeaderValue("Content-Length", response, keys)), |
278 | 289 |
Hash = GetHeaderValue("ETag", response, keys), |
279 | 290 |
Content_Type = GetHeaderValue("Content-Type", response, keys), |
280 |
Tags=tags |
|
291 |
Tags=tags, |
|
292 |
Extensions=extensions |
|
281 | 293 |
}; |
282 | 294 |
case HttpStatusCode.NotFound: |
283 | 295 |
return ObjectInfo.Empty; |
... | ... | |
309 | 321 |
var response = _client.Request(request); |
310 | 322 |
|
311 | 323 |
if (response.StatusCode != HttpStatusCode.Created && response.StatusCode != HttpStatusCode.Accepted) |
312 |
throw new WebException(String.Format("CreateFolder failed with unexpected status code {0}", response.StatusCode));
|
|
324 |
throw CreateWebException("CreateFolder", response.StatusCode);
|
|
313 | 325 |
|
314 | 326 |
} |
315 | 327 |
|
... | ... | |
335 | 347 |
case HttpStatusCode.NotFound: |
336 | 348 |
return ContainerInfo.Empty; |
337 | 349 |
default: |
338 |
throw new WebException(String.Format("ContainerExists failed with unexpected status code {0}",response.StatusCode));
|
|
350 |
throw CreateWebException("GetContainerInfo", response.StatusCode);
|
|
339 | 351 |
} |
340 | 352 |
} |
341 | 353 |
|
... | ... | |
347 | 359 |
var request = new RestRequest { Path = container, Method = WebMethod.Put, RetryPolicy = _retryPolicy,Timeout = _shortTimeout }; |
348 | 360 |
|
349 | 361 |
var response = _client.Request(request); |
350 |
|
|
351 |
if (response.StatusCode!=HttpStatusCode.Created && response.StatusCode!=HttpStatusCode.Accepted ) |
|
352 |
throw new WebException(String.Format("ContainerExists failed with unexpected status code {0}", response.StatusCode)); |
|
362 |
|
|
363 |
var expectedCodes = new[]{HttpStatusCode.Created ,HttpStatusCode.Accepted , HttpStatusCode.OK}; |
|
364 |
if (!expectedCodes.Contains(response.StatusCode)) |
|
365 |
throw CreateWebException("CreateContainer", response.StatusCode); |
|
353 | 366 |
} |
354 | 367 |
|
355 | 368 |
public void DeleteContainer(string container) |
... | ... | |
360 | 373 |
var request = new RestRequest { Path = container, Method = WebMethod.Delete, RetryPolicy = _retryPolicy,Timeout = _shortTimeout }; |
361 | 374 |
var response = _client.Request(request); |
362 | 375 |
|
363 |
if (response.StatusCode == HttpStatusCode.NotFound || response.StatusCode == HttpStatusCode.NoContent) |
|
364 |
return; |
|
365 |
else |
|
366 |
throw new WebException(String.Format("DeleteContainer failed with unexpected status code {0}", response.StatusCode)); |
|
376 |
var expectedCodes = new[] { HttpStatusCode.NotFound, HttpStatusCode.NoContent}; |
|
377 |
if (!expectedCodes.Contains(response.StatusCode)) |
|
378 |
throw CreateWebException("DeleteContainer", response.StatusCode); |
|
367 | 379 |
|
368 | 380 |
} |
369 | 381 |
|
... | ... | |
539 | 551 |
var request = new RestRequest { Path = container + "/" + objectName, Method = WebMethod.Delete, RetryPolicy = _retryPolicy,Timeout = _shortTimeout }; |
540 | 552 |
var response = _client.Request(request); |
541 | 553 |
|
542 |
if (response.StatusCode == HttpStatusCode.NotFound || response.StatusCode == HttpStatusCode.NoContent) |
|
543 |
return; |
|
544 |
else |
|
545 |
throw new WebException(String.Format("DeleteObject failed with unexpected status code {0}", response.StatusCode)); |
|
554 |
var expectedCodes = new[] { HttpStatusCode.NotFound, HttpStatusCode.NoContent }; |
|
555 |
if (!expectedCodes.Contains(response.StatusCode)) |
|
556 |
throw CreateWebException("DeleteObject", response.StatusCode); |
|
546 | 557 |
|
547 | 558 |
} |
548 | 559 |
|
549 |
public void MoveObject(string container, string oldObjectName, string newObjectName)
|
|
560 |
public void MoveObject(string sourceContainer, string oldObjectName, string targetContainer,string newObjectName)
|
|
550 | 561 |
{ |
551 |
if (String.IsNullOrWhiteSpace(container))
|
|
552 |
throw new ArgumentNullException("container", "The container property can't be empty");
|
|
562 |
if (String.IsNullOrWhiteSpace(sourceContainer))
|
|
563 |
throw new ArgumentNullException("sourceContainer", "The container property can't be empty");
|
|
553 | 564 |
if (String.IsNullOrWhiteSpace(oldObjectName)) |
554 | 565 |
throw new ArgumentNullException("oldObjectName", "The oldObjectName property can't be empty"); |
566 |
if (String.IsNullOrWhiteSpace(targetContainer)) |
|
567 |
throw new ArgumentNullException("targetContainer", "The container property can't be empty"); |
|
555 | 568 |
if (String.IsNullOrWhiteSpace(newObjectName)) |
556 | 569 |
throw new ArgumentNullException("newObjectName", "The newObjectName property can't be empty"); |
557 | 570 |
|
558 |
var request = new RestRequest { Path = container + "/" + newObjectName, Method = WebMethod.Put }; |
|
559 |
request.AddHeader("X-Copy-From",String.Format("/{0}/{1}",container,oldObjectName)); |
|
571 |
var targetUrl = targetContainer + "/" + newObjectName; |
|
572 |
var sourceUrl = String.Format("/{0}/{1}", sourceContainer, oldObjectName); |
|
573 |
|
|
574 |
var request = new RestRequest { Path = targetUrl, Method = WebMethod.Put }; |
|
575 |
request.AddHeader("X-Copy-From",sourceUrl); |
|
560 | 576 |
request.AddPostContent(new byte[]{}); |
561 | 577 |
var response = _client.Request(request); |
562 | 578 |
|
563 |
if (response.StatusCode == HttpStatusCode.OK || response.StatusCode == HttpStatusCode.NoContent || response.StatusCode==HttpStatusCode.Created) |
|
579 |
|
|
580 |
var expectedCodes = new[] { HttpStatusCode.OK ,HttpStatusCode.NoContent ,HttpStatusCode.Created }; |
|
581 |
if (expectedCodes.Contains(response.StatusCode)) |
|
564 | 582 |
{ |
565 |
this.DeleteObject(container,oldObjectName);
|
|
583 |
this.DeleteObject(sourceContainer,oldObjectName);
|
|
566 | 584 |
} |
567 | 585 |
else |
568 |
throw new WebException(String.Format("MoveObject failed with unexpected status code {0}", response.StatusCode));
|
|
586 |
throw CreateWebException("MoveObject", response.StatusCode);
|
|
569 | 587 |
} |
570 | 588 |
|
571 | 589 |
private string GetHeaderValue(string headerName, RestResponse response, IQueryable<string> keys) |
... | ... | |
582 | 600 |
if (status < 200 || status >= 300) |
583 | 601 |
throw new WebException(String.Format("{0} with code {1}",message, status)); |
584 | 602 |
} |
603 |
|
|
604 |
private static WebException CreateWebException(string operation, HttpStatusCode statusCode) |
|
605 |
{ |
|
606 |
return new WebException(String.Format("{0} failed with unexpected status code {1}", operation, statusCode)); |
|
607 |
} |
|
608 |
|
|
585 | 609 |
} |
586 | 610 |
} |
b/trunk/Pithos.Setup.x64/Pithos.Setup.x64.vdproj | ||
---|---|---|
267 | 267 |
} |
268 | 268 |
"Entry" |
269 | 269 |
{ |
270 |
"MsmKey" = "8:_75D885F375DFDB481975C88F857E2ACF" |
|
271 |
"OwnerKey" = "8:_311197E10704448D93A69A8EC39C3C80" |
|
272 |
"MsmSig" = "8:_UNDEFINED" |
|
273 |
} |
|
274 |
"Entry" |
|
275 |
{ |
|
276 | 270 |
"MsmKey" = "8:_8046A0650A0FDBD7044C0059B48CB6EA" |
277 | 271 |
"OwnerKey" = "8:_C4EB6477683944848E47C160C41EA94A" |
278 | 272 |
"MsmSig" = "8:_UNDEFINED" |
... | ... | |
472 | 466 |
"Entry" |
473 | 467 |
{ |
474 | 468 |
"MsmKey" = "8:_E573D8AD1AAEB39255958325DA5EDBD5" |
469 |
"OwnerKey" = "8:_BAA515E0FCDE402CBF2A6FF3D94A0B83" |
|
470 |
"MsmSig" = "8:_UNDEFINED" |
|
471 |
} |
|
472 |
"Entry" |
|
473 |
{ |
|
474 |
"MsmKey" = "8:_E573D8AD1AAEB39255958325DA5EDBD5" |
|
475 | 475 |
"OwnerKey" = "8:_1082D2B1D4BC998D946F5A9AADC3F5BE" |
476 | 476 |
"MsmSig" = "8:_UNDEFINED" |
477 | 477 |
} |
... | ... | |
610 | 610 |
"Entry" |
611 | 611 |
{ |
612 | 612 |
"MsmKey" = "8:_UNDEFINED" |
613 |
"OwnerKey" = "8:_75D885F375DFDB481975C88F857E2ACF" |
|
614 |
"MsmSig" = "8:_UNDEFINED" |
|
615 |
} |
|
616 |
"Entry" |
|
617 |
{ |
|
618 |
"MsmKey" = "8:_UNDEFINED" |
|
619 | 613 |
"OwnerKey" = "8:_8202743C43C25F5033105429DB6BB9A3" |
620 | 614 |
"MsmSig" = "8:_UNDEFINED" |
621 | 615 |
} |
... | ... | |
712 | 706 |
"DisplayName" = "8:Release" |
713 | 707 |
"IsDebugOnly" = "11:FALSE" |
714 | 708 |
"IsReleaseOnly" = "11:TRUE" |
715 |
"OutputFilename" = "8:Release\\Pithos.Setup.msi"
|
|
709 |
"OutputFilename" = "8:Release\\Pithos.x64.msi"
|
|
716 | 710 |
"PackageFilesAs" = "3:2" |
717 | 711 |
"PackageFileSize" = "3:-2147483648" |
718 | 712 |
"CabType" = "3:1" |
... | ... | |
1144 | 1138 |
"IsDependency" = "11:TRUE" |
1145 | 1139 |
"IsolateTo" = "8:" |
1146 | 1140 |
} |
1147 |
"{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_75D885F375DFDB481975C88F857E2ACF" |
|
1148 |
{ |
|
1149 |
"AssemblyRegister" = "3:1" |
|
1150 |
"AssemblyIsInGAC" = "11:FALSE" |
|
1151 |
"AssemblyAsmDisplayName" = "8:log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=1b44e1d426115821, processorArchitecture=MSIL" |
|
1152 |
"ScatterAssemblies" |
|
1153 |
{ |
|
1154 |
"_75D885F375DFDB481975C88F857E2ACF" |
|
1155 |
{ |
|
1156 |
"Name" = "8:log4net.dll" |
|
1157 |
"Attributes" = "3:512" |
|
1158 |
} |
|
1159 |
} |
|
1160 |
"SourcePath" = "8:log4net.dll" |
|
1161 |
"TargetName" = "8:" |
|
1162 |
"Tag" = "8:" |
|
1163 |
"Folder" = "8:_2E4412A903CE41838ECE5DCF9470F71C" |
|
1164 |
"Condition" = "8:" |
|
1165 |
"Transitive" = "11:FALSE" |
|
1166 |
"Vital" = "11:TRUE" |
|
1167 |
"ReadOnly" = "11:FALSE" |
|
1168 |
"Hidden" = "11:FALSE" |
|
1169 |
"System" = "11:FALSE" |
|
1170 |
"Permanent" = "11:FALSE" |
|
1171 |
"SharedLegacy" = "11:FALSE" |
|
1172 |
"PackageAs" = "3:1" |
|
1173 |
"Register" = "3:1" |
|
1174 |
"Exclude" = "11:FALSE" |
|
1175 |
"IsDependency" = "11:TRUE" |
|
1176 |
"IsolateTo" = "8:" |
|
1177 |
} |
|
1178 | 1141 |
"{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_8046A0650A0FDBD7044C0059B48CB6EA" |
1179 | 1142 |
{ |
1180 | 1143 |
"AssemblyRegister" = "3:1" |
... | ... | |
1531 | 1494 |
"Name" = "8:Microsoft Visual Studio" |
1532 | 1495 |
"ProductName" = "8:Pithos" |
1533 | 1496 |
"ProductCode" = "8:{6DF108D9-D8FB-4438-9B83-A06A272FF56D}" |
1534 |
"PackageCode" = "8:{8E3F2A81-BB48-40F5-9B4E-227968B82A9D}"
|
|
1497 |
"PackageCode" = "8:{39630321-B3C1-43A3-AA45-6CEBCFE10B93}"
|
|
1535 | 1498 |
"UpgradeCode" = "8:{9D7BB283-458F-4124-A847-E42AFC9D5514}" |
1536 | 1499 |
"AspNetVersion" = "8:4.0.30319.0" |
1537 | 1500 |
"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 |
|
b/trunk/Pithos.ShellExtensions/Pithos.ShellExtensions.csproj | ||
---|---|---|
13 | 13 |
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion> |
14 | 14 |
<FileAlignment>512</FileAlignment> |
15 | 15 |
<CodeContractsAssemblyMode>1</CodeContractsAssemblyMode> |
16 |
<TargetFrameworkProfile>Client</TargetFrameworkProfile> |
|
16 | 17 |
</PropertyGroup> |
17 | 18 |
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> |
18 | 19 |
<DebugSymbols>true</DebugSymbols> |
... | ... | |
167 | 168 |
<EmbeddedResource Include="Properties\Resources.resx"> |
168 | 169 |
<Generator>ResXFileCodeGenerator</Generator> |
169 | 170 |
<LastGenOutput>Resources.Designer.cs</LastGenOutput> |
171 |
<SubType>Designer</SubType> |
|
170 | 172 |
</EmbeddedResource> |
171 | 173 |
</ItemGroup> |
172 | 174 |
<ItemGroup> |
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 |
} |
|
76 |
|
|
77 |
internal static System.Drawing.Icon Tray { |
|
78 |
get { |
|
79 |
object obj = ResourceManager.GetObject("Tray", resourceCulture); |
|
80 |
return ((System.Drawing.Icon)(obj)); |
|
81 |
} |
|
82 |
} |
|
83 | 62 |
} |
84 | 63 |
} |
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=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
|
115 |
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.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=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
|
118 |
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.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> |
|
127 |
<data name="Tray" type="System.Resources.ResXFileRef, System.Windows.Forms"> |
|
128 |
<value>..\Resources\Tray.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> |
|
129 |
</data> |
|
130 | 120 |
</root> |
b/trunk/Pithos.ShellExtensions/app.config | ||
---|---|---|
1 |
<?xml version="1.0" encoding="utf-8" ?>
|
|
1 |
<?xml version="1.0"?>
|
|
2 | 2 |
<configuration> |
3 | 3 |
<system.serviceModel> |
4 | 4 |
<bindings> |
5 | 5 |
<netNamedPipeBinding> |
6 |
<binding name="NetNamedPipeBinding_IStatusService" closeTimeout="00:01:00" |
|
7 |
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" |
|
8 |
transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions" |
|
9 |
hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" |
|
10 |
maxBufferSize="65536" maxConnections="10" maxReceivedMessageSize="65536"> |
|
11 |
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" |
|
12 |
maxBytesPerRead="4096" maxNameTableCharCount="16384" /> |
|
6 |
<binding name="NetNamedPipeBinding_IStatusService" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxBufferSize="65536" maxConnections="10" maxReceivedMessageSize="65536"> |
|
7 |
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/> |
|
13 | 8 |
<security mode="None"> |
14 |
<transport protectionLevel="EncryptAndSign" />
|
|
9 |
<transport protectionLevel="EncryptAndSign"/> |
|
15 | 10 |
</security> |
16 | 11 |
</binding> |
17 |
<binding name="NetNamedPipeBinding_ISettingsService" closeTimeout="00:01:00" |
|
18 |
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" |
|
19 |
transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions" |
|
20 |
hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" |
|
21 |
maxBufferSize="65536" maxConnections="10" maxReceivedMessageSize="65536"> |
|
22 |
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" |
|
23 |
maxBytesPerRead="4096" maxNameTableCharCount="16384" /> |
|
12 |
<binding name="NetNamedPipeBinding_ISettingsService" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxBufferSize="65536" maxConnections="10" maxReceivedMessageSize="65536"> |
|
13 |
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/> |
|
24 | 14 |
<security mode="None"> |
25 |
<transport protectionLevel="EncryptAndSign" />
|
|
15 |
<transport protectionLevel="EncryptAndSign"/> |
|
26 | 16 |
</security> |
27 | 17 |
</binding> |
28 | 18 |
</netNamedPipeBinding> |
29 | 19 |
</bindings> |
30 | 20 |
<client> |
31 |
<endpoint address="net.pipe://localhost/pithos/statuscache" binding="netNamedPipeBinding" |
|
32 |
bindingConfiguration="NetNamedPipeBinding_IStatusService" |
|
33 |
contract="PithosService.IStatusService" name="NetNamedPipeBinding_IStatusService" /> |
|
34 |
<endpoint address="net.pipe://localhost/pithos/settings" binding="netNamedPipeBinding" |
|
35 |
bindingConfiguration="NetNamedPipeBinding_ISettingsService" |
|
36 |
contract="PithosService.ISettingsService" name="NetNamedPipeBinding_ISettingsService" /> |
|
21 |
<endpoint address="net.pipe://localhost/pithos/statuscache" binding="netNamedPipeBinding" bindingConfiguration="NetNamedPipeBinding_IStatusService" contract="PithosService.IStatusService" name="NetNamedPipeBinding_IStatusService"/> |
|
22 |
<endpoint address="net.pipe://localhost/pithos/settings" binding="netNamedPipeBinding" bindingConfiguration="NetNamedPipeBinding_ISettingsService" contract="PithosService.ISettingsService" name="NetNamedPipeBinding_ISettingsService"/> |
|
37 | 23 |
</client> |
38 | 24 |
</system.serviceModel> |
39 |
</configuration> |
|
25 |
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0,Profile=Client"/></startup></configuration> |
Also available in: Unified diff