fix: handle close errors

This commit is contained in:
2026-05-12 16:05:36 +02:00
parent 31796543c2
commit b03e90fc47
15 changed files with 36 additions and 33 deletions

View File

@@ -88,7 +88,7 @@ func (c *allAnimeClient) graphqlRequest(ctx context.Context, query string, varia
if err != nil {
return nil, fmt.Errorf("execute graphql request: %w", err)
}
defer resp.Body.Close()
defer func() { _ = resp.Body.Close() }()
respBody, err := io.ReadAll(io.LimitReader(resp.Body, 2*1024*1024))
if err != nil {
@@ -143,7 +143,7 @@ func (c *allAnimeClient) graphqlRequestWithHash(ctx context.Context, showID, epi
if err != nil {
return nil, fmt.Errorf("execute GET request: %w", err)
}
defer resp.Body.Close()
defer func() { _ = resp.Body.Close() }()
respBody, err := io.ReadAll(io.LimitReader(resp.Body, 2*1024*1022))
if err != nil {

View File

@@ -243,7 +243,7 @@ func (h *Handler) HandleProxy(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(statusCode)
if bodyReader != nil {
defer bodyReader.Close()
defer func() { _ = bodyReader.Close() }()
_, _ = io.Copy(w, bodyReader)
} else {
_, _ = w.Write(content)
@@ -389,7 +389,7 @@ func (h *Handler) HandleEpisodeData(w http.ResponseWriter, r *http.Request) {
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]any{
if err := writeJSON(w, map[string]any{
"mal_id": watchData.MalID,
"title": watchData.Title,
"current_episode": watchData.CurrentEpisode,
@@ -400,7 +400,9 @@ func (h *Handler) HandleEpisodeData(w http.ResponseWriter, r *http.Request) {
"mode_sources": watchData.ModeSources,
"segments": watchData.Segments,
"episode_title": "", // Find episode title if possible
})
}); err != nil {
log.Printf("watch page encode error: %v", err)
}
}
// HandleEpisodeThumbnails returns episode list for the thumbnail strip.
@@ -459,5 +461,11 @@ func (h *Handler) HandleEpisodeThumbnails(w http.ResponseWriter, r *http.Request
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(results)
if err := writeJSON(w, results); err != nil {
log.Printf("thumbnails encode error: %v", err)
}
}
func writeJSON(w http.ResponseWriter, v any) error {
return json.NewEncoder(w).Encode(v)
}

View File

@@ -23,7 +23,7 @@ func (s *Service) SaveProgress(ctx context.Context, userID string, animeID int64
return err
}
defer tx.Rollback()
defer func() { _ = tx.Rollback() }()
if animeSeed != nil {
if _, err := txQueries.UpsertAnime(ctx, *animeSeed); err != nil {
@@ -89,7 +89,7 @@ func (s *Service) CompleteAnime(ctx context.Context, userID string, animeID int6
return err
}
defer tx.Rollback()
defer func() { _ = tx.Rollback() }()
watchListEntry, watchListErr := txQueries.GetWatchListEntry(ctx, db.GetWatchListEntryParams{
UserID: userID,

View File

@@ -51,7 +51,7 @@ func (e *providerExtractor) ExtractVideoLinks(ctx context.Context, providerPath
}
}
defer resp.Body.Close()
defer func() { _ = resp.Body.Close() }()
body, err := io.ReadAll(io.LimitReader(resp.Body, 2*1024*1024)) // 2MB limit
if err != nil {
@@ -155,7 +155,7 @@ func (e *providerExtractor) parseM3U8(ctx context.Context, masterURL string, ref
if err != nil {
return nil, err
}
defer resp.Body.Close()
defer func() { _ = resp.Body.Close() }()
body, err := io.ReadAll(io.LimitReader(resp.Body, 512*1024)) // 512KB limit
if err != nil {

View File

@@ -23,7 +23,7 @@ func (s *Service) fetchSkipSegments(ctx context.Context, malID int, episode stri
if err != nil {
return nil
}
defer resp.Body.Close()
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK {
return nil

View File

@@ -59,7 +59,7 @@ func (s *Service) handleProxyResponse(ctx context.Context, resp *http.Response,
// check if response is an m3u8 playlist that needs rewriting
if isM3U8(targetURL, resp.Header.Get("Content-Type")) {
defer resp.Body.Close()
defer func() { _ = resp.Body.Close() }()
body, readErr := io.ReadAll(io.LimitReader(resp.Body, 2*1024*1024))
if readErr != nil {
return 0, nil, nil, nil, fmt.Errorf("read playlist failed: %w", readErr)

View File

@@ -140,7 +140,7 @@ func (s *Service) probeDirectMedia(ctx context.Context, source StreamSource) (bo
if err != nil {
return false, ""
}
defer resp.Body.Close()
defer func() { _ = resp.Body.Close() }()
// check content-type header first
contentType := strings.ToLower(resp.Header.Get("Content-Type"))
@@ -192,7 +192,7 @@ func (s *Service) probeEmbedSource(ctx context.Context, source StreamSource) boo
if err != nil {
return false
}
defer resp.Body.Close()
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode >= http.StatusBadRequest {
return false

View File

@@ -171,7 +171,7 @@ func (s *Service) DeleteContinueWatching(ctx context.Context, userID string, ani
if err != nil {
return fmt.Errorf("failed to begin transaction: %w", err)
}
defer tx.Rollback()
defer func() { _ = tx.Rollback() }()
if err := txQueries.DeleteContinueWatchingEntry(ctx, params); err != nil {
return fmt.Errorf("failed to delete continue watching entry: %w", err)

View File

@@ -26,7 +26,7 @@ func main() {
if err != nil {
log.Fatalf("failed to open db: %v", err)
}
defer dbConn.Close()
defer func() { _ = dbConn.Close() }()
queries, err := db.Init(dbConn)
if err != nil {

View File

@@ -18,7 +18,7 @@ func main() {
if err != nil {
log.Fatalf("failed to open db: %v", err)
}
defer dbConn.Close()
defer func() { _ = dbConn.Close() }()
if len(os.Args) == 2 && os.Args[1] == "update-avatar" {
updateAvatars(dbConn)
@@ -83,7 +83,7 @@ func updateAvatars(dbConn *sql.DB) {
if err != nil {
log.Fatalf("failed to fetch users: %v", err)
}
defer rows.Close()
defer func() { _ = rows.Close() }()
count := 0
for rows.Next() {

View File

@@ -236,11 +236,6 @@ func (c *Client) setCache(parentCtx context.Context, key string, data any, ttl t
})
}
type cacheResult struct {
data any
hasStale bool
}
// isEmptyResult detects if response contains no meaningful data.
func isEmptyResult(out any) bool {
switch v := out.(type) {
@@ -336,7 +331,7 @@ func (c *Client) fetchWithRetry(ctx context.Context, urlStr string, out any) err
}
if retryable && attempt < maxRetries-1 {
resp.Body.Close()
_ = resp.Body.Close()
delay := max(retryAfter, retryDelay(attempt))
if retryErr := waitForRetry(ctx, delay); retryErr != nil {
@@ -347,7 +342,7 @@ func (c *Client) fetchWithRetry(ctx context.Context, urlStr string, out any) err
}
err = json.NewDecoder(resp.Body).Decode(out)
resp.Body.Close()
_ = resp.Body.Close()
if err == nil {
return nil
}
@@ -356,7 +351,7 @@ func (c *Client) fetchWithRetry(ctx context.Context, urlStr string, out any) err
}
err = json.NewDecoder(resp.Body).Decode(out)
resp.Body.Close()
_ = resp.Body.Close()
if err == nil {
return nil
}

View File

@@ -155,7 +155,7 @@ func (c *Client) GetFullRelations(ctx context.Context, id int) ([]RelationEntry,
}
go func() {
g.Wait()
_ = g.Wait()
close(results)
}()

View File

@@ -106,7 +106,7 @@ func fetchDocument(ctx context.Context, httpClient *http.Client, url string) (*g
if err != nil {
return nil, fmt.Errorf("request failed: %w", err)
}
defer response.Body.Close()
defer func() { _ = response.Body.Close() }()
if response.StatusCode != http.StatusOK {
// limit body read for error context; avoid reading large error pages
@@ -235,7 +235,7 @@ func fetchProxyText(ctx context.Context, httpClient *http.Client, url string) (s
if err != nil {
return "", fmt.Errorf("proxy request failed: %w", err)
}
defer response.Body.Close()
defer func() { _ = response.Body.Close() }()
if response.StatusCode != http.StatusOK {
return "", fmt.Errorf("proxy status %d", response.StatusCode)

View File

@@ -77,7 +77,7 @@ func loadAppliedMigrationNames(db *sql.DB) (map[string]struct{}, error) {
if err != nil {
return nil, err
}
defer rows.Close()
defer func() { _ = rows.Close() }()
applied := make(map[string]struct{})
for rows.Next() {

View File

@@ -38,7 +38,7 @@ func (rt *UtlsRoundTripper) RoundTrip(req *http.Request) (*http.Response, error)
}, utls.HelloFirefox_120)
if err := uconn.HandshakeContext(req.Context()); err != nil {
uconn.Close()
_ = uconn.Close()
return nil, fmt.Errorf("utls handshake: %w", err)
}
@@ -47,7 +47,7 @@ func (rt *UtlsRoundTripper) RoundTrip(req *http.Request) (*http.Response, error)
t := &http2.Transport{}
cc, err := t.NewClientConn(uconn)
if err != nil {
uconn.Close()
_ = uconn.Close()
return nil, fmt.Errorf("http2 client conn: %w", err)
}
return cc.RoundTrip(req)
@@ -55,7 +55,7 @@ func (rt *UtlsRoundTripper) RoundTrip(req *http.Request) (*http.Response, error)
// Fallback to HTTP/1.1
if err := req.Write(uconn); err != nil {
uconn.Close()
_ = uconn.Close()
return nil, fmt.Errorf("http1 write: %w", err)
}
return http.ReadResponse(bufio.NewReader(uconn), req)