Selaa lähdekoodia

First swing at putting metadata handling into the storage layer

pull/294/head
stefanbenten 4 vuotta sitten
vanhempi
commit
9a2fb917b7
3 muutettua tiedostoa jossa 315 lisäystä ja 186 poistoa
  1. +39
    -101
      server/handlers.go
  2. +2
    -0
      server/server.go
  3. +274
    -85
      server/storage.go

+ 39
- 101
server/handlers.go Näytä tiedosto

@@ -32,7 +32,6 @@ import (
"archive/zip"
"bytes"
"compress/gzip"
"encoding/json"
"errors"
"fmt"
blackfriday "github.com/russross/blackfriday/v2"
@@ -92,7 +91,7 @@ func initHTMLTemplates() *html_template.Template {
}

func healthHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Approaching Neutral Zone, all systems normal and functioning.")
_, _ = w.Write([]byte("Approaching Neutral Zone, all systems normal and functioning."))
}

/* The preview handler will show a preview of the content for browsers (accept type text/html), and referer is not transfer.sh */
@@ -111,11 +110,6 @@ func (s *Server) previewHandler(w http.ResponseWriter, r *http.Request) {
}

contentType := metadata.ContentType
contentLength, err := s.storage.Head(token, filename)
if err != nil {
http.Error(w, http.StatusText(404), 404)
return
}

var templatePath string
var content html_template.HTML
@@ -181,7 +175,7 @@ func (s *Server) previewHandler(w http.ResponseWriter, r *http.Request) {
UrlGet string
Hostname string
WebAddress string
ContentLength uint64
ContentLength int64
GAKey string
UserVoiceKey string
QRCode string
@@ -193,7 +187,7 @@ func (s *Server) previewHandler(w http.ResponseWriter, r *http.Request) {
resolvedURLGet,
hostname,
webAddress,
contentLength,
metadata.ContentLength,
s.gaKey,
s.userVoiceKey,
qrCode,
@@ -295,10 +289,10 @@ func (s *Server) postHandler(w http.ResponseWriter, r *http.Request) {
log.Fatal(err)
}

defer cleanTmpFile(file)

n, err = io.Copy(file, io.MultiReader(&b, f))
if err != nil {
cleanTmpFile(file)

log.Printf("%s", err.Error())
http.Error(w, err.Error(), 500)
return
@@ -309,28 +303,11 @@ func (s *Server) postHandler(w http.ResponseWriter, r *http.Request) {
reader = bytes.NewReader(b.Bytes())
}

contentLength := n
metadata := s.metadataForRequest(contentType, n, r)

metadata := MetadataForRequest(contentType, r)

buffer := &bytes.Buffer{}
if err := json.NewEncoder(buffer).Encode(metadata); err != nil {
log.Printf("%s", err.Error())
http.Error(w, errors.New("Could not encode metadata").Error(), 500)

cleanTmpFile(file)
return
} else if err := s.storage.Put(token, fmt.Sprintf("%s.metadata", filename), buffer, "text/json", uint64(buffer.Len())); err != nil {
log.Printf("%s", err.Error())
http.Error(w, errors.New("Could not save metadata").Error(), 500)
log.Printf("Uploading %s %s %d %s", token, filename, metadata.ContentLength, metadata.ContentType)

cleanTmpFile(file)
return
}

log.Printf("Uploading %s %s %d %s", token, filename, contentLength, contentType)

if err = s.storage.Put(token, filename, reader, contentType, uint64(contentLength)); err != nil {
if err = s.storage.Put(token, filename, reader, metadata); err != nil {
log.Printf("Backend storage error: %s", err.Error())
http.Error(w, err.Error(), 500)
return
@@ -339,9 +316,7 @@ func (s *Server) postHandler(w http.ResponseWriter, r *http.Request) {

filename = url.PathEscape(filename)
relativeURL, _ := url.Parse(path.Join(s.proxyPath, token, filename))
fmt.Fprintln(w, getURL(r).ResolveReference(relativeURL).String())

cleanTmpFile(file)
_, _ = fmt.Fprintln(w, getURL(r).ResolveReference(relativeURL).String())
}
}
}
@@ -360,25 +335,11 @@ func cleanTmpFile(f *os.File) {
}
}

type Metadata struct {
// ContentType is the original uploading content type
ContentType string
// Secret as knowledge to delete file
// Secret string
// Downloads is the actual number of downloads
Downloads int
// MaxDownloads contains the maximum numbers of downloads
MaxDownloads int
// MaxDate contains the max age of the file
MaxDate time.Time
// DeletionToken contains the token to match against for deletion
DeletionToken string
}

func MetadataForRequest(contentType string, r *http.Request) Metadata {
func (s *Server) metadataForRequest(contentType string, contentLength int64, r *http.Request) Metadata {
metadata := Metadata{
ContentType: contentType,
MaxDate: time.Time{},
ContentLength: contentLength,
MaxDate: time.Now().Add(s.lifetime),
Downloads: 0,
MaxDownloads: -1,
DeletionToken: Encode(10000000+int64(rand.Intn(1000000000))) + Encode(10000000+int64(rand.Intn(1000000000))),
@@ -390,12 +351,13 @@ func MetadataForRequest(contentType string, r *http.Request) Metadata {
metadata.MaxDownloads = v
}

if v := r.Header.Get("Max-Days"); v == "" {
} else if v, err := strconv.Atoi(v); err != nil {
} else {
if maxDays := r.Header.Get("Max-Days"); maxDays != "" {
v, err := strconv.Atoi(maxDays)
if err != nil {
return metadata
}
metadata.MaxDate = time.Now().Add(time.Hour * 24 * time.Duration(v))
}

return metadata
}

@@ -469,24 +431,13 @@ func (s *Server) putHandler(w http.ResponseWriter, r *http.Request) {

token := Encode(10000000 + int64(rand.Intn(1000000000)))

metadata := MetadataForRequest(contentType, r)

buffer := &bytes.Buffer{}
if err := json.NewEncoder(buffer).Encode(metadata); err != nil {
log.Printf("%s", err.Error())
http.Error(w, errors.New("Could not encode metadata").Error(), 500)
return
} else if err := s.storage.Put(token, fmt.Sprintf("%s.metadata", filename), buffer, "text/json", uint64(buffer.Len())); err != nil {
log.Printf("%s", err.Error())
http.Error(w, errors.New("Could not save metadata").Error(), 500)
return
}
metadata := s.metadataForRequest(contentType, contentLength, r)

log.Printf("Uploading %s %s %d %s", token, filename, contentLength, contentType)

var err error

if err = s.storage.Put(token, filename, reader, contentType, uint64(contentLength)); err != nil {
if err = s.storage.Put(token, filename, reader, metadata); err != nil {
log.Printf("Error putting new file: %s", err.Error())
http.Error(w, errors.New("Could not save file").Error(), 500)
return
@@ -502,7 +453,7 @@ func (s *Server) putHandler(w http.ResponseWriter, r *http.Request) {

w.Header().Set("X-Url-Delete", resolveURL(r, deleteURL))

fmt.Fprint(w, resolveURL(r, relativeURL))
_, _ = fmt.Fprint(w, resolveURL(r, relativeURL))
}

func resolveURL(r *http.Request, u *url.URL) string {
@@ -613,18 +564,14 @@ func (s *Server) CheckMetadata(token, filename string, increaseDownload bool) (M

var metadata Metadata

r, _, err := s.storage.Get(token, fmt.Sprintf("%s.metadata", filename))
metadata, err := s.storage.Head(token, filename)
if s.storage.IsNotExist(err) {
return metadata, nil
} else if err != nil {
return metadata, err
}

defer r.Close()

if err := json.NewDecoder(r).Decode(&metadata); err != nil {
return metadata, err
} else if metadata.MaxDownloads != -1 && metadata.Downloads >= metadata.MaxDownloads {
if metadata.MaxDownloads != -1 && metadata.Downloads >= metadata.MaxDownloads {
return metadata, errors.New("MaxDownloads expired.")
} else if !metadata.MaxDate.IsZero() && time.Now().After(metadata.MaxDate) {
return metadata, errors.New("MaxDate expired.")
@@ -636,10 +583,7 @@ func (s *Server) CheckMetadata(token, filename string, increaseDownload bool) (M
metadata.Downloads++
}

buffer := &bytes.Buffer{}
if err := json.NewEncoder(buffer).Encode(metadata); err != nil {
return metadata, errors.New("Could not encode metadata")
} else if err := s.storage.Put(token, fmt.Sprintf("%s.metadata", filename), buffer, "text/json", uint64(buffer.Len())); err != nil {
if err := s.storage.Meta(token, filename, metadata); err != nil {
return metadata, errors.New("Could not save metadata")
}
}
@@ -653,18 +597,15 @@ func (s *Server) CheckDeletionToken(deletionToken, token, filename string) error

var metadata Metadata

r, _, err := s.storage.Get(token, fmt.Sprintf("%s.metadata", filename))
metadata, err := s.storage.Head(token, filename)
if s.storage.IsNotExist(err) {
return nil
} else if err != nil {
}
if err != nil {
return err
}

defer r.Close()

if err := json.NewDecoder(r).Decode(&metadata); err != nil {
return err
} else if metadata.DeletionToken != deletionToken {
if metadata.DeletionToken != deletionToken {
return errors.New("Deletion token doesn't match.")
}

@@ -774,10 +715,10 @@ func (s *Server) tarGzHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", tarfilename))
w.Header().Set("Connection", "close")

os := gzip.NewWriter(w)
defer os.Close()
writer := gzip.NewWriter(w)
defer writer.Close()

zw := tar.NewWriter(os)
zw := tar.NewWriter(writer)
defer zw.Close()

for _, key := range strings.Split(files, ",") {
@@ -791,7 +732,7 @@ func (s *Server) tarGzHandler(w http.ResponseWriter, r *http.Request) {
continue
}

reader, contentLength, err := s.storage.Get(token, filename)
reader, metadata, err := s.storage.Get(token, filename)
if err != nil {
if s.storage.IsNotExist(err) {
http.Error(w, "File not found", 404)
@@ -807,7 +748,7 @@ func (s *Server) tarGzHandler(w http.ResponseWriter, r *http.Request) {

header := &tar.Header{
Name: strings.Split(key, "/")[1],
Size: int64(contentLength),
Size: metadata.ContentLength,
}

err = zw.WriteHeader(header)
@@ -850,7 +791,7 @@ func (s *Server) tarHandler(w http.ResponseWriter, r *http.Request) {
continue
}

reader, contentLength, err := s.storage.Get(token, filename)
reader, metadata, err := s.storage.Get(token, filename)
if err != nil {
if s.storage.IsNotExist(err) {
http.Error(w, "File not found", 404)
@@ -866,7 +807,7 @@ func (s *Server) tarHandler(w http.ResponseWriter, r *http.Request) {

header := &tar.Header{
Name: strings.Split(key, "/")[1],
Size: int64(contentLength),
Size: metadata.ContentLength,
}

err = zw.WriteHeader(header)
@@ -898,8 +839,6 @@ func (s *Server) headHandler(w http.ResponseWriter, r *http.Request) {
return
}

contentType := metadata.ContentType
contentLength, err := s.storage.Head(token, filename)
if s.storage.IsNotExist(err) {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
return
@@ -911,8 +850,8 @@ func (s *Server) headHandler(w http.ResponseWriter, r *http.Request) {

remainingDownloads, remainingDays := metadata.remainingLimitHeaderValues()

w.Header().Set("Content-Type", contentType)
w.Header().Set("Content-Length", strconv.FormatUint(contentLength, 10))
w.Header().Set("Content-Type", metadata.ContentType)
w.Header().Set("Content-Length", strconv.FormatInt(metadata.ContentLength, 10))
w.Header().Set("Connection", "close")
w.Header().Set("X-Remaining-Downloads", remainingDownloads)
w.Header().Set("X-Remaining-Days", remainingDays)
@@ -933,8 +872,7 @@ func (s *Server) getHandler(w http.ResponseWriter, r *http.Request) {
return
}

contentType := metadata.ContentType
reader, contentLength, err := s.storage.Get(token, filename)
reader, _, err := s.storage.Get(token, filename)
if s.storage.IsNotExist(err) {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
return
@@ -956,8 +894,8 @@ func (s *Server) getHandler(w http.ResponseWriter, r *http.Request) {

remainingDownloads, remainingDays := metadata.remainingLimitHeaderValues()

w.Header().Set("Content-Type", contentType)
w.Header().Set("Content-Length", strconv.FormatUint(contentLength, 10))
w.Header().Set("Content-Type", metadata.ContentType)
w.Header().Set("Content-Length", strconv.FormatInt(metadata.ContentLength, 10))
w.Header().Set("Content-Disposition", fmt.Sprintf("%s; filename=\"%s\"", disposition, filename))
w.Header().Set("Connection", "keep-alive")
w.Header().Set("X-Remaining-Downloads", remainingDownloads)


+ 2
- 0
server/server.go Näytä tiedosto

@@ -259,6 +259,8 @@ type Server struct {

storage Storage

lifetime time.Duration

forceHTTPs bool

ipFilterOptions *IPFilterOptions


+ 274
- 85
server/storage.go Näytä tiedosto

@@ -1,6 +1,7 @@
package server

import (
"bytes"
"encoding/json"
"fmt"
"io"
@@ -9,7 +10,9 @@ import (
"net/http"
"os"
"path/filepath"
"strconv"
"strings"
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
@@ -23,12 +26,31 @@ import (
"google.golang.org/api/googleapi"
)

type Metadata struct {
// ContentType is the original uploading content type
ContentType string
// ContentLength contains the length of the actual object
ContentLength int64
// Downloads is the actual number of downloads
Downloads int
// MaxDownloads contains the maximum numbers of downloads
MaxDownloads int
// MaxDate contains the max age of the file
MaxDate time.Time
// DeletionToken contains the token to match against for deletion
DeletionToken string
// Secret as knowledge to delete file
Secret string
}

type Storage interface {
Get(token string, filename string) (reader io.ReadCloser, contentLength uint64, err error)
Head(token string, filename string) (contentLength uint64, err error)
Put(token string, filename string, reader io.Reader, contentType string, contentLength uint64) error
Get(token string, filename string) (reader io.ReadCloser, metaData Metadata, err error)
Head(token string, filename string) (metadata Metadata, err error)
Meta(token string, filename string, metadata Metadata) error
Put(token string, filename string, reader io.Reader, metadata Metadata) error
Delete(token string, filename string) error
IsNotExist(err error) bool
DeleteExpired() error

Type() string
}
@@ -47,55 +69,56 @@ func (s *LocalStorage) Type() string {
return "local"
}

func (s *LocalStorage) Head(token string, filename string) (contentLength uint64, err error) {
func (s *LocalStorage) Get(token string, filename string) (reader io.ReadCloser, metadata Metadata, err error) {
path := filepath.Join(s.basedir, token, filename)

var fi os.FileInfo
if fi, err = os.Lstat(path); err != nil {
return
// content type , content length
reader, err = os.Open(path)
if err != nil {
return nil, Metadata{}, err
}

contentLength = uint64(fi.Size())

return
metadata, err = s.Head(token, filename)
if err != nil {
return nil, Metadata{}, err
}
return reader, metadata, nil
}

func (s *LocalStorage) Get(token string, filename string) (reader io.ReadCloser, contentLength uint64, err error) {
func (s *LocalStorage) Head(token string, filename string) (metadata Metadata, err error) {
path := filepath.Join(s.basedir, token, filename)

// content type , content length
if reader, err = os.Open(path); err != nil {
fi, err := os.Open(path)
if err != nil {
return
}

var fi os.FileInfo
if fi, err = os.Lstat(path); err != nil {
return
err = json.NewDecoder(fi).Decode(&metadata)
if err != nil {
return Metadata{}, err
}

contentLength = uint64(fi.Size())

return
return metadata, nil
}

func (s *LocalStorage) Delete(token string, filename string) (err error) {
metadata := filepath.Join(s.basedir, token, fmt.Sprintf("%s.metadata", filename))
os.Remove(metadata)

path := filepath.Join(s.basedir, token, filename)
err = os.Remove(path)
return
func (s *LocalStorage) Meta(token string, filename string, metadata Metadata) error {
return s.putMetadata(token, filename, metadata)
}

func (s *LocalStorage) IsNotExist(err error) bool {
if err == nil {
return false
func (s *LocalStorage) Put(token string, filename string, reader io.Reader, metadata Metadata) error {
err := s.putMetadata(token, filename, metadata)
if err != nil {
return err
}

return os.IsNotExist(err)
err = s.put(token, filename, reader)
if err != nil {
//Delete the metadata if the put failed
_ = s.Delete(token, fmt.Sprintf("%s.metadata", filename))
}
return err
}

func (s *LocalStorage) Put(token string, filename string, reader io.Reader, contentType string, contentLength uint64) error {
func (s *LocalStorage) put(token string, filename string, reader io.Reader) error {
var f io.WriteCloser
var err error

@@ -111,10 +134,41 @@ func (s *LocalStorage) Put(token string, filename string, reader io.Reader, cont

defer f.Close()

if _, err = io.Copy(f, reader); err != nil {
_, err = io.Copy(f, reader)
return err
}

func (s *LocalStorage) putMetadata(token string, filename string, metadata Metadata) error {
buffer := &bytes.Buffer{}
if err := json.NewEncoder(buffer).Encode(metadata); err != nil {
log.Printf("%s", err.Error())
return err
} else if err := s.put(token, filename, buffer); err != nil {
log.Printf("%s", err.Error())

return nil
}
return nil
}

func (s *LocalStorage) Delete(token string, filename string) (err error) {
metadata := filepath.Join(s.basedir, token, fmt.Sprintf("%s.metadata", filename))
_ = os.Remove(metadata)

path := filepath.Join(s.basedir, token, filename)
err = os.Remove(path)
return
}

func (s *LocalStorage) IsNotExist(err error) bool {
if err == nil {
return false
}

return os.IsNotExist(err)
}

func (s *LocalStorage) DeleteExpired() error {
return nil
}

@@ -137,7 +191,7 @@ func (s *S3Storage) Type() string {
return "s3"
}

func (s *S3Storage) Head(token string, filename string) (contentLength uint64, err error) {
func (s *S3Storage) Head(token string, filename string) (metadata Metadata, err error) {
key := fmt.Sprintf("%s/%s", token, filename)

headRequest := &s3.HeadObjectInput{
@@ -148,32 +202,60 @@ func (s *S3Storage) Head(token string, filename string) (contentLength uint64, e
// content type , content length
response, err := s.s3.HeadObject(headRequest)
if err != nil {
return
return Metadata{}, err
}

if response.ContentLength != nil {
contentLength = uint64(*response.ContentLength)
downloads, err := strconv.Atoi(*response.Metadata["downloads"])
if err != nil {
return Metadata{}, err
}
maxdownloads, err := strconv.Atoi(*response.Metadata["maxDownloads"])
if err != nil {
return Metadata{}, err
}
expires, err := time.Parse("2020-02-02 02:02:02", *response.Expires)
if err != nil {
return Metadata{}, err
}

return
metadata = Metadata{
ContentType: "",
ContentLength: *response.ContentLength,
Downloads: downloads,
MaxDownloads: maxdownloads,
MaxDate: expires,
DeletionToken: *response.Metadata["deletionToken"],
Secret: *response.Metadata["deletionSecret"],
}
return metadata, nil
}

func (s *S3Storage) IsNotExist(err error) bool {
if err == nil {
return false
}
func (s *S3Storage) Meta(token string, filename string, metadata Metadata) error {
key := fmt.Sprintf("%s/%s", token, filename)

if aerr, ok := err.(awserr.Error); ok {
switch aerr.Code() {
case s3.ErrCodeNoSuchKey:
return true
}
input := &s3.CopyObjectInput{
Bucket: aws.String(s.bucket),
CopySource: aws.String(key),
Key: aws.String(key),
MetadataDirective: aws.String("REPLACE"),
Metadata: map[string]*string{
"downloads": aws.String(strconv.Itoa(metadata.Downloads)),
"maxDownloads": aws.String(strconv.Itoa(metadata.MaxDownloads)),
"deletionToken": aws.String(metadata.DeletionToken),
"deletionSecret": aws.String(metadata.Secret),
},
ContentType: aws.String(metadata.ContentType),
Expires: aws.Time(metadata.MaxDate),
}

_, err := s.s3.CopyObject(input)
if err != nil {
return err
}

return false
return nil
}

func (s *S3Storage) Get(token string, filename string) (reader io.ReadCloser, contentLength uint64, err error) {
func (s *S3Storage) Get(token string, filename string) (reader io.ReadCloser, metadata Metadata, err error) {
key := fmt.Sprintf("%s/%s", token, filename)

getRequest := &s3.GetObjectInput{
@@ -186,8 +268,27 @@ func (s *S3Storage) Get(token string, filename string) (reader io.ReadCloser, co
return
}

if response.ContentLength != nil {
contentLength = uint64(*response.ContentLength)
downloads, err := strconv.Atoi(*response.Metadata["downloads"])
if err != nil {
return nil, Metadata{}, err
}
maxdownloads, err := strconv.Atoi(*response.Metadata["maxDownloads"])
if err != nil {
return nil, Metadata{}, err
}
expires, err := time.Parse("2020-02-02 02:02:02", *response.Expires)
if err != nil {
return nil, Metadata{}, err
}

metadata = Metadata{
ContentType: "",
ContentLength: *response.ContentLength,
Downloads: downloads,
MaxDownloads: maxdownloads,
MaxDate: expires,
DeletionToken: *response.Metadata["deletionToken"],
Secret: *response.Metadata["deletionSecret"],
}

reader = response.Body
@@ -217,7 +318,7 @@ func (s *S3Storage) Delete(token string, filename string) (err error) {
return
}

func (s *S3Storage) Put(token string, filename string, reader io.Reader, contentType string, contentLength uint64) (err error) {
func (s *S3Storage) Put(token string, filename string, reader io.Reader, metadata Metadata) (err error) {
key := fmt.Sprintf("%s/%s", token, filename)

s.logger.Printf("Uploading file %s to S3 Bucket", filename)
@@ -238,11 +339,39 @@ func (s *S3Storage) Put(token string, filename string, reader io.Reader, content
Bucket: aws.String(s.bucket),
Key: aws.String(key),
Body: reader,
Metadata: map[string]*string{
"downloads": aws.String(strconv.Itoa(metadata.Downloads)),
"maxDownloads": aws.String(strconv.Itoa(metadata.MaxDownloads)),
"deletionToken": aws.String(metadata.DeletionToken),
"deletionSecret": aws.String(metadata.Secret),
},
ContentType: aws.String(metadata.ContentType),
Expires: aws.Time(metadata.MaxDate),
})

return
}

func (s *S3Storage) IsNotExist(err error) bool {
if err == nil {
return false
}

if aerr, ok := err.(awserr.Error); ok {
switch aerr.Code() {
case s3.ErrCodeNoSuchKey:
return true
}
}

return false
}

func (s *S3Storage) DeleteExpired() error {
// not necessary, as S3 has expireDate on files to automatically delete the them
return nil
}

type GDrive struct {
service *drive.Service
rootId string
@@ -385,7 +514,7 @@ func (s *GDrive) Type() string {
return "gdrive"
}

func (s *GDrive) Head(token string, filename string) (contentLength uint64, err error) {
func (s *GDrive) Get(token string, filename string) (reader io.ReadCloser, metadata Metadata, err error) {
var fileId string
fileId, err = s.findId(filename, token)
if err != nil {
@@ -393,30 +522,37 @@ func (s *GDrive) Head(token string, filename string) (contentLength uint64, err
}

var fi *drive.File
if fi, err = s.service.Files.Get(fileId).Fields("size").Do(); err != nil {
fi, err = s.service.Files.Get(fileId).Do()
if !s.hasChecksum(fi) {
err = fmt.Errorf("Cannot find file %s/%s", token, filename)
return
}

contentLength = uint64(fi.Size)

return
}

func (s *GDrive) Get(token string, filename string) (reader io.ReadCloser, contentLength uint64, err error) {
var fileId string
fileId, err = s.findId(filename, token)
if err != nil {
return
return nil, Metadata{}, err
}

var fi *drive.File
fi, err = s.service.Files.Get(fileId).Fields("size", "md5Checksum").Do()
if !s.hasChecksum(fi) {
err = fmt.Errorf("Cannot find file %s/%s", token, filename)
return
downloads, err := strconv.Atoi(fi.Properties["downloads"])
if err != nil {
return nil, Metadata{}, err
}
maxdownloads, err := strconv.Atoi(fi.Properties["maxDownloads"])
if err != nil {
return nil, Metadata{}, err
}
expires, err := time.Parse("2020-02-02 02:02:02", fi.Properties["expires"])
if err != nil {
return nil, Metadata{}, err
}

contentLength = uint64(fi.Size)
metadata = Metadata{
ContentType: "",
ContentLength: fi.Size,
Downloads: downloads,
MaxDownloads: maxdownloads,
MaxDate: expires,
DeletionToken: fi.Properties["deletionToken"],
Secret: fi.Properties["deletionSecret"],
}

ctx := context.Background()
var res *http.Response
@@ -430,31 +566,49 @@ func (s *GDrive) Get(token string, filename string) (reader io.ReadCloser, conte
return
}

func (s *GDrive) Delete(token string, filename string) (err error) {
metadata, _ := s.findId(fmt.Sprintf("%s.metadata", filename), token)
s.service.Files.Delete(metadata).Do()

func (s *GDrive) Head(token string, filename string) (metadata Metadata, err error) {
var fileId string
fileId, err = s.findId(filename, token)
if err != nil {
return
}

err = s.service.Files.Delete(fileId).Do()
return
}
var fi *drive.File
if fi, err = s.service.Files.Get(fileId).Do(); err != nil {
return
}

func (s *GDrive) IsNotExist(err error) bool {
downloads, err := strconv.Atoi(fi.Properties["downloads"])
if err != nil {
if e, ok := err.(*googleapi.Error); ok {
return e.Code == http.StatusNotFound
}
return Metadata{}, err
}
maxdownloads, err := strconv.Atoi(fi.Properties["maxDownloads"])
if err != nil {
return Metadata{}, err
}
expires, err := time.Parse("2020-02-02 02:02:02", fi.Properties["expires"])
if err != nil {
return Metadata{}, err
}

return false
metadata = Metadata{
ContentType: "",
ContentLength: fi.Size,
Downloads: downloads,
MaxDownloads: maxdownloads,
MaxDate: expires,
DeletionToken: fi.Properties["deletionToken"],
Secret: fi.Properties["deletionSecret"],
}

return
}

func (s *GDrive) Meta(token string, filename string, metadata Metadata) error {
return nil
}

func (s *GDrive) Put(token string, filename string, reader io.Reader, contentType string, contentLength uint64) error {
func (s *GDrive) Put(token string, filename string, reader io.Reader, metadata Metadata) error {
dirId, err := s.findId("", token)
if err != nil {
return err
@@ -479,7 +633,14 @@ func (s *GDrive) Put(token string, filename string, reader io.Reader, contentTyp
dst := &drive.File{
Name: filename,
Parents: []string{dirId},
MimeType: contentType,
MimeType: metadata.ContentType,
Properties: map[string]string{
"downloads": strconv.Itoa(metadata.Downloads),
"maxDownloads": strconv.Itoa(metadata.MaxDownloads),
"deletionToken": metadata.DeletionToken,
"deletionSecret": metadata.Secret,
"expires": metadata.MaxDate.String(),
},
}

ctx := context.Background()
@@ -492,6 +653,34 @@ func (s *GDrive) Put(token string, filename string, reader io.Reader, contentTyp
return nil
}

func (s *GDrive) Delete(token string, filename string) (err error) {
metadata, _ := s.findId(fmt.Sprintf("%s.metadata", filename), token)
s.service.Files.Delete(metadata).Do()

var fileId string
fileId, err = s.findId(filename, token)
if err != nil {
return
}

err = s.service.Files.Delete(fileId).Do()
return
}

func (s *GDrive) IsNotExist(err error) bool {
if err != nil {
if e, ok := err.(*googleapi.Error); ok {
return e.Code == http.StatusNotFound
}
}

return false
}

func (s *GDrive) DeleteExpired() error {
return nil
}

// Retrieve a token, saves the token, then returns the generated client.
func getGDriveClient(config *oauth2.Config, localConfigPath string, logger *log.Logger) *http.Client {
tokenFile := filepath.Join(localConfigPath, GDriveTokenJsonFile)


Ladataan…
Peruuta
Tallenna