Skip to content

khIbrahim/go-print-service

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Go Pixel Aura Print Service

Service d'impression thermal ESC/POS avec système de queue distribué et persistence db et retry automatique.

Ce projet gère :

  • Queue persistante : les jobs survivent aux redémarrages
  • Retry automatique : backoff exponentiel sur les échecs
  • Workers concurrents : traitement parallèle avec goroutines
  • Recovery : récupération des jobs pending au démarrage
  • Monitoring : API REST pour suivre l'état de chaque job
  • Extensible : facile d'ajouter de nouveaux types de jobs et templates
  • Supporte les codes-barres : CODE128, EAN13, EAN8, QR Code

Stack technique

  • Go 1.21+ : concurrence native, channels, context
  • SQLite : persistence des jobs (CGO requis)
  • Gin : router HTTP léger
  • ESC/POS : commandes raw pour imprimantes thermal

Build

go mod download
go build -o print-service cmd/api/main.go

Architecture

┌─────────────────────────────────────────────────────┐
│                   HTTP Handler                       │
│      (handlers/print.go, jobs.go, printer.go)       │
└──────────────────────┬──────────────────────────────┘
                       ↓
┌─────────────────────────────────────────────────────┐
│                  Queue Manager                       │
│                  (queue/queue.go)                    │
│  - Enqueue jobs                                      │
│  - Get status                                        │
│  - List jobs                                         │
└──────────────────────┬──────────────────────────────┘
                       ↓
           ┌───────────┴───────────┐
           ↓                       ↓
┌──────────────────┐    ┌──────────────────┐
│   Job Store      │    │   Worker Pool    │
│ (queue/job_store)│    │ (queue/worker.go)│
│  - SQLite        │    │  - 5 workers     │
│  - CRUD jobs     │    │  - Consume queue │
└──────────────────┘    └────────┬─────────┘
                                 ↓
                    ┌────────────────────────┐
                    │     Renderer           │
                    │  (renderer/renderer)   │
                    │  - ESC/POS generation  │
                    └────────────┬───────────┘
                                 ↓
                    ┌────────────────────────┐
                    │   Printer Service      │
                    │ (printer/service.go)   │
                    │  - Get printer config  │
                    │  - TCP connection      │
                    │  - Send to printer     │
                    └────────┬───────────────┘
                             ↓
            ┌────────────────┴────────────────┐
            ↓                ↓                 ↓
    ┌──────────────┐  ┌──────────────┐  ┌──────────────┐
    │   Registry   │  │    Storage   │  │  API Client  │
    │  (cache mem) │  │ (JSON file)  │  │  (Laravel)   │
    │  - Fast get  │  │  - Persist   │  │  - Sync      │
    └──────────────┘  └──────────────┘  └──────────────┘

NOTE IMPORTANTE : go-sqlite3 nécessite CGO, il faut donc installer un compilateur C (jpense mingw-w64 est bon) et mettre CGO_ENABLED=1 Consultez aussi : le build dans les workflows GitHub Actions pour Windows qui montre comment faire.

pour définir la variable de façon permanente
go env -w CGO_ENABLED=1

pour la session powershell:
$env:CGO_ENABLED = "1

Pour lancer une seule commande avec CGO activé :
$env:CGO_ENABLED = "1"; go build -o .\cmd\api\api.exe .\cmd\api\main.go

Builder :

On travaille avec le language ESC/POS qui travaille souvent en mono-octet (8 bits) via des codes pages et l'UTF-8 n'est pas tjr nativement compris par les modèles chinois ou autre qui ont souvent un double byte (dbcs) car ils ont firmware déstiné au marché asiatique avec des paires d'octets et souvent ça ignore complètement le text 8-bit "occidental" donc code page du self test n'est pas tjr la vérité absolue et ça c'est nul car le firmware CN peut rester en DBCS pour les raw data

Fix :

l'idée est de tout simplement:

  1. désactiver le DBCS FS . est la clé
  2. passer en jeu international (France ajuste qlq symboles) : Touche seulement qlq glyphes mais ne remplace pas le code page
  3. activer le code page 1252 (Windows Estern) Je le mettrai pas dans le ENV, car c'est la dictature
  4. envoyer le texte brut en OCTETS EN CP12525
ESC @        (0x1B 0x40)     // init
FS  .        (0x1C 0x2E)     // DBCS OFF
ESC R 3      (0x1B 0x52 0x03)// jeu international
ESC t 16     (0x1B 0x74 0x10)// codepage = 1252 (Windows Western)
... octets en CP1252 ...
GS V 0       (0x1D 0x56 0x00)// cut
  • init en go qu'on utilisera
var (
    escInit   = []byte{0x1B, 0x40}
    fsExitCJK = []byte{0x1C, 0x2E}
    escIntlFR = []byte{0x1B, 0x52, 0x03}
    escCP1252 = []byte{0x1B, 0x74, 0x10}
    cutFull   = []byte{0x1D, 0x56, 0x00}
)

qlq notes :

  1. ESC t choisit le mapping 8-bit complet et ESC R ajuste certains caractères spéciaux (symbole monétaire, diacritiques rares) selon la région
  2. la plus part des printers ne gèrent pas l'UTF-8 brut en mode texte donc soit Transcoder en CP1252/850/858 avant envoi ou Rasteriser en image (bitmap) et imprimer l’image (plus lent, mais 100% fiable)

BARCODE LAYER

  1. Gestion des codes-barres via l'engine ESC/POS
  2. Supporte les formats:
    • CODE128
    • EAN13
    • EAN8
    • QR Code (si supporté par l'imprimante)

Pour le CODE128:

la hauteur est automatiquement ajustée
width peut être 2-6 (2 par défaut)
hri = human readable interpretation (texte lisible)

RENDERER & TEMPLATES

  1. Renderer → transforme data en ESC/POS
  2. Templates supportés:
    • Base (template générique)
    • Kitchen (commandes cuisine)
    • Receipt (tickets de caisse)
    • Customer (tickets clients)

Comment ça marche:

  1. Data → Template choisi selon PrintType et caché dans le manager
  2. Template applique son layout
  3. Renderer génère les commandes ESC/POS ↓
  4. Output = raw bytes pour l'imprimante

API

Endpoint principal : /api/v1/print

Le point d'entrée pour créer des impressions multiples en une seule requête.

Format de requête

{
  "order_number": "ORDER-12345",
  "printings": {
    "kitchen": "kitchen_printer",
    "receipt": "receipt_printer",
    "customer": "customer_printer"
  },
  "data": {
    "items": ["..."],
    "total": 45.50,
    "payment_method": "card"
  }
}

Flow Interne

  1. Validation : bind JSON → PrintRequest
  2. Conversion : req.ToRawData() → sérialise data en JSON brut
  3. Multi-job : pour chaque entry dans printings :
  • Crée un PrintJob avec {type, printer, raw_data}
  • Enqueue(job) → persist SQLite + envoi au channel
  1. Response 202 : retourne les IDs de chaque job créé

Exemple de réponse

{
  "message": "Jobs créés et envoyé aux workers",
  "jobs": {
    "kitchen": "abc-123-def",
    "receipt": "ghi-456-jkl",
    "customer": "mno-789-pqr"
  }
}

Jobs

# Créer des impressions
POST /api/v1/print
{
  "order_number": "12345",
  "printings": {
    "kitchen": "kitchen_printer",
    "receipt": "receipt_printer"
  },
  "data": { ... }
}

# Lister les jobs
GET /api/v1/jobs?status=pending&limit=10

# Détails d'un job
GET /api/v1/jobs/:id

# Status rapide
GET /api/v1/jobs/:id/status

# Retry manuel (jobs dead)
POST /api/v1/jobs/:id/retry

# Statistiques
GET /api/v1/jobs/stats

Printers

# Lister les imprimantes
GET /api/v1/printers

# Détails
GET /api/v1/printers/:name

# Status (online/offline)
GET /api/v1/printers/:name/status

# Test print
POST /api/v1/printers/:name/test

# Sync depuis API externe
POST /api/v1/printers/sync

Lance ton print

/api/print

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages