27 août 2010

REST_Client et REST_Puller à la sauce Swift

Dans mes précédents billets, j'ai présenté REST_Client et REST_Puller. Ces 2 classes PHP ont été écrites rapidement à plusieurs mois d'intervalle dans des contextes différents puis rassemblées dans un unique package PEAR. La conséquence est un manque flagrant de cohérence. Et bien c'est maintenant terminé !

Refactoring

Par la volonté et l'aide de kerphi le package REST_Client a subit une grosse refactorisation. Nous avons soigné la POO en appliquant quelques grands motifs de conception et une interface objet à la mode. Un style de programmation que l'on trouve par exemple dans la librairie Swift. Maintenant le package s'utilise très simplement avec 2 classes REST_Client et REST_EasyClient.

REST_EasyClient

Comme son nom l'indique, cette classe est simple et rapide à utiliser. Elle est idéale si l'on souhaite récupérer le résultat d'une ou plusieurs requêtes HTTP envoyées à un même serveur.

Exemples


echo REST_EasyClient::newInstance('fr.php.net')->get('/curl')->content;

// La même chose avec un Proxy
echo REST_EasyClient::newInstance('fr.php.net')
       ->setHttpProxy('proxy.exemple.com:8080')
       ->get('/curl')
       ->content;

// la même chose façon vieille école  ;-)

$client = new REST_EasyClient('fr.php.net');
$client->setHttpProxy('proxy.exemple.com:8080');
$response = $client->get('/curl');
echo $response->content;

REST_Client

Contrairement à la classe précédente, REST_Client permet de maîtriser finement la construction de la requête HTTP et la façon de l'envoyer. REST_Client permet donc d'envoyer plusieurs requêtes plus ou moins différentes de manière synchrones ou asynchrones, le tout avec une interface d'utilisation identique.

Requêtes synchrones

Permet le lancement de plusieurs requêtes séquentiellement.


$r = REST_Request::newInstance()
     ->setProtocol('http')
     ->setHost('fr.php.net')
     ->setPort(80)
     ->setMethod('GET')
     ->setUrl('/curl');

$c = REST_Client::factory('sync', array('verbose' => false));
$id = $c->fire($r);
$response = $c->fetch();

echo $response->id . PHP_EOL;
echo $response->code . PHP_EOL;
echo $response->content . PHP_EOL;

$r->setUrl('/dom');

$id = $c->fire($r);
$response = $c->fetch();

echo $response->id . PHP_EOL;
echo $response->code . PHP_EOL;
echo $response->content . PHP_EOL;

Requêtes asynchrones

Permet le lancement de plusieurs requêtes en parallèle et de manière asynchrone (Les résultats arrivent dans un ordre différent de l'ordre de lancement). Cette classe remplace feu REST_Puller.


$r = REST_Request::newInstance()
     ->setProtocol('http')
     ->setHost('fr.php.net')
     ->setHttpProxy('proxy.example.com');


$c = REST_Client::factory('sync', array(
    'verbose' => false,
    'queue_size' => 2,
));

$urls = array('/dom','/curl','/strings', '/pcre', '/xml', '/ftp', '/sockets');

foreach($urls as $i => $url) {
  $id = $c->fire($r->get($url));
  if ($i > $c->getOption('queue_size')) {
     $response = $p->fetch();
     var_dump($response);
  }
}

while($response = $p->fetch()) {
    var_dump($response);
}

Téléchargement et code source

Le code source est disponible sur GitHub : http://github.com/touv/rest_client

Ou, on peut directement l'installer avec PEAR en s'abonnant au Channel Respear :


% pear channel-discover pear.respear.net
% pear install respear/REST_Client

20 août 2010

REST_Puller, mitraillette HTTP en PHP

Dans un précédent billet, j'ai présenté le package REST_Client. Comme je l'avais laissé entendre, l'intérêt principal de ce package n'est pas de fournir une interface objet au module cURL. La fonctionnalité principale, celle que l'on trouve difficilement sur le Net, est de fournir une classe capable de lancer des centaines de milliers de requêtes HTTP : REST_Puller

Explications

Si vous connaissez le module cURL, vous savez qu'il propose une série de fonction nommé curl_multi_*. Ces fonctions permettent de lancer en parallèle plusieurs requêtes HTTP. Mais plusieurs ne veut pas dire des centaines de millier, et c'est là que la classe REST_Puller devient intéressante. Avec elle on va pouvoir charger sans interruption plusieurs milliers de requêtes dans une file d'attente qui sera vider progressivement par paquet de requêtes asynchrones. Par vider, j'entends lancement de la requête et récupération de son résultat, le tout s'effectuant en parallèle.

Démonstration

Voici un petit bout de code qui lance 50 000 requêtes avec au maximum 150 clients en parallèle.

  $p = new REST_Puller(array(
            // Pour voir le déroulement des opérations
            'debug' => true,  
   ));

   $requests = 50000; // Nombre de requêtes à tirer
   $clients  = 150;   // Nombre maximum de client à utiliser en parallèle
   $p->setOption('queue_size', $clients);

   $r = new REST_Request('localhost', 8000);

   // On charge le tireur 
   for($i = 0; $i < $requests; $i++) {

      // On tire !!!
      $id = $p->fire($r->get('/'));

      // On peut déjà récupérer les requêtes exécutées
      if ($i > $clients) 
          if (list($k, $h) = $p->fetch()) {
              echo "Request #$k ";
              echo $h->code == 200 ? 'Completed' : 'Failed';
              echo PHP_EOL;
          }
   }

   // On boucle tant que toutes les requêtes ne sont pas terminées
   while(list(, $h) = $p->fetch()) {
       echo 'Request #'.$k;
       echo $h->code == 200 ? 'Completed' : 'Failed';
       echo PHP_EOL;
   }

   // On affiche quelques statistiques
   echo $p->getInfo('requests').PHP_EOL;
   echo $p->getInfo('requests_avg').PHP_EOL;
   echo $p->getInfo('requests_sec').PHP_EOL;
   echo $p->getInfo('fetchs_hit').PHP_EOL;
   echo $p->getInfo('pulls_hit').PHP_EOL;
   echo $p->getInfo('loads_hit').PHP_EOL;
   echo $p->getInfo('time').PHP_EOL; 

Téléchargement et code source

Le code source est disponible sur GitHub : http://github.com/touv/rest_client

Ou, on peut directement l'installer avec PEAR en s'abonnant au Channel Respear :


% pear channel-discover pear.respear.net
% pear install respear/REST_Client

18 août 2010

REST_Client, pour surfer la vague

Comme le titre le laisse supposer ;-), REST_Client est un package PHP compatible PEAR qui fournit quelques classes pour interroger un serveur REST.
C'est un client HTTP, et quand on parle client HTTP en PHP, on pense directement au module cURL.
Et bien cet ensemble de classe PHP propose une interface objet orientée REST pour cURL. Cela ne constitue pas l'intérêt principal de ce package. Mais en attendant de découvrir la "killer feature" dans un prochain billet, voyons comme utiliser la classe REST_Client.

Démonstration

<?php

require_once "REST/Client.php';

$rs = new REST_Client('rest.server.com', 8080);

// GET Method
$o = $rs->get('/path/to/get')

// check network error
if ($o->isError()) die($o->error);

// check http response code
if ($o->code == 404) die('Oups, where is my page ?');

// display the content of the page
echo $o->content;

// DELETE Method
$o = $rs->delete('/path/to/delete');

// POST Method
$data = http_build_query(array('key' => 'value'));
$o = $rs->post('/path/to/post', $data)

// PUT Method
$data = '<xml>some data</xml>';
$o = $rs->put('/path/to/put', $data);

// Retrieve & print HTTP headers
echo $o->headers['x-powered-by'];
echo $o->headers['location'];

?>

Téléchargement et code source

Le code source est disponible sur GitHub : http://github.com/touv/rest_client

Ou, on peut directement l'installer avec PEAR en s'abonnant au Channel Respear :


% pear channel-discover pear.respear.net
% pear install respear/REST_Client