init
This commit is contained in:
21
vendor/github.com/anacrolix/missinggo/LICENSE
generated
vendored
Normal file
21
vendor/github.com/anacrolix/missinggo/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Matt Joiner
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
4
vendor/github.com/anacrolix/missinggo/README.md
generated
vendored
Normal file
4
vendor/github.com/anacrolix/missinggo/README.md
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
# missinggo
|
||||
[](https://godoc.org/github.com/anacrolix/missinggo)
|
||||
|
||||
Stuff that supplements Go's stdlib, or isn't significant enough to be in its own repo.
|
44
vendor/github.com/anacrolix/missinggo/addr.go
generated
vendored
Normal file
44
vendor/github.com/anacrolix/missinggo/addr.go
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Extracts the port as an integer from an address string.
|
||||
func AddrPort(addr net.Addr) int {
|
||||
switch raw := addr.(type) {
|
||||
case *net.UDPAddr:
|
||||
return raw.Port
|
||||
case *net.TCPAddr:
|
||||
return raw.Port
|
||||
default:
|
||||
_, port, err := net.SplitHostPort(addr.String())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
i64, err := strconv.ParseInt(port, 0, 0)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return int(i64)
|
||||
}
|
||||
}
|
||||
|
||||
func AddrIP(addr net.Addr) net.IP {
|
||||
if addr == nil {
|
||||
return nil
|
||||
}
|
||||
switch raw := addr.(type) {
|
||||
case *net.UDPAddr:
|
||||
return raw.IP
|
||||
case *net.TCPAddr:
|
||||
return raw.IP
|
||||
default:
|
||||
host, _, err := net.SplitHostPort(addr.String())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return net.ParseIP(host)
|
||||
}
|
||||
}
|
11
vendor/github.com/anacrolix/missinggo/atime.go
generated
vendored
Normal file
11
vendor/github.com/anacrolix/missinggo/atime.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Extracts the access time from the FileInfo internals.
|
||||
func FileInfoAccessTime(fi os.FileInfo) time.Time {
|
||||
return fileInfoAccessTime(fi)
|
||||
}
|
14
vendor/github.com/anacrolix/missinggo/atime_atim.go
generated
vendored
Normal file
14
vendor/github.com/anacrolix/missinggo/atime_atim.go
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
// +build linux dragonfly openbsd solaris
|
||||
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func fileInfoAccessTime(fi os.FileInfo) time.Time {
|
||||
ts := fi.Sys().(*syscall.Stat_t).Atim
|
||||
return time.Unix(int64(ts.Sec), int64(ts.Nsec))
|
||||
}
|
14
vendor/github.com/anacrolix/missinggo/atime_atimespec.go
generated
vendored
Normal file
14
vendor/github.com/anacrolix/missinggo/atime_atimespec.go
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
// +build darwin freebsd netbsd
|
||||
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func fileInfoAccessTime(fi os.FileInfo) time.Time {
|
||||
ts := fi.Sys().(*syscall.Stat_t).Atimespec
|
||||
return time.Unix(int64(ts.Sec), int64(ts.Nsec))
|
||||
}
|
12
vendor/github.com/anacrolix/missinggo/atime_plan9.go
generated
vendored
Normal file
12
vendor/github.com/anacrolix/missinggo/atime_plan9.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func fileInfoAccessTime(fi os.FileInfo) time.Time {
|
||||
sec := fi.Sys().(*syscall.Dir).Atime
|
||||
return time.Unix(int64(sec), 0)
|
||||
}
|
12
vendor/github.com/anacrolix/missinggo/atime_windows.go
generated
vendored
Normal file
12
vendor/github.com/anacrolix/missinggo/atime_windows.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func fileInfoAccessTime(fi os.FileInfo) time.Time {
|
||||
ts := fi.Sys().(*syscall.Win32FileAttributeData).LastAccessTime
|
||||
return time.Unix(0, int64(ts.Nanoseconds()))
|
||||
}
|
171
vendor/github.com/anacrolix/missinggo/bitmap/bitmap.go
generated
vendored
Normal file
171
vendor/github.com/anacrolix/missinggo/bitmap/bitmap.go
generated
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
// Package bitmap provides a []bool/bitmap implementation with standardized
|
||||
// iteration. Bitmaps are the equivalent of []bool, with improved compression
|
||||
// for runs of similar values, and faster operations on ranges and the like.
|
||||
package bitmap
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/RoaringBitmap/roaring"
|
||||
|
||||
"github.com/anacrolix/missinggo/iter"
|
||||
)
|
||||
|
||||
const MaxInt = -1
|
||||
|
||||
type BitIndex = int
|
||||
|
||||
type Interface interface {
|
||||
Len() int
|
||||
}
|
||||
|
||||
// Bitmaps store the existence of values in [0,math.MaxUint32] more
|
||||
// efficiently than []bool. The empty value starts with no bits set.
|
||||
type Bitmap struct {
|
||||
rb *roaring.Bitmap
|
||||
}
|
||||
|
||||
var ToEnd int = -1
|
||||
|
||||
// The number of set bits in the bitmap. Also known as cardinality.
|
||||
func (me *Bitmap) Len() int {
|
||||
if me.rb == nil {
|
||||
return 0
|
||||
}
|
||||
return int(me.rb.GetCardinality())
|
||||
}
|
||||
|
||||
func (me Bitmap) ToSortedSlice() (ret []int) {
|
||||
if me.rb == nil {
|
||||
return
|
||||
}
|
||||
for _, ui32 := range me.rb.ToArray() {
|
||||
ret = append(ret, int(int32(ui32)))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (me *Bitmap) lazyRB() *roaring.Bitmap {
|
||||
if me.rb == nil {
|
||||
me.rb = roaring.NewBitmap()
|
||||
}
|
||||
return me.rb
|
||||
}
|
||||
|
||||
func (me Bitmap) Iter(cb iter.Callback) {
|
||||
me.IterTyped(func(i int) bool {
|
||||
return cb(i)
|
||||
})
|
||||
}
|
||||
|
||||
// Returns true if all values were traversed without early termination.
|
||||
func (me Bitmap) IterTyped(f func(int) bool) bool {
|
||||
if me.rb == nil {
|
||||
return true
|
||||
}
|
||||
it := me.rb.Iterator()
|
||||
for it.HasNext() {
|
||||
if !f(int(it.Next())) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func checkInt(i BitIndex) {
|
||||
if i < math.MinInt32 || i > math.MaxInt32 {
|
||||
panic("out of bounds")
|
||||
}
|
||||
}
|
||||
|
||||
func (me *Bitmap) Add(is ...BitIndex) {
|
||||
rb := me.lazyRB()
|
||||
for _, i := range is {
|
||||
checkInt(i)
|
||||
rb.AddInt(i)
|
||||
}
|
||||
}
|
||||
|
||||
func (me *Bitmap) AddRange(begin, end BitIndex) {
|
||||
if begin >= end {
|
||||
return
|
||||
}
|
||||
me.lazyRB().AddRange(uint64(begin), uint64(end))
|
||||
}
|
||||
|
||||
func (me *Bitmap) Remove(i BitIndex) bool {
|
||||
if me.rb == nil {
|
||||
return false
|
||||
}
|
||||
return me.rb.CheckedRemove(uint32(i))
|
||||
}
|
||||
|
||||
func (me *Bitmap) Union(other Bitmap) {
|
||||
me.lazyRB().Or(other.lazyRB())
|
||||
}
|
||||
|
||||
func (me *Bitmap) Contains(i int) bool {
|
||||
if me.rb == nil {
|
||||
return false
|
||||
}
|
||||
return me.rb.Contains(uint32(i))
|
||||
}
|
||||
|
||||
func (me *Bitmap) Sub(other Bitmap) {
|
||||
if other.rb == nil {
|
||||
return
|
||||
}
|
||||
if me.rb == nil {
|
||||
return
|
||||
}
|
||||
me.rb.AndNot(other.rb)
|
||||
}
|
||||
|
||||
func (me *Bitmap) Clear() {
|
||||
if me.rb == nil {
|
||||
return
|
||||
}
|
||||
me.rb.Clear()
|
||||
}
|
||||
|
||||
func (me Bitmap) Copy() (ret Bitmap) {
|
||||
ret = me
|
||||
if ret.rb != nil {
|
||||
ret.rb = ret.rb.Clone()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (me *Bitmap) FlipRange(begin, end BitIndex) {
|
||||
me.lazyRB().FlipInt(begin, end)
|
||||
}
|
||||
|
||||
func (me *Bitmap) Get(bit BitIndex) bool {
|
||||
return me.rb != nil && me.rb.ContainsInt(bit)
|
||||
}
|
||||
|
||||
func (me *Bitmap) Set(bit BitIndex, value bool) {
|
||||
if value {
|
||||
me.lazyRB().AddInt(bit)
|
||||
} else {
|
||||
if me.rb != nil {
|
||||
me.rb.Remove(uint32(bit))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (me *Bitmap) RemoveRange(begin, end BitIndex) *Bitmap {
|
||||
if me.rb == nil {
|
||||
return me
|
||||
}
|
||||
rangeEnd := uint64(end)
|
||||
if end == ToEnd {
|
||||
rangeEnd = 0x100000000
|
||||
}
|
||||
me.rb.RemoveRange(uint64(begin), rangeEnd)
|
||||
return me
|
||||
}
|
||||
|
||||
func (me Bitmap) IsEmpty() bool {
|
||||
return me.rb == nil || me.rb.IsEmpty()
|
||||
}
|
15
vendor/github.com/anacrolix/missinggo/bitmap/global.go
generated
vendored
Normal file
15
vendor/github.com/anacrolix/missinggo/bitmap/global.go
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
package bitmap
|
||||
|
||||
import "github.com/RoaringBitmap/roaring"
|
||||
|
||||
func Sub(left, right Bitmap) Bitmap {
|
||||
return Bitmap{
|
||||
rb: roaring.AndNot(left.lazyRB(), right.lazyRB()),
|
||||
}
|
||||
}
|
||||
|
||||
func Flip(bm Bitmap, start, end int) Bitmap {
|
||||
return Bitmap{
|
||||
rb: roaring.FlipInt(bm.lazyRB(), start, end),
|
||||
}
|
||||
}
|
24
vendor/github.com/anacrolix/missinggo/bitmap/iter.go
generated
vendored
Normal file
24
vendor/github.com/anacrolix/missinggo/bitmap/iter.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
package bitmap
|
||||
|
||||
import "github.com/RoaringBitmap/roaring"
|
||||
|
||||
type Iter struct {
|
||||
ii roaring.IntIterable
|
||||
}
|
||||
|
||||
func (me *Iter) Next() bool {
|
||||
if me == nil {
|
||||
return false
|
||||
}
|
||||
return me.ii.HasNext()
|
||||
}
|
||||
|
||||
func (me *Iter) Value() interface{} {
|
||||
return me.ValueInt()
|
||||
}
|
||||
|
||||
func (me *Iter) ValueInt() int {
|
||||
return int(me.ii.Next())
|
||||
}
|
||||
|
||||
func (me *Iter) Stop() {}
|
46
vendor/github.com/anacrolix/missinggo/certdir.go
generated
vendored
Normal file
46
vendor/github.com/anacrolix/missinggo/certdir.go
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func LoadCertificateDir(dir string) (certs []tls.Certificate, err error) {
|
||||
d, err := os.Open(dir)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer d.Close()
|
||||
const defaultPEMFile = "default.pem"
|
||||
if p := filepath.Join(dir, defaultPEMFile); FilePathExists(p) {
|
||||
cert, err := tls.LoadX509KeyPair(p, p)
|
||||
if err == nil {
|
||||
certs = append(certs, cert)
|
||||
} else {
|
||||
log.Printf("error loading default certicate: %s", err)
|
||||
}
|
||||
}
|
||||
files, err := d.Readdir(-1)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, f := range files {
|
||||
if f.Name() == defaultPEMFile {
|
||||
continue
|
||||
}
|
||||
if !strings.HasSuffix(f.Name(), ".pem") {
|
||||
continue
|
||||
}
|
||||
p := filepath.Join(dir, f.Name())
|
||||
cert, err := tls.LoadX509KeyPair(p, p)
|
||||
if err != nil {
|
||||
log.Printf("error loading key pair from %q: %s", p, err)
|
||||
continue
|
||||
}
|
||||
certs = append(certs, cert)
|
||||
}
|
||||
return
|
||||
}
|
36
vendor/github.com/anacrolix/missinggo/chancond.go
generated
vendored
Normal file
36
vendor/github.com/anacrolix/missinggo/chancond.go
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
package missinggo
|
||||
|
||||
import "sync"
|
||||
|
||||
type ChanCond struct {
|
||||
mu sync.Mutex
|
||||
ch chan struct{}
|
||||
}
|
||||
|
||||
func (me *ChanCond) Wait() <-chan struct{} {
|
||||
me.mu.Lock()
|
||||
defer me.mu.Unlock()
|
||||
if me.ch == nil {
|
||||
me.ch = make(chan struct{})
|
||||
}
|
||||
return me.ch
|
||||
}
|
||||
|
||||
func (me *ChanCond) Signal() {
|
||||
me.mu.Lock()
|
||||
defer me.mu.Unlock()
|
||||
select {
|
||||
case me.ch <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
func (me *ChanCond) Broadcast() {
|
||||
me.mu.Lock()
|
||||
defer me.mu.Unlock()
|
||||
if me.ch == nil {
|
||||
return
|
||||
}
|
||||
close(me.ch)
|
||||
me.ch = nil
|
||||
}
|
34
vendor/github.com/anacrolix/missinggo/copy.go
generated
vendored
Normal file
34
vendor/github.com/anacrolix/missinggo/copy.go
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Copy elements from src to dst. Panics if the length of src and dst are
|
||||
// different.
|
||||
func CopyExact(dest interface{}, src interface{}) {
|
||||
dV := reflect.ValueOf(dest)
|
||||
sV := reflect.ValueOf(src)
|
||||
if dV.Kind() == reflect.Ptr {
|
||||
dV = dV.Elem()
|
||||
}
|
||||
if dV.Kind() == reflect.Array && !dV.CanAddr() {
|
||||
panic(fmt.Sprintf("dest not addressable: %T", dest))
|
||||
}
|
||||
if sV.Kind() == reflect.Ptr {
|
||||
sV = sV.Elem()
|
||||
}
|
||||
if sV.Kind() == reflect.String {
|
||||
sV = sV.Convert(reflect.SliceOf(dV.Type().Elem()))
|
||||
}
|
||||
if !sV.IsValid() {
|
||||
panic("invalid source, probably nil")
|
||||
}
|
||||
if dV.Len() != sV.Len() {
|
||||
panic(fmt.Sprintf("dest len (%d) != src len (%d)", dV.Len(), sV.Len()))
|
||||
}
|
||||
if dV.Len() != reflect.Copy(dV, sV) {
|
||||
panic("dammit")
|
||||
}
|
||||
}
|
18
vendor/github.com/anacrolix/missinggo/croak.go
generated
vendored
Normal file
18
vendor/github.com/anacrolix/missinggo/croak.go
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func Unchomp(s string) string {
|
||||
if len(s) > 0 && s[len(s)-1] == '\n' {
|
||||
return s
|
||||
}
|
||||
return s + "\n"
|
||||
}
|
||||
|
||||
func Fatal(msg interface{}) {
|
||||
os.Stderr.WriteString(Unchomp(fmt.Sprint(msg)))
|
||||
os.Exit(1)
|
||||
}
|
3
vendor/github.com/anacrolix/missinggo/doc.go
generated
vendored
Normal file
3
vendor/github.com/anacrolix/missinggo/doc.go
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
// Package missinggo contains miscellaneous helpers used in many of anacrolix'
|
||||
// projects.
|
||||
package missinggo
|
33
vendor/github.com/anacrolix/missinggo/empty_value.go
generated
vendored
Normal file
33
vendor/github.com/anacrolix/missinggo/empty_value.go
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
package missinggo
|
||||
|
||||
import "reflect"
|
||||
|
||||
func IsZeroValue(i interface{}) bool {
|
||||
return IsEmptyValue(reflect.ValueOf(i))
|
||||
}
|
||||
|
||||
// Returns whether the value represents the empty value for its type. Used for
|
||||
// example to determine if complex types satisfy the common "omitempty" tag
|
||||
// option for marshalling. Taken from
|
||||
// http://stackoverflow.com/a/23555352/149482.
|
||||
func IsEmptyValue(v reflect.Value) bool {
|
||||
switch v.Kind() {
|
||||
case reflect.Func, reflect.Map, reflect.Slice:
|
||||
return v.IsNil()
|
||||
case reflect.Array:
|
||||
z := true
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
z = z && IsEmptyValue(v.Index(i))
|
||||
}
|
||||
return z
|
||||
case reflect.Struct:
|
||||
z := true
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
z = z && IsEmptyValue(v.Field(i))
|
||||
}
|
||||
return z
|
||||
}
|
||||
// Compare other types directly:
|
||||
z := reflect.Zero(v.Type())
|
||||
return v.Interface() == z.Interface()
|
||||
}
|
15
vendor/github.com/anacrolix/missinggo/encoding.go
generated
vendored
Normal file
15
vendor/github.com/anacrolix/missinggo/encoding.go
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
package missinggo
|
||||
|
||||
// An interface for "encoding/base64".Encoder
|
||||
type Encoding interface {
|
||||
EncodeToString([]byte) string
|
||||
DecodeString(string) ([]byte, error)
|
||||
}
|
||||
|
||||
// An encoding that does nothing.
|
||||
type IdentityEncoding struct{}
|
||||
|
||||
var _ Encoding = IdentityEncoding{}
|
||||
|
||||
func (IdentityEncoding) EncodeToString(b []byte) string { return string(b) }
|
||||
func (IdentityEncoding) DecodeString(s string) ([]byte, error) { return []byte(s), nil }
|
65
vendor/github.com/anacrolix/missinggo/event.go
generated
vendored
Normal file
65
vendor/github.com/anacrolix/missinggo/event.go
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
package missinggo
|
||||
|
||||
import "sync"
|
||||
|
||||
// Events are boolean flags that provide a channel that's closed when true.
|
||||
// This could go in the sync package, but that's more of a debug wrapper on
|
||||
// the standard library sync.
|
||||
type Event struct {
|
||||
ch chan struct{}
|
||||
closed bool
|
||||
}
|
||||
|
||||
func (me *Event) LockedChan(lock sync.Locker) <-chan struct{} {
|
||||
lock.Lock()
|
||||
ch := me.C()
|
||||
lock.Unlock()
|
||||
return ch
|
||||
}
|
||||
|
||||
// Returns a chan that is closed when the event is true.
|
||||
func (me *Event) C() <-chan struct{} {
|
||||
if me.ch == nil {
|
||||
me.ch = make(chan struct{})
|
||||
}
|
||||
return me.ch
|
||||
}
|
||||
|
||||
// TODO: Merge into Set.
|
||||
func (me *Event) Clear() {
|
||||
if me.closed {
|
||||
me.ch = nil
|
||||
me.closed = false
|
||||
}
|
||||
}
|
||||
|
||||
// Set the event to true/on.
|
||||
func (me *Event) Set() (first bool) {
|
||||
if me.closed {
|
||||
return false
|
||||
}
|
||||
if me.ch == nil {
|
||||
me.ch = make(chan struct{})
|
||||
}
|
||||
close(me.ch)
|
||||
me.closed = true
|
||||
return true
|
||||
}
|
||||
|
||||
// TODO: Change to Get.
|
||||
func (me *Event) IsSet() bool {
|
||||
return me.closed
|
||||
}
|
||||
|
||||
func (me *Event) Wait() {
|
||||
<-me.C()
|
||||
}
|
||||
|
||||
// TODO: Merge into Set.
|
||||
func (me *Event) SetBool(b bool) {
|
||||
if b {
|
||||
me.Set()
|
||||
} else {
|
||||
me.Clear()
|
||||
}
|
||||
}
|
26
vendor/github.com/anacrolix/missinggo/event_synchronized.go
generated
vendored
Normal file
26
vendor/github.com/anacrolix/missinggo/event_synchronized.go
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
package missinggo
|
||||
|
||||
import "sync"
|
||||
|
||||
type SynchronizedEvent struct {
|
||||
mu sync.Mutex
|
||||
e Event
|
||||
}
|
||||
|
||||
func (me *SynchronizedEvent) Set() {
|
||||
me.mu.Lock()
|
||||
me.e.Set()
|
||||
me.mu.Unlock()
|
||||
}
|
||||
|
||||
func (me *SynchronizedEvent) Clear() {
|
||||
me.mu.Lock()
|
||||
me.e.Clear()
|
||||
me.mu.Unlock()
|
||||
}
|
||||
|
||||
func (me *SynchronizedEvent) C() <-chan struct{} {
|
||||
me.mu.Lock()
|
||||
defer me.mu.Unlock()
|
||||
return me.e.C()
|
||||
}
|
63
vendor/github.com/anacrolix/missinggo/expect/assert.go
generated
vendored
Normal file
63
vendor/github.com/anacrolix/missinggo/expect/assert.go
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
package expect // import "github.com/anacrolix/missinggo/expect"
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func Nil(x interface{}) {
|
||||
if x != nil {
|
||||
panic(fmt.Sprintf("expected nil; got %v", x))
|
||||
}
|
||||
}
|
||||
|
||||
func NotNil(x interface{}) {
|
||||
if x == nil {
|
||||
panic(x)
|
||||
}
|
||||
}
|
||||
|
||||
func Equal(x, y interface{}) {
|
||||
if x == y {
|
||||
return
|
||||
}
|
||||
yAsXType := reflect.ValueOf(y).Convert(reflect.TypeOf(x)).Interface()
|
||||
if !reflect.DeepEqual(x, yAsXType) {
|
||||
panic(fmt.Sprintf("%v != %v", x, y))
|
||||
}
|
||||
}
|
||||
|
||||
func StrictlyEqual(x, y interface{}) {
|
||||
if x != y {
|
||||
panic(fmt.Sprintf("%s != %s", x, y))
|
||||
}
|
||||
}
|
||||
|
||||
func OneRowAffected(r sql.Result) {
|
||||
count, err := r.RowsAffected()
|
||||
Nil(err)
|
||||
if count != 1 {
|
||||
panic(count)
|
||||
}
|
||||
}
|
||||
|
||||
func True(b bool) {
|
||||
if !b {
|
||||
panic(b)
|
||||
}
|
||||
}
|
||||
|
||||
var Ok = True
|
||||
|
||||
func False(b bool) {
|
||||
if b {
|
||||
panic(b)
|
||||
}
|
||||
}
|
||||
|
||||
func Zero(x interface{}) {
|
||||
if x != reflect.Zero(reflect.TypeOf(x)).Interface() {
|
||||
panic(x)
|
||||
}
|
||||
}
|
35
vendor/github.com/anacrolix/missinggo/expvarIndentMap.go
generated
vendored
Normal file
35
vendor/github.com/anacrolix/missinggo/expvarIndentMap.go
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"expvar"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type IndentMap struct {
|
||||
expvar.Map
|
||||
}
|
||||
|
||||
var _ expvar.Var = (*IndentMap)(nil)
|
||||
|
||||
func NewExpvarIndentMap(name string) *IndentMap {
|
||||
v := new(IndentMap)
|
||||
v.Init()
|
||||
expvar.Publish(name, v)
|
||||
return v
|
||||
}
|
||||
|
||||
func (v *IndentMap) String() string {
|
||||
var b bytes.Buffer
|
||||
fmt.Fprintf(&b, "{")
|
||||
first := true
|
||||
v.Do(func(kv expvar.KeyValue) {
|
||||
if !first {
|
||||
fmt.Fprintf(&b, ",")
|
||||
}
|
||||
fmt.Fprintf(&b, "\n\t%q: %v", kv.Key, kv.Value)
|
||||
first = false
|
||||
})
|
||||
fmt.Fprintf(&b, "}")
|
||||
return b.String()
|
||||
}
|
41
vendor/github.com/anacrolix/missinggo/flag.go
generated
vendored
Normal file
41
vendor/github.com/anacrolix/missinggo/flag.go
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
package missinggo
|
||||
|
||||
import "sync"
|
||||
|
||||
// Flag represents a boolean value, that signals sync.Cond's when it changes.
|
||||
// It's not concurrent safe by intention.
|
||||
type Flag struct {
|
||||
Conds map[*sync.Cond]struct{}
|
||||
value bool
|
||||
}
|
||||
|
||||
func (me *Flag) Set(value bool) {
|
||||
if value != me.value {
|
||||
me.broadcastChange()
|
||||
}
|
||||
me.value = value
|
||||
}
|
||||
|
||||
func (me *Flag) Get() bool {
|
||||
return me.value
|
||||
}
|
||||
|
||||
func (me *Flag) broadcastChange() {
|
||||
for cond := range me.Conds {
|
||||
cond.Broadcast()
|
||||
}
|
||||
}
|
||||
|
||||
func (me *Flag) addCond(c *sync.Cond) {
|
||||
if me.Conds == nil {
|
||||
me.Conds = make(map[*sync.Cond]struct{})
|
||||
}
|
||||
me.Conds[c] = struct{}{}
|
||||
}
|
||||
|
||||
// Adds the sync.Cond to all the given Flag's.
|
||||
func AddCondToFlags(cond *sync.Cond, flags ...*Flag) {
|
||||
for _, f := range flags {
|
||||
f.addCond(cond)
|
||||
}
|
||||
}
|
18
vendor/github.com/anacrolix/missinggo/go.mod
generated
vendored
Normal file
18
vendor/github.com/anacrolix/missinggo/go.mod
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
module github.com/anacrolix/missinggo
|
||||
|
||||
require (
|
||||
github.com/RoaringBitmap/roaring v0.4.7
|
||||
github.com/anacrolix/envpprof v0.0.0-20180404065416-323002cec2fa
|
||||
github.com/anacrolix/tagflag v0.0.0-20180109131632-2146c8d41bf0
|
||||
github.com/bradfitz/iter v0.0.0-20140124041915-454541ec3da2
|
||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815
|
||||
github.com/dustin/go-humanize v0.0.0-20180421182945-02af3965c54e
|
||||
github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db
|
||||
github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a
|
||||
github.com/huandu/xstrings v1.0.0
|
||||
github.com/philhofer/fwd v1.0.0
|
||||
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46
|
||||
github.com/stretchr/testify v1.2.1
|
||||
github.com/tinylib/msgp v1.0.2
|
||||
)
|
52
vendor/github.com/anacrolix/missinggo/hostmaybeport.go
generated
vendored
Normal file
52
vendor/github.com/anacrolix/missinggo/hostmaybeport.go
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Represents a split host port.
|
||||
type HostMaybePort struct {
|
||||
Host string // Just the host, with no port.
|
||||
Port int // The port if NoPort is false.
|
||||
NoPort bool // Whether a port is specified.
|
||||
Err error // The error returned from net.SplitHostPort.
|
||||
}
|
||||
|
||||
func (me *HostMaybePort) String() string {
|
||||
if me.NoPort {
|
||||
return me.Host
|
||||
}
|
||||
return net.JoinHostPort(me.Host, strconv.FormatInt(int64(me.Port), 10))
|
||||
}
|
||||
|
||||
// Parse a "hostport" string, a concept that floats around the stdlib a lot
|
||||
// and is painful to work with. If no port is present, what's usually present
|
||||
// is just the host.
|
||||
func SplitHostMaybePort(hostport string) HostMaybePort {
|
||||
host, portStr, err := net.SplitHostPort(hostport)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "missing port") {
|
||||
return HostMaybePort{
|
||||
Host: hostport,
|
||||
NoPort: true,
|
||||
}
|
||||
}
|
||||
return HostMaybePort{
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
portI64, err := strconv.ParseInt(portStr, 0, 0)
|
||||
if err != nil {
|
||||
return HostMaybePort{
|
||||
Host: host,
|
||||
Port: -1,
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
return HostMaybePort{
|
||||
Host: host,
|
||||
Port: int(portI64),
|
||||
}
|
||||
}
|
19
vendor/github.com/anacrolix/missinggo/hostport.go
generated
vendored
Normal file
19
vendor/github.com/anacrolix/missinggo/hostport.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func ParseHostPort(hostport string) (host string, port int, err error) {
|
||||
host, portStr, err := net.SplitHostPort(hostport)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
port64, err := strconv.ParseInt(portStr, 0, 0)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
port = int(port64)
|
||||
return
|
||||
}
|
75
vendor/github.com/anacrolix/missinggo/httpresponsestatus.go
generated
vendored
Normal file
75
vendor/github.com/anacrolix/missinggo/httpresponsestatus.go
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
package missinggo
|
||||
|
||||
// todo move to httptoo as ResponseRecorder
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// A http.ResponseWriter that tracks the status of the response. The status
|
||||
// code, and number of bytes written for example.
|
||||
type StatusResponseWriter struct {
|
||||
http.ResponseWriter
|
||||
Code int
|
||||
BytesWritten int64
|
||||
Started time.Time
|
||||
Ttfb time.Duration // Time to first byte
|
||||
GotFirstByte bool
|
||||
WroteHeader Event
|
||||
Hijacked bool
|
||||
}
|
||||
|
||||
var _ interface {
|
||||
http.ResponseWriter
|
||||
http.Hijacker
|
||||
} = (*StatusResponseWriter)(nil)
|
||||
|
||||
func (me *StatusResponseWriter) Write(b []byte) (n int, err error) {
|
||||
// Exactly how it's done in the standard library. This ensures Code is
|
||||
// correct.
|
||||
if !me.WroteHeader.IsSet() {
|
||||
me.WriteHeader(http.StatusOK)
|
||||
}
|
||||
if !me.GotFirstByte && len(b) > 0 {
|
||||
if me.Started.IsZero() {
|
||||
panic("Started was not initialized")
|
||||
}
|
||||
me.Ttfb = time.Since(me.Started)
|
||||
me.GotFirstByte = true
|
||||
}
|
||||
n, err = me.ResponseWriter.Write(b)
|
||||
me.BytesWritten += int64(n)
|
||||
return
|
||||
}
|
||||
|
||||
func (me *StatusResponseWriter) WriteHeader(code int) {
|
||||
me.ResponseWriter.WriteHeader(code)
|
||||
if !me.WroteHeader.IsSet() {
|
||||
me.Code = code
|
||||
me.WroteHeader.Set()
|
||||
}
|
||||
}
|
||||
|
||||
func (me *StatusResponseWriter) Hijack() (c net.Conn, b *bufio.ReadWriter, err error) {
|
||||
me.Hijacked = true
|
||||
c, b, err = me.ResponseWriter.(http.Hijacker).Hijack()
|
||||
if b.Writer.Buffered() != 0 {
|
||||
panic("unexpected buffered writes")
|
||||
}
|
||||
c = responseConn{c, me}
|
||||
return
|
||||
}
|
||||
|
||||
type responseConn struct {
|
||||
net.Conn
|
||||
s *StatusResponseWriter
|
||||
}
|
||||
|
||||
func (me responseConn) Write(b []byte) (n int, err error) {
|
||||
n, err = me.Conn.Write(b)
|
||||
me.s.BytesWritten += int64(n)
|
||||
return
|
||||
}
|
42
vendor/github.com/anacrolix/missinggo/httptoo/accept.go
generated
vendored
Normal file
42
vendor/github.com/anacrolix/missinggo/httptoo/accept.go
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
package httptoo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/anacrolix/missinggo/mime"
|
||||
)
|
||||
|
||||
func ParseAccept(line string) (parsed AcceptDirectives, err error) {
|
||||
dirs := strings.Split(line, ",")
|
||||
for _, d := range dirs {
|
||||
p := AcceptDirective{
|
||||
Q: 1,
|
||||
}
|
||||
ss := strings.Split(d, ";")
|
||||
switch len(ss) {
|
||||
case 2:
|
||||
p.Q, err = strconv.ParseFloat(ss[1], 32)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
case 1:
|
||||
p.MimeType.FromString(ss[0])
|
||||
default:
|
||||
err = fmt.Errorf("error parsing %q", d)
|
||||
return
|
||||
}
|
||||
parsed = append(parsed, p)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type (
|
||||
AcceptDirectives []AcceptDirective
|
||||
AcceptDirective struct {
|
||||
MimeType mime.Type
|
||||
Q float64
|
||||
}
|
||||
)
|
106
vendor/github.com/anacrolix/missinggo/httptoo/bytes_content_range.go
generated
vendored
Normal file
106
vendor/github.com/anacrolix/missinggo/httptoo/bytes_content_range.go
generated
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
package httptoo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type BytesContentRange struct {
|
||||
First, Last, Length int64
|
||||
}
|
||||
|
||||
type BytesRange struct {
|
||||
First, Last int64
|
||||
}
|
||||
|
||||
func (me BytesRange) String() string {
|
||||
if me.Last == math.MaxInt64 {
|
||||
return fmt.Sprintf("bytes=%d-", me.First)
|
||||
}
|
||||
return fmt.Sprintf("bytes=%d-%d", me.First, me.Last)
|
||||
}
|
||||
|
||||
var (
|
||||
httpBytesRangeRegexp = regexp.MustCompile(`bytes[ =](\d+)-(\d*)`)
|
||||
)
|
||||
|
||||
func ParseBytesRange(s string) (ret BytesRange, ok bool) {
|
||||
ss := httpBytesRangeRegexp.FindStringSubmatch(s)
|
||||
if ss == nil {
|
||||
return
|
||||
}
|
||||
var err error
|
||||
ret.First, err = strconv.ParseInt(ss[1], 10, 64)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if ss[2] == "" {
|
||||
ret.Last = math.MaxInt64
|
||||
} else {
|
||||
ret.Last, err = strconv.ParseInt(ss[2], 10, 64)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
ok = true
|
||||
return
|
||||
}
|
||||
|
||||
func parseUnitRanges(s string) (unit, ranges string) {
|
||||
s = strings.TrimSpace(s)
|
||||
i := strings.IndexAny(s, " =")
|
||||
if i == -1 {
|
||||
return
|
||||
}
|
||||
unit = s[:i]
|
||||
ranges = s[i+1:]
|
||||
return
|
||||
}
|
||||
|
||||
func parseFirstLast(s string) (first, last int64) {
|
||||
ss := strings.SplitN(s, "-", 2)
|
||||
first, err := strconv.ParseInt(ss[0], 10, 64)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
last, err = strconv.ParseInt(ss[1], 10, 64)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func parseContentRange(s string) (ret BytesContentRange) {
|
||||
ss := strings.SplitN(s, "/", 2)
|
||||
firstLast := strings.TrimSpace(ss[0])
|
||||
if firstLast == "*" {
|
||||
ret.First = -1
|
||||
ret.Last = -1
|
||||
} else {
|
||||
ret.First, ret.Last = parseFirstLast(firstLast)
|
||||
}
|
||||
il := strings.TrimSpace(ss[1])
|
||||
if il == "*" {
|
||||
ret.Length = -1
|
||||
} else {
|
||||
var err error
|
||||
ret.Length, err = strconv.ParseInt(il, 10, 64)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ParseBytesContentRange(s string) (ret BytesContentRange, ok bool) {
|
||||
unit, ranges := parseUnitRanges(s)
|
||||
if unit != "bytes" {
|
||||
return
|
||||
}
|
||||
ret = parseContentRange(ranges)
|
||||
ok = true
|
||||
return
|
||||
}
|
19
vendor/github.com/anacrolix/missinggo/httptoo/client.go
generated
vendored
Normal file
19
vendor/github.com/anacrolix/missinggo/httptoo/client.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
package httptoo
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Returns the http.Client's TLS Config, traversing and generating any
|
||||
// defaults along the way to get it.
|
||||
func ClientTLSConfig(cl *http.Client) *tls.Config {
|
||||
if cl.Transport == nil {
|
||||
cl.Transport = http.DefaultTransport
|
||||
}
|
||||
tr := cl.Transport.(*http.Transport)
|
||||
if tr.TLSClientConfig == nil {
|
||||
tr.TLSClientConfig = &tls.Config{}
|
||||
}
|
||||
return tr.TLSClientConfig
|
||||
}
|
31
vendor/github.com/anacrolix/missinggo/httptoo/fs.go
generated
vendored
Normal file
31
vendor/github.com/anacrolix/missinggo/httptoo/fs.go
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
package httptoo
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Wraps a http.FileSystem, disabling directory listings, per the commonly
|
||||
// requested feature at https://groups.google.com/forum/#!topic/golang-
|
||||
// nuts/bStLPdIVM6w .
|
||||
type JustFilesFilesystem struct {
|
||||
Fs http.FileSystem
|
||||
}
|
||||
|
||||
func (fs JustFilesFilesystem) Open(name string) (http.File, error) {
|
||||
f, err := fs.Fs.Open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
d, err := f.Stat()
|
||||
if err != nil {
|
||||
f.Close()
|
||||
return nil, err
|
||||
}
|
||||
if d.IsDir() {
|
||||
f.Close()
|
||||
// This triggers http.FileServer to show a 404.
|
||||
return nil, os.ErrNotExist
|
||||
}
|
||||
return f, nil
|
||||
}
|
49
vendor/github.com/anacrolix/missinggo/httptoo/gzip.go
generated
vendored
Normal file
49
vendor/github.com/anacrolix/missinggo/httptoo/gzip.go
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
package httptoo
|
||||
|
||||
import (
|
||||
"compress/gzip"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type gzipResponseWriter struct {
|
||||
io.Writer
|
||||
http.ResponseWriter
|
||||
haveWritten bool
|
||||
}
|
||||
|
||||
var _ http.ResponseWriter = &gzipResponseWriter{}
|
||||
|
||||
func (w *gzipResponseWriter) Write(b []byte) (int, error) {
|
||||
if w.haveWritten {
|
||||
goto write
|
||||
}
|
||||
w.haveWritten = true
|
||||
if w.Header().Get("Content-Type") != "" {
|
||||
goto write
|
||||
}
|
||||
if type_ := http.DetectContentType(b); type_ != "application/octet-stream" {
|
||||
w.Header().Set("Content-Type", type_)
|
||||
}
|
||||
write:
|
||||
return w.Writer.Write(b)
|
||||
}
|
||||
|
||||
// Gzips response body if the request says it'll allow it.
|
||||
func GzipHandler(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") || w.Header().Get("Content-Encoding") != "" || w.Header().Get("Vary") != "" {
|
||||
h.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Encoding", "gzip")
|
||||
w.Header().Set("Vary", "Accept-Encoding")
|
||||
gz := gzip.NewWriter(w)
|
||||
defer gz.Close()
|
||||
h.ServeHTTP(&gzipResponseWriter{
|
||||
Writer: gz,
|
||||
ResponseWriter: w,
|
||||
}, r)
|
||||
})
|
||||
}
|
61
vendor/github.com/anacrolix/missinggo/httptoo/headers.go
generated
vendored
Normal file
61
vendor/github.com/anacrolix/missinggo/httptoo/headers.go
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
package httptoo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Visibility int
|
||||
|
||||
const (
|
||||
Default = 0
|
||||
Public = 1
|
||||
Private = 2
|
||||
)
|
||||
|
||||
type CacheControlHeader struct {
|
||||
MaxAge time.Duration
|
||||
Caching Visibility
|
||||
NoStore bool
|
||||
}
|
||||
|
||||
func (me *CacheControlHeader) caching() []string {
|
||||
switch me.Caching {
|
||||
case Public:
|
||||
return []string{"public"}
|
||||
case Private:
|
||||
return []string{"private"}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (me *CacheControlHeader) maxAge() []string {
|
||||
if me.MaxAge == 0 {
|
||||
return nil
|
||||
}
|
||||
d := me.MaxAge
|
||||
if d < 0 {
|
||||
d = 0
|
||||
}
|
||||
return []string{fmt.Sprintf("max-age=%d", d/time.Second)}
|
||||
}
|
||||
|
||||
func (me *CacheControlHeader) noStore() []string {
|
||||
if me.NoStore {
|
||||
return []string{"no-store"}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (me *CacheControlHeader) concat(sss ...[]string) (ret []string) {
|
||||
for _, ss := range sss {
|
||||
ret = append(ret, ss...)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (me CacheControlHeader) String() string {
|
||||
return strings.Join(me.concat(me.caching(), me.maxAge()), ", ")
|
||||
}
|
42
vendor/github.com/anacrolix/missinggo/httptoo/httptoo.go
generated
vendored
Normal file
42
vendor/github.com/anacrolix/missinggo/httptoo/httptoo.go
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
package httptoo
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/bradfitz/iter"
|
||||
|
||||
"github.com/anacrolix/missinggo"
|
||||
)
|
||||
|
||||
func OriginatingProtocol(r *http.Request) string {
|
||||
if fp := r.Header.Get("X-Forwarded-Proto"); fp != "" {
|
||||
return fp
|
||||
} else if r.TLS != nil {
|
||||
return "https"
|
||||
} else {
|
||||
return "http"
|
||||
}
|
||||
}
|
||||
|
||||
// Clears the named cookie for every domain that leads to the current one.
|
||||
func NukeCookie(w http.ResponseWriter, r *http.Request, name, path string) {
|
||||
parts := strings.Split(missinggo.SplitHostMaybePort(r.Host).Host, ".")
|
||||
for i := range iter.N(len(parts) + 1) { // Include the empty domain.
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: name,
|
||||
MaxAge: -1,
|
||||
Path: path,
|
||||
Domain: strings.Join(parts[i:], "."),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Performs quoted-string from http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html
|
||||
func EncodeQuotedString(s string) string {
|
||||
return strconv.Quote(s)
|
||||
}
|
||||
|
||||
// https://httpstatuses.com/499
|
||||
const StatusClientCancelledRequest = 499
|
112
vendor/github.com/anacrolix/missinggo/httptoo/inproc_roundtrip.go
generated
vendored
Normal file
112
vendor/github.com/anacrolix/missinggo/httptoo/inproc_roundtrip.go
generated
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
package httptoo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
"github.com/anacrolix/missinggo"
|
||||
)
|
||||
|
||||
type responseWriter struct {
|
||||
mu sync.Mutex
|
||||
r http.Response
|
||||
headerWritten missinggo.Event
|
||||
bodyWriter io.WriteCloser
|
||||
bodyClosed missinggo.SynchronizedEvent
|
||||
}
|
||||
|
||||
var _ interface {
|
||||
http.ResponseWriter
|
||||
// We're able to emulate this easily enough.
|
||||
http.CloseNotifier
|
||||
} = &responseWriter{}
|
||||
|
||||
// Use Request.Context.Done instead.
|
||||
func (me *responseWriter) CloseNotify() <-chan bool {
|
||||
ret := make(chan bool, 1)
|
||||
go func() {
|
||||
<-me.bodyClosed.C()
|
||||
ret <- true
|
||||
}()
|
||||
return ret
|
||||
}
|
||||
|
||||
func (me *responseWriter) Header() http.Header {
|
||||
if me.r.Header == nil {
|
||||
me.r.Header = make(http.Header)
|
||||
}
|
||||
return me.r.Header
|
||||
}
|
||||
|
||||
func (me *responseWriter) Write(b []byte) (int, error) {
|
||||
me.mu.Lock()
|
||||
if !me.headerWritten.IsSet() {
|
||||
me.writeHeader(200)
|
||||
}
|
||||
me.mu.Unlock()
|
||||
return me.bodyWriter.Write(b)
|
||||
}
|
||||
|
||||
func (me *responseWriter) WriteHeader(status int) {
|
||||
me.mu.Lock()
|
||||
me.writeHeader(status)
|
||||
me.mu.Unlock()
|
||||
}
|
||||
|
||||
func (me *responseWriter) writeHeader(status int) {
|
||||
if me.headerWritten.IsSet() {
|
||||
return
|
||||
}
|
||||
me.r.StatusCode = status
|
||||
me.headerWritten.Set()
|
||||
}
|
||||
|
||||
func (me *responseWriter) runHandler(h http.Handler, req *http.Request) {
|
||||
var pr *io.PipeReader
|
||||
pr, me.bodyWriter = io.Pipe()
|
||||
me.r.Body = struct {
|
||||
io.Reader
|
||||
io.Closer
|
||||
}{pr, eventCloser{pr, &me.bodyClosed}}
|
||||
// Shouldn't be writing to the response after the handler returns.
|
||||
defer me.bodyWriter.Close()
|
||||
// Send a 200 if nothing was written yet.
|
||||
defer me.WriteHeader(200)
|
||||
// Wrap the context in the given Request with one that closes when either
|
||||
// the handler returns, or the response body is closed.
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
go func() {
|
||||
<-me.bodyClosed.C()
|
||||
cancel()
|
||||
}()
|
||||
h.ServeHTTP(me, req.WithContext(ctx))
|
||||
}
|
||||
|
||||
type eventCloser struct {
|
||||
c io.Closer
|
||||
closed *missinggo.SynchronizedEvent
|
||||
}
|
||||
|
||||
func (me eventCloser) Close() (err error) {
|
||||
err = me.c.Close()
|
||||
me.closed.Set()
|
||||
return
|
||||
}
|
||||
|
||||
func RoundTripHandler(req *http.Request, h http.Handler) (*http.Response, error) {
|
||||
rw := responseWriter{}
|
||||
go rw.runHandler(h, req)
|
||||
<-rw.headerWritten.LockedChan(&rw.mu)
|
||||
return &rw.r, nil
|
||||
}
|
||||
|
||||
type InProcRoundTripper struct {
|
||||
Handler http.Handler
|
||||
}
|
||||
|
||||
func (me *InProcRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
return RoundTripHandler(req, me.Handler)
|
||||
}
|
23
vendor/github.com/anacrolix/missinggo/httptoo/request.go
generated
vendored
Normal file
23
vendor/github.com/anacrolix/missinggo/httptoo/request.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
package httptoo
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
|
||||
"github.com/anacrolix/missinggo"
|
||||
)
|
||||
|
||||
// Request is intended for localhost, either with a localhost name, or
|
||||
// loopback IP.
|
||||
func RequestIsForLocalhost(r *http.Request) bool {
|
||||
hostHost := missinggo.SplitHostMaybePort(r.Host).Host
|
||||
if ip := net.ParseIP(hostHost); ip != nil {
|
||||
return ip.IsLoopback()
|
||||
}
|
||||
return hostHost == "localhost"
|
||||
}
|
||||
|
||||
// Request originated from a loopback IP.
|
||||
func RequestIsFromLocalhost(r *http.Request) bool {
|
||||
return net.ParseIP(missinggo.SplitHostMaybePort(r.RemoteAddr).Host).IsLoopback()
|
||||
}
|
138
vendor/github.com/anacrolix/missinggo/httptoo/reverse_proxy.go
generated
vendored
Normal file
138
vendor/github.com/anacrolix/missinggo/httptoo/reverse_proxy.go
generated
vendored
Normal file
@@ -0,0 +1,138 @@
|
||||
package httptoo
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/gob"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func deepCopy(dst, src interface{}) error {
|
||||
r, w := io.Pipe()
|
||||
e := gob.NewEncoder(w)
|
||||
d := gob.NewDecoder(r)
|
||||
var decErr, encErr error
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
decErr = d.Decode(dst)
|
||||
r.Close()
|
||||
}()
|
||||
encErr = e.Encode(src)
|
||||
// Always returns nil.
|
||||
w.CloseWithError(encErr)
|
||||
wg.Wait()
|
||||
if encErr != nil {
|
||||
return encErr
|
||||
}
|
||||
return decErr
|
||||
}
|
||||
|
||||
// Takes a request, and alters its destination fields, for proxying.
|
||||
func RedirectedRequest(r *http.Request, newUrl string) (ret *http.Request, err error) {
|
||||
u, err := url.Parse(newUrl)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
ret = new(http.Request)
|
||||
*ret = *r
|
||||
ret.Header = nil
|
||||
err = deepCopy(&ret.Header, r.Header)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
ret.URL = u
|
||||
ret.RequestURI = ""
|
||||
return
|
||||
}
|
||||
|
||||
func CopyHeaders(w http.ResponseWriter, r *http.Response) {
|
||||
for h, vs := range r.Header {
|
||||
for _, v := range vs {
|
||||
w.Header().Add(h, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ForwardResponse(w http.ResponseWriter, r *http.Response) {
|
||||
CopyHeaders(w, r)
|
||||
w.WriteHeader(r.StatusCode)
|
||||
// Errors frequently occur writing the body when the client hangs up.
|
||||
io.Copy(w, r.Body)
|
||||
r.Body.Close()
|
||||
}
|
||||
|
||||
func SetOriginRequestForwardingHeaders(o, f *http.Request) {
|
||||
xff := o.Header.Get("X-Forwarded-For")
|
||||
hop, _, _ := net.SplitHostPort(f.RemoteAddr)
|
||||
if xff == "" {
|
||||
xff = hop
|
||||
} else {
|
||||
xff += "," + hop
|
||||
}
|
||||
o.Header.Set("X-Forwarded-For", xff)
|
||||
o.Header.Set("X-Forwarded-Proto", OriginatingProtocol(f))
|
||||
}
|
||||
|
||||
// w is for the client response. r is the request to send to the origin
|
||||
// (already "forwarded"). originUrl is where to send the request.
|
||||
func ReverseProxyUpgrade(w http.ResponseWriter, r *http.Request, originUrl string) (err error) {
|
||||
u, err := url.Parse(originUrl)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
oc, err := net.Dial("tcp", u.Host)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer oc.Close()
|
||||
err = r.Write(oc)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
originConnReadBuffer := bufio.NewReader(oc)
|
||||
originResp, err := http.ReadResponse(originConnReadBuffer, r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if originResp.StatusCode != 101 {
|
||||
ForwardResponse(w, originResp)
|
||||
return
|
||||
}
|
||||
cc, _, err := w.(http.Hijacker).Hijack()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer cc.Close()
|
||||
originResp.Write(cc)
|
||||
go io.Copy(oc, cc)
|
||||
// Let the origin connection control when this routine returns, as we
|
||||
// should trust it more.
|
||||
io.Copy(cc, originConnReadBuffer)
|
||||
return
|
||||
}
|
||||
|
||||
func ReverseProxy(w http.ResponseWriter, r *http.Request, originUrl string, client *http.Client) (err error) {
|
||||
originRequest, err := RedirectedRequest(r, originUrl)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
SetOriginRequestForwardingHeaders(originRequest, r)
|
||||
if r.Header.Get("Connection") == "Upgrade" {
|
||||
return ReverseProxyUpgrade(w, originRequest, originUrl)
|
||||
}
|
||||
rt := client.Transport
|
||||
if rt == nil {
|
||||
rt = http.DefaultTransport
|
||||
}
|
||||
originResp, err := rt.RoundTrip(originRequest)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
ForwardResponse(w, originResp)
|
||||
return
|
||||
}
|
64
vendor/github.com/anacrolix/missinggo/httptoo/url.go
generated
vendored
Normal file
64
vendor/github.com/anacrolix/missinggo/httptoo/url.go
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
package httptoo
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// Deep copies a URL. I could call it DeepCopyURL, but what else would you be
|
||||
// copying when you have a *url.URL? Of note is that the Userinfo is deep
|
||||
// copied. The returned URL shares no references with the original.
|
||||
func CopyURL(u *url.URL) (ret *url.URL) {
|
||||
ret = new(url.URL)
|
||||
*ret = *u
|
||||
if u.User != nil {
|
||||
ret.User = new(url.Userinfo)
|
||||
*ret.User = *u.User
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Reconstructs the URL that would have produced the given Request.
|
||||
// Request.URLs are not fully populated in http.Server handlers.
|
||||
func RequestedURL(r *http.Request) (ret *url.URL) {
|
||||
ret = CopyURL(r.URL)
|
||||
ret.Host = r.Host
|
||||
ret.Scheme = OriginatingProtocol(r)
|
||||
return
|
||||
}
|
||||
|
||||
// The official URL struct parameters, for tracking changes and reference
|
||||
// here.
|
||||
//
|
||||
// Scheme string
|
||||
// Opaque string // encoded opaque data
|
||||
// User *Userinfo // username and password information
|
||||
// Host string // host or host:port
|
||||
// Path string
|
||||
// RawPath string // encoded path hint (Go 1.5 and later only; see EscapedPath method)
|
||||
// ForceQuery bool // append a query ('?') even if RawQuery is empty
|
||||
// RawQuery string // encoded query values, without '?'
|
||||
// Fragment string // fragment for references, without '#'
|
||||
|
||||
// Return the first URL extended with elements of the second, in the manner
|
||||
// that occurs throughout my projects. Noteworthy difference from
|
||||
// url.URL.ResolveReference is that if the reference has a scheme, the base is
|
||||
// not completely ignored.
|
||||
func AppendURL(u, v *url.URL) *url.URL {
|
||||
u = CopyURL(u)
|
||||
clobberString(&u.Scheme, v.Scheme)
|
||||
clobberString(&u.Host, v.Host)
|
||||
u.Path += v.Path
|
||||
q := u.Query()
|
||||
for k, v := range v.Query() {
|
||||
q[k] = append(q[k], v...)
|
||||
}
|
||||
u.RawQuery = q.Encode()
|
||||
return u
|
||||
}
|
||||
|
||||
func clobberString(s *string, value string) {
|
||||
if value != "" {
|
||||
*s = value
|
||||
}
|
||||
}
|
226
vendor/github.com/anacrolix/missinggo/inproc/inproc.go
generated
vendored
Normal file
226
vendor/github.com/anacrolix/missinggo/inproc/inproc.go
generated
vendored
Normal file
@@ -0,0 +1,226 @@
|
||||
package inproc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"math"
|
||||
"net"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/anacrolix/missinggo"
|
||||
)
|
||||
|
||||
var (
|
||||
mu sync.Mutex
|
||||
cond = sync.Cond{L: &mu}
|
||||
nextPort int = 1
|
||||
conns = map[int]*packetConn{}
|
||||
)
|
||||
|
||||
type Addr struct {
|
||||
Port int
|
||||
}
|
||||
|
||||
func (Addr) Network() string {
|
||||
return "inproc"
|
||||
}
|
||||
|
||||
func (me Addr) String() string {
|
||||
return ":" + strconv.FormatInt(int64(me.Port), 10)
|
||||
}
|
||||
|
||||
func getPort() (port int) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
port = nextPort
|
||||
nextPort++
|
||||
return
|
||||
}
|
||||
|
||||
func ResolveAddr(network, str string) (net.Addr, error) {
|
||||
return ResolveInprocAddr(network, str)
|
||||
}
|
||||
|
||||
func ResolveInprocAddr(network, str string) (addr Addr, err error) {
|
||||
if str == "" {
|
||||
addr.Port = getPort()
|
||||
return
|
||||
}
|
||||
_, p, err := net.SplitHostPort(str)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
i64, err := strconv.ParseInt(p, 10, 0)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
addr.Port = int(i64)
|
||||
if addr.Port == 0 {
|
||||
addr.Port = getPort()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ListenPacket(network, addrStr string) (nc net.PacketConn, err error) {
|
||||
addr, err := ResolveInprocAddr(network, addrStr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
if _, ok := conns[addr.Port]; ok {
|
||||
err = errors.New("address in use")
|
||||
return
|
||||
}
|
||||
pc := &packetConn{
|
||||
addr: addr,
|
||||
readDeadline: newCondDeadline(&cond),
|
||||
writeDeadline: newCondDeadline(&cond),
|
||||
}
|
||||
conns[addr.Port] = pc
|
||||
nc = pc
|
||||
return
|
||||
}
|
||||
|
||||
type packet struct {
|
||||
data []byte
|
||||
addr Addr
|
||||
}
|
||||
|
||||
type packetConn struct {
|
||||
closed bool
|
||||
addr Addr
|
||||
reads []packet
|
||||
readDeadline *condDeadline
|
||||
writeDeadline *condDeadline
|
||||
}
|
||||
|
||||
func (me *packetConn) Close() error {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
me.closed = true
|
||||
delete(conns, me.addr.Port)
|
||||
cond.Broadcast()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (me *packetConn) LocalAddr() net.Addr {
|
||||
return me.addr
|
||||
}
|
||||
|
||||
type errTimeout struct{}
|
||||
|
||||
func (errTimeout) Error() string {
|
||||
return "i/o timeout"
|
||||
}
|
||||
|
||||
func (errTimeout) Temporary() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (errTimeout) Timeout() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
var _ net.Error = errTimeout{}
|
||||
|
||||
func (me *packetConn) WriteTo(b []byte, na net.Addr) (n int, err error) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
if me.closed {
|
||||
err = errors.New("closed")
|
||||
return
|
||||
}
|
||||
if me.writeDeadline.exceeded() {
|
||||
err = errTimeout{}
|
||||
return
|
||||
}
|
||||
n = len(b)
|
||||
port := missinggo.AddrPort(na)
|
||||
c, ok := conns[port]
|
||||
if !ok {
|
||||
// log.Printf("no conn for port %d", port)
|
||||
return
|
||||
}
|
||||
c.reads = append(c.reads, packet{append([]byte(nil), b...), me.addr})
|
||||
cond.Broadcast()
|
||||
return
|
||||
}
|
||||
|
||||
func (me *packetConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
for {
|
||||
if len(me.reads) != 0 {
|
||||
r := me.reads[0]
|
||||
me.reads = me.reads[1:]
|
||||
n = copy(b, r.data)
|
||||
addr = r.addr
|
||||
// log.Println(addr)
|
||||
return
|
||||
}
|
||||
if me.closed {
|
||||
err = io.EOF
|
||||
return
|
||||
}
|
||||
if me.readDeadline.exceeded() {
|
||||
err = errTimeout{}
|
||||
return
|
||||
}
|
||||
cond.Wait()
|
||||
}
|
||||
}
|
||||
|
||||
func (me *packetConn) SetDeadline(t time.Time) error {
|
||||
me.writeDeadline.setDeadline(t)
|
||||
me.readDeadline.setDeadline(t)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (me *packetConn) SetReadDeadline(t time.Time) error {
|
||||
me.readDeadline.setDeadline(t)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (me *packetConn) SetWriteDeadline(t time.Time) error {
|
||||
me.writeDeadline.setDeadline(t)
|
||||
return nil
|
||||
}
|
||||
|
||||
func newCondDeadline(cond *sync.Cond) (ret *condDeadline) {
|
||||
ret = &condDeadline{
|
||||
timer: time.AfterFunc(math.MaxInt64, func() {
|
||||
mu.Lock()
|
||||
ret._exceeded = true
|
||||
mu.Unlock()
|
||||
cond.Broadcast()
|
||||
}),
|
||||
}
|
||||
ret.setDeadline(time.Time{})
|
||||
return
|
||||
}
|
||||
|
||||
type condDeadline struct {
|
||||
mu sync.Mutex
|
||||
_exceeded bool
|
||||
timer *time.Timer
|
||||
}
|
||||
|
||||
func (me *condDeadline) setDeadline(t time.Time) {
|
||||
me.mu.Lock()
|
||||
defer me.mu.Unlock()
|
||||
me._exceeded = false
|
||||
if t.IsZero() {
|
||||
me.timer.Stop()
|
||||
return
|
||||
}
|
||||
me.timer.Reset(t.Sub(time.Now()))
|
||||
}
|
||||
|
||||
func (me *condDeadline) exceeded() bool {
|
||||
me.mu.Lock()
|
||||
defer me.mu.Unlock()
|
||||
return me._exceeded
|
||||
}
|
30
vendor/github.com/anacrolix/missinggo/ioutil.go
generated
vendored
Normal file
30
vendor/github.com/anacrolix/missinggo/ioutil.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
package missinggo
|
||||
|
||||
import "io"
|
||||
|
||||
type StatWriter struct {
|
||||
Written int64
|
||||
w io.Writer
|
||||
}
|
||||
|
||||
func (me *StatWriter) Write(b []byte) (n int, err error) {
|
||||
n, err = me.w.Write(b)
|
||||
me.Written += int64(n)
|
||||
return
|
||||
}
|
||||
|
||||
func NewStatWriter(w io.Writer) *StatWriter {
|
||||
return &StatWriter{w: w}
|
||||
}
|
||||
|
||||
var ZeroReader zeroReader
|
||||
|
||||
type zeroReader struct{}
|
||||
|
||||
func (me zeroReader) Read(b []byte) (n int, err error) {
|
||||
for i := range b {
|
||||
b[i] = 0
|
||||
}
|
||||
n = len(b)
|
||||
return
|
||||
}
|
11
vendor/github.com/anacrolix/missinggo/iter/chain.go
generated
vendored
Normal file
11
vendor/github.com/anacrolix/missinggo/iter/chain.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
package iter
|
||||
|
||||
func Chain(fs ...Func) Func {
|
||||
return func(cb Callback) {
|
||||
for _, f := range fs {
|
||||
if !All(cb, f) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
22
vendor/github.com/anacrolix/missinggo/iter/func.go
generated
vendored
Normal file
22
vendor/github.com/anacrolix/missinggo/iter/func.go
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
package iter
|
||||
|
||||
// Callback receives a value and returns true if another value should be
|
||||
// received or false to stop iteration.
|
||||
type Callback func(value interface{}) (more bool)
|
||||
|
||||
// Func iterates by calling Callback for each of its values.
|
||||
type Func func(Callback)
|
||||
|
||||
func All(cb Callback, fs ...Func) bool {
|
||||
for _, f := range fs {
|
||||
all := true
|
||||
f(func(v interface{}) bool {
|
||||
all = all && cb(v)
|
||||
return all
|
||||
})
|
||||
if !all {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
105
vendor/github.com/anacrolix/missinggo/iter/groupby.go
generated
vendored
Normal file
105
vendor/github.com/anacrolix/missinggo/iter/groupby.go
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
package iter
|
||||
|
||||
type groupBy struct {
|
||||
curKey interface{}
|
||||
curKeyOk bool
|
||||
curValue interface{}
|
||||
keyFunc func(interface{}) interface{}
|
||||
input Iterator
|
||||
groupKey interface{}
|
||||
groupKeyOk bool
|
||||
}
|
||||
|
||||
type Group interface {
|
||||
Iterator
|
||||
Key() interface{}
|
||||
}
|
||||
|
||||
type group struct {
|
||||
gb *groupBy
|
||||
key interface{}
|
||||
first bool
|
||||
stopped bool
|
||||
}
|
||||
|
||||
func (me *group) Stop() {
|
||||
me.stopped = true
|
||||
}
|
||||
|
||||
func (me *group) Next() (ok bool) {
|
||||
if me.stopped {
|
||||
return false
|
||||
}
|
||||
if me.first {
|
||||
me.first = false
|
||||
return true
|
||||
}
|
||||
me.gb.advance()
|
||||
if !me.gb.curKeyOk || me.gb.curKey != me.key {
|
||||
me.Stop()
|
||||
return
|
||||
}
|
||||
ok = true
|
||||
return
|
||||
}
|
||||
|
||||
func (me group) Value() (ret interface{}) {
|
||||
if me.stopped {
|
||||
panic("iterator stopped")
|
||||
}
|
||||
ret = me.gb.curValue
|
||||
return
|
||||
}
|
||||
|
||||
func (me group) Key() interface{} {
|
||||
return me.key
|
||||
}
|
||||
|
||||
func (me *groupBy) advance() {
|
||||
me.curKeyOk = me.input.Next()
|
||||
if me.curKeyOk {
|
||||
me.curValue = me.input.Value()
|
||||
me.curKey = me.keyFunc(me.curValue)
|
||||
}
|
||||
}
|
||||
|
||||
func (me *groupBy) Next() (ok bool) {
|
||||
for me.curKey == me.groupKey {
|
||||
ok = me.input.Next()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
me.curValue = me.input.Value()
|
||||
me.curKey = me.keyFunc(me.curValue)
|
||||
me.curKeyOk = true
|
||||
}
|
||||
me.groupKey = me.curKey
|
||||
me.groupKeyOk = true
|
||||
return true
|
||||
}
|
||||
|
||||
func (me *groupBy) Value() (ret interface{}) {
|
||||
return &group{me, me.groupKey, true, false}
|
||||
}
|
||||
|
||||
func (me *groupBy) Stop() {
|
||||
}
|
||||
|
||||
// Allows use of nil as a return from the key func.
|
||||
var uniqueKey = new(int)
|
||||
|
||||
// Group by returns an iterator of iterators over the values of the input
|
||||
// iterator that consecutively return the same value when input to the key
|
||||
// function. Note that repeated calls to each value of the GroupBy Iterator
|
||||
// does not return a new iterator over the values for that key.
|
||||
func GroupBy(input Iterator, keyFunc func(interface{}) interface{}) Iterator {
|
||||
if keyFunc == nil {
|
||||
keyFunc = func(a interface{}) interface{} { return a }
|
||||
}
|
||||
return &groupBy{
|
||||
input: input,
|
||||
keyFunc: keyFunc,
|
||||
groupKey: uniqueKey,
|
||||
curKey: uniqueKey,
|
||||
}
|
||||
}
|
16
vendor/github.com/anacrolix/missinggo/iter/head.go
generated
vendored
Normal file
16
vendor/github.com/anacrolix/missinggo/iter/head.go
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
package iter
|
||||
|
||||
func Head(n int, f Func) Func {
|
||||
return func(cb Callback) {
|
||||
if n <= 0 {
|
||||
return
|
||||
}
|
||||
f(func(v interface{}) bool {
|
||||
n--
|
||||
if !cb(v) {
|
||||
return false
|
||||
}
|
||||
return n > 0
|
||||
})
|
||||
}
|
||||
}
|
69
vendor/github.com/anacrolix/missinggo/iter/iterable.go
generated
vendored
Normal file
69
vendor/github.com/anacrolix/missinggo/iter/iterable.go
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
package iter
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/anacrolix/missinggo"
|
||||
)
|
||||
|
||||
type Iterable interface {
|
||||
Iter(Callback)
|
||||
}
|
||||
|
||||
type iterator struct {
|
||||
it Iterable
|
||||
ch chan interface{}
|
||||
value interface{}
|
||||
ok bool
|
||||
mu sync.Mutex
|
||||
stopped missinggo.Event
|
||||
}
|
||||
|
||||
func NewIterator(it Iterable) (ret *iterator) {
|
||||
ret = &iterator{
|
||||
it: it,
|
||||
ch: make(chan interface{}),
|
||||
}
|
||||
go func() {
|
||||
// Have to do this in a goroutine, because the interface is synchronous.
|
||||
it.Iter(func(value interface{}) bool {
|
||||
select {
|
||||
case ret.ch <- value:
|
||||
return true
|
||||
case <-ret.stopped.LockedChan(&ret.mu):
|
||||
return false
|
||||
}
|
||||
})
|
||||
close(ret.ch)
|
||||
ret.mu.Lock()
|
||||
ret.stopped.Set()
|
||||
ret.mu.Unlock()
|
||||
}()
|
||||
return
|
||||
}
|
||||
|
||||
func (me *iterator) Value() interface{} {
|
||||
if !me.ok {
|
||||
panic("no value")
|
||||
}
|
||||
return me.value
|
||||
}
|
||||
|
||||
func (me *iterator) Next() bool {
|
||||
me.value, me.ok = <-me.ch
|
||||
return me.ok
|
||||
}
|
||||
|
||||
func (me *iterator) Stop() {
|
||||
me.mu.Lock()
|
||||
me.stopped.Set()
|
||||
me.mu.Unlock()
|
||||
}
|
||||
|
||||
func IterableAsSlice(it Iterable) (ret []interface{}) {
|
||||
it.Iter(func(value interface{}) bool {
|
||||
ret = append(ret, value)
|
||||
return true
|
||||
})
|
||||
return
|
||||
}
|
69
vendor/github.com/anacrolix/missinggo/iter/iterator.go
generated
vendored
Normal file
69
vendor/github.com/anacrolix/missinggo/iter/iterator.go
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
package iter
|
||||
|
||||
import "github.com/anacrolix/missinggo/slices"
|
||||
|
||||
type Iterator interface {
|
||||
// Advances to the next value. Returns false if there are no more values.
|
||||
// Must be called before the first value.
|
||||
Next() bool
|
||||
// Returns the current value. Should panic when the iterator is in an
|
||||
// invalid state.
|
||||
Value() interface{}
|
||||
// Ceases iteration prematurely. This should occur implicitly if Next
|
||||
// returns false.
|
||||
Stop()
|
||||
}
|
||||
|
||||
func ToFunc(it Iterator) Func {
|
||||
return func(cb Callback) {
|
||||
defer it.Stop()
|
||||
for it.Next() {
|
||||
if !cb(it.Value()) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type sliceIterator struct {
|
||||
slice []interface{}
|
||||
value interface{}
|
||||
ok bool
|
||||
}
|
||||
|
||||
func (me *sliceIterator) Next() bool {
|
||||
if len(me.slice) == 0 {
|
||||
return false
|
||||
}
|
||||
me.value = me.slice[0]
|
||||
me.slice = me.slice[1:]
|
||||
me.ok = true
|
||||
return true
|
||||
}
|
||||
|
||||
func (me *sliceIterator) Value() interface{} {
|
||||
if !me.ok {
|
||||
panic("no value; call Next")
|
||||
}
|
||||
return me.value
|
||||
}
|
||||
|
||||
func (me *sliceIterator) Stop() {}
|
||||
|
||||
func Slice(a []interface{}) Iterator {
|
||||
return &sliceIterator{
|
||||
slice: a,
|
||||
}
|
||||
}
|
||||
|
||||
func StringIterator(a string) Iterator {
|
||||
return Slice(slices.ToEmptyInterface(a))
|
||||
}
|
||||
|
||||
func ToSlice(f Func) (ret []interface{}) {
|
||||
f(func(v interface{}) bool {
|
||||
ret = append(ret, v)
|
||||
return true
|
||||
})
|
||||
return
|
||||
}
|
42
vendor/github.com/anacrolix/missinggo/iter/iterutils.go
generated
vendored
Normal file
42
vendor/github.com/anacrolix/missinggo/iter/iterutils.go
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
package iter
|
||||
|
||||
import "math/rand"
|
||||
|
||||
type seq struct {
|
||||
i []int
|
||||
}
|
||||
|
||||
// Creates sequence of values from [0, n)
|
||||
func newSeq(n int) seq {
|
||||
return seq{make([]int, n, n)}
|
||||
}
|
||||
|
||||
func (me seq) Index(i int) (ret int) {
|
||||
ret = me.i[i]
|
||||
if ret == 0 {
|
||||
ret = i
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (me seq) Len() int {
|
||||
return len(me.i)
|
||||
}
|
||||
|
||||
// Remove the nth value from the sequence.
|
||||
func (me *seq) DeleteIndex(index int) {
|
||||
me.i[index] = me.Index(me.Len() - 1)
|
||||
me.i = me.i[:me.Len()-1]
|
||||
}
|
||||
|
||||
func ForPerm(n int, callback func(i int) (more bool)) bool {
|
||||
s := newSeq(n)
|
||||
for s.Len() > 0 {
|
||||
r := rand.Intn(s.Len())
|
||||
if !callback(s.Index(r)) {
|
||||
return false
|
||||
}
|
||||
s.DeleteIndex(r)
|
||||
}
|
||||
return true
|
||||
}
|
7
vendor/github.com/anacrolix/missinggo/iter/n.go
generated
vendored
Normal file
7
vendor/github.com/anacrolix/missinggo/iter/n.go
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
package iter
|
||||
|
||||
import "github.com/bradfitz/iter"
|
||||
|
||||
func N(n int) []struct{} {
|
||||
return iter.N(n)
|
||||
}
|
17
vendor/github.com/anacrolix/missinggo/jitter.go
generated
vendored
Normal file
17
vendor/github.com/anacrolix/missinggo/jitter.go
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Returns random duration in the range [average-plusMinus,
|
||||
// average+plusMinus]. Negative plusMinus will likely panic. Be aware that if
|
||||
// plusMinus >= average, you may get a zero or negative Duration. The
|
||||
// distribution function is unspecified, in case I find a more appropriate one
|
||||
// in the future.
|
||||
func JitterDuration(average, plusMinus time.Duration) (ret time.Duration) {
|
||||
ret = average - plusMinus
|
||||
ret += time.Duration(rand.Int63n(2*int64(plusMinus) + 1))
|
||||
return
|
||||
}
|
7
vendor/github.com/anacrolix/missinggo/limitlen.go
generated
vendored
Normal file
7
vendor/github.com/anacrolix/missinggo/limitlen.go
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
package missinggo
|
||||
|
||||
// Sets an upper bound on the len of b. max can be any type that will cast to
|
||||
// int64.
|
||||
func LimitLen(b []byte, max ...interface{}) []byte {
|
||||
return b[:MinInt(len(b), max...)]
|
||||
}
|
18
vendor/github.com/anacrolix/missinggo/mime/mime.go
generated
vendored
Normal file
18
vendor/github.com/anacrolix/missinggo/mime/mime.go
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
package mime
|
||||
|
||||
import "strings"
|
||||
|
||||
type Type struct {
|
||||
Class string
|
||||
Specific string
|
||||
}
|
||||
|
||||
func (t Type) String() string {
|
||||
return t.Class + "/" + t.Specific
|
||||
}
|
||||
|
||||
func (t *Type) FromString(s string) {
|
||||
ss := strings.SplitN(s, "/", 1)
|
||||
t.Class = ss[0]
|
||||
t.Specific = ss[1]
|
||||
}
|
34
vendor/github.com/anacrolix/missinggo/minmax.go
generated
vendored
Normal file
34
vendor/github.com/anacrolix/missinggo/minmax.go
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
package missinggo
|
||||
|
||||
import "reflect"
|
||||
|
||||
func Max(_less interface{}, vals ...interface{}) interface{} {
|
||||
ret := reflect.ValueOf(vals[0])
|
||||
retType := ret.Type()
|
||||
less := reflect.ValueOf(_less)
|
||||
for _, _v := range vals[1:] {
|
||||
v := reflect.ValueOf(_v).Convert(retType)
|
||||
out := less.Call([]reflect.Value{ret, v})
|
||||
if out[0].Bool() {
|
||||
ret = v
|
||||
}
|
||||
}
|
||||
return ret.Interface()
|
||||
}
|
||||
|
||||
func MaxInt(first int64, rest ...interface{}) int64 {
|
||||
return Max(func(l, r interface{}) bool {
|
||||
return l.(int64) < r.(int64)
|
||||
}, append([]interface{}{first}, rest...)...).(int64)
|
||||
}
|
||||
|
||||
func MinInt(first interface{}, rest ...interface{}) int64 {
|
||||
ret := reflect.ValueOf(first).Int()
|
||||
for _, _i := range rest {
|
||||
i := reflect.ValueOf(_i).Int()
|
||||
if i < ret {
|
||||
ret = i
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
44
vendor/github.com/anacrolix/missinggo/monotonic.go
generated
vendored
Normal file
44
vendor/github.com/anacrolix/missinggo/monotonic.go
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Monotonic time represents time since an arbitrary point in the past, where
|
||||
// the concept of now is only ever moving in a positive direction.
|
||||
type MonotonicTime struct {
|
||||
skewedStdTime time.Time
|
||||
}
|
||||
|
||||
func (me MonotonicTime) Sub(other MonotonicTime) time.Duration {
|
||||
return me.skewedStdTime.Sub(other.skewedStdTime)
|
||||
}
|
||||
|
||||
var (
|
||||
stdNowFunc = time.Now
|
||||
monotonicMu sync.Mutex
|
||||
lastStdNow time.Time
|
||||
monotonicSkew time.Duration
|
||||
)
|
||||
|
||||
func skewedStdNow() time.Time {
|
||||
monotonicMu.Lock()
|
||||
defer monotonicMu.Unlock()
|
||||
stdNow := stdNowFunc()
|
||||
if !lastStdNow.IsZero() && stdNow.Before(lastStdNow) {
|
||||
monotonicSkew += lastStdNow.Sub(stdNow)
|
||||
}
|
||||
lastStdNow = stdNow
|
||||
return stdNow.Add(monotonicSkew)
|
||||
}
|
||||
|
||||
// Consecutive calls always produce the same or greater time than previous
|
||||
// calls.
|
||||
func MonotonicNow() MonotonicTime {
|
||||
return MonotonicTime{skewedStdNow()}
|
||||
}
|
||||
|
||||
func MonotonicSince(since MonotonicTime) (ret time.Duration) {
|
||||
return skewedStdNow().Sub(since.skewedStdTime)
|
||||
}
|
7
vendor/github.com/anacrolix/missinggo/net.go
generated
vendored
Normal file
7
vendor/github.com/anacrolix/missinggo/net.go
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
package missinggo
|
||||
|
||||
import "strings"
|
||||
|
||||
func IsAddrInUse(err error) bool {
|
||||
return strings.Contains(err.Error(), "address already in use")
|
||||
}
|
7
vendor/github.com/anacrolix/missinggo/openflags.go
generated
vendored
Normal file
7
vendor/github.com/anacrolix/missinggo/openflags.go
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
const O_ACCMODE = os.O_RDONLY | os.O_WRONLY | os.O_RDWR
|
100
vendor/github.com/anacrolix/missinggo/orderedmap/google_btree.go
generated
vendored
Normal file
100
vendor/github.com/anacrolix/missinggo/orderedmap/google_btree.go
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
package orderedmap
|
||||
|
||||
import (
|
||||
"github.com/google/btree"
|
||||
|
||||
"github.com/anacrolix/missinggo/iter"
|
||||
)
|
||||
|
||||
type GoogleBTree struct {
|
||||
bt *btree.BTree
|
||||
lesser func(l, r interface{}) bool
|
||||
}
|
||||
|
||||
type googleBTreeItem struct {
|
||||
less func(l, r interface{}) bool
|
||||
key interface{}
|
||||
value interface{}
|
||||
}
|
||||
|
||||
func (me googleBTreeItem) Less(right btree.Item) bool {
|
||||
return me.less(me.key, right.(*googleBTreeItem).key)
|
||||
}
|
||||
|
||||
func NewGoogleBTree(lesser func(l, r interface{}) bool) *GoogleBTree {
|
||||
return &GoogleBTree{
|
||||
bt: btree.New(32),
|
||||
lesser: lesser,
|
||||
}
|
||||
}
|
||||
|
||||
func (me *GoogleBTree) Set(key interface{}, value interface{}) {
|
||||
me.bt.ReplaceOrInsert(&googleBTreeItem{me.lesser, key, value})
|
||||
}
|
||||
|
||||
func (me *GoogleBTree) Get(key interface{}) interface{} {
|
||||
ret, _ := me.GetOk(key)
|
||||
return ret
|
||||
}
|
||||
|
||||
func (me *GoogleBTree) GetOk(key interface{}) (interface{}, bool) {
|
||||
item := me.bt.Get(&googleBTreeItem{me.lesser, key, nil})
|
||||
if item == nil {
|
||||
return nil, false
|
||||
}
|
||||
return item.(*googleBTreeItem).value, true
|
||||
}
|
||||
|
||||
type googleBTreeIter struct {
|
||||
i btree.Item
|
||||
bt *btree.BTree
|
||||
}
|
||||
|
||||
func (me *googleBTreeIter) Next() bool {
|
||||
if me.bt == nil {
|
||||
return false
|
||||
}
|
||||
if me.i == nil {
|
||||
me.bt.Ascend(func(i btree.Item) bool {
|
||||
me.i = i
|
||||
return false
|
||||
})
|
||||
} else {
|
||||
var n int
|
||||
me.bt.AscendGreaterOrEqual(me.i, func(i btree.Item) bool {
|
||||
n++
|
||||
if n == 1 {
|
||||
return true
|
||||
}
|
||||
me.i = i
|
||||
return false
|
||||
})
|
||||
if n != 2 {
|
||||
me.i = nil
|
||||
}
|
||||
}
|
||||
return me.i != nil
|
||||
}
|
||||
|
||||
func (me *googleBTreeIter) Value() interface{} {
|
||||
return me.i.(*googleBTreeItem).value
|
||||
}
|
||||
|
||||
func (me *googleBTreeIter) Stop() {
|
||||
me.bt = nil
|
||||
me.i = nil
|
||||
}
|
||||
|
||||
func (me *GoogleBTree) Iter(f iter.Callback) {
|
||||
me.bt.Ascend(func(i btree.Item) bool {
|
||||
return f(i.(*googleBTreeItem).value)
|
||||
})
|
||||
}
|
||||
|
||||
func (me *GoogleBTree) Unset(key interface{}) {
|
||||
me.bt.Delete(&googleBTreeItem{me.lesser, key, nil})
|
||||
}
|
||||
|
||||
func (me *GoogleBTree) Len() int {
|
||||
return me.bt.Len()
|
||||
}
|
16
vendor/github.com/anacrolix/missinggo/orderedmap/orderedmap.go
generated
vendored
Normal file
16
vendor/github.com/anacrolix/missinggo/orderedmap/orderedmap.go
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
package orderedmap
|
||||
|
||||
import "github.com/anacrolix/missinggo/iter"
|
||||
|
||||
func New(lesser func(l, r interface{}) bool) OrderedMap {
|
||||
return NewGoogleBTree(lesser)
|
||||
}
|
||||
|
||||
type OrderedMap interface {
|
||||
Get(key interface{}) interface{}
|
||||
GetOk(key interface{}) (interface{}, bool)
|
||||
iter.Iterable
|
||||
Set(key, value interface{})
|
||||
Unset(key interface{})
|
||||
Len() int
|
||||
}
|
66
vendor/github.com/anacrolix/missinggo/orderedmap/skiplist.go
generated
vendored
Normal file
66
vendor/github.com/anacrolix/missinggo/orderedmap/skiplist.go
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
package orderedmap
|
||||
|
||||
import "github.com/ryszard/goskiplist/skiplist"
|
||||
|
||||
type skiplistOrderedMap struct {
|
||||
sl *skiplist.SkipList
|
||||
}
|
||||
|
||||
func NewSkipList(lesser func(l, r interface{}) bool) *skiplistOrderedMap {
|
||||
return &skiplistOrderedMap{skiplist.NewCustomMap(lesser)}
|
||||
}
|
||||
|
||||
func (me *skiplistOrderedMap) Set(key interface{}, value interface{}) {
|
||||
me.sl.Set(key, value)
|
||||
}
|
||||
|
||||
func (me *skiplistOrderedMap) Get(key interface{}) interface{} {
|
||||
if me == nil {
|
||||
return nil
|
||||
}
|
||||
ret, _ := me.sl.Get(key)
|
||||
return ret
|
||||
}
|
||||
|
||||
func (me *skiplistOrderedMap) GetOk(key interface{}) (interface{}, bool) {
|
||||
if me == nil {
|
||||
return nil, false
|
||||
}
|
||||
return me.sl.Get(key)
|
||||
}
|
||||
|
||||
type Iter struct {
|
||||
it skiplist.Iterator
|
||||
}
|
||||
|
||||
func (me *Iter) Next() bool {
|
||||
if me == nil {
|
||||
return false
|
||||
}
|
||||
return me.it.Next()
|
||||
}
|
||||
|
||||
func (me *Iter) Value() interface{} {
|
||||
return me.it.Value()
|
||||
}
|
||||
|
||||
func (me *skiplistOrderedMap) Iter() *Iter {
|
||||
if me == nil {
|
||||
return nil
|
||||
}
|
||||
return &Iter{me.sl.Iterator()}
|
||||
}
|
||||
|
||||
func (me *skiplistOrderedMap) Unset(key interface{}) {
|
||||
if me == nil {
|
||||
return
|
||||
}
|
||||
me.sl.Delete(key)
|
||||
}
|
||||
|
||||
func (me *skiplistOrderedMap) Len() int {
|
||||
if me.sl == nil {
|
||||
return 0
|
||||
}
|
||||
return me.sl.Len()
|
||||
}
|
20
vendor/github.com/anacrolix/missinggo/path.go
generated
vendored
Normal file
20
vendor/github.com/anacrolix/missinggo/path.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
)
|
||||
|
||||
// Splits the pathname p into Root and Ext, such that Root+Ext==p.
|
||||
func PathSplitExt(p string) (ret struct {
|
||||
Root, Ext string
|
||||
}) {
|
||||
ret.Ext = path.Ext(p)
|
||||
ret.Root = p[:len(p)-len(ret.Ext)]
|
||||
return
|
||||
}
|
||||
|
||||
func FilePathExists(p string) bool {
|
||||
_, err := os.Stat(p)
|
||||
return err == nil
|
||||
}
|
38
vendor/github.com/anacrolix/missinggo/perf/event.go
generated
vendored
Normal file
38
vendor/github.com/anacrolix/missinggo/perf/event.go
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
package perf
|
||||
|
||||
import (
|
||||
"math"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Event struct {
|
||||
Mu sync.RWMutex
|
||||
Count int64
|
||||
Total time.Duration
|
||||
Min time.Duration
|
||||
Max time.Duration
|
||||
}
|
||||
|
||||
func (e *Event) Add(t time.Duration) {
|
||||
e.Mu.Lock()
|
||||
defer e.Mu.Unlock()
|
||||
if t > e.Max {
|
||||
e.Max = t
|
||||
}
|
||||
if t < e.Min {
|
||||
e.Min = t
|
||||
}
|
||||
e.Count++
|
||||
e.Total += t
|
||||
}
|
||||
|
||||
func (e *Event) MeanTime() time.Duration {
|
||||
e.Mu.RLock()
|
||||
defer e.Mu.RUnlock()
|
||||
return e.Total / time.Duration(e.Count)
|
||||
}
|
||||
|
||||
func (e *Event) Init() {
|
||||
e.Min = math.MaxInt64
|
||||
}
|
47
vendor/github.com/anacrolix/missinggo/perf/events.go
generated
vendored
Normal file
47
vendor/github.com/anacrolix/missinggo/perf/events.go
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
package perf
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"sort"
|
||||
"sync"
|
||||
"text/tabwriter"
|
||||
)
|
||||
|
||||
var (
|
||||
mu sync.RWMutex
|
||||
events = map[string]*Event{}
|
||||
)
|
||||
|
||||
func init() {
|
||||
http.HandleFunc("/debug/perf", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/plain; charset=UTF-8")
|
||||
WriteEventsTable(w)
|
||||
})
|
||||
}
|
||||
|
||||
func WriteEventsTable(w io.Writer) {
|
||||
tw := tabwriter.NewWriter(w, 0, 0, 2, ' ', 0)
|
||||
fmt.Fprint(tw, "description\ttotal\tcount\tmin\tmean\tmax\n")
|
||||
type t struct {
|
||||
d string
|
||||
e Event
|
||||
}
|
||||
mu.RLock()
|
||||
es := make([]t, 0, len(events))
|
||||
for d, e := range events {
|
||||
e.Mu.RLock()
|
||||
es = append(es, t{d, *e})
|
||||
e.Mu.RUnlock()
|
||||
}
|
||||
mu.RUnlock()
|
||||
sort.Slice(es, func(i, j int) bool {
|
||||
return es[i].e.Total > es[j].e.Total
|
||||
})
|
||||
for _, el := range es {
|
||||
e := el.e
|
||||
fmt.Fprintf(tw, "%s\t%v\t%v\t%v\t%v\t%v\n", el.d, e.Total, e.Count, e.Min, e.MeanTime(), e.Max)
|
||||
}
|
||||
tw.Flush()
|
||||
}
|
48
vendor/github.com/anacrolix/missinggo/perf/mutex.go
generated
vendored
Normal file
48
vendor/github.com/anacrolix/missinggo/perf/mutex.go
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
package perf
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/anacrolix/missinggo"
|
||||
)
|
||||
|
||||
type TimedLocker struct {
|
||||
L sync.Locker
|
||||
Desc string
|
||||
}
|
||||
|
||||
func (me *TimedLocker) Lock() {
|
||||
tr := NewTimer()
|
||||
me.L.Lock()
|
||||
tr.Mark(me.Desc)
|
||||
}
|
||||
|
||||
func (me *TimedLocker) Unlock() {
|
||||
me.L.Unlock()
|
||||
}
|
||||
|
||||
type TimedRWLocker struct {
|
||||
RWL missinggo.RWLocker
|
||||
WriteDesc string
|
||||
ReadDesc string
|
||||
}
|
||||
|
||||
func (me *TimedRWLocker) Lock() {
|
||||
tr := NewTimer()
|
||||
me.RWL.Lock()
|
||||
tr.Mark(me.WriteDesc)
|
||||
}
|
||||
|
||||
func (me *TimedRWLocker) Unlock() {
|
||||
me.RWL.Unlock()
|
||||
}
|
||||
|
||||
func (me *TimedRWLocker) RLock() {
|
||||
tr := NewTimer()
|
||||
me.RWL.RLock()
|
||||
tr.Mark(me.ReadDesc)
|
||||
}
|
||||
|
||||
func (me *TimedRWLocker) RUnlock() {
|
||||
me.RWL.RUnlock()
|
||||
}
|
39
vendor/github.com/anacrolix/missinggo/perf/scope.go
generated
vendored
Normal file
39
vendor/github.com/anacrolix/missinggo/perf/scope.go
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
package perf
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func ScopeTimer(opts ...timerOpt) func() {
|
||||
t := NewTimer(CallerName(1))
|
||||
return func() { t.Mark("returned") }
|
||||
}
|
||||
|
||||
func ScopeTimerOk(ok *bool) func() {
|
||||
t := NewTimer(CallerName(1))
|
||||
return func() { t.MarkOk(*ok) }
|
||||
}
|
||||
|
||||
func ScopeTimerErr(err *error) func() {
|
||||
t := NewTimer(CallerName(1))
|
||||
return func() {
|
||||
r := recover()
|
||||
if r != nil {
|
||||
t.Mark("panic")
|
||||
panic(r)
|
||||
}
|
||||
t.MarkErr(*err)
|
||||
}
|
||||
}
|
||||
|
||||
func CallerName(skip int) timerOpt {
|
||||
return Name(getCallerName(skip))
|
||||
}
|
||||
|
||||
func getCallerName(skip int) string {
|
||||
var pc [1]uintptr
|
||||
runtime.Callers(3+skip, pc[:])
|
||||
fs := runtime.CallersFrames(pc[:])
|
||||
f, _ := fs.Next()
|
||||
return f.Func.Name()
|
||||
}
|
104
vendor/github.com/anacrolix/missinggo/perf/timer.go
generated
vendored
Normal file
104
vendor/github.com/anacrolix/missinggo/perf/timer.go
generated
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
package perf
|
||||
|
||||
import (
|
||||
"log"
|
||||
"runtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Timer struct {
|
||||
started time.Time
|
||||
log bool
|
||||
name string
|
||||
marked bool
|
||||
}
|
||||
|
||||
func NewTimer(opts ...timerOpt) (t *Timer) {
|
||||
t = &Timer{
|
||||
started: time.Now(),
|
||||
}
|
||||
for _, o := range opts {
|
||||
o(t)
|
||||
}
|
||||
if t.log && t.name != "" {
|
||||
log.Printf("starting timer %q", t.name)
|
||||
}
|
||||
runtime.SetFinalizer(t, func(t *Timer) {
|
||||
if t.marked {
|
||||
return
|
||||
}
|
||||
log.Printf("timer %#v was never marked", t)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
type timerOpt func(*Timer)
|
||||
|
||||
func Log(t *Timer) {
|
||||
t.log = true
|
||||
}
|
||||
|
||||
func Name(name string) func(*Timer) {
|
||||
return func(t *Timer) {
|
||||
t.name = name
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Timer) Mark(events ...string) time.Duration {
|
||||
d := time.Since(t.started)
|
||||
if len(events) == 0 {
|
||||
if t.name == "" {
|
||||
panic("no name or events specified")
|
||||
}
|
||||
t.addDuration(t.name, d)
|
||||
} else {
|
||||
for _, e := range events {
|
||||
if t.name != "" {
|
||||
e = t.name + "/" + e
|
||||
}
|
||||
t.addDuration(e, d)
|
||||
}
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func (t *Timer) MarkOk(ok bool) {
|
||||
if ok {
|
||||
t.Mark("ok")
|
||||
} else {
|
||||
t.Mark("not ok")
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Timer) MarkErr(err error) {
|
||||
if err == nil {
|
||||
t.Mark("success")
|
||||
} else {
|
||||
t.Mark("error")
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Timer) addDuration(desc string, d time.Duration) {
|
||||
t.marked = true
|
||||
mu.RLock()
|
||||
e := events[desc]
|
||||
mu.RUnlock()
|
||||
if e == nil {
|
||||
mu.Lock()
|
||||
e = events[desc]
|
||||
if e == nil {
|
||||
e = new(Event)
|
||||
e.Init()
|
||||
events[desc] = e
|
||||
}
|
||||
mu.Unlock()
|
||||
}
|
||||
e.Add(d)
|
||||
if t.log {
|
||||
if t.name != "" {
|
||||
log.Printf("timer %q got event %q after %s", t.name, desc, d)
|
||||
} else {
|
||||
log.Printf("marking event %q after %s", desc, d)
|
||||
}
|
||||
}
|
||||
}
|
97
vendor/github.com/anacrolix/missinggo/pproffd/pproffd.go
generated
vendored
Normal file
97
vendor/github.com/anacrolix/missinggo/pproffd/pproffd.go
generated
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
// Package pproffd is for detecting resource leaks due to unclosed handles.
|
||||
package pproffd
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"runtime/pprof"
|
||||
)
|
||||
|
||||
const enabled = false
|
||||
|
||||
var p *pprof.Profile
|
||||
|
||||
func init() {
|
||||
if enabled {
|
||||
p = pprof.NewProfile("fds")
|
||||
}
|
||||
}
|
||||
|
||||
type fd int
|
||||
|
||||
func (me *fd) Closed() {
|
||||
p.Remove(me)
|
||||
}
|
||||
|
||||
func add(skip int) (ret *fd) {
|
||||
ret = new(fd)
|
||||
p.Add(ret, skip+2)
|
||||
return
|
||||
}
|
||||
|
||||
type closeWrapper struct {
|
||||
fd *fd
|
||||
c io.Closer
|
||||
}
|
||||
|
||||
func (me closeWrapper) Close() error {
|
||||
me.fd.Closed()
|
||||
return me.c.Close()
|
||||
}
|
||||
|
||||
func newCloseWrapper(c io.Closer) closeWrapper {
|
||||
return closeWrapper{
|
||||
fd: add(2),
|
||||
c: c,
|
||||
}
|
||||
}
|
||||
|
||||
type wrappedNetConn struct {
|
||||
net.Conn
|
||||
closeWrapper
|
||||
}
|
||||
|
||||
func (me wrappedNetConn) Close() error {
|
||||
return me.closeWrapper.Close()
|
||||
}
|
||||
|
||||
// Tracks a net.Conn until Close() is explicitly called.
|
||||
func WrapNetConn(nc net.Conn) net.Conn {
|
||||
if !enabled {
|
||||
return nc
|
||||
}
|
||||
if nc == nil {
|
||||
return nil
|
||||
}
|
||||
return wrappedNetConn{
|
||||
nc,
|
||||
newCloseWrapper(nc),
|
||||
}
|
||||
}
|
||||
|
||||
type OSFile interface {
|
||||
io.Reader
|
||||
io.Seeker
|
||||
io.Closer
|
||||
io.Writer
|
||||
Stat() (os.FileInfo, error)
|
||||
io.ReaderAt
|
||||
io.WriterAt
|
||||
}
|
||||
|
||||
type wrappedOSFile struct {
|
||||
*os.File
|
||||
closeWrapper
|
||||
}
|
||||
|
||||
func (me wrappedOSFile) Close() error {
|
||||
return me.closeWrapper.Close()
|
||||
}
|
||||
|
||||
func WrapOSFile(f *os.File) OSFile {
|
||||
if !enabled {
|
||||
return f
|
||||
}
|
||||
return &wrappedOSFile{f, newCloseWrapper(f)}
|
||||
}
|
178
vendor/github.com/anacrolix/missinggo/prioritybitmap/prioritybitmap.go
generated
vendored
Normal file
178
vendor/github.com/anacrolix/missinggo/prioritybitmap/prioritybitmap.go
generated
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
// Package prioritybitmap implements a set of integers ordered by attached
|
||||
// priorities.
|
||||
package prioritybitmap
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/anacrolix/missinggo/bitmap"
|
||||
"github.com/anacrolix/missinggo/iter"
|
||||
"github.com/anacrolix/missinggo/orderedmap"
|
||||
)
|
||||
|
||||
var (
|
||||
bitSets = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return make(map[int]struct{}, 1)
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// Maintains set of ints ordered by priority.
|
||||
type PriorityBitmap struct {
|
||||
mu sync.Mutex
|
||||
// From priority to singleton or set of bit indices.
|
||||
om orderedmap.OrderedMap
|
||||
// From bit index to priority
|
||||
priorities map[int]int
|
||||
}
|
||||
|
||||
var _ bitmap.Interface = (*PriorityBitmap)(nil)
|
||||
|
||||
func (me *PriorityBitmap) Contains(bit int) bool {
|
||||
_, ok := me.priorities[bit]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (me *PriorityBitmap) Len() int {
|
||||
return len(me.priorities)
|
||||
}
|
||||
|
||||
func (me *PriorityBitmap) Clear() {
|
||||
me.om = nil
|
||||
me.priorities = nil
|
||||
}
|
||||
|
||||
func (me *PriorityBitmap) deleteBit(bit int) (priority int, ok bool) {
|
||||
priority, ok = me.priorities[bit]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
switch v := me.om.Get(priority).(type) {
|
||||
case int:
|
||||
if v != bit {
|
||||
panic("invariant broken")
|
||||
}
|
||||
case map[int]struct{}:
|
||||
if _, ok := v[bit]; !ok {
|
||||
panic("invariant broken")
|
||||
}
|
||||
delete(v, bit)
|
||||
if len(v) != 0 {
|
||||
return
|
||||
}
|
||||
bitSets.Put(v)
|
||||
}
|
||||
me.om.Unset(priority)
|
||||
if me.om.Len() == 0 {
|
||||
me.om = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func bitLess(l, r interface{}) bool {
|
||||
return l.(int) < r.(int)
|
||||
}
|
||||
|
||||
func (me *PriorityBitmap) lazyInit() {
|
||||
me.om = orderedmap.New(func(l, r interface{}) bool {
|
||||
return l.(int) < r.(int)
|
||||
})
|
||||
me.priorities = make(map[int]int)
|
||||
}
|
||||
|
||||
// Returns true if the priority is changed, or the bit wasn't present.
|
||||
func (me *PriorityBitmap) Set(bit int, priority int) bool {
|
||||
if p, ok := me.priorities[bit]; ok && p == priority {
|
||||
return false
|
||||
}
|
||||
if oldPriority, deleted := me.deleteBit(bit); deleted && oldPriority == priority {
|
||||
panic("should have already returned")
|
||||
}
|
||||
if me.priorities == nil {
|
||||
me.priorities = make(map[int]int)
|
||||
}
|
||||
me.priorities[bit] = priority
|
||||
if me.om == nil {
|
||||
me.om = orderedmap.New(bitLess)
|
||||
}
|
||||
_v, ok := me.om.GetOk(priority)
|
||||
if !ok {
|
||||
// No other bits with this priority, set it to a lone int.
|
||||
me.om.Set(priority, bit)
|
||||
return true
|
||||
}
|
||||
switch v := _v.(type) {
|
||||
case int:
|
||||
newV := bitSets.Get().(map[int]struct{})
|
||||
newV[v] = struct{}{}
|
||||
newV[bit] = struct{}{}
|
||||
me.om.Set(priority, newV)
|
||||
case map[int]struct{}:
|
||||
v[bit] = struct{}{}
|
||||
default:
|
||||
panic(v)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (me *PriorityBitmap) Remove(bit int) bool {
|
||||
me.mu.Lock()
|
||||
defer me.mu.Unlock()
|
||||
if _, ok := me.deleteBit(bit); !ok {
|
||||
return false
|
||||
}
|
||||
delete(me.priorities, bit)
|
||||
if len(me.priorities) == 0 {
|
||||
me.priorities = nil
|
||||
}
|
||||
if me.om != nil && me.om.Len() == 0 {
|
||||
me.om = nil
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (me *PriorityBitmap) Iter(f iter.Callback) {
|
||||
me.IterTyped(func(i int) bool {
|
||||
return f(i)
|
||||
})
|
||||
}
|
||||
|
||||
func (me *PriorityBitmap) IterTyped(_f func(i bitmap.BitIndex) bool) bool {
|
||||
me.mu.Lock()
|
||||
defer me.mu.Unlock()
|
||||
if me == nil || me.om == nil {
|
||||
return true
|
||||
}
|
||||
f := func(i int) bool {
|
||||
me.mu.Unlock()
|
||||
defer me.mu.Lock()
|
||||
return _f(i)
|
||||
}
|
||||
return iter.All(func(value interface{}) bool {
|
||||
switch v := value.(type) {
|
||||
case int:
|
||||
return f(v)
|
||||
case map[int]struct{}:
|
||||
for i := range v {
|
||||
if !f(i) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}, me.om.Iter)
|
||||
}
|
||||
|
||||
func (me *PriorityBitmap) IsEmpty() bool {
|
||||
if me.om == nil {
|
||||
return true
|
||||
}
|
||||
return me.om.Len() == 0
|
||||
}
|
||||
|
||||
// ok is false if the bit is not set.
|
||||
func (me *PriorityBitmap) GetPriority(bit int) (prio int, ok bool) {
|
||||
prio, ok = me.priorities[bit]
|
||||
return
|
||||
}
|
117
vendor/github.com/anacrolix/missinggo/pubsub/pubsub.go
generated
vendored
Normal file
117
vendor/github.com/anacrolix/missinggo/pubsub/pubsub.go
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
package pubsub
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
type PubSub struct {
|
||||
mu sync.Mutex
|
||||
next chan item
|
||||
closed bool
|
||||
}
|
||||
|
||||
type item struct {
|
||||
value interface{}
|
||||
next chan item
|
||||
}
|
||||
|
||||
type Subscription struct {
|
||||
next chan item
|
||||
Values chan interface{}
|
||||
mu sync.Mutex
|
||||
closed chan struct{}
|
||||
}
|
||||
|
||||
func NewPubSub() (ret *PubSub) {
|
||||
return new(PubSub)
|
||||
}
|
||||
|
||||
func (me *PubSub) init() {
|
||||
me.next = make(chan item, 1)
|
||||
}
|
||||
|
||||
func (me *PubSub) lazyInit() {
|
||||
me.mu.Lock()
|
||||
defer me.mu.Unlock()
|
||||
if me.closed {
|
||||
return
|
||||
}
|
||||
if me.next == nil {
|
||||
me.init()
|
||||
}
|
||||
}
|
||||
|
||||
func (me *PubSub) Publish(v interface{}) {
|
||||
me.lazyInit()
|
||||
next := make(chan item, 1)
|
||||
i := item{v, next}
|
||||
me.mu.Lock()
|
||||
if !me.closed {
|
||||
me.next <- i
|
||||
me.next = next
|
||||
}
|
||||
me.mu.Unlock()
|
||||
}
|
||||
|
||||
func (me *Subscription) Close() {
|
||||
me.mu.Lock()
|
||||
defer me.mu.Unlock()
|
||||
select {
|
||||
case <-me.closed:
|
||||
default:
|
||||
close(me.closed)
|
||||
}
|
||||
}
|
||||
|
||||
func (me *Subscription) runner() {
|
||||
defer close(me.Values)
|
||||
for {
|
||||
select {
|
||||
case i, ok := <-me.next:
|
||||
if !ok {
|
||||
me.Close()
|
||||
return
|
||||
}
|
||||
// Send the value back into the channel for someone else. This
|
||||
// won't block because the channel has a capacity of 1, and this
|
||||
// is currently the only copy of this value being sent to this
|
||||
// channel.
|
||||
me.next <- i
|
||||
// The next value comes from the channel given to us by the value
|
||||
// we just got.
|
||||
me.next = i.next
|
||||
select {
|
||||
case me.Values <- i.value:
|
||||
case <-me.closed:
|
||||
return
|
||||
}
|
||||
case <-me.closed:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (me *PubSub) Subscribe() (ret *Subscription) {
|
||||
me.lazyInit()
|
||||
ret = &Subscription{
|
||||
closed: make(chan struct{}),
|
||||
Values: make(chan interface{}),
|
||||
}
|
||||
me.mu.Lock()
|
||||
ret.next = me.next
|
||||
me.mu.Unlock()
|
||||
go ret.runner()
|
||||
return
|
||||
}
|
||||
|
||||
func (me *PubSub) Close() {
|
||||
me.mu.Lock()
|
||||
defer me.mu.Unlock()
|
||||
if me.closed {
|
||||
return
|
||||
}
|
||||
if me.next != nil {
|
||||
close(me.next)
|
||||
}
|
||||
me.closed = true
|
||||
}
|
16
vendor/github.com/anacrolix/missinggo/reader_context.go
generated
vendored
Normal file
16
vendor/github.com/anacrolix/missinggo/reader_context.go
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
package missinggo
|
||||
|
||||
import "context"
|
||||
|
||||
type ContextedReader struct {
|
||||
R ReadContexter
|
||||
Ctx context.Context
|
||||
}
|
||||
|
||||
func (me ContextedReader) Read(b []byte) (int, error) {
|
||||
return me.R.ReadContext(me.Ctx, b)
|
||||
}
|
||||
|
||||
type ReadContexter interface {
|
||||
ReadContext(context.Context, []byte) (int, error)
|
||||
}
|
196
vendor/github.com/anacrolix/missinggo/resource/http.go
generated
vendored
Normal file
196
vendor/github.com/anacrolix/missinggo/resource/http.go
generated
vendored
Normal file
@@ -0,0 +1,196 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Provides access to resources through a http.Client.
|
||||
type HTTPProvider struct {
|
||||
Client *http.Client
|
||||
}
|
||||
|
||||
var _ Provider = &HTTPProvider{}
|
||||
|
||||
func (me *HTTPProvider) NewInstance(urlStr string) (r Instance, err error) {
|
||||
_r := new(httpInstance)
|
||||
_r.URL, err = url.Parse(urlStr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_r.Client = me.Client
|
||||
if _r.Client == nil {
|
||||
_r.Client = http.DefaultClient
|
||||
}
|
||||
r = _r
|
||||
return
|
||||
}
|
||||
|
||||
type httpInstance struct {
|
||||
Client *http.Client
|
||||
URL *url.URL
|
||||
}
|
||||
|
||||
var _ Instance = &httpInstance{}
|
||||
|
||||
func mustNewRequest(method, urlStr string, body io.Reader) *http.Request {
|
||||
req, err := http.NewRequest(method, urlStr, body)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return req
|
||||
}
|
||||
|
||||
func responseError(r *http.Response) error {
|
||||
if r.StatusCode == http.StatusNotFound {
|
||||
return os.ErrNotExist
|
||||
}
|
||||
return errors.New(r.Status)
|
||||
}
|
||||
|
||||
func (me *httpInstance) Get() (ret io.ReadCloser, err error) {
|
||||
resp, err := me.Client.Get(me.URL.String())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if resp.StatusCode == http.StatusOK {
|
||||
ret = resp.Body
|
||||
return
|
||||
}
|
||||
resp.Body.Close()
|
||||
err = responseError(resp)
|
||||
return
|
||||
}
|
||||
|
||||
func (me *httpInstance) Put(r io.Reader) (err error) {
|
||||
resp, err := me.Client.Do(mustNewRequest("PUT", me.URL.String(), r))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
resp.Body.Close()
|
||||
if resp.StatusCode == http.StatusOK {
|
||||
return
|
||||
}
|
||||
err = responseError(resp)
|
||||
return
|
||||
}
|
||||
|
||||
func (me *httpInstance) ReadAt(b []byte, off int64) (n int, err error) {
|
||||
req := mustNewRequest("GET", me.URL.String(), nil)
|
||||
req.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", off, off+int64(len(b))-1))
|
||||
resp, err := me.Client.Do(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
switch resp.StatusCode {
|
||||
case http.StatusPartialContent:
|
||||
case http.StatusRequestedRangeNotSatisfiable:
|
||||
err = io.EOF
|
||||
return
|
||||
default:
|
||||
err = responseError(resp)
|
||||
return
|
||||
}
|
||||
// TODO: This will crash if ContentLength was not provided (-1). Do
|
||||
// something about that.
|
||||
b = b[:resp.ContentLength]
|
||||
return io.ReadFull(resp.Body, b)
|
||||
}
|
||||
|
||||
func (me *httpInstance) WriteAt(b []byte, off int64) (n int, err error) {
|
||||
req := mustNewRequest("PATCH", me.URL.String(), bytes.NewReader(b))
|
||||
req.ContentLength = int64(len(b))
|
||||
req.Header.Set("Content-Range", fmt.Sprintf("bytes=%d-%d", off, off+int64(len(b))-1))
|
||||
resp, err := me.Client.Do(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
err = responseError(resp)
|
||||
}
|
||||
n = len(b)
|
||||
return
|
||||
}
|
||||
|
||||
func (me *httpInstance) Stat() (fi os.FileInfo, err error) {
|
||||
resp, err := me.Client.Head(me.URL.String())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
resp.Body.Close()
|
||||
if resp.StatusCode == http.StatusNotFound {
|
||||
err = os.ErrNotExist
|
||||
return
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
err = errors.New(resp.Status)
|
||||
return
|
||||
}
|
||||
var _fi httpFileInfo
|
||||
if h := resp.Header.Get("Last-Modified"); h != "" {
|
||||
_fi.lastModified, err = time.Parse(http.TimeFormat, h)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("error parsing Last-Modified header: %s", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
if h := resp.Header.Get("Content-Length"); h != "" {
|
||||
_fi.contentLength, err = strconv.ParseInt(h, 10, 64)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("error parsing Content-Length header: %s", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
fi = _fi
|
||||
return
|
||||
}
|
||||
|
||||
func (me *httpInstance) Delete() (err error) {
|
||||
resp, err := me.Client.Do(mustNewRequest("DELETE", me.URL.String(), nil))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = responseError(resp)
|
||||
resp.Body.Close()
|
||||
return
|
||||
}
|
||||
|
||||
type httpFileInfo struct {
|
||||
lastModified time.Time
|
||||
contentLength int64
|
||||
}
|
||||
|
||||
var _ os.FileInfo = httpFileInfo{}
|
||||
|
||||
func (fi httpFileInfo) IsDir() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (fi httpFileInfo) Mode() os.FileMode {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (fi httpFileInfo) Name() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (fi httpFileInfo) Size() int64 {
|
||||
return fi.contentLength
|
||||
}
|
||||
|
||||
func (fi httpFileInfo) ModTime() time.Time {
|
||||
return fi.lastModified
|
||||
}
|
||||
|
||||
func (fi httpFileInfo) Sys() interface{} {
|
||||
return nil
|
||||
}
|
61
vendor/github.com/anacrolix/missinggo/resource/osfile.go
generated
vendored
Normal file
61
vendor/github.com/anacrolix/missinggo/resource/osfile.go
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Provides access to resources through the native OS filesystem.
|
||||
type OSFileProvider struct{}
|
||||
|
||||
var _ Provider = OSFileProvider{}
|
||||
|
||||
func (me OSFileProvider) NewInstance(filePath string) (r Instance, err error) {
|
||||
return &osFileInstance{filePath}, nil
|
||||
}
|
||||
|
||||
type osFileInstance struct {
|
||||
path string
|
||||
}
|
||||
|
||||
var _ Instance = &osFileInstance{}
|
||||
|
||||
func (me *osFileInstance) Get() (ret io.ReadCloser, err error) {
|
||||
return os.Open(me.path)
|
||||
}
|
||||
|
||||
func (me *osFileInstance) Put(r io.Reader) (err error) {
|
||||
f, err := os.OpenFile(me.path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0640)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
_, err = io.Copy(f, r)
|
||||
return
|
||||
}
|
||||
|
||||
func (me *osFileInstance) ReadAt(b []byte, off int64) (n int, err error) {
|
||||
f, err := os.Open(me.path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
return f.ReadAt(b, off)
|
||||
}
|
||||
|
||||
func (me *osFileInstance) WriteAt(b []byte, off int64) (n int, err error) {
|
||||
f, err := os.OpenFile(me.path, os.O_CREATE|os.O_WRONLY, 0640)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
return f.WriteAt(b, off)
|
||||
}
|
||||
|
||||
func (me *osFileInstance) Stat() (fi os.FileInfo, err error) {
|
||||
return os.Stat(me.path)
|
||||
}
|
||||
|
||||
func (me *osFileInstance) Delete() error {
|
||||
return os.Remove(me.path)
|
||||
}
|
21
vendor/github.com/anacrolix/missinggo/resource/provider.go
generated
vendored
Normal file
21
vendor/github.com/anacrolix/missinggo/resource/provider.go
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
package resource
|
||||
|
||||
type Provider interface {
|
||||
NewInstance(string) (Instance, error)
|
||||
}
|
||||
|
||||
// TranslatedProvider manipulates resource locations, so as to allow
|
||||
// sandboxing, or relative paths for example.
|
||||
type TranslatedProvider struct {
|
||||
// The underlying Provider.
|
||||
BaseProvider Provider
|
||||
// Some location used in calculating final locations.
|
||||
BaseLocation string
|
||||
// Function that takes BaseLocation, and the caller location and returns
|
||||
// the location to be used with the BaseProvider.
|
||||
JoinLocations func(base, rel string) string
|
||||
}
|
||||
|
||||
func (me *TranslatedProvider) NewInstance(rel string) (Instance, error) {
|
||||
return me.BaseProvider.NewInstance(me.JoinLocations(me.BaseLocation, rel))
|
||||
}
|
46
vendor/github.com/anacrolix/missinggo/resource/resource.go
generated
vendored
Normal file
46
vendor/github.com/anacrolix/missinggo/resource/resource.go
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
// An Instance represents the content at some location accessed through some
|
||||
// Provider. It's the data at some URL.
|
||||
type Instance interface {
|
||||
Get() (io.ReadCloser, error)
|
||||
Put(io.Reader) error
|
||||
Stat() (os.FileInfo, error)
|
||||
ReadAt([]byte, int64) (int, error)
|
||||
WriteAt([]byte, int64) (int, error)
|
||||
Delete() error
|
||||
}
|
||||
|
||||
// Creates a io.ReadSeeker to an Instance.
|
||||
func ReadSeeker(r Instance) io.ReadSeeker {
|
||||
fi, err := r.Stat()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return io.NewSectionReader(r, 0, fi.Size())
|
||||
}
|
||||
|
||||
// Move instance content, deleting the source if it succeeds.
|
||||
func Move(from, to Instance) (err error) {
|
||||
rc, err := from.Get()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer rc.Close()
|
||||
err = to.Put(rc)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
from.Delete()
|
||||
return
|
||||
}
|
||||
|
||||
func Exists(i Instance) bool {
|
||||
_, err := i.Stat()
|
||||
return err == nil
|
||||
}
|
46
vendor/github.com/anacrolix/missinggo/rle.go
generated
vendored
Normal file
46
vendor/github.com/anacrolix/missinggo/rle.go
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
package missinggo
|
||||
|
||||
// A RunLengthEncoder counts successive duplicate elements and emits the
|
||||
// element and the run length when the element changes or the encoder is
|
||||
// flushed.
|
||||
type RunLengthEncoder interface {
|
||||
// Add a series of identical elements to the stream.
|
||||
Append(element interface{}, count uint64)
|
||||
// Emit the current element and its count if non-zero without waiting for
|
||||
// the element to change.
|
||||
Flush()
|
||||
}
|
||||
|
||||
type runLengthEncoder struct {
|
||||
eachRun func(element interface{}, count uint64)
|
||||
element interface{}
|
||||
count uint64
|
||||
}
|
||||
|
||||
// Creates a new RunLengthEncoder. eachRun is called when an element and its
|
||||
// count is emitted, per the RunLengthEncoder interface.
|
||||
func NewRunLengthEncoder(eachRun func(element interface{}, count uint64)) RunLengthEncoder {
|
||||
return &runLengthEncoder{
|
||||
eachRun: eachRun,
|
||||
}
|
||||
}
|
||||
|
||||
func (me *runLengthEncoder) Append(element interface{}, count uint64) {
|
||||
if element == me.element {
|
||||
me.count += count
|
||||
return
|
||||
}
|
||||
if me.count != 0 {
|
||||
me.eachRun(me.element, me.count)
|
||||
}
|
||||
me.count = count
|
||||
me.element = element
|
||||
}
|
||||
|
||||
func (me *runLengthEncoder) Flush() {
|
||||
if me.count == 0 {
|
||||
return
|
||||
}
|
||||
me.eachRun(me.element, me.count)
|
||||
me.count = 0
|
||||
}
|
75
vendor/github.com/anacrolix/missinggo/section_read_seeker.go
generated
vendored
Normal file
75
vendor/github.com/anacrolix/missinggo/section_read_seeker.go
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
type sectionReadSeeker struct {
|
||||
base io.ReadSeeker
|
||||
off, size int64
|
||||
}
|
||||
|
||||
type ReadSeekContexter interface {
|
||||
io.ReadSeeker
|
||||
ReadContexter
|
||||
}
|
||||
|
||||
// Returns a ReadSeeker on a section of another ReadSeeker.
|
||||
func NewSectionReadSeeker(base io.ReadSeeker, off, size int64) (ret ReadSeekContexter) {
|
||||
ret = §ionReadSeeker{
|
||||
base: base,
|
||||
off: off,
|
||||
size: size,
|
||||
}
|
||||
seekOff, err := ret.Seek(0, io.SeekStart)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if seekOff != 0 {
|
||||
panic(seekOff)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (me *sectionReadSeeker) Seek(off int64, whence int) (ret int64, err error) {
|
||||
switch whence {
|
||||
case io.SeekStart:
|
||||
off += me.off
|
||||
case io.SeekCurrent:
|
||||
case io.SeekEnd:
|
||||
off += me.off + me.size
|
||||
whence = io.SeekStart
|
||||
default:
|
||||
err = fmt.Errorf("unhandled whence: %d", whence)
|
||||
return
|
||||
}
|
||||
ret, err = me.base.Seek(off, whence)
|
||||
ret -= me.off
|
||||
return
|
||||
}
|
||||
|
||||
func (me *sectionReadSeeker) ReadContext(ctx context.Context, b []byte) (int, error) {
|
||||
off, err := me.Seek(0, io.SeekCurrent)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
left := me.size - off
|
||||
if left <= 0 {
|
||||
return 0, io.EOF
|
||||
}
|
||||
b = LimitLen(b, left)
|
||||
if rc, ok := me.base.(ReadContexter); ok {
|
||||
return rc.ReadContext(ctx, b)
|
||||
}
|
||||
if ctx != context.Background() {
|
||||
// Can't handle cancellation.
|
||||
panic(ctx)
|
||||
}
|
||||
return me.base.Read(b)
|
||||
}
|
||||
|
||||
func (me *sectionReadSeeker) Read(b []byte) (int, error) {
|
||||
return me.ReadContext(context.Background(), b)
|
||||
}
|
23
vendor/github.com/anacrolix/missinggo/section_writer.go
generated
vendored
Normal file
23
vendor/github.com/anacrolix/missinggo/section_writer.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
package missinggo
|
||||
|
||||
import "io"
|
||||
|
||||
type SectionWriter struct {
|
||||
w io.WriterAt
|
||||
off, len int64
|
||||
}
|
||||
|
||||
func NewSectionWriter(w io.WriterAt, off, len int64) *SectionWriter {
|
||||
return &SectionWriter{w, off, len}
|
||||
}
|
||||
|
||||
func (me *SectionWriter) WriteAt(b []byte, off int64) (n int, err error) {
|
||||
if off >= me.len {
|
||||
err = io.EOF
|
||||
return
|
||||
}
|
||||
if off+int64(len(b)) > me.len {
|
||||
b = b[:me.len-off]
|
||||
}
|
||||
return me.w.WriteAt(b, me.off+off)
|
||||
}
|
60
vendor/github.com/anacrolix/missinggo/selfcert.go
generated
vendored
Normal file
60
vendor/github.com/anacrolix/missinggo/selfcert.go
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"log"
|
||||
"math/big"
|
||||
"time"
|
||||
)
|
||||
|
||||
func publicKey(priv interface{}) interface{} {
|
||||
switch k := priv.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
return &k.PublicKey
|
||||
case *ecdsa.PrivateKey:
|
||||
return &k.PublicKey
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Creates a self-signed certificate in memory for use with tls.Config.
|
||||
func NewSelfSignedCertificate() (cert tls.Certificate, err error) {
|
||||
cert.PrivateKey, err = rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
notBefore := time.Now()
|
||||
notAfter := notBefore.Add(365 * 24 * time.Hour)
|
||||
|
||||
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
|
||||
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to generate serial number: %s", err)
|
||||
}
|
||||
|
||||
template := x509.Certificate{
|
||||
SerialNumber: serialNumber,
|
||||
Subject: pkix.Name{
|
||||
Organization: []string{"Acme Co"},
|
||||
},
|
||||
NotBefore: notBefore,
|
||||
NotAfter: notAfter,
|
||||
|
||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||
BasicConstraintsValid: true,
|
||||
}
|
||||
|
||||
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(cert.PrivateKey), cert.PrivateKey)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create certificate: %s", err)
|
||||
}
|
||||
cert.Certificate = [][]byte{derBytes}
|
||||
return
|
||||
}
|
49
vendor/github.com/anacrolix/missinggo/singleflight.go
generated
vendored
Normal file
49
vendor/github.com/anacrolix/missinggo/singleflight.go
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
package missinggo
|
||||
|
||||
import "sync"
|
||||
|
||||
type ongoing struct {
|
||||
do sync.Mutex
|
||||
users int
|
||||
}
|
||||
|
||||
type SingleFlight struct {
|
||||
mu sync.Mutex
|
||||
ongoing map[string]*ongoing
|
||||
}
|
||||
|
||||
type Operation struct {
|
||||
sf *SingleFlight
|
||||
id string
|
||||
}
|
||||
|
||||
func (op Operation) Unlock() {
|
||||
op.sf.Unlock(op.id)
|
||||
}
|
||||
|
||||
func (me *SingleFlight) Lock(id string) Operation {
|
||||
me.mu.Lock()
|
||||
on, ok := me.ongoing[id]
|
||||
if !ok {
|
||||
on = new(ongoing)
|
||||
if me.ongoing == nil {
|
||||
me.ongoing = make(map[string]*ongoing)
|
||||
}
|
||||
me.ongoing[id] = on
|
||||
}
|
||||
on.users++
|
||||
me.mu.Unlock()
|
||||
on.do.Lock()
|
||||
return Operation{me, id}
|
||||
}
|
||||
|
||||
func (me *SingleFlight) Unlock(id string) {
|
||||
me.mu.Lock()
|
||||
on := me.ongoing[id]
|
||||
on.do.Unlock()
|
||||
on.users--
|
||||
if on.users == 0 {
|
||||
delete(me.ongoing, id)
|
||||
}
|
||||
me.mu.Unlock()
|
||||
}
|
46
vendor/github.com/anacrolix/missinggo/slices/cast.go
generated
vendored
Normal file
46
vendor/github.com/anacrolix/missinggo/slices/cast.go
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
package slices
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/bradfitz/iter"
|
||||
)
|
||||
|
||||
// Returns a copy of all the elements of slice []T as a slice of interface{}.
|
||||
func ToEmptyInterface(slice interface{}) (ret []interface{}) {
|
||||
v := reflect.ValueOf(slice)
|
||||
l := v.Len()
|
||||
ret = make([]interface{}, 0, l)
|
||||
for i := range iter.N(v.Len()) {
|
||||
ret = append(ret, v.Index(i).Interface())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Makes and sets a slice at *ptrTo, and type asserts all the elements from
|
||||
// from to it.
|
||||
func MakeInto(ptrTo interface{}, from interface{}) {
|
||||
fromSliceValue := reflect.ValueOf(from)
|
||||
fromLen := fromSliceValue.Len()
|
||||
if fromLen == 0 {
|
||||
return
|
||||
}
|
||||
// Deref the pointer to slice.
|
||||
slicePtrValue := reflect.ValueOf(ptrTo)
|
||||
if slicePtrValue.Kind() != reflect.Ptr {
|
||||
panic("destination is not a pointer")
|
||||
}
|
||||
destSliceValue := slicePtrValue.Elem()
|
||||
// The type of the elements of the destination slice.
|
||||
destSliceElemType := destSliceValue.Type().Elem()
|
||||
destSliceValue.Set(reflect.MakeSlice(destSliceValue.Type(), fromLen, fromLen))
|
||||
for i := range iter.N(fromSliceValue.Len()) {
|
||||
// The value inside the interface in the slice element.
|
||||
itemValue := fromSliceValue.Index(i)
|
||||
if itemValue.Kind() == reflect.Interface {
|
||||
itemValue = itemValue.Elem()
|
||||
}
|
||||
convertedItem := itemValue.Convert(destSliceElemType)
|
||||
destSliceValue.Index(i).Set(convertedItem)
|
||||
}
|
||||
}
|
5
vendor/github.com/anacrolix/missinggo/slices/doc.go
generated
vendored
Normal file
5
vendor/github.com/anacrolix/missinggo/slices/doc.go
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
// Package slices has several utilities for operating on slices given Go's
|
||||
// lack of generic types. Many functions take an argument of type func(l, r T)
|
||||
// bool, that's expected to compute l < r where T is T in []T, the type of the
|
||||
// given slice.
|
||||
package slices
|
17
vendor/github.com/anacrolix/missinggo/slices/filter.go
generated
vendored
Normal file
17
vendor/github.com/anacrolix/missinggo/slices/filter.go
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
package slices
|
||||
|
||||
import "reflect"
|
||||
|
||||
// sl []T, f is func(*T) bool.
|
||||
func FilterInPlace(sl interface{}, f interface{}) {
|
||||
v := reflect.ValueOf(sl).Elem()
|
||||
j := 0
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
e := v.Index(i)
|
||||
if reflect.ValueOf(f).Call([]reflect.Value{e.Addr()})[0].Bool() {
|
||||
v.Index(j).Set(e)
|
||||
j++
|
||||
}
|
||||
}
|
||||
v.SetLen(j)
|
||||
}
|
49
vendor/github.com/anacrolix/missinggo/slices/map.go
generated
vendored
Normal file
49
vendor/github.com/anacrolix/missinggo/slices/map.go
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
package slices
|
||||
|
||||
import "reflect"
|
||||
|
||||
type MapItem struct {
|
||||
Key, Elem interface{}
|
||||
}
|
||||
|
||||
// Creates a []struct{Key K; Value V} for map[K]V.
|
||||
func FromMap(m interface{}) (slice []MapItem) {
|
||||
mapValue := reflect.ValueOf(m)
|
||||
for _, key := range mapValue.MapKeys() {
|
||||
slice = append(slice, MapItem{key.Interface(), mapValue.MapIndex(key).Interface()})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Returns all the elements []T, from m where m is map[K]T.
|
||||
func FromMapElems(m interface{}) interface{} {
|
||||
inValue := reflect.ValueOf(m)
|
||||
outValue := reflect.MakeSlice(reflect.SliceOf(inValue.Type().Elem()), inValue.Len(), inValue.Len())
|
||||
for i, key := range inValue.MapKeys() {
|
||||
outValue.Index(i).Set(inValue.MapIndex(key))
|
||||
}
|
||||
return outValue.Interface()
|
||||
}
|
||||
|
||||
// Returns all the elements []K, from m where m is map[K]T.
|
||||
func FromMapKeys(m interface{}) interface{} {
|
||||
inValue := reflect.ValueOf(m)
|
||||
outValue := reflect.MakeSlice(reflect.SliceOf(inValue.Type().Key()), inValue.Len(), inValue.Len())
|
||||
for i, key := range inValue.MapKeys() {
|
||||
outValue.Index(i).Set(key)
|
||||
}
|
||||
return outValue.Interface()
|
||||
}
|
||||
|
||||
// f: (T)T, input: []T, outout: []T
|
||||
func Map(f, input interface{}) interface{} {
|
||||
inputValue := reflect.ValueOf(input)
|
||||
funcValue := reflect.ValueOf(f)
|
||||
_len := inputValue.Len()
|
||||
retValue := reflect.MakeSlice(reflect.TypeOf(input), _len, _len)
|
||||
for i := 0; i < _len; i++ {
|
||||
out := funcValue.Call([]reflect.Value{inputValue.Index(i)})
|
||||
retValue.Index(i).Set(out[0])
|
||||
}
|
||||
return retValue.Interface()
|
||||
}
|
36
vendor/github.com/anacrolix/missinggo/slices/sort.go
generated
vendored
Normal file
36
vendor/github.com/anacrolix/missinggo/slices/sort.go
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
package slices
|
||||
|
||||
import (
|
||||
"container/heap"
|
||||
"reflect"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// Sorts the slice in place. Returns sl for convenience.
|
||||
func Sort(sl interface{}, less interface{}) interface{} {
|
||||
sorter := sorter{
|
||||
sl: reflect.ValueOf(sl),
|
||||
less: reflect.ValueOf(less),
|
||||
}
|
||||
sort.Sort(&sorter)
|
||||
return sorter.sl.Interface()
|
||||
}
|
||||
|
||||
// Creates a modifiable copy of a slice reference. Because you can't modify
|
||||
// non-pointer types inside an interface{}.
|
||||
func addressableSlice(slice interface{}) reflect.Value {
|
||||
v := reflect.ValueOf(slice)
|
||||
p := reflect.New(v.Type())
|
||||
p.Elem().Set(v)
|
||||
return p.Elem()
|
||||
}
|
||||
|
||||
// Returns a "container/heap".Interface for the provided slice.
|
||||
func HeapInterface(sl interface{}, less interface{}) heap.Interface {
|
||||
ret := &sorter{
|
||||
sl: addressableSlice(sl),
|
||||
less: reflect.ValueOf(less),
|
||||
}
|
||||
heap.Init(ret)
|
||||
return ret
|
||||
}
|
36
vendor/github.com/anacrolix/missinggo/slices/sorter.go
generated
vendored
Normal file
36
vendor/github.com/anacrolix/missinggo/slices/sorter.go
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
package slices
|
||||
|
||||
import "reflect"
|
||||
|
||||
type sorter struct {
|
||||
sl reflect.Value
|
||||
less reflect.Value
|
||||
}
|
||||
|
||||
func (s *sorter) Len() int {
|
||||
return s.sl.Len()
|
||||
}
|
||||
|
||||
func (s *sorter) Less(i, j int) bool {
|
||||
return s.less.Call([]reflect.Value{
|
||||
s.sl.Index(i),
|
||||
s.sl.Index(j),
|
||||
})[0].Bool()
|
||||
}
|
||||
|
||||
func (s *sorter) Swap(i, j int) {
|
||||
t := reflect.New(s.sl.Type().Elem()).Elem()
|
||||
t.Set(s.sl.Index(i))
|
||||
s.sl.Index(i).Set(s.sl.Index(j))
|
||||
s.sl.Index(j).Set(t)
|
||||
}
|
||||
|
||||
func (s *sorter) Pop() interface{} {
|
||||
ret := s.sl.Index(s.sl.Len() - 1).Interface()
|
||||
s.sl.SetLen(s.sl.Len() - 1)
|
||||
return ret
|
||||
}
|
||||
|
||||
func (s *sorter) Push(val interface{}) {
|
||||
s.sl = reflect.Append(s.sl, reflect.ValueOf(val))
|
||||
}
|
17
vendor/github.com/anacrolix/missinggo/sqlite.go
generated
vendored
Normal file
17
vendor/github.com/anacrolix/missinggo/sqlite.go
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"time"
|
||||
)
|
||||
|
||||
type SqliteTime time.Time
|
||||
|
||||
var _ sql.Scanner = (*SqliteTime)(nil)
|
||||
|
||||
func (me *SqliteTime) Scan(src interface{}) error {
|
||||
var tt time.Time
|
||||
tt, err := time.Parse("2006-01-02 15:04:05", string(src.([]byte)))
|
||||
*me = SqliteTime(tt)
|
||||
return err
|
||||
}
|
23
vendor/github.com/anacrolix/missinggo/stack.go
generated
vendored
Normal file
23
vendor/github.com/anacrolix/missinggo/stack.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func WriteStack(w io.Writer, stack []uintptr) {
|
||||
for _, pc := range stack {
|
||||
if pc == 0 {
|
||||
break
|
||||
}
|
||||
pc--
|
||||
f := runtime.FuncForPC(pc)
|
||||
if f.Name() == "runtime.goexit" {
|
||||
continue
|
||||
}
|
||||
file, line := f.FileLine(pc)
|
||||
fmt.Fprintf(w, "# %s:\t%s:%d\n", f.Name(), file, line)
|
||||
}
|
||||
fmt.Fprintf(w, "\n")
|
||||
}
|
25
vendor/github.com/anacrolix/missinggo/strbool.go
generated
vendored
Normal file
25
vendor/github.com/anacrolix/missinggo/strbool.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
func StringTruth(s string) (ret bool) {
|
||||
s = strings.TrimFunc(s, func(r rune) bool {
|
||||
return r == 0 || unicode.IsSpace(r)
|
||||
})
|
||||
if s == "" {
|
||||
return false
|
||||
}
|
||||
ret, err := strconv.ParseBool(s)
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
i, err := strconv.ParseInt(s, 0, 0)
|
||||
if err == nil {
|
||||
return i != 0
|
||||
}
|
||||
return true
|
||||
}
|
11
vendor/github.com/anacrolix/missinggo/strcase.go
generated
vendored
Normal file
11
vendor/github.com/anacrolix/missinggo/strcase.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/huandu/xstrings"
|
||||
)
|
||||
|
||||
func KebabCase(s string) string {
|
||||
return strings.Replace(xstrings.ToSnakeCase(s), "_", "-", -1)
|
||||
}
|
11
vendor/github.com/anacrolix/missinggo/sync.go
generated
vendored
Normal file
11
vendor/github.com/anacrolix/missinggo/sync.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
type RWLocker interface {
|
||||
sync.Locker
|
||||
RLock()
|
||||
RUnlock()
|
||||
}
|
25
vendor/github.com/anacrolix/missinggo/testing.go
generated
vendored
Normal file
25
vendor/github.com/anacrolix/missinggo/testing.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// It will be the one and only identifier after a package specifier.
|
||||
var testNameRegexp = regexp.MustCompile(`\.(Test[\p{L}_\p{N}]*)`)
|
||||
|
||||
// Returns the name of the test function from the call stack. See
|
||||
// http://stackoverflow.com/q/35535635/149482 for another method.
|
||||
func GetTestName() string {
|
||||
pc := make([]uintptr, 32)
|
||||
n := runtime.Callers(0, pc)
|
||||
for i := 0; i < n; i++ {
|
||||
name := runtime.FuncForPC(pc[i]).Name()
|
||||
ms := testNameRegexp.FindStringSubmatch(name)
|
||||
if ms == nil {
|
||||
continue
|
||||
}
|
||||
return ms[1]
|
||||
}
|
||||
panic("test name could not be recovered")
|
||||
}
|
15
vendor/github.com/anacrolix/missinggo/timer.go
generated
vendored
Normal file
15
vendor/github.com/anacrolix/missinggo/timer.go
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"math"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Returns a time.Timer that calls f. The timer is initially stopped.
|
||||
func StoppedFuncTimer(f func()) (t *time.Timer) {
|
||||
t = time.AfterFunc(math.MaxInt64, f)
|
||||
if !t.Stop() {
|
||||
panic("timer already fired")
|
||||
}
|
||||
return
|
||||
}
|
32
vendor/github.com/anacrolix/missinggo/tls.go
generated
vendored
Normal file
32
vendor/github.com/anacrolix/missinggo/tls.go
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Select the best named certificate per the usual behaviour if
|
||||
// c.GetCertificate is nil, and c.NameToCertificate is not.
|
||||
func BestNamedCertificate(c *tls.Config, clientHello *tls.ClientHelloInfo) (*tls.Certificate, bool) {
|
||||
name := strings.ToLower(clientHello.ServerName)
|
||||
for len(name) > 0 && name[len(name)-1] == '.' {
|
||||
name = name[:len(name)-1]
|
||||
}
|
||||
|
||||
if cert, ok := c.NameToCertificate[name]; ok {
|
||||
return cert, true
|
||||
}
|
||||
|
||||
// try replacing labels in the name with wildcards until we get a
|
||||
// match.
|
||||
labels := strings.Split(name, ".")
|
||||
for i := range labels {
|
||||
labels[i] = "*"
|
||||
candidate := strings.Join(labels, ".")
|
||||
if cert, ok := c.NameToCertificate[candidate]; ok {
|
||||
return cert, true
|
||||
}
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
3
vendor/github.com/anacrolix/missinggo/units.go
generated
vendored
Normal file
3
vendor/github.com/anacrolix/missinggo/units.go
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
package missinggo
|
||||
|
||||
const MiB = 1 << 20
|
42
vendor/github.com/anacrolix/missinggo/url.go
generated
vendored
Normal file
42
vendor/github.com/anacrolix/missinggo/url.go
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"path"
|
||||
)
|
||||
|
||||
// Returns URL opaque as an unrooted path.
|
||||
func URLOpaquePath(u *url.URL) string {
|
||||
if u.Opaque != "" {
|
||||
return u.Opaque
|
||||
}
|
||||
return u.Path
|
||||
}
|
||||
|
||||
// Cleans the (absolute) URL path, removing unnecessary . and .. elements. See
|
||||
// "net/http".cleanPath.
|
||||
func CleanURLPath(p string) string {
|
||||
if p == "" {
|
||||
return "/"
|
||||
}
|
||||
if p[0] != '/' {
|
||||
p = "/" + p
|
||||
}
|
||||
cp := path.Clean(p)
|
||||
// Add the trailing slash back, as it's relevant to a URL.
|
||||
if p[len(p)-1] == '/' && cp != "/" {
|
||||
cp += "/"
|
||||
}
|
||||
return cp
|
||||
}
|
||||
|
||||
func URLJoinSubPath(base, rel string) string {
|
||||
baseURL, err := url.Parse(base)
|
||||
if err != nil {
|
||||
// Honey badger doesn't give a fuck.
|
||||
panic(err)
|
||||
}
|
||||
rel = CleanURLPath(rel)
|
||||
baseURL.Path = path.Join(baseURL.Path, rel)
|
||||
return baseURL.String()
|
||||
}
|
19
vendor/github.com/anacrolix/missinggo/wait_event.go
generated
vendored
Normal file
19
vendor/github.com/anacrolix/missinggo/wait_event.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func WaitEvents(l sync.Locker, evs ...*Event) {
|
||||
cases := make([]reflect.SelectCase, 0, len(evs))
|
||||
for _, ev := range evs {
|
||||
cases = append(cases, reflect.SelectCase{
|
||||
Dir: reflect.SelectRecv,
|
||||
Chan: reflect.ValueOf(ev.C()),
|
||||
})
|
||||
}
|
||||
l.Unlock()
|
||||
reflect.Select(cases)
|
||||
l.Lock()
|
||||
}
|
51
vendor/github.com/anacrolix/missinggo/wolf.go
generated
vendored
Normal file
51
vendor/github.com/anacrolix/missinggo/wolf.go
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"log"
|
||||
"runtime"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
const debug = false
|
||||
|
||||
// A Wolf represents some event that becomes less and less interesting as it
|
||||
// occurs. Call CryHeard to see if we should pay attention this time.
|
||||
type Wolf struct {
|
||||
cries uint64
|
||||
}
|
||||
|
||||
// Returns true less and less often. Convenient for exponentially decreasing
|
||||
// the amount of noise due to errors.
|
||||
func (me *Wolf) CryHeard() bool {
|
||||
n := atomic.AddUint64(&me.cries, 1)
|
||||
return n&(n-1) == 0
|
||||
}
|
||||
|
||||
var (
|
||||
mu sync.Mutex
|
||||
wolves map[uintptr]*Wolf
|
||||
)
|
||||
|
||||
// Calls CryHeard() on a Wolf that is unique to the callers program counter.
|
||||
// i.e. every CryHeard() expression has its own Wolf.
|
||||
func CryHeard() bool {
|
||||
pc, file, line, ok := runtime.Caller(1)
|
||||
if debug {
|
||||
log.Println(pc, file, line, ok)
|
||||
}
|
||||
if !ok {
|
||||
return true
|
||||
}
|
||||
mu.Lock()
|
||||
if wolves == nil {
|
||||
wolves = make(map[uintptr]*Wolf)
|
||||
}
|
||||
w, ok := wolves[pc]
|
||||
if !ok {
|
||||
w = new(Wolf)
|
||||
wolves[pc] = w
|
||||
}
|
||||
mu.Unlock()
|
||||
return w.CryHeard()
|
||||
}
|
8
vendor/github.com/anacrolix/missinggo/x/panic.go
generated
vendored
Normal file
8
vendor/github.com/anacrolix/missinggo/x/panic.go
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
package x
|
||||
|
||||
// Panic if error. Just fucking add exceptions, please.
|
||||
func Pie(err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user