Rewrites the internal/api comment blocks to rule 32: task, milestone and rule ids gone, the stories behind them restated as the constraint they left, stale references corrected (the stream secret is wired from config, the timezone handler already refreshes the scheduler, the Android app is the native client, the design docs cited are not in the repo). Also rewraps comment lines over 80 columns left by the earlier batches. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
80 lines
3.2 KiB
Go
80 lines
3.2 KiB
Go
package api
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"net/http"
|
|
|
|
"git.fabledsword.com/bvandeusen/minstrel/internal/apierror"
|
|
"git.fabledsword.com/bvandeusen/minstrel/internal/library"
|
|
)
|
|
|
|
// fingerprintSettingsBody is the wire shape for GET and PUT
|
|
// /api/admin/library/fingerprint-settings. The threshold travels as the
|
|
// bit-error rate the matcher uses; the card presents it as a match percentage.
|
|
type fingerprintSettingsBody struct {
|
|
Enabled bool `json:"enabled"`
|
|
ChromaprintLengthSec int32 `json:"chromaprint_length_sec"`
|
|
AcousticMaxBitErrorRate float64 `json:"acoustic_max_bit_error_rate"`
|
|
BackfillConcurrency int32 `json:"backfill_concurrency"`
|
|
SweepIntervalHours int32 `json:"sweep_interval_hours"`
|
|
// AutoResolve is a pointer so a client that predates it and leaves
|
|
// it out keeps the saved value rather than switching the resolver off.
|
|
AutoResolve *bool `json:"auto_resolve"`
|
|
}
|
|
|
|
func fingerprintSettingsBodyOf(s library.FingerprintSettings) fingerprintSettingsBody {
|
|
return fingerprintSettingsBody{
|
|
Enabled: s.Enabled,
|
|
ChromaprintLengthSec: s.ChromaprintLengthSec,
|
|
AcousticMaxBitErrorRate: s.AcousticMaxBitErrorRate,
|
|
BackfillConcurrency: s.BackfillConcurrency,
|
|
SweepIntervalHours: s.SweepIntervalHours,
|
|
AutoResolve: &s.AutoResolve,
|
|
}
|
|
}
|
|
|
|
// handleGetFingerprintSettings implements GET
|
|
// /api/admin/library/fingerprint-settings.
|
|
func (h *handlers) handleGetFingerprintSettings(w http.ResponseWriter, _ *http.Request) {
|
|
writeJSON(w, http.StatusOK, fingerprintSettingsBodyOf(h.fingerprintSettings.Get()))
|
|
}
|
|
|
|
// handleUpdateFingerprintSettings implements PUT
|
|
// /api/admin/library/fingerprint-settings.
|
|
//
|
|
// A whole-row write. A body that leaves a field out decodes it as zero, which
|
|
// no field accepts, so a partial save is refused rather than zeroing what it
|
|
// omitted. auto_resolve is the exception: left out, it keeps its saved value.
|
|
// The saved settings reach the scanner and both workers at once: they share the
|
|
// service instance.
|
|
func (h *handlers) handleUpdateFingerprintSettings(w http.ResponseWriter, r *http.Request) {
|
|
var req fingerprintSettingsBody
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
writeErr(w, apierror.BadRequest("invalid_body", "malformed JSON"))
|
|
return
|
|
}
|
|
autoResolve := h.fingerprintSettings.Get().AutoResolve
|
|
if req.AutoResolve != nil {
|
|
autoResolve = *req.AutoResolve
|
|
}
|
|
saved, err := h.fingerprintSettings.Set(r.Context(), library.FingerprintSettings{
|
|
Enabled: req.Enabled,
|
|
ChromaprintLengthSec: req.ChromaprintLengthSec,
|
|
AcousticMaxBitErrorRate: req.AcousticMaxBitErrorRate,
|
|
BackfillConcurrency: req.BackfillConcurrency,
|
|
SweepIntervalHours: req.SweepIntervalHours,
|
|
AutoResolve: autoResolve,
|
|
})
|
|
if err != nil {
|
|
// Validation mirrors migration 0061's CHECKs and names the field.
|
|
if errors.Is(err, library.ErrFingerprintSettingOutOfRange) {
|
|
writeErr(w, apierror.BadRequest("invalid_setting", err.Error()))
|
|
return
|
|
}
|
|
writeErrWithLog(w, h.logger, "admin fingerprint settings: update failed", apierror.Internal(err))
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, fingerprintSettingsBodyOf(saved))
|
|
}
|