Simply backend interface
Rename CreateBlob() method to Create(), remove old Create* methods
This commit is contained in:
parent
35636a9d92
commit
72c951a6ec
6 changed files with 82 additions and 210 deletions
|
@ -38,9 +38,7 @@ type Getter interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Creater interface {
|
type Creater interface {
|
||||||
Create(Type, []byte) (ID, error)
|
Create(Type) (Blob, error)
|
||||||
CreateFrom(Type, io.Reader) (ID, error)
|
|
||||||
CreateBlob(Type) (Blob, error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Tester interface {
|
type Tester interface {
|
||||||
|
|
|
@ -10,8 +10,6 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/juju/arrar"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -183,96 +181,6 @@ func (b *Local) dirname(t Type, id ID) string {
|
||||||
return filepath.Join(b.p, n)
|
return filepath.Join(b.p, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create stores new content of type t and data and returns the ID. If the blob
|
|
||||||
// is already present, returns ErrAlreadyPresent and the blob's ID.
|
|
||||||
func (b *Local) Create(t Type, data []byte) (ID, error) {
|
|
||||||
// TODO: make sure that tempfile is removed upon error
|
|
||||||
|
|
||||||
// check if blob is already present in backend
|
|
||||||
id := IDFromData(data)
|
|
||||||
res, err := b.Test(t, id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, arrar.Annotate(err, "test for presence")
|
|
||||||
}
|
|
||||||
|
|
||||||
if res {
|
|
||||||
return id, ErrAlreadyPresent
|
|
||||||
}
|
|
||||||
|
|
||||||
// create tempfile in backend
|
|
||||||
file, err := b.tempFile()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// write data to tempfile
|
|
||||||
_, err = file.Write(data)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = file.Close()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// return id
|
|
||||||
err = b.renameFile(file, t, id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return id, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateFrom reads content from rd and stores it as type t. Returned is the
|
|
||||||
// storage ID. If the blob is already present, returns ErrAlreadyPresent and
|
|
||||||
// the blob's ID.
|
|
||||||
func (b *Local) CreateFrom(t Type, rd io.Reader) (ID, error) {
|
|
||||||
// TODO: make sure that tempfile is removed upon error
|
|
||||||
|
|
||||||
// check hash while writing
|
|
||||||
hr := NewHashingReader(rd, newHash())
|
|
||||||
|
|
||||||
// create tempfile in backend
|
|
||||||
file, err := b.tempFile()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// write data to tempfile
|
|
||||||
_, err = io.Copy(file, hr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = file.Close()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// get ID
|
|
||||||
id := ID(hr.Sum(nil))
|
|
||||||
|
|
||||||
// check for duplicate ID
|
|
||||||
res, err := b.Test(t, id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, arrar.Annotate(err, "test for presence")
|
|
||||||
}
|
|
||||||
|
|
||||||
if res {
|
|
||||||
return id, ErrAlreadyPresent
|
|
||||||
}
|
|
||||||
|
|
||||||
// rename file
|
|
||||||
err = b.renameFile(file, t, id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return id, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type localBlob struct {
|
type localBlob struct {
|
||||||
f *os.File
|
f *os.File
|
||||||
h hash.Hash
|
h hash.Hash
|
||||||
|
@ -325,7 +233,7 @@ func (lb *localBlob) ID() (ID, error) {
|
||||||
// Create creates a new blob of type t. Blob implements io.WriteCloser. Once
|
// Create creates a new blob of type t. Blob implements io.WriteCloser. Once
|
||||||
// Close() has been called, ID() can be used to retrieve the ID. If the blob is
|
// Close() has been called, ID() can be used to retrieve the ID. If the blob is
|
||||||
// already present, Close() returns ErrAlreadyPresent.
|
// already present, Close() returns ErrAlreadyPresent.
|
||||||
func (b *Local) CreateBlob(t Type) (Blob, error) {
|
func (b *Local) Create(t Type) (Blob, error) {
|
||||||
// TODO: make sure that tempfile is removed upon error
|
// TODO: make sure that tempfile is removed upon error
|
||||||
|
|
||||||
// create tempfile in backend
|
// create tempfile in backend
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"sort"
|
"sort"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -69,7 +70,7 @@ func testBackend(b backend.Backend, t *testing.T) {
|
||||||
// add files
|
// add files
|
||||||
for _, test := range TestStrings {
|
for _, test := range TestStrings {
|
||||||
// store string in backend
|
// store string in backend
|
||||||
blob, err := b.CreateBlob(tpe)
|
blob, err := b.Create(tpe)
|
||||||
ok(t, err)
|
ok(t, err)
|
||||||
|
|
||||||
_, err = blob.Write([]byte(test.data))
|
_, err = blob.Write([]byte(test.data))
|
||||||
|
@ -97,24 +98,43 @@ func testBackend(b backend.Backend, t *testing.T) {
|
||||||
equals(t, test.data, string(buf))
|
equals(t, test.data, string(buf))
|
||||||
}
|
}
|
||||||
|
|
||||||
// test stream functions with first file
|
// test adding the first file again
|
||||||
test := TestStrings[0]
|
test := TestStrings[0]
|
||||||
id, err := backend.ParseID(test.id)
|
id, err := backend.ParseID(test.id)
|
||||||
ok(t, err)
|
ok(t, err)
|
||||||
|
|
||||||
// create with reader, should return error
|
// create blob
|
||||||
_, err = b.CreateFrom(tpe, bytes.NewReader([]byte(test.data)))
|
blob, err := b.Create(tpe)
|
||||||
|
ok(t, err)
|
||||||
|
|
||||||
|
_, err = io.Copy(blob, bytes.NewReader([]byte(test.data)))
|
||||||
|
ok(t, err)
|
||||||
|
err = blob.Close()
|
||||||
assert(t, err == backend.ErrAlreadyPresent,
|
assert(t, err == backend.ErrAlreadyPresent,
|
||||||
"expected ErrAlreadyPresent, got %v", err)
|
"wrong error returned: expected %v, got %v",
|
||||||
|
backend.ErrAlreadyPresent, err)
|
||||||
|
|
||||||
|
id2, err := blob.ID()
|
||||||
|
ok(t, err)
|
||||||
|
|
||||||
|
assert(t, id.Equal(id2), "IDs do not match: expected %v, got %v", id, id2)
|
||||||
|
|
||||||
// remove and recreate
|
// remove and recreate
|
||||||
err = b.Remove(tpe, id)
|
err = b.Remove(tpe, id)
|
||||||
ok(t, err)
|
ok(t, err)
|
||||||
|
|
||||||
id2, err := b.CreateFrom(tpe, bytes.NewReader([]byte(test.data)))
|
// create blob
|
||||||
|
blob, err = b.Create(tpe)
|
||||||
ok(t, err)
|
ok(t, err)
|
||||||
assert(t, id.Equal(id2),
|
|
||||||
"expected id %v, got %v", id, id2)
|
_, err = io.Copy(blob, bytes.NewReader([]byte(test.data)))
|
||||||
|
ok(t, err)
|
||||||
|
err = blob.Close()
|
||||||
|
ok(t, err)
|
||||||
|
|
||||||
|
id2, err = blob.ID()
|
||||||
|
ok(t, err)
|
||||||
|
assert(t, id.Equal(id2), "IDs do not match: expected %v, got %v", id, id2)
|
||||||
|
|
||||||
// list items
|
// list items
|
||||||
IDs := backend.IDs{}
|
IDs := backend.IDs{}
|
||||||
|
|
|
@ -15,7 +15,6 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/juju/arrar"
|
|
||||||
"github.com/pkg/sftp"
|
"github.com/pkg/sftp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -291,96 +290,6 @@ func (r *SFTP) dirname(t Type, id ID) string {
|
||||||
return filepath.Join(r.p, n)
|
return filepath.Join(r.p, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create stores new content of type t and data and returns the ID. If the blob
|
|
||||||
// is already present, returns ErrAlreadyPresent and the blob's ID.
|
|
||||||
func (r *SFTP) Create(t Type, data []byte) (ID, error) {
|
|
||||||
// TODO: make sure that tempfile is removed upon error
|
|
||||||
|
|
||||||
// check if blob is already present in backend
|
|
||||||
id := IDFromData(data)
|
|
||||||
res, err := r.Test(t, id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, arrar.Annotate(err, "test for presence")
|
|
||||||
}
|
|
||||||
|
|
||||||
if res {
|
|
||||||
return id, ErrAlreadyPresent
|
|
||||||
}
|
|
||||||
|
|
||||||
// create tempfile in backend
|
|
||||||
filename, file, err := r.tempFile()
|
|
||||||
if err != nil {
|
|
||||||
return nil, arrar.Annotate(err, "create tempfile")
|
|
||||||
}
|
|
||||||
|
|
||||||
// write data to tempfile
|
|
||||||
_, err = file.Write(data)
|
|
||||||
if err != nil {
|
|
||||||
return nil, arrar.Annotate(err, "writing data to tempfile")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = file.Close()
|
|
||||||
if err != nil {
|
|
||||||
return nil, arrar.Annotate(err, "close tempfile")
|
|
||||||
}
|
|
||||||
|
|
||||||
// return id
|
|
||||||
err = r.renameFile(filename, t, id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, arrar.Annotate(err, "rename file")
|
|
||||||
}
|
|
||||||
|
|
||||||
return id, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateFrom reads content from rd and stores it as type t. Returned is the
|
|
||||||
// storage ID. If the blob is already present, returns ErrAlreadyPresent and
|
|
||||||
// the blob's ID.
|
|
||||||
func (r *SFTP) CreateFrom(t Type, rd io.Reader) (ID, error) {
|
|
||||||
// TODO: make sure that tempfile is removed upon error
|
|
||||||
|
|
||||||
// check hash while writing
|
|
||||||
hr := NewHashingReader(rd, newHash())
|
|
||||||
|
|
||||||
// create tempfile in backend
|
|
||||||
filename, file, err := r.tempFile()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// write data to tempfile
|
|
||||||
_, err = io.Copy(file, hr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = file.Close()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// get ID
|
|
||||||
id := ID(hr.Sum(nil))
|
|
||||||
|
|
||||||
// check for duplicate ID
|
|
||||||
res, err := r.Test(t, id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, arrar.Annotate(err, "test for presence")
|
|
||||||
}
|
|
||||||
|
|
||||||
if res {
|
|
||||||
return id, ErrAlreadyPresent
|
|
||||||
}
|
|
||||||
|
|
||||||
// rename file
|
|
||||||
err = r.renameFile(filename, t, id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return id, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type sftpBlob struct {
|
type sftpBlob struct {
|
||||||
f *sftp.File
|
f *sftp.File
|
||||||
name string
|
name string
|
||||||
|
@ -434,7 +343,7 @@ func (sb *sftpBlob) ID() (ID, error) {
|
||||||
// Create creates a new blob of type t. Blob implements io.WriteCloser. Once
|
// Create creates a new blob of type t. Blob implements io.WriteCloser. Once
|
||||||
// Close() has been called, ID() can be used to retrieve the ID. If the blob is
|
// Close() has been called, ID() can be used to retrieve the ID. If the blob is
|
||||||
// already present, Close() returns ErrAlreadyPresent.
|
// already present, Close() returns ErrAlreadyPresent.
|
||||||
func (r *SFTP) CreateBlob(t Type) (Blob, error) {
|
func (r *SFTP) Create(t Type) (Blob, error) {
|
||||||
// TODO: make sure that tempfile is removed upon error
|
// TODO: make sure that tempfile is removed upon error
|
||||||
|
|
||||||
// create tempfile in backend
|
// create tempfile in backend
|
||||||
|
|
18
key.go
18
key.go
|
@ -209,10 +209,26 @@ func AddKey(s Server, password string, template *Key) (*Key, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// store in repository and return
|
// store in repository and return
|
||||||
id, err := s.Create(backend.Key, buf)
|
blob, err := s.Create(backend.Key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_, err = blob.Write(buf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = blob.Close()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
id, err := blob.ID()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
newkey.id = id
|
newkey.id = id
|
||||||
|
|
||||||
FreeChunkBuf("key", newkey.Data)
|
FreeChunkBuf("key", newkey.Data)
|
||||||
|
|
47
server.go
47
server.go
|
@ -169,7 +169,22 @@ func (s Server) Save(t backend.Type, data []byte, id backend.ID) (Blob, error) {
|
||||||
ciphertext = ciphertext[:n]
|
ciphertext = ciphertext[:n]
|
||||||
|
|
||||||
// save blob
|
// save blob
|
||||||
sid, err := s.Create(t, ciphertext)
|
backendBlob, err := s.Create(t)
|
||||||
|
if err != nil {
|
||||||
|
return Blob{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = backendBlob.Write(ciphertext)
|
||||||
|
if err != nil {
|
||||||
|
return Blob{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = backendBlob.Close()
|
||||||
|
if err != nil {
|
||||||
|
return Blob{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
sid, err := backendBlob.ID()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Blob{}, err
|
return Blob{}, err
|
||||||
}
|
}
|
||||||
|
@ -225,8 +240,22 @@ func (s Server) SaveFrom(t backend.Type, id backend.ID, length uint, rd io.Reade
|
||||||
|
|
||||||
ciphertext = ciphertext[:n]
|
ciphertext = ciphertext[:n]
|
||||||
|
|
||||||
// save blob
|
backendBlob, err := s.Create(t)
|
||||||
sid, err := s.Create(t, ciphertext)
|
if err != nil {
|
||||||
|
return Blob{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = backendBlob.Write(ciphertext)
|
||||||
|
if err != nil {
|
||||||
|
return Blob{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = backendBlob.Close()
|
||||||
|
if err != nil {
|
||||||
|
return Blob{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
sid, err := backendBlob.ID()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Blob{}, err
|
return Blob{}, err
|
||||||
}
|
}
|
||||||
|
@ -322,16 +351,8 @@ func (s Server) GetReader(t backend.Type, id backend.ID) (io.ReadCloser, error)
|
||||||
return s.be.GetReader(t, id)
|
return s.be.GetReader(t, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s Server) Create(t backend.Type, data []byte) (backend.ID, error) {
|
func (s Server) Create(t backend.Type) (backend.Blob, error) {
|
||||||
return s.be.Create(t, data)
|
return s.be.Create(t)
|
||||||
}
|
|
||||||
|
|
||||||
func (s Server) CreateFrom(t backend.Type, r io.Reader) (backend.ID, error) {
|
|
||||||
return s.be.CreateFrom(t, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Server) CreateBlob(t backend.Type) (backend.Blob, error) {
|
|
||||||
return s.be.CreateBlob(t)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s Server) Test(t backend.Type, id backend.ID) (bool, error) {
|
func (s Server) Test(t backend.Type, id backend.ID) (bool, error) {
|
||||||
|
|
Loading…
Reference in a new issue