- dms/internal/retentionclient: HTTP-Client fuer Archive RET-05/RET-09 - dms/internal/retentiondestroy: RegisterOrRequeue (FDN-04-Requeue bei Fehlschlag, kein Absturz/stilles Verwerfen), DestroyCallbackHandler (physische Loeschung aller Datei-Revisionen ueber storage.Service, markiert Dokument als vernichtet, 2xx erst danach) - dms/cmd/app: mountet destroy-callback, registriert beim Start - dms/cmd/worker: verarbeitet Requeue-Jobs (Retry) - nur dms_document registriert (DOC-01/FDN-02 kennen keinen separaten Anhang-Typ, kein Umbau angrenzender Bereiche) - real getestet: registrierung gegen echten fake-RET-05-Server, echte Loeschung inkl. Storage-Byte-Nachweis, echter Requeue-Eintrag bei Fehlschlag, erfolgreicher Retry - live auf 131 gegen echten RET-09-Dienst (Port 8095) verifiziert, echter curl-Vernichtungs-Rueckruf mit real geloeschter Datei - reale Core-API-06-Deploy-Luecke dokumentiert (nicht verschwiegen): /internal/resync/usage auf 131 aktuell nicht gemountet Pruefungen siehe dms/docs/DOC-16-PRUEFPROTOKOLL.md
79 lines
2.5 KiB
Go
79 lines
2.5 KiB
Go
// Package retentionclient ist ein schlanker HTTP-Client für Archive
|
|
// RET-05 (RET-09: archive/internal/moduleadapter.RegisterHandler, real
|
|
// als Dienst gestartet). DMS ist ein physisch getrenntes Go-Modul und
|
|
// kann Archive-internen Go-Code nicht direkt importieren.
|
|
package retentionclient
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
)
|
|
|
|
type Client struct {
|
|
BaseURL string
|
|
HTTPClient *http.Client
|
|
}
|
|
|
|
func New(baseURL string) *Client {
|
|
return &Client{BaseURL: baseURL, HTTPClient: http.DefaultClient}
|
|
}
|
|
|
|
type registerRequest struct {
|
|
ModuleName string `json:"module_name"`
|
|
ObjectType string `json:"object_type"`
|
|
RetentionClass string `json:"retention_class"`
|
|
CallbackURL string `json:"callback_url"`
|
|
}
|
|
|
|
// Registration spiegelt RET-05s Registration-Antwort.
|
|
type Registration struct {
|
|
ID string `json:"ID"`
|
|
ModuleName string `json:"ModuleName"`
|
|
ObjectType string `json:"ObjectType"`
|
|
RetentionClass string `json:"RetentionClass"`
|
|
CallbackURL string `json:"CallbackURL"`
|
|
}
|
|
|
|
// Register registriert einen Objekttyp bei Archive RET-05. Jeder Fehler
|
|
// (Transport, Timeout, Nicht-2xx) wird als Fehler zurückgegeben — der
|
|
// Aufrufer entscheidet ueber Requeue statt stillem Verwerfen
|
|
// (Akzeptanzkriterium 3).
|
|
func (c *Client) Register(ctx context.Context, moduleName, objectType, retentionClass, callbackURL string) (Registration, error) {
|
|
body, err := json.Marshal(registerRequest{
|
|
ModuleName: moduleName, ObjectType: objectType, RetentionClass: retentionClass, CallbackURL: callbackURL,
|
|
})
|
|
if err != nil {
|
|
return Registration{}, fmt.Errorf("retentionclient: request kodieren: %w", err)
|
|
}
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.BaseURL+"/register", bytes.NewReader(body))
|
|
if err != nil {
|
|
return Registration{}, fmt.Errorf("retentionclient: request bauen: %w", err)
|
|
}
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
resp, err := c.httpClient().Do(req)
|
|
if err != nil {
|
|
return Registration{}, fmt.Errorf("retentionclient: aufruf fehlgeschlagen: %w", err)
|
|
}
|
|
defer func() { _ = resp.Body.Close() }()
|
|
|
|
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
|
return Registration{}, fmt.Errorf("retentionclient: unerwarteter status %d", resp.StatusCode)
|
|
}
|
|
var out Registration
|
|
if err := json.NewDecoder(resp.Body).Decode(&out); err != nil {
|
|
return Registration{}, fmt.Errorf("retentionclient: antwort dekodieren: %w", err)
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
func (c *Client) httpClient() *http.Client {
|
|
if c.HTTPClient != nil {
|
|
return c.HTTPClient
|
|
}
|
|
return http.DefaultClient
|
|
}
|