Rename Config->ClientConfig and change how defaults work

This is a very breaking change.
This commit is contained in:
Matt Joiner 2018-06-16 16:30:04 +10:00
parent ad5e44eaf5
commit e97f487d2e
5 changed files with 71 additions and 96 deletions

View File

@ -27,7 +27,6 @@ import (
"github.com/davecgh/go-spew/spew" "github.com/davecgh/go-spew/spew"
"github.com/dustin/go-humanize" "github.com/dustin/go-humanize"
"github.com/google/btree" "github.com/google/btree"
"golang.org/x/time/rate"
"github.com/anacrolix/torrent/bencode" "github.com/anacrolix/torrent/bencode"
"github.com/anacrolix/torrent/iplist" "github.com/anacrolix/torrent/iplist"
@ -44,7 +43,7 @@ type Client struct {
event sync.Cond event sync.Cond
closed missinggo.Event closed missinggo.Event
config Config config *ClientConfig
logger *log.Logger logger *log.Logger
halfOpenLimit int halfOpenLimit int
@ -56,8 +55,6 @@ type Client struct {
ipBlockList iplist.Ranger ipBlockList iplist.Ranger
// Our BitTorrent protocol extension bytes, sent in our BT handshakes. // Our BitTorrent protocol extension bytes, sent in our BT handshakes.
extensionBytes peerExtensionBytes extensionBytes peerExtensionBytes
uploadLimit *rate.Limiter
downloadLimit *rate.Limiter
// Set of addresses that have our client ID. This intentionally will // Set of addresses that have our client ID. This intentionally will
// include ourselves if we end up trying to connect to our own address // include ourselves if we end up trying to connect to our own address
@ -173,12 +170,10 @@ func (cl *Client) announceKey() int32 {
return int32(binary.BigEndian.Uint32(cl.peerID[16:20])) return int32(binary.BigEndian.Uint32(cl.peerID[16:20]))
} }
func NewClient(cfg *Config) (cl *Client, err error) { func NewClient(cfg *ClientConfig) (cl *Client, err error) {
if cfg == nil { if cfg == nil {
cfg = &Config{} cfg = NewDefaultClientConfig()
} }
cfg.setDefaults()
defer func() { defer func() {
if err != nil { if err != nil {
cl = nil cl = nil
@ -186,7 +181,7 @@ func NewClient(cfg *Config) (cl *Client, err error) {
}() }()
cl = &Client{ cl = &Client{
halfOpenLimit: cfg.HalfOpenConnsPerTorrent, halfOpenLimit: cfg.HalfOpenConnsPerTorrent,
config: *cfg, config: cfg,
dopplegangerAddrs: make(map[string]struct{}), dopplegangerAddrs: make(map[string]struct{}),
torrents: make(map[metainfo.Hash]*Torrent), torrents: make(map[metainfo.Hash]*Torrent),
} }
@ -198,16 +193,6 @@ func NewClient(cfg *Config) (cl *Client, err error) {
} }
cl.Close() cl.Close()
}() }()
if cfg.UploadRateLimiter == nil {
cl.uploadLimit = unlimited
} else {
cl.uploadLimit = cfg.UploadRateLimiter
}
if cfg.DownloadRateLimiter == nil {
cl.downloadLimit = unlimited
} else {
cl.downloadLimit = cfg.DownloadRateLimiter
}
cl.extensionBytes = defaultPeerExtensionBytes() cl.extensionBytes = defaultPeerExtensionBytes()
cl.event.L = &cl.mu cl.event.L = &cl.mu
storageImpl := cfg.DefaultStorage storageImpl := cfg.DefaultStorage
@ -492,7 +477,7 @@ func dialUTP(ctx context.Context, addr string, sock utpSocket) (c net.Conn, err
var allPeerNetworks = []string{"tcp4", "tcp6", "udp4", "udp6"} var allPeerNetworks = []string{"tcp4", "tcp6", "udp4", "udp6"}
func peerNetworkEnabled(network string, cfg Config) bool { func peerNetworkEnabled(network string, cfg *ClientConfig) bool {
c := func(s string) bool { c := func(s string) bool {
return strings.Contains(network, s) return strings.Contains(network, s)
} }
@ -1178,7 +1163,7 @@ func (cl *Client) newConnection(nc net.Conn, outgoing bool) (c *connection) {
c.writerCond.L = &cl.mu c.writerCond.L = &cl.mu
c.setRW(connStatsReadWriter{nc, c}) c.setRW(connStatsReadWriter{nc, c})
c.r = &rateLimitedReader{ c.r = &rateLimitedReader{
l: cl.downloadLimit, l: cl.config.DownloadRateLimiter,
r: c.r, r: c.r,
} }
return return

View File

@ -30,15 +30,14 @@ import (
"github.com/anacrolix/torrent/storage" "github.com/anacrolix/torrent/storage"
) )
func TestingConfig() *Config { func TestingConfig() *ClientConfig {
return &Config{ cfg := NewDefaultClientConfig()
ListenHost: LoopbackListenHost, cfg.ListenHost = LoopbackListenHost
NoDHT: true, cfg.NoDHT = true
DataDir: tempDir(), cfg.DataDir = tempDir()
DisableTrackers: true, cfg.DisableTrackers = true
NoDefaultPortForwarding: true, cfg.NoDefaultPortForwarding = true
// Debug: true, return cfg
}
} }
func TestClientDefault(t *testing.T) { func TestClientDefault(t *testing.T) {
@ -105,7 +104,9 @@ func TestPieceHashSize(t *testing.T) {
func TestTorrentInitialState(t *testing.T) { func TestTorrentInitialState(t *testing.T) {
dir, mi := testutil.GreetingTestTorrent() dir, mi := testutil.GreetingTestTorrent()
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
cl := &Client{} cl := &Client{
config: &ClientConfig{},
}
cl.initLogger() cl.initLogger()
tor := cl.newTorrent( tor := cl.newTorrent(
mi.HashInfoBytes(), mi.HashInfoBytes(),
@ -138,8 +139,7 @@ func TestUnmarshalPEXMsg(t *testing.T) {
} }
func TestReducedDialTimeout(t *testing.T) { func TestReducedDialTimeout(t *testing.T) {
cfg := &Config{} cfg := NewDefaultClientConfig()
cfg.setDefaults()
for _, _case := range []struct { for _, _case := range []struct {
Max time.Duration Max time.Duration
HalfOpenLimit int HalfOpenLimit int
@ -357,7 +357,9 @@ func testClientTransfer(t *testing.T, ps testClientTransferParams) {
// Create seeder and a Torrent. // Create seeder and a Torrent.
cfg := TestingConfig() cfg := TestingConfig()
cfg.Seed = true cfg.Seed = true
if ps.SeederUploadRateLimiter != nil {
cfg.UploadRateLimiter = ps.SeederUploadRateLimiter cfg.UploadRateLimiter = ps.SeederUploadRateLimiter
}
// cfg.ListenAddr = "localhost:4000" // cfg.ListenAddr = "localhost:4000"
if ps.SeederStorage != nil { if ps.SeederStorage != nil {
cfg.DefaultStorage = ps.SeederStorage(greetingTempDir) cfg.DefaultStorage = ps.SeederStorage(greetingTempDir)
@ -380,12 +382,15 @@ func testClientTransfer(t *testing.T, ps testClientTransferParams) {
leecherDataDir, err := ioutil.TempDir("", "") leecherDataDir, err := ioutil.TempDir("", "")
require.NoError(t, err) require.NoError(t, err)
defer os.RemoveAll(leecherDataDir) defer os.RemoveAll(leecherDataDir)
cfg = TestingConfig()
if ps.LeecherStorage == nil { if ps.LeecherStorage == nil {
cfg.DataDir = leecherDataDir cfg.DataDir = leecherDataDir
} else { } else {
cfg.DefaultStorage = ps.LeecherStorage(leecherDataDir) cfg.DefaultStorage = ps.LeecherStorage(leecherDataDir)
} }
if ps.LeecherDownloadRateLimiter != nil {
cfg.DownloadRateLimiter = ps.LeecherDownloadRateLimiter cfg.DownloadRateLimiter = ps.LeecherDownloadRateLimiter
}
cfg.Seed = false cfg.Seed = false
leecher, err := NewClient(cfg) leecher, err := NewClient(cfg)
require.NoError(t, err) require.NoError(t, err)
@ -443,6 +448,7 @@ func assertReadAllGreeting(t *testing.T, r io.ReadSeeker) {
func TestSeedAfterDownloading(t *testing.T) { func TestSeedAfterDownloading(t *testing.T) {
greetingTempDir, mi := testutil.GreetingTestTorrent() greetingTempDir, mi := testutil.GreetingTestTorrent()
defer os.RemoveAll(greetingTempDir) defer os.RemoveAll(greetingTempDir)
cfg := TestingConfig() cfg := TestingConfig()
cfg.Seed = true cfg.Seed = true
cfg.DataDir = greetingTempDir cfg.DataDir = greetingTempDir
@ -454,6 +460,9 @@ func TestSeedAfterDownloading(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
assert.True(t, ok) assert.True(t, ok)
seederTorrent.VerifyData() seederTorrent.VerifyData()
cfg = TestingConfig()
cfg.Seed = true
cfg.DataDir, err = ioutil.TempDir("", "") cfg.DataDir, err = ioutil.TempDir("", "")
require.NoError(t, err) require.NoError(t, err)
defer os.RemoveAll(cfg.DataDir) defer os.RemoveAll(cfg.DataDir)
@ -461,6 +470,8 @@ func TestSeedAfterDownloading(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
defer leecher.Close() defer leecher.Close()
testutil.ExportStatusWriter(leecher, "l") testutil.ExportStatusWriter(leecher, "l")
cfg = TestingConfig()
cfg.Seed = false cfg.Seed = false
cfg.DataDir, err = ioutil.TempDir("", "") cfg.DataDir, err = ioutil.TempDir("", "")
require.NoError(t, err) require.NoError(t, err)
@ -982,8 +993,11 @@ func TestSetMaxEstablishedConn(t *testing.T) {
defer ss.Close() defer ss.Close()
var tts []*Torrent var tts []*Torrent
ih := testutil.GreetingMetaInfo().HashInfoBytes() ih := testutil.GreetingMetaInfo().HashInfoBytes()
cfg := TestingConfig()
cfg.DisableAcceptRateLimiting = true
cfg.dropDuplicatePeerIds = true
for i := range iter.N(3) { for i := range iter.N(3) {
cl, err := NewClient(TestingConfig()) cl, err := NewClient(cfg)
require.NoError(t, err) require.NoError(t, err)
defer cl.Close() defer cl.Close()
tt, _ := cl.AddTorrentInfoHash(ih) tt, _ := cl.AddTorrentInfoHash(ih)

View File

@ -16,20 +16,10 @@ import (
"github.com/anacrolix/torrent/storage" "github.com/anacrolix/torrent/storage"
) )
var DefaultHTTPClient = &http.Client{
Timeout: time.Second * 15,
Transport: &http.Transport{
Dial: (&net.Dialer{
Timeout: 15 * time.Second,
}).Dial,
TLSHandshakeTimeout: 15 * time.Second,
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
},
}
var DefaultHTTPUserAgent = "Go-Torrent/1.0" var DefaultHTTPUserAgent = "Go-Torrent/1.0"
// Override Client defaults. // Probably not safe to modify this after it's given to a Client.
type Config struct { type ClientConfig struct {
// Store torrent file data in this directory unless .DefaultStorage is // Store torrent file data in this directory unless .DefaultStorage is
// specified. // specified.
DataDir string `long:"data-dir" description:"directory to store downloaded torrent data"` DataDir string `long:"data-dir" description:"directory to store downloaded torrent data"`
@ -120,7 +110,7 @@ type Config struct {
PublicIp6 net.IP PublicIp6 net.IP
} }
func (cfg *Config) SetListenAddr(addr string) *Config { func (cfg *ClientConfig) SetListenAddr(addr string) *ClientConfig {
host, port, err := missinggo.ParseHostPort(addr) host, port, err := missinggo.ParseHostPort(addr)
expect.Nil(err) expect.Nil(err)
cfg.ListenHost = func(string) string { return host } cfg.ListenHost = func(string) string { return host }
@ -128,53 +118,35 @@ func (cfg *Config) SetListenAddr(addr string) *Config {
return cfg return cfg
} }
func (cfg *Config) setDefaults() { func NewDefaultClientConfig() *ClientConfig {
if cfg.HTTP == nil { return &ClientConfig{
cfg.HTTP = DefaultHTTPClient HTTP: &http.Client{
if cfg.ProxyURL != "" { Timeout: time.Second * 15,
cfg.setProxyURL() Transport: &http.Transport{
} Dial: (&net.Dialer{
} Timeout: 15 * time.Second,
if cfg.HTTPUserAgent == "" { }).Dial,
cfg.HTTPUserAgent = DefaultHTTPUserAgent TLSHandshakeTimeout: 15 * time.Second,
} TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
if cfg.ExtendedHandshakeClientVersion == "" { }},
cfg.ExtendedHandshakeClientVersion = "go.torrent dev 20150624" HTTPUserAgent: DefaultHTTPUserAgent,
} ExtendedHandshakeClientVersion: "go.torrent dev 20150624",
if cfg.Bep20 == "" { Bep20: "-GT0001-",
cfg.Bep20 = "-GT0001-" NominalDialTimeout: 30 * time.Second,
} MinDialTimeout: 5 * time.Second,
if cfg.NominalDialTimeout == 0 { EstablishedConnsPerTorrent: 50,
cfg.NominalDialTimeout = 30 * time.Second HalfOpenConnsPerTorrent: 25,
} TorrentPeersHighWater: 500,
if cfg.MinDialTimeout == 0 { TorrentPeersLowWater: 50,
cfg.MinDialTimeout = 5 * time.Second HandshakesTimeout: 20 * time.Second,
} DhtStartingNodes: dht.GlobalBootstrapAddrs,
if cfg.EstablishedConnsPerTorrent == 0 { ListenHost: func(string) string { return "" },
cfg.EstablishedConnsPerTorrent = 50 UploadRateLimiter: unlimited,
} DownloadRateLimiter: unlimited,
if cfg.HalfOpenConnsPerTorrent == 0 {
cfg.HalfOpenConnsPerTorrent = (cfg.EstablishedConnsPerTorrent + 1) / 2
}
if cfg.TorrentPeersHighWater == 0 {
// Memory and freshness are the concern here.
cfg.TorrentPeersHighWater = 500
}
if cfg.TorrentPeersLowWater == 0 {
cfg.TorrentPeersLowWater = 2 * cfg.HalfOpenConnsPerTorrent
}
if cfg.HandshakesTimeout == 0 {
cfg.HandshakesTimeout = 20 * time.Second
}
if cfg.DhtStartingNodes == nil {
cfg.DhtStartingNodes = dht.GlobalBootstrapAddrs
}
if cfg.ListenHost == nil {
cfg.ListenHost = func(string) string { return "" }
} }
} }
func (cfg *Config) setProxyURL() { func (cfg *ClientConfig) setProxyURL() {
fixedURL, err := url.Parse(cfg.ProxyURL) fixedURL, err := url.Parse(cfg.ProxyURL)
if err != nil { if err != nil {
return return

View File

@ -1308,7 +1308,7 @@ another:
return false return false
} }
for r := range c.PeerRequests { for r := range c.PeerRequests {
res := c.t.cl.uploadLimit.ReserveN(time.Now(), int(r.Length)) res := c.t.cl.config.UploadRateLimiter.ReserveN(time.Now(), int(r.Length))
if !res.OK() { if !res.OK() {
panic(fmt.Sprintf("upload rate limiter burst size < %d", r.Length)) panic(fmt.Sprintf("upload rate limiter burst size < %d", r.Length))
} }

View File

@ -21,7 +21,9 @@ import (
// Have that would potentially alter it. // Have that would potentially alter it.
func TestSendBitfieldThenHave(t *testing.T) { func TestSendBitfieldThenHave(t *testing.T) {
r, w := io.Pipe() r, w := io.Pipe()
var cl Client cl := Client{
config: &ClientConfig{DownloadRateLimiter: unlimited},
}
cl.initLogger() cl.initLogger()
c := cl.newConnection(nil, false) c := cl.newConnection(nil, false)
c.setTorrent(cl.newTorrent(metainfo.Hash{}, nil)) c.setTorrent(cl.newTorrent(metainfo.Hash{}, nil))
@ -87,7 +89,9 @@ func (me *torrentStorage) WriteAt(b []byte, _ int64) (int, error) {
func BenchmarkConnectionMainReadLoop(b *testing.B) { func BenchmarkConnectionMainReadLoop(b *testing.B) {
cl := &Client{ cl := &Client{
downloadLimit: unlimited, config: &ClientConfig{
DownloadRateLimiter: unlimited,
},
} }
ts := &torrentStorage{} ts := &torrentStorage{}
t := &Torrent{ t := &Torrent{