├── LICENSE ├── README ├── main.go └── vendor ├── github.com ├── anacrolix │ ├── envpprof │ │ ├── LICENSE │ │ └── envpprof.go │ ├── missinggo │ │ ├── LICENSE │ │ ├── addr.go │ │ ├── atime.go │ │ ├── atime_atim.go │ │ ├── atime_atimespec.go │ │ ├── atime_plan9.go │ │ ├── atime_windows.go │ │ ├── bitmap │ │ │ └── bitmap.go │ │ ├── certdir.go │ │ ├── chancond.go │ │ ├── chans │ │ │ └── drain.go │ │ ├── cmd │ │ │ ├── filecache │ │ │ │ └── main.go │ │ │ ├── go-env │ │ │ │ └── main.go │ │ │ ├── http-file-server │ │ │ │ └── main.go │ │ │ ├── nop │ │ │ │ └── main.go │ │ │ ├── query-escape │ │ │ │ └── main.go │ │ │ └── query-unescape │ │ │ │ └── main.go │ │ ├── copy.go │ │ ├── croak.go │ │ ├── ctrlflow │ │ │ └── ctrlflow.go │ │ ├── doc.go │ │ ├── docopt │ │ │ └── docopt.go │ │ ├── empty_value.go │ │ ├── event.go │ │ ├── event_synchronized.go │ │ ├── expvarIndentMap.go │ │ ├── filecache │ │ │ ├── cache.go │ │ │ ├── file.go │ │ │ ├── fs.go │ │ │ ├── lruitems.go │ │ │ └── uniform.go │ │ ├── flag.go │ │ ├── fs.go │ │ ├── futures │ │ │ ├── funcs.go │ │ │ └── future.go │ │ ├── hostmaybeport.go │ │ ├── hostport.go │ │ ├── http.go │ │ ├── httpfile │ │ │ ├── defaultfs.go │ │ │ ├── file.go │ │ │ ├── fs.go │ │ │ └── misc.go │ │ ├── httpmux │ │ │ └── httpmux.go │ │ ├── httpresponsestatus.go │ │ ├── httptoo │ │ │ ├── bytes_content_range.go │ │ │ ├── client.go │ │ │ ├── gzip.go │ │ │ ├── httptoo.go │ │ │ ├── inproc_roundtrip.go │ │ │ ├── middleware.go │ │ │ ├── reverse_proxy.go │ │ │ └── url.go │ │ ├── inherit.go │ │ ├── inproc │ │ │ └── inproc.go │ │ ├── ioutil.go │ │ ├── itertools │ │ │ ├── groupby.go │ │ │ ├── iterable.go │ │ │ ├── iterator.go │ │ │ └── iterutils.go │ │ ├── jitter.go │ │ ├── limitlen.go │ │ ├── max.go │ │ ├── monotonic.go │ │ ├── openflags.go │ │ ├── orderedmap │ │ │ ├── google_btree.go │ │ │ ├── orderedmap.go │ │ │ └── skiplist.go │ │ ├── path.go │ │ ├── perf │ │ │ ├── mutex.go │ │ │ └── perf.go │ │ ├── pproffd │ │ │ └── pproffd.go │ │ ├── prioritybitmap │ │ │ ├── iter.go │ │ │ └── prioritybitmap.go │ │ ├── pubsub │ │ │ └── pubsub.go │ │ ├── resource │ │ │ ├── http.go │ │ │ ├── osfile.go │ │ │ ├── provider.go │ │ │ └── resource.go │ │ ├── rle.go │ │ ├── section_read_seeker.go │ │ ├── section_writer.go │ │ ├── selfcert.go │ │ ├── singleflight.go │ │ ├── slices │ │ │ ├── cast.go │ │ │ ├── doc.go │ │ │ ├── map.go │ │ │ ├── sort.go │ │ │ └── sorter.go │ │ ├── stack.go │ │ ├── strbool.go │ │ ├── sync.go │ │ ├── testing.go │ │ ├── timer.go │ │ ├── units.go │ │ ├── url.go │ │ ├── wait_event.go │ │ └── wolf.go │ ├── tagflag │ │ ├── arg.go │ │ ├── arity.go │ │ ├── builtin.go │ │ ├── bytes.go │ │ ├── doc.go │ │ ├── errors.go │ │ ├── marshalers.go │ │ ├── misc.go │ │ ├── parseopt.go │ │ ├── parser.go │ │ ├── tagflag.go │ │ └── usage.go │ └── torrent │ │ ├── bencode │ │ ├── LICENSE │ │ ├── api.go │ │ ├── bytes.go │ │ ├── decode.go │ │ ├── encode.go │ │ ├── fuzz.go │ │ └── tags.go │ │ ├── metainfo │ │ ├── LICENSE │ │ ├── hash.go │ │ ├── info.go │ │ ├── magnet.go │ │ ├── metainfo.go │ │ ├── nodes.go │ │ ├── piece.go │ │ └── piece_key.go │ │ ├── tracker │ │ ├── LICENSE │ │ ├── http.go │ │ ├── server.go │ │ ├── tracker.go │ │ └── udp.go │ │ └── util │ │ ├── LICENSE │ │ ├── dirwatch │ │ └── dirwatch.go │ │ └── types.go └── sprt │ └── byt │ ├── LICENSE │ └── byt.go └── manifest /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 sprt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Ratioboss simulates data download and upload in order to boost your ratio 2 | on BitTorrent trackers. No data actually flows between you and other peers, 3 | thus data usage is marginal. Be aware that aside from the transfer speeds 4 | being fuzzed, no attempts are made at avoiding detection; 5 | it is therefore recommended to point this tool at popular torrents. 6 | 7 | Here is an example of a ratioboss session set up to download a file 8 | at 5 MiB/s and upload at 2 MiB/s: 9 | 10 | $ ratioboss -down 5M -up 2M foo.torrent 11 | 9:31PM Torrent name: Foo 12 | 9:31PM Torrent size: 8.80 GiB 13 | 9:31PM Announce: 0.00 B downloaded, 0.00 B uploaded 14 | 9:31PM Next announce: 10:31PM 15 | 10:31PM Announce: 8.80 GiB downloaded, 2.64 GiB uploaded 16 | 10:31PM Next announce: 11:31PM 17 | ^C10:45PM Quitting... 18 | 10:46PM Announce: 8.80 GiB downloaded, 4.83 GiB uploaded 19 | 20 | INSTALLATION 21 | 22 | If you have Go installed: 23 | 24 | $ go get github.com/sprt/ratioboss 25 | 26 | Or you can download a precompiled binary at: 27 | 28 | https://github.com/sprt/ratioboss/releases 29 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | // Ratioboss simulates data download and upload in order to boost your ratio 2 | // on BitTorrent trackers. No data actually flows between you and other peers, 3 | // thus data usage is marginal. Be aware that aside from the transfer speeds 4 | // being fuzzed, no attempts are made at avoiding detection; 5 | // it is therefore recommended to point this tool at popular torrents. 6 | // 7 | // Here is an example of a ratioboss session set up to download a file 8 | // at 5 MiB/s and upload at 2 MiB/s: 9 | // 10 | // $ ratioboss -down 5M -up 2M foo.torrent 11 | // 9:31PM Torrent name: Foo 12 | // 9:31PM Torrent size: 8.80 GiB 13 | // 9:31PM Announce: 0.00 B downloaded, 0.00 B uploaded 14 | // 9:31PM Next announce: 10:31PM 15 | // 10:31PM Announce: 8.80 GiB downloaded, 2.64 GiB uploaded 16 | // 10:31PM Next announce: 11:31PM 17 | // ^C10:45PM Quitting... 18 | // 10:46PM Announce: 8.80 GiB downloaded, 4.83 GiB uploaded 19 | // 20 | package main 21 | 22 | import ( 23 | "flag" 24 | "fmt" 25 | "log" 26 | "math/rand" 27 | "os" 28 | "os/signal" 29 | "time" 30 | 31 | "github.com/anacrolix/torrent/metainfo" 32 | "github.com/anacrolix/torrent/tracker" 33 | "github.com/sprt/byt" 34 | ) 35 | 36 | const ( 37 | noise = 0.3 38 | retryInterval = 30 * time.Second 39 | ) 40 | 41 | var ( 42 | downSpeed, upSpeed byt.Size 43 | 44 | announceURL string 45 | hash, peerID metainfo.Hash 46 | size byt.Size 47 | 48 | complete, stall bool 49 | down, up byt.Size 50 | interval <-chan time.Time 51 | lastResp time.Time 52 | ) 53 | 54 | func init() { 55 | flag.Usage = usage 56 | flag.Var(&downSpeed, "down", "download speed") 57 | flag.Var(&upSpeed, "up", "upload speed") 58 | 59 | log.SetFlags(0) 60 | log.SetOutput(new(logWriter)) 61 | 62 | rand.Seed(time.Now().UnixNano()) 63 | } 64 | 65 | func main() { 66 | flag.Parse() 67 | if downSpeed == 0 || upSpeed == 0 || flag.NArg() != 1 { 68 | flag.Usage() 69 | os.Exit(1) 70 | } 71 | 72 | meta, err := metainfo.LoadFromFile(flag.Arg(0)) 73 | if err != nil { 74 | fmt.Fprint(os.Stderr, err) 75 | os.Exit(1) 76 | } 77 | 78 | interrupt := make(chan os.Signal, 1) 79 | signal.Notify(interrupt, os.Interrupt) 80 | 81 | _, err = rand.Read(peerID[:]) 82 | if err != nil { 83 | fmt.Fprintln(os.Stderr, err) 84 | os.Exit(1) 85 | } 86 | 87 | announceURL = meta.Announce 88 | hash = meta.HashInfoBytes() 89 | info := meta.UnmarshalInfo() 90 | size = byt.Size(info.TotalLength()) 91 | 92 | log.Printf("Torrent name: %s", info.Name) 93 | log.Printf("Torrent size: %.2f", size.Binary()) 94 | 95 | announce(tracker.Started) 96 | loop: 97 | for { 98 | select { 99 | case <-interval: 100 | announce(tracker.None) 101 | case <-interrupt: 102 | break loop 103 | } 104 | } 105 | log.Println("Quitting...") 106 | announce(tracker.Stopped) 107 | } 108 | 109 | func usage() { 110 | fmt.Fprintf(os.Stderr, "Usage: %s -down -up \n", os.Args[0]) 111 | fmt.Fprintf(os.Stderr, "%s", byt.FlagUsage) 112 | } 113 | 114 | func announce(event tracker.AnnounceEvent) { 115 | if !lastResp.IsZero() && !stall { 116 | elapsed := time.Since(lastResp).Seconds() 117 | down = min(size, down+byt.Size(elapsed*fuzz(downSpeed))) 118 | if down == size && !complete { 119 | event = tracker.Completed 120 | complete = true 121 | } 122 | up += byt.Size(elapsed * fuzz(upSpeed)) 123 | } 124 | 125 | log.Printf("Announce: %.2f downloaded, %.2f uploaded", down.Binary(), up.Binary()) 126 | req := &tracker.AnnounceRequest{ 127 | InfoHash: hash, 128 | PeerId: peerID, 129 | Downloaded: int64(down), 130 | Left: uint64(size - down), 131 | Uploaded: int64(up), 132 | Event: event, 133 | NumWant: -1, 134 | } 135 | resp, err := tracker.Announce(announceURL, req) 136 | lastResp = time.Now() 137 | if err != nil { 138 | if event == tracker.Stopped { 139 | log.Println("Announce error") 140 | interval = nil 141 | return 142 | } 143 | log.Println("Announce error, retrying in", retryInterval) 144 | interval = time.After(retryInterval) 145 | return 146 | } 147 | 148 | if event == tracker.Stopped { 149 | interval = nil 150 | return 151 | } 152 | nextInterval := time.Duration(resp.Interval) * time.Second 153 | log.Println("Next announce:", time.Now().Add(nextInterval).Format(time.Kitchen)) 154 | interval = time.After(nextInterval) 155 | } 156 | 157 | func fuzz(n byt.Size) float64 { 158 | return float64(n) + (rand.Float64()-0.5)*2*noise*float64(n) 159 | } 160 | 161 | func min(a, b byt.Size) byt.Size { 162 | if a < b { 163 | return a 164 | } 165 | return b 166 | } 167 | 168 | type logWriter struct{} 169 | 170 | func (writer logWriter) Write(bytes []byte) (int, error) { 171 | return fmt.Print(time.Now().Format(time.Kitchen) + " " + string(bytes)) 172 | } 173 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/envpprof/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Matt Joiner 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/envpprof/envpprof.go: -------------------------------------------------------------------------------- 1 | package envpprof 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "log" 7 | "net" 8 | "net/http" 9 | _ "net/http/pprof" 10 | "os" 11 | "path/filepath" 12 | "runtime" 13 | "runtime/pprof" 14 | "strings" 15 | ) 16 | 17 | var ( 18 | pprofDir = filepath.Join(os.Getenv("HOME"), "pprof") 19 | heap bool 20 | ) 21 | 22 | func writeHeapProfile() { 23 | os.Mkdir(pprofDir, 0750) 24 | f, err := ioutil.TempFile(pprofDir, "heap") 25 | if err != nil { 26 | log.Printf("error creating heap profile file: %s", err) 27 | return 28 | } 29 | defer f.Close() 30 | pprof.WriteHeapProfile(f) 31 | log.Printf("wrote heap profile to %q", f.Name()) 32 | } 33 | 34 | func Stop() { 35 | pprof.StopCPUProfile() 36 | if heap { 37 | writeHeapProfile() 38 | } 39 | } 40 | 41 | func startHTTP() { 42 | var l net.Listener 43 | for port := uint16(6061); port != 6060; port++ { 44 | var err error 45 | l, err = net.Listen("tcp", fmt.Sprintf("localhost:%d", port)) 46 | if err == nil { 47 | break 48 | } 49 | } 50 | if l == nil { 51 | log.Print("unable to create envpprof listener for http") 52 | return 53 | } 54 | log.Printf("envpprof serving http://%s", l.Addr()) 55 | go func() { 56 | defer l.Close() 57 | log.Printf("error serving http on envpprof listener: %s", http.Serve(l, nil)) 58 | }() 59 | } 60 | 61 | func init() { 62 | _var := os.Getenv("GOPPROF") 63 | if _var == "" { 64 | return 65 | } 66 | for _, item := range strings.Split(os.Getenv("GOPPROF"), ",") { 67 | equalsPos := strings.IndexByte(item, '=') 68 | var key, value string 69 | if equalsPos < 0 { 70 | key = item 71 | } else { 72 | key = item[:equalsPos] 73 | value = item[equalsPos+1:] 74 | } 75 | if value != "" { 76 | log.Printf("values not yet supported") 77 | } 78 | switch key { 79 | case "http": 80 | startHTTP() 81 | case "cpu": 82 | os.Mkdir(pprofDir, 0750) 83 | f, err := ioutil.TempFile(pprofDir, "cpu") 84 | if err != nil { 85 | log.Printf("error creating cpu pprof file: %s", err) 86 | break 87 | } 88 | err = pprof.StartCPUProfile(f) 89 | if err != nil { 90 | log.Printf("error starting cpu profiling: %s", err) 91 | break 92 | } 93 | log.Printf("cpu profiling to file %q", f.Name()) 94 | case "block": 95 | runtime.SetBlockProfileRate(1) 96 | case "heap": 97 | heap = true 98 | default: 99 | log.Printf("unexpected GOPPROF key %q", key) 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Matt Joiner 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/addr.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import ( 4 | "net" 5 | "strconv" 6 | ) 7 | 8 | // Extracts the port as an integer from an address string. 9 | func AddrPort(addr net.Addr) int { 10 | switch raw := addr.(type) { 11 | case *net.UDPAddr: 12 | return raw.Port 13 | default: 14 | _, port, err := net.SplitHostPort(addr.String()) 15 | if err != nil { 16 | panic(err) 17 | } 18 | i64, err := strconv.ParseInt(port, 0, 0) 19 | if err != nil { 20 | panic(err) 21 | } 22 | return int(i64) 23 | } 24 | } 25 | 26 | func AddrIP(addr net.Addr) net.IP { 27 | switch raw := addr.(type) { 28 | case *net.UDPAddr: 29 | return raw.IP 30 | case *net.TCPAddr: 31 | return raw.IP 32 | default: 33 | host, _, err := net.SplitHostPort(addr.String()) 34 | if err != nil { 35 | panic(err) 36 | } 37 | return net.ParseIP(host) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/atime.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import ( 4 | "os" 5 | "time" 6 | ) 7 | 8 | // Extracts the access time from the FileInfo internals. 9 | func FileInfoAccessTime(fi os.FileInfo) time.Time { 10 | return fileInfoAccessTime(fi) 11 | } 12 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/atime_atim.go: -------------------------------------------------------------------------------- 1 | // +build linux dragonfly openbsd solaris 2 | 3 | package missinggo 4 | 5 | import ( 6 | "os" 7 | "syscall" 8 | "time" 9 | ) 10 | 11 | func fileInfoAccessTime(fi os.FileInfo) time.Time { 12 | ts := fi.Sys().(*syscall.Stat_t).Atim 13 | return time.Unix(int64(ts.Sec), int64(ts.Nsec)) 14 | } 15 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/atime_atimespec.go: -------------------------------------------------------------------------------- 1 | // +build darwin freebsd netbsd 2 | 3 | package missinggo 4 | 5 | import ( 6 | "os" 7 | "syscall" 8 | "time" 9 | ) 10 | 11 | func fileInfoAccessTime(fi os.FileInfo) time.Time { 12 | ts := fi.Sys().(*syscall.Stat_t).Atimespec 13 | return time.Unix(int64(ts.Sec), int64(ts.Nsec)) 14 | } 15 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/atime_plan9.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import ( 4 | "os" 5 | "syscall" 6 | "time" 7 | ) 8 | 9 | func fileInfoAccessTime(fi os.FileInfo) time.Time { 10 | sec := fi.Sys().(*syscall.Dir).Atime 11 | return time.Unix(int64(sec), 0) 12 | } 13 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/atime_windows.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import ( 4 | "os" 5 | "syscall" 6 | "time" 7 | ) 8 | 9 | func fileInfoAccessTime(fi os.FileInfo) time.Time { 10 | ts := fi.Sys().(syscall.Win32FileAttributeData).LastAccessTime 11 | return time.Unix(0, int64(ts.Nanoseconds())) 12 | } 13 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/bitmap/bitmap.go: -------------------------------------------------------------------------------- 1 | // Package bitmap provides a []bool/bitmap implementation with standardized 2 | // iteration. Bitmaps are the equivalent of []bool, with improved compression 3 | // for runs of similar values, and faster operations on ranges and the like. 4 | package bitmap 5 | 6 | import ( 7 | "math" 8 | 9 | "github.com/RoaringBitmap/roaring" 10 | ) 11 | 12 | const MaxInt = -1 13 | 14 | // Bitmaps store the existence of values in [0,math.MaxUint32] more 15 | // efficiently than []bool. The empty value starts with no bits set. 16 | type Bitmap struct { 17 | rb *roaring.Bitmap 18 | } 19 | 20 | // The number of set bits in the bitmap. Also known as cardinality. 21 | func (me *Bitmap) Len() int { 22 | if me.rb == nil { 23 | return 0 24 | } 25 | return int(me.rb.GetCardinality()) 26 | } 27 | 28 | func (me Bitmap) ToSortedSlice() (ret []int) { 29 | if me.rb == nil { 30 | return 31 | } 32 | for _, ui32 := range me.rb.ToArray() { 33 | ret = append(ret, int(int32(ui32))) 34 | } 35 | return 36 | } 37 | 38 | func (me *Bitmap) lazyRB() *roaring.Bitmap { 39 | if me.rb == nil { 40 | me.rb = roaring.NewBitmap() 41 | } 42 | return me.rb 43 | } 44 | 45 | func (me *Bitmap) Iter(f func(interface{}) bool) { 46 | me.IterTyped(func(i int) bool { 47 | return f(i) 48 | }) 49 | } 50 | 51 | // Returns true if all values were traversed without early termination. 52 | func (me Bitmap) IterTyped(f func(int) bool) bool { 53 | if me.rb == nil { 54 | return true 55 | } 56 | it := me.rb.Iterator() 57 | for it.HasNext() { 58 | if !f(int(it.Next())) { 59 | return false 60 | } 61 | } 62 | return true 63 | } 64 | 65 | func checkInt(i int) { 66 | if i < math.MinInt32 || i > math.MaxInt32 { 67 | panic("out of bounds") 68 | } 69 | } 70 | 71 | func (me *Bitmap) Add(is ...int) { 72 | rb := me.lazyRB() 73 | for _, i := range is { 74 | checkInt(i) 75 | rb.AddInt(i) 76 | } 77 | } 78 | 79 | func (me *Bitmap) AddRange(begin, end int) { 80 | if begin >= end { 81 | return 82 | } 83 | me.lazyRB().AddRange(uint64(begin), uint64(end)) 84 | } 85 | 86 | func (me *Bitmap) Remove(i int) { 87 | if me.rb == nil { 88 | return 89 | } 90 | me.rb.Remove(uint32(i)) 91 | } 92 | 93 | func (me *Bitmap) Union(other *Bitmap) { 94 | me.lazyRB().Or(other.lazyRB()) 95 | } 96 | 97 | func (me *Bitmap) Contains(i int) bool { 98 | if me.rb == nil { 99 | return false 100 | } 101 | return me.rb.Contains(uint32(i)) 102 | } 103 | 104 | type Iter struct { 105 | ii roaring.IntIterable 106 | } 107 | 108 | func (me *Iter) Next() bool { 109 | if me == nil { 110 | return false 111 | } 112 | return me.ii.HasNext() 113 | } 114 | 115 | func (me *Iter) Value() interface{} { 116 | return me.ValueInt() 117 | } 118 | 119 | func (me *Iter) ValueInt() int { 120 | return int(me.ii.Next()) 121 | } 122 | 123 | func (me *Iter) Stop() {} 124 | 125 | func Sub(left, right *Bitmap) *Bitmap { 126 | return &Bitmap{ 127 | rb: roaring.AndNot(left.lazyRB(), right.lazyRB()), 128 | } 129 | } 130 | 131 | func (me *Bitmap) Sub(other *Bitmap) { 132 | if other.rb == nil { 133 | return 134 | } 135 | if me.rb == nil { 136 | return 137 | } 138 | me.rb.AndNot(other.rb) 139 | } 140 | 141 | func (me *Bitmap) Clear() { 142 | if me.rb == nil { 143 | return 144 | } 145 | me.rb.Clear() 146 | } 147 | 148 | func (me Bitmap) Copy() (ret Bitmap) { 149 | ret = me 150 | if ret.rb != nil { 151 | ret.rb = ret.rb.Clone() 152 | } 153 | return 154 | } 155 | 156 | func (me *Bitmap) FlipRange(begin, end int) { 157 | me.lazyRB().FlipInt(begin, end) 158 | } 159 | 160 | func (me *Bitmap) Get(bit int) bool { 161 | return me.rb != nil && me.rb.ContainsInt(bit) 162 | } 163 | 164 | func (me *Bitmap) Set(bit int, value bool) { 165 | if value { 166 | me.lazyRB().AddInt(bit) 167 | } else { 168 | if me.rb != nil { 169 | me.rb.Remove(uint32(bit)) 170 | } 171 | } 172 | } 173 | 174 | func (me *Bitmap) RemoveRange(begin, end int) *Bitmap { 175 | if me.rb == nil { 176 | return me 177 | } 178 | me.rb.RemoveRange(uint64(begin), uint64(end)) 179 | return me 180 | } 181 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/certdir.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import ( 4 | "crypto/tls" 5 | "log" 6 | "os" 7 | "path/filepath" 8 | "strings" 9 | ) 10 | 11 | func LoadCertificateDir(dir string) (certs []tls.Certificate, err error) { 12 | d, err := os.Open(dir) 13 | if err != nil { 14 | return 15 | } 16 | defer d.Close() 17 | const defaultPEMFile = "default.pem" 18 | if p := filepath.Join(dir, defaultPEMFile); FilePathExists(p) { 19 | cert, err := tls.LoadX509KeyPair(p, p) 20 | if err == nil { 21 | certs = append(certs, cert) 22 | } else { 23 | log.Printf("error loading default certicate: %s", err) 24 | } 25 | } 26 | files, err := d.Readdir(-1) 27 | if err != nil { 28 | return 29 | } 30 | for _, f := range files { 31 | if f.Name() == defaultPEMFile { 32 | continue 33 | } 34 | if !strings.HasSuffix(f.Name(), ".pem") { 35 | continue 36 | } 37 | p := filepath.Join(dir, f.Name()) 38 | cert, err := tls.LoadX509KeyPair(p, p) 39 | if err != nil { 40 | log.Printf("error loading key pair from %q: %s", p, err) 41 | continue 42 | } 43 | certs = append(certs, cert) 44 | } 45 | return 46 | } 47 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/chancond.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import "sync" 4 | 5 | type ChanCond struct { 6 | mu sync.Mutex 7 | ch chan struct{} 8 | } 9 | 10 | func (me *ChanCond) Wait() <-chan struct{} { 11 | me.mu.Lock() 12 | defer me.mu.Unlock() 13 | if me.ch == nil { 14 | me.ch = make(chan struct{}) 15 | } 16 | return me.ch 17 | } 18 | 19 | func (me *ChanCond) Signal() { 20 | me.mu.Lock() 21 | defer me.mu.Unlock() 22 | select { 23 | case me.ch <- struct{}{}: 24 | default: 25 | } 26 | } 27 | 28 | func (me *ChanCond) Broadcast() { 29 | me.mu.Lock() 30 | defer me.mu.Unlock() 31 | if me.ch == nil { 32 | return 33 | } 34 | close(me.ch) 35 | me.ch = nil 36 | } 37 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/chans/drain.go: -------------------------------------------------------------------------------- 1 | package chans 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | // Receives from any channel until it's closed. 8 | func Drain(ch interface{}) { 9 | chValue := reflect.ValueOf(ch) 10 | for { 11 | _, ok := chValue.Recv() 12 | if !ok { 13 | break 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/cmd/filecache/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/tls" 5 | "fmt" 6 | "io" 7 | "log" 8 | "net/http" 9 | "os" 10 | "regexp" 11 | "strconv" 12 | 13 | _ "github.com/anacrolix/envpprof" 14 | "github.com/anacrolix/tagflag" 15 | "github.com/dustin/go-humanize" 16 | 17 | "github.com/anacrolix/missinggo" 18 | "github.com/anacrolix/missinggo/filecache" 19 | ) 20 | 21 | var c *filecache.Cache 22 | 23 | func handleNewData(w http.ResponseWriter, path string, offset int64, r io.Reader) (served bool) { 24 | f, err := c.OpenFile(path, os.O_CREATE|os.O_WRONLY) 25 | if err != nil { 26 | log.Print(err) 27 | http.Error(w, "couldn't open file", http.StatusInternalServerError) 28 | return true 29 | } 30 | defer f.Close() 31 | f.Seek(offset, os.SEEK_SET) 32 | _, err = io.Copy(f, r) 33 | if err != nil { 34 | log.Print(err) 35 | f.Remove() 36 | http.Error(w, "didn't complete", http.StatusInternalServerError) 37 | return true 38 | } 39 | return 40 | } 41 | 42 | // Parses out the first byte from a Content-Range header. Returns 0 if it 43 | // isn't found, which is what is implied if there is no header. 44 | func parseContentRangeFirstByte(s string) int64 { 45 | matches := regexp.MustCompile(`(\d+)-`).FindStringSubmatch(s) 46 | if matches == nil { 47 | return 0 48 | } 49 | ret, _ := strconv.ParseInt(matches[1], 0, 64) 50 | return ret 51 | } 52 | 53 | func handleDelete(w http.ResponseWriter, path string) { 54 | err := c.Remove(path) 55 | if err != nil { 56 | log.Print(err) 57 | http.Error(w, "didn't work", http.StatusInternalServerError) 58 | return 59 | } 60 | } 61 | 62 | func main() { 63 | log.SetFlags(log.Flags() | log.Lshortfile) 64 | args := struct { 65 | Capacity tagflag.Bytes `short:"c"` 66 | Addr string 67 | }{ 68 | Capacity: -1, 69 | Addr: "localhost:2076", 70 | } 71 | tagflag.Parse(&args) 72 | root, err := os.Getwd() 73 | if err != nil { 74 | log.Fatal(err) 75 | } 76 | log.Printf("cache root at %q", root) 77 | c, err = filecache.NewCache(root) 78 | if err != nil { 79 | log.Fatalf("error creating cache: %s", err) 80 | } 81 | if args.Capacity < 0 { 82 | log.Printf("no capacity set, no evictions will occur") 83 | } else { 84 | c.SetCapacity(args.Capacity.Int64()) 85 | log.Printf("setting capacity to %s bytes", humanize.Comma(args.Capacity.Int64())) 86 | } 87 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 88 | p := r.URL.Path[1:] 89 | switch r.Method { 90 | case "DELETE": 91 | log.Printf("%s %s", r.Method, r.RequestURI) 92 | handleDelete(w, p) 93 | return 94 | case "PUT", "PATCH", "POST": 95 | contentRange := r.Header.Get("Content-Range") 96 | firstByte := parseContentRangeFirstByte(contentRange) 97 | log.Printf("%s (%d-) %s", r.Method, firstByte, r.RequestURI) 98 | handleNewData(w, p, firstByte, r.Body) 99 | return 100 | } 101 | log.Printf("%s %s %s", r.Method, r.Header.Get("Range"), r.RequestURI) 102 | f, err := c.OpenFile(p, os.O_RDONLY) 103 | if os.IsNotExist(err) { 104 | http.NotFound(w, r) 105 | return 106 | } 107 | if err != nil { 108 | log.Printf("couldn't open requested file: %s", err) 109 | http.Error(w, "couldn't open file", http.StatusInternalServerError) 110 | return 111 | } 112 | defer func() { 113 | go f.Close() 114 | }() 115 | info, _ := f.Stat() 116 | w.Header().Set("Content-Range", fmt.Sprintf("*/%d", info.Size())) 117 | http.ServeContent(w, r, p, info.ModTime(), f) 118 | }) 119 | http.HandleFunc("/status", func(w http.ResponseWriter, r *http.Request) { 120 | info := c.Info() 121 | fmt.Fprintf(w, "Capacity: %d\n", info.Capacity) 122 | fmt.Fprintf(w, "Current Size: %d\n", info.Filled) 123 | fmt.Fprintf(w, "Item Count: %d\n", info.NumItems) 124 | }) 125 | http.HandleFunc("/lru", func(w http.ResponseWriter, r *http.Request) { 126 | c.WalkItems(func(item filecache.ItemInfo) { 127 | fmt.Fprintf(w, "%s\t%d\t%s\n", item.Accessed, item.Size, item.Path) 128 | }) 129 | }) 130 | cert, err := missinggo.NewSelfSignedCertificate() 131 | if err != nil { 132 | log.Fatal(err) 133 | } 134 | srv := http.Server{ 135 | Addr: args.Addr, 136 | TLSConfig: &tls.Config{ 137 | Certificates: []tls.Certificate{cert}, 138 | }, 139 | } 140 | log.Fatal(srv.ListenAndServeTLS("", "")) 141 | } 142 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/cmd/go-env/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | func main() { 9 | for _, v := range os.Environ() { 10 | fmt.Printf("%s\n", v) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/cmd/http-file-server/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net" 6 | "net/http" 7 | "os" 8 | 9 | "github.com/anacrolix/tagflag" 10 | ) 11 | 12 | func setIfGetHeader(w http.ResponseWriter, r *http.Request, set, get string) { 13 | h := r.Header.Get(get) 14 | if h == "" { 15 | return 16 | } 17 | w.Header().Set(set, h) 18 | } 19 | 20 | func allowCORS(h http.Handler) http.Handler { 21 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 22 | if origin := r.Header.Get("Origin"); origin != "" { 23 | w.Header().Set("Access-Control-Allow-Origin", origin) 24 | w.Header().Set("Access-Control-Allow-Credentials", "true") 25 | setIfGetHeader(w, r, "Access-Control-Allow-Methods", "Access-Control-Request-Method") 26 | setIfGetHeader(w, r, "Access-Control-Allow-Headers", "Access-Control-Request-Headers") 27 | w.Header().Set("Access-Control-Expose-Headers", "Content-Type") 28 | } 29 | h.ServeHTTP(w, r) 30 | }) 31 | } 32 | 33 | func main() { 34 | var flags = struct { 35 | Addr string 36 | }{ 37 | Addr: "localhost:8080", 38 | } 39 | tagflag.Parse(&flags) 40 | dir, err := os.Getwd() 41 | if err != nil { 42 | log.Fatal(err) 43 | } 44 | l, err := net.Listen("tcp", flags.Addr) 45 | if err != nil { 46 | log.Fatal(err) 47 | } 48 | defer l.Close() 49 | addr := l.Addr() 50 | log.Printf("serving %q at %s", dir, addr) 51 | log.Fatal(http.Serve(l, allowCORS(http.FileServer(http.Dir(dir))))) 52 | } 53 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/cmd/nop/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() {} 4 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/cmd/query-escape/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/url" 6 | "os" 7 | ) 8 | 9 | func main() { 10 | fmt.Println(url.QueryEscape(os.Args[1])) 11 | } 12 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/cmd/query-unescape/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "net/url" 6 | "os" 7 | ) 8 | 9 | func main() { 10 | fmt.Println(url.QueryUnescape(os.Args[1])) 11 | } 12 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/copy.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | // Copy elements from src to dst. Panics if the length of src and dst are 9 | // different. 10 | func CopyExact(dest interface{}, src interface{}) { 11 | dV := reflect.ValueOf(dest) 12 | sV := reflect.ValueOf(src) 13 | if dV.Kind() == reflect.Ptr { 14 | dV = dV.Elem() 15 | } 16 | if dV.Kind() == reflect.Array && !dV.CanAddr() { 17 | panic(fmt.Sprintf("dest not addressable: %T", dest)) 18 | } 19 | if sV.Kind() == reflect.Ptr { 20 | sV = sV.Elem() 21 | } 22 | if sV.Kind() == reflect.String { 23 | sV = sV.Convert(reflect.SliceOf(dV.Type().Elem())) 24 | } 25 | if !sV.IsValid() { 26 | panic("invalid source, probably nil") 27 | } 28 | if dV.Len() != sV.Len() { 29 | panic(fmt.Sprintf("dest len (%d) != src len (%d)", dV.Len(), sV.Len())) 30 | } 31 | if dV.Len() != reflect.Copy(dV, sV) { 32 | panic("dammit") 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/croak.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | func Unchomp(s string) string { 9 | if len(s) > 0 && s[len(s)-1] == '\n' { 10 | return s 11 | } 12 | return s + "\n" 13 | } 14 | 15 | func Fatal(msg interface{}) { 16 | os.Stderr.WriteString(Unchomp(fmt.Sprint(msg))) 17 | os.Exit(1) 18 | } 19 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/ctrlflow/ctrlflow.go: -------------------------------------------------------------------------------- 1 | package ctrlflow 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type valueWrapper struct { 8 | value interface{} 9 | } 10 | 11 | func (me valueWrapper) String() string { 12 | return fmt.Sprint(me.value) 13 | } 14 | 15 | func Panic(val interface{}) { 16 | panic(valueWrapper{val}) 17 | } 18 | 19 | func Recover(handler func(interface{}) bool) { 20 | r := recover() 21 | if r == nil { 22 | return 23 | } 24 | if vw, ok := r.(valueWrapper); ok { 25 | if handler(vw.value) { 26 | return 27 | } 28 | } 29 | panic(r) 30 | } 31 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/doc.go: -------------------------------------------------------------------------------- 1 | // Package missinggo contains miscellaneous helpers used in many of anacrolix' 2 | // projects. 3 | package missinggo 4 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/docopt/docopt.go: -------------------------------------------------------------------------------- 1 | package docopt 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/docopt/docopt-go" 8 | ) 9 | 10 | func Parse(doc string) (opts map[string]interface{}) { 11 | opts, err := docopt.Parse(doc, nil, true, "1.2.3", false, false) 12 | if ue, ok := err.(*docopt.UserError); ok { 13 | if ue.Error() != "" { 14 | fmt.Fprintf(os.Stderr, "\n%s\n", ue) 15 | } 16 | os.Exit(2) 17 | } 18 | if err != nil { 19 | fmt.Fprintf(os.Stderr, "error parsing docopt: %#v\n", err) 20 | os.Exit(1) 21 | } 22 | return 23 | } 24 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/empty_value.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import "reflect" 4 | 5 | // Returns whether the value represents the empty value for its type. Used for 6 | // example to determine if complex types satisfy the common "omitempty" tag 7 | // option for marshalling. Taken from 8 | // http://stackoverflow.com/a/23555352/149482. 9 | func IsEmptyValue(v reflect.Value) bool { 10 | switch v.Kind() { 11 | case reflect.Func, reflect.Map, reflect.Slice: 12 | return v.IsNil() 13 | case reflect.Array: 14 | z := true 15 | for i := 0; i < v.Len(); i++ { 16 | z = z && IsEmptyValue(v.Index(i)) 17 | } 18 | return z 19 | case reflect.Struct: 20 | z := true 21 | for i := 0; i < v.NumField(); i++ { 22 | z = z && IsEmptyValue(v.Field(i)) 23 | } 24 | return z 25 | } 26 | // Compare other types directly: 27 | z := reflect.Zero(v.Type()) 28 | return v.Interface() == z.Interface() 29 | } 30 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/event.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import "sync" 4 | 5 | // Events are boolean flags that provide a channel that's closed when true. 6 | type Event struct { 7 | ch chan struct{} 8 | closed bool 9 | } 10 | 11 | func (me *Event) LockedChan(lock sync.Locker) <-chan struct{} { 12 | lock.Lock() 13 | ch := me.C() 14 | lock.Unlock() 15 | return ch 16 | } 17 | 18 | func (me *Event) C() <-chan struct{} { 19 | if me.ch == nil { 20 | me.ch = make(chan struct{}) 21 | } 22 | return me.ch 23 | } 24 | 25 | func (me *Event) Clear() { 26 | if me.closed { 27 | me.ch = nil 28 | me.closed = false 29 | } 30 | } 31 | 32 | func (me *Event) Set() (first bool) { 33 | if me.closed { 34 | return false 35 | } 36 | if me.ch == nil { 37 | me.ch = make(chan struct{}) 38 | } 39 | close(me.ch) 40 | me.closed = true 41 | return true 42 | } 43 | 44 | func (me *Event) IsSet() bool { 45 | return me.closed 46 | } 47 | 48 | func (me *Event) Wait() { 49 | <-me.C() 50 | } 51 | 52 | func (me *Event) SetBool(b bool) { 53 | if b { 54 | me.Set() 55 | } else { 56 | me.Clear() 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/event_synchronized.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import "sync" 4 | 5 | type SynchronizedEvent struct { 6 | mu sync.Mutex 7 | e Event 8 | } 9 | 10 | func (me *SynchronizedEvent) Set() { 11 | me.mu.Lock() 12 | me.e.Set() 13 | me.mu.Unlock() 14 | } 15 | 16 | func (me *SynchronizedEvent) Clear() { 17 | me.mu.Lock() 18 | me.e.Clear() 19 | me.mu.Unlock() 20 | } 21 | 22 | func (me *SynchronizedEvent) C() <-chan struct{} { 23 | me.mu.Lock() 24 | defer me.mu.Unlock() 25 | return me.e.C() 26 | } 27 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/expvarIndentMap.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import ( 4 | "bytes" 5 | "expvar" 6 | "fmt" 7 | ) 8 | 9 | type IndentMap struct { 10 | expvar.Map 11 | } 12 | 13 | var _ expvar.Var = &IndentMap{} 14 | 15 | func NewExpvarIndentMap(name string) *IndentMap { 16 | v := new(IndentMap) 17 | v.Init() 18 | expvar.Publish(name, v) 19 | return v 20 | } 21 | 22 | func (v *IndentMap) String() string { 23 | var b bytes.Buffer 24 | fmt.Fprintf(&b, "{") 25 | first := true 26 | v.Do(func(kv expvar.KeyValue) { 27 | if !first { 28 | fmt.Fprintf(&b, ",") 29 | } 30 | fmt.Fprintf(&b, "\n\t%q: %v", kv.Key, kv.Value) 31 | first = false 32 | }) 33 | fmt.Fprintf(&b, "}") 34 | return b.String() 35 | } 36 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/filecache/cache.go: -------------------------------------------------------------------------------- 1 | package filecache 2 | 3 | import ( 4 | "errors" 5 | "log" 6 | "os" 7 | "path" 8 | "path/filepath" 9 | "sync" 10 | "time" 11 | 12 | "github.com/anacrolix/missinggo" 13 | "github.com/anacrolix/missinggo/pproffd" 14 | "github.com/anacrolix/missinggo/resource" 15 | ) 16 | 17 | const ( 18 | dirPerm = 0755 19 | filePerm = 0644 20 | ) 21 | 22 | type Cache struct { 23 | mu sync.Mutex 24 | capacity int64 25 | filled int64 26 | items *lruItems 27 | paths map[string]ItemInfo 28 | root string 29 | } 30 | 31 | type CacheInfo struct { 32 | Capacity int64 33 | Filled int64 34 | NumItems int 35 | } 36 | 37 | type ItemInfo struct { 38 | Accessed time.Time 39 | Size int64 40 | Path string 41 | } 42 | 43 | // Calls the function for every item known to the cache. The ItemInfo should 44 | // not be modified. 45 | func (me *Cache) WalkItems(cb func(ItemInfo)) { 46 | me.mu.Lock() 47 | defer me.mu.Unlock() 48 | for e := me.items.Front(); e != nil; e = e.Next() { 49 | cb(e.Value().(ItemInfo)) 50 | } 51 | } 52 | 53 | func (me *Cache) Info() (ret CacheInfo) { 54 | me.mu.Lock() 55 | defer me.mu.Unlock() 56 | ret.Capacity = me.capacity 57 | ret.Filled = me.filled 58 | ret.NumItems = len(me.paths) 59 | return 60 | } 61 | 62 | // Setting a negative capacity means unlimited. 63 | func (me *Cache) SetCapacity(capacity int64) { 64 | me.mu.Lock() 65 | defer me.mu.Unlock() 66 | me.capacity = capacity 67 | } 68 | 69 | func NewCache(root string) (ret *Cache, err error) { 70 | root, err = filepath.Abs(root) 71 | ret = &Cache{ 72 | root: root, 73 | capacity: -1, // unlimited 74 | } 75 | ret.mu.Lock() 76 | go func() { 77 | defer ret.mu.Unlock() 78 | ret.rescan() 79 | }() 80 | return 81 | } 82 | 83 | // An empty return path is an error. 84 | func sanitizePath(p string) (ret string) { 85 | if p == "" { 86 | return 87 | } 88 | ret = path.Clean("/" + p) 89 | if ret[0] == '/' { 90 | ret = ret[1:] 91 | } 92 | return 93 | } 94 | 95 | // Leaf is a descendent of root. 96 | func pruneEmptyDirs(root string, leaf string) (err error) { 97 | rootInfo, err := os.Stat(root) 98 | if err != nil { 99 | return 100 | } 101 | for { 102 | var leafInfo os.FileInfo 103 | leafInfo, err = os.Stat(leaf) 104 | if os.IsNotExist(err) { 105 | goto parent 106 | } 107 | if err != nil { 108 | return 109 | } 110 | if !leafInfo.IsDir() { 111 | return 112 | } 113 | if os.SameFile(rootInfo, leafInfo) { 114 | return 115 | } 116 | if os.Remove(leaf) != nil { 117 | return 118 | } 119 | parent: 120 | leaf = filepath.Dir(leaf) 121 | } 122 | } 123 | 124 | func (me *Cache) Remove(path string) (err error) { 125 | path = sanitizePath(path) 126 | me.mu.Lock() 127 | defer me.mu.Unlock() 128 | err = me.remove(path) 129 | return 130 | } 131 | 132 | var ( 133 | ErrBadPath = errors.New("bad path") 134 | ErrIsDir = errors.New("is directory") 135 | ) 136 | 137 | func (me *Cache) StatFile(path string) (os.FileInfo, error) { 138 | return os.Stat(me.realpath(sanitizePath(path))) 139 | } 140 | 141 | func (me *Cache) OpenFile(path string, flag int) (ret *File, err error) { 142 | path = sanitizePath(path) 143 | if path == "" { 144 | err = ErrIsDir 145 | return 146 | } 147 | f, err := os.OpenFile(me.realpath(path), flag, filePerm) 148 | if flag&os.O_CREATE != 0 && os.IsNotExist(err) { 149 | os.MkdirAll(me.root, dirPerm) 150 | os.MkdirAll(filepath.Dir(me.realpath(path)), dirPerm) 151 | f, err = os.OpenFile(me.realpath(path), flag, filePerm) 152 | if err != nil { 153 | me.pruneEmptyDirs(path) 154 | } 155 | } 156 | if err != nil { 157 | return 158 | } 159 | ret = &File{ 160 | c: me, 161 | path: path, 162 | f: pproffd.WrapOSFile(f), 163 | } 164 | me.mu.Lock() 165 | go func() { 166 | defer me.mu.Unlock() 167 | me.statItem(path, time.Now()) 168 | }() 169 | return 170 | } 171 | 172 | func (me *Cache) rescan() { 173 | me.filled = 0 174 | me.items = newLRUItems() 175 | me.paths = make(map[string]ItemInfo) 176 | err := filepath.Walk(me.root, func(path string, info os.FileInfo, err error) error { 177 | if os.IsNotExist(err) { 178 | return nil 179 | } 180 | if err != nil { 181 | return err 182 | } 183 | if info.IsDir() { 184 | return nil 185 | } 186 | path, err = filepath.Rel(me.root, path) 187 | if err != nil { 188 | log.Print(err) 189 | return nil 190 | } 191 | me.statItem(path, time.Time{}) 192 | return nil 193 | }) 194 | if err != nil { 195 | panic(err) 196 | } 197 | } 198 | 199 | func (me *Cache) insertItem(i ItemInfo) { 200 | me.items.Insert(i) 201 | } 202 | 203 | func (me *Cache) removeInfo(path string) (ret ItemInfo, ok bool) { 204 | ret, ok = me.paths[path] 205 | if !ok { 206 | return 207 | } 208 | if !me.items.Remove(ret) { 209 | panic(ret) 210 | } 211 | me.filled -= ret.Size 212 | delete(me.paths, path) 213 | return 214 | } 215 | 216 | // Triggers the item for path to be updated. If access is non-zero, set the 217 | // item's access time to that value, otherwise deduce it appropriately. 218 | func (me *Cache) statItem(path string, access time.Time) { 219 | info, ok := me.removeInfo(path) 220 | fi, err := os.Stat(me.realpath(path)) 221 | if os.IsNotExist(err) { 222 | return 223 | } 224 | if err != nil { 225 | panic(err) 226 | } 227 | if !ok { 228 | info.Path = path 229 | } 230 | if !access.IsZero() { 231 | info.Accessed = access 232 | } 233 | if info.Accessed.IsZero() { 234 | info.Accessed = missinggo.Max( 235 | func(left, right time.Time) bool { return left.Before(right) }, 236 | missinggo.FileInfoAccessTime(fi), 237 | fi.ModTime(), 238 | ).(time.Time) 239 | } 240 | info.Size = fi.Size() 241 | me.filled += info.Size 242 | me.insertItem(info) 243 | me.paths[path] = info 244 | } 245 | 246 | func (me *Cache) realpath(path string) string { 247 | return filepath.Join(me.root, filepath.FromSlash(sanitizePath(path))) 248 | } 249 | 250 | func (me *Cache) TrimToCapacity() { 251 | me.mu.Lock() 252 | defer me.mu.Unlock() 253 | me.trimToCapacity() 254 | } 255 | 256 | func (me *Cache) pruneEmptyDirs(path string) { 257 | pruneEmptyDirs(me.root, me.realpath(path)) 258 | } 259 | 260 | func (me *Cache) remove(path string) (err error) { 261 | err = os.Remove(me.realpath(path)) 262 | if os.IsNotExist(err) { 263 | err = nil 264 | } 265 | me.pruneEmptyDirs(path) 266 | me.removeInfo(path) 267 | return 268 | } 269 | 270 | func (me *Cache) trimToCapacity() { 271 | if me.capacity < 0 { 272 | return 273 | } 274 | for me.filled > me.capacity { 275 | item := me.items.LRU() 276 | me.remove(item.Path) 277 | } 278 | } 279 | 280 | func (me *Cache) pathInfo(p string) ItemInfo { 281 | return me.paths[p] 282 | } 283 | 284 | func (me *Cache) Rename(from, to string) (err error) { 285 | _from := sanitizePath(from) 286 | _to := sanitizePath(to) 287 | me.mu.Lock() 288 | defer me.mu.Unlock() 289 | err = os.MkdirAll(filepath.Dir(me.realpath(_to)), dirPerm) 290 | if err != nil { 291 | return 292 | } 293 | err = os.Rename(me.realpath(_from), me.realpath(_to)) 294 | if err != nil { 295 | return 296 | } 297 | me.removeInfo(_from) 298 | me.pruneEmptyDirs(_from) 299 | me.statItem(_to, time.Now()) 300 | return 301 | } 302 | 303 | func (me *Cache) Stat(path string) (os.FileInfo, error) { 304 | return os.Stat(me.realpath(path)) 305 | } 306 | 307 | func (me *Cache) AsFileStore() missinggo.FileStore { 308 | return fileStore{me} 309 | } 310 | 311 | func (me *Cache) AsResourceProvider() resource.Provider { 312 | return &uniformResourceProvider{me} 313 | } 314 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/filecache/file.go: -------------------------------------------------------------------------------- 1 | package filecache 2 | 3 | import ( 4 | "errors" 5 | "math" 6 | "os" 7 | "sync" 8 | "time" 9 | 10 | "github.com/anacrolix/missinggo/pproffd" 11 | ) 12 | 13 | type File struct { 14 | mu sync.Mutex 15 | c *Cache 16 | path string 17 | f pproffd.OSFile 18 | gone bool 19 | } 20 | 21 | func (me *File) Remove() (err error) { 22 | return me.c.Remove(me.path) 23 | } 24 | 25 | func (me *File) Seek(offset int64, whence int) (ret int64, err error) { 26 | ret, err = me.f.Seek(offset, whence) 27 | return 28 | } 29 | 30 | func (me *File) maxWrite() (max int64, err error) { 31 | if me.c.capacity < 0 { 32 | max = math.MaxInt64 33 | return 34 | } 35 | pos, err := me.Seek(0, os.SEEK_CUR) 36 | if err != nil { 37 | return 38 | } 39 | max = me.c.capacity - pos 40 | if max < 0 { 41 | max = 0 42 | } 43 | return 44 | } 45 | 46 | var ( 47 | ErrFileTooLarge = errors.New("file too large for cache") 48 | ErrFileDisappeared = errors.New("file disappeared") 49 | ) 50 | 51 | func (me *File) checkGone() { 52 | if me.gone { 53 | return 54 | } 55 | ffi, _ := me.Stat() 56 | fsfi, _ := os.Stat(me.c.realpath(me.path)) 57 | me.gone = !os.SameFile(ffi, fsfi) 58 | } 59 | 60 | func (me *File) goneErr() error { 61 | me.mu.Lock() 62 | defer me.mu.Unlock() 63 | me.checkGone() 64 | if me.gone { 65 | me.f.Close() 66 | return ErrFileDisappeared 67 | } 68 | return nil 69 | } 70 | 71 | func (me *File) Write(b []byte) (n int, err error) { 72 | err = me.goneErr() 73 | if err != nil { 74 | return 75 | } 76 | n, err = me.f.Write(b) 77 | me.c.mu.Lock() 78 | me.c.statItem(me.path, time.Now()) 79 | me.c.trimToCapacity() 80 | me.c.mu.Unlock() 81 | if err == nil { 82 | err = me.goneErr() 83 | } 84 | return 85 | } 86 | 87 | func (me *File) WriteAt(b []byte, off int64) (n int, err error) { 88 | err = me.goneErr() 89 | if err != nil { 90 | return 91 | } 92 | n, err = me.f.WriteAt(b, off) 93 | me.c.mu.Lock() 94 | me.c.statItem(me.path, time.Now()) 95 | me.c.trimToCapacity() 96 | me.c.mu.Unlock() 97 | if err == nil { 98 | err = me.goneErr() 99 | } 100 | return 101 | } 102 | 103 | func (me *File) Close() error { 104 | return me.f.Close() 105 | } 106 | 107 | func (me *File) Stat() (os.FileInfo, error) { 108 | return me.f.Stat() 109 | } 110 | 111 | func (me *File) Read(b []byte) (n int, err error) { 112 | err = me.goneErr() 113 | if err != nil { 114 | return 115 | } 116 | defer func() { 117 | me.c.mu.Lock() 118 | defer me.c.mu.Unlock() 119 | me.c.statItem(me.path, time.Now()) 120 | }() 121 | return me.f.Read(b) 122 | } 123 | 124 | func (me *File) ReadAt(b []byte, off int64) (n int, err error) { 125 | err = me.goneErr() 126 | if err != nil { 127 | return 128 | } 129 | defer func() { 130 | me.c.mu.Lock() 131 | defer me.c.mu.Unlock() 132 | me.c.statItem(me.path, time.Now()) 133 | }() 134 | return me.f.ReadAt(b, off) 135 | } 136 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/filecache/fs.go: -------------------------------------------------------------------------------- 1 | package filecache 2 | 3 | import "github.com/anacrolix/missinggo" 4 | 5 | type fileStore struct { 6 | *Cache 7 | } 8 | 9 | func (me fileStore) OpenFile(p string, f int) (missinggo.File, error) { 10 | return me.Cache.OpenFile(p, f) 11 | } 12 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/filecache/lruitems.go: -------------------------------------------------------------------------------- 1 | package filecache 2 | 3 | // TODO: Dump this file for orderedmap. 4 | 5 | import ( 6 | "container/list" 7 | "io" 8 | 9 | "github.com/cznic/b" 10 | ) 11 | 12 | type Iterator interface { 13 | Next() Iterator 14 | Value() interface{} 15 | } 16 | 17 | type listElementIterator struct { 18 | le *list.Element 19 | } 20 | 21 | func (me listElementIterator) Next() Iterator { 22 | e := me.le.Next() 23 | if e == nil { 24 | return nil 25 | } 26 | return listElementIterator{e} 27 | } 28 | 29 | func (me listElementIterator) Value() interface{} { 30 | return me.le.Value 31 | } 32 | 33 | func newLRUItems() *lruItems { 34 | return &lruItems{b.TreeNew(func(_a, _b interface{}) int { 35 | a := _a.(ItemInfo) 36 | b := _b.(ItemInfo) 37 | if a.Accessed != b.Accessed { 38 | if a.Accessed.Before(b.Accessed) { 39 | return -1 40 | } else { 41 | return 1 42 | } 43 | } 44 | if a.Path == b.Path { 45 | return 0 46 | } 47 | if a.Path < b.Path { 48 | return -1 49 | } 50 | return 1 51 | })} 52 | } 53 | 54 | // TODO: Dumps this for orderedmap. 55 | type lruItems struct { 56 | tree *b.Tree 57 | } 58 | 59 | type bEnumeratorIterator struct { 60 | e *b.Enumerator 61 | v ItemInfo 62 | } 63 | 64 | func (me bEnumeratorIterator) Next() Iterator { 65 | _, v, err := me.e.Next() 66 | if err == io.EOF { 67 | return nil 68 | } 69 | return bEnumeratorIterator{me.e, v.(ItemInfo)} 70 | } 71 | 72 | func (me bEnumeratorIterator) Value() interface{} { 73 | return me.v 74 | } 75 | 76 | func (me *lruItems) Front() Iterator { 77 | e, _ := me.tree.SeekFirst() 78 | if e == nil { 79 | return nil 80 | } 81 | return bEnumeratorIterator{ 82 | e: e, 83 | }.Next() 84 | } 85 | 86 | func (me *lruItems) LRU() ItemInfo { 87 | _, v := me.tree.First() 88 | return v.(ItemInfo) 89 | } 90 | 91 | func (me *lruItems) Insert(ii ItemInfo) { 92 | me.tree.Set(ii, ii) 93 | } 94 | 95 | func (me *lruItems) Remove(ii ItemInfo) bool { 96 | return me.tree.Delete(ii) 97 | } 98 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/filecache/uniform.go: -------------------------------------------------------------------------------- 1 | package filecache 2 | 3 | import ( 4 | "io" 5 | "os" 6 | 7 | "github.com/anacrolix/missinggo/resource" 8 | ) 9 | 10 | type uniformResourceProvider struct { 11 | *Cache 12 | } 13 | 14 | var _ resource.Provider = &uniformResourceProvider{} 15 | 16 | func (me *uniformResourceProvider) NewInstance(loc string) (resource.Instance, error) { 17 | return &uniformResource{me.Cache, loc}, nil 18 | } 19 | 20 | type uniformResource struct { 21 | Cache *Cache 22 | Location string 23 | } 24 | 25 | func (me *uniformResource) Get() (io.ReadCloser, error) { 26 | return me.Cache.OpenFile(me.Location, os.O_RDONLY) 27 | } 28 | 29 | func (me *uniformResource) Put(r io.Reader) (err error) { 30 | f, err := me.Cache.OpenFile(me.Location, os.O_WRONLY|os.O_CREATE|os.O_TRUNC) 31 | if err != nil { 32 | return 33 | } 34 | defer f.Close() 35 | _, err = io.Copy(f, r) 36 | return 37 | } 38 | 39 | func (me *uniformResource) ReadAt(b []byte, off int64) (n int, err error) { 40 | f, err := me.Cache.OpenFile(me.Location, os.O_RDONLY) 41 | if err != nil { 42 | return 43 | } 44 | defer f.Close() 45 | return f.ReadAt(b, off) 46 | } 47 | 48 | func (me *uniformResource) WriteAt(b []byte, off int64) (n int, err error) { 49 | f, err := me.Cache.OpenFile(me.Location, os.O_CREATE|os.O_WRONLY) 50 | if err != nil { 51 | return 52 | } 53 | defer f.Close() 54 | return f.WriteAt(b, off) 55 | } 56 | 57 | func (me *uniformResource) Stat() (fi os.FileInfo, err error) { 58 | return me.Cache.Stat(me.Location) 59 | } 60 | 61 | func (me *uniformResource) Delete() error { 62 | return me.Cache.Remove(me.Location) 63 | } 64 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/flag.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import "sync" 4 | 5 | // Flag represents a boolean value, that signals sync.Cond's when it changes. 6 | // It's not concurrent safe by intention. 7 | type Flag struct { 8 | Conds map[*sync.Cond]struct{} 9 | value bool 10 | } 11 | 12 | func (me *Flag) Set(value bool) { 13 | if value != me.value { 14 | me.broadcastChange() 15 | } 16 | me.value = value 17 | } 18 | 19 | func (me *Flag) Get() bool { 20 | return me.value 21 | } 22 | 23 | func (me *Flag) broadcastChange() { 24 | for cond := range me.Conds { 25 | cond.Broadcast() 26 | } 27 | } 28 | 29 | func (me *Flag) addCond(c *sync.Cond) { 30 | if me.Conds == nil { 31 | me.Conds = make(map[*sync.Cond]struct{}) 32 | } 33 | me.Conds[c] = struct{}{} 34 | } 35 | 36 | // Adds the sync.Cond to all the given Flag's. 37 | func AddCondToFlags(cond *sync.Cond, flags ...*Flag) { 38 | for _, f := range flags { 39 | f.addCond(cond) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/fs.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import ( 4 | "io" 5 | "os" 6 | ) 7 | 8 | type FileStore interface { 9 | OpenFile(path string, flags int) (File, error) 10 | Stat(path string) (os.FileInfo, error) 11 | Rename(from, to string) error 12 | Remove(path string) error 13 | } 14 | 15 | type File interface { 16 | io.ReaderAt 17 | io.WriterAt 18 | io.Writer 19 | io.Reader 20 | io.Closer 21 | io.Seeker 22 | Stat() (os.FileInfo, error) 23 | } 24 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/futures/funcs.go: -------------------------------------------------------------------------------- 1 | package futures 2 | 3 | import ( 4 | "sync" 5 | ) 6 | 7 | func AsCompleted(fs ...*F) <-chan *F { 8 | ret := make(chan *F, len(fs)) 9 | var wg sync.WaitGroup 10 | for _, f := range fs { 11 | wg.Add(1) 12 | go func(f *F) { 13 | defer wg.Done() 14 | <-f.Done() 15 | ret <- f 16 | }(f) 17 | } 18 | go func() { 19 | wg.Wait() 20 | close(ret) 21 | }() 22 | return ret 23 | } 24 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/futures/future.go: -------------------------------------------------------------------------------- 1 | package futures 2 | 3 | import "sync" 4 | 5 | func Start(fn func() interface{}) *F { 6 | f := &F{ 7 | done: make(chan struct{}), 8 | } 9 | go func() { 10 | result := fn() 11 | f.setResult(result) 12 | }() 13 | return f 14 | } 15 | 16 | type F struct { 17 | mu sync.Mutex 18 | result interface{} 19 | done chan struct{} 20 | } 21 | 22 | func (f *F) Result() interface{} { 23 | <-f.done 24 | f.mu.Lock() 25 | defer f.mu.Unlock() 26 | return f.result 27 | } 28 | 29 | func (f *F) Done() <-chan struct{} { 30 | return f.done 31 | } 32 | 33 | func (f *F) setResult(result interface{}) { 34 | f.mu.Lock() 35 | defer f.mu.Unlock() 36 | f.result = result 37 | close(f.done) 38 | } 39 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/hostmaybeport.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import ( 4 | "net" 5 | "strconv" 6 | "strings" 7 | ) 8 | 9 | // Represents a split host port. 10 | type HostMaybePort struct { 11 | Host string // Just the host, with no port. 12 | Port int // The port if NoPort is false. 13 | NoPort bool // Whether a port is specified. 14 | Err error // The error returned from net.SplitHostPort. 15 | } 16 | 17 | func (me *HostMaybePort) String() string { 18 | if me.NoPort { 19 | return me.Host 20 | } 21 | return net.JoinHostPort(me.Host, strconv.FormatInt(int64(me.Port), 10)) 22 | } 23 | 24 | // Parse a "hostport" string, a concept that floats around the stdlib a lot 25 | // and is painful to work with. If no port is present, what's usually present 26 | // is just the host. 27 | func SplitHostMaybePort(hostport string) HostMaybePort { 28 | host, portStr, err := net.SplitHostPort(hostport) 29 | if err != nil { 30 | if strings.Contains(err.Error(), "missing port") { 31 | return HostMaybePort{ 32 | Host: hostport, 33 | NoPort: true, 34 | } 35 | } 36 | return HostMaybePort{ 37 | Err: err, 38 | } 39 | } 40 | portI64, err := strconv.ParseInt(portStr, 0, 0) 41 | if err != nil { 42 | return HostMaybePort{ 43 | Host: host, 44 | Port: -1, 45 | Err: err, 46 | } 47 | } 48 | return HostMaybePort{ 49 | Host: host, 50 | Port: int(portI64), 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/hostport.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import ( 4 | "net" 5 | "strconv" 6 | ) 7 | 8 | func ParseHostPort(hostport string) (host string, port int, err error) { 9 | host, portStr, err := net.SplitHostPort(hostport) 10 | if err != nil { 11 | return 12 | } 13 | port64, err := strconv.ParseInt(portStr, 0, 0) 14 | if err != nil { 15 | return 16 | } 17 | port = int(port64) 18 | return 19 | } 20 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/http.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import "strconv" 4 | 5 | // Performs quoted-string from http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html 6 | func HTTPQuotedString(s string) string { 7 | return strconv.Quote(s) 8 | } 9 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/httpfile/defaultfs.go: -------------------------------------------------------------------------------- 1 | package httpfile 2 | 3 | import ( 4 | "net/http" 5 | ) 6 | 7 | var DefaultFS = &FS{ 8 | Client: http.DefaultClient, 9 | } 10 | 11 | // Returns the length of the resource in bytes. 12 | func GetLength(url string) (ret int64, err error) { 13 | return DefaultFS.GetLength(url) 14 | } 15 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/httpfile/file.go: -------------------------------------------------------------------------------- 1 | package httpfile 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "fmt" 7 | "io" 8 | "net/http" 9 | "os" 10 | "strconv" 11 | 12 | "github.com/anacrolix/missinggo" 13 | "github.com/anacrolix/missinggo/httptoo" 14 | ) 15 | 16 | type File struct { 17 | off int64 18 | r io.ReadCloser 19 | rOff int64 20 | length int64 21 | url string 22 | flags int 23 | fs *FS 24 | } 25 | 26 | func (me *File) headLength() (err error) { 27 | l, err := me.fs.GetLength(me.url) 28 | if err != nil { 29 | return 30 | } 31 | if l != -1 { 32 | me.length = l 33 | } 34 | return 35 | } 36 | 37 | func (me *File) prepareReader() (err error) { 38 | if me.r != nil && me.off != me.rOff { 39 | me.r.Close() 40 | me.r = nil 41 | } 42 | if me.r != nil { 43 | return nil 44 | } 45 | if me.flags&missinggo.O_ACCMODE == os.O_WRONLY { 46 | err = errors.New("read flags missing") 47 | return 48 | } 49 | req, err := http.NewRequest("GET", me.url, nil) 50 | if err != nil { 51 | return 52 | } 53 | if me.off != 0 { 54 | req.Header.Set("Range", fmt.Sprintf("bytes=%d-", me.off)) 55 | } 56 | resp, err := me.fs.Client.Do(req) 57 | if err != nil { 58 | return 59 | } 60 | switch resp.StatusCode { 61 | case http.StatusPartialContent: 62 | cr, ok := httptoo.ParseBytesContentRange(resp.Header.Get("Content-Range")) 63 | if !ok || cr.First != me.off { 64 | err = errors.New("bad response") 65 | resp.Body.Close() 66 | return 67 | } 68 | me.length = cr.Length 69 | case http.StatusOK: 70 | if me.off != 0 { 71 | err = errors.New("bad response") 72 | resp.Body.Close() 73 | return 74 | } 75 | if h := resp.Header.Get("Content-Length"); h != "" { 76 | var cl uint64 77 | cl, err = strconv.ParseUint(h, 10, 64) 78 | if err != nil { 79 | resp.Body.Close() 80 | return 81 | } 82 | me.length = int64(cl) 83 | } 84 | case http.StatusNotFound: 85 | err = ErrNotFound 86 | resp.Body.Close() 87 | return 88 | default: 89 | err = errors.New(resp.Status) 90 | resp.Body.Close() 91 | return 92 | } 93 | me.r = resp.Body 94 | me.rOff = me.off 95 | return 96 | } 97 | 98 | func (me *File) Read(b []byte) (n int, err error) { 99 | err = me.prepareReader() 100 | if err != nil { 101 | return 102 | } 103 | n, err = me.r.Read(b) 104 | me.off += int64(n) 105 | me.rOff += int64(n) 106 | return 107 | } 108 | 109 | func (me *File) Seek(offset int64, whence int) (ret int64, err error) { 110 | switch whence { 111 | case os.SEEK_SET: 112 | ret = offset 113 | case os.SEEK_CUR: 114 | ret = me.off + offset 115 | case os.SEEK_END: 116 | // Try to update the resource length. 117 | err = me.headLength() 118 | if err != nil { 119 | if me.length == -1 { 120 | // Don't even have an old value. 121 | return 122 | } 123 | err = nil 124 | } 125 | ret = me.length + offset 126 | default: 127 | err = fmt.Errorf("unhandled whence: %d", whence) 128 | return 129 | } 130 | me.off = ret 131 | return 132 | } 133 | 134 | func (me *File) Write(b []byte) (n int, err error) { 135 | if me.flags&(os.O_WRONLY|os.O_RDWR) == 0 || me.flags&os.O_CREATE == 0 { 136 | err = errors.New("cannot write without write and create flags") 137 | return 138 | } 139 | req, err := http.NewRequest("PATCH", me.url, bytes.NewReader(b)) 140 | if err != nil { 141 | return 142 | } 143 | req.Header.Set("Content-Range", fmt.Sprintf("bytes=%d-", me.off)) 144 | req.ContentLength = int64(len(b)) 145 | resp, err := me.fs.Client.Do(req) 146 | if err != nil { 147 | return 148 | } 149 | resp.Body.Close() 150 | if resp.StatusCode != http.StatusPartialContent { 151 | err = errors.New(resp.Status) 152 | return 153 | } 154 | n = len(b) 155 | me.off += int64(n) 156 | return 157 | } 158 | 159 | func (me *File) Close() error { 160 | me.url = "" 161 | me.length = -1 162 | if me.r != nil { 163 | me.r.Close() 164 | me.r = nil 165 | } 166 | return nil 167 | } 168 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/httpfile/fs.go: -------------------------------------------------------------------------------- 1 | package httpfile 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "net/http" 7 | "os" 8 | ) 9 | 10 | type FS struct { 11 | Client *http.Client 12 | } 13 | 14 | func (fs *FS) Delete(urlStr string) (err error) { 15 | req, err := http.NewRequest("DELETE", urlStr, nil) 16 | if err != nil { 17 | return 18 | } 19 | resp, err := fs.Client.Do(req) 20 | if err != nil { 21 | return 22 | } 23 | resp.Body.Close() 24 | if resp.StatusCode == http.StatusNotFound { 25 | err = ErrNotFound 26 | return 27 | } 28 | if resp.StatusCode != 200 { 29 | err = fmt.Errorf("response: %s", resp.Status) 30 | } 31 | return 32 | } 33 | 34 | func (fs *FS) GetLength(url string) (ret int64, err error) { 35 | resp, err := fs.Client.Head(url) 36 | if err != nil { 37 | return 38 | } 39 | resp.Body.Close() 40 | if resp.StatusCode == http.StatusNotFound { 41 | err = ErrNotFound 42 | return 43 | } 44 | return instanceLength(resp) 45 | } 46 | 47 | func (fs *FS) OpenSectionReader(url string, off, n int64) (ret io.ReadCloser, err error) { 48 | req, err := http.NewRequest("GET", url, nil) 49 | if err != nil { 50 | return 51 | } 52 | req.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", off, off+n-1)) 53 | resp, err := fs.Client.Do(req) 54 | if err != nil { 55 | return 56 | } 57 | if resp.StatusCode == http.StatusNotFound { 58 | err = ErrNotFound 59 | resp.Body.Close() 60 | return 61 | } 62 | if resp.StatusCode != http.StatusPartialContent { 63 | err = fmt.Errorf("bad response status: %s", resp.Status) 64 | resp.Body.Close() 65 | return 66 | } 67 | ret = resp.Body 68 | return 69 | } 70 | 71 | func (fs *FS) Open(url string, flags int) (ret *File, err error) { 72 | ret = &File{ 73 | url: url, 74 | flags: flags, 75 | length: -1, 76 | fs: fs, 77 | } 78 | if flags&os.O_CREATE == 0 { 79 | err = ret.headLength() 80 | } 81 | return 82 | } 83 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/httpfile/misc.go: -------------------------------------------------------------------------------- 1 | package httpfile 2 | 3 | import ( 4 | "errors" 5 | "net/http" 6 | "os" 7 | "strconv" 8 | 9 | "github.com/anacrolix/missinggo/httptoo" 10 | ) 11 | 12 | var ( 13 | ErrNotFound = os.ErrNotExist 14 | ) 15 | 16 | // ok is false if the response just doesn't specify anything we handle. 17 | func instanceLength(r *http.Response) (l int64, err error) { 18 | switch r.StatusCode { 19 | case http.StatusOK: 20 | l, err = strconv.ParseInt(r.Header.Get("Content-Length"), 10, 64) 21 | return 22 | case http.StatusPartialContent: 23 | cr, parseOk := httptoo.ParseBytesContentRange(r.Header.Get("Content-Range")) 24 | l = cr.Length 25 | if !parseOk { 26 | err = errors.New("error parsing Content-Range") 27 | } 28 | return 29 | default: 30 | err = errors.New("unhandled status code") 31 | return 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/httpmux/httpmux.go: -------------------------------------------------------------------------------- 1 | package httpmux 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "path" 7 | "regexp" 8 | "strings" 9 | 10 | "golang.org/x/net/context" 11 | ) 12 | 13 | var pathParamContextKey = &struct{}{} 14 | 15 | type Mux struct { 16 | handlers []handler 17 | } 18 | 19 | func New() *Mux { 20 | return new(Mux) 21 | } 22 | 23 | type handler struct { 24 | path *regexp.Regexp 25 | userHandler http.Handler 26 | } 27 | 28 | func (me *Mux) ServeHTTP(w http.ResponseWriter, r *http.Request) { 29 | matches := me.matchingHandlers(r) 30 | switch len(matches) { 31 | case 0: 32 | http.NotFound(w, r) 33 | return 34 | case 1: 35 | m := matches[0] 36 | r = r.WithContext(context.WithValue(r.Context(), pathParamContextKey, &PathParams{m})) 37 | m.handler.userHandler.ServeHTTP(w, r) 38 | default: 39 | panic("multiple handlers match: " + strings.Join(func() (ret []string) { 40 | for _, m := range matches { 41 | ret = append(ret, m.handler.path.String()) 42 | } 43 | return 44 | }(), ", ")) 45 | } 46 | } 47 | 48 | type match struct { 49 | handler handler 50 | submatches []string 51 | } 52 | 53 | func (me *Mux) matchingHandlers(r *http.Request) (ret []match) { 54 | for _, h := range me.handlers { 55 | subs := h.path.FindStringSubmatch(r.URL.Path) 56 | if subs == nil { 57 | continue 58 | } 59 | ret = append(ret, match{h, subs}) 60 | } 61 | return 62 | } 63 | 64 | func (me *Mux) Handle(path string, h http.Handler) { 65 | if !strings.HasSuffix(path, "$") { 66 | path += "$" 67 | } 68 | re, err := regexp.Compile("^" + path) 69 | if err != nil { 70 | panic(err) 71 | } 72 | me.handlers = append(me.handlers, handler{re, h}) 73 | } 74 | 75 | func (me *Mux) HandleFunc(path string, hf func(http.ResponseWriter, *http.Request)) { 76 | me.Handle(path, http.HandlerFunc(hf)) 77 | } 78 | 79 | func Path(parts ...string) string { 80 | return path.Join(parts...) 81 | } 82 | 83 | type PathParams struct { 84 | match match 85 | } 86 | 87 | func (me *PathParams) ByName(name string) string { 88 | for i, sn := range me.match.handler.path.SubexpNames()[1:] { 89 | if sn == name { 90 | return me.match.submatches[i+1] 91 | } 92 | } 93 | return "" 94 | } 95 | 96 | func RequestPathParams(r *http.Request) *PathParams { 97 | ctx := r.Context() 98 | return ctx.Value(pathParamContextKey).(*PathParams) 99 | } 100 | 101 | func PathRegexpParam(name string, re string) string { 102 | return fmt.Sprintf("(?P<%s>%s)", name, re) 103 | } 104 | 105 | func Param(name string) string { 106 | return fmt.Sprintf("(?P<%s>[^/]+)", name) 107 | } 108 | 109 | func RestParam(name string) string { 110 | return fmt.Sprintf("(?P<%s>.*)$", name) 111 | } 112 | 113 | func NonEmptyRestParam(name string) string { 114 | return fmt.Sprintf("(?P<%s>.+)$", name) 115 | } 116 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/httpresponsestatus.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import "net/http" 4 | 5 | // A http.ResponseWriter that tracks the status of the response. The status 6 | // code, and number of bytes written for example. 7 | type StatusResponseWriter struct { 8 | RW http.ResponseWriter 9 | Code int 10 | BytesWritten int64 11 | visible interface { 12 | http.Hijacker 13 | http.CloseNotifier 14 | } 15 | } 16 | 17 | func (me *StatusResponseWriter) Base() interface{} { return me.RW } 18 | func (me *StatusResponseWriter) Visible() interface{} { 19 | return &me.visible 20 | } 21 | 22 | var ( 23 | _ http.ResponseWriter = &StatusResponseWriter{} 24 | _ Inheriter = &StatusResponseWriter{} 25 | ) 26 | 27 | func (me *StatusResponseWriter) Header() http.Header { 28 | return me.RW.Header() 29 | } 30 | 31 | func (me *StatusResponseWriter) Write(b []byte) (n int, err error) { 32 | if me.Code == 0 { 33 | me.Code = 200 34 | } 35 | n, err = me.RW.Write(b) 36 | me.BytesWritten += int64(n) 37 | return 38 | } 39 | 40 | func (me *StatusResponseWriter) WriteHeader(code int) { 41 | me.RW.WriteHeader(code) 42 | me.Code = code 43 | } 44 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/httptoo/bytes_content_range.go: -------------------------------------------------------------------------------- 1 | package httptoo 2 | 3 | import ( 4 | "math" 5 | "regexp" 6 | "strconv" 7 | "strings" 8 | ) 9 | 10 | type BytesContentRange struct { 11 | First, Last, Length int64 12 | } 13 | 14 | type BytesRange struct { 15 | First, Last int64 16 | } 17 | 18 | var ( 19 | httpBytesRangeRegexp = regexp.MustCompile(`bytes[ =](\d+)-(\d*)`) 20 | ) 21 | 22 | func ParseBytesRange(s string) (ret BytesRange, ok bool) { 23 | ss := httpBytesRangeRegexp.FindStringSubmatch(s) 24 | if ss == nil { 25 | return 26 | } 27 | var err error 28 | ret.First, err = strconv.ParseInt(ss[1], 10, 64) 29 | if err != nil { 30 | return 31 | } 32 | if ss[2] == "" { 33 | ret.Last = math.MaxInt64 34 | } else { 35 | ret.Last, err = strconv.ParseInt(ss[2], 10, 64) 36 | if err != nil { 37 | return 38 | } 39 | } 40 | ok = true 41 | return 42 | } 43 | 44 | func parseUnitRanges(s string) (unit, ranges string) { 45 | s = strings.TrimSpace(s) 46 | i := strings.IndexAny(s, " =") 47 | if i == -1 { 48 | return 49 | } 50 | unit = s[:i] 51 | ranges = s[i+1:] 52 | return 53 | } 54 | 55 | func parseFirstLast(s string) (first, last int64) { 56 | ss := strings.SplitN(s, "-", 2) 57 | first, err := strconv.ParseInt(ss[0], 10, 64) 58 | if err != nil { 59 | panic(err) 60 | } 61 | last, err = strconv.ParseInt(ss[1], 10, 64) 62 | if err != nil { 63 | panic(err) 64 | } 65 | return 66 | } 67 | 68 | func parseContentRange(s string) (ret BytesContentRange) { 69 | ss := strings.SplitN(s, "/", 2) 70 | firstLast := strings.TrimSpace(ss[0]) 71 | if firstLast == "*" { 72 | ret.First = -1 73 | ret.Last = -1 74 | } else { 75 | ret.First, ret.Last = parseFirstLast(firstLast) 76 | } 77 | il := strings.TrimSpace(ss[1]) 78 | if il == "*" { 79 | ret.Length = -1 80 | } else { 81 | var err error 82 | ret.Length, err = strconv.ParseInt(il, 10, 64) 83 | if err != nil { 84 | panic(err) 85 | } 86 | } 87 | return 88 | } 89 | 90 | func ParseBytesContentRange(s string) (ret BytesContentRange, ok bool) { 91 | unit, ranges := parseUnitRanges(s) 92 | if unit != "bytes" { 93 | return 94 | } 95 | ret = parseContentRange(ranges) 96 | ok = true 97 | return 98 | } 99 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/httptoo/client.go: -------------------------------------------------------------------------------- 1 | package httptoo 2 | 3 | import ( 4 | "crypto/tls" 5 | "net/http" 6 | ) 7 | 8 | // Returns the http.Client's TLS Config, traversing and generating any 9 | // defaults along the way to get it. 10 | func ClientTLSConfig(cl *http.Client) *tls.Config { 11 | if cl.Transport == nil { 12 | cl.Transport = http.DefaultTransport 13 | } 14 | tr := cl.Transport.(*http.Transport) 15 | if tr.TLSClientConfig == nil { 16 | tr.TLSClientConfig = &tls.Config{} 17 | } 18 | return tr.TLSClientConfig 19 | } 20 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/httptoo/gzip.go: -------------------------------------------------------------------------------- 1 | package httptoo 2 | 3 | import ( 4 | "compress/gzip" 5 | "io" 6 | "net/http" 7 | "strings" 8 | ) 9 | 10 | type gzipResponseWriter struct { 11 | io.Writer 12 | http.ResponseWriter 13 | haveWritten bool 14 | } 15 | 16 | var _ http.ResponseWriter = &gzipResponseWriter{} 17 | 18 | func (w *gzipResponseWriter) Write(b []byte) (int, error) { 19 | if w.haveWritten { 20 | goto write 21 | } 22 | w.haveWritten = true 23 | if w.Header().Get("Content-Type") != "" { 24 | goto write 25 | } 26 | if type_ := http.DetectContentType(b); type_ != "application/octet-stream" { 27 | w.Header().Set("Content-Type", type_) 28 | } 29 | write: 30 | return w.Writer.Write(b) 31 | } 32 | 33 | // Gzips response body if the request says it'll allow it. 34 | func GzipHandler(h http.Handler) http.Handler { 35 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 36 | if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") || w.Header().Get("Content-Encoding") != "" || w.Header().Get("Vary") != "" { 37 | h.ServeHTTP(w, r) 38 | return 39 | } 40 | w.Header().Set("Content-Encoding", "gzip") 41 | w.Header().Set("Vary", "Accept-Encoding") 42 | gz := gzip.NewWriter(w) 43 | defer gz.Close() 44 | h.ServeHTTP(&gzipResponseWriter{ 45 | Writer: gz, 46 | ResponseWriter: w, 47 | }, r) 48 | }) 49 | } 50 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/httptoo/httptoo.go: -------------------------------------------------------------------------------- 1 | package httptoo 2 | 3 | import ( 4 | "net/http" 5 | "strings" 6 | 7 | "github.com/bradfitz/iter" 8 | 9 | "github.com/anacrolix/missinggo" 10 | ) 11 | 12 | func OriginatingProtocol(r *http.Request) string { 13 | if fp := r.Header.Get("X-Forwarded-Proto"); fp != "" { 14 | return fp 15 | } else if r.TLS != nil { 16 | return "https" 17 | } else { 18 | return "http" 19 | } 20 | } 21 | 22 | // Clears the named cookie for every domain that leads to the current one. 23 | func NukeCookie(w http.ResponseWriter, r *http.Request, name, path string) { 24 | parts := strings.Split(missinggo.SplitHostMaybePort(r.Host).Host, ".") 25 | for i := range iter.N(len(parts) + 1) { // Include the empty domain. 26 | http.SetCookie(w, &http.Cookie{ 27 | Name: name, 28 | MaxAge: -1, 29 | Path: path, 30 | Domain: strings.Join(parts[i:], "."), 31 | }) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/httptoo/inproc_roundtrip.go: -------------------------------------------------------------------------------- 1 | package httptoo 2 | 3 | import ( 4 | "io" 5 | "net/http" 6 | "sync" 7 | 8 | "github.com/anacrolix/missinggo" 9 | ) 10 | 11 | type responseWriter struct { 12 | mu sync.Mutex 13 | r http.Response 14 | headerWritten missinggo.Event 15 | bodyWriter io.WriteCloser 16 | } 17 | 18 | func (me *responseWriter) Header() http.Header { 19 | if me.r.Header == nil { 20 | me.r.Header = make(http.Header) 21 | } 22 | return me.r.Header 23 | } 24 | 25 | func (me *responseWriter) Write(b []byte) (int, error) { 26 | me.mu.Lock() 27 | if !me.headerWritten.IsSet() { 28 | me.writeHeader(200) 29 | } 30 | me.mu.Unlock() 31 | return me.bodyWriter.Write(b) 32 | } 33 | 34 | func (me *responseWriter) WriteHeader(status int) { 35 | me.mu.Lock() 36 | me.writeHeader(status) 37 | me.mu.Unlock() 38 | } 39 | 40 | func (me *responseWriter) writeHeader(status int) { 41 | if me.headerWritten.IsSet() { 42 | return 43 | } 44 | me.r.StatusCode = status 45 | me.headerWritten.Set() 46 | } 47 | 48 | func (me *responseWriter) runHandler(h http.Handler, req *http.Request) { 49 | me.r.Body, me.bodyWriter = io.Pipe() 50 | defer me.bodyWriter.Close() 51 | defer me.WriteHeader(200) 52 | h.ServeHTTP(me, req) 53 | } 54 | 55 | func RoundTripHandler(req *http.Request, h http.Handler) (*http.Response, error) { 56 | rw := responseWriter{} 57 | go rw.runHandler(h, req) 58 | <-rw.headerWritten.LockedChan(&rw.mu) 59 | return &rw.r, nil 60 | } 61 | 62 | type InProcRoundTripper struct { 63 | Handler http.Handler 64 | } 65 | 66 | func (me *InProcRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { 67 | return RoundTripHandler(req, me.Handler) 68 | } 69 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/httptoo/middleware.go: -------------------------------------------------------------------------------- 1 | package httptoo 2 | 3 | import "net/http" 4 | 5 | type Middleware func(http.Handler) http.Handler 6 | 7 | func WrapHandler(middleware []Middleware, h http.Handler) (ret http.Handler) { 8 | ret = h 9 | for i := range middleware { 10 | ret = middleware[len(middleware)-1-i](ret) 11 | } 12 | return 13 | } 14 | 15 | func WrapHandlerFunc(middleware []Middleware, hf func(http.ResponseWriter, *http.Request)) (ret http.Handler) { 16 | return WrapHandler(middleware, http.HandlerFunc(hf)) 17 | } 18 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/httptoo/reverse_proxy.go: -------------------------------------------------------------------------------- 1 | package httptoo 2 | 3 | import ( 4 | "bufio" 5 | "encoding/gob" 6 | "io" 7 | "net" 8 | "net/http" 9 | "net/url" 10 | "sync" 11 | ) 12 | 13 | func deepCopy(dst, src interface{}) error { 14 | r, w := io.Pipe() 15 | e := gob.NewEncoder(w) 16 | d := gob.NewDecoder(r) 17 | var decErr, encErr error 18 | var wg sync.WaitGroup 19 | wg.Add(1) 20 | go func() { 21 | defer wg.Done() 22 | decErr = d.Decode(dst) 23 | r.Close() 24 | }() 25 | encErr = e.Encode(src) 26 | // Always returns nil. 27 | w.CloseWithError(encErr) 28 | wg.Wait() 29 | if encErr != nil { 30 | return encErr 31 | } 32 | return decErr 33 | } 34 | 35 | // Takes a request, and alters its destination fields, for proxying. 36 | func RedirectedRequest(r *http.Request, newUrl string) (ret *http.Request, err error) { 37 | u, err := url.Parse(newUrl) 38 | if err != nil { 39 | return 40 | } 41 | ret = new(http.Request) 42 | *ret = *r 43 | ret.Header = nil 44 | err = deepCopy(&ret.Header, r.Header) 45 | if err != nil { 46 | return 47 | } 48 | ret.URL = u 49 | ret.RequestURI = "" 50 | return 51 | } 52 | 53 | func ForwardResponse(w http.ResponseWriter, r *http.Response) { 54 | for h, vs := range r.Header { 55 | for _, v := range vs { 56 | w.Header().Add(h, v) 57 | } 58 | } 59 | w.WriteHeader(r.StatusCode) 60 | // Errors frequently occur writing the body when the client hangs up. 61 | io.Copy(w, r.Body) 62 | r.Body.Close() 63 | } 64 | 65 | func SetOriginRequestForwardingHeaders(o, f *http.Request) { 66 | xff := o.Header.Get("X-Forwarded-For") 67 | hop, _, _ := net.SplitHostPort(f.RemoteAddr) 68 | if xff == "" { 69 | xff = hop 70 | } else { 71 | xff += "," + hop 72 | } 73 | o.Header.Set("X-Forwarded-For", xff) 74 | o.Header.Set("X-Forwarded-Proto", OriginatingProtocol(f)) 75 | } 76 | 77 | // w is for the client response. r is the request to send to the origin 78 | // (already "forwarded"). originUrl is where to send the request. 79 | func ReverseProxyUpgrade(w http.ResponseWriter, r *http.Request, originUrl string) (err error) { 80 | u, err := url.Parse(originUrl) 81 | if err != nil { 82 | return 83 | } 84 | oc, err := net.Dial("tcp", u.Host) 85 | if err != nil { 86 | return 87 | } 88 | defer oc.Close() 89 | err = r.Write(oc) 90 | if err != nil { 91 | return 92 | } 93 | originConnReadBuffer := bufio.NewReader(oc) 94 | originResp, err := http.ReadResponse(originConnReadBuffer, r) 95 | if err != nil { 96 | return 97 | } 98 | if originResp.StatusCode != 101 { 99 | ForwardResponse(w, originResp) 100 | return 101 | } 102 | cc, _, err := w.(http.Hijacker).Hijack() 103 | if err != nil { 104 | return 105 | } 106 | defer cc.Close() 107 | originResp.Write(cc) 108 | go io.Copy(oc, cc) 109 | // Let the origin connection control when this routine returns, as we 110 | // should trust it more. 111 | io.Copy(cc, originConnReadBuffer) 112 | return 113 | } 114 | 115 | func ReverseProxy(w http.ResponseWriter, r *http.Request, originUrl string, client *http.Client) (err error) { 116 | originRequest, err := RedirectedRequest(r, originUrl) 117 | if err != nil { 118 | return 119 | } 120 | SetOriginRequestForwardingHeaders(originRequest, r) 121 | if r.Header.Get("Connection") == "Upgrade" { 122 | return ReverseProxyUpgrade(w, originRequest, originUrl) 123 | } 124 | if client == nil { 125 | client = http.DefaultClient 126 | } 127 | originResp, err := client.Do(originRequest) 128 | if err != nil { 129 | return 130 | } 131 | ForwardResponse(w, originResp) 132 | return 133 | } 134 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/httptoo/url.go: -------------------------------------------------------------------------------- 1 | package httptoo 2 | 3 | import ( 4 | "net/http" 5 | "net/url" 6 | ) 7 | 8 | // Deep copies a URL. 9 | func CopyURL(u *url.URL) (ret *url.URL) { 10 | ret = new(url.URL) 11 | *ret = *u 12 | if u.User != nil { 13 | ret.User = new(url.Userinfo) 14 | *ret.User = *u.User 15 | } 16 | return 17 | } 18 | 19 | // Reconstructs the URL that would have produced the given Request. 20 | // Request.URLs are not fully populated in http.Server handlers. 21 | func RequestedURL(r *http.Request) (ret *url.URL) { 22 | ret = CopyURL(r.URL) 23 | ret.Host = r.Host 24 | ret.Scheme = OriginatingProtocol(r) 25 | return 26 | } 27 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/inherit.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import "reflect" 4 | 5 | // A sort-of implementation of single dispatch polymorphic inheritance. 6 | type Inheriter interface { 7 | // Return the base-class object value. 8 | Base() interface{} 9 | // Return a pointer to an interface containing the methods retrievable 10 | // from the base. 11 | Visible() interface{} 12 | } 13 | 14 | // Obtains the desired value pointed to by dest, from source. If it's not 15 | // found in source, it will walk source's inheritance values until either 16 | // blocked by visibility, an implementation is found, or there are no further 17 | // bases. TODO: If an implementation is obtained from a base class that 18 | // contains some methods present on a derived class, this might break 19 | // encapsulation. Maybe there should be a check to ensure this isn't possible. 20 | func Dispatch(dest, source interface{}) bool { 21 | destValue := reflect.ValueOf(dest).Elem() 22 | destType := destValue.Type() 23 | sourceValue := reflect.ValueOf(source) 24 | sourceType := sourceValue.Type() 25 | // Try the source first. 26 | if implements(destType, sourceType) { 27 | destValue.Set(sourceValue) 28 | return true 29 | } 30 | class, ok := source.(Inheriter) 31 | if !ok { 32 | // No bases, give up. 33 | return false 34 | } 35 | if !visible(destType, reflect.TypeOf(class.Visible()).Elem()) { 36 | // The desired type is masked by the visibility. 37 | return false 38 | } 39 | // Try again from the base class. 40 | return Dispatch(dest, class.Base()) 41 | } 42 | 43 | func visible(wanted reflect.Type, mask reflect.Type) bool { 44 | return mask.ConvertibleTo(wanted) 45 | } 46 | 47 | func implements(wanted, source reflect.Type) bool { 48 | return source.ConvertibleTo(wanted) 49 | } 50 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/inproc/inproc.go: -------------------------------------------------------------------------------- 1 | package inproc 2 | 3 | import ( 4 | "errors" 5 | "io" 6 | "math" 7 | "net" 8 | "strconv" 9 | "sync" 10 | "time" 11 | 12 | "github.com/anacrolix/missinggo" 13 | ) 14 | 15 | var ( 16 | mu sync.Mutex 17 | cond = sync.Cond{L: &mu} 18 | nextPort int = 1 19 | conns = map[int]*packetConn{} 20 | ) 21 | 22 | type addr struct { 23 | Port int 24 | } 25 | 26 | func (addr) Network() string { 27 | return "inproc" 28 | } 29 | 30 | func (me addr) String() string { 31 | return ":" + strconv.FormatInt(int64(me.Port), 10) 32 | } 33 | 34 | func getPort() (port int) { 35 | mu.Lock() 36 | defer mu.Unlock() 37 | port = nextPort 38 | nextPort++ 39 | return 40 | } 41 | 42 | func ResolveAddr(network, str string) (net.Addr, error) { 43 | return ResolveInprocAddr(network, str) 44 | } 45 | 46 | func ResolveInprocAddr(network, str string) (addr addr, err error) { 47 | if str == "" { 48 | addr.Port = getPort() 49 | return 50 | } 51 | _, p, err := net.SplitHostPort(str) 52 | if err != nil { 53 | return 54 | } 55 | i64, err := strconv.ParseInt(p, 10, 0) 56 | if err != nil { 57 | return 58 | } 59 | addr.Port = int(i64) 60 | if addr.Port == 0 { 61 | addr.Port = getPort() 62 | } 63 | return 64 | } 65 | 66 | func ListenPacket(network, addrStr string) (nc net.PacketConn, err error) { 67 | addr, err := ResolveInprocAddr(network, addrStr) 68 | if err != nil { 69 | return 70 | } 71 | mu.Lock() 72 | defer mu.Unlock() 73 | if _, ok := conns[addr.Port]; ok { 74 | err = errors.New("address in use") 75 | return 76 | } 77 | pc := &packetConn{ 78 | addr: addr, 79 | readDeadline: newCondDeadline(&cond), 80 | writeDeadline: newCondDeadline(&cond), 81 | } 82 | conns[addr.Port] = pc 83 | nc = pc 84 | return 85 | } 86 | 87 | type packet struct { 88 | data []byte 89 | addr addr 90 | } 91 | 92 | type packetConn struct { 93 | closed bool 94 | addr addr 95 | reads []packet 96 | readDeadline *condDeadline 97 | writeDeadline *condDeadline 98 | } 99 | 100 | func (me *packetConn) Close() error { 101 | mu.Lock() 102 | defer mu.Unlock() 103 | me.closed = true 104 | delete(conns, me.addr.Port) 105 | cond.Broadcast() 106 | return nil 107 | } 108 | 109 | func (me *packetConn) LocalAddr() net.Addr { 110 | return me.addr 111 | } 112 | 113 | var errTimeout = errors.New("i/o timeout") 114 | 115 | func (me *packetConn) WriteTo(b []byte, na net.Addr) (n int, err error) { 116 | mu.Lock() 117 | defer mu.Unlock() 118 | if me.closed { 119 | err = errors.New("closed") 120 | return 121 | } 122 | if me.writeDeadline.exceeded() { 123 | err = errTimeout 124 | return 125 | } 126 | n = len(b) 127 | port := missinggo.AddrPort(na) 128 | c, ok := conns[port] 129 | if !ok { 130 | // log.Printf("no conn for port %d", port) 131 | return 132 | } 133 | c.reads = append(c.reads, packet{append([]byte(nil), b...), me.addr}) 134 | cond.Broadcast() 135 | return 136 | } 137 | 138 | func (me *packetConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) { 139 | mu.Lock() 140 | defer mu.Unlock() 141 | for { 142 | if len(me.reads) != 0 { 143 | r := me.reads[0] 144 | me.reads = me.reads[1:] 145 | n = copy(b, r.data) 146 | addr = r.addr 147 | // log.Println(addr) 148 | return 149 | } 150 | if me.closed { 151 | err = io.EOF 152 | return 153 | } 154 | if me.readDeadline.exceeded() { 155 | err = errTimeout 156 | return 157 | } 158 | cond.Wait() 159 | } 160 | } 161 | 162 | func (me *packetConn) SetDeadline(t time.Time) error { 163 | me.writeDeadline.setDeadline(t) 164 | me.readDeadline.setDeadline(t) 165 | return nil 166 | } 167 | 168 | func (me *packetConn) SetReadDeadline(t time.Time) error { 169 | me.readDeadline.setDeadline(t) 170 | return nil 171 | } 172 | 173 | func (me *packetConn) SetWriteDeadline(t time.Time) error { 174 | me.writeDeadline.setDeadline(t) 175 | return nil 176 | } 177 | 178 | func newCondDeadline(cond *sync.Cond) (ret *condDeadline) { 179 | ret = &condDeadline{ 180 | timer: time.AfterFunc(math.MaxInt64, func() { 181 | mu.Lock() 182 | ret._exceeded = true 183 | mu.Unlock() 184 | cond.Broadcast() 185 | }), 186 | } 187 | ret.setDeadline(time.Time{}) 188 | return 189 | } 190 | 191 | type condDeadline struct { 192 | mu sync.Mutex 193 | _exceeded bool 194 | timer *time.Timer 195 | } 196 | 197 | func (me *condDeadline) setDeadline(t time.Time) { 198 | me.mu.Lock() 199 | defer me.mu.Unlock() 200 | me._exceeded = false 201 | if t.IsZero() { 202 | me.timer.Stop() 203 | return 204 | } 205 | me.timer.Reset(t.Sub(time.Now())) 206 | } 207 | 208 | func (me *condDeadline) exceeded() bool { 209 | me.mu.Lock() 210 | defer me.mu.Unlock() 211 | return me._exceeded 212 | } 213 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/ioutil.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import "io" 4 | 5 | type StatWriter struct { 6 | Written int64 7 | w io.Writer 8 | } 9 | 10 | func (me *StatWriter) Write(b []byte) (n int, err error) { 11 | n, err = me.w.Write(b) 12 | me.Written += int64(n) 13 | return 14 | } 15 | 16 | func NewStatWriter(w io.Writer) *StatWriter { 17 | return &StatWriter{w: w} 18 | } 19 | 20 | var ZeroReader zeroReader 21 | 22 | type zeroReader struct{} 23 | 24 | func (me zeroReader) Read(b []byte) (n int, err error) { 25 | for i := range b { 26 | b[i] = 0 27 | } 28 | n = len(b) 29 | return 30 | } 31 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/itertools/groupby.go: -------------------------------------------------------------------------------- 1 | package itertools 2 | 3 | type groupBy struct { 4 | curKey interface{} 5 | curKeyOk bool 6 | curValue interface{} 7 | keyFunc func(interface{}) interface{} 8 | input Iterator 9 | groupKey interface{} 10 | groupKeyOk bool 11 | } 12 | 13 | type Group interface { 14 | Iterator 15 | Key() interface{} 16 | } 17 | 18 | type group struct { 19 | gb *groupBy 20 | key interface{} 21 | first bool 22 | stopped bool 23 | } 24 | 25 | func (me *group) Stop() { 26 | me.stopped = true 27 | } 28 | 29 | func (me *group) Next() (ok bool) { 30 | if me.stopped { 31 | return false 32 | } 33 | if me.first { 34 | me.first = false 35 | return true 36 | } 37 | me.gb.advance() 38 | if !me.gb.curKeyOk || me.gb.curKey != me.key { 39 | me.Stop() 40 | return 41 | } 42 | ok = true 43 | return 44 | } 45 | 46 | func (me group) Value() (ret interface{}) { 47 | if me.stopped { 48 | panic("iterator stopped") 49 | } 50 | ret = me.gb.curValue 51 | return 52 | } 53 | 54 | func (me group) Key() interface{} { 55 | return me.key 56 | } 57 | 58 | func (me *groupBy) advance() { 59 | me.curKeyOk = me.input.Next() 60 | if me.curKeyOk { 61 | me.curValue = me.input.Value() 62 | me.curKey = me.keyFunc(me.curValue) 63 | } 64 | } 65 | 66 | func (me *groupBy) Next() (ok bool) { 67 | for me.curKey == me.groupKey { 68 | ok = me.input.Next() 69 | if !ok { 70 | return 71 | } 72 | me.curValue = me.input.Value() 73 | me.curKey = me.keyFunc(me.curValue) 74 | me.curKeyOk = true 75 | } 76 | me.groupKey = me.curKey 77 | me.groupKeyOk = true 78 | return true 79 | } 80 | 81 | func (me *groupBy) Value() (ret interface{}) { 82 | return &group{me, me.groupKey, true, false} 83 | } 84 | 85 | func (me *groupBy) Stop() { 86 | } 87 | 88 | // Allows use of nil as a return from the key func. 89 | var uniqueKey = new(int) 90 | 91 | // Group by returns an iterator of iterators over the values of the input 92 | // iterator that consecutively return the same value when input to the key 93 | // function. Note that repeated calls to each value of the GroupBy Iterator 94 | // does not return a new iterator over the values for that key. 95 | func GroupBy(input Iterator, keyFunc func(interface{}) interface{}) Iterator { 96 | if keyFunc == nil { 97 | keyFunc = func(a interface{}) interface{} { return a } 98 | } 99 | return &groupBy{ 100 | input: input, 101 | keyFunc: keyFunc, 102 | groupKey: uniqueKey, 103 | curKey: uniqueKey, 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/itertools/iterable.go: -------------------------------------------------------------------------------- 1 | package itertools 2 | 3 | import ( 4 | "sync" 5 | 6 | "github.com/anacrolix/missinggo" 7 | ) 8 | 9 | type Iterable interface { 10 | Iter(func(value interface{}) (more bool)) 11 | } 12 | 13 | type iterator struct { 14 | it Iterable 15 | ch chan interface{} 16 | value interface{} 17 | ok bool 18 | mu sync.Mutex 19 | stopped missinggo.Event 20 | } 21 | 22 | func NewIterator(it Iterable) (ret *iterator) { 23 | ret = &iterator{ 24 | it: it, 25 | ch: make(chan interface{}), 26 | } 27 | go func() { 28 | // Have to do this in a goroutine, because the interface is synchronous. 29 | it.Iter(func(value interface{}) bool { 30 | select { 31 | case ret.ch <- value: 32 | return true 33 | case <-ret.stopped.LockedChan(&ret.mu): 34 | return false 35 | } 36 | }) 37 | close(ret.ch) 38 | ret.mu.Lock() 39 | ret.stopped.Set() 40 | ret.mu.Unlock() 41 | }() 42 | return 43 | } 44 | 45 | func (me *iterator) Value() interface{} { 46 | if !me.ok { 47 | panic("no value") 48 | } 49 | return me.value 50 | } 51 | 52 | func (me *iterator) Next() bool { 53 | me.value, me.ok = <-me.ch 54 | return me.ok 55 | } 56 | 57 | func (me *iterator) Stop() { 58 | me.mu.Lock() 59 | me.stopped.Set() 60 | me.mu.Unlock() 61 | } 62 | 63 | func IterableAsSlice(it Iterable) (ret []interface{}) { 64 | it.Iter(func(value interface{}) bool { 65 | ret = append(ret, value) 66 | return true 67 | }) 68 | return 69 | } 70 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/itertools/iterator.go: -------------------------------------------------------------------------------- 1 | package itertools 2 | 3 | import "github.com/anacrolix/missinggo/slices" 4 | 5 | type Iterator interface { 6 | // Advances to the next value. Returns false if there are no more values. 7 | // Must be called before the first value. 8 | Next() bool 9 | // Returns the current value. Should panic when the iterator is in an 10 | // invalid state. 11 | Value() interface{} 12 | // Ceases iteration prematurely. This should occur implicitly if Next 13 | // returns false. 14 | Stop() 15 | } 16 | 17 | type sliceIterator struct { 18 | slice []interface{} 19 | value interface{} 20 | ok bool 21 | } 22 | 23 | func (me *sliceIterator) Next() bool { 24 | if len(me.slice) == 0 { 25 | return false 26 | } 27 | me.value = me.slice[0] 28 | me.slice = me.slice[1:] 29 | me.ok = true 30 | return true 31 | } 32 | 33 | func (me *sliceIterator) Value() interface{} { 34 | if !me.ok { 35 | panic("no value; call Next") 36 | } 37 | return me.value 38 | } 39 | 40 | func (me *sliceIterator) Stop() {} 41 | 42 | func SliceIterator(a []interface{}) Iterator { 43 | return &sliceIterator{ 44 | slice: a, 45 | } 46 | } 47 | 48 | func StringIterator(a string) Iterator { 49 | return SliceIterator(slices.ToEmptyInterface(a)) 50 | } 51 | 52 | func IteratorAsSlice(it Iterator) (ret []interface{}) { 53 | for it.Next() { 54 | ret = append(ret, it.Value()) 55 | } 56 | return 57 | } 58 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/itertools/iterutils.go: -------------------------------------------------------------------------------- 1 | package itertools 2 | 3 | import "math/rand" 4 | 5 | type seq struct { 6 | i []int 7 | } 8 | 9 | // Creates sequence of values from [0, n) 10 | func newSeq(n int) seq { 11 | return seq{make([]int, n, n)} 12 | } 13 | 14 | func (me seq) Index(i int) (ret int) { 15 | ret = me.i[i] 16 | if ret == 0 { 17 | ret = i 18 | } 19 | return 20 | } 21 | 22 | func (me seq) Len() int { 23 | return len(me.i) 24 | } 25 | 26 | // Remove the nth value from the sequence. 27 | func (me *seq) DeleteIndex(index int) { 28 | me.i[index] = me.Index(me.Len() - 1) 29 | me.i = me.i[:me.Len()-1] 30 | } 31 | 32 | func ForPerm(n int, callback func(i int) (more bool)) bool { 33 | s := newSeq(n) 34 | for s.Len() > 0 { 35 | r := rand.Intn(s.Len()) 36 | if !callback(s.Index(r)) { 37 | return false 38 | } 39 | s.DeleteIndex(r) 40 | } 41 | return true 42 | } 43 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/jitter.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import ( 4 | "math/rand" 5 | "time" 6 | ) 7 | 8 | // Returns random duration in the range [average-plusMinus, 9 | // average+plusMinus]. Negative plusMinus will likely panic. Be aware that if 10 | // plusMinus >= average, you may get a zero or negative Duration. The 11 | // distribution function is unspecified, in case I find a more appropriate one 12 | // in the future. 13 | func JitterDuration(average, plusMinus time.Duration) (ret time.Duration) { 14 | ret = average - plusMinus 15 | ret += time.Duration(rand.Int63n(2*int64(plusMinus) + 1)) 16 | return 17 | } 18 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/limitlen.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | // Sets an upper bound on the len of b. max can be any type that will cast to 8 | // int64. 9 | func LimitLen(b *[]byte, max interface{}) { 10 | _max := reflect.ValueOf(max).Int() 11 | if int64(len(*b)) > _max { 12 | *b = (*b)[:_max] 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/max.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import "reflect" 4 | 5 | func Max(_less interface{}, vals ...interface{}) interface{} { 6 | ret := reflect.ValueOf(vals[0]) 7 | less := reflect.ValueOf(_less) 8 | for _, _v := range vals[1:] { 9 | v := reflect.ValueOf(_v) 10 | out := less.Call([]reflect.Value{ret, v}) 11 | if out[0].Bool() { 12 | ret = v 13 | } 14 | } 15 | return ret.Interface() 16 | } 17 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/monotonic.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import ( 4 | "sync" 5 | "time" 6 | ) 7 | 8 | // Monotonic time represents time since an arbitrary point in the past, where 9 | // the concept of now is only ever moving in a positive direction. 10 | type MonotonicTime struct { 11 | skewedStdTime time.Time 12 | } 13 | 14 | func (me MonotonicTime) Sub(other MonotonicTime) time.Duration { 15 | return me.skewedStdTime.Sub(other.skewedStdTime) 16 | } 17 | 18 | var ( 19 | stdNowFunc = time.Now 20 | monotonicMu sync.Mutex 21 | lastStdNow time.Time 22 | monotonicSkew time.Duration 23 | ) 24 | 25 | func skewedStdNow() time.Time { 26 | monotonicMu.Lock() 27 | defer monotonicMu.Unlock() 28 | stdNow := stdNowFunc() 29 | if !lastStdNow.IsZero() && stdNow.Before(lastStdNow) { 30 | monotonicSkew += lastStdNow.Sub(stdNow) 31 | } 32 | lastStdNow = stdNow 33 | return stdNow.Add(monotonicSkew) 34 | } 35 | 36 | // Consecutive calls always produce the same or greater time than previous 37 | // calls. 38 | func MonotonicNow() MonotonicTime { 39 | return MonotonicTime{skewedStdNow()} 40 | } 41 | 42 | func MonotonicSince(since MonotonicTime) (ret time.Duration) { 43 | return skewedStdNow().Sub(since.skewedStdTime) 44 | } 45 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/openflags.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import ( 4 | "os" 5 | ) 6 | 7 | const O_ACCMODE = os.O_RDONLY | os.O_WRONLY | os.O_RDWR 8 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/orderedmap/google_btree.go: -------------------------------------------------------------------------------- 1 | package orderedmap 2 | 3 | import "github.com/google/btree" 4 | 5 | type GoogleBTree struct { 6 | bt *btree.BTree 7 | lesser func(l, r interface{}) bool 8 | } 9 | 10 | type googleBTreeItem struct { 11 | less func(l, r interface{}) bool 12 | key interface{} 13 | value interface{} 14 | } 15 | 16 | func (me googleBTreeItem) Less(right btree.Item) bool { 17 | return me.less(me.key, right.(*googleBTreeItem).key) 18 | } 19 | 20 | func NewGoogleBTree(lesser func(l, r interface{}) bool) *GoogleBTree { 21 | return &GoogleBTree{ 22 | bt: btree.New(32), 23 | lesser: lesser, 24 | } 25 | } 26 | 27 | func (me *GoogleBTree) Set(key interface{}, value interface{}) { 28 | me.bt.ReplaceOrInsert(&googleBTreeItem{me.lesser, key, value}) 29 | } 30 | 31 | func (me *GoogleBTree) Get(key interface{}) interface{} { 32 | ret, _ := me.GetOk(key) 33 | return ret 34 | } 35 | 36 | func (me *GoogleBTree) GetOk(key interface{}) (interface{}, bool) { 37 | item := me.bt.Get(&googleBTreeItem{me.lesser, key, nil}) 38 | if item == nil { 39 | return nil, false 40 | } 41 | return item.(*googleBTreeItem).value, true 42 | } 43 | 44 | type googleBTreeIter struct { 45 | i btree.Item 46 | bt *btree.BTree 47 | } 48 | 49 | func (me *googleBTreeIter) Next() bool { 50 | if me.bt == nil { 51 | return false 52 | } 53 | if me.i == nil { 54 | me.bt.Ascend(func(i btree.Item) bool { 55 | me.i = i 56 | return false 57 | }) 58 | } else { 59 | var n int 60 | me.bt.AscendGreaterOrEqual(me.i, func(i btree.Item) bool { 61 | n++ 62 | if n == 1 { 63 | return true 64 | } 65 | me.i = i 66 | return false 67 | }) 68 | if n != 2 { 69 | me.i = nil 70 | } 71 | } 72 | return me.i != nil 73 | } 74 | 75 | func (me *googleBTreeIter) Value() interface{} { 76 | return me.i.(*googleBTreeItem).value 77 | } 78 | 79 | func (me *googleBTreeIter) Stop() { 80 | me.bt = nil 81 | me.i = nil 82 | } 83 | 84 | func (me *GoogleBTree) Iter(f func(value interface{}) bool) { 85 | me.bt.Ascend(func(i btree.Item) bool { 86 | return f(i.(*googleBTreeItem).value) 87 | }) 88 | } 89 | 90 | func (me *GoogleBTree) Unset(key interface{}) { 91 | me.bt.Delete(&googleBTreeItem{me.lesser, key, nil}) 92 | } 93 | 94 | func (me *GoogleBTree) Len() int { 95 | return me.bt.Len() 96 | } 97 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/orderedmap/orderedmap.go: -------------------------------------------------------------------------------- 1 | package orderedmap 2 | 3 | import "github.com/anacrolix/missinggo/itertools" 4 | 5 | func New(lesser func(l, r interface{}) bool) OrderedMap { 6 | return NewGoogleBTree(lesser) 7 | } 8 | 9 | type OrderedMap interface { 10 | Get(key interface{}) interface{} 11 | GetOk(key interface{}) (interface{}, bool) 12 | itertools.Iterable 13 | Set(key, value interface{}) 14 | Unset(key interface{}) 15 | Len() int 16 | } 17 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/orderedmap/skiplist.go: -------------------------------------------------------------------------------- 1 | package orderedmap 2 | 3 | import "github.com/ryszard/goskiplist/skiplist" 4 | 5 | type skiplistOrderedMap struct { 6 | sl *skiplist.SkipList 7 | } 8 | 9 | func NewSkipList(lesser func(l, r interface{}) bool) *skiplistOrderedMap { 10 | return &skiplistOrderedMap{skiplist.NewCustomMap(lesser)} 11 | } 12 | 13 | func (me *skiplistOrderedMap) Set(key interface{}, value interface{}) { 14 | me.sl.Set(key, value) 15 | } 16 | 17 | func (me *skiplistOrderedMap) Get(key interface{}) interface{} { 18 | if me == nil { 19 | return nil 20 | } 21 | ret, _ := me.sl.Get(key) 22 | return ret 23 | } 24 | 25 | func (me *skiplistOrderedMap) GetOk(key interface{}) (interface{}, bool) { 26 | if me == nil { 27 | return nil, false 28 | } 29 | return me.sl.Get(key) 30 | } 31 | 32 | type Iter struct { 33 | it skiplist.Iterator 34 | } 35 | 36 | func (me *Iter) Next() bool { 37 | if me == nil { 38 | return false 39 | } 40 | return me.it.Next() 41 | } 42 | 43 | func (me *Iter) Value() interface{} { 44 | return me.it.Value() 45 | } 46 | 47 | func (me *skiplistOrderedMap) Iter() *Iter { 48 | if me == nil { 49 | return nil 50 | } 51 | return &Iter{me.sl.Iterator()} 52 | } 53 | 54 | func (me *skiplistOrderedMap) Unset(key interface{}) { 55 | if me == nil { 56 | return 57 | } 58 | me.sl.Delete(key) 59 | } 60 | 61 | func (me *skiplistOrderedMap) Len() int { 62 | if me.sl == nil { 63 | return 0 64 | } 65 | return me.sl.Len() 66 | } 67 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/path.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import ( 4 | "os" 5 | "path" 6 | ) 7 | 8 | // Splits the pathname p into Root and Ext, such that Root+Ext==p. 9 | func PathSplitExt(p string) (ret struct { 10 | Root, Ext string 11 | }) { 12 | ret.Ext = path.Ext(p) 13 | ret.Root = p[:len(p)-len(ret.Ext)] 14 | return 15 | } 16 | 17 | func FilePathExists(p string) bool { 18 | _, err := os.Stat(p) 19 | return err == nil 20 | } 21 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/perf/mutex.go: -------------------------------------------------------------------------------- 1 | package perf 2 | 3 | import ( 4 | "sync" 5 | 6 | "github.com/anacrolix/missinggo" 7 | ) 8 | 9 | type TimedLocker struct { 10 | L sync.Locker 11 | Desc string 12 | } 13 | 14 | func (me *TimedLocker) Lock() { 15 | tr := NewTimer() 16 | me.L.Lock() 17 | tr.Stop(me.Desc) 18 | } 19 | 20 | func (me *TimedLocker) Unlock() { 21 | me.L.Unlock() 22 | } 23 | 24 | type TimedRWLocker struct { 25 | RWL missinggo.RWLocker 26 | WriteDesc string 27 | ReadDesc string 28 | } 29 | 30 | func (me *TimedRWLocker) Lock() { 31 | tr := NewTimer() 32 | me.RWL.Lock() 33 | tr.Stop(me.WriteDesc) 34 | } 35 | 36 | func (me *TimedRWLocker) Unlock() { 37 | me.RWL.Unlock() 38 | } 39 | 40 | func (me *TimedRWLocker) RLock() { 41 | tr := NewTimer() 42 | me.RWL.RLock() 43 | tr.Stop(me.ReadDesc) 44 | } 45 | 46 | func (me *TimedRWLocker) RUnlock() { 47 | me.RWL.RUnlock() 48 | } 49 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/perf/perf.go: -------------------------------------------------------------------------------- 1 | package perf 2 | 3 | import ( 4 | "bytes" 5 | "expvar" 6 | "fmt" 7 | "math" 8 | "sync" 9 | "time" 10 | 11 | "github.com/anacrolix/missinggo" 12 | ) 13 | 14 | var ( 15 | em = missinggo.NewExpvarIndentMap("perfBuckets") 16 | mu sync.RWMutex 17 | ) 18 | 19 | type Timer struct { 20 | started time.Time 21 | } 22 | 23 | func NewTimer() Timer { 24 | return Timer{time.Now()} 25 | } 26 | 27 | // The exponent is the upper bound of the duration in seconds. 28 | func bucketExponent(d time.Duration) int { 29 | e := -9 30 | for d != 0 { 31 | d /= 10 32 | e++ 33 | } 34 | return e 35 | } 36 | 37 | type buckets struct { 38 | mu sync.Mutex 39 | buckets []int64 40 | } 41 | 42 | func (me *buckets) Add(t time.Duration) { 43 | e := bucketExponent(t) 44 | me.mu.Lock() 45 | for e+9 >= len(me.buckets) { 46 | me.buckets = append(me.buckets, 0) 47 | } 48 | me.buckets[e+9]++ 49 | me.mu.Unlock() 50 | } 51 | 52 | func humanExponent(e int) string { 53 | if e == -9 { 54 | return "<1ns" 55 | } 56 | return ">" + time.Duration(math.Pow10(e-1)).String() 57 | } 58 | 59 | func (me *buckets) String() string { 60 | var b bytes.Buffer 61 | fmt.Fprintf(&b, "{") 62 | first := true 63 | me.mu.Lock() 64 | for i, count := range me.buckets { 65 | if first { 66 | if count == 0 { 67 | continue 68 | } 69 | first = false 70 | } else { 71 | fmt.Fprintf(&b, ", ") 72 | } 73 | fmt.Fprintf(&b, "%q: %d", humanExponent(i), count) 74 | } 75 | me.mu.Unlock() 76 | fmt.Fprintf(&b, "}") 77 | return b.String() 78 | } 79 | 80 | var _ expvar.Var = &buckets{} 81 | 82 | func (t *Timer) Stop(desc string) time.Duration { 83 | d := time.Since(t.started) 84 | t.addDuration(desc, d) 85 | return d 86 | } 87 | 88 | func (t *Timer) addDuration(desc string, d time.Duration) { 89 | mu.RLock() 90 | _m := em.Get(desc) 91 | mu.RUnlock() 92 | if _m == nil { 93 | mu.Lock() 94 | _m = em.Get(desc) 95 | if _m == nil { 96 | _m = new(buckets) 97 | em.Set(desc, _m) 98 | } 99 | mu.Unlock() 100 | } 101 | m := _m.(*buckets) 102 | m.Add(d) 103 | } 104 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/pproffd/pproffd.go: -------------------------------------------------------------------------------- 1 | package pproffd 2 | 3 | import ( 4 | "io" 5 | "net" 6 | "os" 7 | "runtime/pprof" 8 | ) 9 | 10 | var p = pprof.NewProfile("fds") 11 | 12 | type fd int 13 | 14 | func (me *fd) Closed() { 15 | p.Remove(me) 16 | } 17 | 18 | func Add(skip int) (ret *fd) { 19 | ret = new(fd) 20 | p.Add(ret, skip+2) 21 | return 22 | } 23 | 24 | type closeWrapper struct { 25 | fd *fd 26 | c io.Closer 27 | } 28 | 29 | func (me closeWrapper) Close() error { 30 | me.fd.Closed() 31 | return me.c.Close() 32 | } 33 | 34 | func newCloseWrapper(c io.Closer) closeWrapper { 35 | return closeWrapper{ 36 | fd: Add(2), 37 | c: c, 38 | } 39 | } 40 | 41 | type wrappedNetConn struct { 42 | net.Conn 43 | closeWrapper 44 | } 45 | 46 | func (me wrappedNetConn) Close() error { 47 | return me.closeWrapper.Close() 48 | } 49 | 50 | // Tracks a net.Conn until Close() is explicitly called. 51 | func WrapNetConn(nc net.Conn) net.Conn { 52 | if nc == nil { 53 | return nil 54 | } 55 | return wrappedNetConn{ 56 | nc, 57 | newCloseWrapper(nc), 58 | } 59 | } 60 | 61 | type OSFile interface { 62 | io.Reader 63 | io.Seeker 64 | io.Closer 65 | io.Writer 66 | Stat() (os.FileInfo, error) 67 | io.ReaderAt 68 | io.WriterAt 69 | } 70 | 71 | type wrappedOSFile struct { 72 | *os.File 73 | closeWrapper 74 | } 75 | 76 | func (me wrappedOSFile) Close() error { 77 | return me.closeWrapper.Close() 78 | } 79 | 80 | func WrapOSFile(f *os.File) OSFile { 81 | return &wrappedOSFile{f, newCloseWrapper(f)} 82 | } 83 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/prioritybitmap/iter.go: -------------------------------------------------------------------------------- 1 | package prioritybitmap 2 | 3 | import "github.com/anacrolix/missinggo/itertools" 4 | 5 | type Iter struct { 6 | it itertools.Iterator 7 | } 8 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/prioritybitmap/prioritybitmap.go: -------------------------------------------------------------------------------- 1 | // Package prioritybitmap implements a set of integers ordered by attached 2 | // priorities. 3 | package prioritybitmap 4 | 5 | import ( 6 | "sync" 7 | 8 | "github.com/anacrolix/missinggo/orderedmap" 9 | ) 10 | 11 | var ( 12 | bitSets = sync.Pool{ 13 | New: func() interface{} { 14 | return make(map[int]struct{}, 1) 15 | }, 16 | } 17 | ) 18 | 19 | type PriorityBitmap struct { 20 | // Protects against unsychronized modifications to bitsets and 21 | mu sync.Mutex 22 | om orderedmap.OrderedMap 23 | // From bit index to priority 24 | priorities map[int]int 25 | } 26 | 27 | func (me *PriorityBitmap) Clear() { 28 | me.om = nil 29 | me.priorities = nil 30 | } 31 | 32 | func (me *PriorityBitmap) deleteBit(bit int) { 33 | p, ok := me.priorities[bit] 34 | if !ok { 35 | return 36 | } 37 | switch v := me.om.Get(p).(type) { 38 | case int: 39 | case map[int]struct{}: 40 | delete(v, bit) 41 | if len(v) != 0 { 42 | return 43 | } 44 | bitSets.Put(v) 45 | } 46 | me.om.Unset(p) 47 | if me.om.Len() == 0 { 48 | me.om = nil 49 | } 50 | } 51 | 52 | func bitLess(l, r interface{}) bool { 53 | return l.(int) < r.(int) 54 | } 55 | 56 | func (me *PriorityBitmap) lazyInit() { 57 | me.om = orderedmap.New(func(l, r interface{}) bool { 58 | return l.(int) < r.(int) 59 | }) 60 | me.priorities = make(map[int]int) 61 | } 62 | 63 | func (me *PriorityBitmap) Set(bit int, priority int) { 64 | me.deleteBit(bit) 65 | if me.priorities == nil { 66 | me.priorities = make(map[int]int) 67 | } 68 | me.priorities[bit] = priority 69 | if me.om == nil { 70 | me.om = orderedmap.New(bitLess) 71 | } 72 | _v, ok := me.om.GetOk(priority) 73 | if !ok { 74 | me.om.Set(priority, bit) 75 | return 76 | } 77 | switch v := _v.(type) { 78 | case int: 79 | newV := bitSets.Get().(map[int]struct{}) 80 | newV[v] = struct{}{} 81 | newV[bit] = struct{}{} 82 | me.om.Set(priority, newV) 83 | case map[int]struct{}: 84 | v[bit] = struct{}{} 85 | } 86 | } 87 | 88 | func (me *PriorityBitmap) Remove(bit int) { 89 | me.mu.Lock() 90 | defer me.mu.Unlock() 91 | me.deleteBit(bit) 92 | delete(me.priorities, bit) 93 | if len(me.priorities) == 0 { 94 | me.priorities = nil 95 | } 96 | if me.om != nil && me.om.Len() == 0 { 97 | me.om = nil 98 | } 99 | } 100 | 101 | func (me *PriorityBitmap) Iter(f func(value interface{}) bool) { 102 | me.IterTyped(func(i int) bool { 103 | return f(i) 104 | }) 105 | } 106 | 107 | func (me *PriorityBitmap) IterTyped(_f func(i int) bool) { 108 | me.mu.Lock() 109 | defer me.mu.Unlock() 110 | if me == nil || me.om == nil { 111 | return 112 | } 113 | f := func(i int) bool { 114 | me.mu.Unlock() 115 | defer me.mu.Lock() 116 | return _f(i) 117 | } 118 | me.om.Iter(func(value interface{}) bool { 119 | switch v := value.(type) { 120 | case int: 121 | return f(v) 122 | case map[int]struct{}: 123 | for i := range v { 124 | if !f(i) { 125 | return false 126 | } 127 | } 128 | } 129 | return true 130 | }) 131 | } 132 | 133 | func (me *PriorityBitmap) IsEmpty() bool { 134 | if me.om == nil { 135 | return true 136 | } 137 | return me.om.Len() == 0 138 | } 139 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/pubsub/pubsub.go: -------------------------------------------------------------------------------- 1 | package pubsub 2 | 3 | import ( 4 | "sync" 5 | ) 6 | 7 | type PubSub struct { 8 | mu sync.Mutex 9 | next chan item 10 | closed bool 11 | } 12 | 13 | type item struct { 14 | value interface{} 15 | next chan item 16 | } 17 | 18 | type Subscription struct { 19 | next chan item 20 | Values chan interface{} 21 | mu sync.Mutex 22 | closed chan struct{} 23 | } 24 | 25 | func NewPubSub() (ret *PubSub) { 26 | return new(PubSub) 27 | } 28 | 29 | func (me *PubSub) init() { 30 | me.next = make(chan item, 1) 31 | } 32 | 33 | func (me *PubSub) lazyInit() { 34 | me.mu.Lock() 35 | defer me.mu.Unlock() 36 | if me.closed { 37 | return 38 | } 39 | if me.next == nil { 40 | me.init() 41 | } 42 | } 43 | 44 | func (me *PubSub) Publish(v interface{}) { 45 | me.lazyInit() 46 | next := make(chan item, 1) 47 | i := item{v, next} 48 | me.mu.Lock() 49 | if !me.closed { 50 | me.next <- i 51 | me.next = next 52 | } 53 | me.mu.Unlock() 54 | } 55 | 56 | func (me *Subscription) Close() { 57 | me.mu.Lock() 58 | defer me.mu.Unlock() 59 | select { 60 | case <-me.closed: 61 | default: 62 | close(me.closed) 63 | } 64 | } 65 | 66 | func (me *Subscription) runner() { 67 | defer close(me.Values) 68 | for { 69 | select { 70 | case i, ok := <-me.next: 71 | if !ok { 72 | me.Close() 73 | return 74 | } 75 | // Send the value back into the channel for someone else. This 76 | // won't block because the channel has a capacity of 1, and this 77 | // is currently the only copy of this value being sent to this 78 | // channel. 79 | me.next <- i 80 | // The next value comes from the channel given to us by the value 81 | // we just got. 82 | me.next = i.next 83 | select { 84 | case me.Values <- i.value: 85 | case <-me.closed: 86 | return 87 | } 88 | case <-me.closed: 89 | return 90 | } 91 | } 92 | } 93 | 94 | func (me *PubSub) Subscribe() (ret *Subscription) { 95 | me.lazyInit() 96 | ret = &Subscription{ 97 | closed: make(chan struct{}), 98 | Values: make(chan interface{}), 99 | } 100 | me.mu.Lock() 101 | ret.next = me.next 102 | me.mu.Unlock() 103 | go ret.runner() 104 | return 105 | } 106 | 107 | func (me *PubSub) Close() { 108 | me.mu.Lock() 109 | defer me.mu.Unlock() 110 | if me.closed { 111 | return 112 | } 113 | if me.next != nil { 114 | close(me.next) 115 | } 116 | me.closed = true 117 | } 118 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/resource/http.go: -------------------------------------------------------------------------------- 1 | package resource 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "fmt" 7 | "io" 8 | "net/http" 9 | "net/url" 10 | "os" 11 | "strconv" 12 | "time" 13 | ) 14 | 15 | // Provides access to resources through a http.Client. 16 | type HTTPProvider struct { 17 | Client *http.Client 18 | } 19 | 20 | var _ Provider = &HTTPProvider{} 21 | 22 | func (me *HTTPProvider) NewInstance(urlStr string) (r Instance, err error) { 23 | _r := new(httpInstance) 24 | _r.URL, err = url.Parse(urlStr) 25 | if err != nil { 26 | return 27 | } 28 | _r.Client = me.Client 29 | if _r.Client == nil { 30 | _r.Client = http.DefaultClient 31 | } 32 | r = _r 33 | return 34 | } 35 | 36 | type httpInstance struct { 37 | Client *http.Client 38 | URL *url.URL 39 | } 40 | 41 | var _ Instance = &httpInstance{} 42 | 43 | func mustNewRequest(method, urlStr string, body io.Reader) *http.Request { 44 | req, err := http.NewRequest(method, urlStr, body) 45 | if err != nil { 46 | panic(err) 47 | } 48 | return req 49 | } 50 | 51 | func responseError(r *http.Response) error { 52 | if r.StatusCode == http.StatusNotFound { 53 | return os.ErrNotExist 54 | } 55 | return errors.New(r.Status) 56 | } 57 | 58 | func (me *httpInstance) Get() (ret io.ReadCloser, err error) { 59 | resp, err := me.Client.Get(me.URL.String()) 60 | if err != nil { 61 | return 62 | } 63 | if resp.StatusCode == http.StatusOK { 64 | ret = resp.Body 65 | return 66 | } 67 | resp.Body.Close() 68 | err = responseError(resp) 69 | return 70 | } 71 | 72 | func (me *httpInstance) Put(r io.Reader) (err error) { 73 | resp, err := me.Client.Do(mustNewRequest("PUT", me.URL.String(), r)) 74 | if err != nil { 75 | return 76 | } 77 | resp.Body.Close() 78 | if resp.StatusCode == http.StatusOK { 79 | return 80 | } 81 | err = responseError(resp) 82 | return 83 | } 84 | 85 | func (me *httpInstance) ReadAt(b []byte, off int64) (n int, err error) { 86 | req := mustNewRequest("GET", me.URL.String(), nil) 87 | req.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", off, off+int64(len(b))-1)) 88 | resp, err := me.Client.Do(req) 89 | if err != nil { 90 | return 91 | } 92 | defer resp.Body.Close() 93 | switch resp.StatusCode { 94 | case http.StatusPartialContent: 95 | case http.StatusRequestedRangeNotSatisfiable: 96 | err = io.EOF 97 | return 98 | default: 99 | err = responseError(resp) 100 | return 101 | } 102 | // TODO: This will crash if ContentLength was not provided (-1). Do 103 | // something about that. 104 | b = b[:resp.ContentLength] 105 | return io.ReadFull(resp.Body, b) 106 | } 107 | 108 | func (me *httpInstance) WriteAt(b []byte, off int64) (n int, err error) { 109 | req := mustNewRequest("PATCH", me.URL.String(), bytes.NewReader(b)) 110 | req.ContentLength = int64(len(b)) 111 | req.Header.Set("Content-Range", fmt.Sprintf("bytes=%d-%d", off, off+int64(len(b))-1)) 112 | resp, err := me.Client.Do(req) 113 | if err != nil { 114 | return 115 | } 116 | resp.Body.Close() 117 | if resp.StatusCode != http.StatusOK { 118 | err = responseError(resp) 119 | } 120 | n = len(b) 121 | return 122 | } 123 | 124 | func (me *httpInstance) Stat() (fi os.FileInfo, err error) { 125 | resp, err := me.Client.Head(me.URL.String()) 126 | if err != nil { 127 | return 128 | } 129 | resp.Body.Close() 130 | if resp.StatusCode == http.StatusNotFound { 131 | err = os.ErrNotExist 132 | return 133 | } 134 | if resp.StatusCode != http.StatusOK { 135 | err = errors.New(resp.Status) 136 | return 137 | } 138 | var _fi httpFileInfo 139 | if h := resp.Header.Get("Last-Modified"); h != "" { 140 | _fi.lastModified, err = time.Parse(http.TimeFormat, h) 141 | if err != nil { 142 | err = fmt.Errorf("error parsing Last-Modified header: %s", err) 143 | return 144 | } 145 | } 146 | if h := resp.Header.Get("Content-Length"); h != "" { 147 | _fi.contentLength, err = strconv.ParseInt(h, 10, 64) 148 | if err != nil { 149 | err = fmt.Errorf("error parsing Content-Length header: %s", err) 150 | return 151 | } 152 | } 153 | fi = _fi 154 | return 155 | } 156 | 157 | func (me *httpInstance) Delete() (err error) { 158 | resp, err := me.Client.Do(mustNewRequest("DELETE", me.URL.String(), nil)) 159 | if err != nil { 160 | return 161 | } 162 | err = responseError(resp) 163 | resp.Body.Close() 164 | return 165 | } 166 | 167 | type httpFileInfo struct { 168 | lastModified time.Time 169 | contentLength int64 170 | } 171 | 172 | var _ os.FileInfo = httpFileInfo{} 173 | 174 | func (fi httpFileInfo) IsDir() bool { 175 | return false 176 | } 177 | 178 | func (fi httpFileInfo) Mode() os.FileMode { 179 | return 0 180 | } 181 | 182 | func (fi httpFileInfo) Name() string { 183 | return "" 184 | } 185 | 186 | func (fi httpFileInfo) Size() int64 { 187 | return fi.contentLength 188 | } 189 | 190 | func (fi httpFileInfo) ModTime() time.Time { 191 | return fi.lastModified 192 | } 193 | 194 | func (fi httpFileInfo) Sys() interface{} { 195 | return nil 196 | } 197 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/resource/osfile.go: -------------------------------------------------------------------------------- 1 | package resource 2 | 3 | import ( 4 | "io" 5 | "os" 6 | ) 7 | 8 | // Provides access to resources through the native OS filesystem. 9 | type OSFileProvider struct{} 10 | 11 | var _ Provider = OSFileProvider{} 12 | 13 | func (me OSFileProvider) NewInstance(filePath string) (r Instance, err error) { 14 | return &osFileInstance{filePath}, nil 15 | } 16 | 17 | type osFileInstance struct { 18 | path string 19 | } 20 | 21 | var _ Instance = &osFileInstance{} 22 | 23 | func (me *osFileInstance) Get() (ret io.ReadCloser, err error) { 24 | return os.Open(me.path) 25 | } 26 | 27 | func (me *osFileInstance) Put(r io.Reader) (err error) { 28 | f, err := os.OpenFile(me.path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0640) 29 | if err != nil { 30 | return 31 | } 32 | defer f.Close() 33 | _, err = io.Copy(f, r) 34 | return 35 | } 36 | 37 | func (me *osFileInstance) ReadAt(b []byte, off int64) (n int, err error) { 38 | f, err := os.Open(me.path) 39 | if err != nil { 40 | return 41 | } 42 | defer f.Close() 43 | return f.ReadAt(b, off) 44 | } 45 | 46 | func (me *osFileInstance) WriteAt(b []byte, off int64) (n int, err error) { 47 | f, err := os.OpenFile(me.path, os.O_CREATE|os.O_WRONLY, 0640) 48 | if err != nil { 49 | return 50 | } 51 | defer f.Close() 52 | return f.WriteAt(b, off) 53 | } 54 | 55 | func (me *osFileInstance) Stat() (fi os.FileInfo, err error) { 56 | return os.Stat(me.path) 57 | } 58 | 59 | func (me *osFileInstance) Delete() error { 60 | return os.Remove(me.path) 61 | } 62 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/resource/provider.go: -------------------------------------------------------------------------------- 1 | package resource 2 | 3 | type Provider interface { 4 | NewInstance(string) (Instance, error) 5 | } 6 | 7 | // TranslatedProvider manipulates resource locations, so as to allow 8 | // sandboxing, or relative paths for example. 9 | type TranslatedProvider struct { 10 | // The underlying Provider. 11 | BaseProvider Provider 12 | // Some location used in calculating final locations. 13 | BaseLocation string 14 | // Function that takes BaseLocation, and the caller location and returns 15 | // the location to be used with the BaseProvider. 16 | JoinLocations func(base, rel string) string 17 | } 18 | 19 | func (me *TranslatedProvider) NewInstance(rel string) (Instance, error) { 20 | return me.BaseProvider.NewInstance(me.JoinLocations(me.BaseLocation, rel)) 21 | } 22 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/resource/resource.go: -------------------------------------------------------------------------------- 1 | package resource 2 | 3 | import ( 4 | "io" 5 | "os" 6 | ) 7 | 8 | // An Instance represents the content at some location accessed through some 9 | // Provider. It's the data at some URL. 10 | type Instance interface { 11 | Get() (io.ReadCloser, error) 12 | Put(io.Reader) error 13 | Stat() (os.FileInfo, error) 14 | ReadAt([]byte, int64) (int, error) 15 | WriteAt([]byte, int64) (int, error) 16 | Delete() error 17 | } 18 | 19 | // Creates a io.ReadSeeker to an Instance. 20 | func ReadSeeker(r Instance) io.ReadSeeker { 21 | fi, err := r.Stat() 22 | if err != nil { 23 | return nil 24 | } 25 | return io.NewSectionReader(r, 0, fi.Size()) 26 | } 27 | 28 | // Move instance content, deleting the source if it succeeds. 29 | func Move(from, to Instance) (err error) { 30 | rc, err := from.Get() 31 | if err != nil { 32 | return 33 | } 34 | defer rc.Close() 35 | err = to.Put(rc) 36 | if err != nil { 37 | return 38 | } 39 | from.Delete() 40 | return 41 | } 42 | 43 | func Exists(i Instance) bool { 44 | _, err := i.Stat() 45 | return err == nil 46 | } 47 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/rle.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | // A RunLengthEncoder counts successive duplicate elements and emits the 4 | // element and the run length when the element changes or the encoder is 5 | // flushed. 6 | type RunLengthEncoder interface { 7 | // Add a series of identical elements to the stream. 8 | Append(element interface{}, count uint64) 9 | // Emit the current element and its count if non-zero without waiting for 10 | // the element to change. 11 | Flush() 12 | } 13 | 14 | type runLengthEncoder struct { 15 | eachRun func(element interface{}, count uint64) 16 | element interface{} 17 | count uint64 18 | } 19 | 20 | // Creates a new RunLengthEncoder. eachRun is called when an element and its 21 | // count is emitted, per the RunLengthEncoder interface. 22 | func NewRunLengthEncoder(eachRun func(element interface{}, count uint64)) RunLengthEncoder { 23 | return &runLengthEncoder{ 24 | eachRun: eachRun, 25 | } 26 | } 27 | 28 | func (me *runLengthEncoder) Append(element interface{}, count uint64) { 29 | if element == me.element { 30 | me.count += count 31 | return 32 | } 33 | if me.count != 0 { 34 | me.eachRun(me.element, me.count) 35 | } 36 | me.count = count 37 | me.element = element 38 | } 39 | 40 | func (me *runLengthEncoder) Flush() { 41 | if me.count == 0 { 42 | return 43 | } 44 | me.eachRun(me.element, me.count) 45 | me.count = 0 46 | } 47 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/section_read_seeker.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "os" 7 | ) 8 | 9 | type sectionReadSeeker struct { 10 | base io.ReadSeeker 11 | off, size int64 12 | } 13 | 14 | // Returns a ReadSeeker on a section of another ReadSeeker. 15 | func NewSectionReadSeeker(base io.ReadSeeker, off, size int64) (ret io.ReadSeeker) { 16 | ret = §ionReadSeeker{ 17 | base: base, 18 | off: off, 19 | size: size, 20 | } 21 | seekOff, err := ret.Seek(0, os.SEEK_SET) 22 | if err != nil { 23 | panic(err) 24 | } 25 | if seekOff != 0 { 26 | panic(seekOff) 27 | } 28 | return 29 | } 30 | 31 | func (me *sectionReadSeeker) Seek(off int64, whence int) (ret int64, err error) { 32 | switch whence { 33 | case os.SEEK_SET: 34 | off += me.off 35 | case os.SEEK_CUR: 36 | case os.SEEK_END: 37 | off += me.off + me.size 38 | whence = os.SEEK_SET 39 | default: 40 | err = fmt.Errorf("unhandled whence: %d", whence) 41 | return 42 | } 43 | ret, err = me.base.Seek(off, whence) 44 | ret -= me.off 45 | return 46 | } 47 | 48 | func (me *sectionReadSeeker) Read(b []byte) (n int, err error) { 49 | off, err := me.Seek(0, os.SEEK_CUR) 50 | if err != nil { 51 | return 52 | } 53 | left := me.size - off 54 | if left <= 0 { 55 | err = io.EOF 56 | return 57 | } 58 | if int64(len(b)) > left { 59 | b = b[:left] 60 | } 61 | return me.base.Read(b) 62 | } 63 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/section_writer.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import "io" 4 | 5 | type SectionWriter struct { 6 | w io.WriterAt 7 | off, len int64 8 | } 9 | 10 | func NewSectionWriter(w io.WriterAt, off, len int64) *SectionWriter { 11 | return &SectionWriter{w, off, len} 12 | } 13 | 14 | func (me *SectionWriter) WriteAt(b []byte, off int64) (n int, err error) { 15 | if off >= me.len { 16 | err = io.EOF 17 | return 18 | } 19 | if off+int64(len(b)) > me.len { 20 | b = b[:me.len-off] 21 | } 22 | return me.w.WriteAt(b, me.off+off) 23 | } 24 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/selfcert.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import ( 4 | "crypto/ecdsa" 5 | "crypto/rand" 6 | "crypto/rsa" 7 | "crypto/tls" 8 | "crypto/x509" 9 | "crypto/x509/pkix" 10 | "log" 11 | "math/big" 12 | "time" 13 | ) 14 | 15 | func publicKey(priv interface{}) interface{} { 16 | switch k := priv.(type) { 17 | case *rsa.PrivateKey: 18 | return &k.PublicKey 19 | case *ecdsa.PrivateKey: 20 | return &k.PublicKey 21 | default: 22 | return nil 23 | } 24 | } 25 | 26 | // Creates a self-signed certificate in memory for use with tls.Config. 27 | func NewSelfSignedCertificate() (cert tls.Certificate, err error) { 28 | cert.PrivateKey, err = rsa.GenerateKey(rand.Reader, 2048) 29 | if err != nil { 30 | return 31 | } 32 | notBefore := time.Now() 33 | notAfter := notBefore.Add(365 * 24 * time.Hour) 34 | 35 | serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) 36 | serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) 37 | if err != nil { 38 | log.Fatalf("failed to generate serial number: %s", err) 39 | } 40 | 41 | template := x509.Certificate{ 42 | SerialNumber: serialNumber, 43 | Subject: pkix.Name{ 44 | Organization: []string{"Acme Co"}, 45 | }, 46 | NotBefore: notBefore, 47 | NotAfter: notAfter, 48 | 49 | KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, 50 | ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, 51 | BasicConstraintsValid: true, 52 | } 53 | 54 | derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(cert.PrivateKey), cert.PrivateKey) 55 | if err != nil { 56 | log.Fatalf("Failed to create certificate: %s", err) 57 | } 58 | cert.Certificate = [][]byte{derBytes} 59 | return 60 | } 61 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/singleflight.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import "sync" 4 | 5 | type ongoing struct { 6 | do sync.Mutex 7 | users int 8 | } 9 | 10 | type SingleFlight struct { 11 | mu sync.Mutex 12 | ongoing map[string]*ongoing 13 | } 14 | 15 | type Operation struct { 16 | sf *SingleFlight 17 | id string 18 | } 19 | 20 | func (op Operation) Unlock() { 21 | op.sf.Unlock(op.id) 22 | } 23 | 24 | func (me *SingleFlight) Lock(id string) Operation { 25 | me.mu.Lock() 26 | on, ok := me.ongoing[id] 27 | if !ok { 28 | on = new(ongoing) 29 | if me.ongoing == nil { 30 | me.ongoing = make(map[string]*ongoing) 31 | } 32 | me.ongoing[id] = on 33 | } 34 | on.users++ 35 | me.mu.Unlock() 36 | on.do.Lock() 37 | return Operation{me, id} 38 | } 39 | 40 | func (me *SingleFlight) Unlock(id string) { 41 | me.mu.Lock() 42 | on := me.ongoing[id] 43 | on.do.Unlock() 44 | on.users-- 45 | if on.users == 0 { 46 | delete(me.ongoing, id) 47 | } 48 | me.mu.Unlock() 49 | } 50 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/slices/cast.go: -------------------------------------------------------------------------------- 1 | package slices 2 | 3 | import ( 4 | "reflect" 5 | 6 | "github.com/bradfitz/iter" 7 | ) 8 | 9 | // Returns a copy of all the elements of slice []T as a slice of interface{}. 10 | func ToEmptyInterface(slice interface{}) (ret []interface{}) { 11 | v := reflect.ValueOf(slice) 12 | l := v.Len() 13 | ret = make([]interface{}, 0, l) 14 | for i := range iter.N(v.Len()) { 15 | ret = append(ret, v.Index(i).Interface()) 16 | } 17 | return 18 | } 19 | 20 | // Makes and sets a slice at *ptrTo, and type asserts all the elements from 21 | // from to it. 22 | func MakeInto(ptrTo interface{}, from interface{}) { 23 | fromSliceValue := reflect.ValueOf(from) 24 | fromLen := fromSliceValue.Len() 25 | if fromLen == 0 { 26 | return 27 | } 28 | // Deref the pointer to slice. 29 | slicePtrValue := reflect.ValueOf(ptrTo) 30 | if slicePtrValue.Kind() != reflect.Ptr { 31 | panic("destination is not a pointer") 32 | } 33 | destSliceValue := slicePtrValue.Elem() 34 | // The type of the elements of the destination slice. 35 | destSliceElemType := destSliceValue.Type().Elem() 36 | destSliceValue.Set(reflect.MakeSlice(destSliceValue.Type(), fromLen, fromLen)) 37 | for i := range iter.N(fromSliceValue.Len()) { 38 | // The value inside the interface in the slice element. 39 | itemValue := fromSliceValue.Index(i) 40 | if itemValue.Kind() == reflect.Interface { 41 | itemValue = itemValue.Elem() 42 | } 43 | convertedItem := itemValue.Convert(destSliceElemType) 44 | destSliceValue.Index(i).Set(convertedItem) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/slices/doc.go: -------------------------------------------------------------------------------- 1 | // Package slices has several utilities for operating on slices given Go's 2 | // lack of generic types. Many functions take an argument of type func(l, r T) 3 | // bool, that's expected to compute l < r where T is T in []T, the type of the 4 | // given slice. 5 | package slices 6 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/slices/map.go: -------------------------------------------------------------------------------- 1 | package slices 2 | 3 | import "reflect" 4 | 5 | type MapItem struct { 6 | Key, Elem interface{} 7 | } 8 | 9 | // Creates a []struct{Key K; Value V} for map[K]V. 10 | func FromMap(m interface{}) (slice []MapItem) { 11 | mapValue := reflect.ValueOf(m) 12 | for _, key := range mapValue.MapKeys() { 13 | slice = append(slice, MapItem{key.Interface(), mapValue.MapIndex(key).Interface()}) 14 | } 15 | return 16 | } 17 | 18 | // Returns all the elements []T, from m where m is map[K]T. 19 | func FromMapElems(m interface{}) interface{} { 20 | inValue := reflect.ValueOf(m) 21 | outValue := reflect.MakeSlice(reflect.SliceOf(inValue.Type().Elem()), inValue.Len(), inValue.Len()) 22 | for i, key := range inValue.MapKeys() { 23 | outValue.Index(i).Set(inValue.MapIndex(key)) 24 | } 25 | return outValue.Interface() 26 | } 27 | 28 | // Returns all the elements []K, from m where m is map[K]T. 29 | func FromMapKeys(m interface{}) interface{} { 30 | inValue := reflect.ValueOf(m) 31 | outValue := reflect.MakeSlice(reflect.SliceOf(inValue.Type().Key()), inValue.Len(), inValue.Len()) 32 | for i, key := range inValue.MapKeys() { 33 | outValue.Index(i).Set(key) 34 | } 35 | return outValue.Interface() 36 | } 37 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/slices/sort.go: -------------------------------------------------------------------------------- 1 | package slices 2 | 3 | import ( 4 | "container/heap" 5 | "reflect" 6 | "sort" 7 | ) 8 | 9 | // Sorts the slice in place. Returns sl for convenience. 10 | func Sort(sl interface{}, less interface{}) interface{} { 11 | sorter := sorter{ 12 | sl: reflect.ValueOf(sl), 13 | less: reflect.ValueOf(less), 14 | } 15 | sort.Sort(&sorter) 16 | return sorter.sl.Interface() 17 | } 18 | 19 | // Creates a modifiable copy of a slice reference. Because you can't modify 20 | // non-pointer types inside an interface{}. 21 | func addressableSlice(slice interface{}) reflect.Value { 22 | v := reflect.ValueOf(slice) 23 | p := reflect.New(v.Type()) 24 | p.Elem().Set(v) 25 | return p.Elem() 26 | } 27 | 28 | // Returns a "container/heap".Interface for the provided slice. 29 | func HeapInterface(sl interface{}, less interface{}) heap.Interface { 30 | ret := &sorter{ 31 | sl: addressableSlice(sl), 32 | less: reflect.ValueOf(less), 33 | } 34 | heap.Init(ret) 35 | return ret 36 | } 37 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/slices/sorter.go: -------------------------------------------------------------------------------- 1 | package slices 2 | 3 | import "reflect" 4 | 5 | type sorter struct { 6 | sl reflect.Value 7 | less reflect.Value 8 | } 9 | 10 | func (s *sorter) Len() int { 11 | return s.sl.Len() 12 | } 13 | 14 | func (s *sorter) Less(i, j int) bool { 15 | return s.less.Call([]reflect.Value{ 16 | s.sl.Index(i), 17 | s.sl.Index(j), 18 | })[0].Bool() 19 | } 20 | 21 | func (s *sorter) Swap(i, j int) { 22 | t := reflect.New(s.sl.Type().Elem()).Elem() 23 | t.Set(s.sl.Index(i)) 24 | s.sl.Index(i).Set(s.sl.Index(j)) 25 | s.sl.Index(j).Set(t) 26 | } 27 | 28 | func (s *sorter) Pop() interface{} { 29 | ret := s.sl.Index(s.sl.Len() - 1).Interface() 30 | s.sl.SetLen(s.sl.Len() - 1) 31 | return ret 32 | } 33 | 34 | func (s *sorter) Push(val interface{}) { 35 | s.sl = reflect.Append(s.sl, reflect.ValueOf(val)) 36 | } 37 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/stack.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "runtime" 7 | ) 8 | 9 | func WriteStack(w io.Writer, stack []uintptr) { 10 | for _, pc := range stack { 11 | if pc == 0 { 12 | break 13 | } 14 | pc-- 15 | f := runtime.FuncForPC(pc) 16 | if f.Name() == "runtime.goexit" { 17 | continue 18 | } 19 | file, line := f.FileLine(pc) 20 | fmt.Fprintf(w, "# %s:\t%s:%d\n", f.Name(), file, line) 21 | } 22 | fmt.Fprintf(w, "\n") 23 | } 24 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/strbool.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import ( 4 | "strconv" 5 | ) 6 | 7 | func StringTruth(s string) (ret bool) { 8 | if s == "" { 9 | return false 10 | } 11 | ret, err := strconv.ParseBool(s) 12 | if err == nil { 13 | return 14 | } 15 | i, err := strconv.ParseInt(s, 0, 0) 16 | if err == nil { 17 | return i != 0 18 | } 19 | return true 20 | } 21 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/sync.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import ( 4 | "sync" 5 | ) 6 | 7 | type RWLocker interface { 8 | sync.Locker 9 | RLock() 10 | RUnlock() 11 | } 12 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/testing.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import ( 4 | "regexp" 5 | "runtime" 6 | ) 7 | 8 | // It will be the one and only identifier after a package specifier. 9 | var testNameRegexp = regexp.MustCompile(`\.(Test[\p{L}_\p{N}]*)$`) 10 | 11 | // Returns the name of the test function from the call stack. See 12 | // http://stackoverflow.com/q/35535635/149482 for another method. 13 | func GetTestName() string { 14 | pc := make([]uintptr, 32) 15 | n := runtime.Callers(0, pc) 16 | for i := 0; i < n; i++ { 17 | name := runtime.FuncForPC(pc[i]).Name() 18 | ms := testNameRegexp.FindStringSubmatch(name) 19 | if ms == nil { 20 | continue 21 | } 22 | return ms[1] 23 | } 24 | panic("test name could not be recovered") 25 | } 26 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/timer.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import ( 4 | "math" 5 | "time" 6 | ) 7 | 8 | // Returns a time.Timer that calls f. The timer is initially stopped. 9 | func StoppedFuncTimer(f func()) (t *time.Timer) { 10 | t = time.AfterFunc(math.MaxInt64, f) 11 | if !t.Stop() { 12 | panic("timer already fired") 13 | } 14 | return 15 | } 16 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/units.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | const MiB = 1 << 20 4 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/url.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import ( 4 | "net/url" 5 | "path" 6 | ) 7 | 8 | // Returns URL opaque as an unrooted path. 9 | func URLOpaquePath(u *url.URL) string { 10 | if u.Opaque != "" { 11 | return u.Opaque 12 | } 13 | return u.Path 14 | } 15 | 16 | // Cleans the (absolute) URL path, removing unnecessary . and .. elements. See 17 | // "net/http".cleanPath. 18 | func CleanURLPath(p string) string { 19 | if p == "" { 20 | return "/" 21 | } 22 | if p[0] != '/' { 23 | p = "/" + p 24 | } 25 | cp := path.Clean(p) 26 | // Add the trailing slash back, as it's relevant to a URL. 27 | if p[len(p)-1] == '/' && cp != "/" { 28 | cp += "/" 29 | } 30 | return cp 31 | } 32 | 33 | func URLJoinSubPath(base, rel string) string { 34 | baseURL, err := url.Parse(base) 35 | if err != nil { 36 | // Honey badger doesn't give a fuck. 37 | panic(err) 38 | } 39 | rel = CleanURLPath(rel) 40 | baseURL.Path = path.Join(baseURL.Path, rel) 41 | return baseURL.String() 42 | } 43 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/wait_event.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import ( 4 | "reflect" 5 | "sync" 6 | ) 7 | 8 | func WaitEvents(l sync.Locker, evs ...*Event) { 9 | cases := make([]reflect.SelectCase, 0, len(evs)) 10 | for _, ev := range evs { 11 | cases = append(cases, reflect.SelectCase{ 12 | Dir: reflect.SelectRecv, 13 | Chan: reflect.ValueOf(ev.C()), 14 | }) 15 | } 16 | l.Unlock() 17 | reflect.Select(cases) 18 | l.Lock() 19 | } 20 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/missinggo/wolf.go: -------------------------------------------------------------------------------- 1 | package missinggo 2 | 3 | import ( 4 | "log" 5 | "runtime" 6 | "sync" 7 | "sync/atomic" 8 | ) 9 | 10 | const debug = false 11 | 12 | // A Wolf represents some event that becomes less and less interesting as it 13 | // occurs. Call CryHeard to see if we should pay attention this time. 14 | type Wolf struct { 15 | cries uint64 16 | } 17 | 18 | // Returns true less and less often. Convenient for exponentially decreasing 19 | // the amount of noise due to errors. 20 | func (me *Wolf) CryHeard() bool { 21 | n := atomic.AddUint64(&me.cries, 1) 22 | return n&(n-1) == 0 23 | } 24 | 25 | var ( 26 | mu sync.Mutex 27 | wolves map[uintptr]*Wolf 28 | ) 29 | 30 | // Calls CryHeard() on a Wolf that is unique to the callers program counter. 31 | // i.e. every CryHeard() expression has its own Wolf. 32 | func CryHeard() bool { 33 | pc, file, line, ok := runtime.Caller(1) 34 | if debug { 35 | log.Println(pc, file, line, ok) 36 | } 37 | if !ok { 38 | return true 39 | } 40 | mu.Lock() 41 | if wolves == nil { 42 | wolves = make(map[uintptr]*Wolf) 43 | } 44 | w, ok := wolves[pc] 45 | if !ok { 46 | w = new(Wolf) 47 | wolves[pc] = w 48 | } 49 | mu.Unlock() 50 | return w.CryHeard() 51 | } 52 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/tagflag/arg.go: -------------------------------------------------------------------------------- 1 | package tagflag 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | type arg struct { 9 | arity arity 10 | name string 11 | help string 12 | value reflect.Value 13 | } 14 | 15 | func (me arg) marshal(s string, explicitValue bool) error { 16 | m := valueMarshaler(me.value) 17 | if !explicitValue && m.RequiresExplicitValue() { 18 | return userError{fmt.Sprintf("explicit value required (%s%s=VALUE)", flagPrefix, me.name)} 19 | } 20 | return valueMarshaler(me.value).Marshal(me.value, s) 21 | } 22 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/tagflag/arity.go: -------------------------------------------------------------------------------- 1 | package tagflag 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | const infArity = 1000 9 | 10 | type arity struct { 11 | min, max int 12 | } 13 | 14 | func fieldArity(v reflect.Value, sf reflect.StructField) (arity arity) { 15 | arity.min = 1 16 | arity.max = 1 17 | if v.Kind() == reflect.Slice { 18 | arity.max = infArity 19 | } 20 | if sf.Tag.Get("arity") != "" { 21 | switch sf.Tag.Get("arity") { 22 | case "?": 23 | arity.min = 0 24 | case "*": 25 | arity.min = 0 26 | arity.max = infArity 27 | case "+": 28 | arity.max = infArity 29 | default: 30 | panic(fmt.Sprintf("unhandled arity tag: %q", sf.Tag.Get("arity"))) 31 | } 32 | } 33 | return 34 | } 35 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/tagflag/builtin.go: -------------------------------------------------------------------------------- 1 | package tagflag 2 | 3 | import ( 4 | "net" 5 | "net/url" 6 | "reflect" 7 | "time" 8 | ) 9 | 10 | var builtinMarshalers = map[reflect.Type]marshaler{} 11 | 12 | // Convenience function to allow adding marshalers using typed functions. 13 | // marshalFunc is of type func(arg string) T or func(arg string) (T, error), 14 | // where T is the type the function can marshal. 15 | func addBuiltinDynamicMarshaler(marshalFunc interface{}, explicitValueRequired bool) { 16 | marshalFuncValue := reflect.ValueOf(marshalFunc) 17 | marshalType := marshalFuncValue.Type().Out(0) 18 | builtinMarshalers[marshalType] = dynamicMarshaler{ 19 | marshal: func(marshalValue reflect.Value, arg string) error { 20 | out := marshalFuncValue.Call([]reflect.Value{reflect.ValueOf(arg)}) 21 | marshalValue.Set(out[0]) 22 | if len(out) > 1 { 23 | i := out[1].Interface() 24 | if i != nil { 25 | return i.(error) 26 | } 27 | } 28 | return nil 29 | }, 30 | explicitValueRequired: explicitValueRequired, 31 | } 32 | } 33 | 34 | func init() { 35 | // These are some simple builtin types that are nice to be handled without 36 | // wrappers that implement Marshaler. Note that if they return pointer 37 | // types, those must be used in the flag struct, because there's no way to 38 | // know that nothing depends on the address returned. 39 | addBuiltinDynamicMarshaler(func(urlStr string) (*url.URL, error) { 40 | return url.Parse(urlStr) 41 | }, false) 42 | // Empty strings for this type are valid, so we enforce that the value is 43 | // explicit (=), so that the user knows what they're getting into. 44 | addBuiltinDynamicMarshaler(func(s string) (*net.TCPAddr, error) { 45 | return net.ResolveTCPAddr("tcp", s) 46 | }, true) 47 | addBuiltinDynamicMarshaler(func(s string) (time.Duration, error) { 48 | return time.ParseDuration(s) 49 | }, false) 50 | addBuiltinDynamicMarshaler(func(s string) net.IP { 51 | return net.ParseIP(s) 52 | }, false) 53 | } 54 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/tagflag/bytes.go: -------------------------------------------------------------------------------- 1 | package tagflag 2 | 3 | import "github.com/dustin/go-humanize" 4 | 5 | // A nice builtin type that will marshal human readable byte quantities to 6 | // int64. For example 100GB. See https://godoc.org/github.com/dustin/go-humanize. 7 | type Bytes int64 8 | 9 | var _ Marshaler = new(Bytes) 10 | 11 | func (me *Bytes) Marshal(s string) (err error) { 12 | ui64, err := humanize.ParseBytes(s) 13 | if err != nil { 14 | return 15 | } 16 | *me = Bytes(ui64) 17 | return 18 | } 19 | 20 | func (Bytes) RequiresExplicitValue() bool { 21 | return false 22 | } 23 | 24 | func (me Bytes) Int64() int64 { 25 | return int64(me) 26 | } 27 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/tagflag/doc.go: -------------------------------------------------------------------------------- 1 | // Package tagflag uses reflection to derive flags and positional arguments to a 2 | // program, and parses and sets them from a slice of arguments. 3 | // 4 | // For example: 5 | // var opts struct { 6 | // Mmap bool `help:"memory-map torrent data"` 7 | // TestPeer []*net.TCPAddr `help:"addresses of some starting peers"` 8 | // tagflag.StartPos // Marks beginning of positional arguments. 9 | // Torrent []string `arity:"+" help:"torrent file path or magnet uri"` 10 | // } 11 | // tagflag.Parse(&opts) 12 | // 13 | // Supported tags include: 14 | // help: a line of text to show after the option 15 | // arity: defaults to 1. the number of arguments a field requires, or ? for one 16 | // optional argument, + for one or more, or * for zero or more. 17 | // 18 | // MarshalArgs is called on fields that implement ArgsMarshaler. A number of 19 | // arguments matching the arity of the field are passed if possible. 20 | // 21 | // Slices will collect successive values, within the provided arity constraints. 22 | // 23 | // A few helpful types have builtin marshallers, for example Bytes, 24 | // *net.TCPAddr, *url.URL, time.Duration, and net.IP. 25 | // 26 | // Flags are strictly passed with the form -K or -K=V. No space between -K and 27 | // the value is allowed. This allows positional arguments to be mixed in with 28 | // flags, and prevents any confusion due to some flags occasionally not taking 29 | // values. A `--` will terminate flag parsing, and treat all further arguments 30 | // as positional. 31 | // 32 | // A builtin help and usage printer are provided, and activated when passing 33 | // -h or -help. 34 | // 35 | // Flag and positional argument names are automatically munged to fit the 36 | // standard scheme within tagflag. 37 | package tagflag 38 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/tagflag/errors.go: -------------------------------------------------------------------------------- 1 | package tagflag 2 | 3 | type userError struct { 4 | msg string 5 | } 6 | 7 | func (ue userError) Error() string { 8 | return ue.msg 9 | } 10 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/tagflag/marshalers.go: -------------------------------------------------------------------------------- 1 | package tagflag 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "strconv" 7 | ) 8 | 9 | type Marshaler interface { 10 | Marshal(in string) error 11 | RequiresExplicitValue() bool 12 | } 13 | 14 | type marshaler interface { 15 | Marshal(reflect.Value, string) error 16 | RequiresExplicitValue() bool 17 | } 18 | 19 | type dynamicMarshaler struct { 20 | explicitValueRequired bool 21 | marshal func(reflect.Value, string) error 22 | } 23 | 24 | func (me dynamicMarshaler) Marshal(v reflect.Value, s string) error { 25 | return me.marshal(v, s) 26 | } 27 | 28 | func (me dynamicMarshaler) RequiresExplicitValue() bool { 29 | return me.explicitValueRequired 30 | } 31 | 32 | // The fallback marshaler, that attempts to use fmt.Sscan, and recursion to 33 | // sort marshal types. 34 | type defaultMarshaler struct{} 35 | 36 | func (defaultMarshaler) Marshal(v reflect.Value, s string) error { 37 | if v.Kind() == reflect.Slice { 38 | n := reflect.New(v.Type().Elem()) 39 | m := valueMarshaler(n.Elem()) 40 | err := m.Marshal(n.Elem(), s) 41 | if err != nil { 42 | return err 43 | } 44 | v.Set(reflect.Append(v, n.Elem())) 45 | return nil 46 | } 47 | switch v.Kind() { 48 | case reflect.Int: 49 | x, err := strconv.ParseInt(s, 0, 0) 50 | v.SetInt(x) 51 | return err 52 | case reflect.Uint: 53 | x, err := strconv.ParseUint(s, 0, 0) 54 | v.SetUint(x) 55 | return err 56 | case reflect.Int64: 57 | x, err := strconv.ParseInt(s, 0, 64) 58 | v.SetInt(x) 59 | return err 60 | case reflect.String: 61 | v.SetString(s) 62 | return nil 63 | default: 64 | return fmt.Errorf("unhandled builtin type: %s", v.Type().String()) 65 | } 66 | } 67 | 68 | func (defaultMarshaler) RequiresExplicitValue() bool { 69 | return true 70 | } 71 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/tagflag/misc.go: -------------------------------------------------------------------------------- 1 | package tagflag 2 | 3 | import ( 4 | "reflect" 5 | "regexp" 6 | "strconv" 7 | "strings" 8 | 9 | "github.com/bradfitz/iter" 10 | ) 11 | 12 | const flagPrefix = "-" 13 | 14 | // Walks the fields of the given struct, calling the function with the value 15 | // and StructField for each field. Returning true from the function will halt 16 | // traversal. 17 | func foreachStructField(_struct reflect.Value, f func(fv reflect.Value, sf reflect.StructField) (stop bool)) { 18 | t := _struct.Type() 19 | for i := range iter.N(t.NumField()) { 20 | sf := t.Field(i) 21 | fv := _struct.Field(i) 22 | if f(fv, sf) { 23 | break 24 | } 25 | } 26 | } 27 | 28 | func canMarshal(f reflect.Value) bool { 29 | return valueMarshaler(f) != nil 30 | } 31 | 32 | // Returns a marshaler for the given value, or nil if there isn't one. 33 | func valueMarshaler(v reflect.Value) marshaler { 34 | if v.CanAddr() { 35 | if am, ok := v.Addr().Interface().(Marshaler); ok { 36 | return dynamicMarshaler{ 37 | marshal: func(_ reflect.Value, s string) error { return am.Marshal(s) }, 38 | explicitValueRequired: am.RequiresExplicitValue(), 39 | } 40 | } 41 | } 42 | if bm, ok := builtinMarshalers[v.Type()]; ok { 43 | return bm 44 | } 45 | switch v.Kind() { 46 | case reflect.Ptr, reflect.Struct: 47 | return nil 48 | case reflect.Bool: 49 | return dynamicMarshaler{ 50 | marshal: func(v reflect.Value, s string) error { 51 | if s == "" { 52 | v.SetBool(true) 53 | return nil 54 | } 55 | b, err := strconv.ParseBool(s) 56 | v.SetBool(b) 57 | return err 58 | }, 59 | explicitValueRequired: false, 60 | } 61 | } 62 | return defaultMarshaler{} 63 | } 64 | 65 | // Turn a struct field name into a flag name. In particular this lower cases 66 | // leading acronyms, and the first capital letter. 67 | func fieldFlagName(fieldName string) (ret string) { 68 | // defer func() { log.Println(fieldName, ret) }() 69 | // TCP 70 | if ss := regexp.MustCompile("^[[:upper:]]{2,}$").FindStringSubmatch(fieldName); ss != nil { 71 | return strings.ToLower(ss[0]) 72 | } 73 | // TCPAddr 74 | if ss := regexp.MustCompile("^([[:upper:]]+)([[:upper:]][^[:upper:]].*?)$").FindStringSubmatch(fieldName); ss != nil { 75 | return strings.ToLower(ss[1]) + ss[2] 76 | } 77 | // Addr 78 | if ss := regexp.MustCompile("^([[:upper:]])(.*)$").FindStringSubmatch(fieldName); ss != nil { 79 | return strings.ToLower(ss[1]) + ss[2] 80 | } 81 | panic(fieldName) 82 | } 83 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/tagflag/parseopt.go: -------------------------------------------------------------------------------- 1 | package tagflag 2 | 3 | type parseOpt func(p *parser) 4 | 5 | // Don't perform default behaviour if -h or -help are passed. 6 | func NoDefaultHelp() parseOpt { 7 | return func(p *parser) { 8 | p.noDefaultHelp = true 9 | } 10 | } 11 | 12 | // Provides a description for the program to be shown in the usage message. 13 | func Description(desc string) parseOpt { 14 | return func(p *parser) { 15 | p.description = desc 16 | } 17 | } 18 | 19 | func Program(name string) parseOpt { 20 | return func(p *parser) { 21 | p.program = name 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/tagflag/parser.go: -------------------------------------------------------------------------------- 1 | package tagflag 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "reflect" 7 | "strings" 8 | 9 | "github.com/huandu/xstrings" 10 | ) 11 | 12 | type parser struct { 13 | // The value from which the parser is built, and values are assigned. 14 | cmd interface{} 15 | // Disables the default handling of -h and -help. 16 | noDefaultHelp bool 17 | program string 18 | description string 19 | 20 | posArgs []arg 21 | // Maps -K=V to map[K]arg(V) 22 | flags map[string]arg 23 | 24 | // Count of positional arguments parsed so far. Used to locate the next 25 | // positional argument where it's non-trivial (non-unity arity). 26 | numPos int 27 | } 28 | 29 | func (p *parser) hasOptions() bool { 30 | return len(p.flags) != 0 31 | } 32 | 33 | func (p *parser) parse(args []string) (err error) { 34 | args, err = p.parseAny(args) 35 | if err != nil { 36 | return 37 | } 38 | err = p.parsePosArgs(args) 39 | if err != nil { 40 | return 41 | } 42 | if p.numPos < p.minPos() { 43 | return userError{fmt.Sprintf("missing argument: %q", p.indexPosArg(p.numPos).name)} 44 | } 45 | return 46 | } 47 | 48 | func (p *parser) minPos() (min int) { 49 | for _, arg := range p.posArgs { 50 | min += arg.arity.min 51 | } 52 | return 53 | } 54 | 55 | func newParser(cmd interface{}, opts ...parseOpt) (p *parser, err error) { 56 | p = &parser{ 57 | cmd: cmd, 58 | } 59 | for _, opt := range opts { 60 | opt(p) 61 | } 62 | err = p.parseCmd() 63 | return 64 | } 65 | 66 | func (p *parser) parseCmd() error { 67 | if p.cmd == nil { 68 | return nil 69 | } 70 | s := reflect.ValueOf(p.cmd).Elem() 71 | if s.Kind() != reflect.Struct { 72 | return fmt.Errorf("expected struct got %s", s.Type()) 73 | } 74 | return p.parseStruct(reflect.ValueOf(p.cmd).Elem()) 75 | } 76 | 77 | // Positional arguments are marked per struct. 78 | func (p *parser) parseStruct(st reflect.Value) (err error) { 79 | posStarted := false 80 | foreachStructField(st, func(f reflect.Value, sf reflect.StructField) (stop bool) { 81 | if !posStarted && f.Type() == reflect.TypeOf(StartPos{}) { 82 | posStarted = true 83 | return false 84 | } 85 | if sf.PkgPath != "" { 86 | return false 87 | } 88 | if canMarshal(f) { 89 | if posStarted { 90 | err = p.addPos(f, sf) 91 | } else { 92 | err = p.addFlag(f, sf) 93 | if err != nil { 94 | err = fmt.Errorf("error adding flag in %s: %s", st.Type(), err) 95 | } 96 | } 97 | return err != nil 98 | } 99 | if f.Kind() == reflect.Struct { 100 | if canMarshal(f.Addr()) { 101 | err = fmt.Errorf("field %q has type %s, did you mean to use %s?", sf.Name, f.Type(), f.Addr().Type()) 102 | return true 103 | } 104 | err = p.parseStruct(f) 105 | return err != nil 106 | } 107 | err = fmt.Errorf("field has bad type: %v", f.Type()) 108 | return true 109 | }) 110 | return 111 | } 112 | 113 | func newArg(v reflect.Value, sf reflect.StructField, name string) arg { 114 | return arg{ 115 | arity: fieldArity(v, sf), 116 | value: v, 117 | name: name, 118 | help: sf.Tag.Get("help"), 119 | } 120 | } 121 | 122 | func (p *parser) addPos(f reflect.Value, sf reflect.StructField) error { 123 | p.posArgs = append(p.posArgs, newArg(f, sf, strings.ToUpper(xstrings.ToSnakeCase(sf.Name)))) 124 | return nil 125 | } 126 | 127 | func (p *parser) addFlag(f reflect.Value, sf reflect.StructField) error { 128 | name := structFieldFlag(sf) 129 | if _, ok := p.flags[name]; ok { 130 | return fmt.Errorf("flag %q defined more than once", name) 131 | } 132 | if p.flags == nil { 133 | p.flags = make(map[string]arg) 134 | } 135 | p.flags[name] = newArg(f, sf, name) 136 | return nil 137 | } 138 | 139 | func (p *parser) parseAny(args []string) (left []string, err error) { 140 | for len(args) != 0 { 141 | a := args[0] 142 | args = args[1:] 143 | if a == "--" { 144 | left = args[1:] 145 | return 146 | } 147 | if strings.HasPrefix(a, "-") && len(a) > 1 { 148 | err = p.parseFlag(a[1:]) 149 | } else { 150 | err = p.parsePos(a) 151 | } 152 | if err != nil { 153 | break 154 | } 155 | } 156 | return 157 | } 158 | 159 | func (p *parser) parsePosArgs(args []string) (err error) { 160 | for _, a := range args { 161 | err = p.parsePos(a) 162 | if err != nil { 163 | break 164 | } 165 | } 166 | return 167 | } 168 | 169 | func (p *parser) parseFlag(s string) error { 170 | i := strings.IndexByte(s, '=') 171 | k := s 172 | v := "" 173 | if i != -1 { 174 | k = s[:i] 175 | v = s[i+1:] 176 | } 177 | flag, ok := p.flags[k] 178 | if !ok { 179 | if (k == "help" || k == "h") && !p.noDefaultHelp { 180 | return ErrDefaultHelp 181 | } 182 | return userError{fmt.Sprintf("unknown flag: %q", k)} 183 | } 184 | err := flag.marshal(v, i != -1) 185 | if err != nil { 186 | return fmt.Errorf("error setting flag %q: %s", k, err) 187 | } 188 | return nil 189 | } 190 | 191 | func (p *parser) indexPosArg(i int) *arg { 192 | for _, arg := range p.posArgs { 193 | if i < arg.arity.max { 194 | return &arg 195 | } 196 | i -= arg.arity.max 197 | } 198 | return nil 199 | } 200 | 201 | func (p *parser) parsePos(s string) (err error) { 202 | arg := p.indexPosArg(p.numPos) 203 | if arg == nil { 204 | return userError{fmt.Sprintf("excess argument: %q", s)} 205 | } 206 | err = arg.marshal(s, true) 207 | if err != nil { 208 | return 209 | } 210 | p.numPos++ 211 | return 212 | } 213 | 214 | func structFieldFlag(sf reflect.StructField) string { 215 | name := sf.Tag.Get("name") 216 | if name != "" { 217 | return name 218 | } 219 | return fieldFlagName(sf.Name) 220 | } 221 | 222 | // Gets the reflect.Value for the nth positional argument. 223 | func posIndexValue(v reflect.Value, _i int) (ret reflect.Value, i int) { 224 | i = _i 225 | log.Println("posIndexValue", v.Type(), i) 226 | switch v.Kind() { 227 | case reflect.Ptr: 228 | return posIndexValue(v.Elem(), i) 229 | case reflect.Struct: 230 | posStarted := false 231 | foreachStructField(v, func(fv reflect.Value, sf reflect.StructField) bool { 232 | log.Println("posIndexValue struct field", fv, sf) 233 | if !posStarted { 234 | if fv.Type() == reflect.TypeOf(StartPos{}) { 235 | // log.Println("posStarted") 236 | posStarted = true 237 | } 238 | return true 239 | } 240 | ret, i = posIndexValue(fv, i) 241 | if ret.IsValid() { 242 | return false 243 | } 244 | return true 245 | }) 246 | return 247 | case reflect.Slice: 248 | ret = v 249 | return 250 | default: 251 | if i == 0 { 252 | ret = v 253 | return 254 | } 255 | i-- 256 | return 257 | } 258 | } 259 | 260 | func (p *parser) posWithHelp() (ret []arg) { 261 | for _, a := range p.posArgs { 262 | if a.help != "" { 263 | ret = append(ret, a) 264 | } 265 | } 266 | return 267 | } 268 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/tagflag/tagflag.go: -------------------------------------------------------------------------------- 1 | package tagflag 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "os" 7 | "path/filepath" 8 | ) 9 | 10 | // Struct fields after this one are considered positional arguments. 11 | type StartPos struct{} 12 | 13 | // Default help flag was provided, and should be handled. 14 | var ErrDefaultHelp = errors.New("help flag") 15 | 16 | // Parses given arguments, returning any error. 17 | func ParseErr(cmd interface{}, args []string, opts ...parseOpt) (err error) { 18 | p, err := newParser(cmd, opts...) 19 | if err != nil { 20 | return 21 | } 22 | return p.parse(args) 23 | } 24 | 25 | // Parses the command-line arguments, exiting the process appropriately on 26 | // errors or if usage is printed. 27 | func Parse(cmd interface{}, opts ...parseOpt) { 28 | opts = append([]parseOpt{Program(filepath.Base(os.Args[0]))}, opts...) 29 | p, err := newParser(cmd, opts...) 30 | if err == nil { 31 | err = p.parse(os.Args[1:]) 32 | } 33 | if err == ErrDefaultHelp { 34 | p.printUsage(os.Stderr) 35 | os.Exit(0) 36 | } 37 | if err != nil { 38 | fmt.Fprintf(os.Stderr, "tagflag: %s\n", err) 39 | if _, ok := err.(userError); ok { 40 | os.Exit(2) 41 | } 42 | os.Exit(1) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/tagflag/usage.go: -------------------------------------------------------------------------------- 1 | package tagflag 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "text/tabwriter" 7 | 8 | "github.com/anacrolix/missinggo" 9 | "github.com/anacrolix/missinggo/slices" 10 | ) 11 | 12 | func (p *parser) printUsage(w io.Writer) { 13 | fmt.Fprintf(w, "Usage:\n %s", p.program) 14 | if p.hasOptions() { 15 | fmt.Fprintf(w, " [OPTIONS...]") 16 | } 17 | for _, arg := range p.posArgs { 18 | fs := func() string { 19 | switch arg.arity { 20 | case arity{0, 1}: 21 | return "[%s]" 22 | case arity{1, infArity}: 23 | return "%s..." 24 | case arity{0, infArity}: 25 | return "[%s...]" 26 | default: 27 | return "<%s>" 28 | } 29 | }() 30 | // if arg.arity != arity{1,1} { 31 | fmt.Fprintf(w, " "+fs, arg.name) 32 | // } 33 | // if arg.arity > 1 { 34 | // for range iter.N(int(arg.arity - 1)) { 35 | // fmt.Fprintf(w, " "+fs, arg.name) 36 | // } 37 | // } 38 | } 39 | fmt.Fprintf(w, "\n") 40 | if p.description != "" { 41 | fmt.Fprintf(w, "\n%s\n", missinggo.Unchomp(p.description)) 42 | } 43 | if awd := p.posWithHelp(); len(awd) != 0 { 44 | fmt.Fprintf(w, "Arguments:\n") 45 | tw := newUsageTabwriter(w) 46 | for _, a := range awd { 47 | fmt.Fprintf(tw, " %s\t(%s)\t%s\n", a.name, a.value.Type(), a.help) 48 | } 49 | tw.Flush() 50 | } 51 | var opts []arg 52 | for _, v := range p.flags { 53 | opts = append(opts, v) 54 | } 55 | slices.Sort(opts, func(left, right arg) bool { 56 | return left.name < right.name 57 | }) 58 | writeOptionUsage(w, opts) 59 | } 60 | 61 | func newUsageTabwriter(w io.Writer) *tabwriter.Writer { 62 | return tabwriter.NewWriter(w, 8, 2, 3, ' ', 0) 63 | } 64 | 65 | func writeOptionUsage(w io.Writer, flags []arg) { 66 | if len(flags) == 0 { 67 | return 68 | } 69 | fmt.Fprintf(w, "Options:\n") 70 | tw := newUsageTabwriter(w) 71 | for _, f := range flags { 72 | fmt.Fprint(tw, " ") 73 | fmt.Fprintf(tw, "%s%s", flagPrefix, f.name) 74 | fmt.Fprintf(tw, "\t(%s)\t%s\n", f.value.Type(), f.help) 75 | } 76 | tw.Flush() 77 | } 78 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/torrent/bencode/api.go: -------------------------------------------------------------------------------- 1 | package bencode 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "fmt" 7 | "io" 8 | "reflect" 9 | ) 10 | 11 | //---------------------------------------------------------------------------- 12 | // Errors 13 | //---------------------------------------------------------------------------- 14 | 15 | // In case if marshaler cannot encode a type, it will return this error. Typical 16 | // example of such type is float32/float64 which has no bencode representation. 17 | type MarshalTypeError struct { 18 | Type reflect.Type 19 | } 20 | 21 | func (e *MarshalTypeError) Error() string { 22 | return "bencode: unsupported type: " + e.Type.String() 23 | } 24 | 25 | // Unmarshal argument must be a non-nil value of some pointer type. 26 | type UnmarshalInvalidArgError struct { 27 | Type reflect.Type 28 | } 29 | 30 | func (e *UnmarshalInvalidArgError) Error() string { 31 | if e.Type == nil { 32 | return "bencode: Unmarshal(nil)" 33 | } 34 | 35 | if e.Type.Kind() != reflect.Ptr { 36 | return "bencode: Unmarshal(non-pointer " + e.Type.String() + ")" 37 | } 38 | return "bencode: Unmarshal(nil " + e.Type.String() + ")" 39 | } 40 | 41 | // Unmarshaler spotted a value that was not appropriate for a given Go value. 42 | type UnmarshalTypeError struct { 43 | Value string 44 | Type reflect.Type 45 | } 46 | 47 | func (e *UnmarshalTypeError) Error() string { 48 | return "bencode: value (" + e.Value + ") is not appropriate for type: " + 49 | e.Type.String() 50 | } 51 | 52 | // Unmarshaler tried to write to an unexported (therefore unwritable) field. 53 | type UnmarshalFieldError struct { 54 | Key string 55 | Type reflect.Type 56 | Field reflect.StructField 57 | } 58 | 59 | func (e *UnmarshalFieldError) Error() string { 60 | return "bencode: key \"" + e.Key + "\" led to an unexported field \"" + 61 | e.Field.Name + "\" in type: " + e.Type.String() 62 | } 63 | 64 | // Malformed bencode input, unmarshaler failed to parse it. 65 | type SyntaxError struct { 66 | Offset int64 // location of the error 67 | What error // error description 68 | } 69 | 70 | func (e *SyntaxError) Error() string { 71 | return fmt.Sprintf("bencode: syntax error (offset: %d): %s", e.Offset, e.What) 72 | } 73 | 74 | // A non-nil error was returned after calling MarshalBencode on a type which 75 | // implements the Marshaler interface. 76 | type MarshalerError struct { 77 | Type reflect.Type 78 | Err error 79 | } 80 | 81 | func (e *MarshalerError) Error() string { 82 | return "bencode: error calling MarshalBencode for type " + e.Type.String() + ": " + e.Err.Error() 83 | } 84 | 85 | // A non-nil error was returned after calling UnmarshalBencode on a type which 86 | // implements the Unmarshaler interface. 87 | type UnmarshalerError struct { 88 | Type reflect.Type 89 | Err error 90 | } 91 | 92 | func (e *UnmarshalerError) Error() string { 93 | return "bencode: error calling UnmarshalBencode for type " + e.Type.String() + ": " + e.Err.Error() 94 | } 95 | 96 | //---------------------------------------------------------------------------- 97 | // Interfaces 98 | //---------------------------------------------------------------------------- 99 | 100 | // Any type which implements this interface, will be marshaled using the 101 | // specified method. 102 | type Marshaler interface { 103 | MarshalBencode() ([]byte, error) 104 | } 105 | 106 | // Any type which implements this interface, will be unmarshaled using the 107 | // specified method. 108 | type Unmarshaler interface { 109 | UnmarshalBencode([]byte) error 110 | } 111 | 112 | // Marshal the value 'v' to the bencode form, return the result as []byte and an 113 | // error if any. 114 | func Marshal(v interface{}) ([]byte, error) { 115 | var buf bytes.Buffer 116 | e := Encoder{w: bufio.NewWriter(&buf)} 117 | err := e.Encode(v) 118 | if err != nil { 119 | return nil, err 120 | } 121 | return buf.Bytes(), nil 122 | } 123 | 124 | // Unmarshal the bencode value in the 'data' to a value pointed by the 'v' 125 | // pointer, return a non-nil error if any. 126 | func Unmarshal(data []byte, v interface{}) error { 127 | e := Decoder{r: bytes.NewBuffer(data)} 128 | return e.Decode(v) 129 | } 130 | 131 | func NewDecoder(r io.Reader) *Decoder { 132 | return &Decoder{r: bufio.NewReader(r)} 133 | } 134 | 135 | func NewEncoder(w io.Writer) *Encoder { 136 | return &Encoder{w: bufio.NewWriter(w)} 137 | } 138 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/torrent/bencode/bytes.go: -------------------------------------------------------------------------------- 1 | package bencode 2 | 3 | type Bytes []byte 4 | 5 | var ( 6 | _ Unmarshaler = &Bytes{} 7 | _ Marshaler = &Bytes{} 8 | _ Marshaler = Bytes{} 9 | ) 10 | 11 | func (me *Bytes) UnmarshalBencode(b []byte) error { 12 | *me = append([]byte(nil), b...) 13 | return nil 14 | } 15 | 16 | func (me Bytes) MarshalBencode() ([]byte, error) { 17 | return me, nil 18 | } 19 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/torrent/bencode/encode.go: -------------------------------------------------------------------------------- 1 | package bencode 2 | 3 | import ( 4 | "io" 5 | "reflect" 6 | "runtime" 7 | "sort" 8 | "strconv" 9 | "sync" 10 | 11 | "github.com/anacrolix/missinggo" 12 | ) 13 | 14 | func isEmptyValue(v reflect.Value) bool { 15 | return missinggo.IsEmptyValue(v) 16 | } 17 | 18 | type Encoder struct { 19 | w interface { 20 | Flush() error 21 | io.Writer 22 | WriteString(string) (int, error) 23 | } 24 | scratch [64]byte 25 | } 26 | 27 | func (e *Encoder) Encode(v interface{}) (err error) { 28 | if v == nil { 29 | return 30 | } 31 | defer func() { 32 | if e := recover(); e != nil { 33 | if _, ok := e.(runtime.Error); ok { 34 | panic(e) 35 | } 36 | var ok bool 37 | err, ok = e.(error) 38 | if !ok { 39 | panic(e) 40 | } 41 | } 42 | }() 43 | e.reflectValue(reflect.ValueOf(v)) 44 | return e.w.Flush() 45 | } 46 | 47 | type string_values []reflect.Value 48 | 49 | func (sv string_values) Len() int { return len(sv) } 50 | func (sv string_values) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] } 51 | func (sv string_values) Less(i, j int) bool { return sv.get(i) < sv.get(j) } 52 | func (sv string_values) get(i int) string { return sv[i].String() } 53 | 54 | func (e *Encoder) write(s []byte) { 55 | _, err := e.w.Write(s) 56 | if err != nil { 57 | panic(err) 58 | } 59 | } 60 | 61 | func (e *Encoder) writeString(s string) { 62 | _, err := e.w.WriteString(s) 63 | if err != nil { 64 | panic(err) 65 | } 66 | } 67 | 68 | func (e *Encoder) reflectString(s string) { 69 | b := strconv.AppendInt(e.scratch[:0], int64(len(s)), 10) 70 | e.write(b) 71 | e.writeString(":") 72 | e.writeString(s) 73 | } 74 | 75 | func (e *Encoder) reflectByteSlice(s []byte) { 76 | b := strconv.AppendInt(e.scratch[:0], int64(len(s)), 10) 77 | e.write(b) 78 | e.writeString(":") 79 | e.write(s) 80 | } 81 | 82 | // returns true if the value implements Marshaler interface and marshaling was 83 | // done successfully 84 | func (e *Encoder) reflectMarshaler(v reflect.Value) bool { 85 | m, ok := v.Interface().(Marshaler) 86 | if !ok { 87 | // T doesn't work, try *T 88 | if v.Kind() != reflect.Ptr && v.CanAddr() { 89 | m, ok = v.Addr().Interface().(Marshaler) 90 | if ok { 91 | v = v.Addr() 92 | } 93 | } 94 | } 95 | if ok && (v.Kind() != reflect.Ptr || !v.IsNil()) { 96 | data, err := m.MarshalBencode() 97 | if err != nil { 98 | panic(&MarshalerError{v.Type(), err}) 99 | } 100 | e.write(data) 101 | return true 102 | } 103 | 104 | return false 105 | } 106 | 107 | func (e *Encoder) reflectValue(v reflect.Value) { 108 | 109 | if e.reflectMarshaler(v) { 110 | return 111 | } 112 | 113 | switch v.Kind() { 114 | case reflect.Bool: 115 | if v.Bool() { 116 | e.writeString("i1e") 117 | } else { 118 | e.writeString("i0e") 119 | } 120 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 121 | b := strconv.AppendInt(e.scratch[:0], v.Int(), 10) 122 | e.writeString("i") 123 | e.write(b) 124 | e.writeString("e") 125 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 126 | b := strconv.AppendUint(e.scratch[:0], v.Uint(), 10) 127 | e.writeString("i") 128 | e.write(b) 129 | e.writeString("e") 130 | case reflect.String: 131 | e.reflectString(v.String()) 132 | case reflect.Struct: 133 | e.writeString("d") 134 | for _, ef := range encodeFields(v.Type()) { 135 | field_value := v.Field(ef.i) 136 | if ef.omit_empty && isEmptyValue(field_value) { 137 | continue 138 | } 139 | e.reflectString(ef.tag) 140 | e.reflectValue(field_value) 141 | } 142 | e.writeString("e") 143 | case reflect.Map: 144 | if v.Type().Key().Kind() != reflect.String { 145 | panic(&MarshalTypeError{v.Type()}) 146 | } 147 | if v.IsNil() { 148 | e.writeString("de") 149 | break 150 | } 151 | e.writeString("d") 152 | sv := string_values(v.MapKeys()) 153 | sort.Sort(sv) 154 | for _, key := range sv { 155 | e.reflectString(key.String()) 156 | e.reflectValue(v.MapIndex(key)) 157 | } 158 | e.writeString("e") 159 | case reflect.Slice: 160 | if v.IsNil() { 161 | e.writeString("le") 162 | break 163 | } 164 | if v.Type().Elem().Kind() == reflect.Uint8 { 165 | s := v.Bytes() 166 | e.reflectByteSlice(s) 167 | break 168 | } 169 | fallthrough 170 | case reflect.Array: 171 | e.writeString("l") 172 | for i, n := 0, v.Len(); i < n; i++ { 173 | e.reflectValue(v.Index(i)) 174 | } 175 | e.writeString("e") 176 | case reflect.Interface: 177 | e.reflectValue(v.Elem()) 178 | case reflect.Ptr: 179 | if v.IsNil() { 180 | v = reflect.Zero(v.Type().Elem()) 181 | } else { 182 | v = v.Elem() 183 | } 184 | e.reflectValue(v) 185 | default: 186 | panic(&MarshalTypeError{v.Type()}) 187 | } 188 | } 189 | 190 | type encodeField struct { 191 | i int 192 | tag string 193 | omit_empty bool 194 | } 195 | 196 | type encodeFieldsSortType []encodeField 197 | 198 | func (ef encodeFieldsSortType) Len() int { return len(ef) } 199 | func (ef encodeFieldsSortType) Swap(i, j int) { ef[i], ef[j] = ef[j], ef[i] } 200 | func (ef encodeFieldsSortType) Less(i, j int) bool { return ef[i].tag < ef[j].tag } 201 | 202 | var ( 203 | typeCacheLock sync.RWMutex 204 | encodeFieldsCache = make(map[reflect.Type][]encodeField) 205 | ) 206 | 207 | func encodeFields(t reflect.Type) []encodeField { 208 | typeCacheLock.RLock() 209 | fs, ok := encodeFieldsCache[t] 210 | typeCacheLock.RUnlock() 211 | if ok { 212 | return fs 213 | } 214 | 215 | typeCacheLock.Lock() 216 | defer typeCacheLock.Unlock() 217 | fs, ok = encodeFieldsCache[t] 218 | if ok { 219 | return fs 220 | } 221 | 222 | for i, n := 0, t.NumField(); i < n; i++ { 223 | f := t.Field(i) 224 | if f.PkgPath != "" { 225 | continue 226 | } 227 | if f.Anonymous { 228 | continue 229 | } 230 | var ef encodeField 231 | ef.i = i 232 | ef.tag = f.Name 233 | 234 | tv := f.Tag.Get("bencode") 235 | if tv != "" { 236 | if tv == "-" { 237 | continue 238 | } 239 | name, opts := parseTag(tv) 240 | if name != "" { 241 | ef.tag = name 242 | } 243 | ef.omit_empty = opts.contains("omitempty") 244 | } 245 | fs = append(fs, ef) 246 | } 247 | fss := encodeFieldsSortType(fs) 248 | sort.Sort(fss) 249 | encodeFieldsCache[t] = fs 250 | return fs 251 | } 252 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/torrent/bencode/fuzz.go: -------------------------------------------------------------------------------- 1 | // +build gofuzz 2 | 3 | package bencode 4 | 5 | import ( 6 | "fmt" 7 | "reflect" 8 | ) 9 | 10 | func Fuzz(b []byte) int { 11 | var d interface{} 12 | err := Unmarshal(b, &d) 13 | if err != nil { 14 | return 0 15 | } 16 | b0, err := Marshal(d) 17 | if err != nil { 18 | panic(err) 19 | } 20 | var d0 interface{} 21 | err = Unmarshal(b0, &d0) 22 | if err != nil { 23 | panic(err) 24 | } 25 | if !reflect.DeepEqual(d, d0) { 26 | panic(fmt.Sprintf("%s != %s", d, d0)) 27 | } 28 | return 1 29 | } 30 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/torrent/bencode/tags.go: -------------------------------------------------------------------------------- 1 | package bencode 2 | 3 | import ( 4 | "strings" 5 | ) 6 | 7 | type tagOptions string 8 | 9 | func parseTag(tag string) (string, tagOptions) { 10 | if idx := strings.Index(tag, ","); idx != -1 { 11 | return tag[:idx], tagOptions(tag[idx+1:]) 12 | } 13 | return tag, tagOptions("") 14 | } 15 | 16 | func (opts tagOptions) contains(option_name string) bool { 17 | if len(opts) == 0 { 18 | return false 19 | } 20 | 21 | s := string(opts) 22 | for s != "" { 23 | var next string 24 | i := strings.Index(s, ",") 25 | if i != -1 { 26 | s, next = s[:i], s[i+1:] 27 | } 28 | if s == option_name { 29 | return true 30 | } 31 | s = next 32 | } 33 | return false 34 | } 35 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/torrent/metainfo/hash.go: -------------------------------------------------------------------------------- 1 | package metainfo 2 | 3 | import ( 4 | "crypto/sha1" 5 | "encoding/hex" 6 | "fmt" 7 | ) 8 | 9 | // 20-byte SHA1 hash used for info and pieces. 10 | type Hash [20]byte 11 | 12 | func (h Hash) Bytes() []byte { 13 | return h[:] 14 | } 15 | 16 | func (h Hash) AsString() string { 17 | return string(h[:]) 18 | } 19 | 20 | func (h Hash) HexString() string { 21 | return fmt.Sprintf("%x", h[:]) 22 | } 23 | 24 | func (h *Hash) FromHexString(s string) (err error) { 25 | if len(s) != 40 { 26 | err = fmt.Errorf("hash hex string has bad length: %d", len(s)) 27 | return 28 | } 29 | n, err := hex.Decode(h[:], []byte(s)) 30 | if err != nil { 31 | return 32 | } 33 | if n != 20 { 34 | panic(n) 35 | } 36 | return 37 | } 38 | 39 | func NewHashFromHex(s string) (h Hash) { 40 | h.FromHexString(s) 41 | return 42 | } 43 | 44 | func HashBytes(b []byte) (ret Hash) { 45 | hasher := sha1.New() 46 | hasher.Write(b) 47 | copy(ret[:], hasher.Sum(nil)) 48 | return 49 | } 50 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/torrent/metainfo/info.go: -------------------------------------------------------------------------------- 1 | package metainfo 2 | 3 | import ( 4 | "crypto/sha1" 5 | "errors" 6 | "fmt" 7 | "io" 8 | "log" 9 | "os" 10 | "path/filepath" 11 | "strings" 12 | 13 | "github.com/anacrolix/missinggo/slices" 14 | ) 15 | 16 | // The info dictionary. 17 | type Info struct { 18 | PieceLength int64 `bencode:"piece length"` 19 | Pieces []byte `bencode:"pieces"` 20 | Name string `bencode:"name"` 21 | Length int64 `bencode:"length,omitempty"` 22 | Private *bool `bencode:"private,omitempty"` 23 | Files []FileInfo `bencode:"files,omitempty"` 24 | } 25 | 26 | // This is a helper that sets Files and Pieces from a root path and its 27 | // children. 28 | func (info *Info) BuildFromFilePath(root string) (err error) { 29 | info.Name = filepath.Base(root) 30 | info.Files = nil 31 | err = filepath.Walk(root, func(path string, fi os.FileInfo, err error) error { 32 | if err != nil { 33 | return err 34 | } 35 | if fi.IsDir() { 36 | // Directories are implicit in torrent files. 37 | return nil 38 | } else if path == root { 39 | // The root is a file. 40 | info.Length = fi.Size() 41 | return nil 42 | } 43 | relPath, err := filepath.Rel(root, path) 44 | log.Println(relPath, err) 45 | if err != nil { 46 | return fmt.Errorf("error getting relative path: %s", err) 47 | } 48 | info.Files = append(info.Files, FileInfo{ 49 | Path: strings.Split(relPath, string(filepath.Separator)), 50 | Length: fi.Size(), 51 | }) 52 | return nil 53 | }) 54 | if err != nil { 55 | return 56 | } 57 | slices.Sort(info.Files, func(l, r FileInfo) bool { 58 | return strings.Join(l.Path, "/") < strings.Join(r.Path, "/") 59 | }) 60 | err = info.GeneratePieces(func(fi FileInfo) (io.ReadCloser, error) { 61 | return os.Open(filepath.Join(root, strings.Join(fi.Path, string(filepath.Separator)))) 62 | }) 63 | if err != nil { 64 | err = fmt.Errorf("error generating pieces: %s", err) 65 | } 66 | return 67 | } 68 | 69 | func (info *Info) writeFiles(w io.Writer, open func(fi FileInfo) (io.ReadCloser, error)) error { 70 | for _, fi := range info.UpvertedFiles() { 71 | r, err := open(fi) 72 | if err != nil { 73 | return fmt.Errorf("error opening %v: %s", fi, err) 74 | } 75 | wn, err := io.CopyN(w, r, fi.Length) 76 | r.Close() 77 | if wn != fi.Length || err != nil { 78 | return fmt.Errorf("error hashing %v: %s", fi, err) 79 | } 80 | } 81 | return nil 82 | } 83 | 84 | // Set info.Pieces by hashing info.Files. 85 | func (info *Info) GeneratePieces(open func(fi FileInfo) (io.ReadCloser, error)) error { 86 | if info.PieceLength == 0 { 87 | return errors.New("piece length must be non-zero") 88 | } 89 | pr, pw := io.Pipe() 90 | go func() { 91 | err := info.writeFiles(pw, open) 92 | pw.CloseWithError(err) 93 | }() 94 | defer pr.Close() 95 | var pieces []byte 96 | for { 97 | hasher := sha1.New() 98 | wn, err := io.CopyN(hasher, pr, info.PieceLength) 99 | if err == io.EOF { 100 | err = nil 101 | } 102 | if err != nil { 103 | return err 104 | } 105 | if wn == 0 { 106 | break 107 | } 108 | pieces = hasher.Sum(pieces) 109 | if wn < info.PieceLength { 110 | break 111 | } 112 | } 113 | info.Pieces = pieces 114 | return nil 115 | } 116 | 117 | func (info *Info) TotalLength() (ret int64) { 118 | if info.IsDir() { 119 | for _, fi := range info.Files { 120 | ret += fi.Length 121 | } 122 | } else { 123 | ret = info.Length 124 | } 125 | return 126 | } 127 | 128 | func (info *Info) NumPieces() int { 129 | if len(info.Pieces)%20 != 0 { 130 | panic(len(info.Pieces)) 131 | } 132 | return len(info.Pieces) / 20 133 | } 134 | 135 | func (info *Info) IsDir() bool { 136 | return len(info.Files) != 0 137 | } 138 | 139 | // The files field, converted up from the old single-file in the parent info 140 | // dict if necessary. This is a helper to avoid having to conditionally handle 141 | // single and multi-file torrent infos. 142 | func (info *Info) UpvertedFiles() []FileInfo { 143 | if len(info.Files) == 0 { 144 | return []FileInfo{{ 145 | Length: info.Length, 146 | // Callers should determine that Info.Name is the basename, and 147 | // thus a regular file. 148 | Path: nil, 149 | }} 150 | } 151 | return info.Files 152 | } 153 | 154 | func (info *Info) Piece(index int) Piece { 155 | return Piece{info, index} 156 | } 157 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/torrent/metainfo/magnet.go: -------------------------------------------------------------------------------- 1 | package metainfo 2 | 3 | import ( 4 | "encoding/base32" 5 | "encoding/hex" 6 | "fmt" 7 | "net/url" 8 | "strings" 9 | ) 10 | 11 | // Magnet link components. 12 | type Magnet struct { 13 | InfoHash Hash 14 | Trackers []string 15 | DisplayName string 16 | } 17 | 18 | const xtPrefix = "urn:btih:" 19 | 20 | func (m Magnet) String() string { 21 | // net.URL likes to assume //, and encodes ':' on us, so we do most of 22 | // this manually. 23 | ret := "magnet:?xt=" 24 | ret += xtPrefix + hex.EncodeToString(m.InfoHash[:]) 25 | if m.DisplayName != "" { 26 | ret += "&dn=" + url.QueryEscape(m.DisplayName) 27 | } 28 | for _, tr := range m.Trackers { 29 | ret += "&tr=" + url.QueryEscape(tr) 30 | } 31 | return ret 32 | } 33 | 34 | // ParseMagnetURI parses Magnet-formatted URIs into a Magnet instance 35 | func ParseMagnetURI(uri string) (m Magnet, err error) { 36 | u, err := url.Parse(uri) 37 | if err != nil { 38 | err = fmt.Errorf("error parsing uri: %s", err) 39 | return 40 | } 41 | if u.Scheme != "magnet" { 42 | err = fmt.Errorf("unexpected scheme: %q", u.Scheme) 43 | return 44 | } 45 | xt := u.Query().Get("xt") 46 | if !strings.HasPrefix(xt, xtPrefix) { 47 | err = fmt.Errorf("bad xt parameter") 48 | return 49 | } 50 | infoHash := xt[len(xtPrefix):] 51 | 52 | // BTIH hash can be in HEX or BASE32 encoding 53 | // will assign appropriate func judging from symbol length 54 | var decode func(dst, src []byte) (int, error) 55 | switch len(infoHash) { 56 | case 40: 57 | decode = hex.Decode 58 | case 32: 59 | decode = base32.StdEncoding.Decode 60 | } 61 | 62 | if decode == nil { 63 | err = fmt.Errorf("unhandled xt parameter encoding: encoded length %d", len(infoHash)) 64 | return 65 | } 66 | n, err := decode(m.InfoHash[:], []byte(infoHash)) 67 | if err != nil { 68 | err = fmt.Errorf("error decoding xt: %s", err) 69 | return 70 | } 71 | if n != 20 { 72 | panic(n) 73 | } 74 | m.DisplayName = u.Query().Get("dn") 75 | m.Trackers = u.Query()["tr"] 76 | return 77 | } 78 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/torrent/metainfo/metainfo.go: -------------------------------------------------------------------------------- 1 | package metainfo 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "os" 7 | "time" 8 | 9 | "github.com/anacrolix/torrent/bencode" 10 | ) 11 | 12 | type MetaInfo struct { 13 | InfoBytes bencode.Bytes `bencode:"info"` 14 | Announce string `bencode:"announce,omitempty"` 15 | AnnounceList [][]string `bencode:"announce-list,omitempty"` 16 | Nodes []Node `bencode:"nodes,omitempty"` 17 | CreationDate int64 `bencode:"creation date,omitempty"` 18 | Comment string `bencode:"comment,omitempty"` 19 | CreatedBy string `bencode:"created by,omitempty"` 20 | Encoding string `bencode:"encoding,omitempty"` 21 | URLList interface{} `bencode:"url-list,omitempty"` 22 | } 23 | 24 | // Information specific to a single file inside the MetaInfo structure. 25 | type FileInfo struct { 26 | Length int64 `bencode:"length"` 27 | Path []string `bencode:"path"` 28 | } 29 | 30 | // Load a MetaInfo from an io.Reader. Returns a non-nil error in case of 31 | // failure. 32 | func Load(r io.Reader) (*MetaInfo, error) { 33 | var mi MetaInfo 34 | d := bencode.NewDecoder(r) 35 | err := d.Decode(&mi) 36 | if err != nil { 37 | return nil, err 38 | } 39 | return &mi, nil 40 | } 41 | 42 | // Convenience function for loading a MetaInfo from a file. 43 | func LoadFromFile(filename string) (*MetaInfo, error) { 44 | f, err := os.Open(filename) 45 | if err != nil { 46 | return nil, err 47 | } 48 | defer f.Close() 49 | return Load(f) 50 | } 51 | 52 | func (mi MetaInfo) UnmarshalInfo() (info Info) { 53 | err := bencode.Unmarshal(mi.InfoBytes, &info) 54 | if err != nil { 55 | panic(fmt.Sprintf("bad info bytes: %s", err)) 56 | } 57 | return 58 | } 59 | 60 | func (mi MetaInfo) HashInfoBytes() (infoHash Hash) { 61 | return HashBytes(mi.InfoBytes) 62 | } 63 | 64 | // Encode to bencoded form. 65 | func (mi MetaInfo) Write(w io.Writer) error { 66 | return bencode.NewEncoder(w).Encode(mi) 67 | } 68 | 69 | // Set good default values in preparation for creating a new MetaInfo file. 70 | func (mi *MetaInfo) SetDefaults() { 71 | mi.Comment = "yoloham" 72 | mi.CreatedBy = "github.com/anacrolix/torrent" 73 | mi.CreationDate = time.Now().Unix() 74 | // mi.Info.PieceLength = 256 * 1024 75 | } 76 | 77 | // Creates a Magnet from a MetaInfo. 78 | func (mi *MetaInfo) Magnet(displayName string, infoHash Hash) (m Magnet) { 79 | for _, tier := range mi.AnnounceList { 80 | for _, tracker := range tier { 81 | m.Trackers = append(m.Trackers, tracker) 82 | } 83 | } 84 | if m.Trackers == nil && mi.Announce != "" { 85 | m.Trackers = []string{mi.Announce} 86 | } 87 | m.DisplayName = displayName 88 | m.InfoHash = infoHash 89 | return 90 | } 91 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/torrent/metainfo/nodes.go: -------------------------------------------------------------------------------- 1 | package metainfo 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "strconv" 7 | 8 | "github.com/anacrolix/torrent/bencode" 9 | ) 10 | 11 | type Node string 12 | 13 | var ( 14 | _ bencode.Unmarshaler = new(Node) 15 | ) 16 | 17 | func (n *Node) UnmarshalBencode(b []byte) (err error) { 18 | var iface interface{} 19 | err = bencode.Unmarshal(b, &iface) 20 | if err != nil { 21 | return 22 | } 23 | switch v := iface.(type) { 24 | case string: 25 | *n = Node(v) 26 | case []interface{}: 27 | func() { 28 | defer func() { 29 | r := recover() 30 | if r != nil { 31 | err = r.(error) 32 | } 33 | }() 34 | *n = Node(net.JoinHostPort(v[0].(string), strconv.FormatInt(v[1].(int64), 10))) 35 | }() 36 | default: 37 | err = fmt.Errorf("unsupported type: %T", iface) 38 | } 39 | return 40 | } 41 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/torrent/metainfo/piece.go: -------------------------------------------------------------------------------- 1 | package metainfo 2 | 3 | import "github.com/anacrolix/missinggo" 4 | 5 | type Piece struct { 6 | Info *Info 7 | i int 8 | } 9 | 10 | func (p Piece) Length() int64 { 11 | if p.i == p.Info.NumPieces()-1 { 12 | return p.Info.TotalLength() - int64(p.i)*p.Info.PieceLength 13 | } 14 | return p.Info.PieceLength 15 | } 16 | 17 | func (p Piece) Offset() int64 { 18 | return int64(p.i) * p.Info.PieceLength 19 | } 20 | 21 | func (p Piece) Hash() (ret Hash) { 22 | missinggo.CopyExact(&ret, p.Info.Pieces[p.i*20:(p.i+1)*20]) 23 | return 24 | } 25 | 26 | func (p Piece) Index() int { 27 | return p.i 28 | } 29 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/torrent/metainfo/piece_key.go: -------------------------------------------------------------------------------- 1 | package metainfo 2 | 3 | // Uniquely identifies a piece. 4 | type PieceKey struct { 5 | InfoHash Hash 6 | Index int 7 | } 8 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/torrent/tracker/http.go: -------------------------------------------------------------------------------- 1 | package tracker 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "fmt" 7 | "io" 8 | "net" 9 | "net/http" 10 | "net/url" 11 | "strconv" 12 | 13 | "github.com/anacrolix/missinggo/httptoo" 14 | 15 | "github.com/anacrolix/torrent/bencode" 16 | "github.com/anacrolix/torrent/util" 17 | ) 18 | 19 | type httpResponse struct { 20 | FailureReason string `bencode:"failure reason"` 21 | Interval int32 `bencode:"interval"` 22 | TrackerId string `bencode:"tracker id"` 23 | Complete int32 `bencode:"complete"` 24 | Incomplete int32 `bencode:"incomplete"` 25 | Peers interface{} `bencode:"peers"` 26 | } 27 | 28 | func (r *httpResponse) UnmarshalPeers() (ret []Peer, err error) { 29 | s, ok := r.Peers.(string) 30 | if !ok { 31 | err = fmt.Errorf("unsupported peers value type: %T", r.Peers) 32 | return 33 | } 34 | cp, err := util.UnmarshalIPv4CompactPeers([]byte(s)) 35 | if err != nil { 36 | return 37 | } 38 | ret = make([]Peer, 0, len(cp)) 39 | for _, p := range cp { 40 | ret = append(ret, Peer{net.IP(p.IP[:]), int(p.Port)}) 41 | } 42 | return 43 | } 44 | 45 | func setAnnounceParams(_url *url.URL, ar *AnnounceRequest) { 46 | q := _url.Query() 47 | 48 | q.Set("info_hash", string(ar.InfoHash[:])) 49 | q.Set("peer_id", string(ar.PeerId[:])) 50 | q.Set("port", fmt.Sprintf("%d", ar.Port)) 51 | q.Set("uploaded", strconv.FormatInt(ar.Uploaded, 10)) 52 | q.Set("downloaded", strconv.FormatInt(ar.Downloaded, 10)) 53 | q.Set("left", strconv.FormatUint(ar.Left, 10)) 54 | if ar.Event != None { 55 | q.Set("event", ar.Event.String()) 56 | } 57 | // http://stackoverflow.com/questions/17418004/why-does-tracker-server-not-understand-my-request-bittorrent-protocol 58 | q.Set("compact", "1") 59 | // According to https://wiki.vuze.com/w/Message_Stream_Encryption. 60 | q.Set("supportcrypto", "1") 61 | 62 | _url.RawQuery = q.Encode() 63 | } 64 | 65 | func announceHTTP(ar *AnnounceRequest, _url *url.URL, host string) (ret AnnounceResponse, err error) { 66 | _url = httptoo.CopyURL(_url) 67 | setAnnounceParams(_url, ar) 68 | req, err := http.NewRequest("GET", _url.String(), nil) 69 | req.Host = host 70 | resp, err := http.DefaultClient.Do(req) 71 | if err != nil { 72 | return 73 | } 74 | defer resp.Body.Close() 75 | var buf bytes.Buffer 76 | io.Copy(&buf, resp.Body) 77 | if resp.StatusCode != 200 { 78 | err = fmt.Errorf("response from tracker: %s: %s", resp.Status, buf.String()) 79 | return 80 | } 81 | var trackerResponse httpResponse 82 | err = bencode.Unmarshal(buf.Bytes(), &trackerResponse) 83 | if err != nil { 84 | err = fmt.Errorf("error decoding %q: %s", buf.Bytes(), err) 85 | return 86 | } 87 | if trackerResponse.FailureReason != "" { 88 | err = errors.New(trackerResponse.FailureReason) 89 | return 90 | } 91 | ret.Interval = trackerResponse.Interval 92 | ret.Leechers = trackerResponse.Incomplete 93 | ret.Seeders = trackerResponse.Complete 94 | ret.Peers, err = trackerResponse.UnmarshalPeers() 95 | return 96 | } 97 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/torrent/tracker/server.go: -------------------------------------------------------------------------------- 1 | package tracker 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "fmt" 7 | "math/rand" 8 | "net" 9 | 10 | "github.com/anacrolix/torrent/util" 11 | ) 12 | 13 | type torrent struct { 14 | Leechers int32 15 | Seeders int32 16 | Peers util.CompactIPv4Peers 17 | } 18 | 19 | type server struct { 20 | pc net.PacketConn 21 | conns map[int64]struct{} 22 | t map[[20]byte]torrent 23 | } 24 | 25 | func marshal(parts ...interface{}) (ret []byte, err error) { 26 | var buf bytes.Buffer 27 | for _, p := range parts { 28 | err = binary.Write(&buf, binary.BigEndian, p) 29 | if err != nil { 30 | return 31 | } 32 | } 33 | ret = buf.Bytes() 34 | return 35 | } 36 | 37 | func (s *server) respond(addr net.Addr, rh ResponseHeader, parts ...interface{}) (err error) { 38 | b, err := marshal(append([]interface{}{rh}, parts...)...) 39 | if err != nil { 40 | return 41 | } 42 | _, err = s.pc.WriteTo(b, addr) 43 | return 44 | } 45 | 46 | func (s *server) newConn() (ret int64) { 47 | ret = rand.Int63() 48 | if s.conns == nil { 49 | s.conns = make(map[int64]struct{}) 50 | } 51 | s.conns[ret] = struct{}{} 52 | return 53 | } 54 | 55 | func (s *server) serveOne() (err error) { 56 | b := make([]byte, 0x10000) 57 | n, addr, err := s.pc.ReadFrom(b) 58 | if err != nil { 59 | return 60 | } 61 | r := bytes.NewReader(b[:n]) 62 | var h RequestHeader 63 | err = readBody(r, &h) 64 | if err != nil { 65 | return 66 | } 67 | switch h.Action { 68 | case ActionConnect: 69 | if h.ConnectionId != connectRequestConnectionId { 70 | return 71 | } 72 | connId := s.newConn() 73 | err = s.respond(addr, ResponseHeader{ 74 | ActionConnect, 75 | h.TransactionId, 76 | }, ConnectionResponse{ 77 | connId, 78 | }) 79 | return 80 | case ActionAnnounce: 81 | if _, ok := s.conns[h.ConnectionId]; !ok { 82 | s.respond(addr, ResponseHeader{ 83 | TransactionId: h.TransactionId, 84 | Action: ActionError, 85 | }, []byte("not connected")) 86 | return 87 | } 88 | var ar AnnounceRequest 89 | err = readBody(r, &ar) 90 | if err != nil { 91 | return 92 | } 93 | t := s.t[ar.InfoHash] 94 | b, err = t.Peers.MarshalBinary() 95 | if err != nil { 96 | panic(err) 97 | } 98 | err = s.respond(addr, ResponseHeader{ 99 | TransactionId: h.TransactionId, 100 | Action: ActionAnnounce, 101 | }, AnnounceResponseHeader{ 102 | Interval: 900, 103 | Leechers: t.Leechers, 104 | Seeders: t.Seeders, 105 | }, b) 106 | return 107 | default: 108 | err = fmt.Errorf("unhandled action: %d", h.Action) 109 | s.respond(addr, ResponseHeader{ 110 | TransactionId: h.TransactionId, 111 | Action: ActionError, 112 | }, []byte("unhandled action")) 113 | return 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/torrent/tracker/tracker.go: -------------------------------------------------------------------------------- 1 | package tracker 2 | 3 | import ( 4 | "errors" 5 | "net" 6 | "net/url" 7 | ) 8 | 9 | // Marshalled as binary by the UDP client, so be careful making changes. 10 | type AnnounceRequest struct { 11 | InfoHash [20]byte 12 | PeerId [20]byte 13 | Downloaded int64 14 | Left uint64 15 | Uploaded int64 16 | // Apparently this is optional. None can be used for announces done at 17 | // regular intervals. 18 | Event AnnounceEvent 19 | IPAddress int32 20 | Key int32 21 | NumWant int32 // How many peer addresses are desired. -1 for default. 22 | Port uint16 23 | } // 82 bytes 24 | 25 | type AnnounceResponse struct { 26 | Interval int32 // Minimum seconds the local peer should wait before next announce. 27 | Leechers int32 28 | Seeders int32 29 | Peers []Peer 30 | } 31 | 32 | type AnnounceEvent int32 33 | 34 | func (e AnnounceEvent) String() string { 35 | // See BEP 3, "event". 36 | return []string{"empty", "completed", "started", "stopped"}[e] 37 | } 38 | 39 | type Peer struct { 40 | IP net.IP 41 | Port int 42 | } 43 | 44 | const ( 45 | None AnnounceEvent = iota 46 | Completed // The local peer just completed the torrent. 47 | Started // The local peer has just resumed this torrent. 48 | Stopped // The local peer is leaving the swarm. 49 | ) 50 | 51 | var ( 52 | ErrBadScheme = errors.New("unknown scheme") 53 | ) 54 | 55 | func Announce(urlStr string, req *AnnounceRequest) (res AnnounceResponse, err error) { 56 | return AnnounceHost(urlStr, req, "") 57 | } 58 | 59 | func AnnounceHost(urlStr string, req *AnnounceRequest, host string) (res AnnounceResponse, err error) { 60 | _url, err := url.Parse(urlStr) 61 | if err != nil { 62 | return 63 | } 64 | switch _url.Scheme { 65 | case "http", "https": 66 | return announceHTTP(req, _url, host) 67 | case "udp": 68 | return announceUDP(req, _url) 69 | default: 70 | err = ErrBadScheme 71 | return 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/torrent/tracker/udp.go: -------------------------------------------------------------------------------- 1 | package tracker 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "errors" 7 | "fmt" 8 | "io" 9 | "math/rand" 10 | "net" 11 | "net/url" 12 | "time" 13 | 14 | "github.com/anacrolix/missinggo" 15 | "github.com/anacrolix/missinggo/pproffd" 16 | 17 | "github.com/anacrolix/torrent/util" 18 | ) 19 | 20 | type Action int32 21 | 22 | const ( 23 | ActionConnect Action = iota 24 | ActionAnnounce 25 | ActionScrape 26 | ActionError 27 | 28 | connectRequestConnectionId = 0x41727101980 29 | 30 | // BEP 41 31 | optionTypeEndOfOptions = 0 32 | optionTypeNOP = 1 33 | optionTypeURLData = 2 34 | ) 35 | 36 | type ConnectionRequest struct { 37 | ConnectionId int64 38 | Action int32 39 | TransctionId int32 40 | } 41 | 42 | type ConnectionResponse struct { 43 | ConnectionId int64 44 | } 45 | 46 | type ResponseHeader struct { 47 | Action Action 48 | TransactionId int32 49 | } 50 | 51 | type RequestHeader struct { 52 | ConnectionId int64 53 | Action Action 54 | TransactionId int32 55 | } // 16 bytes 56 | 57 | type AnnounceResponseHeader struct { 58 | Interval int32 59 | Leechers int32 60 | Seeders int32 61 | } 62 | 63 | func newTransactionId() int32 { 64 | return int32(rand.Uint32()) 65 | } 66 | 67 | func timeout(contiguousTimeouts int) (d time.Duration) { 68 | if contiguousTimeouts > 8 { 69 | contiguousTimeouts = 8 70 | } 71 | d = 15 * time.Second 72 | for ; contiguousTimeouts > 0; contiguousTimeouts-- { 73 | d *= 2 74 | } 75 | return 76 | } 77 | 78 | type udpAnnounce struct { 79 | contiguousTimeouts int 80 | connectionIdReceived time.Time 81 | connectionId int64 82 | socket net.Conn 83 | url url.URL 84 | } 85 | 86 | func (c *udpAnnounce) Close() error { 87 | if c.socket != nil { 88 | return c.socket.Close() 89 | } 90 | return nil 91 | } 92 | 93 | func (c *udpAnnounce) Do(req *AnnounceRequest) (res AnnounceResponse, err error) { 94 | err = c.connect() 95 | if err != nil { 96 | return 97 | } 98 | reqURI := c.url.RequestURI() 99 | // Clearly this limits the request URI to 255 bytes. BEP 41 supports 100 | // longer but I'm not fussed. 101 | options := append([]byte{optionTypeURLData, byte(len(reqURI))}, []byte(reqURI)...) 102 | b, err := c.request(ActionAnnounce, req, options) 103 | if err != nil { 104 | return 105 | } 106 | var h AnnounceResponseHeader 107 | err = readBody(b, &h) 108 | if err != nil { 109 | if err == io.EOF { 110 | err = io.ErrUnexpectedEOF 111 | } 112 | err = fmt.Errorf("error parsing announce response: %s", err) 113 | return 114 | } 115 | res.Interval = h.Interval 116 | res.Leechers = h.Leechers 117 | res.Seeders = h.Seeders 118 | cps, err := util.UnmarshalIPv4CompactPeers(b.Bytes()) 119 | if err != nil { 120 | return 121 | } 122 | for _, cp := range cps { 123 | res.Peers = append(res.Peers, Peer{ 124 | IP: cp.IP[:], 125 | Port: int(cp.Port), 126 | }) 127 | } 128 | return 129 | } 130 | 131 | // body is the binary serializable request body. trailer is optional data 132 | // following it, such as for BEP 41. 133 | func (c *udpAnnounce) write(h *RequestHeader, body interface{}, trailer []byte) (err error) { 134 | var buf bytes.Buffer 135 | err = binary.Write(&buf, binary.BigEndian, h) 136 | if err != nil { 137 | panic(err) 138 | } 139 | if body != nil { 140 | err = binary.Write(&buf, binary.BigEndian, body) 141 | if err != nil { 142 | panic(err) 143 | } 144 | } 145 | _, err = buf.Write(trailer) 146 | if err != nil { 147 | return 148 | } 149 | n, err := c.socket.Write(buf.Bytes()) 150 | if err != nil { 151 | return 152 | } 153 | if n != buf.Len() { 154 | panic("write should send all or error") 155 | } 156 | return 157 | } 158 | 159 | func read(r io.Reader, data interface{}) error { 160 | return binary.Read(r, binary.BigEndian, data) 161 | } 162 | 163 | func write(w io.Writer, data interface{}) error { 164 | return binary.Write(w, binary.BigEndian, data) 165 | } 166 | 167 | // args is the binary serializable request body. trailer is optional data 168 | // following it, such as for BEP 41. 169 | func (c *udpAnnounce) request(action Action, args interface{}, options []byte) (responseBody *bytes.Buffer, err error) { 170 | tid := newTransactionId() 171 | err = c.write(&RequestHeader{ 172 | ConnectionId: c.connectionId, 173 | Action: action, 174 | TransactionId: tid, 175 | }, args, options) 176 | if err != nil { 177 | return 178 | } 179 | c.socket.SetReadDeadline(time.Now().Add(timeout(c.contiguousTimeouts))) 180 | b := make([]byte, 0x800) // 2KiB 181 | for { 182 | var n int 183 | n, err = c.socket.Read(b) 184 | if opE, ok := err.(*net.OpError); ok { 185 | if opE.Timeout() { 186 | c.contiguousTimeouts++ 187 | return 188 | } 189 | } 190 | if err != nil { 191 | return 192 | } 193 | buf := bytes.NewBuffer(b[:n]) 194 | var h ResponseHeader 195 | err = binary.Read(buf, binary.BigEndian, &h) 196 | switch err { 197 | case io.ErrUnexpectedEOF: 198 | continue 199 | case nil: 200 | default: 201 | return 202 | } 203 | if h.TransactionId != tid { 204 | continue 205 | } 206 | c.contiguousTimeouts = 0 207 | if h.Action == ActionError { 208 | err = errors.New(buf.String()) 209 | } 210 | responseBody = buf 211 | return 212 | } 213 | } 214 | 215 | func readBody(r io.Reader, data ...interface{}) (err error) { 216 | for _, datum := range data { 217 | err = binary.Read(r, binary.BigEndian, datum) 218 | if err != nil { 219 | break 220 | } 221 | } 222 | return 223 | } 224 | 225 | func (c *udpAnnounce) connected() bool { 226 | return !c.connectionIdReceived.IsZero() && time.Now().Before(c.connectionIdReceived.Add(time.Minute)) 227 | } 228 | 229 | func (c *udpAnnounce) connect() (err error) { 230 | if c.connected() { 231 | return nil 232 | } 233 | c.connectionId = connectRequestConnectionId 234 | if c.socket == nil { 235 | hmp := missinggo.SplitHostMaybePort(c.url.Host) 236 | if hmp.NoPort { 237 | hmp.NoPort = false 238 | hmp.Port = 80 239 | } 240 | c.socket, err = net.Dial("udp", hmp.String()) 241 | if err != nil { 242 | return 243 | } 244 | c.socket = pproffd.WrapNetConn(c.socket) 245 | } 246 | b, err := c.request(ActionConnect, nil, nil) 247 | if err != nil { 248 | return 249 | } 250 | var res ConnectionResponse 251 | err = readBody(b, &res) 252 | if err != nil { 253 | return 254 | } 255 | c.connectionId = res.ConnectionId 256 | c.connectionIdReceived = time.Now() 257 | return 258 | } 259 | 260 | func announceUDP(ar *AnnounceRequest, _url *url.URL) (AnnounceResponse, error) { 261 | ua := udpAnnounce{ 262 | url: *_url, 263 | } 264 | defer ua.Close() 265 | return ua.Do(ar) 266 | } 267 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/torrent/util/dirwatch/dirwatch.go: -------------------------------------------------------------------------------- 1 | // Package dirwatch provides filesystem-notification based tracking of torrent 2 | // info files and magnet URIs in a directory. 3 | package dirwatch 4 | 5 | import ( 6 | "bufio" 7 | "log" 8 | "os" 9 | "path/filepath" 10 | "strings" 11 | 12 | "github.com/anacrolix/missinggo" 13 | "github.com/go-fsnotify/fsnotify" 14 | 15 | "github.com/anacrolix/torrent/metainfo" 16 | ) 17 | 18 | type Change uint 19 | 20 | const ( 21 | Added Change = iota 22 | Removed 23 | ) 24 | 25 | type Event struct { 26 | MagnetURI string 27 | Change 28 | TorrentFilePath string 29 | InfoHash metainfo.Hash 30 | } 31 | 32 | type entity struct { 33 | metainfo.Hash 34 | MagnetURI string 35 | TorrentFilePath string 36 | } 37 | 38 | type Instance struct { 39 | w *fsnotify.Watcher 40 | dirName string 41 | Events chan Event 42 | dirState map[metainfo.Hash]entity 43 | } 44 | 45 | func (i *Instance) Close() { 46 | i.w.Close() 47 | } 48 | 49 | func (i *Instance) handleEvents() { 50 | defer close(i.Events) 51 | for e := range i.w.Events { 52 | log.Printf("event: %s", e) 53 | if e.Op == fsnotify.Write { 54 | // TODO: Special treatment as an existing torrent may have changed. 55 | } else { 56 | i.refresh() 57 | } 58 | } 59 | } 60 | 61 | func (i *Instance) handleErrors() { 62 | for err := range i.w.Errors { 63 | log.Printf("error in torrent directory watcher: %s", err) 64 | } 65 | } 66 | 67 | func torrentFileInfoHash(fileName string) (ih metainfo.Hash, ok bool) { 68 | mi, _ := metainfo.LoadFromFile(fileName) 69 | if mi == nil { 70 | return 71 | } 72 | ih = mi.HashInfoBytes() 73 | ok = true 74 | return 75 | } 76 | 77 | func scanDir(dirName string) (ee map[metainfo.Hash]entity) { 78 | d, err := os.Open(dirName) 79 | if err != nil { 80 | log.Print(err) 81 | return 82 | } 83 | defer d.Close() 84 | names, err := d.Readdirnames(-1) 85 | if err != nil { 86 | log.Print(err) 87 | return 88 | } 89 | ee = make(map[metainfo.Hash]entity, len(names)) 90 | addEntity := func(e entity) { 91 | e0, ok := ee[e.Hash] 92 | if ok { 93 | if e0.MagnetURI == "" || len(e.MagnetURI) < len(e0.MagnetURI) { 94 | return 95 | } 96 | } 97 | ee[e.Hash] = e 98 | } 99 | for _, n := range names { 100 | fullName := filepath.Join(dirName, n) 101 | switch filepath.Ext(n) { 102 | case ".torrent": 103 | ih, ok := torrentFileInfoHash(fullName) 104 | if !ok { 105 | break 106 | } 107 | e := entity{ 108 | TorrentFilePath: fullName, 109 | } 110 | missinggo.CopyExact(&e.Hash, ih) 111 | addEntity(e) 112 | case ".magnet": 113 | uris, err := magnetFileURIs(fullName) 114 | if err != nil { 115 | log.Print(err) 116 | break 117 | } 118 | for _, uri := range uris { 119 | m, err := metainfo.ParseMagnetURI(uri) 120 | if err != nil { 121 | log.Printf("error parsing %q in file %q: %s", uri, fullName, err) 122 | continue 123 | } 124 | addEntity(entity{ 125 | Hash: m.InfoHash, 126 | MagnetURI: uri, 127 | }) 128 | } 129 | } 130 | } 131 | return 132 | } 133 | 134 | func magnetFileURIs(name string) (uris []string, err error) { 135 | f, err := os.Open(name) 136 | if err != nil { 137 | return 138 | } 139 | defer f.Close() 140 | scanner := bufio.NewScanner(f) 141 | scanner.Split(bufio.ScanWords) 142 | for scanner.Scan() { 143 | // Allow magnet URIs to be "commented" out. 144 | if strings.HasPrefix(scanner.Text(), "#") { 145 | continue 146 | } 147 | uris = append(uris, scanner.Text()) 148 | } 149 | err = scanner.Err() 150 | return 151 | } 152 | 153 | func (i *Instance) torrentRemoved(ih metainfo.Hash) { 154 | i.Events <- Event{ 155 | InfoHash: ih, 156 | Change: Removed, 157 | } 158 | } 159 | 160 | func (i *Instance) torrentAdded(e entity) { 161 | i.Events <- Event{ 162 | InfoHash: e.Hash, 163 | Change: Added, 164 | MagnetURI: e.MagnetURI, 165 | TorrentFilePath: e.TorrentFilePath, 166 | } 167 | } 168 | 169 | func (i *Instance) refresh() { 170 | _new := scanDir(i.dirName) 171 | old := i.dirState 172 | for ih, _ := range old { 173 | _, ok := _new[ih] 174 | if !ok { 175 | i.torrentRemoved(ih) 176 | } 177 | } 178 | for ih, newE := range _new { 179 | oldE, ok := old[ih] 180 | if ok { 181 | if newE == oldE { 182 | continue 183 | } 184 | i.torrentRemoved(ih) 185 | } 186 | i.torrentAdded(newE) 187 | } 188 | i.dirState = _new 189 | } 190 | 191 | func New(dirName string) (i *Instance, err error) { 192 | w, err := fsnotify.NewWatcher() 193 | if err != nil { 194 | return 195 | } 196 | err = w.Add(dirName) 197 | if err != nil { 198 | w.Close() 199 | return 200 | } 201 | i = &Instance{ 202 | w: w, 203 | dirName: dirName, 204 | Events: make(chan Event), 205 | dirState: make(map[metainfo.Hash]entity, 0), 206 | } 207 | go func() { 208 | i.refresh() 209 | go i.handleEvents() 210 | go i.handleErrors() 211 | }() 212 | return 213 | } 214 | -------------------------------------------------------------------------------- /vendor/github.com/anacrolix/torrent/util/types.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "encoding" 5 | "encoding/binary" 6 | "errors" 7 | "fmt" 8 | "net" 9 | 10 | "github.com/bradfitz/iter" 11 | 12 | "github.com/anacrolix/torrent/bencode" 13 | ) 14 | 15 | // Concatenated 6-byte peer addresses. 16 | type CompactIPv4Peers []CompactPeer 17 | 18 | var ( 19 | // This allows bencode.Unmarshal to do better than a string or []byte. 20 | _ bencode.Unmarshaler = &CompactIPv4Peers{} 21 | _ encoding.BinaryMarshaler = CompactIPv4Peers{} 22 | ) 23 | 24 | // This allows bencode.Unmarshal to do better than a string or []byte. 25 | func (cps *CompactIPv4Peers) UnmarshalBencode(b []byte) (err error) { 26 | var bb []byte 27 | err = bencode.Unmarshal(b, &bb) 28 | if err != nil { 29 | return 30 | } 31 | *cps, err = UnmarshalIPv4CompactPeers(bb) 32 | return 33 | } 34 | 35 | func (cps CompactIPv4Peers) MarshalBinary() (ret []byte, err error) { 36 | ret = make([]byte, len(cps)*6) 37 | for i, cp := range cps { 38 | copy(ret[6*i:], cp.IP.To4()) 39 | binary.BigEndian.PutUint16(ret[6*i+4:], uint16(cp.Port)) 40 | } 41 | return 42 | } 43 | 44 | // Represents peer address in either IPv6 or IPv4 form. 45 | type CompactPeer struct { 46 | IP net.IP 47 | Port int 48 | } 49 | 50 | var ( 51 | _ bencode.Marshaler = &CompactPeer{} 52 | _ bencode.Unmarshaler = &CompactPeer{} 53 | ) 54 | 55 | func (cp CompactPeer) MarshalBencode() (ret []byte, err error) { 56 | ip := cp.IP 57 | if ip4 := ip.To4(); ip4 != nil { 58 | ip = ip4 59 | } 60 | ret = make([]byte, len(ip)+2) 61 | copy(ret, ip) 62 | binary.BigEndian.PutUint16(ret[len(ip):], uint16(cp.Port)) 63 | return bencode.Marshal(ret) 64 | } 65 | 66 | func (cp *CompactPeer) UnmarshalBinary(b []byte) error { 67 | switch len(b) { 68 | case 18: 69 | cp.IP = make([]byte, 16) 70 | case 6: 71 | cp.IP = make([]byte, 4) 72 | default: 73 | return fmt.Errorf("bad compact peer string: %q", b) 74 | } 75 | copy(cp.IP, b) 76 | b = b[len(cp.IP):] 77 | cp.Port = int(binary.BigEndian.Uint16(b)) 78 | return nil 79 | } 80 | 81 | func (cp *CompactPeer) UnmarshalBencode(b []byte) (err error) { 82 | var _b []byte 83 | err = bencode.Unmarshal(b, &_b) 84 | if err != nil { 85 | return 86 | } 87 | return cp.UnmarshalBinary(_b) 88 | } 89 | 90 | func UnmarshalIPv4CompactPeers(b []byte) (ret []CompactPeer, err error) { 91 | if len(b)%6 != 0 { 92 | err = errors.New("bad length") 93 | return 94 | } 95 | num := len(b) / 6 96 | ret = make([]CompactPeer, num) 97 | for i := range iter.N(num) { 98 | off := i * 6 99 | err = ret[i].UnmarshalBinary(b[off : off+6]) 100 | if err != nil { 101 | return 102 | } 103 | } 104 | return 105 | } 106 | -------------------------------------------------------------------------------- /vendor/github.com/sprt/byt/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 sprt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /vendor/github.com/sprt/byt/byt.go: -------------------------------------------------------------------------------- 1 | // Package bytefmt provides utility functions to format and parse byte 2 | // quantities. 3 | package byt 4 | 5 | import ( 6 | "fmt" 7 | "math" 8 | "strconv" 9 | "strings" 10 | ) 11 | 12 | // A Size is a quantity in bytes. It implements the flag.Value interface. 13 | type Size int64 14 | 15 | // FlagUsage is a partial usage message that applications using a Size as a flag 16 | // may wish to include in their -help output. 17 | const FlagUsage = ` 18 | A byte size is a number and optional unit. Units are K,M,G,T,P,E,Z,Y (powers of 19 | 1024) or KB,MB,... (powers of 1000). It is not case sensitive. 20 | ` 21 | 22 | const ( 23 | Byt Size = 1 << (10 * iota) 24 | 25 | Kibibyte 26 | Mebibyte 27 | Gibibyte 28 | Tebibyte 29 | Pebibyte 30 | Exbibyte 31 | 32 | K = Kibibyte 33 | M = Mebibyte 34 | G = Gibibyte 35 | T = Tebibyte 36 | P = Pebibyte 37 | E = Exbibyte 38 | 39 | Kilobyte = 1e3 40 | Megabyte = 1e6 41 | Gigabyte = 1e9 42 | Terabyte = 1e12 43 | Petabyte = 1e15 44 | Exabyte = 1e18 45 | 46 | KB = Kilobyte 47 | MB = Megabyte 48 | GB = Gigabyte 49 | TB = Terabyte 50 | PB = Petabyte 51 | EB = Exabyte 52 | ) 53 | 54 | var symbols = map[Size]string{ 55 | Byt: "B", 56 | 57 | Kibibyte: "KiB", 58 | Mebibyte: "MiB", 59 | Gibibyte: "GiB", 60 | Tebibyte: "TiB", 61 | Pebibyte: "PiB", 62 | Exbibyte: "EiB", 63 | 64 | Kilobyte: "KB", 65 | Megabyte: "MB", 66 | Gigabyte: "GB", 67 | Terabyte: "TB", 68 | Petabyte: "PB", 69 | Exabyte: "EB", 70 | } 71 | 72 | var suffixes = map[string]Size{ 73 | "k": Kibibyte, 74 | "m": Mebibyte, 75 | "g": Gibibyte, 76 | "t": Tebibyte, 77 | "p": Pebibyte, 78 | "e": Exbibyte, 79 | 80 | "kb": Kilobyte, 81 | "mb": Megabyte, 82 | "gb": Gigabyte, 83 | "tb": Terabyte, 84 | "pb": Petabyte, 85 | "eb": Exabyte, 86 | } 87 | 88 | func (s Size) Binary() fmt.Formatter { 89 | return &formatter{s, Kibibyte} 90 | } 91 | 92 | func (s Size) Decimal() fmt.Formatter { 93 | return &formatter{s, Kilobyte} 94 | } 95 | 96 | func (s *Size) Set(v string) error { 97 | x, err := parseCLI(v) 98 | if err != nil { 99 | return err 100 | } 101 | *s = x 102 | return nil 103 | } 104 | 105 | func (s *Size) String() string { 106 | return strconv.FormatInt(int64(*s), 10) 107 | } 108 | 109 | func (s Size) format(un Size) (float64, string) { 110 | u, ss := Byt, s 111 | for ss >= un { 112 | ss /= un 113 | u *= un 114 | } 115 | return float64(s) / float64(u), symbols[u] 116 | } 117 | 118 | type formatter struct { 119 | bs Size 120 | un Size 121 | } 122 | 123 | func (f *formatter) Format(s fmt.State, verb rune) { 124 | n, un := f.bs.format(f.un) 125 | prec, ok := s.Precision() 126 | if !ok { 127 | prec = -1 128 | } 129 | var b []byte 130 | b = strconv.AppendFloat(b, n, 'f', prec, 64) 131 | b = append(b, ' ') 132 | b = append(b, un...) 133 | s.Write(b) 134 | } 135 | 136 | // parseCLI parses a flag value and returns the specified size; 137 | // see FlagUsage for details. 138 | func parseCLI(s string) (Size, error) { 139 | s = strings.ToLower(s) 140 | for suffix, size := range suffixes { 141 | if strings.HasSuffix(s, suffix) { 142 | x, err := parseFloat(strings.TrimSuffix(s, suffix)) 143 | if err != nil { 144 | return 0, err 145 | } 146 | return Size(x * float64(size)), nil 147 | } 148 | } 149 | x, err := strconv.ParseFloat(s, 64) 150 | if err != nil || math.IsInf(x, 0) || math.IsNaN(x) { 151 | return 0, fmt.Errorf("cannot parse %q", s) 152 | } 153 | return Size(x), nil 154 | } 155 | 156 | func parseFloat(s string) (float64, error) { 157 | x, err := strconv.ParseFloat(s, 64) 158 | if err != nil || math.IsInf(x, 0) || math.IsNaN(x) { 159 | return 0, fmt.Errorf("cannot parse %q", s) 160 | } 161 | return x, nil 162 | } 163 | -------------------------------------------------------------------------------- /vendor/manifest: -------------------------------------------------------------------------------- 1 | { 2 | "version": 0, 3 | "dependencies": [ 4 | { 5 | "importpath": "github.com/anacrolix/envpprof", 6 | "repository": "https://github.com/anacrolix/envpprof", 7 | "vcs": "git", 8 | "revision": "0383bfe017e02efb418ffd595fc54777a35e48b0", 9 | "branch": "master", 10 | "notests": true 11 | }, 12 | { 13 | "importpath": "github.com/anacrolix/missinggo", 14 | "repository": "https://github.com/anacrolix/missinggo", 15 | "vcs": "git", 16 | "revision": "86f106025d38e0baf732bb3e6761ab16e87d96cb", 17 | "branch": "master", 18 | "notests": true 19 | }, 20 | { 21 | "importpath": "github.com/anacrolix/tagflag", 22 | "repository": "https://github.com/anacrolix/tagflag", 23 | "vcs": "git", 24 | "revision": "37f7ff37cf0031af33bce62bc878a99a98749739", 25 | "branch": "master", 26 | "notests": true 27 | }, 28 | { 29 | "importpath": "github.com/anacrolix/torrent/bencode", 30 | "repository": "https://github.com/anacrolix/torrent", 31 | "vcs": "git", 32 | "revision": "9a4fbb01f0d2563f2e2cd36c1cb8937016a80279", 33 | "branch": "master", 34 | "path": "/bencode", 35 | "notests": true 36 | }, 37 | { 38 | "importpath": "github.com/anacrolix/torrent/metainfo", 39 | "repository": "https://github.com/anacrolix/torrent", 40 | "vcs": "git", 41 | "revision": "9a4fbb01f0d2563f2e2cd36c1cb8937016a80279", 42 | "branch": "master", 43 | "path": "/metainfo", 44 | "notests": true 45 | }, 46 | { 47 | "importpath": "github.com/anacrolix/torrent/tracker", 48 | "repository": "https://github.com/anacrolix/torrent", 49 | "vcs": "git", 50 | "revision": "9a4fbb01f0d2563f2e2cd36c1cb8937016a80279", 51 | "branch": "master", 52 | "path": "/tracker", 53 | "notests": true 54 | }, 55 | { 56 | "importpath": "github.com/anacrolix/torrent/util", 57 | "repository": "https://github.com/anacrolix/torrent", 58 | "vcs": "git", 59 | "revision": "9a4fbb01f0d2563f2e2cd36c1cb8937016a80279", 60 | "branch": "master", 61 | "path": "/util", 62 | "notests": true 63 | }, 64 | { 65 | "importpath": "github.com/sprt/byt", 66 | "repository": "https://github.com/sprt/byt", 67 | "vcs": "git", 68 | "revision": "c20c6b9163d59badd7ee6173901f26789716e400", 69 | "branch": "master", 70 | "notests": true 71 | } 72 | ] 73 | } --------------------------------------------------------------------------------