#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);
}
}
}