using System;
+using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Diagnostics.Contracts;
using System.IO;
+using System.Linq;
using System.Reflection;
+using System.Threading;
using System.Threading.Tasks;
using Pithos.Interfaces;
using Pithos.Network;
public IStatusNotification StatusNotification { get; set; }
+/*
+ private CancellationTokenSource _cts=new CancellationTokenSource();
+
+ public void SignalStop()
+ {
+ _cts.Cancel();
+ }
+*/
+
+
//Download a file.
- public async Task DownloadCloudFile(AccountInfo accountInfo, ObjectInfo cloudFile, string filePath)
+ public async Task DownloadCloudFile(AccountInfo accountInfo, ObjectInfo cloudFile, string filePath,CancellationToken cancellationToken)
{
if (accountInfo == null)
throw new ArgumentNullException("accountInfo");
if (!Path.IsPathRooted(filePath))
throw new ArgumentException("The filePath must be rooted", "filePath");
Contract.EndContractBlock();
+ using (ThreadContext.Stacks["Operation"].Push("DownloadCloudFile"))
+ {
+ // var cancellationToken=_cts.Token;// .ThrowIfCancellationRequested();
- using (ThreadContext.Stacks["Operation"].Push("DownloadCloudFile"))
- {
+ cancellationToken.ThrowIfCancellationRequested();
+ await UnpauseEvent.WaitAsync();
- var localPath = FileInfoExtensions.GetProperFilePathCapitalization(filePath);
- var relativeUrl = new Uri(cloudFile.Name, UriKind.Relative);
- var url = relativeUrl.ToString();
- if (cloudFile.Name.EndsWith(".ignore", StringComparison.InvariantCultureIgnoreCase))
- return;
+ var localPath = FileInfoExtensions.GetProperFilePathCapitalization(filePath);
+ var relativeUrl = new Uri(cloudFile.Name, UriKind.Relative);
+ var url = relativeUrl.ToString();
+ if (cloudFile.Name.EndsWith(".ignore", StringComparison.InvariantCultureIgnoreCase))
+ return;
- //Are we already downloading or uploading the file?
- using (var gate = NetworkGate.Acquire(localPath, NetworkOperation.Downloading))
- {
- if (gate.Failed)
+ if (!Selectives.IsSelected(cloudFile))
return;
- var client = new CloudFilesClient(accountInfo);
- var account = cloudFile.Account;
- var container = cloudFile.Container;
- if (cloudFile.IsDirectory)
+ //Are we already downloading or uploading the file?
+ using (var gate = NetworkGate.Acquire(localPath, NetworkOperation.Downloading))
{
- if (!Directory.Exists(localPath))
- try
- {
- Directory.CreateDirectory(localPath);
- if (Log.IsDebugEnabled)
- Log.DebugFormat("Created Directory [{0}]", localPath);
- }
- catch (IOException)
- {
- var localInfo = new FileInfo(localPath);
- if (localInfo.Exists && localInfo.Length == 0)
+ if (gate.Failed)
+ return;
+
+ var client = new CloudFilesClient(accountInfo);
+ var account = cloudFile.Account;
+ var container = cloudFile.Container;
+
+ if (cloudFile.IsDirectory)
+ {
+ if (!Directory.Exists(localPath))
+ try
{
- Log.WarnFormat("Malformed directory object detected for [{0}]", localPath);
- localInfo.Delete();
Directory.CreateDirectory(localPath);
if (Log.IsDebugEnabled)
Log.DebugFormat("Created Directory [{0}]", localPath);
}
- }
- }
- else
- {
- var isChanged = IsObjectChanged(cloudFile, localPath);
- if (isChanged)
+ catch (IOException)
+ {
+ var localInfo = new FileInfo(localPath);
+ if (localInfo.Exists && localInfo.Length == 0)
+ {
+ Log.WarnFormat("Malformed directory object detected for [{0}]", localPath);
+ localInfo.Delete();
+ Directory.CreateDirectory(localPath);
+ if (Log.IsDebugEnabled)
+ Log.DebugFormat("Created Directory [{0}]", localPath);
+ }
+ }
+ }
+ else
{
- //Retrieve the hashmap from the server
- var serverHash = await client.GetHashMap(account, container, url);
- //If it's a small file
- if (serverHash.Hashes.Count == 1)
- //Download it in one go
- await
- DownloadEntireFileAsync(accountInfo, client, cloudFile, relativeUrl, localPath);
- //Otherwise download it block by block
- else
- await
- DownloadWithBlocks(accountInfo, client, cloudFile, relativeUrl, localPath,
- serverHash);
-
- if (!cloudFile.IsWritable(accountInfo.UserName))
+ var isChanged = IsObjectChanged(cloudFile, localPath);
+ if (isChanged)
{
- var attributes = File.GetAttributes(localPath);
- File.SetAttributes(localPath, attributes | FileAttributes.ReadOnly);
+ //Retrieve the hashmap from the server
+ var serverHash = await client.GetHashMap(account, container, url);
+ //If it's a small file
+ if (serverHash.Hashes.Count == 1)
+ //Download it in one go
+ await
+ DownloadEntireFileAsync(accountInfo, client, cloudFile, relativeUrl, localPath,cancellationToken);
+ //Otherwise download it block by block
+ else
+ await
+ DownloadWithBlocks(accountInfo, client, cloudFile, relativeUrl, localPath,
+ serverHash,cancellationToken);
+
+ if (!cloudFile.IsWritable(accountInfo.UserName))
+ {
+ var attributes = File.GetAttributes(localPath);
+ File.SetAttributes(localPath, attributes | FileAttributes.ReadOnly);
+ }
}
}
- }
- //Now we can store the object's metadata without worrying about ghost status entries
- StatusKeeper.StoreInfo(localPath, cloudFile);
+ //Now we can store the object's metadata without worrying about ghost status entries
+ StatusKeeper.StoreInfo(localPath, cloudFile);
+ }
}
- }
+
}
//Download a file asynchronously using blocks
- public async Task DownloadWithBlocks(AccountInfo accountInfo, CloudFilesClient client, ObjectInfo cloudFile, Uri relativeUrl, string filePath, TreeHash serverHash)
+ public async Task DownloadWithBlocks(AccountInfo accountInfo, CloudFilesClient client, ObjectInfo cloudFile, Uri relativeUrl, string filePath, TreeHash serverHash, CancellationToken cancellationToken)
{
if (client == null)
throw new ArgumentNullException("client");
throw new ArgumentException("cloudFile is a directory, not a file", "cloudFile");
Contract.EndContractBlock();
+ cancellationToken.ThrowIfCancellationRequested();
+ await UnpauseEvent.WaitAsync();
+
var fileAgent = GetFileAgent(accountInfo);
var localPath = FileInfoExtensions.GetProperFilePathCapitalization(filePath);
var relativePath = relativeUrl.RelativeUriToFilePath();
var blockUpdater = new BlockUpdater(fileAgent.CachePath, localPath, relativePath, serverHash);
-
StatusNotification.SetPithosStatus(PithosStatus.LocalSyncing, String.Format("Calculating hashmap for {0} before download", Path.GetFileName(localPath)));
//Calculate the file's treehash
+
+ //TODO: Should pass cancellation token here
var treeHash = await Signature.CalculateTreeHashAsync(localPath, serverHash.BlockSize, serverHash.BlockHash, 2);
//And compare it with the server's hash
ReportDownloadProgress(Path.GetFileName(localPath), 0, upHashes.Length, cloudFile.Bytes);
for (int i = 0; i < upHashes.Length; i++)
{
+ cancellationToken.ThrowIfCancellationRequested();
+ await UnpauseEvent.WaitAsync();
+
//For every non-matching hash
var upHash = upHashes[i];
if (!localHashes.ContainsKey(upHash))
if (i < upHashes.Length - 1)
end = ((i + 1) * serverHash.BlockSize);
+ //TODO: Pass token here
//Download the missing block
- var block = await client.GetBlock(cloudFile.Account, cloudFile.Container, relativeUrl, start, end);
+ var block = await client.GetBlock(cloudFile.Account, cloudFile.Container, relativeUrl, start, end,cancellationToken);
//and store it
blockUpdater.StoreBlock(i, block);
}
//Download a small file with a single GET operation
- private async Task DownloadEntireFileAsync(AccountInfo accountInfo, CloudFilesClient client, ObjectInfo cloudFile, Uri relativeUrl, string filePath)
+ private async Task DownloadEntireFileAsync(AccountInfo accountInfo, CloudFilesClient client, ObjectInfo cloudFile, Uri relativeUrl, string filePath, CancellationToken cancellationToken)
{
if (client == null)
throw new ArgumentNullException("client");
throw new ArgumentException("cloudFile is a directory, not a file", "cloudFile");
Contract.EndContractBlock();
+ cancellationToken.ThrowIfCancellationRequested();
+ await UnpauseEvent.WaitAsync();
+
var localPath = FileInfoExtensions.GetProperFilePathCapitalization(filePath);
StatusNotification.SetPithosStatus(PithosStatus.LocalSyncing, String.Format("Downloading {0}", Path.GetFileName(localPath)));
StatusNotification.Notify(new CloudNotification { Data = cloudFile });
if (!Directory.Exists(tempFolder))
Directory.CreateDirectory(tempFolder);
+ //TODO: Should pass the token here
+
//Download the object to the temporary location
- await client.GetObject(cloudFile.Account, cloudFile.Container, relativeUrl.ToString(), tempPath);
+ await client.GetObject(cloudFile.Account, cloudFile.Container, relativeUrl.ToString(), tempPath,cancellationToken);
//Create the local folder if it doesn't exist (necessary for shared objects)
var localFolder = Path.GetDirectoryName(localPath);
return AgentLocator<FileAgent>.Get(accountInfo.AccountPath);
}
+ [Import]
+ public Selectives Selectives { get; set; }
+ public AsyncManualResetEvent UnpauseEvent { get; set; }
}
}