Megatokyo 3 en développement

Je me suis enfin lancé dans le développement de la version 3 de mon application universelle Megatokyo.

L’idée est de profiter du portage vers Windows 10 (la version 1 était en Silverlight pour Windows Phone 8, la 2 en UWP pour Windows 8.1) afin de revoir une bonne partie du fonctionnement général de l’application.

En effet, l’application actuelle a comme gros défaut d’avoir du mal à exécuter la tâche de fond qui va vérifier la présence de nouveautés. De plus, le scanne effectué pour extraire les données du site officiel nécessaires au bon fonctionnement est assez lourd et demande pas mal de temps au démarrage de l’application.

Passer à une application 3 tiers

L’idée est donc de déporter tous les traitements vers un serveur qui stockera toutes les informations nécessaires, préviendra les clients des mises à jour et transférera les données sur demande.

Plusieurs avantages à ça :

  • Le client devient plus léger et ne fait que charger des données déjà prêtes.
  • Plus de tâche de fond côté client qui peut échouer faute de ressource et consomme de la batterie.
  • Des notifications beaucoup plus ponctuelles et riches.
  • Plus de demande de traduction pour chaque client, mais une seule fois par langue.

L’idée est aussi d’en profiter pour apprendre à utiliser .NET Core 2.1, la version libre et multi-plateforme de du Framework .NET.

La partie serveur

Le serveur se compose de deux logiciels distincts. Le premier est un service qui va analyser les données et envoyer les notifications, le second un Web Service qui permet au client de venir chercher les données.

Les deux sont donc en .NET Core 2.1 et hebergé sur mon serveur Debian.

Le service de notification

Le service de notification est une simple application console exécutée en tant que daemon via Systemd.

Son principe est de récupérer le flux RSS du site officiel, de détecter les nouvelles entrées (planche ou diatribe) puis de lancer une récolte d’information pour complèter celles reçues via le flux RSS.

Une fois les données récupérées, elles sont stockées dans une base MySQL puis une notification est émise vers Azure Notification Hub qui s’occupe de la distribuée à tous les clients enregistrés.

Le Web Service

Le Web Service est un projet de type Web API en ASP.NET Core 2.1 qui permet d’interroger la base de données MySQL.

Il s’occupe aussi de la traduction des diatribes via Bing Translator (faute de mieux !) et enregistre celle-ci dans la base de données afin qu’elle puisse être réutilisée.

Ce Web Service est accessible via nginx en HTTPS et sait répondre aux demande de certification Let’s Encrypt.

Créer un projet Jenkins Multibranch Pipeline pour Delphi (Seconde partie)

Dans la première partie, nous avons vu comment installer Jenkins et les extensions nécessaires pour compiler un projet Delphi. Nous allons maintenant voir comment créer un script Jenkinsfile de base.

Créer le fichier Jenkinsfile

Les pipelines s’appuient sur des scripts écris en Groovy, un langage de script faisant appel à Java à travers une sandbox.

Jenkins recherche dans chaque branche du dépôt un fichier Jenkinfile contenant un script Groovy définissant les étapes de la compilation.

Structure de base du script

Un script de pipeline commence par la ligne de commentaire #!groovy, ce qui permet aux éditeurs reconnaissant ce format de le coloriser automatiquement. Sous Windows, je n’ai pas trouvé de logiciel le gérant, même si la demande existe pour une intégration dans Notepad++.

Ensuite, le script doit contenir la balise pipeline {}. Elle indique à Jenkins que le script commence. Ensuite, on peut indiquer des options pour ce pipeline et surtout des « stages » qui seront en fait les étapes de notre compilation.

#!groovy
pipeline {
    agent any
    stages {
        stage('Compilation') {
        }
    } 
}

Dans cet exemple, on déclare un pipeline, qu’il peut utiliser n’importe quel agent déclaré dans Jenkins et qu’il n’y a qu’une grande étape, la compilation.

Compilation d’un projet Delphi

Pour pouvoir compiler Jenkins, nous allons créer une étape de compilation faisant appel à MSBuild.

Dans un pipeline Jenkins, les variables d’environnement de Windows ne sont pas prises en compte ! Il faut donc les préciser à Jenkins dans le script.

Pour cela, nous allons rajouter une section « environnement » à notre script et y déclarer toutes les variables d’environnement nécessaires à la compilation.

environment {
    BDS = "C:\\Program Files (x86)\\Embarcadero\\Studio\\17.0"
    BDSINCLUDE = "C:\\Program Files (x86)\\Embarcadero\\Studio\\17.0\\include"
    BDSCOMMONDIR = "C:\\Users\\Public\\Documents\\Embarcadero\\Studio\\17.0"
    FrameworkDir = "C:\\Windows\\Microsoft.NET\\Framework\\v3.5"
    FrameworkVersion= "v3.5"
    FrameworkSDKDir = ""
    PATH = "C:\\Program Files (x86)\\Embarcadero\\Studio\\18.0\\bin;C:\\Users\\Public\\Documents\\Embarcadero\\Studio\\18.0\\Bpl;C:\\Program Files (x86)\\Embarcadero\\Studio\\18.0\\bin64;C:\\Users\\Public\\Documents\\Embarcadero\\Studio\\18.0\\Bpl\\Win64;C:\\Bitnami\\redmine-3.2.0-0\\ruby\\bin;C:\\ProgramData\\Oracle\\Java\\javapath;C:\\Program Files\\ImageMagick-6.9.2-Q16;C:\\Program Files (x86)\\Embarcadero\\Studio\\17.0\\bin;C:\\Users\\Public\\Documents\\Embarcadero\\Studio\\17.0\\Bpl;C:\\Program Files (x86)\\Embarcadero\\Studio\\17.0\\bin64;C:\\Users\\Public\\Documents\\Embarcadero\\Studio\\17.0\\Bpl\\Win64;C:\\Program Files\\Perl64\\site\\bin;C:\\Program Files\\Perl64\\bin;C:\\Windows\\system32;C:\\Windows;C:\\Windows\\System32\\Wbem;C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\;C:\\PROGRA~1\\ITM\\bin;C:\\PROGRA~1\\ITM\\InstallITM;C:\\PROGRA~1\\ITM\\TMAITM6;C:\\Program Files\\ITM\\bin;C:\\Program Files\\ITM\\InstallITM;C:\\Program Files\\ITM\\TMAITM6;C:\\Program Files\\Microsoft\\Web Platform Installer\\;C:\\Program Files\\TortoiseSVN\\bin;%USERPROFILE%\\.dnx\\bin;C:\\Program Files\\Microsoft DNX\\Dnvm\\;C:\\sonar-runner\\bin;C:\\Program Files (x86)\\Windows Kits\\10\\Windows Performance Toolkit\\;C:\\Program Files\\Java\\jre1.8.0_66\\bin;C:\\Program Files\\Git\\cmd;C:\\Program Files\\1E\\NomadBranch\\;C:\\Program Files\\VisualSVN Server\\bin;C:\\Program Files (x86)\\Resource Hacker\\;C:\\Users\\Public\\Documents\\Embarcadero\\Studio\\17.0;C:\\Program Files (x86)\\Embarcadero\\Studio\\17.0\\bin;C:\\Program Files (x86)\\Embarcadero\\Studio\\17.0\\bin64;C:\\Users\\Public\\Documents\\Embarcadero\\InterBase\\redist\\InterBaseXE7\\IDE_spoof;"
    LANGDIR = "FR"
    PLATFORM = ""
    PlatformSDK = ""
}

Comme vous pouvez le voir dans l’exemple ci-dessus, les chemins sont tous absolus, il n’est pas possible d’utiliser %PATH% par exemple pour simplement ajouter quelque chose au PATH existant. Ici, nous avons deux versions de Delphi installées, la 17 (Seatle) et la 18 (Berlin) d’où la présence des deux chemins.

Nous allons maintenant pouvoir appeler la compilation à proprement parler. Pour cela, nous allons déclarer une « steps » et faire appel à notre plugin MSBuild via un « script ».

steps {
    script {
        def msbuildHome = tool 'MSBuild pour Delphi'
        bat "${msbuildHome}\\MSBuild.exe\ "${WORKSPACE}\\MonProjet\\Projet.groupproj\""
}

On commence par indiquer à Jenkins qu’on veut récupérer le chemin d’accès à l’outil MSBuild en l’appelant par le nom déclaré lors de la configuration.

Ensuite, on fait appel à la commande « bat » à laquelle on passe le chemin d’accès absolu à MSBuild et le chemin d’accès absolu à notre fichier .dproj. La variable ${WORSPACE} est renseignée par Jenkins et contient le chemin vers le répertoire de travail où va avoir lieu la compilation.

Si besoin, on peut ajouter des paramètres dans la ligne de commande pour indiquer quel plateforme utilisée ou le mode de compilation.

On obtient donc au final le script suivant :

#!groovy
pipeline {
    agent any
    stages {
        stage('Compilation') {
            environment {
                BDS = "C:\\Program Files (x86)\\Embarcadero\\Studio\\17.0"
                BDSINCLUDE = "C:\\Program Files (x86)\\Embarcadero\\Studio\\17.0\\include"
                BDSCOMMONDIR = "C:\sers\\Public\\Documents\\Embarcadero\\Studio\\17.0"
                FrameworkDir = "C:\\Windows\\Microsoft.NET\\Framework\\v3.5"
                FrameworkVersion= "v3.5"
                FrameworkSDKDir = ""
                PATH = "C:\\Program Files (x86)\\Embarcadero\\Studio\\18.0\\bin;C:\\Users\\Public\\Documents\\Embarcadero\\Studio\\18.0\\Bpl;C:\\Program Files (x86)\\Embarcadero\\Studio\\18.0\\bin64;C:\\Users\\Public\\Documents\\Embarcadero\\Studio\\18.0\\Bpl\\Win64;C:\\Bitnami\\redmine-3.2.0-0\\ruby\\bin;C:\\ProgramData\\Oracle\\Java\\javapath;C:\\Program Files\\ImageMagick-6.9.2-Q16;C:\\Program Files (x86)\\Embarcadero\\Studio\\17.0\\bin;C:\\Users\\Public\\Documents\\Embarcadero\\Studio\\17.0\\Bpl;C:\\Program Files (x86)\\Embarcadero\\Studio\\17.0\\bin64;C:\\Users\\Public\\Documents\\Embarcadero\\Studio\\17.0\\Bpl\\Win64;C:\\Program Files\\Perl64\\site\\bin;C:\\Program Files\\Perl64\\bin;C:\\Windows\\system32;C:\\Windows;C:\\Windows\\System32\\Wbem;C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\;C:\\PROGRA~1\\ITM\\bin;C:\\PROGRA~1\\ITM\\InstallITM;C:\\PROGRA~1\\ITM\\TMAITM6;C:\\Program Files\\ITM\\bin;C:\\Program Files\\ITM\\InstallITM;C:\\Program Files\\ITM\\TMAITM6;C:\\Program Files\\Microsoft\\Web Platform Installer\\;C:\\Program Files\\TortoiseSVN\\bin;%USERPROFILE%\\.dnx\\bin;C:\\Program Files\\Microsoft DNX\\Dnvm\\;C:\\sonar-runner\\bin;C:\\Program Files (x86)\\Windows Kits\\10\\Windows Performance Toolkit\\;C:\\Program Files\\Java\\jre1.8.0_66\\bin;C:\\Program Files\\Git\\cmd;C:\\Program Files\\1E\\NomadBranch\\;C:\\Program Files\\VisualSVN Server\\bin;C:\\Program Files (x86)\\Resource Hacker\\;C:\\Users\\Public\\Documents\\Embarcadero\\Studio\\17.0;C:\\Program Files (x86)\\Embarcadero\\Studio\\17.0\\bin;C:\\Program Files (x86)\\Embarcadero\\Studio\\17.0\\bin64;C:\\Users\\Public\\Documents\\Embarcadero\\InterBase\\redist\\InterBaseXE7\\IDE_spoof;"
                LANGDIR = "FR"
                PLATFORM = ""
                PlatformSDK = ""
                } 
            steps {
                script {
 def msbuildHome = tool 'MSBuild pour Delphi (release)'
 bat "${msbuildHome}\\MSBuild.exe \"${WORKSPACE}\\Composants\\TMSFMXPack\\TMSFMXPackDXE9.groupproj\""
 bat "${msbuildHome}\\MSBuild.exe \"${WORKSPACE}\\WLZ\\WLZcompression.dproj\""
 bat "${msbuildHome}\\MSBuild.exe \"${WORKSPACE}\\EPERMITLIB.XE8\\LIBTOTAL\\Total.dproj\""
 bat "${msbuildHome}\\MSBuild.exe \"${WORKSPACE}\\EPERMITLIB.XE8\\connection monitoring\\DSServerConnectionMonitoring\\DataSnapServerConnectionMonitoring.dproj\""
 bat "${msbuildHome}\\MSBuild.exe \"${WORKSPACE}\\EPERMIT.XE8\\EPERMIT.groupproj\""
                }
            }
        }
    }
}

Et voilà, vous n’avez plus qu’à nomer ce fichier « Jeninksfile » et à le placer à la racine du trunk ou de la branche, puis livrer !

Comme nous n’avons pas encore configuré la compilation automatique sur une livraison SVN, il nous faut lancer un scanne des branches manuellement. Pour cela, dans l’interface de Jenkins, cliquez sur votre projet Mutibranch Pipeline puis sur « Scan Multibranch Pipeline » dans le menu de gauche. Jenkins va alors détecter qu’une branche est à compiler et lancer la compilation.

Plus de 3000 téléchargements !

Depuis le 11 février 2013, date à laquelle est sortie la première version sur Windows Phone 8.0, Megatokyo a été téléchargé plus de 3000 fois pour sa version smartphone !

Microsoft ayant changé ses statistiques, il est difficile de connaître exactement le total de téléchargements, la conservation des données n’étant que sur 12 mois, je n’ai donc pas de données précises quant à la version pour Windows 8.1.

Quoi qu’il en soit, sur les 12 derniers mois, Megatokyo 1403 fois, dont 728 sur Windows Phone 8.1 (soit 51,8%), 289 sur Windows 8.1 (soit 20,6%), 272 sur Windows Phone 8 (soit 19,4%) et 114 Windows 10 (soit 8,2%) .

La répartition selon les pays dépend largement des langues supportés (anglais, français, russe, allemand et japonais), sauf les japonais qui boudent complètement l’application (2 téléchargements…) :

La sortie de Windows 10 a étrangement amplifié le nombre de téléchargements sur Windows 8.1, ce dernier ayant été particulièrement boudé.

J’espère que la future version pour Windows 10 (Mobile) aura du succès, mais je n’avance pas bien vite pour le moment !

C’est parti pour la navigation !

Un peu d’avancée encore ce weekend. Je me suis lancé dans l’interface.

J’ai donc mis en place le menu hamburger à gauche avec la gestion de l’historique (bouton dans la barre de titre). Merci à Microsoft de donner des exemples, car ce n’est pas simple de trouver via la documentation comment faire.

Mais au final, c’est vraiment bien. La barre de titre est maintenant 100% configurable puisqu’on peut la remplacer par une barre totalement personnalisée en XAML. Donc tout est possible ! Onglets, champ de recherche, boutons, case à cocher, etc. C’est très simple une fois qu’on a regardé un peu les exemples.

J’ai juste un petit bogue dans l’historique, des fois il tente de remonter trop loin…

Première confrontation avec les applications UWP

J’ai entamé la migration vers Windows 10 (application universelle). C’est très simple venant de Windows 8.1 (application universelle là aussi, ancien modèle évidemment).

J’ai créé un nouveau projet UWP, puis j’ai repris l’intégralité de ce qui était dans le sous-projet « Shared » de l’application 8.1, c’est à dire tout le code « métier » qui n’est lié ni à Windows 8.1, ni à Windows Phone 8.1. Rien à modifier, tout compile parfaitement du premier coup.

Par contre, toute l’interface est à refaire de 0 puisqu’il faut fusionner le sous-projet Windows 8.1 avec le sous-projet Windows Phone 8.1. Je suis en train de lire la documentation et de choisir les différents types de page à utiliser et comment gérer le redimensionnement automatique en fonction de l’écran qui affiche l’application.

Pour le moment, je n’ai que recréé toute les images nécessaires au projet. Il y en a encore plus qu’avant vu que Windows 10 gère la 4K avec mise à l’échelle à 200% et forcément les tailles ont été légèrement modifiées… Il est vraiment dommage que l’on ne puisse pas simplement utiliser des images vectorielles (genre du SVG).

Ca m’a donc pris un temps fou, vu que pour que ça soit nickel, je suis reparti de l’image vectorielle.

Normalement, je pourrai aussi reprendre sans aucune modification, le projet contenant la tâche de fond. Pour celui gérant les tuiles, la définition des textes à énormément changé, il faut que j’adapte ça. En espérant que Microsoft donne des exemples !

Voilà, j’avance tranquillement. J’espère que ce sera prêt pour la Threshold 2 de cet automne !