Skip to content

Commit

Permalink
humanize error messages
Browse files Browse the repository at this point in the history
  • Loading branch information
cenkalti committed Aug 23, 2019
1 parent a2d10a8 commit c91deae
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 26 deletions.
66 changes: 48 additions & 18 deletions internal/announcer/periodic.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@ package announcer

import (
"context"
"errors"
"math"
"net"
"net/url"
"strconv"
"strings"
"sync"
"time"

"github.com/cenkalti/backoff"
"github.com/cenkalti/rain/internal/logger"
"github.com/cenkalti/rain/internal/tracker"
"github.com/cenkalti/rain/internal/tracker/httptracker"
)

type Status int
Expand All @@ -23,11 +25,6 @@ const (
NotWorking
)

var (
errTimeout = errors.New("timeout")
errUnknown = errors.New("unknown error")
)

type PeriodicalAnnouncer struct {
Tracker tracker.Tracker
status Status
Expand All @@ -37,7 +34,7 @@ type PeriodicalAnnouncer struct {
minInterval time.Duration
seeders int
leechers int
lastError error
lastError *AnnounceError
log logger.Logger
completedC chan struct{}
newPeers chan []*net.TCPAddr
Expand Down Expand Up @@ -161,21 +158,17 @@ func (a *PeriodicalAnnouncer) Run() {
} else {
timer.Reset(a.interval)
}
case a.lastError = <-a.errC:
case err := <-a.errC:
a.status = NotWorking
a.lastAnnounce = time.Now()
// Give more friendly error to the user
if oerr, ok := a.lastError.(*net.OpError); ok && oerr.Error() == "operation was canceled" {
a.log.Debugln("announce error:", a.lastError)
a.lastError = errTimeout
} else if uerr, ok := a.lastError.(*url.Error); ok && uerr.Timeout() {
a.log.Debugln("announce error:", a.lastError)
a.lastError = errTimeout
a.lastError = newAnnounceError(err)
if a.lastError.Unknown {
a.log.Errorln("announce error:", a.lastError.Err.Error())
} else {
a.log.Errorln("announce error:", a.lastError)
a.lastError = errUnknown
a.log.Debugln("announce error:", a.lastError.Err.Error())
}
if terr, ok := a.lastError.(*tracker.Error); ok && terr.RetryIn > 0 {
if terr, ok := a.lastError.Err.(*tracker.Error); ok && terr.RetryIn > 0 {
timer.Reset(terr.RetryIn)
} else {
timer.Reset(a.backoff.NextBackOff())
Expand Down Expand Up @@ -215,7 +208,7 @@ func (a *PeriodicalAnnouncer) announce(ctx context.Context, event tracker.Event,

type Stats struct {
Status Status
Error error
Error *AnnounceError
Seeders int
Leechers int
}
Expand All @@ -228,3 +221,40 @@ func (a *PeriodicalAnnouncer) stats() Stats {
Leechers: a.leechers,
}
}

type AnnounceError struct {
Err error
Message string
Unknown bool
}

func newAnnounceError(err error) *AnnounceError {
e := &AnnounceError{Err: err}
switch err := err.(type) {
case *net.OpError:
if err.Error() == "operation was canceled" {
e.Message = "timeout contacting tracker"
return e
}
case *url.Error:
if err.Timeout() {
e.Message = "timeout contacting tracker"
return e
}
if strings.HasSuffix(err.Error(), "no such host") {
e.Message = "tracker host not found"
return e
}
case *httptracker.StatusError:
if err.Code == 403 || err.Code == 404 {
e.Message = "tracker returned http status: " + strconv.Itoa(err.Code)
return e
}
case *tracker.Error:
e.Message = "announce error: " + err.FailureReason
return e
}
e.Message = "unknown error in announce"
e.Unknown = true
return e
}
3 changes: 3 additions & 0 deletions internal/console/console.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,9 @@ func (c *Console) drawDetails(g *gocui.Gui) error {
if t.Error != nil {
fmt.Fprintf(v, " Error: %s\n", *t.Error)
}
if t.ErrorUnknown {
fmt.Fprintf(v, " Internal Error: %s\n", *t.ErrorInternal)
}
}
case peers:
format := "%2s %21s %7s %8s %6s %s\n"
Expand Down
12 changes: 7 additions & 5 deletions internal/rpctypes/rpctypes.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,13 @@ type Webseed struct {
}

type Tracker struct {
URL string
Status string
Leechers int
Seeders int
Error *string
URL string
Status string
Leechers int
Seeders int
Error *string
ErrorUnknown bool
ErrorInternal *string
}

type SessionStats struct {
Expand Down
14 changes: 14 additions & 0 deletions internal/tracker/httptracker/error.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package httptracker

import (
"strconv"
)

type StatusError struct {
Code int
Body string
}

func (e *StatusError) Error() string {
return "http status: " + strconv.Itoa(e.Code)
}
5 changes: 4 additions & 1 deletion internal/tracker/httptracker/httptracker.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,10 @@ func (t *HTTPTracker) Announce(ctx context.Context, req tracker.AnnounceRequest)
err = bencode.DecodeBytes(body, &response)
if err != nil {
if code != 200 {
return nil, fmt.Errorf("status not 200 OK (status: %d body: %q)", code, string(body))
return nil, &StatusError{
Code: code,
Body: string(body),
}
}
return nil, err
}
Expand Down
3 changes: 3 additions & 0 deletions torrent/session_rpc_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,10 @@ func (h *rpcHandler) GetTorrentTrackers(args *rpctypes.GetTorrentTrackersRequest
}
if t.Error != nil {
errStr := t.Error.Error()
internalErrStr := t.Error.Unwrap().Error()
reply.Trackers[i].Error = &errStr
reply.Trackers[i].ErrorUnknown = t.Error.Unknown()
reply.Trackers[i].ErrorInternal = &internalErrStr
}
}
return nil
Expand Down
19 changes: 18 additions & 1 deletion torrent/torrent_commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"net"
"time"

"github.com/cenkalti/rain/internal/announcer"
"github.com/cenkalti/rain/internal/tracker"
)

Expand Down Expand Up @@ -128,7 +129,23 @@ type Tracker struct {
Status TrackerStatus
Leechers int
Seeders int
Error error
Error *AnnounceError
}

type AnnounceError struct {
err *announcer.AnnounceError
}

func (e *AnnounceError) Error() string {
return e.err.Message
}

func (e *AnnounceError) Unwrap() error {
return e.err.Err
}

func (e *AnnounceError) Unknown() bool {
return e.err.Unknown
}

type trackersRequest struct {
Expand Down
4 changes: 3 additions & 1 deletion torrent/torrent_stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,9 @@ func (t *torrent) getTrackers() []Tracker {
Status: TrackerStatus(st.Status),
Seeders: st.Seeders,
Leechers: st.Leechers,
Error: st.Error,
}
if st.Error != nil {
trackers[i].Error = &AnnounceError{st.Error}
}
}
return trackers
Expand Down

0 comments on commit c91deae

Please sign in to comment.