root / trunk / Pithos.Core / NetworkGate.cs @ cfed7823
History | View | Annotate | Download (4.6 kB)
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 |
public string FilePath { get; private set; } |
21 |
public NetworkOperation Operation { get; private set; } |
22 |
|
23 |
[ContractInvariantMethod] |
24 |
private void Invariants() |
25 |
{ |
26 |
Contract.Invariant(!String.IsNullOrWhiteSpace(FilePath)); |
27 |
Contract.Invariant(Path.IsPathRooted(FilePath)); |
28 |
} |
29 |
|
30 |
//The state of each file is stored in a thread-safe dictionary |
31 |
static readonly ConcurrentDictionary<string, NetworkOperation> NetworkState = new ConcurrentDictionary<string, NetworkOperation>(); |
32 |
|
33 |
public static NetworkOperation GetNetworkState(string path) |
34 |
{ |
35 |
if (String.IsNullOrWhiteSpace(path)) |
36 |
throw new ArgumentNullException("path"); |
37 |
if (!Path.IsPathRooted(path)) |
38 |
throw new ArgumentException("path must be a rooted path", "path"); |
39 |
Contract.EndContractBlock(); |
40 |
|
41 |
NetworkOperation operation; |
42 |
if (NetworkState.TryGetValue(path.ToLower(), out operation)) |
43 |
return operation; |
44 |
return NetworkOperation.None; |
45 |
} |
46 |
|
47 |
//Store a network operation for the specified path |
48 |
public static void SetNetworkState(string path, NetworkOperation operation) |
49 |
{ |
50 |
if (String.IsNullOrWhiteSpace(path)) |
51 |
throw new ArgumentNullException("path"); |
52 |
if (!Path.IsPathRooted(path)) |
53 |
throw new ArgumentException("path must be a rooted path", "path"); |
54 |
Contract.EndContractBlock(); |
55 |
|
56 |
var lower = path.ToLower(); |
57 |
NetworkState[lower] = operation; |
58 |
//By default, None values don't need to be stored. They are stored anyway |
59 |
//because TryRemove may fail. |
60 |
if (operation == NetworkOperation.None) |
61 |
{ |
62 |
NetworkOperation oldOperation; |
63 |
NetworkState.TryRemove(lower, out oldOperation); |
64 |
} |
65 |
} |
66 |
|
67 |
//Clients should acquire a NetworkGate before starting any network operation. |
68 |
//If Acquire fails, another network operation is already in progress |
69 |
public static NetworkGate Acquire(string path, NetworkOperation operation) |
70 |
{ |
71 |
if (String.IsNullOrWhiteSpace(path)) |
72 |
throw new ArgumentNullException("path"); |
73 |
if (!Path.IsPathRooted(path)) |
74 |
throw new ArgumentException("path must be a rooted path", "path"); |
75 |
Contract.EndContractBlock(); |
76 |
|
77 |
var state = GetNetworkState(path); |
78 |
//If no operation is in progress, return a NetworkGate |
79 |
return (state == NetworkOperation.None) |
80 |
? new NetworkGate(path, operation) |
81 |
//otherwise return a gate with Fail flagged |
82 |
: new NetworkGate(path, NetworkOperation.None); |
83 |
} |
84 |
|
85 |
|
86 |
|
87 |
|
88 |
|
89 |
|
90 |
private NetworkGate(string path,NetworkOperation operation) |
91 |
{ |
92 |
if (String.IsNullOrWhiteSpace(path)) |
93 |
throw new ArgumentNullException("path"); |
94 |
if (!Path.IsPathRooted(path)) |
95 |
throw new ArgumentException("path must be rooted","path"); |
96 |
Contract.EndContractBlock(); |
97 |
|
98 |
Operation = operation; |
99 |
FilePath = path.ToLower(); |
100 |
|
101 |
//Skip dummy operations (those with Operation == None) |
102 |
if (Operation != NetworkOperation.None) |
103 |
//and store the file's operation |
104 |
SetNetworkState(FilePath, operation); |
105 |
} |
106 |
|
107 |
//A NetworkGate has Failed if its operation is None |
108 |
public bool Failed { get { return Operation == NetworkOperation.None; } } |
109 |
|
110 |
//Release a gate by setting the NetworkOperation to None |
111 |
public void Release() |
112 |
{ |
113 |
//Skip Failed flags |
114 |
if (!Failed) |
115 |
//And reset the operation state for the file |
116 |
SetNetworkState(FilePath,NetworkOperation.None); |
117 |
} |
118 |
|
119 |
|
120 |
public void Dispose() |
121 |
{ |
122 |
Dispose(true); |
123 |
GC.SuppressFinalize(this); |
124 |
} |
125 |
|
126 |
protected void Dispose(bool disposing) |
127 |
{ |
128 |
if (disposing) |
129 |
{ |
130 |
Release(); |
131 |
} |
132 |
} |
133 |
|
134 |
} |
135 |
} |