21
vendor/github.com/anacrolix/missinggo/v2/LICENSE
generated
vendored
Normal file
21
vendor/github.com/anacrolix/missinggo/v2/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/v2/README.md
generated
vendored
Normal file
4
vendor/github.com/anacrolix/missinggo/v2/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/v2/addr.go
generated
vendored
Normal file
44
vendor/github.com/anacrolix/missinggo/v2/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/v2/atime.go
generated
vendored
Normal file
11
vendor/github.com/anacrolix/missinggo/v2/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/v2/atime_atim.go
generated
vendored
Normal file
14
vendor/github.com/anacrolix/missinggo/v2/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))
|
||||
}
|
||||
15
vendor/github.com/anacrolix/missinggo/v2/atime_atimespec.go
generated
vendored
Normal file
15
vendor/github.com/anacrolix/missinggo/v2/atime_atimespec.go
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
//go:build darwin || freebsd || netbsd
|
||||
// +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/v2/atime_js.go
generated
vendored
Normal file
12
vendor/github.com/anacrolix/missinggo/v2/atime_js.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func fileInfoAccessTime(fi os.FileInfo) time.Time {
|
||||
sys := fi.Sys().(*syscall.Stat_t)
|
||||
return time.Unix(sys.Atime, sys.AtimeNsec)
|
||||
}
|
||||
12
vendor/github.com/anacrolix/missinggo/v2/atime_plan9.go
generated
vendored
Normal file
12
vendor/github.com/anacrolix/missinggo/v2/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/v2/atime_windows.go
generated
vendored
Normal file
12
vendor/github.com/anacrolix/missinggo/v2/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()))
|
||||
}
|
||||
166
vendor/github.com/anacrolix/missinggo/v2/bitmap/bitmap.go
generated
vendored
Normal file
166
vendor/github.com/anacrolix/missinggo/v2/bitmap/bitmap.go
generated
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
// 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 (
|
||||
"github.com/RoaringBitmap/roaring"
|
||||
|
||||
"github.com/anacrolix/missinggo/iter"
|
||||
)
|
||||
|
||||
type (
|
||||
BitIndex = uint32
|
||||
BitRange = uint64
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
const (
|
||||
MaxInt BitIndex = roaring.MaxUint32
|
||||
ToEnd BitRange = roaring.MaxRange
|
||||
)
|
||||
|
||||
// The number of set bits in the bitmap. Also known as cardinality.
|
||||
func (me Bitmap) Len() BitRange {
|
||||
if me.RB == nil {
|
||||
return 0
|
||||
}
|
||||
return me.RB.GetCardinality()
|
||||
}
|
||||
|
||||
func (me Bitmap) ToSortedSlice() []BitIndex {
|
||||
if me.RB == nil {
|
||||
return nil
|
||||
}
|
||||
return me.RB.ToArray()
|
||||
}
|
||||
|
||||
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) {
|
||||
// Nothing to do if BitIndex is uint32, as this matches what roaring can handle.
|
||||
}
|
||||
|
||||
func (me *Bitmap) Add(is ...BitIndex) {
|
||||
rb := me.lazyRB()
|
||||
for _, i := range is {
|
||||
checkInt(i)
|
||||
rb.Add(i)
|
||||
}
|
||||
}
|
||||
|
||||
func (me *Bitmap) AddRange(begin, end BitRange) {
|
||||
// Filter here so we don't prematurely create a bitmap before having roaring do this check
|
||||
// anyway.
|
||||
if begin >= end {
|
||||
return
|
||||
}
|
||||
me.lazyRB().AddRange(begin, 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 BitIndex) bool {
|
||||
if me.RB == nil {
|
||||
return false
|
||||
}
|
||||
return me.RB.Contains(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 BitRange) {
|
||||
me.lazyRB().Flip(begin, end)
|
||||
}
|
||||
|
||||
func (me Bitmap) Get(bit BitIndex) bool {
|
||||
return me.RB != nil && me.RB.Contains(bit)
|
||||
}
|
||||
|
||||
func (me *Bitmap) Set(bit BitIndex, value bool) {
|
||||
if value {
|
||||
me.lazyRB().Add(bit)
|
||||
} else {
|
||||
if me.RB != nil {
|
||||
me.RB.Remove(bit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (me *Bitmap) RemoveRange(begin, end BitRange) *Bitmap {
|
||||
if me.RB == nil {
|
||||
return me
|
||||
}
|
||||
me.RB.RemoveRange(begin, end)
|
||||
return me
|
||||
}
|
||||
|
||||
func (me Bitmap) IsEmpty() bool {
|
||||
return me.RB == nil || me.RB.IsEmpty()
|
||||
}
|
||||
15
vendor/github.com/anacrolix/missinggo/v2/bitmap/global.go
generated
vendored
Normal file
15
vendor/github.com/anacrolix/missinggo/v2/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 BitRange) Bitmap {
|
||||
return Bitmap{
|
||||
RB: roaring.Flip(bm.lazyRB(), start, end),
|
||||
}
|
||||
}
|
||||
24
vendor/github.com/anacrolix/missinggo/v2/bitmap/iter.go
generated
vendored
Normal file
24
vendor/github.com/anacrolix/missinggo/v2/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/v2/certdir.go
generated
vendored
Normal file
46
vendor/github.com/anacrolix/missinggo/v2/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/v2/chancond.go
generated
vendored
Normal file
36
vendor/github.com/anacrolix/missinggo/v2/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/v2/copy.go
generated
vendored
Normal file
34
vendor/github.com/anacrolix/missinggo/v2/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/v2/croak.go
generated
vendored
Normal file
18
vendor/github.com/anacrolix/missinggo/v2/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/v2/doc.go
generated
vendored
Normal file
3
vendor/github.com/anacrolix/missinggo/v2/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/v2/empty_value.go
generated
vendored
Normal file
33
vendor/github.com/anacrolix/missinggo/v2/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/v2/encoding.go
generated
vendored
Normal file
15
vendor/github.com/anacrolix/missinggo/v2/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/v2/event.go
generated
vendored
Normal file
65
vendor/github.com/anacrolix/missinggo/v2/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/v2/event_synchronized.go
generated
vendored
Normal file
26
vendor/github.com/anacrolix/missinggo/v2/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()
|
||||
}
|
||||
35
vendor/github.com/anacrolix/missinggo/v2/expvarIndentMap.go
generated
vendored
Normal file
35
vendor/github.com/anacrolix/missinggo/v2/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/v2/flag.go
generated
vendored
Normal file
41
vendor/github.com/anacrolix/missinggo/v2/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)
|
||||
}
|
||||
}
|
||||
52
vendor/github.com/anacrolix/missinggo/v2/hostmaybeport.go
generated
vendored
Normal file
52
vendor/github.com/anacrolix/missinggo/v2/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/v2/hostport.go
generated
vendored
Normal file
19
vendor/github.com/anacrolix/missinggo/v2/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
|
||||
}
|
||||
76
vendor/github.com/anacrolix/missinggo/v2/httpresponsestatus.go
generated
vendored
Normal file
76
vendor/github.com/anacrolix/missinggo/v2/httpresponsestatus.go
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
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
|
||||
TimeToFirstByte 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.Started.IsZero() {
|
||||
panic("Started was not initialized")
|
||||
}
|
||||
timeBeforeWrite := time.Now()
|
||||
n, err = me.ResponseWriter.Write(b)
|
||||
if n > 0 && !me.GotFirstByte {
|
||||
me.TimeToFirstByte = timeBeforeWrite.Sub(me.Started)
|
||||
me.GotFirstByte = true
|
||||
}
|
||||
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
|
||||
}
|
||||
30
vendor/github.com/anacrolix/missinggo/v2/ioutil.go
generated
vendored
Normal file
30
vendor/github.com/anacrolix/missinggo/v2/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
|
||||
}
|
||||
19
vendor/github.com/anacrolix/missinggo/v2/ipport.go
generated
vendored
Normal file
19
vendor/github.com/anacrolix/missinggo/v2/ipport.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
package missinggo
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type IpPort struct {
|
||||
IP net.IP
|
||||
Port uint16
|
||||
}
|
||||
|
||||
func (me IpPort) String() string {
|
||||
return net.JoinHostPort(me.IP.String(), strconv.FormatUint(uint64(me.Port), 10))
|
||||
}
|
||||
|
||||
func IpPortFromNetAddr(na net.Addr) IpPort {
|
||||
return IpPort{AddrIP(na), uint16(AddrPort(na))}
|
||||
}
|
||||
11
vendor/github.com/anacrolix/missinggo/v2/iter/chain.go
generated
vendored
Normal file
11
vendor/github.com/anacrolix/missinggo/v2/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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
33
vendor/github.com/anacrolix/missinggo/v2/iter/func.go
generated
vendored
Normal file
33
vendor/github.com/anacrolix/missinggo/v2/iter/func.go
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
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
|
||||
}
|
||||
|
||||
// Calls `cb` with the first value yielded by `f` and then stops iteration. `ok` if `cb` was called
|
||||
// with a value. Returning the value interface{} would require the caller to keep a
|
||||
func First(f Func) (value interface{}, ok bool) {
|
||||
f(func(x interface{}) bool {
|
||||
value = x
|
||||
ok = true
|
||||
return false
|
||||
})
|
||||
return
|
||||
}
|
||||
105
vendor/github.com/anacrolix/missinggo/v2/iter/groupby.go
generated
vendored
Normal file
105
vendor/github.com/anacrolix/missinggo/v2/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/v2/iter/head.go
generated
vendored
Normal file
16
vendor/github.com/anacrolix/missinggo/v2/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/v2/iter/iterable.go
generated
vendored
Normal file
69
vendor/github.com/anacrolix/missinggo/v2/iter/iterable.go
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
package iter
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/anacrolix/missinggo/v2"
|
||||
)
|
||||
|
||||
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/v2/iter/iterator.go
generated
vendored
Normal file
69
vendor/github.com/anacrolix/missinggo/v2/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/v2/iter/iterutils.go
generated
vendored
Normal file
42
vendor/github.com/anacrolix/missinggo/v2/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/v2/iter/n.go
generated
vendored
Normal file
7
vendor/github.com/anacrolix/missinggo/v2/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/v2/jitter.go
generated
vendored
Normal file
17
vendor/github.com/anacrolix/missinggo/v2/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/v2/limitlen.go
generated
vendored
Normal file
7
vendor/github.com/anacrolix/missinggo/v2/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...)]
|
||||
}
|
||||
34
vendor/github.com/anacrolix/missinggo/v2/minmax.go
generated
vendored
Normal file
34
vendor/github.com/anacrolix/missinggo/v2/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/v2/monotonic.go
generated
vendored
Normal file
44
vendor/github.com/anacrolix/missinggo/v2/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)
|
||||
}
|
||||
59
vendor/github.com/anacrolix/missinggo/v2/multiless.go
generated
vendored
Normal file
59
vendor/github.com/anacrolix/missinggo/v2/multiless.go
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
package missinggo
|
||||
|
||||
type (
|
||||
// A function that returns equality, and less than. Used for lazily evaluating arguments.
|
||||
SameLessFunc func() (same, less bool)
|
||||
// A helper for long chains of "less-than" comparisons, where later comparisons are only
|
||||
// required if earlier ones haven't resolved the comparison.
|
||||
MultiLess struct {
|
||||
ok bool
|
||||
less bool
|
||||
}
|
||||
)
|
||||
|
||||
// True iff the left is less than the right. Will return false if they're equal, or unresolved.
|
||||
// (Which is okay in certain circumstances.)
|
||||
func (me *MultiLess) Less() bool {
|
||||
return me.ok && me.less
|
||||
}
|
||||
|
||||
// Returns the result of the less-than comparison chains. Panics if the case was not resolved.
|
||||
func (me *MultiLess) Final() bool {
|
||||
if !me.ok {
|
||||
panic("undetermined")
|
||||
}
|
||||
return me.less
|
||||
}
|
||||
|
||||
// Returns less-than, and whether the comparison was definitely resolved.
|
||||
func (me *MultiLess) FinalOk() (left, ok bool) {
|
||||
return me.less, me.ok
|
||||
}
|
||||
|
||||
// `f` is only evaluated if the result is not yet determined.
|
||||
func (me *MultiLess) Next(f SameLessFunc) {
|
||||
if me.ok {
|
||||
return
|
||||
}
|
||||
same, less := f()
|
||||
if same {
|
||||
return
|
||||
}
|
||||
me.ok = true
|
||||
me.less = less
|
||||
}
|
||||
|
||||
// Like Next, but the arguments are already evaluated.
|
||||
func (me *MultiLess) StrictNext(same, less bool) {
|
||||
me.Next(func() (bool, bool) { return same, less })
|
||||
}
|
||||
|
||||
// Compare booleans, where the lesser is the true one, if the other is false.
|
||||
func (me *MultiLess) NextBool(l, r bool) {
|
||||
me.StrictNext(l == r, l)
|
||||
}
|
||||
|
||||
// Next use a common comparison result, where < 0 is less and 0 is equal.
|
||||
func (me *MultiLess) Compare(i int) {
|
||||
me.StrictNext(i == 0, i < 0)
|
||||
}
|
||||
7
vendor/github.com/anacrolix/missinggo/v2/net.go
generated
vendored
Normal file
7
vendor/github.com/anacrolix/missinggo/v2/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/v2/openflags.go
generated
vendored
Normal file
7
vendor/github.com/anacrolix/missinggo/v2/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
|
||||
20
vendor/github.com/anacrolix/missinggo/v2/path.go
generated
vendored
Normal file
20
vendor/github.com/anacrolix/missinggo/v2/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
|
||||
}
|
||||
122
vendor/github.com/anacrolix/missinggo/v2/pproffd/pproffd.go
generated
vendored
Normal file
122
vendor/github.com/anacrolix/missinggo/v2/pproffd/pproffd.go
generated
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
// Package pproffd is for detecting resource leaks due to unclosed handles.
|
||||
package pproffd
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"runtime/pprof"
|
||||
)
|
||||
|
||||
var enabled = func() bool {
|
||||
_, ok := os.LookupEnv("PPROFFD")
|
||||
return ok
|
||||
}()
|
||||
|
||||
var p *pprof.Profile
|
||||
|
||||
func init() {
|
||||
if enabled {
|
||||
p = pprof.NewProfile("fds")
|
||||
}
|
||||
}
|
||||
|
||||
type fd int
|
||||
|
||||
func (me *fd) Closed() {
|
||||
if enabled {
|
||||
p.Remove(me)
|
||||
}
|
||||
}
|
||||
|
||||
func add(skip int) (ret *fd) {
|
||||
if enabled {
|
||||
ret = new(fd)
|
||||
p.Add(ret, skip+2)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type Wrapped interface {
|
||||
Wrapped() io.Closer
|
||||
}
|
||||
|
||||
type CloseWrapper struct {
|
||||
fd *fd
|
||||
c io.Closer
|
||||
}
|
||||
|
||||
func (me CloseWrapper) Wrapped() io.Closer {
|
||||
return me.c
|
||||
}
|
||||
|
||||
func (me CloseWrapper) Close() error {
|
||||
me.fd.Closed()
|
||||
return me.c.Close()
|
||||
}
|
||||
|
||||
func NewCloseWrapper(c io.Closer) CloseWrapper {
|
||||
// TODO: Check enabled?
|
||||
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
|
||||
Wrapped
|
||||
}
|
||||
|
||||
type wrappedOSFile struct {
|
||||
*os.File
|
||||
CloseWrapper
|
||||
}
|
||||
|
||||
func (me wrappedOSFile) Close() error {
|
||||
return me.CloseWrapper.Close()
|
||||
}
|
||||
|
||||
type unwrappedOsFile struct {
|
||||
*os.File
|
||||
}
|
||||
|
||||
func (me unwrappedOsFile) Wrapped() io.Closer {
|
||||
return me.File
|
||||
}
|
||||
|
||||
func WrapOSFile(f *os.File) OSFile {
|
||||
if !enabled {
|
||||
return unwrappedOsFile{f}
|
||||
}
|
||||
return &wrappedOSFile{f, NewCloseWrapper(f)}
|
||||
}
|
||||
16
vendor/github.com/anacrolix/missinggo/v2/reader_context.go
generated
vendored
Normal file
16
vendor/github.com/anacrolix/missinggo/v2/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/v2/resource/http.go
generated
vendored
Normal file
196
vendor/github.com/anacrolix/missinggo/v2/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/v2/resource/osfile.go
generated
vendored
Normal file
61
vendor/github.com/anacrolix/missinggo/v2/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/v2/resource/provider.go
generated
vendored
Normal file
21
vendor/github.com/anacrolix/missinggo/v2/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))
|
||||
}
|
||||
50
vendor/github.com/anacrolix/missinggo/v2/resource/resource.go
generated
vendored
Normal file
50
vendor/github.com/anacrolix/missinggo/v2/resource/resource.go
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
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)
|
||||
io.ReaderAt
|
||||
WriteAt([]byte, int64) (int, error)
|
||||
Delete() error
|
||||
}
|
||||
|
||||
type DirInstance interface {
|
||||
Readdirnames() ([]string, 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/v2/rle.go
generated
vendored
Normal file
46
vendor/github.com/anacrolix/missinggo/v2/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/v2/section_read_seeker.go
generated
vendored
Normal file
75
vendor/github.com/anacrolix/missinggo/v2/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/v2/section_writer.go
generated
vendored
Normal file
23
vendor/github.com/anacrolix/missinggo/v2/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/v2/selfcert.go
generated
vendored
Normal file
60
vendor/github.com/anacrolix/missinggo/v2/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/v2/singleflight.go
generated
vendored
Normal file
49
vendor/github.com/anacrolix/missinggo/v2/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()
|
||||
}
|
||||
17
vendor/github.com/anacrolix/missinggo/v2/sqlite.go
generated
vendored
Normal file
17
vendor/github.com/anacrolix/missinggo/v2/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/v2/stack.go
generated
vendored
Normal file
23
vendor/github.com/anacrolix/missinggo/v2/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/v2/strbool.go
generated
vendored
Normal file
25
vendor/github.com/anacrolix/missinggo/v2/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/v2/strcase.go
generated
vendored
Normal file
11
vendor/github.com/anacrolix/missinggo/v2/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/v2/sync.go
generated
vendored
Normal file
11
vendor/github.com/anacrolix/missinggo/v2/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/v2/testing.go
generated
vendored
Normal file
25
vendor/github.com/anacrolix/missinggo/v2/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/v2/timer.go
generated
vendored
Normal file
15
vendor/github.com/anacrolix/missinggo/v2/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/v2/tls.go
generated
vendored
Normal file
32
vendor/github.com/anacrolix/missinggo/v2/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/v2/units.go
generated
vendored
Normal file
3
vendor/github.com/anacrolix/missinggo/v2/units.go
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
package missinggo
|
||||
|
||||
const MiB = 1 << 20
|
||||
42
vendor/github.com/anacrolix/missinggo/v2/url.go
generated
vendored
Normal file
42
vendor/github.com/anacrolix/missinggo/v2/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/v2/wait_event.go
generated
vendored
Normal file
19
vendor/github.com/anacrolix/missinggo/v2/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()
|
||||
}
|
||||
Reference in New Issue
Block a user