connectionPool = new Connection_ConnectionPool(); $this->clientPool = array(); $this->registeredProtocols = array(); $this->configPool = array(); } /** * Default destructor. Closes connections before being killed. * @return void */ public function __destruct() { unset($this->clientPool); unset($this->connectionPool); } /** * @see Connection_ConnectionPool * @return int */ public function countSockets() { return $this->connectionPool->countSockets(); } /** * Returns the amount of connected connection handlers. * @see 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->clientPool[$connectionHandler->getID()])) continue; //new connections might need a client, so we'll create one here. $this->addClientForConnectionHandler($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->addClientForConnectionHandler($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->clientPool[$connectionHandler->getID()])) $outgoingData .= $this->clientPool[$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($result); } //after that, we're done here. } /** * Calls ConnectionPool in order to create a simple connection. * @see Connection_ConnectionPool * @param string $group * @param boolean $IPv6 * @return Connection_ConnectionHandler */ public function createTcpConnection($group = "", $protocol = "RAW", $IPv6 = FALSE) { return $this->connectionPool->createTcpConnection($group, $protocol, $IPv6); } /** * Closes and removes the connection. * @param Connection_ConnectionHandler $connectionHandler * @return void */ public function removeConnection($connectionHandler) { unset($this->configPool[$connectionHandler->getID()]); unset($this->clientPool[$connectionHandler->getID()]); $this->connectionPool->removeConnectionHandler($connectionHandler); } /** * Registers a protocol with a specific client. * @param string $protocol * @param string $className * @return void */ public function registerProtocol($protocol, $classNamePartial) { $this->registeredProtocols[$protocol] = $classNamePartial; } /** * Unregisters a protocol. * @param string $protocol * @return void */ public function unregisterProtocol($protocol) { unset($this->registeredProtocols[$protocol]); } /** * Attaches a configuration to a connection. * Will overwrite the existing configuration for the connection. * @param array $config * @param Connection_ConnectionHandler $connectionHandler * @return void */ public function attachConfig($config, $connectionHandler) { $this->configPool[$connectionHandler->getID()] = $config; } /** * Calls Connection_Pool * @see 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 Connection_Pool * @see Connection_ConnectionPool * @param string $group * @param string $data * @return void */ public function sendToGroup($group, $data) { return $this->connectionPool->writeToGroup($group, $data); } /** * Searches for the registered client for the given protocol. * Returns a client instance or void. * @param string $protocol * @return mixed * @throws Exception_GeneralException */ protected function createClientForProtocol($protocol) { //look for the protocol if(!in_array($protocol, $this->registeredProtocols)) { throw new Exception_GeneralException("No client registered for protocol: '" . $protocol . "'!", 1290271651); } $className = "Client_" . $protocol . "Client"; //look for the class if(class_exists($className)) { //TODO: This looks ugly and wrong. Ideas, anyone? $client = new $className(); if(!$client instanceof Client_AbstractClient) throw new Exception_GeneralException("Class '" . $className . "' does not implement the AbstractClient-API!", 1294837055); return $client; } else { throw new Exception_GeneralException("Registered class name '" . $className . "' does not exist for protocol: '" . $protocol . "'!", 1290271773); } } /** * Initializes the client of a given connectionHandler. * This should be done after establishing a connection. * @param Connection_ConnectionHandler $connectionHandler * @return void */ protected function initializeClientForConnectionHandler($connectionHandler) { $this->clientPool[$connectionHandler->getID()]->initializeConnection(); //after initializing, have it process an empty string in order to get stuff to write. >.< $result = $this->clientPool[$connectionHandler->getID()]->processRawData(""); if($result !== "") $connectionHandler->write($result); } /** * Creates a new connectionHandler, resets the clients connection status, * copies the old config and assigns the new connectionHandler to the client. * @param 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->clientPool[$connectionHandler->getID()]; $client->resetConnectionStatus(); //assign the client to the new connectionHandler. $this->clientPool[$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 to our client pool. * @param Connection_ConnectionHandler $connectionHandler * @return void */ protected function addClientForConnectionHandler($connectionHandler) { $protocol = $this->registeredProtocols[$connectionHandler->getProtocol()]; //do not try this for raw connections if($protocol === "RAW") return; $client = $this->createClientForProtocol($protocol); if(isset($this->configPool[$connectionHandler->getID()])) { $client->loadConfig($this->configPool[$connectionHandler->getID()]); } $client->injectClientManager($this); $protocolHandlerClass = "Protocol_".$protocol."ProtocolHandler"; //TODO: This looks ugly, too. Is there a better way? $protocolHandler = new $protocolHandlerClass(); $client->injectProtocolHandler($protocolHandler); $client->setID($connectionHandler->getID()); $client->setGroup($connectionHandler->getGroup()); $this->clientPool[$connectionHandler->getID()] = $client; } /** * Removes a client from our client pool. * @param Connection_ConnectionHandler $connectionHandler * @return void */ protected function removeClientForConnectionHandler($connectionHandler) { unset($this->clientPool[$connectionHandler->getID()]); $this->connectionPool->removeConnectionHandler($connectionHandler); } } ?>