Permalink
Find file
Fetching contributors…
Cannot retrieve contributors at this time
260 lines (232 sloc) 10.1 KB
package sk.yoz.net
{
import flash.events.AsyncErrorEvent;
import flash.events.EventDispatcher;
import flash.events.IOErrorEvent;
import flash.events.NetStatusEvent;
import flash.events.SecurityErrorEvent;
import flash.events.TimerEvent;
import flash.net.NetConnection;
import flash.net.NetStream;
import sk.yoz.DataTimer;
import sk.yoz.Log;
import sk.yoz.events.P2PMulticastStreamEvent;
public class P2PMulticastStream extends EventDispatcher
{
private var publishName:String = "com";
private var maxPeerConnections:uint = 100;
private var handshakeURL:String = "rtmfp://stratus.adobe.com"; // eg: rtmfp://stratus.adobe.com
private var developerKey:String = "";
private var clientConnectionTimeout:uint = 15000;
private var stratus:NetConnection;
private var publish:NetStream;
private var clients:Object = {};
public var debug:Boolean = false;
private var log:Log = Log.instance;
public function P2PMulticastStream(developerKey:String = "", publishName:String = "",
maxPeerConnections:uint = 0, handshakeURL:String = "", clientConnectionTimeout:uint = 0)
{
super();
if(publishName)
this.publishName = publishName;
if(maxPeerConnections)
this.maxPeerConnections = maxPeerConnections;
if(handshakeURL)
this.handshakeURL = handshakeURL;
if(developerKey)
this.developerKey = developerKey;
if(clientConnectionTimeout)
this.clientConnectionTimeout = clientConnectionTimeout;
stratus = new NetConnection();
stratus.maxPeerConnections = this.maxPeerConnections;
stratus.addEventListener(NetStatusEvent.NET_STATUS, stratusStatusHandler);
stratus.addEventListener(AsyncErrorEvent.ASYNC_ERROR, stratusAsyncErrorHandler);
stratus.addEventListener(IOErrorEvent.IO_ERROR, stratusIOErrorHandler);
stratus.addEventListener(SecurityErrorEvent.SECURITY_ERROR, stratusSecurityErrorHandler);
stratus.connect(this.handshakeURL + "/" + this.developerKey + "/");
}
public function get connected():Boolean
{
return nearID ? true : false;
}
public function get onlineClients():Array
{
var list:Array = [];
for(var farID:String in clients)
if(client(farID).connected)
list.push(farID);
return list;
}
public function get allConnected():Boolean
{
for(var farID:String in clients)
if(!client(farID).connected)
return false;
return true;
}
private function initPublish():void
{
if(debug)
log.write("P2PMulticastStream.initPublish()");
publish = new NetStream(stratus, NetStream.DIRECT_CONNECTIONS);
publish.addEventListener(NetStatusEvent.NET_STATUS, publishStatusHandler);
publish.addEventListener(AsyncErrorEvent.ASYNC_ERROR, publishAsyncErrorHandler);
publish.addEventListener(IOErrorEvent.IO_ERROR, publishIOErrorHandler);
publish.publish(publishName);
publish.client = {
onPeerConnect: function(caller:NetStream):Boolean
{
connectClient(caller.farID);
return true;
}
};
}
public function get nearID():String
{
return stratus && stratus.connected ? stratus.nearID : '';
}
private function client(farID:String):StratusStream
{
return clients.hasOwnProperty(farID) ? clients[farID] : null;
}
public function connectClient(farID:String):void
{
if(farID == nearID || clients.hasOwnProperty(farID))
return;
if(debug)
log.write("P2PMulticastStream.connectClient(" + farID + ")");
var c:StratusStream = new StratusStream(stratus, farID);
c.addEventListener(NetStatusEvent.NET_STATUS, clientStatusHandler);
c.play(publishName);
c.client = {
onData: function(data:Object):void
{
if(debug)
log.write("P2PMulticastStream.client(" + farID + ").onData(" + data.toString() + ")");
dispatchEvent(new P2PMulticastStreamEvent(P2PMulticastStreamEvent.PEER_DATA, false, false, {farID:farID, data:data}));
}
};
clients[farID] = c;
var timer:DataTimer = new DataTimer(clientConnectionTimeout, 1, {farID:farID});
timer.addEventListener(TimerEvent.TIMER_COMPLETE, clientConnectionTimeoutHandler);
timer.start();
}
private function clientConnectionTimeoutHandler(event:TimerEvent):void
{
var timer:DataTimer = event.target as DataTimer;
var farID:String = timer.data.farID;
if(client(farID) && !client(farID).connected)
disconnectClient(farID);
timer.removeEventListener(TimerEvent.TIMER_COMPLETE, clientConnectionTimeoutHandler);
timer = null;
}
private function disconnectClient(farID:String):void
{
if(farID == nearID || !client(farID))
return;
clients[farID] = null;
delete clients[farID];
if(debug)
log.write("P2PMulticastStream.disconnectClient(" + farID + ")");
dispatchEvent(new P2PMulticastStreamEvent(P2PMulticastStreamEvent.PEER_DISCONNECTED, true, true, {farID:farID}));
}
public function broadcast(data:Object):Boolean
{
if(!connected)
return false;
try
{
publish.send("onData", data);
}
catch(error:Error)
{
if(debug)
log.write("P2PMulticastStream.sendData(" + data.toString() + ") // ERROR: " + error.message);
return false;
}
return true;
}
private function clientStatusHandler(event:NetStatusEvent):void
{
var farID:String = event.target.farID;
if(debug)
log.write("P2PMulticastStream.clientStatusHandler(" + event.info.code + ")");
switch(event.info.code)
{
case "NetStream.Play.Start":
if(debug)
log.write("P2PMulticastStream.clientStatusHandler(" + event.info.code + ") " +
"// client(" + farID + ") connected");
client(farID).connected = true;
dispatchEvent(new P2PMulticastStreamEvent(P2PMulticastStreamEvent.PEER_CONNECTED, true, true, {farID:farID}));
break;
}
}
private function stratusStatusHandler(event:NetStatusEvent):void
{
if(debug)
log.write("P2PMulticastStream.stratusStatusHandler(" + event.info.code + ")");
switch(event.info.code)
{
case "NetConnection.Connect.Success":
if(debug)
log.write("P2PMulticastStream.stratusStatusHandler(" + event.info.code + ") " +
"// p2p connection ready (" + nearID + ")");
initPublish();
dispatchEvent(new P2PMulticastStreamEvent(P2PMulticastStreamEvent.CLIENT_ID_ASSIGNED, true, true, {nearID:nearID}));
break;
case "NetStream.Connect.Closed":
if(debug)
log.write("P2PMulticastStream.stratusStatusHandler(" + event.info.code + ") " +
"// p2p disconnected (" + event.info.stream.farID + ")");
disconnectClient(event.info.stream.farID);
break;
}
}
private function stratusAsyncErrorHandler(event:AsyncErrorEvent):void
{
if(debug)
log.write("P2PMulticastStream.stratusAsyncErrorHandler(" + event.text + ")");
}
private function stratusIOErrorHandler(event:IOErrorEvent):void
{
if(debug)
log.write("P2PMulticastStream.stratusIOErrorHandler(" + event.text + ")");
}
private function stratusSecurityErrorHandler(event:SecurityErrorEvent):void
{
if(debug)
log.write("P2PMulticastStream.stratusSecurityErrorHandler(" + event.text + ")");
}
private function publishStatusHandler(event:NetStatusEvent):void
{
if(debug)
log.write("P2PMulticastStream.publishStatusHandler(" + event.info.code + ")");
switch(event.info.code)
{
case "NetStream.Publish.Start":
if(debug)
log.write("P2PMulticastStream.publishStatusHandler(" + event.info.code + ") " +
"// publishing started (" + nearID + ")");
break;
}
}
private function publishAsyncErrorHandler(event:AsyncErrorEvent):void
{
if(debug)
log.write("P2PMulticastStream.publishAsyncErrorHandler(" + event.text + ")");
}
private function publishIOErrorHandler(event:IOErrorEvent):void
{
if(debug)
log.write("P2PMulticastStream.publishIOErrorHandler(" + event.text + ")");
}
public function getClientList():Array
{
var list:Array = [];
for(var farID:String in clients)
list.push(farID);
return list;
}
}
}