Statistics
| Branch: | Revision:

root / trunk / Pithos.Core / Agents / Downloader.cs @ bf4471a3

History | View | Annotate | Download (17.8 kB)

1 d21f3c77 pkanavos
using System;
2 d21f3c77 pkanavos
using System.Collections.Generic;
3 d21f3c77 pkanavos
using System.ComponentModel.Composition;
4 d21f3c77 pkanavos
using System.Diagnostics.Contracts;
5 d21f3c77 pkanavos
using System.IO;
6 d21f3c77 pkanavos
using System.Linq;
7 d21f3c77 pkanavos
using System.Reflection;
8 d21f3c77 pkanavos
using System.Threading;
9 d21f3c77 pkanavos
using System.Threading.Tasks;
10 d21f3c77 pkanavos
using Pithos.Interfaces;
11 d21f3c77 pkanavos
using Pithos.Network;
12 d21f3c77 pkanavos
using log4net;
13 d21f3c77 pkanavos
14 d21f3c77 pkanavos
namespace Pithos.Core.Agents
15 d21f3c77 pkanavos
{
16 d21f3c77 pkanavos
    [Export(typeof(Downloader))]
17 d21f3c77 pkanavos
    public class Downloader
18 d21f3c77 pkanavos
    {
19 d21f3c77 pkanavos
        private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
20 d21f3c77 pkanavos
21 d21f3c77 pkanavos
        [Import]
22 d21f3c77 pkanavos
        private IStatusKeeper StatusKeeper { get; set; }
23 d21f3c77 pkanavos
24 d21f3c77 pkanavos
        
25 d21f3c77 pkanavos
        public IStatusNotification StatusNotification { get; set; }
26 d21f3c77 pkanavos
27 d21f3c77 pkanavos
/*
28 d21f3c77 pkanavos
        private CancellationTokenSource _cts=new CancellationTokenSource();
29 d21f3c77 pkanavos
30 d21f3c77 pkanavos
        public void SignalStop()
31 d21f3c77 pkanavos
        {
32 d21f3c77 pkanavos
            _cts.Cancel();
33 d21f3c77 pkanavos
        }
34 d21f3c77 pkanavos
*/
35 d21f3c77 pkanavos
36 d21f3c77 pkanavos
37 d21f3c77 pkanavos
        //Download a file.
38 225694f9 pkanavos
        public async Task DownloadCloudFile(AccountInfo accountInfo, ObjectInfo cloudFile, string filePath,CancellationToken cancellationToken)
39 d21f3c77 pkanavos
        {
40 d21f3c77 pkanavos
            if (accountInfo == null)
41 d21f3c77 pkanavos
                throw new ArgumentNullException("accountInfo");
42 d21f3c77 pkanavos
            if (cloudFile == null)
43 d21f3c77 pkanavos
                throw new ArgumentNullException("cloudFile");
44 d21f3c77 pkanavos
            if (String.IsNullOrWhiteSpace(cloudFile.Account))
45 d21f3c77 pkanavos
                throw new ArgumentNullException("cloudFile");
46 d21f3c77 pkanavos
            if (String.IsNullOrWhiteSpace(cloudFile.Container))
47 d21f3c77 pkanavos
                throw new ArgumentNullException("cloudFile");
48 d21f3c77 pkanavos
            if (String.IsNullOrWhiteSpace(filePath))
49 d21f3c77 pkanavos
                throw new ArgumentNullException("filePath");
50 d21f3c77 pkanavos
            if (!Path.IsPathRooted(filePath))
51 d21f3c77 pkanavos
                throw new ArgumentException("The filePath must be rooted", "filePath");
52 d21f3c77 pkanavos
            Contract.EndContractBlock();
53 d21f3c77 pkanavos
                using (ThreadContext.Stacks["Operation"].Push("DownloadCloudFile"))
54 d21f3c77 pkanavos
                {
55 1865ad90 Panagiotis Kanavos
                   // var cancellationToken=_cts.Token;//  .ThrowIfCancellationRequested();
56 1865ad90 Panagiotis Kanavos
57 42af59dc pkanavos
                    if (await WaitOrAbort(accountInfo,cloudFile, cancellationToken).ConfigureAwait(false))
58 d21f3c77 pkanavos
                        return;
59 a60e5887 pkanavos
60 a60e5887 pkanavos
                    var fileName = Path.GetFileName(filePath);
61 a60e5887 pkanavos
                    var progress = new Progress<double>(d =>
62 a60e5887 pkanavos
                        StatusNotification.Notify(new StatusNotification(String.Format("Hashing for Download {0} of {1}", d, fileName))));
63 a60e5887 pkanavos
64 a60e5887 pkanavos
65 225694f9 pkanavos
                    TreeHash localTreeHash;
66 a60e5887 pkanavos
                    
67 a60e5887 pkanavos
                    using (StatusNotification.GetNotifier("Hashing for Download {0}", "Hashed for Download {0}", fileName))
68 225694f9 pkanavos
                    {
69 d21f3c77 pkanavos
70 225694f9 pkanavos
                        localTreeHash = Signature.CalculateTreeHashAsync(filePath,
71 225694f9 pkanavos
                                                                            accountInfo.BlockSize,
72 a60e5887 pkanavos
                                                                            accountInfo.BlockHash, 1,progress);
73 225694f9 pkanavos
                    }
74 d21f3c77 pkanavos
75 d21f3c77 pkanavos
                    var localPath = FileInfoExtensions.GetProperFilePathCapitalization(filePath);
76 d21f3c77 pkanavos
                    var relativeUrl = new Uri(cloudFile.Name, UriKind.Relative);
77 d21f3c77 pkanavos
78 d21f3c77 pkanavos
                    var url = relativeUrl.ToString();
79 d21f3c77 pkanavos
                    if (cloudFile.Name.EndsWith(".ignore", StringComparison.InvariantCultureIgnoreCase))
80 d21f3c77 pkanavos
                        return;
81 d21f3c77 pkanavos
82 5e646964 Panagiotis Kanavos
                    if (!Selectives.IsSelected(accountInfo,cloudFile))
83 d21f3c77 pkanavos
                        return;
84 d21f3c77 pkanavos
85 d21f3c77 pkanavos
86 d21f3c77 pkanavos
                    //Are we already downloading or uploading the file? 
87 d21f3c77 pkanavos
                    using (var gate = NetworkGate.Acquire(localPath, NetworkOperation.Downloading))
88 d21f3c77 pkanavos
                    {
89 d21f3c77 pkanavos
                        if (gate.Failed)
90 d21f3c77 pkanavos
                            return;
91 d21f3c77 pkanavos
92 d21f3c77 pkanavos
                        var client = new CloudFilesClient(accountInfo);
93 d21f3c77 pkanavos
                        var account = cloudFile.Account;
94 d21f3c77 pkanavos
                        var container = cloudFile.Container;
95 d21f3c77 pkanavos
96 d21f3c77 pkanavos
                        if (cloudFile.IsDirectory)
97 d21f3c77 pkanavos
                        {
98 d21f3c77 pkanavos
                            if (!Directory.Exists(localPath))
99 d21f3c77 pkanavos
                                try
100 d21f3c77 pkanavos
                                {
101 d21f3c77 pkanavos
                                    Directory.CreateDirectory(localPath);
102 d21f3c77 pkanavos
                                    if (Log.IsDebugEnabled)
103 d21f3c77 pkanavos
                                        Log.DebugFormat("Created Directory [{0}]", localPath);
104 d21f3c77 pkanavos
                                }
105 d21f3c77 pkanavos
                                catch (IOException)
106 d21f3c77 pkanavos
                                {
107 d21f3c77 pkanavos
                                    var localInfo = new FileInfo(localPath);
108 d21f3c77 pkanavos
                                    if (localInfo.Exists && localInfo.Length == 0)
109 d21f3c77 pkanavos
                                    {
110 d21f3c77 pkanavos
                                        Log.WarnFormat("Malformed directory object detected for [{0}]", localPath);
111 d21f3c77 pkanavos
                                        localInfo.Delete();
112 d21f3c77 pkanavos
                                        Directory.CreateDirectory(localPath);
113 d21f3c77 pkanavos
                                        if (Log.IsDebugEnabled)
114 d21f3c77 pkanavos
                                            Log.DebugFormat("Created Directory [{0}]", localPath);
115 d21f3c77 pkanavos
                                    }
116 d21f3c77 pkanavos
                                }
117 d21f3c77 pkanavos
                        }
118 d21f3c77 pkanavos
                        else
119 d21f3c77 pkanavos
                        {
120 d21f3c77 pkanavos
                            var isChanged = IsObjectChanged(cloudFile, localPath);
121 d21f3c77 pkanavos
                            if (isChanged)
122 d21f3c77 pkanavos
                            {
123 d21f3c77 pkanavos
                                //Retrieve the hashmap from the server
124 42af59dc pkanavos
                                var serverHash = await client.GetHashMap(account, container, url).ConfigureAwait(false);
125 d21f3c77 pkanavos
                                //If it's a small file
126 d21f3c77 pkanavos
                                if (serverHash.Hashes.Count == 1)
127 d21f3c77 pkanavos
                                    //Download it in one go
128 d21f3c77 pkanavos
                                    await
129 d21f3c77 pkanavos
                                        DownloadEntireFileAsync(accountInfo, client, cloudFile, relativeUrl, localPath,cancellationToken);
130 d21f3c77 pkanavos
                                    //Otherwise download it block by block
131 d21f3c77 pkanavos
                                else
132 d21f3c77 pkanavos
                                    await
133 732276d3 pkanavos
                                        DownloadWithBlocks(accountInfo, client, cloudFile, relativeUrl, localPath,localTreeHash,
134 d21f3c77 pkanavos
                                                           serverHash,cancellationToken);
135 d21f3c77 pkanavos
136 d21f3c77 pkanavos
                                if (!cloudFile.IsWritable(accountInfo.UserName))
137 d21f3c77 pkanavos
                                {
138 d21f3c77 pkanavos
                                    var attributes = File.GetAttributes(localPath);
139 d21f3c77 pkanavos
                                    File.SetAttributes(localPath, attributes | FileAttributes.ReadOnly);
140 d21f3c77 pkanavos
                                }
141 d21f3c77 pkanavos
                            }
142 d21f3c77 pkanavos
                        }
143 d21f3c77 pkanavos
144 d21f3c77 pkanavos
                        //Now we can store the object's metadata without worrying about ghost status entries
145 d21f3c77 pkanavos
                        StatusKeeper.StoreInfo(localPath, cloudFile);
146 d21f3c77 pkanavos
147 d21f3c77 pkanavos
                    }
148 d21f3c77 pkanavos
                }
149 d21f3c77 pkanavos
           
150 d21f3c77 pkanavos
        }
151 d21f3c77 pkanavos
152 d21f3c77 pkanavos
        //Download a file asynchronously using blocks
153 732276d3 pkanavos
        public async Task DownloadWithBlocks(AccountInfo accountInfo, CloudFilesClient client, ObjectInfo cloudFile, Uri relativeUrl, string filePath, TreeHash localTreeHash,TreeHash serverHash, CancellationToken cancellationToken)
154 d21f3c77 pkanavos
        {
155 d21f3c77 pkanavos
            if (client == null)
156 d21f3c77 pkanavos
                throw new ArgumentNullException("client");
157 d21f3c77 pkanavos
            if (cloudFile == null)
158 d21f3c77 pkanavos
                throw new ArgumentNullException("cloudFile");
159 d21f3c77 pkanavos
            if (relativeUrl == null)
160 d21f3c77 pkanavos
                throw new ArgumentNullException("relativeUrl");
161 d21f3c77 pkanavos
            if (String.IsNullOrWhiteSpace(filePath))
162 d21f3c77 pkanavos
                throw new ArgumentNullException("filePath");
163 d21f3c77 pkanavos
            if (!Path.IsPathRooted(filePath))
164 d21f3c77 pkanavos
                throw new ArgumentException("The filePath must be rooted", "filePath");
165 d21f3c77 pkanavos
            if (serverHash == null)
166 d21f3c77 pkanavos
                throw new ArgumentNullException("serverHash");
167 d21f3c77 pkanavos
            if (cloudFile.IsDirectory)
168 d21f3c77 pkanavos
                throw new ArgumentException("cloudFile is a directory, not a file", "cloudFile");
169 1865ad90 Panagiotis Kanavos
            Contract.EndContractBlock();
170 1865ad90 Panagiotis Kanavos
171 42af59dc pkanavos
            if (await WaitOrAbort(accountInfo, cloudFile, cancellationToken).ConfigureAwait(false))
172 d21f3c77 pkanavos
                return;
173 d21f3c77 pkanavos
174 d21f3c77 pkanavos
            var fileAgent = GetFileAgent(accountInfo);
175 d21f3c77 pkanavos
            var localPath = FileInfoExtensions.GetProperFilePathCapitalization(filePath);
176 d21f3c77 pkanavos
177 d21f3c77 pkanavos
            //Calculate the relative file path for the new file
178 d21f3c77 pkanavos
            var relativePath = relativeUrl.RelativeUriToFilePath();
179 d21f3c77 pkanavos
            var blockUpdater = new BlockUpdater(fileAgent.CachePath, localPath, relativePath, serverHash);
180 d21f3c77 pkanavos
181 d21f3c77 pkanavos
            StatusNotification.SetPithosStatus(PithosStatus.LocalSyncing, String.Format("Calculating hashmap for {0} before download", Path.GetFileName(localPath)));
182 d21f3c77 pkanavos
            //Calculate the file's treehash
183 d21f3c77 pkanavos
184 a60e5887 pkanavos
            var fileName = Path.GetFileName(localPath);
185 a60e5887 pkanavos
            var progress = new Progress<double>(d =>
186 a60e5887 pkanavos
                StatusNotification.Notify(new StatusNotification(String.Format("Hashing for Download {0} of {1}", d, fileName))));
187 a60e5887 pkanavos
188 d21f3c77 pkanavos
            //TODO: Should pass cancellation token here
189 a60e5887 pkanavos
            var treeHash = localTreeHash ?? Signature.CalculateTreeHashAsync(localPath, (int)serverHash.BlockSize, serverHash.BlockHash, 2,progress);
190 d21f3c77 pkanavos
191 d21f3c77 pkanavos
            //And compare it with the server's hash
192 d21f3c77 pkanavos
            var upHashes = serverHash.GetHashesAsStrings();
193 d21f3c77 pkanavos
            var localHashes = treeHash.HashDictionary;
194 2c0ad917 pkanavos
            ReportDownloadProgress(Path.GetFileName(localPath), 0,0, upHashes.Length, cloudFile.Bytes);
195 2c0ad917 pkanavos
196 2c0ad917 pkanavos
197 69fdb645 Panagiotis Kanavos
            long i = 0;
198 2c0ad917 pkanavos
            client.DownloadProgressChanged += (sender, args) =>
199 2c0ad917 pkanavos
                                ReportDownloadProgress(Path.GetFileName(localPath), i, args.ProgressPercentage, upHashes.Length, cloudFile.Bytes);
200 2c0ad917 pkanavos
201 2c0ad917 pkanavos
202 2c0ad917 pkanavos
            for (i = 0; i < upHashes.Length; i++)
203 1865ad90 Panagiotis Kanavos
            {
204 42af59dc pkanavos
                if (await WaitOrAbort(accountInfo, cloudFile, cancellationToken).ConfigureAwait(false))
205 d21f3c77 pkanavos
                    return;
206 d21f3c77 pkanavos
207 d21f3c77 pkanavos
                //For every non-matching hash
208 d21f3c77 pkanavos
                var upHash = upHashes[i];
209 d21f3c77 pkanavos
                if (!localHashes.ContainsKey(upHash))
210 d21f3c77 pkanavos
                {
211 d21f3c77 pkanavos
                    StatusNotification.Notify(new CloudNotification { Data = cloudFile });
212 2c0ad917 pkanavos
                    ReportDownloadProgress(Path.GetFileName(localPath), i, 0,upHashes.Length, cloudFile.Bytes);
213 d21f3c77 pkanavos
214 d21f3c77 pkanavos
                    if (blockUpdater.UseOrphan(i, upHash))
215 d21f3c77 pkanavos
                    {
216 d21f3c77 pkanavos
                        Log.InfoFormat("[BLOCK GET] ORPHAN FOUND for {0} of {1} for {2}", i, upHashes.Length, localPath);
217 d21f3c77 pkanavos
                        continue;
218 d21f3c77 pkanavos
                    }
219 d21f3c77 pkanavos
                    Log.InfoFormat("[BLOCK GET] START {0} of {1} for {2}", i, upHashes.Length, localPath);
220 69fdb645 Panagiotis Kanavos
                    long start = i * serverHash.BlockSize;
221 d21f3c77 pkanavos
                    //To download the last block just pass a null for the end of the range
222 d21f3c77 pkanavos
                    long? end = null;
223 d21f3c77 pkanavos
                    if (i < upHashes.Length - 1)
224 d21f3c77 pkanavos
                        end = ((i + 1) * serverHash.BlockSize);
225 d21f3c77 pkanavos
226 d21f3c77 pkanavos
                    //TODO: Pass token here
227 d21f3c77 pkanavos
                    //Download the missing block
228 42af59dc pkanavos
                    byte[] block = await client.GetBlock(cloudFile.Account, cloudFile.Container, relativeUrl, start, end, cancellationToken).ConfigureAwait(false);
229 d21f3c77 pkanavos
230 d21f3c77 pkanavos
                    //and store it
231 d21f3c77 pkanavos
                    blockUpdater.StoreBlock(i, block);
232 d21f3c77 pkanavos
233 d21f3c77 pkanavos
234 d21f3c77 pkanavos
                    Log.InfoFormat("[BLOCK GET] FINISH {0} of {1} for {2}", i, upHashes.Length, localPath);
235 d21f3c77 pkanavos
                }
236 2c0ad917 pkanavos
                ReportDownloadProgress(Path.GetFileName(localPath), i, 100,upHashes.Length, cloudFile.Bytes);
237 d21f3c77 pkanavos
            }
238 d21f3c77 pkanavos
239 d21f3c77 pkanavos
            //Want to avoid notifications if no changes were made
240 d21f3c77 pkanavos
            var hasChanges = blockUpdater.HasBlocks;
241 d21f3c77 pkanavos
            blockUpdater.Commit();
242 d21f3c77 pkanavos
243 d21f3c77 pkanavos
            if (hasChanges)
244 d21f3c77 pkanavos
                //Notify listeners that a local file has changed
245 d21f3c77 pkanavos
                StatusNotification.NotifyChangedFile(localPath);
246 d21f3c77 pkanavos
247 d21f3c77 pkanavos
            Log.InfoFormat("[BLOCK GET] COMPLETE {0}", localPath);
248 d21f3c77 pkanavos
        }
249 d21f3c77 pkanavos
250 d21f3c77 pkanavos
        //Download a small file with a single GET operation
251 d21f3c77 pkanavos
        private async Task DownloadEntireFileAsync(AccountInfo accountInfo, CloudFilesClient client, ObjectInfo cloudFile, Uri relativeUrl, string filePath, CancellationToken cancellationToken)
252 d21f3c77 pkanavos
        {
253 d21f3c77 pkanavos
            if (client == null)
254 d21f3c77 pkanavos
                throw new ArgumentNullException("client");
255 d21f3c77 pkanavos
            if (cloudFile == null)
256 d21f3c77 pkanavos
                throw new ArgumentNullException("cloudFile");
257 d21f3c77 pkanavos
            if (relativeUrl == null)
258 d21f3c77 pkanavos
                throw new ArgumentNullException("relativeUrl");
259 d21f3c77 pkanavos
            if (String.IsNullOrWhiteSpace(filePath))
260 d21f3c77 pkanavos
                throw new ArgumentNullException("filePath");
261 d21f3c77 pkanavos
            if (!Path.IsPathRooted(filePath))
262 d21f3c77 pkanavos
                throw new ArgumentException("The localPath must be rooted", "filePath");
263 d21f3c77 pkanavos
            if (cloudFile.IsDirectory)
264 d21f3c77 pkanavos
                throw new ArgumentException("cloudFile is a directory, not a file", "cloudFile");
265 1865ad90 Panagiotis Kanavos
            Contract.EndContractBlock();
266 1865ad90 Panagiotis Kanavos
267 42af59dc pkanavos
            if (await WaitOrAbort(accountInfo, cloudFile, cancellationToken).ConfigureAwait(false))
268 d21f3c77 pkanavos
                return;
269 d21f3c77 pkanavos
270 d21f3c77 pkanavos
            var localPath = FileInfoExtensions.GetProperFilePathCapitalization(filePath);
271 d21f3c77 pkanavos
            StatusNotification.SetPithosStatus(PithosStatus.LocalSyncing, String.Format("Downloading {0}", Path.GetFileName(localPath)));
272 d21f3c77 pkanavos
            StatusNotification.Notify(new CloudNotification { Data = cloudFile });
273 2c0ad917 pkanavos
            ReportDownloadProgress(Path.GetFileName(localPath), 1, 0,1, cloudFile.Bytes);
274 d21f3c77 pkanavos
275 d21f3c77 pkanavos
            var fileAgent = GetFileAgent(accountInfo);
276 d21f3c77 pkanavos
            //Calculate the relative file path for the new file
277 d21f3c77 pkanavos
            var relativePath = relativeUrl.RelativeUriToFilePath();
278 d21f3c77 pkanavos
            //The file will be stored in a temporary location while downloading with an extension .download
279 d21f3c77 pkanavos
            var tempPath = Path.Combine(fileAgent.CachePath, relativePath + ".download");
280 d21f3c77 pkanavos
            //Make sure the target folder exists. DownloadFileTask will not create the folder
281 d21f3c77 pkanavos
            var tempFolder = Path.GetDirectoryName(tempPath);
282 d21f3c77 pkanavos
            if (!Directory.Exists(tempFolder))
283 d21f3c77 pkanavos
                Directory.CreateDirectory(tempFolder);
284 d21f3c77 pkanavos
285 d21f3c77 pkanavos
            //TODO: Should pass the token here
286 d21f3c77 pkanavos
287 d21f3c77 pkanavos
            //Download the object to the temporary location
288 42af59dc pkanavos
            await client.GetObject(cloudFile.Account, cloudFile.Container, relativeUrl.ToString(), tempPath, cancellationToken).ConfigureAwait(false);
289 d21f3c77 pkanavos
290 d21f3c77 pkanavos
            //Create the local folder if it doesn't exist (necessary for shared objects)
291 d21f3c77 pkanavos
            var localFolder = Path.GetDirectoryName(localPath);
292 d21f3c77 pkanavos
            if (!Directory.Exists(localFolder))
293 d21f3c77 pkanavos
                try
294 d21f3c77 pkanavos
                {
295 d21f3c77 pkanavos
                    Directory.CreateDirectory(localFolder);
296 d21f3c77 pkanavos
                }
297 d21f3c77 pkanavos
                catch (IOException)
298 d21f3c77 pkanavos
                {
299 d21f3c77 pkanavos
                    //A file may already exist that has the same name as the new folder.
300 d21f3c77 pkanavos
                    //This may be an artifact of the way Pithos handles directories
301 d21f3c77 pkanavos
                    var fileInfo = new FileInfo(localFolder);
302 d21f3c77 pkanavos
                    if (fileInfo.Exists && fileInfo.Length == 0)
303 d21f3c77 pkanavos
                    {
304 d21f3c77 pkanavos
                        Log.WarnFormat("Malformed directory object detected for [{0}]", localFolder);
305 d21f3c77 pkanavos
                        fileInfo.Delete();
306 d21f3c77 pkanavos
                        Directory.CreateDirectory(localFolder);
307 d21f3c77 pkanavos
                    }
308 d21f3c77 pkanavos
                    else
309 d21f3c77 pkanavos
                        throw;
310 d21f3c77 pkanavos
                }
311 d21f3c77 pkanavos
            //And move it to its actual location once downloading is finished
312 d21f3c77 pkanavos
            if (File.Exists(localPath))
313 d21f3c77 pkanavos
                File.Replace(tempPath, localPath, null, true);
314 d21f3c77 pkanavos
            else
315 d21f3c77 pkanavos
                File.Move(tempPath, localPath);
316 d21f3c77 pkanavos
            //Notify listeners that a local file has changed
317 d21f3c77 pkanavos
            StatusNotification.NotifyChangedFile(localPath);
318 d21f3c77 pkanavos
319 d21f3c77 pkanavos
320 d21f3c77 pkanavos
        }
321 d21f3c77 pkanavos
322 d21f3c77 pkanavos
323 4cf8e4a5 George Pantazis
        private void ReportDownloadProgress(string fileName, long block, int blockPercentage,int totalBlocks, long fileSize)
324 d21f3c77 pkanavos
        {
325 d21f3c77 pkanavos
            StatusNotification.Notify(totalBlocks == 0
326 2c0ad917 pkanavos
                                          ? new ProgressNotification(fileName, "Downloading", 1, blockPercentage,1, fileSize)
327 2c0ad917 pkanavos
                                          : new ProgressNotification(fileName, "Downloading", block, blockPercentage, totalBlocks, fileSize));
328 d21f3c77 pkanavos
        }
329 d21f3c77 pkanavos
330 d21f3c77 pkanavos
        private bool IsObjectChanged(ObjectInfo cloudFile, string localPath)
331 d21f3c77 pkanavos
        {
332 d21f3c77 pkanavos
            //If the target is a directory, there are no changes to download
333 d21f3c77 pkanavos
            if (Directory.Exists(localPath))
334 d21f3c77 pkanavos
                return false;
335 d21f3c77 pkanavos
            //If the file doesn't exist, we have a chagne
336 d21f3c77 pkanavos
            if (!File.Exists(localPath))
337 d21f3c77 pkanavos
                return true;
338 d21f3c77 pkanavos
            //If there is no stored state, we have a change
339 d21f3c77 pkanavos
            var localState = StatusKeeper.GetStateByFilePath(localPath);
340 d21f3c77 pkanavos
            if (localState == null)
341 d21f3c77 pkanavos
                return true;
342 d21f3c77 pkanavos
343 d21f3c77 pkanavos
            var info = new FileInfo(localPath);
344 a60e5887 pkanavos
            var etag = info.ComputeShortHash(StatusNotification);
345 d21f3c77 pkanavos
            //If the file is different from the stored state, we have a change
346 a60e5887 pkanavos
            if (localState.ETag != etag)
347 d21f3c77 pkanavos
                return true;
348 d21f3c77 pkanavos
            //If the top hashes differ, we have a change
349 1cc1e8c5 pkanavos
            return (localState.Checksum != cloudFile.X_Object_Hash);
350 d21f3c77 pkanavos
        }
351 d21f3c77 pkanavos
352 d21f3c77 pkanavos
        private static FileAgent GetFileAgent(AccountInfo accountInfo)
353 d21f3c77 pkanavos
        {
354 d21f3c77 pkanavos
            return AgentLocator<FileAgent>.Get(accountInfo.AccountPath);
355 1865ad90 Panagiotis Kanavos
        }
356 1865ad90 Panagiotis Kanavos
357 5e646964 Panagiotis Kanavos
        private async Task<bool> WaitOrAbort(AccountInfo account,ObjectInfo cloudFile, CancellationToken token)
358 1865ad90 Panagiotis Kanavos
        {
359 1865ad90 Panagiotis Kanavos
            token.ThrowIfCancellationRequested();
360 42af59dc pkanavos
            await UnpauseEvent.WaitAsync().ConfigureAwait(false);
361 5e646964 Panagiotis Kanavos
            var shouldAbort = !Selectives.IsSelected(account,cloudFile);
362 1865ad90 Panagiotis Kanavos
            if (shouldAbort)
363 1865ad90 Panagiotis Kanavos
                Log.InfoFormat("Aborting [{0}]", cloudFile.Uri);
364 1865ad90 Panagiotis Kanavos
            return shouldAbort;
365 d21f3c77 pkanavos
        }
366 d21f3c77 pkanavos
367 d21f3c77 pkanavos
        [Import]
368 d21f3c77 pkanavos
        public Selectives Selectives { get; set; }
369 d21f3c77 pkanavos
370 d21f3c77 pkanavos
        public AsyncManualResetEvent UnpauseEvent { get; set; }
371 d21f3c77 pkanavos
    }
372 d21f3c77 pkanavos
}