Statistics
| Branch: | Revision:

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
}