Fixes to hashing
[pithos-ms-client] / trunk / Pithos.Core / Agents / CloudTransferAction.cs
1 #region
2 /* -----------------------------------------------------------------------
3  * <copyright file="CloudTransferAction.cs" company="GRNet">
4  * 
5  * Copyright 2011-2012 GRNET S.A. All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or
8  * without modification, are permitted provided that the following
9  * conditions are met:
10  *
11  *   1. Redistributions of source code must retain the above
12  *      copyright notice, this list of conditions and the following
13  *      disclaimer.
14  *
15  *   2. Redistributions in binary form must reproduce the above
16  *      copyright notice, this list of conditions and the following
17  *      disclaimer in the documentation and/or other materials
18  *      provided with the distribution.
19  *
20  *
21  * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
22  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
25  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * The views and conclusions contained in the software and
35  * documentation are those of the authors and should not be
36  * interpreted as representing official policies, either expressed
37  * or implied, of GRNET S.A.
38  * </copyright>
39  * -----------------------------------------------------------------------
40  */
41 #endregion
42 using System;
43 using System.Diagnostics.Contracts;
44 using System.IO;
45 using System.Threading;
46 using Pithos.Interfaces;
47 using Pithos.Network;
48
49 namespace Pithos.Core.Agents
50 {
51     public enum CloudActionType
52     {
53         MustSynch,
54         UploadUnconditional,
55         DownloadUnconditional,
56         DeleteLocal,
57         DeleteCloud,
58         RenameCloud,
59         RenameLocal
60     }
61
62     public class CloudAction
63     {
64
65         public object Originator { get; set; }
66         public AccountInfo AccountInfo { get; set; }
67         public CloudActionType Action { get; set; }
68         public FileSystemInfo LocalFile { get; set; }
69         public ObjectInfo CloudFile { get; set; }
70         public FileState FileState { get; set; }
71         public string Container { get; set; }
72
73         public readonly DateTime Created = DateTime.Now;
74
75
76         public Lazy<TreeHash> TreeHash { get; protected set; }
77         //public Lazy<string> TopHash { get; set; }
78
79
80         [ContractInvariantMethod]
81         private void Invariants()
82         {
83             Contract.Invariant(AccountInfo!=null);
84         }
85
86         public bool IsShared
87         {
88             get { return  CloudFile!=null && AccountInfo.UserName != CloudFile.Account; }
89         }
90
91         protected CloudAction(AccountInfo accountInfo,CloudActionType action,object originator)
92         {
93             if (accountInfo==null)
94                 throw new ArgumentNullException("accountInfo");
95             Contract.EndContractBlock();
96
97             Action = action;
98             AccountInfo = accountInfo;
99             Originator = originator;
100         }
101
102         public CloudAction(AccountInfo accountInfo, CloudActionType action, FileSystemInfo localFile, ObjectInfo cloudFile, FileState state, int blockSize, string algorithm,object originator)
103             : this(accountInfo,action,originator)
104         {
105             if(blockSize<=0)
106                 throw new ArgumentOutOfRangeException("blockSize");
107             Contract.EndContractBlock();
108             LocalFile = localFile.WithProperCapitalization();
109             CloudFile = cloudFile;
110             FileState = state;
111             
112             if (LocalFile == null) 
113                 return;
114
115             TreeHash = new Lazy<TreeHash>(() => Signature.CalculateTreeHash(LocalFile, blockSize,algorithm),
116                                             LazyThreadSafetyMode.ExecutionAndPublication);
117         }
118
119         //Calculate the download path for the cloud file
120         public string GetDownloadPath()
121         {
122             if (CloudFile == null)
123                 return String.Empty;
124             var filePath = CloudFile.RelativeUrlToFilePath(AccountInfo.UserName);
125             return Path.Combine(AccountInfo.AccountPath, filePath);
126         }
127
128         public override string ToString()
129         {
130             return String.Format("{0}:{1}->{2}", Action, LocalFile.FullName, CloudFile.Name);
131         }
132
133         protected static ObjectInfo CreateObjectInfoFor(AccountInfo accountInfo, FileSystemInfo fileInfo)
134         {
135             if(accountInfo==null)
136                 throw new ArgumentNullException("accountInfo");
137             if(fileInfo==null)
138                 throw new ArgumentNullException("fileInfo");
139             Contract.Ensures(Contract.Result<ObjectInfo>()!=null);
140             Contract.EndContractBlock();
141
142             var capitalizedFileInfo = fileInfo.WithProperCapitalization();
143             var fullLocalName = capitalizedFileInfo.FullName;
144             var othersPath = Path.Combine(accountInfo.AccountPath, FolderConstants.OthersFolder);
145
146             ObjectInfo objectInfo;
147
148             var isShared = fullLocalName.StartsWith(othersPath, StringComparison.InvariantCultureIgnoreCase);
149             if (isShared)
150             {                
151                 var pathRelativeToOther = fullLocalName.Substring(othersPath.Length + 1);
152                 var otherParts = pathRelativeToOther.Split('\\');
153                 var otherName = otherParts[0];
154                 var otherContainer = otherParts[1];
155                 objectInfo=new ObjectInfo
156                            {
157                                Account = otherName, 
158                                Container = otherContainer, 
159                                Name = String.Join("/", otherParts.Splice(2))
160                            };
161             }
162             else
163                 objectInfo=new ObjectInfo(accountInfo.AccountPath, accountInfo.UserName, fileInfo);
164             
165             objectInfo.Content_Type= (fileInfo is DirectoryInfo)
166                                     ?   "appication/directory"
167                                     :   "application/octet-stream";
168             return objectInfo;
169         }
170     }    
171
172     public class CloudDownloadAction:CloudAction
173     {
174         public CloudDownloadAction(AccountInfo accountInfo, ObjectInfo cloudFile,object originator)
175             :base(accountInfo,CloudActionType.DownloadUnconditional,originator)
176         {            
177             if (String.IsNullOrWhiteSpace(cloudFile.Container))
178                 throw new ArgumentException("CloudFile.Container","cloudFile");
179             Contract.EndContractBlock();
180
181             CloudFile = cloudFile;
182         }
183
184         [ContractInvariantMethod]
185         private void Invariants()
186         {
187             Contract.Invariant(!String.IsNullOrWhiteSpace(CloudFile.Container));
188         }
189
190         public override string ToString()
191         {
192             return String.Format("{0}: _ <- {1}", Action, CloudFile.Name);
193         }
194         
195     }
196     public class CloudDeleteAction:CloudAction
197     {
198         public CloudDeleteAction(AccountInfo accountInfo,FileSystemInfo fileInfo, FileState fileState,object originator)
199             : this(accountInfo,fileInfo,CreateObjectInfoFor(accountInfo, fileInfo),fileState,originator)
200         {            
201         }
202
203         public CloudDeleteAction(AccountInfo accountInfo, FileSystemInfo fileInfo,ObjectInfo cloudFile, FileState fileState,object originator) 
204             : base(accountInfo,CloudActionType.DeleteCloud,originator)
205         {
206             CloudFile = cloudFile;
207             LocalFile = fileInfo;
208             FileState = fileState;
209         }
210
211         public CloudDeleteAction(CloudAction action)
212             : this(action.AccountInfo,action.LocalFile,action.CloudFile,action.FileState,action)
213         {}
214
215         [ContractInvariantMethod]
216         private void Invariants()
217         {
218             Contract.Invariant(!String.IsNullOrWhiteSpace(CloudFile.Container));
219         }
220
221         public override string ToString()
222         {
223             return String.Format("{0}: _ ->{1}", Action, CloudFile.Name);
224         }
225
226     }
227
228     public class CloudUploadAction:CloudAction
229     {
230         public CloudUploadAction(AccountInfo accountInfo, FileSystemInfo fileInfo, FileState state, int blockSize, string algorithm,object originator)
231             : base(accountInfo, CloudActionType.UploadUnconditional,fileInfo,CreateObjectInfoFor(accountInfo,fileInfo),state,blockSize,algorithm,originator)             
232         {
233         }
234
235         [ContractInvariantMethod]
236         private void Invariants()
237         {
238             Contract.Invariant(!String.IsNullOrWhiteSpace(CloudFile.Container));
239         }
240
241     }
242
243     public class CloudMoveAction:CloudAction
244     {
245         public ObjectInfo OldCloudFile { get; set; }
246
247         public FileSystemInfo OldLocalFile { get; set; }
248
249         public CloudMoveAction(AccountInfo accountInfo, CloudActionType action, FileSystemInfo oldFile, FileSystemInfo newFile,object originator)
250             :base(accountInfo,action,originator)
251         {
252             LocalFile = newFile;
253             CloudFile = CreateObjectInfoFor(accountInfo, newFile);
254             
255             OldLocalFile = oldFile;
256             OldCloudFile = CreateObjectInfoFor(accountInfo, oldFile);
257
258             //This is a rename operation, a hash will not be used
259             TreeHash = new Lazy<TreeHash>(() => Network.TreeHash.Empty, LazyThreadSafetyMode.ExecutionAndPublication);
260         }
261
262         public override string ToString()
263         {
264             return String.Format("{0}:{1}->{2}", Action, OldCloudFile.Name, CloudFile.Name);
265         }
266
267     }
268
269 }