diff --git a/Classes/Client/AbstractClient.php b/Classes/Client/AbstractClient.php index 77e0976..9ef3354 100644 --- a/Classes/Client/AbstractClient.php +++ b/Classes/Client/AbstractClient.php @@ -82,6 +82,15 @@ abstract class Client_AbstractClient { } + /** + * This function gets called every time, the connection is established. + * This allows the client to send initial data. + * @return void + */ + public function initializeConnection() { + + } + /** * @param int $id * @return void diff --git a/Classes/Client/BotClient.php b/Classes/Client/BotClient.php index 355f07a..b1b37aa 100644 --- a/Classes/Client/BotClient.php +++ b/Classes/Client/BotClient.php @@ -17,25 +17,31 @@ class Client_BotClient extends Client_AbstractClient { /** * Does all the hard work. - * @param string $data - * @return string + * @param object $contentObject + * @return void */ public function processContentObject($contentObject) { $return = ""; - $data = $contentObject->getRawData(); - if(strpos($data, "-") !== FALSE ) { - $data = explode("-", $data, 2); + $rawData = $contentObject->getRawData(); + + if(trim($rawData) === "list") { + $return = print_r(array("IDs" => $this->clientManager->getIDs(), "Groups" => $this->clientManager->getGroups()), TRUE); + } + + if(strpos($rawData, "-") !== FALSE ) { + $data = explode("-", $rawData, 2); $this->clientManager->sendToID((int) $data[0], $data[1]."\r\n"); $return = print_r($data, TRUE); } - if(strpos($data, "+") !== FALSE ) { - $data = explode("+", $data, 2); + if(strpos($rawData, "+") !== FALSE ) { + $data = explode("+", $rawData, 2); $this->clientManager->sendToGroup($data[0], $data[1]."\r\n"); $return = print_r($data, TRUE); } //TODO: implement this correctly + $return = str_replace("\n", "\r\n", $return); $this->protocolHandler->sendRaw($return); } diff --git a/Classes/Client/ClientManager.php b/Classes/Client/ClientManager.php index 6e7eca1..eda05d0 100644 --- a/Classes/Client/ClientManager.php +++ b/Classes/Client/ClientManager.php @@ -84,6 +84,20 @@ class Client_ClientManager { * @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) { @@ -103,19 +117,23 @@ class Client_ClientManager { $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); - //reconnect or not - this connectionHandler won't do that much. + //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(); } - //create a client for a connection without one. - if(!isset($this->clientPool[$connectionHandler->getID()])) { - $this->addClientForConnectionHandler($connectionHandler); - } + //call the registered client if(isset($this->clientPool[$connectionHandler->getID()])) { //let the client process the data, send the results back. @@ -127,6 +145,7 @@ class Client_ClientManager { } } } + //after that, we're done here. } /** @@ -247,6 +266,30 @@ class Client_ClientManager { 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 diff --git a/Classes/Client/IrcClient.php b/Classes/Client/IrcClient.php index 57d7f71..8b5a52b 100644 --- a/Classes/Client/IrcClient.php +++ b/Classes/Client/IrcClient.php @@ -10,12 +10,12 @@ class Client_IrcClient extends Client_AbstractClient { /** * @var boolean */ - protected $got_001; + protected $joined; /** * @var boolean */ - protected $joined; + protected $got001; /** * @var boolean @@ -53,44 +53,52 @@ class Client_IrcClient extends Client_AbstractClient { */ public function resetConnectionStatus() { $this->lines = 0; - $this->got_001 = FALSE; + $this->got001 = FALSE; $this->joined = FALSE; $this->authed = FALSE; } + /** + * This function gets called every time, the connection is established. + * This allows the client to send initial data. + * @return void + */ + public function initializeConnection() { + if(!$this->authed) { + $data = "USER poweruser as as :JPTs Bot\r\nNICK :" . $this->nick . "\r\n"; + $this->authed = TRUE; + } + $this->protocolHandler->sendRaw($data); + } + /** * Processes the resulting ContentObject from a ProtocolHandler. * Does all the hard work. * @param string $data * @return void */ - public function processContentObject($contentObject) { + protected function processContentObject($contentObject) { $data = $contentObject->getRawData(); - //DEBUG + //DEBUG //var_dump($contentObject); - //echo "[RECV] ".$data; //respond to pings if($contentObject->getCommand() === "PING") $this->protocolHandler->pong($contentObject->getParams()); - $this->clientManager->sendToGroup("srv", "[#".$this->ID."] ".$data."\r\n\r\n"); + $this->clientManager->sendToGroup("srv", "[#".$this->ID."] ".$data); + + if($contentObject->getCommand() === "001") $this->got001 = TRUE; $return = ""; - if(preg_match("/001/", $data)) $this->got_001 = TRUE; $this->lines++; - if(!$this->authed && $this->lines > 1) { - $return .= "USER as as as :Asdfg\r\nNICK :" . $this->nick . "\r\n"; - $this->authed = TRUE; - } - - if($this->got_001 && !$this->joined) { + if(!$this->joined && $this->got001) { $this->joined = TRUE; foreach($this->channels AS $channel) $return .= "JOIN " . $channel . "\r\n"; } - if(strpos($data, "hau ab") !== FALSE) { + if(strpos($data, "multivitamin") !== FALSE) { $return .= "PRIVMSG ".$this->channels[0]." :roger that :D\r\n"; $return .= "QUIT :lol\r\n"; } diff --git a/Classes/Connection/ConnectionHandler.php b/Classes/Connection/ConnectionHandler.php index 0f8f299..e9db515 100644 --- a/Classes/Connection/ConnectionHandler.php +++ b/Classes/Connection/ConnectionHandler.php @@ -207,7 +207,10 @@ class Connection_ConnectionHandler { * @return boolean */ public function writeFromBuffer() { - $result = $this->socketHandler->write($this->buffer_outgoing->getAllBufferContents()); + $bufferContent = $this->buffer_outgoing->getAllBufferContents(); + //this might not be cool, but it should do. + if($bufferContent === "") return TRUE; + $result = $this->socketHandler->write($bufferContent); if($result === FALSE) { $this->shutdown(); return FALSE; diff --git a/Classes/Connection/ConnectionPool.php b/Classes/Connection/ConnectionPool.php index e8d5e97..792c933 100644 --- a/Classes/Connection/ConnectionPool.php +++ b/Classes/Connection/ConnectionPool.php @@ -56,6 +56,14 @@ class Connection_ConnectionPool { return $connectionHandler; } + /** + * Returns the array with the current connectionHandlers. + * @return array + */ + public function getConnectionHandlers() { + return $this->connectionHandlers; + } + /** * Adds a ConnectionHandler to the pool. * @param Connection_ConnectionHandler $add_connectionHandler @@ -108,9 +116,15 @@ class Connection_ConnectionPool { foreach($this->connectionHandlers AS $connectionHandler) { $connectionSocket = $connectionHandler->getSocket(); $read[] = $connectionSocket; - if($connectionHandler->canWrite() && $connectionHandler->isServer() === FALSE) $write[] = $connectionSocket; + if($connectionHandler->canWrite() === TRUE && $connectionHandler->isServer() === FALSE) { + $write[] = $connectionSocket; + //the line above does not work for freshly connected stuff. + //this is the fallback(?) - just write the stuff - no matter what happens. + if($connectionHandler->writeFromBuffer() === FALSE) $this->removeConnectionHandler($connectionHandler); + } } $except = $read; + //Arrays are prepared, let's have socket_select() take a look and process its results. $tempArray = array(); $selectedSockets = $this->socketPool->select($read, $write, $except); @@ -129,6 +143,8 @@ class Connection_ConnectionPool { } break; case "write": + //this might still work on active connections that are "in use". + //however, it does not for freshly connected ones. if($connectionHandler->writeFromBuffer() === FALSE) $this->removeConnectionHandler($connectionHandler); break; case "except": diff --git a/Classes/Protocol/IrcProtocolHandler.php b/Classes/Protocol/IrcProtocolHandler.php index 1bae6d5..cb8d4ef 100644 --- a/Classes/Protocol/IrcProtocolHandler.php +++ b/Classes/Protocol/IrcProtocolHandler.php @@ -6,15 +6,20 @@ */ class Protocol_IrcProtocolHandler extends Protocol_AbstractProtocolHandler { + /** + * @var string + */ + protected $linebreak; + /** * Is called by the constructor. * Shall create the two buffers and set them up. * @return void */ public function createBuffers() { - $linebreak = "\r\n"; - $this->buffer_incoming = new Misc_Buffer($linebreak); - $this->buffer_outgoing = new Misc_Buffer($linebreak); + $this->linebreak = "\n"; + $this->buffer_incoming = new Misc_Buffer($this->linebreak); + $this->buffer_outgoing = new Misc_Buffer($this->linebreak); } /** @@ -153,7 +158,7 @@ class Protocol_IrcProtocolHandler extends Protocol_AbstractProtocolHandler { //break; //tell when stuff is not implemented default: - echo "N.i.y.: " . $command . " [".$data."]\r\n"; + //echo "N.i.y.: " . $command . " [".$data."]\r\n"; break; } @@ -182,7 +187,7 @@ class Protocol_IrcProtocolHandler extends Protocol_AbstractProtocolHandler { * @return void */ public function sendRaw($data) { - $this->buffer_outgoing->addData($data); + $this->buffer_outgoing->addData($data . $this->linebreak); } /** diff --git a/Classes/Socket/SocketHandler.php b/Classes/Socket/SocketHandler.php index 1f1ec72..6dcb160 100644 --- a/Classes/Socket/SocketHandler.php +++ b/Classes/Socket/SocketHandler.php @@ -16,17 +16,17 @@ class Socket_SocketHandler { /** * @var boolean */ - protected $is_connected; + protected $isConnected; /** * @var boolean */ - protected $is_bound; + protected $isBound; /** * @var boolean */ - protected $is_listening; + protected $isListening; /** * Default constructor. Sets the socket. @@ -37,9 +37,9 @@ class Socket_SocketHandler { public function __construct($socket) { if(is_resource($socket) === FALSE) throw new Exception_SocketException("Invalid socket ressource!", 1289663108); $this->socket = $socket; - $this->is_bound = FALSE; - $this->is_connected = FALSE; - $this->is_listening = FALSE; + $this->isBound = FALSE; + $this->isConnected = FALSE; + $this->isListening = FALSE; } /** @@ -62,23 +62,23 @@ class Socket_SocketHandler { * @return boolean */ public function isConnected() { - return $this->is_connected; + return $this->isConnected; } /** - * Sets is_connected-flag. + * Sets isConnected-flag. * @param boolean $connected * @return void */ public function setConnected($connected) { - $this->is_connected = $connected; + $this->isConnected = $connected; } /** * @return boolean */ public function isListening() { - return $this->is_listening; + return $this->isListening; } /** @@ -89,10 +89,10 @@ class Socket_SocketHandler { * @return void */ public function connect($address, $port) { - if($this->is_connected === TRUE) throw new Exception_SocketException("Socket is already connected!", 1289663170); + if($this->isConnected === TRUE) throw new Exception_SocketException("Socket is already connected!", 1289663170); $result = socket_connect($this->socket, $address, $port); if($result === FALSE) $this->error(); - $this->is_connected = TRUE; + $this->isConnected = TRUE; } /** @@ -103,12 +103,12 @@ class Socket_SocketHandler { * @return void */ public function bind($address, $port) { - if($this->is_bound === TRUE) throw new Exception_SocketException("Socket is already bound!", 1289663212); + if($this->isBound === TRUE) throw new Exception_SocketException("Socket is already bound!", 1289663212); $result = socket_set_option($this->socket, SOL_SOCKET, SO_REUSEADDR, 1); if($result === FALSE) $this->error(); $result = socket_bind($this->socket, $address, $port); if($result === FALSE) $this->error(); - $this->is_bound = TRUE; + $this->isBound = TRUE; } /** @@ -117,10 +117,10 @@ class Socket_SocketHandler { * @return void */ public function listen() { - if($this->is_bound === FALSE) throw new Exception_SocketException("Cannot listen on unbound socket!", 1289663220); + if($this->isBound === FALSE) throw new Exception_SocketException("Cannot listen on unbound socket!", 1289663220); $result = socket_listen($this->socket); if($result === FALSE) $this->error(); - $this->is_listening = TRUE; + $this->isListening = TRUE; } /** @@ -128,7 +128,7 @@ class Socket_SocketHandler { * @return void */ public function hasBeenAccepted() { - $this->is_connected = TRUE; + $this->isConnected = TRUE; } /** @@ -138,8 +138,8 @@ class Socket_SocketHandler { * @return ressource */ public function accept() { - if($this->is_bound === FALSE) throw new Exception_SocketException("Cannot accept connections from unbound socket!", 1289663239); - if($this->is_listening === FALSE) throw new Exception_SocketException("Cannot accept connections from socket that is not listening!", 1289663241); + if($this->isBound === FALSE) throw new Exception_SocketException("Cannot accept connections from unbound socket!", 1289663239); + if($this->isListening === FALSE) throw new Exception_SocketException("Cannot accept connections from socket that is not listening!", 1289663241); $accept = socket_accept($this->socket); if($accept === FALSE) $this->error(); return $accept; @@ -151,7 +151,7 @@ class Socket_SocketHandler { * @return string */ public function getRemoteName() { - if($this->is_connected === FALSE) throw new Exception_SocketException("Socket not connected, cannot retrieve remote name!", 1289928192); + if($this->isConnected === FALSE) throw new Exception_SocketException("Socket not connected, cannot retrieve remote name!", 1289928192); $result = socket_getpeername($this->socket, $address, $port); if($result === FALSE) $this->error(); return $address . ":" . $port; @@ -163,7 +163,7 @@ class Socket_SocketHandler { * @return string */ public function getLocalName() { - if($this->is_bound === FALSE ^ $this->is_connected === FALSE) throw new Exception_SocketException("Socket is not bound or connected, no local name available!", 1289928256); + if($this->isBound === FALSE ^ $this->isConnected === FALSE) throw new Exception_SocketException("Socket is not bound or connected, no local name available!", 1289928256); $result = socket_getsockname($this->socket, $address, $port); if($result === FALSE) $this->error(); return $address . ":" . $port; @@ -199,7 +199,7 @@ class Socket_SocketHandler { */ public function close() { usleep(100000); - if($this->is_connected === TRUE) { + if($this->isConnected === TRUE) { $result = socket_shutdown($this->socket); if($result === FALSE) $this->error(); } @@ -207,7 +207,7 @@ class Socket_SocketHandler { $result = socket_close($this->socket); if($result === FALSE) $this->error(); } - $this->is_connected = FALSE; + $this->isConnected = FALSE; } /** diff --git a/Classes/Socket/SocketPool.php b/Classes/Socket/SocketPool.php index 9f5d5f5..1980158 100644 --- a/Classes/Socket/SocketPool.php +++ b/Classes/Socket/SocketPool.php @@ -71,8 +71,8 @@ class Socket_SocketPool { * @return ressource */ public function createTcpSocket($IPv6 = FALSE) { - $Domain = ($IPv6) ? AF_INET6 : AF_INET; - $socket = socket_create($Domain, SOCK_STREAM, SOL_TCP); + $domain = ($IPv6) ? AF_INET6 : AF_INET; + $socket = socket_create($domain, SOCK_STREAM, SOL_TCP); socket_set_block($socket); if($socket === FALSE) throw new Exception_SocketException("socket_create() failed!", 1290273709); $this->addSocket($socket); @@ -90,7 +90,7 @@ class Socket_SocketPool { */ public function select($read, $write, $except, $timeout = NULL) { $n = socket_select($read, $write, $except, $timeout); - if($n === FALSE) throw new Exception_SocketException("socket_select() failed!", 1290273693); + if($n === FALSE) throw new Exception_SocketException("socket_select() failed! - Error: " . socket_strerror(socket_last_error()), 1290273693); if($n === 0) return array("read" => array(), "write" => array(), "except" => array()); return array("read" => $read, "write" => $write, "except" => $except); } diff --git a/Main.php b/Main.php index 8554bfc..6ad8b5d 100644 --- a/Main.php +++ b/Main.php @@ -6,6 +6,7 @@ try { require_once('Testcode/Client/ClientManagerTest.php'); } catch(Exception $e) { - echo "\n\nCaught Exception: " . $e . "\n"; + echo PHP_EOL.PHP_EOL."Caught Exception: " . $e . PHP_EOL; } + ?> \ No newline at end of file diff --git a/Testcode/Client/ClientManagerTest.php b/Testcode/Client/ClientManagerTest.php index 5480541..8cb5860 100644 --- a/Testcode/Client/ClientManagerTest.php +++ b/Testcode/Client/ClientManagerTest.php @@ -13,13 +13,15 @@ $freenode->connect("irc.freenode.net", 6667); $freenode->setReconnect(TRUE); */ -$freenode = $clientManager->createTcpConnection("freenode", "irc"); +$euirc = $clientManager->createTcpConnection("euirc", "irc"); $clientManager->attachConfig(array( "nick" => "Pb42", - "userident" => "uzuguck", - "channels" => array("#mstasty", "#starsim") -), $freenode); -$freenode->connect("irc.freenode.net", 6667); + "userident" => "Serena", + "channels" => array("#kuzuru-subs") +), $euirc); +$euirc->connect("irc.euirc.net", 6667); +$euirc->setReconnect(TRUE); + /*$config_eloxoph = array( "nick" => "Frischmilch",