1. Si vous venez d'arriver sur le forum et que vous êtes un peu perdus, cliquez ici !
    Rejeter la notice

[Logiciel] EnderChest, un nouveau système de mise à jour concurrent et léger.

Discussion dans 'Vos propositions d'articles' créé par Il_totore, 5 Juil 2020.

  1. Il_totore

    Il_totore Nouveau

    Inscrit:
    30 Sept 2017
    Messages:
    3
    Points:
    37
    Sexe:
    Homme
    Bonjour,
    je vais vous présenter aujourd'hui EnderChest. EnderChest est un système de mise à jour comme S-Update, très utilisé pour les launchers.

    EnderChest est à la fois utile pour les propriétaires de serveurs moddés qui veulent un système de mise à jour performant et extrêmement rapide, mais aussi pour les développeurs grâce à une API robuste et lisible.

    Voici un petit aperçu de la consommation de mémoire vive de la future màj serveur (2.0), qui héberge 8072 fichiers (soit un 2.4Go):

    [​IMG]
    La zone en rouge étant 3 clients se connectant simultanément pour recevoir les mises à jour.
    Graphique réalisé avec JVisualVM.

    Pour les personnes plus expérimentées, vous pouvez optimiser les arguments JVM pour obtenir un meilleur résultat (j'ai pour ma part réussi à tomber sur du ~60MB de mémoire vive utilisée pour 2.4GB)

    Features
    Si S-Update existe déjà, pourquoi recréer un système d'update ? Tout simplement parce que ce dernier est très vieux et utilise des mécaniques obsolètes (comme l'algorithme MD5 pour les checksums, une des causes de sa lenteur).

    Après avoir parlé avec Litarvan, l'auteur du prédécesseur d'EC, j'en suis venu à créer mon propre système, avec le but qu'il soit rapide et performant.

    EnderChest est donc né, et possède avec lui les fonctionnalités suivantes:

    • Gestion de la concurrence et requêtes asynchrones, pour empêcher le blocage du thread d'exécution. Principalement faite grâce aux libraries akka-stream et akka-http
    • Utilisation de l'algorithme xxHash32, environ 16.35x plus rapide que MD5.
    • Chunking des données pour empêcher la taille des fichiers d'influer sur la consommation de mémoire vive.
    • Installation du serveur simple, de la même manière que Spigot, SpongeVanilla ou Forge: lancer un jar.
    • Configuration simple du serveur depuis un fichier YAML, créé lors du premier lancement
    • Utilisation du langage Scala, parfaitement adapté à ce genre de systèmes.

    Pourquoi Scala ?
    J'ai choisi d'utiliser pour EnderChest le langage Scala pour EnderChest. Pouvez vous l'utiliser avec Java malgré tout ? Oui, mais je conseille cependant fortement de faire votre launcher, ou du moins d'utiliser cette lib en Scala car ce langage permet énormément de choses concernant la gestion de la concurrence et la clarté du code.


    Installation
    Pour l'installation du serveur, vous devez simplement télécharger dans l'onglet releases le server-xxxx-withDependencies.jar et le lancer. Un fichier de config documenté sera généré. Plus d'informations ici.

    Pour le client, vous pouvez installer la library de 2 manières différentes.

    En utilisant un build tool
    Avec Gradle:
    Code (cpp):
    repositories {
      mavenCentral()
    }

    dependencies {
      implementation 'io.github.iltotore:ec-client_2.13:version'
    }
    Avec SBT:
    Code (cpp):
    libraryDependencies += "io.github.iltotore" %% "ec-client" % "version"
    En utilisant le jar
    Rendez vous sur les releases Github et téléchargez le fichier client-xxx-withDependencies. Vous pouvez ensuite l'importer dans votre IDE comme n'importe quelle autre library.

    Noter que vous devrez probablement incorporer la library à votre jar final. Avec Gradle je vous recommande d'utiliser le plugin shadowJar.



    Les bases
    Créer un FileAnalyzer
    Commençons d'abord par créer une nouvelle instance de FileAnalyzer, qui servira à indexer les fichiers du client Minecraft:
    Code (cpp):
    val rootPath = Paths.get("blabla") //À noter que vous pouvez également résoudre le Path par rapport à la localisation de votre jar, ou le dossier utilisateur.
     
    val analyzer = new FileAnalyzer(rootPath)
    Si vous voulez exclure des fichiers, changer la profondeur de recherche ou changer le degré de parallélisme, précisez le/les comme ceci:
    Code (cpp):
    val analyzer = new FileAnalyzer(
      rootPath, //Le chemin vers le dossier racine des téléchargements.
      exclude = _.startWith("shaderpacks/"), //Exclu tous les fichiers qui sont dans le dossier `shaderpacks`, à la racine des téléchargements.
      maxDepth = Option(100), //La profondeur de recherche maximale est maintenant de 100.
      threadCount = 10 //Utilise 10 thread pour le traitement parallèle.
    ) //Remarque: vous pouvez également déclarer les paramètres sur une ligne.
    À noter que les fichiers exclus seront téléchargés si manquants mais ne seront pas modifiés/supprimés. Les fichiers inconnus ne seront pas non plus effacés si exclus.



    Instancier le client
    Maintenant que nous avons créé notre FileAnalyzer, nous pouvons maintenant créer notre EnderClient qui servira à mettre à jour le système. Nous allons utiliser la méthode apply, qui utilise certaines valeurs par défaut. Notons que Foo.apply() en Scala est la même chose que Foo().
    Code (cpp):
    val client = EnderChest("https://localhost:8080/" /*L'adresse vers le serveur d'update*/, analyzer)
    Vous maintenant prêt à utiliser les fonctionnalités du client !


    Indexer les fichiers
    Cette méthode a la particularité de renvoyer un Future[Int], qui va indexer les fichiers en parallèle. Le paramètre générique Int est utilisé pour symboliser le nombre de fichiers indexés.

    Utilisons maintenant une fonctionnalité de Scala qui vient tout droit de la programmation fonctionnelle: le Pattern Matching.
    Code (cpp):
    client.checkFiles.onComplete {
      case Success(count) => println(count + " fichiers ont été indexés.")

      case Failure(exception) => exception.printStacktrace().
    } //Les paranthèses de la méthode ne sont pas obligatoires.

    Une fois les fichiers analysés, nous pouvons lancer la requête de mise à jour (vous pouvez également indexer les fichiers plus tôt que juste avant d'update si besoin est.). Nous allons simplement utiliser client.update() et la méthode flatMap des futures pour pouvoir lancer l'update dès que l'indexation est finie:
    Code (cpp):
    client.checkFiles.flatMap(_ => client.update()).onComplete {
      case Success(done) => println("Mise à jour terminée !")

      case Failure(exception) => exception.printStacktrace()
    }
    Voilà, vous avez maintenant les bases nécessaire (si tant est que vous avez appris le Scala =p) pour pouvoir utiliser EnderChest.

    Voici quelques liens utiles:

    Le projet est open-source et gratuit sous licence Apache 2.0. Si vous avez des questions/remarques, faites-moi savoir !

    Et si le projet vous a été utile, libre à vous de mettre une star sur Github [​IMG]

    En espérant également que ce projet aura un article dédié pour pouvoir faire profiter les propriétaires de serveur moddés !

    PS: Je suis surtout actif sur Github et Discord.
     
    • J'aime J'aime x 1
    #1 Il_totore, 5 Juil 2020
    Dernière édition: 5 Juil 2020

Partager cette page