root/branches/0_9_1/qcontrol/cocoaDownload.m

Revision 83, 12.7 KB (checked in by cordney, 3 years ago)

[fix] localization: German (downloader)
[fix] downloader: show loading progress of list
[new] downloader: added Guest PCs from kju-app.org for download to the list

Line 
1/*
2 * QEMU Cocoa Control Download Class
3 *
4 * Copyright (c) 2006 René Korthaus
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24 
25#import "cocoaDownload.h"
26
27#define preferences [NSUserDefaults standardUserDefaults]
28
29@implementation cocoaDownload
30
31- (id) initWithHTTP
32{
33    isHTTP = YES;
34    isBT = NO;
35    isQVM = NO;
36   
37    // do initialization here...
38    theDownload = nil;
39    lastReceivedContentLength = [[[NSMutableArray alloc] initWithCapacity:10] retain];
40   
41    return self;
42}
43
44- (id) initWithBT
45{
46    isHTTP = NO;
47    isBT = YES;
48   
49    // do initialization here...
50    fHandle = tr_init();
51   
52    return self;
53}
54
55#pragma mark -
56#pragma mark Get and Set Methods
57
58- (void) setURL:(NSString *)aURL
59{
60    [aURL retain];
61    [url release];
62    url = aURL;
63}
64
65- (void) setName:(NSString *)aName;
66{
67    [aName retain];
68    [name release];
69    name = aName;
70}
71
72- (void) setQVM:(BOOL)val
73{
74    isQVM = val;
75}
76
77- (float) getExpectedData
78{
79    return expectedContentLength;
80}
81
82- (float) getReceivedData
83{
84    return receivedContentLength;
85}
86
87- (int) getLastReceivedData
88{
89    if(isHTTP) {
90        int i;
91        int v_all=0;
92        for(i=0; i<[lastReceivedContentLength count]; i++) {
93            v_all += [[lastReceivedContentLength objectAtIndex:i] intValue];
94        }
95        [lastReceivedContentLength removeAllObjects];
96        return v_all;
97    } else if(isBT) {
98        // return downloadRate*1024 because we get the value from transmission in kB already
99        return downloadRate*1024;
100    }
101   
102    return 0;
103}
104
105- (NSString *) getName
106{
107    return name;
108}
109
110- (NSString *) getSavePath
111{
112    NSLog(@"saveP: %@", savePath);
113    return savePath;
114}
115
116#pragma mark -
117#pragma mark Managing Downloads
118
119- (void) startDownload
120{
121    if(isHTTP) {
122        [self startHTTPDownload];
123    } else if(isBT) {
124        [self startBTDownload];
125    }
126}
127
128// custom HTTP&BT startDownload methods
129- (void) startHTTPDownload
130{
131    // timeout does not work here, instead we fire a 1min timer and check if receivedContentLength > 0
132    NSURLRequest * theRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:url]]; //cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30.0];
133    theDownload = [[NSURLDownload alloc] initWithRequest:theRequest delegate:self];
134    if (theDownload) timer = [[NSTimer scheduledTimerWithTimeInterval:60.0 target:self selector:@selector(checkDownloadStarted) userInfo:nil repeats:NO] retain];
135}
136
137- (void) startBTDownload
138{
139    NSString * torrentPath;
140    // download the torrent file
141    if(isQVM)
142        torrentPath = [[preferences objectForKey:@"dataPath"] stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.torrent", name]];
143    else
144        torrentPath = [[self createQVM] stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.torrent", name]];
145
146    // we need to temporarily save the qvm path here, cause we need it later
147    savePath = torrentPath;
148    [savePath retain];
149   
150    NSData * torrentFile = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
151    if([torrentFile length] == 0) {
152        [[NSNotificationCenter defaultCenter] postNotificationName:@"DownloadDidFail" object:self userInfo:[NSDictionary dictionaryWithObject:NSLocalizedStringFromTable(@"startBTDownload:torrentFile:length", @"Localizable", @"cocoaDownload") forKey:@"ERROR_DESCRIPTION"]];
153        return;
154    }
155    [torrentFile writeToFile:torrentPath atomically:YES];
156    tStat = nil;
157    tInfo = nil;
158    // get the download data every 10ms &
159    // start the torrent download
160    tHandle = tr_torrentInit( fHandle, [torrentPath UTF8String], 0, &tError );
161    if(tHandle != NULL) {
162        tr_torrentSetFolder( tHandle, [[torrentPath stringByDeletingLastPathComponent] UTF8String] );
163        tr_torrentStart( tHandle );
164        fTimer = [NSTimer scheduledTimerWithTimeInterval: 0.1 target: self selector: @selector( BTDownloadDidReceiveData: ) userInfo: nil repeats: YES];
165        // prepare the torrent stats
166        tStat = tr_torrentStat( tHandle );
167        tInfo = tr_torrentInfo ( tHandle );
168        tr_torrentRemoveSaved( tHandle );
169        // set the save path
170        [savePath release];
171        savePath = [[torrentPath stringByDeletingLastPathComponent] stringByAppendingPathComponent:[NSString stringWithUTF8String:tInfo[0].name]];
172        [savePath retain];
173       
174        // tell the controller that the download started
175        [[NSNotificationCenter defaultCenter] postNotificationName:@"DownloadDidReceiveResponse" object:self];
176        // start timer for checking download started
177        timer = [[NSTimer scheduledTimerWithTimeInterval:60.0 target:self selector:@selector(checkDownloadStarted) userInfo:nil repeats:NO] retain];
178    } else {
179        //NSLog(@"Initiating Torrent %@ Failed!", torrentPath);
180        NSString * errorDescription;
181        switch (tError) {
182            case 1:
183                errorDescription = NSLocalizedStringFromTable(@"startBTDownload:torrentFile:tError:invalid", @"Localizable", @"cocoaDownload");
184                break;
185            case 2:
186                errorDescription = NSLocalizedStringFromTable(@"startBTDownload:torrentFile:tError:unsupported", @"Localizable", @"cocoaDownload");
187                break;
188            case 3:
189                errorDescription = NSLocalizedStringFromTable(@"startBTDownload:torrentFile:tError:exists", @"Localizable", @"cocoaDownload");
190                break;
191            case 666:
192                errorDescription = NSLocalizedStringFromTable(@"startBTDownload:torrentFile:tError:miscellanious", @"Localizable", @"cocoaDownload");
193                break;
194            default:
195                errorDescription = NSLocalizedStringFromTable(@"startBTDownload:torrentFile:tError:miscellanious", @"Localizable", @"cocoaDownload");
196        }
197        [[NSNotificationCenter defaultCenter] postNotificationName:@"DownloadDidFail" object:self userInfo:[NSDictionary dictionaryWithObject:errorDescription forKey:@"ERROR_DESCRIPTION"]];
198    }
199}
200
201- (void) checkDownloadStarted
202{
203#if kju_debug
204    NSLog(@"check: receivedBytes %f", receivedContentLength);
205#endif
206    if(receivedContentLength > 0.0) {
207        // download started
208    } else {
209#if kju_debug
210        NSLog(@"download cancelled.");
211#endif
212        // download did not start for 60 seconds, cancel and inform the user
213        NSString * errorDescription = NSLocalizedStringFromTable(@"checkDownloadStarted:errorDescription", @"Localizable", @"cocoaDownload");
214        [[NSNotificationCenter defaultCenter] postNotificationName:@"DownloadDidFail" object:self userInfo:[NSDictionary dictionaryWithObject:errorDescription forKey:@"ERROR_DESCRIPTION"]];
215        [self stopDownload];
216    }
217    // called only once, so invalidate timer
218    [timer invalidate];
219}
220
221- (void) stopDownload
222{
223    if(isHTTP) {
224        //[theDownload cancel];
225        //[theDownload release];
226    } else if(isBT) {
227        tr_torrentStop( tHandle );
228        tr_torrentClose( fHandle, tHandle );
229        tr_close( fHandle );
230        fHandle = nil;
231        tHandle = nil;
232        [fTimer invalidate];
233    }
234}
235
236#pragma mark -
237#pragma mark HTTP Download Methods and Delegates
238
239- (void)downloadDidBegin:(NSURLDownload *)download
240{
241    // do we need to implement it here?
242    //NSLog(@"Download did begin.");
243}
244
245- (void)download:(NSURLDownload *)download didReceiveResponse:(NSURLResponse *)response
246{
247    expectedContentLength = [response expectedContentLength];
248       
249    if (expectedContentLength > 0) {
250        // the download got a response, hence the download starts
251        // we can inform the DownloadController about it
252        // NSLog(@"Download did receive Response.");
253        [[NSNotificationCenter defaultCenter] postNotificationName:@"DownloadDidReceiveResponse" object:self];
254    }
255}
256
257- (void)download:(NSURLDownload *)download decideDestinationWithSuggestedFilename:(NSString *)filename
258{
259    NSString * destinationFilename;
260    if(isQVM)
261        destinationFilename = [[preferences objectForKey:@"dataPath"] stringByAppendingPathComponent:filename];
262    else
263        destinationFilename=[[self createQVM] stringByAppendingPathComponent:filename];
264
265    savePath = destinationFilename;
266    [savePath retain];
267    [download setDestination:destinationFilename allowOverwrite:YES];
268}
269
270- (void)download:(NSURLDownload *)download didReceiveDataOfLength:(unsigned)length
271{
272    if (expectedContentLength > 0.0) {
273        receivedContentLength += length;
274        [lastReceivedContentLength addObject:[NSNumber numberWithInt:length]];
275        [[NSNotificationCenter defaultCenter] postNotificationName:@"DownloadDidReceiveData" object:self];
276    }
277}
278
279- (void)downloadDidFinish:(NSURLDownload *)download
280{
281    [download release];
282    // we should inform the controller about this
283    [[NSNotificationCenter defaultCenter] postNotificationName:@"DownloadDidFinish" object:self];
284    //NSLog(@"Download did finish.");
285}
286
287- (void)download:(NSURLDownload *)download didFailWithError:(NSError *)error
288{
289        // we should inform the controller about this
290        [download release];
291        NSString *errorDescription = [error localizedDescription];
292    if (!errorDescription) {
293        errorDescription = @"Please check your internet connection.";
294    }
295    [[NSNotificationCenter defaultCenter] postNotificationName:@"DownloadDidFail" object:self userInfo:[NSDictionary dictionaryWithObject:errorDescription forKey:@"ERROR_DESCRIPTION"]];
296    //NSLog(@"Download did fail with error: %@", errorDescription);
297}
298
299#pragma mark -
300#pragma mark BT Download Methods and Delegates
301
302- (void) BTDownloadDidReceiveData:(NSTimer *)theTimer
303{
304    //Update download values
305    tStat = tr_torrentStat( tHandle );
306    tInfo = tr_torrentInfo( tHandle );
307   
308    //NSLog(@"rcvCL: %f", receivedContentLength);
309    receivedContentLength = tInfo[0].totalSize * tStat[0].progress;
310    expectedContentLength = tInfo[0].totalSize;
311    downloadRate = tStat[0].rateDownload;
312       
313    [[NSNotificationCenter defaultCenter] postNotificationName:@"DownloadDidReceiveData" object:self];
314   
315    // check if torrent has recently ended.
316
317    if (tStat[0].status & (TR_STATUS_CHECK | TR_STATUS_DOWNLOAD)) {
318        // do nothing
319    } else if (tStat[0].status & TR_STATUS_SEED) {
320        // do nothing
321        //NSLog(@"Seeding download.");
322        if( tr_getFinished( tHandle ) == 1 ) {
323            [[NSNotificationCenter defaultCenter] postNotificationName:@"DownloadDidFinish" object:self];
324        }
325    }
326       
327    // DEBUG output
328    //NSLog(@"peers: %d | dlRate: %d", fStat[0].peersTotal, fStat[0].rateDownload);
329}
330
331#pragma mark -
332#pragma mark Additional Functions
333
334- (NSString *) createQVM
335{
336    NSFileManager *fileManager = [NSFileManager defaultManager];
337    NSString *homeDirectory=[preferences objectForKey:@"dataPath"];
338    NSString * path;
339    // we need to check if qvm already exists
340    int i=1;
341    if([fileManager fileExistsAtPath:[homeDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.qvm", name]]]) {
342        while([fileManager fileExistsAtPath:[homeDirectory stringByAppendingPathComponent:[name stringByAppendingString:[NSString stringWithFormat:@"-%d.qvm", i]]]]) {
343            i++;
344        }
345        [fileManager createDirectoryAtPath:[homeDirectory stringByAppendingPathComponent:[name stringByAppendingString:[NSString stringWithFormat:@"-%d.qvm", i]]] attributes:nil];
346        path = [homeDirectory stringByAppendingPathComponent:[name stringByAppendingString:[NSString stringWithFormat:@"-%d.qvm", i]]];
347    } else {
348        [fileManager createDirectoryAtPath:[homeDirectory stringByAppendingPathComponent:[name stringByAppendingString:@".qvm"]] attributes:nil];
349        path = [homeDirectory stringByAppendingPathComponent:[name stringByAppendingString:@".qvm"]];
350    }
351    return path;
352}
353
354#pragma mark -
355#pragma mark Cleanup
356
357- (void) dealloc
358{
359    [super dealloc];
360    [lastReceivedContentLength removeAllObjects];
361    [lastReceivedContentLength release];
362    [url release];
363    [name release];
364    [savePath release];
365}
366
367@end
Note: See TracBrowser for help on using the browser.