Difference between revisions of "Category:LSL XML-RPC/fr"

From Second Life Wiki
Jump to navigation Jump to search
m
(categorized category, syntax highlighting)
 
Line 1: Line 1:
{{Multi-lang}}
{{LSL Header/fr|ml=*}}{{LSLC/fr|}}{{LSLC/fr|Communications}}
[http://en.wikipedia.org/wiki/XMLRPC XML-RPC] est un standard pour envoyer des "Procedure Calls" (Ex: function calls) à des systèmes distants. XML-RPC envoit des données XML en utilisant le protocol HTTP, que le système distant analyse ensuite.
[http://en.wikipedia.org/wiki/XMLRPC XML-RPC] est un standard pour envoyer des "Procedure Calls" (Ex: function calls) à des systèmes distants. XML-RPC envoit des données XML en utilisant le protocol HTTP, que le système distant analyse ensuite.


Line 26: Line 26:
==Exemples==
==Exemples==


=php=
=== php ===
Pour initialiser un XMLRPC depuis un serveur externe, vous allez avoir besoin d'une application web.
Pour initialiser un XMLRPC depuis un serveur externe, vous allez avoir besoin d'une application web.
Un langage pour créer ce genre d'application est le PHP.
Un langage pour créer ce genre d'application est le PHP.
Voici un exemple qui explique comment envoyer un message XMLRPC à votre script LSL depuis un serveur web avec PHP.
Voici un exemple qui explique comment envoyer un message XMLRPC à votre script LSL depuis un serveur web avec PHP.
<code>&lt;?php
<php><?php
echo '&lt;pre&gt;';
echo '<pre>';
$channel = ""; //Entrez le channel que vous utiliser (key)
$channel = ""; //Entrez le channel que vous utiliser (key)
$xmldata = "&lt;?xml version=\"1.0\"?&gt;&lt;methodCall&gt;&lt;methodName&gt;llRemoteData&lt;/methodName&gt;&lt;params&gt;&lt;param&gt;&lt;value&gt;&lt;struct&gt;&lt;member&gt;&lt;name&gt;Channel&lt;/name&gt;&lt;value&gt;&lt;string&gt;".$channel."&lt;/string&gt;&lt;/value&gt;&lt;/member&gt;&lt;member&gt;&lt;name&gt;IntValue&lt;/name&gt;&lt;value&gt;&lt;int&gt;11261979&lt;/int&gt;&lt;/value&gt;&lt;/member&gt;&lt;member&gt;&lt;name&gt;StringValue&lt;/name&gt;&lt;value&gt;&lt;string&gt;happy birthday&lt;/string&gt;&lt;/value&gt;&lt;/member&gt;&lt;/struct&gt;&lt;/value&gt;&lt;/param&gt;&lt;/params&gt;&lt;/methodCall&gt;";
$xmldata = "<?xml version=\"1.0\"?><methodCall><methodName>llRemoteData</methodName><params><param><value><struct><member><name>Channel</name><value><string>".$channel."</string></value></member><member><name>IntValue</name><value><int>11261979</int></value></member><member><name>StringValue</name><value><string>happy birthday</string></value></member></struct></value></param></params></methodCall>";
echo sendToHost("xmlrpc.secondlife.com", "POST", "/cgi-bin/xmlrpc.cgi", $xmldata);
echo sendToHost("xmlrpc.secondlife.com", "POST", "/cgi-bin/xmlrpc.cgi", $xmldata);
echo '&lt;/pre&gt;';
echo '</pre>';
function sendToHost($host,$method,$path,$data,$useragent=0)
function sendToHost($host,$method,$path,$data,$useragent=0)
{  
{  
$buf="";
$buf="";
// Supply a default method of GET if the one passed was empty  
// Supply a default method of GET if the one passed was empty  
if (empty($method))  
if (empty($method))  
$method = 'GET';  
$method = 'GET';  
$method = strtoupper($method);  
$method = strtoupper($method);  
$fp = fsockopen($host, 80, $errno, $errstr, 30);
$fp = fsockopen($host, 80, $errno, $errstr, 30);
if( !$fp )
if( !$fp )
{
{
$buf = "$errstr ($errno)&lt;br /&gt;\n";
$buf = "$errstr ($errno)<br />\n";
}else
}else
{
{
if ($method == 'GET')  
if ($method == 'GET')  
$path .= '?' . $data;  
$path .= '?' . $data;  
fputs($fp, "$method $path HTTP/1.1\r\n");  
fputs($fp, "$method $path HTTP/1.1\r\n");  
fputs($fp, "Host: $host\r\n");  
fputs($fp, "Host: $host\r\n");  
fputs($fp, "Content-type: text/xml\r\n");  
fputs($fp, "Content-type: text/xml\r\n");  
fputs($fp, "Content-length: " . strlen($data) . "\r\n");  
fputs($fp, "Content-length: " . strlen($data) . "\r\n");  
if ($useragent)  
if ($useragent)  
fputs($fp, "User-Agent: MSIE\r\n");  
fputs($fp, "User-Agent: MSIE\r\n");  
fputs($fp, "Connection: close\r\n\r\n");  
fputs($fp, "Connection: close\r\n\r\n");  
if ($method == 'POST')  
if ($method == 'POST')  
fputs($fp, $data);  
fputs($fp, $data);  
while (!feof($fp))  
while (!feof($fp))  
$buf .= fgets($fp,128);  
$buf .= fgets($fp,128);  
fclose($fp);  
fclose($fp);  
}
}
return $buf;  
return $buf;  
}  
}  
?&gt;</code>
?></php>


=perl=
=perl=
Line 75: Line 75:
Le code perl envoit un message contenant le string "Message to pass" et le nombre "2007". Le code LSL correspondant répond en envoyant le string "I got it" et le nombre "2008".
Le code perl envoit un message contenant le string "Message to pass" et le nombre "2007". Le code LSL correspondant répond en envoyant le string "I got it" et le nombre "2008".


<pre>
<perl>#!/usr/bin/perl
&#35;!/usr/bin/perl
#  
&#35;


use RPC::XML;
use RPC::XML;
Line 89: Line 88:
my $req = RPC::XML::request->new(
my $req = RPC::XML::request->new(
         "llRemoteData",
         "llRemoteData",
         &#123;'Channel' => RPC::XML::string->new("UUID for the open channel from the object GOES HERE!"),
         {'Channel' => RPC::XML::string->new("UUID for the open channel from the object GOES HERE!"),
         'IntValue' => RPC::XML::int->new(2007),
         'IntValue' => RPC::XML::int->new(2007),
         'StringValue' => RPC::XML::string->new("message to pass")&#125;);
         'StringValue' => RPC::XML::string->new("message to pass")});


&#35; Print out the message to send
#  Print out the message to send
print "ref(req): ",ref($req),"\n";
print "ref(req): ",ref($req),"\n";
$xml = $req->as_string();
$xml = $req->as_string();
Line 100: Line 99:
$res = $P->parse($xml);
$res = $P->parse($xml);
print ref($res),"\n";
print ref($res),"\n";
if (ref($res)) &#123;
if (ref($res)) {
     %h = %{$res->args->[0]->value};
     %h = %{$res->args->[0]->value};
     foreach $lupe (keys %h) &#123;
     foreach $lupe (keys %h) {
       print "$lupe: $h{$lupe}\n";
       print "$lupe: $h{$lupe}\n";
     &#125;
     }
&#125;
}


&#35; Submit the request to send the information above.
#  Submit the request to send the information above.
my $resp = $cli->send_request($req);
my $resp = $cli->send_request($req);




&#35; Print out the response
#  Print out the response
print "\n\n\nResponse\n";
print "\n\n\nResponse\n";
print "ref(resp): ",ref($resp),"\n";
print "ref(resp): ",ref($resp),"\n";
Line 119: Line 118:
$res = $P->parse($xml);
$res = $P->parse($xml);
print ref($res),"\n";
print ref($res),"\n";
if (ref($res)) &#123;
if (ref($res)) {
     %h = %{$res->value};
     %h = %{$res->value};
     foreach $lupe (keys %h) &#123;
     foreach $lupe (keys %h) {
       $val =  $h{$lupe};
       $val =  $h{$lupe};
       print "$lupe: $val\n";
       print "$lupe: $val\n";
     &#125;
     }
&#125;
}</perl>
 
 
</pre>


Code LSL correspondant:
Code LSL correspondant:


<pre>
<lsl>key remoteChannel;
key remoteChannel;
init() {
init() &#123;
     llOpenRemoteDataChannel(); // create an XML-RPC channel
     llOpenRemoteDataChannel(); // create an XML-RPC channel
     llOwnerSay("My key is " + (string)llGetKey());
     llOwnerSay("My key is " + (string)llGetKey());
&#125;
}


default &#123;
default {
     state_entry() &#123;
     state_entry() {
         init();
         init();
     &#125;
     }
      
      
     state_exit() &#123;
     state_exit() {
         return;
         return;
     &#125;
     }
                                  
                                  
     on_rez(integer param) &#123;
     on_rez(integer param) {
         llResetScript();         
         llResetScript();         
     &#125;
     }
                                  
                                  
     remote_data(integer type, key channel, key message_id, string sender, integer ival, string sval) &#123;
     remote_data(integer type, key channel, key message_id, string sender, integer ival, string sval) {
         if (type == REMOTE_DATA_CHANNEL) &#123; // channel created
         if (type == REMOTE_DATA_CHANNEL) { // channel created
             llSay(DEBUG_CHANNEL,"Channel opened for REMOTE_DATA_CHANNEL" +  
             llSay(DEBUG_CHANNEL,"Channel opened for REMOTE_DATA_CHANNEL" +  
                 (string)channel + " " + (string)message_id + " " + (string)sender + " " +                         
                 (string)channel + " " + (string)message_id + " " + (string)sender + " " +                         
Line 160: Line 155:
             llOwnerSay("Ready to receive requests on channel \"" + (string)channel + "\"");                         
             llOwnerSay("Ready to receive requests on channel \"" + (string)channel + "\"");                         
             state receiving; // start handling requests
             state receiving; // start handling requests
         &#125; else &#123;
         } else {
             llSay(DEBUG_CHANNEL,"Unexpected event type");  
             llSay(DEBUG_CHANNEL,"Unexpected event type");  
         &#125;                      
         }                      
     &#125;                  
     }                  
&#125;                      
}                      
                                  
                                  


state receiving &#123;
state receiving {


     state_entry() &#123;
     state_entry() {
         llOwnerSay("Ready to receive information from outside SL");
         llOwnerSay("Ready to receive information from outside SL");
     &#125;  
     }  
      
      
     state_exit() &#123;
     state_exit() {
         llOwnerSay("No longer receiving information from outside SL.");
         llOwnerSay("No longer receiving information from outside SL.");
         llCloseRemoteDataChannel(remoteChannel);
         llCloseRemoteDataChannel(remoteChannel);
     &#125;
     }
      
      
     on_rez(integer param) &#123;
     on_rez(integer param) {
         llResetScript();
         llResetScript();
     &#125;
     }
      
      
     remote_data(integer type, key channel, key message_id, string sender, integer ival, string sval) &#123;
     remote_data(integer type, key channel, key message_id, string sender, integer ival, string sval) {
         if (type == REMOTE_DATA_REQUEST) &#123; // handle requests sent to us
         if (type == REMOTE_DATA_REQUEST) { // handle requests sent to us
             llSay(DEBUG_CHANNEL,"Request received for REMOTE_DATA_REQUEST " + (string)channel + " " +
             llSay(DEBUG_CHANNEL,"Request received for REMOTE_DATA_REQUEST " + (string)channel + " " +
                 (string)message_id + " " + (string)sender + " " + (string)ival + " " + (string)sval);
                 (string)message_id + " " + (string)sender + " " + (string)ival + " " + (string)sval);
Line 190: Line 185:
                         " at position " + (string)llGetPos() + "\n" +
                         " at position " + (string)llGetPos() + "\n" +
                       "The string was " +  sval + "\nThe number was " + (string)ival + ".");
                       "The string was " +  sval + "\nThe number was " + (string)ival + ".");
         &#125;
         }
     &#125;
     }
      
      
&#125;
}
 
</lsl>
</pre>

Latest revision as of 05:47, 20 April 2009

XML-RPC est un standard pour envoyer des "Procedure Calls" (Ex: function calls) à des systèmes distants. XML-RPC envoit des données XML en utilisant le protocol HTTP, que le système distant analyse ensuite.

Le script LSL reçoit des requêtes XML-RPC et les redirigent vers les prims concernés. Il ne peut peut-être pas établir de connection, mais il peut répondre et garder une communication à 2 avec le serveur. Ces réponses XML-RPC semblent être capable de transporter le plus de données hors de Second Life (vs. les requêtes Email et HTTP).

http://rpgstats.com/wiki/index.php?title=XMLRPC

A cause de problèmes de copyright, l'article ci-dessus ne peux pas être recopié sur ce wiki, mais vous pouvez le visiter librement.

NOTES IMPORTANTES D'IMPLÉMENTATION:

The current implementation of XML-RPC only allows ONE request to be queued on the front-end server (xmlrpc.secondlife.com) at a time. Any additional requests to the same data channel overwrite any pending one. This has serious ramifications for the design of XML-RPC communications where the in-world object could receive requests faster than it can respond to them. In addition, the 3-second delay in llRemoteDataReply exacerbates this problem even more.

The observed issue is this: if you send multiple quick requests to an in-world object via XML-RPC, one which is scripted to perform some processing and then return a response (via llRemoteDataReply), there is a potential for earlier requests to get lost on the front end server (they still should generate remote_data events, though), and have the response meant for an earlier request end up being passed back to a later one, while the earlier requests will time out back at your external application.

As a result, if you intend to do any serious work with XML-RPC, you will have to design your external client application to manually serialize all requests to each individual RPC channel. That means you have to wait for a response from the previous request before you attempt to send the next one. If you don't care about receiving responses, then this problem is not an issue, as all requests seem to get passed on to the script, regardless of the queueing issue.

Also note that there is NO way to get around the 3-second delay for llRemoteDataReply; you cannot use the multiple-slave-comm-script trick, because XML-RPC channels are *script-specific*, NOT *object-specific*.

Pour plus d'informations, visitez ces sujets sur les forums de SecondLife (anglais) here and here.

Autres Ressources (anglais)

Exemples

php

Pour initialiser un XMLRPC depuis un serveur externe, vous allez avoir besoin d'une application web. Un langage pour créer ce genre d'application est le PHP. Voici un exemple qui explique comment envoyer un message XMLRPC à votre script LSL depuis un serveur web avec PHP. <php><?php

echo '

';
	$channel = ""; //Entrez le channel que vous utiliser (key)
	$xmldata = "<?xml version=\"1.0\"?><methodCall><methodName>llRemoteData</methodName><params><param><value><struct><member><name>Channel</name><value><string>".$channel."</string></value></member><member><name>IntValue</name><value><int>11261979</int></value></member><member><name>StringValue</name><value><string>happy birthday</string></value></member></struct></value></param></params></methodCall>";
	echo sendToHost("xmlrpc.secondlife.com", "POST", "/cgi-bin/xmlrpc.cgi", $xmldata);
	echo '

';

function sendToHost($host,$method,$path,$data,$useragent=0) { $buf=""; // Supply a default method of GET if the one passed was empty if (empty($method)) $method = 'GET'; $method = strtoupper($method);

$fp = fsockopen($host, 80, $errno, $errstr, 30);

if( !$fp ) { $buf = "$errstr ($errno)
\n"; }else { if ($method == 'GET') $path .= '?' . $data; fputs($fp, "$method $path HTTP/1.1\r\n"); fputs($fp, "Host: $host\r\n"); fputs($fp, "Content-type: text/xml\r\n"); fputs($fp, "Content-length: " . strlen($data) . "\r\n"); if ($useragent) fputs($fp, "User-Agent: MSIE\r\n"); fputs($fp, "Connection: close\r\n\r\n"); if ($method == 'POST') fputs($fp, $data); while (!feof($fp)) $buf .= fgets($fp,128); fclose($fp); } return $buf; } ?></php>

perl

Le code perl et le code LSL correspondant pour contacter un objet dans Second Life est donné ci-dessous. Le code perl utilise le module RPC::XML. Vous pouvez lancez le code perl depuis la ligne de commande. Cela crée un objet RPC et envoit un message à l'objet rezzé sur la Grid. Notez que vous devez spécifier l'UUID de l'objet à contacter dans le code perl. Le code perl envoit un message contenant le string "Message to pass" et le nombre "2007". Le code LSL correspondant répond en envoyant le string "I got it" et le nombre "2008".

<perl>#!/usr/bin/perl

use RPC::XML; use RPC::XML::Parser; use RPC::XML::Client;

my $llURL = "http://xmlrpc.secondlife.com/cgi-bin/xmlrpc.cgi"; $P = RPC::XML::Parser->new();

my $cli = RPC::XML::Client->new($llURL); my $req = RPC::XML::request->new(

       "llRemoteData",
       {'Channel' => RPC::XML::string->new("UUID for the open channel from the object GOES HERE!"),
       'IntValue' => RPC::XML::int->new(2007),
       'StringValue' => RPC::XML::string->new("message to pass")});
  1. Print out the message to send

print "ref(req): ",ref($req),"\n"; $xml = $req->as_string(); print "Length: ",$req->length,"\n\n",$xml,"\n\n";

$res = $P->parse($xml); print ref($res),"\n"; if (ref($res)) {

   %h = %{$res->args->[0]->value};
   foreach $lupe (keys %h) {
      print "$lupe: $h{$lupe}\n";
   }

}

  1. Submit the request to send the information above.

my $resp = $cli->send_request($req);


  1. Print out the response

print "\n\n\nResponse\n"; print "ref(resp): ",ref($resp),"\n"; $xml = $resp->as_string(); print "Length: ",$resp->length,"\n\n",$xml,"\n\n";

$res = $P->parse($xml); print ref($res),"\n"; if (ref($res)) {

   %h = %{$res->value};
   foreach $lupe (keys %h) {
      $val =  $h{$lupe};
      print "$lupe: $val\n";
   }

}</perl>

Code LSL correspondant:

<lsl>key remoteChannel; init() {

   llOpenRemoteDataChannel(); // create an XML-RPC channel
   llOwnerSay("My key is " + (string)llGetKey());

}

default {

   state_entry() {
       init();
   }
   
   state_exit() {
       return;
   }
                               
   on_rez(integer param) {
       llResetScript();        
   }
                               
   remote_data(integer type, key channel, key message_id, string sender, integer ival, string sval) {
        if (type == REMOTE_DATA_CHANNEL) { // channel created
            llSay(DEBUG_CHANNEL,"Channel opened for REMOTE_DATA_CHANNEL" + 
               (string)channel + " " + (string)message_id + " " + (string)sender + " " +                         
               (string)ival + " " + (string)sval);
            remoteChannel = channel;
            llOwnerSay("Ready to receive requests on channel \"" + (string)channel + "\"");                        
            state receiving; // start handling requests
        } else {
            llSay(DEBUG_CHANNEL,"Unexpected event type"); 
        }                      
    }                 

}


state receiving {

   state_entry() {
       llOwnerSay("Ready to receive information from outside SL");
   }  
   
   state_exit() {
       llOwnerSay("No longer receiving information from outside SL.");
        llCloseRemoteDataChannel(remoteChannel);
   }
   
   on_rez(integer param) {
       llResetScript();
   }
   
   remote_data(integer type, key channel, key message_id, string sender, integer ival, string sval) {
       if (type == REMOTE_DATA_REQUEST) { // handle requests sent to us
            llSay(DEBUG_CHANNEL,"Request received for REMOTE_DATA_REQUEST " + (string)channel + " " +
               (string)message_id + " " + (string)sender + " " + (string)ival + " " + (string)sval);
           llRemoteDataReply(channel,NULL_KEY,"I got it",2008);
           llOwnerSay("I just recieved data in "+ llGetRegionName() + 
                       " at position " + (string)llGetPos() + "\n" +
                      "The string was " +  sval + "\nThe number was " + (string)ival + ".");
       }
   }
   

} </lsl>