mirror of
https://github.com/J3vb/OwnCord.git
synced 2026-09-03 03:50:00 +03:00
fix(server): resolve golangci-lint contextcheck, errcheck, gocritic findings
contextcheck: add ctx context.Context as first param to ListVisibleChannels,
BlockUser, CreateDM, CreateInvite, UpdateProfile, SendMessage; pass r.Context()
from HTTP handlers and ctx from WS handler; replace context.Background() in
telemetry spans with the propagated ctx.
errcheck: suppress justified Close() errors — defer func(){ _ = rows.Close() }()
in sqlite_events.go (idiomatic; rows.Err() checked), _ = resp.Body.Close() in
host_http.go (body fully consumed), _ = f.Close() in host_ui.go (read-only fd).
gocritic/rangeValCopy: rewrite for _, ch := range all (line 60) to indexed loop
in ChannelService.ListVisibleChannels to avoid 144-byte per-iteration copy.
This commit is contained in:
@@ -76,7 +76,7 @@ func handleListChannels(svc *service.Services) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
channels, err := svc.Channels.ListVisibleChannels(user.ID)
|
||||
channels, err := svc.Channels.ListVisibleChannels(r.Context(), user.ID)
|
||||
if err != nil {
|
||||
slog.Error("handleListChannels", "err", err)
|
||||
writeJSON(w, http.StatusInternalServerError, errorResponse{
|
||||
|
||||
@@ -73,7 +73,7 @@ func handleCreateDM(svc *service.Services) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
result, err := svc.DMs.CreateDM(user.ID, req.RecipientID)
|
||||
result, err := svc.DMs.CreateDM(r.Context(), user.ID, req.RecipientID)
|
||||
if err != nil {
|
||||
writeServiceError(w, err)
|
||||
return
|
||||
@@ -169,7 +169,7 @@ func handleBlockUser(svc *service.Services) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
if err := svc.Blocks.BlockUser(user.ID, targetID); err != nil {
|
||||
if err := svc.Blocks.BlockUser(r.Context(), user.ID, targetID); err != nil {
|
||||
writeServiceError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ func handleCreateInvite(svc *service.Services) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
inv, err := svc.Invites.CreateInvite(user.ID, req.MaxUses, req.ExpiresInHours)
|
||||
inv, err := svc.Invites.CreateInvite(r.Context(), user.ID, req.MaxUses, req.ExpiresInHours)
|
||||
if err != nil {
|
||||
writeServiceError(w, err)
|
||||
return
|
||||
|
||||
@@ -133,7 +133,7 @@ func handleUpdateProfile(svc *service.Services, broadcaster ProfileBroadcaster)
|
||||
req.Avatar = &trimmed
|
||||
}
|
||||
|
||||
updated, err := svc.Users.UpdateProfile(user.ID, req.Username, req.Avatar)
|
||||
updated, err := svc.Users.UpdateProfile(r.Context(), user.ID, req.Username, req.Avatar)
|
||||
if err != nil {
|
||||
writeServiceError(w, err)
|
||||
return
|
||||
|
||||
@@ -120,7 +120,7 @@ func (r *Registry) HTTPDo(ctx context.Context, inst *Instance, req HTTPRequest)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("plugin http: do: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
defer func() { _ = resp.Body.Close() }()
|
||||
// Cap body size so a hostile/large response cannot OOM the host. We
|
||||
// LimitReader to maxResponseBytes+1 so we can detect truncation.
|
||||
limited := io.LimitReader(resp.Body, maxResponseBytes+1)
|
||||
|
||||
@@ -98,7 +98,7 @@ func (r *Registry) AssetHandler(inst *Instance) http.Handler {
|
||||
http.NotFound(w, req)
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
defer func() { _ = f.Close() }()
|
||||
http.ServeContent(w, req, rel, info.ModTime(), f)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -22,8 +22,8 @@ func NewBlockService(st store.Store) *BlockService {
|
||||
|
||||
// BlockUser blocks a target user. Validates the target exists and
|
||||
// prevents self-blocking.
|
||||
func (s *BlockService) BlockUser(blockerID, targetID int64) error {
|
||||
ctx, span := telemetry.GlobalTracer("service/block").Start(context.Background(), "BlockService.BlockUser",
|
||||
func (s *BlockService) BlockUser(ctx context.Context, blockerID, targetID int64) error {
|
||||
ctx, span := telemetry.GlobalTracer("service/block").Start(ctx, "BlockService.BlockUser",
|
||||
telemetry.Int64("blocker_id", blockerID),
|
||||
telemetry.Int64("target_id", targetID),
|
||||
)
|
||||
|
||||
@@ -29,9 +29,9 @@ func NewChannelService(st store.Store, perms *PermissionService) *ChannelService
|
||||
|
||||
// ListVisibleChannels returns channels the user has ReadMessages permission for.
|
||||
// DM channels are excluded (they are accessed via DMService).
|
||||
func (s *ChannelService) ListVisibleChannels(userID int64) ([]db.Channel, error) {
|
||||
func (s *ChannelService) ListVisibleChannels(ctx context.Context, userID int64) ([]db.Channel, error) {
|
||||
// Phase B Step 8 — span the public service entrypoint.
|
||||
ctx, span := telemetry.GlobalTracer("service/channel").Start(context.Background(),
|
||||
ctx, span := telemetry.GlobalTracer("service/channel").Start(ctx,
|
||||
"ChannelService.ListVisibleChannels",
|
||||
telemetry.Int64("user_id", userID),
|
||||
)
|
||||
@@ -57,9 +57,9 @@ func (s *ChannelService) ListVisibleChannels(userID int64) ([]db.Channel, error)
|
||||
if isAdmin {
|
||||
// Admin sees all non-DM channels.
|
||||
var visible []db.Channel
|
||||
for _, ch := range all {
|
||||
if ch.Type != "dm" {
|
||||
visible = append(visible, ch)
|
||||
for i := range all {
|
||||
if all[i].Type != "dm" {
|
||||
visible = append(visible, all[i])
|
||||
}
|
||||
}
|
||||
return visible, nil
|
||||
|
||||
@@ -30,8 +30,8 @@ type CreateDMResult struct {
|
||||
|
||||
// CreateDM creates or retrieves a DM channel between two users.
|
||||
// Validates that neither user has blocked the other.
|
||||
func (s *DMService) CreateDM(userID, recipientID int64) (*CreateDMResult, error) {
|
||||
ctx, span := telemetry.GlobalTracer("service/dm").Start(context.Background(), "DMService.CreateDM",
|
||||
func (s *DMService) CreateDM(ctx context.Context, userID, recipientID int64) (*CreateDMResult, error) {
|
||||
ctx, span := telemetry.GlobalTracer("service/dm").Start(ctx, "DMService.CreateDM",
|
||||
telemetry.Int64("user_id", userID),
|
||||
telemetry.Int64("recipient_id", recipientID),
|
||||
)
|
||||
|
||||
@@ -27,8 +27,8 @@ const maxInviteExpiryHoursVal = 720
|
||||
func MaxInviteExpiryHours() int { return maxInviteExpiryHoursVal }
|
||||
|
||||
// CreateInvite creates a new invite code with optional max uses and expiry.
|
||||
func (s *InviteService) CreateInvite(createdBy int64, maxUses int, expiresInHours int) (*db.Invite, error) {
|
||||
ctx, span := telemetry.GlobalTracer("service/invite").Start(context.Background(), "InviteService.CreateInvite",
|
||||
func (s *InviteService) CreateInvite(ctx context.Context, createdBy int64, maxUses int, expiresInHours int) (*db.Invite, error) {
|
||||
ctx, span := telemetry.GlobalTracer("service/invite").Start(ctx, "InviteService.CreateInvite",
|
||||
telemetry.Int64("created_by", createdBy),
|
||||
)
|
||||
start := time.Now()
|
||||
|
||||
@@ -116,10 +116,10 @@ func NewMessageService(st store.Store, perms *PermissionService, limiter *auth.R
|
||||
|
||||
// SendMessage validates, persists, and prepares broadcast data for a new message.
|
||||
// Callers are responsible for emitting the appropriate events.
|
||||
func (s *MessageService) SendMessage(p SendMessageParams) (*SendMessageResult, error) {
|
||||
func (s *MessageService) SendMessage(ctx context.Context, p SendMessageParams) (*SendMessageResult, error) {
|
||||
// Phase B Step 8 — wrap the public service entrypoint in a tracing span
|
||||
// and a duration histogram. Both are no-ops in the default build.
|
||||
ctx, span := telemetry.GlobalTracer("service/message").Start(context.Background(), "MessageService.SendMessage",
|
||||
ctx, span := telemetry.GlobalTracer("service/message").Start(ctx, "MessageService.SendMessage",
|
||||
telemetry.Int64("user_id", p.UserID),
|
||||
telemetry.Int64("channel_id", p.ChannelID),
|
||||
)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -34,7 +35,7 @@ func newTestMessageService() (*MessageService, *store.MemStore) {
|
||||
func TestSendMessage_Valid(t *testing.T) {
|
||||
svc, _ := newTestMessageService()
|
||||
|
||||
result, err := svc.SendMessage(SendMessageParams{
|
||||
result, err := svc.SendMessage(context.Background(), SendMessageParams{
|
||||
ChannelID: 10,
|
||||
UserID: 1,
|
||||
Username: "alice",
|
||||
@@ -58,7 +59,7 @@ func TestSendMessage_Valid(t *testing.T) {
|
||||
func TestSendMessage_EmptyContent(t *testing.T) {
|
||||
svc, _ := newTestMessageService()
|
||||
|
||||
_, err := svc.SendMessage(SendMessageParams{
|
||||
_, err := svc.SendMessage(context.Background(), SendMessageParams{
|
||||
ChannelID: 10,
|
||||
UserID: 1,
|
||||
Username: "alice",
|
||||
@@ -79,7 +80,7 @@ func TestSendMessage_ExceedsMaxLength(t *testing.T) {
|
||||
// maxMessageLen is 4000 runes; create content that exceeds it.
|
||||
longContent := strings.Repeat("a", 4001)
|
||||
|
||||
_, err := svc.SendMessage(SendMessageParams{
|
||||
_, err := svc.SendMessage(context.Background(), SendMessageParams{
|
||||
ChannelID: 10,
|
||||
UserID: 1,
|
||||
Username: "alice",
|
||||
@@ -97,7 +98,7 @@ func TestSendMessage_ExceedsMaxLength(t *testing.T) {
|
||||
func TestSendMessage_ChannelNotFound(t *testing.T) {
|
||||
svc, _ := newTestMessageService()
|
||||
|
||||
_, err := svc.SendMessage(SendMessageParams{
|
||||
_, err := svc.SendMessage(context.Background(), SendMessageParams{
|
||||
ChannelID: 999,
|
||||
UserID: 1,
|
||||
Username: "alice",
|
||||
@@ -114,7 +115,7 @@ func TestSendMessage_ChannelNotFound(t *testing.T) {
|
||||
func TestSendMessage_InvalidChannelID(t *testing.T) {
|
||||
svc, _ := newTestMessageService()
|
||||
|
||||
_, err := svc.SendMessage(SendMessageParams{
|
||||
_, err := svc.SendMessage(context.Background(), SendMessageParams{
|
||||
ChannelID: 0,
|
||||
UserID: 1,
|
||||
Username: "alice",
|
||||
@@ -145,7 +146,7 @@ func TestSendMessage_NoPermission(t *testing.T) {
|
||||
permSvc := NewPermissionService(ms, checker)
|
||||
svc := NewMessageService(ms, permSvc, nil)
|
||||
|
||||
_, err := svc.SendMessage(SendMessageParams{
|
||||
_, err := svc.SendMessage(context.Background(), SendMessageParams{
|
||||
ChannelID: 10,
|
||||
UserID: 1,
|
||||
Username: "alice",
|
||||
@@ -163,7 +164,7 @@ func TestEditMessage_OwnerCanEdit(t *testing.T) {
|
||||
svc, _ := newTestMessageService()
|
||||
|
||||
// Send a message first.
|
||||
result, err := svc.SendMessage(SendMessageParams{
|
||||
result, err := svc.SendMessage(context.Background(), SendMessageParams{
|
||||
ChannelID: 10,
|
||||
UserID: 1,
|
||||
Username: "alice",
|
||||
@@ -192,7 +193,7 @@ func TestEditMessage_NonOwnerFails(t *testing.T) {
|
||||
ms.SeedUser(&db.User{ID: 2, Username: "bob"})
|
||||
|
||||
// User 1 sends a message.
|
||||
result, err := svc.SendMessage(SendMessageParams{
|
||||
result, err := svc.SendMessage(context.Background(), SendMessageParams{
|
||||
ChannelID: 10,
|
||||
UserID: 1,
|
||||
Username: "alice",
|
||||
@@ -215,7 +216,7 @@ func TestEditMessage_NonOwnerFails(t *testing.T) {
|
||||
func TestEditMessage_EmptyContentFails(t *testing.T) {
|
||||
svc, _ := newTestMessageService()
|
||||
|
||||
result, err := svc.SendMessage(SendMessageParams{
|
||||
result, err := svc.SendMessage(context.Background(), SendMessageParams{
|
||||
ChannelID: 10,
|
||||
UserID: 1,
|
||||
Username: "alice",
|
||||
@@ -237,7 +238,7 @@ func TestEditMessage_EmptyContentFails(t *testing.T) {
|
||||
func TestDeleteMessage_OwnerCanDelete(t *testing.T) {
|
||||
svc, _ := newTestMessageService()
|
||||
|
||||
result, err := svc.SendMessage(SendMessageParams{
|
||||
result, err := svc.SendMessage(context.Background(), SendMessageParams{
|
||||
ChannelID: 10,
|
||||
UserID: 1,
|
||||
Username: "alice",
|
||||
@@ -265,7 +266,7 @@ func TestDeleteMessage_NonOwnerWithoutModFails(t *testing.T) {
|
||||
ms.SeedUser(&db.User{ID: 2, Username: "bob"})
|
||||
|
||||
// User 1 sends.
|
||||
result, err := svc.SendMessage(SendMessageParams{
|
||||
result, err := svc.SendMessage(context.Background(), SendMessageParams{
|
||||
ChannelID: 10,
|
||||
UserID: 1,
|
||||
Username: "alice",
|
||||
@@ -312,7 +313,7 @@ func TestDeleteMessage_ModCanDeleteOthersMessage(t *testing.T) {
|
||||
svc := NewMessageService(ms, permSvc, nil)
|
||||
|
||||
// User 1 sends a message.
|
||||
result, err := svc.SendMessage(SendMessageParams{
|
||||
result, err := svc.SendMessage(context.Background(), SendMessageParams{
|
||||
ChannelID: 10,
|
||||
UserID: 1,
|
||||
Username: "alice",
|
||||
@@ -347,7 +348,7 @@ func TestDeleteMessage_InvalidMessageID(t *testing.T) {
|
||||
func TestSendMessage_HTMLSanitized(t *testing.T) {
|
||||
svc, _ := newTestMessageService()
|
||||
|
||||
result, err := svc.SendMessage(SendMessageParams{
|
||||
result, err := svc.SendMessage(context.Background(), SendMessageParams{
|
||||
ChannelID: 10,
|
||||
UserID: 1,
|
||||
Username: "alice",
|
||||
|
||||
@@ -24,8 +24,8 @@ func NewUserService(st store.Store) *UserService {
|
||||
|
||||
// UpdateProfile updates a user's username and/or avatar.
|
||||
// Returns the updated user for response building.
|
||||
func (s *UserService) UpdateProfile(userID int64, username string, avatar *string) (*db.User, error) {
|
||||
ctx, span := telemetry.GlobalTracer("service/user").Start(context.Background(), "UserService.UpdateProfile",
|
||||
func (s *UserService) UpdateProfile(ctx context.Context, userID int64, username string, avatar *string) (*db.User, error) {
|
||||
ctx, span := telemetry.GlobalTracer("service/user").Start(ctx, "UserService.UpdateProfile",
|
||||
telemetry.Int64("user_id", userID),
|
||||
)
|
||||
start := time.Now()
|
||||
|
||||
@@ -40,7 +40,7 @@ func (s *SQLiteStore) GetEventsSince(ctx context.Context, afterSeq int64, limit
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("GetEventsSince: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
return scanEventRows(rows)
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ func (s *SQLiteStore) GetEventsSinceForChannels(ctx context.Context, afterSeq in
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("GetEventsSinceForChannels (global only): %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
return scanEventRows(rows)
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ func (s *SQLiteStore) GetEventsSinceForChannels(ctx context.Context, afterSeq in
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("GetEventsSinceForChannels: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
return scanEventRows(rows)
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ func (s *SQLiteStore) ListPlugins(ctx context.Context) ([]db.PluginRow, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ListPlugins: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
var out []db.PluginRow
|
||||
for rows.Next() {
|
||||
var p db.PluginRow
|
||||
@@ -233,7 +233,7 @@ func (s *SQLiteStore) PluginKVScan(ctx context.Context, pluginID int64, prefix s
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("PluginKVScan: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
out := make(map[string][]byte)
|
||||
for rows.Next() {
|
||||
var k string
|
||||
|
||||
@@ -15,11 +15,11 @@ func registerChatHandlers(r *HandlerRegistry, deps ChatDeps) {
|
||||
}
|
||||
|
||||
// handleChatSendV2 processes a chat_send command via the MessageService.
|
||||
func handleChatSendV2(_ context.Context, cmd Command, info ClientInfo, deps any) Result {
|
||||
func handleChatSendV2(ctx context.Context, cmd Command, info ClientInfo, deps any) Result {
|
||||
d := deps.(ChatDeps)
|
||||
sendCmd := cmd.(ChatSendCmd)
|
||||
|
||||
result, err := d.MessageSvc.SendMessage(service.SendMessageParams{
|
||||
result, err := d.MessageSvc.SendMessage(ctx, service.SendMessageParams{
|
||||
ChannelID: sendCmd.ChannelID(),
|
||||
UserID: info.UserID,
|
||||
Username: info.Username,
|
||||
|
||||
Reference in New Issue
Block a user