Dennis Nemec ec3760318b fix(service): StartPending-Handshake + Fehler sichtbar, kein Konsolen-Fallback
Der Windows-Dienst startete nicht zuverlaessig (blieb in 'Wird gestartet' /
generischer Startfehler). Behoben:
- StartPending -> Running melden (statt direkt Running): sauberer SCM-Handshake.
- service_main protokolliert Start + Fehler in mailclient-fatal.log (Session 0
  hat keine Konsole); Runtime-/Status-Fehler werden als 'gestoppt mit Fehler'
  gemeldet statt ins Leere zu laufen.
- main faellt bei Dispatcher-Fehler NICHT mehr still in den Konsolenmodus (das
  erzeugte einen nicht vom SCM verwalteten Geisterprozess, der einen
  erfolgreichen Start vortaeuschte + die EXE sperrte). Interaktiv via --console.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 17:21:14 +02:00

Holzleitner Mail-Versende-Client

Langlaufender Windows-Client. Pollt alle 5 Minuten die noch nicht versendeten Belegnummern vom Backend und stößt ERPFRAME.EXE an, das die Mails verschickt.

Ablauf je Tick (Default alle 300 s)

  1. GET {backend}/admin/delivered-belegnummern — Header X-Admin-Api-Key. Liefert nur Belege, deren Liefermail noch offen ist (mail_sent_at IS NULL).
  2. Sind welche offen: ein Aufruf ERPFRAME.EXE <mode> <app_name> <user> <password> <command> <belege_csv> (alle Belegnummern kommagetrennt als ein Argument) und auf Ende warten.
  3. Nur bei ExitCode 0: POST {backend}/admin/mark-mail-sent mit den Belegnummern → markiert sie server-seitig als versendet (Dedup).

Reihenfolge erst ERPframe, dann markieren: schlägt ERPframe fehl, bleiben die Belege offen und werden beim nächsten Tick erneut versucht. Alle Fehler werden geloggt, die Schleife läuft weiter.

Konfiguration

config.json neben der EXE (Vorlage: config.example.json). Enthält Secrets → nicht ins Git (siehe .gitignore).

Feld Bedeutung
backend_base_url z. B. http://10.168.10.2:3000 (ohne /admin)
admin_api_key Wert für Header X-Admin-Api-Key
poll_interval_secs Poll-Intervall (Default 300)
request_timeout_secs HTTP-Timeout je Request (Default 30)
erp_timeout_secs Timeout für den ERPframe-Prozess; 0 = unbegrenzt (Default 600)
belegnummer_separator Trennzeichen für das Belege-Argument (Default ,)
log_dir Log-Verzeichnis (relativ ⇒ relativ zur EXE; Default logs)
erpframe.exe_path voller Pfad zu ERPFRAME.EXE
erpframe.mode erstes Argument (Default AUTOSTARTUP)
erpframe.app_name / user / password / command wie im PowerShell-Skript
erpframe.working_dir Arbeitsverzeichnis (null ⇒ EXE-Verzeichnis)

Logs: <log_dir>/mailclient_YYYY-MM-DD.log (+ stdout).

Build

Das Programm nutzt rustls (kein OpenSSL) → keine C-Abhängigkeiten.

Auf einem Windows-Rechner (empfohlen, MSVC)

cargo build --release

target\release\holzleitner-mailclient.exe

Cross-Compile vom Mac/Linux (GNU-Target)

rustup target add x86_64-pc-windows-gnu
brew install mingw-w64            # macOS; Linux: apt install gcc-mingw-w64
cargo build --release --target x86_64-pc-windows-gnu

target/x86_64-pc-windows-gnu/release/holzleitner-mailclient.exe

In einer Windows-VM auf Apple Silicon (ARM64)

Die VM ist ARM64 — ein einfaches cargo build erzeugt eine ARM64-EXE, die auf dem x64-Server NICHT läuft. Immer explizit x64 bauen:

rustup target add x86_64-pc-windows-msvc
cargo build --release --target x86_64-pc-windows-msvc

Nicht auf einem Shared-Drive (Z:) bauen (Build bricht mit os error 87 ab, weil das Shared-FS die Temp-Datei-Operationen nicht unterstützt) — die Quelle darf dort liegen, aber target/ auf lokales NTFS legen:

$env:CARGO_TARGET_DIR = "C:\cargo-target\mailclient"

Deployment als Windows-Dienst

Die EXE ist dienstfähig — sie spricht direkt mit dem Service Control Manager (sauberes Start/Stop, Autostart, Auto-Restart bei Absturz).

  1. EXE + config.json in ein Verzeichnis legen, z. B. C:\Holzleitner\Mailclient\. config.json muss neben der EXE liegen (der Dienst startet mit Arbeitsverzeichnis C:\Windows\System32).
  2. PowerShell als Administrator öffnen und registrieren:
    cd C:\Holzleitner\Mailclient
    .\install-service.ps1
    # optional unter einem bestimmten Konto (z. B. für ERPframe-DB-/Netzzugriff):
    .\install-service.ps1 -Credential (Get-Credential)
    
    Registriert den Dienst „Holzleitner App Mails" (interner Name HolzleitnerAppMails), verzögerter Autostart, Auto-Restart, und startet ihn.
  3. Verwalten — in services.msc erscheint er als „Holzleitner App Mails":
    Get-Service  HolzleitnerAppMails
    Stop-Service HolzleitnerAppMails
    Start-Service HolzleitnerAppMails
    
  4. Entfernen:
    .\uninstall-service.ps1
    

Konsolenmodus (zum Testen)

Direkter Start (Doppelklick / Konsole) läuft automatisch im Konsolenmodus (der SCM-Dispatcher schlägt fehl → Fallback). Erzwingen mit:

.\holzleitner-mailclient.exe --console

Beenden mit Ctrl-C (sauberer Shutdown). Da die Binary selbst alle 5 Min pollt, keinen zusätzlichen 5-Minuten-Task einrichten — ein Dauerprozess genügt.

Description
No description provided
Readme 56 KiB
Languages
Rust 84.9%
PowerShell 15.1%