Merge pull request #124 from mutantmonkey/cleanup_tool
Add linx-cleanup tool
This commit is contained in:
commit
ceea32de6b
1
.gitignore
vendored
1
.gitignore
vendored
@ -29,3 +29,4 @@ _testmain.go
|
|||||||
linx-server
|
linx-server
|
||||||
files/
|
files/
|
||||||
meta/
|
meta/
|
||||||
|
linx-cleanup
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
FROM golang:alpine
|
FROM golang:alpine
|
||||||
|
|
||||||
RUN set -ex \
|
RUN set -ex \
|
||||||
&& apk add --no-cache --virtual .build-deps git mercurial \
|
&& apk add --no-cache --virtual .build-deps git \
|
||||||
&& go get github.com/andreimarcu/linx-server \
|
&& go get github.com/andreimarcu/linx-server \
|
||||||
&& apk del .build-deps
|
&& apk del .build-deps
|
||||||
|
|
||||||
|
17
README.md
17
README.md
@ -71,6 +71,23 @@ allowhotlink = true
|
|||||||
A helper utility ```linx-genkey``` is provided which hashes keys to the format required in the auth files.
|
A helper utility ```linx-genkey``` is provided which hashes keys to the format required in the auth files.
|
||||||
|
|
||||||
|
|
||||||
|
Cleaning up expired files
|
||||||
|
-------------------------
|
||||||
|
When files expire, access is disabled immediately, but the files and metadata
|
||||||
|
will persist on disk until someone attempts to access them. If you'd like to
|
||||||
|
automatically clean up files that have expired, you can use the included
|
||||||
|
`linx-cleanup` utility. To run it automatically, use a cronjob or similar type
|
||||||
|
of scheduled task.
|
||||||
|
|
||||||
|
You should be careful to ensure that only one instance of `linx-client` runs at
|
||||||
|
a time to avoid unexpected behavior. It does not implement any type of locking.
|
||||||
|
|
||||||
|
#### Options
|
||||||
|
- ```-filespath files/``` -- Path to stored uploads (default is files/)
|
||||||
|
- ```-metapath meta/``` -- Path to stored information about uploads (default is meta/)
|
||||||
|
- ```-nologs``` -- (optionally) disable deletion logs in stdout
|
||||||
|
|
||||||
|
|
||||||
Deployment
|
Deployment
|
||||||
----------
|
----------
|
||||||
Linx-server supports being deployed in a subdirectory (ie. example.com/mylinx/) as well as on its own (example.com/).
|
Linx-server supports being deployed in a subdirectory (ie. example.com/mylinx/) as well as on its own (example.com/).
|
||||||
|
@ -65,6 +65,21 @@ func (b LocalfsBackend) Size(key string) (int64, error) {
|
|||||||
return fileInfo.Size(), nil
|
return fileInfo.Size(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b LocalfsBackend) List() ([]string, error) {
|
||||||
|
var output []string
|
||||||
|
|
||||||
|
files, err := ioutil.ReadDir(b.basePath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, file := range files {
|
||||||
|
output = append(output, file.Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
return output, nil
|
||||||
|
}
|
||||||
|
|
||||||
func NewLocalfsBackend(basePath string) LocalfsBackend {
|
func NewLocalfsBackend(basePath string) LocalfsBackend {
|
||||||
return LocalfsBackend{basePath: basePath}
|
return LocalfsBackend{basePath: basePath}
|
||||||
}
|
}
|
||||||
|
23
backends/meta.go
Normal file
23
backends/meta.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package backends
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MetaBackend interface {
|
||||||
|
Get(key string) (Metadata, error)
|
||||||
|
Put(key string, metadata *Metadata) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type Metadata struct {
|
||||||
|
DeleteKey string
|
||||||
|
Sha256sum string
|
||||||
|
Mimetype string
|
||||||
|
Size int64
|
||||||
|
Expiry time.Time
|
||||||
|
ArchiveFiles []string
|
||||||
|
ShortURL string
|
||||||
|
}
|
||||||
|
|
||||||
|
var BadMetadata = errors.New("Corrupted metadata.")
|
73
backends/metajson/metajson.go
Normal file
73
backends/metajson/metajson.go
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
package metajson
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/andreimarcu/linx-server/backends"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MetadataJSON struct {
|
||||||
|
DeleteKey string `json:"delete_key"`
|
||||||
|
Sha256sum string `json:"sha256sum"`
|
||||||
|
Mimetype string `json:"mimetype"`
|
||||||
|
Size int64 `json:"size"`
|
||||||
|
Expiry int64 `json:"expiry"`
|
||||||
|
ArchiveFiles []string `json:"archive_files,omitempty"`
|
||||||
|
ShortURL string `json:"short_url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MetaJSONBackend struct {
|
||||||
|
storage backends.MetaStorageBackend
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m MetaJSONBackend) Put(key string, metadata *backends.Metadata) error {
|
||||||
|
mjson := MetadataJSON{}
|
||||||
|
mjson.DeleteKey = metadata.DeleteKey
|
||||||
|
mjson.Mimetype = metadata.Mimetype
|
||||||
|
mjson.ArchiveFiles = metadata.ArchiveFiles
|
||||||
|
mjson.Sha256sum = metadata.Sha256sum
|
||||||
|
mjson.Expiry = metadata.Expiry.Unix()
|
||||||
|
mjson.Size = metadata.Size
|
||||||
|
mjson.ShortURL = metadata.ShortURL
|
||||||
|
|
||||||
|
byt, err := json.Marshal(mjson)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := m.storage.Put(key, bytes.NewBuffer(byt)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m MetaJSONBackend) Get(key string) (metadata backends.Metadata, err error) {
|
||||||
|
b, err := m.storage.Get(key)
|
||||||
|
if err != nil {
|
||||||
|
return metadata, backends.BadMetadata
|
||||||
|
}
|
||||||
|
|
||||||
|
mjson := MetadataJSON{}
|
||||||
|
|
||||||
|
err = json.Unmarshal(b, &mjson)
|
||||||
|
if err != nil {
|
||||||
|
return metadata, backends.BadMetadata
|
||||||
|
}
|
||||||
|
|
||||||
|
metadata.DeleteKey = mjson.DeleteKey
|
||||||
|
metadata.Mimetype = mjson.Mimetype
|
||||||
|
metadata.ArchiveFiles = mjson.ArchiveFiles
|
||||||
|
metadata.Sha256sum = mjson.Sha256sum
|
||||||
|
metadata.Expiry = time.Unix(mjson.Expiry, 0)
|
||||||
|
metadata.Size = mjson.Size
|
||||||
|
metadata.ShortURL = mjson.ShortURL
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMetaJSONBackend(storage backends.MetaStorageBackend) MetaJSONBackend {
|
||||||
|
return MetaJSONBackend{storage: storage}
|
||||||
|
}
|
@ -21,3 +21,8 @@ type StorageBackend interface {
|
|||||||
ServeFile(key string, w http.ResponseWriter, r *http.Request)
|
ServeFile(key string, w http.ResponseWriter, r *http.Request)
|
||||||
Size(key string) (int64, error)
|
Size(key string) (int64, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MetaStorageBackend interface {
|
||||||
|
StorageBackend
|
||||||
|
List() ([]string, error)
|
||||||
|
}
|
@ -28,7 +28,7 @@ func deleteHandler(c web.C, w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
if metadata.DeleteKey == requestKey {
|
if metadata.DeleteKey == requestKey {
|
||||||
fileDelErr := fileBackend.Delete(filename)
|
fileDelErr := fileBackend.Delete(filename)
|
||||||
metaDelErr := metaBackend.Delete(filename)
|
metaDelErr := metaStorageBackend.Delete(filename)
|
||||||
|
|
||||||
if (fileDelErr != nil) || (metaDelErr != nil) {
|
if (fileDelErr != nil) || (metaDelErr != nil) {
|
||||||
oopsHandler(c, w, r, RespPLAIN, "Could not delete")
|
oopsHandler(c, w, r, RespPLAIN, "Could not delete")
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/andreimarcu/linx-server/expiry"
|
||||||
"github.com/dustin/go-humanize"
|
"github.com/dustin/go-humanize"
|
||||||
"github.com/flosch/pongo2"
|
"github.com/flosch/pongo2"
|
||||||
"github.com/microcosm-cc/bluemonday"
|
"github.com/microcosm-cc/bluemonday"
|
||||||
@ -32,7 +33,7 @@ func fileDisplayHandler(c web.C, w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
var expiryHuman string
|
var expiryHuman string
|
||||||
if metadata.Expiry != neverExpire {
|
if metadata.Expiry != expiry.NeverExpire {
|
||||||
expiryHuman = humanize.RelTime(time.Now(), metadata.Expiry, "", "")
|
expiryHuman = humanize.RelTime(time.Now(), metadata.Expiry, "", "")
|
||||||
}
|
}
|
||||||
sizeHuman := humanize.Bytes(uint64(metadata.Size))
|
sizeHuman := humanize.Bytes(uint64(metadata.Size))
|
||||||
|
23
expiry.go
23
expiry.go
@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/andreimarcu/linx-server/expiry"
|
||||||
"github.com/dustin/go-humanize"
|
"github.com/dustin/go-humanize"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -21,14 +22,6 @@ type ExpirationTime struct {
|
|||||||
Human string
|
Human string
|
||||||
}
|
}
|
||||||
|
|
||||||
var neverExpire = time.Unix(0, 0)
|
|
||||||
|
|
||||||
// Determine if a file with expiry set to "ts" has expired yet
|
|
||||||
func isTsExpired(ts time.Time) bool {
|
|
||||||
now := time.Now()
|
|
||||||
return ts != neverExpire && now.After(ts)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine if the given filename is expired
|
// Determine if the given filename is expired
|
||||||
func isFileExpired(filename string) (bool, error) {
|
func isFileExpired(filename string) (bool, error) {
|
||||||
metadata, err := metadataRead(filename)
|
metadata, err := metadataRead(filename)
|
||||||
@ -36,7 +29,7 @@ func isFileExpired(filename string) (bool, error) {
|
|||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return isTsExpired(metadata.Expiry), nil
|
return expiry.IsTsExpired(metadata.Expiry), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return a list of expiration times and their humanized versions
|
// Return a list of expiration times and their humanized versions
|
||||||
@ -45,16 +38,16 @@ func listExpirationTimes() []ExpirationTime {
|
|||||||
actualExpiryInList := false
|
actualExpiryInList := false
|
||||||
var expiryList []ExpirationTime
|
var expiryList []ExpirationTime
|
||||||
|
|
||||||
for _, expiry := range defaultExpiryList {
|
for _, expiryEntry := range defaultExpiryList {
|
||||||
if Config.maxExpiry == 0 || expiry <= Config.maxExpiry {
|
if Config.maxExpiry == 0 || expiryEntry <= Config.maxExpiry {
|
||||||
if expiry == Config.maxExpiry {
|
if expiryEntry == Config.maxExpiry {
|
||||||
actualExpiryInList = true
|
actualExpiryInList = true
|
||||||
}
|
}
|
||||||
|
|
||||||
duration := time.Duration(expiry) * time.Second
|
duration := time.Duration(expiryEntry) * time.Second
|
||||||
expiryList = append(expiryList, ExpirationTime{
|
expiryList = append(expiryList, ExpirationTime{
|
||||||
expiry,
|
Seconds: expiryEntry,
|
||||||
humanize.RelTime(epoch, epoch.Add(duration), "", ""),
|
Human: humanize.RelTime(epoch, epoch.Add(duration), "", ""),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
13
expiry/expiry.go
Normal file
13
expiry/expiry.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package expiry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var NeverExpire = time.Unix(0, 0)
|
||||||
|
|
||||||
|
// Determine if a file with expiry set to "ts" has expired yet
|
||||||
|
func IsTsExpired(ts time.Time) bool {
|
||||||
|
now := time.Now()
|
||||||
|
return ts != NeverExpire && now.After(ts)
|
||||||
|
}
|
@ -5,6 +5,7 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/andreimarcu/linx-server/backends"
|
||||||
"github.com/zenazn/goji/web"
|
"github.com/zenazn/goji/web"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -15,7 +16,7 @@ func fileServeHandler(c web.C, w http.ResponseWriter, r *http.Request) {
|
|||||||
if err == NotFoundErr {
|
if err == NotFoundErr {
|
||||||
notFoundHandler(c, w, r)
|
notFoundHandler(c, w, r)
|
||||||
return
|
return
|
||||||
} else if err == BadMetadata {
|
} else if err == backends.BadMetadata {
|
||||||
oopsHandler(c, w, r, RespAUTO, "Corrupt metadata.")
|
oopsHandler(c, w, r, RespAUTO, "Corrupt metadata.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -72,7 +73,7 @@ func checkFile(filename string) error {
|
|||||||
|
|
||||||
if expired {
|
if expired {
|
||||||
fileBackend.Delete(filename)
|
fileBackend.Delete(filename)
|
||||||
metaBackend.Delete(filename)
|
metaStorageBackend.Delete(filename)
|
||||||
return NotFoundErr
|
return NotFoundErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
46
linx-cleanup/cleanup.go
Normal file
46
linx-cleanup/cleanup.go
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/andreimarcu/linx-server/backends/localfs"
|
||||||
|
"github.com/andreimarcu/linx-server/backends/metajson"
|
||||||
|
"github.com/andreimarcu/linx-server/expiry"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var filesDir string
|
||||||
|
var metaDir string
|
||||||
|
var noLogs bool
|
||||||
|
|
||||||
|
flag.StringVar(&filesDir, "filespath", "files/",
|
||||||
|
"path to files directory")
|
||||||
|
flag.StringVar(&metaDir, "metapath", "meta/",
|
||||||
|
"path to metadata directory")
|
||||||
|
flag.BoolVar(&noLogs, "nologs", false,
|
||||||
|
"don't log deleted files")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
metaStorageBackend := localfs.NewLocalfsBackend(metaDir)
|
||||||
|
metaBackend := metajson.NewMetaJSONBackend(metaStorageBackend)
|
||||||
|
fileBackend := localfs.NewLocalfsBackend(filesDir)
|
||||||
|
|
||||||
|
files, err := metaStorageBackend.List()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, filename := range files {
|
||||||
|
metadata, err := metaBackend.Get(filename)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Failed to find metadata for %s", filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
if expiry.IsTsExpired(metadata.Expiry) {
|
||||||
|
log.Printf("Delete %s", filename)
|
||||||
|
fileBackend.Delete(filename)
|
||||||
|
metaStorageBackend.Delete(filename)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
75
meta.go
75
meta.go
@ -3,46 +3,25 @@ package main
|
|||||||
import (
|
import (
|
||||||
"archive/tar"
|
"archive/tar"
|
||||||
"archive/zip"
|
"archive/zip"
|
||||||
"bytes"
|
|
||||||
"compress/bzip2"
|
"compress/bzip2"
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"sort"
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
|
"github.com/andreimarcu/linx-server/backends"
|
||||||
|
"github.com/andreimarcu/linx-server/expiry"
|
||||||
"github.com/dchest/uniuri"
|
"github.com/dchest/uniuri"
|
||||||
"gopkg.in/h2non/filetype.v1"
|
"gopkg.in/h2non/filetype.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MetadataJSON struct {
|
|
||||||
DeleteKey string `json:"delete_key"`
|
|
||||||
Sha256sum string `json:"sha256sum"`
|
|
||||||
Mimetype string `json:"mimetype"`
|
|
||||||
Size int64 `json:"size"`
|
|
||||||
Expiry int64 `json:"expiry"`
|
|
||||||
ArchiveFiles []string `json:"archive_files,omitempty"`
|
|
||||||
ShortURL string `json:"short_url"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Metadata struct {
|
|
||||||
DeleteKey string
|
|
||||||
Sha256sum string
|
|
||||||
Mimetype string
|
|
||||||
Size int64
|
|
||||||
Expiry time.Time
|
|
||||||
ArchiveFiles []string
|
|
||||||
ShortURL string
|
|
||||||
}
|
|
||||||
|
|
||||||
var NotFoundErr = errors.New("File not found.")
|
var NotFoundErr = errors.New("File not found.")
|
||||||
var BadMetadata = errors.New("Corrupted metadata.")
|
|
||||||
|
|
||||||
func generateMetadata(fName string, exp time.Time, delKey string) (m Metadata, err error) {
|
func generateMetadata(fName string, exp time.Time, delKey string) (m backends.Metadata, err error) {
|
||||||
file, err := fileBackend.Open(fName)
|
file, err := fileBackend.Open(fName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@ -145,59 +124,23 @@ func generateMetadata(fName string, exp time.Time, delKey string) (m Metadata, e
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func metadataWrite(filename string, metadata *Metadata) error {
|
func metadataWrite(filename string, metadata *backends.Metadata) error {
|
||||||
mjson := MetadataJSON{}
|
return metaBackend.Put(filename, metadata)
|
||||||
mjson.DeleteKey = metadata.DeleteKey
|
|
||||||
mjson.Mimetype = metadata.Mimetype
|
|
||||||
mjson.ArchiveFiles = metadata.ArchiveFiles
|
|
||||||
mjson.Sha256sum = metadata.Sha256sum
|
|
||||||
mjson.Expiry = metadata.Expiry.Unix()
|
|
||||||
mjson.Size = metadata.Size
|
|
||||||
mjson.ShortURL = metadata.ShortURL
|
|
||||||
|
|
||||||
byt, err := json.Marshal(mjson)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := metaBackend.Put(filename, bytes.NewBuffer(byt)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func metadataRead(filename string) (metadata Metadata, err error) {
|
func metadataRead(filename string) (metadata backends.Metadata, err error) {
|
||||||
b, err := metaBackend.Get(filename)
|
metadata, err = metaBackend.Get(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Metadata does not exist, generate one
|
// Metadata does not exist, generate one
|
||||||
newMData, err := generateMetadata(filename, neverExpire, "")
|
newMData, err := generateMetadata(filename, expiry.NeverExpire, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return metadata, err
|
return metadata, err
|
||||||
}
|
}
|
||||||
metadataWrite(filename, &newMData)
|
metadataWrite(filename, &newMData)
|
||||||
|
|
||||||
b, err = metaBackend.Get(filename)
|
metadata, err = metaBackend.Get(filename)
|
||||||
if err != nil {
|
|
||||||
return metadata, BadMetadata
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mjson := MetadataJSON{}
|
|
||||||
|
|
||||||
err = json.Unmarshal(b, &mjson)
|
|
||||||
if err != nil {
|
|
||||||
return metadata, BadMetadata
|
|
||||||
}
|
|
||||||
|
|
||||||
metadata.DeleteKey = mjson.DeleteKey
|
|
||||||
metadata.Mimetype = mjson.Mimetype
|
|
||||||
metadata.ArchiveFiles = mjson.ArchiveFiles
|
|
||||||
metadata.Sha256sum = mjson.Sha256sum
|
|
||||||
metadata.Expiry = time.Unix(mjson.Expiry, 0)
|
|
||||||
metadata.Size = mjson.Size
|
|
||||||
metadata.ShortURL = mjson.ShortURL
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ import (
|
|||||||
"github.com/GeertJohan/go.rice"
|
"github.com/GeertJohan/go.rice"
|
||||||
"github.com/andreimarcu/linx-server/backends"
|
"github.com/andreimarcu/linx-server/backends"
|
||||||
"github.com/andreimarcu/linx-server/backends/localfs"
|
"github.com/andreimarcu/linx-server/backends/localfs"
|
||||||
|
"github.com/andreimarcu/linx-server/backends/metajson"
|
||||||
"github.com/flosch/pongo2"
|
"github.com/flosch/pongo2"
|
||||||
"github.com/vharitonsky/iniflags"
|
"github.com/vharitonsky/iniflags"
|
||||||
"github.com/zenazn/goji/graceful"
|
"github.com/zenazn/goji/graceful"
|
||||||
@ -65,7 +66,8 @@ var staticBox *rice.Box
|
|||||||
var timeStarted time.Time
|
var timeStarted time.Time
|
||||||
var timeStartedStr string
|
var timeStartedStr string
|
||||||
var remoteAuthKeys []string
|
var remoteAuthKeys []string
|
||||||
var metaBackend backends.StorageBackend
|
var metaStorageBackend backends.MetaStorageBackend
|
||||||
|
var metaBackend backends.MetaBackend
|
||||||
var fileBackend backends.StorageBackend
|
var fileBackend backends.StorageBackend
|
||||||
|
|
||||||
func setup() *web.Mux {
|
func setup() *web.Mux {
|
||||||
@ -124,7 +126,8 @@ func setup() *web.Mux {
|
|||||||
Config.sitePath = "/"
|
Config.sitePath = "/"
|
||||||
}
|
}
|
||||||
|
|
||||||
metaBackend = localfs.NewLocalfsBackend(Config.metaDir)
|
metaStorageBackend = localfs.NewLocalfsBackend(Config.metaDir)
|
||||||
|
metaBackend = metajson.NewMetaJSONBackend(metaStorageBackend)
|
||||||
fileBackend = localfs.NewLocalfsBackend(Config.filesDir)
|
fileBackend = localfs.NewLocalfsBackend(Config.filesDir)
|
||||||
|
|
||||||
// Template setup
|
// Template setup
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/andreimarcu/linx-server/backends"
|
||||||
"github.com/zeebo/bencode"
|
"github.com/zeebo/bencode"
|
||||||
"github.com/zenazn/goji/web"
|
"github.com/zenazn/goji/web"
|
||||||
)
|
)
|
||||||
@ -74,7 +75,7 @@ func fileTorrentHandler(c web.C, w http.ResponseWriter, r *http.Request) {
|
|||||||
if err == NotFoundErr {
|
if err == NotFoundErr {
|
||||||
notFoundHandler(c, w, r)
|
notFoundHandler(c, w, r)
|
||||||
return
|
return
|
||||||
} else if err == BadMetadata {
|
} else if err == backends.BadMetadata {
|
||||||
oopsHandler(c, w, r, RespAUTO, "Corrupt metadata.")
|
oopsHandler(c, w, r, RespAUTO, "Corrupt metadata.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
20
upload.go
20
upload.go
@ -15,6 +15,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/andreimarcu/linx-server/backends"
|
||||||
|
"github.com/andreimarcu/linx-server/expiry"
|
||||||
"github.com/dchest/uniuri"
|
"github.com/dchest/uniuri"
|
||||||
"github.com/zenazn/goji/web"
|
"github.com/zenazn/goji/web"
|
||||||
"gopkg.in/h2non/filetype.v1"
|
"gopkg.in/h2non/filetype.v1"
|
||||||
@ -41,7 +43,7 @@ type UploadRequest struct {
|
|||||||
// Metadata associated with a file as it would actually be stored
|
// Metadata associated with a file as it would actually be stored
|
||||||
type Upload struct {
|
type Upload struct {
|
||||||
Filename string // Final filename on disk
|
Filename string // Final filename on disk
|
||||||
Metadata Metadata
|
Metadata backends.Metadata
|
||||||
}
|
}
|
||||||
|
|
||||||
func uploadPostHandler(c web.C, w http.ResponseWriter, r *http.Request) {
|
func uploadPostHandler(c web.C, w http.ResponseWriter, r *http.Request) {
|
||||||
@ -258,11 +260,11 @@ func processUpload(upReq UploadRequest) (upload Upload, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the rest of the metadata needed for storage
|
// Get the rest of the metadata needed for storage
|
||||||
var expiry time.Time
|
var fileExpiry time.Time
|
||||||
if upReq.expiry == 0 {
|
if upReq.expiry == 0 {
|
||||||
expiry = neverExpire
|
fileExpiry = expiry.NeverExpire
|
||||||
} else {
|
} else {
|
||||||
expiry = time.Now().Add(upReq.expiry)
|
fileExpiry = time.Now().Add(upReq.expiry)
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes, err := fileBackend.Put(upload.Filename, io.MultiReader(bytes.NewReader(header), upReq.src))
|
bytes, err := fileBackend.Put(upload.Filename, io.MultiReader(bytes.NewReader(header), upReq.src))
|
||||||
@ -273,7 +275,7 @@ func processUpload(upReq UploadRequest) (upload Upload, err error) {
|
|||||||
return upload, errors.New("File too large")
|
return upload, errors.New("File too large")
|
||||||
}
|
}
|
||||||
|
|
||||||
upload.Metadata, err = generateMetadata(upload.Filename, expiry, upReq.deletionKey)
|
upload.Metadata, err = generateMetadata(upload.Filename, fileExpiry, upReq.deletionKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fileBackend.Delete(upload.Filename)
|
fileBackend.Delete(upload.Filename)
|
||||||
return
|
return
|
||||||
@ -342,14 +344,14 @@ func parseExpiry(expStr string) time.Duration {
|
|||||||
if expStr == "" {
|
if expStr == "" {
|
||||||
return time.Duration(Config.maxExpiry) * time.Second
|
return time.Duration(Config.maxExpiry) * time.Second
|
||||||
} else {
|
} else {
|
||||||
expiry, err := strconv.ParseUint(expStr, 10, 64)
|
fileExpiry, err := strconv.ParseUint(expStr, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return time.Duration(Config.maxExpiry) * time.Second
|
return time.Duration(Config.maxExpiry) * time.Second
|
||||||
} else {
|
} else {
|
||||||
if Config.maxExpiry > 0 && (expiry > Config.maxExpiry || expiry == 0) {
|
if Config.maxExpiry > 0 && (fileExpiry > Config.maxExpiry || fileExpiry == 0) {
|
||||||
expiry = Config.maxExpiry
|
fileExpiry = Config.maxExpiry
|
||||||
}
|
}
|
||||||
return time.Duration(expiry) * time.Second
|
return time.Duration(fileExpiry) * time.Second
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user