Go-Backend (chi, pgx, golang-migrate) + React/TS-Frontend als PWA. Enthalten: Auth inkl. OIDC, Dateien mit Versionen und Papierkorb, Freigaben (Links + intern), WebDAV, Gruppenordner, Admin/Theming, Volltextsuche mit OCR, eigener PDF-Betrachter und WOPI-Office (Collabora/OnlyOffice). Nicht im Repo: deploy/.env (Sitzungsschlüssel, DB- und Admin-Passwort) sowie alle Daten- und Build-Verzeichnisse – siehe .gitignore. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
67 lines
2.2 KiB
Go
67 lines
2.2 KiB
Go
package documents
|
||
|
||
import (
|
||
"fmt"
|
||
"os"
|
||
"path/filepath"
|
||
"strings"
|
||
"syscall"
|
||
)
|
||
|
||
// minFreeBytes ist die Untergrenze, unter der die Texterkennung pausiert.
|
||
//
|
||
// OCR ist das einzige Stück dieser Anwendung, das von sich aus und ohne
|
||
// Zutun eines Menschen Platz verbraucht: Es arbeitet eine Warteschlange ab,
|
||
// solange etwas darin liegt. Eine Cloud, die ihre eigene Platte vollschreibt,
|
||
// nimmt Uploads nicht mehr an – und das wäre dann kein OCR-Problem mehr,
|
||
// sondern ein Ausfall.
|
||
//
|
||
// 2 GiB ist mit Absicht großzügig: Der Sidecar einer Erkennung ist kaum größer
|
||
// als ein Megabyte, tesseract und ghostscript brauchen währenddessen aber
|
||
// Arbeitsdateien, deren Größe von der Auflösung der Vorlage abhängt. Lieber
|
||
// eine Weile nichts erkennen als eine volle Platte.
|
||
const minFreeBytes = 2 << 30 // 2 GiB
|
||
|
||
// freeBytes meldet den freien Platz auf dem Dateisystem, auf dem path liegt.
|
||
func freeBytes(path string) (uint64, error) {
|
||
var st syscall.Statfs_t
|
||
if err := syscall.Statfs(path, &st); err != nil {
|
||
return 0, fmt.Errorf("statfs %s: %w", path, err)
|
||
}
|
||
// Bavail, nicht Bfree: Bfree zählt auch die Reserve mit, die nur root
|
||
// benutzen darf – der Server läuft aber als unprivilegierter Nutzer und
|
||
// käme daran nie heran.
|
||
return st.Bavail * uint64(st.Bsize), nil
|
||
}
|
||
|
||
// sweepTemp räumt Zwischendateien früherer Läufe weg.
|
||
//
|
||
// Im Normalfall räumt der Arbeiter selbst auf. Wird der Container aber hart
|
||
// beendet – `docker kill`, ein Absturz, Stromausfall –, läuft kein defer mehr,
|
||
// und die angefangene Datei bleibt liegen. Ohne diesen Durchgang sammelt sich
|
||
// das über Monate an, ausgerechnet auf der Platte, die auch die Dateien trägt.
|
||
//
|
||
// Es wird nur weggeräumt, was diese Anwendung selbst angelegt hat: das Präfix
|
||
// "ocr-" im Zwischenverzeichnis. Fremde Dateien bleiben unangetastet.
|
||
func sweepTemp(dir string) (int, int64) {
|
||
entries, err := os.ReadDir(dir)
|
||
if err != nil {
|
||
return 0, 0
|
||
}
|
||
var count int
|
||
var bytes int64
|
||
for _, e := range entries {
|
||
if e.IsDir() || !strings.HasPrefix(e.Name(), "ocr-") {
|
||
continue
|
||
}
|
||
full := filepath.Join(dir, e.Name())
|
||
if info, err := e.Info(); err == nil {
|
||
bytes += info.Size()
|
||
}
|
||
if err := os.Remove(full); err == nil {
|
||
count++
|
||
}
|
||
}
|
||
return count, bytes
|
||
}
|