connectionPool = new Connection_ConnectionPool(); $this->clientPool = array(); $this->registeredProtocols = array(); $this->routingRules = 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 function. * Processes incoming data, calls clients and much more. * TODO: refactor this? (split it into handleFoobar() functions) * @return void */ public function work() { //firstly, create clients for connections without one. foreach($this->connectionPool->getConnectionHandlers() AS $connectionHandler) { if(!isset($this->clientPool[$connectionHandler->getID()])) { //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->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); } } //then, process all connections that have stuff to read. $connectionHandlers = $this->connectionPool->select(); if(isset($connectionHandlers["read"]) === FALSE || count($connectionHandlers["read"]) === 0) return; foreach($connectionHandlers["read"] AS $connectionHandler) { //handle disconnects if($connectionHandler->isConnected() === FALSE && $connectionHandler->isListening() === FALSE) { //check whether the reconnect-flag is set if($connectionHandler->getReconnect() === TRUE) { //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; //remove old connection $this->removeConnection($connectionHandler); //re-initialize the client $this->clientPool[$newConnectionHandler->getID()]->initializeConnection(); //and of course, process stuff to get the buffer filled. :/ $result = $this->clientPool[$newConnectionHandler->getID()]->processRawData(""); if($result !== "") $newConnectionHandler->write($result); } $this->removeClientForConnectionHandler($connectionHandler); //this connectionHandler won't do much anymore - kill it. continue; } //handle accepted sockets, adopt them and treat them with care :-) if($connectionHandler->isListening() === TRUE) { $this->addClientForConnectionHandler($connectionHandler); //TODO: maybe we want to trigger the "client" here, too? -- YES $this->clientPool[$connectionHandler->getID()]->initializeConnection(); } //call the registered client if(isset($this->clientPool[$connectionHandler->getID()])) { //let the client process the data, send the results back. while($data = $connectionHandler->read()) { $result = $this->clientPool[$connectionHandler->getID()]->processRawData($data); if($result !== "") { $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]); } /** * 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)) { $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); } } /** * 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"; $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); } /** * 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); } } ?>