Selective filtering modifications to allow uploading of new root folders
[pithos-ms-client] / trunk / Pithos.Core / Agents / WorkflowAgent.cs
1 #region
2 /* -----------------------------------------------------------------------
3  * <copyright file="WorkflowAgent.cs" company="GRNet">
4  * 
5  * Copyright 2011-2012 GRNET S.A. All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or
8  * without modification, are permitted provided that the following
9  * conditions are met:
10  *
11  *   1. Redistributions of source code must retain the above
12  *      copyright notice, this list of conditions and the following
13  *      disclaimer.
14  *
15  *   2. Redistributions in binary form must reproduce the above
16  *      copyright notice, this list of conditions and the following
17  *      disclaimer in the documentation and/or other materials
18  *      provided with the distribution.
19  *
20  *
21  * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
22  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
25  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * The views and conclusions contained in the software and
35  * documentation are those of the authors and should not be
36  * interpreted as representing official policies, either expressed
37  * or implied, of GRNET S.A.
38  * </copyright>
39  * -----------------------------------------------------------------------
40  */
41 #endregion
42 using System;
43 using System.Collections.Generic;
44 using System.ComponentModel.Composition;
45 using System.Diagnostics;
46 using System.Diagnostics.Contracts;
47 using System.IO;
48 using System.Linq;
49 using System.Reflection;
50 using System.Text;
51 using System.Threading.Tasks;
52 using Castle.ActiveRecord;
53 using Pithos.Interfaces;
54 using Pithos.Network;
55 using log4net;
56
57 namespace Pithos.Core.Agents
58 {
59 /*
60     [Export]
61     public class WorkflowAgent
62     {
63         private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
64
65         readonly Agent<WorkflowState> _agent;
66                 
67         public IStatusNotification StatusNotification { get; set; }
68         [System.ComponentModel.Composition.Import]
69         public IStatusKeeper StatusKeeper { get; set; }
70
71         [System.ComponentModel.Composition.Import]
72         public NetworkAgent NetworkAgent { get; set; }
73
74         [System.ComponentModel.Composition.Import]
75         public IPithosSettings Settings { get; set; }
76
77         [System.ComponentModel.Composition.Import]
78         public Selectives Selectives { get; set; }
79
80         public WorkflowAgent()
81         {
82             /*_agent = Agent<WorkflowState>.Start(inbox =>
83             {
84                 Action loop = null;
85                 loop = () =>
86                 {
87                     var message = inbox.Receive();
88                     var process = message.Then(Process, inbox.CancellationToken);                        
89                     inbox.LoopAsync(process,loop,ex=>
90                             Log.ErrorFormat("[ERROR] Synch for {0}:\r{1}", message.Result.FileName, ex));
91                 };
92                 loop();
93             });#1#
94         }
95
96 /*
97         private Task<object> Process(WorkflowState state)
98         {
99             var accountInfo = state.AccountInfo;
100             using (log4net.ThreadContext.Stacks["Workflow"].Push("Process"))
101             {
102                 try
103                 {
104
105                     if (Log.IsDebugEnabled)
106                         Log.DebugFormat("State {0} {1} {2}", state.FileName, state.Status, state.TriggeringChange);
107
108                     if (state.Skip)
109                     {
110                         if (Log.IsDebugEnabled) Log.DebugFormat("Skipping {0}", state.FileName);
111
112                         return CompletedTask<object>.Default;
113                     }
114
115                     var info = FileInfoExtensions.FromPath(state.Path);// Directory.Exists(state.Path) ? (FileSystemInfo)new DirectoryInfo(state.Path) : new FileInfo(state.Path);
116
117                     //Bypass deleted files, unless the status is Deleted
118                     if (!info.Exists && state.Status != FileStatus.Deleted)
119                     {
120                         state.Skip = true;
121                         this.StatusKeeper.ClearFileStatus(state.Path);
122
123                         if (Log.IsDebugEnabled) Log.DebugFormat("Skipped missing {0}", state.FileName);
124
125                         return CompletedTask<object>.Default;
126                     }
127
128                     using (new SessionScope(FlushAction.Never))
129                     {
130
131                         var fileState = StatusKeeper.GetStateByFilePath(state.Path);
132
133                         switch (state.Status)
134                         {
135                             case FileStatus.Created:
136                             case FileStatus.Modified:
137                                 NetworkAgent.Post(new CloudUploadAction(accountInfo, info, fileState,
138                                                                         accountInfo.BlockSize,
139                                                                         accountInfo.BlockHash,state,state.IsCreation));
140                                 break;
141                             case FileStatus.Deleted:
142                                 DeleteChildObjects(state, fileState);
143                                 NetworkAgent.Post(new CloudDeleteAction(accountInfo, info, fileState,state));
144                                 break;
145                             case FileStatus.Renamed:
146                                 if (state.OldPath == null)
147                                 {
148                                     //We reach this point only if the app closed before propagating a rename to the server
149                                     Log.WarnFormat("Unfinished rename [{0}]",state.Path);
150                                     StatusKeeper.SetFileState(state.Path,FileStatus.Conflict,FileOverlayStatus.Conflict, "Rename without old path");
151                                     break;
152                                 }
153                                 FileSystemInfo oldInfo = Directory.Exists(state.OldPath)
154                                                              ? (FileSystemInfo) new DirectoryInfo(state.OldPath)
155                                                              : new FileInfo(state.OldPath);
156                                 FileSystemInfo newInfo = Directory.Exists(state.Path)
157                                                              ? (FileSystemInfo) new DirectoryInfo(state.Path)
158                                                              : new FileInfo(state.Path);
159                                 NetworkAgent.Post(new CloudMoveAction(accountInfo, CloudActionType.RenameCloud,
160                                                                       oldInfo,
161                                                                       newInfo,state));                                
162                                 //TODO: Do I have to move children as well or will Pithos handle this?
163                                //Need to find all children of the OLD filepath
164                                 //MoveChildObjects(state);
165                                 break;
166                         }
167                     }
168
169                     return CompletedTask<object>.Default;
170                 }
171                 catch (Exception ex)
172                 {
173                     Log.Error(ex.ToString());
174                     throw;
175                 }
176             }
177         }
178 #1#
179
180 /*
181
182         private void DeleteChildObjects(WorkflowState state, FileState fileState)
183         {
184             if (fileState != null)
185             {
186                 var children = StatusKeeper.GetChildren(fileState);
187                 foreach (var child in children)
188                 {
189                     var childInfo = child.IsFolder
190                                         ? (FileSystemInfo) new DirectoryInfo(child.FilePath)
191                                         : new FileInfo(child.FilePath);
192                     NetworkAgent.Post(new CloudDeleteAction(state.AccountInfo, childInfo, child,state));
193                 }
194             }
195         }
196 #1#
197
198         /*private void MoveChildObjects(WorkflowState state)
199         {
200             var oldFileState = StatusKeeper.GetStateByFilePath(state.OldPath);
201             if (oldFileState != null)
202             {
203                 var children = StatusKeeper.GetChildren(oldFileState);
204                 foreach (var child in children)
205                 {
206                     var newPath = Path.Combine(state.Path, child.FilePath.Substring(state.OldPath.Length+1));
207
208                     var oldMoveInfo = child.IsFolder
209                                           ? (FileSystemInfo) new DirectoryInfo(child.FilePath)
210                                           : new FileInfo(child.FilePath);
211                     var newMoveInfo = child.IsFolder
212                                           ? (FileSystemInfo) new DirectoryInfo(newPath)
213                                           : new FileInfo(newPath);
214                     //The new file path will be created by trimming the old root path
215                     //and substituting the new root path
216
217                     NetworkAgent.Post(new CloudMoveAction(state.AccountInfo, CloudActionType.RenameCloud,
218                                                           oldMoveInfo, newMoveInfo));
219                 }
220             }
221         }#1#
222
223
224         //Starts interrupted files for a specific account
225 /*
226         public void RestartInterruptedFiles(AccountInfo accountInfo)
227         {
228             
229             StatusKeeper.CleanupOrphanStates();
230             using (log4net.ThreadContext.Stacks["Operation"].Push("RestartInterrupted"))
231             {
232                 if (Log.IsDebugEnabled)
233                     Log.Debug("Starting interrupted files");
234
235                 var cachePath = Path.Combine(accountInfo.AccountPath, FolderConstants.CacheFolder)
236                     .ToLower();
237
238
239                 
240                 
241                 var account = accountInfo;
242                 var pendingEntries = (from state in FileState.Queryable
243                                      where state.FileStatus != FileStatus.Unchanged &&
244                                             state.FileStatus != FileStatus.Forbidden &&
245                                             state.FileStatus != FileStatus.Conflict &&
246                                            !state.FilePath.StartsWith(cachePath) &&
247                                            !state.FilePath.EndsWith(".ignore") &&
248                                            state.FilePath.StartsWith(account.AccountPath)                                            
249                                      select state).ToList();
250                 if (pendingEntries.Count>0)
251                     StatusNotification.NotifyChange("Restart processing interrupted files", TraceLevel.Verbose);
252
253                 var pendingStates = pendingEntries
254                     .Select(state => new WorkflowState(account, state))
255                     .ToList();
256                 
257                                 
258                 if (Log.IsDebugEnabled)
259                     Log.DebugFormat("Found {0} interrupted files", pendingStates.Count);
260
261                 pendingStates.ForEach(Post);
262             }
263         }
264 #1#
265
266
267
268 /*
269         public void Post(WorkflowState workflowState)
270         {
271             if (Log.IsDebugEnabled)
272                 Log.DebugFormat("Posted {0} {1} {2}", workflowState.Path, workflowState.Status, workflowState.TriggeringChange);
273
274             //Remove invalid state            
275             //For now, ignore paths
276            /* if (Directory.Exists(workflowState.Path))
277                 return;#2#
278             //TODO: Need to handle folder renames            
279
280
281             if (!Selectives.IsSelected(workflowState.AccountInfo, workflowState.Path))
282             {
283                 if (!workflowState.IsCreation || File.Exists(workflowState.Path))
284                 {
285                     Log.InfoFormat("File skipped, not under a selected folder [{0}] ", workflowState.Path);
286                     return;
287                 }
288             }
289
290             Debug.Assert(workflowState.Path.StartsWith(workflowState.AccountInfo.AccountPath, StringComparison.InvariantCultureIgnoreCase), "File from wrong account posted");
291
292             _agent.Post(workflowState);
293         }     
294 #1#
295
296     }
297 */
298 }