<?php
include_once $_SERVER['DOCUMENT_ROOT'] . '/include/shared-manual.inc';
$TOC = array();
$TOC_DEPRECATED = array();
$PARENTS = array();
include_once dirname(__FILE__) ."/toc/book.yar.inc";
$setup = array (
  'home' => 
  array (
    0 => 'index.php',
    1 => 'PHP Manual',
  ),
  'head' => 
  array (
    0 => 'UTF-8',
    1 => 'fr',
  ),
  'this' => 
  array (
    0 => 'yar.protocol.php',
    1 => 'Le protocole Yar',
    2 => 'Le protocole Yar',
  ),
  'up' => 
  array (
    0 => 'book.yar.php',
    1 => 'Yar',
  ),
  'prev' => 
  array (
    0 => 'book.yar.php',
    1 => 'Yar',
  ),
  'next' => 
  array (
    0 => 'yar.setup.php',
    1 => 'Installation/Configuration',
  ),
  'alternatives' => 
  array (
  ),
  'source' => 
  array (
    'lang' => 'fr',
    'path' => 'reference/yar/protocol.xml',
  ),
  'history' => 
  array (
  ),
);
$setup["toc"] = $TOC;
$setup["toc_deprecated"] = $TOC_DEPRECATED;
$setup["parents"] = $PARENTS;
manual_setup($setup);

contributors($setup);

?>
<div id="yar.protocol" class="chapter">
 <h1 class="title">Le protocole Yar</h1>

 <p class="simpara">
  Yar ne s&#039;appuie pas sur un schéma ou un fichier IDL : tout est échangé
  sur le réseau sous forme d&#039;octets bruts. N&#039;importe quel langage capable
  de lire et d&#039;écrire des octets peut communiquer avec un service Yar, sans
  installer aucun framework — il suffit de construire un en-tête binaire de
  taille fixe et un corps de requête sérialisé, de les envoyer à l&#039;URI du
  service, et d&#039;analyser la réponse.
 </p>
 <p class="simpara">
  Un message se compose d&#039;un en-tête de taille fixe de 82 octets suivi d&#039;un
  corps. L&#039;en-tête est disposé exactement comme la structure C suivante,
  compactée sans remplissage, et est écrit sur le réseau champ après champ
  dans l&#039;ordre de déclaration :
 </p>
 <div class="example-contents">
<div class="ccode"><pre class="ccode">typedef struct _yar_header {
    uint32_t       id;            /* identifiant de transaction */
    uint16_t       version;       /* version du protocole, toujours 0 actuellement */
    uint32_t       magic_num;     /* doit valoir 0x80DFEC60 */
    uint32_t       reserved;
    unsigned char  provider[32];  /* émetteur de la requête (authentification) */
    unsigned char  token[32];     /* jeton de la requête (authentification) */
    uint32_t       body_len;      /* longueur du corps entier, y compris
                                     l&#039;identifiant d&#039;empaqueteur */
} __attribute__ ((packed)) yar_header_t;</pre>
</div>
 </div>

 <p class="simpara">
  Les champs <code class="literal">id</code>, <code class="literal">magic_num</code>,
  <code class="literal">reserved</code> et <code class="literal">body_len</code> sont stockés
  dans l&#039;ordre réseau (gros-boutiste) ; les champs restants sont des octets
  bruts.
 </p>
 <p class="simpara">
  Le corps commence par un identifiant d&#039;empaqueteur de 8 octets —
  <code class="literal">PHP</code>, <code class="literal">JSON</code> ou
  <code class="literal">MSGPACK</code>, complété par des zéros — indiquant au
  destinataire comment le reste a été encodé, suivi du contenu sérialisé
  lui-même.
 </p>
 <ul class="itemizedlist">
  <li class="listitem">
   <p class="simpara">
    Le corps de requête se décode en un tableau avec les clés
    <code class="literal">i</code> (l&#039;identifiant de transaction),
    <code class="literal">m</code> (la méthode appelée) et <code class="literal">p</code>
    (la liste des paramètres).
   </p>
  </li>
  <li class="listitem">
   <p class="simpara">
    Le corps de réponse se décode en un tableau avec les clés
    <code class="literal">i</code> (l&#039;identifiant de transaction),
    <code class="literal">s</code> (le statut, l&#039;un des codes
    <code class="literal">YAR_ERR_*</code>), <code class="literal">r</code> (la valeur de
    retour), <code class="literal">o</code> (toute sortie produite par la méthode
    du service) et <code class="literal">e</code> (l&#039;erreur ou l&#039;exception, quand
    l&#039;appel a échoué).
   </p>
  </li>
 </ul>
 <p class="simpara">
  En HTTP le message est envoyé comme corps d&#039;une requête POST, la réponse
  arrivant comme corps de la réponse ; en TCP ou socket Unix il est écrit
  directement sur le flux.
 </p>
 <div class="example" id="example-1">
  <p><strong>Exemple #1 Appel d&#039;un service Yar sans l&#039;extension</strong></p>
  <div class="example-contents"><p>
   Le script autonome suivant construit une requête Yar valide pour
   l&#039;empaqueteur <code class="literal">php</code> avec uniquement des sockets
   standard, l&#039;envoie à un URI de service et affiche la réponse décodée.
   Exécuté contre le service <span class="classname"><strong class="classname">Operator</strong></span> des
   <a href="yar.examples.php" class="link">exemples</a>, il affiche
   <code class="literal">int(3)</code>.
  </p></div>
  <div class="example-contents">
<div class="phpcode"><pre><code style="color: #000000"><span style="color: #0000BB">&lt;?php

$uri </span><span style="color: #007700">= </span><span style="color: #DD0000">"http://api.example.com/operator.php"</span><span style="color: #007700">;

</span><span style="color: #FF8000">/* 1. le corps : identifiant d'empaqueteur + requête sérialisée */
</span><span style="color: #0000BB">$serialized </span><span style="color: #007700">= </span><span style="color: #0000BB">serialize</span><span style="color: #007700">(array(</span><span style="color: #DD0000">"i" </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">1</span><span style="color: #007700">, </span><span style="color: #DD0000">"m" </span><span style="color: #007700">=&gt; </span><span style="color: #DD0000">"add"</span><span style="color: #007700">, </span><span style="color: #DD0000">"p" </span><span style="color: #007700">=&gt; array(</span><span style="color: #0000BB">1</span><span style="color: #007700">, </span><span style="color: #0000BB">2</span><span style="color: #007700">)));
</span><span style="color: #0000BB">$body </span><span style="color: #007700">= </span><span style="color: #0000BB">str_pad</span><span style="color: #007700">(</span><span style="color: #DD0000">"PHP"</span><span style="color: #007700">, </span><span style="color: #0000BB">8</span><span style="color: #007700">, </span><span style="color: #DD0000">"\0"</span><span style="color: #007700">) . </span><span style="color: #0000BB">$serialized</span><span style="color: #007700">;

</span><span style="color: #FF8000">/* 2. l'en-tête : 82 octets, entiers multi-octets dans l'ordre réseau */
</span><span style="color: #0000BB">$header </span><span style="color: #007700">= </span><span style="color: #0000BB">pack</span><span style="color: #007700">(</span><span style="color: #DD0000">"N"</span><span style="color: #007700">, </span><span style="color: #0000BB">1</span><span style="color: #007700">)                    </span><span style="color: #FF8000">/* id */
        </span><span style="color: #007700">. </span><span style="color: #0000BB">pack</span><span style="color: #007700">(</span><span style="color: #DD0000">"v"</span><span style="color: #007700">, </span><span style="color: #0000BB">0</span><span style="color: #007700">)                    </span><span style="color: #FF8000">/* version */
        </span><span style="color: #007700">. </span><span style="color: #0000BB">pack</span><span style="color: #007700">(</span><span style="color: #DD0000">"N"</span><span style="color: #007700">, </span><span style="color: #0000BB">0x80DFEC60</span><span style="color: #007700">)           </span><span style="color: #FF8000">/* nombre magique */
        </span><span style="color: #007700">. </span><span style="color: #0000BB">pack</span><span style="color: #007700">(</span><span style="color: #DD0000">"N"</span><span style="color: #007700">, </span><span style="color: #0000BB">0</span><span style="color: #007700">)                    </span><span style="color: #FF8000">/* reserved */
        </span><span style="color: #007700">. </span><span style="color: #0000BB">str_pad</span><span style="color: #007700">(</span><span style="color: #DD0000">""</span><span style="color: #007700">, </span><span style="color: #0000BB">32</span><span style="color: #007700">, </span><span style="color: #DD0000">"\0"</span><span style="color: #007700">)           </span><span style="color: #FF8000">/* provider */
        </span><span style="color: #007700">. </span><span style="color: #0000BB">str_pad</span><span style="color: #007700">(</span><span style="color: #DD0000">""</span><span style="color: #007700">, </span><span style="color: #0000BB">32</span><span style="color: #007700">, </span><span style="color: #DD0000">"\0"</span><span style="color: #007700">)           </span><span style="color: #FF8000">/* token */
        </span><span style="color: #007700">. </span><span style="color: #0000BB">pack</span><span style="color: #007700">(</span><span style="color: #DD0000">"N"</span><span style="color: #007700">, </span><span style="color: #0000BB">strlen</span><span style="color: #007700">(</span><span style="color: #0000BB">$body</span><span style="color: #007700">));       </span><span style="color: #FF8000">/* longueur du corps */

/* 3. l'envoyer comme corps d'une requête POST */
</span><span style="color: #0000BB">$stream </span><span style="color: #007700">= </span><span style="color: #0000BB">stream_context_create</span><span style="color: #007700">(array(</span><span style="color: #DD0000">"http" </span><span style="color: #007700">=&gt; array(
    </span><span style="color: #DD0000">"method"  </span><span style="color: #007700">=&gt; </span><span style="color: #DD0000">"POST"</span><span style="color: #007700">,
    </span><span style="color: #DD0000">"header"  </span><span style="color: #007700">=&gt; </span><span style="color: #DD0000">"Content-Type: application/octet-stream\r\n"</span><span style="color: #007700">,
    </span><span style="color: #DD0000">"content" </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">$header </span><span style="color: #007700">. </span><span style="color: #0000BB">$body</span><span style="color: #007700">,
)));
</span><span style="color: #0000BB">$reply </span><span style="color: #007700">= </span><span style="color: #0000BB">file_get_contents</span><span style="color: #007700">(</span><span style="color: #0000BB">$uri</span><span style="color: #007700">, </span><span style="color: #0000BB">false</span><span style="color: #007700">, </span><span style="color: #0000BB">$stream</span><span style="color: #007700">);

</span><span style="color: #FF8000">/* 4. analyser la réponse : en-tête de 82 octets, puis le corps */
</span><span style="color: #0000BB">$response </span><span style="color: #007700">= </span><span style="color: #0000BB">unserialize</span><span style="color: #007700">(</span><span style="color: #0000BB">substr</span><span style="color: #007700">(</span><span style="color: #0000BB">$reply</span><span style="color: #007700">, </span><span style="color: #0000BB">82 </span><span style="color: #007700">+ </span><span style="color: #0000BB">8</span><span style="color: #007700">));
</span><span style="color: #0000BB">var_dump</span><span style="color: #007700">(</span><span style="color: #0000BB">$response</span><span style="color: #007700">[</span><span style="color: #DD0000">"r"</span><span style="color: #007700">]);
</span><span style="color: #0000BB">?&gt;</span></code></pre></div>
  </div>

 </div>
 <p class="simpara">
  Une implémentation client plus complète en PHP pur, qui décode également
  l&#039;en-tête de réponse et supporte les appels concurrents, se trouve dans
  le répertoire <code class="literal">tools/</code> du
  <a href="https://github.com/laruence/yar" class="link external">&raquo;&nbsp;dépôt source de Yar</a>.
 </p>
</div>
<?php manual_footer($setup); ?>