Clean up file downloading.
This commit is contained in:
@@ -30,8 +30,7 @@
|
|||||||
- (SidebarEntry *)sidebarModsTree;
|
- (SidebarEntry *)sidebarModsTree;
|
||||||
- (SidebarEntry *)sidebarOtherTree;
|
- (SidebarEntry *)sidebarOtherTree;
|
||||||
|
|
||||||
- (BOOL)downloadUrl:(NSString *)url toFile:(NSString *)filename withId:(NSString *)key;
|
- (BOOL)registerDownload:(NSString *)key withURL:(NSString *)url filePath:(NSString *)path;
|
||||||
- (void)cancelDownload:(NSString *)key;
|
|
||||||
- (Download *)downloadWithKey:(NSString *)key;
|
- (Download *)downloadWithKey:(NSString *)key;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -94,25 +94,16 @@
|
|||||||
[game launchMod:mod];
|
[game launchMod:mod];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)downloadUrl:(NSString *)url toFile:(NSString *)path withId:(NSString *)key
|
- (BOOL)registerDownload:(NSString *)key withURL:(NSString *)url filePath:(NSString *)path;
|
||||||
{
|
{
|
||||||
if ([downloads objectForKey:key] != nil)
|
if ([downloads objectForKey:key] != nil)
|
||||||
{
|
|
||||||
NSLog(@"Download already in progress for %@",key);
|
|
||||||
return NO;
|
return NO;
|
||||||
}
|
|
||||||
|
|
||||||
Download *download = [Download downloadWithURL:url filename:path key:key game:game];
|
[downloads setObject:[Download downloadWithURL:url filename:path key:key game:game]
|
||||||
[downloads setObject:download forKey:key];
|
forKey:key];
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)cancelDownload:(NSString *)key
|
|
||||||
{
|
|
||||||
[[downloads objectForKey:key] cancel];
|
|
||||||
[downloads removeObjectForKey:key];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (Download *)downloadWithKey:(NSString *)key
|
- (Download *)downloadWithKey:(NSString *)key
|
||||||
{
|
{
|
||||||
return [downloads objectForKey:key];
|
return [downloads objectForKey:key];
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
int bytesCompleted;
|
int bytesCompleted;
|
||||||
int bytesTotal;
|
int bytesTotal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property(readonly) NSString *key;
|
@property(readonly) NSString *key;
|
||||||
@property(readonly) NSString *status;
|
@property(readonly) NSString *status;
|
||||||
@property(readonly) int bytesCompleted;
|
@property(readonly) int bytesCompleted;
|
||||||
@@ -27,6 +28,7 @@
|
|||||||
|
|
||||||
+ (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;
|
||||||
- (void)cancel;
|
- (BOOL)start;
|
||||||
|
- (BOOL)cancel;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -32,16 +32,18 @@
|
|||||||
filename = [aFilename retain];
|
filename = [aFilename retain];
|
||||||
key = [aKey retain];
|
key = [aKey retain];
|
||||||
game = [aGame retain];
|
game = [aGame retain];
|
||||||
status = @"Initializing";
|
|
||||||
bytesCompleted = -1;
|
|
||||||
bytesTotal = -1;
|
|
||||||
|
|
||||||
NSLog(@"Starting download...");
|
if ([[NSFileManager defaultManager] fileExistsAtPath:filename])
|
||||||
task = [game runAsyncUtilityWithArg:[NSString stringWithFormat:@"--download-url=%@,%@",url,filename]
|
{
|
||||||
delegate:self
|
status = @"COMPLETE";
|
||||||
responseSelector:@selector(utilityResponded:)
|
bytesCompleted = bytesTotal = [[[NSFileManager defaultManager] attributesOfItemAtPath:filename error:nil] fileSize];
|
||||||
terminatedSelector:@selector(utilityTerminated:)];
|
}
|
||||||
[task retain];
|
else
|
||||||
|
{
|
||||||
|
status = @"AVAILABLE";
|
||||||
|
bytesCompleted = -1;
|
||||||
|
bytesTotal = -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@@ -65,17 +67,13 @@
|
|||||||
|
|
||||||
if ([type isEqualToString:@"Error"])
|
if ([type isEqualToString:@"Error"])
|
||||||
{
|
{
|
||||||
status = @"Error";
|
status = @"ERROR";
|
||||||
}
|
}
|
||||||
else if ([type isEqualToString:@"Status"])
|
else if ([type isEqualToString:@"Status"])
|
||||||
{
|
{
|
||||||
if ([message isEqualToString:@"Initializing"])
|
if ([message isEqualToString:@"Completed"])
|
||||||
{
|
{
|
||||||
status = @"Initializing";
|
status = @"COMPLETE";
|
||||||
}
|
|
||||||
else if ([message isEqualToString:@"Completed"])
|
|
||||||
{
|
|
||||||
status = @"Complete";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse download status info
|
// Parse download status info
|
||||||
@@ -94,15 +92,29 @@
|
|||||||
[[n object] readInBackgroundAndNotify];
|
[[n object] readInBackgroundAndNotify];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)cancel
|
- (BOOL)start
|
||||||
|
{
|
||||||
|
status = @"DOWNLOADING";
|
||||||
|
|
||||||
|
NSLog(@"Starting download...");
|
||||||
|
task = [game runAsyncUtilityWithArg:[NSString stringWithFormat:@"--download-url=%@,%@",url,filename]
|
||||||
|
delegate:self
|
||||||
|
responseSelector:@selector(utilityResponded:)
|
||||||
|
terminatedSelector:@selector(utilityTerminated:)];
|
||||||
|
[task retain];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)cancel
|
||||||
{
|
{
|
||||||
NSLog(@"Cancelling");
|
NSLog(@"Cancelling");
|
||||||
status = @"Cancelled";
|
status = @"ERROR";
|
||||||
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
||||||
[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 terminate];
|
[task terminate];
|
||||||
[task release]; task = nil;
|
[task release]; task = nil;
|
||||||
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)utilityTerminated:(NSNotification *)n
|
- (void)utilityTerminated:(NSNotification *)n
|
||||||
|
|||||||
@@ -45,8 +45,8 @@ static JSBridge *SharedInstance;
|
|||||||
@"existsInMod", NSStringFromSelector(@selector(fileExists:inMod:)),
|
@"existsInMod", NSStringFromSelector(@selector(fileExists:inMod:)),
|
||||||
|
|
||||||
// File downloading
|
// File downloading
|
||||||
@"existsInCache", NSStringFromSelector(@selector(existsInCache:)),
|
@"registerDownload", NSStringFromSelector(@selector(registerDownload:withURL:filename:)),
|
||||||
@"downloadToCache", NSStringFromSelector(@selector(downloadUrl:withName:key:)),
|
@"startDownload", NSStringFromSelector(@selector(startDownload:)),
|
||||||
@"cancelDownload", NSStringFromSelector(@selector(cancelDownload:)),
|
@"cancelDownload", NSStringFromSelector(@selector(cancelDownload:)),
|
||||||
@"downloadStatus", NSStringFromSelector(@selector(downloadStatus:)),
|
@"downloadStatus", NSStringFromSelector(@selector(downloadStatus:)),
|
||||||
@"bytesCompleted", NSStringFromSelector(@selector(bytesCompleted:)),
|
@"bytesCompleted", NSStringFromSelector(@selector(bytesCompleted:)),
|
||||||
@@ -103,36 +103,34 @@ static JSBridge *SharedInstance;
|
|||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)existsInCache:(NSString *)name
|
- (BOOL)registerDownload:(NSString *)key withURL:(NSString *)url filename:(NSString *)filename
|
||||||
{
|
{
|
||||||
// Disallow traversing directories; take only the last component
|
// Disallow traversing directories; take only the last component
|
||||||
id path = [[@"~/Library/Application Support/OpenRA/Downloads/" stringByAppendingPathComponent:[name lastPathComponent]] stringByExpandingTildeInPath];
|
id path = [[@"~/Library/Application Support/OpenRA/Downloads/" stringByAppendingPathComponent:[filename lastPathComponent]] stringByExpandingTildeInPath];
|
||||||
return [[NSFileManager defaultManager] fileExistsAtPath:path];
|
return [controller registerDownload:key withURL:url filePath:path];
|
||||||
}
|
|
||||||
|
|
||||||
- (void)downloadUrl:(NSString *)url withName:(NSString *)name key:(NSString *)key
|
|
||||||
{
|
|
||||||
NSLog(@"downloadFile:%@ intoCacheWithName:%@ key:%@",url,name,key);
|
|
||||||
|
|
||||||
// Disallow traversing directories; take only the last component
|
|
||||||
id path = [[@"~/Library/Application Support/OpenRA/Downloads/" stringByAppendingPathComponent:[name lastPathComponent]] stringByExpandingTildeInPath];
|
|
||||||
[controller downloadUrl:url toFile:path withId:key];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)cancelDownload:(NSString *)key
|
|
||||||
{
|
|
||||||
[controller cancelDownload:key];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)downloadStatus:(NSString *)key
|
- (NSString *)downloadStatus:(NSString *)key
|
||||||
{
|
{
|
||||||
Download *d = [controller downloadWithKey:key];
|
Download *d = [controller downloadWithKey:key];
|
||||||
if (d == nil)
|
if (d == nil)
|
||||||
return @"Invalid";
|
return @"NOT_REGISTERED";
|
||||||
|
|
||||||
return [d status];
|
return [d status];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL)startDownload:(NSString *)key
|
||||||
|
{
|
||||||
|
Download *d = [controller downloadWithKey:key];
|
||||||
|
return (d == nil) ? NO : [d start];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)cancelDownload:(NSString *)key
|
||||||
|
{
|
||||||
|
Download *d = [controller downloadWithKey:key];
|
||||||
|
return (d == nil) ? NO : [d cancel];
|
||||||
|
}
|
||||||
|
|
||||||
- (int)bytesCompleted:(NSString *)key
|
- (int)bytesCompleted:(NSString *)key
|
||||||
{
|
{
|
||||||
Download *d = [controller downloadWithKey:key];
|
Download *d = [controller downloadWithKey:key];
|
||||||
|
|||||||
@@ -102,9 +102,8 @@
|
|||||||
|
|
||||||
function download()
|
function download()
|
||||||
{
|
{
|
||||||
window.external.downloadToCache("http://localhost/~paul/cnc-packages.zip","cnc-packages.zip","cnc-packages");
|
window.external.startDownload("cnc-packages");
|
||||||
document.getElementById("install-download").style.display = "none";
|
refreshDownloadButtons();
|
||||||
document.getElementById("install-downloading").style.display = "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function cancel()
|
function cancel()
|
||||||
@@ -120,8 +119,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onLoad()
|
function onLoad()
|
||||||
|
{
|
||||||
|
refreshSections();
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshSections()
|
||||||
{
|
{
|
||||||
var installed = packagesInstalled();
|
var installed = packagesInstalled();
|
||||||
|
window.external.log("installed: "+installed);
|
||||||
|
|
||||||
document.getElementById("buttons-install").style.display = (installed == 0) ? "" : "none";
|
document.getElementById("buttons-install").style.display = (installed == 0) ? "" : "none";
|
||||||
document.getElementById("buttons-upgrade").style.display = (installed == 1) ? "" : "none";
|
document.getElementById("buttons-upgrade").style.display = (installed == 1) ? "" : "none";
|
||||||
document.getElementById("buttons-play").style.display = (installed == 2) ? "" : "none";
|
document.getElementById("buttons-play").style.display = (installed == 2) ? "" : "none";
|
||||||
@@ -130,10 +136,39 @@
|
|||||||
// Select the correct subsection
|
// Select the correct subsection
|
||||||
if (installed == 0)
|
if (installed == 0)
|
||||||
{
|
{
|
||||||
var downloaded = window.external.existsInCache("cnc-packages.zip");
|
window.external.registerDownload("cnc-packages", "http://localhost/~paul/cnc-packages.zip", "cnc-packages.zip");
|
||||||
window.external.log("downloaded: "+downloaded);
|
refreshDownloadButtons();
|
||||||
document.getElementById("install-extract").style.display = downloaded ? "" : "none";
|
}
|
||||||
document.getElementById("install-download").style.display = !downloaded ? "" : "none";
|
}
|
||||||
|
|
||||||
|
function refreshDownloadButtons()
|
||||||
|
{
|
||||||
|
document.getElementById("download-available").style.display = "none";
|
||||||
|
document.getElementById("download-downloading").style.display = "none";
|
||||||
|
document.getElementById("download-extract").style.display = "none";
|
||||||
|
|
||||||
|
// status can be NOT_REGISTERED, AVAILABLE, DOWNLOADING, COMPLETE, ERROR
|
||||||
|
var status = window.external.downloadStatus("cnc-packages");
|
||||||
|
window.external.log("status: "+status);
|
||||||
|
|
||||||
|
// Download complete, offer button to extract it
|
||||||
|
if (status == "COMPLETE")
|
||||||
|
{
|
||||||
|
document.getElementById("download-extract").style.display = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show the download progress
|
||||||
|
else if (status == "DOWNLOADING")
|
||||||
|
{
|
||||||
|
document.getElementById("download-downloading").style.display = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show the download button
|
||||||
|
else if (status == "AVAILABLE" || status == "ERROR")
|
||||||
|
{
|
||||||
|
document.getElementById("download-available").style.display = "";
|
||||||
|
|
||||||
|
// Todo: set error message
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,29 +177,19 @@
|
|||||||
if (file != "cnc-packages")
|
if (file != "cnc-packages")
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var status = window.external.downloadStatus(file);
|
|
||||||
if (status == "Complete")
|
|
||||||
{
|
|
||||||
document.getElementById("install-extract").style.display = "";
|
|
||||||
document.getElementById("install-downloading").style.display = "none";
|
|
||||||
}
|
|
||||||
var total = window.external.bytesTotal(file);
|
var total = window.external.bytesTotal(file);
|
||||||
var downloaded = window.external.bytesCompleted(file);
|
var downloaded = window.external.bytesCompleted(file);
|
||||||
|
window.external.log(file+" = total: "+total+" downloaded: "+downloaded);
|
||||||
|
|
||||||
var multiplier = 1/1024.0;
|
if (downloaded == -1)
|
||||||
var unit = "kB";
|
return;
|
||||||
|
|
||||||
var max = max(total,downloaded); // total may be -1 if the server doesn't supply a size
|
var multiplier = 1/1048576.0;
|
||||||
if (max > 1.1*1024*1024)
|
|
||||||
{
|
|
||||||
multiplier /= 1024;
|
|
||||||
unit = "MB";
|
|
||||||
}
|
|
||||||
total = (total*multiplier).toPrecision(2);
|
total = (total*multiplier).toPrecision(2);
|
||||||
downloaded = (downloaded*multiplier).toPrecision(2);
|
downloaded = (downloaded*multiplier).toPrecision(2);
|
||||||
|
|
||||||
document.getElementById("download-status").value = downloaded+"/"+total+" "+unit;
|
document.getElementById("download-status").value = downloaded+"/"+total+" MB";
|
||||||
window.external.log("file: "+file+" "+downloaded+"/"+total+" ("+percent+"%)");
|
refreshDownloadButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@@ -186,19 +211,19 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div -->
|
</div -->
|
||||||
<div id="buttons-install" class="buttons">
|
<div id="buttons-install" class="buttons" style="display:none">
|
||||||
<div class="desc">The original game data is required before you can play this mod.<br />
|
<div class="desc">The original game data is required before you can play this mod.<br />
|
||||||
Installing from web will install the minimal files required to play.
|
Installing from web will install the minimal files required to play.
|
||||||
</div>
|
</div>
|
||||||
<div id="install-download">
|
<div id="download-available" style="display:none">
|
||||||
<input type="button" class="button" onclick="download();" value="Download" />
|
<input type="button" class="button" onclick="download();" value="Download" />
|
||||||
</div>
|
</div>
|
||||||
<div id="install-downloading" style="display:none">
|
<div id="download-downloading" style="display:none">
|
||||||
<input type="button" class="button" id="download-status" value="Initializing..." />
|
<input type="button" class="button" id="download-status" value="Initializing..." />
|
||||||
<input type="button" class="button" onclick="cancel();" value="Cancel" />
|
<input type="button" class="button" onclick="cancel();" value="Cancel" />
|
||||||
</div>
|
</div>
|
||||||
<div id="install-extract">
|
<div id="download-extract" style="display:none">
|
||||||
<input type="button" class="button" onclick="install();" value="Install" />
|
<input type="button" class="button" onclick="extract();" value="Install" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="buttons-upgrade" class="buttons" style="display:none">
|
<div id="buttons-upgrade" class="buttons" style="display:none">
|
||||||
|
|||||||
Reference in New Issue
Block a user