/** * URL Prioritization Class * Works with Loader, Sound, URLLoader * (need to add netstream) * * Usage: * * Parameter 1: The target loader * Parameter 2: Priority (int) * Parameter 3: Event Handler * Parameter 4...n: The Target arguments * * // creates a request to be queued * new RequestPool(new Loader(), RequestPool.MEDIUM, handler_method, * new URLRequest('http://www.google.com/intl/en_ALL/images/logo.gif') * ); * new RequestPool(new Sound(), RequestPool.HIGH, handler_method, * new URLRequest('http://www.google.com/some_audio.mp3') * ); * * function handler_method(event:Event, pool:RequestPool):void { * trace(event); // io_error, complete, or security_error, * trace(pool.priority, (priority.args[0] as URLRequest).url); // * } */ package com.danielhai.network { import com.danielhai.core.IDisposable; import flash.display.*; import flash.events.*; import flash.media.Sound; import flash.net.*; import flash.utils.Dictionary; import flash.utils.Timer; /** * Prioritizes requests */ final public class RequestPool extends EventDispatcher implements IDisposable { /** * Stores maximum concurrent requests allowed */ private static const MAXIMUM_CONCURRENT_REQUESTS:int = 2; /** * High priority */ public static const HIGH:int = 10; /** * Medium priority */ public static const MEDIUM:int = 5; /** * Low priority */ public static const LOW:int = 0; /** * @private * Currently queued requests */ private static const _queue:Array = []; /** * @private * Currently loading requests */ private static const _loading:Array = []; /** * @private */ private static const EVENT_PRIORITY:int = 99999; /** * @private */ private static const _hash:Dictionary = new Dictionary(true); /** * */ private static const TIMER:Timer = new Timer(0); /** * Returns objects */ public static function get currentRequests():Array { return _queue; } /** * Returns objects */ public static function get loadingRequests():Array { return _loading; } /** * @private */ private static function _queueNext(event:TimerEvent = null):void { TIMER.removeEventListener(TimerEvent.TIMER, _queueNext); if (_queue.length > 0 && _loading.length < MAXIMUM_CONCURRENT_REQUESTS) { var pool:RequestPool = _queue.shift() as RequestPool; _loading.push(pool); pool.load(); } } /** * @private */ private static function _poolComplete(event:Event):void { var target:IEventDispatcher = event.currentTarget as IEventDispatcher; var pool:RequestPool = _hash[target]; // remove listeners pool.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, _poolComplete); pool.removeEventListener(IOErrorEvent.IO_ERROR, _poolComplete); pool.removeEventListener(Event.COMPLETE, _poolComplete); // remove from the loading array var index:int = _loading.indexOf(pool); if (index >= 0) { _loading.splice(index, 1); } // remove from the index array index = _queue.indexOf(pool); if (index >= 0) { _queue.splice(index, 1); } var method:Function = _hash[pool]; if (method !== null) { method(event, pool); } // load the next loader _queueNext(); } /** * @private * Stores the request to load */ private var _targetArgs:Array; /** * @private * Stores the request to load */ private var _target:IEventDispatcher; /** * @private */ private var _startTime:int; /** * @private * Stores the priority */ public var priority:int; /** * @constructor * Registers a loader, urlloader, Sound */ public function RequestPool(target:IEventDispatcher, priority:int, handler:Function, ... args:Array):void { if (!(target is IEventDispatcher) || !(target is LoaderInfo || target is Loader || (target is Sound) || target is URLLoader)) { throw new Error('Target must be of a url loading type.'); } _target = target; _targetArgs = args; // store it in the hash so the handler can GC without being explicitly disposed _hash[this] = handler; this.priority = priority; target = (target is Loader) ? (target as Loader).contentLoaderInfo : target // create a dispatcher // forward events target.addEventListener(Event.COMPLETE, _poolComplete, false, EVENT_PRIORITY); target.addEventListener(IOErrorEvent.IO_ERROR, _poolComplete, false, EVENT_PRIORITY); target.addEventListener(SecurityErrorEvent.SECURITY_ERROR, _poolComplete, false, EVENT_PRIORITY); // link the target and this _hash[target] = this; // add the queue _queue.push(this); _queue.sortOn('priority', Array.DESCENDING | Array.NUMERIC); // load the next queue, but after a little bit (let everything finish listening); TIMER.addEventListener(TimerEvent.TIMER, _queueNext); TIMER.start(); } /** * Returns the target */ public function get target():IEventDispatcher { return _target; } /** * */ public function get args():Array { return _targetArgs; } /** * @private * Loads the pool */ private function load():void { if (_target is NetStream) { fn = (_target as NetStream).play; } else { fn = _target['load']; } var fn:Function; // load fn.apply(_target, _targetArgs); } /** * @private * Dispose */ public function dispose():void { _target = null; _targetArgs = null; } } }