106 lines
2.3 KiB
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
|
|
}
|