Skip to content

Commit

Permalink
- Initial implementation of the plugins system,
Browse files Browse the repository at this point in the history
- Aded the logger plugin + Zend_Log dependencies
  • Loading branch information
shevron committed Mar 21, 2009
1 parent a8aba35 commit f8e2990
Show file tree
Hide file tree
Showing 13 changed files with 1,100 additions and 8 deletions.
8 changes: 8 additions & 0 deletions examples/server.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,15 @@
);

require_once 'Aspamia/Http/Server.php';
require_once 'Aspamia/Http/Server/Plugin/Logger.php';

// Create the server object with a single static handler
$server = new Aspamia_Http_Server(array(
'handler' => 'Aspamia_Http_Server_Handler_Static'
));

// Register the logger plugin
$server->registerPlugin(new Aspamia_Http_Server_Plugin_Logger());

// Run the server!
$server->run();
148 changes: 140 additions & 8 deletions library/Aspamia/Http/Server.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,25 @@ class Aspamia_Http_Server
'handler' => 'Aspamia_Http_Server_Handler_Mock'
);

/**
* Array of registered plugins
*
* @var unknown_type
*/
protected $_plugins = array();

/**
* Main listening socket
*
* @var resource
*/
protected $_socket = null;

/**
* Stream context (if set)
*
* @var resource
*/
protected $_context = null;

/**
Expand Down Expand Up @@ -51,31 +68,55 @@ public function __construct($config = array())
}
}

/**
* Set the configuration data for this server object
*
* @param Zend_Config | array $config
*/
public function setConfig($config)
{
if ($config instanceof Zend_Config) {
$config = $config->toArray();
}

if (! is_array($config)) {
throw new ErrorException("\$config is expected to be an array or a Zend_Config object, got " . gettype($config));
require_once 'Aspamia/Http/Server/Exception.php';
throw new Aspamia_Http_Server_Exception("\$config is expected to be an array or a Zend_Config object, got " . gettype($config));
}

foreach($config as $k => $v) {
$this->_config[$k] = $v;
}
}

/**
* Register a plug-in
*
* @param Aspamia_Http_Server_Plugin_Abstract $plugin
*/
public function registerPlugin(Aspamia_Http_Server_Plugin_Abstract $plugin)
{
$plugin->setServer($this);
$this->_plugins[] = $plugin;
}

/**
* Get the bind address for the server
*
* @return string
*/
public function getBindAddr()
{
return $this->_config['stream_wrapper'] . '://' .
$this->_config['bind_addr'] . ':' .
$this->_config['bind_port'];
}
/**
* TODO: Should this be adapter based?
*
*/
public function run()
{
$addr = $this->_config['stream_wrapper'] . '://' .
$this->_config['bind_addr'] . ':' .
$this->_config['bind_port'];

$flags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN;

if (! $this->_context) {
Expand All @@ -84,21 +125,32 @@ public function run()

$errno = 0;
$errstr = null;
$this->_socket = stream_socket_server($addr, $errno, $errstr, $flags, $this->_context);
$this->_socket = stream_socket_server($this->getBindAddr(), $errno, $errstr, $flags, $this->_context);
if (! $this->_socket) {
require_once 'Aspamia/Http/Server/Exception.php';
$message = "Unable to bind to '$addr'";
if ($errno || $errstr) $message .= ": [#$errno] $errstr";
throw new Aspamia_Http_Server_Exception($message);
}

$this->_callServerStartupPlugins();

while(true) {
if (($conn = @stream_socket_accept($this->_socket))) {
$this->_handle($conn);
if (($conn = @stream_socket_accept($this->_socket))) {
try {
$this->_handle($conn);
} catch (Aspamia_Http_Exception $ex) {
$this->_callOnErrorPlugins($ex);
// Supress exception and continue looping
} catch (Exception $ex) {
$this->_callOnErrorPlugins($ex);
throw $ex;
}
}
}

fclose($this->_socket);
$this->_callServerShutdownPlugins();
}

public function setHandler(Aspamia_Http_Server_Handler_Abstract $handler)
Expand All @@ -109,8 +161,12 @@ public function setHandler(Aspamia_Http_Server_Handler_Abstract $handler)
protected function _handle($connection)
{
// Read and parse the HTTP request line
$this->_callPreRequestPlugins($connection);
$request = $this->_readRequest($connection);
$this->_callPostRequestPlugins($request);

$response = $this->_handler->handle($request);
$this->_callPreResponsePlugins($response);

$serverSignature = 'Aspamia/' . self::ASPAMIA_VERSION . ' ' .
'PHP/' . PHP_VERSION;
Expand All @@ -124,10 +180,86 @@ protected function _handle($connection)
$response->setHeader('connection', 'close');

fwrite($connection, (string) $response);
$this->_callPostResponsePlugins($connection);
}

protected function _readRequest($connection)
{
return Aspamia_Http_Request::read($connection);
}

/**
* Call the server startup hook of all plugins
*
*/
protected function _callServerStartupPlugins()
{
foreach ($this->_plugins as $plugin) /* @var $plugin Aspamia_Http_Server_Plugin_Abstract */
$plugin->serverStartup();
}

/**
* Call the server shutdown hook of all plugins
*
*/
protected function _callServerShutdownPlugins()
{
foreach ($this->_plugins as $plugin) /* @var $plugin Aspamia_Http_Server_Plugin_Abstract */
$plugin->serverShutdown();
}

/**
* Call the on-error hook of all plugins
*
* @param Exception $ex
*/
protected function _callOnErrorPlugins(Exception $ex)
{
foreach ($this->_plugins as $plugin) /* @var $plugin Aspamia_Http_Server_Plugin_Abstract */
$plugin->onError($ex);
}

/**
* Call the pre-request hook of all plugins
*
* @param resource $conn
*/
protected function _callPreRequestPlugins($conn)
{
foreach ($this->_plugins as $plugin) /* @var $plugin Aspamia_Http_Server_Plugin_Abstract */
$plugin->preRequest($conn);
}

/**
* Call the post-request hook of all plugins
*
* @param Aspamia_Http_Request $request
*/
protected function _callPostRequestPlugins(Aspamia_Http_Request $request)
{
foreach ($this->_plugins as $plugin) /* @var $plugin Aspamia_Http_Server_Plugin_Abstract */
$plugin->postRequest($request);
}

/**
* Call the pre-response hook of all plugins
*
* @param Aspamia_Http_Response $response
*/
protected function _callPreResponsePlugins(Aspamia_Http_Response $response)
{
foreach ($this->_plugins as $plugin) /* @var $plugin Aspamia_Http_Server_Plugin_Abstract */
$plugin->preResponse($response);
}

/**
* Call the post-response hook of all plugins
*
* @param resource $conn
*/
protected function _callPostResponsePlugins($conn)
{
foreach ($this->_plugins as $plugin) /* @var $plugin Aspamia_Http_Server_Plugin_Abstract */
$plugin->postResponse($conn);
}
}
125 changes: 125 additions & 0 deletions library/Aspamia/Http/Server/Plugin/Abstract.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<?php

/**
* Base server plugin class
*
* This class offers various hooks which are called by the server throughout
* the different stages of the server's lifecycle and for each request. It
* should be inherited by different plugins which may implement these
* functions to suite a specific need.
*
*/

abstract class Aspamia_Http_Server_Plugin_Abstract
{
/**
* Configuration data
*
* @var array
*/
protected $_config = array();

/**
* Server object
*
* @var Aspamia_Http_Server
*/
protected $_server = null;

/**
* Create a new plugin object
*
* @param Zend_Config | array $config
*/
public function __construct($config = array())
{
$this->setConfig($config);
}

/**
* Set the configuration for this plugin
*
* @param Zend_Config | array $config
*/
public function setConfig($config)
{
if ($config instanceof Zend_Config) {
$config = $config->toArray();
}

if (! is_array($config)) {
require_once 'Aspamia/Http/Server/Plugin/Exception.php';
throw new Aspamia_Http_Server_Plugin_Exception("\$config is expected to be an array or a Zend_Config object, got " . gettype($config));
}

foreach($config as $k => $v) {
$this->_config[$k] = $v;
}
}

/**
* Set the related server object. Called when registering a plugin
*
* @param Aspamia_Http_Server $server
*/
public function setServer(Aspamia_Http_Server $server)
{
$this->_server = $server;
}

/**
* Called just after server startup
*
*/
public function serverStartup()
{ }

/**
* Called just before server shutdown
*
*/
public function serverShutdown()
{ }

/**
* Called before each request. The open connection is passed in
*
* @param resource $connection
*/
public function preRequest($connection)
{ }

/**
* Called after the request is recieved. The request object is passed in
*
* @param Aspamia_Http_Request $request
*/
public function postRequest(Aspamia_Http_Request $request)
{ }

/**
* Called before the response is sent. The response object is passed in
*
* @param Aspamia_Http_Response $response
*/
public function preResponse(Aspamia_Http_Response $response)
{ }

/**
* Called after the response is sent. The open connection is passed in
*
* @param resource $connection
*/
public function postResponse($connection)
{ }

/**
* Called in case of an error when handling the request.
*
* The caught exception is passed in
*
* @param Exception $ex
*/
public function onError(Exception $ex)
{ }
}
8 changes: 8 additions & 0 deletions library/Aspamia/Http/Server/Plugin/Exception.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

require_once 'Aspamia/Http/Server/Exception.php';

class Aspamia_Http_Server_Plugin_Exception extends Aspamia_Http_Server_Exception
{

}
Loading

0 comments on commit f8e2990

Please sign in to comment.