Commit before switching to sql compact
[pithos-ms-client] / trunk / Pithos.Network / WebExtensions.cs
1 using System;\r
2 using System.Collections.Generic;\r
3 using System.ComponentModel;\r
4 using System.Diagnostics.Contracts;\r
5 using System.Linq;\r
6 using System.Text;\r
7 using System.Net;\r
8 using System.IO;\r
9 using System.Threading;\r
10 using System.Threading.Tasks;\r
11 using log4net;\r
12 \r
13 namespace Pithos.Network\r
14 {\r
15     public static class WebExtensions\r
16     {\r
17         public static string ReadToEnd(this HttpWebResponse response)\r
18         {\r
19             using (var stream = response.GetResponseStream())\r
20             {\r
21                 if (stream == null)\r
22                     return null;\r
23                 using (var reader = new StreamReader(stream))\r
24                 {\r
25                     var body = reader.ReadToEnd();\r
26                     return body;\r
27                 }\r
28             }\r
29         }\r
30 \r
31         public static void LogError(this ILog log, HttpWebResponse response)\r
32         {\r
33             if (log.IsDebugEnabled)\r
34             {\r
35                 if (response != null)\r
36                 {\r
37                     var body = response.ReadToEnd();\r
38                     log.ErrorFormat("Headers:\n{0}\nBody:{1}", response.Headers, body);\r
39                 }\r
40             }\r
41         }\r
42 \r
43         public static TextReader GetLoggedReader(this Stream stream, ILog log)\r
44         {\r
45             var reader = new StreamReader(stream);\r
46             if (!log.IsDebugEnabled)\r
47                 return reader;\r
48 \r
49             using (reader)\r
50             {\r
51                 var body = reader.ReadToEnd();\r
52                 log.DebugFormat("JSON response: {0}", body);\r
53                 return new StringReader(body);\r
54             }\r
55         }\r
56 \r
57 \r
58         public static IEnumerable<T> Range<T>(this IList<T> list, int start, int end)\r
59         {\r
60             Contract.Requires(start >= 0);\r
61             Contract.Requires(end < list.Count);\r
62             Contract.Requires(start <= end);\r
63 \r
64             if (list == null)\r
65                 yield break;\r
66 \r
67             for (var i = 0; i <= end; i++)\r
68             {\r
69                 yield return list[i];\r
70             }\r
71 \r
72         }\r
73 \r
74         public static Task<byte[]> UploadDataTaskAsync(this WebClient webClient, Uri address, string method, byte[] data, CancellationToken cancellationToken, IProgress<UploadProgressChangedEventArgs> progress)\r
75         {\r
76             var tcs = new TaskCompletionSource<byte[]>(address);\r
77             if (cancellationToken.IsCancellationRequested)\r
78             {\r
79                 tcs.TrySetCanceled();\r
80             }\r
81             else\r
82             {\r
83                 CancellationTokenRegistration ctr = cancellationToken.Register(()=>\r
84                 {\r
85                     webClient.CancelAsync();\r
86                 });\r
87                 UploadDataCompletedEventHandler completedHandler = null;\r
88                 UploadProgressChangedEventHandler progressHandler = null;\r
89                 if (progress != null)\r
90                     progressHandler = (s, e) => PithosEAPCommon.HandleProgress(tcs, e, () => e, progress);\r
91                 completedHandler =(sender, e) =>PithosEAPCommon.HandleCompletion(tcs, true, e,() => e.Result,() =>\r
92                 { \r
93                     ctr.Dispose();\r
94                     webClient.UploadDataCompleted -= completedHandler;\r
95                     webClient.UploadProgressChanged -= progressHandler;\r
96                 });\r
97                 webClient.UploadDataCompleted += completedHandler;\r
98                 webClient.UploadProgressChanged += progressHandler;\r
99                 try\r
100                 {\r
101                     webClient.UploadDataAsync(address, method, data, tcs);\r
102                     if (cancellationToken.IsCancellationRequested)\r
103                         webClient.CancelAsync();\r
104                 }\r
105                 catch\r
106                 {\r
107                     webClient.UploadDataCompleted -= completedHandler;\r
108                     webClient.UploadProgressChanged -= progressHandler;\r
109                     throw;\r
110                 }\r
111             }\r
112             return tcs.Task;\r
113         }\r
114 \r
115         public static async Task<T> WithRetries<T>(this Func<Task<T>> func, int retries)\r
116         {\r
117             while (retries > 0)\r
118             {\r
119                 try\r
120                 {\r
121                     var result = await func();\r
122                     return result;\r
123                 }\r
124                 catch (Exception exc)\r
125                 {\r
126                     if (--retries == 0)\r
127                         throw new RetryException("Failed too many times", exc);\r
128                 }\r
129             }\r
130             throw new RetryException();\r
131         }\r
132 \r
133     }\r
134 \r
135     internal static class PithosEAPCommon\r
136     {\r
137         internal static void HandleProgress<T, E>(TaskCompletionSource<T> tcs, ProgressChangedEventArgs eventArgs, Func<E> getProgress, IProgress<E> callback)\r
138         {\r
139             if (eventArgs.UserState != tcs)\r
140                 return;\r
141             callback.Report(getProgress());\r
142         }\r
143 \r
144         internal static void HandleCompletion<T>(TaskCompletionSource<T> tcs, bool requireMatch, AsyncCompletedEventArgs e, Func<T> getResult, Action unregisterHandler)\r
145         {\r
146             if (requireMatch)\r
147             {\r
148                 if (e.UserState != tcs)\r
149                     return;\r
150             }\r
151             try\r
152             {\r
153                 unregisterHandler();\r
154             }\r
155             finally\r
156             {\r
157                 if (e.Cancelled)\r
158                     tcs.TrySetCanceled();\r
159                 else if (e.Error != null)\r
160                     tcs.TrySetException(e.Error);\r
161                 else\r
162                     tcs.TrySetResult(getResult());\r
163             }\r
164         }\r
165     }\r
166 \r
167 }\r