add documentation
This commit is contained in:
parent
f628342b82
commit
f513d02938
17
datastore.go
17
datastore.go
|
@ -8,13 +8,28 @@ type MetaData map[string]string
|
|||
|
||||
type FileInfo struct {
|
||||
Id string
|
||||
// Total file size in bytes specified in the NewUpload call
|
||||
Size int64
|
||||
// Offset in bytes (zero-based)
|
||||
Offset int64
|
||||
MetaData MetaData
|
||||
}
|
||||
|
||||
type DataStore interface {
|
||||
NewUpload(size int64, metaData MetaData) (string, error)
|
||||
// Create a new upload using the size as the file's length. The method must
|
||||
// return an unique id which is used to identify the upload. If no backend
|
||||
// (e.g. Riak) specifes the id you may want to use the uid package to
|
||||
// generate one.
|
||||
NewUpload(size int64, metaData MetaData) (id string, err error)
|
||||
// Write the chunk read from src into the file specified by the id at the
|
||||
// given offset. The handler will take care of validating the offset and
|
||||
// limiting the size of the src to not overflow the file's size. It may
|
||||
// return an os.ErrNotExist which will be interpretet as a 404 Not Found.
|
||||
// It will also lock resources while they are written to ensure only one
|
||||
// write happens per time.
|
||||
WriteChunk(id string, offset int64, src io.Reader) error
|
||||
// Read the fileinformation used to validate the offset and respond to HEAD
|
||||
// requests. It may return an os.ErrNotExist which will be interpretet as a
|
||||
// 404 Not Found.
|
||||
GetInfo(id string) (FileInfo, error)
|
||||
}
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
// FileStore is a storage backend used as a tusd.DataStore in tusd.NewHandler.
|
||||
// It stores the uploads in a directory specified in two different files: The
|
||||
// `[id].info` files are used to store the fileinfo in JSON format. The
|
||||
// `[id].bin` files contain the raw binary data uploaded.
|
||||
// No cleanup is performed so you may want to run a cronjob to ensure your disk
|
||||
// is not filled up with old and finished uploads.
|
||||
package filestore
|
||||
|
||||
import (
|
||||
|
@ -12,7 +18,11 @@ import (
|
|||
|
||||
var defaultFilePerm = os.FileMode(0666)
|
||||
|
||||
// See the tusd.DataStore interface for documentation about the different
|
||||
// methods.
|
||||
type FileStore struct {
|
||||
// Relative or absolute path to store files in. FileStore does not check
|
||||
// whether the path exists, you os.MkdirAll in this case on your own.
|
||||
Path string
|
||||
}
|
||||
|
||||
|
@ -63,14 +73,17 @@ func (store FileStore) GetInfo(id string) (tusd.FileInfo, error) {
|
|||
return info, err
|
||||
}
|
||||
|
||||
// Return the path to the .bin storing the binary data
|
||||
func (store FileStore) binPath(id string) string {
|
||||
return store.Path + "/" + id + ".bin"
|
||||
}
|
||||
|
||||
// Return the path to the .info file storing the file's info
|
||||
func (store FileStore) infoPath(id string) string {
|
||||
return store.Path + "/" + id + ".info"
|
||||
}
|
||||
|
||||
// Update the entire information. Everything will be overwritten.
|
||||
func (store FileStore) writeInfo(id string, info tusd.FileInfo) error {
|
||||
data, err := json.Marshal(info)
|
||||
if err != nil {
|
||||
|
@ -79,6 +92,7 @@ func (store FileStore) writeInfo(id string, info tusd.FileInfo) error {
|
|||
return ioutil.WriteFile(store.infoPath(id), data, defaultFilePerm)
|
||||
}
|
||||
|
||||
// Update the .info file using the new upload.
|
||||
func (store FileStore) setOffset(id string, offset int64) error {
|
||||
info, err := store.GetInfo(id)
|
||||
if err != nil {
|
||||
|
|
14
handler.go
14
handler.go
|
@ -25,6 +25,7 @@ var (
|
|||
ErrSizeExceeded = errors.New("resource's size exceeded")
|
||||
)
|
||||
|
||||
// HTTP status codes sent in the response when the specific error is returned.
|
||||
var ErrStatusCodes = map[error]int{
|
||||
ErrUnsupportedVersion: http.StatusPreconditionFailed,
|
||||
ErrMaxSizeExceeded: http.StatusRequestEntityTooLarge,
|
||||
|
@ -37,6 +38,8 @@ var ErrStatusCodes = map[error]int{
|
|||
}
|
||||
|
||||
type Config struct {
|
||||
// DataStore implementation used to store and retrieve the single uploads.
|
||||
// Must no be nil.
|
||||
DataStore DataStore
|
||||
// MaxSize defines how many bytes may be stored in one single upload. If its
|
||||
// value is is 0 or smaller no limit will be enforced.
|
||||
|
@ -56,6 +59,7 @@ type Handler struct {
|
|||
locks map[string]bool
|
||||
}
|
||||
|
||||
// Create a new handler using the given configuration.
|
||||
func NewHandler(config Config) (*Handler, error) {
|
||||
base := config.BasePath
|
||||
uri, err := url.Parse(base)
|
||||
|
@ -91,6 +95,7 @@ func NewHandler(config Config) (*Handler, error) {
|
|||
return handler, nil
|
||||
}
|
||||
|
||||
// Implement the http.Handler interface.
|
||||
func (handler *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
go logger.Println(r.Method, r.URL.Path)
|
||||
|
||||
|
@ -138,6 +143,8 @@ func (handler *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||
handler.routeHandler.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// Create a new file upload using the datastore after validating the length
|
||||
// and parsing the metadata.
|
||||
func (handler *Handler) postFile(w http.ResponseWriter, r *http.Request) {
|
||||
size, err := strconv.ParseInt(r.Header.Get("Entity-Length"), 10, 64)
|
||||
if err != nil || size < 0 {
|
||||
|
@ -165,6 +172,7 @@ func (handler *Handler) postFile(w http.ResponseWriter, r *http.Request) {
|
|||
w.WriteHeader(http.StatusCreated)
|
||||
}
|
||||
|
||||
// Returns the length and offset for the HEAD request
|
||||
func (handler *Handler) headFile(w http.ResponseWriter, r *http.Request) {
|
||||
id := r.URL.Query().Get(":id")
|
||||
info, err := handler.dataStore.GetInfo(id)
|
||||
|
@ -182,6 +190,8 @@ func (handler *Handler) headFile(w http.ResponseWriter, r *http.Request) {
|
|||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// Add a chunk to an upload. Only allowed if the upload is not locked and enough
|
||||
// space is left.
|
||||
func (handler *Handler) patchFile(w http.ResponseWriter, r *http.Request) {
|
||||
id := r.URL.Query().Get(":id")
|
||||
|
||||
|
@ -246,6 +256,8 @@ func (handler *Handler) patchFile(w http.ResponseWriter, r *http.Request) {
|
|||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// Send the error in the response body. The status code will be looked up in
|
||||
// ErrStatusCodes. If none is found 500 Internal Error will be used.
|
||||
func (handler *Handler) sendError(w http.ResponseWriter, err error) {
|
||||
status, ok := ErrStatusCodes[err]
|
||||
if !ok {
|
||||
|
@ -256,6 +268,8 @@ func (handler *Handler) sendError(w http.ResponseWriter, err error) {
|
|||
w.Write([]byte(err.Error() + "\n"))
|
||||
}
|
||||
|
||||
// Make an absolute URLs to the given upload id. If the base path is absolute
|
||||
// it will be prepended else the host and protocol from the request is used.
|
||||
func (handler *Handler) absFileUrl(r *http.Request, id string) string {
|
||||
if handler.isBasePathAbs {
|
||||
return handler.basePath + id
|
||||
|
|
Loading…
Reference in New Issue