lib/torrent/storage/piecereader/file.go (46 lines of code) (raw):
// Copyright (c) 2016-2019 Uber Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package piecereader
import (
"fmt"
"io"
"github.com/uber/kraken/lib/store"
)
// Opener opens files.
type Opener interface {
Open() (store.FileReader, error)
}
// FileReader is a storage.PieceReader which reads a piece from a file.
type FileReader struct {
offset int64
length int64
opener Opener
closer io.Closer
reader io.Reader
}
// NewFileReader creates a FileReader which reads a piece from f. f should not
// be used once it is given to a FileReader.
func NewFileReader(offset, length int64, opener Opener) *FileReader {
return &FileReader{
offset: offset,
length: length,
opener: opener,
}
}
// Read reads a piece in p.
func (r *FileReader) Read(p []byte) (int, error) {
if r.reader == nil {
f, err := r.opener.Open()
if err != nil {
return 0, fmt.Errorf("open: %s", err)
}
if _, err := f.Seek(r.offset, io.SeekStart); err != nil {
return 0, fmt.Errorf("seek: %s", err)
}
r.reader = io.LimitReader(f, r.length)
r.closer = f
}
return r.reader.Read(p)
}
// Close closes the underlying file.
func (r *FileReader) Close() error {
if r.closer == nil {
return nil
}
return r.closer.Close()
}
// Length returns the length of the piece.
func (r *FileReader) Length() int {
return int(r.length)
}