Category Archives: French

Créer un WebService en C++ avec Qt

Un petit article pour évoquer la possibilité de faire un webservice, en C++/Qt.

Mon besoin est simple, je veux fournir une interface web pour réaliser des lancer de dés avec le système de lancement de dés DiceParser, issu de Rolisteam.

DiceParser est écrit en C++ avec Qt5. A partir de ce constat, je pouvais soit faire un serveur web en C++, soit faire un site web en python/php/whatever pour lancer une commande système et utiliser dice, le client en ligne de commande de DiceParser.

La deuxième solution est  la plus facile mais clairement un peu «sale» et niveau sécurité ce n’est pas idéal. Le «challenge» se trouve dans la première méthode.
Je n’avais pas envie de rĂ©inventer la roue donc j’ai cherchĂ© une solution technique pour satisfaire mon besoin. Un composant C++/Qt qui permet de crĂ©er un serveur http avec possibilitĂ© d’ĂŞtre notifier Ă  chaque requĂŞte. J’ai trouvĂ© un composant qui rĂ©alise cela.

Le dépôt git du composant : https://github.com/azadkuh/qhttp.git

Implémentation du serveur

[pastacode lang=”cpp” manual=”%20%20m_server%20%3D%20new%20qhttp%3A%3Aserver%3A%3AQHttpServer(this)%3B%0A%20%20%20%20m_server-%3Elisten(%20%2F%2F%20listening%20on%200.0.0.0%3A8080%0A%20%20%20%20%20%20%20%20%20%20%20%20QHostAddress%3A%3AAny%2C%20port%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%5B%3D%5D(qhttp%3A%3Aserver%3A%3AQHttpRequest*%20req%2C%20qhttp%3A%3Aserver%3A%3AQHttpResponse*%20res)%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20req-%3EcollectData(1024)%3B%0A%0A%09%09%2F%2F%20Ici%20mettre%20le%20code%20d’analyse%20de%20la%20requ%C3%AAte%0A%0A%20%20%20%20%20%20%20%20%7D)%3B%0A%20%20%20%20if%20(%20!m_server-%3EisListening()%20)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20qDebug()%20%3C%3C%20%22failed%20to%20listen%22%3B%0A%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20else%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20qDebug()%3C%3C%20%22Server%20is%20On!!%22%3B%0A%20%20%20%20%7D” message=”Instancier le serveur web” highlight=”” provider=”manual”/]

Nous crĂ©ons une instance du serveur, nous dĂ©marrons l’Ă©coute sur le port (80 par dĂ©faut pour le protocole http).
L’Ă©coute est rĂ©alisĂ© par une fonction lambda, cela n’a rien d’obligatoire, mais c’est plus minimaliste.

Notre fonction est notifiĂ©e Ă  la rĂ©ception d’une requĂŞte http.

RĂ©cupĂ©rer les informations d’une requĂŞte

[pastacode lang=”cpp” manual=”%2F%2F%20R%C3%A9cup%C3%A8re%20les%20donn%C3%A9es%0Areq-%3EcollectData(1024)%3B%0A%0A%2F%2F%20R%C3%A9cup%C3%A8re%20l’url%20(les%20donn%C3%A9es%20du%20GET)%0AQString%20getArg%20%3D%20req-%3Eurl().toString()%3B%0A%0A%2F%2F%20D%C3%A9coupage%20des%20arguments%0AgetArg%3DgetArg.replace(%22%2F%3F%22%2C%22%22)%3B%0AQStringList%20args%20%3D%20getArg.split(‘%26’)%3B%0AQHash%3CQString%2CQString%3E%20m_hashArgs%3B%0Afor(%20auto%20argument%20%3A%20args)%0A%7B%0A%20%20%20%20QStringList%20keyValue%20%3D%20argument.split(‘%3D’)%3B%0A%20%20%20%20if(keyValue.size()%3D%3D2)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20m_hashArgs.insert(keyValue%5B0%5D%2CkeyValue%5B1%5D)%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%2F%2F%20recherche%20dans%20la%20table%20des%20arguments%20la%20pr%C3%A9sence%20de%20fonction.%0Aif(m_hashArgs.contains(%22cmd%22))%0A%7B%0A%09%2F%2F%20r%C3%A9pondre%20%C3%A0%20la%20requ%C3%AAte%20reconnue.%0A%7D” message=”DĂ©coupage” highlight=”” provider=”manual”/]

Ici, nous analysons la requête pour identifier les actions à réaliser. Nous cherchons le paramètre cmd, pour trouver la commander à identifier. Le travail préalable est des créer une tableau associatif (dans une QHash) pour conserver les paramètres et leur valeur.

Une fois la commande de dĂ©s identifiĂ©s, il faut l’exĂ©cuter.

Exécuter la commande et répondre

[pastacode lang=”cpp” manual=”%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20QString%20result%20%3D%20startDiceParsing(QUrl%3A%3AfromPercentEncoding(m_hashArgs%5B%22cmd%22%5D.toLocal8Bit()))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20res-%3EsetStatusCode(qhttp%3A%3AESTATUS_OK)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20res-%3EaddHeader(%22Access-Control-Allow-Origin%22%2C%20%22*%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20res-%3EaddHeader(%22Access-Control-Allow-Methods%22%2C%20%22POST%2C%20GET%2C%20OPTIONS%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20res-%3EaddHeader(%22Access-Control-Allow-Headers%22%2C%20%22x-requested-with%22)%3B%0A%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20QString%20html(%22%3C!doctype%20html%3E%5Cn%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%3Chtml%3E%5Cn%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%3Chead%3E%5Cn%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%20%20%3Cmeta%20charset%3D%5C%22utf-8%5C%22%3E%5Cn%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%20%20%3Ctitle%3ERolisteam%20Dice%20System%20Webservice%3C%2Ftitle%3E%5Cn%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%20%20%3Cstyle%3E.dice%20%7Bcolor%3A%23FF0000%3Bfont-weight%3A%20bold%3B%7D%3C%2Fstyle%3E%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%3C%2Fhead%3E%5Cn%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%3Cbody%3E%5Cn%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%251%5Cn%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%3C%2Fbody%3E%5Cn%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%3C%2Fhtml%3E%5Cn%22)%3B%0A%0Ares-%3Eend(html.arg(result).toLocal8Bit())%3B” message=”” highlight=”” provider=”manual”/]

La première action est de convertir la commande pour la transformer en données lisibles. Elle est actuellement encodé en mode pourcent. Qt fournit une méthode statique pour faire la conversion. Le resultat de cette conversion est ensuite envoyé à une fonction qui exécute la commande et donne le résultat.

Il faut ensuite générer la réponse. Le premier truc à définir est le code réponse du protocole http. Le module qhttp propose des raccourcis pour cela.

Ensuite, la rĂ©ponse doit contenir 3 paramètres dans les headers afin d’ĂŞtre accessible par des frameworks Ajax/javascript/Web 2.0 (vous ressentez mon dĂ©dain envers ces techno ?).
Après la définition des headers, il faut créer le code html (ou autre) de la réponse.

Créer une page web cliente du service

[pastacode lang=”markup” manual=”%3C!DOCTYPE%20html%3E%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%3Chtml%3E%20%20%20%20%20%20%0A%3Chead%3E%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%3Cmeta%20charset%3D%22utf-8%22%3E%20%0A%3Cmeta%20name%3D%22Author%22%20content%3D%22Renaud%20GUEZENNEC%22%2F%3E%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%3Ctitle%3ERolisteam%20Dice%20System%20Webservice%3C%2Ftitle%3E%20%20%0A%20%20%3Cstyle%3E.dice%20%7Bcolor%3A%23FF0000%3Bfont-weight%3A%20bold%3B%7D%3C%2Fstyle%3E%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%3Cscript%20type%3D%22text%2Fjavascript%22%20src%3D%22js%2Fjquery-3.1.1.min.js%22%20%3E%3C%2Fscript%3E%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%3Cscript%20type%3D%22text%2Fjavascript%22%3E%20%20%0A%20%20%20%20function%20displayResult()%20%7B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20var%20request%20%3D%20%24.ajax(%7B%20%20%20%0A%20%20%20%20%20%20%20%20method%3A%20%22get%22%2C%20%20%20%20%0A%20%20%20%20%20%20%20%20url%3A%20%22http%3A%2F%2F127.0.0.1%3A8085%2F%22%2C%20%20%0A%20%20%20%20%20%20%20%20dataType%3A%20%22html%22%2C%20%20%0A%20%20%20%20%20%20%20%20async%3A%20false%2C%0A%20%20%20%20%20%20%20%20data%3A%20%7Bcmd%3A%20%24(‘%23cmd’).val()%7D%20%0A%20%20%20%20%20%20%7D)%3B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20request.done(function(data)%7B%20%20%0A%20%20%20%20%20%20%20%20var%20str%20%3D%22%3Cp%3E%22%20%0A%20%20%20%20%20%20%20%20str%20%3D%20str.concat(data%2C%22%3C%2Fp%3E%22)%3B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%24(‘.diceresult’).prepend(str)%3B%20%20%20%20%0A%20%20%20%20%20%20%7D)%3B%20%0A%20%20%20%20%7D%20%20%20%0A%20%20%3C%2Fscript%3E%20%20%0A%3C%2Fhead%3E%20%20%20%20%20%20%20%0A%3Cbody%3E%20%20%20%20%0A%3Cform%20method%3D%22POST%22%20action%3D%22%22%2F%3E%20%0A%3Cinput%20id%3D%22cmd%22%20name%3D%22cmd%22%2F%3E%20%20%0A%3Cinput%20id%3D%22roll%22%20name%3D%22roll%22%20type%3D%22button%22%20onclick%3D%22javascript%3AdisplayResult()%3B%20return%200%3B%22%20value%3D%22Roll%22%2F%3E%0A%3C%2Fform%3E%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%3Ca%20href%3D%22index.html%22%3EClear%3C%2Fa%3E%20%0A%3Cdiv%20class%3D%22diceresult%22%3E%0A%3C%2Fdiv%3E%20%20%20%20%20%20%0A%3C%2Fbody%3E%20%0A%3C%2Fhtml%3E” message=”Page cliente” highlight=”” provider=”manual”/]

Le travail ici est assez simple. Il faut crĂ©er un formulaire pour permettre Ă  l’utilisateur de saisir la commande de dĂ©s. J’ai utilisĂ© JQuery comme framework javascript pour rĂ©cupĂ©rer la commande et envoyer la requĂŞte de mon webservice. Quand la requĂŞte s’est bien passĂ©e, le rĂ©sultat s’affiche dans la page sans recharger la page.

Le lien vers le code source: https://github.com/Rolisteam/DiceParser/tree/master/webserver
Le webservice fait partie de projet DiceParser: https://github.com/Rolisteam/DiceParser

rand() moi un entier !

Cet article est une synthèse de plusieurs conférences, de la documentation C++ et de mon expérience sur la génération de nombre aléatoire en C++.

Mon besoin

Je suis le dĂ©veloppeur de Rolisteam. Un logiciel pour faire du jeu de rĂ´le en ligne. Il intègre une solution badass (oui, je m’envoie des fleurs) de lancer de dĂ©s. J’ai passĂ© beaucoup de temps entre juillet 2014 et fĂ©vrier 2015 pour produire un langage de script interprĂ©tĂ© de lancement de commandes de dĂ©s. Vous pouvez y jeter un Ĺ“il sur ce lien: DiceParser. Bref, j’ai crĂ©e tout un système pour lancer les dĂ©s et faire des opĂ©rations sur les rĂ©sultats: tri, relance, filtre, explosion, arithmĂ©tique, gestion des prioritĂ©s mathĂ©matiques et il est mĂŞme capable de gĂ©nĂ©rer l’arbre d’exĂ©cution avec dot.

L’aléatoire

Pour la partie alĂ©atoire dans tout le système, j’ai rĂ©utilisĂ© le code historique de rolistik (l’ancĂŞtre de rolisteam).
Certains utilisateurs sont venus me voir pour me demander de vérifier le système d’aléatoire car ils avaient fait des tests et avez déterminé que Rolisteam favorisait les résultats haut; ou bas selon les personnes.
J’avais droit Ă  un tableau de statistique rĂ©alisĂ© sur quelques dizaines de lancer de dĂ©s.
Argument qu’il est facile de dĂ©truire avec une Ă©tude statistique plus riche en lancer. DiceParser fonctionne en ligne de commande, donc très facile Ă  «scripter». Bref, des gens avaient des doutes sans rĂ©elle preuve.
Du coup, je me suis un peu renseignĂ© s’il n’y avait pas des mĂ©thodes plus «C++» avec le C++11, C++14 et/ou C++17.

L’existant

Quand il s’agit de gĂ©nĂ©rer des nombres alĂ©atoires, la première implĂ©mentation qu’on apprend est souvent celle ci :

[pastacode lang=”cpp” manual=”int%20resultat%20%3D%20std::rand()%25MAX%2Bdebut%3B” message=”usage classique de rand();” highlight=”” provider=”manual”/]

Je pense que tous les Ă©tudiants ont implĂ©mentĂ© cette mĂ©thode, dans leurs premières annĂ©es d’Ă©tudes.  Elle est facile Ă  comprendre. Elle est disponible dans beaucoup de langages. Elle vient du C. Elle met en avant le modulo, ce qui lui donne peut-ĂŞtre une valeur pĂ©dagogique. Elle suffit dans de très nombreux cas.

Nous allons voir un peu ce qui cloche avec cette méthode.

Les défauts

1/ Pauvre entropie
DĂ©jĂ , rand() ou std::rand() sont dĂ©finis dans le “man” comme une solution pauvre pour obtenir de l’alĂ©atoire. Il est prĂ©cisĂ© que les vieilles implĂ©mentations de rand() ou les implĂ©mentations sur d’autres systèmes fournissent un alĂ©atoire pauvre sur les bits de poids faibles. Cela explique peut-ĂŞtre pourquoi certains utilisateurs sous Windows se plaignent.
Donc l’entropie de rand n’est pas bonne. Il existe une autre mĂ©thode: random() qui fonctionne normalement mieux, avec un pĂ©riode beaucoup plus grande.

2/ Erreur de répartition
Ces deux mĂ©thodes gĂ©nèrent un nombre entre 0 et RAND_MAX. Maintenant, nous souhaitons obtenir des rĂ©sultats sur un dĂ©s Ă  100 faces. (C’est un format de dĂ©s courant en Jeux de rĂ´le).
Imaginons que RAND_MAX vaut 32767.

Si je découpe la valeur maximum en tranche de 100 cela donne ceci:

[0 : 99] => 100 valeurs
[100 : 199] => 100 valeurs
[200 : 299] => 100 valeurs
:
:
[32700 : 32767 ] => 67 valeurs.

Nous avons 327 tranches complètes et une dernière de 67.  L’usage du modulo vient faire la correspondance entre la valeur tirĂ©e dans l’espace de valeurs dĂ©sirĂ©es. Cela favorise les rĂ©sultats entre 0 et 67. Il y a une chance supplĂ©mentaire de tomber en dessous de 67. La diffĂ©rence est probablement nĂ©gligeables mais tout de mĂŞme, cela me pose problème d’avoir cela dans mon logiciel.

3/ Problème de portabilité

La valeur RAND_MAX vaut au minimum 32767 dans la norme. Elle diffèrent en fonction des implĂ©mentations, nous avons vu Ă©galement que la portabilitĂ© de la mĂ©thode rand() n’est pas garantie.
Cette somme de problèmes vient conforter les utilisateurs de Rolisteam dans leur idée de problème relatif au système de dés. Deux problèmes de portabilité se cumulent.

Le constat de ces erreurs m’a poussĂ© Ă  chercher une solution moderne pour gĂ©nĂ©rer ces nombres.

Dans les API C++ est arrivĂ© un nouveau “module” avec le C++11. Il s’agit de random.

#include <random>

Ce module présente toute une série de classes pour générer des nombres aléatoires et les répartir.
Il propose un nombre intĂ©ressant d’algorithmes ou de moteurs diffĂ©rents pour la gĂ©nĂ©ration. Je ne suis pas un expert en gĂ©nĂ©ration pseudo-alĂ©atoire de nombre. Du coup, le nom des algorithmes ne me parle pas.
Cependant, il semble que deux éléments sortent du lot: le std::random_device et le std::mt19937.

Le std::random_device

Il est dĂ©fini dans la documentation comme: Un gĂ©nĂ©rateur de nombre alĂ©atoire non dĂ©terministe. En gros, cela signifie qu’on ne peut pas prĂ©voir son comportement.
D’habitude, vous initialisez votre mĂ©thode alĂ©atoire par un seed. Il peut ĂŞtre intĂ©ressant pour des tests automatiques ou une rĂ©solution de bug de pouvoir rejouer une sĂ©quence entière de nombre alĂ©atoire.
Pour atteindre cet objectif, il suffit de mettre la mĂŞme seed. Donc vous avez lĂ  une mĂ©thode de nombre alĂ©atoire qui est dĂ©terministe. random_device n’a pas de seed. Il n’a pas besoin d’ĂŞtre initialiser. Il est donc impossible de lui faire “jouer” deux fois la mĂŞme chose. Dans mon cas, cela me satisfait complètement.

C’est facile Ă  mettre en place:

[pastacode lang=”cpp” manual=”std%3A%3Arandom_device%20rd%3B%0Astd%3A%3Auniform_int_distribution%3Cint%3E%20dist(1%2C%2010)%3B%0Aint%20randomNumber%20%3D%20dist(rd)%3B%0Astd%3A%3Acout%20%3C%3C%20%20randomNumber%20%3C%3C%20std%3A%3Aendl%3B” message=”” highlight=”” provider=”manual”/]

On gĂ©nère une nombre et on le distribue entre 1 et 10. Cela suffit. Il y a rien besoin de plus. C’est propre, Ă©lĂ©gant etc.
J’ai implĂ©mentĂ© cette mĂ©thode dans rolisteam 1.8, malgrĂ© les avertissements qu’on trouve Ă  droit Ă  gauche. Cela donne de bons rĂ©sultats sous Linux. J’ai fait une version pour Windows et lĂ , c’est le drame.
L’entropie du module sous windows est de zĂ©ro. Cela signifie qu’il renvoie toujours le mĂŞme rĂ©sultat. Bref, les dĂ©s Ă©taient toujours de la mĂŞme valeur.
La solution du random_device ne marche pas. Elle n’est pas portable.

Le std::mt19937

Il reste donc la mĂ©thode du std::mt19937. Elle fait toujours partie de l’API de <random>. Voici l’implĂ©mentation finale dans rolisteam.

[pastacode lang=”cpp” manual=”%2F%2F%20dans%20le%20constructeur%20de%20ma%20classe%20d%C3%A9%0Aauto%20seed%20%3D%20std%3A%3Achrono%3A%3Ahigh_resolution_clock%3A%3Anow().time_since_epoch().count()%3B%0Am_rng%20%3D%20std%3A%3Amt19937(quintptr(this)%2Bseed)%3B%0A%0A%2F%2Fdans%20la%20fonction%20lancer%20(roll())%0Astd%3A%3Auniform_int_distribution%3Cqint64%3E%20dist(m_base%2Cm_faces)%3B%0Aqint64%20value%20%3D%20dist(m_rng)%3B” message=”L’implementation dans rolisteam.” highlight=”” provider=”manual”/]

On peut voir qu’elle est plus proche de l’ancienne mĂ©thode car Il est nĂ©cessaire de l’initialiser avec un seed. Pour cela, il est Ă©galement possible d’utiliser une API C++11: <chrono>.

[pastacode lang=”cpp” manual=”%20%23include%20%3Cchrono%3E%0A%E2%80%A6%0Aauto%20seed%20%3D%20std%3A%3Achrono%3A%3Ahigh_resolution_clock%3A%3Anow().time_since_epoch().count()%3B%0Am_rng%20%3D%20std%3A%3Amt19937(quintptr(this)%2Bseed)%3B” message=”Politique Agricole Commune” highlight=”” provider=”manual”/]

 

Autres méthodes:

Conclusion:

J’espère avoir fait le tour des nouvelles API pour la gĂ©nĂ©ration alĂ©atoire de nombres entiers en C++. Il est important de garder Ă  l’esprit que l’API <random> fournit bien sur bien plus de chose que ce que j’ai montrĂ©. Je n’ai pas fait d’étude statistique pour dĂ©montrer que c’est mieux maintenant. Dans tous les cas, j’ai implĂ©mentĂ© le device_random dans mon lecteur audio maison, et je dĂ©couvre plein de nouvelle musique de ma collection.

Les sources:

CppCon 2016: Cheinan Marks “I Just Wanted a Random Integer!”:
https://www.youtube.com/watch?v=4_QO1nm7uJs
Stephan T. Lavavej – rand() Considered Harmful:
https://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful

Distribuer une application Qt

Bonjour,

Si vous suivez ce blog, vous savez que je suis développeur C++/Qt et que je contribue beaucoup à Rolisteam (www.rolisteam.org). C’est un logiciel libre pour faire du jeu de rôle. Il vise un public assez large. Il est donc multi-plateforme. Il fonctionne sous GNU/Linux, windows et Mac Os. Je suis un linuxien convaincu mais je développe sur les autres systèmes pour Rolisteam.

L’aspect développement n’est pas vraiment un problème, grâce à Qt. Cela marche grosso modo bien. La chose devient plus périlleuse quand il s’agit de distribuer le logiciel.

Dans mon activité professionnelle, j’ai constaté,  qu’il est assez rare qu’un développeur connaisse les solutions pour distribuer facilement un logiciel. Je vais essayer ici d’expliquer comment faire. Du moins, comment je fais dans rolisteam et si vous avez d’autres astuces. N’hésitez pas à en faire part dans les commentaires.

Prédicat de base:

Vous avez un logiciel écrit en C++/Qt, il est géré par un fichier .pro. Certains systèmes de build propose des systèmes identiques, voir plus puissant mais plus complexe (e.g: cmake). Je me contente d’évoquer les outils Qt.

Pour GNU/Linux :

Pour ma part, j’ai opté pour une distribution source et la création de package Ubuntu. Grâce à Launchpad, il est possible de créer un dépôt pour son projet et de soumettre des versions. Il faut l’admettre, c’est très pratique. Il existe probablement des services pour faire cela pour d’autres distributions.

Des contributeurs ont créé des package pour d’autres distributions (fedora…). Pour arch-linux, j’ai crĂ©e un script de compilation (Ă  tester).

L’ensemble des outils utilisĂ©es ne sont pas des outils Qt. Cela n’est donc pas le propos de cet article.  Je me suis mis de cĂ´tĂ© la tâche de jeter un coup d’œil Ă  appimage. Cela pourrait ĂŞtre une solution intĂ©ressante.

Pour Windows:

Trouver tous les éléments

Une application a des dĂ©pendances. Sous windows, il est courant d’installer l’exĂ©cutable et ses dĂ©pendances dans un mĂŞme dossier. Il est parfois difficile d’identifier les dĂ©pendances. Rassurez-vous un outil magique a Ă©tĂ© créée. Il s’agit de “windeployqt.exe“. C’est un outil distribuĂ© avec Qt. Son but est de copier toutes les dĂ©pendances Qt d’un binaire dans un dossier.

[pastacode lang=”bash” manual=”windeployqt%20%20%2Fchemin%2Fvers%2Fmon%2Fexecutable.exe” message=”Commande Windeployqt” highlight=”” provider=”manual”/]

Cette commande va lire le binaire et va copier l’ensemble des dépendances identifiés à côté du binaire.

Par soucis de clarté, je préfère utiliser un répertoire propre et distinct du répertoire de compilation.

[pastacode lang=”bash” manual=”windeployqt%20–dir%20%2Fchemin%2Fvers%2Fun%2Fdossier%2Fpropre%20%2Fchemin%2Fvers%2Fmon%2Fapplication.exe” message=”Dossier sĂ©parĂ©” highlight=”” provider=”manual”/]

L’ajout du l’argument –dir permet de dĂ©finir ce «dossier de destination».

Une autre difficulté entre en jeu quand votre application utilise du QML. En effet, il convient de rajouter un argument à la commande afin de permettre à l’outil d’aller lire votre code QML pour trouver ses dépendances.

[pastacode lang=”bash” manual=”windeployqt%20–qmldir%20%2Fchemin%2Fvers%2Fle%2Fdossier%2Fdes%2Fqml%20–dir%20%2Fdossier%2Fpropre%20application.exe” message=”Distributer du QML” highlight=”” provider=”manual”/]

Et après ?

Une fois cette étape terminée, vous aurez dans votre dossier de destination l’ensemble des dépendances Qt (et QML) de votre projets.

Je vous mets un exemple pour un logiciel utilisant Qt5 et un peu de QML le tout fut compilé avec Visual Studio.

├── accessible/
├── audio/
├── bearer/
├── designer/
├── Enginio.dll
├── iconengines/
├── icudt52.dll
├── icuin52.dll
├── icuuc52.dll
├── imageformats
├── mediaservice
├── msvcp120.dll
├── msvcr120.dll
├── platforms/
│ └── qwindows.dll
├── playlistformats/
├── position/
├── printsupport/
├── qml1tooling/
├── qmltooling/
├── Qt5Core.dll
├── Qt5Declarative.dll
├── Qt5Gui.dll
├── Qt5Network.dll
├── Qt5OpenGL.dll
├── Qt5Qml.dll
├── Qt5Quick.dll
├── Qt5WebKit.dll
├── Qt5Widgets.dll
├── Qt5Xml.dll
├── Qt5XmlPatterns.dll
├── sensorgestures/
├── sensors/
├── sqldrivers/
├── unins000.dat
└── unins000.exe

Si votre projet utilise d’autres bibliothèques (zlib …), il convient de rajouter les .dll correspondantes dans le dossier. La dernière étape est d’inclure le .exe de votre application.
En double-clickant sur le .exe, il devrait se lancer. Si ce n’est pas le cas, une dll est probablement manquante.
Cette procédure est à faire après un changement de version de Qt. Il faut vous assurer que les dll embarquées soient de la bonne version.

A ce stade, il ne reste qu’à mettre en place l’outil de publication de votre application.

 

Publication

Pour cette étape, il y a principalement deux méthodes:

La méthode de l’archive Zip, il suffit d’archiver le dossier de destination dans une archive .zip. Ce fichier peut être extrait sur n’importe quel windows, et cela fonctionnera. Il faudra créer à la main les raccourcis et il n’y pas d’autre moyen pour dés-installer le logiciel que de supprimer le dossier extrait à la main.

L’autre méthode est d’utiliser un outil qui va créer un installeur. Les plus connus sont Inno setup et NSIS.
J’utilise pour ma part: InstallForge (http://installforge.net), il est graphique et simple.
Qu’importe l’outil choisi, il faudra lui dire d’installer tous les fichiers de votre dossier de destination (en respectant la hiérarchie des fichiers) chez vos utilisateurs. Ces outils permettent de créer automatiquement des scripts de désinstallation, ils créent également les raccourcis sur le bureau et la barre de démarrage. Ils permettent aussi d’afficher du contenu à l’utilisateur (licence, logo du logiciel) et cela lui permet de prendre des décisions, au cours de l’installation (si besoin).

Pour finir, après cette étape, vous aurez un installeur soit en mode .zip, soit un .exe. Il ne reste plus qu’à mettre cet installeur accessible à vos utilisateurs et c’est bon.

Pensez Ă  le tester quand mĂŞme avant de faire des annonces publiques. On sait jamais !

 

Pour Mac OS:

Pour MacOs, il existe un outil similaire qui s’appelle: macqtdeploy.
Il utilise les mêmes paramètres que la version windows, la seule différence réside dans l’utilisation d’un .app (en lieu et place du .exe).

[pastacode lang=”bash” manual=”macdeploy%20application.app%20-qmldir%3D%2FUser%2Fdossier%2Fvers%2Fcode%2Fqml%20″ message=”sur MacOs X” highlight=”” provider=”manual”/]

Bien sûr, cela peut être intégrer dans QtCreator comme étape de déployement.
Sur MacOs, il est possible de demander à Qt de compiler une application dans un bundle (c’est d’ailleurs la solution par défaut). Un bundle est un dossier se terminant par «.app». Dans l’environnement graphique de MacOs, un double click lance le logiciel qu’il contient. Il est également possible, d’explorer le contenu du bundle en ligne de commande (cela se comporte comme un dossier) ou par un click droit: «afficher le contenu du packet» en graphique.

Dans tous les cas, l’utilisation de la commande va venir placer l’ensemble des dépendances Qt dans le bundle. Pour être précis, les bibliothèques sont placées dans le dossier Contents/Frameworks du bundle. Les modules QML sont dans Resources/qml.

A l’instar de windows, il faut mettre également d’éventuelles autres bibliothèques dans le bundle. C’est une étape un peu technique. Pour rolisteam, j’utilise zlib, voilà le programme bash qui me permet de faire l’ajout et de bien définir les chemins.

[pastacode lang=”bash” manual=”%23!%2Fbin%2Fsh%0A%0A%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%0A%23%20Rolisteam%20%0A%23%20Script%20to%20deploy%20libz%20into%20rolisteam.%0A%23%0A%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%0A%0Aecho%20’Display%20dependancies’%0Aotool%20-L%20rolisteam.app%2FContents%2FMacOS%2Frolisteam%0A%0A%0A%0Aecho%20’Create%20directory’%0Amkdir%20rolisteam.app%2FContents%2FFrameworks%2Flibz.framework%2F%0A%0Aecho%20’Copy%20lib%20binary’%0Acp%20%2Fusr%2Flib%2Flibz.1.dylib%20rolisteam.app%2FContents%2FFrameworks%2Flibz.framework%2F%0A%0Aecho%20’Rewrite%20path%20to%20the%20lib’%0Ainstall_name_tool%20-change%20%2Fusr%2Flib%2Flibz.1.dylib%20%40executable_path%2F..%2FFrameworks%2Flibz.framework%2Flibz.1.dylib%20rolisteam.app%2FContents%2FMacOS%2Frolisteam” message=”Ajouter une dĂ©pendances Ă  un bundle” highlight=”” provider=”manual”/]

En gros, il y a la copie du fichier en lui même puis, la modification de l’exécutable pour lui dire d’aller chercher zlib dans le bundle et non sur mon poste. Cette étape est très importante car sinon, votre bundle ne sera pas portable sur une autre machine.

Et après ?

Le fichier .app complet suffit pour ĂŞtre installĂ© sur une autre machine. Cependant, il est de coutume de distribuer un logiciel par un dmg. Cela permet de le compresser pour faciliter sa distribution et surtout MacOs permet de rendre graphique l’installation par un dmg.

Pour réaliser cela, j’utilise un petit utilitaire: node-appdmg. Il suffit d’un petit fichier de configuration en json pour définir les paramètres.

[pastacode lang=”javascript” manual=”%7B%0A%20%20%22title%22%3A%20%22Rolisteam%20%20-%20Mac%20Os%20X%22%2C%0A%20%20%22icon%22%3A%20%22rolisteam.icns%22%2C%0A%20%20%22background%22%3A%20%221500-rolisteam.png%22%2C%0A%20%20%22icon-size%22%3A%2080%2C%0A%20%20%22contents%22%3A%20%5B%0A%20%20%20%20%7B%20%22x%22%3A%20448%2C%20%22y%22%3A%20344%2C%20%22type%22%3A%20%22link%22%2C%20%22path%22%3A%20%22%2FApplications%22%20%7D%2C%0A%20%20%20%20%7B%20%22x%22%3A%20192%2C%20%22y%22%3A%20344%2C%20%22type%22%3A%20%22file%22%2C%20%22path%22%3A%20%22rolisteam.app%22%20%7D%0A%20%20%5D%0A%7D” message=”Configuration node-appdmg pour rolisteam” highlight=”” provider=”manual”/]

Vous lancez l’utilitaire avec le fichier de configuration et le nom de votre dmg pour obtenir votre dmg tout beau, tout propre.

node-appdmg dmg.json monapplication.dmg

Il ne reste qu’à distribuer votre dmg.

Conclusion

Nous venons de voir les solutions et les outils mis en place pour rolisteam.
Si vous avez des questions sur les outils,  ou si vous voulez en proposer d’autres, les commentaires sont là pour ça.

L5R présentation

Retours d’expérience d’une présentation QML

Pour préparer ma conférence à Pas Sage En Seine [FR], j’ai décidé de faire une présentation QML.
Cela offre un bien meilleur contrôle, bien plus de possibilité graphique (animations, intégration de code, 3D…) et de même de l’interactivité.
Bien sĂ»r, une prĂ©sentation QML demande plus de temps Ă  faire. Le but de l’article est ici d’expliquer les astuces que j’ai mises en place. EspĂ©rant gagner du temps la prochaine fois.

Le contenu de la présentation QML:

Comme vous pouvez le voir, la prĂ©sentation est une application C++ qui affiche du QML. Cette mĂ©thode permet de faciliter le contrĂ´le de la partie QML. Je m’en sers pour enregistrer des captures d’Ă©cran de la prĂ©sentation afin d’en faire un PDF. C’est le meilleur pour distribuer la prĂ©sentation ou dans le cas ou pour Ă©viter l’effet dĂ©mo.
Tout en haut, il y a les classes C++, les fichiers de management du projet et le fichier main.qml. Dans le rĂ©pertoire «pages», vous y trouverez les diffĂ©rentes slides de la prĂ©sentation. Dans rsrc, il y a l’ensemble des images nĂ©cessaire Ă  la prĂ©sentation.

├── cpphighlighter.cpp
├── cpphighlighter.h 
├── deployment.pri 
├── LICENSE 
├── main.cpp 
├── main.qml 
├── pages 
│ ├── 01_intro.qml 
│ ├── 02_presentation.qml 
│ ├── 03_jdr_et_rolisteam.qml 
│ ├── 043_Exemple_code_1.qml 
│ ├── 04_jdr_avantages_pb.qml 
│ ├── 05_avantage_jdr_virtuel.qml 
│ ├── 06_fonctionnalites_rolisteam.qml 
│ ├── 07_rolisteam_debut.qml 
│ ├── 08_Rolistik_a_Rolisteam.qml 
│ ├── 10_frise_chronologique.qml 
│ ├── 11_son_usage.qml 
│ ├── 12_son_fonctionnement.qml 
│ ├── 13_dice_parser.qml 
│ ├── 14_themes_audio_3_pistes.qml 
│ ├── 15_nouveaute_1_8.qml 
│ ├── 16_projet_avenir.qml 
│ ├── 17_reussites.qml 
│ ├── 18_les_lecons.qml 
│ ├── 19_objectif_rolisteam_libre.qml 
│ ├── 20_FAQ.qml 
├── pasSageEnSeine.pro 
├── pasSageEnSeine.pro.user 
├── qmlcontroler.cpp 
├── qmlcontroler.h 
├── qmlcontroler.ui 
├── qml.qrc 
├── README.md 
├── rsrc 
│ ├── all.png 
│ ├── cc.png 
│ └── chat.png

L’application C++

Il peut ĂŞtre utile de connaĂ®tre l’Ă©tat de la prĂ©sentation QML, et de pouvoir lire des notes sur chaque volet. Pour faire cela, j’ai Ă©cris une petite application C++.

le fichier main.cpp

Le premier objectif de l’application est d’afficher la prĂ©sentation QML. Il faut donc charger le QML et Ă©tablir des moyens de communication entre le monde QML et le C++. Comme vous pouvez le voir, je passe en paramètre la taille de la prĂ©sentation en paramètre du QML. Ce dernier Ă©lĂ©ment n’est pas obligatoire car par dĂ©faut j’utilise la taille de l’Ă©cran comme rĂ©fĂ©rence.

[pastacode lang=”cpp” manual=”%23include%20%3CQApplication%3E%0A%23include%20%3CQQmlApplicationEngine%3E%0A%23include%20%22qmlcontroler.h%22%0A%23include%20%3CQQmlContext%3E%0A%23include%20%3CQQuickTextDocument%3E%0A%0A%23include%20%22cpphighlighter.h%22%0A%0Aint%20main(int%20argc%2C%20char%20*argv%5B%5D)%0A%7B%0A%20%20%20%20QApplication%20app(argc%2C%20argv)%3B%0A%0A%20%20%20%20QQmlApplicationEngine%20engine%3B%0A%0A%20%20%20%20engine.rootContext()-%3EsetContextProperty(%22ScreenW%22%2C1280)%3B%0A%20%20%20%20engine.rootContext()-%3EsetContextProperty(%22ScreenH%22%2C720)%3B%0A%0A%20%20%20%20engine.load(QUrl(QStringLiteral(%22qrc%3A%2Fmain.qml%22)))%3B%0A%0A%20%20%20%20QmlControler%20ctr%3B%0A%20%20%20%20ctr.setEngine(%26engine)%3B%0A%0A%20%20%20%20return%20app.exec()%3B%0A%7D%0A” message=”main.cpp” highlight=”” provider=”manual”/]

Dans ce projet, la classe QmlControler est l’objet (fenĂŞtre) C++ qui affiche l’aperçu de la prĂ©sentation et les commentaires/notes.

Regardons en détails cet élément:

La fenĂŞtre d’aperçu

C’est une simple fenĂŞtre. Elle est dĂ©coupĂ©e en deux parties.  Celle de gauche affiche dans un QLabel l’aperçu de la prĂ©sentation QML. La partie de droite affiche les notes et commentaires sur la page courante dans un QTextArea.

[pastacode lang=”cpp” manual=”void%20QmlControler%3A%3AcurrentPageHasChanged(int%20i)%0A%7B%0A%20%20%20%20m_currentScreen%20%3D%20i%3B%0A%20%20%20%20QImage%20img%20%3D%20m_window-%3EgrabWindow()%3B%0A%0A%20%20%20%20if(img.isNull())%0A%20%20%20%20%20%20%20%20return%3B%0A%0A%20%20%20%20static%20int%20count%20%3D%200%3B%0A%0A%0A%20%20%20%20img.save(tr(%22screens%2F%251_screen.png%22).arg(%2B%2Bcount%2C3%2C10%2CQChar(‘0’))%2C%22png%22)%3B%0A%20%20%20%20qDebug()%20%3C%3C%20%22screen%20shot%20save%22%20%3C%3C%20count%3B%0A%0A%20%20%20%20m_ratioImage%20%3D%20(double)img.size().width()%2Fimg.size().height()%3B%0A%20%20%20%20m_ratioImageBis%20%3D%20(double)img.size().height()%2Fimg.size().width()%3B%0A%0A%20%20%20%20m_label-%3EsetPixmap(QPixmap%3A%3AfromImage(img))%3B%0A%0A%20%20%20%20if((i%2B1%3E%3D0)%26%26(i%2B1%3Cm_commentData.size()))%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20ui-%3EtextEdit-%3EsetHtml(m_commentData.at(i%2B1))%3B%0A%20%20%20%20%7D%0A%20%20%20%20resizeLabel()%3B%0A%7D” message=”Current slide has changed” highlight=”” provider=”manual”/]

Quand la page courante change, la fenĂŞtre C++ est informĂ© par l’appel du slot: currentPageHasChanged alors l’application rĂ©cupère une capture de la vue QML, l’affiche Ă  l’Ă©cran (dans la partie gauche), affiche les notes Ă  propos de la page courante et peut sauvegarder la capture dans un fichier.

Sauvegarder les captures dans des fichiers vous permet de crĂ©er un fichier PDF de votre prĂ©sentation. Il s’agit lĂ  d’une solution de secours en cas de problème avec le matĂ©riel de la prĂ©sentation ou une facilitĂ© pour distribuer votre prĂ©sentation.

La commande qui va bien (sous linux) :

$ convert *.png mypresentation.pdf

 

L’application QML

Le système de chargement (Loader)

Par souci de clartĂ©, je prĂ©fère avoir un fichier par page. Cela Ă©vite l’Ă©cueil d’un fichier QML long et complexe. L’application charge les pages en accord avec le modele de donnĂ©es principal dans le mĂŞme ordre.  Pour faire cela, j’ai utilisĂ© un ListModel. Une page est dĂ©finie par un titre, un nom de fichier, un temps (non utilisĂ©), et le nom de la page suivante.
Le fichier main.qml  affiche toutes les pages comme un «delegate» d’un pathview.  Toutes les pages sont chargĂ©s depuis le fichier de ressources de Qt (inclue dans le binaire grâce au système de ressources de Qt).

[pastacode lang=”css” manual=”ListModel%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20id%3A%20panelModel%0A%20%20%20%20%20%20%20%20%20%20%20%20ListElement%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20name%3A%20%22Intro%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20path%3A%20%2201_intro.qml%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20time%3A%201%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20next%3A%20%22Pr%C3%A9sentation%20de%20Rolisteam%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D” message=”First item of the model.” highlight=”” provider=”manual”/]

La donnée vraiment utile pour le chargement est bien sûr le nom du fichier.
Les autres sont là pour aider la rédaction ou la présentation.

Le loader fait son travail, voici les lignes importantes:

[pastacode lang=”css” manual=”%20%20%20%20PathView%20%7B%0A%20%20%20%20%20%20%20%20id%3A%20view%0A%20%20%20%20%20%20%20%20anchors.fill%3A%20parent%0A%20%20%20%20%20%20%20%20model%3A%20panelModel%0A%20%20%20%20%20%20%20%20highlightRangeMode%3APathView.StrictlyEnforceRange%0A%20%20%20%20%20%20%20%20snapMode%3A%20PathView.SnapOneItem%0A%20%20%20%20%20%20%20%20delegate%3A%20%20Loader%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20source%3A%20%22pages%2F%22%2Bpath%0A%20%20%20%20%20%20%20%20%7D” message=”Path View” highlight=”source: “pages/”+path” provider=”manual”/]

Le temps Ă©tait destinĂ© Ă  afficher un compte Ă  rebours pour chaque slide mais je n’ai pas eu le temps de l’implĂ©menter.

Il est important de mettre dans le main.qml tous les Ă©lĂ©ments que vous souhaitez avoir sur toutes les pages: le sommaire, l’indication de la page courante sur le total de pages, etc.

Ajouter un sommaire

Pour rĂ©aliser un sommaire, j’ai ajoutĂ© un ListView avec le modele suivant:

[pastacode lang=”css” manual=”%20%20%20%20ListView%20%7B%0A%20%20%20%20%20%20%20%20id%3A%20listView1%0A%20%20%20%20%20%20%20%20x%3A%20ScreenW*0.02%0A%20%20%20%20%20%20%20%20y%3A%20ScreenH*0.3%0A%20%20%20%20%20%20%20%20width%3A%20ScreenW%2F2%0A%20%20%20%20%20%20%20%20height%3A%20ScreenH*0.2%0A%20%20%20%20%20%20%20%20delegate%3A%20Item%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20width%3A%20ScreenW%2F2%0A%20%20%20%20%20%20%20%20%20%20%20%20height%3A%20listView1.height%2FlistView1.count%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Text%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20color%3A%20view.currentIndex%3E%3Dindex%20%3F%20%22black%22%20%3A%20%22gray%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20text%3A%20name%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20font.pointSize%3A%20ScreenH%2F48%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20anchors.verticalCenter%3A%20parent.verticalCenter%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20font.bold%3A%20true%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20visible%3A%20view.currentIndex%3E0%20%3F%20true%20%3A%20false%0A%0A%20%20%20%20%20%20%20%20model%3A%20ListModel%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20ListElement%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20name%3A%20%22Concepts%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20index%3A1%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20ListElement%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20name%3A%20%22Chroniques%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20index%3A6%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20ListElement%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20name%3A%20%22Logiciel%22%2F%2Fsyst%C3%A8me%20de%20build%2C%20code%20sp%C3%A9cifique%20par%20OS.%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20index%3A9%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20ListElement%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20name%3A%20%22Bilan%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20index%3A15%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D” message=”Table of contents in QML ” highlight=”” provider=”manual”/]

Le champs index du modèle permet de connaître la page qui démarre cette section du sommaire.

Page suivante

Quand il y a beaucoup de pages il peut ĂŞtre intĂ©ressant de connaĂ®tre la prochaine page afin de faire une petite transition vers elle. Dans mon cas, j’affiche dans le coin haut-droit le titre de la prochaine page. Ce fut assez utile pour les rĂ©pĂ©titions, je n’en ai presque pas eu besoin pendant la confĂ©rence.

[pastacode lang=”css” manual=”%20%20%20%20Text%20%7B%0A%20%20%20%20%20%20%20%20anchors.top%3A%20parent.top%0A%20%20%20%20%20%20%20%20anchors.right%3A%20parent.right%0A%20%20%20%20%20%20%20%20text%3A%20panelModel.get(view.currentIndex).next%2B%22%3E%22%0A%20%20%20%20%7D” message=”Next slide” highlight=”” provider=”manual”/]

L’autre possibilitĂ© est d’utiliser les notes dans la fenĂŞtre C++.

Créer une Page de présentation QML

Chaque page est indĂ©pendante, elles peuvent ĂŞtre totalement diffĂ©rentes cependant pour des raisons de simplicitĂ©, elle utilise une conception identique. Dans mon cas, elles sont constituĂ©es d’une ListView avec un modèle. Chaque Ă©lĂ©ment du modèle est un titre de section Ă  Ă©voquer pendant la prĂ©sentation.

Les Ă©lĂ©ments ont un index. Cet index est contrĂ´lĂ© par le clavier (flèche bas pour augmenter l’index, haut pour rĂ©duire l’index).  Grâce Ă  cet index, il est possible de cacher la liste et d’afficher une image, un schĂ©ma ou une vidĂ©o.

Par exemple, dans ma prĂ©sentation la fonctionnalitĂ© «Alias de dĂ©s» a pour index 10. Quand la index de la page devient 10, l’Ă©lĂ©ment «Alias de dĂ©s» apparaĂ®t avec une petite animation. Puis l’index passe Ă  11, j’affiche une image illustrant la fonctionnalitĂ© des alias de dĂ©s. A 12, l’image disparaĂ®t et le texte revient.

Position et taille

Pour s’assurer de la lisibilitĂ© des Ă©lĂ©ments, je rĂ©alise l’ensemble des calculs en rapport Ă  la taille de l’Ă©cran. Le positionnement est assurĂ© par des ancres (anchors en qml).

[pastacode lang=”css” manual=”%20%20%20%20Image%20%7B%0A%20%20%20%20%20%20%20%20id%3A%20image1%0A%20%20%20%20%20%20%20%20anchors.left%3A%20parent.left%0A%20%20%20%20%20%20%20%20anchors.top%3A%20parent.top%0A%20%20%20%20%20%20%20%20anchors.leftMargin%3A%20ScreenW*0.04%0A%20%20%20%20%20%20%20%20fillMode%3A%20Image.PreserveAspectFit%0A%20%20%20%20%20%20%20%20source%3A%20%22qrc%3A%2Frsrc%2FRolisteam.svg%22%0A%20%20%20%20%20%20%20%20width%3A%20ScreenW*0.2%0A%20%20%20%20%7D” message=”Display the logo at the right position and size.” highlight=”” provider=”manual”/]

Autre piste

Il existe un module qui fournit des Ă©lĂ©ments QML pour faciliter la rĂ©alisation d’une prĂ©sentation. Je ne l’ai pas utilisĂ© mais il y a des choses intĂ©ressantes.

Module QML

Obtenir le code de mes présentations

Je vous invite Ă  cloner ce code : https://github.com/obiwankennedy/pses

Autre exemple avec une image: https://github.com/obiwankennedy/l5rSummary

L5R présentation QML

Exemple de présentation QML

 

 

Convertir toutes les images (png) d’un dossier en niveaux de gris.

Bonjour,

Une petite commande pour créer des copies en niveaux de gris des images png du dossier courant.

for i in *.png; do name=`echo $i | awk -F '.' '{print $1}'`; convert $i -colorspace Gray $name-gray.png; done

Les copies portent le mĂŞme nom que l’original avec le suffixe -gray.
Cela peut facilement ĂŞtre adaptĂ© pour des jpg ou autres formats d’images.

Définir le terminal par défaut dans Nautilus

Nautilus propose dans son menu contextuel d’ouvrir un terminal.

C’est très pratique mais parfois, nautilus prĂ©fère lancer xterm plutĂ´t que gnome-terminal.

Si cela vous arrive; pas de panique. Les deux commandes suivantes peuvent vous aider.

gsettings set org.gnome.desktop.default-applications.terminal exec /usr/bin/gnome-terminal
gsettings set org.gnome.desktop.default-applications.terminal exec-arg '-x'

Il faut donc dĂ©finir l’exĂ©cutable et ses arguments.

Introduction Ă  Dbus avec Qt4

Dbus

Dbus est un bus système de messagerie. C’est un moyen simple pour des applications de communiquer entre elles. En plus de la communication interprocessus, Dbus est aussi un outil aidant au cycle de vie du processus. Il peut vous permettre de n’autoriser qu’une seule instance de votre application ou de votre daemon. Il peut vous permettre de dĂ©marrer votre application ou daemon Ă  la demande quand elles sont nĂ©cessaires. Il est possible d’Ă©tablir deux types de connexions: point Ă  point ou point d’accès (daemon central). Grâce au daemon, vos applications peuvent ĂŞtre prĂ©venues du branchement d’un nouvel composant matĂ©riel. Le bus de session (un par utilisateur connectĂ©) est le canal gĂ©nĂ©rique de communication. Dbus est destinĂ© Ă  la communication entre application d’un mĂŞme ordinateur. Il est cependant possible de communiquer par TCP/IP cryptĂ© avec un dossier home partagĂ© par NFS. Ce genre d’usage reste rare et expĂ©rimental.

Il est possible d’utiliser Dbus dans de nombreux langages: C/C++, python, ruby, perl, java, C#. Je vais me concenter sur l’implĂ©mentation de Dbus dans Qt4, dans cet article.

Dbus dans Qt4

Qt4 implement sa propre API Dbus. Le support de Dbus sur windows Ă©tant en cours (d’après le site internet), Qt a Ă©tĂ© sage de regrouper toutes les fonctionnalitĂ©s dans un module. Pour des environnements linux, il suffit d’installer la bibliothèque et Ă  l’Ă©dition des liens, ajouter

QT += dbus

Dans le fichier pro pour inclure le module dbus Ă  votre projet.

Les deux classes importantes sont QDbusMessage et QDbusInterface. La première permet d’envoyer facilement un message vers un service Dbus. C’est un moyen rapide pour communiquer une information vers une application dont vous ne maitrisez rien. Le QBusInterface permet une communication plus transparente, car tous les signaux/slots de votre application (d’une classe, pour ĂŞtre prĂ©cis) seront mis sur Dbus.

Monitorer Dbus

Vous ne le savez peut-ĂŞtre pas mais votre système GNU/Linux (s’il est assez moderne) utilise probablement DBUS en continue. Pour se donner une idĂ©e, il existe deux utilitaires assez intĂ©ressant: dbus-monitor et qdbusviewer.

capture de qdbusviewer

 

Connexion Ă  un service : Pidgin

Nous allons maintenant implĂ©mentĂ© une solution pour utiliser un service d’une application. Nous voulons mettre Ă  jour la petite phrase de status de pidgin. Ainsi votre logiciel de lecture audio pourra mettre en petite phrase la chanson actuellement jouĂ©e.

La première Ă©tape est d’identifiĂ© la fonction (et son chemin) qui nous intĂ©resse. En gĂ©nĂ©ral, les logiciels libres fournissent dans leur documentation l’API dbus qu’ils offrent. Cependant, l’outil qdbusviewer vous permet de voir toutes ces informations.

En terme de code, cela reste très simple. Vous déclarez un message Dbus. Il faut définir les bonnes valeurs: chemin, destinataire, noms..

[pastacode lang=”cpp” message=”Connexion Ă  un service dbus” highlight=”” provider=”manual” manual=”QDBusConnection%20sessionbus%20%3D%20QDBusConnection%3A%3AsessionBus()%3B%0A%0Aif%20(%20!sessionbus.isConnected()%20)%0A%7B%0A%20%20%20%20qDebug()%20%3C%3C%20%22Could%20not%20connect%20to%20session%20bus%22%3B%0A%7D%0A%20%20%20%20QDBusMessage%20m%20%3D%20%0A%20%20%20%20QDBusMessage%3A%3AcreateMethodCall(%22im.pidgin.purple.PurpleService%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%2Fim%2Fpidgin%2Fpurple%2FPurpleObject%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22im.pidgin.purple.PurpleInterface%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22PurpleUtilSetCurrentSong%22)%3B%0A%20%20%20%20QList%3CQVariant%3E%20args%3B%0A%20%20%20%20args%20%3C%3C%20m_p-%3ETitle%20%3C%3C%20m_p-%3EArtist%20%3C%3C%20m_p-%3Ealbum%3B%0A%20%20%20%20m.setArguments(args)%3B%0A%20%20%20%20QDBusMessage%20metadatamsg%20%3D%20sessionbus.call(m)%3B%0A%20%20%20%20if(metadatamsg.type()%20!%3D%20QDBusMessage%3A%3AReplyMessage)%0A%20%20%20%20%20%20%20%20qDebug()%20%3C%3C%20%22Error%20its%20not%20a%20message%20%22%20%3C%3C%20metadatamsg.type()%20%3C%3C%20metadatamsg.errorMessage%20()%3B”/]

La première Ă©tape est de dĂ©finir quel bus vous allez utiliser : le sessionBus ou le systembus? Dans notre cas, c’est le sessionBus. On verifie que tout se passe bien niveau connection au bus. Il convient ensuite de crĂ©er un message. Les paramètres du messages sont les suivants :

  • Le nom du service (la colonne de gauche de qdbusviewer)
  • Le chemin vers l’objet (concatĂ©nation de tous les noeuds de l’arbre sauf celui de l’interface).
  • Le chemin vers l’interface (noeud en italique dans qdbusviewer).
  • Une liste d’arguments peut ĂŞtre passĂ©e Ă  l’appel de la mĂ©thode du service. Dans notre cas, nous passons le titre de la chanson, l’artiste et le nom de l’album.
  • Dernière Ă©tape, appel de la mĂ©thode suivit d’une vĂ©rification d’erreur.

La voie royale pour faire communiquer deux applications via dbus grâce Ă  Qt est l’utilisation des adaptors. Ils traduisent les signaux et slots d’une classe Qt en message Dbus. C’est totalement transparent. Pour faire un exemple simple, je vais faire une application qui propose un service “dbus_example_Service”, de dĂ©finition de brigthness et les clients peuvent dĂ©finir le nouveau de volume. Plusieurs applications peuvent envoyer le volume au service et elles peuvent Ă©galement recevoir la brightness. Une seule et unique application peut faire office de service. Deux instance de l’application “dbus_example_Service” vont entrainĂ© des comportements inconnus.

qdbuscpp2xml -S -M mainwindow.h -o org.homelinux.renaudguezennec.xml

qdbusxml2cpp -c GuiAdaptor -a guiadaptor.h:guiadaptor.cpp org.homelinux.renaudguezennec.xml

qdbusxml2cpp -c GuiAdaptor -p test.h:test.cpp org.homelinux.renaudguezennec.xml

La première commande vous permet de gĂ©nĂ©rer un fichier xml: org.homelinux.renaudguezennec.xml qui contiendra l’ensemble de l’API de votre fichier .h.
Le resultat est de la forme suivante:

[pastacode lang=”markup” message=”Xml gĂ©nĂ©rĂ©” highlight=”” provider=”manual” manual=”%3C!DOCTYPE%20node%20PUBLIC%20%22-%2F%2Ffreedesktop%2F%2FDTD%20D-BUS%20Object%20Introspection%201.0%2F%2FEN%22%20%22http%3A%2F%2Fwww.freedesktop.org%2Fstandards%2Fdbus%2F1.0%2Fintrospect.dtd%22%3E%0A%3Cnode%3E%0A%20%20%3Cinterface%20name%3D%22org.homelinux.renaudguezennec%22%3E%0A%20%20%20%20%3Csignal%20name%3D%22brightnessChanged%22%3E%0A%20%20%20%20%20%20%3Carg%20type%3D%22i%22%20direction%3D%22out%22%2F%3E%0A%20%20%20%20%3C%2Fsignal%3E%0A%20%20%20%20%3Cmethod%20name%3D%22setVolumeLevel%22%3E%0A%20%20%20%20%20%20%3Carg%20type%3D%22i%22%20direction%3D%22in%22%2F%3E%0A%20%20%20%20%3C%2Fmethod%3E%0A%20%20%3C%2Finterface%3E%0A%3C%2Fnode%3E”/]


La deuxième commande crĂ©e une classe GuiAdaptor (dans les fichiers: guiadaptor.h et guiadaptor.cpp) qui expose l’API d’Ă©crire dans le xml. Cette classe sera utile cotĂ© service.

La troisième commande crĂ©e une classe GuiAdaptor (dans les fichiers: test.h et test.cpp) que sera capable de contacter l’API dĂ©crite dans le xml. Nous allons utiliser cette classe dans le client pour l’API dĂ©crite dans le xml.

L’Ă©tape suivante consiste Ă  gĂ©nĂ©rer une classe Adaptor qui transformera vos signaux/Slots Qt en message dbus. Il est utilisĂ© cĂ´tĂ© service. Dans le main de votre programme, il convient d’instancier un adaptor gĂ©nĂ©rĂ© (ici: ControlPanelAdaptor), comme cela:

[pastacode lang=”cpp” message=”Creation de service” highlight=”” provider=”manual” manual=”%23include%20%3CQtGui%2FQApplication%3E%0A%23include%20%22mainwindow.h%22%0A%23include%20%22guiadaptor.h%22%0Aint%20main(int%20argc%2C%20char%20*argv%5B%5D)%0A%7B%0A%20%20%20%20QApplication%20a(argc%2C%20argv)%3B%0A%20%20%20%20MainWindow%20w%3B%0A%20%20%20%20new%20GuiAdaptor(%26w)%3B%0A%20%20%20%20w.show()%3B%0A%0A%20%20%20%20QDBusConnection%20connection%20%3D%20QDBusConnection%3A%3AsessionBus()%3B%0A%20%20%20%20bool%20rel%20%3D%20connection.registerService(%22org.homelinux.renaudguezennec%22)%3B%0A%20%20%20%20rel%20%3D%20connection.registerObject(%22%2F%22%2C%26w)%3B%0A%0A%20%20%20%20return%20a.exec()%3B%0A%7D”/]


A ce stade, votre application peut-être un service dbus. Il fournit une API à travers DBus. Nous allons voir maintenant comment créer des clients qui vont utiliser cette API.

Nous allons donc construire un nouveau projet : dbus_example_client. Il contiendra la rĂ©ciproque du service. Le service est capable d’envoyer le signal brightnessChanged et reçoit son volume par l’appel Ă  setVolumeLevel. Le client lui sera capable d’appeler setVolumeLevel du service et de recevoir la valeur de brightnessChanged. Pour se faire, nous allons utilisĂ© la class GuiAdaptor (test.h et test.cpp) dans notre application cliente.

[pastacode lang=”cpp” message=”Client Qt” highlight=”” provider=”manual” manual=”%23include%20%3CQtGui%2FQApplication%3E%0A%23include%20%22mainwindow.h%22%0A%23include%20%22test.h%22%0A%0Aint%20main(int%20argc%2C%20char%20*argv%5B%5D)%0A%7B%0A%20%20%20QApplication%20a(argc%2C%20argv)%3B%0A%20%20%20MainWindow%20w%3B%0A%0A%20%20%20%20GuiAdaptor*%20adapteur%20%3D%20new%20GuiAdaptor(%22org.homelinux.renaudguezennec%22%2C%20%0A%20%20%20%20%22%2F%22%2CQDBusConnection%3A%3AsessionBus()%2C0)%3B%0A%0A%20%20%20%20QObject%3A%3Aconnect(%26w%2CSIGNAL(volumeChanged(int))%2Cadapteur%2C%0A%20%20%20%20SLOT(setVolumeLevel(int)))%3B%0A%0A%20%20%20%20QObject%3A%3Aconnect(adapteur%2CSIGNAL(brightnessChanged(int))%2C%26w%2C%0A%20%20%20%20SLOT(setBrightnessChanged(int)))%3B%0A%20%20%20%20w.show()%3B%0A%0A%20%20%20%20return%20a.exec()%3B%0A%7D”/]


Comme vous pouvez le voir, il suffit d’instancier une classe GuiAdaptor (#include “test.h”) et de connecter les signals et les slots de notre application avec cette instance. En l’occurence, notre application emet le signal volumeChanged(int), nous le lions au slot setVolumeLevel(int) de notre adapteur. Le signal Ă©mit par l’adapteur est rĂ©cupĂ©rĂ© dans un slot de notre application.

S’auto-hĂ©berger avec un serveur Fanless sur un système GNU/Debian.

Historique des versions

Version Date Auteur Description
0.1 (draft) 22 Mars 2010 Renaud Guezennec Montage d’un serveur fanless, installation système, dĂ©ploiement des premiers services (ssh et apache2) et configuration rĂ©seau.

Introduction

Faire du vrai internet, c’est facile. Ce tutorial prĂ©sente les Ă©tapes Ă  effectuer. Vous comprendrez que vous en ĂŞtes pleinement capable:
Si vous savez lire, que vous êtes motivés et un minimum patient, vous y arriverez.

Pourquoi hĂ©berger son site soi-mĂŞme? Pour des raisons d’indĂ©pendance: Je souhaite ĂŞtre la seule personne capable couper ma machine du rĂ©seau. Je veux savoir oĂą sont stockĂ©s mes fichiers. Faite de votre internet un point intelligent du rĂ©seau.
N’utilisez pas internet comme un minitel 2.0.J’ai fais le choix de monter un serveur fanless (sans ventilateur), pour deux raisons principales:

  • Le bruit : un ordinateur qui est destinĂ© Ă  fonctionner 24h/24 doit ĂŞtre silencieux.
  • L’Ă©conomie d’Ă©nergie : mes choix techniques sont principalement vouĂ©s Ă  rĂ©duire la consommation Ă©lectrique de l’appareil. Il existe des solutions bien plus performante que ma solution de ce point de vue, lĂ .

Matériel

Le matĂ©riel que j’ai choisi n’est pas vraiment la solution la plus Ă©conomique. Il est vrai qu’essayer de monter un serveur fanless n’est pas encore très facile; j’espère ouvrir un peu la voie.
On arrive dans des domaines assez inconnus. C’est très rare de trouver des cartes mères passives.
Les boitiers ont souvent un petit ventillo pour l’alimentation ou les disques. J’ai aussi souhaitĂ© avoir une capacitĂ© en disque importante, cette condition Ă©limine la plupart des solutions tout en un. Je n’avais pas envie d’avoir une boitier relier Ă  un disque dur externe ou une clĂ© USB. Cependant, sachez que ces solutions existent!

Je vous communique les rĂ©fĂ©rences des diffĂ©rentes pièces que j’ai achetĂ©es.

Montage

Les pièces utiles:

ensemble des composantsle lecteur CD est vraiment optionnel, je n’en ai pas eu besoin.

La carte mère:

carte mèreLe cĂ´tĂ© pratique, c’est que les cartes mères atom sont fournies avec le cpu dĂ©jĂ  installĂ© et sĂ»rement soudĂ© Ă  la carte. L’installation en est plus facile mais ça empèche toute Ă©volution matĂ©rielle par la suite.

le boitier:

boitierCe boitier est mal agencĂ©, je trouve. Il est gros pour pas grand chose. Le support disque dur n’accueille qu’un disque alors qu’il y a la place d’en mettre bien plus. C’est d’ailleur ce que j’ai fait.

Installation de la carte mère:

La première chose Ă  dire, c’est que le montage ce n’est pas facile. J’ai dĂ©jĂ  montĂ© pas mal d’ordinateurs. Celui-ci fut assez pĂ©nible. L’absence de documentation pour le boitier est vraiment un problème. La carte mère se colle directement sur le fond du boitier. Il n’y pas les habituelles chemises.

installationLes cables d’alimentations sont assez mal fichus. Ils sont trop long et surtout le socle du lecteur de CD gène Ă©normĂ©ment. Par chance, vous pouvez enlever les socles CD et disque. Faites-le pour vous dĂ©gager l’espace. Sans ça, le branchement des LED power/disque et des USB sera très compliquĂ©. Pour les disques, j’ai branchĂ© le premier sur le socle prĂ©vu Ă  cet effet. Le deuxième repose sur un lit de polystirène sous le premier.
Après plusieurs tentatives, ça ne dĂ©marrĂ© pas. J’ai dĂ©branchĂ© le lecteur CD, vĂ©rifiĂ© certains branchements puis il a enfin dĂ©marrĂ©.

Installation du système et des services

Je suis un fidèle du système de paquet DEB, crĂ©er par/pour la distribution debian. J’utilise Ubuntu pour mon poste de travail mais pour un serveur, une vraie debian est bien mieux [Ce n’est que mon avis].
Dans les autres distributions pour faire un serveur, je dirais que Gentoo me parait un bon choix. (Elle reste cependant assez compliqué au premier abord.)
Comment installe-t-on un système debian?

Télécharger les bons fichiers

J’ai installĂ© Debian Lenny. Les images ont Ă©tĂ© tĂ©lĂ©chargĂ©es le 05/03/2010.
J’ai optĂ© pour un installation assez exotique. DĂ©marrer sur clĂ© USB qui embarque une image iso minimale (netinst).

L’image Ă  copier sur la clĂ© s’appelle boot.img.gz
Une fois l’image tĂ©lĂ©chargĂ©e, il suffit de l’Ă©crire sur votre clĂ© usb (attention, ça Ă©crasera tout le reste) par la commande:

# zcat boot.img.gz /dev/sdX

(La commande sudo ne marche pas. Faite-le en root! C’est surement une histoire de droit de l’utilisateur sur les pĂ©riphĂ©riques).

Montez la clé:

# mount /dev/sdX /mnt

Deux images peuvent ĂŞtre utilisĂ©es: la “netinst” et la “businesscard”. J’ai choisi la netinst, elle est très lĂ©gère, l’installation est très minimaliste (Ă  condition de choisir les bonnes options), cependant le système doit ĂŞtre sur internet pour l’installation.

Pour tĂ©lĂ©charger l’image netinst :

debian-504-i386-netinst.iso
Copier l’image dans la clĂ©:

# cp /chemin/vers/image/iso/debian-504-i386-netinst.iso /mnt/

Installer sa GNU/Debian

DĂ©marrer l’installation, rien de plus facile. Il suffit de brancher la clĂ© usb puis de dĂ©marrer la machine. On voit la still picture (le logo du fabriquant de la carte mère). Vint, en suite, l’Ă©cran de choix de la langue de l’installateur debian.

langueJ’ai choisi anglais en langue et un clavier français. Après cet Ă©cran, le mini système GNU/Linux cherchera sur la clĂ© installĂ©ei, l’image iso Ă  utiliser. L’installeur vous demandera de dĂ©finir les partitions. J’ai crĂ©e deux partitions sur le premier disque: le swap et le point de montage / . Mon swap fait 20 go, ça devrai ĂŞtre suffisant. Le deuxième disque est montĂ© sur /home. Après l’Ă©tape des disques, il faudra choisir le type d’installation. Par dĂ©faut, la version desktop est sĂ©lectionnĂ©. J’ai choisi l’installation du strict minimum. Il vous posera des questions pour dĂ©finir le mot de passe root et le login/password de votre utilisateur.

A l’aboutissement de l’installation, vous redĂ©marrez l’ordinateur en dĂ©branchant la clĂ© usb. Maintenant, votre ordinateur est fonctionnel. Nous pouvons lui installer les services et outils nĂ©cessaires pour le transformer en vrai serveur.

Installation des premiers services

Le service des services, le premier pas du voyage, c’est le serveur SSH. Afin d’administer son serveur Ă  distante, plus besoin d’Ă©cran et de clavier. Ensuite, apache2 le serveur web, l’arme noble pour l’expression de vos libertĂ©s. PHP5 pour crĂ©er des sites cotĂ© serveur. Vim, l’Ă©diteur en ligne de commande que je prĂ©fère. Le serveur mysql avec son support php afin d’utiliser une base de donnĂ©es pour vos sites. En dernier lieu, php5-gd c’est un module assez utile pour php.

# apt-get install openssh-server
# apt-get install apache2
# apt-get install php5
# apt-get install vim
# apt-get install mysql-server php5-mysql
# apt-get install php5-gd

Sécurisation des premiers services

Configuration ssh server (la base d’une bonne sĂ©curitĂ©)

Editer en root, le fichier /etc/ssh/sshd_config.
Changer le port par dĂ©faut (22) par un port quelconque. C’est une sĂ©curitĂ© contre les attaques de force brute:
Port 22 en Port 9999
vous pouvez prendre n’importe quelle valeur comprise entre 1024 et 65536. (plus d’info)
DĂ©sactiver l’autorisation de login en root directement. Cela augmente la complexitĂ© pour forcer le passage. Les mĂ©chants devront trouver votre login et mot de passe. De plus, il est plus propre de se connecter en tant qu’utilisateur normal.
PermitRootLogin yes en PermitRootLogin no
Cette option est pour les utilisateurs avancĂ©s. Il vous faudra mettre dans votre serveur une clĂ© ssh. Cela rend l’authentification plus sĂ»re.
PasswordAuthentication yes en PasswordAuthentication no

Voici une copie de mon fichier de configuration:

# Package generated configuration file
# See the sshd(8) manpage for details

# What ports, IPs and protocols we listen for
Port 999
# Use these options to restrict which interfaces/protocols 
# sshd will bind to
#ListenAddress ::
#ListenAddress 0.0.0.0
Protocol 2
# HostKeys for protocol version 2
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_dsa_key
#Privilege Separation is turned on for security
UsePrivilegeSeparation yes

# Lifetime and size of ephemeral version 1 server key
KeyRegenerationInterval 3600
ServerKeyBits 768

# Logging
SyslogFacility AUTH
LogLevel INFO

# Authentication:
LoginGraceTime 120
PermitRootLogin no
StrictModes yes

RSAAuthentication yes
PubkeyAuthentication yes
#AuthorizedKeysFile	%h/.ssh/authorized_keys

# Don't read the user's ~/.rhosts and ~/.shosts files
IgnoreRhosts yes
# For this to work you will also need host keys
# in /etc/ssh_known_hosts
RhostsRSAAuthentication no
# similar for protocol version 2
HostbasedAuthentication no
# Uncomment if you don't trust ~/.ssh/known_hosts 
# for RhostsRSAAuthentication
#IgnoreUserKnownHosts yes

# To enable empty passwords, change to yes (NOT RECOMMENDED)
PermitEmptyPasswords no

# Change to yes to enable challenge-response passwords
# (beware issues with some PAM modules and threads)
ChallengeResponseAuthentication no

# Change to no to disable tunnelled clear text passwords
PasswordAuthentication no

# Kerberos options
#KerberosAuthentication no
#KerberosGetAFSToken no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes

# GSSAPI options
#GSSAPIAuthentication no
#GSSAPICleanupCredentials yes

X11Forwarding no
X11DisplayOffset 10
PrintMotd no
PrintLastLog yes
TCPKeepAlive yes
#UseLogin no

#MaxStartups 10:30:60
#Banner /etc/issue.net

# Allow client to pass locale environment variables
AcceptEnv LANG LC_*

Subsystem sftp /usr/lib/openssh/sftp-server

UsePAM yes

Connexion & réseau

L’auto-hĂ©bergement nĂ©cessite certaines conditions Ă  propos de votre connexion internet. Elle ne sont pas obligatoire mais cela facilite grandement la vie. Il faut une connexion en continue: type adsl ou (encore mieux) fibre optique, Ă©viter les contrats limitĂ©s Ă  un volume de donnĂ©es transmis. Personnellement, je n’ai jamais utilisĂ© les “machinBox”. PrĂ©fĂ©rant acheter un modem/routeur configurable: j’utilise le Netgear DG834G et le Netgear DGN2000. Je suis très content de ses deux modèles. Il est facile d’ouvrir les ports et rediriger vers telle ou telle machine. Le contrĂ´le du DHCP permet une gestion Ă©lĂ©gante de votre rĂ©seau LAN.

Hypothèse: vous avez deux machines différentes dans votre LAN réliée à un routeur/modem.

La première des choses Ă  faire est de s’assurer que le serveur recevra toujours la mĂŞme ip au sein du rĂ©seau LAN. Pour cela, il y a deux possibilitĂ©s:

  • IP fixe dans le LAN
  • Utilisation d’un serveur DHCP bien configurĂ©

Je dĂ©conseille la première solution. Elle nĂ©cessite la configuration de chaque poste, une mauvaise configuration peut entrainĂ© des conflits d’adresse IP. De plus, l’ajout d’une nouvelle machine vous obligera Ă  configurer celle-ci.
La 2ème mĂ©thode est plus souple. Votre routeur/modem donne l’adresse IP pour chaque machine et pour fixer les adresses IP, il se fonde sur les adresses MAC.
L’adresse MAC est une sorte de numĂ©ro d’immatriculation de votre carte rĂ©seau. Il est “normalement” unique au monde. (Dans les faits, il peut ĂŞtre changer logiciellement donc…)
Il est donc possible d’obliger votre modem/routeur Ă  donner l’adresse 192.168.0.3 Ă  votre serveur, l’adresse 192.168.0.2 Ă  votre pc de bureau et de spĂ©cifier que pour toutes autres machines, la plage 192.168.0.10 Ă  192.168.0.120 doit ĂŞtre utilisĂ©.
Pour Ă©viter les problèmes, je vous conseillerais de dĂ©sactiver le Wi-Fi de votre rĂ©seau. Ce n’est pas une technologie très sĂ»re.

La machine serveur reçoit toujours la mĂŞme ip ? Il est temps de passer Ă  la redirection des ports. Les 1024 premiers ports sont rĂ©servĂ©s Ă  des usages dĂ©finis. Par exemple, le port standard d’un serveur http est le 80: www.trucmuche.org et www.trucmuche.org:80 sont strictement identiques dans un navigateur.
Quelques autres ports/protocoles Ă  connaitre (ou pas):

  • https: 440
  • FTP: 20 et 21
  • ssh: 22
  • smtp(mail) : 25
  • DNS: 53

Nous voulons rendre accessible notre serveur sur la toile. Le port 80 doit renvoyer vers l’ip du serveur. Toutes les demandes sur le port 80 Ă  l’adresse: 80.80.80.80 seront transmises vers l’ip 192.168.0.3.
La mĂŞme chose doit ĂŞtre faite pour chaque service qui tourne sur votre serveur et que vous voulez accessible depuis l’extĂ©rieur. Le ssh, par exemple, est maintenant sur le port 9999. Parametrez votre routeur/modem afin d’acheminer les connexions sur le port 9999 vers votre serveur. Pour rĂ©aliser le chapitre suivant, la redirection du port 53 est nĂ©cessaire.

Dynamique Name Server

C’est une partie que je maitrise moins. Je vais donc expliquer ce que j’ai compris. Vous avez achetĂ© un nom de domaine: trucmuche.org. vous voudriez maintenant qu’il pointe vers votre serveur homemade dans votre placard? Il y a en gros, deux solutions: GĂ©rer son DNS Ă  la maison. ou le faire gĂ©rer par quelqu’un d’autre (probablement votre FAI ou votre registar).
Le premier cas est la solution la plus éducative et la plus souple: Si vous avez choisi cette option (comme moi), il faut installer bind9. Bind est le soft qui fait marcher internet. Il est le serveur DNS. Les DNS traduisent un nom de domaine en adresse ip.

Pour l’installer:

# apt-get install bind9

La configuration est bien plus complexe. Etudiont d’abord, la hiĂ©rarchie des fichiers de configuration.

homemade:~# ls -l /etc/bind/
total 48
-rw-r--r-- 1 root root  237 2009-12-20 21:21 db.0
-rw-r--r-- 1 root root  271 2009-12-20 21:21 db.127
-rw-r--r-- 1 root root  237 2009-12-20 21:21 db.255
-rw-r--r-- 1 root root  353 2009-12-20 21:21 db.empty
-rw-r--r-- 1 root root  270 2009-12-20 21:21 db.local
-rw-r--r-- 1 root root 2878 2009-12-20 21:21 db.root
-rw-r--r-- 1 root bind  907 2009-12-20 21:21 named.conf
-rw-r--r-- 1 root bind  240 2010-03-17 21:24 named.conf.local
-rw-r--r-- 1 root bind  572 2010-03-17 21:50 named.conf.options
-rw-r----- 1 bind bind   77 2010-03-17 21:05 rndc.key
-rw-r--r-- 1 root root 1317 2009-12-20 21:21 zones.rfc1918

Les fichiers de forme db.* sont des fichiers de configuration de zone dns; (nous verrons dans quelques instants, comment créer la zone pour trucmuche.org). Le fichier named.conf.options est le fichier de configuration du serveur. named.conf ne doit pas être modifier enfin sauf si vous êtes un super expert de la mort qui tue. Il convient de modifier named.conf.local pour ajouter notre zone.

Déclarons une zone sous la responsabilité de notre dns.

zone "trucmuche.org" {
	type master;
	file "/etc/bind/db.trucmuche.org";
};

Il y a deux type de zone: master (primaire) et slave (secondaire). Un nom de domaine est forcément attaché, au minimum, à deux serveurs dns: un seul primaire et un (ou plusieurs) secondaire. Le serveur primaire fait loi, les secondaires se mettront à jour par rapport à lui. Créer un fichier, /etc/bind/db.trucmuche.org Il doit contenir ceci:

$ORIGIN trucmuche.org.
$TTL 3h
@       IN      SOA     ns.trucmuche.org. gamemaster.trucmuche.org. (
                                2010031703
                                8H
                                2H
                                1W
                                1D )

@       	IN  NS  ns.trucmuche.org.

@       	IN  MX  10   mail2.trucmuche.org.

@  			IN	A	80.80.80.80


ns			IN	A	80.80.80.80
mail2   	IN	A   80.80.80.80
wiki    	IN	CNAME	trucmuche.org.
forum       IN  CNAME   trucmuche.org.
www         IN  CNAME   trucmuche.org.
};

La première ligne n’est pas importante, elle dĂ©finit une variable Ă  l’intĂ©rieur pour faciliter l’Ă©criture du fichier de conf. Le TTL est le temps de valider des informations de votre zone. Il convient de dĂ©finir une zone SOA.

  • 2010031703 : Serial sorte de numero de version de la configuration, on utilise en gĂ©nĂ©ral la date du jour plus un champ 00 qu’on incrĂ©mente Ă  chaque modification.
  • 8H : Rafraichissement: le serveur secondaire se mettra Ă  jour en respectant ce temps ci.
  • 2H : retry : temps d’attente avant de rĂ©essayer quand une requĂŞte de mise Ă  jour Ă  Ă©chouer.
  • 1W : Expire : Temps après lequel la zone est gelĂ©e si les dns secondaire ne peuvent se mettre Ă  jour.
  • 1D : Semblable Ă  TTL.

@ IN NS ns.trucmuche.org.
Vous définissez le serveur de nom (DNS) qui définit la zone courante.
@ IN MX 10 mail2.trucmuche.org.
Vous définissez le serveur de mail principal de votre domaine.
@ IN A 80.80.80.80
Vous dĂ©finissez l’ip principale de votre domaine, N’oubliez pas remplacer 80.80.80.80 par votre ip fixe.

ns 		IN	A   80.80.80.80
mail2   	IN	A   80.80.80.80

Définition des adresses ip pour votre serveur de nom et courriel.

wiki    	IN	CNAME	trucmuche.org.
forum       IN  CNAME   trucmuche.org.
www         IN  CNAME   trucmuche.org.

DĂ©finition de sorte d’alias, ainsi {wiki,forum,www}.trucmuche.org pointeront vers trucmuche.org. C’est apache (le serveur web) qui fera l’aiguillage.

Configuration Apache

Introduction

Apache, le serveur web du monde libre, le support de votre libertĂ© d’expression, votre megaphone du web. Pour le rendre fonctionnel et l’adapter Ă  vos besoins, il est important de le configurer.
Les dossiers de configuration d’apache se trouve dans l’arborĂ©scence /etc/apache2/

-rw-r--r-- 1 root root 10104 2009-11-14 21:20 apache2.conf
drwxr-xr-x 2 root root  4096 2010-03-05 23:24 conf.d
-rw-r--r-- 1 root root   378 2009-11-14 21:20 envvars
-rw-r--r-- 1 root root    21 2010-03-07 12:59 httpd.conf
drwxr-xr-x 2 root root  4096 2010-03-05 23:24 mods-available
drwxr-xr-x 2 root root  4096 2010-03-07 14:42 mods-enabled
-rw-r--r-- 1 root root   513 2009-11-14 21:20 ports.conf
drwxr-xr-x 2 root root  4096 2010-03-19 00:04 sites-available
drwxr-xr-x 2 root root  4096 2010-03-19 00:05 sites-enabled

Dans l’ordre, le fichier apache2.conf dĂ©finit la configuration vitale du serveur. Il est dĂ©conseillĂ© d’y toucher.
Ce fichier définit le comportement par défaut du serveur: nombre de thread, les chemins et/ou nom de fichier pour modifier la configuration localement.
Le dossier conf.d contient des fichiers de configurations pour des points très spĂ©cifique d’apache.
envvars dĂ©finit des variables d’environnements, prĂ©sentement, le groupe et l’utilisateur sous lequel apache2 tourne. (Par dĂ©faut, www-data)

httpd.conf est partiquement vide. Nous allons utiliser des virtualhosts donc ce fichier ne prĂ©sente plus beaucoup d’intĂ©rĂŞt.
mods-available est un dossier regroupeant les fichiers de conf des modules disponibles pour apache. Un module permet d’Ă©tendre les fonctionnalitĂ©s d’apache. Php est intĂ©grĂ© dans apache sous la forme de module. Le support du ssl est aussi un module, il en existe beaucoup et vous pouvez mĂŞme crĂ©er le votre, si cela vous intĂ©resse.mods-enabled regroupe des liens symboliques vers les fichiers de configuration du module prĂ©sents dans mods-available. Il faut bien comprendre qu’un module prĂ©sent dans mods-available regroupe les modules activables et mods-enabled regroupe les modules activĂ©s. Pour activer un module, il suffit de placer les fichiers du module dans le dossier mods-enabled.

Dans le mĂŞme principe, les dossiers sites-available et sites-enabled sont rĂ©spectivement le dossier des sites internet disponibles et le des sites internet actifs. LĂ  encore, il est bon de crĂ©er un fichier de configuration dans available et d’ajouter un lien dans enabled. Nous verrons dans la partie virtuals hosts, comment configurer son site ou plutĂ´t ses sites.

Utilisateur et droit

Il y a plusieurs moyens de gérer un serveur apache au niveau des droits. Cela dépend beaucoup de votre utilisation et de votre philosophie. Les différents choix:

  1. Votre serveur, c’est le votre. Il n’hebergera que votre site et rien d’autre.
  2. Votre serveur hĂ©bergera un gros site (par exemple le site d’une association, ou un site divisĂ© en plusieurs sous-domaines: forum, wiki et www). Ils seront gĂ©rĂ© par vous et une poignĂ©e d’Ă©lus.
  3. Vous voulez que chaque utilisateur de votre serveur aie un site web et un compte utilisateur.
Le cas #1

La situation la plus facile. Vous n’avez pas d’accès Ă  ouvrir. Vous pouvez coder/mettre Ă  jour votre site par ssh. Vous n’aurais pas besoin de FTP.
Je vous conseille de crĂ©er un dossier “trucmuche” dans /home/toto. Votre utilisateur (toto) aura tous les droits sur votre futur site et apache sera limitĂ©.
Render l’utilisateur www-data membre du groupe toto. Pour cela, Ă©diter le fichier /etc/group comme ceci.

# vi /etc/group

Ajouter www-data Ă  la fin de la ligne toto:

toto:x:1000:www-data

Assurez-vous que le groupe toto ait les droits de lecture sur l’ensemble des sous-dossiers et fichiers prĂ©sents dans /home/toto/trucmuche. Si vous voulez permettre Ă  votre site uploader des fichiers, le serveur aura besoin des droits en Ă©criture sur le rĂ©pertoire de destination. C’est un effort de codage sur votre site. Cette configuration est propre et minimaliste.

Si cette vision vous convient sauter directement Ă  la section Cas 1 : virtual host
Si vous cherchez une solution plus puissante et moins minimaliste, vous pouvez lire les sections suivantes.

Le cas #2

C’est dĂ©jĂ  plus risquĂ©. Je vous conseillerais de crĂ©er un utilisateur webmaster et de crĂ©er un dossier dans /home/webmaster/ par site web: [/home/webmaster/www,/home/webmaster/wiki,/home/webmaster/forum]. En termes de droits, il suffit de rendre www-data membre du groupe webmaster:

# vi /etc/group

Ajouter www-data Ă  la fin de la ligne webmaster:

webmaster:x:1001:www-data

Si vous déployez des outils libres, comme un CMS, un wiki et un forum. Il vous suffira de créer des comptes administrateurs dans ces outils.
Si vous voulez donner un accès plus direct. Il est possible de mettre en place un FTP ou bien de donner les identifiants de webmaster.
[Il est encore plus intelligent de crĂ©er un utilisateur pour chaque “Ă©lu” et de rendre ces utilisateurs membre du groupe webmaster. Les fichiers devront ĂŞtre modifiable par les membres du groupe. Cependant, il vous sera plus facile de connaitre l’identitĂ© d’une personne responsable d’une bĂ©tise/erreur].

Si cette description répond à votre besoin aller directement à la section Cas 2 : virtual host

Le cas #3

Le plus complèxe des trois Ă  mettre en place. Vous voulez que chaque utilisateur dispose d’un dossier particulier dans leur home (html_public ou www). Ils auront un accès direct au serveur par ssh ou FTP. Chaque utilisateur aura une base de donnĂ©es. Ce cas est assez frĂ©quent dans les universitĂ©s et/ou hĂ©bergeurs. Pour des raisons de sĂ©curitĂ©s, je vous conseillerais de ne pas donner d’accès ssh.

Cette configuation est relativement complexe, je vous conseillerais de jouer un peu avec les cas précédents. Afin de bien, vous faire la main sur les fichiers de configuration apache et autres.

La gestion des droits est délicate. Il y a plusieurs approches:

  • Rendre tout le monde membre du groupe d’apache [www-data]
  • l’opposĂ©; n’ajouter personne mais les fichiers devront ĂŞtre accessible en lecture pour tous le monde.
  • Le troisième cas, Ă©xĂ©cuter apache avec les droits d’un autre utilisateur (voir la section Cas 3 : virtual host)

les virtuals hosts

Ces cas typiques sont des exemples. N’hesitez pas Ă  mĂ©langer les solutions techniques.

Un site unique (cas 1)

La première chose à faire est de créer un dossier dans votre home /home/toto/monsite/.

$ mkdir /home/toto/monsite

Il faut ensuite créer un lien de

/var/www/

vers

/home/toto/monsite/

. Pour cela, tapez la commande suivante dans un terminal (root):

# cd /var/www
# ln -s /home/toto/monsite site

N’oubliez pas de vĂ©rifier les droits du groupe.

Ouvrez le fichier /etc/apache2/site-enabled/000-default pour y mettre ceci :
[Les lignes commençant par # sont des commentaires, je les utilise pour expliquer]

<VirtualHost 192.168.0.3:80>
    ServerAdmin toto@trucmuche.org
    ServerName trucmuche.org

    DocumentRoot /var/www/site1/
    #nous définissons le dossier racine du site.
    <Directory /var/www/site1>
        Options Indexes FollowSymLinks
        # Indexes : autorise apache à générer des indexes.
        # nous autorisons apache Ă  suivre les liens symboliques. 
        # Important car /var/www/site1/ est un lien symbolique 
        # vers /home/toto/monsite/
        AllowOverride All
        # Nous autorisons Apache Ă  changer sa configuration 
        # si un fichier .htaccess existe dans le dossier 
        # /var/www/site1
        Order allow,deny
        # Ordre de description des règles
        allow from all
        # Autorise tout le monde 
        # (pas besoin de règle d'interdiction)
        # Vous pouvez ajouter une plage d'ip interdite 
        # avec une ligne du genre Deny from XXX.XXX.XXX.XXX/XXX 
    </Directory>

    
    ErrorLog /var/log/apache2/error.log

# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.
    LogLevel warn

    CustomLog /var/log/apache2/access.log combined
    ServerSignature On

     # Configuration par défaut des logs
     # A savoir: 
     # Niveau de log: avertissement (warm). 
     # [debug, info, notice, warn, error, crit]
     # Fichier d'enregistrement des logs dans:
     # /var/log/apache2/access.log 
     # La signature du serveur est activée.


    
    Alias /phpMyAdmin/ "/var/www/phpMyAdmin/"
    <Directory "/var/www/phpMyAdmin/">
        AllowOverride None
        Order allow,deny
        Deny from all
        Allow from 192.168.0.0/24 
        #on restrint l'accès au gestionnaire de base de données.
        #Seule les adresses de type 192.168.0.XXX seront acceptées. 
    </Directory>
    
</VirtualHost>
Un gros site avec sous-domaine (cas 2)

Je vais prendre, dans cet exemple, trois sous-domaines : www, wiki et forum qui afficheront respectivement la page principale du site, un wiki et un forum. La première étape consiste à créer 3 fichiers de configuration dans /etc/apache2/sites-available (en root).

# cd /etc/apache2/sites-available
# touch wiki.trucmuche.org
# touch forum.trucmuche.org
# touch www.trucmuche.org

Il convient ensuite d’installer les diffĂ©rents logiciels. A titre d’exemple, je vous explique la marche Ă  suivre pour installer mediawiki, fluxbb et drupal.

Positionnez-vous, d’abord, dans le rĂ©pertoire de votre utilisateur webmaster (Il faut ĂŞtre l’utilisateur webmaster).
Téléchargement des logiciels et installation:

$ cd /home/webmaster
$ wget http://download.wikimedia.org/mediawiki/1.15/mediawiki-1.15.1.tar.gz
$ wget http://fluxbb.org/download/releases/1.4-rc1/fluxbb-1.4-rc1.tar.gz
$ wget http://ftp.drupal.org/files/projects/drupal-6.16.tar.gz

$ tar -xzvf drupal-6.16.tar.gz
$ mv drupal-6.16/ drupal

$ tar -xzvf fluxbb-1.4-rc1.tar.gz
$ mv fluxbb-1.4-rc1/ forum

$ tar -xzvf mediawiki-1.15.1.tar.gz
$ mv mediawiki-1.15.1/ wiki

Après cette étape, vous devriez avoir les dossiers : wiki, forum et drupal dans /home/webmaster
Il faut maintenant faire la configuration du serveur apache pour qu’il aille chercher les fichiers au bon endroit.
Commençons par drupal (qui sera www.trucmuche.org): Éditez le ficher : /etc/apache2/sites-available/www.trucmuche.org qui est normalement vide.

<VirtualHost *:80>
	ServerName www.trucmuche.org
    #definition du sous-domaine
	ServerAdmin webmaster@trucmuche.org
	
	DocumentRoot /var/www/webmaster/drupal
	<Directory /home/www/webmaster/drupal>
		Options Indexes FollowSymLinks MultiViews
		AllowOverride All
		Order allow,deny
		Allow from all
	</Directory>
	ErrorLog /var/log/apache2/error.log
	LogLevel warn
	CustomLog /var/log/apache2/trucmuche/trucmuche.log combined
    # Nous spécialisons le log de sortie pour clarifier les logs.
</VirtualHost>

Il faut faire la mĂŞme chose pour le wiki et le forum:

<VirtualHost *:80>
	ServerName wiki.trucmuche.org
	ServerAdmin webmaster@trucmuche.org
	
	DocumentRoot /var/www/webmaster/wiki
	<Directory /home/www/webmaster/wiki>
		Options Indexes FollowSymLinks MultiViews
		AllowOverride All
		Order deny,allow
		Deny from all
		Allow from 127.0.0.0/255.0.0.0 ::1/128			
	</Directory>
	ErrorLog /var/log/apache2/error.log
	LogLevel warn
   CustomLog /var/log/apache2/trucmuche/wiki.trucmuche.log combined
</VirtualHost>
<VirtualHost *:80>
	ServerName forum.trucmuche.org
	ServerAdmin webmaster@trucmuche.org
	
	DocumentRoot /var/www/webmaster/forum
	<Directory /home/www/webmaster/forum>
		Options Indexes FollowSymLinks MultiViews
		AllowOverride All
		Order deny,allow
		Deny from all
		Allow from 127.0.0.0/255.0.0.0 ::1/128			
	</Directory>
	ErrorLog /var/log/apache2/error.log
	LogLevel warn
CustomLog /var/log/apache2/trucmuche/forum.trucmuche.log combined
</VirtualHost>

Pour finaliser la configuration, il faut créer des liens symboliques dans /etc/apache2/sites-enabled/

# cd /etc/apache2/sites-enabled/
# ln -s ../sites-available/forum.trucmuche.org forum.trucmuche.org
# ln -s ../sites-available/wiki.trucmuche.org wiki.trucmuche.org
# ln -s ../sites-available/www.trucmuche.org www.trucmuche.org
L’usine Ă  site (cas 3)

Je ne donnerai pas de fichier de configuration Apache dans cette section. Je vous conseillerais de regarder du côté des hotes virtuels dynamiques et/ou de la commande suEXEC.

Activer et configurer certains modules : url_rewrite et php5.

Les modules url_rewrite et php sont très utilisés. Ils apportent des fonctionnalités bien appréciables.
Pour les activer, il suffit de faire un lien de leurs fichiers de mods-available vers mods-enabled. [Il est possible qu’ils soient dĂ©jĂ  activĂ©s par dĂ©faut.]

# cd /etc/apache2/mods-enabled/
# ln -s ../mods-available/php5.load php5.load
# ln -s ../mods-available/php5.load php5.conf
# ln -s ../mods-available/rewrite.load rewrite.load

Si vous voulez jouer avec la configuration de php5: éditer le fichier /etc/php5/apache2/php.ini.
Pour utiliser url_rewrite, il suffit d’activer le mode rewrite dans un .htaccess en spĂ©cifiant les règles de réécriture.

Installer une solution mail: Smtp + imap + spamAssassin

Section en cours d’Ă©criture.

Script de sauvegarde & crontab

Il est important d’assurer la pĂ©rĂ©nitĂ© de ses donnĂ©es. C’est pourquoi, il est très fortement conseillĂ© de mettre, en production, un serveur uniquement si un système de sauvegarde et restauration est fonctionnel. Les Ă©lĂ©ments Ă  mettre dans une sauvegarde sont:

  • La hiĂ©rarchie de dossiers et fichiers du site/des sites
  • Un dump des bases de donnĂ©es
  • Les fichiers de configuration (si vous estimez que les modifications sont importantes)
  • Le dossier /home (dans le cas ou des utilisateurs ont des donnĂ©es autres que leur site web.)
#!/bin/sh
HOST='ftp.somewhere.fr'
USERFTP='toto@somewhere.fr'
USER=toto
PASSWDFTP='bidule'
PASSWDSQL='bidule'
DATE=`date +%d`
DRUPALFILE=/home/$USER/script/backup-drupal-file-$DATE.sql
WIKIFILE=/home/$USER/script/backup-wiki-file-$DATE.sql
FORUMFILE=/home/$USER/script/backup-forum-file-$DATE.sql

ARCHIVE=/home/$USER/monsite-$DATE.tar.gz
#tar le dossier /home/toto/monsite
tar -czvf $ARCHIVE /home/$USER/monsite


#dump de postgresql 
export PGPASSWORD=passwordPostgresql
pg_dump -f $DRUPALFILE -U $USER drupal 

#dump de mysql 
mysqldump --set-charset  -u $USER -p$PASSWDSQL wiki > $WIKIFILE
mysqldump --set-charset  -u $USER -p$PASSWDSQL forum > $FORUMFILE



ftp -n $HOST <<END_SCRIPT
quote USER $USERFTP
quote PASS $PASSWD
send $DRUPALFILE backup_drupal_$DATE.sql
send $WIKIFILE backup_wiki_$DATE.sql
send $FORUMFILE backup_forum_$DATE.sql
send $ARCHIVE monsite-$DATE.tar.gz

quit
END_SCRIPT
exit 0

VoilĂ , un exemple de script de sauvergarde. Il exporte deux bases de donnĂ©es mysql et d’une postgresql dans des fichiers .sql. Il fait aussi une archive du dossier /home/toto/monsite. Tous les fichiers ont le numero du jour du le mois (Ca fait une rotation de sauvegarde de 30 jours en moyennes). Les sauvegardes sont envoyer par FTP sur un autre serveur. Bien entendu, rien ne vous empĂŞche d’amĂ©liorer ça. Vous trouverez des multitudes de scripts pour vous aider.
Il faut ensuite executer ce script de façon régulière. Crontab est là pour vous sauver. Tapez la commande suivantes pour ajouter une règle.

# crontab -e

Ajouter la ligne suivante dans le fichier.

0 0 * * * sh /home/toto/script/sauvegarde.sh

La sauvegarde se fera tous les jours Ă  minuit.

Foire Aux Questions

Mon serveur semble ne pas marcher Ă  l’extĂ©rieur de mon rĂ©seau local.

Vérifiez bien la configuration de votre routeur. Les connexions entrantes sur le port 80 (http) doivent être redirigées vers votre serveur.

Je n’arrive pas Ă  uploader des fichiers.

C’est probablement un problème de droit en Ă©criture sur le serveur. Apache doit pouvoir Ă©crire dans le rĂ©pertoire de partage choisi. (chmod g+w et chown user:www-data)

Plus d’informations

Cerfication Qt

j’ai obtenu ma certification Qt : (Qt Essentials).

Je dĂ©cris vite fait l’examen:
-50 questions Ă  choix multiples.
-1h pour le faire + 30 mins, si vous ĂŞtes dans un pays dont la langue officielle n’est pas l’anglais.
– Prix: 140 € si ma mĂ©moire est bonne. (75 € si vous voulez le repasser après un Ă©chec)

Je suis sĂ»r d’avoir rĂ©ussi 40 questions, j’ai des doutes sur les 10 autres. C’Ă©tait souvent des questions ou il y avait plusieurs rĂ©ponses demandĂ©es, j’en avais souvent une de sĂ»re mais de sĂ©rieux doutes pour les autres. Cela ne m’a pas empĂŞchĂ© de rĂ©ussir.

Je suis donc officiellement “Nokia Certified Qt Developer”.

partage WebDav sur Ubuntu, Configuration des clients sous Ubuntu/Gnome, MacOS X et Windows XP

Introduction

Un serveur WebDav est un serveur web classique couplĂ© avec un module pour faciliter l’envoie de fichier. Dans ce tutorial, Nous allons mettre en place un serveur webdav sur un serveur web Apache 2. Nous verrons ensuite que l’ensemble des systèmes d’exploitations fournissent un système transparent pour la connexion Ă  ce genre de partage. Le client webdav est souvent inclus dans le navigateur de fichier.

Installer un serveur WebDav

Je pars du principe que vous avez un serveur Apache 2 fonctionnel sur votre serveur. Pour notre exemple, le dossier de partage sera le dossier /var/www/sharing. Le dossier de configuration d’apache est Ă  l’adresse: /etc/apache2/. Les comptes utilisateurs (et leurs mots de passes) seront enregistrĂ©s dans le fichier : /var/www/sharing/.webdav.passwd

Les prérequis

La première Ă©tape est de gĂ©nĂ©rer un certificat SSL et une clĂ© SSL. C’est primordial pour assurer le cryptage des donnĂ©es. Un certificat est un fichier avec l’extension .crt (server.crt dans ce tutorial) et la clĂ© sera server.key. Pour crĂ©er la clĂ© et le certificat, tapez ces commandes dans un terminal:

$ mkdir /tmp/ssl_conf 
$ cd /tmp/ssl_conf 
$ openssl req -config /etc/ssl/openssl.cnf -new -out server.csr

DĂ©finissez une passphrase, tapez un mot de passe mĂ©morisable. Ensuite, rĂ©pondez aux questions sur la localisation de votre serveur. (Il n’est pas nĂ©cessaire de rĂ©pondre Ă  toutes les questions.)

$ openssl rsa -in privkey.pem -out server.key 
$ openssl x509 -in server.csr -out server.crt -req -signkey server.key -days 3650 
$ openssl x509 -in server.crt -out server.der.crt -outform DER

Le certificat sera valable environ 10 ans.
La dernière Ă©tape pour l’instant est de copier/coller les deux fichiers importants dans le rĂ©pertoire d’apache2.

# cp server.crt /etc/apache2/
# cp server.key /etc/apache2/

(Vous aurez besoin d’ĂŞtre root pour faire ça)

Configurer son serveur apache

Il y a 4 étapes à faire:
-Définir un virtualhost
-Activer le support SSL
-Activer le support WebDav
-Activer l’authentification http.

Voici le code du virtualhost à définir dans /etc/apache2/site-enable/000-default

<VirtualHost 192.168.1.2:443>
        ServerName toto
        DocumentRoot /var/www/sharing
        <Directory "/var/www/sharing">
                Options Indexes FollowSymLinks MultiViews
                AllowOverride None
                Order allow,deny
                Allow from all
        </Directory>

        SSLEngine on
        SSLCertificateFile /etc/apache2/server.crt
        SSLCertificateKeyFile /etc/apache2/server.key

        <Location />
            Dav on
            AuthType Basic
            AuthName "Sharing  Repository"
            AuthUserFile /var/www/sharing/.webdav.passwd
            Require valid-user
        </location>
</VirtualHost>

Définition des champs:
remplacez 192.168.1.2 par l’ip de votre machine sur le rĂ©seau local.
Le répertoire de partage sera /var/www/sharing

les lignes suivantes activent le support du ssl (https), en définissant également, les chemins vers les fichiers clé et certificat.

        SSLEngine on
        SSLCertificateFile /etc/apache2/server.crt
        SSLCertificateKeyFile /etc/apache2/server.key

Le dernier groupe de lignes active le webdav et spĂ©cifie la mĂ©thode d’authentification.

        <Location />
            Dav on
            AuthType Basic
            AuthName "Sharing  Repository"
            AuthUserFile /var/www/sharing/.webdav.passwd
            Require valid-user
        </location>

Pour résumer, nous avons maintenant un serveur configuré et un certificat ssl prêt pour le service. Il nous faut donc créer un fichier de .passwd et activer les modules webdav et ssl.

Créer un fichier de mot de passe

Une simple commande suffit pour crĂ©er ce fichier et ajouter l’utilisateur toto:

# htpasswd -c /var/www/sharing/.webdav.passwd toto

L’option -c crĂ©e le fichier, s’il n’existe pas. Le mot de passe vous sera demandĂ© dans la suite de la commande. Il est conservĂ© cryptĂ© dans le fichier.

Pour ajouter un autre utilisateur

# htpasswd /var/www/sharing/.webdav.passwd tata

Activer les modules webdav et ssl dans Apache2

Pour cela, il faut crĂ©er des liens symboliques dans les dossiers de configuration d’apache.

cd /etc/apache2/mods-enabled
ln -s ../mods-available/dav* .
ln -s ../mods-available/ssl* .

A ce stade, il vous reste plus qu’a redĂ©marrer votre serveur apache.

sudo /etc/init.d/apache2 restart

Vous avez normalement un serveur webdav fonctionnel. Pour vĂ©rifier, tapez l’adresse de votre serveur dans un navigateur web. Acceptez le certificat, identifier vous grâce Ă  votre login/mot de passe.
Vous devriez voir une page de ce style:

resultat webdav

Configuration des Clients

Nous allons maintenant voir comment configurer des clients WebDav. Pour tĂ©lĂ©charger des fichiers depuis le serveur un simple navigateur web suffit. Cependant le plus intĂ©ressant, reste la possibilitĂ© de dĂ©poser des fichiers dans ce partage. Il est donc nĂ©cessaire d’utiliser un vrai client WebDAV.

Sous MacOS X

Ouvrez un finder, cliquez sur le menu “Aller” > “Se connecter Ă  un serveur distant” (cmd + K). Une petite boĂ®te de dialogue, vous demandera l’adresse. Tapez l’adresse du votre serveur. Il vous demandera le login et le mot de passe de l’utilisateur (.webdav.passwd). Si l’authentification, c’est bien passĂ© vous avez un nouveau dossier dans votre finder. VoilĂ , vous pouvez partager des fichiers.

Sous Gnome (Ubuntu)

C’est très simple: dans le menu Raccourcis, cliquez sur “Se connecter Ă  un serveur…”

assistant windows 1

Sous Windows XP

Ouvrez les favoris rĂ©seaux. Cliquez sur “Ajouter un Favori rĂ©seau” sur le menu de gauche. une fenĂŞtre s’ouvre.

assistant windows 1

Séléctionnez le premier choix et faite suivant.

assistant windows 2

Rentrez l’adresse dans le champs comme sur l’image ci-dessus.

assistant windows 3

Acceptez le certificat.

assistant windows 4

Saississez votre login et votre mot de passe.

assistant windows 5

Entrez un nom (celui que vous voulez ou laissez le nom par défaut).
Il est possible que l’acceptation du certificat vous soit souvent demandĂ©e tout comme que votre login/mot de passe.

FAQ

Mon serveur semble ne pas marcher Ă  l’extĂ©rieur de mon rĂ©seau local.

Vérifiez bien la configuration de votre routeur. Les connexions entrantes sur le port 443 (https) doivent être redirigées vers votre serveur.

Je n’arrive pas Ă  uploader des fichiers.

C’est probablement un problème de droit en Ă©criture sur le serveur. Apache doit pouvoir Ă©crire dans le rĂ©pertoire de partage choisi. (chmod g+w et chown user:www-data)

Plus d’informations