Package: circe-certic
CirceAPI web pour la transformation de documents.Table des matièresDescription du serviceFormat d'échangeStructure du fichier job.jsonWeb APIGET /transformations/POST /job/GET /job/[UUID]NotificationServeur de référencePré-requisInstallation et démarrage du serviceVariables d'environnement et configuration par défaut:Utilisation en ligne de commandeAuthentificationAjouter des transformationsClients de référenceTestsMise en productionDescription du serviceFormat d'échangeLe client fournit au serveur une tâche (unjob) à effectuer sous forme d'une archive targzippée(*.tar.gz)
contenant a minimaà sa racine:les fichiers à transformerun fichier nommé job.json décrivant les transformations souhaitées sur ces fichiersOn peut également ajouter des fichiers utiles à la conversion, tel que des feuilles de styles ou des fichiers de
fontes par exemple.Structure du fichier job.jsonEst placé dans l'archive un fichierjob.jsondécrivant l'ensemble des opérations à faire sur les fichiers.Un cas minimal:{
    "transformations": [
        {"name": "html2pdf"}
    ]
}... décrit une transformation unique à effectuer sur les documents fournis dans l'archive, sans options.La seule clef obligatoire pour le job est la cleftransformations, contenant la liste des transformations à faire.
La seule clef obligatoire pour la transformation est la clefname, contenant le nom de la transformation.Un cas plus complet:{
    "transformations": [
        {"name": "html2pdf",
         "options": {"compression": 1}},
        {"name": "donothing",}
    ],
    "notify_hook": "http://www.domain.tld/notify-me/"
}... décrit 2 transformations consécutives, dont une avec une option, ainsi qu'une URL de notification
(notify_hook) qui sera appelée par le serveur à la fin dujob.Les résultats des transformations sont également fournis par le serveur sous forme d'archive targzippée.Web APIGET /transformations/Retourne une liste JSON des transformations supportées. Exemple:["html2pdf","donothing", "docx2markdown"]POST /job/Attend dans le corps de la requête une archive dejobcorrectement formée.Retourne unUUID version 4sous
forme de chaîne de caractères. L'UUID retourné est l'identifiant dujob, à conserver pour les prochaines requêtes.Si l'optionblock=1est passée dans l'URL (/job/?block=1), alors le comportement est différent: ce n'est
pas l'UUID qui sera retourné mais directement le résultat des transformations, de manière identique àGET /job/[UUID].En fonction de la configuration du serveur, la soumission d'un nouveaujobpeut nécessiter une authentification.
Dans ce cas, l'entête HTTP Authorization doit être renseigné sous la forme suivante:Authorization: [UUID de l'application] [signature HMAC de l'archive]Voir le source du client Python pour un exemple de signature HMAC.GET /job/[UUID]Récupère l'archive contenant les fichiers transformés par le serveur. Exemple:curl http://www.domain.tl/job/55d87fe0-3924-423a-893d-23aa45614ad9Un statut HTTP 200 est retourné et l'archive avec les documents transformés est contenue dans le corps de la réponse.Au cas où lejobne serait pas terminé, un statut HTTP 202 est retourné.Au cas où l'UUID fait référence à unjobn'existant pas sur ce serveur, un statut HTTP 404 est retourné.En fonction de la configuration du serveur, la récupération d'unjobterminé peut nécessiter une authentification.
Dans ce cas, l'entête HTTP Authorization doit être renseigné sous la forme suivante:Authorization: [UUID de l'application] [signature HMAC de l'UUID du job]Voir le source du client Python pour un exemple de signature HMAC.NotificationDans le cas où une URL a été fournie dans la clefnotify_hookdu fichier job.json, le serveur effectue une
requête POST sur cette URL avec l'UUID dujoben corps de requête.Serveur de référenceUn serveur de référence est implémenté en Python. Deux composants sont fournis:un serveur HTTP exposant l'interface HTTP du serviceun pool de workers effectivement chargés des transformationsPré-requisPython >= 3.6Installation et démarrage du serviceCréation et activation d'un venv:python3 -m venv myvenv
. ./myvenv/bin/activateInstallation de Circe:pip install circe-CERTICDémarrage du service HTTP:circe serveDémarrage des workers:circe start-workersDémarrage simultané du service HTTP et des workers:circe runVariables d'environnement et configuration par défaut:CIRCE_HOST(127.0.0.1)CIRCE_PORT(8000)CIRCE_DEBUG(0)CIRCE_WORKERS(number of CPUs)CIRCE_WORKING_DIR($HOME/.circe/)CIRCE_ENABLE_WEB_UI(0)CIRCE_WEB_UI_CRYPT_KEY("you should really change this")CIRCE_WEB_UI_REMOVE_USER_FILES_DELAY(7200)CIRCE_WEB_UI_SECURE_COOKIE(1)CIRCE_USE_AUTH(1)CIRCE_TRANSFORMATIONS_MODULE(None)Vous pouvez renseigner ces variables à différents endroits, en fonction de vos besoins:dans le fichier lu au démarrage de votre shell (~/.zshrc, ~/.bashrc, etc)dans un fichier .env dans votre répertoire de travail (celui où vous vos trouvez quand vous lancez circe)directement avant la commande circe, sur la même ligneExemple type d'un fichier .env:CIRCE_TRANSFORMATIONS_MODULE=mon_module_de_transfos
CIRCE_ENABLE_WEB_UI=1
CIRCE_WEB_UI_CRYPT_KEY="53CreT"
CIRCE_USE_AUTH=0Utilisation en ligne de commandeUn certain nombre de commande sont disponibles dans circe. Pour les afficher:(venv) ➜  src ✗ circe --help
usage: circe [-h]
             {serve,start-workers,make-api-access,remove-api-access,list-api-access,list-transformations,run}
             ...

positional arguments:
  {serve,start-workers,make-api-access,remove-api-access,list-api-access,list-transformations,run}
    serve               Start Circe HTTP server
    start-workers       Start job workers
    make-api-access     Create new app uuid / secret couple for api access.
    remove-api-access   Remove access to the API
    list-api-access     List all access tokens to the API
    list-transformations
    run                 Start both HTTP server and job workers

optional arguments:
  -h, --help            show this help message and exitIl est possible d'obtenir de l'aide sur chaque commande:(venv) ➜  src ✗ circe serve --help
usage: circe serve [-h] [--host HOST] [-p PORT] [-w WORKERS] [-d] [-a]

Start Circe HTTP server

optional arguments:
  -h, --help            show this help message and exit
  --host HOST           '127.0.0.1'
  -p PORT, --port PORT  8000
  -w WORKERS, --workers WORKERS
                        1
  -d, --debug           False
  -a, --access-log      FalseAuthentificationLorsque la variable d'environnement CIRCE_USE_AUTH est à "1", le serveur attend
une authentification sous la forme d'un hash HMAC du corps de la requête avec
une clef partagée entre le serveur est le client. Ce hash est ajouté aux entêtes
de la requête avec un identifiant propre au client de la façon suivante:Authorization: [identifiant du client] [hash HMAC du corps de la requête]Pour plus de détails sur le hash HMAC, voir les différentes implémentations dans les
librairies clients listées en bas de ce README.Toute la gestion des accès à l'API Circe se fait en ligne de commande.Pour la création de l'accès:(venv) ➜  circe-server ✗ circe make-api-access -t MonClientDeTest
Access granted to MonClientDeTest
uuid    : 33f3f6c5-3bbc-4eeb-b661-e4579b2d9671
secret: &#H-9csMX|0):'-eUP6'u,I6=5X}U|z/Le client se voit attribué un UUID ainsi qu'une clef qu'il utilisera pour le hâchage.Pour la suppression de l'accès:(venv) ➜  circe-server ✗ circe remove-api-access 33f3f6c5-3bbc-4eeb-b661-e4579b2d9671Pour lister tous les accès:(venv) ➜  circe-server ✗ circe list-api-access                                       
7afa5930a3c549b9a7003c0f98b55e73 : rcY<S<"\oHvjUJdf'w"J:YKE\?AKiG"~  [test client]
3a5eb39cadb04c8e9b30ee167c2e4cb5 : ~1!|J;yxGkW)?Z]hQ\v+Rn*52?`y(_:z  [test client]
a9e836331612498cb1681bc953132d82 : EQbQ&>)BxC|J/5Gz?4$BNr)~&\|k89`I  [test client]
1f902a30f124450bbe267b56026d347f : L$xc8cwFiczK4z7n%.{eSg^y0xFrzBtX  [test client]Ajouter des transformationsLa variable d'environnement CIRCE_TRANSFORMATIONS_MODULE contient le nom du module Python contenant les transformations
que vous souhaitez rendre disponible dans le service.Une transformation est un Python callable (fonction ou classe) prenant en argument le dossier de travail du job, une
instance de logging.Logger ainsi qu'un dictionnaire d'options (facultatif). Exemple minimal d'une transformation:def ne_fait_rien(working_dir: str, logger: logging.Logger, options: dict = None):
    pass  # ajouter ici le code transformant les documentsL'instance de logging.Logger peut prendre ee paramêtre une chaîne ou un dictionnaire:logger.info('message de log")
logger.info({"message": "message de log", "autre info utile": 42}Les transformations peuvent fournir une description de leur fonctionnement ainsi:ne_fait_rien.description = {
	"label": "Ne fait rien",
	"help": "Ne fait rien absolument rien. Utile pour tester l'API.",
	"options": [],  # aucune option pour cette transformation
}Ces descriptions sont utiles pour les clients.Des exemples de transformations sont disponibles dans ce dépôt:https://git.unicaen.fr/certic/circe-transformationsClients de référenceUne librairie cliente de référence en python est proposée.Installation:pip install circe-client-CERTICUtilisation:from circe_client import Client

# Les paramètres peuvent être ignorés si les variables
# d'environnement CIRCE_ENDPOINT, CIRCE_SECRET et CIRCE_APP_UUID
# existent.    
client = Client(
    api_endpoint="http://host.tld/,
    secret_key="notsosecret",
    application_uuid="786d1b69a6034eb89178fed2a195a1ed",
)

if "html2pdf" in client.available_transformations():
    job = client.new_job()
    job.add_file("index.html")
    # on peut adjoindre tout fichier utile à la transformation
    job.add_file("style.css")
    job.add_transformation("html2pdf")
    # en option, une URL qui recevra une notification en POST
    # à la fin du job:
    # job.set_notify_hook("https://acme.tld/notify-me/")

    # wait=True pour un appel synchrone à l'API,
    # à privilégier pour les jobs courts et/ou les
    # transformations rapides:
    client.send(job, wait=True)
    
    # pour un appel asynchrone, retournant un UUID de job,
    # à privilégier pour les jobs longs (transformations lentes
    # et/ou nombreux fichiers):
    #
    # client.send(job)
    # print(job.uuid)
    # 
    # On peut ensuite tenter une récupération du job avec
    # un timeout:
    #
    # client.poll(job, timeout=60)

    # liste les fichiers disponible dans l'archive de résultat
    # sous la forme d'un tuple (nom de fichier, pointeur vers le fichier)
    for file_name, file_handle in job.result.files:
        print(file_name)Unelibrairie cliente équivalente en Javaest disponible
ainsi qu'unelibrairie minimale en PHPet unoutil en ligne de commande implémenté en Go.TestsUn ensemble de tests exécutables par Pytest sont disponibles dans le fichiertest.py.Mise en productionUne façon simple de faire fonctionner Circe en production sur Linux est de maintenir le service via systemd
et de le mettre en reverse proxy derrière un serveur web.Pour le service sous systemd, ajouter ceci dans un fichier /etc/systemd/system/circe.service, en prenant soin
de changer les chemins en fonction de votre installation, ainsi que votre utilisateur/groupe:[Unit]
Description=Circe Service
 
[Service]
Type=simple
 
# ici on a créé un utilisateur spécifique pour le service
User=circe
Group=circe
UMask=007
 
# On utilise ici le chemin complet vers le script circe installé dans le virtualenv 
ExecStart=/home/circe/venvs/circe_env/bin/circe run
Environment="PATH=/usr/bin:/home/circe/venvs/circe_env/bin:$PATH" 
# Vous pouvez changer ici toutes les variables d'environnement propres à la configuration de Circe
Environment="CIRCE_WEB_UI_CRYPT_KEY=qpoiurfIPUBeriIPU"
Environment="CIRCE_TRANSFORMATIONS_MODULE=your_transformations"
Environment="CIRCE_ENABLE_WEB_UI=0"
Restart=always 
RestartSec=0
 
# Configures the time to wait before service is stopped forcefully.
TimeoutStopSec=30

[Install]
WantedBy=multi-user.targetPuis, dans votre shell avec les droits root:systemctl daemon-reload
systemctl enable circe
systemctl start circeVous pouvez vérifier que le service est bien démarré avec la commande suivante:systemctl status circeLe serveur devrait écouter en locahost (127.0.0.1) sur le port 8000 si vous n'avez pas modifié sa configuration.
Vous pouvez maintenant placer ce service derrière le serveur web de votre choix.PourCaddy, dans votre /etc/caddy/CaddyFile:circe.yourhost.com {
	reverse_proxy 127.0.0.1:8000
	header -Server
}Pour Apache, dans la configuration de votre vhost:<Location />
	ProxyPass "http://127.0.0.1:8000/"
	ProxyPassReverse "http://127.0.0.1:8000/"
</Location>Référez-vous à la documentation de votre serveur web pour plus de détail.