URL: https://linuxfr.org/users/pied/journaux/coroutines-histoire-d-un-nouvel-inutilitaire Title: Coroutines, histoire d'un nouvel inutilitaire... Authors: Pinaraf Date: 2023年10月20日T15:14:26+02:00 License: CC By-SA Tags: coroutine, ovh, c++ et qt Score: 80 Salutations ! À mon travail, nous utilisons actuellement pour la plupart de nos besoins des serveurs dédiés loués à une petite PME roubaisienne (connue pour son étroite collaboration avec le SDIS). Nous devons avoir à la louche une vingtaine de serveurs chez cet hébergeur. Globalement, on peut le dire, tout va bien. Son réseau est en carton, pirouette cacahouete, ses escaliers non-ignifugés... mais on a des redondances entre centres de données, tout devrait bien se passer. Mais il y a une chose qui est difficile à supporter : le célèbre "Manager", l'espace client. Quiconque l'a déjà utilisé sera d'accord avec ces chiffres, mais pour d'autres ce sera peut-être une surprise. - Temps requis pour se connecter : 7 secondes. - Temps requis pour lister les serveurs après connexion : 3 secondes. - Temps requis pour afficher les informations d'un serveur : 5 secondes. Je ne plaisante pas, et il était en forme lors de mon test, j'ai déjà eu des temps à plus de 15 secondes pour afficher les informations d'un serveur par exemple. Quand une urgence demande qu'on se connecte au KVM d'un serveur, ces temps s'ajoutent aux 15 secondes nécessaires pour que le KVM soit accessible et fait donc plus que le doubler (et encore, dans le manager c'est plus long que 15 secondes). Insupportable. Sans oublier tous les problèmes d'ergonomie inhérents aux applications web modernes (notamment parce qu'il faut 'aérer' les interfaces, quitte à ce que rien ne soit faisable sans devoir défiler ou aller dans différents onglets, mais aussi parce que les applications web ont leur limites ou juste parce que les concepteurs vivent sur leur nuage). Or, la logique chez OVH −au diable la subtilité− est simple : si les clients veulent une interface plus pratique, plus adaptée à leurs besoins, on donne des APIs donc ils peuvent la coder eux-même. C'est d'ailleurs sur cette logique que les applications mobiles et desktop (MoM et Momi) ont disparu. Du coup... ça m'emmerde, je déteste faire le travail d'une entreprise que je paie déjà pour ce service en théorie, mais pas le choix, il va falloir que je code un outil pour automatiser l'accès au KVM. Choix des armes =============== Comme je le dis souvent (et j'ai toujours raison), on ne choisit pas vraiment son langage de programmation. Si on a, par chance, à l'intersection de toutes les contraintes plusieurs langages, alors on a un choix, mais voilà, ça ne sera pas un choix pleinement libre. Mes principales contraintes : - avoir des bibliothèques pour faire des applications graphiques (et pas du web, non merci), - avoir dans les composants disponibles un moteur de rendu HTML complet (parce que le KVM est en «HTML5»), - pouvoir intégrer des appels HTTP sans que ça ne soit la mort (pas de callbacks ou autre fonctionnement à l'ancienne, il va y avoir trop d'appels pour que ça ne finisse pas vite en code spaghetti), - j'ai envie d'apprendre des nouveaux trucs, mais il faut quand même que je puisse avancer assez vite, la courbe d'apprentissage ne doit pas ressembler à un mur de parpaings. À la base je voulais utiliser FreePascal et Lazarus, mais je n'ai pas trouvé de solution acceptable pour intégrer le KVM HTML5 (petits regrets sur l'absence d'un équivalent de COM sur nos environnements de bureau, il y a le KParts de KDE éventuellement mais quitte à utiliser Qt autant prendre QtWebEngine dans ce cas ). Java, même combat pour le rendu HTML. C# avec WebkitGtkSharp par contre, ça pourrait le faire. J'ai regardé Rust, mais rebelote sur le HTML, et le développement d'applications graphiques c'est pas encore trop ça. Et il y a les traditionnels GTK/Qt en C/C++, et éventuellement les bindings Python (ou autre langage) pour ces derniers, à condition qu'ils intègrent QtWebEngine, QtWebKit ou GtkWebKit. Pour que les appels HTTP soient «jolis», le plus simple reste les coroutines. Chance, c'est possible en C++20 avec les coroutines et qcoro pour l'intégration Qt (mais je n'ai rien trouvé pour gtkmm). Ou avec Python3 et qasync/asyncqt pour l'intégration avec Qt. Ça semble plus facile sur Python / GTK, mais je ne trouve pas de solution simple pour intégrer GtkWebKit dans ce cadre. Étant donné ma contrainte sur la « quantité » d'apprentissage, j'ai préféré me rabattre sur C++20/Qt, pour me concentrer sur la découverte et l'apprentissage de cette implémentation des coroutines. C#/GTK m'intrigue, mais je reste inquiet par rapport aux outils de développement (MonoDevelop est mort, VSCode est propriétaire et ses plugins C# sont de mémoire propriétaires également) Le développement ================ Je n'aimerais pas lire un journal «tuto - écrire une application C++/Qt». Par contre je pense que vous apprécierez peut-être d'avoir des informations sur les coroutines en C++ avec Qt, parce que franchement, c'est une bouffée d'air frais pour ce genre d'application. Tout d'abord, si vous n'avez jamais utilisé QNetworkAccessManager et ses APIs pour faire des appels HTTP, petit rappel des faits. Vous instanciez cette classe et vous appelez dessus des méthodes get, post, put ou deleteResource (delete étant un mot clé du C++, le nom change, forcément...). Vous obtenez alors en retour un pointeur vers un QNetworkReply. Une fois que ce dernier émet le signal finished(), vous pouvez récupérer ce que le serveur vous a répondu. Le problème, concrêtement, c'est si vous devez enchaîner deux, trois, quatre appels. Vous aurez alors un code ressemblant à : ```c++ auto reply1 = nam->get(QUrl("http://www.example.com/1")); QObject::connect(reply1, &QNetworkReply::finished, [reply1, ui, nam] () { ui->label1->setText("Request finished, yay"); auto target = QUrl(QString::fromUtf8(reply1->readAll())); auto reply2 = nam->get(target); QObject::connect(reply2, &QNetworkReply::finished, [reply2, ui, nam] () { ui->label1->setText("Finished request 2, yay again"); reply2->deleteLater(); }); reply1->deleteLater(); }); ``` Et là, c'est pour deux appels. Lancer le KVM avec l'API d'OVH prend 3 appels, puis une boucle d'attente avec un appel répété, puis un dernier appel pour avoir l'URL... Bonjour l'armée de callbacks ! Écrivons avec QCoro l'équivalent du code qui précède : ```c++ auto reply1 = co_await nam->get(QUrl("http://www.example.com/1")); ui->label1->setText("Request finished, yay"); auto target = QUrl(QString::fromUtf8(reply1->readAll())); auto reply2 = co_await nam->get(target); ui->label1->setText("Finished request 2, yay again"); delete reply2; delete reply1; ``` C'est beaucoup plus clair et lisible. On attend le résultat du premier get, on exécute du code, on attend le deuxième get, on exécute du code. En procédant ainsi, on se simplifie tellement la vie. Et c'est pour ainsi dire «gratuit». Les coroutines sont des fonctions interruptibles, donc on n'a pas lancé des threads ou des processus en parallèle. Tout au plus utilise-t-on une quantité négligeable de RAM pour stocker l'état d'une fonction interrompue, pas beaucoup plus gros que ce que l'on utilisait (sans le voir) précédemment pour le contexte de nos fonctions lambdas. Et du coup, pour les gens que ça intéresse, mon mini projet a une encapsulation basique de l'API d'OVH avec Qt et QCoro. L'utilisation est simple : ```c++ auto ovh = new OvhApi{"https://eu.api.ovh.com/1.0", this}; ovh->setConsumerKey(key); auto meInfo = (co_await ovh->get("/me/")).object(); qDebug() << meInfo; ``` Sont cachés l'authentification avec la signature des requêtes, la construction de JSON, les concaténations d'URLs... On pourrait aller plus loin, mais à court terme, ce sera amplement suffisant. Par ailleurs, si une base de données est instanciée (avec QtSql), on peut passer à get un paramètre pour préciser une durée de mise en cache de la réponse. Cela accélère d'une façon phénoménale l'application, l'API OVH restant désespérément lente... ```c++ auto ovh = new OvhApi{"https://eu.api.ovh.com/1.0", this}; ovh->setConsumerKey(key); auto meInfo = (co_await ovh->get("/me/", 1h)).object(); qDebug() << meInfo; ``` Certaines informations ne changeant que rarement (les spécifications d'un serveur, le détail d'une facture...), on peut mettre un cache très aggressif pour certaines données et avoir alors des appels instantanés. Le résultat =========== C'est une application graphique, donc capture d'écran obligatoire. ![l'interface de base avec un serveur affiché](https://rock.pinaraf.info/~pinaraf/ovhkvm/ovhkvm-1.png) Avec un KVM ouvert... ![et ici avec un KVM dans un deuxième onglet](https://rock.pinaraf.info/~pinaraf/ovhkvm/ovhkvm-2.png) Les temps de chargement sont sans commune mesure avec les temps du manager d'OVH, surtout quand les caches sont chargés. Et en prime, les pires pièges de facturation d'OVH que je connaisse (notamment l'engagement tacitement reconduit) sont clairement indiqués dans l'interface, pour aider à s'y retrouver. Il y a plein de choses qu'on pourrait y ajouter. Mais ça fait le taf pour moi et mes collègues. Pour ceux que ça intéresse, le code est là, sous licence GPL3 : https://git.entrouvert.org/entrouvert/OvhKvm Forkez à votre guise, faites-en ce que vous voulez, comme je l'ai dit ça a fait son taf pour nous. La bise, bon week-end à vous PS... «Tu devrais diffuser cette application aux autres clients d'OVH, je suis sûr que ça pourrait plaire.» À cela, j'ai répondu, un peu en troll mais beaucoup parce que je refuse d'avoir à payer Apple pour diffuser mon appli «Peut-être, mais je refuse de diffuser une version sous forme de binaire pour MacOS de l'application, par contre une version Haiku pourquoi pas...» C'est vrai ça, pourquoi pas... Pourquoi pas... Hop, une VM avec Haiku, et c'est parti ! Qt a été porté sur Haiku, il y a un G++ récent, «ça va bien se passer» comme dit l'autre. Surprise, dans les ports, QCoro est disponible ! Bon ben maintenant il faut que je soumette sur haikuports une mise à jour de QCoro, peut-être deux/trois autres petits trucs... PPS... Alors moi je bosse en DBA et admin sys, mais on recrute des devs python, pour ceux que ça intéresse... https://www.entrouvert.com/actualites/2023/embauche-developpeuse-eur-python-django/

AltStyle によって変換されたページ (->オリジナル) /