$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. * * @var array */ protected $registeredClientDispatchers; /** * Contains Connection-attached configurations. * * @var array */ protected $configPool; /** * Default constructor. * * @return void */ public function __construct() { $this->connectionPool = new \JPT\SocketFramework\Connection\ConnectionPool(); $this->clientDispatcherPool = array(); $this->registeredProtocols = array(); $this->configPool = array(); } /** * Default destructor. Closes connections before being killed. * * @return void */ public function __destruct() { unset($this->clientDispatcherPool); unset($this->connectionPool); } /** * @see Connection_ConnectionPool * @return int */ public function countSockets() { return $this->connectionPool->countSockets(); } /** * Returns the amount of connected connection handlers. * * @see \JPT\SocketFramework\Connection\ConnectionPool * @return int */ public function countActiveConnections() { return $this->connectionPool->countActiveConnections(); } /** * Main worker procedure. * Processes incoming data, calls clients and much more. * * @return void */ public function work() { //first, create clients for connections that do NOT have one already. foreach($this->connectionPool->getConnectionHandlers() AS $connectionHandler) { if(isset($this->clientDispatcherPool[$connectionHandler->getID()])) continue; //new connections might need a client, so we'll create one here. $this->addClientDispatcherForConnectionHandler($connectionHandler); //allow client to send initial stuff right after connecting to the server. $this->initializeClientForConnectionHandler($connectionHandler); } //then, process all connections that have stuff to read. $connectionHandlers = $this->connectionPool->select(); //nothing to do? return right now. :) if(isset($connectionHandlers["read"]) === FALSE || count($connectionHandlers["read"]) === 0) return; foreach($connectionHandlers["read"] AS $connectionHandler) { //handle disconnects if($connectionHandler->isConnected() === FALSE && $connectionHandler->isListening() === FALSE) { //do we need to reconnect? do it. if($connectionHandler->getReconnect() === TRUE) $this->handleReconnectForConnectionHandler($connectionHandler); //this old connectionHandler won't do much anymore - kill it. $this->removeClientForConnectionHandler($connectionHandler); //since the old connectionHandler does not exist anymore, continue. continue; } //handle accepted sockets, adopt them and treat them with care :-) if($connectionHandler->isListening() === TRUE) { $this->addClientDispatcherForConnectionHandler($connectionHandler); $this->initializeClientForConnectionHandler($connectionHandler); } //prepare and get input $incomingData = ""; $outgoingData = ""; while($data = $connectionHandler->read()) $incomingData .= $data; unset($data); //call the registered client 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); } //i don't know what to do here... maybe call a connection bridge? //output will be sent. if($outgoingData !== "") $connectionHandler->write($outgoingData); } //after that, we're done here. } /** * Calls ConnectionPool in order to create a simple connection. * * @see \JPT\SocketFramework\Connection\ConnectionPool * @param string $group * @param boolean $IPv6 * @return \JPT\SocketFramework\Connection\ConnectionHandler */ public function createTcpConnection($group = "", $protocol = "RAW", $IPv6 = FALSE) { return $this->connectionPool->createTcpConnection($group, $protocol, $IPv6); } /** * Closes and removes the connection. * * @param \JPT\SocketFramework\Connection\ConnectionHandler $connectionHandler * @return void */ public function removeConnection($connectionHandler) { unset($this->configPool[$connectionHandler->getID()]); unset($this->clientDispatcherPool[$connectionHandler->getID()]); $this->connectionPool->removeConnectionHandler($connectionHandler); } /** * Registers a protocol identifier and its specific client dispatcher. * * @param string $protocolIdentifier * @param string $className * @return void */ public function registerClientDispatcherByProtocol($protocolIdentifier, $className) { $this->registeredClientDispatchers[$protocolIdentifier] = $className; } /** * Unregisters a client dispatcher by its protocol identifier. * * @param string $protocol * @return void */ public function unregisterClientDispatcherByProtocol($protocolIdentifier) { unset($this->registeredClientDispatchers[$protocolIdentifier]); } /** * Attaches a configuration to a connection. * Will overwrite the existing configuration for the connection. * * @param array $config * @param \JPT\SocketFramework\Connection\ConnectionHandler $connectionHandler * @return void */ public function attachConfig($config, $connectionHandler) { $this->configPool[$connectionHandler->getID()] = $config; } /** * Calls ConnectionPool. * * @see \JPT\SocketFramework\Connection\ConnectionPool * @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. * * @return array */ public function getIDs() { $list = array(); foreach($this->connectionPool->getConnectionHandlers() AS $connectionHandler) $list[] = $connectionHandler->getID(); return $list; } /** * Returns a list of available connection groups. * * @return array */ public function getGroups() { $list = array(); foreach($this->connectionPool->getConnectionHandlers() AS $connectionHandler) $list[] = $connectionHandler->getGroup(); return $list; } /** * Calls \JPT\SocketFramework\Connection\ConnectionPool. * * @see \JPT\SocketFramework\Connection\ConnectionPool * @param string $group * @param string $data * @return void */ public function sendToGroup($group, $data) { return $this->connectionPool->writeToGroup($group, $data); } /** * Searches the registered client dispatcher for the given protocol. * Returns a client dispatcher instance or void. * * @param string $protocol * @return mixed * @throws \JPT\SocketFramework\Exception\GeneralException */ protected function createClientDispatcherForProtocol($protocolIdentifier) { //look for the protocol if(isset($this->registeredClientDispatchers[$protocolIdentifier]) === FALSE) { throw new \JPT\SocketFramework\Exception\GeneralException("No client dispatcher is registered for protocol: '" . $protocolIdentifier . "'!", 1290271651); } $className = $this->registeredClientDispatchers[$protocolIdentifier]; //look for the class if(class_exists($className)) { //TODO: This looks ugly and wrong. Ideas, anyone? $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; } else { throw new \JPT\SocketFramework\Exception\GeneralException("Registered class name '" . $className . "' does not exist for protocol: '" . $protocolIdentifier . "'!", 1290271773); } } /** * Initializes the client dispatcher of a given connectionHandler. * This should be done after establishing a connection. * * @param \JPT\SocketFramework\Connection\ConnectionHandler $connectionHandler * @return void */ protected function initializeClientForConnectionHandler($connectionHandler) { if(!isset($this->clientDispatcherPool[$connectionHandler->getID()])) return; $this->clientDispatcherPool[$connectionHandler->getID()]->initializeConnection(); //after initializing, have it process an empty string in order to get stuff to write. >.< $result = $this->clientDispatcherPool[$connectionHandler->getID()]->processRawData(""); if($result !== "") $connectionHandler->write($result); } /** * 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 * @return void */ protected function handleReconnectForConnectionHandler($connectionHandler) { //have the connectionHandler do the reconnect. $newConnectionHandler = $connectionHandler->reconnect(); //get the client and reset it. $client = $this->clientDispatcherPool[$connectionHandler->getID()]; $client->resetConnectionStatus(); //assign the client to the new connectionHandler. $this->clientDispatcherPool[$newConnectionHandler->getID()] = $client; //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); } /** * 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 * @return void */ protected function addClientDispatcherForConnectionHandler($connectionHandler) { $protocolIdentifier = $connectionHandler->getProtocol(); //do not try this for "RAW" connections - might or might not be useful. if($protocolIdentifier === "RAW") return; $clientDispatcher = $this->createClientDispatcherForProtocol($protocolIdentifier); if(isset($this->configPool[$connectionHandler->getID()])) { $clientDispatcher->loadConfig($this->configPool[$connectionHandler->getID()]); } $clientDispatcher->injectClientManager($this); $clientDispatcher->setID($connectionHandler->getID()); $clientDispatcher->setGroup($connectionHandler->getGroup()); $this->clientDispatcherPool[$connectionHandler->getID()] = $clientDispatcher; } /** * Removes a client dispatcher from our client dispatcher pool. * * @param \JPT\SocketFramework\Connection\ConnectionHandler $connectionHandler * @return void * @throws \JPT\SocketFramework\Exception\WrongDatatypeException */ protected function removeClientForConnectionHandler($connectionHandler) { unset($this->clientDispatcherPool[$connectionHandler->getID()]); $this->connectionPool->removeConnectionHandler($connectionHandler); } } ?>