Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 99 additions & 4 deletions methods.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ func (c *Client) GetBuildInfoCtx(ctx context.Context) (BuildInfo, error) {

defer drainAndClose(resp)

if resp.StatusCode != http.StatusOK {
return bi, errors.Wrap(ErrUnexpectedStatus, "could not get app build info; status code: %d", resp.StatusCode)
}

if err = json.NewDecoder(resp.Body).Decode(&bi); err != nil {
return bi, errors.Wrap(err, "could not unmarshal body")
}
Expand Down Expand Up @@ -207,6 +211,10 @@ func (c *Client) GetAppPreferencesCtx(ctx context.Context) (AppPreferences, erro

defer drainAndClose(resp)

if resp.StatusCode != http.StatusOK {
return app, errors.Wrap(ErrUnexpectedStatus, "could not get app preferences; status code: %d", resp.StatusCode)
}

if err := json.NewDecoder(resp.Body).Decode(&app); err != nil {
return app, errors.Wrap(err, "could not unmarshal body")
}
Expand Down Expand Up @@ -321,6 +329,10 @@ func (c *Client) GetTorrentsCtx(ctx context.Context, o TorrentFilterOptions) ([]

defer drainAndClose(resp)

if resp.StatusCode != http.StatusOK {
return nil, errors.Wrap(ErrUnexpectedStatus, "could not get torrents; status code: %d", resp.StatusCode)
}

var torrents []Torrent
if err := json.NewDecoder(resp.Body).Decode(&torrents); err != nil {
return nil, errors.Wrap(err, "could not unmarshal body")
Expand Down Expand Up @@ -363,11 +375,23 @@ func (c *Client) GetTorrentPropertiesCtx(ctx context.Context, hash string) (Torr
var prop TorrentProperties
resp, err := c.getCtx(ctx, "torrents/properties", opts)
if err != nil {
return prop, errors.Wrap(err, "could not get app preferences")
return prop, errors.Wrap(err, "could not get torrent properties")
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed a likely copy/paste error in the message

}

defer drainAndClose(resp)

// HTTP Status Code Scenario
// 404 Torrent hash was not found
// 200 All other scenarios
switch resp.StatusCode {
case http.StatusOK:
break
case http.StatusNotFound:
return prop, errors.Wrap(ErrTorrentNotFound, "could not get torrent properties; torrent hash '%s' was not found", hash)
default:
return prop, errors.Wrap(ErrUnexpectedStatus, "could not get torrent properties; status code: %d", resp.StatusCode)
}

if err := json.NewDecoder(resp.Body).Decode(&prop); err != nil {
return prop, errors.Wrap(err, "could not unmarshal body")
}
Expand All @@ -387,6 +411,10 @@ func (c *Client) GetTorrentsRawCtx(ctx context.Context) (string, error) {

defer drainAndClose(resp)

if resp.StatusCode != http.StatusOK {
return "", errors.Wrap(ErrUnexpectedStatus, "could not get torrents raw; status code: %d", resp.StatusCode)
}

data, err := io.ReadAll(resp.Body)
if err != nil {
return "", errors.Wrap(err, "could not get read body torrents raw")
Expand All @@ -412,10 +440,14 @@ func (c *Client) GetTorrentTrackersCtx(ctx context.Context, hash string) ([]Torr
defer drainAndClose(resp)

switch resp.StatusCode {
case http.StatusOK:
break
case http.StatusNotFound:
return nil, nil
case http.StatusForbidden:
return nil, nil
default:
return nil, errors.Wrap(ErrUnexpectedStatus, "could not get torrent trackers; status code: %d", resp.StatusCode)
}

var trackers []TorrentTracker
Expand Down Expand Up @@ -557,6 +589,10 @@ func (c *Client) GetTransferInfoCtx(ctx context.Context) (*TransferInfo, error)

defer drainAndClose(resp)

if resp.StatusCode != http.StatusOK {
return nil, errors.Wrap(ErrUnexpectedStatus, "could not get transfer info; status code: %d", resp.StatusCode)
}

var info TransferInfo
if err := json.NewDecoder(resp.Body).Decode(&info); err != nil {
return nil, errors.Wrap(err, "could not unmarshal body")
Expand Down Expand Up @@ -611,6 +647,10 @@ func (c *Client) SyncMainDataCtxWithRaw(ctx context.Context, rid int64) (*MainDa

defer drainAndClose(resp)

if resp.StatusCode != http.StatusOK {
return nil, nil, errors.Wrap(ErrUnexpectedStatus, "could not get main data; status code: %d", resp.StatusCode)
}

rp, wp := io.Pipe()
var rawData map[string]interface{}
var mapErr error
Expand Down Expand Up @@ -986,6 +1026,10 @@ func (c *Client) GetCategoriesCtx(ctx context.Context) (map[string]Category, err

defer drainAndClose(resp)

if resp.StatusCode != http.StatusOK {
return nil, errors.Wrap(ErrUnexpectedStatus, "could not get categories; status code: %d", resp.StatusCode)
}

m := make(map[string]Category)
if err := json.NewDecoder(resp.Body).Decode(&m); err != nil {
return nil, errors.Wrap(err, "could not unmarshal body")
Expand All @@ -1009,6 +1053,15 @@ func (c *Client) GetFilesInformationCtx(ctx context.Context, hash string) (*Torr

defer drainAndClose(resp)

switch resp.StatusCode {
case http.StatusOK:
break
case http.StatusNotFound:
return nil, errors.Wrap(ErrTorrentNotFound, "could not get files info; torrent hash not found: %s", hash)
default:
return nil, errors.Wrap(ErrUnexpectedStatus, "could not get files info; torrent hash: %s, status code: %d", hash, resp.StatusCode)
}

var info TorrentFiles
if err := json.NewDecoder(resp.Body).Decode(&info); err != nil {
return nil, errors.Wrap(err, "could not unmarshal body")
Expand Down Expand Up @@ -1075,6 +1128,15 @@ func (c *Client) ExportTorrentCtx(ctx context.Context, hash string) ([]byte, err

defer drainAndClose(resp)

switch resp.StatusCode {
case http.StatusOK:
break
case http.StatusNotFound:
return nil, errors.Wrap(ErrTorrentNotFound, "could not get export; torrent hash not found: %v", hash)
default:
return nil, errors.Wrap(ErrUnexpectedStatus, "could not get export; torrent hash: %v | status code: %d", hash, resp.StatusCode)
}

return io.ReadAll(resp.Body)
}

Expand Down Expand Up @@ -1189,6 +1251,10 @@ func (c *Client) GetTagsCtx(ctx context.Context) ([]string, error) {

defer drainAndClose(resp)

if resp.StatusCode != http.StatusOK {
return nil, errors.Wrap(ErrUnexpectedStatus, "could not get tags; status code: %d", resp.StatusCode)
}

var m []string
if err := json.NewDecoder(resp.Body).Decode(&m); err != nil {
return nil, errors.Wrap(err, "could not unmarshal body")
Expand Down Expand Up @@ -1654,6 +1720,10 @@ func (c *Client) GetAlternativeSpeedLimitsModeCtx(ctx context.Context) (bool, er

defer drainAndClose(resp)

if resp.StatusCode != http.StatusOK {
return m, errors.Wrap(ErrUnexpectedStatus, "could not get alternative speed limits mode; status code: %d", resp.StatusCode)
}

var d int64
if err := json.NewDecoder(resp.Body).Decode(&d); err != nil {
return m, errors.Wrap(err, "could not unmarshal body")
Expand Down Expand Up @@ -1702,6 +1772,10 @@ func (c *Client) GetGlobalDownloadLimitCtx(ctx context.Context) (int64, error) {

defer drainAndClose(resp)

if resp.StatusCode != http.StatusOK {
return m, errors.Wrap(ErrUnexpectedStatus, "could not get global download limit; status code: %d", resp.StatusCode)
}

if err := json.NewDecoder(resp.Body).Decode(&m); err != nil {
return m, errors.Wrap(err, "could not unmarshal body")
}
Expand Down Expand Up @@ -1748,6 +1822,10 @@ func (c *Client) GetGlobalUploadLimitCtx(ctx context.Context) (int64, error) {

defer drainAndClose(resp)

if resp.StatusCode != http.StatusOK {
return m, errors.Wrap(ErrUnexpectedStatus, "could not get global upload limit; status code: %d", resp.StatusCode)
}

if err := json.NewDecoder(resp.Body).Decode(&m); err != nil {
return m, errors.Wrap(err, "could not unmarshal body")
}
Expand Down Expand Up @@ -1983,10 +2061,8 @@ func (c *Client) SetTorrentShareLimitCtx(ctx context.Context, hashes []string, r
case http.StatusBadRequest:
return ErrInvalidShareLimit
default:
errors.Wrap(ErrUnexpectedStatus, "could not set share limits; hashes: %v | ratioLimit: %v | seedingTimeLimit: %v | inactiveSeedingTimeLimit %v | status code: %d", hashes, ratioLimit, seedingTimeLimit, inactiveSeedingTimeLimit, resp.StatusCode)
return errors.Wrap(ErrUnexpectedStatus, "could not set share limits; hashes: %v | ratioLimit: %v | seedingTimeLimit: %v | inactiveSeedingTimeLimit %v | status code: %d", hashes, ratioLimit, seedingTimeLimit, inactiveSeedingTimeLimit, resp.StatusCode)
Comment on lines -1986 to +2064
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously this created an error that was not returned, and fell through to the return nil path below

}

return nil
}

// SetTorrentUploadLimit set upload limit for torrent specified by hashes
Expand Down Expand Up @@ -2027,6 +2103,10 @@ func (c *Client) GetAppVersionCtx(ctx context.Context) (string, error) {

defer drainAndClose(resp)

if resp.StatusCode != http.StatusOK {
return "", errors.Wrap(ErrUnexpectedStatus, "could not get app version; status code: %d", resp.StatusCode)
}

body, err := io.ReadAll(resp.Body)
if err != nil {
return "", errors.Wrap(err, "could not read body")
Expand Down Expand Up @@ -2204,6 +2284,13 @@ func (c *Client) GetWebAPIVersionCtx(ctx context.Context) (string, error) {

defer drainAndClose(resp)

// HTTP Status Code Scenario
// 200 All scenarios
// Non-200 response codes are expected when a reverse proxy is used in front of qBittorrent API.
if resp.StatusCode != http.StatusOK {
return "", errors.Wrap(ErrUnexpectedStatus, "could not get webapi version; status code: %d", resp.StatusCode)
}

body, err := io.ReadAll(resp.Body)
if err != nil {
return "", errors.Wrap(err, "could not read body")
Expand All @@ -2226,6 +2313,10 @@ func (c *Client) GetLogsCtx(ctx context.Context) ([]Log, error) {

defer drainAndClose(resp)

if resp.StatusCode != http.StatusOK {
return nil, errors.Wrap(ErrUnexpectedStatus, "could not get main client logs; status code: %d", resp.StatusCode)
}

var m []Log
if err := json.NewDecoder(resp.Body).Decode(&m); err != nil {
return nil, errors.Wrap(err, "could not unmarshal body")
Expand All @@ -2247,6 +2338,10 @@ func (c *Client) GetPeerLogsCtx(ctx context.Context) ([]PeerLog, error) {

defer drainAndClose(resp)

if resp.StatusCode != http.StatusOK {
return nil, errors.Wrap(ErrUnexpectedStatus, "could not get peer logs; status code: %d", resp.StatusCode)
}

var m []PeerLog
if err := json.NewDecoder(resp.Body).Decode(&m); err != nil {
return m, errors.Wrap(err, "could not unmarshal body")
Expand Down
25 changes: 25 additions & 0 deletions methods_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package qbittorrent_test

import (
"os"
"regexp"
"testing"
"time"

Expand Down Expand Up @@ -335,3 +336,27 @@ func TestClient_GetTorrentsWebSeeds(t *testing.T) {
_, err = client.GetTorrentsWebSeeds(hash)
assert.NoError(t, err)
}

func TestClient_GetWebAPIVersion(t *testing.T) {
client := qbittorrent.NewClient(qbittorrent.Config{
Host: qBittorrentBaseURL,
Username: qBittorrentUsername,
Password: qBittorrentPassword,
})

version, err := client.GetWebAPIVersion()
assert.NoError(t, err)
assert.Regexp(t, regexp.MustCompile("\\d+\\.\\d+\\.\\d+"), version)
}

func TestClient_GetWebAPIVersion_IncorrectPath(t *testing.T) {
client := qbittorrent.NewClient(qbittorrent.Config{
Host: qBittorrentBaseURL + "/incorrect_path/",
// No username and password to bypass login, which would fail due to the incorrect path.
Username: "",
Password: "",
})

_, err := client.GetWebAPIVersion()
assert.ErrorContains(t, err, "could not get webapi version; status code: 404")
}