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() {
|
func main() {
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
database, err := db.OpenDB(*databasePath)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
defer database.Close()
|
|
||||||
filestore, err := db.OpenFileStore(*fileStorePath)
|
filestore, err := db.OpenFileStore(*fileStorePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
|
database, err := db.OpenDB(*databasePath, filestore)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
defer database.Close()
|
||||||
|
|
||||||
go rushlink.StartMetricsServer(*metricsListen, database, filestore)
|
go rushlink.StartMetricsServer(*metricsListen, database, filestore)
|
||||||
rushlink.StartMainServer(*httpListen, database, filestore)
|
rushlink.StartMainServer(*httpListen, database, filestore)
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
package db
|
package db
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"log"
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"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
|
// If we alter the database format, we bump this number and write a new
|
||||||
// database migration in migrate().
|
// database migration in migrate().
|
||||||
const CurrentMigrateVersion = 2
|
const CurrentMigrateVersion = 3
|
||||||
|
|
||||||
// BucketConf holds the name for the "configuration" bucket.
|
// BucketConf holds the name for the "configuration" bucket.
|
||||||
//
|
//
|
||||||
@ -42,7 +46,7 @@ const BucketFileUpload = "fileUpload"
|
|||||||
const KeyMigrateVersion = "migrate_version"
|
const KeyMigrateVersion = "migrate_version"
|
||||||
|
|
||||||
// OpenDB opens a database file located at path.
|
// OpenDB opens a database file located at path.
|
||||||
func OpenDB(path string) (*Database, error) {
|
func OpenDB(path string, fs *FileStore) (*Database, error) {
|
||||||
if path == "" {
|
if path == "" {
|
||||||
return nil, errors.New("database not set")
|
return nil, errors.New("database not set")
|
||||||
}
|
}
|
||||||
@ -51,7 +55,7 @@ func OpenDB(path string) (*Database, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to open database at '%v'", path)
|
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 nil, err
|
||||||
}
|
}
|
||||||
return &Database{db}, nil
|
return &Database{db}, nil
|
||||||
@ -66,7 +70,12 @@ func (db *Database) Close() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Initialize and migrate the database to the current version
|
// 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)
|
dbVersion, err := dbVersion(tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,6 +153,10 @@ func GetFileUpload(tx *bolt.Tx, id uuid.UUID) (*FileUpload, error) {
|
|||||||
if storedBytes == nil {
|
if storedBytes == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
return decodeFileUpload(storedBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeFileUpload(storedBytes []byte) (*FileUpload, error) {
|
||||||
fu := &FileUpload{}
|
fu := &FileUpload{}
|
||||||
err := gobmarsh.Unmarshal(storedBytes, fu)
|
err := gobmarsh.Unmarshal(storedBytes, fu)
|
||||||
return fu, err
|
return fu, err
|
||||||
|
Loading…
Reference in New Issue
Block a user