I am using a Downloader class to get large files from a IIS server on WS2012 and handle download progress.
It works fine, however when the client's bandwidth is too saturated, Progress events aren't fired anymore and after a certain amount of time the download just stops (the Complete event seems to be triggered?), despite the download being unfinished, leaving the client with a corrupt file.
I couldn't find out how to solve this, or even what strategy I should take on this problem (finish the download and display an error? Wait for bandwidth availability to get my next piece of bytes?)
Here's the Downloader.as class
public class Downloader extends EventDispatcher
{
[Event(name="DownloadComplete", type="DownloadEvent")]
public static var spd:int = 0;
private var file:File;
private var fileStream:FileStream;
private var url:String;
private var urlStream:URLStream;
var mc_background:MovieClip;
var howManyTimes:Number = 3; //How many times per second the download speed will be traced
var bytesLoaded:Number = 0; //don't change, necessary for calculation
var lastTime:int = 0; //don't change, necessary for calculation
private var waitingForDataToWrite:Boolean = false;
public function Downloader(s:MovieClip)
{
mc_background = s;
lastTime = getTimer();
urlStream = new URLStream();
urlStream.addEventListener(Event.OPEN, onOpenEvent);
urlStream.addEventListener(ProgressEvent.PROGRESS, onProgressEvent);
urlStream.addEventListener(Event.COMPLETE, onCompleteEvent);
fileStream = new FileStream();
fileStream.addEventListener(OutputProgressEvent.OUTPUT_PROGRESS, writeProgressHandler)
}
public function download(formUrl:String, toFile:File):void {
this.url = formUrl;
this.file = toFile;
mc_background.pb.file_txt.text = file.name;
fileStream.openAsync(file, FileMode.WRITE);
urlStream.load(new URLRequest(url));
}
private function onOpenEvent(event:Event):void {
waitingForDataToWrite = true;
dispatchEvent(event.clone());
}
private function onProgressEvent(event:ProgressEvent):void {
var time:int = getTimer();
if(time - lastTime >= (1000/howManyTimes))
{
var kiloBytes:Number = (event.bytesLoaded - bytesLoaded)/1000;
var timeInSecs:Number = (time - lastTime)/1000;
var kbsPerSecVal:Number = Math.floor(kiloBytes/timeInSecs);
trace(kbsPerSecVal + " kbs/s");
mc_background.pb.speed_txt.text = kbsPerSecVal + " kbs/s";
bytesLoaded = event.bytesLoaded;
lastTime = getTimer();
}
if(waitingForDataToWrite){
writeToDisk();
dispatchEvent(event.clone());
}
}
private function writeToDisk():void {
var fileData:ByteArray = new ByteArray();
urlStream.readBytes(fileData, 0, urlStream.bytesAvailable);
fileStream.writeBytes(fileData,0,fileData.length);
waitingForDataToWrite = false;
dispatchEvent(new DataEvent(DataEvent.DATA));
}
private function writeProgressHandler(evt:OutputProgressEvent):void{
waitingForDataToWrite = true;
}
private function onCompleteEvent(event:Event):void {
if(urlStream.bytesAvailable>0)
writeToDisk();
fileStream.close();
fileStream.removeEventListener(OutputProgressEvent.OUTPUT_PROGRESS, writeProgressHandler);
dispatchEvent(event.clone());
// dispatch additional DownloadEvent
dispatchEvent(new DownloadEvent(DownloadEvent.DOWNLOAD_COMPLETE, url, file));
}
}