This commit is contained in:
2018-11-04 15:58:15 +01:00
commit f956bcee28
1178 changed files with 584552 additions and 0 deletions

21
vendor/github.com/anacrolix/missinggo/LICENSE generated vendored Normal file
View 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
View File

@@ -0,0 +1,4 @@
# missinggo
[![GoDoc](https://godoc.org/github.com/anacrolix/missinggo?status.svg)](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
View 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
View 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
View 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))
}

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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()
}
}

View 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
View 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)
}
}

View 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
View 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
View 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
View 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
View 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
}

View 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
}

View 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
}
)

View 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
}

View 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
View 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
View 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)
})
}

View 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()), ", ")
}

View 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

View 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)
}

View 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()
}

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
}

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File

@@ -0,0 +1,7 @@
package missinggo
import (
"os"
)
const O_ACCMODE = os.O_RDONLY | os.O_WRONLY | os.O_RDWR

View 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()
}

View 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
}

View 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
View 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
View 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
View 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
View 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
View 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
View 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)
}
}
}

View 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)}
}

View 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
View 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
}

View 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
View 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
}

View 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)
}

View 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))
}

View 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
View 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
}

View 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 = &sectionReadSeeker{
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)
}

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File

@@ -0,0 +1,3 @@
package missinggo
const MiB = 1 << 20

42
vendor/github.com/anacrolix/missinggo/url.go generated vendored Normal file
View 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
View 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
View 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
View File

@@ -0,0 +1,8 @@
package x
// Panic if error. Just fucking add exceptions, please.
func Pie(err error) {
if err != nil {
panic(err)
}
}