root / trunk / Pithos.Core / Agents / PollAgent.cs @ b666b39a
History | View | Annotate | Download (26.3 kB)
1 | aa7ac00e | Panagiotis Kanavos | #region |
---|---|---|---|
2 | aa7ac00e | Panagiotis Kanavos | /* ----------------------------------------------------------------------- |
3 | aa7ac00e | Panagiotis Kanavos | * <copyright file="PollAgent.cs" company="GRNet"> |
4 | aa7ac00e | Panagiotis Kanavos | * |
5 | aa7ac00e | Panagiotis Kanavos | * Copyright 2011-2012 GRNET S.A. All rights reserved. |
6 | aa7ac00e | Panagiotis Kanavos | * |
7 | aa7ac00e | Panagiotis Kanavos | * Redistribution and use in source and binary forms, with or |
8 | aa7ac00e | Panagiotis Kanavos | * without modification, are permitted provided that the following |
9 | aa7ac00e | Panagiotis Kanavos | * conditions are met: |
10 | aa7ac00e | Panagiotis Kanavos | * |
11 | aa7ac00e | Panagiotis Kanavos | * 1. Redistributions of source code must retain the above |
12 | aa7ac00e | Panagiotis Kanavos | * copyright notice, this list of conditions and the following |
13 | aa7ac00e | Panagiotis Kanavos | * disclaimer. |
14 | aa7ac00e | Panagiotis Kanavos | * |
15 | aa7ac00e | Panagiotis Kanavos | * 2. Redistributions in binary form must reproduce the above |
16 | aa7ac00e | Panagiotis Kanavos | * copyright notice, this list of conditions and the following |
17 | aa7ac00e | Panagiotis Kanavos | * disclaimer in the documentation and/or other materials |
18 | aa7ac00e | Panagiotis Kanavos | * provided with the distribution. |
19 | aa7ac00e | Panagiotis Kanavos | * |
20 | aa7ac00e | Panagiotis Kanavos | * |
21 | aa7ac00e | Panagiotis Kanavos | * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS |
22 | aa7ac00e | Panagiotis Kanavos | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
23 | aa7ac00e | Panagiotis Kanavos | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
24 | aa7ac00e | Panagiotis Kanavos | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR |
25 | aa7ac00e | Panagiotis Kanavos | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
26 | aa7ac00e | Panagiotis Kanavos | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
27 | aa7ac00e | Panagiotis Kanavos | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
28 | aa7ac00e | Panagiotis Kanavos | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
29 | aa7ac00e | Panagiotis Kanavos | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
30 | aa7ac00e | Panagiotis Kanavos | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
31 | aa7ac00e | Panagiotis Kanavos | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
32 | aa7ac00e | Panagiotis Kanavos | * POSSIBILITY OF SUCH DAMAGE. |
33 | aa7ac00e | Panagiotis Kanavos | * |
34 | aa7ac00e | Panagiotis Kanavos | * The views and conclusions contained in the software and |
35 | aa7ac00e | Panagiotis Kanavos | * documentation are those of the authors and should not be |
36 | aa7ac00e | Panagiotis Kanavos | * interpreted as representing official policies, either expressed |
37 | aa7ac00e | Panagiotis Kanavos | * or implied, of GRNET S.A. |
38 | aa7ac00e | Panagiotis Kanavos | * </copyright> |
39 | aa7ac00e | Panagiotis Kanavos | * ----------------------------------------------------------------------- |
40 | aa7ac00e | Panagiotis Kanavos | */ |
41 | aa7ac00e | Panagiotis Kanavos | #endregion |
42 | aa7ac00e | Panagiotis Kanavos | |
43 | aa7ac00e | Panagiotis Kanavos | using System.Collections.Concurrent; |
44 | aa7ac00e | Panagiotis Kanavos | using System.ComponentModel.Composition; |
45 | aa7ac00e | Panagiotis Kanavos | using System.Diagnostics; |
46 | aa7ac00e | Panagiotis Kanavos | using System.Diagnostics.Contracts; |
47 | aa7ac00e | Panagiotis Kanavos | using System.IO; |
48 | aa7ac00e | Panagiotis Kanavos | using System.Threading; |
49 | aa7ac00e | Panagiotis Kanavos | using System.Threading.Tasks; |
50 | aa7ac00e | Panagiotis Kanavos | using System.Threading.Tasks.Dataflow; |
51 | aa7ac00e | Panagiotis Kanavos | using Castle.ActiveRecord; |
52 | aa7ac00e | Panagiotis Kanavos | using Pithos.Interfaces; |
53 | aa7ac00e | Panagiotis Kanavos | using Pithos.Network; |
54 | aa7ac00e | Panagiotis Kanavos | using log4net; |
55 | aa7ac00e | Panagiotis Kanavos | |
56 | aa7ac00e | Panagiotis Kanavos | namespace Pithos.Core.Agents |
57 | aa7ac00e | Panagiotis Kanavos | { |
58 | aa7ac00e | Panagiotis Kanavos | using System; |
59 | aa7ac00e | Panagiotis Kanavos | using System.Collections.Generic; |
60 | aa7ac00e | Panagiotis Kanavos | using System.Linq; |
61 | aa7ac00e | Panagiotis Kanavos | using System.Text; |
62 | aa7ac00e | Panagiotis Kanavos | |
63 | aa7ac00e | Panagiotis Kanavos | /// <summary> |
64 | aa7ac00e | Panagiotis Kanavos | /// PollAgent periodically polls the server to detect object changes. The agent retrieves a listing of all |
65 | aa7ac00e | Panagiotis Kanavos | /// objects and compares it with a previously cached version to detect differences. |
66 | aa7ac00e | Panagiotis Kanavos | /// New files are downloaded, missing files are deleted from the local file system and common files are compared |
67 | aa7ac00e | Panagiotis Kanavos | /// to determine the appropriate action |
68 | aa7ac00e | Panagiotis Kanavos | /// </summary> |
69 | aa7ac00e | Panagiotis Kanavos | [Export] |
70 | aa7ac00e | Panagiotis Kanavos | public class PollAgent |
71 | aa7ac00e | Panagiotis Kanavos | { |
72 | aa7ac00e | Panagiotis Kanavos | private static readonly ILog Log = LogManager.GetLogger("PollAgent"); |
73 | aa7ac00e | Panagiotis Kanavos | |
74 | aa7ac00e | Panagiotis Kanavos | [System.ComponentModel.Composition.Import] |
75 | aa7ac00e | Panagiotis Kanavos | public IStatusKeeper StatusKeeper { get; set; } |
76 | aa7ac00e | Panagiotis Kanavos | |
77 | aa7ac00e | Panagiotis Kanavos | [System.ComponentModel.Composition.Import] |
78 | aa7ac00e | Panagiotis Kanavos | public IPithosSettings Settings { get; set; } |
79 | aa7ac00e | Panagiotis Kanavos | |
80 | aa7ac00e | Panagiotis Kanavos | [System.ComponentModel.Composition.Import] |
81 | aa7ac00e | Panagiotis Kanavos | public NetworkAgent NetworkAgent { get; set; } |
82 | aa7ac00e | Panagiotis Kanavos | |
83 | aa7ac00e | Panagiotis Kanavos | public IStatusNotification StatusNotification { get; set; } |
84 | aa7ac00e | Panagiotis Kanavos | |
85 | aa7ac00e | Panagiotis Kanavos | private bool _firstPoll = true; |
86 | aa7ac00e | Panagiotis Kanavos | |
87 | aa7ac00e | Panagiotis Kanavos | //The Sync Event signals a manual synchronisation |
88 | aa7ac00e | Panagiotis Kanavos | private readonly AsyncManualResetEvent _syncEvent = new AsyncManualResetEvent(); |
89 | aa7ac00e | Panagiotis Kanavos | |
90 | aa7ac00e | Panagiotis Kanavos | private ConcurrentDictionary<string, DateTime> _lastSeen = new ConcurrentDictionary<string, DateTime>(); |
91 | aa7ac00e | Panagiotis Kanavos | private readonly ConcurrentBag<AccountInfo> _accounts = new ConcurrentBag<AccountInfo>(); |
92 | aa7ac00e | Panagiotis Kanavos | |
93 | aa7ac00e | Panagiotis Kanavos | |
94 | aa7ac00e | Panagiotis Kanavos | /// <summary> |
95 | aa7ac00e | Panagiotis Kanavos | /// Start a manual synchronization |
96 | aa7ac00e | Panagiotis Kanavos | /// </summary> |
97 | aa7ac00e | Panagiotis Kanavos | public void SynchNow() |
98 | aa7ac00e | Panagiotis Kanavos | { |
99 | aa7ac00e | Panagiotis Kanavos | _syncEvent.Set(); |
100 | aa7ac00e | Panagiotis Kanavos | } |
101 | aa7ac00e | Panagiotis Kanavos | |
102 | fec5da06 | Panagiotis Kanavos | /// <summary> |
103 | fec5da06 | Panagiotis Kanavos | /// Remote files are polled periodically. Any changes are processed |
104 | fec5da06 | Panagiotis Kanavos | /// </summary> |
105 | fec5da06 | Panagiotis Kanavos | /// <param name="since"></param> |
106 | fec5da06 | Panagiotis Kanavos | /// <returns></returns> |
107 | aa7ac00e | Panagiotis Kanavos | public async Task PollRemoteFiles(DateTime? since = null) |
108 | aa7ac00e | Panagiotis Kanavos | { |
109 | aa7ac00e | Panagiotis Kanavos | Debug.Assert(Thread.CurrentThread.IsBackground, "Polling Ended up in the main thread!"); |
110 | aa7ac00e | Panagiotis Kanavos | |
111 | aa7ac00e | Panagiotis Kanavos | UpdateStatus(PithosStatus.Syncing); |
112 | aa7ac00e | Panagiotis Kanavos | StatusNotification.Notify(new PollNotification()); |
113 | aa7ac00e | Panagiotis Kanavos | |
114 | aa7ac00e | Panagiotis Kanavos | using (log4net.ThreadContext.Stacks["Retrieve Remote"].Push("All accounts")) |
115 | aa7ac00e | Panagiotis Kanavos | { |
116 | aa7ac00e | Panagiotis Kanavos | //If this poll fails, we will retry with the same since value |
117 | aa7ac00e | Panagiotis Kanavos | var nextSince = since; |
118 | aa7ac00e | Panagiotis Kanavos | try |
119 | aa7ac00e | Panagiotis Kanavos | { |
120 | aa7ac00e | Panagiotis Kanavos | //Next time we will check for all changes since the current check minus 1 second |
121 | aa7ac00e | Panagiotis Kanavos | //This is done to ensure there are no discrepancies due to clock differences |
122 | aa7ac00e | Panagiotis Kanavos | var current = DateTime.Now.AddSeconds(-1); |
123 | aa7ac00e | Panagiotis Kanavos | |
124 | aa7ac00e | Panagiotis Kanavos | var tasks = from accountInfo in _accounts |
125 | aa7ac00e | Panagiotis Kanavos | select ProcessAccountFiles(accountInfo, since); |
126 | aa7ac00e | Panagiotis Kanavos | |
127 | aa7ac00e | Panagiotis Kanavos | await TaskEx.WhenAll(tasks.ToList()); |
128 | aa7ac00e | Panagiotis Kanavos | |
129 | aa7ac00e | Panagiotis Kanavos | _firstPoll = false; |
130 | aa7ac00e | Panagiotis Kanavos | //Reschedule the poll with the current timestamp as a "since" value |
131 | aa7ac00e | Panagiotis Kanavos | nextSince = current; |
132 | aa7ac00e | Panagiotis Kanavos | } |
133 | aa7ac00e | Panagiotis Kanavos | catch (Exception ex) |
134 | aa7ac00e | Panagiotis Kanavos | { |
135 | aa7ac00e | Panagiotis Kanavos | Log.ErrorFormat("Error while processing accounts\r\n{0}", ex); |
136 | aa7ac00e | Panagiotis Kanavos | //In case of failure retry with the same "since" value |
137 | aa7ac00e | Panagiotis Kanavos | } |
138 | aa7ac00e | Panagiotis Kanavos | |
139 | aa7ac00e | Panagiotis Kanavos | UpdateStatus(PithosStatus.InSynch); |
140 | fec5da06 | Panagiotis Kanavos | //The multiple try blocks are required because we can't have an await call |
141 | fec5da06 | Panagiotis Kanavos | //inside a finally block |
142 | fec5da06 | Panagiotis Kanavos | //TODO: Find a more elegant solution for reschedulling in the event of an exception |
143 | fec5da06 | Panagiotis Kanavos | try |
144 | fec5da06 | Panagiotis Kanavos | { |
145 | fec5da06 | Panagiotis Kanavos | //Wait for the polling interval to pass or the Sync event to be signalled |
146 | fec5da06 | Panagiotis Kanavos | nextSince = await WaitForScheduledOrManualPoll(nextSince); |
147 | fec5da06 | Panagiotis Kanavos | } |
148 | fec5da06 | Panagiotis Kanavos | finally |
149 | fec5da06 | Panagiotis Kanavos | { |
150 | fec5da06 | Panagiotis Kanavos | //Ensure polling is scheduled even in case of error |
151 | fec5da06 | Panagiotis Kanavos | TaskEx.Run(() => PollRemoteFiles(nextSince)); |
152 | fec5da06 | Panagiotis Kanavos | } |
153 | aa7ac00e | Panagiotis Kanavos | } |
154 | aa7ac00e | Panagiotis Kanavos | } |
155 | aa7ac00e | Panagiotis Kanavos | |
156 | aa7ac00e | Panagiotis Kanavos | /// <summary> |
157 | aa7ac00e | Panagiotis Kanavos | /// Wait for the polling period to expire or a manual sync request |
158 | aa7ac00e | Panagiotis Kanavos | /// </summary> |
159 | aa7ac00e | Panagiotis Kanavos | /// <param name="since"></param> |
160 | aa7ac00e | Panagiotis Kanavos | /// <returns></returns> |
161 | aa7ac00e | Panagiotis Kanavos | private async Task<DateTime?> WaitForScheduledOrManualPoll(DateTime? since) |
162 | aa7ac00e | Panagiotis Kanavos | { |
163 | aa7ac00e | Panagiotis Kanavos | var sync = _syncEvent.WaitAsync(); |
164 | aa7ac00e | Panagiotis Kanavos | var wait = TaskEx.Delay(TimeSpan.FromSeconds(Settings.PollingInterval), NetworkAgent.CancellationToken); |
165 | aa7ac00e | Panagiotis Kanavos | var signaledTask = await TaskEx.WhenAny(sync, wait); |
166 | aa7ac00e | Panagiotis Kanavos | |
167 | aa7ac00e | Panagiotis Kanavos | //Wait for network processing to finish before polling |
168 | 38ac43a6 | Panagiotis Kanavos | var pauseTask=NetworkAgent.ProceedEvent.WaitAsync(); |
169 | aa7ac00e | Panagiotis Kanavos | await TaskEx.WhenAll(signaledTask, pauseTask); |
170 | aa7ac00e | Panagiotis Kanavos | |
171 | aa7ac00e | Panagiotis Kanavos | //If polling is signalled by SynchNow, ignore the since tag |
172 | aa7ac00e | Panagiotis Kanavos | if (sync.IsCompleted) |
173 | aa7ac00e | Panagiotis Kanavos | { |
174 | aa7ac00e | Panagiotis Kanavos | //TODO: Must convert to AutoReset |
175 | aa7ac00e | Panagiotis Kanavos | _syncEvent.Reset(); |
176 | aa7ac00e | Panagiotis Kanavos | return null; |
177 | aa7ac00e | Panagiotis Kanavos | } |
178 | aa7ac00e | Panagiotis Kanavos | return since; |
179 | aa7ac00e | Panagiotis Kanavos | } |
180 | aa7ac00e | Panagiotis Kanavos | |
181 | aa7ac00e | Panagiotis Kanavos | public async Task ProcessAccountFiles(AccountInfo accountInfo, DateTime? since = null) |
182 | aa7ac00e | Panagiotis Kanavos | { |
183 | aa7ac00e | Panagiotis Kanavos | if (accountInfo == null) |
184 | aa7ac00e | Panagiotis Kanavos | throw new ArgumentNullException("accountInfo"); |
185 | aa7ac00e | Panagiotis Kanavos | if (String.IsNullOrWhiteSpace(accountInfo.AccountPath)) |
186 | aa7ac00e | Panagiotis Kanavos | throw new ArgumentException("The AccountInfo.AccountPath is empty", "accountInfo"); |
187 | aa7ac00e | Panagiotis Kanavos | Contract.EndContractBlock(); |
188 | aa7ac00e | Panagiotis Kanavos | |
189 | aa7ac00e | Panagiotis Kanavos | |
190 | aa7ac00e | Panagiotis Kanavos | using (log4net.ThreadContext.Stacks["Retrieve Remote"].Push(accountInfo.UserName)) |
191 | aa7ac00e | Panagiotis Kanavos | { |
192 | aa7ac00e | Panagiotis Kanavos | await NetworkAgent.GetDeleteAwaiter(); |
193 | aa7ac00e | Panagiotis Kanavos | |
194 | aa7ac00e | Panagiotis Kanavos | Log.Info("Scheduled"); |
195 | aa7ac00e | Panagiotis Kanavos | var client = new CloudFilesClient(accountInfo); |
196 | aa7ac00e | Panagiotis Kanavos | |
197 | 99e6329f | Panagiotis Kanavos | //We don't need to check the trash container |
198 | 99e6329f | Panagiotis Kanavos | var containers = client.ListContainers(accountInfo.UserName).Where(c=>c.Name!="trash"); |
199 | aa7ac00e | Panagiotis Kanavos | |
200 | aa7ac00e | Panagiotis Kanavos | |
201 | aa7ac00e | Panagiotis Kanavos | CreateContainerFolders(accountInfo, containers); |
202 | aa7ac00e | Panagiotis Kanavos | |
203 | aa7ac00e | Panagiotis Kanavos | try |
204 | aa7ac00e | Panagiotis Kanavos | { |
205 | 759bd3c4 | Panagiotis Kanavos | //Wait for any deletions to finish |
206 | aa7ac00e | Panagiotis Kanavos | await NetworkAgent.GetDeleteAwaiter(); |
207 | aa7ac00e | Panagiotis Kanavos | //Get the poll time now. We may miss some deletions but it's better to keep a file that was deleted |
208 | aa7ac00e | Panagiotis Kanavos | //than delete a file that was created while we were executing the poll |
209 | aa7ac00e | Panagiotis Kanavos | var pollTime = DateTime.Now; |
210 | aa7ac00e | Panagiotis Kanavos | |
211 | aa7ac00e | Panagiotis Kanavos | //Get the list of server objects changed since the last check |
212 | aa7ac00e | Panagiotis Kanavos | //The name of the container is passed as state in order to create a dictionary of tasks in a subsequent step |
213 | aa7ac00e | Panagiotis Kanavos | var listObjects = (from container in containers |
214 | aa7ac00e | Panagiotis Kanavos | select Task<IList<ObjectInfo>>.Factory.StartNew(_ => |
215 | aa7ac00e | Panagiotis Kanavos | client.ListObjects(accountInfo.UserName, container.Name, since), container.Name)).ToList(); |
216 | 126f90b3 | Panagiotis Kanavos | //BUG: Can't detect difference between no changes or no objects |
217 | 126f90b3 | Panagiotis Kanavos | //ListObjects returns nothing if there are no changes since the last check time (since value) |
218 | 99e6329f | Panagiotis Kanavos | //TODO: Must detect the difference between no server objects and no change |
219 | 99e6329f | Panagiotis Kanavos | |
220 | 99e6329f | Panagiotis Kanavos | //NOTE: One option is to "mark" all result lists with their container name, or |
221 | 99e6329f | Panagiotis Kanavos | //rather the url of the container |
222 | 99e6329f | Panagiotis Kanavos | //Another option |
223 | 99e6329f | Panagiotis Kanavos | |
224 | 99e6329f | Panagiotis Kanavos | var listShared = Task<IList<ObjectInfo>>.Factory.StartNew(_ => |
225 | 99e6329f | Panagiotis Kanavos | client.ListSharedObjects(since), "shared"); |
226 | aa7ac00e | Panagiotis Kanavos | listObjects.Add(listShared); |
227 | aa7ac00e | Panagiotis Kanavos | var listTasks = await Task.Factory.WhenAll(listObjects.ToArray()); |
228 | aa7ac00e | Panagiotis Kanavos | |
229 | aa7ac00e | Panagiotis Kanavos | using (log4net.ThreadContext.Stacks["SCHEDULE"].Push("Process Results")) |
230 | aa7ac00e | Panagiotis Kanavos | { |
231 | aa7ac00e | Panagiotis Kanavos | var dict = listTasks.ToDictionary(t => t.AsyncState); |
232 | aa7ac00e | Panagiotis Kanavos | |
233 | aa7ac00e | Panagiotis Kanavos | //Get all non-trash objects. Remember, the container name is stored in AsyncState |
234 | aa7ac00e | Panagiotis Kanavos | var remoteObjects = from objectList in listTasks |
235 | aa7ac00e | Panagiotis Kanavos | where (string)objectList.AsyncState != "trash" |
236 | aa7ac00e | Panagiotis Kanavos | from obj in objectList.Result |
237 | aa7ac00e | Panagiotis Kanavos | select obj; |
238 | aa7ac00e | Panagiotis Kanavos | |
239 | aa7ac00e | Panagiotis Kanavos | var sharedObjects = dict["shared"].Result; |
240 | aa7ac00e | Panagiotis Kanavos | |
241 | aa7ac00e | Panagiotis Kanavos | //DON'T process trashed files |
242 | aa7ac00e | Panagiotis Kanavos | //If some files are deleted and added again to a folder, they will be deleted |
243 | aa7ac00e | Panagiotis Kanavos | //even though they are new. |
244 | aa7ac00e | Panagiotis Kanavos | //We would have to check file dates and hashes to ensure that a trashed file |
245 | aa7ac00e | Panagiotis Kanavos | //can be deleted safely from the local hard drive. |
246 | aa7ac00e | Panagiotis Kanavos | /* |
247 | aa7ac00e | Panagiotis Kanavos | //Items with the same name, hash may be both in the container and the trash |
248 | aa7ac00e | Panagiotis Kanavos | //Don't delete items that exist in the container |
249 | aa7ac00e | Panagiotis Kanavos | var realTrash = from trash in trashObjects |
250 | aa7ac00e | Panagiotis Kanavos | where |
251 | aa7ac00e | Panagiotis Kanavos | !remoteObjects.Any( |
252 | aa7ac00e | Panagiotis Kanavos | info => info.Name == trash.Name && info.Hash == trash.Hash) |
253 | aa7ac00e | Panagiotis Kanavos | select trash; |
254 | aa7ac00e | Panagiotis Kanavos | ProcessTrashedFiles(accountInfo, realTrash); |
255 | aa7ac00e | Panagiotis Kanavos | */ |
256 | aa7ac00e | Panagiotis Kanavos | |
257 | aa7ac00e | Panagiotis Kanavos | var cleanRemotes = (from info in remoteObjects.Union(sharedObjects) |
258 | 92f18b56 | Panagiotis Kanavos | let name = info.Name??"" |
259 | aa7ac00e | Panagiotis Kanavos | where !name.EndsWith(".ignore", StringComparison.InvariantCultureIgnoreCase) && |
260 | aa7ac00e | Panagiotis Kanavos | !name.StartsWith(FolderConstants.CacheFolder + "/", |
261 | aa7ac00e | Panagiotis Kanavos | StringComparison.InvariantCultureIgnoreCase) |
262 | aa7ac00e | Panagiotis Kanavos | select info).ToList(); |
263 | aa7ac00e | Panagiotis Kanavos | |
264 | aa7ac00e | Panagiotis Kanavos | var differencer = _differencer.PostSnapshot(accountInfo, cleanRemotes); |
265 | aa7ac00e | Panagiotis Kanavos | |
266 | fec5da06 | Panagiotis Kanavos | ProcessDeletedFiles(accountInfo, differencer.Deleted.FilterDirectlyBelow(SelectiveUris), pollTime); |
267 | 759bd3c4 | Panagiotis Kanavos | |
268 | 759bd3c4 | Panagiotis Kanavos | // @@@ NEED To add previous state here as well, To compare with previous hash |
269 | 759bd3c4 | Panagiotis Kanavos | |
270 | 759bd3c4 | Panagiotis Kanavos | |
271 | aa7ac00e | Panagiotis Kanavos | |
272 | aa7ac00e | Panagiotis Kanavos | //Create a list of actions from the remote files |
273 | b666b39a | Panagiotis Kanavos | var allActions = MovesToActions(accountInfo,differencer.Moved.FilterDirectlyBelow(SelectiveUris)) |
274 | b666b39a | Panagiotis Kanavos | .Union( |
275 | b666b39a | Panagiotis Kanavos | ChangesToActions(accountInfo, differencer.Changed.FilterDirectlyBelow(SelectiveUris))) |
276 | aa7ac00e | Panagiotis Kanavos | .Union( |
277 | fec5da06 | Panagiotis Kanavos | CreatesToActions(accountInfo, differencer.Created.FilterDirectlyBelow(SelectiveUris))); |
278 | aa7ac00e | Panagiotis Kanavos | |
279 | aa7ac00e | Panagiotis Kanavos | //And remove those that are already being processed by the agent |
280 | aa7ac00e | Panagiotis Kanavos | var distinctActions = allActions |
281 | aa7ac00e | Panagiotis Kanavos | .Except(NetworkAgent.GetEnumerable(), new PithosMonitor.LocalFileComparer()) |
282 | aa7ac00e | Panagiotis Kanavos | .ToList(); |
283 | aa7ac00e | Panagiotis Kanavos | |
284 | aa7ac00e | Panagiotis Kanavos | //Queue all the actions |
285 | aa7ac00e | Panagiotis Kanavos | foreach (var message in distinctActions) |
286 | aa7ac00e | Panagiotis Kanavos | { |
287 | aa7ac00e | Panagiotis Kanavos | NetworkAgent.Post(message); |
288 | aa7ac00e | Panagiotis Kanavos | } |
289 | aa7ac00e | Panagiotis Kanavos | |
290 | aa7ac00e | Panagiotis Kanavos | Log.Info("[LISTENER] End Processing"); |
291 | aa7ac00e | Panagiotis Kanavos | } |
292 | aa7ac00e | Panagiotis Kanavos | } |
293 | aa7ac00e | Panagiotis Kanavos | catch (Exception ex) |
294 | aa7ac00e | Panagiotis Kanavos | { |
295 | aa7ac00e | Panagiotis Kanavos | Log.ErrorFormat("[FAIL] ListObjects for{0} in ProcessRemoteFiles with {1}", accountInfo.UserName, ex); |
296 | aa7ac00e | Panagiotis Kanavos | return; |
297 | aa7ac00e | Panagiotis Kanavos | } |
298 | aa7ac00e | Panagiotis Kanavos | |
299 | aa7ac00e | Panagiotis Kanavos | Log.Info("[LISTENER] Finished"); |
300 | aa7ac00e | Panagiotis Kanavos | |
301 | aa7ac00e | Panagiotis Kanavos | } |
302 | aa7ac00e | Panagiotis Kanavos | } |
303 | aa7ac00e | Panagiotis Kanavos | |
304 | aa7ac00e | Panagiotis Kanavos | AccountsDifferencer _differencer = new AccountsDifferencer(); |
305 | 759bd3c4 | Panagiotis Kanavos | private List<Uri> _selectiveUris=new List<Uri>(); |
306 | aa7ac00e | Panagiotis Kanavos | |
307 | aa7ac00e | Panagiotis Kanavos | /// <summary> |
308 | aa7ac00e | Panagiotis Kanavos | /// Deletes local files that are not found in the list of cloud files |
309 | aa7ac00e | Panagiotis Kanavos | /// </summary> |
310 | aa7ac00e | Panagiotis Kanavos | /// <param name="accountInfo"></param> |
311 | aa7ac00e | Panagiotis Kanavos | /// <param name="cloudFiles"></param> |
312 | aa7ac00e | Panagiotis Kanavos | /// <param name="pollTime"></param> |
313 | aa7ac00e | Panagiotis Kanavos | private void ProcessDeletedFiles(AccountInfo accountInfo, IEnumerable<ObjectInfo> cloudFiles, DateTime pollTime) |
314 | aa7ac00e | Panagiotis Kanavos | { |
315 | aa7ac00e | Panagiotis Kanavos | if (accountInfo == null) |
316 | aa7ac00e | Panagiotis Kanavos | throw new ArgumentNullException("accountInfo"); |
317 | aa7ac00e | Panagiotis Kanavos | if (String.IsNullOrWhiteSpace(accountInfo.AccountPath)) |
318 | aa7ac00e | Panagiotis Kanavos | throw new ArgumentException("The AccountInfo.AccountPath is empty", "accountInfo"); |
319 | aa7ac00e | Panagiotis Kanavos | if (cloudFiles == null) |
320 | aa7ac00e | Panagiotis Kanavos | throw new ArgumentNullException("cloudFiles"); |
321 | aa7ac00e | Panagiotis Kanavos | Contract.EndContractBlock(); |
322 | aa7ac00e | Panagiotis Kanavos | |
323 | aa7ac00e | Panagiotis Kanavos | //On the first run |
324 | aa7ac00e | Panagiotis Kanavos | if (_firstPoll) |
325 | aa7ac00e | Panagiotis Kanavos | { |
326 | aa7ac00e | Panagiotis Kanavos | //Only consider files that are not being modified, ie they are in the Unchanged state |
327 | aa7ac00e | Panagiotis Kanavos | var deleteCandidates = FileState.Queryable.Where(state => |
328 | aa7ac00e | Panagiotis Kanavos | state.FilePath.StartsWith(accountInfo.AccountPath) |
329 | aa7ac00e | Panagiotis Kanavos | && state.FileStatus == FileStatus.Unchanged).ToList(); |
330 | aa7ac00e | Panagiotis Kanavos | |
331 | aa7ac00e | Panagiotis Kanavos | |
332 | aa7ac00e | Panagiotis Kanavos | //TODO: filesToDelete must take into account the Others container |
333 | aa7ac00e | Panagiotis Kanavos | var filesToDelete = (from deleteCandidate in deleteCandidates |
334 | aa7ac00e | Panagiotis Kanavos | let localFile = FileInfoExtensions.FromPath(deleteCandidate.FilePath) |
335 | aa7ac00e | Panagiotis Kanavos | let relativeFilePath = localFile.AsRelativeTo(accountInfo.AccountPath) |
336 | aa7ac00e | Panagiotis Kanavos | where |
337 | aa7ac00e | Panagiotis Kanavos | !cloudFiles.Any(r => r.RelativeUrlToFilePath(accountInfo.UserName) == relativeFilePath) |
338 | aa7ac00e | Panagiotis Kanavos | select localFile).ToList(); |
339 | aa7ac00e | Panagiotis Kanavos | |
340 | aa7ac00e | Panagiotis Kanavos | |
341 | aa7ac00e | Panagiotis Kanavos | |
342 | aa7ac00e | Panagiotis Kanavos | //Set the status of missing files to Conflict |
343 | aa7ac00e | Panagiotis Kanavos | foreach (var item in filesToDelete) |
344 | aa7ac00e | Panagiotis Kanavos | { |
345 | aa7ac00e | Panagiotis Kanavos | //Try to acquire a gate on the file, to take into account files that have been dequeued |
346 | aa7ac00e | Panagiotis Kanavos | //and are being processed |
347 | aa7ac00e | Panagiotis Kanavos | using (var gate = NetworkGate.Acquire(item.FullName, NetworkOperation.Deleting)) |
348 | aa7ac00e | Panagiotis Kanavos | { |
349 | aa7ac00e | Panagiotis Kanavos | if (gate.Failed) |
350 | aa7ac00e | Panagiotis Kanavos | continue; |
351 | aa7ac00e | Panagiotis Kanavos | StatusKeeper.SetFileState(item.FullName, FileStatus.Conflict, FileOverlayStatus.Deleted); |
352 | aa7ac00e | Panagiotis Kanavos | } |
353 | aa7ac00e | Panagiotis Kanavos | } |
354 | aa7ac00e | Panagiotis Kanavos | UpdateStatus(PithosStatus.HasConflicts); |
355 | aa7ac00e | Panagiotis Kanavos | StatusNotification.NotifyConflicts(filesToDelete, String.Format("{0} local files are missing from Pithos, possibly because they were deleted", filesToDelete.Count)); |
356 | aa7ac00e | Panagiotis Kanavos | StatusNotification.NotifyForFiles(filesToDelete, String.Format("{0} files were deleted", filesToDelete.Count), TraceLevel.Info); |
357 | aa7ac00e | Panagiotis Kanavos | } |
358 | aa7ac00e | Panagiotis Kanavos | else |
359 | aa7ac00e | Panagiotis Kanavos | { |
360 | aa7ac00e | Panagiotis Kanavos | var deletedFiles = new List<FileSystemInfo>(); |
361 | aa7ac00e | Panagiotis Kanavos | foreach (var objectInfo in cloudFiles) |
362 | aa7ac00e | Panagiotis Kanavos | { |
363 | aa7ac00e | Panagiotis Kanavos | var relativePath = objectInfo.RelativeUrlToFilePath(accountInfo.UserName); |
364 | fbbbe99b | Panagiotis Kanavos | var item = FileAgent.GetFileAgent(accountInfo).GetFileSystemInfo(relativePath); |
365 | aa7ac00e | Panagiotis Kanavos | if (item.Exists) |
366 | aa7ac00e | Panagiotis Kanavos | { |
367 | aa7ac00e | Panagiotis Kanavos | if ((item.Attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly) |
368 | aa7ac00e | Panagiotis Kanavos | { |
369 | aa7ac00e | Panagiotis Kanavos | item.Attributes = item.Attributes & ~FileAttributes.ReadOnly; |
370 | aa7ac00e | Panagiotis Kanavos | |
371 | aa7ac00e | Panagiotis Kanavos | } |
372 | aa7ac00e | Panagiotis Kanavos | item.Delete(); |
373 | aa7ac00e | Panagiotis Kanavos | DateTime lastDate; |
374 | aa7ac00e | Panagiotis Kanavos | _lastSeen.TryRemove(item.FullName, out lastDate); |
375 | aa7ac00e | Panagiotis Kanavos | deletedFiles.Add(item); |
376 | aa7ac00e | Panagiotis Kanavos | } |
377 | aa7ac00e | Panagiotis Kanavos | StatusKeeper.SetFileState(item.FullName, FileStatus.Deleted, FileOverlayStatus.Deleted); |
378 | aa7ac00e | Panagiotis Kanavos | } |
379 | aa7ac00e | Panagiotis Kanavos | StatusNotification.NotifyForFiles(deletedFiles, String.Format("{0} files were deleted", deletedFiles.Count), TraceLevel.Info); |
380 | aa7ac00e | Panagiotis Kanavos | } |
381 | aa7ac00e | Panagiotis Kanavos | |
382 | aa7ac00e | Panagiotis Kanavos | } |
383 | aa7ac00e | Panagiotis Kanavos | |
384 | b666b39a | Panagiotis Kanavos | /// <summary> |
385 | b666b39a | Panagiotis Kanavos | /// Creates a Sync action for each changed server file |
386 | b666b39a | Panagiotis Kanavos | /// </summary> |
387 | b666b39a | Panagiotis Kanavos | /// <param name="accountInfo"></param> |
388 | b666b39a | Panagiotis Kanavos | /// <param name="changes"></param> |
389 | b666b39a | Panagiotis Kanavos | /// <returns></returns> |
390 | aa7ac00e | Panagiotis Kanavos | private IEnumerable<CloudAction> ChangesToActions(AccountInfo accountInfo, IEnumerable<ObjectInfo> changes) |
391 | aa7ac00e | Panagiotis Kanavos | { |
392 | aa7ac00e | Panagiotis Kanavos | if (changes == null) |
393 | aa7ac00e | Panagiotis Kanavos | throw new ArgumentNullException(); |
394 | aa7ac00e | Panagiotis Kanavos | Contract.EndContractBlock(); |
395 | fbbbe99b | Panagiotis Kanavos | var fileAgent = FileAgent.GetFileAgent(accountInfo); |
396 | aa7ac00e | Panagiotis Kanavos | |
397 | aa7ac00e | Panagiotis Kanavos | //In order to avoid multiple iterations over the files, we iterate only once |
398 | aa7ac00e | Panagiotis Kanavos | //over the remote files |
399 | aa7ac00e | Panagiotis Kanavos | foreach (var objectInfo in changes) |
400 | aa7ac00e | Panagiotis Kanavos | { |
401 | aa7ac00e | Panagiotis Kanavos | var relativePath = objectInfo.RelativeUrlToFilePath(accountInfo.UserName); |
402 | b666b39a | Panagiotis Kanavos | //If a directory object already exists, we may need to sync it |
403 | aa7ac00e | Panagiotis Kanavos | if (fileAgent.Exists(relativePath)) |
404 | aa7ac00e | Panagiotis Kanavos | { |
405 | aa7ac00e | Panagiotis Kanavos | var localFile = fileAgent.GetFileSystemInfo(relativePath); |
406 | b666b39a | Panagiotis Kanavos | //We don't need to sync directories |
407 | aa7ac00e | Panagiotis Kanavos | if (objectInfo.Content_Type == @"application/directory" && localFile is DirectoryInfo) |
408 | aa7ac00e | Panagiotis Kanavos | continue; |
409 | aa7ac00e | Panagiotis Kanavos | using (new SessionScope(FlushAction.Never)) |
410 | aa7ac00e | Panagiotis Kanavos | { |
411 | aa7ac00e | Panagiotis Kanavos | var state = StatusKeeper.GetStateByFilePath(localFile.FullName); |
412 | aa7ac00e | Panagiotis Kanavos | _lastSeen[localFile.FullName] = DateTime.Now; |
413 | aa7ac00e | Panagiotis Kanavos | //Common files should be checked on a per-case basis to detect differences, which is newer |
414 | aa7ac00e | Panagiotis Kanavos | |
415 | aa7ac00e | Panagiotis Kanavos | yield return new CloudAction(accountInfo, CloudActionType.MustSynch, |
416 | aa7ac00e | Panagiotis Kanavos | localFile, objectInfo, state, accountInfo.BlockSize, |
417 | aa7ac00e | Panagiotis Kanavos | accountInfo.BlockHash); |
418 | aa7ac00e | Panagiotis Kanavos | } |
419 | aa7ac00e | Panagiotis Kanavos | } |
420 | aa7ac00e | Panagiotis Kanavos | else |
421 | aa7ac00e | Panagiotis Kanavos | { |
422 | aa7ac00e | Panagiotis Kanavos | //Remote files should be downloaded |
423 | aa7ac00e | Panagiotis Kanavos | yield return new CloudDownloadAction(accountInfo, objectInfo); |
424 | aa7ac00e | Panagiotis Kanavos | } |
425 | aa7ac00e | Panagiotis Kanavos | } |
426 | aa7ac00e | Panagiotis Kanavos | } |
427 | aa7ac00e | Panagiotis Kanavos | |
428 | b666b39a | Panagiotis Kanavos | /// <summary> |
429 | b666b39a | Panagiotis Kanavos | /// Creates a Local Move action for each moved server file |
430 | b666b39a | Panagiotis Kanavos | /// </summary> |
431 | b666b39a | Panagiotis Kanavos | /// <param name="accountInfo"></param> |
432 | b666b39a | Panagiotis Kanavos | /// <param name="moves"></param> |
433 | b666b39a | Panagiotis Kanavos | /// <returns></returns> |
434 | b666b39a | Panagiotis Kanavos | private IEnumerable<CloudAction> MovesToActions(AccountInfo accountInfo, IEnumerable<ObjectInfo> moves) |
435 | b666b39a | Panagiotis Kanavos | { |
436 | b666b39a | Panagiotis Kanavos | if (moves == null) |
437 | b666b39a | Panagiotis Kanavos | throw new ArgumentNullException(); |
438 | b666b39a | Panagiotis Kanavos | Contract.EndContractBlock(); |
439 | b666b39a | Panagiotis Kanavos | var fileAgent = FileAgent.GetFileAgent(accountInfo); |
440 | b666b39a | Panagiotis Kanavos | |
441 | b666b39a | Panagiotis Kanavos | //In order to avoid multiple iterations over the files, we iterate only once |
442 | b666b39a | Panagiotis Kanavos | //over the remote files |
443 | b666b39a | Panagiotis Kanavos | foreach (var objectInfo in moves) |
444 | b666b39a | Panagiotis Kanavos | { |
445 | b666b39a | Panagiotis Kanavos | var previousRelativepath = objectInfo.Previous.RelativeUrlToFilePath(accountInfo.UserName); |
446 | b666b39a | Panagiotis Kanavos | //If the previous file already exists, we can execute a Move operation |
447 | b666b39a | Panagiotis Kanavos | if (fileAgent.Exists(previousRelativepath)) |
448 | b666b39a | Panagiotis Kanavos | { |
449 | b666b39a | Panagiotis Kanavos | var previousFile = fileAgent.GetFileSystemInfo(previousRelativepath); |
450 | b666b39a | Panagiotis Kanavos | using (new SessionScope(FlushAction.Never)) |
451 | b666b39a | Panagiotis Kanavos | { |
452 | b666b39a | Panagiotis Kanavos | var state = StatusKeeper.GetStateByFilePath(previousFile.FullName); |
453 | b666b39a | Panagiotis Kanavos | _lastSeen[previousFile.FullName] = DateTime.Now; |
454 | b666b39a | Panagiotis Kanavos | |
455 | b666b39a | Panagiotis Kanavos | //For each moved object we need to move both the local file and update |
456 | b666b39a | Panagiotis Kanavos | yield return new CloudAction(accountInfo, CloudActionType.RenameLocal, |
457 | b666b39a | Panagiotis Kanavos | previousFile, objectInfo, state, accountInfo.BlockSize, |
458 | b666b39a | Panagiotis Kanavos | accountInfo.BlockHash); |
459 | b666b39a | Panagiotis Kanavos | //For modified files, we need to download the changes as well |
460 | b666b39a | Panagiotis Kanavos | if (objectInfo.Hash!=objectInfo.PreviousHash) |
461 | b666b39a | Panagiotis Kanavos | yield return new CloudDownloadAction(accountInfo,objectInfo); |
462 | b666b39a | Panagiotis Kanavos | } |
463 | b666b39a | Panagiotis Kanavos | } |
464 | b666b39a | Panagiotis Kanavos | //If the previous file does not exist, we need to download it in the new location |
465 | b666b39a | Panagiotis Kanavos | else |
466 | b666b39a | Panagiotis Kanavos | { |
467 | b666b39a | Panagiotis Kanavos | //Remote files should be downloaded |
468 | b666b39a | Panagiotis Kanavos | yield return new CloudDownloadAction(accountInfo, objectInfo); |
469 | b666b39a | Panagiotis Kanavos | } |
470 | b666b39a | Panagiotis Kanavos | } |
471 | b666b39a | Panagiotis Kanavos | } |
472 | b666b39a | Panagiotis Kanavos | |
473 | b666b39a | Panagiotis Kanavos | |
474 | b666b39a | Panagiotis Kanavos | /// <summary> |
475 | b666b39a | Panagiotis Kanavos | /// Creates a download action for each new server file |
476 | b666b39a | Panagiotis Kanavos | /// </summary> |
477 | b666b39a | Panagiotis Kanavos | /// <param name="accountInfo"></param> |
478 | b666b39a | Panagiotis Kanavos | /// <param name="creates"></param> |
479 | b666b39a | Panagiotis Kanavos | /// <returns></returns> |
480 | aa7ac00e | Panagiotis Kanavos | private IEnumerable<CloudAction> CreatesToActions(AccountInfo accountInfo, IEnumerable<ObjectInfo> creates) |
481 | aa7ac00e | Panagiotis Kanavos | { |
482 | aa7ac00e | Panagiotis Kanavos | if (creates == null) |
483 | aa7ac00e | Panagiotis Kanavos | throw new ArgumentNullException(); |
484 | aa7ac00e | Panagiotis Kanavos | Contract.EndContractBlock(); |
485 | fbbbe99b | Panagiotis Kanavos | var fileAgent = FileAgent.GetFileAgent(accountInfo); |
486 | aa7ac00e | Panagiotis Kanavos | |
487 | aa7ac00e | Panagiotis Kanavos | //In order to avoid multiple iterations over the files, we iterate only once |
488 | aa7ac00e | Panagiotis Kanavos | //over the remote files |
489 | aa7ac00e | Panagiotis Kanavos | foreach (var objectInfo in creates) |
490 | aa7ac00e | Panagiotis Kanavos | { |
491 | aa7ac00e | Panagiotis Kanavos | var relativePath = objectInfo.RelativeUrlToFilePath(accountInfo.UserName); |
492 | b666b39a | Panagiotis Kanavos | //If the object already exists, we probably have a conflict |
493 | aa7ac00e | Panagiotis Kanavos | if (fileAgent.Exists(relativePath)) |
494 | aa7ac00e | Panagiotis Kanavos | { |
495 | aa7ac00e | Panagiotis Kanavos | //If a directory object already exists, we don't need to perform any other action |
496 | aa7ac00e | Panagiotis Kanavos | var localFile = fileAgent.GetFileSystemInfo(relativePath); |
497 | aa7ac00e | Panagiotis Kanavos | StatusKeeper.SetFileState(localFile.FullName, FileStatus.Conflict, FileOverlayStatus.Conflict); |
498 | aa7ac00e | Panagiotis Kanavos | } |
499 | aa7ac00e | Panagiotis Kanavos | else |
500 | aa7ac00e | Panagiotis Kanavos | { |
501 | aa7ac00e | Panagiotis Kanavos | //Remote files should be downloaded |
502 | aa7ac00e | Panagiotis Kanavos | yield return new CloudDownloadAction(accountInfo, objectInfo); |
503 | aa7ac00e | Panagiotis Kanavos | } |
504 | aa7ac00e | Panagiotis Kanavos | } |
505 | aa7ac00e | Panagiotis Kanavos | } |
506 | aa7ac00e | Panagiotis Kanavos | |
507 | aa7ac00e | Panagiotis Kanavos | private void ProcessTrashedFiles(AccountInfo accountInfo, IEnumerable<ObjectInfo> trashObjects) |
508 | aa7ac00e | Panagiotis Kanavos | { |
509 | fbbbe99b | Panagiotis Kanavos | var fileAgent = FileAgent.GetFileAgent(accountInfo); |
510 | aa7ac00e | Panagiotis Kanavos | foreach (var trashObject in trashObjects) |
511 | aa7ac00e | Panagiotis Kanavos | { |
512 | aa7ac00e | Panagiotis Kanavos | var barePath = trashObject.RelativeUrlToFilePath(accountInfo.UserName); |
513 | aa7ac00e | Panagiotis Kanavos | //HACK: Assume only the "pithos" container is used. Must find out what happens when |
514 | aa7ac00e | Panagiotis Kanavos | //deleting a file from a different container |
515 | aa7ac00e | Panagiotis Kanavos | var relativePath = Path.Combine("pithos", barePath); |
516 | aa7ac00e | Panagiotis Kanavos | fileAgent.Delete(relativePath); |
517 | aa7ac00e | Panagiotis Kanavos | } |
518 | aa7ac00e | Panagiotis Kanavos | } |
519 | aa7ac00e | Panagiotis Kanavos | |
520 | fec5da06 | Panagiotis Kanavos | /// <summary> |
521 | fec5da06 | Panagiotis Kanavos | /// Notify the UI to update the visual status |
522 | fec5da06 | Panagiotis Kanavos | /// </summary> |
523 | fec5da06 | Panagiotis Kanavos | /// <param name="status"></param> |
524 | aa7ac00e | Panagiotis Kanavos | private void UpdateStatus(PithosStatus status) |
525 | aa7ac00e | Panagiotis Kanavos | { |
526 | fec5da06 | Panagiotis Kanavos | try |
527 | fec5da06 | Panagiotis Kanavos | { |
528 | fec5da06 | Panagiotis Kanavos | StatusKeeper.SetPithosStatus(status); |
529 | fec5da06 | Panagiotis Kanavos | StatusNotification.Notify(new Notification()); |
530 | fec5da06 | Panagiotis Kanavos | } |
531 | fec5da06 | Panagiotis Kanavos | catch (Exception exc) |
532 | fec5da06 | Panagiotis Kanavos | { |
533 | fec5da06 | Panagiotis Kanavos | //Failure is not critical, just log it |
534 | fec5da06 | Panagiotis Kanavos | Log.Warn("Error while updating status", exc); |
535 | fec5da06 | Panagiotis Kanavos | } |
536 | aa7ac00e | Panagiotis Kanavos | } |
537 | aa7ac00e | Panagiotis Kanavos | |
538 | aa7ac00e | Panagiotis Kanavos | private static void CreateContainerFolders(AccountInfo accountInfo, IEnumerable<ContainerInfo> containers) |
539 | aa7ac00e | Panagiotis Kanavos | { |
540 | aa7ac00e | Panagiotis Kanavos | var containerPaths = from container in containers |
541 | aa7ac00e | Panagiotis Kanavos | let containerPath = Path.Combine(accountInfo.AccountPath, container.Name) |
542 | aa7ac00e | Panagiotis Kanavos | where container.Name != FolderConstants.TrashContainer && !Directory.Exists(containerPath) |
543 | aa7ac00e | Panagiotis Kanavos | select containerPath; |
544 | aa7ac00e | Panagiotis Kanavos | |
545 | aa7ac00e | Panagiotis Kanavos | foreach (var path in containerPaths) |
546 | aa7ac00e | Panagiotis Kanavos | { |
547 | aa7ac00e | Panagiotis Kanavos | Directory.CreateDirectory(path); |
548 | aa7ac00e | Panagiotis Kanavos | } |
549 | aa7ac00e | Panagiotis Kanavos | } |
550 | 759bd3c4 | Panagiotis Kanavos | |
551 | fec5da06 | Panagiotis Kanavos | public void SetSyncUris(Uri[] uris) |
552 | fec5da06 | Panagiotis Kanavos | { |
553 | fec5da06 | Panagiotis Kanavos | SelectiveUris=uris.ToList(); |
554 | 759bd3c4 | Panagiotis Kanavos | } |
555 | 759bd3c4 | Panagiotis Kanavos | |
556 | 759bd3c4 | Panagiotis Kanavos | protected List<Uri> SelectiveUris |
557 | 759bd3c4 | Panagiotis Kanavos | { |
558 | 759bd3c4 | Panagiotis Kanavos | get { return _selectiveUris;} |
559 | 759bd3c4 | Panagiotis Kanavos | set { _selectiveUris = value; } |
560 | 759bd3c4 | Panagiotis Kanavos | } |
561 | fec5da06 | Panagiotis Kanavos | |
562 | fec5da06 | Panagiotis Kanavos | public void AddAccount(AccountInfo accountInfo) |
563 | fec5da06 | Panagiotis Kanavos | { |
564 | fec5da06 | Panagiotis Kanavos | if (!_accounts.Contains(accountInfo)) |
565 | fec5da06 | Panagiotis Kanavos | _accounts.Add(accountInfo); |
566 | fec5da06 | Panagiotis Kanavos | } |
567 | aa7ac00e | Panagiotis Kanavos | } |
568 | aa7ac00e | Panagiotis Kanavos | } |