﻿<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Tag PackageDescriptor - Constellation</title>
	<atom:link href="https://developer.myconstellation.io/tag/packagedescriptor/feed/" rel="self" type="application/rss+xml" />
	<link>https://developer.myconstellation.io/tag/packagedescriptor/</link>
	<description>Votre plateforme d&#039;interconnexion</description>
	<lastBuildDate>Mon, 30 Apr 2018 12:40:00 +0000</lastBuildDate>
	<language>fr-FR</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.0.11</generator>

<image>
	<url>https://developer.myconstellation.io/wp-content/uploads/2016/02/256x256-e1457476015859.png</url>
	<title>Tag PackageDescriptor - Constellation</title>
	<link>https://developer.myconstellation.io/tag/packagedescriptor/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Nouvelle librairie Constellation pour Arduino / ESP8266 en version 2.0</title>
		<link>https://developer.myconstellation.io/blog/nouvelle-librairie-constellation-pour-arduino-esp8266-en-version-2-0/</link>
					<comments>https://developer.myconstellation.io/blog/nouvelle-librairie-constellation-pour-arduino-esp8266-en-version-2-0/#comments</comments>
		
		<dc:creator><![CDATA[Sebastien Warin]]></dc:creator>
		<pubDate>Tue, 13 Sep 2016 13:20:38 +0000</pubDate>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Saga]]></category>
		<category><![CDATA[PurgeStateObject]]></category>
		<category><![CDATA[StateObjectLink]]></category>
		<category><![CDATA[PackageDescriptor]]></category>
		<category><![CDATA[HTTP]]></category>
		<category><![CDATA[Virtuel]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[Subscribe]]></category>
		<category><![CDATA[SendMessage]]></category>
		<category><![CDATA[Arduino]]></category>
		<category><![CDATA[PushStateObject]]></category>
		<category><![CDATA[ESP8266]]></category>
		<category><![CDATA[REST]]></category>
		<category><![CDATA[ESP]]></category>
		<category><![CDATA[Package]]></category>
		<category><![CDATA[Messaging]]></category>
		<category><![CDATA[Message]]></category>
		<category><![CDATA[Console]]></category>
		<category><![CDATA[MessageCallback]]></category>
		<category><![CDATA[MessageContext]]></category>
		<guid isPermaLink="false">https://developer.myconstellation.io/?p=2546</guid>

					<description><![CDATA[<p>J’ai le plaisir de  vous annoncer l’arrivée de la nouvelle libraire Constellation pour Arduino/ESP en version 2.0. Cette nouvelle version amène beaucoup de nouveautés que je vous propose de découvrir dans cet article. La librairie a été testé avec succès</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/blog/nouvelle-librairie-constellation-pour-arduino-esp8266-en-version-2-0/">Nouvelle librairie Constellation pour Arduino / ESP8266 en version 2.0</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>J’ai le plaisir de  vous annoncer l’arrivée de la nouvelle libraire Constellation pour Arduino/ESP en version 2.0.</p>
<p>Cette nouvelle version amène beaucoup de nouveautés que je vous propose de découvrir dans cet article. La librairie a été testé avec succès sur différentes cartes animées par un ESP8266 (ESP-01, 05, 07 et D1 Mini) ainsi qu’un Arduino/Genuino MKR1000.</p>
<p>Pour la mise à jour, téléchargez la libraire ci-dessous et dézippez les fichiers dans le dossier “Constellation” dans votre répertoire de libraire Arduino.</p>

<p><u>Attention</u> : cette version 2.x de la librairie Constellation pour Arduino/ESP nécessite la version <a href="/constellation-platform/changelog/#05092016_Update_Server_18116249">1.8.1.16249</a> ou plus récente du serveur Constellation pour fonctionner correctement. Pour mettre à jour votre plateforme Constellation, lancez le <a href="/downloads/">Web Platform Installer</a>.</p>
<h3>Réception de message et StateObject “asynchrone”</h3>
<p>Il s’agit d’une grosse évolution par rapport à la version 1.x. Pour “récupérer” du serveur Constellation les messages à destination de votre package virtuel ou les StateObjects pour lequel votre package (virtuel) s’est abonné, il faut invoquer les actions “<a href="/client-api/rest-api/interface-rest-constellation/#Recevoir_des_messages">GetMessages</a>” et “<a href="/client-api/rest-api/interface-rest-constellation/#Subscribe">GetStateObjects</a>” sur l’interface REST.</p>
<p>Ces méthodes supportent le “long-polling” c’est à dire qu’elles mettent en attente la requête tant qu’il n’y a pas de messages ou StateObjects à retourner avec la notion de timeout (par défaut 60 secondes).</p>
<p>Le problème sur les versions 1.x de la libraire Arduino est que le client HTTP est “synchrone”, c’est à dire qu’il envoi la requête HTTP et attend la réponse du serveur pour traitement ce qui est incompatible avec du long-polling car cela bloquerait le code de l’Arduino. De ce fait, les anciennes versions spécifiées le “timeout” de ces requêtes à 1 seconde.</p>
<p>Ainsi jusqu’à maintenant, l’interrogation des messages et SO pouvaient bloquer jusqu’à 2 secondes votre Arduino (1 seconde pour le GetMessage et 1 seconde pour le GetStateObject) et engendrait donc 1 requêtes HTTP toutes les secondes entre votre ESP/Arduino et le serveur Constellation.</p>
<p>Dans cette nouvelle version, la librairie utilisent 3 clients HTTP différents : un pour toutes les requêtes synchrones, un pour la réception de message (<em>GetMessage</em>) et un pour la réception des StateObjects (<em>GetStateObjects</em>).</p>
<p>Le client synchrone est donc toujours disponible et il n’y a aucun blocage, aucune attente pour la réception de message et de SO. De plus il n’y a plus besoin de “poller” ou “flooder” le serveur d’une requête toute les secondes, en réactivant le long-polling le 2ème et 3ème client HTTP, on lance une requête toutes les minutes (60 sec par défaut) dans l’attente de message et SO.</p>
<p>De ce fait, il y a quelques modifications à apporter dans votre code !</p>
<p>Premièrement, vous ne devez plus passer la référence de votre client réseau mais plutôt spécifier le type de votre client dans le template de la classe Constellation. Par exemple, si vous utilisez un ESP8266 ou un Arduino MKR1000, vous utiliserez la classe “WifiClient “” :</p>
<p></p><pre class="crayon-plain-tag">/* Create the Constellation client */
Constellation&lt;WiFiClient&gt; constellation("constellation.monserveur.com", 8088, "MyVirtualSentine", "MyPackage", "MyAccessKey123!");</pre><p></p>
<p>Ensuite, il n’y a plus besoin d’invoquer la méthode “poll” dans votre boucle principale avec un timer, vous devez tout simplement appeler la méthode “loop” autant de fois que vous voulez :</p>
<p></p><pre class="crayon-plain-tag">void loop(void) {
  // Process incoming message &amp; StateObject updates
  constellation.loop();
}</pre><p></p>
<p>Cette méthode vérifie en fait si il y a eu une réponse sur le client utilisé pour la réception de message et sur le client pour la réception de SO afin de les dispatcher dans votre code.</p>
<h3>Support du PackageDescriptor</h3>
<p>Autre nouveauté majeure pour cette version 2, le support du “Package Descriptor”.</p>
<p>Pour rappel le “Package Descriptor” est un objet envoyé par un package au serveur pour décrire ses StateObjects et ses MessageCallbacks exposés par le package.</p>
<p>Le MessageCallback Explorer de la Console Constellation s’appuie sur le “Package Descriptor” de chaque package pour lister chaque MessageCallback avec un formulaire de test. Sans cette description cela serait impossible !</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image.png"><img class="colorbox-2546"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="MessageCallback Explorer" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb.png" alt="MessageCallback Explorer" width="350" height="168" border="0" /></a></p>
<p>Les versions 1.x ne supportaient pas “Package Descriptor”, de ce fait il n’était pas possible d’explorer/découvrir les MessageCallbacks d’un package Arduino/ESP. Vous devez nécessairement connaitre par vous même les MC exposés par le package et le type des StateObjects qu’il pouvait publier.</p>
<p>Avec la version 2.0, l’Arduino/ESP envoie au serveur la description des MC exposés et des types utilisés par les SO et arguments des MC.</p>
<p>Dans la suite de cet article, vous découvrirez comment ajouter des types dans la description de votre package, mais n’oubliez jamais d’envoyer votre “Package Descriptor” en invoquant la méthode “declarePackageDescriptor”, typiquement une fois votre code Arduino initialisé (par exemple à la fin de la méthode <em>setup()</em>) :</p>
<p></p><pre class="crayon-plain-tag">// Declare the package descriptor
constellation.declarePackageDescriptor();</pre><p></p>
<h3>Amélioration du PushStateObject</h3>
<p>La méthode “PushStateObject” permet de publier un StateObject sur le serveur Constellation.</p>
<p>Tout d’abord la méthode expose des surcharges vous permettant de spécifier comme “value” de votre SO des int, uint, double, float, long et bool et supporte en paramètre optionnel le “lifetime”, c’st à dire la durée en seconde de “vie” de votre StateObject avant d’être considéré comme expiré.</p>
<p></p><pre class="crayon-plain-tag">// Dummy data
uint16_t lux = 123;

// Push a simple type on Constellation 
constellation.pushStateObject("DemoLux", lux);  

// Push a simple type on Constellation with lifetime of 20 seconds
constellation.pushStateObject("DemoLux", lux, 20);</pre><p></p>
<p>Vous pouvez toujours publier des StateObjects dont la valeur (value) est un objet complexe (formaté en JSON).</p>
<p>Le JSON peut être formaté sous forme d’une chaine de caractère avec la méthode “stringFormat” :</p>
<p></p><pre class="crayon-plain-tag">// Push a complex object on Constellation with stringFormat
constellation.pushStateObject("DemoLux", stringFormat("{ 'Lux':%d, 'Broadband':%d, 'IR':%d }", lux, full, ir));</pre><p></p>
<p>Vous pouvez également définir votre propre type pour ce StateObject, par exemple nommons cet objet “MyLuxData” :</p>
<p></p><pre class="crayon-plain-tag">constellation.pushStateObject("DemoLux", stringFormat("{ 'Lux':%d, 'Broadband':%d, 'IR':%d }", lux, full, ir), "MyLuxData");</pre><p></p>
<p>Sans oublier d’ajouter ce type “personnalisé” dans le “package descriptor”. Par exemple, dans le “setup()” et avant de faire un “declarePackageDescriptor”, on aurait décrit “MyLuxData” de la façon suivante :</p>
<p></p><pre class="crayon-plain-tag">constellation.addStateObjectType("MyLuxData", TypeDescriptor().setDescription("MyLuxData demo").addProperty("Broadband", "System.Int32").addProperty("IR", "System.Int32").addProperty("Lux", "System.Int32"));</pre><p></p>
<p>Pour finir, vous pouvez toujours publier un StateObject en construisant la valeur dans un objet JsonObject de façon suivante :</p>
<p></p><pre class="crayon-plain-tag">// Push a complex object on Constellation with JsonObject
const int BUFFER_SIZE = JSON_OBJECT_SIZE(5);
StaticJsonBuffer&lt;BUFFER_SIZE&gt; jsonBuffer;
JsonObject&amp; myStateObject = jsonBuffer.createObject();
myStateObject["Lux"] = lux;
myStateObject["Broadband"] = full;
myStateObject["IR"] = ir;
constellation.pushStateObject("DemoLux", myStateObject);</pre><p></p>
<p>Dans les surcharges de cette méthode, vous pouvez également spécifier le type de votre StateObject et/ou sa durée de vie :</p>
<p></p><pre class="crayon-plain-tag">constellation.pushStateObject("DemoLux", myStateObject, "MyLuxData", 20);</pre><p></p>
<p>Pour finir, nouveauté de la librairie 2.0, vous pouvez également spécifier des “meta-données” à vos StateObjects. Par exemple :</p>
<p></p><pre class="crayon-plain-tag">// Ajout de metadatas au StateObject
JsonObject&amp; metadatas = jsonBuffer.createObject();
metadatas["ChipId"] = ESP.getChipId();
metadatas["Timestamp"] = millis();
constellation.pushStateObject("DemoLux", myStateObject, "MyStateObject", 20, &amp;metadatas);</pre><p></p>
<h3>Les StateObjectLinks</h3>
<p>En version 1.x de la librairie Arduino, vous pouvez :</p>
<ul>
<li>interroger des StateObjects de la Constellation en invoquant la méthode “requestStateObjects” qui vous retourne les StateObjects à l’instant T correspondant à votre requête :</li>
</ul>
<p></p><pre class="crayon-plain-tag">// Example : print the all SO's value named "/intelcpu/0/load/0" and produced by the "HWMonitor" package (on all sentinels)
JsonArray&amp; cpus = constellation.requestStateObjects("*", "HWMonitor", "/intelcpu/0/load/0");
for(int i=0; i &lt; cpus.size(); i++) { 
  constellation.writeInfo("CPU on %s is currently %d %", cpus[i]["SentinelName"].asString(), cpus[i]["Value"]["Value"].as&lt;float&gt;());
}</pre><p></p>
<ul>
<li>vous abonnez aux mises à jour des StateObjects pour être notifié en temps réel des que les SO changent :</li>
</ul>
<p></p><pre class="crayon-plain-tag">// set a StateObject update callback and subscribe to SO
constellation.setStateObjectUpdateCallback([] (JsonObject&amp; so) {
constellation.writeInfo("StateObject updated ! StateObject name = %s", so["Name"].asString()); 
});
// Subscribe to SO named "/intelcpu/0/load/0" and produced by the "HWMonitor" package (on all sentinels)
constellation.subscribeToStateObjects("*", "HWMonitor", "/intelcpu/0/load/0");</pre><p></p>
<p>Vous pouvez invoquer plusieurs fois la méthode “subscribeToStateObjects” pour ajouter des abonnements à d’autre StateObjects mais il n’y a qu’un seul callback de réception des SO (défini par la méthode setStateObjectUpdateCallback). C’est à vous de “dispatcher” les SO reçus.</p>
<p>La nouveauté en 2.0 vient de l’ajout de la méthode “registerStateObjectLink” qui vous permet d’associer un callback à un abonnement laissant ainsi à la librairie la charge du “dispatch”.</p>
<p>Par exemple, on peut désormais écrire :</p>
<p></p><pre class="crayon-plain-tag">constellation.registerStateObjectLink("*", "HWMonitor", "/intelcpu/0/load/0", [](JsonObject&amp; so) {
  constellation.writeInfo("CPU on %s is currently %d %", so["SentinelName"].asString(), so["Value"]["Value"].as&lt;float&gt;());
});</pre><p></p>
<p>Ici on enregistre un “StateObject Link” sur tous les SO nommés « /intelcpu/0/load/0 » produits par le package “HWMonitor” de toutes les sentinelles de votre Constellation. Dès qu’un de ces StateObjects changent on exécutera le callback associé, qui ici écrit dans le log un message indiquant la nouvelle valeur du CPU.</p>
<p>Vous bien entendu enregistrer autant de StateObjectLink que vous souhaitez.</p>
<h3>Enregistrement des MessageCallbacks</h3>
<p>Le principe est le même que celui décrit ci-dessus pour les abonnements aux StateObjects.</p>
<p>En version 1.x, on devait définir un callback pour réception de message et invoquer la méthode “subscribeToMessage” :</p>
<p></p><pre class="crayon-plain-tag">// Set callback for all incoming messages
 constellation.setMessageReceiveCallback([](JsonObject&amp; json) { 
   constellation.writeInfo("Message receive ! Message key = %s", json["Key"].asString());     
 }); 
 // Subscribe to message
 constellation.subscribeToMessage();</pre><p></p>
<p>C’était donc à votre charge de “dispatcher” les messages reçus en fonction du “MessageKey”.</p>
<p>Désormais avec la version 2.0, vous pouvez enregistrer un callback pour un “MessageKey” donné. Par exemple :</p>
<p></p><pre class="crayon-plain-tag">constellation.registerMessageCallback("HelloWorld",
  [](JsonObject&amp; json) {
    constellation.writeInfo("Hello Constellation !");
 });</pre><p></p>
<p>Dans l’exemple ci-dessous, on ajoute/expose un MessageCallback “HelloWorld” qui écrit dans les logs !</p>
<p>Il n’y donc plus besoin de “dispatcher”, un MessageCallback est donc associé à un “MessageKey” unique et un callback. Il n’y a plus besoin non plus de faire un “subscribeToMessage” (cette méthode est invoquée implicitement par le <em>registerMessageCallback</em>).</p>
<p>De plus cette méthode ajoute implicitement les MessageCallbacks dans le Package Descriptor de sorte que chaque MC soit ainsi référencé dans la Constellation</p>
<p>(console)</p>
<p>Vous pouvez également passer un “MessageCallbackDescriptor” dans l’enregistrement de vos MC pour ajouter une description par exemple :</p>
<p></p><pre class="crayon-plain-tag">constellation.registerMessageCallback("HelloWorld",
  MessageCallbackDescriptor().setDescription("Say Hello to Constellation"),
  [](JsonObject&amp; json) {
    constellation.writeInfo("Hello Constellation !");
 });</pre><p></p>
<p>Et même définir les paramètres de vos MC :</p>
<p></p><pre class="crayon-plain-tag">constellation.registerMessageCallback("SayHello",
  MessageCallbackDescriptor().setDescription("Say hello !").addParameter("FirstName", "System.String").addParameter("LastName", "System.String"),
  [](JsonObject&amp; json) {
    constellation.writeInfo("Hello %s %s", json["Data"][0].asString(), json["Data"][1].asString()); 
 });</pre><p></p>
<p>Ici on déclare un MC nommé “SayHello” prenant deux paramètres de type String avec un texte de description. Dans la code nous verrons :</p>
<p>(console)</p>
<p>Tout comme les StateObjects, les types des arguments des MC peuvent être des types complexes.</p>
<p>Par exemple enregistrons un MC prenant un seul argument de type “SampleUserData” que nous allons décrire avec la méthode “addMessageCallbackType” comme un objet composé de deux propriétés de type String :</p>
<p></p><pre class="crayon-plain-tag">// Expose a MessageCallback with complex parameter :
constellation.registerMessageCallback("SayHello2",
  MessageCallbackDescriptor().setDescription("Say hello with complex object!").addParameter("User", "SampleUserData"),
  [](JsonObject&amp; json) {
    constellation.writeInfo("Hello %s %s", json["Data"][0]["FirstName"].asString(), json["Data"][0]["LastName"].asString()); 
});  
// and describe the complex parameter "SampleUserData"  
constellation.addMessageCallbackType("SampleUserData", TypeDescriptor().setDescription("This is a smaple user data").addProperty("FirstName", "System.String").addProperty("LastName", "System.String"));</pre><p></p>
<p>Enfin la méthode “registerMessageCallback” accepte également des callbacks prenant en paramètre le “MessageContext” :</p>
<p></p><pre class="crayon-plain-tag">constellation.registerMessageCallback("HelloWorld",
  MessageCallbackDescriptor().setDescription("Say Hello to Constellation"),
  [](JsonObject&amp; json, MessageContext ctx) {
    constellation.writeInfo("Message received from %s", ctx.sender.friendlyName);
 });</pre><p></p>
<p>L’objet “MessageContext” est défini de la façon suivante :</p>
<p></p><pre class="crayon-plain-tag">typedef struct {
    const char* sagaId;
    bool isSaga;
    const char* messageKey;
    MessageSender sender;
    ScopeType scope;
} MessageContext;

typedef struct {
    SenderType type;
    const char* friendlyName;
    const char* connectionId;
} MessageSender;</pre><p></p>
<p>Vous pouvez donc récupérer les informations sur l’émetteur (Sender) du message, le scope et l’identifiant de Saga si c’est une saga (isSaga = true).</p>
<h3>Support des Saga (messages avec réponse)</h3>
<p>Une <a href="/concepts/messaging-message-scope-messagecallback-saga/#Les_Sagas">saga</a> est un identifiant unique qu’on affecte à des messages pour les lier entre eux. Cela permet de faire des couples de message “Requête / Réponse”. Une “réponse” étant un message renvoyé à l’émetteur de la requête avec le même identifiant de saga pour que ce dernier puisse l’identifier comme la “réponse” à son message d’origine.</p>
<p>Vous pouvez exposer des MessageCallbacks qui “répondent”, c’est à dire des  MessageCallbacks qui retournent un message de réponse.</p>
<p>Par exemple, exposons un MC pour réaliser des Additions sur un Arduino. Vous enregistrerez un MC “Addition” prenant en parametre deux entiers et qui en retourne un (le résultat) :</p>
<p></p><pre class="crayon-plain-tag">constellation.registerMessageCallback("Addition",
  MessageCallbackDescriptor().setDescription("Do addition on this tiny device").addParameter("a", "System.Int32").addParameter("b", "System.Int32").setReturnType("System.Int32"),
  [](JsonObject&amp; json, MessageContext ctx) {        
    int a = json["Data"][0].as&lt;int&gt;();      
    int b = json["Data"][1].as&lt;int&gt;();
    int result = a + b;
    constellation.writeInfo("Addition %d + %d = %d", a, b, result);      
    if(ctx.isSaga) {
      constellation.writeInfo("Doing additoon for %s (sagaId: %s)", ctx.sender.friendlyName, ctx.sagaId);   
    // Return the result :
      constellation.sendResponse&lt;int&gt;(ctx, result);
    }
    else {
      constellation.writeInfo("No saga, no response !");
    }
 });</pre><p></p>
<p>Vous remarquerez dans le “MessageCallbackDescriptor” l’appel de la méthode “setReturnType” pour spécifier le type de retour (et que le fait qu’il s’agit d’un MC acceptant les sagas).</p>
<p>L’envoi de la réponse étant réalisé par la méthode sendReponse. Cette méthode a plusieurs surcharges :</p>
<p></p><pre class="crayon-plain-tag">template&lt;typename T&gt; bool sendResponse(MessageContext context, T data);
bool sendResponse(MessageContext context, const char* data, ...);
bool sendResponse(MessageContext context, JsonObject&amp; data);</pre><p></p>
<p>Notez aussi que vous devriez faire un “sendResponse” si et seulement le message reçu est associé à une saga, c’est à dire que le champs “isSaga” du contexte (MessageContext) est “vrai”. Sinon ca ne sert à rien de répondre <img class="wlEmoticon wlEmoticon-winkingsmile colorbox-2546" style="border-style: none;" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/wlEmoticon-winkingsmile.png" alt="Clignement d'œil" /></p>
<p>Pour finir, cette nouvelle version supporte également l’envoi de message dans une saga. C’est à dire que vous pouvez envoyer un message qui attend une réponse et donc enregistrer un callback de traitement de la réponse.</p>
<p>Par exemple le package “NetworkTools” expose un MC “Ping” permettant de faire un ping. Le package retourne dans la saga un message contenant le temps en milliseconde du ping. On pourrait alors invoquer cette méthode depuis notre Arduino de la façon suivante :</p>
<p></p><pre class="crayon-plain-tag">const char* ip = "192.168.0.10";
// Send message in a saga and attach a callback for response :
constellation.sendMessageWithSaga([](JsonObject&amp; json) {
  constellation.writeInfo("Ping response in %s ms", json["Data"].asString()); 
}, Package, "NetworkTools", "Ping", "[ '%s' ]", ip);</pre><p></p>
<p>Ici on envoi un message au scope “Package” pour atteindre le(x) package(s) “NetworkTools” afin d’invoquer le MessageCallback “Ping” en passant en argument l’IP à pinger. Vous remarquerez qu’on utilise le formatage implicite des arguments.</p>
<p>La méthode n’est pas la traditionnelle “sendMessage” mais “sendMessageWithSaga” qui prend un argument supplémentaire : le callback de traitement de la réponse.</p>
<p>Ainsi quand le package “NetworkTools” répondra, on executera le callback associé qui ici affichera le temps de réponse de notre ping (Data) dans les logs Constellation (writeInfo).</p>
<p>De ce fait, avec cette nouvelle libraire vos Arduino/ESP peuvent invoquer des MC dans sagas pour exploiter la réponse mais également exposer des MC qui retournent des résultats.</p>
<h3>Autres nouveautés</h3>
<p>En vrac, vous disposez maintenant une méthode “purgeStateObjects” permettant de supprimer des StateObjects de votre package.</p>
<p>De plus la méthode “setDebugMode” accepte en argument l’énumération “DebugMode” composée des valeurs suivantes :</p>
<ul>
<li>“Quiet” (mode silencieux, la libraire ne produit aucune trace dans l’interface Serial)</li>
<li>“Normal” (mode par défaut, écrit quelques informations dans l’interface Serial)</li>
<li>“Verbose” (écrit beaucoup d’information dans l’interface Serial comme par exemple les requêtes et réponse HTTP v ers Constellation)</li>
</ul>
<p>Enfin les exemples fournis dans la libraire ont été complètement revus.</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/blog/nouvelle-librairie-constellation-pour-arduino-esp8266-en-version-2-0/">Nouvelle librairie Constellation pour Arduino / ESP8266 en version 2.0</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://developer.myconstellation.io/blog/nouvelle-librairie-constellation-pour-arduino-esp8266-en-version-2-0/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>MessageCallback : Exposer des méthodes Python</title>
		<link>https://developer.myconstellation.io/client-api/python-api/messagecallbacks-exposer-des-methodes-python/</link>
					<comments>https://developer.myconstellation.io/client-api/python-api/messagecallbacks-exposer-des-methodes-python/#respond</comments>
		
		<dc:creator><![CDATA[Sebastien Warin]]></dc:creator>
		<pubDate>Wed, 24 Aug 2016 09:47:40 +0000</pubDate>
				<category><![CDATA[Python API]]></category>
		<category><![CDATA[Package]]></category>
		<category><![CDATA[Message]]></category>
		<category><![CDATA[MessageCallback]]></category>
		<category><![CDATA[Saga]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[MessageContext]]></category>
		<category><![CDATA[PackageDescriptor]]></category>
		<guid isPermaLink="false">https://developer.myconstellation.io/?p=2511</guid>

					<description><![CDATA[<p>Exposer une méthode Pour exposer une méthode Python dans Constellation vous devez tout simplement ajouter le décorateur “Constellation.MessageCallback” sur votre méthode : [crayon-6972c89cda427719760578/] Ici nous déclarons le MessageCallback “SimpleMessageCallback” sans paramètre ni documentation. Vous pouvez ajouter un ou plusieurs arguments</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/client-api/python-api/messagecallbacks-exposer-des-methodes-python/">MessageCallback : Exposer des méthodes Python</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h3>Exposer une méthode</h3>
<p>Pour exposer une méthode Python dans Constellation vous devez tout simplement ajouter le décorateur “<em>Constellation.MessageCallback</em>” sur votre méthode :</p>
<p></p><pre class="crayon-plain-tag">@Constellation.MessageCallback()
def SimpleMessageCallback():
    Constellation.WriteInfo('Hello Python !')</pre><p></p>
<p>Ici nous déclarons le MessageCallback “SimpleMessageCallback” sans paramètre ni documentation.</p>
<p>Vous pouvez ajouter un ou plusieurs arguments à votre MC et utiliser la syntaxe de Python pour commenter vos MC :</p>
<p></p><pre class="crayon-plain-tag">@Constellation.MessageCallback()
def DemoArg(data):
    "Ceci est la description du MessageCallback DemoArg avec 1 argument"
    Constellation.WriteInfo('arg = %s', data)

@Constellation.MessageCallback()
def DemoArgs(a, b, c):
    "Ceci est la description du MessageCallback DemoArgs avec 3 arguments"
    Constellation.WriteInfo(a)
    Constellation.WriteInfo(b)
    Constellation.WriteInfo(c)</pre><p></p>
<p>Le ou les paramètres peuvent être des types simples (string, int, bool, etc..) ou des types (objets) complexes :</p>
<p></p><pre class="crayon-plain-tag">@Constellation.MessageCallback()
def ComplexMessageCallback(data):
    "Ceci est la description du MessageCallback ComplexMessageCallback avec un objet complexe en argument"
    Constellation.WriteInfo(data.A)
    Constellation.WriteInfo(data.B)
    Constellation.WriteInfo(data.C)</pre><p></p>
<p>L’ensemble de ces méthodes déclarées “MessageCallbacks” seront alors référencées dans la Constellation. Vous pouvez les découvrir en interrogeant le Package Descriptor de votre package.</p>
<p>Par exemple, lancez la Console Constellation et rendez-vous dans le “MessageCallback Browser”. Vous aurez la liste de vos méthodes avec la possibilité de les invoquer directement depuis l’interface :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2018/04/image-9.png"><img class="colorbox-2511"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="MessageCallbacks Explorer" src="https://developer.myconstellation.io/wp-content/uploads/2018/04/image_thumb-8.png" alt="MessageCallbacks Explorer" width="484" height="346" border="0" /></a></p>
<h3>Documenter son MessageCallback</h3>
<h4>Description des MessageCallbacks</h4>
<p>Comme vous l’avez remarqué dans les exemples précédents, nous utilisons la documentation des méthodes de Python :</p>
<p></p><pre class="crayon-plain-tag">@Constellation.MessageCallback()
def Demo():
    "Ceci est la description du MessageCallback !"
    pass</pre><p></p>
<p>La documentation de la méthode est utilisée comme description du MessageCallback :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/08/image-72.png"><img class="colorbox-2511"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/08/image_thumb-61.png" alt="image" width="350" height="109" border="0" /></a></p>
<p>La description de la méthode peut être écrite sur plusieurs lignes :</p>
<p></p><pre class="crayon-plain-tag">@Constellation.MessageCallback()
def Demo():
    '''
    The first line is brief explanation, which may be completed with 
    a longer one. For instance to discuss about its methods.
    '''
    pass</pre><p></p>
<h4>Description des arguments des MessageCallbacks</h4>
<p><u>Note</u> : la description des arguments est disponible depuis l’API Python 1.8.4.x. Pensez à mettre à jour la référence de votre API par Nuget depuis Visual Studio ou en <a href="/client-api/python-api/developper-avec-le-package-tools-cli/#Mise_a_jour_du_template">mettant à jour le template depuis la CLI</a>.</p>
<p>Si vous regardez attentivement les arguments des MC dans le MessageCallback Explorer, ils sont reconnus comme « System.Object » étant donné que les arguments d&rsquo;une fonction en Python ne sont pas typés.</p>
<p>Pour décrire les paramètres utilisez la syntaxe suivante dans la description du MC :</p>
<p></p><pre class="crayon-plain-tag">:param &lt;type&gt; &lt;name&gt; : &lt;description&gt;</pre><p></p>
<p>Par exemple :</p>
<p></p><pre class="crayon-plain-tag">@Constellation.MessageCallback()
def Demo(a, b, c):
    '''
    Ceci est un exemple de MC avec 3 parametres

    :param int a: My int value
    :param bool b: My boolean value
    :param string c: My string value
    '''
    Constellation.WriteInfo("a = %s - type: %s" % (a, type(a)))
    Constellation.WriteInfo("b = %s - type: %s" % (b, type(b)))
    Constellation.WriteInfo("c = %s - type: %s" % (c, type(c)))</pre><p></p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2018/04/image-10.png"><img class="colorbox-2511"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Description des arguments d'un MC en Python" src="https://developer.myconstellation.io/wp-content/uploads/2018/04/image_thumb-9.png" alt="Description des arguments d'un MC en Python" width="484" height="166" border="0" /></a></p>
<p align="left">Ainsi en retournant sur le MC Explorer, chaque argument est correctement typé dans Constellation.</p>
<h4 align="left">Paramètres optionnels avec valeur par défaut</h4>
<p align="left">Vous pouvez également définir que certains paramètres sont optionnels en spécifiant leurs valeurs par défaut avec la syntaxe [default: XXX] :</p>
<p></p><pre class="crayon-plain-tag">@Constellation.MessageCallback()
def DemoOptional(a, b):
    '''
    Ceci est un exemple de MC des paramètres optionnels

    :param int a: My int value [default:10]
    :param bool b: My boolean value [default:true]
    '''
    Constellation.WriteInfo("a = %s" % a)
    Constellation.WriteInfo("b = %s" % b)</pre><p></p>
<p>&nbsp;</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2018/04/image-11.png"><img class="colorbox-2511"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Arguments optionnels avec valeur par défaut" src="https://developer.myconstellation.io/wp-content/uploads/2018/04/image_thumb-10.png" alt="Arguments optionnels avec valeur par défaut" width="484" height="138" border="0" /></a></p>
<h4>Décrire les arguments de type complexe</h4>
<p>Dans le cas où un MC prend en paramètre un (ou plusieurs) type complexe, il faudra d&rsquo;abord décrie le type dans la méthode « Start ».</p>
<p>Par exemple, enregistrons au démarrage du package (méthode Start), le type “CredentialInfo” :</p>
<p></p><pre class="crayon-plain-tag">Constellation.DescribeMessageCallbackType("CredentialInfo", "Credential information", [
    { 'Name':'Username', 'Type':'string', 'Description': 'The username' },
    { 'Name':'Password', 'Type':'string', 'Description': 'The password' },
])</pre><p></p>
<p>Une fois tous vos types déclarés, il faut publier le “Package Descriptor” de votre package à Constellation par la ligne :</p>
<p></p><pre class="crayon-plain-tag">Constellation.DeclarePackageDescriptor()</pre><p></p>
<p>Nous pouvons maintenant déclarer un MC avec un parametre de type “CredentialInfo”. Par exemple :</p>
<p></p><pre class="crayon-plain-tag">@Constellation.MessageCallback()
def DemoAuth(credential):
    '''
    Demo MC avec avec un paramètre de type complexe

    :param CredentialInfo credential: the credential info
    '''
    Constellation.WriteInfo("User=%s Password=%s" % (credential.Username, credential.Password))</pre><p></p>
<p>Comme vous pourrez le voir dans le MessageCallbacks Explorer, votre méthode Python est correctement décrite ainsi que son paramètre “credential” de type “Credentialnfo”.</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2018/04/image-12.png"><img class="colorbox-2511"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Argument de type complexe" src="https://developer.myconstellation.io/wp-content/uploads/2018/04/image_thumb-11.png" alt="Argument de type complexe" width="484" height="150" border="0" /></a></p>
<p>Notez également que la description du type CredentialInfo est accessible en cliquant sur le type :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2018/04/image-13.png"><img class="colorbox-2511"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Argument de type complexe" src="https://developer.myconstellation.io/wp-content/uploads/2018/04/image_thumb-12.png" alt="Argument de type complexe" width="484" height="186" border="0" /></a></p>
<h3>Personnaliser le MessageCallback</h3>
<p>Comme pour l’API.NET, par défaut le nom du MessageCallback déclaré dans la Constellation est le nom de votre méthode mais vous pouvez redéfinir le nom exposé dans la Constellation :</p>
<p></p><pre class="crayon-plain-tag">@Constellation.MessageCallback("MySuperName")
def MyInternalMethodName():
    Constellation.WriteInfo("Hello")</pre><p></p>
<p>Aussi vous pouvez “cacher” ce MessageCallback à la Constellation.</p>
<p></p><pre class="crayon-plain-tag">@Constellation.MessageCallback(False)
def HiddenMessageCallback():
    "Hidden message callback"
    Constellation.WriteInfo("I'm here !!")</pre><p></p>
<p>Tous les packages ou consommateurs de votre Constellation pourront envoyer un message “HiddenMessageCallback” à votre package Python et donc invoquer votre méthode mais celle-ci ne sera pas déclarée dans le “Package  Descriptor”.</p>
<h3>Récupérer le contexte</h3>
<p>Comme avec l’API.NET, vous pouvez récupérer le contexte de réception du message en déclarant comme dernier argument de votre MessageCallback, le paramètre “context”.</p>
<p>Par exemple :</p>
<p></p><pre class="crayon-plain-tag">@Constellation.MessageCallback("MaMethode") # méthode renommée !
def DemoSeb5(context):
    "Test du contexte"
    Constellation.WriteInfo("Sender : %s" % context.Sender.FriendlyName)
    Constellation.WriteInfo("test sans parametre")</pre><p></p>
<p>Ou avec des paramètres :</p>
<p></p><pre class="crayon-plain-tag">@Constellation.MessageCallback()
def DemoSeb5(a, b, context):
    "Test du contexte avec parametre"
    Constellation.WriteInfo("Sender : %s" % context.Sender.FriendlyName)
    Constellation.WriteInfo("a = %s et b = %s" % (a, b))</pre><p></p>
<p>Il faut juste que le dernier argument soit nommé “context”. Notez qu’il ne fait pas partie de la signature de votre MessageCallback.</p>
<p>Ci-dessus, le 1er exemple est un MessageCallback caché et sans paramètre et le 2ème n’a que deux paramètres “a” et “b”.</p>
<p>L’objet “context” correspondant à la classe “<em>Constellation.Package.MessageContext</em>”. Vous retrouvez les propriétés suivantes :</p>
<ul>
<li>IsSaga : indique si le message reçu appartient à une Saga</li>
<li>SagaId : identifiant de la Saga (si <em>IsSaga = true</em>)</li>
<li>Scope : scope d’envoi du message reçu
<ul>
<li>Type : type du scope (All, Group, Package, Sentinel, Others)</li>
<li>Args : arguments du scope (ex : nom du groupe, du package ou de la sentinelle)</li>
</ul>
</li>
<li>Sender : représente l’émetteur du message
<ul>
<li>ConnectionId : identifiant de connexion unique de l’émetteur</li>
<li>Type : type de l’émetteur (ConsumerHub, ConstellationHub, ConsumerHttp ou ConstellationHttp)</li>
<li>FriendlyName : nom de l’émetteur</li>
</ul>
</li>
</ul>
<h3>Répondre aux Sagas</h3>
<p>Votre méthode peut également retourner une réponse à l’appelant, c’est ce que l’on appelle <a href="/concepts/messaging-message-scope-messagecallback-saga/">une saga</a>. Pour cela vous pouvez spécifier le type de la valeur de retour dans le décorateur de la façon suivante :</p>
<p></p><pre class="crayon-plain-tag">@Constellation.MessageCallback(returnType='System.Boolean')
def DemoSaga(user, password):
    "Test de saga"
    Constellation.WriteInfo("User=%s Password=%s" % (user, password))
    return user == password</pre><p></p>
<p>Cependant il est recommandé d&rsquo;utiliser la description du MC pour spécifier le type de retour avec la syntaxe</p>
<p></p><pre class="crayon-plain-tag">:return &lt;type&gt;: &lt;description&gt;</pre><p></p>
<p>Par exemple :</p>
<p></p><pre class="crayon-plain-tag">@Constellation.MessageCallback()
def DemoSaga(user, password):
    '''
    Test de saga

    :param string user: The username
    :param string password: The password
    :return bool: if user match
    '''
    Constellation.WriteInfo("User=%s Password=%s" % (user, password))
    return user == password</pre><p></p>
<p>Cela marche également en combinant la récupération du contexte :</p>
<p></p><pre class="crayon-plain-tag">@Constellation.MessageCallback()
def DemoAuth(user, password, context):
    '''
    Test de saga

    :param string user: The username
    :param string password: The password
    :return bool: if user match
    '''
    Constellation.WriteInfo("Sender : %s" % context.Sender.FriendlyName)
    Constellation.WriteInfo("User=%s Password=%s" % (user, password))
    return user == password</pre><p></p>
<p align="left">Par exemple en ouvrant le “Message Callback Explorer” de la Console Constellation vous constaterez que votre MC “DemoAuth” est bien référencé comme retournant un “Booléen” en prenant deux arguments (car l’argument “context” n’est pas pris en compte dans la signature du MC) :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2018/04/image-14.png"><img class="colorbox-2511"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;" title="Saga" src="https://developer.myconstellation.io/wp-content/uploads/2018/04/image_thumb-13.png" alt="Saga" width="484" height="142" border="0" /></a></p>
<p align="left">En invoquant cette méthode depuis la console, vous recevrez alors la réponse du package, ici un booléen :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/08/image-74.png"><img class="colorbox-2511"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/08/image_thumb-63.png" alt="image" width="350" height="241" border="0" /></a></p>
<p align="left">Dans les logs, on retrouve bien la trace de l’invocation de notre Saga avec le “contexte” :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/08/image-75.png"><img class="colorbox-2511"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/08/image_thumb-64.png" alt="image" width="350" height="104" border="0" /></a></p>
<p>(le FriendlyName de la Console Constellation est “<em>Consumer/ControlCenter:&lt;user&gt;</em>”).</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/client-api/python-api/messagecallbacks-exposer-des-methodes-python/">MessageCallback : Exposer des méthodes Python</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://developer.myconstellation.io/client-api/python-api/messagecallbacks-exposer-des-methodes-python/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>MessageCallbacks : exposez vos méthodes</title>
		<link>https://developer.myconstellation.io/client-api/net-package-api/messagecallbacks/</link>
					<comments>https://developer.myconstellation.io/client-api/net-package-api/messagecallbacks/#comments</comments>
		
		<dc:creator><![CDATA[Sebastien Warin]]></dc:creator>
		<pubDate>Wed, 16 Mar 2016 14:14:25 +0000</pubDate>
				<category><![CDATA[.NET API]]></category>
		<category><![CDATA[MessageCallback]]></category>
		<category><![CDATA[Saga]]></category>
		<category><![CDATA[Messaging]]></category>
		<category><![CDATA[MessageContent]]></category>
		<category><![CDATA[PackageDescriptor]]></category>
		<guid isPermaLink="false">https://developer.myconstellation.io/?p=1343</guid>

					<description><![CDATA[<p>Avant de tout, il est recommandé de lire cet article d’introduction aux concepts de Message, Scope, MessageCallback &#38; Saga dans Constellation pour bien comprendre le principe des MessageCallbacks. Exposer des méthodes Pour exposer une méthode .NET dans Constellation, il suffit</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/client-api/net-package-api/messagecallbacks/">MessageCallbacks : exposez vos méthodes</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Avant de tout, il est recommandé de lire <a href="/concepts/messaging-message-scope-messagecallback-saga/">cet article d’introduction aux concepts de Message, Scope, MessageCallback &amp; Saga</a> dans Constellation pour bien comprendre le principe des MessageCallbacks.</p>
<h3>Exposer des méthodes</h3>
<p>Pour exposer une méthode .NET dans Constellation, il suffit d&rsquo;ajouter l&rsquo;attribut “MessageCallback” sur une méthode :</p>
<p></p><pre class="crayon-plain-tag">[MessageCallback]
void MyMethod()
{
    PackageHost.WriteInfo("This is a MessageCallback !");
}</pre><p></p>
<p>Cela fonctionne que votre méthode soit privée ou public, d&rsquo;instance ou statique.</p>
<p>Une méthode marquée MessageCallback peut accepter zéro, un ou plusieurs paramètres :</p>
<p></p><pre class="crayon-plain-tag">[MessageCallback]       
void MyMethodWithMultipleParameters(string input, int number, bool boolean)
{
    PackageHost.WriteInfo("Input= {0} - Number: {1} - Boolean: {2}", input, number, boolean);
}</pre><p></p>
<p>De plus chaque paramètre peut être de type simple ou complexe :</p>
<p></p><pre class="crayon-plain-tag">[MessageCallback] 
void MyMethodWithComplexParameter(UserInfo user)
{
    PackageHost.WriteInfo("User: {0} &amp; Password = {1}", user.User, user.Password); 
}</pre><p></p>
<p>Par défaut seules les méthodes marquées [MessageCallback] sur votre classe ”<a href="/client-api/net-package-api/les-bases-des-packages-net/">IPackage</a>” sont enregistrées.</p>
<p>Si vous souhaitez également enregistrer les MessageCallbacks référencés de vos autres types, vous devez appeler la méthode “RegisterMessageCallbacks” en passant en paramètre l&rsquo;instance ou le type à enregistrer :</p>
<p></p><pre class="crayon-plain-tag">PackageHost.RegisterMessageCallbacks(source);</pre><p></p>
<h3>Testez vos MessageCallbacks depuis la Console Constellation</h3>
<p>Si vous <a href="/constellation-platform/constellation-sdk/publier-package-visual-studio/">publiez votre package</a> ou <a href="/getting-started/creez-votre-premier-package-constellation-en-csharp/">démarrer votre package depuis VS</a>  avec les trois méthodes ci-dessus, vous retrouverez ces trois MessageCallbacks dans <a href="/constellation-platform/constellation-console/messagecallbacks-explorer/">l’explorateur </a>:</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-116.png"><img class="colorbox-1343"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="MessageCallback Explorer" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-93.png" alt="MessageCallback Explorer" width="424" height="191" border="0" /></a></p>
<p align="left">Tout y est décrit, y compris les types complexes :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-117.png"><img class="colorbox-1343"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Description des types" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-94.png" alt="Description des types" width="424" height="165" border="0" /></a></p>
<p align="left">Vous pourrez alors directement tester vos MC depuis la Console :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-118.png"><img class="colorbox-1343"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="MessageCallback Explorer" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-95.png" alt="MessageCallback Explorer" width="424" height="58" border="0" /></a></p>
<p align="left">Ce qui compte tenu du code donné en exemple ci-dessus affichera des messages dans les logs Constellation visible sur la <a href="/constellation-platform/constellation-console/console-log/">Console Log</a> :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-119.png"><img class="colorbox-1343"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Demo" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-96.png" alt="Demo" width="424" height="25" border="0" /></a></p>
<h3 align="left">Personnaliser le nom du MessageCallback</h3>
<p align="left">Vous pouvez également changer le nom du MessageCallback sans forcement changer le nom de votre méthode :</p>
<p></p><pre class="crayon-plain-tag">[MessageCallback(Key="Logon")]
void MyMethodWithComplexParameter(UserInfo user)
{
    PackageHost.WriteInfo("User: {0} &amp; Password = {1}", user.User, user.Password);
}</pre><p></p>
<p align="left">Ici la méthode se nomme toujours “MyMethodWithComplexParameter” dans notre code C# mais est vue dans Constellation comme le MessageCallback nommé “Logon” :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-120.png"><img class="colorbox-1343"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="MessageCallback Explorer" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-97.png" alt="MessageCallback Explorer" width="424" height="212" border="0" /></a></p>
<h3 align="left">MessageCallback caché</h3>
<p align="left">Vous pouvez aussi exposer des MessageCallbacks que vous ne souhaitez “rendre publique”. En d&rsquo;autre mots, vous ne souhaitez pas que votre MC soit référencé dans la description de votre package.</p>
<p align="left">Exemple : vous avez un package qui envoie des messages à un groupe pour prévenir de l’arrivée d’un événement (ex: le téléphone sonne). Vous souhaitez, dans le code de votre package, déclencher une méthode lorsque cet événement se produit. Autrement dit, vous créez une méthode marquée “MessageCallback“ qui porte le même nom que le MessageKey envoyé par l’autre package (le même nom de méthode ou via la propriété Key comme vu ci-dessus).</p>
<p align="left">Ainsi, comme votre package fait partie du groupe cible, lorsque le téléphone sonne, l’autre package envoie un message au groupe, vous recevez donc le message et comme vous avez un MessageCallback du même nom, votre méthode est invoquée !</p>
<p align="left">C’est parfait à l’exception que tout le monde “voit l’existence” de cette méthode et peuvent tous l’invoquer !</p>
<p align="left">Deux solutions :</p>
<ul>
<li>
<div align="left">Cacher le MessageCallback (= ne pas le déclarer dans la description du package)</div>
</li>
<li>
<div align="left">Vérifier l’émetteur</div>
</li>
</ul>
<p align="left">Pour cacher un MC, il suffit simple de définir la propriété “IsHidden” à vrai :</p>
<p></p><pre class="crayon-plain-tag">[MessageCallback(IsHidden = true)]
void HiddenMethod()
{
    PackageHost.WriteInfo("This is a MessageCallback !");
}</pre><p></p>
<p align="left">Ainsi la méthode, n&rsquo;apparaîtra nulle part, personne ne pourra savoir que votre package “écoute” des messages dont la clé est ici “HiddenMethod”.</p>
<h3 align="left">MessageContext</h3>
<p align="left">Vous pouvez, dans le code d&rsquo;un “MessageCallback”, accéder au contexte du message reçu via la propriété “<em>MessageContext.Current</em>”.</p>
<p align="left">Le contexte du message contient notamment le MessageSender (identifié de l’émetteur du message) et le MessageScope (scope dans lequel le message a été envoyé ).</p>
<p align="left">Par exemple on pourrait écrire :</p>
<p></p><pre class="crayon-plain-tag">[MessageCallback(IsHidden = true)]
void HiddenMethod()
{
    if(MessageContext.Current.Sender.FriendlyName == "SENTINEL-DEMO/MySafePackage")
    {
        PackageHost.WriteInfo("OK j’autorise le package MySafePackage de la sentinelle SENTINEL-DEMO");
    }
    else
    {
        PackageHost.WriteWarn("Je refuse que {0} puisse invoquer cette méthode !", MessageContext.Current.Sender.FriendlyName);
    }
}</pre><p></p>
<h3>Répondre à une saga</h3>
<p>Comme nous l’avons vu dans les concepts, il est possible de répondre à un message en renvoyant un message avec le même identifiant de saga. De ce fait, un MessageCallback peut renvoyer une réponse.</p>
<p>Dans la pratique, il suffit de regarder dans le contexte du message si c’est une saga (c’est à dire que le scope porte un identifiant de saga). Si c’est une saga, vous pouvez appeler la méthode d’extension “<em>SendResponse</em>” qui se chargera pour vous d’envoyer le contenu de votre message dans un scope portant le même identifiant de saga et à destination du package émetteur.</p>
<p>De plus, pour indiquer que le MessageCallback répond aux sagas, on indique quel est le type de l’objet de réponse dans l&rsquo;attribut [MessageCallback] avec la propriété <em>ResponseType</em>.</p>
<p>Par exemple :</p>
<p></p><pre class="crayon-plain-tag">[MessageCallback(Key="Logon", ResponseType=typeof(bool))]
void MyMethodWithComplexParameter(UserInfo user)
{
    PackageHost.WriteInfo("User: {0} &amp; Password = {1}", user.User, user.Password);

    if (MessageContext.Current.IsSaga)
    {
        MessageContext.Current.SendResponse(user.User == user.Password);
    }
}</pre><p></p>
<p>Avec Constellation 1.8, la syntaxe est encore plus simple. Vous pouvez simplement écrire votre MessageCallback avec une fonction .NET, c&rsquo;est à dire une méthode qui retourne (<em>return</em>) une valeur :</p>
<p></p><pre class="crayon-plain-tag">[MessageCallback(Key="Logon")]
bool MyMethodWithComplexParameter(UserInfo user)
{
    PackageHost.WriteInfo("User: {0} &amp; Password = {1}", user.User, user.Password);

    return user.User == user.Password;
}</pre><p></p>
<p>La propriété “ResponseType” du MessageCallback est automatiquement définie avec le type de retour de la méthode. C’est l’API .NET qui se chargera d’envoyer la réponse si le message est reçu est une saga. La réponse renvoyée étant l’objet retourné par votre méthode, dans l’exemple ci-dessus un booléen.</p>
<p>Ainsi en republiant le package avec le code ci-dessus, vous constaterez dans le <a href="/constellation-platform/constellation-console/messagecallbacks-explorer/">MessageCallbacks Explorer</a> que votre MessageCallback indique son type de réponse dans le cas d&rsquo;une saga :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-121.png"><img class="colorbox-1343"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="MessageCallback avec saga" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-98.png" alt="MessageCallback avec saga" width="424" height="209" border="0" /></a></p>
<p align="left">Vous pourrez alors tester votre MessageCallback :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-122.png"><img class="colorbox-1343"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Envoyer un message dans une saga" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-99.png" alt="Envoyer un message dans une saga" width="424" height="244" border="0" /></a></p>
<p align="left">Et visualisez le message de retour, ici un booléen :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-123.png"><img class="colorbox-1343"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Réponse d'une saga" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-100.png" alt="Réponse d'une saga" width="424" height="438" border="0" /></a></p>
<h3>Décrire ses MessageCallbacks</h3>
<p>Pour finir il est vivement conseillé de décrire ses MessageCallbacks et les types utilisés en paramètre ou en réponse.</p>
<p>Vous avez deux possibilités :</p>
<ul>
<li>Utilisez la propriété “Description” sur l’attribut MessageCallback (mais limité aux MC et non aux types)</li>
<li>Utilisez les commentaires de documentation XML</li>
</ul>
<p>Pour gagner en productivité, je vous recommande l’extension Visual Studio <a href="http://submain.com/products/ghostdoc.aspx">GhostDoc de SubMain</a> pour générer automatiquement des commentaires de documentation XML dans votre code .NET.</p>
<p>Ainsi ajoutons des commentaires de documentation XML sur nos MessageCallbacks et sur la classe UserInfo utilisée dans nos exemples comme paramètre de notre MC :</p>
<p></p><pre class="crayon-plain-tag">/// &lt;summary&gt;
/// Methode d'identification d'un utilisateur.
/// &lt;/summary&gt;
/// &lt;param name="user"&gt;L'utilisateur à identifier.&lt;/param&gt;
/// &lt;returns&gt;&lt;c&gt;true&lt;/c&gt; si identifié&lt;/returns&gt;
[MessageCallback(Key="Logon")]
bool MyMethodWithComplexParameter(UserInfo user)
{
    PackageHost.WriteInfo("User: {0} &amp; Password = {1}", user.User, user.Password);

    return user.User == user.Password;
}

/// &lt;summary&gt;
/// Classe decrivrant un utilisateur
/// &lt;/summary&gt;
public class UserInfo
{
    /// &lt;summary&gt;
    /// Le nom d'utilisateur
    /// &lt;/summary&gt;
    public string User { get; set; }

    /// &lt;summary&gt;
    /// Le mot de passe de l'utilisateur
    /// &lt;/summary&gt;
    public string Password { get; set; }
}</pre><p></p>
<p>Si vous redéployez le package, vous observerez que l&rsquo;ensemble des MessageCallbacks et des paramètres sont décrits par vos commentaires XML :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-124.png"><img class="colorbox-1343"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="MessageCallback documenté" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-101.png" alt="MessageCallback documenté" width="424" height="128" border="0" /></a></p>
<h3>S’abonner et recevoir les messages d’un groupe</h3>
<p>Comme <a href="/concepts/messaging-message-scope-messagecallback-saga/">vous le savez</a>, il existe plusieurs type de scope pour recevoir un message. Par défaut votre package recevra les messages adressés au scope “All” et “Other” (si il n’est pas l’émetteur du message) mais aussi et surtout ceux destinés au scope de sa sentinelle et/ou de son package.</p>
<p>Il y a un dernier type de scope fort utile : “les groupes”. Pour recevoir des messages destinés à un groupe, il faut d&rsquo;abord s’abonner au groupe.</p>
<p>Vous avez deux manières d’ajouter votre package dans un groupe :</p>
<ul>
<li>Depuis la configuration du serveur</li>
<li>Depuis le code de votre package</li>
</ul>
<p>La première méthode se réalise dans la configuration de votre package directement dans la configuration du serveur Constellation.</p>
<p>Il suffit d’ajouter un élément “group” en indiquant les noms des groupes à rejoindre.</p>
<p></p><pre class="crayon-plain-tag">&lt;sentinel name="PO-SWARIN" credential="StandardAccess"&gt;
    &lt;packages&gt;        
        &lt;package name="HWMonitor" enable="true"&gt;&lt;/package&gt;  
        &lt;package name="ConstellationPackageConsole1" enable="true"&gt;&lt;/package&gt; 
        &lt;package name="MonPremierPackage" enable="true"&gt;
            &lt;groups&gt;
                &lt;group name="MonGroupDemo" /&gt;
            &lt;/groups&gt;
            &lt;settings&gt;
                &lt;setting key="Interval" value="2000" /&gt;
            &lt;/settings&gt;
        &lt;/package&gt;  
    &lt;/packages&gt;                
 &lt;/sentinel&gt;</pre><p></p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/03/image-149.png"><img class="colorbox-1343"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="Ajout de groupe dans la configuration" src="https://developer.myconstellation.io/wp-content/uploads/2016/03/image_thumb-126.png" alt="Ajout de groupe dans la configuration" width="424" height="261" border="0" /></a></p>
<p style="text-align: left;" align="center">Vous pouvez aussi utiliser<a href="/constellation-platform/constellation-console/gerer-packages-avec-la-console-constellation/#Editer_les_groupes_dun_package"> la Console Constellation pour éditer les groupes</a> de chaque package.</p>
<p align="left">Autre manière, directement dans votre code en utilisant la méthode “<em>PackageHost.SubscribeMessages</em>” (ou <em>PackageHost.UnsubscribeMessages</em>).</p>
<p align="left">Par exemple :</p>
<p></p><pre class="crayon-plain-tag">PackageHost.SubscribeMessages("MonGroupDemo");</pre><p></p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/client-api/net-package-api/messagecallbacks/">MessageCallbacks : exposez vos méthodes</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://developer.myconstellation.io/client-api/net-package-api/messagecallbacks/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Contrôler votre Constellation en Javascript</title>
		<link>https://developer.myconstellation.io/client-api/javascript-api/controler-constellation-api-javascript/</link>
					<comments>https://developer.myconstellation.io/client-api/javascript-api/controler-constellation-api-javascript/#respond</comments>
		
		<dc:creator><![CDATA[Sebastien Warin]]></dc:creator>
		<pubDate>Thu, 18 Aug 2016 14:48:37 +0000</pubDate>
				<category><![CDATA[Javascript API]]></category>
		<category><![CDATA[StateObject]]></category>
		<category><![CDATA[Package]]></category>
		<category><![CDATA[ControlHub]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[PurgeStateObject]]></category>
		<category><![CDATA[PackageDescriptor]]></category>
		<category><![CDATA[AngularJS]]></category>
		<category><![CDATA[Controller]]></category>
		<category><![CDATA[Hub]]></category>
		<guid isPermaLink="false">https://developer.myconstellation.io/?p=2329</guid>

					<description><![CDATA[<p>Le hub de contrôle expose des méthodes pour contrôler la Constellation comme arrêter/démarrer des packages, s’abonner et récupérer en temps réel les logs des packages de la Constellation, propager les changements de configuration dans la Constellation, suivre les états et</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/client-api/javascript-api/controler-constellation-api-javascript/">Contrôler votre Constellation en Javascript</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Le <a href="/concepts/les-diffrents-types-de-hub-et-interfaces-rest-du-serveur-constellation/">hub de contrôle</a> expose des méthodes pour contrôler la Constellation comme arrêter/démarrer des packages, s’abonner et récupérer en temps réel les logs des packages de la Constellation, propager les changements de configuration dans la Constellation, suivre les états et la consommation de ressource des packages, etc…</p>
<p>Les deux librairies JavaScript Constellation intègrent un client permettant de se connecter sur ce hub afin de pouvoir piloter votre Constellation. La Console Constellation est d’ailleurs basée sur ce client.</p>
<p>Dans cet article découvrons les fonctionnalités de ce client avec l’API JavaScript et l’API AngularJS.</p>
<h3>Connecter une page HTML au hub de contrôle</h3>
<h4>Etape 1 : Ajouter les librairies</h4>
<h5>En utilisant le CDN</h5>
<p>Les librairies JavaScripts sont accessibles sur : <a href="http://cdn.myconstellation.io/js/">http://cdn.myconstellation.io/js/</a> (en HTTP ou HTTPS).</p>
<p>Pour utiliser la librairie JavaScript :</p>
<p></p><pre class="crayon-plain-tag">&lt;script type="text/javascript" src="https://code.jquery.com/jquery-2.2.4.min.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="https://ajax.aspnetcdn.com/ajax/signalr/jquery.signalr-2.2.2.min.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="https://cdn.myconstellation.io/js/Constellation-1.8.2.min.js"&gt;&lt;/script&gt;</pre><p></p>
<p>Ou si vous souhaitez l&rsquo;utiliser avec le framework AngularJS :</p>
<p></p><pre class="crayon-plain-tag">&lt;script type="text/javascript" src="https://code.jquery.com/jquery-2.2.4.min.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="https://ajax.aspnetcdn.com/ajax/signalr/jquery.signalr-2.2.2.min.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="https://cdn.myconstellation.io/js/Constellation-1.8.2.min.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" src="https://cdn.myconstellation.io/js/ngConstellation-1.8.2.min.js"&gt;&lt;/script&gt;</pre><p></p>
<h5>Par Nuget en utilisant Visual Studio</h5>
<p>Dans Visual Studio et ouvrez le gestionnaire de package NuGet.</p>
<p>En sélectionnant la source “Constellation”, installez le package Nuget “Constellation.Javascript” pour l’API JavaScript ou “Constellation.AngularJS” pour l’API AngularJS :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/08/image-12.png"><img class="colorbox-2329"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/08/image_thumb-12.png" alt="image" width="354" height="122" border="0" /></a></p>
<h4>Etape 2 : Connexion au hub de contrôle</h4>
<p>Avec l’API JavaScript (JS) vous devez créer le client avec la méthode “createConstellationController” en spécifiant l’URL de votre Constellation, une clé d’accès et un friendly name :</p>
<p></p><pre class="crayon-plain-tag">var controller = $.signalR.createConstellationController("http://localhost:8088", "123456789", "TestAPI");
controller.connection.stateChanged(function (change) {
  if (change.newState === $.signalR.connectionState.connected) {
    console.log("Connected to the ControlHub");
  }
});
controller.connection.start();</pre><p></p>
<p>Avec l’API AngularJS (NG), vous devez injecter le client “constellationController” dans votre contrôleur puis l’initialiser avec la méthode “initializeClient” en spécifiant l’URL de votre Constellation, une clé d’accès et un friendly name :</p>
<p></p><pre class="crayon-plain-tag">var demo = angular.module('demoApp', ['ngConstellation']);
demo.controller('MyController', ['$scope',  'constellationController', function ($scope, controller) {

  controller.initializeClient("http://localhost:8088", "123456789", "TestAPI");
    
  controller.onConnectionStateChanged(function (change) {
    if (change.newState === $.signalR.connectionState.connected) {
      console.log("Connected to the ControlHub");
    }
  });
    
  controller.connect();
}]);</pre><p></p>
<p>La clé d’accès (<a href="/concepts/securite-accesskey-credential-authorization/">AccessKey</a>) utilisée pour se connecter au hub de contrôle doit avoir l’attribut “enableControlHub” à “true”. Vous pouvez <a href="/constellation-platform/constellation-console/gerer-credentials-avec-la-console-constellation/">gérer les credentials dans la Console Constellation</a> ou dans <a href="/constellation-platform/constellation-server/fichier-de-configuration/#Section_credentials">le fichier de configuration</a>.</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-35.png"><img class="colorbox-2329"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-34.png" alt="image" width="350" height="287" border="0" /></a></p>
<h3>Superviser les sentinelles</h3>
<p>Vous disposez de deux méthodes :</p>
<ul>
<li>requestSentinelsList() : pour recevoir la liste des sentinelles de votre Constellation</li>
<li>requestSentinelUpdates() : pour recevoir toutes les mises à jour des sentinelles de votre Constellation (ajout ou suppression de sentinelles, connexion ou déconnexion des sentinelles, mise à jour des informations, etc…).</li>
</ul>
<p>Ces deux méthodes sont de type “void”. Les réponses sont réceptionnées par les handlers respectivement nommés ”onUpdateSentinelsList” et “onUpdateSentinel”.</p>
<ul>
<li>Avec l’API JS :</li>
</ul>
<p></p><pre class="crayon-plain-tag">controller.client.onUpdateSentinelsList(function (list) {
  console.log(list);
});

controller.client.onUpdateSentinel(function (sentinel) {
  console.log(sentinel);
});

controller.connection.onConnectionStateChanged(function (change) {
  if (change.newState === $.signalR.connectionState.connected) {
    controller.server.requestSentinelsList();
    controller.server.requestSentinelUpdates();
  }
}</pre><p></p>
<ul>
<li>Avec l’API NG :</li>
</ul>
<p></p><pre class="crayon-plain-tag">controller.onUpdateSentinelsList (function (list) {
  console.log(list);
});

controller.onUpdateSentinel  (function (se) {
  console.log(se);
});

controller.onConnectionStateChanged(function (change) {
  if (change.newState === $.signalR.connectionState.connected) {
    controller.requestSentinelsList();
    controller.requestSentinelUpdates ();
  }
});</pre><p></p>
<p>Par exemple utilisons l’API NG pour créer une page affichant l’ensemble des sentinelles avec leur statuts en temps dans une page :</p>
<p>Dans le code du contrôleur, ajoutons un handler sur la mise à jour sentinelle afin de stocker les objets “sentinelle” dans une variable  de scope :</p>
<p></p><pre class="crayon-plain-tag">$scope.sentinels = {};
controller.onUpdateSentinel  (function (sentinel) {
  $scope.$apply(function() {
    $scope.sentinels[sentinel.Description.SentinelName.replace("-", "")] = sentinel;
  });
});</pre><p></p>
<p>Nous sommes obligé de faire un “<em>replace(« -« , «  »)</em>” car nous utilisons le nom de la sentinelle comme nom pour la propriété de notre variable de scope, or en JavaScript une propriété ou variable ne peut pas comporter de “-“.</p>
<p>Lors de la connexion, abonnons-nous aux mises à jour des sentinelles afin de maintenir notre page à jour :</p>
<p></p><pre class="crayon-plain-tag">controller.onConnectionStateChanged(function (change) {
  if (change.newState === $.signalR.connectionState.connected) {
    console.log("Connected to the ControlHub");
    controller.requestSentinelUpdates ();
  }
});</pre><p></p>
<p>Enfin dans le template HTML affichons nos différentes sentinelles dans une simple liste à puce :</p>
<p></p><pre class="crayon-plain-tag">&lt;ul&gt;
  &lt;li ng-repeat="s in sentinels"&gt;{{s.Description.SentinelName}} [{{s.IsConnected ? "CONNECTED" : "DISCONNECTED"}}] ({{s.Description.OSVersion}})&lt;/li&gt;
&lt;/ul&gt;</pre><p></p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-36.png"><img class="colorbox-2329"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-35.png" alt="image" width="350" height="160" border="0" /></a></p>
<p>Veuillez noter que seule les sentinelles “<a href="/concepts/sentinels-packages-virtuels/">réelles</a>” qui se sont connectées au moins une fois peuvent être récupérer car cette technique. Pour les sentinelles qui ne se sont jamais connectées comme pour les <a href="/concepts/sentinels-packages-virtuels/">sentinelles virtuelles</a>, vous devez lire le fichier de configuration en utilisant l’API REST de Management (Management API).</p>
<p>Voici la structure de l’objet ”sentinelle” :</p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-37.png"><img class="colorbox-2329"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-36.png" alt="image" width="350" height="128" border="0" /></a></p>
<h3>Superviser les packages</h3>
<p>Une fois la liste de vos sentinelles connue, vous pouvez récupérer la liste des packages pour chaque sentinelle en invoquant la méthode “requestPackagesList “ et en ajoutant un handler sur le “onUpdatePackageList”.</p>
<ul>
<li>Avec l’API JS :</li>
</ul>
<p></p><pre class="crayon-plain-tag">controller.client.onUpdatePackageList (function (list) {
  console.log(list);
});
controller.server.requestPackagesList("MySentinel");</pre><p></p>
<ul>
<li>Avec l’API NG :</li>
</ul>
<p></p><pre class="crayon-plain-tag">controller.onUpdatePackageList (function (list) {
  console.log(list);
});
controller.requestPackagesList("MySentinel");</pre><p></p>
<p>Reprenons notre page ci-dessus et ajoutons la liste des packages pour chaque sentinelle de notre Constellation.</p>
<p>Dans le handler “onUpdateSentinel” défini dans la section précédente, demandons au hub de contrôle la liste des packages pour chaque sentinelle :</p>
<p></p><pre class="crayon-plain-tag">controller.onUpdateSentinel  (function (sentinel) {
  $scope.$apply(function() {
    $scope.sentinels[sentinel.Description.SentinelName.replace("-", "")] = sentinel;
  });
  controller.requestPackagesList(sentinel.Description.SentinelName);
});</pre><p></p>
<p>Et ajoutons dans notre scope le handler “onUpdatePackageList” de manière à ajouter la liste des packages dans une propriété “Packages” que nous ajouterons dans nos objets “sentinelles” :</p>
<p></p><pre class="crayon-plain-tag">controller.onUpdatePackageList (function (p) {
  $scope.$apply(function() {
    $scope.sentinels[p.SentinelName.replace("-", "")]["Packages"] = p.List;
  });
});</pre><p></p>
<p>Nous pouvons maintenant enrichir notre template pour afficher les packages de chacune de nos sentinelles :</p>
<p></p><pre class="crayon-plain-tag">&lt;ul&gt;
  &lt;li ng-repeat="s in sentinels"&gt;{{s.Description.SentinelName}} [{{s.IsConnected ? "CONNECTED" : "DISCONNECTED"}}] ({{s.Description.OSVersion}})
    &lt;ul&gt;
      &lt;li ng-repeat="p in s.Packages"&gt;{{p.Package.Name}} version {{p.PackageVersion}} [{{p.State}}]&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;</pre><p></p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-38.png"><img class="colorbox-2329"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-width: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-37.png" alt="image" width="350" height="433" border="0" /></a></p>
<h3>Surveiller l’état et la consommation des packages</h3>
<p>La liste de package récupérée ci-dessus n’est pas maintenue à jour. Pour recevoir les mises à jour de vos packages afin d’être notifié de chaque changement d’état vous pouvez ajouter le handler “onReportPackageState”.</p>
<p>De plus vous pouvez aussi vous abonner aux informations de consommation des ressources de vos packages avec le handler “onReportPackageUsage”.</p>
<ul>
<li>Avec l’API JS :</li>
</ul>
<p></p><pre class="crayon-plain-tag">controller.client.onReportPackageUsage  (function (usage) {
  console.log(usage);
});

controller.client.onReportPackageState  (function (usage) {
  console.log(usage);
});</pre><p></p>
<ul>
<li>Avec l’API NG :</li>
</ul>
<p></p><pre class="crayon-plain-tag">controller.onReportPackageUsage  (function (usage) {
  console.log(usage);
});

controller.onReportPackageState  (function (usage) {
  console.log(usage);
});</pre><p></p>
<p>Par exemple ajoutons dans notre page la consommation de CPU et de RAM pour chaque package de notre Constellation :</p>
<p></p><pre class="crayon-plain-tag">controller.onReportPackageUsage(function (usage) {
  $scope.$apply(function() {
    var sentinelName = usage.SentinelName.replace("-", "");
    for(var idx in $scope.sentinels[sentinelName].Packages) {
      var p = $scope.sentinels[sentinelName].Packages[idx];
      if(p.Package.Name == usage.PackageName) {
        p["CPU"] = usage.CPU;
        p["RAM"] = usage.RAM;
      }
    }
  });
});</pre><p></p>
<p>Dans le code ci-dessus, on ajoute dans chaque objet “Package” la valeur de la consommation du CPU et de RAM.</p>
<p>Ainsi on peut enrichir le template HTML avec le code :</p>
<p></p><pre class="crayon-plain-tag">&lt;ul&gt;
  &lt;li ng-repeat="s in sentinels"&gt;{{s.Description.SentinelName}} [{{s.IsConnected ? "CONNECTED" : "DISCONNECTED"}}] ({{s.Description.OSVersion}})
    &lt;ul&gt;
      &lt;li ng-repeat="p in s.Packages"&gt;{{p.Package.Name}} version {{p.PackageVersion}} [{{p.State}}]
        &lt;ul&gt;
          &lt;li&gt;CPU: {{p.CPU | number : 0 }}% - RAM: {{p.RAM / 1024 / 1024 | number: 0}}Mo&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;</pre><p></p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-39.png"><img class="colorbox-2329"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-38.png" alt="image" width="350" height="452" border="0" /></a></p>
<h3>Contrôler les packages</h3>
<p>Pour contrôler les instances de package vous disposez des méthodes suivantes :</p>
<ul>
<li><em>start(sentinelName, packageName)</em> : démarre un package</li>
<li><em>stop(sentinelName, packageName)</em> : arrête un package</li>
<li><em>restart(sentinelName, packageName)</em> : redémarre un package</li>
<li><em>reload(sentinelName, packageName)</em> : arrête un package, force la sentinelle à télécharger la dernière version du package sur le serveur et redémarre le package</li>
<li><em>updatePackageSettings(sentinelName, packageName)</em> : pousse les settings d’un package au package en cours de fonctionnement (à charge au package à prendre en compte ses nouveaux paramètres).</li>
</ul>
<p>Avec l’API JS :</p>
<p></p><pre class="crayon-plain-tag">controller.server.start(sentinelName, packageName);
controller.server.stop(sentinelName, packageName);
controller.server.restart(sentinelName, packageName);
controller.server.reload(sentinelName, packageName);
controller.server.updatePackageSettings(sentinelName, packageName);</pre><p></p>
<p>Avec l’API NG :</p>
<p></p><pre class="crayon-plain-tag">controller.start(sentinelName, packageName);
controller.stop(sentinelName, packageName);
controller.restart(sentinelName, packageName);
controller.reload(sentinelName, packageName);
controller.updatePackageSettings(sentinelName, packageName);</pre><p></p>
<p>Par exemple ajoutons dans notre page la possibilité de piloter les packages.</p>
<p>Pour ce faire exposons notre client “controller” dans le scope Angular de façon à pouvoir l’utiliser dans le template HTML :</p>
<p></p><pre class="crayon-plain-tag">$scope.controller = controller;</pre><p></p>
<p>Dans notre template ajoutons ensuite des boutons en spécifiant l&rsquo;action du clic grâce à l&rsquo;attribut “ng-click” :</p>
<p></p><pre class="crayon-plain-tag">&lt;button ng-click="controller.start(s.Description.SentinelName, p.Package.Name)"&gt;Start&lt;/button&gt;
&lt;button ng-click="controller.stop(s.Description.SentinelName, p.Package.Name)"&gt;Stop&lt;/button&gt;
&lt;button ng-click="controller.reload(s.Description.SentinelName, p.Package.Name)"&gt;Reload&lt;/button&gt;
&lt;button ng-click="controller.restart(s.Description.SentinelName, p.Package.Name)"&gt;Restart&lt;/button&gt;</pre><p></p>
<p>Pour aller plus loin on peut également afficher/cacher les boutons en fonction de l’état du package, par exemple ne pas afficher le bouton “Start” si le package est déjà démarré :</p>
<p></p><pre class="crayon-plain-tag">&lt;button ng-hide="p.State == 'Started'" ng-click="controller.start(s.Description.SentinelName, p.Package.Name)"&gt;Start&lt;/button&gt;
&lt;button ng-show="p.State == 'Started'" ng-click="controller.stop(s.Description.SentinelName, p.Package.Name)"&gt;Stop&lt;/button&gt;
&lt;button ng-click="controller.reload(s.Description.SentinelName, p.Package.Name)"&gt;Reload&lt;/button&gt;
&lt;button ng-show="p.State == 'Started'" ng-click="controller.restart(s.Description.SentinelName, p.Package.Name)"&gt;Restart&lt;/button&gt;</pre><p></p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-40.png"><img class="colorbox-2329"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-39.png" alt="image" width="350" height="261" border="0" /></a></p>
<h3>S’abonner aux logs de Constellation</h3>
<p>Pour récupérer les logs produits par les packages (virtuels ou non) en temps réel dans votre page Web, vous devez ajouter un handler sur “onReceiveLogMessage”.</p>
<ul>
<li>Avec l’API JS :</li>
</ul>
<p></p><pre class="crayon-plain-tag">controller.client.onReceiveLogMessage(function (log) {
  console.log(log);
});</pre><p></p>
<ul>
<li>Avec l’API NG :</li>
</ul>
<p></p><pre class="crayon-plain-tag">controller.onReceiveLogMessage(function (log) {
  console.log(log);
});</pre><p></p>
<p>Par exemple ajoutons à notre page la capacité d’afficher les logs des packages de notre Constellation en temps réel.</p>
<p>Pour cela nous allons nous abonner aux logs et les stocker dans un tableau de notre scope Angular :</p>
<p></p><pre class="crayon-plain-tag">$scope.logs = [];
controller.onReceiveLogMessage(function (log) {
  $scope.$apply(function() {
    $scope.logs.push(log);
  });
});</pre><p></p>
<p>Nous pouvons donc maintenant afficher proprement nos logs dans notre template HTML :</p>
<p></p><pre class="crayon-plain-tag">&lt;ul&gt;
  &lt;li ng-repeat="log in logs"&gt;{{log.Date | date: 'dd/MM/yyyy HH:mm:ss' }} on {{log.SentinelName}}/{{log.PackageName}} : [{{ log.Level.toUpperCase() }}] {{log.Message}}&lt;/li&gt;
&lt;/ul&gt;</pre><p></p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-41.png"><img class="colorbox-2329"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-40.png" alt="image" width="350" height="194" border="0" /></a></p>
<h3>Récupérer les PackageDescriptors</h3>
<p>Le <a href="/concepts/messaging-message-scope-messagecallback-saga/#Auto-description_des_MessageCallbacks">PackageDescriptor</a> est un objet publié par les packages qui permet de décrire les MessagesCallbacks que les packages exposent ainsi que les types utilisés dans leurs MC et StateObjects.</p>
<p>Pour récupérer un PackageDescriptor vous devez invoquer la méthode ”requestPackageDescriptor” en spécifiant le nom du package et attacher un handler “onUpdatePackageDescriptor” pour récupérer le résultat.</p>
<ul>
<li>Avec l’API JS :</li>
</ul>
<p></p><pre class="crayon-plain-tag">controller.client.onUpdatePackageDescriptor(function (descriptor) {
  console.log(descriptor);
});

controller.server.requestPackageDescriptor(packageName);</pre><p></p>
<ul>
<li>Avec l’API NG :</li>
</ul>
<p></p><pre class="crayon-plain-tag">controller.onUpdatePackageDescriptor(function (descriptor) {
  console.log(descriptor);
});

controller.requestPackageDescriptor(packageName);</pre><p></p>
<p>Par exemple sur notre page ci-dessus, ajoutons un bouton permettant d’afficher dans une simple boite de dialogue la liste des MessageCallbacks d’un package :</p>
<p>Dans le template HTML :</p>
<p></p><pre class="crayon-plain-tag">&lt;button ng-click="controller.requestPackageDescriptor(p.Package.Name)"&gt;Show MessageCallbacks&lt;/button&gt;</pre><p></p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-42.png"><img class="colorbox-2329"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-41.png" alt="image" width="350" height="144" border="0" /></a></p>
<p align="left">Et dans le code de notre contrôleur, de manière grossière :</p>
<p></p><pre class="crayon-plain-tag">controller.onUpdatePackageDescriptor(function (descriptor) {
  var result = "Package "+ descriptor.PackageName + " :";
  for(var idx in descriptor.Descriptor.MessageCallbacks) {
    result += "\n - " + descriptor.Descriptor.MessageCallbacks[idx].MessageKey;
  }
  alert(result);          
});</pre><p></p>
<p align="center"><a href="https://developer.myconstellation.io/wp-content/uploads/2016/09/image-43.png"><img class="colorbox-2329"  loading="lazy" style="background-image: none; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border: 0px;" title="image" src="https://developer.myconstellation.io/wp-content/uploads/2016/09/image_thumb-42.png" alt="image" width="350" height="195" border="0" /></a></p>
<p align="left">Une <a href="/client-api/rest-api/interface-rest-constellation/#Declarer_le_Package_Descriptor">description plus détaillée des PackageDesciptors</a> se trouve <a href="/client-api/rest-api/interface-rest-constellation/#Declarer_le_Package_Descriptor">ici</a>.</p>
<h3>Effacer des StateObjects</h3>
<p>Vous pouvez effacer des StateObjects en invoquant la méthode “purgeStateObjects” :</p>
<ul>
<li>Avec l’API JS :</li>
</ul>
<p></p><pre class="crayon-plain-tag">controller.server.purgeStateObjects(sentinelName, packageName, name, type);</pre><p></p>
<ul>
<li>Avec l’API NG :</li>
</ul>
<p></p><pre class="crayon-plain-tag">controller.purgeStateObjects(sentinelName, packageName, name, type);</pre><p></p>
<p>Vous devez indiquer les filtres de sélection des StateObjects à supprimer avec la possibilité d’utiliser le wildcard ”*” seulement pour les paramètres “name” et “type”. Autrement dit vous êtes obliger de spécifier le “sentinelName” et “packageName”.</p>
<h3>Rafraichir et déployer la configuration</h3>
<p>Vous pouvez recharger la configuration Constellation avec la méthode “reloadServerConfiguration” :</p>
<ul>
<li>Avec l’API JS :</li>
</ul>
<p></p><pre class="crayon-plain-tag">controller.server.reloadServerConfiguration(deployConfiguration);</pre><p></p>
<ul>
<li>Avec l’API NG :</li>
</ul>
<p></p><pre class="crayon-plain-tag">controller.reloadServerConfiguration(deployConfiguration);</pre><p></p>
<p>Cette méthode attend un booléen (deployConfiguration) pour indiquer si oui ou non la configuration doit être déployée après son rechargement. Dans le cas d’un déploiement, la nouvelle configuration est envoyée à toutes les sentinelles et packages de votre Constellation.</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/client-api/javascript-api/controler-constellation-api-javascript/">Contrôler votre Constellation en Javascript</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://developer.myconstellation.io/client-api/javascript-api/controler-constellation-api-javascript/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>L&#8217;interface REST « Constellation »</title>
		<link>https://developer.myconstellation.io/client-api/rest-api/interface-rest-constellation/</link>
					<comments>https://developer.myconstellation.io/client-api/rest-api/interface-rest-constellation/#comments</comments>
		
		<dc:creator><![CDATA[Sebastien Warin]]></dc:creator>
		<pubDate>Tue, 16 Aug 2016 08:51:20 +0000</pubDate>
				<category><![CDATA[REST API]]></category>
		<category><![CDATA[SendMessage]]></category>
		<category><![CDATA[PushStateObject]]></category>
		<category><![CDATA[Package]]></category>
		<category><![CDATA[REST]]></category>
		<category><![CDATA[WriteLog]]></category>
		<category><![CDATA[Setting]]></category>
		<category><![CDATA[Settings]]></category>
		<category><![CDATA[PurgeStateObject]]></category>
		<category><![CDATA[MessageCallback]]></category>
		<category><![CDATA[PackageDescriptor]]></category>
		<category><![CDATA[Saga]]></category>
		<category><![CDATA[AccessKey]]></category>
		<category><![CDATA[HTTP]]></category>
		<category><![CDATA[Virtuel]]></category>
		<category><![CDATA[Credential]]></category>
		<category><![CDATA[Authorization]]></category>
		<category><![CDATA[group]]></category>
		<category><![CDATA[Request]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[Subscribe]]></category>
		<guid isPermaLink="false">https://developer.myconstellation.io/?p=2296</guid>

					<description><![CDATA[<p>L’interface REST “Constellation” est une API HTTP permettant d’exposer les fonctionnalités de base pour les packages “virtuels”. Avec cette interface vous pourrez via des requêtes HTTP : Publier, consommer ou purger des StateObjects Envoyer et recevoir des messages Récupérer les</p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/client-api/rest-api/interface-rest-constellation/">L&rsquo;interface REST « Constellation »</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>L’interface REST “Constellation” est une API HTTP permettant d’exposer les fonctionnalités de base pour les <a href="/concepts/sentinels-packages-virtuels/">packages “virtuels”</a>.</p>
<p>Avec cette interface vous pourrez via des requêtes HTTP :</p>
<ul>
<li>Publier, consommer ou purger des StateObjects</li>
<li>Envoyer et recevoir des messages</li>
<li>Récupérer les settings du package « virtuel »</li>
<li>Produire des logs</li>
<li>Déclarer le “Package Descriptor” (MessageCallbacks exposés ou les types utilisés par les MC ou SO)</li>
</ul>
<p>De ce fait un script Bash ou Powershell, une page PHP, un Arduino, ESP ou NetDuino, bref n’importe quel système, objet ou langage pouvant effectuer des appels HTTP peut être considéré comme un package (dit virtuel) de votre Constellation et produire ou consommer des StateObjects, envoyer ou recevoir des messages, écrire des logs, etc…</p>
<h3>Généralités</h3>
<h4>Construction de l’URL</h4>
<p>L’URL est :  &lt;Root URI&gt;/rest/constellation/&lt;action&gt;?&lt;paramètres&gt;</p>
<p>Partons du principe que votre Constellation est exposée en HTTP sur le port 8088 (sans path). On retrouvera dans le <a href="/constellation-server/fichier-de-configuration/">fichier de configuration</a> la section suivante :</p>
<p></p><pre class="crayon-plain-tag">&lt;listenUris&gt;
  &lt;uri listenUri="http://+:8088/" /&gt;
&lt;/listenUris&gt;</pre><p></p>
<p>La “Root URI “ est donc “<strong>http://&lt;ip ou dns&gt;:8088/</strong>”.</p>
<p>Par exemple si nous sommes en local, nous pourrions écrire :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/xxxxx</pre><p></p>
<h4>Authentification</h4>
<p>Comme pour toutes les requêtes vers Constellation vous devez impérativement spécifier dans <u>les headers HTTP</u> <strong>ou</strong> dans <u>les paramètres de l’URL</u> (querystring), les paramètres “SentinelName”, “PackageName” et “AccessKey” pour l’authentification.</p>
<p>Ici votre “<a href="/concepts/sentinels-packages-virtuels/">package virtuel</a>” doit être déclaré dans la <a href="/constellation-platform/constellation-server/fichier-de-configuration/">configuration</a> de votre Constellation comme un véritable package, c’est à dire avec une sentinelle (dite virtuelle) et un package qui peut contenir des settings, etc…</p>
<p>Par exemple :</p>
<p></p><pre class="crayon-plain-tag">&lt;sentinels&gt;
  &lt;sentinel name="MyVirtualSentinel" credential="Standard"&gt;
    &lt;packages&gt;        
      &lt;package name="MyVirtualPackage" enable="true"&gt;
        &lt;settings&gt;
          &lt;setting key="IntSetting" value="42" /&gt;
          &lt;setting key="StringSetting" value="sample config value" /&gt;
        &lt;/settings&gt;
      &lt;/package&gt;
    &lt;/packages&gt;
  &lt;/sentinel&gt;
&lt;/sentinels&gt;</pre><p></p>
<p>On a ici déclaré une sentinelle virtuelle “MyVirtualSentinel” qui contient le package virtuelle “MonPackageVirtuel”. Ce package <a href="/concepts/securite-accesskey-credential-authorization/">utilise implicitement l’AccessKey</a> du credential “Standard” déclaré au niveau de la sentinelle.</p>
<p>De ce fait, pour chaque appel on passera les paramètres suivants (dans l’URL ou dans les headers) :</p>
<ul>
<li>SentinelName = MyVirtualSentinel</li>
<li>PackageName = MyVirtualPackage</li>
<li>AccessKey = MyAccessKey (en partant du principe que l’AccessKey déclaré pour le credential “Standard” est “MyAccessKey”)</li>
</ul>
<p>Pour la suite de cet article nous passerons tous les paramètres dans l’URL, ainsi chaque appel sera sous la forme :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/&lt;action&gt;?SentinelName=MyVirtualSentinel&amp;PackageName=MyVirtualPackage&amp;AccessKey=MyAccessKey&amp;&lt;paramètres&gt;</pre><p></p>
<h4>Check Access</h4>
<p>Toutes les API REST de Constellation exposent une méthode en GET “CheckAccess” qui retourne un code HTTP 200 (OK). Cela permet de tester la connexion et l’authentification au serveur Constellation.</p>
<ul>
<li>Action : “CheckAccess” (GET)</li>
<li>Paramètres : aucun</li>
</ul>
<p>Exemple :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/CheckAccess?SentinelName=MyVirtualSentinel&amp;PackageName=MyVirtualPackage&amp;AccessKey=MyAccessKey</pre><p></p>
<h3>Publier des StateObjects</h3>
<ul>
<li>Action : “PushStateObject” (GET ou POST)</li>
<li>En GET, voici les paramètres de l’URL :
<ul>
<li><u>name</u> : le nom du StateObject</li>
<li><u>value</u> : la valeur du StateObject</li>
<li><u>type</u> (optionnel) : le type du StateObject</li>
<li><u>lifetime</u> (optionnel – par défaut 0) : la durée de vie (en seconde) du StateObject avant d’être marqué “expiré”. (0 = durée de vie infinie)<!--EndFragment--></li>
</ul>
</li>
</ul>
<p>Pour publier un StateObject vous devez obligatoirement spécifier son nom (name) et sa valeur (value). La valeur peut être un type simple (un Int, String, bool, etc..) ou un objet complexe formaté en JSON. Optionnellement vous pouvez spécifier le type et la durée de vie de votre SO (en seconde).</p>
<p>Par exemple publions un StateObject nommé “Temperature” dont la valeur est le nombre “21” :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/PushStateObject?SentinelName=MyVirtualSentinel&amp;PackageName=MyVirtualPackage&amp;AccessKey=MyAccessKey&amp;name=Temperature&amp;value=21</pre><p></p>
<p>Autre exemple avec un objet complexe contenant deux propriété (Temperature et Humidity) dont la durée de vie est de 60 secondes et le type nommé “TemperatureHumidity” :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/PushStateObject?SentinelName=MyVirtualSentinel&amp;PackageName=MyVirtualPackage&amp;AccessKey=MyAccessKey&amp;name=Temperature&amp;value={ Temperature: 21, Humidity: 72 }&amp;type=TemperatureHumidity&amp;lifetime=60</pre><p></p>
<p>Si la valeur du StateObject est trop grande pour être passée dans l’URL ou si vous souhaitez ajouter des métadonnées (metadatas) à votre StateObject vous pouvez “poster” le StateObject dans le corps de la requête HTTP en utilisant le verbe “POST” (sans oublier de définir le Content-Type à “application/json”).</p>
<p>Pour publier par un POST le même StateObject en lui ajoutant deux métadonnées :</p>
<p></p><pre class="crayon-plain-tag">POST http://localhost:8088/rest/constellation/PushStateObject?SentinelName=MyVirtualSentinel&amp;PackageName=MyVirtualPackage&amp;AccessKey=MyAccessKey
Host: localhost:8088
Content-Length: 189
Content-Type: application/json

{
  "Name" : "Temperature",
  "Value" : { Temperature: 21, Humidity: 72 },
  "Type" : "TemperatureHumidity",
  "Lifetime" : 60,
  "Metadatas": { "ChipId":"ABC123", "Room":"Garden" }
}</pre><p></p>
<h3>Purger ses StateObjects</h3>
<p>Un package peut supprimer ses StateObjects qu’il produit avec la méthode “PurgeStateObjects”.</p>
<ul>
<li>Action : “PurgeStateObjects” (GET)</li>
<li>Paramètres:
<ul>
<li><u>name</u> (optionnel – par défaut “*”) : le nom du StateObject</li>
<li><u>type</u> (optionnel – par défaut “*”) : le type du StateObject</li>
</ul>
</li>
</ul>
<p>Vous pouvez spécifier le nom du StateObject à supprimer et/ou son type. Par défaut ces deux paramètres sont définis à “*”. C’est à dire que si vous ne précisez rien, tous les StateObjects du package seront purgés.</p>
<ul><!--EndFragment--></ul>
<p>Par exemple pour purger tous les StateObjects de notre package virtuel (instance MyVirtualSentinel/MyVirtualPackage):</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/PurgeStateObjects?SentinelName=MyVirtualSentinel&amp;PackageName=MyVirtualPackage&amp;AccessKey=MyAccessKey</pre><p></p>
<p>Pour purger tous les StateObjects de type “Temperature” de cette même instance :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/PurgeStateObjects?SentinelName=MyVirtualSentinel&amp;PackageName=MyVirtualPackage&amp;AccessKey=MyAccessKey&amp;type=Temperature</pre><p></p>
<p>Ou pour supprimer le StateObject nommé “Demo” :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/PurgeStateObjects?SentinelName=MyVirtualSentinel&amp;PackageName=MyVirtualPackage&amp;AccessKey=MyAccessKey&amp;name=Demo</pre><p></p>
<h3>Ecrire des logs</h3>
<p>Les packages peuvent écrire des logs qui seront remontés dans le hub Constellation.</p>
<ul>
<li>Action : “WriteLog” (GET)</li>
<li>Paramètres:
<ul>
<li><u>message</u> : texte du log</li>
<li><u>level</u> (optionnel – par défaut “Info”) : le niveau du log (Info, Warn ou Error)</li>
</ul>
<p><!--EndFragment--></li>
</ul>
<p>Exemple d’un message “Info” :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/WriteLog?SentinelName=MyVirtualSentinel&amp;PackageName=MyVirtualPackage&amp;AccessKey=MyAccessKey&amp;message=Hello World</pre><p></p>
<p>Exemple pour produire un message d’erreur (Error) :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/WriteLog?SentinelName=MyVirtualSentinel&amp;PackageName=MyVirtualPackage&amp;AccessKey=MyAccessKey&amp;message=Il y  a une erreur ici&amp;level=Error</pre><p></p>
<h3>Récupérer ses settings</h3>
<p>Les settings sont récupérés en invoquant la méthode “GetSettings”.</p>
<ul>
<li>Action : “GetSettings” (GET)</li>
<li>Paramètres:  aucun</li>
</ul>
<p>Par exemple pour récupérer les settings (dictionnaire de clé / valeur) définis pour notre package virtuel :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/GetSettings?SentinelName=MyVirtualSentinel&amp;PackageName=MyVirtualPackage&amp;AccessKey=MyAccessKey</pre><p></p>
<h3>Envoyer des messages</h3>
<ul>
<li>Action : “SendMessage” (GET ou POST)</li>
<li>En GET, voici les paramètres de l’URL :
<ul>
<li><u>scope</u> : le type de scope (All, Other, Group, Sentinel ou Package)</li>
<li><u>args</u> : les arguments du scope (par exemple le nom du groupe, de la sentinelle, du package ou de l’instance du package – plusieurs valeurs possibles séparées par des virgules)</li>
<li><u>key</u> : la clé du message (= la méthode à invoquer)</li>
<li><u>data</u> : le contenu du message (= les arguments de la méthode)</li>
<li><u>sagaId</u> (optionnel) : l’identification de la saga si le message est envoyé dans une saga</li>
</ul>
</li>
</ul>
<p>Vous pouvez également invoquer cette action en POST. Le corps de votre requête contiendra l’objet JSON suivant :</p>
<p></p><pre class="crayon-plain-tag">{
  "Scope" : { "Type" : "&lt;type&gt;", Args: [ "&lt;arg1&gt;", "&lt;args2&gt;", .... ], "SagaId":"Identifiant de la Saga" },
  "Key" : "&lt;Key&gt;",
  "Data" : "&lt;Data&gt;"
}</pre><p></p>
<p>La propriété “SagaId” dans le JSON ci-dessus est optionnelle.</p>
<p>Par exemple pour envoyer un message au package Nest en invoquant la méthode (key) “SetTargetTemperature” avec en paramètre le nombre “21” :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/SendMessage?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123&amp;scope=Package&amp;args=Nest&amp;key=SetTargetTemperature&amp;data=21</pre><p></p>
<p>Ce même MessageCallback “SetTargetTemperature” du package Nest peut être invoqué dans une saga afin de recevoir un accusé de réception :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/SendMessage?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123&amp;scope=Package&amp;args=Nest&amp;key=SetTargetTemperature&amp;data=21&amp;sagaId=123456789</pre><p></p>
<p>Il faudra ensuite “récupérer” les messages reçus (voir dessous) pour lire la réponse à votre saga que nous avons ici identifié par la clé “123456789”.</p>
<h3>Recevoir des messages</h3>
<h4>Créer un abonnement de réception</h4>
<p>Tout d’abord pour recevoir des messages il faut s’abonner aux messages.</p>
<ul>
<li>Action : “SubscribeToMessage” (GET)</li>
<li>Paramètres :
<ul>
<li><u>subscriptionId</u> (optionnel) : identifiant de l’abonnement si déjà connu</li>
</ul>
</li>
</ul>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/SubscribeToMessage?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123</pre><p></p>
<p>Vous obtiendrez en réponse l’ID de votre abonnement, le “Subscription Id”.</p>
<h4>Relever les messages</h4>
<ul>
<li>Action : “GetMessages” (GET)</li>
<li>Paramètres :
<ul>
<li><u>subscriptionId</u> : identifiant de l’abonnement</li>
<li><u>timeout</u> (optionnel – par défaut 60000) : temps maximal en milliseconde de la mise en attente de la requête (entre 1000ms et 120000ms)</li>
<li><u>limit</u> (optionnel – par défaut 0) : nombre maximum de message à retourner pour l’appel</li>
</ul>
</li>
</ul>
<p>Il s’agit d’une requête en “long-polling” c’est à dire que la requête sera “bloquée” sur le serveur tant qu’il n’y a pas de message reçu évitant ainsi de “flooder” en continue le serveur pour savoir si de nouveaux messages sont disponibles ou non. Par défaut la requête est bloquée 60 secondes maximum mais vous pouvez personnaliser cette valeur avec le paramètre “timeout”. Si il y a des messages disponibles, le serveur vous renvoi un tableau JSON avec les messages reçus. Si il n’y a pas de réponse dans le délai spécifié par le paramètre “timeout” (60 secondes par défaut), le tableau retourné sera vide.</p>
<p>A chaque réponse vous devez donc relancer une requête “GetMessages” pour “écouter” les prochains messages qui vont sont destinés.</p>
<p>Il est également possible de limiter le nombre de message dans la réponse avec le paramètre “limit” ce qui peut être utile sur de petits “devices” ne disposant pas de beaucoup de mémoire RAM pour désérialiser de gros tableaux JSON.</p>
<p>Exemple simple :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/GetMessages?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123&amp;subscriptionId=xxxxx</pre><p></p>
<p>Autre exemple en limitant le nombre de message à 2 par appel et en bloquant la requête pendant 10 secondes au maximum :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/GetMessages?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123&amp;subscriptionId=xxxxx&amp;timeout=10000&amp;limit=2</pre><p></p>
<h4>S’abonner à un groupe</h4>
<p>Vous pouvez vous abonner à des groupes pour recevoir les messages envoyés dans ces groupes par l’action “SubscribeToMessageGroup” en précisant le nom du groupe et votre ID d’abonnement.</p>
<ul>
<li>Action : “SubscribeToMessageGroup” (GET)</li>
<li>Paramètres :
<ul>
<li><u>group</u> : le nom du groupe à joindre</li>
<li><u>subscriptionId</u> (optionnel) : identifiant de l’abonnement si déjà connu</li>
</ul>
</li>
</ul>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/SubscribeToMessageGroup?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123&amp;subscriptionId=xxxxx&amp;group=A</pre><p></p>
<p>Comme l’action “SubscribeToMessage”, cette action vous retourne l’ID d’abonnement à utiliser pour l’action “GetMessages”.</p>
<h3>Consommation de StateObjects</h3>
<h4>Request</h4>
<p>Cette méthode permet de récupérer la valeur actuelle d’un ou de plusieurs StateObjects.</p>
<ul>
<li>Action : “RequestStateObjects” (GET)</li>
<li>Paramètres :
<ul>
<li><u>sentinel</u> (optionnel – par défaut “*”): nom de la sentinelle</li>
<li><u>package</u> (optionnel – par défaut “*”) : nom du package</li>
<li><u>name</u> (optionnel – par défaut “*”) : nom du StateObject</li>
<li><u>type</u> (optionnel – par défaut “*”) : type du StateObject</li>
</ul>
</li>
</ul>
<p>Par exemple pour récupérer tous les StateObject de votre Constellation :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/RequestStateObjects?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123</pre><p></p>
<p>Ou seulement ceux produits par le package “HWMonitor” (quelque soit la sentinelle) :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/RequestStateObjects?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123&amp;package=HWMonitor</pre><p></p>
<p>Ou encore tous les StateObjects nommés “/intelcpu/load/0” et produits le package “HWMonitor” (quelque soit la sentinelle) :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/RequestStateObjects?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123&amp;package=HWMonitor&amp;name=/intelcpu/load/0</pre><p></p>
<h4>Subscribe</h4>
<p>Vous pouvez également vous abonner aux mises à jour des StateObjects.</p>
<p>Le principe est le même qu’avec les messages : il faut récupérer un ID d’abonnement et invoquer une méthode en long-polling pour recevoir les mises à jour.</p>
<h5>S’abonner à des StateObjects</h5>
<ul>
<li>Action : “SubscribeToStateObjects” (GET)</li>
<li>Paramètres :
<ul>
<li><u>subscriptionId</u> (optionnel) : identifiant de l’abonnement si déjà connu</li>
<li><u>sentinel</u> (optionnel – par défaut “*”): nom de la sentinelle</li>
<li><u>package</u> (optionnel – par défaut “*”) : nom du package</li>
<li><u>name</u> (optionnel – par défaut “*”) : nom du StateObject</li>
<li><u>type</u> (optionnel – par défaut “*”) : type du StateObject</li>
</ul>
</li>
</ul>
<p>En retour vous obtiendrez l’ID d’abonnement (un GUID).</p>
<p>Par exemple pour s’abonner au SO “/intelcpu/load/0”, produit le package “HWMonitor” sur la sentinelle “MON-PC” :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/SubscribeToStateObjects?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123&amp;sentinel=MON-PC&amp;package=HWMonitor&amp;name=/intelcpu/load/0</pre><p></p>
<p><strong>ATTENTION</strong> : si vous souhaitez “ajouter” des SO à votre abonnement vous devez <u>impérativement</u> préciser votre ID d’abonnement récupéré lors du 1er appel autrement vous allez créer un nouvel abonnement.</p>
<p>Par exemple pour “ajouter” le SO correspondant à la consommation RAM :</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/SubscribeToStateObjects?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123&amp;sentinel=MON-PC&amp;package=HWMonitor&amp;name=/ram/load&amp;subscriptionId=&lt;subId&gt;</pre><p></p>
<h5>Relever les StateObjects mis à jour</h5>
<p>Pour récupérer les SO de votre abonnement qui ont changés entre deux appels vous devez invoquer l’action “GetStateObjects” en spécifiant l’ID de votre abonnement :</p>
<ul>
<li>Action : “GetStateObjects” (GET)</li>
<li>Paramètres :
<ul>
<li><u>subscriptionId</u> : identifiant de l’abonnement</li>
<li><u>timeout</u> (optionnel – par défaut 60000) : temps maximal en milliseconde de la mise en attente de la requête (entre 1000ms et 120000ms)</li>
<li><u>limit</u> (optionnel – par défaut 0) : nombre maximum de message à retourner pour l’appel</li>
</ul>
</li>
</ul>
<p>Comme pour les messages, vous pouvez limiter le nombre de SO (limit) et le timeout de la requête (timeout).</p>
<p></p><pre class="crayon-plain-tag">http://localhost:8088/rest/constellation/GetStateObjects?SentinelName=Consumer&amp;PackageName=Demo&amp;AccessKey=MaCleDeTest123&amp;subscriptionId=&lt;subId&gt;</pre><p></p>
<p>Notez que si un StateObject pour lequel vous êtes abonné change plusieurs fois entre deux appels “GetStateObjects”, vous obtiendrez la dernière valeur et non l’historique de tous les changements.</p>
<h3>Déclarer le “Package Descriptor”</h3>
<p>Action : “DeclarePackageDescriptor” (POST)</p>
<p>Le “<a href="/concepts/messaging-message-scope-messagecallback-saga/#Auto-description_des_MessageCallbacks">Package Descriptor</a>” permet décrire les MessagesCallbacks d’un package ainsi que les types utilisés par ses MC ou StateObjects.</p>
<p>Ainsi en publiant le PackageDescriptor, la Constellation aura connaissance des MessageCallbacks qu’expose un package ainsi que le type des StateObject qu’il publie. C’est grâce au Package Descriiptor que fonctionne le “MessageCallback Explorer” de la Console Constellation.</p>
<p>Le Package Descriptor est un objet JSON contenant :</p>
<ul>
<li>Le nom du package</li>
<li>La liste des MessageCallbacks du package</li>
<li>La liste des types utilisés par les MessageCallbacks du package</li>
<li>La liste des types utilisés par les StateObjects publiés par le package</li>
</ul>
<p>La structure de base est donc :</p>
<p></p><pre class="crayon-plain-tag">{
  "PackageName": "MyVirtualPackage",
  "MessageCallbacks": [],
  "MessageCallbackTypes": [],
  "StateObjectTypes": [],
}</pre><p></p>
<p>Chaque “MessageCallback” est un objet contenant :</p>
<ul>
<li><u>MessageKey</u> : la clé du message (le nom/clé du MessageCallback)</li>
<li><u>Description</u> (optionnel) : description du MessageCallback</li>
<li><u>ResponseType</u> (optionnel) : le type du message de retour dans le cas où le MC répond au Saga</li>
<li><u>Parameters</u> (optionnel) : la liste des paramètres du MC</li>
</ul>
<p>Un paramètre est décrit par un objet contenant :</p>
<ul>
<li><u>Name</u> : le nom du paramètre</li>
<li><u>TypeName</u> : le type du paramètre</li>
<li><u>Description</u> (optionnel) : la description du paramètre</li>
<li><u>Type</u> : le type de paramètre (doit être obligatoirement défini à 2 pour un paramètre d’un MC)</li>
<li><u>IsOptional</u> (optionnel) : booléen (true ou false) qui indique si le paramètre est optionnel ou non</li>
<li><u>DefaultValue</u> (optionnel) : la valeur par défaut du paramètre si optionnel</li>
</ul>
<p>Le type d’un paramètre peut être un type simple décrit par les types .NET (System.Int16, System.Int32, System.Int64, System.Double, System.Decimal, System.Float, System.Boolean, System.String) ou un type personnalisé.</p>
<p>Les types personnalisés utilisés dans les paramètres des MC seront décrits dans la propriété “MessageCallbackTypes” du Package Descriptor et les types personnalisés utilisés pour les StateObjects seront décrits dans la propriété “StateObjectTypes” du Package Descriptor.</p>
<p>Dans les deux cas il s’agit de la même structure de donnée.</p>
<p>La description d’un type est un objet contenant :</p>
<ul>
<li><u>TypeName</u> : le nom du type (l’identifiant)</li>
<li><u>TypeFullname</u> : le nom complet du type (utilisé pour identifier le nom complet d’un type .NET par exemple)</li>
<li><u>Description</u> (optionnel) : la description du type</li>
<li><u>IsGeneric</u> (optionnel) : booléen (true ou false) qui indique si le type est un type générique</li>
<li><u>IsArray</u> (optionnel) : booléen (true ou false) qui indique si le type est un tableau</li>
<li><u>GenericParameters</u> (optionnel) : la liste des types génériques si il s’agit d’un type générique ou d’un tableau</li>
<li><u>IsEnum</u> (optionnel) : booléen (true ou false) qui indique si le type est une énumération</li>
<li><u>EnumValues</u> (optionnel) : la liste des valeurs de l’énumérations si le type est une énumération</li>
<li><u>Properties</u> (optionnel) : la liste des propriétés du type</li>
</ul>
<p>Les propriétés d’un type tout comme les valeurs d’une énumération sont décrits de la même manière qu’un paramètre d’un MessageCallback déjà détaillé ci-dessus.</p>
<p>Seule la propriété “Type” change :</p>
<ul>
<li>Type = 0 : pour décrire une propriété</li>
<li>Type = 1 : pour décrire une valeur d’une énumération</li>
<li>Type = 2 : pour décrire une paramètre d’un MessageCallback comme expliqué précédemment</li>
</ul>
<h4>Exemple 1 – Package “NetworkTools”</h4>
<p>Voici le Package Descriptor du package “NetworkTools” :</p>
<p></p><pre class="crayon-plain-tag">{
   "PackageName":"NetworkTools",
   "MessageCallbacks":[  
      {  
         "MessageKey":"Ping",
         "Description":"Pings the specified host and return the response time.",
         "ResponseType":"System.Int64",
         "Parameters":[  
            {  
               "Name":"host",
               "TypeName":"System.String",
               "Description":"The host.",
               "Type":2,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"timeout",
               "TypeName":"System.Int32",
               "Description":"The timeout (5000ms by defaut).",
               "Type":2,
               "IsOptional":false,
               "DefaultValue":null
            }
         ]
      },
      {  
         "MessageKey":"CheckPort",
         "Description":"Check a port's status by entering an address and port number above and return the response time.",
         "ResponseType":"System.Int64",
         "Parameters":[  
            {  
               "Name":"host",
               "TypeName":"System.String",
               "Description":"The host.",
               "Type":2,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"port",
               "TypeName":"System.Int32",
               "Description":"The port.",
               "Type":2,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"timeout",
               "TypeName":"System.Int32",
               "Description":"The timeout (5000ms by defaut).",
               "Type":2,
               "IsOptional":false,
               "DefaultValue":null
            }
         ]
      },
      {  
         "MessageKey":"CheckHttp",
         "Description":"Checks the HTTP address and return the response time.",
         "ResponseType":"System.Int64",
         "Parameters":[  
            {  
               "Name":"address",
               "TypeName":"System.String",
               "Description":"The address.",
               "Type":2,
               "IsOptional":false,
               "DefaultValue":null
            }
         ]
      },
      {  
         "MessageKey":"ScanPort",
         "Description":"Scans TCP port range to discover which TCP ports are open on your target host.",
         "ResponseType":"System.Collections.Generic.Dictionary`2[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]",
         "Parameters":[  
            {  
               "Name":"host",
               "TypeName":"System.String",
               "Description":"The host.",
               "Type":2,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"startPort",
               "TypeName":"System.Int32",
               "Description":"The start port.",
               "Type":2,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"endPort",
               "TypeName":"System.Int32",
               "Description":"The end port.",
               "Type":2,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"timeout",
               "TypeName":"System.Int32",
               "Description":"The timeout (5000ms by defaut).",
               "Type":2,
               "IsOptional":false,
               "DefaultValue":null
            }
         ]
      },
      {  
         "MessageKey":"WakeUp",
         "Description":"Wakes up the specified host.",
         "ResponseType":"System.Boolean",
         "Parameters":[  
            {  
               "Name":"host",
               "TypeName":"System.String",
               "Description":"The host.",
               "Type":2,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"macAddress",
               "TypeName":"System.String",
               "Description":"The mac address.",
               "Type":2,
               "IsOptional":false,
               "DefaultValue":null
            }
         ]
      },
      {  
         "MessageKey":"DnsLookup",
         "Description":"Resolves a host name or IP address.",
         "ResponseType":"System.String[]",
         "Parameters":[  
            {  
               "Name":"host",
               "TypeName":"System.String",
               "Description":"The host.",
               "Type":2,
               "IsOptional":false,
               "DefaultValue":null
            }
         ]
      }
   ],
   "MessageCallbackTypes":[  
      {  
         "Description":null,
         "IsGeneric":true,
         "IsArray":false,
         "GenericParameters":[  
            "System.Int32",
            "System.Boolean"
         ],
         "IsEnum":false,
         "EnumValues":null,
         "TypeName":"Dictionary`2",
         "TypeFullname":"System.Collections.Generic.Dictionary`2[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]",
         "Properties":null
      },
      {  
         "Description":null,
         "IsGeneric":false,
         "IsArray":true,
         "GenericParameters":[  
            "System.String"
         ],
         "IsEnum":false,
         "EnumValues":null,
         "TypeName":"String[]",
         "TypeFullname":"System.String[]",
         "Properties":null
      }
   ],
   "StateObjectTypes":[  
      {  
         "Description":"Monitoring type",
         "IsGeneric":false,
         "IsArray":false,
         "GenericParameters":null,
         "IsEnum":false,
         "EnumValues":null,
         "TypeName":"MonitoringResult",
         "TypeFullname":"NetworkTools.MonitoringResult",
         "Properties":[  
            {  
               "Name":"ResponseTime",
               "TypeName":"System.Int64",
               "Description":"Gets or sets the response time in millisecond.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"State",
               "TypeName":"System.Boolean",
               "Description":"Gets or sets the state.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            }
         ]
      }
   ]
}</pre><p></p>
<h4>Exemple 2 – Package “Paradox”</h4>
<p>Autre exemple plus complet, le Package Descriptor du package “Paradox” :</p>
<p></p><pre class="crayon-plain-tag">{  
   "PackageName":"Paradox",
   "MessageCallbacks":[  
      {  
         "MessageKey":"AreaArm",
         "Description":"Arm the area.",
         "ResponseType":"System.Boolean",
         "Parameters":[  
            {  
               "Name":"request",
               "TypeName":"ParadoxOnConstellation.ArmingRequestData",
               "Description":"The request.",
               "Type":2,
               "IsOptional":false,
               "DefaultValue":null
            }
         ]
      },
      {  
         "MessageKey":"AreaDisarm",
         "Description":"Disarm the area.",
         "ResponseType":"System.Boolean",
         "Parameters":[  
            {  
               "Name":"request",
               "TypeName":"ParadoxOnConstellation.ArmingRequestData",
               "Description":"The request.",
               "Type":2,
               "IsOptional":false,
               "DefaultValue":null
            }
         ]
      },
      {  
         "MessageKey":"RefreshArea",
         "Description":"Refreshes the area.",
         "ResponseType":null,
         "Parameters":[  
            {  
               "Name":"area",
               "TypeName":"Paradox.Core.Area",
               "Description":"The area.",
               "Type":2,
               "IsOptional":false,
               "DefaultValue":null
            }
         ]
      },
      {  
         "MessageKey":"RefreshAll",
         "Description":"Refreshes all.",
         "ResponseType":null,
         "Parameters":[  

         ]
      }
   ],
   "MessageCallbackTypes":[  
      {  
         "Description":"Arming or disarming request",
         "IsGeneric":false,
         "IsArray":false,
         "GenericParameters":null,
         "IsEnum":false,
         "EnumValues":null,
         "TypeName":"ArmingRequestData",
         "TypeFullname":"ParadoxOnConstellation.ArmingRequestData",
         "Properties":[  
            {  
               "Name":"Area",
               "TypeName":"Paradox.Core.Area",
               "Description":"The number of area.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Mode",
               "TypeName":"Paradox.Core.ArmingMode",
               "Description":"The mode number.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"PinCode",
               "TypeName":"System.String",
               "Description":"The pin code.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            }
         ]
      },
      {  
         "Description":null,
         "IsGeneric":false,
         "IsArray":false,
         "GenericParameters":null,
         "IsEnum":true,
         "EnumValues":[  
            {  
               "Name":"All",
               "TypeName":"Paradox.Core.Area",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Area1",
               "TypeName":"Paradox.Core.Area",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Area2",
               "TypeName":"Paradox.Core.Area",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Area3",
               "TypeName":"Paradox.Core.Area",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Area4",
               "TypeName":"Paradox.Core.Area",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Area5",
               "TypeName":"Paradox.Core.Area",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Area6",
               "TypeName":"Paradox.Core.Area",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Area7",
               "TypeName":"Paradox.Core.Area",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Area8",
               "TypeName":"Paradox.Core.Area",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            }
         ],
         "TypeName":"Area",
         "TypeFullname":"Paradox.Core.Area",
         "Properties":null
      },
      {  
         "Description":null,
         "IsGeneric":false,
         "IsArray":false,
         "GenericParameters":null,
         "IsEnum":true,
         "EnumValues":[  
            {  
               "Name":"RegularArm",
               "TypeName":"Paradox.Core.ArmingMode",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"ForceArm",
               "TypeName":"Paradox.Core.ArmingMode",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"StayArm",
               "TypeName":"Paradox.Core.ArmingMode",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"InstantArm",
               "TypeName":"Paradox.Core.ArmingMode",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            }
         ],
         "TypeName":"ArmingMode",
         "TypeFullname":"Paradox.Core.ArmingMode",
         "Properties":null
      }
   ],
   "StateObjectTypes":[  
      {  
         "Description":null,
         "IsGeneric":false,
         "IsArray":false,
         "GenericParameters":null,
         "IsEnum":false,
         "EnumValues":null,
         "TypeName":"UserInfo",
         "TypeFullname":"ParadoxOnConstellation.UserInfo",
         "Properties":[  
            {  
               "Name":"Id",
               "TypeName":"System.Int32",
               "Description":"The identifier.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Type",
               "TypeName":"System.String",
               "Description":"The object type.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Name",
               "TypeName":"System.String",
               "Description":"The name.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"LastActivity",
               "TypeName":"System.DateTime",
               "Description":"The last activity.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            }
         ]
      },
      {  
         "Description":null,
         "IsGeneric":false,
         "IsArray":false,
         "GenericParameters":null,
         "IsEnum":false,
         "EnumValues":null,
         "TypeName":"DateTime",
         "TypeFullname":"System.DateTime",
         "Properties":[  
            {  
               "Name":"Date",
               "TypeName":"System.DateTime",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Day",
               "TypeName":"System.Int32",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"DayOfWeek",
               "TypeName":"System.DayOfWeek",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"DayOfYear",
               "TypeName":"System.Int32",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Hour",
               "TypeName":"System.Int32",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Kind",
               "TypeName":"System.DateTimeKind",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Millisecond",
               "TypeName":"System.Int32",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Minute",
               "TypeName":"System.Int32",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Month",
               "TypeName":"System.Int32",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Now",
               "TypeName":"System.DateTime",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"UtcNow",
               "TypeName":"System.DateTime",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Second",
               "TypeName":"System.Int32",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Ticks",
               "TypeName":"System.Int64",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"TimeOfDay",
               "TypeName":"System.TimeSpan",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Today",
               "TypeName":"System.DateTime",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Year",
               "TypeName":"System.Int32",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            }
         ]
      },
      {  
         "Description":null,
         "IsGeneric":false,
         "IsArray":false,
         "GenericParameters":null,
         "IsEnum":true,
         "EnumValues":[  
            {  
               "Name":"Sunday",
               "TypeName":"System.DayOfWeek",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Monday",
               "TypeName":"System.DayOfWeek",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Tuesday",
               "TypeName":"System.DayOfWeek",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Wednesday",
               "TypeName":"System.DayOfWeek",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Thursday",
               "TypeName":"System.DayOfWeek",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Friday",
               "TypeName":"System.DayOfWeek",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Saturday",
               "TypeName":"System.DayOfWeek",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            }
         ],
         "TypeName":"DayOfWeek",
         "TypeFullname":"System.DayOfWeek",
         "Properties":null
      },
      {  
         "Description":null,
         "IsGeneric":false,
         "IsArray":false,
         "GenericParameters":null,
         "IsEnum":true,
         "EnumValues":[  
            {  
               "Name":"Unspecified",
               "TypeName":"System.DateTimeKind",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Utc",
               "TypeName":"System.DateTimeKind",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Local",
               "TypeName":"System.DateTimeKind",
               "Description":null,
               "Type":0,
               "IsOptional":false,
               "DefaultValue":null
            }
         ],
         "TypeName":"DateTimeKind",
         "TypeFullname":"System.DateTimeKind",
         "Properties":null
      },
      {  
         "Description":null,
         "IsGeneric":false,
         "IsArray":false,
         "GenericParameters":null,
         "IsEnum":false,
         "EnumValues":null,
         "TypeName":"TimeSpan",
         "TypeFullname":"System.TimeSpan",
         "Properties":[  
            {  
               "Name":"Ticks",
               "TypeName":"System.Int64",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Days",
               "TypeName":"System.Int32",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Hours",
               "TypeName":"System.Int32",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Milliseconds",
               "TypeName":"System.Int32",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Minutes",
               "TypeName":"System.Int32",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Seconds",
               "TypeName":"System.Int32",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"TotalDays",
               "TypeName":"System.Double",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"TotalHours",
               "TypeName":"System.Double",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"TotalMilliseconds",
               "TypeName":"System.Double",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"TotalMinutes",
               "TypeName":"System.Double",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"TotalSeconds",
               "TypeName":"System.Double",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            }
         ]
      },
      {  
         "Description":"Represent Zone information",
         "IsGeneric":false,
         "IsArray":false,
         "GenericParameters":null,
         "IsEnum":false,
         "EnumValues":null,
         "TypeName":"ZoneInfo",
         "TypeFullname":"ParadoxOnConstellation.ZoneInfo",
         "Properties":[  
            {  
               "Name":"IsOpen",
               "TypeName":"System.Boolean",
               "Description":"A value indicating whether this zone is open.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"IsTamper",
               "TypeName":"System.Boolean",
               "Description":"A value indicating whether this zone is tamper.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"InAlarm",
               "TypeName":"System.Boolean",
               "Description":"A value indicating whether this zone is in alarm.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"InFireAlarm",
               "TypeName":"System.Boolean",
               "Description":"A value indicating whether this zone is in fire alarm].",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"SupervisionLost",
               "TypeName":"System.Boolean",
               "Description":"A value indicating whether this zone has supervision lost.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"LowBattery",
               "TypeName":"System.Boolean",
               "Description":"A value indicating whether this zone has low battery.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Id",
               "TypeName":"System.Int32",
               "Description":"The identifier.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Type",
               "TypeName":"System.String",
               "Description":"The object type.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Name",
               "TypeName":"System.String",
               "Description":"The name.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"LastActivity",
               "TypeName":"System.DateTime",
               "Description":"The last activity.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            }
         ]
      },
      {  
         "Description":null,
         "IsGeneric":false,
         "IsArray":false,
         "GenericParameters":null,
         "IsEnum":false,
         "EnumValues":null,
         "TypeName":"AreaInfo",
         "TypeFullname":"ParadoxOnConstellation.AreaInfo",
         "Properties":[  
            {  
               "Name":"IsFullArmed",
               "TypeName":"System.Boolean",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"IsStayArmed",
               "TypeName":"System.Boolean",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"ZoneInMemory",
               "TypeName":"System.Boolean",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"HasTrouble",
               "TypeName":"System.Boolean",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"IsReady",
               "TypeName":"System.Boolean",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"IsInProgramming",
               "TypeName":"System.Boolean",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"InAlarm",
               "TypeName":"System.Boolean",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Strobe",
               "TypeName":"System.Boolean",
               "Description":null,
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Id",
               "TypeName":"System.Int32",
               "Description":"The identifier.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Type",
               "TypeName":"System.String",
               "Description":"The object type.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"Name",
               "TypeName":"System.String",
               "Description":"The name.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            },
            {  
               "Name":"LastActivity",
               "TypeName":"System.DateTime",
               "Description":"The last activity.",
               "Type":1,
               "IsOptional":false,
               "DefaultValue":null
            }
         ]
      }
   ]
}</pre><p></p>
<p>The post <a rel="nofollow" href="https://developer.myconstellation.io/client-api/rest-api/interface-rest-constellation/">L&rsquo;interface REST « Constellation »</a> appeared first on <a rel="nofollow" href="https://developer.myconstellation.io">Constellation</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://developer.myconstellation.io/client-api/rest-api/interface-rest-constellation/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/?utm_source=w3tc&utm_medium=footer_comment&utm_campaign=free_plugin

Mise en cache de page à l’aide de Disk: Enhanced 

Served from: developer.myconstellation.io @ 2026-01-23 02:02:21 by W3 Total Cache
-->