[TASK] Added function for clients, so they're able to send initial data right after connecting to a server.
[TASK] Restructured parts of the core to support sending data right after connecting. [TASK] Adapted core part for automatic reconnect to support sending initial data, too.
This commit is contained in:
parent
4c9f5ba7f3
commit
2c5e520c9f
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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":
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
3
Main.php
3
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;
|
||||
}
|
||||
|
||||
?>
|
|
@ -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",
|
||||
|
|
Loading…
Reference in New Issue