#region /* ----------------------------------------------------------------------- * * * Copyright 2011-2012 GRNET S.A. All rights reserved. * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and * documentation are those of the authors and should not be * interpreted as representing official policies, either expressed * or implied, of GRNET S.A. * * ----------------------------------------------------------------------- */ #endregion using System; using System.Diagnostics.Contracts; using System.IO; using System.Threading; using Pithos.Interfaces; using Pithos.Network; namespace Pithos.Core.Agents { public enum CloudActionType { MustSynch, UploadUnconditional, DownloadUnconditional, DeleteLocal, DeleteCloud, RenameCloud, RenameLocal } public class CloudAction { public AccountInfo AccountInfo { get; set; } public CloudActionType Action { get; set; } public FileSystemInfo LocalFile { get; set; } public ObjectInfo CloudFile { get; set; } public FileState FileState { get; set; } public string Container { get; set; } public readonly DateTime Created = DateTime.Now; public Lazy TreeHash { get; protected set; } //public Lazy TopHash { get; set; } [ContractInvariantMethod] private void Invariants() { Contract.Invariant(AccountInfo!=null); } public bool IsShared { get { return CloudFile!=null && AccountInfo.UserName != CloudFile.Account; } } protected CloudAction(AccountInfo accountInfo,CloudActionType action) { if (accountInfo==null) throw new ArgumentNullException("accountInfo"); Contract.EndContractBlock(); Action = action; AccountInfo = accountInfo; } public CloudAction(AccountInfo accountInfo, CloudActionType action, FileSystemInfo localFile, ObjectInfo cloudFile, FileState state, int blockSize, string algorithm) : this(accountInfo,action) { if(blockSize<=0) throw new ArgumentOutOfRangeException("blockSize"); Contract.EndContractBlock(); LocalFile = localFile.WithProperCapitalization(); CloudFile = cloudFile; FileState = state; if (LocalFile == null) return; TreeHash = new Lazy(() => Signature.CalculateTreeHash(LocalFile, blockSize,algorithm), LazyThreadSafetyMode.ExecutionAndPublication); } //Calculate the download path for the cloud file public string GetDownloadPath() { if (CloudFile == null) return String.Empty; var filePath = CloudFile.RelativeUrlToFilePath(AccountInfo.UserName); return Path.Combine(AccountInfo.AccountPath, filePath); } public override string ToString() { return String.Format("{0}:{1}->{2}", Action, LocalFile.FullName, CloudFile.Name); } protected static ObjectInfo CreateObjectInfoFor(AccountInfo accountInfo, FileSystemInfo fileInfo) { if(accountInfo==null) throw new ArgumentNullException("accountInfo"); if(fileInfo==null) throw new ArgumentNullException("fileInfo"); Contract.Ensures(Contract.Result()!=null); Contract.EndContractBlock(); var capitalizedFileInfo = fileInfo.WithProperCapitalization(); var fullLocalName = capitalizedFileInfo.FullName; var othersPath = Path.Combine(accountInfo.AccountPath, FolderConstants.OthersFolder); var isShared = fullLocalName.StartsWith(othersPath, StringComparison.InvariantCultureIgnoreCase); if (isShared) { var pathRelativeToOther = fullLocalName.Substring(othersPath.Length + 1); var otherParts = pathRelativeToOther.Split('\\'); var otherName = otherParts[0]; var otherContainer = otherParts[1]; return new ObjectInfo { Account = otherName, Container = otherContainer, Name = String.Join("/", otherParts.Splice(2)) }; } return new ObjectInfo(accountInfo.AccountPath, accountInfo.UserName, fileInfo); } } public class CloudDownloadAction:CloudAction { public CloudDownloadAction(AccountInfo accountInfo, ObjectInfo cloudFile) :base(accountInfo,CloudActionType.DownloadUnconditional) { if (String.IsNullOrWhiteSpace(cloudFile.Container)) throw new ArgumentException("CloudFile.Container","cloudFile"); Contract.EndContractBlock(); CloudFile = cloudFile; } [ContractInvariantMethod] private void Invariants() { Contract.Invariant(!String.IsNullOrWhiteSpace(CloudFile.Container)); } public override string ToString() { return String.Format("{0}: _ <- {1}", this.Action, this.CloudFile.Name); } } public class CloudDeleteAction:CloudAction { public CloudDeleteAction(AccountInfo accountInfo,FileSystemInfo fileInfo, FileState fileState) : this(accountInfo,fileInfo,CreateObjectInfoFor(accountInfo, fileInfo),fileState) { } public CloudDeleteAction(AccountInfo accountInfo, FileSystemInfo fileInfo,ObjectInfo cloudFile, FileState fileState) : base(accountInfo,CloudActionType.DeleteCloud) { CloudFile = cloudFile; LocalFile = fileInfo; FileState = fileState; } public CloudDeleteAction(CloudAction action) : this(action.AccountInfo,action.LocalFile,action.CloudFile,action.FileState) {} [ContractInvariantMethod] private void Invariants() { Contract.Invariant(!String.IsNullOrWhiteSpace(CloudFile.Container)); } public override string ToString() { return String.Format("{0}: _ ->{1}", Action, CloudFile.Name); } } public class CloudUploadAction:CloudAction { public CloudUploadAction(AccountInfo accountInfo, FileSystemInfo fileInfo, FileState state, int blockSize, string algorithm) : base(accountInfo, CloudActionType.UploadUnconditional,fileInfo,CreateObjectInfoFor(accountInfo,fileInfo),state,blockSize,algorithm) { } [ContractInvariantMethod] private void Invariants() { Contract.Invariant(!String.IsNullOrWhiteSpace(CloudFile.Container)); } } public class CloudMoveAction:CloudAction { public ObjectInfo OldCloudFile { get; set; } public FileSystemInfo OldLocalFile { get; set; } public CloudMoveAction(AccountInfo accountInfo, CloudActionType action, FileSystemInfo oldFile, FileSystemInfo newFile) :base(accountInfo,action) { LocalFile = newFile; CloudFile = CreateObjectInfoFor(accountInfo, newFile); OldLocalFile = oldFile; OldCloudFile = CreateObjectInfoFor(accountInfo, oldFile); //This is a rename operation, a hash will not be used TreeHash = new Lazy(() => Network.TreeHash.Empty, LazyThreadSafetyMode.ExecutionAndPublication); } public override string ToString() { return String.Format("{0}:{1}->{2}", Action, OldCloudFile.Name, CloudFile.Name); } } }