117 lines
3.3 KiB
Go
117 lines
3.3 KiB
Go
package app
|
|
|
|
import (
|
|
"encoding/json"
|
|
"io"
|
|
"net/http"
|
|
"strings"
|
|
)
|
|
|
|
func handleTransportOwnerLocksClear(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodPost {
|
|
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
|
|
var body TransportOwnerLocksClearRequest
|
|
if r.Body != nil {
|
|
defer r.Body.Close()
|
|
if err := json.NewDecoder(io.LimitReader(r.Body, 1<<20)).Decode(&body); err != nil && err != io.EOF {
|
|
http.Error(w, "bad json", http.StatusBadRequest)
|
|
return
|
|
}
|
|
}
|
|
|
|
filter, err := normalizeTransportOwnerLockClearRequest(body)
|
|
if err != nil {
|
|
writeJSON(w, http.StatusOK, TransportOwnerLocksClearResponse{
|
|
OK: false,
|
|
Message: err.Error(),
|
|
Code: "OWNER_LOCK_CLEAR_INVALID_REQUEST",
|
|
})
|
|
return
|
|
}
|
|
|
|
transportMu.Lock()
|
|
defer transportMu.Unlock()
|
|
|
|
locks := loadTransportOwnerLocksState()
|
|
baseRevision := locks.PolicyRevision
|
|
if body.BaseRevision > 0 && body.BaseRevision != baseRevision {
|
|
writeJSON(w, http.StatusOK, TransportOwnerLocksClearResponse{
|
|
OK: false,
|
|
Message: "stale owner-lock revision",
|
|
Code: "OWNER_LOCK_CLEAR_REVISION_MISMATCH",
|
|
BaseRevision: baseRevision,
|
|
})
|
|
return
|
|
}
|
|
|
|
matched, remaining := splitTransportOwnerLocksByFilter(locks.Items, filter)
|
|
if len(matched) == 0 {
|
|
writeJSON(w, http.StatusOK, TransportOwnerLocksClearResponse{
|
|
OK: true,
|
|
Message: "no matching owner locks",
|
|
BaseRevision: baseRevision,
|
|
MatchCount: 0,
|
|
ClearedCount: 0,
|
|
RemainingCount: len(locks.Items),
|
|
})
|
|
return
|
|
}
|
|
|
|
digest := digestTransportOwnerLocksClear(baseRevision, filter, matched)
|
|
confirmToken := strings.TrimSpace(body.ConfirmToken)
|
|
if !consumeTransportOwnerLocksClearToken(confirmToken, baseRevision, digest) {
|
|
nextToken := issueTransportOwnerLocksClearToken(baseRevision, digest)
|
|
code := "OWNER_LOCK_CLEAR_CONFIRM_REQUIRED"
|
|
msg := "confirm token required to clear owner locks"
|
|
if confirmToken != "" {
|
|
code = "OWNER_LOCK_CLEAR_CONFIRM_INVALID"
|
|
msg = "invalid or expired confirm token"
|
|
}
|
|
writeJSON(w, http.StatusOK, TransportOwnerLocksClearResponse{
|
|
OK: false,
|
|
Message: msg,
|
|
Code: code,
|
|
BaseRevision: baseRevision,
|
|
ConfirmRequired: true,
|
|
ConfirmToken: nextToken,
|
|
MatchCount: len(matched),
|
|
RemainingCount: len(locks.Items),
|
|
Items: matched,
|
|
})
|
|
return
|
|
}
|
|
|
|
next := locks
|
|
next.Items = append([]TransportOwnerLockRecord(nil), remaining...)
|
|
next.PolicyRevision = baseRevision
|
|
if err := saveTransportOwnerLocksState(next); err != nil {
|
|
writeJSON(w, http.StatusOK, TransportOwnerLocksClearResponse{
|
|
OK: false,
|
|
Message: "owner-lock save failed: " + err.Error(),
|
|
Code: "OWNER_LOCK_CLEAR_SAVE_FAILED",
|
|
BaseRevision: baseRevision,
|
|
})
|
|
return
|
|
}
|
|
|
|
events.push("transport_owner_locks_cleared", map[string]any{
|
|
"base_revision": baseRevision,
|
|
"cleared_count": len(matched),
|
|
"remaining_count": len(next.Items),
|
|
"client_id": filter.ClientID,
|
|
})
|
|
|
|
writeJSON(w, http.StatusOK, TransportOwnerLocksClearResponse{
|
|
OK: true,
|
|
Message: "owner locks cleared",
|
|
BaseRevision: baseRevision,
|
|
MatchCount: len(matched),
|
|
ClearedCount: len(matched),
|
|
RemainingCount: len(next.Items),
|
|
Items: matched,
|
|
})
|
|
}
|