Add URLLoader for HTML5, other platforms TBD

This commit is contained in:
Joshua Granick
2014-06-18 13:45:17 -07:00
parent 6ee3e66ecf
commit 226e5e787a
9 changed files with 490 additions and 1 deletions

View File

View File

303
lime/net/URLLoader.hx Normal file
View File

@@ -0,0 +1,303 @@
package lime.net;
import lime.app.Event;
import lime.utils.ByteArray;
#if js
import js.html.EventTarget;
import js.html.XMLHttpRequest;
import js.Browser;
import js.Lib;
#end
class URLLoader {
public var bytesLoaded:Int;
public var bytesTotal:Int;
public var data:Dynamic;
public var dataFormat (default, set):URLLoaderDataFormat;
public var onComplete = new Event<URLLoader->Void> ();
public var onHTTPStatus = new Event<URLLoader->Int->Void> ();
public var onIOError = new Event<URLLoader->String->Void> ();
public var onOpen = new Event<URLLoader->Void> ();
public var onProgress = new Event<URLLoader->Int->Int->Void> ();
public var onSecurityError = new Event<URLLoader->String->Void> ();
public function new (request:URLRequest = null) {
bytesLoaded = 0;
bytesTotal = 0;
dataFormat = URLLoaderDataFormat.TEXT;
if (request != null) {
load (request);
}
}
public function close ():Void {
}
private dynamic function getData ():Dynamic {
return null;
}
public function load (request:URLRequest):Void {
#if js
requestUrl (request.url, request.method, request.data, request.formatRequestHeaders ());
#end
}
#if js
private function registerEvents (subject:EventTarget):Void {
var self = this;
if (untyped __js__("typeof XMLHttpRequestProgressEvent") != __js__('"undefined"')) {
subject.addEventListener ("progress", __onProgress, false);
}
untyped subject.onreadystatechange = function () {
if (subject.readyState != 4) return;
var s = try subject.status catch (e:Dynamic) null;
if (s == untyped __js__("undefined")) {
s = null;
}
if (s != null) {
self.onHTTPStatus.dispatch (this, s);
}
//js.Lib.alert (s);
if (s != null && s >= 200 && s < 400) {
self.__onData (subject.response);
} else {
if (s == null) {
self.onIOError.dispatch (this, "Failed to connect or resolve host");
} else if (s == 12029) {
self.onIOError.dispatch (this, "Failed to connect to host");
} else if (s == 12007) {
self.onIOError.dispatch (this, "Unknown host");
} else if (s == 0) {
self.onIOError.dispatch (this, "Unable to make request (may be blocked due to cross-domain permissions)");
self.onSecurityError.dispatch (this, "Unable to make request (may be blocked due to cross-domain permissions)");
} else {
self.onIOError.dispatch (this, "Http Error #" + subject.status);
}
}
};
}
private function requestUrl (url:String, method:String, data:Dynamic, requestHeaders:Array<URLRequestHeader>):Void {
var xmlHttpRequest:XMLHttpRequest = untyped __new__("XMLHttpRequest");
registerEvents (cast xmlHttpRequest);
var uri:Dynamic = "";
if (Std.is (data, ByteArray)) {
var data:ByteArray = cast data;
switch (dataFormat) {
//case BINARY: uri = data.__getBuffer ();
default: uri = data.readUTFBytes (data.length);
}
} else if (Std.is (data, URLVariables)) {
var data:URLVariables = cast data;
for (p in Reflect.fields (data)) {
if (uri.length != 0) uri += "&";
uri += StringTools.urlEncode (p) + "=" + StringTools.urlEncode (Reflect.field (data, p));
}
} else {
if (data != null) {
uri = data.toString ();
}
}
try {
if (method == "GET" && uri != null && uri != "") {
var question = url.split ("?").length <= 1;
xmlHttpRequest.open (method, url + (if (question) "?" else "&") + uri, true);
uri = "";
} else {
//js.Lib.alert ("open: " + method + ", " + url + ", true");
xmlHttpRequest.open (method, url, true);
}
} catch (e:Dynamic) {
onIOError.dispatch (this, e.toString ());
return;
}
//js.Lib.alert ("dataFormat: " + dataFormat);
switch (dataFormat) {
case BINARY: untyped xmlHttpRequest.responseType = 'arraybuffer';
default:
}
for (header in requestHeaders) {
//js.Lib.alert ("setRequestHeader: " + header.name + ", " + header.value);
xmlHttpRequest.setRequestHeader (header.name, header.value);
}
//js.Lib.alert ("uri: " + uri);
xmlHttpRequest.send (uri);
onOpen.dispatch (this);
getData = function () {
if (xmlHttpRequest.response != null) {
return xmlHttpRequest.response;
} else {
return xmlHttpRequest.responseText;
}
};
}
#end
// Event Handlers
private function __onData (_):Void {
#if js
var content:Dynamic = getData ();
switch (dataFormat) {
//case BINARY: this.data = ByteArray.__ofBuffer (content);
default: this.data = Std.string (content);
}
#end
onComplete.dispatch (this);
}
private function __onProgress (event:XMLHttpRequestProgressEvent):Void {
bytesLoaded = event.loaded;
bytesTotal = event.total;
onProgress.dispatch (this, bytesLoaded, bytesTotal);
}
// Get & Set Methods
private function set_dataFormat (inputVal:URLLoaderDataFormat):URLLoaderDataFormat {
#if js
// prevent inadvertently using typed arrays when they are unsupported
// @todo move these sorts of tests somewhere common in the vein of Modernizr
if (inputVal == URLLoaderDataFormat.BINARY && !Reflect.hasField (Browser.window, "ArrayBuffer")) {
dataFormat = URLLoaderDataFormat.TEXT;
} else {
dataFormat = inputVal;
}
return dataFormat;
#else
return inputVal;
#end
}
}
typedef XMLHttpRequestProgressEvent = Dynamic;

View File

@@ -0,0 +1,15 @@
package lime.net; #if !flash
enum URLLoaderDataFormat {
BINARY;
TEXT;
VARIABLES;
}
#else
typedef URLLoaderDataFormat = flash.net.URLLoaderDataFormat;
#end

57
lime/net/URLRequest.hx Normal file
View File

@@ -0,0 +1,57 @@
package lime.net; #if !flash
import lime.utils.ByteArray;
class URLRequest {
public var contentType:String;
public var data:Dynamic;
public var method:String;
public var requestHeaders:Array<URLRequestHeader>;
public var url:String;
public var userAgent:String;
public function new (inURL:String = null) {
if (inURL != null) {
url = inURL;
}
requestHeaders = [];
method = URLRequestMethod.GET;
contentType = null; // "application/x-www-form-urlencoded";
}
public function formatRequestHeaders ():Array<URLRequestHeader> {
var res = requestHeaders;
if (res == null) res = [];
if (method == URLRequestMethod.GET || data == null) return res;
if (Std.is (data, String) || Std.is (data, ByteArray)) {
res = res.copy ();
res.push (new URLRequestHeader ("Content-Type", contentType != null ? contentType : "application/x-www-form-urlencoded"));
}
return res;
}
}
#else
typedef URLRequest = flash.net.URLRequest;
#end

View File

@@ -0,0 +1,24 @@
package lime.net; #if !flash
class URLRequestHeader {
public var name : String;
public var value : String;
public function new (name:String = "", value:String = "") {
this.name = name;
this.value = value;
}
}
#else
typedef URLRequestHeader = flash.net.URLRequestHeader;
#end

View File

@@ -0,0 +1,18 @@
package lime.net; #if !flash
class URLRequestMethod {
public static var DELETE:String = "DELETE";
public static var GET:String = "GET";
public static var HEAD:String = "HEAD";
public static var OPTIONS:String = "OPTIONS";
public static var POST:String = "POST";
public static var PUT:String = "PUT";
}
#else
typedef URLRequestMethod = flash.net.URLRequestMethod;
#end

70
lime/net/URLVariables.hx Normal file
View File

@@ -0,0 +1,70 @@
package lime.net; #if !flash
class URLVariables implements Dynamic {
public function new (inEncoded:String = null) {
if (inEncoded != null) {
decode (inEncoded);
}
}
public function decode (inVars:String):Void {
var fields = Reflect.fields (this);
for (f in fields) {
Reflect.deleteField (this, f);
}
var fields = inVars.split (";").join ("&").split ("&");
for (f in fields) {
var eq = f.indexOf ("=");
if (eq > 0) {
Reflect.setField (this, StringTools.urlDecode (f.substr(0, eq)), StringTools.urlDecode (f.substr(eq + 1)));
} else if (eq != 0) {
Reflect.setField (this, StringTools.urlDecode (f), "");
}
}
}
public function toString ():String {
var result = new Array<String> ();
var fields = Reflect.fields (this);
for (f in fields) {
result.push (StringTools.urlEncode (f) + "=" + StringTools.urlEncode (Reflect.field (this, f)));
}
return result.join ("&");
}
}
#else
typedef URLVariables = flash.net.URLVariables;
#end

View File

@@ -38,8 +38,10 @@ class ApplicationMain {
}
#if (js && munit)
#if js
#if munit
embed (null, ::WIN_WIDTH::, ::WIN_HEIGHT::, "::WIN_FLASHBACKGROUND::");
#end
#else
create ();
#end