10 "github.com/anacrolix/missinggo/v2/resource"
12 "github.com/anacrolix/torrent/metainfo"
15 type piecePerResource struct {
19 func NewResourcePieces(p resource.Provider) ClientImpl {
20 return &piecePerResource{
25 func (s *piecePerResource) OpenTorrent(info *metainfo.Info, infoHash metainfo.Hash) (TorrentImpl, error) {
29 func (s *piecePerResource) Close() error {
33 func (s *piecePerResource) Piece(p metainfo.Piece) PieceImpl {
34 return piecePerResourcePiece{
40 type piecePerResourcePiece struct {
45 func (s piecePerResourcePiece) Completion() Completion {
46 fi, err := s.completed().Stat()
48 Complete: err == nil && fi.Size() == s.mp.Length(),
53 func (s piecePerResourcePiece) MarkComplete() error {
54 incompleteChunks := s.getChunks()
55 err := s.completed().Put(io.NewSectionReader(incompleteChunks, 0, s.mp.Length()))
57 for _, c := range incompleteChunks {
64 func (s piecePerResourcePiece) MarkNotComplete() error {
65 return s.completed().Delete()
68 func (s piecePerResourcePiece) ReadAt(b []byte, off int64) (int, error) {
69 if s.Completion().Complete {
70 return s.completed().ReadAt(b, off)
72 return s.getChunks().ReadAt(b, off)
75 func (s piecePerResourcePiece) WriteAt(b []byte, off int64) (n int, err error) {
76 i, err := s.rp.NewInstance(path.Join(s.incompleteDirPath(), strconv.FormatInt(off, 10)))
80 r := bytes.NewReader(b)
88 instance resource.Instance
93 func (me chunks) ReadAt(b []byte, off int64) (int, error) {
98 if me[0].offset <= off {
103 n, err := me[0].instance.ReadAt(b, off-me[0].offset)
107 if err == nil || err == io.EOF {
108 n_, err := me[1:].ReadAt(b[n:], off+int64(n))
114 func (s piecePerResourcePiece) getChunks() (chunks chunks) {
115 names, err := s.incompleteDir().Readdirnames()
119 for _, n := range names {
120 offset, err := strconv.ParseInt(n, 10, 64)
124 i, err := s.rp.NewInstance(path.Join(s.incompleteDirPath(), n))
128 chunks = append(chunks, chunk{offset, i})
130 sort.Slice(chunks, func(i, j int) bool {
131 return chunks[i].offset < chunks[j].offset
136 func (s piecePerResourcePiece) completed() resource.Instance {
137 i, err := s.rp.NewInstance(path.Join("completed", s.mp.Hash().HexString()))
144 func (s piecePerResourcePiece) incompleteDirPath() string {
145 return path.Join("incompleted", s.mp.Hash().HexString())
148 func (s piecePerResourcePiece) incompleteDir() resource.DirInstance {
149 i, err := s.rp.NewInstance(s.incompleteDirPath())
153 return i.(resource.DirInstance)