Skip to content

Commit c9a6fb9

Browse files
committed
fix(services): harden tracker rule updates, reannounce debounce, and instance selection
1 parent 8d2b3f3 commit c9a6fb9

4 files changed

Lines changed: 13 additions & 12 deletions

File tree

internal/api/handlers/tracker_rules.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"database/sql"
88
"encoding/json"
99
"errors"
10+
"fmt"
1011
"net/http"
1112
"strconv"
1213
"strings"
@@ -150,6 +151,11 @@ func (h *TrackerRuleHandler) Update(w http.ResponseWriter, r *http.Request) {
150151

151152
rule, err := h.store.Update(r.Context(), payload.toModel(instanceID, ruleID))
152153
if err != nil {
154+
if errors.Is(err, sql.ErrNoRows) {
155+
log.Error().Err(err).Int("instanceID", instanceID).Int("ruleID", ruleID).Msg("tracker rule not found for update")
156+
RespondError(w, http.StatusNotFound, "Tracker rule not found")
157+
return
158+
}
153159
log.Error().Err(err).Int("instanceID", instanceID).Int("ruleID", ruleID).Msg("failed to update tracker rule")
154160
RespondError(w, http.StatusInternalServerError, "Failed to update tracker rule")
155161
return
@@ -229,7 +235,7 @@ func parseInstanceID(w http.ResponseWriter, r *http.Request) (int, error) {
229235
instanceID, err := strconv.Atoi(instanceIDStr)
230236
if err != nil || instanceID <= 0 {
231237
RespondError(w, http.StatusBadRequest, "Invalid instance ID")
232-
return 0, err
238+
return 0, fmt.Errorf("invalid instance ID: %s", instanceIDStr)
233239
}
234240
return instanceID, nil
235241
}

internal/services/reannounce/service.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -341,9 +341,6 @@ func (s *Service) enqueue(instanceID int, hash string, torrentName string, track
341341
// Determine debounce window: aggressive uses retry interval; non-aggressive uses global cooldown.
342342
debounceWindow := s.cfg.DebounceWindow
343343
if isAggressive {
344-
if settings == nil {
345-
settings = models.DefaultInstanceReannounceSettings(instanceID)
346-
}
347344
if interval := time.Duration(settings.ReannounceIntervalSeconds) * time.Second; interval > 0 {
348345
debounceWindow = interval
349346
}

internal/services/trackerrules/service.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -254,9 +254,6 @@ func limitHashBatch(hashes []string, max int) [][]string {
254254

255255
func selectRule(torrent qbt.Torrent, rules []*models.TrackerRule, sm *qbittorrent.SyncManager) *models.TrackerRule {
256256
trackerDomains := collectTrackerDomains(torrent, sm)
257-
if len(trackerDomains) == 0 {
258-
return nil
259-
}
260257

261258
for _, rule := range rules {
262259
if !matchesTracker(rule.TrackerPattern, trackerDomains) {

web/src/pages/Services.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,15 @@ export function Services() {
2727

2828
const selectedInstanceId = useMemo(() => {
2929
const fromSearch = search.instanceId ? Number(search.instanceId) : undefined
30-
if (fromSearch && activeInstances.some((inst) => inst.id === fromSearch)) {
30+
const allInstances = instances ?? []
31+
if (fromSearch && allInstances.some((inst) => inst.id === fromSearch)) {
3132
return fromSearch
3233
}
33-
if (activeInstances.length > 0) {
34-
return activeInstances[0]?.id
34+
if (allInstances.length > 0) {
35+
return allInstances[0]?.id
3536
}
3637
return undefined
37-
}, [activeInstances, search.instanceId])
38+
}, [instances, search.instanceId])
3839

3940
const handleInstanceChange = (value: string) => {
4041
navigate({
@@ -74,7 +75,7 @@ export function Services() {
7475
</div>
7576
</SelectTrigger>
7677
<SelectContent>
77-
{instances.map((instance) => (
78+
{(instances ?? []).map((instance) => (
7879
<SelectItem key={instance.id} value={String(instance.id)}>
7980
<div className="flex items-center max-w-40 gap-2">
8081
<span className="truncate">{instance.name}</span>

0 commit comments

Comments
 (0)