feat: Waku v2 bridge

Issue #12610
This commit is contained in:
Michal Iskierko
2023-11-12 13:29:38 +01:00
parent 56e7bd01ca
commit 6d31343205
6716 changed files with 1982502 additions and 5891 deletions

21
vendor/github.com/anacrolix/missinggo/v2/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/v2/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/v2/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/v2/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/v2/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,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
View 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)
}

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

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

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

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 BitRange) Bitmap {
return Bitmap{
RB: roaring.Flip(bm.lazyRB(), start, end),
}
}

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/v2/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/v2/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/v2/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/v2/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/v2/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

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/v2/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/v2/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()
}

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/v2/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)
}
}

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/v2/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,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
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
}

19
vendor/github.com/anacrolix/missinggo/v2/ipport.go generated vendored Normal file
View 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
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
}
}
}
}

33
vendor/github.com/anacrolix/missinggo/v2/iter/func.go generated vendored Normal file
View 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
}

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/v2/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
})
}
}

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

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/v2/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/v2/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/v2/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...)]
}

34
vendor/github.com/anacrolix/missinggo/v2/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/v2/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)
}

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

@@ -0,0 +1,7 @@
package missinggo
import "strings"
func IsAddrInUse(err error) bool {
return strings.Contains(err.Error(), "address already in use")
}

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

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

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

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,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
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/v2/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
}

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

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

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

42
vendor/github.com/anacrolix/missinggo/v2/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/v2/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()
}