2010-11-21 23:48:11 +01:00
< ? php
2011-12-03 12:28:02 +01:00
namespace JPT\SocketFramework\Client ;
2010-11-21 23:48:11 +01:00
/**
* This class contains the connection handler .
* It handles all the incoming and outgoing data by forwarding it
* to the clients for the specific connection .
2011-12-03 12:28:02 +01:00
*
2010-11-21 23:48:11 +01:00
* @ author jpt
* @ package Client
* @ depends Connection
*/
2011-12-03 12:28:02 +01:00
class ClientManager {
2010-11-21 23:48:11 +01:00
/**
2011-12-03 12:28:02 +01:00
* @ var \JPT\SocketFramework\Connection\ConnectionPool
2010-11-21 23:48:11 +01:00
*/
protected $connectionPool ;
/**
* An array that contains all client instances for each connection .
2011-12-03 12:28:02 +01:00
*
2010-11-21 23:48:11 +01:00
* @ var array
*/
2011-12-03 12:28:02 +01:00
protected $clientDispatcherPool ;
2010-11-21 23:48:11 +01:00
/**
2011-12-03 12:28:02 +01:00
* An array that contains all client dispatchers we have for certain " protocols " .
* How it works : Each independent client dispatcher is assigned a - hopefully unique -
* identifier for the protocol it implements .
* e . g . [ " MyAwesomeIrcClientStuff " ] -> $classNameOfMyClientDispatcher
* This way , we can register any client dispatcher from even seperate projects ,
* so we can use them within this framework .
*
* Ah , maybe this is important to understand it :
* The protocol identifier pointing to the class name of the client dispatcher
* is used to bind the client dispatcher to a connection created .
*
2010-11-21 23:48:11 +01:00
* @ var array
*/
2011-12-03 12:28:02 +01:00
protected $registeredClientDispatchers ;
2010-11-21 23:48:11 +01:00
/**
* Contains Connection - attached configurations .
2011-12-03 12:28:02 +01:00
*
2010-11-21 23:48:11 +01:00
* @ var array
*/
protected $configPool ;
/**
* Default constructor .
2011-12-03 12:28:02 +01:00
*
2010-11-21 23:48:11 +01:00
* @ return void
*/
2010-12-18 15:42:56 +01:00
public function __construct () {
2011-12-03 12:28:02 +01:00
$this -> connectionPool = new \JPT\SocketFramework\Connection\ConnectionPool ();
$this -> clientDispatcherPool = array ();
2010-11-21 23:48:11 +01:00
$this -> registeredProtocols = array ();
$this -> configPool = array ();
}
/**
* Default destructor . Closes connections before being killed .
2011-12-03 12:28:02 +01:00
*
2010-11-21 23:48:11 +01:00
* @ return void
*/
2010-12-18 15:42:56 +01:00
public function __destruct () {
2011-12-03 12:28:02 +01:00
unset ( $this -> clientDispatcherPool );
2010-11-21 23:48:11 +01:00
unset ( $this -> connectionPool );
}
/**
* @ see Connection_ConnectionPool
* @ return int
*/
2010-12-08 17:47:04 +01:00
public function countSockets () {
return $this -> connectionPool -> countSockets ();
2010-11-21 23:48:11 +01:00
}
2010-12-08 17:54:08 +01:00
/**
* Returns the amount of connected connection handlers .
2011-12-03 12:28:02 +01:00
*
* @ see \JPT\SocketFramework\Connection\ConnectionPool
2010-12-08 17:54:08 +01:00
* @ return int
*/
public function countActiveConnections () {
return $this -> connectionPool -> countActiveConnections ();
}
2010-11-21 23:48:11 +01:00
/**
2011-06-29 21:16:08 +02:00
* Main worker procedure .
2010-11-21 23:48:11 +01:00
* Processes incoming data , calls clients and much more .
2011-12-03 12:28:02 +01:00
*
2010-11-21 23:48:11 +01:00
* @ return void
*/
public function work () {
2011-06-29 20:25:43 +02:00
//first, create clients for connections that do NOT have one already.
2011-06-26 00:13:53 +02:00
foreach ( $this -> connectionPool -> getConnectionHandlers () AS $connectionHandler ) {
2011-12-03 12:28:02 +01:00
if ( isset ( $this -> clientDispatcherPool [ $connectionHandler -> getID ()])) continue ;
2011-06-26 01:04:19 +02:00
//new connections might need a client, so we'll create one here.
2011-12-03 20:58:08 +01:00
$this -> addClientDispatcherForConnectionHandler ( $connectionHandler );
2011-06-26 01:04:19 +02:00
//allow client to send initial stuff right after connecting to the server.
$this -> initializeClientForConnectionHandler ( $connectionHandler );
2011-06-26 00:13:53 +02:00
}
//then, process all connections that have stuff to read.
2010-11-21 23:48:11 +01:00
$connectionHandlers = $this -> connectionPool -> select ();
2011-06-29 20:25:43 +02:00
//nothing to do? return right now. :)
2010-11-21 23:48:11 +01:00
if ( isset ( $connectionHandlers [ " read " ]) === FALSE || count ( $connectionHandlers [ " read " ]) === 0 ) return ;
foreach ( $connectionHandlers [ " read " ] AS $connectionHandler ) {
//handle disconnects
if ( $connectionHandler -> isConnected () === FALSE && $connectionHandler -> isListening () === FALSE ) {
2011-06-29 20:25:43 +02:00
//do we need to reconnect? do it.
if ( $connectionHandler -> getReconnect () === TRUE ) $this -> handleReconnectForConnectionHandler ( $connectionHandler );
//this old connectionHandler won't do much anymore - kill it.
2011-06-26 01:04:19 +02:00
$this -> removeClientForConnectionHandler ( $connectionHandler );
2011-06-29 20:25:43 +02:00
//since the old connectionHandler does not exist anymore, continue.
2010-11-28 17:38:03 +01:00
continue ;
2010-11-21 23:48:11 +01:00
}
2010-11-27 20:59:11 +01:00
//handle accepted sockets, adopt them and treat them with care :-)
2010-11-21 23:48:11 +01:00
if ( $connectionHandler -> isListening () === TRUE ) {
2011-12-03 20:58:08 +01:00
$this -> addClientDispatcherForConnectionHandler ( $connectionHandler );
2011-06-26 01:04:19 +02:00
$this -> initializeClientForConnectionHandler ( $connectionHandler );
2010-11-21 23:48:11 +01:00
}
2011-06-26 00:13:53 +02:00
2011-06-29 20:25:43 +02:00
//prepare and get input
$incomingData = " " ;
$outgoingData = " " ;
while ( $data = $connectionHandler -> read ()) $incomingData .= $data ;
unset ( $data );
2010-11-27 20:59:11 +01:00
//call the registered client
2011-12-04 14:31:18 +01:00
if ( isset ( $this -> clientDispatcherPool [ $connectionHandler -> getID ()])) {
//other output data has priority.
$outgoingData .= $this -> clientDispatcherPool [ $connectionHandler -> getID ()] -> getOutputData ();
//returned data from the processing will be sent.
$outgoingData .= $this -> clientDispatcherPool [ $connectionHandler -> getID ()] -> processRawData ( $incomingData );
}
2011-06-29 20:25:43 +02:00
2011-06-29 21:16:08 +02:00
//i don't know what to do here... maybe call a connection bridge?
2011-06-29 20:25:43 +02:00
//output will be sent.
2011-07-16 16:13:29 +02:00
if ( $outgoingData !== " " ) $connectionHandler -> write ( $outgoingData );
2010-11-21 23:48:11 +01:00
}
2011-06-26 00:13:53 +02:00
//after that, we're done here.
2010-11-21 23:48:11 +01:00
}
/**
* Calls ConnectionPool in order to create a simple connection .
2011-12-03 12:28:02 +01:00
*
* @ see \JPT\SocketFramework\Connection\ConnectionPool
2010-11-21 23:48:11 +01:00
* @ param string $group
* @ param boolean $IPv6
2011-12-03 12:28:02 +01:00
* @ return \JPT\SocketFramework\Connection\ConnectionHandler
2010-11-21 23:48:11 +01:00
*/
public function createTcpConnection ( $group = " " , $protocol = " RAW " , $IPv6 = FALSE ) {
return $this -> connectionPool -> createTcpConnection ( $group , $protocol , $IPv6 );
}
/**
* Closes and removes the connection .
2011-12-03 12:28:02 +01:00
*
* @ param \JPT\SocketFramework\Connection\ConnectionHandler $connectionHandler
2010-12-19 15:26:32 +01:00
* @ return void
2010-11-21 23:48:11 +01:00
*/
public function removeConnection ( $connectionHandler ) {
unset ( $this -> configPool [ $connectionHandler -> getID ()]);
2011-12-03 12:28:02 +01:00
unset ( $this -> clientDispatcherPool [ $connectionHandler -> getID ()]);
2010-11-21 23:48:11 +01:00
$this -> connectionPool -> removeConnectionHandler ( $connectionHandler );
}
/**
2011-12-03 12:28:02 +01:00
* Registers a protocol identifier and its specific client dispatcher .
*
* @ param string $protocolIdentifier
2010-11-21 23:48:11 +01:00
* @ param string $className
* @ return void
*/
2011-12-03 12:28:02 +01:00
public function registerClientDispatcherByProtocol ( $protocolIdentifier , $className ) {
$this -> registeredClientDispatchers [ $protocolIdentifier ] = $className ;
2010-11-21 23:48:11 +01:00
}
/**
2011-12-03 12:28:02 +01:00
* Unregisters a client dispatcher by its protocol identifier .
*
2010-11-21 23:48:11 +01:00
* @ param string $protocol
* @ return void
*/
2011-12-03 12:28:02 +01:00
public function unregisterClientDispatcherByProtocol ( $protocolIdentifier ) {
unset ( $this -> registeredClientDispatchers [ $protocolIdentifier ]);
2010-11-21 23:48:11 +01:00
}
2011-06-26 01:16:28 +02:00
/**
* Attaches a configuration to a connection .
* Will overwrite the existing configuration for the connection .
2011-12-03 12:28:02 +01:00
*
2011-06-26 01:16:28 +02:00
* @ param array $config
2011-12-03 12:28:02 +01:00
* @ param \JPT\SocketFramework\Connection\ConnectionHandler $connectionHandler
2011-06-26 01:16:28 +02:00
* @ return void
*/
public function attachConfig ( $config , $connectionHandler ) {
$this -> configPool [ $connectionHandler -> getID ()] = $config ;
}
/**
2011-12-03 12:28:02 +01:00
* Calls ConnectionPool .
*
* @ see \JPT\SocketFramework\Connection\ConnectionPool
2011-06-26 01:16:28 +02:00
* @ param int $id
* @ param string $data
* @ return void
*/
public function sendToID ( $id , $data ) {
return $this -> connectionPool -> writeToID ( $id , $data );
}
/**
* Returns a list of available connection IDs .
2011-12-03 12:28:02 +01:00
*
2011-06-26 01:16:28 +02:00
* @ return array
*/
public function getIDs () {
$list = array ();
2011-06-29 21:16:08 +02:00
foreach ( $this -> connectionPool -> getConnectionHandlers () AS $connectionHandler ) $list [] = $connectionHandler -> getID ();
2011-06-26 01:16:28 +02:00
return $list ;
}
/**
* Returns a list of available connection groups .
2011-12-03 12:28:02 +01:00
*
2011-06-26 01:16:28 +02:00
* @ return array
*/
public function getGroups () {
$list = array ();
2011-06-29 21:16:08 +02:00
foreach ( $this -> connectionPool -> getConnectionHandlers () AS $connectionHandler ) $list [] = $connectionHandler -> getGroup ();
2011-06-26 01:16:28 +02:00
return $list ;
}
/**
2011-12-03 20:58:08 +01:00
* Calls \JPT\SocketFramework\Connection\ConnectionPool .
2011-12-03 12:28:02 +01:00
*
* @ see \JPT\SocketFramework\Connection\ConnectionPool
2011-06-26 01:16:28 +02:00
* @ param string $group
* @ param string $data
* @ return void
*/
public function sendToGroup ( $group , $data ) {
return $this -> connectionPool -> writeToGroup ( $group , $data );
}
2010-11-21 23:48:11 +01:00
/**
2011-12-03 12:28:02 +01:00
* Searches the registered client dispatcher for the given protocol .
* Returns a client dispatcher instance or void .
*
2010-11-21 23:48:11 +01:00
* @ param string $protocol
* @ return mixed
2011-12-03 12:28:02 +01:00
* @ throws \JPT\SocketFramework\Exception\GeneralException
2010-11-21 23:48:11 +01:00
*/
2011-12-03 12:28:02 +01:00
protected function createClientDispatcherForProtocol ( $protocolIdentifier ) {
2010-11-21 23:48:11 +01:00
//look for the protocol
2011-12-03 20:58:08 +01:00
if ( isset ( $this -> registeredClientDispatchers [ $protocolIdentifier ]) === FALSE ) {
throw new \JPT\SocketFramework\Exception\GeneralException ( " No client dispatcher is registered for protocol: ' " . $protocolIdentifier . " '! " , 1290271651 );
2010-11-21 23:48:11 +01:00
}
2011-12-03 12:28:02 +01:00
$className = $this -> registeredClientDispatchers [ $protocolIdentifier ];
2010-11-21 23:48:11 +01:00
//look for the class
if ( class_exists ( $className )) {
2011-06-29 21:16:08 +02:00
//TODO: This looks ugly and wrong. Ideas, anyone?
2011-12-03 12:28:02 +01:00
$clientDispatcher = new $className ();
if ( ! $clientDispatcher instanceof \JPT\SocketFramework\Client\AbstractClientDispatcher ) throw new \JPT\SocketFramework\Exception\GeneralException ( " Class ' " . $className . " ' does not implement the AbstractClientDispatcher-API! " , 1294837055 );
return $clientDispatcher ;
2010-11-21 23:48:11 +01:00
} else {
2011-12-03 20:58:08 +01:00
throw new \JPT\SocketFramework\Exception\GeneralException ( " Registered class name ' " . $className . " ' does not exist for protocol: ' " . $protocolIdentifier . " '! " , 1290271773 );
2010-11-21 23:48:11 +01:00
}
}
2011-06-26 01:04:19 +02:00
/**
2011-12-03 12:28:02 +01:00
* Initializes the client dispatcher of a given connectionHandler .
2011-06-26 01:04:19 +02:00
* This should be done after establishing a connection .
2011-12-03 12:28:02 +01:00
*
* @ param \JPT\SocketFramework\Connection\ConnectionHandler $connectionHandler
2011-06-26 01:04:19 +02:00
* @ return void
*/
protected function initializeClientForConnectionHandler ( $connectionHandler ) {
2011-12-03 20:58:08 +01:00
if ( ! isset ( $this -> clientDispatcherPool [ $connectionHandler -> getID ()])) return ;
2011-12-03 12:28:02 +01:00
$this -> clientDispatcherPool [ $connectionHandler -> getID ()] -> initializeConnection ();
2011-06-26 01:04:19 +02:00
//after initializing, have it process an empty string in order to get stuff to write. >.<
2011-12-03 12:28:02 +01:00
$result = $this -> clientDispatcherPool [ $connectionHandler -> getID ()] -> processRawData ( " " );
2011-06-26 01:04:19 +02:00
if ( $result !== " " ) $connectionHandler -> write ( $result );
}
/**
2011-12-03 12:28:02 +01:00
* Creates a new connectionHandler , resets the client dispatchers connection status ,
* copies the old config and assigns the new connectionHandler to the clientdispatcher .
*
* @ param \JPT\SocketFramework\Connection\ConnectionHandler $connectionHandler
2011-06-26 01:04:19 +02:00
* @ return void
*/
protected function handleReconnectForConnectionHandler ( $connectionHandler ) {
//have the connectionHandler do the reconnect.
$newConnectionHandler = $connectionHandler -> reconnect ();
//get the client and reset it.
2011-12-03 12:28:02 +01:00
$client = $this -> clientDispatcherPool [ $connectionHandler -> getID ()];
2011-06-26 01:04:19 +02:00
$client -> resetConnectionStatus ();
//assign the client to the new connectionHandler.
2011-12-03 12:28:02 +01:00
$this -> clientDispatcherPool [ $newConnectionHandler -> getID ()] = $client ;
2011-06-26 01:04:19 +02:00
//get the config and assign it to the new connectionHandler, too.
$config = $this -> configPool [ $connectionHandler -> getID ()];
$this -> configPool [ $newConnectionHandler -> getID ()] = $config ;
//re-initialize the client
$this -> initializeClientForConnectionHandler ( $newConnectionHandler );
//remove old connection
$this -> removeConnection ( $connectionHandler );
}
2010-11-21 23:48:11 +01:00
/**
2011-12-03 12:28:02 +01:00
* Adds a client dispatcher to our client dispatcher pool .
* The " RAW " protocol identifier is used to not create a client .
*
* @ param \JPT\SocketFramework\Connection\ConnectionHandler $connectionHandler
2010-11-21 23:48:11 +01:00
* @ return void
*/
2011-12-03 12:28:02 +01:00
protected function addClientDispatcherForConnectionHandler ( $connectionHandler ) {
2011-12-03 20:58:08 +01:00
$protocolIdentifier = $connectionHandler -> getProtocol ();
2011-12-03 12:28:02 +01:00
//do not try this for "RAW" connections - might or might not be useful.
if ( $protocolIdentifier === " RAW " ) return ;
$clientDispatcher = $this -> createClientDispatcherForProtocol ( $protocolIdentifier );
2010-11-21 23:48:11 +01:00
if ( isset ( $this -> configPool [ $connectionHandler -> getID ()])) {
2011-12-03 12:28:02 +01:00
$clientDispatcher -> loadConfig ( $this -> configPool [ $connectionHandler -> getID ()]);
2010-11-21 23:48:11 +01:00
}
2011-12-03 12:28:02 +01:00
$clientDispatcher -> injectClientManager ( $this );
$clientDispatcher -> setID ( $connectionHandler -> getID ());
$clientDispatcher -> setGroup ( $connectionHandler -> getGroup ());
$this -> clientDispatcherPool [ $connectionHandler -> getID ()] = $clientDispatcher ;
2010-11-21 23:48:11 +01:00
}
/**
2011-12-03 12:28:02 +01:00
* Removes a client dispatcher from our client dispatcher pool .
*
* @ param \JPT\SocketFramework\Connection\ConnectionHandler $connectionHandler
2010-11-21 23:48:11 +01:00
* @ return void
2011-12-03 12:28:02 +01:00
* @ throws \JPT\SocketFramework\Exception\WrongDatatypeException
2010-11-21 23:48:11 +01:00
*/
protected function removeClientForConnectionHandler ( $connectionHandler ) {
2011-12-03 12:28:02 +01:00
unset ( $this -> clientDispatcherPool [ $connectionHandler -> getID ()]);
2010-11-21 23:48:11 +01:00
$this -> connectionPool -> removeConnectionHandler ( $connectionHandler );
}
}
?>