API HTTP/REST

Bonjour,

Je suis nouveau sur constellation et merci beaucoup pour votre site et vos tuto qui me sont très utiles.
J’ai créé un package avec un messagecallback. Tout fonctionne bien si je le teste dans constellation.

J’essaie maintenant de le lancer par l’API HTTP/REST. Mais j’ai en retour le message suivant : “{“Message”:“The requested resource does not support http method ‘GET’.”}”

Voila l’URL que je lance
http://localhost:8088/rest/consumer/SendMessage?SentinelName=Consumer&PackageName=Test&AccessKey=MACLE&scope=Package&args=PackageTest&key=Url

Est ce que j’ai raté quelque chose ? Il faut modifier quelque chose au niveau de ma methode ?
Voila le code dans visual studio

namespace PackageTest
{
    public class Program : PackageBase
    {
        static void Main(string[] args)
        {
            PackageHost.Start<Program>(args);
        }

        public override void OnStart()
        {
        }

        [MessageCallback]
        static void Url()
        {
            PackageHost.WriteInfo("This is a MessageCallback !");
        }
    }
    }

Merci d’avance pour votre aide
Oogver

Bonjour Oogver,

Que ce soit pour l’API REST « Consumer » ou « Constellation », pour envoyer un message le parametre « key » (le nom du MC) mais aussi la « Data » du message (arguments du MC) sont obligatoire.

Même si le MC ne prend aucun argument, il faut préciser « data={} ».

N’hesitez pas à regarder les exemples donnés par le générateur de code de la Console en cliquant sur l’icone Generateur à côté du nom de votre MC depuis le « MessageCallbacks Explorer ».

Si le parametre « data » n’est pas passé dans l’URL le serveur Constellation pensera que vous envoyez un message par un POST d’où le message d’erreur. Donc soit on passe tous les paramètres dans l’URL (query string) avec un GET soit on passe tous les paramètres dans l’entete (header) avec un POST.

Dans les deux cas le « data » est obligatoire même si le MC ne prend aucun paramètre !

Bien à vous

Merci beaucoup pour ta réponse, ca marche maintenant.
Je me doutais qu’il ne manquait pas grand chose, c’est ma faute, j’ai voulu simplifier l’URL.

J’en profite pour poser une autre question. Mon but est en fait de lancer une URL à l’appel de mon MC. Tout ça pour commander ma livebox a distance, lors de l’appel du MC et a terme par IFTTT et Google Home.
Ma méthode fonctionne bien lorsque je fais du debug dans constellation depuis visual studio mais lors de l’appel du MC, l’URL n’est pas lancée.

Voila le code de mon MC. Dans le log j’ai bien le message ‘Test’ qui remonte mais l’URL n’est pas lancée.
Par contre, si j’ouvre le debug dans visual studio (donc la méthode Onstart est lancée et la console ouverte) et en parallèle j’invoque le MC depuis constellation, cela fonctionne.
A noter que je n’ai pas besoin que mon navigateur s’ouvre au lancement de l’URL, je ne sais pas si ça a un impact.

        [MessageCallback]
        static void Url()
        {
            PackageHost.WriteInfo("Test");
            Process process = new Process();
            process.StartInfo.UseShellExecute = true;
            process.StartInfo.CreateNoWindow = true;
            process.StartInfo.FileName = "http://XX.XX.XX.XX:XXXX/remoteControl/cmd?operation=01&key=115&mode=0";
            process.Start();

        }

Merci d’avance.

Salut Oogver,

Message très intéressant par ça touche à pas mal de chose :wink:

Bon déjà sur l’API REST le feedback est bon car oui après réflexion si les datas sont null ({}) alors on devrait pouvoir les omettre de l’URL sans lever d’erreur ! Je note donc cette remarque dans ma todo list pour les futures updates du serveur.

Concernant ton MC, tu as besoin d’appeler une adresse HTTP depuis ton package à partir d’un MC exposé dans Constellation. Je reviendrais ci-dessous sur une manière plus conventionnelle mais analysons ton code ci-dessus.

Tu exposes une méthode statique “Url” qui crée un Processus Windows avec comme “filename” l’URL à appeler. Dans ce cas, Windows, voyant le schème “http://” va chercher l’application liée à ce sheme, en gros le navigateur Web défini par défaut sur ton système.
Une fois trouvé, il va simplement lancer le process du navigateur avec en paramètre l’URL que tu veux ouvrir. Dans mon cas il lancera “chrome.exe” avec l’URL à appeler.
TU constates ensuite que ca marche en “debug” dans Visual Studio mais pas quand tu déploies ton package sur ta sentinelle !

C’est normal :wink: En effet, tu lances le processus de ton navigateur Web (FF, Chrome ou autre) qui lui s’exécute au sein d’une session utilisateur avec une interface graphique ! Quand tu lances ton package en debug dans VS, ton package est lancé au sein de ta session Windows, pas de probleme on peut lancer le navigateur (tu le vois d’ailleurs se lancer visuellement!).

Par contre, si tu le déploie sur une sentinelle de ta Constellation, et pour être très précis, sur une sentinelle “Service”, le MC semble s’exécuter (car on voit passer ton WriteInfo(“Test”) dans la Console log) mais l’appel HTTP n’est pas fait !
En effet, une sentinelle service est un service Windows qui se lance avec le système et n’est pas lié à une session utilisateur !

Je cite :

Il existe deux types de sentinelle : - La “Sentinel Service” : il s’agit d’un service compatible Windows et Linux qui tourne en arrière plan et permet de déployer des packages Constellation sans interface graphique. - La “Sentinel UI” : il s’agit d’une application Windows s’exécutant au sein d’une session Windows et permettant de déployer des packages Constellation avec interface graphique (dit Package UI) ou encore des packages ayant besoin d’interagir avec la session de l’utilisateur.
(https://developer.myconstellation.io/getting-started/ajouter-des-sentinelles/#Prerequis)

Donc dans le cas où tu déploies ton package sur une sentinelle service, ton package n’est pas lancé au sein de ta session utilisateur, il tourne véritablement en “background” et donc ne peut pas accéder à l’interface graphique et donc ne peut pas lancer un navigateur internet !

Pour que ton code ci-dessus fonctionne, il faut déployer ton package sur une “sentinelle UI”, c’est à dire une sentinelle qui s’exécute au sein d’une session utilisateur avec donc l’accès à l’interface graphique.

Et c’est toute la différence entre la sentinelle “Service” et “UI” : les deux ont exactement le même code, le même fonctionnement, c’est juste le container qui change ! Dans le cas de la sentinelle “Service”, elle s’exécute hors session utilisateur, on n’a donc pas besoin d’ouvrir une session pour que la sentinelle s’exécute et déploie les package, parfait pour les serveurs & co mais par contre, il n’a pas accès aux informations de session ou à l’UI de Windows.
A l’inverse la sentinelle UI s’execute au sein d’une session Windows, il faut donc qu’un utilisateur ouvre sa session Windows pour que la sentinelle puisse se lancer, mais une fois lancé, on peut déployer des packages ayant besoin d’interagir avec la session ou l’interface graphique, comme dans ton cas pour lancer un navigateur Web.

Ceci étant dit, ton code n’est pas optimal! En effet si tu cherches à lancer un appel HTTP il y a mieux que de lancer le processus de ton navigateur! Dans ton cas, ton code nécessite une sentinelle UI, donc une session utilisateur ouverte, et est de ce fait limité à Windows (ton package n’est pas déployable sur Linux) et de plus tu auras autant de fenêtre de ton navigateur ouverte sur ton poste que d’appel que tu lances depuis ton package !!! Aussi, tu n’as aucun contrôle, impossible d’obtenir la réponse de l’appel HTTP, on se contente juste de lancer le navigateur sur une URL sans avoir de retour ni de contrôle !

Ainsi pour lancer un appel HTTP depuis un package C#, le mieux est d’utiliser les classes dans System.Net.

Pour faire simple tu peux utiliser le WebClient. Par exemple :

[MessageCallback]
private void DemoAppelUrl(string url)
{
    PackageHost.WriteInfo($"GET {url}");
    WebClient wc = new WebClient();
    string response = wc.DownloadString(url);
    PackageHost.WriteInfo($"Reponse : {response}");
}

La méthode “DownloadString” permet d’exécuter un GET HTTP sur l’URL passée en paramètre et te retourne le contenu de la réponse HTTP !

Dans ton cas, tu es entrain de changer de chaîne sur ta livebox si j’ai bien cerné :wink: Le décodeur TV te renverras un JSON de réponse contenant dans un objet “result” le code de réponse (0 si OK, 1 si erreur) et le message de la réponse (“OK” si le changement de chaine est effectué).

Tu pourrais donc aller plus loin en “parsant” le JSON de la réponse récupéré par le DownloadString.

Par exemple, ajoutons ces deux lignes :

dynamic objResponse = Newtonsoft.Json.JsonConvert.DeserializeObject(response);
PackageHost.WriteInfo($"Code de retour de la Livebox : {objResponse.result.responseCode} - Message: {objResponse.result.message}");

On parse le retour de ton décodeur et on affiche le “responseCode” et “message” de la LB.

Le WebClient est très simple a prendre en main mais n’est pas super complet (gestion fine de la requête, headers, cookie & co) et aussi n’est pas thread-safe (si deux appels simultanés à ton MC ca lèvera une erreur). C’est pourquoi pour aller plus loin j’utilise plutôt les “HttpWebRequest” !

Très complet mais plus compliqué à utiliser pour un néophyte : https://www.codeproject.com/Articles/6554/How-to-use-HttpWebRequest-and-HttpWebResponse-in-N.

A titre d’exemple, deux packages utilisants des HttpWebRequest :

Et un autre package, celui “FreeboxTV” créé par Gio et Hydro qui lui utilise les WebClients : https://github.com/myconstellation/constellation-packages/blob/master/FreeboxTV/FreeboxTV/Remote/HttpFreeRemoteController.cs

Pour finir, ton message m’a inspiré pour connecter mon décodeur Orange TV :slight_smile: J’ai donc écris hier soir un package pour intégrer le décodeur TV Orange dans Constellation. Je publie le package prochainement sur le store :wink:

Salut,

Merci beaucoup pour cette réponse plus que complète.
J’ai eu le temps de la digérer ainsi que la dinde de Noël et je trouve le temps de te répondre.

Concernant l’utilisation de la méthode qui utilise le process windows, je me doutais qu’il y avait un souci vu que je voyais mon navigateur s’ouvrir. C’est pour cela que j’avais déployé le package sur une sentinelle non UI, j’avais espéré que ca lance l’URL en arrière plan.
Bon j’avoue, je suis débutant et j’essaie un peu n’importe quoi. lol

Du coup, j’ai remplacé mon code par le tien et ça marche super bien. J’utilise donc un MC avec en paramètre le numéro de la chaine (ou le nom) et cela me lance la chaine sur la box. Au final, j’utilise Google Home qui me lance un IFTTT qui appelle le MC par l’API REST/HTTP.

J’en profite pour une autre question. Je ne m’en sers pas pour l’instant mais je n’ai pas trouvé comment passer plusieurs paramètres dans la partie “data” de l’API REST. Est ce que c’est possible ?

A plus
Florian

Oui of course, il faut passer un tableau JSON ou un objet