2009-11-11 Chris Toshok <toshok@ximian.com>
[moon.git] / gtk / Moonlight.Gtk / ManagedDownloader.cs
blob455b289e261b7b40509be36e44328e025e48538f
1 //
2 // ManagedDownloader.cs: The managed implementation that uses System.Net
3 // to provide services to the Downloader class.
4 //
5 // Author:
6 // Miguel de Icaza (miguel@novell.com)
7 //
8 // Copyright 2007 Novell, Inc.
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 //
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 using System;
30 using System.Threading;
31 using System.IO;
32 using System.Collections;
33 using System.Runtime.InteropServices;
34 using System.Net;
35 using Mono;
37 namespace Moonlight.Gtk {
39 internal class ManagedDownloader {
40 static int keyid;
41 static Hashtable downloaders = new Hashtable ();
43 // The pointer to the agclr downloader object
44 IntPtr downloader;
46 // Where we track the download
47 delegate void DownloadDelegate ();
49 int count;
50 byte [] buffer;
51 AutoResetEvent auto_reset;
52 DownloadDelegate down;
53 IAsyncResult async_result;
54 volatile bool downloading = true;
57 // Either request is non-null, or fname is non-null.
58 // This is merely an optimization: for fname, instead of going
59 // through FileWebRequest threads and the gtk main loop, we just
60 // emit the ready signal as soon as we can.
62 WebRequest request = null;
63 string fname;
65 Mono.TickCallHandler tick_call;
67 ManagedDownloader (IntPtr native)
69 downloader = native;
72 void Download ()
74 // we can't call event_object_get_surface (or other stuff) if the download has been aborted
75 if (!downloading)
76 return;
78 IntPtr time_manager = NativeMethods.surface_get_time_manager (NativeMethods.event_object_get_surface (downloader));
79 // Special case: local file, just notify that we are done
81 if (fname != null) {
82 if (File.Exists (fname)) {
83 NativeMethods.time_manager_add_tick_call (time_manager, tick_call = delegate (IntPtr data) {
84 if (!downloading)
85 return;
86 tick_call = null;
87 NativeMethods.downloader_notify_finished (downloader, fname);
88 }, IntPtr.Zero);
90 else {
91 NativeMethods.time_manager_add_tick_call (time_manager, tick_call = delegate (IntPtr data) {
92 if (!downloading)
93 return;
94 tick_call = null;
95 NativeMethods.downloader_notify_failed (downloader, String.Format ("File `{0}' not found", fname));
96 }, IntPtr.Zero);
98 return;
102 if (request == null)
103 throw new Exception ("This Downloader has not been configured yet, call Open");
105 string path;
106 int offset;
108 try {
109 using (WebResponse r = request.GetResponse ()){
110 NativeMethods.time_manager_add_tick_call (time_manager, tick_call = delegate (IntPtr data) {
111 if (!downloading)
112 return;
113 NativeMethods.downloader_notify_size (downloader, r.ContentLength);
114 tick_call = null;
115 auto_reset.Set ();
116 }, IntPtr.Zero);
117 auto_reset.WaitOne ();
119 using (Stream rstream = r.GetResponseStream ()){
120 buffer = new byte [32*1024];
121 count = 0;
122 offset = 0;
124 while (downloading){
125 count = rstream.Read (buffer, 0, buffer.Length);
126 if (count == 0){
127 buffer = null;
128 break;
131 NativeMethods.time_manager_add_tick_call (time_manager, tick_call = delegate (IntPtr data) {
132 if (!downloading)
133 return;
134 tick_call = null;
135 unsafe {
136 fixed (byte *buf = &buffer[0]) {
137 NativeMethods.downloader_write (downloader, (IntPtr)buf, offset, count);
140 auto_reset.Set ();
141 }, IntPtr.Zero);
142 auto_reset.WaitOne ();
143 offset += count;
146 // We are done
147 NativeMethods.time_manager_add_tick_call (time_manager, tick_call = delegate (IntPtr data) {
148 if (!downloading)
149 return;
150 tick_call = null;
151 NativeMethods.downloader_notify_finished (downloader, null);
152 }, IntPtr.Zero);
154 } catch (Exception e){
155 Console.Error.WriteLine ("There was an error {0}", e);
156 NativeMethods.downloader_notify_failed (downloader, e.Message);
161 // Initiates the download
163 void Start ()
166 // Need to use a separate thread
168 auto_reset = new AutoResetEvent (false);
169 down = new DownloadDelegate (Download);
170 downloading = true;
171 async_result = down.BeginInvoke (new AsyncCallback (DownloadDone), null);
174 public static void Send (IntPtr state)
176 ManagedDownloader m = (ManagedDownloader) downloaders [state];
177 if (m == null)
178 return;
180 m.Start ();
183 void DownloadDone (IAsyncResult async_result)
185 down.EndInvoke (async_result);
186 this.async_result = null;
189 void Open (string verb, string uri)
191 if (verb != "GET" && verb.ToUpper () != "GET"){
192 Console.WriteLine ("Do not know what to do with verb {0}", verb);
193 return;
196 try {
197 if (uri.StartsWith ("file://"))
198 fname = uri.Substring (7);
199 if (uri.StartsWith ("/"))
200 fname = uri;
201 else {
202 try {
203 request = WebRequest.Create (uri);
204 } catch (UriFormatException){
205 fname = Path.GetFullPath (uri);
208 } catch (Exception e){
209 Console.WriteLine ("An error happened with the given url {0}", e);
210 // Do something with this
212 if (request == null && fname == null){
213 Console.WriteLine ("An error happened with the given url, the result was null");
214 return;
218 public static IntPtr CreateDownloader (IntPtr native)
220 ManagedDownloader m = new ManagedDownloader (native);
221 int key = keyid++;
222 downloaders [(IntPtr) key] = m;
224 return (IntPtr) key;
227 public static void DestroyDownloader (IntPtr state)
229 ManagedDownloader m = (ManagedDownloader) downloaders [state];
230 if (m == null)
231 return;
233 downloaders [state] = null;
235 m.downloading = false;
238 public static void Open (IntPtr state, string verb, string uri, bool custom_header_support, bool disable_cache)
240 ManagedDownloader m = (ManagedDownloader) downloaders [state];
241 if (m == null)
242 return;
244 m.Open (verb, uri);
247 public static void Abort (IntPtr state)
249 ManagedDownloader m = (ManagedDownloader) downloaders [state];
250 if (m == null)
251 return;
253 m.downloading = false;
256 public static void Header (IntPtr state, string header, string value)
258 ManagedDownloader m = (ManagedDownloader) downloaders [state];
259 if (m == null)
260 return;
262 m.request.Headers [header] = value;
265 public static void Body (IntPtr state, IntPtr body, int length)
267 ManagedDownloader m = (ManagedDownloader) downloaders [state];
268 if (m == null)
269 return;
271 Stream stream = m.request.GetRequestStream ();
273 byte[] buffer = new byte[length];
275 Marshal.Copy (body, buffer, 0, length);
276 stream.Write (buffer, 0, length);
279 public static IntPtr CreateWebRequest (string method, string uri, IntPtr context)
281 throw new NotImplementedException ();
284 public static string GetResponseText (string part, IntPtr state)
286 ManagedDownloader m = (ManagedDownloader) downloaders [state];
287 if (m == null)
288 return null;
290 // Ask toshok what he wants here.
291 return null;