Immutable value objects

master
Caj Larsson 3 years ago
parent ee58da4f2d
commit 5bad2c5335

@ -5,32 +5,36 @@ type FileSizeQuota struct {
CurrentUsage int64 CurrentUsage int64
} }
func (f *FileSizeQuota) Allows(size int64) bool { func (f FileSizeQuota) Allows(size int64) bool {
return f.Remaining() >= size return f.Remaining() >= size
} }
func (f *FileSizeQuota) Remaining() int64 { func (f FileSizeQuota) Remaining() int64 {
return f.AllowanceKB - f.CurrentUsage return f.AllowanceKB - f.CurrentUsage
} }
func (f *FileSizeQuota) Add(size int64) error { func (f FileSizeQuota) Add(size int64) (*FileSizeQuota, error) {
if !f.Allows(size) { if !f.Allows(size) {
return ErrExceedQuota return nil, ErrExceedQuota
} }
f.CurrentUsage += size n := FileSizeQuota {
f.AllowanceKB,
return nil f.CurrentUsage + size,
}
return &n, nil
} }
func (f *FileSizeQuota) Remove(size int64) error { func (f FileSizeQuota) Remove(size int64) (*FileSizeQuota, error) {
if size > f.CurrentUsage { if size > f.CurrentUsage {
return ErrQuotaInvalid return nil, ErrQuotaInvalid
} }
f.CurrentUsage -= size n := FileSizeQuota {
f.AllowanceKB,
return nil f.CurrentUsage - size,
}
return &n, nil
} }
type FileStat struct { type FileStat struct {

@ -15,23 +15,27 @@ func TestQuota(t *testing.T) {
func TestQuotaManipulation(t *testing.T) { func TestQuotaManipulation(t *testing.T) {
is := is.New(t) is := is.New(t)
quota := FileSizeQuota{1000, 0} quota := &FileSizeQuota{1000, 0}
quota, err := quota.Add(500)
is.NoErr(quota.Add(500)) is.NoErr(err)
is.Equal(quota.CurrentUsage, int64(500)) is.Equal(quota.CurrentUsage, int64(500))
is.NoErr(quota.Add(500)) quota, err = quota.Add(500)
is.NoErr(err)
is.Equal(quota.Add(1), ErrExceedQuota) _ , err = quota.Add(1)
is.Equal(err, ErrExceedQuota)
is.Equal(quota.CurrentUsage, int64(1000)) is.Equal(quota.CurrentUsage, int64(1000))
is.Equal(quota.Remove(1001), ErrQuotaInvalid) _ , err = quota.Remove(1001)
is.Equal(err, ErrQuotaInvalid)
is.Equal(quota.CurrentUsage, int64(1000)) is.Equal(quota.CurrentUsage, int64(1000))
is.NoErr(quota.Remove(1000)) quota, err = quota.Remove(1000)
is.NoErr(err)
is.Equal(quota.CurrentUsage, int64(0)) is.Equal(quota.CurrentUsage, int64(0))
} }

@ -61,7 +61,7 @@ func (s SwampFileService) getOrCreateNs(namespace_in string) *namespace.Namespac
func (s SwampFileService) SaveFile(ref swampfile.FileReference, src io.Reader, size int64) error { func (s SwampFileService) SaveFile(ref swampfile.FileReference, src io.Reader, size int64) error {
ns := s.getOrCreateNs(ref.UserAgent) ns := s.getOrCreateNs(ref.UserAgent)
err := ref.Clean(true) r, err := ref.Clean(true)
if err != nil { if err != nil {
return err return err
@ -71,7 +71,7 @@ func (s SwampFileService) SaveFile(ref swampfile.FileReference, src io.Reader, s
return namespace.ErrExceedQuota return namespace.ErrExceedQuota
} }
f, err := s.swamp_file_repo.Create(ref.Path, strconv.FormatInt(ns.ID, 10)) f, err := s.swamp_file_repo.Create(r.Path, strconv.FormatInt(ns.ID, 10))
if err != nil { if err != nil {
return err return err
@ -80,7 +80,7 @@ func (s SwampFileService) SaveFile(ref swampfile.FileReference, src io.Reader, s
written, err := io.CopyN(f, src, size) written, err := io.CopyN(f, src, size)
if written < size { if written < size {
s.swamp_file_repo.Delete(ref.Path, strconv.FormatInt(ns.ID, 10)) s.swamp_file_repo.Delete(r.Path, strconv.FormatInt(ns.ID, 10))
return swampfile.ErrContentSizeExaggerated return swampfile.ErrContentSizeExaggerated
} }
@ -89,12 +89,16 @@ func (s SwampFileService) SaveFile(ref swampfile.FileReference, src io.Reader, s
overread, err := src.Read(buf) overread, err := src.Read(buf)
if overread > 0 || err != io.EOF { if overread > 0 || err != io.EOF {
s.swamp_file_repo.Delete(ref.Path, strconv.FormatInt(ns.ID, 10)) s.swamp_file_repo.Delete(r.Path, strconv.FormatInt(ns.ID, 10))
return swampfile.ErrContentSizeExceeded return swampfile.ErrContentSizeExceeded
} }
f.Close() f.Close()
ns.FileQuota.Add(size) uq, err := ns.FileQuota.Add(size)
if err != nil {
return err
}
ns.FileQuota = *uq
ns.Usage = ns.Usage.Add(size) ns.Usage = ns.Usage.Add(size)
ns.Upload = ns.Upload.Add(size) ns.Upload = ns.Upload.Add(size)
s.namespace_repo.Update(ns.ID, *ns) s.namespace_repo.Update(ns.ID, *ns)
@ -105,13 +109,13 @@ func (s SwampFileService) SaveFile(ref swampfile.FileReference, src io.Reader, s
func (s SwampFileService) OpenOutFile(ref swampfile.FileReference) (swampfile.SwampOutFile, error) { func (s SwampFileService) OpenOutFile(ref swampfile.FileReference) (swampfile.SwampOutFile, error) {
ns := s.getOrCreateNs(ref.UserAgent) ns := s.getOrCreateNs(ref.UserAgent)
err := ref.Clean(true) r, err := ref.Clean(true)
if err != nil { if err != nil {
return nil, err return nil, err
} }
f, err := s.swamp_file_repo.Open(ref.Path, strconv.FormatInt(ns.ID, 10)) f, err := s.swamp_file_repo.Open(r.Path, strconv.FormatInt(ns.ID, 10))
if err != nil { if err != nil {
return nil, err return nil, err
@ -140,7 +144,11 @@ func (s SwampFileService) CleanUpExpiredFiles() error {
dfs, err := s.swamp_file_repo.DeleteOlderThan(strconv.FormatInt(ns.ID, 10), expiry) dfs, err := s.swamp_file_repo.DeleteOlderThan(strconv.FormatInt(ns.ID, 10), expiry)
for _, df := range dfs { for _, df := range dfs {
ns.FileQuota.Remove(df.Size) dq, err := ns.FileQuota.Remove(df.Size)
if err != nil {
dq.CurrentUsage = 0
}
ns.FileQuota = *dq
} }
if err != nil { if err != nil {

@ -36,14 +36,17 @@ type DeletedSwampFile struct {
Size int64 Size int64
} }
func (fr *FileReference) Clean(strict bool) error { func (fr *FileReference) Clean(strict bool) (*FileReference, error) {
c := filepath.FromSlash(path.Clean("/" + strings.Trim(fr.Path, "/"))) c := filepath.FromSlash(path.Clean("/" + strings.Trim(fr.Path, "/")))
if c != fr.Path && strict { if c != fr.Path && strict {
return ErrUnacceptablePath return nil, ErrUnacceptablePath
} }
fr.Path = c n := FileReference {
c,
fr.UserAgent,
}
return nil return &n, nil
} }

@ -25,9 +25,9 @@ func TestSwampPathNotStrict(t *testing.T) {
"ns", "ns",
} }
err := rf.Clean(false) rc, err := rf.Clean(false)
is.NoErr(err) is.NoErr(err)
is.Equal(rf.Path, tc.clean) is.Equal(rc.Path, tc.clean)
} }
} }
@ -39,6 +39,6 @@ func TestSwampPathStrict(t *testing.T) {
"ns", "ns",
} }
err := rf.Clean(true) _, err := rf.Clean(true)
is.Equal(err, ErrUnacceptablePath) is.Equal(err, ErrUnacceptablePath)
} }

Loading…
Cancel
Save