Use utility app for http requests; Make them async.

This commit is contained in:
Paul Chote
2010-12-30 13:34:13 +13:00
parent 428999fc0b
commit 39ed6087cb
12 changed files with 100 additions and 49 deletions

View File

@@ -18,6 +18,7 @@
SidebarEntry *sidebarItems;
GameInstall *game;
NSDictionary *allMods;
NSMutableArray *httpRequests;
NSMutableDictionary *downloads;
BOOL hasMono;
@@ -33,6 +34,7 @@
- (SidebarEntry *)sidebarModsTree;
- (SidebarEntry *)sidebarOtherTree;
- (void)fetchURL:(NSString *)url withCallback:(NSString *)cb;
- (BOOL)registerDownload:(NSString *)key withURL:(NSString *)url filePath:(NSString *)path;
- (Download *)downloadWithKey:(NSString *)key;
- (BOOL)hasSupportedMono;

View File

@@ -13,6 +13,7 @@
#import "ImageAndTextCell.h"
#import "JSBridge.h"
#import "Download.h"
#import "HttpRequest.h"
@implementation Controller
@synthesize allMods;
@@ -32,6 +33,7 @@
game = [[GameInstall alloc] initWithPath:gamePath];
[[JSBridge sharedInstance] setController:self];
downloads = [[NSMutableDictionary alloc] init];
httpRequests = [[NSMutableArray alloc] init];
hasMono = [self hasSupportedMono];
if (hasMono)
{
@@ -120,6 +122,7 @@
{
[sidebarItems release]; sidebarItems = nil;
[downloads release]; downloads = nil;
[httpRequests release]; httpRequests = nil;
[super dealloc];
}
@@ -176,6 +179,17 @@
return [downloads objectForKey:key];
}
- (void)fetchURL:(NSString *)url withCallback:(NSString *)cb
{
// Clean up any completed requests
for (int i = [httpRequests count] - 1; i >= 0; i--)
if ([[httpRequests objectAtIndex:i] terminated])
[httpRequests removeObjectAtIndex:i];
// Create request
[httpRequests addObject:[HttpRequest requestWithURL:url callback:cb game:game]];
}
#pragma mark Sidebar Datasource and Delegate
- (NSInteger)outlineView:(NSOutlineView *)anOutlineView numberOfChildrenOfItem:(id)item
{
@@ -245,6 +259,10 @@ objectValueForTableColumn:(NSTableColumn *)tableColumn
#pragma mark WebView delegates
- (void)webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)windowObject forFrame:(WebFrame *)frame
{
// Cancel any in progress http requests
for (HttpRequest *r in httpRequests)
[r cancel];
[windowObject setValue:[JSBridge sharedInstance] forKey:@"external"];
}

View File

@@ -69,7 +69,7 @@
[[NSFileManager defaultManager] removeItemAtPath:filename error:NULL];
bytesCompleted = bytesTotal = -1;
[[JSBridge sharedInstance] notifyDownloadProgress:self];
[[JSBridge sharedInstance] runCallback:@"downloadProgressed" withArgument:[self key]];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:NSFileHandleReadCompletionNotification
object:[[task standardOutput] fileHandleForReading]];
@@ -120,7 +120,7 @@
}
}
}
[[JSBridge sharedInstance] notifyDownloadProgress:self];
[[JSBridge sharedInstance] runCallback:@"downloadProgressed" withArgument:[self key]];
// Keep reading
if ([n object] != nil)
@@ -171,7 +171,7 @@
}
}
}
[[JSBridge sharedInstance] notifyExtractProgress:self];
[[JSBridge sharedInstance] runCallback:@"extractProgressed" withArgument:[self key]];
// Keep reading
if ([n object] != nil)

View File

@@ -19,6 +19,5 @@
+ (JSBridge *)sharedInstance;
- (void)setController:(Controller *)aController;
- (void)notifyDownloadProgress:(Download *)download;
- (void)notifyExtractProgress:(Download *)download;
- (void)runCallback:(NSString *)cb withArgument:(NSString *)arg;
@end

View File

@@ -44,7 +44,7 @@ static JSBridge *SharedInstance;
@"log", NSStringFromSelector(@selector(log:)),
@"existsInMod", NSStringFromSelector(@selector(fileExists:inMod:)),
@"metadata", NSStringFromSelector(@selector(metadata:forMod:)),
@"httpRequest", NSStringFromSelector(@selector(httpRequest:)),
@"httpRequest", NSStringFromSelector(@selector(httpRequest:withCallback:)),
// File downloading
@"registerDownload", NSStringFromSelector(@selector(registerDownload:withURL:filename:)),
@@ -71,6 +71,13 @@ static JSBridge *SharedInstance;
[super dealloc];
}
- (void)runCallback:(NSString *)cb withArgument:(NSString *)arg
{
NSString *cmd = [NSString stringWithFormat:@"%@('%@')", cb,
[arg stringByReplacingOccurrencesOfString:@"\n" withString:@"\\n"]];
[[[controller webView] windowScriptObject] evaluateWebScript:cmd];
}
#pragma mark JS API methods
- (BOOL)launchMod:(NSString *)aMod
@@ -155,18 +162,6 @@ static JSBridge *SharedInstance;
return (d == nil) ? -1 : [d bytesTotal];
}
- (void)notifyDownloadProgress:(Download *)download
{
[[[controller webView] windowScriptObject] evaluateWebScript:
[NSString stringWithFormat:@"downloadProgressed('%@')",[download key]]];
}
- (void)notifyExtractProgress:(Download *)download
{
[[[controller webView] windowScriptObject] evaluateWebScript:
[NSString stringWithFormat:@"extractProgressed('%@')",[download key]]];
}
- (BOOL)extractDownload:(NSString *)key toPath:(NSString *)aFile inMod:(NSString *)aMod
{
Download *d = [controller downloadWithKey:key];
@@ -233,12 +228,9 @@ static JSBridge *SharedInstance;
return @"";
}
- (NSString *)httpRequest:(NSString *)url
- (void)httpRequest:(NSString *)url withCallback:(NSString *)cb
{
NSLog(@"Requesting url %@",url);
NSString *response = [NSString stringWithContentsOfURL:[NSURL URLWithString:url] encoding:NSASCIIStringEncoding error:NULL];
NSLog(@"Response %@",response);
return response;
[controller fetchURL:url withCallback:cb];
}
@end

View File

@@ -20,6 +20,7 @@
DA81FC3F12911E2B00C48F2F /* GameInstall.m in Sources */ = {isa = PBXBuildFile; fileRef = DA81FC3E12911E2B00C48F2F /* GameInstall.m */; };
DA9295A712921DF900EDB02E /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA9295A612921DF900EDB02E /* WebKit.framework */; };
DA9296901292328200EDB02E /* SidebarEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = DA92968F1292328200EDB02E /* SidebarEntry.m */; };
DAA3F31C12CBF60D00E214BF /* HttpRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = DAA3F31B12CBF60D00E214BF /* HttpRequest.m */; };
DAB887F5129E5D6C00C99407 /* SDL in Resources */ = {isa = PBXBuildFile; fileRef = DAB887EE129E5D6100C99407 /* SDL */; };
/* End PBXBuildFile section */
@@ -49,6 +50,8 @@
DA9295A612921DF900EDB02E /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; };
DA92968E1292328200EDB02E /* SidebarEntry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SidebarEntry.h; sourceTree = "<group>"; };
DA92968F1292328200EDB02E /* SidebarEntry.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SidebarEntry.m; sourceTree = "<group>"; };
DAA3F31A12CBF60D00E214BF /* HttpRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HttpRequest.h; sourceTree = "<group>"; };
DAA3F31B12CBF60D00E214BF /* HttpRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HttpRequest.m; sourceTree = "<group>"; };
DAB887EE129E5D6100C99407 /* SDL */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; path = SDL; sourceTree = "<group>"; };
/* End PBXFileReference section */
@@ -80,8 +83,10 @@
DA7D85661295E92900E58547 /* Download.m */,
DA92968E1292328200EDB02E /* SidebarEntry.h */,
DA92968F1292328200EDB02E /* SidebarEntry.m */,
DA38212012925344003B0BB5 /* JSBridge.h */,
DA38212112925344003B0BB5 /* JSBridge.m */,
DA38212012925344003B0BB5 /* JSBridge.h */,
DAA3F31A12CBF60D00E214BF /* HttpRequest.h */,
DAA3F31B12CBF60D00E214BF /* HttpRequest.m */,
);
name = Classes;
sourceTree = "<group>";
@@ -229,6 +234,7 @@
DA9296901292328200EDB02E /* SidebarEntry.m in Sources */,
DA38212212925344003B0BB5 /* JSBridge.m in Sources */,
DA7D85671295E92900E58547 /* Download.m in Sources */,
DAA3F31C12CBF60D00E214BF /* HttpRequest.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@@ -85,16 +85,19 @@ namespace OpenRA.Utility
public static void DownloadUrl(string argValue)
{
string[] args = argValue.Split(',');
if (args.Length != 2)
{
Console.WriteLine("Error: invalid syntax");
return;
}
string url = args[0];
WebClient wc = new WebClient();
if (args.Length == 1)
{
wc.DownloadStringCompleted += DownloadStringCompleted;
wc.DownloadStringAsync(new Uri(url));
}
else if (args.Length == 2)
{
string path = args[1].Replace("~",Environment.GetFolderPath(Environment.SpecialFolder.Personal));
WebClient wc = new WebClient();
wc.DownloadProgressChanged += DownloadProgressChanged;
wc.DownloadFileCompleted += DownloadFileCompleted;
@@ -102,12 +105,28 @@ namespace OpenRA.Utility
Console.WriteLine("Status: Initializing");
wc.DownloadFileAsync(new Uri(url), path);
}
else
{
Console.WriteLine("Error: invalid syntax");
return;
}
while (!completed)
Thread.Sleep(500);
}
static bool completed = false;
static void DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error != null)
Console.WriteLine("Error: {0}", e.Error.Message);
else
Console.WriteLine(e.Result);
completed = true;
}
static void DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
if (e.Error != null)

View File

@@ -81,7 +81,7 @@ namespace OpenRA.Utility
Console.WriteLine();
Console.WriteLine(" -l,--list-mods List currently installed mods");
Console.WriteLine(" -i=MODS,--mod-info=MODS List metadata for MODS (comma separated list of mods)");
Console.WriteLine(" --download-url=URL,DEST Download a file from URL to DEST");
Console.WriteLine(" --download-url=URL,DEST Download a file from URL to DEST (omit DEST to print to stdout)");
Console.WriteLine(" --extract-zip=ZIPFILE,PATH Extract the zip ZIPFILE to DEST (relative to openra dir)");
Console.WriteLine(" --install-ra-packages=PATH Install required packages for RA from CD to PATH");
Console.WriteLine(" --install-cnc-packages=PATH Install required packages for C&C from CD to PATH");

View File

@@ -123,15 +123,23 @@
window.external.extractDownload("cnc-packages","packages","cnc");
}
function versionCallback(version)
{
document.getElementById("latestversion").innerHTML = version;
}
function motdCallback(motd)
{
document.getElementById("motd").innerHTML = motd;
}
function onLoad()
{
refreshSections();
var version = window.external.metadata("VERSION", "cnc");
document.getElementById("installedversion").innerHTML = version;
document.getElementById("latestversion").innerHTML = window.external.httpRequest("http://master.open-ra.org/VERSION");
var motd = window.external.httpRequest("http://master.open-ra.org/motd.php?v="+version);
if (motd != undefined)
document.getElementById("motd").innerHTML = motd.substring(3);
window.external.httpRequest("http://master.open-ra.org/VERSION", "versionCallback");
window.external.httpRequest("http://master.open-ra.org/motd.php?v="+version, "motdCallback");
}
function refreshSections()
@@ -223,7 +231,7 @@
<div id="main">
<div id="content">
<p>Latest version: <span id="latestversion">Unknown</span></p>
<p>Latest version: <span id="latestversion">Checking...</span></p>
<p id="motd"></p>
</div>
<div id="buttons-install" class="buttons" style="display:none">

View File

@@ -123,16 +123,23 @@
window.external.extractDownload("ra-packages","packages","ra");
}
function versionCallback(version)
{
document.getElementById("latestversion").innerHTML = version;
}
function motdCallback(motd)
{
document.getElementById("motd").innerHTML = motd;
}
function onLoad()
{
refreshSections();
var version = window.external.metadata("VERSION", "ra");
var version = window.external.metadata("VERSION", "cnc");
document.getElementById("installedversion").innerHTML = version;
document.getElementById("latestversion").innerHTML = window.external.httpRequest("http://master.open-ra.org/VERSION");
var motd = window.external.httpRequest("http://master.open-ra.org/motd.php?v="+version);
if (motd != undefined)
document.getElementById("motd").innerHTML = motd.substring(3);
window.external.httpRequest("http://master.open-ra.org/VERSION", "versionCallback");
window.external.httpRequest("http://master.open-ra.org/motd.php?v="+version, "motdCallback");
}
function refreshSections()
@@ -224,7 +231,7 @@
<div id="main">
<div id="content">
<p>Latest version: <span id="latestversion">Unknown</span></p>
<p>Latest version: <span id="latestversion">Checking...</span></p>
<p id="motd"></p>
</div>
<div id="buttons-install" class="buttons" style="display:none">