906ce5d8006e801161bcaf250b7169a5ed142170
[pithos-ms-client] / trunk / Pithos.Core / NetworkGate.cs
1 using System;
2 using System.Collections.Concurrent;
3 using System.Collections.Generic;
4 using System.Diagnostics.Contracts;
5 using System.IO;
6
7 namespace Pithos.Core
8 {
9     public enum NetworkOperation
10     {
11         None,
12         Uploading,
13         Downloading
14     }
15
16     //The NetworkGate prevents starting download/uploads for files that are already in the process of downloading,
17     //uploading.   
18     public class NetworkGate:IDisposable
19     {
20         //The state of each file is stored in a thread-safe dictionary
21         static readonly ConcurrentDictionary<string, NetworkOperation> NetworkState = new ConcurrentDictionary<string, NetworkOperation>();
22
23         public static NetworkOperation GetNetworkState(string path)
24         {
25             if (String.IsNullOrWhiteSpace(path))
26                 throw new ArgumentNullException("path");
27             if (!Path.IsPathRooted(path))
28                 throw new ArgumentException("path must be a rooted path", "path");
29             Contract.EndContractBlock();
30
31             NetworkOperation operation;
32             if (NetworkState.TryGetValue(path.ToLower(), out operation))
33                 return operation;
34             return NetworkOperation.None;
35         }
36
37         //Store a network operation for the specified path
38         public static void SetNetworkState(string path, NetworkOperation operation)
39         {
40             if (String.IsNullOrWhiteSpace(path))
41                 throw new ArgumentNullException("path");
42             if (!Path.IsPathRooted(path))
43                 throw new ArgumentException("path must be a rooted path", "path");
44             Contract.EndContractBlock();
45
46             var lower = path.ToLower();
47             NetworkState[lower] = operation;            
48             //By default, None values don't need to be stored. They are stored anyway
49             //because TryRemove may fail.
50             if (operation == NetworkOperation.None)
51             {
52                 NetworkOperation oldOperation;
53                 NetworkState.TryRemove(lower, out oldOperation);
54             }
55         }
56
57         //Clients should acquire a NetworkGate before starting any network operation.
58         //If Acquire fails, another network operation is already in progress
59         public static NetworkGate Acquire(string path, NetworkOperation operation)
60         {
61             if (String.IsNullOrWhiteSpace(path))
62                 throw new ArgumentNullException("path");
63             if (!Path.IsPathRooted(path))
64                 throw new ArgumentException("path must be a rooted path", "path");
65             Contract.EndContractBlock();
66
67             var state = GetNetworkState(path);
68             //If no operation is in progress, return a NetworkGate
69             return (state == NetworkOperation.None)
70                        ? new NetworkGate(path, operation)
71                    //otherwise return a gate with Fail flagged
72                        : new NetworkGate(path, NetworkOperation.None);
73         }
74
75
76
77         public string FilePath { get; private set; }
78         public NetworkOperation Operation { get; private set; }
79
80         private NetworkGate(string path,NetworkOperation operation)
81         {
82             if (String.IsNullOrWhiteSpace(path))
83                 throw new ArgumentNullException("path");
84             Contract.EndContractBlock();
85
86             Operation = operation;
87             FilePath = path.ToLower();
88
89             //Skip dummy operations (those with Operation == None)
90             if (Operation != NetworkOperation.None)
91                 //and store the file's operation
92                 SetNetworkState(FilePath, operation);
93         }
94
95         //A NetworkGate has Failed if its operation is None
96         public bool Failed { get { return Operation == NetworkOperation.None; } }
97
98         //Release a gate by setting the NetworkOperation to None
99         public void Release()
100         {
101             //Skip Failed flags
102             if (!Failed)
103                 //And reset the operation state for the file
104                 SetNetworkState(FilePath,NetworkOperation.None);
105         }
106
107
108         public void Dispose()
109         {
110             Dispose(true);
111             GC.SuppressFinalize(this);
112         }
113
114         protected void Dispose(bool disposing)
115         {
116             if (disposing)
117             {
118                 Release();
119             }
120         }
121
122     }
123 }