kraken
142 строки · 3.9 Кб
1// Copyright (c) 2016-2019 Uber Technologies, Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14package originstorage15
16import (17"errors"18"fmt"19
20"github.com/uber/kraken/core"21"github.com/uber/kraken/lib/store"22"github.com/uber/kraken/lib/torrent/storage"23"github.com/uber/kraken/lib/torrent/storage/piecereader"24
25"github.com/willf/bitset"26"go.uber.org/atomic"27)
28
29// Torrent errors.
30var (31ErrReadOnly = errors.New("Read-only torrent is being written to")32)
33
34// Torrent is a read-only storage.Torrent. It allows concurrent reads on all
35// pieces.
36type Torrent struct {37metaInfo *core.MetaInfo38cas *store.CAStore39numComplete *atomic.Int3240}
41
42// NewTorrent creates a new Torrent.
43func NewTorrent(cas *store.CAStore, mi *core.MetaInfo) (*Torrent, error) {44return &Torrent{45cas: cas,46metaInfo: mi,47numComplete: atomic.NewInt32(int32(mi.NumPieces())),48}, nil49}
50
51// Digest returns the digest of the target blob.
52func (t *Torrent) Digest() core.Digest {53return t.metaInfo.Digest()54}
55
56// Stat returns the TorrentInfo for t.
57func (t *Torrent) Stat() *storage.TorrentInfo {58return storage.NewTorrentInfo(t.metaInfo, t.Bitfield())59}
60
61// InfoHash returns the torrent metainfo hash.
62func (t *Torrent) InfoHash() core.InfoHash {63return t.metaInfo.InfoHash()64}
65
66// NumPieces returns the number of pieces in the torrent.
67func (t *Torrent) NumPieces() int {68return t.metaInfo.NumPieces()69}
70
71// Length returns the length of the target file.
72func (t *Torrent) Length() int64 {73return t.metaInfo.Length()74}
75
76// PieceLength returns the length of piece pi.
77func (t *Torrent) PieceLength(pi int) int64 {78return t.metaInfo.GetPieceLength(pi)79}
80
81// MaxPieceLength returns the longest piece length of the torrent.
82func (t *Torrent) MaxPieceLength() int64 {83return t.PieceLength(0)84}
85
86// Complete is always true.
87func (t *Torrent) Complete() bool {88return true89}
90
91// BytesDownloaded always returns the total number of bytes.
92func (t *Torrent) BytesDownloaded() int64 {93return t.metaInfo.Length()94}
95
96// WritePiece returns error, since Torrent is read-only.
97func (t *Torrent) WritePiece(src storage.PieceReader, pi int) error {98return ErrReadOnly99}
100
101// Bitfield always returns a completed bitfield.
102func (t *Torrent) Bitfield() *bitset.BitSet {103return bitset.New(uint(t.NumPieces())).Complement()104}
105
106func (t *Torrent) String() string {107downloaded := int(float64(t.BytesDownloaded()) / float64(t.metaInfo.Length()) * 100)108return fmt.Sprintf("torrent(hash=%s, downloaded=%d%%)", t.InfoHash().Hex(), downloaded)109}
110
111type opener struct {112torrent *Torrent113}
114
115func (o *opener) Open() (store.FileReader, error) {116return o.torrent.cas.GetCacheFileReader(o.torrent.Digest().Hex())117}
118
119// GetPieceReader returns a reader for piece pi.
120func (t *Torrent) GetPieceReader(pi int) (storage.PieceReader, error) {121if pi >= t.NumPieces() {122return nil, fmt.Errorf("invalid piece index %d: num pieces = %d", pi, t.NumPieces())123}124return piecereader.NewFileReader(t.getFileOffset(pi), t.PieceLength(pi), &opener{t}), nil125}
126
127// HasPiece returns if piece pi is complete.
128// For Torrent it's always true.
129func (t *Torrent) HasPiece(pi int) bool {130return true131}
132
133// MissingPieces always returns empty list.
134func (t *Torrent) MissingPieces() []int {135return []int{}136}
137
138// getFileOffset calculates the offset in the torrent file given piece index.
139// Assumes pi is a valid piece index.
140func (t *Torrent) getFileOffset(pi int) int64 {141return t.metaInfo.PieceLength() * int64(pi)142}
143