init
This commit is contained in:
196
vendor/github.com/anacrolix/missinggo/resource/http.go
generated
vendored
Normal file
196
vendor/github.com/anacrolix/missinggo/resource/http.go
generated
vendored
Normal file
@ -0,0 +1,196 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Provides access to resources through a http.Client.
|
||||
type HTTPProvider struct {
|
||||
Client *http.Client
|
||||
}
|
||||
|
||||
var _ Provider = &HTTPProvider{}
|
||||
|
||||
func (me *HTTPProvider) NewInstance(urlStr string) (r Instance, err error) {
|
||||
_r := new(httpInstance)
|
||||
_r.URL, err = url.Parse(urlStr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_r.Client = me.Client
|
||||
if _r.Client == nil {
|
||||
_r.Client = http.DefaultClient
|
||||
}
|
||||
r = _r
|
||||
return
|
||||
}
|
||||
|
||||
type httpInstance struct {
|
||||
Client *http.Client
|
||||
URL *url.URL
|
||||
}
|
||||
|
||||
var _ Instance = &httpInstance{}
|
||||
|
||||
func mustNewRequest(method, urlStr string, body io.Reader) *http.Request {
|
||||
req, err := http.NewRequest(method, urlStr, body)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return req
|
||||
}
|
||||
|
||||
func responseError(r *http.Response) error {
|
||||
if r.StatusCode == http.StatusNotFound {
|
||||
return os.ErrNotExist
|
||||
}
|
||||
return errors.New(r.Status)
|
||||
}
|
||||
|
||||
func (me *httpInstance) Get() (ret io.ReadCloser, err error) {
|
||||
resp, err := me.Client.Get(me.URL.String())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if resp.StatusCode == http.StatusOK {
|
||||
ret = resp.Body
|
||||
return
|
||||
}
|
||||
resp.Body.Close()
|
||||
err = responseError(resp)
|
||||
return
|
||||
}
|
||||
|
||||
func (me *httpInstance) Put(r io.Reader) (err error) {
|
||||
resp, err := me.Client.Do(mustNewRequest("PUT", me.URL.String(), r))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
resp.Body.Close()
|
||||
if resp.StatusCode == http.StatusOK {
|
||||
return
|
||||
}
|
||||
err = responseError(resp)
|
||||
return
|
||||
}
|
||||
|
||||
func (me *httpInstance) ReadAt(b []byte, off int64) (n int, err error) {
|
||||
req := mustNewRequest("GET", me.URL.String(), nil)
|
||||
req.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", off, off+int64(len(b))-1))
|
||||
resp, err := me.Client.Do(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
switch resp.StatusCode {
|
||||
case http.StatusPartialContent:
|
||||
case http.StatusRequestedRangeNotSatisfiable:
|
||||
err = io.EOF
|
||||
return
|
||||
default:
|
||||
err = responseError(resp)
|
||||
return
|
||||
}
|
||||
// TODO: This will crash if ContentLength was not provided (-1). Do
|
||||
// something about that.
|
||||
b = b[:resp.ContentLength]
|
||||
return io.ReadFull(resp.Body, b)
|
||||
}
|
||||
|
||||
func (me *httpInstance) WriteAt(b []byte, off int64) (n int, err error) {
|
||||
req := mustNewRequest("PATCH", me.URL.String(), bytes.NewReader(b))
|
||||
req.ContentLength = int64(len(b))
|
||||
req.Header.Set("Content-Range", fmt.Sprintf("bytes=%d-%d", off, off+int64(len(b))-1))
|
||||
resp, err := me.Client.Do(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
err = responseError(resp)
|
||||
}
|
||||
n = len(b)
|
||||
return
|
||||
}
|
||||
|
||||
func (me *httpInstance) Stat() (fi os.FileInfo, err error) {
|
||||
resp, err := me.Client.Head(me.URL.String())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
resp.Body.Close()
|
||||
if resp.StatusCode == http.StatusNotFound {
|
||||
err = os.ErrNotExist
|
||||
return
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
err = errors.New(resp.Status)
|
||||
return
|
||||
}
|
||||
var _fi httpFileInfo
|
||||
if h := resp.Header.Get("Last-Modified"); h != "" {
|
||||
_fi.lastModified, err = time.Parse(http.TimeFormat, h)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("error parsing Last-Modified header: %s", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
if h := resp.Header.Get("Content-Length"); h != "" {
|
||||
_fi.contentLength, err = strconv.ParseInt(h, 10, 64)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("error parsing Content-Length header: %s", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
fi = _fi
|
||||
return
|
||||
}
|
||||
|
||||
func (me *httpInstance) Delete() (err error) {
|
||||
resp, err := me.Client.Do(mustNewRequest("DELETE", me.URL.String(), nil))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = responseError(resp)
|
||||
resp.Body.Close()
|
||||
return
|
||||
}
|
||||
|
||||
type httpFileInfo struct {
|
||||
lastModified time.Time
|
||||
contentLength int64
|
||||
}
|
||||
|
||||
var _ os.FileInfo = httpFileInfo{}
|
||||
|
||||
func (fi httpFileInfo) IsDir() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (fi httpFileInfo) Mode() os.FileMode {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (fi httpFileInfo) Name() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (fi httpFileInfo) Size() int64 {
|
||||
return fi.contentLength
|
||||
}
|
||||
|
||||
func (fi httpFileInfo) ModTime() time.Time {
|
||||
return fi.lastModified
|
||||
}
|
||||
|
||||
func (fi httpFileInfo) Sys() interface{} {
|
||||
return nil
|
||||
}
|
61
vendor/github.com/anacrolix/missinggo/resource/osfile.go
generated
vendored
Normal file
61
vendor/github.com/anacrolix/missinggo/resource/osfile.go
generated
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Provides access to resources through the native OS filesystem.
|
||||
type OSFileProvider struct{}
|
||||
|
||||
var _ Provider = OSFileProvider{}
|
||||
|
||||
func (me OSFileProvider) NewInstance(filePath string) (r Instance, err error) {
|
||||
return &osFileInstance{filePath}, nil
|
||||
}
|
||||
|
||||
type osFileInstance struct {
|
||||
path string
|
||||
}
|
||||
|
||||
var _ Instance = &osFileInstance{}
|
||||
|
||||
func (me *osFileInstance) Get() (ret io.ReadCloser, err error) {
|
||||
return os.Open(me.path)
|
||||
}
|
||||
|
||||
func (me *osFileInstance) Put(r io.Reader) (err error) {
|
||||
f, err := os.OpenFile(me.path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0640)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
_, err = io.Copy(f, r)
|
||||
return
|
||||
}
|
||||
|
||||
func (me *osFileInstance) ReadAt(b []byte, off int64) (n int, err error) {
|
||||
f, err := os.Open(me.path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
return f.ReadAt(b, off)
|
||||
}
|
||||
|
||||
func (me *osFileInstance) WriteAt(b []byte, off int64) (n int, err error) {
|
||||
f, err := os.OpenFile(me.path, os.O_CREATE|os.O_WRONLY, 0640)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
return f.WriteAt(b, off)
|
||||
}
|
||||
|
||||
func (me *osFileInstance) Stat() (fi os.FileInfo, err error) {
|
||||
return os.Stat(me.path)
|
||||
}
|
||||
|
||||
func (me *osFileInstance) Delete() error {
|
||||
return os.Remove(me.path)
|
||||
}
|
21
vendor/github.com/anacrolix/missinggo/resource/provider.go
generated
vendored
Normal file
21
vendor/github.com/anacrolix/missinggo/resource/provider.go
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
package resource
|
||||
|
||||
type Provider interface {
|
||||
NewInstance(string) (Instance, error)
|
||||
}
|
||||
|
||||
// TranslatedProvider manipulates resource locations, so as to allow
|
||||
// sandboxing, or relative paths for example.
|
||||
type TranslatedProvider struct {
|
||||
// The underlying Provider.
|
||||
BaseProvider Provider
|
||||
// Some location used in calculating final locations.
|
||||
BaseLocation string
|
||||
// Function that takes BaseLocation, and the caller location and returns
|
||||
// the location to be used with the BaseProvider.
|
||||
JoinLocations func(base, rel string) string
|
||||
}
|
||||
|
||||
func (me *TranslatedProvider) NewInstance(rel string) (Instance, error) {
|
||||
return me.BaseProvider.NewInstance(me.JoinLocations(me.BaseLocation, rel))
|
||||
}
|
46
vendor/github.com/anacrolix/missinggo/resource/resource.go
generated
vendored
Normal file
46
vendor/github.com/anacrolix/missinggo/resource/resource.go
generated
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
// An Instance represents the content at some location accessed through some
|
||||
// Provider. It's the data at some URL.
|
||||
type Instance interface {
|
||||
Get() (io.ReadCloser, error)
|
||||
Put(io.Reader) error
|
||||
Stat() (os.FileInfo, error)
|
||||
ReadAt([]byte, int64) (int, error)
|
||||
WriteAt([]byte, int64) (int, error)
|
||||
Delete() error
|
||||
}
|
||||
|
||||
// Creates a io.ReadSeeker to an Instance.
|
||||
func ReadSeeker(r Instance) io.ReadSeeker {
|
||||
fi, err := r.Stat()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return io.NewSectionReader(r, 0, fi.Size())
|
||||
}
|
||||
|
||||
// Move instance content, deleting the source if it succeeds.
|
||||
func Move(from, to Instance) (err error) {
|
||||
rc, err := from.Get()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer rc.Close()
|
||||
err = to.Put(rc)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
from.Delete()
|
||||
return
|
||||
}
|
||||
|
||||
func Exists(i Instance) bool {
|
||||
_, err := i.Stat()
|
||||
return err == nil
|
||||
}
|
Reference in New Issue
Block a user