134 lines
3.9 KiB
Go
134 lines
3.9 KiB
Go
package handler
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"log/slog"
|
|
"net/http"
|
|
"os"
|
|
"strings"
|
|
|
|
"mkiso-server/internal/service"
|
|
)
|
|
|
|
// writeJSON is a helper to write a JSON response.
|
|
func writeJSON(w http.ResponseWriter, status int, v interface{}) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(status)
|
|
json.NewEncoder(w).Encode(v)
|
|
}
|
|
|
|
// DownloadSingle handles GET /api/iso/download?accession_number=X
|
|
// Returns an ISO file as application/octet-stream.
|
|
func DownloadSingle(isoSvc *service.ISOService) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
acc := r.URL.Query().Get("accession_number")
|
|
if acc == "" {
|
|
writeJSON(w, http.StatusBadRequest, map[string]string{"error": "missing accession_number"})
|
|
return
|
|
}
|
|
acc = strings.TrimSpace(acc)
|
|
|
|
slog.Info("handling download single", "accession", acc)
|
|
|
|
item, err := isoSvc.GenerateISO(r.Context(), acc)
|
|
if err != nil {
|
|
slog.Error("ISO generation failed", "accession", acc, "error", err)
|
|
status := http.StatusInternalServerError
|
|
msg := "ISO creation failed"
|
|
if strings.Contains(err.Error(), "no DICOM data") {
|
|
status = http.StatusNotFound
|
|
msg = "no DICOM data for accession_number"
|
|
}
|
|
writeJSON(w, status, map[string]string{
|
|
"error": msg,
|
|
"detail": err.Error(),
|
|
})
|
|
return
|
|
}
|
|
defer item.Cleanup()
|
|
|
|
// Stream ISO file
|
|
w.Header().Set("Content-Type", "application/octet-stream")
|
|
w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, item.Filename))
|
|
|
|
data, err := os.ReadFile(item.Path)
|
|
if err != nil {
|
|
slog.Error("read ISO file failed", "path", item.Path, "error", err)
|
|
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": "failed to read ISO"})
|
|
return
|
|
}
|
|
|
|
w.Write(data)
|
|
slog.Info("ISO download completed", "accession", acc, "size", len(data))
|
|
}
|
|
}
|
|
|
|
// DownloadMultiple handles GET /api/iso/download-multiple?accession_numbers=X,Y,Z
|
|
// Returns an ISO file as application/octet-stream.
|
|
func DownloadMultiple(isoSvc *service.ISOService) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
raw := r.URL.Query().Get("accession_numbers")
|
|
if raw == "" {
|
|
// Also check for "accession_number" with comma (backward compat)
|
|
raw = r.URL.Query().Get("accession_number")
|
|
}
|
|
if raw == "" {
|
|
writeJSON(w, http.StatusBadRequest, map[string]string{"error": "missing accession_numbers"})
|
|
return
|
|
}
|
|
|
|
accs := parseAccessions(raw)
|
|
if len(accs) == 0 {
|
|
writeJSON(w, http.StatusBadRequest, map[string]string{"error": "empty accession_number list"})
|
|
return
|
|
}
|
|
|
|
slog.Info("handling download multiple", "accessions", accs)
|
|
|
|
item, err := isoSvc.GenerateISOMultiple(r.Context(), accs)
|
|
if err != nil {
|
|
slog.Error("ISO generation failed", "accessions", accs, "error", err)
|
|
status := http.StatusInternalServerError
|
|
msg := "ISO creation failed"
|
|
if strings.Contains(err.Error(), "no DICOM data") {
|
|
status = http.StatusNotFound
|
|
msg = "no DICOM data for accession_numbers"
|
|
}
|
|
writeJSON(w, status, map[string]string{
|
|
"error": msg,
|
|
"detail": err.Error(),
|
|
})
|
|
return
|
|
}
|
|
defer item.Cleanup()
|
|
|
|
w.Header().Set("Content-Type", "application/octet-stream")
|
|
w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, item.Filename))
|
|
|
|
data, err := os.ReadFile(item.Path)
|
|
if err != nil {
|
|
slog.Error("read ISO file failed", "path", item.Path, "error", err)
|
|
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": "failed to read ISO"})
|
|
return
|
|
}
|
|
|
|
w.Write(data)
|
|
slog.Info("ISO download completed (multiple)", "accessions", accs, "size", len(data))
|
|
}
|
|
}
|
|
|
|
// parseAccessions parses a comma-separated list of accession numbers,
|
|
// trimming whitespace and filtering empty entries.
|
|
func parseAccessions(raw string) []string {
|
|
parts := strings.Split(raw, ",")
|
|
var result []string
|
|
for _, p := range parts {
|
|
p = strings.TrimSpace(p)
|
|
if p != "" {
|
|
result = append(result, p)
|
|
}
|
|
}
|
|
return result
|
|
}
|