Selective Sync now shows both server AND local folders
[pithos-ms-client] / trunk / Pithos.Core / NetworkGate.cs
1 #region
2 /* -----------------------------------------------------------------------
3  * <copyright file="NetworkGate.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.Concurrent;
44 using System.Collections.Generic;
45 using System.Diagnostics.Contracts;
46 using System.IO;
47
48 namespace Pithos.Core
49 {
50     public enum NetworkOperation
51     {
52         None,
53         Uploading,
54         Downloading,
55         Deleting,
56         Renaming
57     }
58
59     //The NetworkGate prevents starting download/uploads for files that are already in the process of downloading,
60     //uploading.   
61     public class NetworkGate:IDisposable
62     {
63         public string FilePath { get; private set; }
64         public NetworkOperation Operation { get; private set; }
65
66         [ContractInvariantMethod]
67         private void Invariants()
68         {
69             Contract.Invariant(!String.IsNullOrWhiteSpace(FilePath));
70             Contract.Invariant(Path.IsPathRooted(FilePath));
71         }
72
73         //The state of each file is stored in a thread-safe dictionary
74         static readonly ConcurrentDictionary<string, NetworkOperation> NetworkState = new ConcurrentDictionary<string, NetworkOperation>();
75
76         public static NetworkOperation GetNetworkState(string path)
77         {
78             if (String.IsNullOrWhiteSpace(path))
79                 throw new ArgumentNullException("path");
80             if (!Path.IsPathRooted(path))
81                 throw new ArgumentException("path must be a rooted path", "path");
82             Contract.EndContractBlock();
83
84             NetworkOperation operation;
85             var lower = path.ToLower();
86             if (NetworkState.TryGetValue(lower, out operation))
87                 return operation;
88             return NetworkOperation.None;
89         }
90
91         //Store a network operation for the specified path
92         public static void SetNetworkState(string path, NetworkOperation operation)
93         {
94             if (String.IsNullOrWhiteSpace(path))
95                 throw new ArgumentNullException("path");
96             if (!Path.IsPathRooted(path))
97                 throw new ArgumentException("path must be a rooted path", "path");
98             Contract.EndContractBlock();
99
100             var lower = path.ToLower();
101             NetworkState[lower] = operation;            
102             //By default, None values don't need to be stored. They are stored anyway
103             //because TryRemove may fail.
104             if (operation == NetworkOperation.None)
105             {
106                 NetworkOperation oldOperation;
107                 NetworkState.TryRemove(lower, out oldOperation);
108             }
109         }
110
111         //Clients should acquire a NetworkGate before starting any network operation.
112         //If Acquire fails, another network operation is already in progress
113         public static NetworkGate Acquire(string path, NetworkOperation operation)
114         {
115             if (String.IsNullOrWhiteSpace(path))
116                 throw new ArgumentNullException("path");
117             if (!Path.IsPathRooted(path))
118                 throw new ArgumentException("path must be a rooted path", "path");
119             Contract.EndContractBlock();
120
121             var lower = path.ToLower();
122             var state = GetNetworkState(lower);
123             //If no operation is in progress, return a NetworkGate
124             return (state == NetworkOperation.None)
125                        ? new NetworkGate(lower, operation)
126                    //otherwise return a gate with Fail flagged
127                        : new NetworkGate(lower, NetworkOperation.None);
128         }
129
130
131
132
133
134
135         private NetworkGate(string path,NetworkOperation operation)
136         {
137             if (String.IsNullOrWhiteSpace(path))
138                 throw new ArgumentNullException("path");
139             if (!Path.IsPathRooted(path))
140                 throw new ArgumentException("path must be rooted","path");
141             Contract.EndContractBlock();
142
143             Operation = operation;
144             FilePath = path.ToLower();            
145
146             //Skip dummy operations (those with Operation == None)
147             if (Operation != NetworkOperation.None)
148                 //and store the file's operation
149                 SetNetworkState(FilePath, operation);
150         }
151
152         //A NetworkGate has Failed if its operation is None
153         public bool Failed { get { return Operation == NetworkOperation.None; } }
154
155         //Release a gate by setting the NetworkOperation to None
156         public void Release()
157         {
158             //Skip Failed flags
159             if (!Failed)
160                 //And reset the operation state for the file
161                 SetNetworkState(FilePath,NetworkOperation.None);
162         }
163
164
165         public void Dispose()
166         {
167             Dispose(true);
168             GC.SuppressFinalize(this);
169         }
170
171         protected void Dispose(bool disposing)
172         {
173             if (disposing)
174             {
175                 Release();
176             }
177         }
178
179     }
180 }