From ccabeee1f1fa3955b32139d1f5bdff1b92db0f80 Mon Sep 17 00:00:00 2001 From: Anton Vakhrushev Date: Thu, 12 Feb 2026 18:00:32 +0300 Subject: [PATCH] fix golint errors --- .golangci.yml | 34 ++++++++++++++++++++++++++++++++++ cmd/remembos/main.go | 22 ++++++++++++++-------- internal/memos/client.go | 4 ++-- internal/search/scoring.go | 2 +- internal/search/selector.go | 9 +++------ internal/storage/history.go | 2 +- internal/storage/storage.go | 2 +- internal/telegram/bot.go | 11 ++++++++--- internal/telegram/format.go | 2 +- internal/web/handler.go | 14 +++++++++----- 10 files changed, 74 insertions(+), 28 deletions(-) create mode 100644 .golangci.yml diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..b59dc44 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,34 @@ +linters: + enable: + - bodyclose + - errcheck + - errorlint + - goconst + - gocritic + - gofmt + - gosec + - gosimple + - govet + - ineffassign + - misspell + - noctx + - prealloc + - revive + - staticcheck + - typecheck + - unconvert + - unparam + - unused + - wastedassign + +linters-settings: + gocritic: + enabled-tags: + - diagnostic + - style + - performance + revive: + rules: + - name: blank-imports + - name: exported + disabled: true diff --git a/cmd/remembos/main.go b/cmd/remembos/main.go index d098272..4df63f0 100644 --- a/cmd/remembos/main.go +++ b/cmd/remembos/main.go @@ -63,7 +63,7 @@ func main() { client := memos.NewClient(cfg.Memos.URL, cfg.Memos.Token) // Search selector - selector := search.NewSelector(client, store, cfg.Search, loc, logger) + selector := search.NewSelector(client, store, &cfg.Search, loc, logger) // Memory service memorySvc := memory.NewService(selector, store, loc, logger) @@ -71,6 +71,18 @@ func main() { // Web handler handler := web.NewHandler(memorySvc, cfg.Memos.URL, cfg.Memos.PublicURL, cfg.General.AllowLoadMore, logger) + // Telegram bot + var tgBot *telegram.Bot + if cfg.Telegram.Enabled { + var err error + tgBot, err = telegram.NewBot(cfg.Telegram, memorySvc, client, cfg.Memos.URL, cfg.Memos.PublicURL, cfg.General.AllowLoadMore, loc, logger) + if err != nil { + logger.Error("failed to create telegram bot", "error", err) + store.Close() + os.Exit(1) //nolint:gocritic // store.Close() called above; linter doesn't track manual cleanup + } + } + // HTTP server srv := &http.Server{ Addr: cfg.Web.Listen, @@ -84,13 +96,7 @@ func main() { ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) defer stop() - // Telegram bot - if cfg.Telegram.Enabled { - tgBot, err := telegram.NewBot(cfg.Telegram, memorySvc, client, cfg.Memos.URL, cfg.Memos.PublicURL, cfg.General.AllowLoadMore, loc, logger) - if err != nil { - logger.Error("failed to create telegram bot", "error", err) - os.Exit(1) - } + if tgBot != nil { go tgBot.Run(ctx) } diff --git a/internal/memos/client.go b/internal/memos/client.go index d03225b..f48d9db 100644 --- a/internal/memos/client.go +++ b/internal/memos/client.go @@ -43,7 +43,7 @@ func (c *Client) ListMemos(ctx context.Context, filter string, pageSize int, pag } u.RawQuery = q.Encode() - req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), http.NoBody) if err != nil { return nil, fmt.Errorf("create request: %w", err) } @@ -79,7 +79,7 @@ func (c *Client) DownloadAttachment(ctx context.Context, att Attachment) ([]byte needsAuth = true } - req, err := http.NewRequestWithContext(ctx, http.MethodGet, reqURL, nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, reqURL, http.NoBody) if err != nil { return nil, fmt.Errorf("create request: %w", err) } diff --git a/internal/search/scoring.go b/internal/search/scoring.go index 440ec2b..33bb567 100644 --- a/internal/search/scoring.go +++ b/internal/search/scoring.go @@ -54,7 +54,7 @@ func weightedSelect(candidates []candidate, preferOlder bool, maxYearsBack int) total += score } - r := rand.Float64() * total + r := rand.Float64() * total //nolint:gosec // non-cryptographic use var cumulative float64 for i, s := range scores { cumulative += s diff --git a/internal/search/selector.go b/internal/search/selector.go index 7995779..df19f1d 100644 --- a/internal/search/selector.go +++ b/internal/search/selector.go @@ -22,19 +22,16 @@ type Selector struct { logger *slog.Logger } -func NewSelector(client *memos.Client, store *storage.Storage, cfg config.SearchConfig, loc *time.Location, logger *slog.Logger) *Selector { +func NewSelector(client *memos.Client, store *storage.Storage, cfg *config.SearchConfig, loc *time.Location, logger *slog.Logger) *Selector { return &Selector{ client: client, store: store, - cfg: cfg, + cfg: *cfg, loc: loc, logger: logger, } } -// tierFunc returns date ranges for a given tier. -type tierFunc func(today time.Time, maxYears int, loc *time.Location) []DateRange - // Select runs the full search algorithm and returns one Memory for the given day. func (s *Selector) Select(ctx context.Context, today time.Time) (*Memory, error) { weights := s.cfg.TierWeights.AsSlice() @@ -248,7 +245,7 @@ func weightedTierOrder(weights [7]int) []int { break } - r := rand.IntN(totalWeight) + r := rand.IntN(totalWeight) //nolint:gosec // non-cryptographic use cumulative := 0 for i, e := range remaining { cumulative += e.weight diff --git a/internal/storage/history.go b/internal/storage/history.go index f1b5e1d..8d0cac0 100644 --- a/internal/storage/history.go +++ b/internal/storage/history.go @@ -43,7 +43,7 @@ func (s *Storage) GetShowCounts(ctx context.Context, memoNames []string) (map[st args[i] = name } - query := fmt.Sprintf( + query := fmt.Sprintf( //nolint:gosec // placeholders are always "?" `SELECT memo_name, COUNT(*) FROM show_history WHERE memo_name IN (%s) GROUP BY memo_name`, strings.Join(placeholders, ",")) diff --git a/internal/storage/storage.go b/internal/storage/storage.go index b24f92b..0e5c302 100644 --- a/internal/storage/storage.go +++ b/internal/storage/storage.go @@ -5,7 +5,7 @@ import ( "database/sql" "fmt" - _ "modernc.org/sqlite" + _ "modernc.org/sqlite" // SQLite driver ) type Storage struct { diff --git a/internal/telegram/bot.go b/internal/telegram/bot.go index 4d2ae99..16dbd61 100644 --- a/internal/telegram/bot.go +++ b/internal/telegram/bot.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "log/slog" + "strconv" "strings" "time" @@ -93,8 +94,12 @@ func (b *Bot) nextSendTime() time.Time { hour := 9 minute := 0 if len(parts) == 2 { - fmt.Sscanf(parts[0], "%d", &hour) - fmt.Sscanf(parts[1], "%d", &minute) + if h, err := strconv.Atoi(parts[0]); err == nil { + hour = h + } + if m, err := strconv.Atoi(parts[1]); err == nil { + minute = m + } } target := time.Date(now.Year(), now.Month(), now.Day(), hour, minute, 0, 0, b.loc) @@ -185,7 +190,7 @@ type imageFile struct { // downloadImages downloads image attachments, skipping failures. func (b *Bot) downloadImages(ctx context.Context, attachments []memos.Attachment) []imageFile { - var files []imageFile + files := make([]imageFile, 0, len(attachments)) for _, att := range attachments { data, err := b.client.DownloadAttachment(ctx, att) if err != nil { diff --git a/internal/telegram/format.go b/internal/telegram/format.go index 75023e5..cc029cd 100644 --- a/internal/telegram/format.go +++ b/internal/telegram/format.go @@ -41,7 +41,7 @@ func formatMemory(mem *search.Memory, publicURL string) (mainText, captionText s // Link to original memoURL := fmt.Sprintf("%s/%s", publicURL, mem.Memo.Name) - b.WriteString(fmt.Sprintf("\n\nОригинал", memoURL)) + b.WriteString("\n\nОригинал") full := b.String() mainText = truncateHTML(full, maxMessageLen) diff --git a/internal/web/handler.go b/internal/web/handler.go index bf7c171..04a4c06 100644 --- a/internal/web/handler.go +++ b/internal/web/handler.go @@ -80,21 +80,25 @@ func (h *Handler) handleMemory(w http.ResponseWriter, r *http.Request) { if err != nil { h.logger.Error("failed to get memory", "error", err) w.WriteHeader(http.StatusInternalServerError) - templates.ExecuteTemplate(w, "error.html", errorData{ + if err := templates.ExecuteTemplate(w, "error.html", errorData{ Message: "Не удалось загрузить воспоминание", - }) + }); err != nil { + h.logger.Error("template render failed", "error", err) + } return } if mem == nil { w.WriteHeader(http.StatusOK) - templates.ExecuteTemplate(w, "error.html", errorData{ + if err := templates.ExecuteTemplate(w, "error.html", errorData{ Message: "Нет заметок для воспоминания", - }) + }); err != nil { + h.logger.Error("template render failed", "error", err) + } return } - var images []imageData + images := make([]imageData, 0, len(mem.Memo.Attachments)) for _, att := range mem.Memo.Attachments { if !att.IsImage() { continue