Handle download errors

This commit is contained in:
Paul Chote
2010-11-25 12:36:14 +13:00
parent 6f66a19b18
commit 2fe7e10750
4 changed files with 66 additions and 37 deletions

View File

@@ -16,7 +16,8 @@
NSString *filename; NSString *filename;
GameInstall *game; GameInstall *game;
NSTask *task; NSTask *task;
NSString * status; NSString *status;
NSString *error;
int bytesCompleted; int bytesCompleted;
int bytesTotal; int bytesTotal;
} }
@@ -25,6 +26,7 @@
@property(readonly) NSString *status; @property(readonly) NSString *status;
@property(readonly) int bytesCompleted; @property(readonly) int bytesCompleted;
@property(readonly) int bytesTotal; @property(readonly) int bytesTotal;
@property(readonly) NSString *error;
+ (id)downloadWithURL:(NSString *)aURL filename:(NSString *)aFilename key:(NSString *)aKey game:(GameInstall *)aGame; + (id)downloadWithURL:(NSString *)aURL filename:(NSString *)aFilename key:(NSString *)aKey game:(GameInstall *)aGame;
- (id)initWithURL:(NSString *)aURL filename:(NSString *)aFilename key:(NSString *)aKey game:(GameInstall *)game; - (id)initWithURL:(NSString *)aURL filename:(NSString *)aFilename key:(NSString *)aKey game:(GameInstall *)game;

View File

@@ -15,6 +15,7 @@
@synthesize status; @synthesize status;
@synthesize bytesCompleted; @synthesize bytesCompleted;
@synthesize bytesTotal; @synthesize bytesTotal;
@synthesize error;
+ (id)downloadWithURL:(NSString *)aURL filename:(NSString *)aFilename key:(NSString *)aKey game:(GameInstall *)aGame + (id)downloadWithURL:(NSString *)aURL filename:(NSString *)aFilename key:(NSString *)aKey game:(GameInstall *)aGame
{ {
@@ -32,17 +33,17 @@
filename = [aFilename retain]; filename = [aFilename retain];
key = [aKey retain]; key = [aKey retain];
game = [aGame retain]; game = [aGame retain];
error = @"";
if ([[NSFileManager defaultManager] fileExistsAtPath:filename]) if ([[NSFileManager defaultManager] fileExistsAtPath:filename])
{ {
status = @"COMPLETE"; status = @"COMPLETE";
bytesCompleted = bytesTotal = [[[NSFileManager defaultManager] attributesOfItemAtPath:filename error:nil] fileSize]; bytesCompleted = bytesTotal = [[[NSFileManager defaultManager] attributesOfItemAtPath:filename error:NULL] fileSize];
} }
else else
{ {
status = @"AVAILABLE"; status = @"AVAILABLE";
bytesCompleted = -1; bytesCompleted = bytesTotal = -1;
bytesTotal = -1;
} }
} }
return self; return self;
@@ -68,7 +69,13 @@
if ([type isEqualToString:@"Error"]) if ([type isEqualToString:@"Error"])
{ {
status = @"ERROR"; status = @"ERROR";
[error autorelease];
if ([[message substringToIndex:36] isEqualToString:@"The remote server returned an error:"])
error = [[message substringFromIndex:37] retain];
else
error = [message retain];
} }
else if ([type isEqualToString:@"Status"]) else if ([type isEqualToString:@"Status"])
{ {
if ([message isEqualToString:@"Completed"]) if ([message isEqualToString:@"Completed"])
@@ -95,8 +102,6 @@
- (BOOL)start - (BOOL)start
{ {
status = @"DOWNLOADING"; status = @"DOWNLOADING";
NSLog(@"Starting download...");
task = [game runAsyncUtilityWithArg:[NSString stringWithFormat:@"--download-url=%@,%@",url,filename] task = [game runAsyncUtilityWithArg:[NSString stringWithFormat:@"--download-url=%@,%@",url,filename]
delegate:self delegate:self
responseSelector:@selector(utilityResponded:) responseSelector:@selector(utilityResponded:)
@@ -107,13 +112,13 @@
- (BOOL)cancel - (BOOL)cancel
{ {
NSLog(@"Cancelling");
status = @"ERROR"; status = @"ERROR";
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; error = @"Download Cancelled";
[nc removeObserver:self name:NSFileHandleReadCompletionNotification object:[[task standardOutput] fileHandleForReading]]; [[JSBridge sharedInstance] notifyDownloadProgress:self];
[nc removeObserver:self name:NSTaskDidTerminateNotification object:task]; [[NSNotificationCenter defaultCenter] removeObserver:self
name:NSFileHandleReadCompletionNotification
object:[[task standardOutput] fileHandleForReading]];
[task terminate]; [task terminate];
[task release]; task = nil;
return YES; return YES;
} }
@@ -124,6 +129,12 @@
[nc removeObserver:self name:NSFileHandleReadCompletionNotification object:[[task standardOutput] fileHandleForReading]]; [nc removeObserver:self name:NSFileHandleReadCompletionNotification object:[[task standardOutput] fileHandleForReading]];
[nc removeObserver:self name:NSTaskDidTerminateNotification object:task]; [nc removeObserver:self name:NSTaskDidTerminateNotification object:task];
[task release]; task = nil; [task release]; task = nil;
if (status == @"ERROR")
{
[[NSFileManager defaultManager] removeItemAtPath:filename error:NULL];
bytesCompleted = bytesTotal = -1;
}
} }
@end @end

View File

@@ -49,6 +49,7 @@ static JSBridge *SharedInstance;
@"startDownload", NSStringFromSelector(@selector(startDownload:)), @"startDownload", NSStringFromSelector(@selector(startDownload:)),
@"cancelDownload", NSStringFromSelector(@selector(cancelDownload:)), @"cancelDownload", NSStringFromSelector(@selector(cancelDownload:)),
@"downloadStatus", NSStringFromSelector(@selector(downloadStatus:)), @"downloadStatus", NSStringFromSelector(@selector(downloadStatus:)),
@"downloadError", NSStringFromSelector(@selector(downloadError:)),
@"bytesCompleted", NSStringFromSelector(@selector(bytesCompleted:)), @"bytesCompleted", NSStringFromSelector(@selector(bytesCompleted:)),
@"bytesTotal", NSStringFromSelector(@selector(bytesTotal:)), @"bytesTotal", NSStringFromSelector(@selector(bytesTotal:)),
nil] retain]; nil] retain];
@@ -67,12 +68,6 @@ static JSBridge *SharedInstance;
[super dealloc]; [super dealloc];
} }
- (void)notifyDownloadProgress:(Download *)download
{
[[[controller webView] windowScriptObject] evaluateWebScript:
[NSString stringWithFormat:@"downloadProgressed('%@')",[download key]]];
}
#pragma mark JS API methods #pragma mark JS API methods
- (BOOL)launchMod:(NSString *)aMod - (BOOL)launchMod:(NSString *)aMod
@@ -119,6 +114,15 @@ static JSBridge *SharedInstance;
return [d status]; return [d status];
} }
- (NSString *)downloadError:(NSString *)key
{
Download *d = [controller downloadWithKey:key];
if (d == nil)
return @"";
return [d error];
}
- (BOOL)startDownload:(NSString *)key - (BOOL)startDownload:(NSString *)key
{ {
Download *d = [controller downloadWithKey:key]; Download *d = [controller downloadWithKey:key];
@@ -143,6 +147,13 @@ static JSBridge *SharedInstance;
return (d == nil) ? -1 : [d bytesTotal]; return (d == nil) ? -1 : [d bytesTotal];
} }
- (void)notifyDownloadProgress:(Download *)download
{
[[[controller webView] windowScriptObject] evaluateWebScript:
[NSString stringWithFormat:@"downloadProgressed('%@')",[download key]]];
}
- (void)log:(NSString *)message - (void)log:(NSString *)message
{ {
NSLog(@"js: %@",message); NSLog(@"js: %@",message);

View File

@@ -53,7 +53,7 @@
padding:20px; padding:20px;
} }
div.desc .desc
{ {
font-size:0.75em; font-size:0.75em;
} }
@@ -102,15 +102,13 @@
function download() function download()
{ {
document.getElementById("download-status").value = "Initializing..."
window.external.startDownload("cnc-packages"); window.external.startDownload("cnc-packages");
refreshDownloadButtons();
} }
function cancel() function cancel()
{ {
window.external.cancelDownload("cnc-packages"); window.external.cancelDownload("cnc-packages");
// TODO: Remove incomplete file from cache
// TODO: Restore buttons to the before-downloading state
} }
function extract() function extract()
@@ -136,7 +134,10 @@
// Select the correct subsection // Select the correct subsection
if (installed == 0) if (installed == 0)
{ {
window.external.registerDownload("cnc-packages", "http://localhost/~paul/cnc-packages.zip", "cnc-packages.zip"); //var url = "http://localhost/~paul/cnc-packages.zip";
//var url = "http://localhost/~paul/cnc-packages.bogus";
var url = "http://open-ra.org/get-dependency.php?file=cnc-packages";
window.external.registerDownload("cnc-packages", url, "cnc-packages.zip");
refreshDownloadButtons(); refreshDownloadButtons();
} }
} }
@@ -146,6 +147,7 @@
document.getElementById("download-available").style.display = "none"; document.getElementById("download-available").style.display = "none";
document.getElementById("download-downloading").style.display = "none"; document.getElementById("download-downloading").style.display = "none";
document.getElementById("download-extract").style.display = "none"; document.getElementById("download-extract").style.display = "none";
document.getElementById("download-error").style.display = "none";
// status can be NOT_REGISTERED, AVAILABLE, DOWNLOADING, COMPLETE, ERROR // status can be NOT_REGISTERED, AVAILABLE, DOWNLOADING, COMPLETE, ERROR
var status = window.external.downloadStatus("cnc-packages"); var status = window.external.downloadStatus("cnc-packages");
@@ -153,22 +155,21 @@
// Download complete, offer button to extract it // Download complete, offer button to extract it
if (status == "COMPLETE") if (status == "COMPLETE")
{
document.getElementById("download-extract").style.display = ""; document.getElementById("download-extract").style.display = "";
}
// Show the download progress // Show the download progress
else if (status == "DOWNLOADING") else if (status == "DOWNLOADING")
{
document.getElementById("download-downloading").style.display = ""; document.getElementById("download-downloading").style.display = "";
}
// Show the download button // Show the download button
else if (status == "AVAILABLE" || status == "ERROR") else if (status == "AVAILABLE")
{
document.getElementById("download-available").style.display = ""; document.getElementById("download-available").style.display = "";
// Todo: set error message else if (status == "ERROR")
{
var message = window.external.downloadError("cnc-packages");
document.getElementById("error-message").innerHTML = message;
document.getElementById("download-error").style.display = "";
} }
} }
@@ -181,14 +182,14 @@
var downloaded = window.external.bytesCompleted(file); var downloaded = window.external.bytesCompleted(file);
window.external.log(file+" = total: "+total+" downloaded: "+downloaded); window.external.log(file+" = total: "+total+" downloaded: "+downloaded);
if (downloaded == -1) if (downloaded > 0)
return; {
var multiplier = 1/1048576.0;
total = (total*multiplier).toPrecision(2);
downloaded = (downloaded*multiplier).toPrecision(2);
var multiplier = 1/1048576.0; document.getElementById("download-status").value = downloaded+"/"+total+" MB";
total = (total*multiplier).toPrecision(2); }
downloaded = (downloaded*multiplier).toPrecision(2);
document.getElementById("download-status").value = downloaded+"/"+total+" MB";
refreshDownloadButtons(); refreshDownloadButtons();
} }
@@ -225,6 +226,10 @@
<div id="download-extract" style="display:none"> <div id="download-extract" style="display:none">
<input type="button" class="button" onclick="extract();" value="Install" /> <input type="button" class="button" onclick="extract();" value="Install" />
</div> </div>
<div id="download-error" style="display:none">
<input type="button" class="button" onclick="download();" value="Retry" />
<span class="desc" id="error-message"></span>
</div>
</div> </div>
<div id="buttons-upgrade" class="buttons" style="display:none"> <div id="buttons-upgrade" class="buttons" style="display:none">
<div class="desc"> <div class="desc">