From 0bc6227427fe3fa7e0858f86858a3b280ad66f46 Mon Sep 17 00:00:00 2001 From: royalcat Date: Sun, 8 Sep 2024 21:39:11 +0300 Subject: [PATCH] qbittorrent tracing --- pkg/qbittorrent/application.go | 21 +++ pkg/qbittorrent/authentication.go | 12 +- pkg/qbittorrent/client.go | 39 ++++- pkg/qbittorrent/client_impl.go | 17 +- pkg/qbittorrent/client_pool.go | 53 ------ pkg/qbittorrent/log.go | 6 + pkg/qbittorrent/rss.go | 36 +++++ pkg/qbittorrent/sync.go | 6 + pkg/qbittorrent/torrent.go | 261 ++++++++++++++++++++++++------ pkg/qbittorrent/transfer.go | 24 +++ 10 files changed, 353 insertions(+), 122 deletions(-) delete mode 100644 pkg/qbittorrent/client_pool.go diff --git a/pkg/qbittorrent/application.go b/pkg/qbittorrent/application.go index 31daefd..3fa5587 100644 --- a/pkg/qbittorrent/application.go +++ b/pkg/qbittorrent/application.go @@ -240,6 +240,9 @@ type Preferences struct { } func (c *client) Version(ctx context.Context) (string, error) { + ctx, span := trace.Start(ctx, "qbittorrent.Application.Version") + defer span.End() + apiUrl := fmt.Sprintf("%s/api/v2/app/version", c.config.Address) result, err := c.doRequest(ctx, &requestData{ @@ -257,6 +260,9 @@ func (c *client) Version(ctx context.Context) (string, error) { } func (c *client) WebApiVersion(ctx context.Context) (string, error) { + ctx, span := trace.Start(ctx, "qbittorrent.Application.WebApiVersion") + defer span.End() + apiUrl := fmt.Sprintf("%s/api/v2/app/webapiVersion", c.config.Address) result, err := c.doRequest(ctx, &requestData{ url: apiUrl, @@ -273,6 +279,9 @@ func (c *client) WebApiVersion(ctx context.Context) (string, error) { } func (c *client) BuildInfo(ctx context.Context) (*BuildInfo, error) { + ctx, span := trace.Start(ctx, "qbittorrent.Application.BuildInfo") + defer span.End() + apiUrl := fmt.Sprintf("%s/api/v2/app/buildInfo", c.config.Address) result, err := c.doRequest(ctx, &requestData{ url: apiUrl, @@ -294,6 +303,9 @@ func (c *client) BuildInfo(ctx context.Context) (*BuildInfo, error) { } func (c *client) Shutdown(ctx context.Context) error { + ctx, span := trace.Start(ctx, "qbittorrent.Application.Shutdown") + defer span.End() + apiUrl := fmt.Sprintf("%s/api/v2/app/shutdown", c.config.Address) result, err := c.doRequest(ctx, &requestData{ method: http.MethodPost, @@ -311,6 +323,9 @@ func (c *client) Shutdown(ctx context.Context) error { } func (c *client) GetPreferences(ctx context.Context) (*Preferences, error) { + ctx, span := trace.Start(ctx, "qbittorrent.Application.GetPreferences") + defer span.End() + apiUrl := fmt.Sprintf("%s/api/v2/app/preferences", c.config.Address) result, err := c.doRequest(ctx, &requestData{ url: apiUrl, @@ -332,6 +347,9 @@ func (c *client) GetPreferences(ctx context.Context) (*Preferences, error) { } func (c *client) SetPreferences(ctx context.Context, prefs *Preferences) error { + ctx, span := trace.Start(ctx, "qbittorrent.Application.SetPreferences") + defer span.End() + apiUrl := fmt.Sprintf("%s/api/v2/app/setPreferences", c.config.Address) data, err := json.Marshal(prefs) if err != nil { @@ -359,6 +377,9 @@ func (c *client) SetPreferences(ctx context.Context, prefs *Preferences) error { } func (c *client) DefaultSavePath(ctx context.Context) (string, error) { + ctx, span := trace.Start(ctx, "qbittorrent.Application.DefaultSavePath") + defer span.End() + apiUrl := fmt.Sprintf("%s/api/v2/app/defaultSavePath", c.config.Address) result, err := c.doRequest(ctx, &requestData{ url: apiUrl, diff --git a/pkg/qbittorrent/authentication.go b/pkg/qbittorrent/authentication.go index eb91b2c..f975d7f 100644 --- a/pkg/qbittorrent/authentication.go +++ b/pkg/qbittorrent/authentication.go @@ -19,6 +19,9 @@ type Authentication interface { } func (c *client) Login(ctx context.Context) error { + ctx, span := trace.Start(ctx, "qbittorrent.Authentication.Login") + defer span.End() + if c.config.Username == "" || c.config.Password == "" { return errors.New("username or password is empty") } @@ -51,8 +54,8 @@ func (c *client) Login(ctx context.Context) error { return errors.New("login failed: " + string(result.body)) } - if c.cookieJar == nil { - c.cookieJar, err = cookiejar.New(nil) + if c.client.Jar == nil { + c.client.Jar, err = cookiejar.New(nil) if err != nil { return err } @@ -62,12 +65,15 @@ func (c *client) Login(ctx context.Context) error { if err != nil { return err } - c.cookieJar.SetCookies(u, result.cookies) + c.client.Jar.SetCookies(u, result.cookies) return nil } func (c *client) Logout(ctx context.Context) error { + ctx, span := trace.Start(ctx, "qbittorrent.Authentication.Logout") + defer span.End() + apiUrl := fmt.Sprintf("%s/api/v2/auth/logout", c.config.Address) result, err := c.doRequest(ctx, &requestData{ method: http.MethodPost, diff --git a/pkg/qbittorrent/client.go b/pkg/qbittorrent/client.go index 2ec6fba..fb259d6 100644 --- a/pkg/qbittorrent/client.go +++ b/pkg/qbittorrent/client.go @@ -1,6 +1,16 @@ package qbittorrent -import "context" +import ( + "context" + "crypto/tls" + "net" + "net/http" + "time" + + "go.opentelemetry.io/otel" +) + +var trace = otel.Tracer("git.kmsign.ru/royalcat/tstor/pkg/qbittorrent") // Client represents a qBittorrent client type Client interface { @@ -23,12 +33,12 @@ type Client interface { } func NewClient(ctx context.Context, cfg *Config) (Client, error) { - var c = &client{config: cfg, clientPool: newClientPool(cfg.ConnectionMaxIdles, cfg.ConnectionTimeout)} + var c = &client{config: cfg, client: newClient(cfg.ConnectionMaxIdles, cfg.ConnectionTimeout)} return c, nil } func LoginClient(ctx context.Context, cfg *Config) (Client, error) { - var c = &client{config: cfg, clientPool: newClientPool(cfg.ConnectionMaxIdles, cfg.ConnectionTimeout)} + var c = &client{config: cfg, client: newClient(cfg.ConnectionMaxIdles, cfg.ConnectionTimeout)} if err := c.Authentication().Login(ctx); err != nil { return nil, err } @@ -37,3 +47,26 @@ func LoginClient(ctx context.Context, cfg *Config) (Client, error) { } return c, nil } + +// newClient creates and returns a new clientPool +func newClient(maxIdle int, timeout time.Duration) *http.Client { + if maxIdle == 0 { + maxIdle = 128 + } + if timeout == 0 { + timeout = time.Second * 3 + } + + return &http.Client{ + Transport: &http.Transport{ + Proxy: http.ProxyFromEnvironment, + DialContext: (&net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + }).DialContext, + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + MaxIdleConns: maxIdle, + }, + Timeout: timeout, + } +} diff --git a/pkg/qbittorrent/client_impl.go b/pkg/qbittorrent/client_impl.go index 5151fd5..21d167d 100644 --- a/pkg/qbittorrent/client_impl.go +++ b/pkg/qbittorrent/client_impl.go @@ -5,7 +5,6 @@ import ( "fmt" "io" "net/http" - "net/http/cookiejar" "net/url" "strings" "time" @@ -27,9 +26,8 @@ type requestData struct { var _ Client = (*client)(nil) type client struct { - config *Config - clientPool *clientPool - cookieJar *cookiejar.Jar + config *Config + client *http.Client } func (c *client) Authentication() Authentication { @@ -81,13 +79,8 @@ func (c *client) doRequest(ctx context.Context, data *requestData) (*responseRes for key, value := range c.config.CustomHeaders { request.Header.Set(key, value) } - hc := c.clientPool.GetClient() - defer c.clientPool.ReleaseClient(hc) - if c.cookieJar != nil { - hc.Jar = c.cookieJar - } - resp, err := hc.Do(request) + resp, err := c.client.Do(request) if err != nil { return nil, err } @@ -102,14 +95,14 @@ func (c *client) doRequest(ctx context.Context, data *requestData) (*responseRes } func (c *client) cookies() (string, error) { - if c.cookieJar == nil { + if c.client.Jar == nil { return "", ErrNotLogin } u, err := url.Parse(c.config.Address) if err != nil { return "", err } - cookies := c.cookieJar.Cookies(u) + cookies := c.client.Jar.Cookies(u) if len(cookies) == 0 { return "", ErrNotLogin } diff --git a/pkg/qbittorrent/client_pool.go b/pkg/qbittorrent/client_pool.go deleted file mode 100644 index d390665..0000000 --- a/pkg/qbittorrent/client_pool.go +++ /dev/null @@ -1,53 +0,0 @@ -package qbittorrent - -import ( - "crypto/tls" - "net" - "net/http" - "sync" - "time" -) - -// clientPool defines a pool of HTTP clients -type clientPool struct { - // pool store http.Client instances - *sync.Pool -} - -// newClientPool creates and returns a new clientPool -func newClientPool(maxIdle int, timeout time.Duration) *clientPool { - if maxIdle == 0 { - maxIdle = 128 - } - if timeout == 0 { - timeout = time.Second * 3 - } - return &clientPool{ - Pool: &sync.Pool{ - New: func() any { - return &http.Client{ - Transport: &http.Transport{ - Proxy: http.ProxyFromEnvironment, - DialContext: (&net.Dialer{ - Timeout: 30 * time.Second, - KeepAlive: 30 * time.Second, - }).DialContext, - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - MaxIdleConns: maxIdle, - }, - Timeout: timeout, - } - }, - }, - } -} - -// GetClient retrieves a http.Client from the pool -func (p *clientPool) GetClient() *http.Client { - return p.Get().(*http.Client) -} - -// ReleaseClient returns a http.Client back to the pool -func (p *clientPool) ReleaseClient(client *http.Client) { - p.Put(client) -} diff --git a/pkg/qbittorrent/log.go b/pkg/qbittorrent/log.go index d81fbef..bfb7110 100644 --- a/pkg/qbittorrent/log.go +++ b/pkg/qbittorrent/log.go @@ -36,6 +36,9 @@ type Log interface { } func (c *client) GetLog(ctx context.Context, option *LogOption) ([]*LogEntry, error) { + ctx, span := trace.Start(ctx, "qbittorrent.Log.GetLog") + defer span.End() + var form = url.Values{} err := encoder.Encode(option, form) if err != nil { @@ -64,6 +67,9 @@ func (c *client) GetLog(ctx context.Context, option *LogOption) ([]*LogEntry, er } func (c *client) GetPeerLog(ctx context.Context, lastKnownId int) ([]*LogEntry, error) { + ctx, span := trace.Start(ctx, "qbittorrent.Log.GetPeerLog") + defer span.End() + apiUrl := fmt.Sprintf("%s/api/v2/log/peers", c.config.Address) var form = url.Values{} form.Add("last_known_id", strconv.Itoa(lastKnownId)) diff --git a/pkg/qbittorrent/rss.go b/pkg/qbittorrent/rss.go index 2e5da65..09f141a 100644 --- a/pkg/qbittorrent/rss.go +++ b/pkg/qbittorrent/rss.go @@ -87,6 +87,9 @@ type RssAutoDownloadingRuleDef struct { } func (c *client) AddFolder(ctx context.Context, path string) error { + ctx, span := trace.Start(ctx, "qbittorrent.RSS.AddFolder") + defer span.End() + var formData = url.Values{} formData.Add("path", path) var apiUrl = fmt.Sprintf("%s/api/v2/rss/addFolder", c.config.Address) @@ -106,6 +109,9 @@ func (c *client) AddFolder(ctx context.Context, path string) error { } func (c *client) AddFeed(ctx context.Context, opt *RssAddFeedOption) error { + ctx, span := trace.Start(ctx, "qbittorrent.RSS.AddFeed") + defer span.End() + var formData = url.Values{} err := encoder.Encode(opt, formData) if err != nil { @@ -128,6 +134,9 @@ func (c *client) AddFeed(ctx context.Context, opt *RssAddFeedOption) error { } func (c *client) RemoveItem(ctx context.Context, path string) error { + ctx, span := trace.Start(ctx, "qbittorrent.RSS.RemoveItem") + defer span.End() + var formData = url.Values{} formData.Add("path", path) var apiUrl = fmt.Sprintf("%s/api/v2/rss/removeItem", c.config.Address) @@ -147,6 +156,9 @@ func (c *client) RemoveItem(ctx context.Context, path string) error { } func (c *client) MoveItem(ctx context.Context, srcPath, destPath string) error { + ctx, span := trace.Start(ctx, "qbittorrent.RSS.MoveItem") + defer span.End() + var formData = url.Values{} formData.Add("itemPath", srcPath) formData.Add("destPath", destPath) @@ -167,6 +179,9 @@ func (c *client) MoveItem(ctx context.Context, srcPath, destPath string) error { } func (c *client) GetItems(ctx context.Context, withData bool) (map[string]interface{}, error) { + ctx, span := trace.Start(ctx, "qbittorrent.RSS.GetItems") + defer span.End() + var apiUrl = fmt.Sprintf("%s/api/v2/rss/items?withData=%t", c.config.Address, withData) result, err := c.doRequest(ctx, &requestData{ url: apiUrl, @@ -185,6 +200,9 @@ func (c *client) GetItems(ctx context.Context, withData bool) (map[string]interf } func (c *client) MarkAsRead(ctx context.Context, opt *RssMarkAsReadOption) error { + ctx, span := trace.Start(ctx, "qbittorrent.RSS.MarkAsRead") + defer span.End() + var formData = url.Values{} err := encoder.Encode(opt, formData) if err != nil { @@ -207,6 +225,9 @@ func (c *client) MarkAsRead(ctx context.Context, opt *RssMarkAsReadOption) error } func (c *client) RefreshItem(ctx context.Context, itemPath string) error { + ctx, span := trace.Start(ctx, "qbittorrent.RSS.RefreshItem") + defer span.End() + var formData = url.Values{} formData.Add("itemPath", itemPath) var apiUrl = fmt.Sprintf("%s/api/v2/rss/refreshItem", c.config.Address) @@ -226,6 +247,9 @@ func (c *client) RefreshItem(ctx context.Context, itemPath string) error { } func (c *client) SetAutoDownloadingRule(ctx context.Context, ruleName string, ruleDef *RssAutoDownloadingRuleDef) error { + ctx, span := trace.Start(ctx, "qbittorrent.RSS.SetAutoDownloadingRule") + defer span.End() + var formData = url.Values{} formData.Add("ruleName", ruleName) ruleDefBytes, err := json.Marshal(ruleDef) @@ -250,6 +274,9 @@ func (c *client) SetAutoDownloadingRule(ctx context.Context, ruleName string, ru } func (c *client) RenameAutoDownloadingRule(ctx context.Context, ruleName, newRuleName string) error { + ctx, span := trace.Start(ctx, "qbittorrent.RSS.RenameAutoDownloadingRule") + defer span.End() + var formData = url.Values{} formData.Add("ruleName", ruleName) formData.Add("newRuleName", newRuleName) @@ -270,6 +297,9 @@ func (c *client) RenameAutoDownloadingRule(ctx context.Context, ruleName, newRul } func (c *client) RemoveAutoDownloadingRule(ctx context.Context, ruleName string) error { + ctx, span := trace.Start(ctx, "qbittorrent.RSS.RemoveAutoDownloadingRule") + defer span.End() + var formData = url.Values{} formData.Add("ruleName", ruleName) var apiUrl = fmt.Sprintf("%s/api/v2/rss/removeRule", c.config.Address) @@ -289,6 +319,9 @@ func (c *client) RemoveAutoDownloadingRule(ctx context.Context, ruleName string) } func (c *client) GetAllAutoDownloadingRules(ctx context.Context) (map[string]*RssAutoDownloadingRuleDef, error) { + ctx, span := trace.Start(ctx, "qbittorrent.RSS.GetAllAutoDownloadingRules") + defer span.End() + var apiUrl = fmt.Sprintf("%s/api/v2/rss/matchingArticles", c.config.Address) result, err := c.doRequest(ctx, &requestData{ url: apiUrl, @@ -305,6 +338,9 @@ func (c *client) GetAllAutoDownloadingRules(ctx context.Context) (map[string]*Rs } func (c *client) GetAllArticlesMatchingRule(ctx context.Context, ruleName string) (map[string][]string, error) { + ctx, span := trace.Start(ctx, "qbittorrent.RSS.GetAllArticlesMatchingRule") + defer span.End() + var formData = url.Values{} formData.Add("ruleName", ruleName) var apiUrl = fmt.Sprintf("%s/api/v2/rss/matchingArticles?%s", c.config.Address, formData.Encode()) diff --git a/pkg/qbittorrent/sync.go b/pkg/qbittorrent/sync.go index cfd5abc..4518a01 100644 --- a/pkg/qbittorrent/sync.go +++ b/pkg/qbittorrent/sync.go @@ -76,6 +76,9 @@ type SyncTorrentPeer struct { } func (c *client) MainData(ctx context.Context, rid int) (*SyncMainData, error) { + ctx, span := trace.Start(ctx, "qbittorrent.Sync.MainData") + defer span.End() + apiUrl := fmt.Sprintf("%s/api/v2/sync/maindata?rid=%d", c.config.Address, rid) result, err := c.doRequest(ctx, &requestData{ url: apiUrl, @@ -97,6 +100,9 @@ func (c *client) MainData(ctx context.Context, rid int) (*SyncMainData, error) { } func (c *client) TorrentPeersData(ctx context.Context, hash string, rid int) (*SyncTorrentPeers, error) { + ctx, span := trace.Start(ctx, "qbittorrent.Sync.TorrentPeersData") + defer span.End() + var formData = url.Values{} formData.Add("hash", hash) formData.Add("rid", strconv.Itoa(rid)) diff --git a/pkg/qbittorrent/torrent.go b/pkg/qbittorrent/torrent.go index 298955e..0777157 100644 --- a/pkg/qbittorrent/torrent.go +++ b/pkg/qbittorrent/torrent.go @@ -138,58 +138,82 @@ type TorrentOption struct { Hashes []string `schema:"-"` } +type TorrentState string + +const ( + TorrentStateError TorrentState = "error" + TorrentStateMissingFiles TorrentState = "missingFiles" + TorrentStateUploading TorrentState = "uploading" + TorrentStatePausedUP TorrentState = "pausedUP" + TorrentStateQueuedUP TorrentState = "queuedUP" + TorrentStateStalledUP TorrentState = "stalledUP" + TorrentStateCheckingUP TorrentState = "checkingUP" + TorrentStateForcedUP TorrentState = "forcedUP" + TorrentStateAllocating TorrentState = "allocating" + TorrentStateDownloading TorrentState = "downloading" + TorrentStateMetaDL TorrentState = "metaDL" + TorrentStatePausedDL TorrentState = "pausedDL" + TorrentStateQueuedDL TorrentState = "queuedDL" + TorrentStateStalledDL TorrentState = "stalledDL" + TorrentStateCheckingDL TorrentState = "checkingDL" + TorrentStateForcedDL TorrentState = "forcedDL" + TorrentStateCheckingResumeData TorrentState = "checkingResumeData" + TorrentStateMoving TorrentState = "moving" + TorrentStateUnknown TorrentState = "unknown" +) + type TorrentInfo struct { - AddedOn int `json:"added_on"` - AmountLeft int `json:"amount_left"` - AutoTmm bool `json:"auto_tmm"` - Availability float64 `json:"availability"` - Category string `json:"category"` - Completed int `json:"completed"` - CompletionOn int `json:"completion_on"` - ContentPath string `json:"content_path"` - DlLimit int `json:"dl_limit"` - Dlspeed int `json:"dlspeed"` - DownloadPath string `json:"download_path"` - Downloaded int `json:"downloaded"` - DownloadedSession int `json:"downloaded_session"` - Eta int `json:"eta"` - FLPiecePrio bool `json:"f_l_piece_prio"` - ForceStart bool `json:"force_start"` - Hash string `json:"hash"` - InactiveSeedingTimeLimit int `json:"inactive_seeding_time_limit"` - InfohashV1 string `json:"infohash_v1"` - InfohashV2 string `json:"infohash_v2"` - LastActivity int `json:"last_activity"` - MagnetURI string `json:"magnet_uri"` - MaxInactiveSeedingTime int `json:"max_inactive_seeding_time"` - MaxRatio int `json:"max_ratio"` - MaxSeedingTime int `json:"max_seeding_time"` - Name string `json:"name"` - NumComplete int `json:"num_complete"` - NumIncomplete int `json:"num_incomplete"` - NumLeechs int `json:"num_leechs"` - NumSeeds int `json:"num_seeds"` - Priority int `json:"priority"` - Progress float64 `json:"progress"` - Ratio float64 `json:"ratio"` - RatioLimit int `json:"ratio_limit"` - SavePath string `json:"save_path"` - SeedingTime int `json:"seeding_time"` - SeedingTimeLimit int `json:"seeding_time_limit"` - SeenComplete int `json:"seen_complete"` - SeqDl bool `json:"seq_dl"` - Size int `json:"size"` - State string `json:"state"` - SuperSeeding bool `json:"super_seeding"` - Tags string `json:"tags"` - TimeActive int `json:"time_active"` - TotalSize int `json:"total_size"` - Tracker string `json:"tracker"` - TrackersCount int `json:"trackers_count"` - UpLimit int `json:"up_limit"` - Uploaded int `json:"uploaded"` - UploadedSession int `json:"uploaded_session"` - Upspeed int `json:"upspeed"` + AddedOn int `json:"added_on"` + AmountLeft int `json:"amount_left"` + AutoTmm bool `json:"auto_tmm"` + Availability float64 `json:"availability"` + Category string `json:"category"` + Completed int `json:"completed"` + CompletionOn int `json:"completion_on"` + ContentPath string `json:"content_path"` + DlLimit int `json:"dl_limit"` + Dlspeed int `json:"dlspeed"` + DownloadPath string `json:"download_path"` + Downloaded int `json:"downloaded"` + DownloadedSession int `json:"downloaded_session"` + Eta int `json:"eta"` + FLPiecePrio bool `json:"f_l_piece_prio"` + ForceStart bool `json:"force_start"` + Hash string `json:"hash"` + InactiveSeedingTimeLimit int `json:"inactive_seeding_time_limit"` + InfohashV1 string `json:"infohash_v1"` + InfohashV2 string `json:"infohash_v2"` + LastActivity int `json:"last_activity"` + MagnetURI string `json:"magnet_uri"` + MaxInactiveSeedingTime int `json:"max_inactive_seeding_time"` + MaxRatio int `json:"max_ratio"` + MaxSeedingTime int `json:"max_seeding_time"` + Name string `json:"name"` + NumComplete int `json:"num_complete"` + NumIncomplete int `json:"num_incomplete"` + NumLeechs int `json:"num_leechs"` + NumSeeds int `json:"num_seeds"` + Priority int `json:"priority"` + Progress float64 `json:"progress"` + Ratio float64 `json:"ratio"` + RatioLimit int `json:"ratio_limit"` + SavePath string `json:"save_path"` + SeedingTime int `json:"seeding_time"` + SeedingTimeLimit int `json:"seeding_time_limit"` + SeenComplete int `json:"seen_complete"` + SeqDl bool `json:"seq_dl"` + Size int `json:"size"` + State TorrentState `json:"state"` + SuperSeeding bool `json:"super_seeding"` + Tags string `json:"tags"` + TimeActive int `json:"time_active"` + TotalSize int `json:"total_size"` + Tracker string `json:"tracker"` + TrackersCount int `json:"trackers_count"` + UpLimit int `json:"up_limit"` + Uploaded int `json:"uploaded"` + UploadedSession int `json:"uploaded_session"` + Upspeed int `json:"upspeed"` } type TorrentProperties struct { @@ -294,6 +318,9 @@ type TorrentCategory struct { } func (c *client) GetTorrents(ctx context.Context, opt *TorrentOption) ([]*TorrentInfo, error) { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.GetTorrents") + defer span.End() + var formData = url.Values{} err := encoder.Encode(opt, formData) if err != nil { @@ -324,6 +351,9 @@ func (c *client) GetTorrents(ctx context.Context, opt *TorrentOption) ([]*Torren } func (c *client) GetProperties(ctx context.Context, hash string) (*TorrentProperties, error) { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.GetProperties") + defer span.End() + apiUrl := fmt.Sprintf("%s/api/v2/torrents/properties?hash=%s", c.config.Address, hash) result, err := c.doRequest(ctx, &requestData{ url: apiUrl, @@ -345,6 +375,9 @@ func (c *client) GetProperties(ctx context.Context, hash string) (*TorrentProper } func (c *client) GetTrackers(ctx context.Context, hash string) ([]*TorrentTracker, error) { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.GetTrackers") + defer span.End() + apiUrl := fmt.Sprintf("%s/api/v2/torrents/trackers?hash=%s", c.config.Address, hash) result, err := c.doRequest(ctx, &requestData{ url: apiUrl, @@ -366,6 +399,9 @@ func (c *client) GetTrackers(ctx context.Context, hash string) ([]*TorrentTracke } func (c *client) GetWebSeeds(ctx context.Context, hash string) ([]*TorrentWebSeed, error) { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.GetWebSeeds") + defer span.End() + apiUrl := fmt.Sprintf("%s/api/v2/torrents/webseeds?hash=%s", c.config.Address, hash) result, err := c.doRequest(ctx, &requestData{ url: apiUrl, @@ -395,6 +431,9 @@ func sliceItoa[E constraints.Integer](in []E) []string { } func (c *client) GetContents(ctx context.Context, hash string, indexes ...int) ([]*TorrentContent, error) { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.GetContents") + defer span.End() + var apiUrl string if len(indexes) != 0 { @@ -422,6 +461,9 @@ func (c *client) GetContents(ctx context.Context, hash string, indexes ...int) ( } func (c *client) GetPiecesStates(ctx context.Context, hash string) ([]int, error) { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.GetPiecesStates") + defer span.End() + var apiUrl = fmt.Sprintf("%s/api/v2/torrents/pieceStates?hash=%s", c.config.Address, hash) result, err := c.doRequest(ctx, &requestData{ url: apiUrl, @@ -443,6 +485,9 @@ func (c *client) GetPiecesStates(ctx context.Context, hash string) ([]int, error } func (c *client) GetPiecesHashes(ctx context.Context, hash string) ([]string, error) { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.GetPiecesHashes") + defer span.End() + var apiUrl = fmt.Sprintf("%s/api/v2/torrents/pieceHashes?hash=%s", c.config.Address, hash) result, err := c.doRequest(ctx, &requestData{ url: apiUrl, @@ -464,6 +509,9 @@ func (c *client) GetPiecesHashes(ctx context.Context, hash string) ([]string, er } func (c *client) PauseTorrents(ctx context.Context, hashes []string) error { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.PauseTorrents") + defer span.End() + if len(hashes) == 0 { return errors.New("no torrent hashes provided") } @@ -486,6 +534,9 @@ func (c *client) PauseTorrents(ctx context.Context, hashes []string) error { } func (c *client) ResumeTorrents(ctx context.Context, hashes []string) error { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.ResumeTorrents") + defer span.End() + if len(hashes) == 0 { return errors.New("no torrent hashes provided") } @@ -508,6 +559,9 @@ func (c *client) ResumeTorrents(ctx context.Context, hashes []string) error { } func (c *client) DeleteTorrents(ctx context.Context, hashes []string, deleteFile bool) error { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.DeleteTorrents") + defer span.End() + if len(hashes) == 0 { return errors.New("no torrent hashes provided") } @@ -531,6 +585,9 @@ func (c *client) DeleteTorrents(ctx context.Context, hashes []string, deleteFile } func (c *client) RecheckTorrents(ctx context.Context, hashes []string) error { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.RecheckTorrents") + defer span.End() + if len(hashes) == 0 { return errors.New("no torrent hashes provided") } @@ -553,6 +610,9 @@ func (c *client) RecheckTorrents(ctx context.Context, hashes []string) error { } func (c *client) ReAnnounceTorrents(ctx context.Context, hashes []string) error { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.ReAnnounceTorrents") + defer span.End() + if len(hashes) == 0 { return errors.New("no torrent hashes provided") } @@ -575,6 +635,9 @@ func (c *client) ReAnnounceTorrents(ctx context.Context, hashes []string) error } func (c *client) AddNewTorrent(ctx context.Context, opt *TorrentAddOption) error { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.AddNewTorrent") + defer span.End() + var requestBody bytes.Buffer var writer = multipart.NewWriter(&requestBody) @@ -662,6 +725,9 @@ func (c *client) AddNewTorrent(ctx context.Context, opt *TorrentAddOption) error } func (c *client) AddTrackers(ctx context.Context, hash string, urls []string) error { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.AddTrackers") + defer span.End() + if len(urls) == 0 { return errors.New("no torrent tracker provided") } @@ -685,6 +751,9 @@ func (c *client) AddTrackers(ctx context.Context, hash string, urls []string) er } func (c *client) EditTrackers(ctx context.Context, hash, origUrl, newUrl string) error { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.EditTrackers") + defer span.End() + var formData = url.Values{} formData.Add("origUrl", origUrl) formData.Add("newUrl", newUrl) @@ -706,6 +775,9 @@ func (c *client) EditTrackers(ctx context.Context, hash, origUrl, newUrl string) } func (c *client) RemoveTrackers(ctx context.Context, hash string, urls []string) error { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.RemoveTrackers") + defer span.End() + if len(urls) == 0 { return errors.New("no torrent tracker provided") } @@ -729,6 +801,9 @@ func (c *client) RemoveTrackers(ctx context.Context, hash string, urls []string) } func (c *client) AddPeers(ctx context.Context, hashes []string, peers []string) error { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.AddPeers") + defer span.End() + if len(hashes) == 0 { return errors.New("no hashes provided") } @@ -755,6 +830,9 @@ func (c *client) AddPeers(ctx context.Context, hashes []string, peers []string) } func (c *client) IncreasePriority(ctx context.Context, hashes []string) error { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.IncreasePriority") + defer span.End() + if len(hashes) == 0 { return errors.New("no hashes provided") } @@ -777,6 +855,9 @@ func (c *client) IncreasePriority(ctx context.Context, hashes []string) error { } func (c *client) DecreasePriority(ctx context.Context, hashes []string) error { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.DecreasePriority") + defer span.End() + if len(hashes) == 0 { return errors.New("no hashes provided") } @@ -799,6 +880,9 @@ func (c *client) DecreasePriority(ctx context.Context, hashes []string) error { } func (c *client) MaxPriority(ctx context.Context, hashes []string) error { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.MaxPriority") + defer span.End() + if len(hashes) == 0 { return errors.New("no hashes provided") } @@ -821,6 +905,9 @@ func (c *client) MaxPriority(ctx context.Context, hashes []string) error { } func (c *client) MinPriority(ctx context.Context, hashes []string) error { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.MinPriority") + defer span.End() + if len(hashes) == 0 { return errors.New("no hashes provided") } @@ -843,6 +930,9 @@ func (c *client) MinPriority(ctx context.Context, hashes []string) error { } func (c *client) SetFilePriority(ctx context.Context, hash string, id string, priority int) error { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.SetFilePriority") + defer span.End() + var formData = url.Values{} formData.Add("hash", hash) formData.Add("id", id) @@ -864,6 +954,9 @@ func (c *client) SetFilePriority(ctx context.Context, hash string, id string, pr } func (c *client) GetDownloadLimit(ctx context.Context, hashes []string) (map[string]int, error) { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.GetDownloadLimit") + defer span.End() + if len(hashes) == 0 { return nil, errors.New("no hashes provided") } @@ -888,6 +981,9 @@ func (c *client) GetDownloadLimit(ctx context.Context, hashes []string) (map[str } func (c *client) SetDownloadLimit(ctx context.Context, hashes []string, limit int) error { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.SetDownloadLimit") + defer span.End() + if len(hashes) == 0 { return errors.New("no hashes provided") } @@ -911,6 +1007,9 @@ func (c *client) SetDownloadLimit(ctx context.Context, hashes []string, limit in } func (c *client) SetShareLimit(ctx context.Context, hashes []string, ratioLimit float64, seedingTimeLimit, inactiveSeedingTimeLimit int) error { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.SetShareLimit") + defer span.End() + if len(hashes) == 0 { return errors.New("no hashes provided") } @@ -936,6 +1035,9 @@ func (c *client) SetShareLimit(ctx context.Context, hashes []string, ratioLimit } func (c *client) GetUploadLimit(ctx context.Context, hashes []string) (map[string]int, error) { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.GetUploadLimit") + defer span.End() + if len(hashes) == 0 { return nil, errors.New("no hashes provided") } @@ -960,6 +1062,9 @@ func (c *client) GetUploadLimit(ctx context.Context, hashes []string) (map[strin } func (c *client) SetUploadLimit(ctx context.Context, hashes []string, limit int) error { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.SetUploadLimit") + defer span.End() + if len(hashes) == 0 { return errors.New("no hashes provided") } @@ -983,6 +1088,9 @@ func (c *client) SetUploadLimit(ctx context.Context, hashes []string, limit int) } func (c *client) SetLocation(ctx context.Context, hashes []string, location string) error { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.SetLocation") + defer span.End() + if len(hashes) == 0 { return errors.New("no hashes provided") } @@ -1006,6 +1114,9 @@ func (c *client) SetLocation(ctx context.Context, hashes []string, location stri } func (c *client) SetName(ctx context.Context, hash string, name string) error { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.SetName") + defer span.End() + var formData = url.Values{} formData.Add("hash", hash) formData.Add("name", name) @@ -1026,6 +1137,9 @@ func (c *client) SetName(ctx context.Context, hash string, name string) error { } func (c *client) SetCategory(ctx context.Context, hashes []string, category string) error { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.SetCategory") + defer span.End() + if len(hashes) == 0 { return errors.New("no hashes provided") } @@ -1049,6 +1163,9 @@ func (c *client) SetCategory(ctx context.Context, hashes []string, category stri } func (c *client) GetCategories(ctx context.Context) (map[string]*TorrentCategory, error) { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.GetCategories") + defer span.End() + var apiUrl = fmt.Sprintf("%s/api/v2/torrents/categories", c.config.Address) result, err := c.doRequest(ctx, &requestData{ url: apiUrl, @@ -1067,6 +1184,9 @@ func (c *client) GetCategories(ctx context.Context) (map[string]*TorrentCategory } func (c *client) AddNewCategory(ctx context.Context, category, savePath string) error { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.AddNewCategory") + defer span.End() + var formData = url.Values{} formData.Add("category", category) formData.Add("savePath", savePath) @@ -1087,6 +1207,9 @@ func (c *client) AddNewCategory(ctx context.Context, category, savePath string) } func (c *client) EditCategory(ctx context.Context, category, savePath string) error { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.EditCategory") + defer span.End() + var formData = url.Values{} formData.Add("category", category) formData.Add("savePath", savePath) @@ -1107,6 +1230,9 @@ func (c *client) EditCategory(ctx context.Context, category, savePath string) er } func (c *client) RemoveCategories(ctx context.Context, categories []string) error { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.RemoveCategories") + defer span.End() + var formData = url.Values{} formData.Add("categories", strings.Join(categories, "\n")) var apiUrl = fmt.Sprintf("%s/api/v2/torrents/removeCategories", c.config.Address) @@ -1146,6 +1272,9 @@ func (c *client) AddTags(ctx context.Context, hashes []string, tags []string) er } func (c *client) RemoveTags(ctx context.Context, hashes []string, tags []string) error { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.RemoveTags") + defer span.End() + var formData = url.Values{} formData.Add("hashes", strings.Join(hashes, "|")) formData.Add("tags", strings.Join(tags, ",")) @@ -1166,6 +1295,9 @@ func (c *client) RemoveTags(ctx context.Context, hashes []string, tags []string) } func (c *client) GetTags(ctx context.Context) ([]string, error) { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.GetTags") + defer span.End() + var apiUrl = fmt.Sprintf("%s/api/v2/torrents/tags", c.config.Address) result, err := c.doRequest(ctx, &requestData{ url: apiUrl, @@ -1184,6 +1316,9 @@ func (c *client) GetTags(ctx context.Context) ([]string, error) { } func (c *client) CreateTags(ctx context.Context, tags []string) error { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.CreateTags") + defer span.End() + var formData = url.Values{} formData.Add("tags", strings.Join(tags, ",")) var apiUrl = fmt.Sprintf("%s/api/v2/torrents/createTags", c.config.Address) @@ -1203,6 +1338,9 @@ func (c *client) CreateTags(ctx context.Context, tags []string) error { } func (c *client) DeleteTags(ctx context.Context, tags []string) error { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.DeleteTags") + defer span.End() + var formData = url.Values{} formData.Add("tags", strings.Join(tags, ",")) var apiUrl = fmt.Sprintf("%s/api/v2/torrents/deleteTags", c.config.Address) @@ -1222,6 +1360,9 @@ func (c *client) DeleteTags(ctx context.Context, tags []string) error { } func (c *client) SetAutomaticManagement(ctx context.Context, hashes []string, enable bool) error { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.SetAutomaticManagement") + defer span.End() + var formData = url.Values{} formData.Add("hashes", strings.Join(hashes, "|")) formData.Add("enable", strconv.FormatBool(enable)) @@ -1242,6 +1383,9 @@ func (c *client) SetAutomaticManagement(ctx context.Context, hashes []string, en } func (c *client) ToggleSequentialDownload(ctx context.Context, hashes []string) error { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.ToggleSequentialDownload") + defer span.End() + var formData = url.Values{} formData.Add("hashes", strings.Join(hashes, "|")) var apiUrl = fmt.Sprintf("%s/api/v2/torrents/toggleSequentialDownload", c.config.Address) @@ -1261,6 +1405,9 @@ func (c *client) ToggleSequentialDownload(ctx context.Context, hashes []string) } func (c *client) SetFirstLastPiecePriority(ctx context.Context, hashes []string) error { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.SetFirstLastPiecePriority") + defer span.End() + var formData = url.Values{} formData.Add("hashes", strings.Join(hashes, "|")) var apiUrl = fmt.Sprintf("%s/api/v2/torrents/toggleFirstLastPiecePrio", c.config.Address) @@ -1280,6 +1427,9 @@ func (c *client) SetFirstLastPiecePriority(ctx context.Context, hashes []string) } func (c *client) SetForceStart(ctx context.Context, hashes []string, force bool) error { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.SetForceStart") + defer span.End() + var formData = url.Values{} formData.Add("hashes", strings.Join(hashes, "|")) formData.Add("value", strconv.FormatBool(force)) @@ -1300,6 +1450,9 @@ func (c *client) SetForceStart(ctx context.Context, hashes []string, force bool) } func (c *client) SetSuperSeeding(ctx context.Context, hashes []string, enable bool) error { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.SetSuperSeeding") + defer span.End() + var formData = url.Values{} formData.Add("hashes", strings.Join(hashes, "|")) formData.Add("value", strconv.FormatBool(enable)) @@ -1320,6 +1473,9 @@ func (c *client) SetSuperSeeding(ctx context.Context, hashes []string, enable bo } func (c *client) RenameFile(ctx context.Context, hash, oldPath, newPath string) error { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.RenameFile") + defer span.End() + var formData = url.Values{} formData.Add("oldPath", oldPath) formData.Add("newPath", newPath) @@ -1341,6 +1497,9 @@ func (c *client) RenameFile(ctx context.Context, hash, oldPath, newPath string) } func (c *client) RenameFolder(ctx context.Context, hash, oldPath, newPath string) error { + ctx, span := trace.Start(ctx, "qbittorrent.Torrent.RenameFolder") + defer span.End() + var formData = url.Values{} formData.Add("oldPath", oldPath) formData.Add("newPath", newPath) diff --git a/pkg/qbittorrent/transfer.go b/pkg/qbittorrent/transfer.go index e6f0a51..6619966 100644 --- a/pkg/qbittorrent/transfer.go +++ b/pkg/qbittorrent/transfer.go @@ -47,6 +47,9 @@ type Transfer interface { } func (c *client) GlobalStatusBar(ctx context.Context) (*TransferStatusBar, error) { + ctx, span := trace.Start(ctx, "qbittorrent.Transfer.GlobalStatusBar") + defer span.End() + apiUrl := fmt.Sprintf("%s/api/v2/transfer/info", c.config.Address) result, err := c.doRequest(ctx, &requestData{ url: apiUrl, @@ -68,6 +71,9 @@ func (c *client) GlobalStatusBar(ctx context.Context) (*TransferStatusBar, error } func (c *client) BanPeers(ctx context.Context, peers []string) error { + ctx, span := trace.Start(ctx, "qbittorrent.Transfer.BanPeers") + defer span.End() + apiUrl := fmt.Sprintf("%s/api/v2/transfer/banPeers", c.config.Address) var form = url.Values{} form.Add("peers", strings.Join(peers, "|")) @@ -88,6 +94,9 @@ func (c *client) BanPeers(ctx context.Context, peers []string) error { } func (c *client) GetSpeedLimitsMode(ctx context.Context) (string, error) { + ctx, span := trace.Start(ctx, "qbittorrent.Transfer.GetSpeedLimitsMode") + defer span.End() + apiUrl := fmt.Sprintf("%s/api/v2/transfer/speedLimitsMode", c.config.Address) result, err := c.doRequest(ctx, &requestData{ url: apiUrl, @@ -104,6 +113,9 @@ func (c *client) GetSpeedLimitsMode(ctx context.Context) (string, error) { } func (c *client) ToggleSpeedLimitsMode(ctx context.Context) error { + ctx, span := trace.Start(ctx, "qbittorrent.Transfer.ToggleSpeedLimitsMode") + defer span.End() + apiUrl := fmt.Sprintf("%s/api/v2/transfer/toggleSpeedLimitsMode", c.config.Address) result, err := c.doRequest(ctx, &requestData{ url: apiUrl, @@ -121,6 +133,9 @@ func (c *client) ToggleSpeedLimitsMode(ctx context.Context) error { } func (c *client) GetGlobalUploadLimit(ctx context.Context) (string, error) { + ctx, span := trace.Start(ctx, "qbittorrent.Transfer.GetGlobalUploadLimit") + defer span.End() + apiUrl := fmt.Sprintf("%s/api/v2/transfer/uploadLimit", c.config.Address) result, err := c.doRequest(ctx, &requestData{ url: apiUrl, @@ -137,6 +152,9 @@ func (c *client) GetGlobalUploadLimit(ctx context.Context) (string, error) { } func (c *client) SetGlobalUploadLimit(ctx context.Context, limit int) error { + ctx, span := trace.Start(ctx, "qbittorrent.Transfer.SetGlobalUploadLimit") + defer span.End() + apiUrl := fmt.Sprintf("%s/api/v2/transfer/setUploadLimit?limit=%d", c.config.Address, limit) result, err := c.doRequest(ctx, &requestData{ url: apiUrl, @@ -153,6 +171,9 @@ func (c *client) SetGlobalUploadLimit(ctx context.Context, limit int) error { } func (c *client) GetGlobalDownloadLimit(ctx context.Context) (string, error) { + ctx, span := trace.Start(ctx, "qbittorrent.Transfer.GetGlobalDownloadLimit") + defer span.End() + apiUrl := fmt.Sprintf("%s/api/v2/transfer/downloadLimit", c.config.Address) result, err := c.doRequest(ctx, &requestData{ url: apiUrl, @@ -169,6 +190,9 @@ func (c *client) GetGlobalDownloadLimit(ctx context.Context) (string, error) { } func (c *client) SetGlobalDownloadLimit(ctx context.Context, limit int) error { + ctx, span := trace.Start(ctx, "qbittorrent.Transfer.SetGlobalDownloadLimit") + defer span.End() + apiUrl := fmt.Sprintf("%s/api/v2/transfer/setDownloadLimit?limit=%d", c.config.Address, limit) result, err := c.doRequest(ctx, &requestData{ url: apiUrl,