working commit
This commit is contained in:
@@ -3,6 +3,7 @@ package config
|
|||||||
type Config struct {
|
type Config struct {
|
||||||
Service Service `json:"service" yaml:"service"`
|
Service Service `json:"service" yaml:"service"`
|
||||||
Database Database `json:"database" yaml:"database"`
|
Database Database `json:"database" yaml:"database"`
|
||||||
|
Storage Storage `json:"storage" yaml:"storage"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Service struct {
|
type Service struct {
|
||||||
@@ -14,6 +15,10 @@ type Database struct {
|
|||||||
Basepath string `json:"basepath" yaml:"basepath"`
|
Basepath string `json:"basepath" yaml:"basepath"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Storage struct {
|
||||||
|
Basepath string `json:"basepath" yaml:"basepath"`
|
||||||
|
}
|
||||||
|
|
||||||
func NewConfig() (*Config, error) {
|
func NewConfig() (*Config, error) {
|
||||||
var err error
|
var err error
|
||||||
return &Config{
|
return &Config{
|
||||||
@@ -24,5 +29,8 @@ func NewConfig() (*Config, error) {
|
|||||||
Database: Database{
|
Database: Database{
|
||||||
Basepath: datadir,
|
Basepath: datadir,
|
||||||
},
|
},
|
||||||
|
Storage: Storage{
|
||||||
|
Basepath: datadir,
|
||||||
|
},
|
||||||
}, err
|
}, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ type File struct {
|
|||||||
ID string `db:"id" json:"id,omitempty" yaml:"id,omitempty"`
|
ID string `db:"id" json:"id,omitempty" yaml:"id,omitempty"`
|
||||||
Collection string `db:"collection" json:"collection,omitempty" yaml:"collection,omitempty"`
|
Collection string `db:"collection" json:"collection,omitempty" yaml:"collection,omitempty"`
|
||||||
Name string `db:"name" json:"name,omitempty" yaml:"name,omitempty"`
|
Name string `db:"name" json:"name,omitempty" yaml:"name,omitempty"`
|
||||||
|
Type string `db:"type" json:"type,omitempty" yaml:"type,omitempty"`
|
||||||
Checksum string `db:"checksum" json:"checksum,omitempty" yaml:"checksum,omitempty"`
|
Checksum string `db:"checksum" json:"checksum,omitempty" yaml:"checksum,omitempty"`
|
||||||
Size int64 `db:"size" json:"size,omitempty" yaml:"size,omitempty"`
|
Size int64 `db:"size" json:"size,omitempty" yaml:"size,omitempty"`
|
||||||
CreatedAt string `db:"created_at" json:"createdAt,omitempty" yaml:"createdAt,omitempty"`
|
CreatedAt string `db:"created_at" json:"createdAt,omitempty" yaml:"createdAt,omitempty"`
|
||||||
|
|||||||
+17
-10
@@ -6,7 +6,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (hand *Handler) FileExists(rctx *router.Context) {
|
func (hand *Handler) FileExists(rctx *router.Context) {
|
||||||
hand.logg.Debugf("handle FileExists")
|
hand.logg.Debugf("Handle FileExists")
|
||||||
|
|
||||||
filepath := rctx.PathMap["filepath"]
|
filepath := rctx.PathMap["filepath"]
|
||||||
params := &operator.FileExistsParams{
|
params := &operator.FileExistsParams{
|
||||||
@@ -19,21 +19,28 @@ func (hand *Handler) FileExists(rctx *router.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (hand *Handler) PutFile(rctx *router.Context) {
|
func (hand *Handler) PutFile(rctx *router.Context) {
|
||||||
hand.logg.Debugf("handle PutFile")
|
hand.logg.Debugf("Handle PutFile")
|
||||||
|
|
||||||
|
contentLength := rctx.GetHeader("Content-Length")
|
||||||
|
contentType := rctx.GetHeader("Content-Type")
|
||||||
filepath := rctx.PathMap["filepath"]
|
filepath := rctx.PathMap["filepath"]
|
||||||
params := &operator.PutFileParams{
|
|
||||||
Filepath: filepath,
|
|
||||||
Source: rctx.Request.Body,
|
|
||||||
}
|
|
||||||
hand.logg.Debugf("filepath: %s", filepath)
|
|
||||||
|
|
||||||
code, _, _ := hand.oper.PutFile(params)
|
params := &operator.PutFileParams{
|
||||||
|
Filepath: filepath,
|
||||||
|
ContentLength: contentLength,
|
||||||
|
ContentType: contentType,
|
||||||
|
Source: rctx.Request.Body,
|
||||||
|
}
|
||||||
|
code, res, err := hand.oper.PutFile(params)
|
||||||
|
if err != nil {
|
||||||
|
hand.logg.Errorf("Error: %v", err)
|
||||||
|
}
|
||||||
rctx.SetStatus(code)
|
rctx.SetStatus(code)
|
||||||
|
hand.SendResult(rctx, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hand *Handler) GetFile(rctx *router.Context) {
|
func (hand *Handler) GetFile(rctx *router.Context) {
|
||||||
hand.logg.Debugf("handle GetFile")
|
hand.logg.Debugf("Handle GetFile")
|
||||||
|
|
||||||
filepath := rctx.PathMap["filepath"]
|
filepath := rctx.PathMap["filepath"]
|
||||||
params := &operator.GetFileParams{
|
params := &operator.GetFileParams{
|
||||||
@@ -48,7 +55,7 @@ func (hand *Handler) GetFile(rctx *router.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (hand *Handler) DeleteFile(rctx *router.Context) {
|
func (hand *Handler) DeleteFile(rctx *router.Context) {
|
||||||
hand.logg.Debugf("handle DeleteFile")
|
hand.logg.Debugf("Handle DeleteFile")
|
||||||
|
|
||||||
filepath := rctx.PathMap["filepath"]
|
filepath := rctx.PathMap["filepath"]
|
||||||
params := &operator.DeleteFileParams{
|
params := &operator.DeleteFileParams{
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (hand *Handler) SendHello(rctx *router.Context) {
|
func (hand *Handler) SendHello(rctx *router.Context) {
|
||||||
hand.logg.Debugf("handle sendHello")
|
hand.logg.Debugf("Handle SendHello")
|
||||||
|
|
||||||
params := &operator.SendHelloParams{}
|
params := &operator.SendHelloParams{}
|
||||||
res, _ := hand.oper.SendHello(params)
|
res, _ := hand.oper.SendHello(params)
|
||||||
|
|||||||
+7
-7
@@ -6,9 +6,9 @@ import (
|
|||||||
|
|
||||||
func (db *Database) InsertFile(file *descr.File) error {
|
func (db *Database) InsertFile(file *descr.File) error {
|
||||||
var err error
|
var err error
|
||||||
request := `INSERT INTO file(id, collection, name, checksum, size, created_at, updated_at, created_by, updated_by)
|
request := `INSERT INTO file(id, collection, name, type, checksum, size, created_at, updated_at, created_by, updated_by)
|
||||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)`
|
||||||
_, err = db.db.Exec(request, file.ID, file.Collection, file.Name, file.Checksum, file.Size,
|
_, err = db.db.Exec(request, file.ID, file.Collection, file.Name, file.Type, file.Checksum, file.Size,
|
||||||
file.CreatedAt, file.UpdatedAt, file.CreatedBy, file.UpdatedBy)
|
file.CreatedAt, file.UpdatedAt, file.CreatedBy, file.UpdatedBy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -18,10 +18,10 @@ func (db *Database) InsertFile(file *descr.File) error {
|
|||||||
|
|
||||||
func (db *Database) UpdateFileByID(fileID string, file *descr.File) error {
|
func (db *Database) UpdateFileByID(fileID string, file *descr.File) error {
|
||||||
var err error
|
var err error
|
||||||
request := `UPDATE file SET id = $1, collection = $2, name = $3, checksum = $4,
|
request := `UPDATE file SET id = $1, collection = $2, name = $3, type = $4, checksum = $5,
|
||||||
size = $5, updated_at = $6, created_by = $7, updated_by = $8
|
size = $6, updated_at = $7, created_by = $8, updated_by = $9
|
||||||
WHERE id = $9`
|
WHERE id = $10`
|
||||||
_, err = db.db.Exec(request, file.ID, file.Collection, file.Name, file.Checksum,
|
_, err = db.db.Exec(request, file.ID, file.Collection, file.Name, file.Type, file.Checksum,
|
||||||
file.Size, file.UpdatedAt, file.CreatedBy, file.UpdatedBy, fileID)
|
file.Size, file.UpdatedAt, file.CreatedBy, file.UpdatedBy, fileID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ func TestFile(t *testing.T) {
|
|||||||
ID: id,
|
ID: id,
|
||||||
Collection: "foo",
|
Collection: "foo",
|
||||||
Name: "bare",
|
Name: "bare",
|
||||||
|
Type: "application/octet-stream",
|
||||||
CreatedAt: timenow,
|
CreatedAt: timenow,
|
||||||
UpdatedAt: timenow,
|
UpdatedAt: timenow,
|
||||||
CreatedBy: creator,
|
CreatedBy: creator,
|
||||||
@@ -43,4 +44,7 @@ func TestFile(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, len(files), 1)
|
require.Equal(t, len(files), 1)
|
||||||
require.Equal(t, files[0].ID, id)
|
require.Equal(t, files[0].ID, id)
|
||||||
|
require.Equal(t, files[0].Type, "application/octet-stream")
|
||||||
|
require.Equal(t, files[0].Name, "bare")
|
||||||
|
require.Equal(t, files[0].Collection, "foo")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ const schema = `
|
|||||||
id VARCHAR(255) NOT NULL,
|
id VARCHAR(255) NOT NULL,
|
||||||
collection VARCHAR(255) NOT NULL,
|
collection VARCHAR(255) NOT NULL,
|
||||||
name VARCHAR(255) NOT NULL,
|
name VARCHAR(255) NOT NULL,
|
||||||
|
type VARCHAR(255) NOT NULL,
|
||||||
checksum VARCHAR(255) NOT NULL,
|
checksum VARCHAR(255) NOT NULL,
|
||||||
size INTEGER,
|
size INTEGER,
|
||||||
created_at VARCHAR(255) NOT NULL,
|
created_at VARCHAR(255) NOT NULL,
|
||||||
|
|||||||
+87
-8
@@ -3,7 +3,12 @@ package operator
|
|||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
//"path"
|
"path"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"mstore/app/descr"
|
||||||
|
"mstore/pkg/auxtool"
|
||||||
|
"mstore/pkg/auxuuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
// File exists
|
// File exists
|
||||||
@@ -12,16 +17,23 @@ type FileExistsParams struct {
|
|||||||
Source string
|
Source string
|
||||||
Dest string
|
Dest string
|
||||||
}
|
}
|
||||||
type FileExistsResult struct{}
|
type FileExistsResult struct {
|
||||||
|
Descr *descr.File
|
||||||
|
}
|
||||||
|
|
||||||
func (oper *Operator) FileExists(param *FileExistsParams) (int, *FileExistsResult, error) {
|
func (oper *Operator) FileExists(param *FileExistsParams) (int, *FileExistsResult, error) {
|
||||||
var err error
|
var err error
|
||||||
|
code := http.StatusNotFound
|
||||||
//filename := path.Base(param.Filepath)
|
|
||||||
//dirname := path.Dir(filepath)
|
|
||||||
|
|
||||||
res := &FileExistsResult{}
|
res := &FileExistsResult{}
|
||||||
code := http.StatusOK
|
|
||||||
|
filename := path.Base(param.Filepath)
|
||||||
|
collection := path.Dir(param.Filepath)
|
||||||
|
|
||||||
|
exist, file, err := oper.mdb.GetFileByCollection(collection, filename)
|
||||||
|
if exist {
|
||||||
|
code = http.StatusOK
|
||||||
|
res.Descr = file
|
||||||
|
}
|
||||||
return code, res, err
|
return code, res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,11 +44,78 @@ type PutFileParams struct {
|
|||||||
Filepath string
|
Filepath string
|
||||||
Source io.ReadCloser
|
Source io.ReadCloser
|
||||||
}
|
}
|
||||||
type PutFileResult struct{}
|
type PutFileResult struct {
|
||||||
|
Descr *descr.File
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultContentType = "application/octet-stream"
|
||||||
|
|
||||||
func (oper *Operator) PutFile(param *PutFileParams) (int, *PutFileResult, error) {
|
func (oper *Operator) PutFile(param *PutFileParams) (int, *PutFileResult, error) {
|
||||||
var err error
|
var err error
|
||||||
res := &PutFileResult{}
|
res := &PutFileResult{}
|
||||||
|
|
||||||
|
size, err := strconv.ParseInt(param.ContentLength, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
code := http.StatusLengthRequired
|
||||||
|
return code, res, err
|
||||||
|
}
|
||||||
|
contentType := param.ContentType
|
||||||
|
if contentType == "" {
|
||||||
|
contentType = defaultContentType
|
||||||
|
}
|
||||||
|
|
||||||
|
filename := path.Base(param.Filepath)
|
||||||
|
collection := path.Dir(param.Filepath)
|
||||||
|
oper.logg.Debugf("Put file %s %s", collection, filename)
|
||||||
|
|
||||||
|
tmpname, size, checksum, err := oper.store.WriteTempFile(param.Source)
|
||||||
|
if err != nil {
|
||||||
|
code := http.StatusInternalServerError
|
||||||
|
return code, res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
exists, fileDescr, err := oper.mdb.GetFileByCollection(collection, filename)
|
||||||
|
if err != nil {
|
||||||
|
code := http.StatusInternalServerError
|
||||||
|
return code, res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
now := auxtool.TimeNow()
|
||||||
|
if exists {
|
||||||
|
fileDescr.Size = size
|
||||||
|
fileDescr.Checksum = checksum
|
||||||
|
fileDescr.UpdatedAt = now
|
||||||
|
fileDescr.Type = contentType
|
||||||
|
err = oper.mdb.UpdateFileByID(fileDescr.ID, fileDescr)
|
||||||
|
if err != nil {
|
||||||
|
code := http.StatusInternalServerError
|
||||||
|
return code, res, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fileDescr = &descr.File{
|
||||||
|
ID: auxuuid.NewUUID(),
|
||||||
|
Name: filename,
|
||||||
|
Collection: collection,
|
||||||
|
Size: size,
|
||||||
|
Type: contentType,
|
||||||
|
Checksum: checksum,
|
||||||
|
CreatedAt: now,
|
||||||
|
UpdatedAt: now,
|
||||||
|
}
|
||||||
|
err = oper.mdb.InsertFile(fileDescr)
|
||||||
|
if err != nil {
|
||||||
|
code := http.StatusInternalServerError
|
||||||
|
return code, res, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = oper.store.LinkFile(tmpname, collection, filename)
|
||||||
|
if err != nil {
|
||||||
|
code := http.StatusInternalServerError
|
||||||
|
return code, res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res.Descr = fileDescr
|
||||||
code := http.StatusOK
|
code := http.StatusOK
|
||||||
return code, res, err
|
return code, res, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,28 @@
|
|||||||
package operator
|
package operator
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"mstore/app/logger"
|
||||||
"mstore/app/maindb"
|
"mstore/app/maindb"
|
||||||
|
"mstore/app/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
type OperatorParams struct {
|
type OperatorParams struct {
|
||||||
MainDB *maindb.Database
|
MainDB *maindb.Database
|
||||||
|
Store *storage.Storage
|
||||||
}
|
}
|
||||||
|
|
||||||
type Operator struct {
|
type Operator struct {
|
||||||
maindb *maindb.Database
|
mdb *maindb.Database
|
||||||
|
store *storage.Storage
|
||||||
|
logg *logger.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewOperator(params *OperatorParams) (*Operator, error) {
|
func NewOperator(params *OperatorParams) (*Operator, error) {
|
||||||
var err error
|
var err error
|
||||||
oper := &Operator{
|
oper := &Operator{
|
||||||
maindb: params.MainDB,
|
mdb: params.MainDB,
|
||||||
|
store: params.Store,
|
||||||
}
|
}
|
||||||
|
oper.logg = logger.NewLogger("operator")
|
||||||
return oper, err
|
return oper, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,5 +43,5 @@ func (rctx *Context) SendText(payload string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (rctx *Context) GetHeader(key string) string {
|
func (rctx *Context) GetHeader(key string) string {
|
||||||
return rctx.Request.URL.Query().Get(key)
|
return rctx.Request.Header.Get(key)
|
||||||
}
|
}
|
||||||
|
|||||||
+33
-11
@@ -18,15 +18,17 @@ import (
|
|||||||
"mstore/app/maindb"
|
"mstore/app/maindb"
|
||||||
"mstore/app/operator"
|
"mstore/app/operator"
|
||||||
"mstore/app/service"
|
"mstore/app/service"
|
||||||
|
"mstore/app/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
conf *config.Config
|
conf *config.Config
|
||||||
oper *operator.Operator
|
oper *operator.Operator
|
||||||
svc *service.Service
|
svc *service.Service
|
||||||
maindb *maindb.Database
|
mdb *maindb.Database
|
||||||
hand *handler.Handler
|
hand *handler.Handler
|
||||||
logg *logger.Logger
|
logg *logger.Logger
|
||||||
|
stor *storage.Storage
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServer() (*Server, error) {
|
func NewServer() (*Server, error) {
|
||||||
@@ -56,31 +58,49 @@ func (srv *Server) Build() error {
|
|||||||
srv.logg.Infof("Server build")
|
srv.logg.Infof("Server build")
|
||||||
|
|
||||||
// Database create
|
// Database create
|
||||||
|
srv.logg.Infof("Create database directory")
|
||||||
dbdir := srv.conf.Database.Basepath
|
dbdir := srv.conf.Database.Basepath
|
||||||
err = os.MkdirAll(srv.conf.Database.Basepath, 0750)
|
err = os.MkdirAll(dbdir, 0750)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
maindb := maindb.NewDatabase(dbdir)
|
mdb := maindb.NewDatabase(dbdir)
|
||||||
err = maindb.OpenDatabase()
|
srv.logg.Infof("Open database")
|
||||||
|
err = mdb.OpenDatabase()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = maindb.InitDatabase()
|
srv.logg.Infof("Initialize database")
|
||||||
|
err = mdb.InitDatabase()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
srv.mdb = mdb
|
||||||
|
|
||||||
|
// Storage create
|
||||||
|
srv.logg.Infof("Create storage directory")
|
||||||
|
datadir := srv.conf.Database.Basepath
|
||||||
|
err = os.MkdirAll(datadir, 0750)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
srv.logg.Infof("Create storage")
|
||||||
|
store := storage.NewStorage(datadir)
|
||||||
|
srv.stor = store
|
||||||
|
|
||||||
// Operator create
|
// Operator create
|
||||||
|
srv.logg.Infof("Create operator")
|
||||||
operatorParams := &operator.OperatorParams{
|
operatorParams := &operator.OperatorParams{
|
||||||
MainDB: srv.maindb,
|
MainDB: srv.mdb,
|
||||||
|
Store: srv.stor,
|
||||||
}
|
}
|
||||||
srv.oper, err = operator.NewOperator(operatorParams)
|
srv.oper, err = operator.NewOperator(operatorParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Handler create
|
// Handler create
|
||||||
|
srv.logg.Infof("Create handler")
|
||||||
handlerParams := &handler.HandlerParams{
|
handlerParams := &handler.HandlerParams{
|
||||||
Operator: srv.oper,
|
Operator: srv.oper,
|
||||||
}
|
}
|
||||||
@@ -92,6 +112,7 @@ func (srv *Server) Build() error {
|
|||||||
serviceParams := &service.ServiceParams{
|
serviceParams := &service.ServiceParams{
|
||||||
Handler: srv.hand,
|
Handler: srv.hand,
|
||||||
}
|
}
|
||||||
|
srv.logg.Infof("Create service")
|
||||||
srv.svc, err = service.NewService(serviceParams)
|
srv.svc, err = service.NewService(serviceParams)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -118,6 +139,7 @@ func (srv *Server) Run() error {
|
|||||||
svcDone := make(chan error, 1)
|
svcDone := make(chan error, 1)
|
||||||
|
|
||||||
// Service run
|
// Service run
|
||||||
|
srv.logg.Infof("Start service")
|
||||||
startService := func(svc *service.Service, done chan error) {
|
startService := func(svc *service.Service, done chan error) {
|
||||||
err = svc.Run()
|
err = svc.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -1 +1,76 @@
|
|||||||
package storage
|
package storage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"mstore/app/logger"
|
||||||
|
"mstore/pkg/auxuuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Storage struct {
|
||||||
|
basepath string
|
||||||
|
logg *logger.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStorage(basepath string) *Storage {
|
||||||
|
res := &Storage{
|
||||||
|
basepath: basepath,
|
||||||
|
}
|
||||||
|
res.logg = logger.NewLogger("storage")
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func (store *Storage) LinkFile(tmpname, collection, filename string) error {
|
||||||
|
var err error
|
||||||
|
dirname := filepath.Join(store.basepath, collection)
|
||||||
|
err = os.MkdirAll(dirname, 0750)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
filename = filepath.Join(store.basepath, collection, filename)
|
||||||
|
os.Remove(filename)
|
||||||
|
|
||||||
|
err = os.Link(tmpname, filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = os.Remove(tmpname)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (store *Storage) WriteTempFile(source io.Reader) (string, int64, string, error) {
|
||||||
|
var err error
|
||||||
|
var size int64
|
||||||
|
var digest string
|
||||||
|
|
||||||
|
tmpname := auxuuid.NewUUID()
|
||||||
|
tmpname = fmt.Sprintf("file-%s.tmp", tmpname)
|
||||||
|
tmppath := filepath.Join(store.basepath, tmpname)
|
||||||
|
|
||||||
|
file, err := os.OpenFile(tmppath, os.O_WRONLY|os.O_CREATE, 0640)
|
||||||
|
if err != nil {
|
||||||
|
return tmppath, size, digest, err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
hasher := sha256.New()
|
||||||
|
writer := io.MultiWriter(file, hasher)
|
||||||
|
|
||||||
|
size, err = io.Copy(writer, source)
|
||||||
|
if err != nil {
|
||||||
|
return tmppath, size, digest, err
|
||||||
|
}
|
||||||
|
digest = hex.EncodeToString(hasher.Sum(nil))
|
||||||
|
digest = fmt.Sprintf("sha256:%s", digest)
|
||||||
|
|
||||||
|
return tmppath, size, digest, err
|
||||||
|
}
|
||||||
|
|||||||
+49
-5
@@ -1,20 +1,21 @@
|
|||||||
package test
|
package test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"mstore/app/router"
|
"mstore/app/router"
|
||||||
"mstore/app/server"
|
"mstore/app/server"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func MakeServer(t *testing.T) *server.Server {
|
func MakeServer(t *testing.T) *server.Server {
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
srv, err := server.NewServer()
|
srv, err := server.NewServer()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -28,7 +29,10 @@ func MakeServer(t *testing.T) *server.Server {
|
|||||||
return srv
|
return srv
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFileExists(t *testing.T) {
|
func TestFileLife(t *testing.T) {
|
||||||
|
}
|
||||||
|
|
||||||
|
func xxxTestFileExists(t *testing.T) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
srv := MakeServer(t)
|
srv := MakeServer(t)
|
||||||
@@ -46,6 +50,46 @@ func TestFileExists(t *testing.T) {
|
|||||||
request, err := http.NewRequest("HEAD", reqPath, nil)
|
request, err := http.NewRequest("HEAD", reqPath, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
rout.ServeHTTP(recorder, request)
|
||||||
|
require.Equal(t, http.StatusNotFound, recorder.Code)
|
||||||
|
|
||||||
|
fmt.Printf("Response code: %d\n", recorder.Code)
|
||||||
|
|
||||||
|
bodyReader := recorder.Body
|
||||||
|
bodyBytes, err := io.ReadAll(bodyReader)
|
||||||
|
|
||||||
|
fmt.Printf("Response body: %s\n", string(bodyBytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPutFile(t *testing.T) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
srv := MakeServer(t)
|
||||||
|
require.NotNil(t, srv)
|
||||||
|
|
||||||
|
reqPath := `/v3/api/file/foo/bare`
|
||||||
|
routePath := `/v3/api/file/{filepath}`
|
||||||
|
|
||||||
|
rout := router.NewRouter()
|
||||||
|
hand := srv.Handler()
|
||||||
|
require.NotNil(t, hand)
|
||||||
|
|
||||||
|
rout.Put(routePath, hand.PutFile)
|
||||||
|
|
||||||
|
datasize := 16
|
||||||
|
filedata := make([]byte, datasize)
|
||||||
|
_, err = rand.Read(filedata)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
source := bytes.NewReader(filedata)
|
||||||
|
|
||||||
|
request, err := http.NewRequest("PUT", reqPath, source)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
request.Header.Set("Content-Length", fmt.Sprintf("%d", datasize))
|
||||||
|
request.Header.Set("Content-Type", "application/octet-stream")
|
||||||
|
|
||||||
recorder := httptest.NewRecorder()
|
recorder := httptest.NewRecorder()
|
||||||
rout.ServeHTTP(recorder, request)
|
rout.ServeHTTP(recorder, request)
|
||||||
require.Equal(t, http.StatusOK, recorder.Code)
|
require.Equal(t, http.StatusOK, recorder.Code)
|
||||||
@@ -58,7 +102,7 @@ func TestFileExists(t *testing.T) {
|
|||||||
fmt.Printf("Response body: %s\n", string(bodyBytes))
|
fmt.Printf("Response body: %s\n", string(bodyBytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestServiceHello(t *testing.T) {
|
func xxxTestServiceHello(t *testing.T) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
srv := MakeServer(t)
|
srv := MakeServer(t)
|
||||||
|
|||||||
Reference in New Issue
Block a user