Notify javascript when download status changes. Allow js to query information about a download.
This commit is contained in:
@@ -12,6 +12,7 @@
|
|||||||
@class SidebarEntry;
|
@class SidebarEntry;
|
||||||
@class GameInstall;
|
@class GameInstall;
|
||||||
@class JSBridge;
|
@class JSBridge;
|
||||||
|
@class Download;
|
||||||
@interface Controller : NSObject
|
@interface Controller : NSObject
|
||||||
{
|
{
|
||||||
SidebarEntry *sidebarItems;
|
SidebarEntry *sidebarItems;
|
||||||
@@ -31,5 +32,6 @@
|
|||||||
|
|
||||||
- (BOOL)downloadUrl:(NSString *)url toFile:(NSString *)filename withId:(NSString *)key;
|
- (BOOL)downloadUrl:(NSString *)url toFile:(NSString *)filename withId:(NSString *)key;
|
||||||
- (void)cancelDownload:(NSString *)key;
|
- (void)cancelDownload:(NSString *)key;
|
||||||
|
- (Download *)downloadWithKey:(NSString *)key;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
@implementation Controller
|
@implementation Controller
|
||||||
@synthesize allMods;
|
@synthesize allMods;
|
||||||
@synthesize webView;
|
@synthesize webView;
|
||||||
|
|
||||||
- (void)awakeFromNib
|
- (void)awakeFromNib
|
||||||
{
|
{
|
||||||
game = [[GameInstall alloc] initWithURL:[NSURL URLWithString:@"/Users/paul/src/OpenRA"]];
|
game = [[GameInstall alloc] initWithURL:[NSURL URLWithString:@"/Users/paul/src/OpenRA"]];
|
||||||
@@ -101,7 +102,6 @@
|
|||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Download *download = [Download downloadWithURL:url filename:path key:key game:game];
|
Download *download = [Download downloadWithURL:url filename:path key:key game:game];
|
||||||
[downloads setObject:download forKey:key];
|
[downloads setObject:download forKey:key];
|
||||||
return YES;
|
return YES;
|
||||||
@@ -113,6 +113,11 @@
|
|||||||
[downloads removeObjectForKey:key];
|
[downloads removeObjectForKey:key];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (Download *)downloadWithKey:(NSString *)key
|
||||||
|
{
|
||||||
|
return [downloads objectForKey:key];
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark Sidebar Datasource and Delegate
|
#pragma mark Sidebar Datasource and Delegate
|
||||||
- (int)outlineView:(NSOutlineView *)anOutlineView numberOfChildrenOfItem:(id)item
|
- (int)outlineView:(NSOutlineView *)anOutlineView numberOfChildrenOfItem:(id)item
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,6 +7,15 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import <Cocoa/Cocoa.h>
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
Initializing,
|
||||||
|
Downloading,
|
||||||
|
Complete,
|
||||||
|
Cancelled,
|
||||||
|
Error
|
||||||
|
} DownloadStatus;
|
||||||
|
|
||||||
@class GameInstall;
|
@class GameInstall;
|
||||||
@interface Download : NSObject
|
@interface Download : NSObject
|
||||||
{
|
{
|
||||||
@@ -15,7 +24,15 @@
|
|||||||
NSString *filename;
|
NSString *filename;
|
||||||
GameInstall *game;
|
GameInstall *game;
|
||||||
NSTask *task;
|
NSTask *task;
|
||||||
|
DownloadStatus status;
|
||||||
|
int bytesCompleted;
|
||||||
|
int bytesTotal;
|
||||||
}
|
}
|
||||||
|
@property(readonly) NSString *key;
|
||||||
|
@property(readonly) DownloadStatus status;
|
||||||
|
@property(readonly) int bytesCompleted;
|
||||||
|
@property(readonly) int bytesTotal;
|
||||||
|
|
||||||
+ (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;
|
- (void)cancel;
|
||||||
|
|||||||
@@ -11,6 +11,10 @@
|
|||||||
#import "JSBridge.h"
|
#import "JSBridge.h"
|
||||||
|
|
||||||
@implementation Download
|
@implementation Download
|
||||||
|
@synthesize key;
|
||||||
|
@synthesize status;
|
||||||
|
@synthesize bytesCompleted;
|
||||||
|
@synthesize bytesTotal;
|
||||||
|
|
||||||
+ (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
|
||||||
{
|
{
|
||||||
@@ -28,6 +32,9 @@
|
|||||||
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...");
|
NSLog(@"Starting download...");
|
||||||
task = [game runAsyncUtilityWithArg:[NSString stringWithFormat:@"--download-url=%@,%@",url,filename]
|
task = [game runAsyncUtilityWithArg:[NSString stringWithFormat:@"--download-url=%@,%@",url,filename]
|
||||||
@@ -39,22 +46,47 @@
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)cancel
|
|
||||||
{
|
|
||||||
// Stop the download task. utilityTerminated: will handle the cleanup
|
|
||||||
NSLog(@"Cancelling");
|
|
||||||
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
|
||||||
[nc removeObserver:self name:NSFileHandleReadCompletionNotification object:[[task standardOutput] fileHandleForReading]];
|
|
||||||
[nc removeObserver:self name:NSTaskDidTerminateNotification object:task];
|
|
||||||
[task terminate];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)utilityResponded:(NSNotification *)n
|
- (void)utilityResponded:(NSNotification *)n
|
||||||
{
|
{
|
||||||
NSData *data = [[n userInfo] valueForKey:NSFileHandleNotificationDataItem];
|
NSData *data = [[n userInfo] valueForKey:NSFileHandleNotificationDataItem];
|
||||||
NSString *response = [[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding] autorelease];
|
NSString *response = [[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding] autorelease];
|
||||||
NSLog(@"r: %@",response);
|
|
||||||
|
|
||||||
|
// Response can contain multiple lines, or no lines. Split into lines, and parse each in turn
|
||||||
|
NSArray *lines = [response componentsSeparatedByString:@"\n"];
|
||||||
|
for (NSString *line in lines)
|
||||||
|
{
|
||||||
|
NSRange separator = [line rangeOfString:@":"];
|
||||||
|
if (separator.location == NSNotFound)
|
||||||
|
continue; // We only care about messages of the form key: value
|
||||||
|
|
||||||
|
NSString *type = [line substringToIndex:separator.location];
|
||||||
|
NSString *message = [[line substringFromIndex:separator.location+1]
|
||||||
|
stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
||||||
|
|
||||||
|
if ([type isEqualToString:@"Error"])
|
||||||
|
{
|
||||||
|
status = Error;
|
||||||
|
}
|
||||||
|
else if ([type isEqualToString:@"Status"])
|
||||||
|
{
|
||||||
|
if ([message isEqualToString:@"Initializing"])
|
||||||
|
{
|
||||||
|
status = Initializing;
|
||||||
|
}
|
||||||
|
else if ([message isEqualToString:@"Completed"])
|
||||||
|
{
|
||||||
|
status = Complete;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse download status info
|
||||||
|
int done,total;
|
||||||
|
if (sscanf([message UTF8String], "%*d%% %d/%d bytes", &done, &total) == 2)
|
||||||
|
{
|
||||||
|
bytesCompleted = done;
|
||||||
|
bytesTotal = total;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
[[JSBridge sharedInstance] notifyDownloadProgress:self];
|
[[JSBridge sharedInstance] notifyDownloadProgress:self];
|
||||||
|
|
||||||
// Keep reading
|
// Keep reading
|
||||||
@@ -62,6 +94,17 @@
|
|||||||
[[n object] readInBackgroundAndNotify];
|
[[n object] readInBackgroundAndNotify];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)cancel
|
||||||
|
{
|
||||||
|
NSLog(@"Cancelling");
|
||||||
|
status = Cancelled;
|
||||||
|
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
||||||
|
[nc removeObserver:self name:NSFileHandleReadCompletionNotification object:[[task standardOutput] fileHandleForReading]];
|
||||||
|
[nc removeObserver:self name:NSTaskDidTerminateNotification object:task];
|
||||||
|
[task terminate];
|
||||||
|
[task release]; task = nil;
|
||||||
|
}
|
||||||
|
|
||||||
- (void)utilityTerminated:(NSNotification *)n
|
- (void)utilityTerminated:(NSNotification *)n
|
||||||
{
|
{
|
||||||
NSLog(@"utility terminated");
|
NSLog(@"utility terminated");
|
||||||
|
|||||||
@@ -42,10 +42,15 @@ static JSBridge *SharedInstance;
|
|||||||
methods = [[NSDictionary dictionaryWithObjectsAndKeys:
|
methods = [[NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
@"launchMod", NSStringFromSelector(@selector(launchMod:)),
|
@"launchMod", NSStringFromSelector(@selector(launchMod:)),
|
||||||
@"log", NSStringFromSelector(@selector(log:)),
|
@"log", NSStringFromSelector(@selector(log:)),
|
||||||
@"fileExistsInMod", NSStringFromSelector(@selector(fileExists:inMod:)),
|
@"existsInMod", NSStringFromSelector(@selector(exists:inMod:)),
|
||||||
@"fileExistsInCache", NSStringFromSelector(@selector(fileExistsInCache:)),
|
|
||||||
@"downloadFileToCache", NSStringFromSelector(@selector(downloadFileIntoCache:withName:key:)),
|
// File downloading
|
||||||
|
@"existsInCache", NSStringFromSelector(@selector(existsInCache:)),
|
||||||
|
@"downloadToCache", NSStringFromSelector(@selector(downloadUrl:withName:key:)),
|
||||||
@"cancelDownload", NSStringFromSelector(@selector(cancelDownload:)),
|
@"cancelDownload", NSStringFromSelector(@selector(cancelDownload:)),
|
||||||
|
@"isDownloading", NSStringFromSelector(@selector(isDownloading:)),
|
||||||
|
@"bytesCompleted", NSStringFromSelector(@selector(bytesCompleted:)),
|
||||||
|
@"bytesTotal", NSStringFromSelector(@selector(bytesTotal:)),
|
||||||
nil] retain];
|
nil] retain];
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
@@ -64,9 +69,8 @@ static JSBridge *SharedInstance;
|
|||||||
|
|
||||||
- (void)notifyDownloadProgress:(Download *)download
|
- (void)notifyDownloadProgress:(Download *)download
|
||||||
{
|
{
|
||||||
NSLog(@"notified");
|
[[[controller webView] windowScriptObject] evaluateWebScript:
|
||||||
//[[[controller webView] windowScriptObject] evaluateWebScript:
|
[NSString stringWithFormat:@"downloadProgressed('%@')",[download key]]];
|
||||||
// @"updateDownloadStatus(’sample_graphic.jpg’, ‘320’, ‘240’)"];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark JS API methods
|
#pragma mark JS API methods
|
||||||
@@ -99,14 +103,14 @@ static JSBridge *SharedInstance;
|
|||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)fileExistsInCache:(NSString *)name
|
- (BOOL)existsInCache:(NSString *)name
|
||||||
{
|
{
|
||||||
// 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:[name lastPathComponent]] stringByExpandingTildeInPath];
|
||||||
return [[NSFileManager defaultManager] fileExistsAtPath:path];
|
return [[NSFileManager defaultManager] fileExistsAtPath:path];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)downloadFileIntoCache:(NSString *)url withName:(NSString *)name key:(NSString *)key
|
- (void)downloadUrl:(NSString *)url withName:(NSString *)name key:(NSString *)key
|
||||||
{
|
{
|
||||||
NSLog(@"downloadFile:%@ intoCacheWithName:%@ key:%@",url,name,key);
|
NSLog(@"downloadFile:%@ intoCacheWithName:%@ key:%@",url,name,key);
|
||||||
|
|
||||||
@@ -120,6 +124,23 @@ static JSBridge *SharedInstance;
|
|||||||
[controller cancelDownload:key];
|
[controller cancelDownload:key];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL)isDownloading:(NSString *)key
|
||||||
|
{
|
||||||
|
return [controller downloadWithKey:key] != nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (int)bytesCompleted:(NSString *)key
|
||||||
|
{
|
||||||
|
Download *d = [controller downloadWithKey:key];
|
||||||
|
return (d == nil) ? -1 : [d bytesCompleted];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (int)bytesTotal:(NSString *)key
|
||||||
|
{
|
||||||
|
Download *d = [controller downloadWithKey:key];
|
||||||
|
return (d == nil) ? -1 : [d bytesTotal];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)log:(NSString *)message
|
- (void)log:(NSString *)message
|
||||||
{
|
{
|
||||||
NSLog(@"js: %@",message);
|
NSLog(@"js: %@",message);
|
||||||
|
|||||||
@@ -90,10 +90,10 @@
|
|||||||
// Returns 2 if basic files plus music are installed
|
// Returns 2 if basic files plus music are installed
|
||||||
function packagesInstalled()
|
function packagesInstalled()
|
||||||
{
|
{
|
||||||
if (window.external.fileExistsInMod('packages/conquer.mix','cnc') != 1)
|
if (window.external.existsInMod('packages/conquer.mix','cnc') != 1)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return (window.external.fileExistsInMod('packages/scores.mix','cnc') == 1) ? 2 : 1;
|
return (window.external.existsInMod('packages/scores.mix','cnc') == 1) ? 2 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
function play()
|
function play()
|
||||||
@@ -101,18 +101,14 @@
|
|||||||
window.external.launchMod("cnc");
|
window.external.launchMod("cnc");
|
||||||
}
|
}
|
||||||
|
|
||||||
function installFromCD()
|
|
||||||
{
|
|
||||||
window.external.log("installFromCD()");
|
|
||||||
}
|
|
||||||
|
|
||||||
function download1()
|
function download1()
|
||||||
{
|
{
|
||||||
window.external.downloadFileToCache("http://www.open-ra.org/get-dependency.php?file=cnc-packages","test.zip","cnc-packages");
|
window.external.downloadToCache("http://localhost/~paul/cnc-packages.zip","test.zip","cnc-packages");
|
||||||
}
|
}
|
||||||
|
|
||||||
function download2()
|
function download2()
|
||||||
{
|
{
|
||||||
window.external.downloadFileToCache("http://www.open-ra.org/get-dependency.php?file=ra-packages","test2.zip","ra-packages");
|
window.external.downloadToCache("http://localhost/~paul/ra-packages.zip","test2.zip","ra-packages");
|
||||||
}
|
}
|
||||||
|
|
||||||
function cancel1()
|
function cancel1()
|
||||||
@@ -131,6 +127,15 @@
|
|||||||
document.getElementById("buttons-upgrade").style.display = (packagesInstalled() == 1) ? "" : "none";
|
document.getElementById("buttons-upgrade").style.display = (packagesInstalled() == 1) ? "" : "none";
|
||||||
document.getElementById("buttons-play").style.display = (packagesInstalled() == 2) ? "" : "none";
|
document.getElementById("buttons-play").style.display = (packagesInstalled() == 2) ? "" : "none";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function downloadProgressed(file)
|
||||||
|
{
|
||||||
|
var total = window.external.bytesTotal(file);
|
||||||
|
var downloaded = window.external.bytesCompleted(file);
|
||||||
|
var percent = (100*downloaded/total).toPrecision(3);
|
||||||
|
window.external.log("file: "+file+" "+downloaded+"/"+total+" ("+percent+"%)");
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body onload="onLoad();">
|
<body onload="onLoad();">
|
||||||
|
|||||||
Reference in New Issue
Block a user