Statistics
| Branch: | Revision:

root / trunk / Pithos.Core / Agents / Downloader.cs @ 2f5fcd2f

History | View | Annotate | Download (19 kB)

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