autobrr/internal/download_client/service.go
ze0s 604c7896bd
chore: add LICENSE GPLv2-or-later (#897)
* chore: add LICENSE

* chore: add LICENSE to README
2023-05-01 16:21:59 +02:00

188 lines
4.6 KiB
Go

// Copyright (c) 2021 - 2023, Ludvig Lundgren and the autobrr contributors.
// SPDX-License-Identifier: GPL-2.0-or-later
package download_client
import (
"context"
"log"
"sync"
"github.com/autobrr/autobrr/internal/domain"
"github.com/autobrr/autobrr/internal/logger"
"github.com/autobrr/go-qbittorrent"
"github.com/dcarbone/zadapters/zstdlog"
"github.com/rs/zerolog"
)
type Service interface {
List(ctx context.Context) ([]domain.DownloadClient, error)
FindByID(ctx context.Context, id int32) (*domain.DownloadClient, error)
Store(ctx context.Context, client domain.DownloadClient) (*domain.DownloadClient, error)
Update(ctx context.Context, client domain.DownloadClient) (*domain.DownloadClient, error)
Delete(ctx context.Context, clientID int) error
Test(ctx context.Context, client domain.DownloadClient) error
GetCachedClient(ctx context.Context, clientId int32) *domain.DownloadClientCached
}
type service struct {
log zerolog.Logger
repo domain.DownloadClientRepo
subLogger *log.Logger
qbitClients map[int32]*domain.DownloadClientCached
m sync.RWMutex
}
func NewService(log logger.Logger, repo domain.DownloadClientRepo) Service {
s := &service{
log: log.With().Str("module", "download_client").Logger(),
repo: repo,
qbitClients: map[int32]*domain.DownloadClientCached{},
m: sync.RWMutex{},
}
s.subLogger = zstdlog.NewStdLoggerWithLevel(s.log.With().Logger(), zerolog.TraceLevel)
return s
}
func (s *service) List(ctx context.Context) ([]domain.DownloadClient, error) {
clients, err := s.repo.List(ctx)
if err != nil {
s.log.Error().Err(err).Msg("could not list download clients")
return nil, err
}
return clients, nil
}
func (s *service) FindByID(ctx context.Context, id int32) (*domain.DownloadClient, error) {
client, err := s.repo.FindByID(ctx, id)
if err != nil {
s.log.Error().Err(err).Msgf("could not find download client by id: %v", id)
return nil, err
}
return client, nil
}
func (s *service) Store(ctx context.Context, client domain.DownloadClient) (*domain.DownloadClient, error) {
// basic validation of client
if err := client.Validate(); err != nil {
return nil, err
}
// store
c, err := s.repo.Store(ctx, client)
if err != nil {
s.log.Error().Err(err).Msgf("could not store download client: %+v", client)
return nil, err
}
return c, err
}
func (s *service) Update(ctx context.Context, client domain.DownloadClient) (*domain.DownloadClient, error) {
// basic validation of client
if err := client.Validate(); err != nil {
return nil, err
}
// update
c, err := s.repo.Update(ctx, client)
if err != nil {
s.log.Error().Err(err).Msgf("could not update download client: %+v", client)
return nil, err
}
if client.Type == domain.DownloadClientTypeQbittorrent {
s.m.Lock()
delete(s.qbitClients, int32(client.ID))
s.m.Unlock()
}
return c, err
}
func (s *service) Delete(ctx context.Context, clientID int) error {
if err := s.repo.Delete(ctx, clientID); err != nil {
s.log.Error().Err(err).Msgf("could not delete download client: %v", clientID)
return err
}
s.m.Lock()
delete(s.qbitClients, int32(clientID))
s.m.Unlock()
return nil
}
func (s *service) Test(ctx context.Context, client domain.DownloadClient) error {
// basic validation of client
if err := client.Validate(); err != nil {
return err
}
// test
if err := s.testConnection(ctx, client); err != nil {
s.log.Error().Err(err).Msg("client connection test error")
return err
}
return nil
}
func (s *service) GetCachedClient(ctx context.Context, clientId int32) *domain.DownloadClientCached {
// check if client exists in cache
s.m.RLock()
cached, ok := s.qbitClients[clientId]
s.m.RUnlock()
if ok {
return cached
}
// get client for action
client, err := s.FindByID(ctx, clientId)
if err != nil {
return nil
}
if client == nil {
return nil
}
qbtSettings := qbittorrent.Config{
Host: client.BuildLegacyHost(),
Username: client.Username,
Password: client.Password,
TLSSkipVerify: client.TLSSkipVerify,
}
// setup sub logger adapter which is compatible with *log.Logger
qbtSettings.Log = zstdlog.NewStdLoggerWithLevel(s.log.With().Str("type", "qBittorrent").Str("client", client.Name).Logger(), zerolog.TraceLevel)
// only set basic auth if enabled
if client.Settings.Basic.Auth {
qbtSettings.BasicUser = client.Settings.Basic.Username
qbtSettings.BasicPass = client.Settings.Basic.Password
}
qc := &domain.DownloadClientCached{
Dc: client,
Qbt: qbittorrent.NewClient(qbtSettings),
}
cached = qc
s.m.Lock()
s.qbitClients[clientId] = cached
s.m.Unlock()
return cached
}