Yar no depende de un esquema ni de un fichero IDL: todo se intercambia por la red como bytes sin formato. Cualquier lenguaje capaz de leer y escribir bytes puede comunicarse con un servicio Yar, sin instalar ningún framework —basta con construir una cabecera binaria de tamaño fijo y un cuerpo de petición serializado, enviarlos al URI del servicio y analizar la respuesta.
Un mensaje consta de una cabecera de tamaño fijo de 82 bytes seguida de un cuerpo. La cabecera tiene exactamente la disposición de la siguiente estructura C, empaquetada sin relleno, y se escribe en la red campo a campo en el orden de declaración:
typedef struct _yar_header {
uint32_t id; /* identificador de la transacción */
uint16_t version; /* versión del protocolo, actualmente siempre 0 */
uint32_t magic_num; /* debe ser 0x80DFEC60 */
uint32_t reserved;
unsigned char provider[32]; /* de quién procede la petición (autenticación) */
unsigned char token[32]; /* token de la petición (autenticación) */
uint32_t body_len; /* longitud del cuerpo completo, incluido
el identificador del empaquetador */
} __attribute__ ((packed)) yar_header_t;
Los campos id, magic_num,
reserved y body_len se almacenan
en el orden de bytes de red (big-endian); los campos restantes son
bytes sin formato.
El cuerpo comienza con un identificador de empaquetador de 8 bytes
—PHP, JSON o
MSGPACK, rellenado con ceros— que indica al receptor
cómo se ha codificado el resto, seguido del propio contenido
serializado.
El cuerpo de la petición se decodifica en un array con las claves
i (el identificador de la transacción),
m (el método invocado) y p (la
lista de parámetros).
El cuerpo de la respuesta se decodifica en un array con las claves
i (el identificador de la transacción),
s (el estado, uno de los códigos
YAR_ERR_*), r (el valor
devuelto), o (la salida producida por el método
del servicio) y e (el error o la excepción, cuando
la llamada ha fallado).
Sobre HTTP, el mensaje se envía como cuerpo de una petición POST, y la respuesta llega como cuerpo de la contestación; sobre TCP o sockets Unix se escribe directamente en el flujo.
Ejemplo #1 Llamada a un servicio Yar sin la extensión
El siguiente script autónomo construye una petición Yar válida para el
empaquetador php únicamente con sockets estándar, la
envía al URI de un servicio y muestra la respuesta decodificada. Al
ejecutarlo contra el servicio Operator de los
ejemplos, muestra
int(3).
<?php
$uri = "http://api.example.com/operator.php";
/* 1. el cuerpo: identificador del empaquetador + petición serializada */
$serialized = serialize(array("i" => 1, "m" => "add", "p" => array(1, 2)));
$body = str_pad("PHP", 8, "\0") . $serialized;
/* 2. la cabecera: 82 bytes, enteros multibyte en orden de bytes de red */
$header = pack("N", 1) /* id */
. pack("v", 0) /* versión */
. pack("N", 0x80DFEC60) /* número mágico */
. pack("N", 0) /* reservado */
. str_pad("", 32, "\0") /* proveedor */
. str_pad("", 32, "\0") /* token */
. pack("N", strlen($body)); /* longitud del cuerpo */
/* 3. se envía como cuerpo de una petición POST */
$stream = stream_context_create(array("http" => array(
"method" => "POST",
"header" => "Content-Type: application/octet-stream\r\n",
"content" => $header . $body,
)));
$reply = file_get_contents($uri, false, $stream);
/* 4. se analiza la respuesta: cabecera de 82 bytes, luego el cuerpo */
$response = unserialize(substr($reply, 82 + 8));
var_dump($response["r"]);
?>
En el directorio tools/ del
» repositorio de código
fuente de Yar se encuentra una implementación de cliente más
completa en PHP puro, que además decodifica la cabecera de la respuesta
y admite llamadas concurrentes.