From 5bad2c53352cac0a4f057223b93af000ccda20e4 Mon Sep 17 00:00:00 2001 From: Caj Larsson Date: Sat, 7 May 2022 13:50:22 +0800 Subject: [PATCH] Immutable value objects --- dataswamp/namespace/valueobjects.go | 28 ++++++++++++++---------- dataswamp/namespace/valueobjects_test.go | 18 +++++++++------ dataswamp/services.go | 24 +++++++++++++------- dataswamp/swampfile/valueobjects.go | 11 ++++++---- dataswamp/swampfile/valueobjects_test.go | 6 ++--- 5 files changed, 53 insertions(+), 34 deletions(-) diff --git a/dataswamp/namespace/valueobjects.go b/dataswamp/namespace/valueobjects.go index 4dd6ea6..421ffea 100644 --- a/dataswamp/namespace/valueobjects.go +++ b/dataswamp/namespace/valueobjects.go @@ -5,32 +5,36 @@ type FileSizeQuota struct { CurrentUsage int64 } -func (f *FileSizeQuota) Allows(size int64) bool { +func (f FileSizeQuota) Allows(size int64) bool { return f.Remaining() >= size } -func (f *FileSizeQuota) Remaining() int64 { +func (f FileSizeQuota) Remaining() int64 { return f.AllowanceKB - f.CurrentUsage } -func (f *FileSizeQuota) Add(size int64) error { +func (f FileSizeQuota) Add(size int64) (*FileSizeQuota, error) { if !f.Allows(size) { - return ErrExceedQuota + return nil, ErrExceedQuota } - f.CurrentUsage += size - - return nil + n := FileSizeQuota { + f.AllowanceKB, + 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 { - return ErrQuotaInvalid + return nil, ErrQuotaInvalid } - f.CurrentUsage -= size - - return nil + n := FileSizeQuota { + f.AllowanceKB, + f.CurrentUsage - size, + } + return &n, nil } type FileStat struct { diff --git a/dataswamp/namespace/valueobjects_test.go b/dataswamp/namespace/valueobjects_test.go index 7133e6e..4e1b6ba 100644 --- a/dataswamp/namespace/valueobjects_test.go +++ b/dataswamp/namespace/valueobjects_test.go @@ -15,23 +15,27 @@ func TestQuota(t *testing.T) { func TestQuotaManipulation(t *testing.T) { is := is.New(t) - quota := FileSizeQuota{1000, 0} - - is.NoErr(quota.Add(500)) + quota := &FileSizeQuota{1000, 0} + quota, err := quota.Add(500) + is.NoErr(err) 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.Remove(1001), ErrQuotaInvalid) + _ , err = quota.Remove(1001) + is.Equal(err, ErrQuotaInvalid) 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)) } diff --git a/dataswamp/services.go b/dataswamp/services.go index caefe28..a36cad1 100644 --- a/dataswamp/services.go +++ b/dataswamp/services.go @@ -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 { ns := s.getOrCreateNs(ref.UserAgent) - err := ref.Clean(true) + r, err := ref.Clean(true) if err != nil { return err @@ -71,7 +71,7 @@ func (s SwampFileService) SaveFile(ref swampfile.FileReference, src io.Reader, s 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 { return err @@ -80,7 +80,7 @@ func (s SwampFileService) SaveFile(ref swampfile.FileReference, src io.Reader, s written, err := io.CopyN(f, src, 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 } @@ -89,12 +89,16 @@ func (s SwampFileService) SaveFile(ref swampfile.FileReference, src io.Reader, s overread, err := src.Read(buf) 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 } 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.Upload = ns.Upload.Add(size) 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) { ns := s.getOrCreateNs(ref.UserAgent) - err := ref.Clean(true) + r, err := ref.Clean(true) if err != nil { 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 { 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) 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 { diff --git a/dataswamp/swampfile/valueobjects.go b/dataswamp/swampfile/valueobjects.go index 9bec9c2..c3f00f5 100644 --- a/dataswamp/swampfile/valueobjects.go +++ b/dataswamp/swampfile/valueobjects.go @@ -36,14 +36,17 @@ type DeletedSwampFile struct { 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, "/"))) if c != fr.Path && strict { - return ErrUnacceptablePath + return nil, ErrUnacceptablePath } - fr.Path = c + n := FileReference { + c, + fr.UserAgent, + } - return nil + return &n, nil } diff --git a/dataswamp/swampfile/valueobjects_test.go b/dataswamp/swampfile/valueobjects_test.go index a4a5c3b..c2fa840 100644 --- a/dataswamp/swampfile/valueobjects_test.go +++ b/dataswamp/swampfile/valueobjects_test.go @@ -25,9 +25,9 @@ func TestSwampPathNotStrict(t *testing.T) { "ns", } - err := rf.Clean(false) + rc, err := rf.Clean(false) 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", } - err := rf.Clean(true) + _, err := rf.Clean(true) is.Equal(err, ErrUnacceptablePath) }