forked from electricdusk/rushlink
db: Migrate FileUpload.ContentTypes to auto-detect
This commit is contained in:
parent
eec5e4def4
commit
62e82d831e
@ -18,15 +18,15 @@ var (
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
database, err := db.OpenDB(*databasePath)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
defer database.Close()
|
||||
filestore, err := db.OpenFileStore(*fileStorePath)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
database, err := db.OpenDB(*databasePath, filestore)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
defer database.Close()
|
||||
|
||||
go rushlink.StartMetricsServer(*metricsListen, database, filestore)
|
||||
rushlink.StartMainServer(*httpListen, database, filestore)
|
||||
|
@ -1,8 +1,12 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
@ -24,7 +28,7 @@ type Database struct {
|
||||
//
|
||||
// If we alter the database format, we bump this number and write a new
|
||||
// database migration in migrate().
|
||||
const CurrentMigrateVersion = 2
|
||||
const CurrentMigrateVersion = 3
|
||||
|
||||
// BucketConf holds the name for the "configuration" bucket.
|
||||
//
|
||||
@ -42,7 +46,7 @@ const BucketFileUpload = "fileUpload"
|
||||
const KeyMigrateVersion = "migrate_version"
|
||||
|
||||
// OpenDB opens a database file located at path.
|
||||
func OpenDB(path string) (*Database, error) {
|
||||
func OpenDB(path string, fs *FileStore) (*Database, error) {
|
||||
if path == "" {
|
||||
return nil, errors.New("database not set")
|
||||
}
|
||||
@ -51,7 +55,7 @@ func OpenDB(path string) (*Database, error) {
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to open database at '%v'", path)
|
||||
}
|
||||
if err := db.Update(migrate); err != nil {
|
||||
if err := db.Update(func(tx *bolt.Tx) error { return migrate(tx, fs) }); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Database{db}, nil
|
||||
@ -66,7 +70,12 @@ func (db *Database) Close() error {
|
||||
}
|
||||
|
||||
// Initialize and migrate the database to the current version
|
||||
func migrate(tx *bolt.Tx) error {
|
||||
func migrate(tx *bolt.Tx, fs *FileStore) error {
|
||||
// Guidelines for error handling:
|
||||
// - Errors based on malformed *structure* should be fatal!
|
||||
// - Errors based on malformed *data* should print a warning
|
||||
// (and if possible try to fix the error).
|
||||
|
||||
dbVersion, err := dbVersion(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -104,6 +113,54 @@ func migrate(tx *bolt.Tx) error {
|
||||
}
|
||||
}
|
||||
|
||||
if dbVersion < 3 {
|
||||
log.Println("migrating database to version 3")
|
||||
// In this version, we changed te way how Content-Types are being
|
||||
// stored. Previously, we allowed clients to provide their own
|
||||
// Content-Types for files, using the Content-Disposition header in
|
||||
// multipart forms. The new way detects these types using
|
||||
// http.DetectContentType.
|
||||
//
|
||||
// Scan through all the FileUploads and update their ContentTypes.
|
||||
bucket := tx.Bucket([]byte(BucketFileUpload))
|
||||
cursor := bucket.Cursor()
|
||||
var id, storedBytes []byte
|
||||
id, storedBytes = cursor.First()
|
||||
for id != nil {
|
||||
fu, err := decodeFileUpload(storedBytes)
|
||||
if err != nil {
|
||||
log.Print("error: ", errors.Wrapf(err, "corrupted FileUpload in database at '%v'", id))
|
||||
id, storedBytes = cursor.Next()
|
||||
continue
|
||||
}
|
||||
if fu.State != FileUploadStatePresent {
|
||||
id, storedBytes = cursor.Next()
|
||||
continue
|
||||
}
|
||||
filePath := fu.Path(fs)
|
||||
file, err := os.Open(fu.Path(fs))
|
||||
if err != nil {
|
||||
log.Print("error: ", errors.Wrapf(err, "could not open file at '%v'", filePath))
|
||||
id, storedBytes = cursor.Next()
|
||||
continue
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
buf.Grow(512)
|
||||
io.CopyN(&buf, file, 512)
|
||||
contentType := http.DetectContentType(buf.Bytes())
|
||||
if contentType != fu.ContentType {
|
||||
fu.ContentType = contentType
|
||||
fu.Save(tx)
|
||||
cursor.Seek(id)
|
||||
}
|
||||
id, storedBytes = cursor.Next()
|
||||
}
|
||||
// Update the version number
|
||||
if err := setDBVersion(tx, 3); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -153,6 +153,10 @@ func GetFileUpload(tx *bolt.Tx, id uuid.UUID) (*FileUpload, error) {
|
||||
if storedBytes == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return decodeFileUpload(storedBytes)
|
||||
}
|
||||
|
||||
func decodeFileUpload(storedBytes []byte) (*FileUpload, error) {
|
||||
fu := &FileUpload{}
|
||||
err := gobmarsh.Unmarshal(storedBytes, fu)
|
||||
return fu, err
|
||||
|
Loading…
Reference in New Issue
Block a user