package de.dtele.net.protocol {
import co.uk.mikestead.net.URLFileVariable;
import co.uk.mikestead.net.URLRequestBuilder;
import com.adobe.serialization.json.JSON;
import com.adobe.serialization.json.JSONParseError;
import com.hurlant.util.Base64;
import de.dtele.data.MimeTypes;
import de.dtele.messages.MessageManager;
import de.dtele.net.MediaRequest;
import de.dtele.net.MediaRequestError;
import de.dtele.net.MediaResponse;
import de.dtele.net.events.ProtocolHandlerErrorEvent;
import de.dtele.net.events.ProtocolHandlerEvent;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.events.SecurityErrorEvent;
import flash.net.FileReference;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.net.URLRequestMethod;
import flash.net.URLVariables;
/**
* Dispatched when the connection to a source has been established
*
* @eventType de.dtele.net.events.ProtocolHandlerEvent.CONNECTED
*/
[Event("connected", type="de.dtele.net.events.ProtocolHandlerEvent")]
/**
* Dispatched when the connection to a source has been closed
*
* @eventType de.dtele.net.events.ProtocolHandlerEvent.DISCONNECTED
*/
[Event("disconnected", type="de.dtele.net.events.ProtocolHandlerEvent")]
/**
* Dispatched when a message from the source was received
*
* @eventType de.dtele.net.events.ProtocolHandlerEvent.RESPONSE
*/
[Event("response", type="de.dtele.net.events.ProtocolHandlerEvent")]
/**
* Dispatched when an error has occurred
*
* @eventType de.dtele.net.events.ProtocolHandlerErrorEvent.ERROR
*/
[Event("error", type="de.dtele.net.events.ProtocolHandlerErrorEvent")]
/**
* Implements the HTTP protocol for MediaRequest
*
* @see http://blog.mikestead.me/upload-multiple-files-with-a-single-request-in-flash/
* @see co.uk.mikestead.net.URLRequestBuilder
*
* @author Mathias Brodala
*/
public class HTTPProtocolHandler extends EventDispatcher implements IProtocolHandler {
/**
* The URL request object for a given URL
*/
private var sourceURL:String;
/**
* List of managed requests
*/
private var loaders:Vector.<URLLoader> = new Vector.<URLLoader>();
/**
* Connects this handler to a source
*
* @param url The url of a source
*/
public function connect(url:String):void {
this.sourceURL = url;
this.dispatchEvent(new ProtocolHandlerEvent(ProtocolHandlerEvent.CONNECTED));
}
/**
* Disconnects this handler from a source
*/
public function disconnect():void {
this.loaders.forEach(function(loader:URLLoader):void {
loader.close();
});
loaders.length = 0;
this.dispatchEvent(new ProtocolHandlerEvent(ProtocolHandlerEvent.DISCONNECTED));
}
/**
* Performs a request to a source
* @see http://blog.mikestead.me/upload-multiple-files-with-a-single-request-in-flash/
*
* XXX: Workaround due to restrictions wrt uploading file data
* @see http://www.adobe.com/devnet/flashplayer/articles/fplayer10_uia_requirements.html
* @see http://jessewarden.com/2008/10/flash-player-10-surprise-error-2176.html
*
* @param request The request to submit
*/
public function send(request:MediaRequest):void {
var handler:HTTPProtocolHandler = this;
var loader:URLLoader = new URLLoader();
var data:URLVariables = new URLVariables();
var fileOperations:Array = [];
data["mediaRequest[version]"] = request.version;
data["mediaRequest[type]"] = request.type;
if (request.credentials) {
data["mediaRequest[credentials]"] = JSON.encode(request.credentials);
}
switch (request.type) {
case MediaRequest.ADD:
case MediaRequest.REMOVE:
if (request.resources) {
data["mediaRequest[resources]"] = JSON.encode(request.resources);
}
case MediaRequest.ADD:
if (request.files) {
request.files.forEach(function(file:FileReference, ...a):void {
fileOperations.push(file);
});
}
break;
}
loader.addEventListener(Event.COMPLETE, function(e:Event):void {
var loader:URLLoader = e.target as URLLoader;
loaders.splice(loaders.indexOf(loader), 1);
var response:MediaResponse;
try {
trace("[HTTPProtocolHandler] Got response with data: " + loader.data);
response = new MediaResponse(JSON.decode(loader.data));
} catch (e:JSONParseError) {
handler.dispatchEvent(new ProtocolHandlerErrorEvent(
ProtocolHandlerErrorEvent.ERROR,
new MediaRequestError(MediaRequestError.MALFORMED_RESPONSE),
request
));
return;
}
handler.dispatchEvent(new ProtocolHandlerEvent(ProtocolHandlerEvent.RESPONSE, request, response));
});
loader.addEventListener(ProgressEvent.PROGRESS, function(e:ProgressEvent):void {
request.bytesLoaded = e.bytesLoaded;
request.bytesTotal = e.bytesTotal;
});
loader.addEventListener(IOErrorEvent.IO_ERROR, function(e:IOErrorEvent):void {
loaders.splice(loaders.indexOf(e.target as URLLoader), 1);
handler.dispatchEvent(new ProtocolHandlerErrorEvent(
ProtocolHandlerErrorEvent.ERROR,
new MediaRequestError(MediaRequestError.CONNECTION_FAILED, e.text),
request
));
});
loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function(e:SecurityErrorEvent):void {
loaders.splice(loaders.indexOf(e.target as URLLoader), 1);
handler.dispatchEvent(new ProtocolHandlerErrorEvent(
ProtocolHandlerErrorEvent.ERROR,
new MediaRequestError(MediaRequestError.CONNECTION_FAILED, e.text),
request
));
});
request.addEventListener(Event.CANCEL, function(e:Event):void {
fileOperations.forEach(function(file:FileReference, ...a):void {
file.cancel();
});
try { loader.close(); } catch (e:Error) {}
});
if (fileOperations.length > 0) {
data["mediaRequest[files]"] = [];
fileOperations.forEach(function(file:FileReference, ...a):void {
file.addEventListener(Event.COMPLETE, function(e:Event):void {
var file:FileReference = e.target as FileReference;
fileOperations.splice(fileOperations.indexOf(file), 1);
var type:String = file.type;
var dotPosition:int = type.indexOf(".");
if (dotPosition > -1) {
type = MimeTypes.getMimeType(type.substr(dotPosition + 1));
}
data["mediaRequest[files]"].push({
name: file.name,
type: type,
size: file.size,
data: Base64.encodeByteArray(file.data)
});
if (fileOperations.length == 0) {
data["mediaRequest[files]"] = JSON.encode(data["mediaRequest[files]"]);
var urlRequest:URLRequest = new URLRequest(handler.sourceURL);
urlRequest.method = URLRequestMethod.POST;
urlRequest.data = data;
trace("[HTTPProtocolHandler] Sending request with data: " + urlRequest.data);
loader.load(urlRequest);
loaders.push(loader);
}
});
file.addEventListener(ProgressEvent.PROGRESS, function(e:ProgressEvent):void {
request.bytesLoaded = e.bytesLoaded;
request.bytesTotal = e.bytesTotal;
});
file.addEventListener(IOErrorEvent.IO_ERROR, function(e:Event):void {
var file:FileReference = e.target as FileReference;
fileOperations.splice(fileOperations.indexOf(file), 1);
MessageManager.instance.addWarning(
"Lesevorgang fehlgeschlagen",
"Das Lesen der Datei " + file.name + " ist fehlgeschlagen."
);
});
file.load();
});
} else {
var urlRequest:URLRequest = new URLRequest(handler.sourceURL);
urlRequest.method = URLRequestMethod.POST;
urlRequest.data = data;
trace("[HTTPProtocolHandler] Sending request with data: " + urlRequest.data);
loader.load(urlRequest);
loaders.push(loader);
}
}
}
}