]> Sergey Matveev's repositories - btrtrc.git/commitdiff
Add piece blob torrent.Data storage, and move testutil to internal/, add basic transf...
authorMatt Joiner <anacrolix@gmail.com>
Thu, 26 Feb 2015 14:46:02 +0000 (01:46 +1100)
committerMatt Joiner <anacrolix@gmail.com>
Thu, 26 Feb 2015 14:46:02 +0000 (01:46 +1100)
client_test.go
data/blob/blob.go [new file with mode: 0644]
fs/torrentfs_test.go
internal/testutil/testutil.go [moved from testutil/testutil.go with 98% similarity]

index c480fecd66c8266a9a72002d2d78d541019acccb..d873fbe1a7e37e4a68b8a286136f0b187626b735 100644 (file)
@@ -1,19 +1,35 @@
 package torrent
 
 import (
+       "encoding/binary"
        "fmt"
+       "io"
+       "io/ioutil"
        "log"
        "net"
        "os"
        "testing"
        "time"
 
-       "bitbucket.org/anacrolix/go.torrent/testutil"
+       "bitbucket.org/anacrolix/go.torrent/data/blob"
+       "github.com/anacrolix/libtorgo/metainfo"
+
+       "github.com/bradfitz/iter"
+
+       "bitbucket.org/anacrolix/go.torrent/internal/testutil"
        "bitbucket.org/anacrolix/go.torrent/util"
        "bitbucket.org/anacrolix/utp"
        "github.com/anacrolix/libtorgo/bencode"
 )
 
+var TestingConfig = Config{
+       ListenAddr:           ":0",
+       NoDHT:                true,
+       DisableTrackers:      true,
+       NoDefaultBlocklist:   true,
+       DisableMetainfoCache: true,
+}
+
 func TestClientDefault(t *testing.T) {
        cl, err := NewClient(&Config{
                NoDefaultBlocklist: true,
@@ -74,7 +90,7 @@ func TestTorrentInitialState(t *testing.T) {
        if err != nil {
                t.Fatal(err)
        }
-       if len(tor.Pieces) != 1 {
+       if len(tor.Pieces) != 3 {
                t.Fatal("wrong number of pieces")
        }
        p := tor.Pieces[0]
@@ -82,10 +98,13 @@ func TestTorrentInitialState(t *testing.T) {
        if len(p.PendingChunkSpecs) != 1 {
                t.Fatalf("should only be 1 chunk: %v", p.PendingChunkSpecs)
        }
-       if _, ok := p.PendingChunkSpecs[chunkSpec{
-               Length: 13,
-       }]; !ok {
-               t.Fatal("pending chunk spec is incorrect")
+       // TODO: Set chunkSize to 2, to test odd/even silliness.
+       if false {
+               if _, ok := p.PendingChunkSpecs[chunkSpec{
+                       Length: 13,
+               }]; !ok {
+                       t.Fatal("pending chunk spec is incorrect")
+               }
        }
 }
 
@@ -208,3 +227,51 @@ func TestTwoClientsArbitraryPorts(t *testing.T) {
                defer cl.Stop()
        }
 }
+
+func TestAddDropManyTorrents(t *testing.T) {
+       cl, _ := NewClient(&TestingConfig)
+       defer cl.Stop()
+       var m Magnet
+       for i := range iter.N(1000) {
+               binary.PutVarint(m.InfoHash[:], int64(i))
+               cl.AddMagnet(m.String())
+       }
+}
+
+func TestClientTransfer(t *testing.T) {
+       greetingTempDir, mi := testutil.GreetingTestTorrent()
+       defer os.RemoveAll(greetingTempDir)
+       cfg := TestingConfig
+       cfg.DataDir = greetingTempDir
+       seeder, err := NewClient(&cfg)
+       if err != nil {
+               t.Fatal(err)
+       }
+       defer seeder.Stop()
+       seeder.AddTorrent(mi)
+       leecherDataDir, err := ioutil.TempDir("", "")
+       if err != nil {
+               t.Fatal(err)
+       }
+       defer os.RemoveAll(leecherDataDir)
+       cfg.TorrentDataOpener = func(info *metainfo.Info) (Data, error) {
+               return blob.TorrentData(info, leecherDataDir), nil
+       }
+       leecher, _ := NewClient(&cfg)
+       defer leecher.Stop()
+       leecherGreeting, _ := leecher.AddTorrent(mi)
+       leecherGreeting.AddPeers([]Peer{
+               Peer{
+                       IP:   util.AddrIP(seeder.ListenAddr()),
+                       Port: util.AddrPort(seeder.ListenAddr()),
+               },
+       })
+       _greeting, err := ioutil.ReadAll(io.NewSectionReader(leecherGreeting, 0, leecherGreeting.Length()))
+       if err != nil {
+               t.Fatal(err)
+       }
+       greeting := string(_greeting)
+       if greeting != testutil.GreetingFileContents {
+               t.Fatal(":(")
+       }
+}
diff --git a/data/blob/blob.go b/data/blob/blob.go
new file mode 100644 (file)
index 0000000..43657f2
--- /dev/null
@@ -0,0 +1,127 @@
+package blob
+
+import (
+       "encoding/hex"
+       "errors"
+       "io"
+       "os"
+
+       "github.com/anacrolix/libtorgo/metainfo"
+)
+
+type data struct {
+       info    *metainfo.Info
+       baseDir string
+}
+
+func TorrentData(info *metainfo.Info, baseDir string) *data {
+       return &data{info, baseDir}
+}
+
+func (me *data) pieceHashHex(i int) string {
+       return hex.EncodeToString(me.info.Pieces[i*20 : (i+1)*20])
+}
+
+func (me *data) Close() {}
+
+func (me *data) ReadAt(p []byte, off int64) (n int, err error) {
+       hash := me.pieceHashHex(int(off / me.info.PieceLength))
+       f, err := os.Open(me.baseDir + "/complete/" + hash)
+       if os.IsNotExist(err) {
+               f, err = os.Open(me.baseDir + "/incomplete/" + hash)
+               if os.IsNotExist(err) {
+                       err = io.EOF
+                       return
+               }
+               if err != nil {
+                       return
+               }
+       } else if err != nil {
+               return
+       }
+       defer f.Close()
+       off %= me.info.PieceLength
+       return f.ReadAt(p, off)
+}
+
+func (me *data) openComplete(piece int) (f *os.File, err error) {
+       return os.OpenFile(me.baseDir+"/complete/"+me.pieceHashHex(piece), os.O_RDWR, 0660)
+}
+
+func (me *data) WriteAt(p []byte, off int64) (n int, err error) {
+       i := int(off / me.info.PieceLength)
+       off %= me.info.PieceLength
+       for len(p) != 0 {
+               _, err = os.Stat(me.baseDir + "/complete/" + me.pieceHashHex(i))
+               if err == nil {
+                       err = errors.New("can't write to completed piece")
+                       return
+               }
+               os.MkdirAll(me.baseDir+"/incomplete", 0750)
+               var f *os.File
+               f, err = os.OpenFile(me.baseDir+"/incomplete/"+me.pieceHashHex(i), os.O_WRONLY|os.O_CREATE, 0640)
+               if err != nil {
+                       return
+               }
+               p1 := p
+               maxN := me.info.Piece(i).Length() - off
+               if int64(len(p1)) > maxN {
+                       p1 = p1[:maxN]
+               }
+               var n1 int
+               n1, err = f.WriteAt(p1, off)
+               f.Close()
+               n += n1
+               if err != nil {
+                       return
+               }
+               p = p[n1:]
+               off = 0
+       }
+       return
+}
+
+func (me *data) pieceReader(piece int, off int64) (ret io.ReadCloser, err error) {
+       hash := me.pieceHashHex(piece)
+       f, err := os.Open(me.baseDir + "/complete/" + hash)
+       if os.IsNotExist(err) {
+               f, err = os.Open(me.baseDir + "/incomplete/" + hash)
+               if os.IsNotExist(err) {
+                       err = io.EOF
+                       return
+               }
+               if err != nil {
+                       return
+               }
+       } else if err != nil {
+               return
+       }
+       return struct {
+               io.Reader
+               io.Closer
+       }{io.NewSectionReader(f, off, me.info.Piece(piece).Length()-off), f}, nil
+}
+
+func (me *data) WriteSectionTo(w io.Writer, off, n int64) (written int64, err error) {
+       i := int(off / me.info.PieceLength)
+       off %= me.info.PieceLength
+       for n != 0 {
+               var pr io.ReadCloser
+               pr, err = me.pieceReader(i, off)
+               if err != nil {
+                       if err == io.EOF {
+                               err = nil
+                       }
+                       return
+               }
+               var n1 int64
+               n1, err = io.CopyN(w, pr, n)
+               written += n1
+               n -= n1
+               if err != nil {
+                       return
+               }
+               off = 0
+       }
+       return
+}
index 72b932c189a95380a56aa918d51de11f7cdbf41c..69df66b02bb3db0891696844c2a138980a9fa9ca 100644 (file)
@@ -18,7 +18,7 @@ import (
 
        "bitbucket.org/anacrolix/go.torrent"
        "bitbucket.org/anacrolix/go.torrent/data/mmap"
-       "bitbucket.org/anacrolix/go.torrent/testutil"
+       "bitbucket.org/anacrolix/go.torrent/internal/testutil"
        "bitbucket.org/anacrolix/go.torrent/util"
 
        "github.com/anacrolix/libtorgo/metainfo"
@@ -27,10 +27,6 @@ import (
        fusefs "bazil.org/fuse/fs"
 )
 
-func init() {
-       go http.ListenAndServe(":6061", nil)
-}
-
 func TestTCPAddrString(t *testing.T) {
        l, err := net.Listen("tcp4", "localhost:0")
        if err != nil {
similarity index 98%
rename from testutil/testutil.go
rename to internal/testutil/testutil.go
index db0462530723bd12c667941c4245136a768595ca..af1230f6f0f8bfff82efc5afe22c9b2a6e80d34a 100644 (file)
@@ -29,6 +29,7 @@ func CreateMetaInfo(name string, w io.Writer) {
        builder := metainfo.Builder{}
        builder.AddFile(name)
        builder.AddAnnounceGroup([]string{"lol://cheezburger"})
+       builder.SetPieceLength(5)
        batch, err := builder.Submit()
        if err != nil {
                panic(err)