goshort/internal/service/shortlog/shortlogservice.go

106 lines
2.3 KiB
Go

package shortlogservice
import (
"context"
"fmt"
"log/slog"
"net/http"
"time"
"git.maronato.dev/maronato/goshort/internal/storage"
"git.maronato.dev/maronato/goshort/internal/storage/models"
"git.maronato.dev/maronato/goshort/internal/util/logging"
)
const logChLength = 100
type ShortLogService struct {
db storage.Storage
logCh chan *models.ShortLog
// debugCh exposes the log channel to the tests
debugCh chan *models.ShortLog
}
func NewShortLogService(db storage.Storage) *ShortLogService {
logCh := make(chan *models.ShortLog, logChLength)
debugCh := make(chan *models.ShortLog)
return &ShortLogService{
db: db,
logCh: logCh,
debugCh: debugCh,
}
}
func (s *ShortLogService) StartWorker(ctx context.Context) (stopWorker context.CancelFunc, debugCh <-chan *models.ShortLog) {
workerCtx, stopWorker := context.WithCancel(ctx)
// Start the goroutine
go s.shortLogWorker(workerCtx)
debugCh = s.debugCh
return stopWorker, debugCh
}
func (s *ShortLogService) shortLogWorker(ctx context.Context) {
l := logging.FromCtx(ctx)
l.Debug("starting short log worker")
for {
select {
case <-ctx.Done():
l.Debug("stopping short log worker")
return
case shortLog := <-s.logCh:
l.Debug("writing short log to storage", slog.String("short_id", shortLog.ShortID))
err := s.db.CreateShortLog(ctx, shortLog)
select {
case s.debugCh <- shortLog:
default:
l.Warn("short log debug queue is full, dropping log")
}
if err != nil {
l.Warn("failed to log short access", "error", err)
}
}
}
}
func (s *ShortLogService) LogShortAccess(ctx context.Context, short *models.Short, r *http.Request) {
l := logging.FromCtx(ctx)
// Log the access
shortLog := &models.ShortLog{
ShortID: short.ID,
IPAddress: r.RemoteAddr,
UserAgent: r.UserAgent(),
Referer: r.Referer(),
CreatedAt: time.Now(),
}
l.Debug("adding short log to queue", slog.String("short_id", short.ID))
// Send the log to the channel
select {
case s.logCh <- shortLog:
default:
l.Warn("short log queue is full, dropping log")
}
}
func (s *ShortLogService) ListLogs(ctx context.Context, short *models.Short) ([]*models.ShortLog, error) {
// Get the logs from storage
logs, err := s.db.ListShortLogs(ctx, short)
if err != nil {
return nil, fmt.Errorf("failed to get short logs from storage: %w", err)
}
return logs, nil
}