Deblan blog

Futilités de Geek

Remote i3-wm WS : ma télécommande pour bureau Debian GNU/Linux

Il m'arrive d'avoir besoin de prendre le contrôle de ma machine via mon Android (bouger la souris, scroller et taper du texte).

J'ai quasiment toujours utilisé l'application Pointer Host. elle s'appuie sur un serveur Java lancé sur ma machine. Pour bouger la souris et générer des cliques, elle est très efficace. Cependant, l'écriture de caractères a toujours posé problème (chiffres et lettres accentuées erronés).

Depuis quelques semaines, j'ai envie de jouer avec les websockets et réécrire une appli du genre m'a semblé être un bon exercice.

Ce que je vais vous présenter est une POC. Cette application n'est pas sécurisée et est orientée pour mes besoins. Il est cependant très simple de la faire évoluer.

Voici mon cahier des charges :

  1. aucune application ne doit être installée sur mon téléphone
  2. utilisation du navigateur web pour le pilotage
  3. pouvoir bouger la souris
  4. pouvoir générer des cliques
  5. pouvoir scroller
  6. pouvoir taper des mots
  7. pouvoir lancer des raccouris claviers
  8. pouvoir gérer le volume du son
  9. pour Spotify : lancer et mettre en pause la musique, avancer et reculer dans la playlist en cours de lecture
  10. pouvoir changer de workspace dans mon gestionnaire de fenêtres i3-wm

Les outils pour scripter tout ça sont connus :

  • xdotool pour simuler un clavier et une souris (3, 4, 5, 6, 7) :
    • xdotool type "ceci va être tapé"
    • xdotool key Enter (touche Entrée)
    • xdotool click 1 (clique gauche)
  • amixer pour gérer le volume (8) :
    • amixer set Master 50% (volume à 50%)
  • playerctl pour piloter Spotify (9) :
    • playerctl -p spotify next (titre suivant)
  • i3-msg pour piloter i3-wm (10) :
    • i3-msg 'workspace "Foo"' (affichage du workspace Foo)

Websocket est un protocole réseau issu du web qui permet de créer un canal full-duplex entre un client et un serveur. Ils peuvent donc communiquer en temps réel dans une connexion TCP.

Comme à mon habitude et par esprit de contradiction (pas de NodeJS), j'ai décidé d'écrire la partie serveur en PHP 7. La partie cliente est en HTML 5 avec un peu de javascript.

Entre le serveur et le client, ce sont des messages textes qui sont échangés. J'ai décidé de les formater en JSON et seul le client va en envoyer. Ils sont toujours sous cette forme : {"type":"un type de message", [données complémentaires]}. Voici quelques exemples :

  • {"type":"workspace","value":"1. IRC"}
  • {"type":"pointer","click":"left"}
  • {"type":"media","value":"next"}
  • {"type":"volume","value":"down"}
  • {"type":"scroll","value":"up"}
  • {"type":"pointer","x":"-2","y":"3"}
  • {"type":"text","value":"Un texte"}

On peut aussi envoyer plusieurs messages dans un seul. Voici un exemple qui va permettre d'ouvrir urxvt via dmenu que je lance avec win+d :

{"type":"messages","value":[{"type":"keys","value":"win,d"},{"type":"text","value":"urxvt"},{"type":"key","value":"enter"}]}

Ces messages sont générés par le client et sont interprétés par des messageHandler une fois transmis au serveur. En voici un exemple :

Le code source de l'application est disponible sur deblan/remote-i3wm-ws et la procédure d'installation est simple :

Pour lancer le serveur websocket, il faut exécuter server/server start (@see restart et stop). Le serveur va écouter sur le port 14598. Concernant la partie cliente, vous pouvez créer un vhost Apache/Nginx qui pointera sur client/ ou lancer le serveur web built-in de PHP via php -S 0.0.0.0:15000 -t client/. Il faudra à présent vous connecter au serveur web depuis un navigateur.

Quelques captures de la partie cliente :

Remote i3-wm WS: keyboardRemote i3-wm WS: i3Remote i3-wm WS: mouseRemote i3-wm WS: media

Je vais essayer de faire une vidéo de démonstration. Depuis mon Samsung S8, ça fonctionne du feu de dieu et sur un petit Iphone 4S, c'est tout aussi fonctionnel (à part l'interface web un peu étriquée).

Edit 1

  • dbus-send a été remplacé par playerctl (merci Thomas L)
  • le type messages a été ajouté et permet d'envoyer plusieurs messages (cf l'exemple avec urxvt) et les mises à jour du code

Edit 2

  • Le code PHP du serveur a été déplacé dans server/src/resource/server.php
  • server/server est à présent un script shell et permet de lancer, relancer et stopper le serveur websocket (server/server start|restart|stop)

Monitordisplay : gérer ses dispositions d'écrans

Je branche très souvent des écrans externes à mon laptop et je suis un peu lassé de bidouiller xrandr. En effet, ses instructions sont simples mais assez longues et pénibles à écrire.

Ainsi, j'ai décidé de me faire un outil pour pouvoir configurer des modes d'affichage, pouvoir ajouter plusieurs dispositions et les activer rapidement.

Comme à mon habitude, c'est un outil en ligne de commande. J'ai décidé d'utiliser PHP pour une question de pratique pour moi.

Installation de monitordisplay

Il faut installer l'interpréteur PHP (5 ou 7) :

Maintenant que PHP est installé, il faut récupérer le projet :

Configuration

monitordisplay va essayer de charger 3 fichiers. Chaque fichier peut surcharger la configuration du précédent. Voici la liste :

  • /etc/monitordisplay/config.ini
  • $HOME/.config/monitordisplay/config.ini
  • $HOME/.monitordisplay

Je suis le seul utilisateur du laptop donc je vais juste créer le dernier.

Le fichier de configuration copié contient 2 écrans :

laptop et hdmi sont les identifiants "humains" sur lesquels je vais m'appuyer pour réaliser les dispositions. Le paramètre name contient l'identifiant technique passé à xrand. resolutionX et resolutionY indiquent la résolution de l'écran.

Il est possible de configurer plusieurs fois le même écran. Il suffit de modifier l'identifiant humain. Vous pouvez ainsi prévoir plusieurs résolutions.

Maintenant, il reste à renseigner des modes d'affichage. En voici trois exemples :

Tout comme un écran, le mode d'affichage porte un identifiant. Il possède également une liste de dispositions (config[]) et un indicateur (optionnel) d'écran principal (primary). L'ordre des identifiants définie la position, de gauche à droite, des écrans.

Utilisation

Pour activer un mode d'affichage (exemple : work), il suffit de lancer cette ligne de commande :

Le mode work contient deux dispositions. Pour passer à la seconde disposition, il suffit de lancer :

-t permet donc de passer successivement d'une disposition à une autre.

Quand monitordisplay charge un mode ou change de disposition, par défaut, il désactive les écrans non pris en charge. Si vous souhaitez outre-passer ce comportement, il suffit de passer l'argument -s. C'est assez pratique quand vous souhaitez initialiser une résolution sur un écran sans désactiver les autres.

Le code source est disponible sur gitnet et c'est open bar ;)


[TIPS] Rocketchat : désactiver SSL sans l'interface d'administration

C'est en testant le logiciel franz, un outil qui permet de centraliser les clients web de pas mal de services de messageries dont Skype, Messenger et surtout Rocketchat. Comme j'ai ma propre instance de rocket, j'ai directement ajouté mon adresse mais manque de bol, ma version n'était pas compatible. Alors je me suis empressé de récupérer un build récent et j'ai mis à jour tout ça ! D'ailleurs, c'est plutôt simple car je n'ai eu qu'à remplacer le code source…

Bref, ça fonctionnait :

Rocketchat deblan

Et en regardant toutes les nouveautés, j'ai par malheur forcé SSL alors que l'instance est derrière un proxy… Pourtant c'était écrit noir sur blanc mais je n'ai pas lu. Quoiqu'il en soit, impossible d'accéder à l'interface et j'ai du attaquer directement la base mongodb. J'ai lancé la commande mongo et je suis arrivé sur un shell.

> show dbs # Permet récupérer la liste des bases
> use rocketchat # J'indique dans quelle base de je veux travailler
# Je ne sais pas s'il y a plus sexy mais mongo est une première !
# Je passe simplement la valeur de l'option "Force_SSL" à false et j'enregistre
> db.rocketchat_settings.find({_id: "Force_SSL"}).forEach(function(o) { 
    o.value = false; 
    db.rocketchat_settings.save(o);
});

Une fois Rocketchat relancé, tout est rentré dans l'ordre !


t411-console : plugin Oh My Zsh

Un court article pour publier un plugin qui permet d'auto-compléter les commandes de t411-console dans ZSH via Oh My Zsh.

Il faut à présent l'activer en modifiant la liste des plugins dans votre .zshrc : plugins=(... t411)

Enjoy :)


Sauvegarde, panne, reprise de service

Si vous me suiviez depuis un moment, vous savez sans doute que je suis hébergé chez moi. J'ai en effet deux machines dans mon appartement qui me servent de serveurs pour mes sites web, mes mails, de l'IRC, GIT, etc. Bref, tout ce qui peut être hébergé dans mon appartement le sera.

J'ai cependant essuyé une panne matérielle qui m'a séparé de mon principal serveur. Une simple panne de disque qui a rendu indisponible ces différents services pendant quelques heures. Pour autant, je n'ai perdu (presque) aucune donnée et en dehors du temps qu'il m'a fallu pour reconfigurer la machine de réplication, tout est reparti dans l'ordre relativement rapidement.

J'en profite donc pour vous donner des pistes qui pourraient vous aider dans votre infrastructure. La question du jour est donc simple : comment mettre en place des outils de sauvegarde suffisamment performants pour rétablir des services assez rapidement ?

J'ai donc deux machines : celle qui offre tous les services (Hinata) et celle qui fait office de serveur réplication (Haruhi). Je n'ai pas encore l'envie de faire de la haute disponibilité (et dans un appartement, c'est peu probable que ça arrive…).

Sur Hinata était connecté un disque dur qui hébergeait de la sauvegarde versionnée. En effet, j'utilise l'excellent rsnapshot qui s'appuie sur Rsync et construit des sauvegardes sur des périodes données. J'ai 3 copies journalières, une copie quotidienne conservée pendant 7 jours, une copie par semaine conservée pour 1 mois et une copie mensuelle conservée sur une année…ce qui fait près de 25 versions ! Mes sites web y étaient sauvegardés, ainsi que mes dump SQL générés par wetddump (disponible sur mon dépot debian). J'y plaçait également des sauvegardes des répertoires /etc et /home. Mais ce n'est pas suffisant. Pour peu comme ce disque soit HS et qu'Hinata tombe avec, plus aucune donnée n'aurait été disponible. J'avais donc une synchronisation quotidienne des services sur Haruhi et une copie de sauvegarde des fichiers de configuration. J'en profitais également pour générer un fichier contenant la liste des paquets installés sur Hinata et je m'assurait que les utilisateurs et les groupes étaient toujours les mêmes des 2 cotés.

Après un peu plus d'un an de bons et loyaux services, Hinata est tombé et je devais tout refaire fonctionner sur Haruhi. J'ai donc pu installé les paquets qui manquaient en très peu de temps. Je me suis attardé à synchroniser les fichiers de configuration pour avoir le même comportement que sur Hinata et via la sauvegarde la plus récent du disque, je me suis assuré que mes services étaient bien à jour.

Au final, je me suis rendu compte que je n'ai pas sauvegardé 2 programmes compilés manuellement et qui se trouvaient de /usr/local. Je prendrai le temps de les réinstaller plus tard car ils ne sont pas critiques pour moi.

je suis satisfait de tout ça car ça s'est finalement bien passé et sans casse ! Voila pour la petite expérience…