This commit is contained in:
zhoujunhao 2018-09-26 14:42:01 +08:00
parent 6a077c268b
commit 4d2a50bf77
75 changed files with 4796 additions and 0 deletions

1
.docker/.buildNodeID Normal file
View File

@ -0,0 +1 @@
003620d97ecf10a5d0b1542ea0e21a8db2c2ee38ad9691e99afbdecc5049269d

9
vendor/github.com/google/uuid/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,9 @@
language: go
go:
- 1.4.3
- 1.5.3
- tip
script:
- go test -v ./...

10
vendor/github.com/google/uuid/CONTRIBUTING.md generated vendored Normal file
View File

@ -0,0 +1,10 @@
# How to contribute
We definitely welcome patches and contribution to this project!
### Legal requirements
In order to protect both you and ourselves, you will need to sign the
[Contributor License Agreement](https://cla.developers.google.com/clas).
You may have already signed it for other Google projects.

9
vendor/github.com/google/uuid/CONTRIBUTORS generated vendored Normal file
View File

@ -0,0 +1,9 @@
Paul Borman <borman@google.com>
bmatsuo
shawnps
theory
jboverfelt
dsymonds
cd1
wallclockbuilder
dansouza

27
vendor/github.com/google/uuid/LICENSE generated vendored Normal file
View File

@ -0,0 +1,27 @@
Copyright (c) 2009,2014 Google Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

19
vendor/github.com/google/uuid/README.md generated vendored Normal file
View File

@ -0,0 +1,19 @@
# uuid ![build status](https://travis-ci.org/google/uuid.svg?branch=master)
The uuid package generates and inspects UUIDs based on
[RFC 4122](http://tools.ietf.org/html/rfc4122)
and DCE 1.1: Authentication and Security Services.
This package is based on the github.com/pborman/uuid package (previously named
code.google.com/p/go-uuid). It differs from these earlier packages in that
a UUID is a 16 byte array rather than a byte slice. One loss due to this
change is the ability to represent an invalid UUID (vs a NIL UUID).
###### Install
`go get github.com/google/uuid`
###### Documentation
[![GoDoc](https://godoc.org/github.com/google/uuid?status.svg)](http://godoc.org/github.com/google/uuid)
Full `go doc` style documentation for the package can be viewed online without
installing this package by using the GoDoc site here:
http://godoc.org/github.com/google/uuid

80
vendor/github.com/google/uuid/dce.go generated vendored Normal file
View File

@ -0,0 +1,80 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"encoding/binary"
"fmt"
"os"
)
// A Domain represents a Version 2 domain
type Domain byte
// Domain constants for DCE Security (Version 2) UUIDs.
const (
Person = Domain(0)
Group = Domain(1)
Org = Domain(2)
)
// NewDCESecurity returns a DCE Security (Version 2) UUID.
//
// The domain should be one of Person, Group or Org.
// On a POSIX system the id should be the users UID for the Person
// domain and the users GID for the Group. The meaning of id for
// the domain Org or on non-POSIX systems is site defined.
//
// For a given domain/id pair the same token may be returned for up to
// 7 minutes and 10 seconds.
func NewDCESecurity(domain Domain, id uint32) (UUID, error) {
uuid, err := NewUUID()
if err == nil {
uuid[6] = (uuid[6] & 0x0f) | 0x20 // Version 2
uuid[9] = byte(domain)
binary.BigEndian.PutUint32(uuid[0:], id)
}
return uuid, err
}
// NewDCEPerson returns a DCE Security (Version 2) UUID in the person
// domain with the id returned by os.Getuid.
//
// NewDCESecurity(Person, uint32(os.Getuid()))
func NewDCEPerson() (UUID, error) {
return NewDCESecurity(Person, uint32(os.Getuid()))
}
// NewDCEGroup returns a DCE Security (Version 2) UUID in the group
// domain with the id returned by os.Getgid.
//
// NewDCESecurity(Group, uint32(os.Getgid()))
func NewDCEGroup() (UUID, error) {
return NewDCESecurity(Group, uint32(os.Getgid()))
}
// Domain returns the domain for a Version 2 UUID. Domains are only defined
// for Version 2 UUIDs.
func (uuid UUID) Domain() Domain {
return Domain(uuid[9])
}
// ID returns the id for a Version 2 UUID. IDs are only defined for Version 2
// UUIDs.
func (uuid UUID) ID() uint32 {
return binary.BigEndian.Uint32(uuid[0:4])
}
func (d Domain) String() string {
switch d {
case Person:
return "Person"
case Group:
return "Group"
case Org:
return "Org"
}
return fmt.Sprintf("Domain%d", int(d))
}

12
vendor/github.com/google/uuid/doc.go generated vendored Normal file
View File

@ -0,0 +1,12 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package uuid generates and inspects UUIDs.
//
// UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security
// Services.
//
// A UUID is a 16 byte (128 bit) array. UUIDs may be used as keys to
// maps or compared directly.
package uuid

1
vendor/github.com/google/uuid/go.mod generated vendored Normal file
View File

@ -0,0 +1 @@
module github.com/google/uuid

53
vendor/github.com/google/uuid/hash.go generated vendored Normal file
View File

@ -0,0 +1,53 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"crypto/md5"
"crypto/sha1"
"hash"
)
// Well known namespace IDs and UUIDs
var (
NameSpaceDNS = Must(Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8"))
NameSpaceURL = Must(Parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8"))
NameSpaceOID = Must(Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8"))
NameSpaceX500 = Must(Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8"))
Nil UUID // empty UUID, all zeros
)
// NewHash returns a new UUID derived from the hash of space concatenated with
// data generated by h. The hash should be at least 16 byte in length. The
// first 16 bytes of the hash are used to form the UUID. The version of the
// UUID will be the lower 4 bits of version. NewHash is used to implement
// NewMD5 and NewSHA1.
func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID {
h.Reset()
h.Write(space[:])
h.Write(data)
s := h.Sum(nil)
var uuid UUID
copy(uuid[:], s)
uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4)
uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 4122 variant
return uuid
}
// NewMD5 returns a new MD5 (Version 3) UUID based on the
// supplied name space and data. It is the same as calling:
//
// NewHash(md5.New(), space, data, 3)
func NewMD5(space UUID, data []byte) UUID {
return NewHash(md5.New(), space, data, 3)
}
// NewSHA1 returns a new SHA1 (Version 5) UUID based on the
// supplied name space and data. It is the same as calling:
//
// NewHash(sha1.New(), space, data, 5)
func NewSHA1(space UUID, data []byte) UUID {
return NewHash(sha1.New(), space, data, 5)
}

62
vendor/github.com/google/uuid/json_test.go generated vendored Normal file
View File

@ -0,0 +1,62 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"encoding/json"
"reflect"
"testing"
)
var testUUID = Must(Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479"))
func TestJSON(t *testing.T) {
type S struct {
ID1 UUID
ID2 UUID
}
s1 := S{ID1: testUUID}
data, err := json.Marshal(&s1)
if err != nil {
t.Fatal(err)
}
var s2 S
if err := json.Unmarshal(data, &s2); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(&s1, &s2) {
t.Errorf("got %#v, want %#v", s2, s1)
}
}
func BenchmarkUUID_MarshalJSON(b *testing.B) {
x := &struct {
UUID UUID `json:"uuid"`
}{}
var err error
x.UUID, err = Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479")
if err != nil {
b.Fatal(err)
}
for i := 0; i < b.N; i++ {
js, err := json.Marshal(x)
if err != nil {
b.Fatalf("marshal json: %#v (%v)", js, err)
}
}
}
func BenchmarkUUID_UnmarshalJSON(b *testing.B) {
js := []byte(`{"uuid":"f47ac10b-58cc-0372-8567-0e02b2c3d479"}`)
var x *struct {
UUID UUID `json:"uuid"`
}
for i := 0; i < b.N; i++ {
err := json.Unmarshal(js, &x)
if err != nil {
b.Fatalf("marshal json: %#v (%v)", js, err)
}
}
}

37
vendor/github.com/google/uuid/marshal.go generated vendored Normal file
View File

@ -0,0 +1,37 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import "fmt"
// MarshalText implements encoding.TextMarshaler.
func (uuid UUID) MarshalText() ([]byte, error) {
var js [36]byte
encodeHex(js[:], uuid)
return js[:], nil
}
// UnmarshalText implements encoding.TextUnmarshaler.
func (uuid *UUID) UnmarshalText(data []byte) error {
id, err := ParseBytes(data)
if err == nil {
*uuid = id
}
return err
}
// MarshalBinary implements encoding.BinaryMarshaler.
func (uuid UUID) MarshalBinary() ([]byte, error) {
return uuid[:], nil
}
// UnmarshalBinary implements encoding.BinaryUnmarshaler.
func (uuid *UUID) UnmarshalBinary(data []byte) error {
if len(data) != 16 {
return fmt.Errorf("invalid UUID (got %d bytes)", len(data))
}
copy(uuid[:], data)
return nil
}

89
vendor/github.com/google/uuid/node.go generated vendored Normal file
View File

@ -0,0 +1,89 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"sync"
)
var (
nodeMu sync.Mutex
ifname string // name of interface being used
nodeID [6]byte // hardware for version 1 UUIDs
zeroID [6]byte // nodeID with only 0's
)
// NodeInterface returns the name of the interface from which the NodeID was
// derived. The interface "user" is returned if the NodeID was set by
// SetNodeID.
func NodeInterface() string {
defer nodeMu.Unlock()
nodeMu.Lock()
return ifname
}
// SetNodeInterface selects the hardware address to be used for Version 1 UUIDs.
// If name is "" then the first usable interface found will be used or a random
// Node ID will be generated. If a named interface cannot be found then false
// is returned.
//
// SetNodeInterface never fails when name is "".
func SetNodeInterface(name string) bool {
defer nodeMu.Unlock()
nodeMu.Lock()
return setNodeInterface(name)
}
func setNodeInterface(name string) bool {
iname, addr := getHardwareInterface(name) // null implementation for js
if iname != "" && addr != nil {
ifname = iname
copy(nodeID[:], addr)
return true
}
// We found no interfaces with a valid hardware address. If name
// does not specify a specific interface generate a random Node ID
// (section 4.1.6)
if name == "" {
randomBits(nodeID[:])
return true
}
return false
}
// NodeID returns a slice of a copy of the current Node ID, setting the Node ID
// if not already set.
func NodeID() []byte {
defer nodeMu.Unlock()
nodeMu.Lock()
if nodeID == zeroID {
setNodeInterface("")
}
nid := nodeID
return nid[:]
}
// SetNodeID sets the Node ID to be used for Version 1 UUIDs. The first 6 bytes
// of id are used. If id is less than 6 bytes then false is returned and the
// Node ID is not set.
func SetNodeID(id []byte) bool {
if len(id) < 6 {
return false
}
defer nodeMu.Unlock()
nodeMu.Lock()
copy(nodeID[:], id)
ifname = "user"
return true
}
// NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is
// not valid. The NodeID is only well defined for version 1 and 2 UUIDs.
func (uuid UUID) NodeID() []byte {
var node [6]byte
copy(node[:], uuid[10:])
return node[:]
}

12
vendor/github.com/google/uuid/node_js.go generated vendored Normal file
View File

@ -0,0 +1,12 @@
// Copyright 2017 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build js
package uuid
// getHardwareInterface returns nil values for the JS version of the code.
// This remvoves the "net" dependency, because it is not used in the browser.
// Using the "net" library inflates the size of the transpiled JS code by 673k bytes.
func getHardwareInterface(name string) (string, []byte) { return "", nil }

33
vendor/github.com/google/uuid/node_net.go generated vendored Normal file
View File

@ -0,0 +1,33 @@
// Copyright 2017 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !js
package uuid
import "net"
var interfaces []net.Interface // cached list of interfaces
// getHardwareInterface returns the name and hardware address of interface name.
// If name is "" then the name and hardware address of one of the system's
// interfaces is returned. If no interfaces are found (name does not exist or
// there are no interfaces) then "", nil is returned.
//
// Only addresses of at least 6 bytes are returned.
func getHardwareInterface(name string) (string, []byte) {
if interfaces == nil {
var err error
interfaces, err = net.Interfaces()
if err != nil {
return "", nil
}
}
for _, ifs := range interfaces {
if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) {
return ifs.Name, ifs.HardwareAddr
}
}
return "", nil
}

66
vendor/github.com/google/uuid/seq_test.go generated vendored Normal file
View File

@ -0,0 +1,66 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"flag"
"runtime"
"testing"
"time"
)
// This test is only run when --regressions is passed on the go test line.
var regressions = flag.Bool("regressions", false, "run uuid regression tests")
// TestClockSeqRace tests for a particular race condition of returning two
// identical Version1 UUIDs. The duration of 1 minute was chosen as the race
// condition, before being fixed, nearly always occurred in under 30 seconds.
func TestClockSeqRace(t *testing.T) {
if !*regressions {
t.Skip("skipping regression tests")
}
duration := time.Minute
done := make(chan struct{})
defer close(done)
ch := make(chan UUID, 10000)
ncpu := runtime.NumCPU()
switch ncpu {
case 0, 1:
// We can't run the test effectively.
t.Skip("skipping race test, only one CPU detected")
return
default:
runtime.GOMAXPROCS(ncpu)
}
for i := 0; i < ncpu; i++ {
go func() {
for {
select {
case <-done:
return
case ch <- Must(NewUUID()):
}
}
}()
}
uuids := make(map[string]bool)
cnt := 0
start := time.Now()
for u := range ch {
s := u.String()
if uuids[s] {
t.Errorf("duplicate uuid after %d in %v: %s", cnt, time.Since(start), s)
return
}
uuids[s] = true
if time.Since(start) > duration {
return
}
cnt++
}
}

59
vendor/github.com/google/uuid/sql.go generated vendored Normal file
View File

@ -0,0 +1,59 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"database/sql/driver"
"fmt"
)
// Scan implements sql.Scanner so UUIDs can be read from databases transparently
// Currently, database types that map to string and []byte are supported. Please
// consult database-specific driver documentation for matching types.
func (uuid *UUID) Scan(src interface{}) error {
switch src := src.(type) {
case nil:
return nil
case string:
// if an empty UUID comes from a table, we return a null UUID
if src == "" {
return nil
}
// see Parse for required string format
u, err := Parse(src)
if err != nil {
return fmt.Errorf("Scan: %v", err)
}
*uuid = u
case []byte:
// if an empty UUID comes from a table, we return a null UUID
if len(src) == 0 {
return nil
}
// assumes a simple slice of bytes if 16 bytes
// otherwise attempts to parse
if len(src) != 16 {
return uuid.Scan(string(src))
}
copy((*uuid)[:], src)
default:
return fmt.Errorf("Scan: unable to scan type %T into UUID", src)
}
return nil
}
// Value implements sql.Valuer so that UUIDs can be written to databases
// transparently. Currently, UUIDs map to strings. Please consult
// database-specific driver documentation for matching types.
func (uuid UUID) Value() (driver.Value, error) {
return uuid.String(), nil
}

113
vendor/github.com/google/uuid/sql_test.go generated vendored Normal file
View File

@ -0,0 +1,113 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"strings"
"testing"
)
func TestScan(t *testing.T) {
stringTest := "f47ac10b-58cc-0372-8567-0e02b2c3d479"
badTypeTest := 6
invalidTest := "f47ac10b-58cc-0372-8567-0e02b2c3d4"
byteTest := make([]byte, 16)
byteTestUUID := Must(Parse(stringTest))
copy(byteTest, byteTestUUID[:])
// sunny day tests
var uuid UUID
err := (&uuid).Scan(stringTest)
if err != nil {
t.Fatal(err)
}
err = (&uuid).Scan([]byte(stringTest))
if err != nil {
t.Fatal(err)
}
err = (&uuid).Scan(byteTest)
if err != nil {
t.Fatal(err)
}
// bad type tests
err = (&uuid).Scan(badTypeTest)
if err == nil {
t.Error("int correctly parsed and shouldn't have")
}
if !strings.Contains(err.Error(), "unable to scan type") {
t.Error("attempting to parse an int returned an incorrect error message")
}
// invalid/incomplete uuids
err = (&uuid).Scan(invalidTest)
if err == nil {
t.Error("invalid uuid was parsed without error")
}
if !strings.Contains(err.Error(), "invalid UUID") {
t.Error("attempting to parse an invalid UUID returned an incorrect error message")
}
err = (&uuid).Scan(byteTest[:len(byteTest)-2])
if err == nil {
t.Error("invalid byte uuid was parsed without error")
}
if !strings.Contains(err.Error(), "invalid UUID") {
t.Error("attempting to parse an invalid byte UUID returned an incorrect error message")
}
// empty tests
uuid = UUID{}
var emptySlice []byte
err = (&uuid).Scan(emptySlice)
if err != nil {
t.Fatal(err)
}
for _, v := range uuid {
if v != 0 {
t.Error("UUID was not nil after scanning empty byte slice")
}
}
uuid = UUID{}
var emptyString string
err = (&uuid).Scan(emptyString)
if err != nil {
t.Fatal(err)
}
for _, v := range uuid {
if v != 0 {
t.Error("UUID was not nil after scanning empty byte slice")
}
}
uuid = UUID{}
err = (&uuid).Scan(nil)
if err != nil {
t.Fatal(err)
}
for _, v := range uuid {
if v != 0 {
t.Error("UUID was not nil after scanning nil")
}
}
}
func TestValue(t *testing.T) {
stringTest := "f47ac10b-58cc-0372-8567-0e02b2c3d479"
uuid := Must(Parse(stringTest))
val, _ := uuid.Value()
if val != stringTest {
t.Error("Value() did not return expected string")
}
}

123
vendor/github.com/google/uuid/time.go generated vendored Normal file
View File

@ -0,0 +1,123 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"encoding/binary"
"sync"
"time"
)
// A Time represents a time as the number of 100's of nanoseconds since 15 Oct
// 1582.
type Time int64
const (
lillian = 2299160 // Julian day of 15 Oct 1582
unix = 2440587 // Julian day of 1 Jan 1970
epoch = unix - lillian // Days between epochs
g1582 = epoch * 86400 // seconds between epochs
g1582ns100 = g1582 * 10000000 // 100s of a nanoseconds between epochs
)
var (
timeMu sync.Mutex
lasttime uint64 // last time we returned
clockSeq uint16 // clock sequence for this run
timeNow = time.Now // for testing
)
// UnixTime converts t the number of seconds and nanoseconds using the Unix
// epoch of 1 Jan 1970.
func (t Time) UnixTime() (sec, nsec int64) {
sec = int64(t - g1582ns100)
nsec = (sec % 10000000) * 100
sec /= 10000000
return sec, nsec
}
// GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and
// clock sequence as well as adjusting the clock sequence as needed. An error
// is returned if the current time cannot be determined.
func GetTime() (Time, uint16, error) {
defer timeMu.Unlock()
timeMu.Lock()
return getTime()
}
func getTime() (Time, uint16, error) {
t := timeNow()
// If we don't have a clock sequence already, set one.
if clockSeq == 0 {
setClockSequence(-1)
}
now := uint64(t.UnixNano()/100) + g1582ns100
// If time has gone backwards with this clock sequence then we
// increment the clock sequence
if now <= lasttime {
clockSeq = ((clockSeq + 1) & 0x3fff) | 0x8000
}
lasttime = now
return Time(now), clockSeq, nil
}
// ClockSequence returns the current clock sequence, generating one if not
// already set. The clock sequence is only used for Version 1 UUIDs.
//
// The uuid package does not use global static storage for the clock sequence or
// the last time a UUID was generated. Unless SetClockSequence is used, a new
// random clock sequence is generated the first time a clock sequence is
// requested by ClockSequence, GetTime, or NewUUID. (section 4.2.1.1)
func ClockSequence() int {
defer timeMu.Unlock()
timeMu.Lock()
return clockSequence()
}
func clockSequence() int {
if clockSeq == 0 {
setClockSequence(-1)
}
return int(clockSeq & 0x3fff)
}
// SetClockSequence sets the clock sequence to the lower 14 bits of seq. Setting to
// -1 causes a new sequence to be generated.
func SetClockSequence(seq int) {
defer timeMu.Unlock()
timeMu.Lock()
setClockSequence(seq)
}
func setClockSequence(seq int) {
if seq == -1 {
var b [2]byte
randomBits(b[:]) // clock sequence
seq = int(b[0])<<8 | int(b[1])
}
oldSeq := clockSeq
clockSeq = uint16(seq&0x3fff) | 0x8000 // Set our variant
if oldSeq != clockSeq {
lasttime = 0
}
}
// Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in
// uuid. The time is only defined for version 1 and 2 UUIDs.
func (uuid UUID) Time() Time {
time := int64(binary.BigEndian.Uint32(uuid[0:4]))
time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32
time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48
return Time(time)
}
// ClockSequence returns the clock sequence encoded in uuid.
// The clock sequence is only well defined for version 1 and 2 UUIDs.
func (uuid UUID) ClockSequence() int {
return int(binary.BigEndian.Uint16(uuid[8:10])) & 0x3fff
}

43
vendor/github.com/google/uuid/util.go generated vendored Normal file
View File

@ -0,0 +1,43 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"io"
)
// randomBits completely fills slice b with random data.
func randomBits(b []byte) {
if _, err := io.ReadFull(rander, b); err != nil {
panic(err.Error()) // rand should never fail
}
}
// xvalues returns the value of a byte as a hexadecimal digit or 255.
var xvalues = [256]byte{
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255,
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
}
// xtob converts hex characters x1 and x2 into a byte.
func xtob(x1, x2 byte) (byte, bool) {
b1 := xvalues[x1]
b2 := xvalues[x2]
return (b1 << 4) | b2, b1 != 255 && b2 != 255
}

245
vendor/github.com/google/uuid/uuid.go generated vendored Normal file
View File

@ -0,0 +1,245 @@
// Copyright 2018 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"bytes"
"crypto/rand"
"encoding/hex"
"errors"
"fmt"
"io"
"strings"
)
// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC
// 4122.
type UUID [16]byte
// A Version represents a UUID's version.
type Version byte
// A Variant represents a UUID's variant.
type Variant byte
// Constants returned by Variant.
const (
Invalid = Variant(iota) // Invalid UUID
RFC4122 // The variant specified in RFC4122
Reserved // Reserved, NCS backward compatibility.
Microsoft // Reserved, Microsoft Corporation backward compatibility.
Future // Reserved for future definition.
)
var rander = rand.Reader // random function
// Parse decodes s into a UUID or returns an error. Both the standard UUID
// forms of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded as well as the
// Microsoft encoding {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} and the raw hex
// encoding: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.
func Parse(s string) (UUID, error) {
var uuid UUID
switch len(s) {
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
case 36:
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
case 36 + 9:
if strings.ToLower(s[:9]) != "urn:uuid:" {
return uuid, fmt.Errorf("invalid urn prefix: %q", s[:9])
}
s = s[9:]
// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
case 36 + 2:
s = s[1:]
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
case 32:
var ok bool
for i := range uuid {
uuid[i], ok = xtob(s[i*2], s[i*2+1])
if !ok {
return uuid, errors.New("invalid UUID format")
}
}
return uuid, nil
default:
return uuid, fmt.Errorf("invalid UUID length: %d", len(s))
}
// s is now at least 36 bytes long
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
return uuid, errors.New("invalid UUID format")
}
for i, x := range [16]int{
0, 2, 4, 6,
9, 11,
14, 16,
19, 21,
24, 26, 28, 30, 32, 34} {
v, ok := xtob(s[x], s[x+1])
if !ok {
return uuid, errors.New("invalid UUID format")
}
uuid[i] = v
}
return uuid, nil
}
// ParseBytes is like Parse, except it parses a byte slice instead of a string.
func ParseBytes(b []byte) (UUID, error) {
var uuid UUID
switch len(b) {
case 36: // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
case 36 + 9: // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
if !bytes.Equal(bytes.ToLower(b[:9]), []byte("urn:uuid:")) {
return uuid, fmt.Errorf("invalid urn prefix: %q", b[:9])
}
b = b[9:]
case 36 + 2: // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
b = b[1:]
case 32: // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
var ok bool
for i := 0; i < 32; i += 2 {
uuid[i/2], ok = xtob(b[i], b[i+1])
if !ok {
return uuid, errors.New("invalid UUID format")
}
}
return uuid, nil
default:
return uuid, fmt.Errorf("invalid UUID length: %d", len(b))
}
// s is now at least 36 bytes long
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
if b[8] != '-' || b[13] != '-' || b[18] != '-' || b[23] != '-' {
return uuid, errors.New("invalid UUID format")
}
for i, x := range [16]int{
0, 2, 4, 6,
9, 11,
14, 16,
19, 21,
24, 26, 28, 30, 32, 34} {
v, ok := xtob(b[x], b[x+1])
if !ok {
return uuid, errors.New("invalid UUID format")
}
uuid[i] = v
}
return uuid, nil
}
// MustParse is like Parse but panics if the string cannot be parsed.
// It simplifies safe initialization of global variables holding compiled UUIDs.
func MustParse(s string) UUID {
uuid, err := Parse(s)
if err != nil {
panic(`uuid: Parse(` + s + `): ` + err.Error())
}
return uuid
}
// FromBytes creates a new UUID from a byte slice. Returns an error if the slice
// does not have a length of 16. The bytes are copied from the slice.
func FromBytes(b []byte) (uuid UUID, err error) {
err = uuid.UnmarshalBinary(b)
return uuid, err
}
// Must returns uuid if err is nil and panics otherwise.
func Must(uuid UUID, err error) UUID {
if err != nil {
panic(err)
}
return uuid
}
// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
// , or "" if uuid is invalid.
func (uuid UUID) String() string {
var buf [36]byte
encodeHex(buf[:], uuid)
return string(buf[:])
}
// URN returns the RFC 2141 URN form of uuid,
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, or "" if uuid is invalid.
func (uuid UUID) URN() string {
var buf [36 + 9]byte
copy(buf[:], "urn:uuid:")
encodeHex(buf[9:], uuid)
return string(buf[:])
}
func encodeHex(dst []byte, uuid UUID) {
hex.Encode(dst, uuid[:4])
dst[8] = '-'
hex.Encode(dst[9:13], uuid[4:6])
dst[13] = '-'
hex.Encode(dst[14:18], uuid[6:8])
dst[18] = '-'
hex.Encode(dst[19:23], uuid[8:10])
dst[23] = '-'
hex.Encode(dst[24:], uuid[10:])
}
// Variant returns the variant encoded in uuid.
func (uuid UUID) Variant() Variant {
switch {
case (uuid[8] & 0xc0) == 0x80:
return RFC4122
case (uuid[8] & 0xe0) == 0xc0:
return Microsoft
case (uuid[8] & 0xe0) == 0xe0:
return Future
default:
return Reserved
}
}
// Version returns the version of uuid.
func (uuid UUID) Version() Version {
return Version(uuid[6] >> 4)
}
func (v Version) String() string {
if v > 15 {
return fmt.Sprintf("BAD_VERSION_%d", v)
}
return fmt.Sprintf("VERSION_%d", v)
}
func (v Variant) String() string {
switch v {
case RFC4122:
return "RFC4122"
case Reserved:
return "Reserved"
case Microsoft:
return "Microsoft"
case Future:
return "Future"
case Invalid:
return "Invalid"
}
return fmt.Sprintf("BadVariant%d", int(v))
}
// SetRand sets the random number generator to r, which implements io.Reader.
// If r.Read returns an error when the package requests random data then
// a panic will be issued.
//
// Calling SetRand with nil sets the random number generator to the default
// generator.
func SetRand(r io.Reader) {
if r == nil {
rander = rand.Reader
return
}
rander = r
}

559
vendor/github.com/google/uuid/uuid_test.go generated vendored Normal file
View File

@ -0,0 +1,559 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"bytes"
"fmt"
"os"
"runtime"
"strings"
"testing"
"time"
"unsafe"
)
type test struct {
in string
version Version
variant Variant
isuuid bool
}
var tests = []test{
{"f47ac10b-58cc-0372-8567-0e02b2c3d479", 0, RFC4122, true},
{"f47ac10b-58cc-1372-8567-0e02b2c3d479", 1, RFC4122, true},
{"f47ac10b-58cc-2372-8567-0e02b2c3d479", 2, RFC4122, true},
{"f47ac10b-58cc-3372-8567-0e02b2c3d479", 3, RFC4122, true},
{"f47ac10b-58cc-4372-8567-0e02b2c3d479", 4, RFC4122, true},
{"f47ac10b-58cc-5372-8567-0e02b2c3d479", 5, RFC4122, true},
{"f47ac10b-58cc-6372-8567-0e02b2c3d479", 6, RFC4122, true},
{"f47ac10b-58cc-7372-8567-0e02b2c3d479", 7, RFC4122, true},
{"f47ac10b-58cc-8372-8567-0e02b2c3d479", 8, RFC4122, true},
{"f47ac10b-58cc-9372-8567-0e02b2c3d479", 9, RFC4122, true},
{"f47ac10b-58cc-a372-8567-0e02b2c3d479", 10, RFC4122, true},
{"f47ac10b-58cc-b372-8567-0e02b2c3d479", 11, RFC4122, true},
{"f47ac10b-58cc-c372-8567-0e02b2c3d479", 12, RFC4122, true},
{"f47ac10b-58cc-d372-8567-0e02b2c3d479", 13, RFC4122, true},
{"f47ac10b-58cc-e372-8567-0e02b2c3d479", 14, RFC4122, true},
{"f47ac10b-58cc-f372-8567-0e02b2c3d479", 15, RFC4122, true},
{"urn:uuid:f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true},
{"URN:UUID:f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true},
{"f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true},
{"f47ac10b-58cc-4372-1567-0e02b2c3d479", 4, Reserved, true},
{"f47ac10b-58cc-4372-2567-0e02b2c3d479", 4, Reserved, true},
{"f47ac10b-58cc-4372-3567-0e02b2c3d479", 4, Reserved, true},
{"f47ac10b-58cc-4372-4567-0e02b2c3d479", 4, Reserved, true},
{"f47ac10b-58cc-4372-5567-0e02b2c3d479", 4, Reserved, true},
{"f47ac10b-58cc-4372-6567-0e02b2c3d479", 4, Reserved, true},
{"f47ac10b-58cc-4372-7567-0e02b2c3d479", 4, Reserved, true},
{"f47ac10b-58cc-4372-8567-0e02b2c3d479", 4, RFC4122, true},
{"f47ac10b-58cc-4372-9567-0e02b2c3d479", 4, RFC4122, true},
{"f47ac10b-58cc-4372-a567-0e02b2c3d479", 4, RFC4122, true},
{"f47ac10b-58cc-4372-b567-0e02b2c3d479", 4, RFC4122, true},
{"f47ac10b-58cc-4372-c567-0e02b2c3d479", 4, Microsoft, true},
{"f47ac10b-58cc-4372-d567-0e02b2c3d479", 4, Microsoft, true},
{"f47ac10b-58cc-4372-e567-0e02b2c3d479", 4, Future, true},
{"f47ac10b-58cc-4372-f567-0e02b2c3d479", 4, Future, true},
{"f47ac10b158cc-5372-a567-0e02b2c3d479", 0, Invalid, false},
{"f47ac10b-58cc25372-a567-0e02b2c3d479", 0, Invalid, false},
{"f47ac10b-58cc-53723a567-0e02b2c3d479", 0, Invalid, false},
{"f47ac10b-58cc-5372-a56740e02b2c3d479", 0, Invalid, false},
{"f47ac10b-58cc-5372-a567-0e02-2c3d479", 0, Invalid, false},
{"g47ac10b-58cc-4372-a567-0e02b2c3d479", 0, Invalid, false},
{"{f47ac10b-58cc-0372-8567-0e02b2c3d479}", 0, RFC4122, true},
{"{f47ac10b-58cc-0372-8567-0e02b2c3d479", 0, Invalid, false},
{"f47ac10b-58cc-0372-8567-0e02b2c3d479}", 0, Invalid, false},
{"f47ac10b58cc037285670e02b2c3d479", 0, RFC4122, true},
{"f47ac10b58cc037285670e02b2c3d4790", 0, Invalid, false},
{"f47ac10b58cc037285670e02b2c3d47", 0, Invalid, false},
}
var constants = []struct {
c interface{}
name string
}{
{Person, "Person"},
{Group, "Group"},
{Org, "Org"},
{Invalid, "Invalid"},
{RFC4122, "RFC4122"},
{Reserved, "Reserved"},
{Microsoft, "Microsoft"},
{Future, "Future"},
{Domain(17), "Domain17"},
{Variant(42), "BadVariant42"},
}
func testTest(t *testing.T, in string, tt test) {
uuid, err := Parse(in)
if ok := (err == nil); ok != tt.isuuid {
t.Errorf("Parse(%s) got %v expected %v\b", in, ok, tt.isuuid)
}
if err != nil {
return
}
if v := uuid.Variant(); v != tt.variant {
t.Errorf("Variant(%s) got %d expected %d\b", in, v, tt.variant)
}
if v := uuid.Version(); v != tt.version {
t.Errorf("Version(%s) got %d expected %d\b", in, v, tt.version)
}
}
func testBytes(t *testing.T, in []byte, tt test) {
uuid, err := ParseBytes(in)
if ok := (err == nil); ok != tt.isuuid {
t.Errorf("ParseBytes(%s) got %v expected %v\b", in, ok, tt.isuuid)
}
if err != nil {
return
}
suuid, _ := Parse(string(in))
if uuid != suuid {
t.Errorf("ParseBytes(%s) got %v expected %v\b", in, uuid, suuid)
}
}
func TestUUID(t *testing.T) {
for _, tt := range tests {
testTest(t, tt.in, tt)
testTest(t, strings.ToUpper(tt.in), tt)
testBytes(t, []byte(tt.in), tt)
}
}
func TestFromBytes(t *testing.T) {
b := []byte{
0x7d, 0x44, 0x48, 0x40,
0x9d, 0xc0,
0x11, 0xd1,
0xb2, 0x45,
0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2,
}
uuid, err := FromBytes(b)
if err != nil {
t.Fatalf("%s", err)
}
for i := 0; i < len(uuid); i++ {
if b[i] != uuid[i] {
t.Fatalf("FromBytes() got %v expected %v\b", uuid[:], b)
}
}
}
func TestConstants(t *testing.T) {
for x, tt := range constants {
v, ok := tt.c.(fmt.Stringer)
if !ok {
t.Errorf("%x: %v: not a stringer", x, v)
} else if s := v.String(); s != tt.name {
v, _ := tt.c.(int)
t.Errorf("%x: Constant %T:%d gives %q, expected %q", x, tt.c, v, s, tt.name)
}
}
}
func TestRandomUUID(t *testing.T) {
m := make(map[string]bool)
for x := 1; x < 32; x++ {
uuid := New()
s := uuid.String()
if m[s] {
t.Errorf("NewRandom returned duplicated UUID %s", s)
}
m[s] = true
if v := uuid.Version(); v != 4 {
t.Errorf("Random UUID of version %s", v)
}
if uuid.Variant() != RFC4122 {
t.Errorf("Random UUID is variant %d", uuid.Variant())
}
}
}
func TestNew(t *testing.T) {
m := make(map[UUID]bool)
for x := 1; x < 32; x++ {
s := New()
if m[s] {
t.Errorf("New returned duplicated UUID %s", s)
}
m[s] = true
uuid, err := Parse(s.String())
if err != nil {
t.Errorf("New.String() returned %q which does not decode", s)
continue
}
if v := uuid.Version(); v != 4 {
t.Errorf("Random UUID of version %s", v)
}
if uuid.Variant() != RFC4122 {
t.Errorf("Random UUID is variant %d", uuid.Variant())
}
}
}
func TestClockSeq(t *testing.T) {
// Fake time.Now for this test to return a monotonically advancing time; restore it at end.
defer func(orig func() time.Time) { timeNow = orig }(timeNow)
monTime := time.Now()
timeNow = func() time.Time {
monTime = monTime.Add(1 * time.Second)
return monTime
}
SetClockSequence(-1)
uuid1, err := NewUUID()
if err != nil {
t.Fatalf("could not create UUID: %v", err)
}
uuid2, err := NewUUID()
if err != nil {
t.Fatalf("could not create UUID: %v", err)
}
if s1, s2 := uuid1.ClockSequence(), uuid2.ClockSequence(); s1 != s2 {
t.Errorf("clock sequence %d != %d", s1, s2)
}
SetClockSequence(-1)
uuid2, err = NewUUID()
if err != nil {
t.Fatalf("could not create UUID: %v", err)
}
// Just on the very off chance we generated the same sequence
// two times we try again.
if uuid1.ClockSequence() == uuid2.ClockSequence() {
SetClockSequence(-1)
uuid2, err = NewUUID()
if err != nil {
t.Fatalf("could not create UUID: %v", err)
}
}
if s1, s2 := uuid1.ClockSequence(), uuid2.ClockSequence(); s1 == s2 {
t.Errorf("Duplicate clock sequence %d", s1)
}
SetClockSequence(0x1234)
uuid1, err = NewUUID()
if err != nil {
t.Fatalf("could not create UUID: %v", err)
}
if seq := uuid1.ClockSequence(); seq != 0x1234 {
t.Errorf("%s: expected seq 0x1234 got 0x%04x", uuid1, seq)
}
}
func TestCoding(t *testing.T) {
text := "7d444840-9dc0-11d1-b245-5ffdce74fad2"
urn := "urn:uuid:7d444840-9dc0-11d1-b245-5ffdce74fad2"
data := UUID{
0x7d, 0x44, 0x48, 0x40,
0x9d, 0xc0,
0x11, 0xd1,
0xb2, 0x45,
0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2,
}
if v := data.String(); v != text {
t.Errorf("%x: encoded to %s, expected %s", data, v, text)
}
if v := data.URN(); v != urn {
t.Errorf("%x: urn is %s, expected %s", data, v, urn)
}
uuid, err := Parse(text)
if err != nil {
t.Errorf("Parse returned unexpected error %v", err)
}
if data != uuid {
t.Errorf("%s: decoded to %s, expected %s", text, uuid, data)
}
}
func TestVersion1(t *testing.T) {
uuid1, err := NewUUID()
if err != nil {
t.Fatalf("could not create UUID: %v", err)
}
uuid2, err := NewUUID()
if err != nil {
t.Fatalf("could not create UUID: %v", err)
}
if uuid1 == uuid2 {
t.Errorf("%s:duplicate uuid", uuid1)
}
if v := uuid1.Version(); v != 1 {
t.Errorf("%s: version %s expected 1", uuid1, v)
}
if v := uuid2.Version(); v != 1 {
t.Errorf("%s: version %s expected 1", uuid2, v)
}
n1 := uuid1.NodeID()
n2 := uuid2.NodeID()
if !bytes.Equal(n1, n2) {
t.Errorf("Different nodes %x != %x", n1, n2)
}
t1 := uuid1.Time()
t2 := uuid2.Time()
q1 := uuid1.ClockSequence()
q2 := uuid2.ClockSequence()
switch {
case t1 == t2 && q1 == q2:
t.Error("time stopped")
case t1 > t2 && q1 == q2:
t.Error("time reversed")
case t1 < t2 && q1 != q2:
t.Error("clock sequence changed unexpectedly")
}
}
func TestNode(t *testing.T) {
// This test is mostly to make sure we don't leave nodeMu locked.
ifname = ""
if ni := NodeInterface(); ni != "" {
t.Errorf("NodeInterface got %q, want %q", ni, "")
}
if SetNodeInterface("xyzzy") {
t.Error("SetNodeInterface succeeded on a bad interface name")
}
if !SetNodeInterface("") {
t.Error("SetNodeInterface failed")
}
if runtime.GOARCH != "js" {
if ni := NodeInterface(); ni == "" {
t.Error("NodeInterface returned an empty string")
}
}
ni := NodeID()
if len(ni) != 6 {
t.Errorf("ni got %d bytes, want 6", len(ni))
}
hasData := false
for _, b := range ni {
if b != 0 {
hasData = true
}
}
if !hasData {
t.Error("nodeid is all zeros")
}
id := []byte{1, 2, 3, 4, 5, 6, 7, 8}
SetNodeID(id)
ni = NodeID()
if !bytes.Equal(ni, id[:6]) {
t.Errorf("got nodeid %v, want %v", ni, id[:6])
}
if ni := NodeInterface(); ni != "user" {
t.Errorf("got interface %q, want %q", ni, "user")
}
}
func TestNodeAndTime(t *testing.T) {
// Time is February 5, 1998 12:30:23.136364800 AM GMT
uuid, err := Parse("7d444840-9dc0-11d1-b245-5ffdce74fad2")
if err != nil {
t.Fatalf("Parser returned unexpected error %v", err)
}
node := []byte{0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2}
ts := uuid.Time()
c := time.Unix(ts.UnixTime())
want := time.Date(1998, 2, 5, 0, 30, 23, 136364800, time.UTC)
if !c.Equal(want) {
t.Errorf("Got time %v, want %v", c, want)
}
if !bytes.Equal(node, uuid.NodeID()) {
t.Errorf("Expected node %v got %v", node, uuid.NodeID())
}
}
func TestMD5(t *testing.T) {
uuid := NewMD5(NameSpaceDNS, []byte("python.org")).String()
want := "6fa459ea-ee8a-3ca4-894e-db77e160355e"
if uuid != want {
t.Errorf("MD5: got %q expected %q", uuid, want)
}
}
func TestSHA1(t *testing.T) {
uuid := NewSHA1(NameSpaceDNS, []byte("python.org")).String()
want := "886313e1-3b8a-5372-9b90-0c9aee199e5d"
if uuid != want {
t.Errorf("SHA1: got %q expected %q", uuid, want)
}
}
func TestNodeID(t *testing.T) {
nid := []byte{1, 2, 3, 4, 5, 6}
SetNodeInterface("")
s := NodeInterface()
if runtime.GOARCH != "js" {
if s == "" || s == "user" {
t.Errorf("NodeInterface %q after SetInterface", s)
}
}
node1 := NodeID()
if node1 == nil {
t.Error("NodeID nil after SetNodeInterface", s)
}
SetNodeID(nid)
s = NodeInterface()
if s != "user" {
t.Errorf("Expected NodeInterface %q got %q", "user", s)
}
node2 := NodeID()
if node2 == nil {
t.Error("NodeID nil after SetNodeID", s)
}
if bytes.Equal(node1, node2) {
t.Error("NodeID not changed after SetNodeID", s)
} else if !bytes.Equal(nid, node2) {
t.Errorf("NodeID is %x, expected %x", node2, nid)
}
}
func testDCE(t *testing.T, name string, uuid UUID, err error, domain Domain, id uint32) {
if err != nil {
t.Errorf("%s failed: %v", name, err)
return
}
if v := uuid.Version(); v != 2 {
t.Errorf("%s: %s: expected version 2, got %s", name, uuid, v)
return
}
if v := uuid.Domain(); v != domain {
t.Errorf("%s: %s: expected domain %d, got %d", name, uuid, domain, v)
}
if v := uuid.ID(); v != id {
t.Errorf("%s: %s: expected id %d, got %d", name, uuid, id, v)
}
}
func TestDCE(t *testing.T) {
uuid, err := NewDCESecurity(42, 12345678)
testDCE(t, "NewDCESecurity", uuid, err, 42, 12345678)
uuid, err = NewDCEPerson()
testDCE(t, "NewDCEPerson", uuid, err, Person, uint32(os.Getuid()))
uuid, err = NewDCEGroup()
testDCE(t, "NewDCEGroup", uuid, err, Group, uint32(os.Getgid()))
}
type badRand struct{}
func (r badRand) Read(buf []byte) (int, error) {
for i := range buf {
buf[i] = byte(i)
}
return len(buf), nil
}
func TestBadRand(t *testing.T) {
SetRand(badRand{})
uuid1 := New()
uuid2 := New()
if uuid1 != uuid2 {
t.Errorf("expected duplicates, got %q and %q", uuid1, uuid2)
}
SetRand(nil)
uuid1 = New()
uuid2 = New()
if uuid1 == uuid2 {
t.Errorf("unexpected duplicates, got %q", uuid1)
}
}
var asString = "f47ac10b-58cc-0372-8567-0e02b2c3d479"
var asBytes = []byte(asString)
func BenchmarkParse(b *testing.B) {
for i := 0; i < b.N; i++ {
_, err := Parse(asString)
if err != nil {
b.Fatal(err)
}
}
}
func BenchmarkParseBytes(b *testing.B) {
for i := 0; i < b.N; i++ {
_, err := ParseBytes(asBytes)
if err != nil {
b.Fatal(err)
}
}
}
// parseBytesUnsafe is to benchmark using unsafe.
func parseBytesUnsafe(b []byte) (UUID, error) {
return Parse(*(*string)(unsafe.Pointer(&b)))
}
func BenchmarkParseBytesUnsafe(b *testing.B) {
for i := 0; i < b.N; i++ {
_, err := parseBytesUnsafe(asBytes)
if err != nil {
b.Fatal(err)
}
}
}
// parseBytesCopy is to benchmark not using unsafe.
func parseBytesCopy(b []byte) (UUID, error) {
return Parse(string(b))
}
func BenchmarkParseBytesCopy(b *testing.B) {
for i := 0; i < b.N; i++ {
_, err := parseBytesCopy(asBytes)
if err != nil {
b.Fatal(err)
}
}
}
func BenchmarkNew(b *testing.B) {
for i := 0; i < b.N; i++ {
New()
}
}
func BenchmarkUUID_String(b *testing.B) {
uuid, err := Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479")
if err != nil {
b.Fatal(err)
}
for i := 0; i < b.N; i++ {
if uuid.String() == "" {
b.Fatal("invalid uuid")
}
}
}
func BenchmarkUUID_URN(b *testing.B) {
uuid, err := Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479")
if err != nil {
b.Fatal(err)
}
for i := 0; i < b.N; i++ {
if uuid.URN() == "" {
b.Fatal("invalid uuid")
}
}
}

44
vendor/github.com/google/uuid/version1.go generated vendored Normal file
View File

@ -0,0 +1,44 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"encoding/binary"
)
// NewUUID returns a Version 1 UUID based on the current NodeID and clock
// sequence, and the current time. If the NodeID has not been set by SetNodeID
// or SetNodeInterface then it will be set automatically. If the NodeID cannot
// be set NewUUID returns nil. If clock sequence has not been set by
// SetClockSequence then it will be set automatically. If GetTime fails to
// return the current NewUUID returns nil and an error.
//
// In most cases, New should be used.
func NewUUID() (UUID, error) {
nodeMu.Lock()
if nodeID == zeroID {
setNodeInterface("")
}
nodeMu.Unlock()
var uuid UUID
now, seq, err := GetTime()
if err != nil {
return uuid, err
}
timeLow := uint32(now & 0xffffffff)
timeMid := uint16((now >> 32) & 0xffff)
timeHi := uint16((now >> 48) & 0x0fff)
timeHi |= 0x1000 // Version 1
binary.BigEndian.PutUint32(uuid[0:], timeLow)
binary.BigEndian.PutUint16(uuid[4:], timeMid)
binary.BigEndian.PutUint16(uuid[6:], timeHi)
binary.BigEndian.PutUint16(uuid[8:], seq)
copy(uuid[10:], nodeID[:])
return uuid, nil
}

38
vendor/github.com/google/uuid/version4.go generated vendored Normal file
View File

@ -0,0 +1,38 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import "io"
// New creates a new random UUID or panics. New is equivalent to
// the expression
//
// uuid.Must(uuid.NewRandom())
func New() UUID {
return Must(NewRandom())
}
// NewRandom returns a Random (Version 4) UUID.
//
// The strength of the UUIDs is based on the strength of the crypto/rand
// package.
//
// A note about uniqueness derived from the UUID Wikipedia entry:
//
// Randomly generated UUIDs have 122 random bits. One's annual risk of being
// hit by a meteorite is estimated to be one chance in 17 billion, that
// means the probability is about 0.00000000006 (6 × 1011),
// equivalent to the odds of creating a few tens of trillions of UUIDs in a
// year and having one duplicate.
func NewRandom() (UUID, error) {
var uuid UUID
_, err := io.ReadFull(rander, uuid[:])
if err != nil {
return Nil, err
}
uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10
return uuid, nil
}

10
vendor/github.com/pborman/uuid/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,10 @@
language: go
go:
- "1.9"
- "1.10"
- "1.11"
- tip
script:
- go test -v ./...

10
vendor/github.com/pborman/uuid/CONTRIBUTING.md generated vendored Normal file
View File

@ -0,0 +1,10 @@
# How to contribute
We definitely welcome patches and contribution to this project!
### Legal requirements
In order to protect both you and ourselves, you will need to sign the
[Contributor License Agreement](https://cla.developers.google.com/clas).
You may have already signed it for other Google projects.

1
vendor/github.com/pborman/uuid/CONTRIBUTORS generated vendored Normal file
View File

@ -0,0 +1 @@
Paul Borman <borman@google.com>

27
vendor/github.com/pborman/uuid/LICENSE generated vendored Normal file
View File

@ -0,0 +1,27 @@
Copyright (c) 2009,2014 Google Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

15
vendor/github.com/pborman/uuid/README.md generated vendored Normal file
View File

@ -0,0 +1,15 @@
This project was automatically exported from code.google.com/p/go-uuid
# uuid ![build status](https://travis-ci.org/pborman/uuid.svg?branch=master)
The uuid package generates and inspects UUIDs based on [RFC 4122](http://tools.ietf.org/html/rfc4122) and DCE 1.1: Authentication and Security Services.
This package now leverages the github.com/google/uuid package (which is based off an earlier version of this package).
###### Install
`go get github.com/pborman/uuid`
###### Documentation
[![GoDoc](https://godoc.org/github.com/pborman/uuid?status.svg)](http://godoc.org/github.com/pborman/uuid)
Full `go doc` style documentation for the package can be viewed online without installing this package by using the GoDoc site here:
http://godoc.org/github.com/pborman/uuid

84
vendor/github.com/pborman/uuid/dce.go generated vendored Normal file
View File

@ -0,0 +1,84 @@
// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"encoding/binary"
"fmt"
"os"
)
// A Domain represents a Version 2 domain
type Domain byte
// Domain constants for DCE Security (Version 2) UUIDs.
const (
Person = Domain(0)
Group = Domain(1)
Org = Domain(2)
)
// NewDCESecurity returns a DCE Security (Version 2) UUID.
//
// The domain should be one of Person, Group or Org.
// On a POSIX system the id should be the users UID for the Person
// domain and the users GID for the Group. The meaning of id for
// the domain Org or on non-POSIX systems is site defined.
//
// For a given domain/id pair the same token may be returned for up to
// 7 minutes and 10 seconds.
func NewDCESecurity(domain Domain, id uint32) UUID {
uuid := NewUUID()
if uuid != nil {
uuid[6] = (uuid[6] & 0x0f) | 0x20 // Version 2
uuid[9] = byte(domain)
binary.BigEndian.PutUint32(uuid[0:], id)
}
return uuid
}
// NewDCEPerson returns a DCE Security (Version 2) UUID in the person
// domain with the id returned by os.Getuid.
//
// NewDCEPerson(Person, uint32(os.Getuid()))
func NewDCEPerson() UUID {
return NewDCESecurity(Person, uint32(os.Getuid()))
}
// NewDCEGroup returns a DCE Security (Version 2) UUID in the group
// domain with the id returned by os.Getgid.
//
// NewDCEGroup(Group, uint32(os.Getgid()))
func NewDCEGroup() UUID {
return NewDCESecurity(Group, uint32(os.Getgid()))
}
// Domain returns the domain for a Version 2 UUID or false.
func (uuid UUID) Domain() (Domain, bool) {
if v, _ := uuid.Version(); v != 2 {
return 0, false
}
return Domain(uuid[9]), true
}
// Id returns the id for a Version 2 UUID or false.
func (uuid UUID) Id() (uint32, bool) {
if v, _ := uuid.Version(); v != 2 {
return 0, false
}
return binary.BigEndian.Uint32(uuid[0:4]), true
}
func (d Domain) String() string {
switch d {
case Person:
return "Person"
case Group:
return "Group"
case Org:
return "Org"
}
return fmt.Sprintf("Domain%d", int(d))
}

13
vendor/github.com/pborman/uuid/doc.go generated vendored Normal file
View File

@ -0,0 +1,13 @@
// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// The uuid package generates and inspects UUIDs.
//
// UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security
// Services.
//
// This package is a partial wrapper around the github.com/google/uuid package.
// This package represents a UUID as []byte while github.com/google/uuid
// represents a UUID as [16]byte.
package uuid

3
vendor/github.com/pborman/uuid/go.mod generated vendored Normal file
View File

@ -0,0 +1,3 @@
module github.com/pborman/uuid
require github.com/google/uuid v1.0.0

2
vendor/github.com/pborman/uuid/go.sum generated vendored Normal file
View File

@ -0,0 +1,2 @@
github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=

53
vendor/github.com/pborman/uuid/hash.go generated vendored Normal file
View File

@ -0,0 +1,53 @@
// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"crypto/md5"
"crypto/sha1"
"hash"
)
// Well known Name Space IDs and UUIDs
var (
NameSpace_DNS = Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
NameSpace_URL = Parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8")
NameSpace_OID = Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8")
NameSpace_X500 = Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8")
NIL = Parse("00000000-0000-0000-0000-000000000000")
)
// NewHash returns a new UUID derived from the hash of space concatenated with
// data generated by h. The hash should be at least 16 byte in length. The
// first 16 bytes of the hash are used to form the UUID. The version of the
// UUID will be the lower 4 bits of version. NewHash is used to implement
// NewMD5 and NewSHA1.
func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID {
h.Reset()
h.Write(space)
h.Write([]byte(data))
s := h.Sum(nil)
uuid := make([]byte, 16)
copy(uuid, s)
uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4)
uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 4122 variant
return uuid
}
// NewMD5 returns a new MD5 (Version 3) UUID based on the
// supplied name space and data.
//
// NewHash(md5.New(), space, data, 3)
func NewMD5(space UUID, data []byte) UUID {
return NewHash(md5.New(), space, data, 3)
}
// NewSHA1 returns a new SHA1 (Version 5) UUID based on the
// supplied name space and data.
//
// NewHash(sha1.New(), space, data, 5)
func NewSHA1(space UUID, data []byte) UUID {
return NewHash(sha1.New(), space, data, 5)
}

85
vendor/github.com/pborman/uuid/marshal.go generated vendored Normal file
View File

@ -0,0 +1,85 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"errors"
"fmt"
guuid "github.com/google/uuid"
)
// MarshalText implements encoding.TextMarshaler.
func (u UUID) MarshalText() ([]byte, error) {
if len(u) != 16 {
return nil, nil
}
var js [36]byte
encodeHex(js[:], u)
return js[:], nil
}
// UnmarshalText implements encoding.TextUnmarshaler.
func (u *UUID) UnmarshalText(data []byte) error {
if len(data) == 0 {
return nil
}
id := Parse(string(data))
if id == nil {
return errors.New("invalid UUID")
}
*u = id
return nil
}
// MarshalBinary implements encoding.BinaryMarshaler.
func (u UUID) MarshalBinary() ([]byte, error) {
return u[:], nil
}
// UnmarshalBinary implements encoding.BinaryUnmarshaler.
func (u *UUID) UnmarshalBinary(data []byte) error {
if len(data) == 0 {
return nil
}
if len(data) != 16 {
return fmt.Errorf("invalid UUID (got %d bytes)", len(data))
}
var id [16]byte
copy(id[:], data)
*u = id[:]
return nil
}
// MarshalText implements encoding.TextMarshaler.
func (u Array) MarshalText() ([]byte, error) {
var js [36]byte
encodeHex(js[:], u[:])
return js[:], nil
}
// UnmarshalText implements encoding.TextUnmarshaler.
func (u *Array) UnmarshalText(data []byte) error {
id, err := guuid.ParseBytes(data)
if err != nil {
return err
}
*u = Array(id)
return nil
}
// MarshalBinary implements encoding.BinaryMarshaler.
func (u Array) MarshalBinary() ([]byte, error) {
return u[:], nil
}
// UnmarshalBinary implements encoding.BinaryUnmarshaler.
func (u *Array) UnmarshalBinary(data []byte) error {
if len(data) != 16 {
return fmt.Errorf("invalid UUID (got %d bytes)", len(data))
}
copy(u[:], data)
return nil
}

124
vendor/github.com/pborman/uuid/marshal_test.go generated vendored Normal file
View File

@ -0,0 +1,124 @@
// Copyright 2014 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"bytes"
"encoding/json"
"reflect"
"testing"
)
var testUUID = Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479")
var testArray = testUUID.Array()
func TestJSON(t *testing.T) {
type S struct {
ID1 UUID
ID2 UUID
}
s1 := S{ID1: testUUID}
data, err := json.Marshal(&s1)
if err != nil {
t.Fatal(err)
}
var s2 S
if err := json.Unmarshal(data, &s2); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(&s1, &s2) {
t.Errorf("got %#v, want %#v", s2, s1)
}
}
func TestJSONArray(t *testing.T) {
type S struct {
ID1 Array
ID2 Array
}
s1 := S{ID1: testArray}
data, err := json.Marshal(&s1)
if err != nil {
t.Fatal(err)
}
var s2 S
if err := json.Unmarshal(data, &s2); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(&s1, &s2) {
t.Errorf("got %#v, want %#v", s2, s1)
}
}
func TestMarshal(t *testing.T) {
data, err := testUUID.MarshalBinary()
if err != nil {
t.Fatalf("MarhsalBinary returned unexpected error %v", err)
}
if !bytes.Equal(data, testUUID) {
t.Fatalf("MarhsalBinary returns %x, want %x", data, testUUID)
}
var u UUID
u.UnmarshalBinary(data)
if !Equal(data, u) {
t.Fatalf("UnmarhsalBinary returns %v, want %v", u, testUUID)
}
}
func TestMarshalArray(t *testing.T) {
data, err := testArray.MarshalBinary()
if err != nil {
t.Fatalf("MarhsalBinary returned unexpected error %v", err)
}
if !bytes.Equal(data, testUUID) {
t.Fatalf("MarhsalBinary returns %x, want %x", data, testUUID)
}
var a Array
a.UnmarshalBinary(data)
if a != testArray {
t.Fatalf("UnmarhsalBinary returns %v, want %v", a, testArray)
}
}
func TestMarshalTextArray(t *testing.T) {
data, err := testArray.MarshalText()
if err != nil {
t.Fatalf("MarhsalText returned unexpected error %v", err)
}
var a Array
a.UnmarshalText(data)
if a != testArray {
t.Fatalf("UnmarhsalText returns %v, want %v", a, testArray)
}
}
func BenchmarkUUID_MarshalJSON(b *testing.B) {
x := &struct {
UUID UUID `json:"uuid"`
}{}
x.UUID = Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479")
if x.UUID == nil {
b.Fatal("invalid uuid")
}
for i := 0; i < b.N; i++ {
js, err := json.Marshal(x)
if err != nil {
b.Fatalf("marshal json: %#v (%v)", js, err)
}
}
}
func BenchmarkUUID_UnmarshalJSON(b *testing.B) {
js := []byte(`{"uuid":"f47ac10b-58cc-0372-8567-0e02b2c3d479"}`)
var x *struct {
UUID UUID `json:"uuid"`
}
for i := 0; i < b.N; i++ {
err := json.Unmarshal(js, &x)
if err != nil {
b.Fatalf("marshal json: %#v (%v)", js, err)
}
}
}

50
vendor/github.com/pborman/uuid/node.go generated vendored Normal file
View File

@ -0,0 +1,50 @@
// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
guuid "github.com/google/uuid"
)
// NodeInterface returns the name of the interface from which the NodeID was
// derived. The interface "user" is returned if the NodeID was set by
// SetNodeID.
func NodeInterface() string {
return guuid.NodeInterface()
}
// SetNodeInterface selects the hardware address to be used for Version 1 UUIDs.
// If name is "" then the first usable interface found will be used or a random
// Node ID will be generated. If a named interface cannot be found then false
// is returned.
//
// SetNodeInterface never fails when name is "".
func SetNodeInterface(name string) bool {
return guuid.SetNodeInterface(name)
}
// NodeID returns a slice of a copy of the current Node ID, setting the Node ID
// if not already set.
func NodeID() []byte {
return guuid.NodeID()
}
// SetNodeID sets the Node ID to be used for Version 1 UUIDs. The first 6 bytes
// of id are used. If id is less than 6 bytes then false is returned and the
// Node ID is not set.
func SetNodeID(id []byte) bool {
return guuid.SetNodeID(id)
}
// NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is
// not valid. The NodeID is only well defined for version 1 and 2 UUIDs.
func (uuid UUID) NodeID() []byte {
if len(uuid) != 16 {
return nil
}
node := make([]byte, 6)
copy(node, uuid[10:])
return node
}

66
vendor/github.com/pborman/uuid/seq_test.go generated vendored Normal file
View File

@ -0,0 +1,66 @@
// Copyright 2014 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"flag"
"runtime"
"testing"
"time"
)
// This test is only run when --regressions is passed on the go test line.
var regressions = flag.Bool("regressions", false, "run uuid regression tests")
// TestClockSeqRace tests for a particular race condition of returning two
// identical Version1 UUIDs. The duration of 1 minute was chosen as the race
// condition, before being fixed, nearly always occured in under 30 seconds.
func TestClockSeqRace(t *testing.T) {
if !*regressions {
t.Skip("skipping regression tests")
}
duration := time.Minute
done := make(chan struct{})
defer close(done)
ch := make(chan UUID, 10000)
ncpu := runtime.NumCPU()
switch ncpu {
case 0, 1:
// We can't run the test effectively.
t.Skip("skipping race test, only one CPU detected")
return
default:
runtime.GOMAXPROCS(ncpu)
}
for i := 0; i < ncpu; i++ {
go func() {
for {
select {
case <-done:
return
case ch <- NewUUID():
}
}
}()
}
uuids := make(map[string]bool)
cnt := 0
start := time.Now()
for u := range ch {
s := u.String()
if uuids[s] {
t.Errorf("duplicate uuid after %d in %v: %s", cnt, time.Since(start), s)
return
}
uuids[s] = true
if time.Since(start) > duration {
return
}
cnt++
}
}

68
vendor/github.com/pborman/uuid/sql.go generated vendored Normal file
View File

@ -0,0 +1,68 @@
// Copyright 2015 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"database/sql/driver"
"errors"
"fmt"
)
// Scan implements sql.Scanner so UUIDs can be read from databases transparently
// Currently, database types that map to string and []byte are supported. Please
// consult database-specific driver documentation for matching types.
func (uuid *UUID) Scan(src interface{}) error {
switch src.(type) {
case string:
// if an empty UUID comes from a table, we return a null UUID
if src.(string) == "" {
return nil
}
// see uuid.Parse for required string format
parsed := Parse(src.(string))
if parsed == nil {
return errors.New("Scan: invalid UUID format")
}
*uuid = parsed
case []byte:
b := src.([]byte)
// if an empty UUID comes from a table, we return a null UUID
if len(b) == 0 {
return nil
}
// assumes a simple slice of bytes if 16 bytes
// otherwise attempts to parse
if len(b) == 16 {
parsed := make([]byte, 16)
copy(parsed, b)
*uuid = UUID(parsed)
} else {
u := Parse(string(b))
if u == nil {
return errors.New("Scan: invalid UUID format")
}
*uuid = u
}
default:
return fmt.Errorf("Scan: unable to scan type %T into UUID", src)
}
return nil
}
// Value implements sql.Valuer so that UUIDs can be written to databases
// transparently. Currently, UUIDs map to strings. Please consult
// database-specific driver documentation for matching types.
func (uuid UUID) Value() (driver.Value, error) {
return uuid.String(), nil
}

96
vendor/github.com/pborman/uuid/sql_test.go generated vendored Normal file
View File

@ -0,0 +1,96 @@
// Copyright 2015 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"strings"
"testing"
)
func TestScan(t *testing.T) {
var stringTest string = "f47ac10b-58cc-0372-8567-0e02b2c3d479"
var byteTest []byte = Parse(stringTest)
var badTypeTest int = 6
var invalidTest string = "f47ac10b-58cc-0372-8567-0e02b2c3d4"
// sunny day tests
var uuid UUID
err := (&uuid).Scan(stringTest)
if err != nil {
t.Fatal(err)
}
err = (&uuid).Scan([]byte(stringTest))
if err != nil {
t.Fatal(err)
}
err = (&uuid).Scan(byteTest)
if err != nil {
t.Fatal(err)
}
// bad type tests
err = (&uuid).Scan(badTypeTest)
if err == nil {
t.Error("int correctly parsed and shouldn't have")
}
if !strings.Contains(err.Error(), "unable to scan type") {
t.Error("attempting to parse an int returned an incorrect error message")
}
// invalid/incomplete uuids
err = (&uuid).Scan(invalidTest)
if err == nil {
t.Error("invalid uuid was parsed without error")
}
if !strings.Contains(err.Error(), "invalid UUID") {
t.Error("attempting to parse an invalid UUID returned an incorrect error message")
}
err = (&uuid).Scan(byteTest[:len(byteTest)-2])
if err == nil {
t.Error("invalid byte uuid was parsed without error")
}
if !strings.Contains(err.Error(), "invalid UUID") {
t.Error("attempting to parse an invalid byte UUID returned an incorrect error message")
}
// empty tests
uuid = nil
var emptySlice []byte
err = (&uuid).Scan(emptySlice)
if err != nil {
t.Fatal(err)
}
if uuid != nil {
t.Error("UUID was not nil after scanning empty byte slice")
}
uuid = nil
var emptyString string
err = (&uuid).Scan(emptyString)
if err != nil {
t.Fatal(err)
}
if uuid != nil {
t.Error("UUID was not nil after scanning empty string")
}
}
func TestValue(t *testing.T) {
stringTest := "f47ac10b-58cc-0372-8567-0e02b2c3d479"
uuid := Parse(stringTest)
val, _ := uuid.Value()
if val != stringTest {
t.Error("Value() did not return expected string")
}
}

57
vendor/github.com/pborman/uuid/time.go generated vendored Normal file
View File

@ -0,0 +1,57 @@
// Copyright 2014 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"encoding/binary"
guuid "github.com/google/uuid"
)
// A Time represents a time as the number of 100's of nanoseconds since 15 Oct
// 1582.
type Time = guuid.Time
// GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and
// clock sequence as well as adjusting the clock sequence as needed. An error
// is returned if the current time cannot be determined.
func GetTime() (Time, uint16, error) { return guuid.GetTime() }
// ClockSequence returns the current clock sequence, generating one if not
// already set. The clock sequence is only used for Version 1 UUIDs.
//
// The uuid package does not use global static storage for the clock sequence or
// the last time a UUID was generated. Unless SetClockSequence a new random
// clock sequence is generated the first time a clock sequence is requested by
// ClockSequence, GetTime, or NewUUID. (section 4.2.1.1) sequence is generated
// for
func ClockSequence() int { return guuid.ClockSequence() }
// SetClockSeq sets the clock sequence to the lower 14 bits of seq. Setting to
// -1 causes a new sequence to be generated.
func SetClockSequence(seq int) { guuid.SetClockSequence(seq) }
// Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in
// uuid. It returns false if uuid is not valid. The time is only well defined
// for version 1 and 2 UUIDs.
func (uuid UUID) Time() (Time, bool) {
if len(uuid) != 16 {
return 0, false
}
time := int64(binary.BigEndian.Uint32(uuid[0:4]))
time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32
time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48
return Time(time), true
}
// ClockSequence returns the clock sequence encoded in uuid. It returns false
// if uuid is not valid. The clock sequence is only well defined for version 1
// and 2 UUIDs.
func (uuid UUID) ClockSequence() (int, bool) {
if len(uuid) != 16 {
return 0, false
}
return int(binary.BigEndian.Uint16(uuid[8:10])) & 0x3fff, true
}

32
vendor/github.com/pborman/uuid/util.go generated vendored Normal file
View File

@ -0,0 +1,32 @@
// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
// xvalues returns the value of a byte as a hexadecimal digit or 255.
var xvalues = [256]byte{
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255,
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
}
// xtob converts the the first two hex bytes of x into a byte.
func xtob(x string) (byte, bool) {
b1 := xvalues[x[0]]
b2 := xvalues[x[1]]
return (b1 << 4) | b2, b1 != 255 && b2 != 255
}

162
vendor/github.com/pborman/uuid/uuid.go generated vendored Normal file
View File

@ -0,0 +1,162 @@
// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"bytes"
"crypto/rand"
"encoding/hex"
"io"
guuid "github.com/google/uuid"
)
// Array is a pass-by-value UUID that can be used as an effecient key in a map.
type Array [16]byte
// UUID converts uuid into a slice.
func (uuid Array) UUID() UUID {
return uuid[:]
}
// String returns the string representation of uuid,
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
func (uuid Array) String() string {
return guuid.UUID(uuid).String()
}
// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC
// 4122.
type UUID []byte
// A Version represents a UUIDs version.
type Version = guuid.Version
// A Variant represents a UUIDs variant.
type Variant = guuid.Variant
// Constants returned by Variant.
const (
Invalid = guuid.Invalid // Invalid UUID
RFC4122 = guuid.RFC4122 // The variant specified in RFC4122
Reserved = guuid.Reserved // Reserved, NCS backward compatibility.
Microsoft = guuid.Microsoft // Reserved, Microsoft Corporation backward compatibility.
Future = guuid.Future // Reserved for future definition.
)
var rander = rand.Reader // random function
// New returns a new random (version 4) UUID as a string. It is a convenience
// function for NewRandom().String().
func New() string {
return NewRandom().String()
}
// Parse decodes s into a UUID or returns nil. See github.com/google/uuid for
// the formats parsed.
func Parse(s string) UUID {
gu, err := guuid.Parse(s)
if err == nil {
return gu[:]
}
return nil
}
// ParseBytes is like Parse, except it parses a byte slice instead of a string.
func ParseBytes(b []byte) (UUID, error) {
gu, err := guuid.ParseBytes(b)
if err == nil {
return gu[:], nil
}
return nil, err
}
// Equal returns true if uuid1 and uuid2 are equal.
func Equal(uuid1, uuid2 UUID) bool {
return bytes.Equal(uuid1, uuid2)
}
// Array returns an array representation of uuid that can be used as a map key.
// Array panics if uuid is not valid.
func (uuid UUID) Array() Array {
if len(uuid) != 16 {
panic("invalid uuid")
}
var a Array
copy(a[:], uuid)
return a
}
// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
// , or "" if uuid is invalid.
func (uuid UUID) String() string {
if len(uuid) != 16 {
return ""
}
var buf [36]byte
encodeHex(buf[:], uuid)
return string(buf[:])
}
// URN returns the RFC 2141 URN form of uuid,
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, or "" if uuid is invalid.
func (uuid UUID) URN() string {
if len(uuid) != 16 {
return ""
}
var buf [36 + 9]byte
copy(buf[:], "urn:uuid:")
encodeHex(buf[9:], uuid)
return string(buf[:])
}
func encodeHex(dst []byte, uuid UUID) {
hex.Encode(dst[:], uuid[:4])
dst[8] = '-'
hex.Encode(dst[9:13], uuid[4:6])
dst[13] = '-'
hex.Encode(dst[14:18], uuid[6:8])
dst[18] = '-'
hex.Encode(dst[19:23], uuid[8:10])
dst[23] = '-'
hex.Encode(dst[24:], uuid[10:])
}
// Variant returns the variant encoded in uuid. It returns Invalid if
// uuid is invalid.
func (uuid UUID) Variant() Variant {
if len(uuid) != 16 {
return Invalid
}
switch {
case (uuid[8] & 0xc0) == 0x80:
return RFC4122
case (uuid[8] & 0xe0) == 0xc0:
return Microsoft
case (uuid[8] & 0xe0) == 0xe0:
return Future
default:
return Reserved
}
}
// Version returns the version of uuid. It returns false if uuid is not
// valid.
func (uuid UUID) Version() (Version, bool) {
if len(uuid) != 16 {
return 0, false
}
return Version(uuid[6] >> 4), true
}
// SetRand sets the random number generator to r, which implements io.Reader.
// If r.Read returns an error when the package requests random data then
// a panic will be issued.
//
// Calling SetRand with nil sets the random number generator to the default
// generator.
func SetRand(r io.Reader) {
guuid.SetRand(r)
}

410
vendor/github.com/pborman/uuid/uuid_test.go generated vendored Normal file
View File

@ -0,0 +1,410 @@
// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
// Some of these tests can probably be removed as they are redundant with the
// tests in github.com/google/uuid.
import (
"bytes"
"fmt"
"os"
"strings"
"testing"
)
type test struct {
in string
version Version
variant Variant
isuuid bool
}
var tests = []test{
{"f47ac10b-58cc-0372-8567-0e02b2c3d479", 0, RFC4122, true},
{"f47ac10b-58cc-1372-8567-0e02b2c3d479", 1, RFC4122, true},
{"f47ac10b-58cc-2372-8567-0e02b2c3d479", 2, RFC4122, true},
{"f47ac10b-58cc-3372-8567-0e02b2c3d479", 3, RFC4122, true},
{"f47ac10b-58cc-4372-8567-0e02b2c3d479", 4, RFC4122, true},
{"f47ac10b-58cc-5372-8567-0e02b2c3d479", 5, RFC4122, true},
{"f47ac10b-58cc-6372-8567-0e02b2c3d479", 6, RFC4122, true},
{"f47ac10b-58cc-7372-8567-0e02b2c3d479", 7, RFC4122, true},
{"f47ac10b-58cc-8372-8567-0e02b2c3d479", 8, RFC4122, true},
{"f47ac10b-58cc-9372-8567-0e02b2c3d479", 9, RFC4122, true},
{"f47ac10b-58cc-a372-8567-0e02b2c3d479", 10, RFC4122, true},
{"f47ac10b-58cc-b372-8567-0e02b2c3d479", 11, RFC4122, true},
{"f47ac10b-58cc-c372-8567-0e02b2c3d479", 12, RFC4122, true},
{"f47ac10b-58cc-d372-8567-0e02b2c3d479", 13, RFC4122, true},
{"f47ac10b-58cc-e372-8567-0e02b2c3d479", 14, RFC4122, true},
{"f47ac10b-58cc-f372-8567-0e02b2c3d479", 15, RFC4122, true},
{"urn:uuid:f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true},
{"URN:UUID:f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true},
{"f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true},
{"f47ac10b-58cc-4372-1567-0e02b2c3d479", 4, Reserved, true},
{"f47ac10b-58cc-4372-2567-0e02b2c3d479", 4, Reserved, true},
{"f47ac10b-58cc-4372-3567-0e02b2c3d479", 4, Reserved, true},
{"f47ac10b-58cc-4372-4567-0e02b2c3d479", 4, Reserved, true},
{"f47ac10b-58cc-4372-5567-0e02b2c3d479", 4, Reserved, true},
{"f47ac10b-58cc-4372-6567-0e02b2c3d479", 4, Reserved, true},
{"f47ac10b-58cc-4372-7567-0e02b2c3d479", 4, Reserved, true},
{"f47ac10b-58cc-4372-8567-0e02b2c3d479", 4, RFC4122, true},
{"f47ac10b-58cc-4372-9567-0e02b2c3d479", 4, RFC4122, true},
{"f47ac10b-58cc-4372-a567-0e02b2c3d479", 4, RFC4122, true},
{"f47ac10b-58cc-4372-b567-0e02b2c3d479", 4, RFC4122, true},
{"f47ac10b-58cc-4372-c567-0e02b2c3d479", 4, Microsoft, true},
{"f47ac10b-58cc-4372-d567-0e02b2c3d479", 4, Microsoft, true},
{"f47ac10b-58cc-4372-e567-0e02b2c3d479", 4, Future, true},
{"f47ac10b-58cc-4372-f567-0e02b2c3d479", 4, Future, true},
{"f47ac10b158cc-5372-a567-0e02b2c3d479", 0, Invalid, false},
{"f47ac10b-58cc25372-a567-0e02b2c3d479", 0, Invalid, false},
{"f47ac10b-58cc-53723a567-0e02b2c3d479", 0, Invalid, false},
{"f47ac10b-58cc-5372-a56740e02b2c3d479", 0, Invalid, false},
{"f47ac10b-58cc-5372-a567-0e02-2c3d479", 0, Invalid, false},
{"g47ac10b-58cc-4372-a567-0e02b2c3d479", 0, Invalid, false},
}
var constants = []struct {
c interface{}
name string
}{
{Person, "Person"},
{Group, "Group"},
{Org, "Org"},
{Invalid, "Invalid"},
{RFC4122, "RFC4122"},
{Reserved, "Reserved"},
{Microsoft, "Microsoft"},
{Future, "Future"},
{Domain(17), "Domain17"},
{Variant(42), "BadVariant42"},
}
func testTest(t *testing.T, in string, tt test) {
uuid := Parse(in)
if ok := (uuid != nil); ok != tt.isuuid {
t.Errorf("Parse(%s) got %v expected %v\b", in, ok, tt.isuuid)
}
if uuid == nil {
return
}
if v := uuid.Variant(); v != tt.variant {
t.Errorf("Variant(%s) got %d expected %d\b", in, v, tt.variant)
}
if v, _ := uuid.Version(); v != tt.version {
t.Errorf("Version(%s) got %d expected %d\b", in, v, tt.version)
}
}
func TestUUID(t *testing.T) {
for _, tt := range tests {
testTest(t, tt.in, tt)
testTest(t, strings.ToUpper(tt.in), tt)
}
}
func TestConstants(t *testing.T) {
for x, tt := range constants {
v, ok := tt.c.(fmt.Stringer)
if !ok {
t.Errorf("%x: %v: not a stringer", x, v)
} else if s := v.String(); s != tt.name {
v, _ := tt.c.(int)
t.Errorf("%x: Constant %T:%d gives %q, expected %q", x, tt.c, v, s, tt.name)
}
}
}
func TestRandomUUID(t *testing.T) {
m := make(map[string]bool)
for x := 1; x < 32; x++ {
uuid := NewRandom()
s := uuid.String()
if m[s] {
t.Errorf("NewRandom returned duplicated UUID %s", s)
}
m[s] = true
if v, _ := uuid.Version(); v != 4 {
t.Errorf("Random UUID of version %s", v)
}
if uuid.Variant() != RFC4122 {
t.Errorf("Random UUID is variant %d", uuid.Variant())
}
}
}
func TestNew(t *testing.T) {
m := make(map[string]bool)
for x := 1; x < 32; x++ {
s := New()
if m[s] {
t.Errorf("New returned duplicated UUID %s", s)
}
m[s] = true
uuid := Parse(s)
if uuid == nil {
t.Errorf("New returned %q which does not decode", s)
continue
}
if v, _ := uuid.Version(); v != 4 {
t.Errorf("Random UUID of version %s", v)
}
if uuid.Variant() != RFC4122 {
t.Errorf("Random UUID is variant %d", uuid.Variant())
}
}
}
func TestCoding(t *testing.T) {
text := "7d444840-9dc0-11d1-b245-5ffdce74fad2"
urn := "urn:uuid:7d444840-9dc0-11d1-b245-5ffdce74fad2"
data := UUID{
0x7d, 0x44, 0x48, 0x40,
0x9d, 0xc0,
0x11, 0xd1,
0xb2, 0x45,
0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2,
}
if v := data.String(); v != text {
t.Errorf("%x: encoded to %s, expected %s", data, v, text)
}
if v := data.URN(); v != urn {
t.Errorf("%x: urn is %s, expected %s", data, v, urn)
}
uuid := Parse(text)
if !Equal(uuid, data) {
t.Errorf("%s: decoded to %s, expected %s", text, uuid, data)
}
}
func TestVersion1(t *testing.T) {
uuid1 := NewUUID()
uuid2 := NewUUID()
if Equal(uuid1, uuid2) {
t.Errorf("%s:duplicate uuid", uuid1)
}
if v, _ := uuid1.Version(); v != 1 {
t.Errorf("%s: version %s expected 1", uuid1, v)
}
if v, _ := uuid2.Version(); v != 1 {
t.Errorf("%s: version %s expected 1", uuid2, v)
}
n1 := uuid1.NodeID()
n2 := uuid2.NodeID()
if !bytes.Equal(n1, n2) {
t.Errorf("Different nodes %x != %x", n1, n2)
}
t1, ok := uuid1.Time()
if !ok {
t.Errorf("%s: invalid time", uuid1)
}
t2, ok := uuid2.Time()
if !ok {
t.Errorf("%s: invalid time", uuid2)
}
q1, ok := uuid1.ClockSequence()
if !ok {
t.Errorf("%s: invalid clock sequence", uuid1)
}
q2, ok := uuid2.ClockSequence()
if !ok {
t.Errorf("%s: invalid clock sequence", uuid2)
}
switch {
case t1 == t2 && q1 == q2:
t.Error("time stopped")
case t1 > t2 && q1 == q2:
t.Error("time reversed")
case t1 < t2 && q1 != q2:
t.Error("clock sequence chaned unexpectedly")
}
}
func TestMD5(t *testing.T) {
uuid := NewMD5(NameSpace_DNS, []byte("python.org")).String()
want := "6fa459ea-ee8a-3ca4-894e-db77e160355e"
if uuid != want {
t.Errorf("MD5: got %q expected %q", uuid, want)
}
}
func TestSHA1(t *testing.T) {
uuid := NewSHA1(NameSpace_DNS, []byte("python.org")).String()
want := "886313e1-3b8a-5372-9b90-0c9aee199e5d"
if uuid != want {
t.Errorf("SHA1: got %q expected %q", uuid, want)
}
}
func testDCE(t *testing.T, name string, uuid UUID, domain Domain, id uint32) {
if uuid == nil {
t.Errorf("%s failed", name)
return
}
if v, _ := uuid.Version(); v != 2 {
t.Errorf("%s: %s: expected version 2, got %s", name, uuid, v)
return
}
if v, ok := uuid.Domain(); !ok || v != domain {
if !ok {
t.Errorf("%s: %d: Domain failed", name, uuid)
} else {
t.Errorf("%s: %s: expected domain %d, got %d", name, uuid, domain, v)
}
}
if v, ok := uuid.Id(); !ok || v != id {
if !ok {
t.Errorf("%s: %d: Id failed", name, uuid)
} else {
t.Errorf("%s: %s: expected id %d, got %d", name, uuid, id, v)
}
}
}
func TestDCE(t *testing.T) {
testDCE(t, "NewDCESecurity", NewDCESecurity(42, 12345678), 42, 12345678)
testDCE(t, "NewDCEPerson", NewDCEPerson(), Person, uint32(os.Getuid()))
testDCE(t, "NewDCEGroup", NewDCEGroup(), Group, uint32(os.Getgid()))
}
type badRand struct{}
func (r badRand) Read(buf []byte) (int, error) {
for i, _ := range buf {
buf[i] = byte(i)
}
return len(buf), nil
}
func TestBadRand(t *testing.T) {
SetRand(badRand{})
uuid1 := New()
uuid2 := New()
if uuid1 != uuid2 {
t.Errorf("expected duplicates, got %q and %q", uuid1, uuid2)
}
SetRand(nil)
uuid1 = New()
uuid2 = New()
if uuid1 == uuid2 {
t.Errorf("unexpected duplicates, got %q", uuid1)
}
}
func TestUUID_Array(t *testing.T) {
expect := Array{
0xf4, 0x7a, 0xc1, 0x0b,
0x58, 0xcc,
0x03, 0x72,
0x85, 0x67,
0x0e, 0x02, 0xb2, 0xc3, 0xd4, 0x79,
}
uuid := Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479")
if uuid == nil {
t.Fatal("invalid uuid")
}
if uuid.Array() != expect {
t.Fatal("invalid array")
}
}
func TestArray_UUID(t *testing.T) {
array := Array{
0xf4, 0x7a, 0xc1, 0x0b,
0x58, 0xcc,
0x03, 0x72,
0x85, 0x67,
0x0e, 0x02, 0xb2, 0xc3, 0xd4, 0x79,
}
expect := Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479")
if expect == nil {
t.Fatal("invalid uuid")
}
if !bytes.Equal(array.UUID(), expect) {
t.Fatal("invalid uuid")
}
}
func BenchmarkParse(b *testing.B) {
for i := 0; i < b.N; i++ {
uuid := Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479")
if uuid == nil {
b.Fatal("invalid uuid")
}
}
}
func BenchmarkNew(b *testing.B) {
for i := 0; i < b.N; i++ {
New()
}
}
func BenchmarkUUID_String(b *testing.B) {
uuid := Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479")
if uuid == nil {
b.Fatal("invalid uuid")
}
for i := 0; i < b.N; i++ {
if uuid.String() == "" {
b.Fatal("invalid uuid")
}
}
}
func BenchmarkUUID_URN(b *testing.B) {
uuid := Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479")
if uuid == nil {
b.Fatal("invalid uuid")
}
for i := 0; i < b.N; i++ {
if uuid.URN() == "" {
b.Fatal("invalid uuid")
}
}
}
func BenchmarkUUID_Array(b *testing.B) {
expect := Array{
0xf4, 0x7a, 0xc1, 0x0b,
0x58, 0xcc,
0x03, 0x72,
0x85, 0x67,
0x0e, 0x02, 0xb2, 0xc3, 0xd4, 0x79,
}
uuid := Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479")
if uuid == nil {
b.Fatal("invalid uuid")
}
for i := 0; i < b.N; i++ {
if uuid.Array() != expect {
b.Fatal("invalid array")
}
}
}
func BenchmarkArray_UUID(b *testing.B) {
array := Array{
0xf4, 0x7a, 0xc1, 0x0b,
0x58, 0xcc,
0x03, 0x72,
0x85, 0x67,
0x0e, 0x02, 0xb2, 0xc3, 0xd4, 0x79,
}
expect := Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479")
if expect == nil {
b.Fatal("invalid uuid")
}
for i := 0; i < b.N; i++ {
if !bytes.Equal(array.UUID(), expect) {
b.Fatal("invalid uuid")
}
}
}

23
vendor/github.com/pborman/uuid/version1.go generated vendored Normal file
View File

@ -0,0 +1,23 @@
// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
guuid "github.com/google/uuid"
)
// NewUUID returns a Version 1 UUID based on the current NodeID and clock
// sequence, and the current time. If the NodeID has not been set by SetNodeID
// or SetNodeInterface then it will be set automatically. If the NodeID cannot
// be set NewUUID returns nil. If clock sequence has not been set by
// SetClockSequence then it will be set automatically. If GetTime fails to
// return the current NewUUID returns nil.
func NewUUID() UUID {
gu, err := guuid.NewUUID()
if err == nil {
return UUID(gu[:])
}
return nil
}

26
vendor/github.com/pborman/uuid/version4.go generated vendored Normal file
View File

@ -0,0 +1,26 @@
// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import guuid "github.com/google/uuid"
// Random returns a Random (Version 4) UUID or panics.
//
// The strength of the UUIDs is based on the strength of the crypto/rand
// package.
//
// A note about uniqueness derived from the UUID Wikipedia entry:
//
// Randomly generated UUIDs have 122 random bits. One's annual risk of being
// hit by a meteorite is estimated to be one chance in 17 billion, that
// means the probability is about 0.00000000006 (6 × 1011),
// equivalent to the odds of creating a few tens of trillions of UUIDs in a
// year and having one duplicate.
func NewRandom() UUID {
if gu, err := guuid.NewRandom(); err == nil {
return UUID(gu[:])
}
return nil
}

4
vendor/gopkg.in/gotsunami/coquelicot.v1/.gitignore generated vendored Normal file
View File

@ -0,0 +1,4 @@
*.swp
tags
bin/coquelicot/coquelicot
bin/coquelicot/dummy/root_storage/*

142
vendor/gopkg.in/gotsunami/coquelicot.v1/Draft.md generated vendored Normal file
View File

@ -0,0 +1,142 @@
# Draft API
## Response
Single file:
```
{
"directory": "/image/2014/6f/w015i",
"type": "image",
"versions": {
"original": {
"filename": "original-15h1.png",
"height": 60,
"mime": "image/png",
"url": "/image/2014/6f/w015i/original-15h1.png",
"size": 3464,
"width": 53
},
"pic": {
"filename": "pic-15h1.png",
"height": 90,
"mime": "image/png",
"url": "/image/2014/6f/w015i/pic-15h1.png",
"size": 7648,
"width": 120
}
}
}
```
Multiple files:
```
{
"files": [
{...},
{...}
]
}
```
## Binary upload
```
POST /files HTTP/1.1
Content-Length: 21744
Accept: application/json
Content-Disposition: attachment; filename="pic.jpg"
...bytes...
```
## Multipart
```
POST /files HTTP/1.1
Content-Length: 21929
Accept: application/json
Content-Type: multipart/form-data; boundary=----5XhQf4IXV9Q26uHM
------5XhQf4IXV9Q26uHM
Content-Disposition: form-data; name="files[]"; filename="pic.jpg"
Content-Type: image/jpeg
...bytes...
```
## Chunked multipart
First request create temporary file
```
POST /files HTTP/1.1
Content-Length: 25185
Content-Range: bytes 0-24999/52097
Content-Disposition: attachment; filename="kino.jpg"
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryAD3u12ABYZTJiIy3
------WebKitFormBoundaryAD3u12ABYZTJiIy3
Content-Disposition: form-data; name="files[]"; filename="kino.jpg"
Content-Type: image/jpeg
...bytes...
------WebKitFormBoundaryAD3u12ABYZTJiIy3--
```
Second request write chunk to exists temporary file
```
POST /files HTTP/1.1
Content-Length: 25185
Content-Range: bytes 25000-49999/52097
Content-Disposition: attachment; filename="kino.jpg"
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryvbE2anvAQyF3PWZS
------WebKitFormBoundaryvbE2anvAQyF3PWZS
Content-Disposition: form-data; name="files[]"; filename="kino.jpg"
Content-Type: image/jpeg
...bytes...
------WebKitFormBoundaryvbE2anvAQyF3PWZS--
```
Last request write chunk to exists temporary file, complete upload, create attachment.
```
POST /files HTTP/1.1
Content-Length: 2282
Content-Range: bytes 50000-52096/52097
Content-Disposition: attachment; filename="kino.jpg"
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryrHBafxSExXodxlnL
------WebKitFormBoundaryrHBafxSExXodxlnL
Content-Disposition: form-data; name="files[]"; filename="kino.jpg"
Content-Type: image/jpeg
...bytes...
------WebKitFormBoundaryrHBafxSExXodxlnL--
```
## Chunked binary
```
POST /files HTTP/1.1
Content-Length: 10240
Content-Range: bytes 0-10239/36431
Accept: application/json
Content-Disposition: attachment; filename="pic.jpg"
Content-Type: image/jpeg
...bytes...
```
## Check chunked upload progress
```
PUT /files/some_url HTTP/1.1
Content-Length: 0
Content-Range: bytes */2000000
```
```
HTTP/1.1 308 Resume Incomplete
Content-Length: 0
Range: 0-42
```

22
vendor/gopkg.in/gotsunami/coquelicot.v1/LICENSE generated vendored Normal file
View File

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2014 Zaur Abasmirzoev
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.

73
vendor/gopkg.in/gotsunami/coquelicot.v1/README.md generated vendored Normal file
View File

@ -0,0 +1,73 @@
## Coquelicot
Coquelicot is an easy to use server-side upload service written in Go.
It is compatible with the [jQuery-File-Upload](https://github.com/blueimp/jQuery-File-Upload)
widget and supports chunked and resumable file upload.
Using Coquelicot, you can add upload functionality to your project
very easily. Just download and unzip the Coquelicot binary distribution
for your OS and configure the jQuery-File-Upload widget.
![logo](http://go-tsunami.com/assets/images/coquelicotLogo.jpg)
### Server Setup
You can use a binary release or get the project if you have a working Go installation.
#### Binary Release
Grab the latest [binary release](https://github.com/gotsunami/coquelicot/releases) for you system. Unzip it
and run
```
$ ./coquelicot -storage /tmp/files -host localhost:9073
```
to store uploaded files into `/tmp/files` and make the application listen on the loopback interface port 9073
(run `coquelicot.exe` on Windows).
#### Source Release
Grab the latest stable version with:
```
$ go get gopkg.in/gotsunami/coquelicot.v1
```
See the [API documentation](http://gopkg.in/gotsunami/coquelicot.v1).
### jQuery-File-Upload Setup (Client)
The `fileupload` object needs the `xhrFields`, `maxChunkSize` and `add` fields to be defined.
- `xhrFields`: enables sending of cross-domain cookies, which is required to properly handle chunks of data server-side
- `maxChunkSize`: enables uploading chunks of file
- `add`: overwrites the default `add` handler to support resuming file upload
Download the [latest release](https://github.com/blueimp/jQuery-File-Upload/releases) of jQuery-File-Upload,
edit the `js/main.js` file in the distribution and make the `fileupload` initialization look like
(replacing the `localhost:9073` part with the name:port of your server running the `coquelicot` program):
```
$('#fileupload').fileupload({
// Send cross-domain cookies
xhrFields: {withCredentials: true},
url: 'http://localhost:9073/files',
// Chunk size in bytes
maxChunkSize: 1000000,
// Enable file resume
add: function (e, data) {
var that = this;
$.ajax({
url: 'http://localhost:9073/resume',
xhrFields: {withCredentials: true},
data: {file: data.files[0].name}
}).done(function(result) {
var file = result.file;
data.uploadedBytes = file && file.size;
$.blueimp.fileupload.prototype.options.add.call(that, e, data);
});
}
});
```

81
vendor/gopkg.in/gotsunami/coquelicot.v1/attachment.go generated vendored Normal file
View File

@ -0,0 +1,81 @@
package coquelicot
import (
"os"
)
// attachment contain info about directory, base mime type and all files saved.
type attachment struct {
originalFile *originalFile
Dir *dirManager
Versions map[string]fileManager
}
// Function receive root directory, original file, convertion parameters.
// Return attachment saved. The final chunk is deleted if delChunk is true.
func create(storage string, ofile *originalFile, converts map[string]string, delChunk bool) (*attachment, error) {
dm, err := createDir(storage, ofile.BaseMime)
if err != nil {
return nil, err
}
at := &attachment{
originalFile: ofile,
Dir: dm,
Versions: make(map[string]fileManager),
}
if ofile.BaseMime == "image" {
converts["thumbnail"] = "120x90"
}
makeVersion := func(a *attachment, version, convert string) error {
fm, err := at.createVersion(version, convert)
if err != nil {
return err
}
at.Versions[version] = fm
return nil
}
if err := makeVersion(at, "original", ""); err != nil {
return nil, err
}
if makeThumbnail {
if err := makeVersion(at, "thumbnail", converts["thumbnail"]); err != nil {
return nil, err
}
}
if delChunk {
return at, os.Remove(at.originalFile.Filepath)
}
return at, nil
}
// Directly save single version and return fileManager.
func (attachment *attachment) createVersion(version string, convert string) (fileManager, error) {
fm := newFileManager(attachment.Dir, attachment.originalFile.BaseMime, version)
fm.SetFilename(attachment.originalFile)
if err := fm.convert(attachment.originalFile.Filepath, convert); err != nil {
return nil, err
}
return fm, nil
}
func (attachment *attachment) ToJson() map[string]interface{} {
data := make(map[string]interface{})
data["type"] = attachment.originalFile.BaseMime
data["dir"] = attachment.Dir.Path
data["name"] = attachment.originalFile.Filename
versions := make(map[string]interface{})
for version, fm := range attachment.Versions {
versions[version] = fm.ToJson()
}
data["versions"] = versions
return data
}

View File

@ -0,0 +1,39 @@
package coquelicot
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestCreateAttachment(t *testing.T) {
assert := assert.New(t)
ofile := originalImageFile()
storage := dummy + "/root_storage"
converts := map[string]string{"original": "", "thumbnail": "120x80"}
attachment, err := create(storage, ofile, converts, false)
assert.Nil(err)
// Convert option not set
assert.Equal(len(attachment.Versions), 1)
data := attachment.ToJson()
assert.Equal(data["type"], "image")
}
func originalImageFile() *originalFile {
return &originalFile{
BaseMime: "image",
Filepath: dummy + "/32509211_news_bigpic.jpg",
Filename: "32509211_news_bigpic.jpg",
}
}
func originalPdfFile() *originalFile {
return &originalFile{
BaseMime: "application",
Filepath: dummy + "/Learning-Go-latest.pdf",
Filename: "Learning-Go-latest.pdf",
}
}

View File

@ -0,0 +1,2 @@
Build it with `./build.sh` which includes a version number (from git).

View File

@ -0,0 +1,17 @@
#!/bin/sh
# Writes a version file with the latest git commit id
# and any tag associated with it.
COMMIT=$(git log --format="%h" -n 1)
TAG=$(git describe --all --exact-match $COMMIT)
cat > version.go << EOF
package main
const (
appVersion = "$COMMIT $TAG"
)
EOF
go build && rm -f version.go

View File

@ -0,0 +1,13 @@
package main
import "flag"
var (
// Root for storage
storage = flag.String("storage", "./dummy/root_storage", "Root for storage")
// Host and port falco server
host = flag.String("host", "localhost:9073", "host:port for pavo server")
version = flag.Bool("version", false, "App version")
convert = flag.Bool("convert", false, "Use ImageMagick convert to create a thumbnail image")
)

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

View File

@ -0,0 +1,39 @@
package main
import (
"flag"
"fmt"
"log"
"net/http"
"os"
"gopkg.in/gotsunami/coquelicot.v1"
)
func main() {
flag.Parse()
if *version {
fmt.Printf("version: %s\n", appVersion)
return
}
s := coquelicot.NewStorage(*storage)
s.Option(coquelicot.Convert(*convert))
logger := log.New(os.Stdout, "", log.LstdFlags)
routes := map[string]http.HandlerFunc{
"/files": s.UploadHandler,
"/resume": s.ResumeHandler,
}
for path, handler := range routes {
http.Handle(path, coquelicot.Adapt(http.HandlerFunc(handler),
coquelicot.CORSMiddleware(),
coquelicot.LogMiddleware(logger)),
)
}
log.Printf("Storage place in: %s", s.StorageDir())
log.Printf("Start server on %s", *host)
log.Fatal(http.ListenAndServe(*host, nil))
}

View File

@ -0,0 +1,43 @@
package main
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
)
func TestUploadBinary(t *testing.T) {
assert := assert.New(t)
req, _ := http.NewRequest("POST", "/files", nil)
req.Header.Set("Content-Type", "application/octet-stream")
req.Header.Set("X-File", "./dummy/bin-data")
req.Header.Set("Content-Disposition", `attachment; filename="basta.png"`)
req.AddCookie(&http.Cookie{Name: "coquelicot", Value: "abcdef"})
r := gin.Default()
r.POST("/files", CreateAttachment)
rw := httptest.NewRecorder()
r.ServeHTTP(rw, req)
assert.Equal(http.StatusCreated, rw.Code)
//var d map[string]interface{}
//json.Unmarshal(rw.Body.Bytes(), &d)
//t.Logf("json decode: %+v", d)
}
func TestGetConvertParams(t *testing.T) {
assert := assert.New(t)
req, _ := http.NewRequest("POST", `/files?converts={"pic":"120x90"}`, nil)
convert, err := GetConvertParams(req)
assert.Nil(err)
assert.Equal("120x90", convert["pic"])
}

View File

@ -0,0 +1,45 @@
#!/bin/sh
# Writes a version file with the latest git commit id
# and any tag associated with it.
COMMIT=$(git log --format="%h" -n 1)
TAG=$(git describe --all --exact-match $COMMIT)
BIN=coquelicot
cat > version.go << EOF
package main
const (
appVersion = "$COMMIT $TAG"
)
EOF
echo "(use -a to build for all platforms (go >= 1.5)"
ARCH=amd64
OSLIST=$(uname -s|tr '[:upper:]' '[:lower:]')
if [ "$1" = "-a" ]; then
OSLIST="linux windows freebsd darwin"
fi
rm -f /tmp/$BIN*.zip
RTAG=$(git tag|tail -1)
if [ -z "$RTAG" ]; then
RTAG=$COMMIT
fi
for OS in $OSLIST; do
echo "Building for $OS ..."
TMP=/tmp/c$OS$ARCH
rm -rf $TMP
GOOS=$OS GOARCH=$ARCH go build -o $TMP/$BIN
if [ "$OS" = "windows" ]; then
mv $TMP/$BIN $TMP/$BIN.exe
fi
zip -j /tmp/$BIN-$RTAG-$OS-$ARCH.zip $TMP/$BIN* && rm -rf $TMP
done
rm -f version.go

39
vendor/gopkg.in/gotsunami/coquelicot.v1/body.go generated vendored Normal file
View File

@ -0,0 +1,39 @@
package coquelicot
import (
"bufio"
"io"
"mime/multipart"
"os"
)
// Upload body info.
type body struct {
XFile *os.File
body io.Reader
MR *multipart.Reader
Available bool
}
// Check exists body in xfile and return body.
func newBody(xfile string, req_body io.Reader) (*body, error) {
if xfile == "" {
return &body{body: req_body, Available: true}, nil
}
fh, err := os.Open(xfile)
if err != nil {
return nil, err
}
return &body{XFile: fh, body: bufio.NewReader(fh), Available: true}, nil
}
// Close filehandler of body if XFile exists.
func (body *body) Close() error {
if body.XFile != nil {
return body.XFile.Close()
}
return nil
}

18
vendor/gopkg.in/gotsunami/coquelicot.v1/coquelicot.go generated vendored Normal file
View File

@ -0,0 +1,18 @@
// Package coquelicot provides (chunked) file upload capability (with resume).
package coquelicot
type Storage struct {
output string
verbosity int
}
// FIXME: global for now
var makeThumbnail bool
func (s *Storage) StorageDir() string {
return s.output
}
func NewStorage(rootDir string) *Storage {
return &Storage{output: rootDir}
}

76
vendor/gopkg.in/gotsunami/coquelicot.v1/dir.go generated vendored Normal file
View File

@ -0,0 +1,76 @@
package coquelicot
import (
"crypto/sha1"
"errors"
"fmt"
"io"
"math/rand"
"os"
"path/filepath"
"strconv"
"time"
)
// Directory mananger
type dirManager struct {
Root string
Path string
}
// Prepare dirManager given root, mime.
func createDir(root, mime string) (*dirManager, error) {
dm := newDirManager(root)
dm.CalcPath(mime)
if err := dm.create(); err != nil {
return nil, err
}
return dm, nil
}
// Check path and return dirManager.
func checkDir(root, path string) (*dirManager, error) {
dm := newDirManager(root)
if m, _ := filepath.Match("/[a-z]*/[0-9]*/[0-9a-z]*/[0-9a-z]*", path); m != true {
return nil, errors.New("dir: path does not match the pattern")
}
dm.Path = path
return dm, nil
}
// newDirManager returns a new dirManager given a root.
func newDirManager(root string) *dirManager {
return &dirManager{Root: root}
}
// Return absolute path for directory
func (dm *dirManager) Abs() string {
return filepath.Join(dm.Root, dm.Path)
}
// Create directory obtained by concatenating the root and path.
func (dm *dirManager) create() error {
return os.MkdirAll(dm.Root+dm.Path, 0755)
}
// Generate path given mime and date.
func (dm *dirManager) CalcPath(mime string) {
h := sha1.New()
io.WriteString(h, fmt.Sprintf("%d", time.Now().UnixNano()))
dm.Path = fmt.Sprintf("/%x", h.Sum(nil))
}
func yearDay(t time.Time) string {
return strconv.FormatInt(int64(t.YearDay()), 36)
}
func containerName(t time.Time) string {
r := rand.New(rand.NewSource(time.Now().UnixNano())).Intn(1000)
seconds := t.Hour()*3600 + t.Minute()*60 + t.Second()
return strconv.FormatInt(int64(seconds*1000+r), 36)
}

19
vendor/gopkg.in/gotsunami/coquelicot.v1/dir_test.go generated vendored Normal file
View File

@ -0,0 +1,19 @@
package coquelicot
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestPrepareDir(t *testing.T) {
assert := assert.New(t)
root := "dummy/root_storage"
dm, err := createDir(root, "image")
assert.Nil(err)
assert.Equal(root, dm.Root)
dm, err = checkDir(root, "/image/2014/2a/q1b12")
assert.Nil(err)
}

View File

@ -0,0 +1,40 @@
package coquelicot
import (
"os"
)
type fileDefaultManager struct {
*fileBaseManager
Size int64
}
func (fdm *fileDefaultManager) convert(src string, convert string) error {
return fdm.rawCopy(src, convert)
}
func (fdm *fileDefaultManager) ToJson() map[string]interface{} {
return map[string]interface{}{
"url": fdm.Url(),
"filename": fdm.Filename,
"size": fdm.Size,
}
}
func (fdm *fileDefaultManager) rawCopy(src, convert string) error {
if err := fdm.copyFile(src, fdm.Filepath()); err != nil {
return err
}
f, err := os.Open(fdm.Filepath())
if err != nil {
return err
}
fi, err := f.Stat()
if err != nil {
return err
}
fdm.Size = fi.Size()
return nil
}

View File

@ -0,0 +1,75 @@
package coquelicot
import (
"fmt"
"os/exec"
)
type fileImageManager struct {
*fileDefaultManager
Width int
Height int
thumbnail bool // Add resized version with ImageMagick
}
// Save version from original with convert command-line tool.
func (fim *fileImageManager) convert(src string, convert string) error {
if !fim.thumbnail {
// Raw copy
return fim.rawCopy(src, convert)
}
err := convertImage(src, fim.Filepath(), convert)
if err != nil {
return err
}
fim.Width, fim.Height, fim.Size, err = identifyImageSizes(fim.Filepath())
if err != nil {
return err
}
return nil
}
func (fim *fileImageManager) ToJson() map[string]interface{} {
return map[string]interface{}{
"url": fim.Url(),
"filename": fim.Filename,
"size": fim.Size,
"width": fim.Width,
"height": fim.Height,
}
}
func convertImage(src, dest, convert string) error {
args := []string{src, "-strip"}
if convert != "" {
cv := []string{"-resize", convert + "^", "-gravity", "center", "-extent", convert}
args = append(args, cv...)
}
args = append(args, dest)
out, err := exec.Command("convert", args...).CombinedOutput()
if err != nil {
return fmt.Errorf("Error move original: %s, %s", err, string(out))
}
return nil
}
func identifyImageSizes(filepath string) (int, int, int64, error) {
cmd := exec.Command("identify", "-format", `"%w:%h:%b"`, filepath)
out, err := cmd.CombinedOutput()
if err != nil {
return 0, 0, 0, fmt.Errorf("Identify Sizes: %s; detail: %s", err, string(out))
}
var w, h int
var s int64
fmt.Sscanf(string(out), `"%d:%d:%dB"`, &w, &h, &s)
return w, h, s, nil
}

113
vendor/gopkg.in/gotsunami/coquelicot.v1/file_manager.go generated vendored Normal file
View File

@ -0,0 +1,113 @@
package coquelicot
import (
"fmt"
"io"
"os"
"path/filepath"
"time"
)
type fileManager interface {
convert(string, string) error
SetFilename(*originalFile)
ToJson() map[string]interface{}
}
type fileBaseManager struct {
Dir *dirManager
Version string
Filename string
}
// Return fileManager for given base mime and version.
func newFileManager(dm *dirManager, mime_base, version string) fileManager {
fbm := &fileBaseManager{Dir: dm, Version: version}
fdm := &fileDefaultManager{fileBaseManager: fbm}
switch mime_base {
case "image":
return &fileImageManager{fileDefaultManager: fdm, thumbnail: makeThumbnail}
}
return fdm
}
func (fbm *fileBaseManager) SetFilename(file *originalFile) {
ext := filepath.Ext(file.Filename)
fbm.Filename = file.Filename[:len(file.Filename)-len(ext)] + "-" + fbm.Version + file.Ext()
if fbm.Version == "original" {
fbm.Filename = file.Filename
}
}
func (fbm *fileBaseManager) Filepath() string {
return filepath.Join(fbm.Dir.Abs(), fbm.Filename)
}
func (fbm *fileBaseManager) Url() string {
return filepath.Join(fbm.Dir.Path, fbm.Filename)
}
// copyFile copies a file from src to dst. If src and dst files exist, and are
// the same, then return success. Otherwise copy the file contents from src to dst.
func (fbm *fileBaseManager) copyFile(src, dst string) error {
sfi, err := os.Stat(src)
if err != nil {
return err
}
if !sfi.Mode().IsRegular() {
// cannot copy non-regular files (e.g., directories,
// symlinks, devices, etc.)
// FIXME
return fmt.Errorf("CopyFile: non-regular source file %s (%q)", sfi.Name(), sfi.Mode().String())
}
dfi, err := os.Stat(dst)
if err != nil {
if !os.IsNotExist(err) {
return err
}
} else {
if !(dfi.Mode().IsRegular()) {
return fmt.Errorf("CopyFile: non-regular destination file %s (%q)", dfi.Name(), dfi.Mode().String())
}
if os.SameFile(sfi, dfi) {
return err
}
}
if err := fbm.copyFileContents(src, dst); err != nil {
return err
}
return nil
}
// copyFileContents copies the contents of the file named src to the file named
// by dst. The file will be created if it does not already exist. If the
// destination file exists, all it's contents will be replaced by the contents
// of the source file.
func (fbm *fileBaseManager) copyFileContents(src, dst string) error {
var err error
in, err := os.Open(src)
if err != nil {
return err
}
defer in.Close()
out, err := os.Create(dst)
if err != nil {
return err
}
defer func() {
cerr := out.Close()
if err == nil {
err = cerr
}
}()
if _, err = io.Copy(out, in); err != nil {
return err
}
err = out.Sync()
return err
}
func seconds() int64 {
t := time.Now()
return int64(t.Hour()*3600 + t.Minute()*60 + t.Second())
}

113
vendor/gopkg.in/gotsunami/coquelicot.v1/meta.go generated vendored Normal file
View File

@ -0,0 +1,113 @@
package coquelicot
import (
"errors"
"fmt"
"mime"
"net/http"
)
// Info about request headers
type meta struct {
MediaType string
Boundary string
Range *dataRange
Filename string
UploadSid string
}
type dataRange struct {
Start int64
End int64
Size int64
}
// Parse request headers and make Meta.
func parseMeta(req *http.Request) (*meta, error) {
m := &meta{}
if err := m.parseContentType(req.Header.Get("Content-Type")); err != nil {
return nil, err
}
if err := m.parseContentRange(req.Header.Get("Content-Range")); err != nil {
return nil, err
}
if err := m.parseContentDisposition(req.Header.Get("Content-Disposition")); err != nil {
return nil, err
}
cookie, err := req.Cookie("coquelicot")
if err != nil {
return nil, err
}
if cookie != nil {
m.UploadSid = cookie.Value
}
return m, nil
}
func (m *meta) parseContentType(ct string) error {
if ct == "" {
m.MediaType = "application/octet-stream"
return nil
}
mediatype, params, err := mime.ParseMediaType(ct)
if err != nil {
return err
}
if mediatype == "multipart/form-data" {
boundary, ok := params["boundary"]
if !ok {
return errors.New("meta: boundary not defined")
}
m.MediaType = mediatype
m.Boundary = boundary
} else {
m.MediaType = "application/octet-stream"
}
return nil
}
func (m *meta) parseContentRange(cr string) error {
if cr == "" {
return nil
}
var start, end, size int64
_, err := fmt.Sscanf(cr, "bytes %d-%d/%d", &start, &end, &size)
if err != nil {
return err
}
m.Range = &dataRange{Start: start, End: end, Size: size}
return nil
}
func (m *meta) parseContentDisposition(cd string) error {
if cd == "" {
return nil
}
_, params, err := mime.ParseMediaType(cd)
if err != nil {
return err
}
filename, ok := params["filename"]
if !ok {
return errors.New("meta: filename in Content-Disposition not defined")
}
m.Filename = filename
return nil
}

32
vendor/gopkg.in/gotsunami/coquelicot.v1/meta_test.go generated vendored Normal file
View File

@ -0,0 +1,32 @@
package coquelicot
import (
"net/http"
"testing"
"github.com/stretchr/testify/assert"
)
func TestparseMeta(t *testing.T) {
assert := assert.New(t)
req, _ := http.NewRequest("POST", "/files", nil)
req.Header.Set("Content-Type", "multipart/form-data; boundary=----Zam1WUeLK7vBj4wN")
req.Header.Set("Content-Range", "bytes 512000-1023999/1141216")
req.Header.Set("Content-Disposition", `attachment; filename="picture.jpg"`)
req.AddCookie(&http.Cookie{Name: "coquelicot", Value: "abcdef"})
meta, err := parseMeta(req)
assert.Nil(err)
assert.Equal(meta.MediaType, "multipart/form-data")
assert.Equal(meta.Boundary, "----Zam1WUeLK7vBj4wN")
assert.Equal(meta.Range.Start, int64(512000))
assert.Equal(meta.Range.End, int64(1023999))
assert.Equal(meta.Range.Size, int64(1141216))
assert.Equal(meta.Filename, "picture.jpg")
assert.Equal(meta.UploadSid, "abcdef")
}

50
vendor/gopkg.in/gotsunami/coquelicot.v1/middleware.go generated vendored Normal file
View File

@ -0,0 +1,50 @@
package coquelicot
import (
"log"
"net/http"
)
type Adapter func(http.Handler) http.Handler
func Adapt(h http.Handler, adapters ...Adapter) http.Handler {
for k := len(adapters) - 1; k >= 0; k-- {
h = adapters[k](h)
}
return h
}
func CORSMiddleware() Adapter {
return func(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, PATCH, DELETE")
w.Header().Set("Access-Control-Allow-Headers",
"Content-Type, Content-Length, Accept-Encoding, Content-Range, Content-Disposition, Authorization")
// Since we need to support cross-domain cookies, we must support XHR requests
// with credentials, so the Access-Control-Allow-Credentials header is required
// and Access-Control-Allow-Origin cannot be equal to "*" but reply with the same Origin.
// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS.
w.Header().Set("Access-Control-Allow-Credentials", "true")
w.Header().Set("Access-Control-Allow-Origin", r.Header.Get("Origin"))
if r.Method == "OPTIONS" {
return
}
h.ServeHTTP(w, r)
})
}
}
func LogMiddleware(logger *log.Logger) Adapter {
return func(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
h.ServeHTTP(w, r)
path := r.URL.Path
if len(r.URL.RawQuery) > 0 {
path += "?" + r.URL.RawQuery
}
logger.Printf("%s %s [%s]\n", r.Method, path, r.RemoteAddr)
})
}
}

23
vendor/gopkg.in/gotsunami/coquelicot.v1/options.go generated vendored Normal file
View File

@ -0,0 +1,23 @@
package coquelicot
type option func(*Storage)
func (s *Storage) Option(opts ...option) {
for _, opt := range opts {
opt(s)
}
}
// Verbosity sets verbosity level (1 to 3).
func Verbosity(level int) option {
return func(s *Storage) {
s.verbosity = level
}
}
// Convert generates an image thumbnail using ImageMagick.
func Convert(b bool) option {
return func(s *Storage) {
makeThumbnail = b
}
}

231
vendor/gopkg.in/gotsunami/coquelicot.v1/upload.go generated vendored Normal file
View File

@ -0,0 +1,231 @@
package coquelicot
import (
"crypto/md5"
"encoding/hex"
"errors"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"os"
"path/filepath"
"strings"
)
// Error incomplete returned by uploader when loaded non-last chunk.
var incomplete = errors.New("incomplete")
// Structure describes the state of the original file.
type originalFile struct {
BaseMime string
Filepath string
Filename string
Size int64
}
func (ofile *originalFile) Ext() string {
return strings.ToLower(filepath.Ext(ofile.Filename))
}
// Downloading files from the received request.
// The root directory of storage, storage, used to temporarily store chunks.
// Returns an array of the original files and error.
// If you load a portion of the file, chunk, it will be stored in err error incomplete,
// and in an array of a single file. File size will fit the current size.
func process(req *http.Request, storage string) ([]*originalFile, error) {
meta, err := parseMeta(req)
if err != nil {
return nil, err
}
body, err := newBody(req.Header.Get("X-File"), req.Body)
if err != nil {
return nil, err
}
up := &uploader{Root: storage, Meta: meta, body: body}
files, err := up.SaveFiles()
if err == incomplete {
return files, err
}
if err != nil {
return nil, err
}
return files, nil
}
// Upload manager.
type uploader struct {
Root string
Meta *meta
body *body
}
// Function SaveFiles sequentially loads the original files or chunk's.
func (up *uploader) SaveFiles() ([]*originalFile, error) {
files := make([]*originalFile, 0)
for {
ofile, err := up.SaveFile()
if err == io.EOF {
break
}
if err == incomplete {
files = append(files, ofile)
return files, err
}
if err != nil {
return nil, err
}
files = append(files, ofile)
}
return files, nil
}
// Function loads one or download the original file chunk.
// Asks for the starting position in the body of the request to read the next file.
// Asks for a temporary file.
// Writes data from the request body into a temporary file.
// Specifies the size of the resulting temporary file.
// If the query specified header Content-Range,
// and the size of the resulting file does not match, it returns an error incomplete.
// Otherwise, defines the basic mime type, and returns the original file.
func (up *uploader) SaveFile() (*originalFile, error) {
body, filename, err := up.Reader()
if err != nil {
return nil, err
}
temp_file, err := up.tempFile()
if err != nil {
return nil, err
}
defer temp_file.Close()
if err = up.Write(temp_file, body); err != nil {
return nil, err
}
fi, err := temp_file.Stat()
if err != nil {
return nil, err
}
ofile := &originalFile{Filename: filename, Filepath: temp_file.Name(), Size: fi.Size()}
if up.Meta.Range != nil && ofile.Size != up.Meta.Range.Size {
return ofile, incomplete
}
ofile.BaseMime, err = identifyMime(ofile.Filepath)
if err != nil {
return nil, err
}
return ofile, nil
}
// Returns the reader to read the file or chunk of request body and the original file name.
// If the request header Content-Type is multipart/form-data, returns the next copy part.
// If all of part read the case of binary loading read the request body, an error is returned io.EOF.
func (up *uploader) Reader() (io.Reader, string, error) {
if up.Meta.MediaType == "multipart/form-data" {
if up.body.MR == nil {
up.body.MR = multipart.NewReader(up.body.body, up.Meta.Boundary)
}
for {
part, err := up.body.MR.NextPart()
if err != nil {
return nil, "", err
}
if part.FormName() == "files[]" {
return part, part.FileName(), nil
}
}
}
if !up.body.Available {
return nil, "", io.EOF
}
up.body.Available = false
return up.body.body, up.Meta.Filename, nil
}
// Returns a temporary file to download the file or resume chunk.
func (up *uploader) tempFile() (*os.File, error) {
if up.Meta.Range == nil {
return tempFile()
}
return tempFileChunks(up.Meta.Range.Start, up.Root, up.Meta.UploadSid, up.Meta.Filename)
}
// Returns the newly created temporary file.
func tempFile() (*os.File, error) {
return ioutil.TempFile(os.TempDir(), "coquelicot")
}
// Returns a temporary file to download chunk.
// To calculate a unique file name used cookie named coquelicot and the original file name.
// File located in the directory chunks storage root directory.
// Before returning the file pointer is shifted by the value of offset,
// in a situation where the pieces are loaded from the second to the last.
func tempFileChunks(offset int64, storage, upload_sid, user_filename string) (*os.File, error) {
hasher := md5.New()
hasher.Write([]byte(upload_sid + user_filename))
filename := hex.EncodeToString(hasher.Sum(nil))
path := filepath.Join(storage, "chunks")
err := os.MkdirAll(path, 0755)
if err != nil {
return nil, err
}
file, err := os.OpenFile(filepath.Join(path, filename), os.O_CREATE|os.O_WRONLY, 0664)
if err != nil {
return nil, err
}
if _, err = file.Seek(offset, 0); err != nil {
return nil, err
}
return file, nil
}
// The function writes a temporary file value from reader.
func (up *uploader) Write(temp_file *os.File, body io.Reader) error {
var err error
if up.Meta.Range == nil {
_, err = io.Copy(temp_file, body)
} else {
chunk_size := up.Meta.Range.End - up.Meta.Range.Start + 1
_, err = io.CopyN(temp_file, body, chunk_size)
}
return err
}
// identifyMine gets base mime type.
func identifyMime(file string) (string, error) {
f, err := os.Open(file)
if err != nil {
return "", err
}
defer f.Close()
// DetectContentType reads at most the first 512 bytes
buf := make([]byte, 512)
_, err = f.Read(buf)
if err != nil {
return "", err
}
mime := strings.Split(http.DetectContentType(buf), "/")[0]
return mime, nil
}

129
vendor/gopkg.in/gotsunami/coquelicot.v1/upload_test.go generated vendored Normal file
View File

@ -0,0 +1,129 @@
package coquelicot
import (
"bytes"
"fmt"
"io"
"mime/multipart"
"net/http"
"os"
"path/filepath"
"testing"
"code.google.com/p/go-uuid/uuid"
"github.com/stretchr/testify/assert"
)
const dummy = "bin/coquelicot/dummy"
func TestUploadMultipart(t *testing.T) {
assert := assert.New(t)
var body bytes.Buffer
mw := multipart.NewWriter(&body)
if err := writeMPbody(dummy+"/32509211_news_bigpic.jpg", mw); err != nil {
assert.Error(err)
}
if err := writeMPbody(dummy+"/kino.jpg", mw); err != nil {
assert.Error(err)
}
mw.Close()
req, _ := http.NewRequest("POST", "/files", &body)
req.Header.Set("Content-Type", mw.FormDataContentType())
req.AddCookie(&http.Cookie{Name: "coquelicot", Value: "abcdef"})
files, err := process(req, dummy+"/root_storage")
assert.Nil(err)
assert.Equal("kino.jpg", files[1].Filename)
assert.Equal("image", files[1].BaseMime)
}
func TestUploadBinary(t *testing.T) {
assert := assert.New(t)
req, _ := http.NewRequest("POST", "/files", nil)
req.Header.Set("Content-Type", "application/octet-stream")
req.Header.Set("X-File", dummy+"/bin-data")
req.Header.Set("Content-Disposition", `attachment; filename="basta.png"`)
req.AddCookie(&http.Cookie{Name: "coquelicot", Value: "abcdef"})
files, err := process(req, dummy+"/root_storage")
assert.Nil(err)
assert.Equal("basta.png", files[0].Filename)
assert.Equal("image", files[0].BaseMime)
}
func TestUploadChunked(t *testing.T) {
assert := assert.New(t)
storage := dummy + "/root_storage"
fname := dummy + "/kino.jpg"
f, _ := os.Open(fname)
defer f.Close()
cookie := &http.Cookie{Name: "coquelicot", Value: uuid.New()}
req := createChunkRequest(f, 0, 24999)
req.AddCookie(cookie)
files, err := process(req, storage)
assert.Equal(incomplete, err)
assert.Equal(25000, int(files[0].Size))
req = createChunkRequest(f, 25000, 49999)
req.AddCookie(cookie)
files, err = process(req, storage)
assert.Equal(incomplete, err)
assert.Equal(50000, int(files[0].Size))
req = createChunkRequest(f, 50000, 52096)
req.AddCookie(cookie)
files, err = process(req, storage)
assert.Nil(err)
assert.Equal(52097, int(files[0].Size))
assert.Equal("kino.jpg", files[0].Filename)
}
func createChunkRequest(f *os.File, start int64, end int64) *http.Request {
var body bytes.Buffer
mw := multipart.NewWriter(&body)
fi, _ := f.Stat()
fw, _ := mw.CreateFormFile("files[]", fi.Name())
io.CopyN(fw, f, end-start+1)
mw.Close()
req, _ := http.NewRequest("POST", "/files", &body)
req.Header.Set("Content-Type", mw.FormDataContentType())
req.Header.Set("Content-Disposition", `attachment; filename="`+fi.Name()+`"`)
req.Header.Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", start, end, fi.Size()))
return req
}
func TestTempFileChunks(t *testing.T) {
assert := assert.New(t)
file, err := tempFileChunks(0, dummy+"/root_storage", "abcdef", "kino.jpg")
assert.Nil(err)
assert.NotNil(file)
}
func writeMPbody(fname string, mw *multipart.Writer) error {
fw, _ := mw.CreateFormFile("files[]", filepath.Base(fname))
f, err := os.Open(fname)
if err != nil {
return err
}
defer f.Close()
_, err = io.Copy(fw, f)
if err != nil {
return err
}
return nil
}

157
vendor/gopkg.in/gotsunami/coquelicot.v1/web.go generated vendored Normal file
View File

@ -0,0 +1,157 @@
package coquelicot
import (
"crypto/md5"
"encoding/hex"
"encoding/json"
"fmt"
"log"
"net/http"
"os"
"path"
"time"
// "github.com/gin-gonic/gin"
"github.com/pborman/uuid"
)
type H map[string]interface{}
func toJSON(w http.ResponseWriter, code int, obj interface{}) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(code)
b, err := json.Marshal(obj)
if err != nil {
log.Println("error:", err.Error())
return
}
if _, err := w.Write(b); err != nil {
log.Println("error:", err.Error())
return
}
}
// ResumeHandler allows resuming a file upload.
//func (s *Storage) ResumeHandler(c *gin.Context) {
func (s *Storage) ResumeHandler(w http.ResponseWriter, r *http.Request) {
status := http.StatusOK
filename := r.URL.Query().Get("file")
cookie, _ := r.Cookie("coquelicot")
offset := int64(0)
if cookie != nil {
hasher := md5.New()
hasher.Write([]byte(cookie.Value + filename))
chunkname := hex.EncodeToString(hasher.Sum(nil))
fi, err := os.Stat(path.Join(s.output, "chunks", chunkname))
if err != nil {
if !os.IsNotExist(err) {
toJSON(w, http.StatusInternalServerError, H{
"status": http.StatusText(http.StatusInternalServerError),
"error": fmt.Sprintf("Resume error: %q", err.Error()),
})
return
}
} else {
offset = fi.Size()
}
}
toJSON(w, status, H{"status": http.StatusText(status), "file": H{"size": offset}})
}
// UploadHandler is the endpoint for uploading and storing files.
//func (s *Storage) UploadHandler(c *gin.Context) {
func (s *Storage) UploadHandler(w http.ResponseWriter, r *http.Request) {
if r.Method == "GET" {
status := http.StatusOK
// FIXME: nil content
toJSON(w, status, H{"status": http.StatusText(status), "files": nil})
return
}
if r.Method != "POST" {
http.NotFound(w, r)
return
}
converts, err := getConvertParams(r)
if err != nil {
toJSON(w, http.StatusBadRequest, H{
"status": "error",
"error": fmt.Sprintf("Query params: %s", err),
})
return
}
converts["original"] = ""
// File upload cookie so we can keep track of chunks.
cookie, _ := r.Cookie("coquelicot")
if cookie == nil {
cookie = &http.Cookie{
Name: "coquelicot",
Value: uuid.New(),
Expires: time.Now().Add(2 * 24 * time.Hour),
Path: "/",
}
r.AddCookie(cookie)
http.SetCookie(w, cookie)
}
// Performs the processing of writing data into chunk files.
files, err := process(r, s.StorageDir())
if err == incomplete {
toJSON(w, http.StatusOK, H{
"status": http.StatusText(http.StatusOK),
"file": H{"size": files[0].Size},
})
return
}
if err != nil {
toJSON(w, http.StatusBadRequest, H{
"status": http.StatusText(http.StatusBadRequest),
"error": fmt.Sprintf("Upload error: %q", err.Error()),
})
return
}
data := make([]map[string]interface{}, 0)
// Expected status if no error
status := http.StatusCreated
for _, ofile := range files {
// true to delete final chunk
attachment, err := create(s.StorageDir(), ofile, converts, true)
if err != nil {
data = append(data, map[string]interface{}{
"name": ofile.Filename,
"size": ofile.Size,
"error": err.Error(),
})
status = http.StatusInternalServerError
continue
}
data = append(data, attachment.ToJson())
}
toJSON(w, status, H{"status": http.StatusText(status), "files": data})
}
// Get parameters for convert from Request query string
func getConvertParams(req *http.Request) (map[string]string, error) {
raw_converts := req.URL.Query().Get("converts")
if raw_converts == "" {
raw_converts = "{}"
}
convert := make(map[string]string)
err := json.Unmarshal([]byte(raw_converts), &convert)
if err != nil {
return nil, err
}
return convert, nil
}