Tidy up doc, file names, naming

This commit is contained in:
Matt Joiner 2020-11-09 10:56:27 +11:00
parent 20d9c63885
commit e6da640bb2
13 changed files with 57 additions and 49 deletions

View File

@ -455,7 +455,7 @@ func (cl *Client) rejectAccepted(conn net.Conn) error {
return nil return nil
} }
func (cl *Client) acceptConnections(l net.Listener) { func (cl *Client) acceptConnections(l Listener) {
for { for {
conn, err := l.Accept() conn, err := l.Accept()
torrent.Add("client listener accepts", 1) torrent.Add("client listener accepts", 1)
@ -1178,7 +1178,7 @@ func (t *Torrent) MergeSpec(spec *TorrentSpec) error {
} }
} }
cl := t.cl cl := t.cl
cl.AddDHTNodes(spec.DhtNodes) cl.AddDhtNodes(spec.DhtNodes)
cl.lock() cl.lock()
defer cl.unlock() defer cl.unlock()
useTorrentSources(spec.Sources, t) useTorrentSources(spec.Sources, t)
@ -1293,7 +1293,7 @@ func (cl *Client) torrentsAsSlice() (ret []*Torrent) {
} }
func (cl *Client) AddMagnet(uri string) (T *Torrent, err error) { func (cl *Client) AddMagnet(uri string) (T *Torrent, err error) {
spec, err := TorrentSpecFromMagnetURI(uri) spec, err := TorrentSpecFromMagnetUri(uri)
if err != nil { if err != nil {
return return
} }
@ -1318,7 +1318,7 @@ func (cl *Client) DhtServers() []DhtServer {
return cl.dhtServers return cl.dhtServers
} }
func (cl *Client) AddDHTNodes(nodes []string) { func (cl *Client) AddDhtNodes(nodes []string) {
for _, n := range nodes { for _, n := range nodes {
hmp := missinggo.SplitHostMaybePort(n) hmp := missinggo.SplitHostMaybePort(n)
ip := net.ParseIP(hmp.Host) ip := net.ParseIP(hmp.Host)
@ -1412,7 +1412,7 @@ func (cl *Client) eachListener(f func(Listener) bool) {
} }
} }
func (cl *Client) findListener(f func(net.Listener) bool) (ret net.Listener) { func (cl *Client) findListener(f func(Listener) bool) (ret Listener) {
cl.eachListener(func(l Listener) bool { cl.eachListener(func(l Listener) bool {
ret = l ret = l
return !f(l) return !f(l)
@ -1437,7 +1437,7 @@ func (cl *Client) publicIp(peer net.IP) net.IP {
func (cl *Client) findListenerIp(f func(net.IP) bool) net.IP { func (cl *Client) findListenerIp(f func(net.IP) bool) net.IP {
l := cl.findListener( l := cl.findListener(
func(l net.Listener) bool { func(l Listener) bool {
return f(addrIpOrNil(l.Addr())) return f(addrIpOrNil(l.Addr()))
}, },
) )

View File

@ -18,7 +18,7 @@ import (
func argSpec(arg string) (ts *torrent.TorrentSpec, err error) { func argSpec(arg string) (ts *torrent.TorrentSpec, err error) {
if strings.HasPrefix(arg, "magnet:") { if strings.HasPrefix(arg, "magnet:") {
return torrent.TorrentSpecFromMagnetURI(arg) return torrent.TorrentSpecFromMagnetUri(arg)
} }
mi, err := metainfo.LoadFromFile(arg) mi, err := metainfo.LoadFromFile(arg)
if err != nil { if err != nil {

View File

@ -128,7 +128,7 @@ type ClientConfig struct {
// OnQuery hook func // OnQuery hook func
DHTOnQuery func(query *krpc.Msg, source net.Addr) (propagate bool) DHTOnQuery func(query *krpc.Msg, source net.Addr) (propagate bool)
DefaultRequestStrategy RequestStrategyMaker DefaultRequestStrategy requestStrategyMaker
Extensions PeerExtensionBits Extensions PeerExtensionBits

View File

@ -46,8 +46,8 @@ func (m Magnet) String() string {
return u.String() return u.String()
} }
// ParseMagnetURI parses Magnet-formatted URIs into a Magnet instance // ParseMagnetUri parses Magnet-formatted URIs into a Magnet instance
func ParseMagnetURI(uri string) (m Magnet, err error) { func ParseMagnetUri(uri string) (m Magnet, err error) {
u, err := url.Parse(uri) u, err := url.Parse(uri)
if err != nil { if err != nil {
err = fmt.Errorf("error parsing uri: %w", err) err = fmt.Errorf("error parsing uri: %w", err)

View File

@ -25,7 +25,7 @@ func init() {
// Converting from our Magnet type to URL string. // Converting from our Magnet type to URL string.
func TestMagnetString(t *testing.T) { func TestMagnetString(t *testing.T) {
m, err := ParseMagnetURI(exampleMagnet.String()) m, err := ParseMagnetUri(exampleMagnet.String())
require.NoError(t, err) require.NoError(t, err)
assert.EqualValues(t, exampleMagnet, m) assert.EqualValues(t, exampleMagnet, m)
} }
@ -37,18 +37,18 @@ func TestParseMagnetURI(t *testing.T) {
// parsing the legit Magnet URI with btih-formatted xt should not return errors // parsing the legit Magnet URI with btih-formatted xt should not return errors
uri = "magnet:?xt=urn:btih:ZOCMZQIPFFW7OLLMIC5HUB6BPCSDEOQU" uri = "magnet:?xt=urn:btih:ZOCMZQIPFFW7OLLMIC5HUB6BPCSDEOQU"
_, err = ParseMagnetURI(uri) _, err = ParseMagnetUri(uri)
if err != nil { if err != nil {
t.Errorf("Attempting parsing the proper Magnet btih URI:\"%v\" failed with err: %v", uri, err) t.Errorf("Attempting parsing the proper Magnet btih URI:\"%v\" failed with err: %v", uri, err)
} }
// Checking if the magnet instance struct is built correctly from parsing // Checking if the magnet instance struct is built correctly from parsing
m, err = ParseMagnetURI(exampleMagnetURI) m, err = ParseMagnetUri(exampleMagnetURI)
assert.EqualValues(t, exampleMagnet, m) assert.EqualValues(t, exampleMagnet, m)
assert.NoError(t, err) assert.NoError(t, err)
// empty string URI case // empty string URI case
_, err = ParseMagnetURI("") _, err = ParseMagnetUri("")
if err == nil { if err == nil {
t.Errorf("Parsing empty string as URI should have returned an error but didn't") t.Errorf("Parsing empty string as URI should have returned an error but didn't")
} }
@ -56,14 +56,14 @@ func TestParseMagnetURI(t *testing.T) {
// only BTIH (BitTorrent info hash)-formatted magnet links are currently supported // only BTIH (BitTorrent info hash)-formatted magnet links are currently supported
// must return error correctly when encountering other URN formats // must return error correctly when encountering other URN formats
uri = "magnet:?xt=urn:sha1:YNCKHTQCWBTRNJIV4WNAE52SJUQCZO5C" uri = "magnet:?xt=urn:sha1:YNCKHTQCWBTRNJIV4WNAE52SJUQCZO5C"
_, err = ParseMagnetURI(uri) _, err = ParseMagnetUri(uri)
if err == nil { if err == nil {
t.Errorf("Magnet URI with non-BTIH URNs (like \"%v\") are not supported and should return an error", uri) t.Errorf("Magnet URI with non-BTIH URNs (like \"%v\") are not supported and should return an error", uri)
} }
// resilience to the broken hash // resilience to the broken hash
uri = "magnet:?xt=urn:btih:this hash is really broken" uri = "magnet:?xt=urn:btih:this hash is really broken"
_, err = ParseMagnetURI(uri) _, err = ParseMagnetUri(uri)
if err == nil { if err == nil {
t.Errorf("Failed to detect broken Magnet URI: %v", uri) t.Errorf("Failed to detect broken Magnet URI: %v", uri)
} }

View File

@ -240,6 +240,8 @@ func (p *Piece) uncachedPriority() (ret piecePriority) {
return return
} }
// Tells the Client to refetch the completion status from storage, updating priority etc. if
// necessary. Might be useful if you know the state of the piece data has changed externally.
func (p *Piece) UpdateCompletion() { func (p *Piece) UpdateCompletion() {
p.t.cl.lock() p.t.cl.lock()
defer p.t.cl.unlock() defer p.t.cl.unlock()

View File

@ -11,12 +11,18 @@ import (
"github.com/anacrolix/missinggo" "github.com/anacrolix/missinggo"
) )
// Accesses Torrent data via a Client. Reads block until the data is available. Seeks and readahead
// also drive Client behaviour.
type Reader interface { type Reader interface {
io.Reader io.Reader
io.Seeker io.Seeker
io.Closer io.Closer
missinggo.ReadContexter missinggo.ReadContexter
// Configure the number of bytes ahead of a read that should also be prioritized in preparation
// for further reads.
SetReadahead(int64) SetReadahead(int64)
// Don't wait for pieces to complete and be verified. Read calls return as soon as they can when
// the underlying chunks become available.
SetResponsive() SetResponsive()
} }
@ -25,33 +31,26 @@ type pieceRange struct {
begin, end pieceIndex begin, end pieceIndex
} }
// Accesses Torrent data via a Client. Reads block until the data is
// available. Seeks and readahead also drive Client behaviour.
type reader struct { type reader struct {
t *Torrent t *Torrent
responsive bool responsive bool
// Adjust the read/seek window to handle Readers locked to File extents // Adjust the read/seek window to handle Readers locked to File extents and the like.
// and the like.
offset, length int64 offset, length int64
// Ensure operations that change the position are exclusive, like Read() // Ensure operations that change the position are exclusive, like Read() and Seek().
// and Seek().
opMu sync.Mutex opMu sync.Mutex
// Required when modifying pos and readahead, or reading them without // Required when modifying pos and readahead, or reading them without opMu.
// opMu.
mu sync.Locker mu sync.Locker
pos int64 pos int64
readahead int64 readahead int64
// The cached piece range this reader wants downloaded. The zero value // The cached piece range this reader wants downloaded. The zero value corresponds to nothing.
// corresponds to nothing. We cache this so that changes can be detected, // We cache this so that changes can be detected, and bubbled up to the Torrent only as
// and bubbled up to the Torrent only as required. // required.
pieces pieceRange pieces pieceRange
} }
var _ io.ReadCloser = &reader{} var _ io.ReadCloser = (*reader)(nil)
// Don't wait for pieces to complete and be verified. Read calls return as
// soon as they can when the underlying chunks become available.
func (r *reader) SetResponsive() { func (r *reader) SetResponsive() {
r.responsive = true r.responsive = true
r.t.cl.event.Broadcast() r.t.cl.event.Broadcast()
@ -63,8 +62,6 @@ func (r *reader) SetNonResponsive() {
r.t.cl.event.Broadcast() r.t.cl.event.Broadcast()
} }
// Configure the number of bytes ahead of a read that should also be
// prioritized in preparation for further reads.
func (r *reader) SetReadahead(readahead int64) { func (r *reader) SetReadahead(readahead int64) {
r.mu.Lock() r.mu.Lock()
r.readahead = readahead r.readahead = readahead
@ -101,13 +98,11 @@ func (r *reader) available(off, max int64) (ret int64) {
} }
func (r *reader) waitReadable(off int64) { func (r *reader) waitReadable(off int64) {
// We may have been sent back here because we were told we could read but // We may have been sent back here because we were told we could read but it failed.
// it failed.
r.t.cl.event.Wait() r.t.cl.event.Wait()
} }
// Calculates the pieces this reader wants downloaded, ignoring the cached // Calculates the pieces this reader wants downloaded, ignoring the cached value at r.pieces.
// value at r.pieces.
func (r *reader) piecesUncached() (ret pieceRange) { func (r *reader) piecesUncached() (ret pieceRange) {
ra := r.readahead ra := r.readahead
if ra < 1 { if ra < 1 {
@ -143,8 +138,8 @@ func (r *reader) ReadContext(ctx context.Context, b []byte) (n int, err error) {
r.t.cl.unlock() r.t.cl.unlock()
}() }()
} }
// Hmmm, if a Read gets stuck, this means you can't change position for // Hmmm, if a Read gets stuck, this means you can't change position for other purposes. That
// other purposes. That seems reasonable, but unusual. // seems reasonable, but unusual.
r.opMu.Lock() r.opMu.Lock()
defer r.opMu.Unlock() defer r.opMu.Unlock()
n, err = r.readOnceAt(b, r.pos, &ctxErr) n, err = r.readOnceAt(b, r.pos, &ctxErr)
@ -168,8 +163,8 @@ func (r *reader) ReadContext(ctx context.Context, b []byte) (n int, err error) {
return return
} }
// Wait until some data should be available to read. Tickles the client if it // Wait until some data should be available to read. Tickles the client if it isn't. Returns how
// isn't. Returns how much should be readable without blocking. // much should be readable without blocking.
func (r *reader) waitAvailable(pos, wanted int64, ctxErr *error, wait bool) (avail int64, err error) { func (r *reader) waitAvailable(pos, wanted int64, ctxErr *error, wait bool) (avail int64, err error) {
r.t.cl.lock() r.t.cl.lock()
defer r.t.cl.unlock() defer r.t.cl.unlock()
@ -244,6 +239,7 @@ func (r *reader) readOnceAt(b []byte, pos int64, ctxErr *error) (n int, err erro
} }
} }
// Hodor
func (r *reader) Close() error { func (r *reader) Close() error {
r.t.cl.lock() r.t.cl.lock()
defer r.t.cl.unlock() defer r.t.cl.unlock()

View File

@ -67,17 +67,17 @@ type requestStrategyFastest struct {
requestStrategyDefaults requestStrategyDefaults
} }
func newRequestStrategyMaker(rs requestStrategy) RequestStrategyMaker { func newRequestStrategyMaker(rs requestStrategy) requestStrategyMaker {
return func(requestStrategyCallbacks, sync.Locker) requestStrategy { return func(requestStrategyCallbacks, sync.Locker) requestStrategy {
return rs return rs
} }
} }
func RequestStrategyFastest() RequestStrategyMaker { func RequestStrategyFastest() requestStrategyMaker {
return newRequestStrategyMaker(requestStrategyFastest{}) return newRequestStrategyMaker(requestStrategyFastest{})
} }
func RequestStrategyFuzzing() RequestStrategyMaker { func RequestStrategyFuzzing() requestStrategyMaker {
return newRequestStrategyMaker(requestStrategyFuzzing{}) return newRequestStrategyMaker(requestStrategyFuzzing{})
} }
@ -110,9 +110,10 @@ type requestStrategyDuplicateRequestTimeout struct {
timeoutLocker sync.Locker timeoutLocker sync.Locker
} }
type RequestStrategyMaker func(callbacks requestStrategyCallbacks, clientLocker sync.Locker) requestStrategy // Generates a request strategy instance for a given torrent. callbacks are probably specific to the torrent.
type requestStrategyMaker func(callbacks requestStrategyCallbacks, clientLocker sync.Locker) requestStrategy
func RequestStrategyDuplicateRequestTimeout(duplicateRequestTimeout time.Duration) RequestStrategyMaker { func RequestStrategyDuplicateRequestTimeout(duplicateRequestTimeout time.Duration) requestStrategyMaker {
return func(callbacks requestStrategyCallbacks, clientLocker sync.Locker) requestStrategy { return func(callbacks requestStrategyCallbacks, clientLocker sync.Locker) requestStrategy {
return requestStrategyDuplicateRequestTimeout{ return requestStrategyDuplicateRequestTimeout{
duplicateRequestTimeout: duplicateRequestTimeout, duplicateRequestTimeout: duplicateRequestTimeout,

View File

@ -11,12 +11,17 @@ import (
) )
type Listener interface { type Listener interface {
net.Listener // Accept waits for and returns the next connection to the listener.
Accept() (net.Conn, error)
// Addr returns the listener's network address.
Addr() net.Addr
} }
type socket interface { type socket interface {
Listener Listener
Dialer Dialer
Close() error
} }
func listen(n network, addr string, f firewallCallback) (socket, error) { func listen(n network, addr string, f firewallCallback) (socket, error) {

View File

@ -28,8 +28,8 @@ type TorrentSpec struct {
DisallowDataDownload bool DisallowDataDownload bool
} }
func TorrentSpecFromMagnetURI(uri string) (spec *TorrentSpec, err error) { func TorrentSpecFromMagnetUri(uri string) (spec *TorrentSpec, err error) {
m, err := metainfo.ParseMagnetURI(uri) m, err := metainfo.ParseMagnetUri(uri)
if err != nil { if err != nil {
return return
} }

View File

@ -2043,6 +2043,7 @@ func (t *Torrent) AllowDataDownload() {
}) })
} }
// Enables uploading data, if it was disabled.
func (t *Torrent) AllowDataUpload() { func (t *Torrent) AllowDataUpload() {
t.cl.lock() t.cl.lock()
defer t.cl.unlock() defer t.cl.unlock()
@ -2052,6 +2053,7 @@ func (t *Torrent) AllowDataUpload() {
} }
} }
// Disables uploading data, if it was enabled.
func (t *Torrent) DisallowDataUpload() { func (t *Torrent) DisallowDataUpload() {
t.cl.lock() t.cl.lock()
defer t.cl.unlock() defer t.cl.unlock()
@ -2061,6 +2063,8 @@ func (t *Torrent) DisallowDataUpload() {
} }
} }
// Sets a handler that is called if there's an error writing a chunk to local storage. By default,
// or if nil, a critical message is logged, and data download is disabled.
func (t *Torrent) SetOnWriteChunkError(f func(error)) { func (t *Torrent) SetOnWriteChunkError(f func(error)) {
t.cl.lock() t.cl.lock()
defer t.cl.unlock() defer t.cl.unlock()

View File

@ -116,7 +116,7 @@ func scanDir(dirName string) (ee map[metainfo.Hash]entity) {
break break
} }
for _, uri := range uris { for _, uri := range uris {
m, err := metainfo.ParseMagnetURI(uri) m, err := metainfo.ParseMagnetUri(uri)
if err != nil { if err != nil {
log.Printf("error parsing %q in file %q: %s", uri, fullName, err) log.Printf("error parsing %q in file %q: %s", uri, fullName, err)
continue continue