Skip to content

Instantly share code, notes, and snippets.

@xaliphostes
Last active October 9, 2024 09:21
Show Gist options
  • Save xaliphostes/64047a435df2333e52c5653f898e75d6 to your computer and use it in GitHub Desktop.
Save xaliphostes/64047a435df2333e52c5653f898e75d6 to your computer and use it in GitHub Desktop.
Docker, C++ et appel depuis le web

Appel d'un programme C++ en docker depuis une page web

Si votre application C++ est un programme en ligne de commande qui prend uniquement deux arguments (un fichier d'entrée et un fichier de sortie) et ne connaît pas HTTP ou les appels réseau, vous pouvez tout de même créer une API pour la piloter en utilisant une architecture où un serveur web intermédiaire exécute l'application C++ en arrière-plan.

Dans ce cas, vous n'avez pas besoin d'ajouter de code HTTP dans votre application C++. Vous créerez un conteneur Docker qui :

Expose une API via un serveur web léger (comme Flask ou Express). Utilise cette API pour déclencher l'exécution de votre application C++ en ligne de commande avec les arguments appropriés. Solution globale : L'API : Un serveur web léger (Flask) qui accepte les requêtes HTTP pour lancer votre programme en ligne de commande. L'application C++ : Elle reste inchangée. Le serveur web appelle l'application en utilisant subprocess ou un équivalent pour exécuter les commandes en ligne. Étapes détaillées

Exemple d'application C++

Supposons que votre programme C++ s'appelle my_program.cpp et ressemble à ceci :

// my_program.cpp
#include <iostream>
#include <fstream>

int main(int argc, char* argv[]) {
    if (argc != 3) {
        std::cerr << "Usage: " << argv[0] << " <input_file> <output_file>" << std::endl;
        return 1;
    }

    std::ifstream input(argv[1]);
    std::ofstream output(argv[2]);

    if (!input.is_open() || !output.is_open()) {
        std::cerr << "Error: could not open files." << std::endl;
        return 1;
    }

    std::string line;
    while (std::getline(input, line)) {
        // Exemple simple : écrire chaque ligne en majuscules dans le fichier de sortie
        for (auto & c: line) c = toupper(c);
        output << line << std::endl;
    }

    input.close();
    output.close();
    std::cout << "Processing complete!" << std::endl;

    return 0;
}

Ce programme prend un fichier d'entrée et un fichier de sortie, puis écrit le contenu en majuscules dans le fichier de sortie.

Création d'un serveur API avec Flask

Vous allez maintenant créer un serveur Flask pour accepter une requête HTTP et appeler le programme C++ avec les fichiers spécifiés.

Créez un fichier Python server.py :

# server.py
import subprocess
from flask import Flask, request, jsonify
import os

app = Flask(__name__)

@app.route('/run', methods=['POST'])
def run_program():
    data = request.json
    input_file = data.get('input_file')
    output_file = data.get('output_file')

    if not input_file or not output_file:
        return jsonify({'error': 'Missing input or output file'}), 400

    # Vérifiez que les fichiers existent pour éviter les erreurs
    if not os.path.exists(input_file):
        return jsonify({'error': 'Input file does not exist'}), 400

    try:
        # Exécuter le programme C++ avec subprocess
        result = subprocess.run(['./my_program', input_file, output_file], capture_output=True, text=True)

        if result.returncode != 0:
            return jsonify({'error': 'Execution failed', 'details': result.stderr}), 500
        
        return jsonify({'message': 'Execution successful', 'output_file': output_file})
    
    except Exception as e:
        return jsonify({'error': str(e)}), 500

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

Création du Dockerfile

Le Dockerfile compile l'application C++, installe Python et Flask, et configure le conteneur pour exécuter le serveur Flask et appeler l'application C++.

# Utiliser une image Ubuntu de base
FROM ubuntu:20.04

# Installer les dépendances
RUN apt-get update && apt-get install -y \
    g++ \
    python3 \
    python3-pip

# Installer Flask pour Python
RUN pip3 install flask

# Créer un dossier de travail
WORKDIR /app

# Copier les fichiers C++ et Python
COPY my_program.cpp .
COPY server.py .

# Compiler le programme C++
RUN g++ -o my_program my_program.cpp

# Exposer le port 5000 pour l'API Flask
EXPOSE 5000

# Exécuter le serveur Flask
CMD ["python3", "server.py"]

Construction de l'image Docker

Construisez l'image Docker en exécutant la commande suivante dans le même répertoire que le Dockerfile et les fichiers :

docker build -t cpp-api-server .

Exécution du conteneur Docker

Lancez le conteneur avec cette commande :

docker run -p 5000:5000 cpp-api-server

Test de l'API

Vous pouvez maintenant envoyer une requête POST à l'API pour exécuter le programme C++ en fournissant les fichiers d'entrée et de sortie.

Exemple de requête avec curl :

curl -X POST http://localhost:5000/run -H "Content-Type: application/json" \
    -d '{"input_file": "/path/to/input.txt", "output_file": "/path/to/output.txt"}'

Ou avec Postman ou un autre client HTTP.

Résultat attendu

L'API appelle votre programme C++ avec les fichiers spécifiés, traite le fichier d'entrée, et enregistre les résultats dans le fichier de sortie. Si tout se passe bien, l'API renverra une réponse JSON indiquant le succès de l'exécution et mentionnant le fichier de sortie.

Résumé des fichiers :

  • my_program.cpp : Votre application C++ qui traite un fichier d'entrée et génère un fichier de sortie.

  • server.py : Un serveur Flask qui accepte les requêtes HTTP et appelle votre programme C++.

  • Dockerfile : Instructions pour créer l'image Docker, compiler le programme C++ et exécuter le serveur Flask.

Avantages :

  • Votre application C++ reste inchangée.
  • Le serveur Flask sert d'intermédiaire pour permettre l'accès via HTTP.
  • Flexibilité pour l'intégration avec d'autres systèmes via l'API.





Appel depuis une page web

Pour appeler votre API exposée par le serveur Flask depuis une page web, vous utiliserez JavaScript (avec fetch ou une bibliothèque comme Axios) pour envoyer une requête HTTP à l'API Flask hébergée dans Docker.

Voici les étapes pour appeler l'API depuis une page web :

Code HTML avec JavaScript

Voici un exemple de page web simple qui contient un formulaire permettant de spécifier les noms des fichiers d'entrée et de sortie, puis d'envoyer une requête à votre API Flask via JavaScript.

<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Appel API C++</title>
</head>
<body>

    <h1>Appel de l'application C++ via API</h1>

    <form id="fileForm">
        <label for="inputFile">Fichier d'entrée :</label>
        <input type="text" id="inputFile" name="inputFile" placeholder="/path/to/input.txt" required><br><br>

        <label for="outputFile">Fichier de sortie :</label>
        <input type="text" id="outputFile" name="outputFile" placeholder="/path/to/output.txt" required><br><br>

        <button type="submit">Envoyer</button>
    </form>

    <p id="result"></p>

    <script>
        document.getElementById('fileForm').addEventListener('submit', function(event) {
            event.preventDefault(); // Empêche le rechargement de la page

            // Récupération des valeurs du formulaire
            const inputFile = document.getElementById('inputFile').value;
            const outputFile = document.getElementById('outputFile').value;

            // Préparation des données à envoyer
            const data = {
                input_file: inputFile,
                output_file: outputFile
            };

            // Envoi de la requête POST avec fetch
            fetch('http://localhost:5000/run', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify(data)
            })
            .then(response => response.json())
            .then(data => {
                // Affiche le résultat sur la page
                if (data.error) {
                    document.getElementById('result').innerText = `Erreur : ${data.error}`;
                } else {
                    document.getElementById('result').innerText = `Succès : fichier de sortie généré à ${data.output_file}`;
                }
            })
            .catch(error => {
                document.getElementById('result').innerText = `Erreur : ${error}`;
            });
        });
    </script>

</body>
</html>

Explications du code :

Formulaire HTML : Un formulaire simple avec deux champs où l'utilisateur peut entrer les chemins du fichier d'entrée et du fichier de sortie. JavaScript (fetch API) : Le formulaire est lié à une fonction JavaScript qui intercepte la soumission du formulaire, empêche le rechargement de la page avec event.preventDefault(), puis envoie une requête POST à l'API Flask. fetch : Envoie une requête POST avec un corps JSON contenant les noms de fichiers d'entrée et de sortie. Gestion de la réponse : Une fois la réponse reçue de l'API Flask, la page affiche le message de succès ou d'erreur dans un paragraphe avec l'id result.

Exécuter l'API Flask et tester

Lancement de Docker : Assurez-vous que votre conteneur Docker (avec le serveur Flask et l'application C++) est en cours d'exécution :

docker run -p 5000:5000 cpp-api-server

Tester la page web : Ouvrez le fichier HTML dans un navigateur web (vous pouvez simplement l'ouvrir en double-cliquant dessus). Remplissez les champs du formulaire avec les chemins du fichier d'entrée et de sortie, puis cliquez sur Envoyer. Le JavaScript dans la page web enverra la requête POST à l'API Flask, et le résultat sera affiché directement dans la page.

Gestion du CORS

Si la page web et l'API Flask sont hébergées sur des origines différentes (par exemple, l'API est sur localhost:5000 et la page web sur un autre port), vous devrez gérer les Cross-Origin Resource Sharing (CORS) dans Flask.

Ajoutez la gestion de CORS dans votre serveur Flask en installant le module flask-cors et en l'activant dans votre application.

Installation de flask-cors :

Ajoutez cette ligne dans votre Dockerfile avant la commande CMD :

RUN pip3 install flask-cors

Modification du serveur Flask (server.py) :

Modifiez le fichier server.py pour activer le CORS :

from flask_cors import CORS

app = Flask(__name__)
CORS(app)  # Permettre les requêtes Cross-Origin

Cela permettra à votre page web d'envoyer des requêtes à l'API Flask même si elles sont sur des origines différentes.

Déploiement en production (optionnel)

Pour une utilisation en production, il serait préférable d'héberger l'API Flask et la page web sur un serveur, plutôt que d'utiliser localhost. Vous pouvez :

Déployer l'API sur un service comme AWS, Heroku, ou une machine virtuelle. Héberger la page web avec un serveur HTTP léger comme Nginx ou Apache, ou directement sur un service d'hébergement web.

Conclusion :

Appel de l'API : La page web envoie une requête HTTP via JavaScript à votre API Flask exposée par Docker. API en ligne de commande : Le serveur Flask exécute l'application C++ en ligne de commande, prend les fichiers spécifiés en entrée, et génère les résultats. Cela vous permet de déclencher l'exécution de votre programme C++ depuis une interface web de manière simple et intuitive.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment