From 3063eb722ac2e9f06b28abe6a59e3d19dea9a0ec Mon Sep 17 00:00:00 2001 From: Nicolas Mahe Date: Wed, 19 Sep 2018 16:55:10 +0700 Subject: [PATCH 1/2] Extract encode functions to dedicated file and create DecodeError. --- database/services/all.go | 6 ++---- database/services/encode.go | 21 +++++++++++++++++++++ database/services/encode_test.go | 14 ++++++++++++++ database/services/errors.go | 13 ++++++++++++- database/services/get.go | 5 +---- database/services/save.go | 4 +--- 6 files changed, 51 insertions(+), 12 deletions(-) create mode 100644 database/services/encode.go create mode 100644 database/services/encode_test.go diff --git a/database/services/all.go b/database/services/all.go index e2227aebb..f7c420d66 100644 --- a/database/services/all.go +++ b/database/services/all.go @@ -1,8 +1,6 @@ package services import ( - "encoding/json" - "github.com/mesg-foundation/core/service" ) @@ -16,9 +14,9 @@ func All() ([]*service.Service, error) { var services []*service.Service iter := db.NewIterator(nil, nil) for iter.Next() { - var service service.Service - if err := json.Unmarshal(iter.Value(), &service); err != nil { return nil, err + service, err := decode(string(iter.Key()), iter.Value()) + if err != nil { } services = append(services, &service) } diff --git a/database/services/encode.go b/database/services/encode.go new file mode 100644 index 000000000..a767c2f8e --- /dev/null +++ b/database/services/encode.go @@ -0,0 +1,21 @@ +package services + +import ( + "encoding/json" + + "github.com/mesg-foundation/core/service" +) + +// encode returns the marshaled version of the service +func encode(service *service.Service) ([]byte, error) { + return json.Marshal(service) +} + +// decode decodes the data and return an DecodeError if not possible +func decode(hash string, data []byte) (*service.Service, error) { + s := &service.Service{} + if err := json.Unmarshal(data, s); err != nil { + return nil, &DecodeError{Hash: hash} + } + return s, nil +} diff --git a/database/services/encode_test.go b/database/services/encode_test.go new file mode 100644 index 000000000..a7146f63f --- /dev/null +++ b/database/services/encode_test.go @@ -0,0 +1,14 @@ +package services + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestDecodeError(t *testing.T) { + hash := "IDToTest" + _, err := decode(hash, []byte("oaiwdhhiodoihwaiohwa")) + require.Error(t, err) + require.IsType(t, &DecodeError{}, err) +} diff --git a/database/services/errors.go b/database/services/errors.go index 0a596b588..64391bb9c 100644 --- a/database/services/errors.go +++ b/database/services/errors.go @@ -1,6 +1,8 @@ package services import ( + "fmt" + leveldbErrors "github.com/syndtr/goleveldb/leveldb/errors" ) @@ -10,7 +12,7 @@ type NotFound struct { } func (e NotFound) Error() string { - return "Database services: Service with hash '" + e.Hash + "' not found" + return fmt.Sprintf("Database services: Service %q not found", e.Hash) } func handleErrorNotFound(err error, hash string) error { @@ -19,3 +21,12 @@ func handleErrorNotFound(err error, hash string) error { } return err } + +// DecodeError represents a service impossible to decode +type DecodeError struct { + Hash string +} + +func (e *DecodeError) Error() string { + return fmt.Sprintf("Database services: Could not decode service %q.", e.Hash) +} diff --git a/database/services/get.go b/database/services/get.go index d83505cc5..2ec4de988 100644 --- a/database/services/get.go +++ b/database/services/get.go @@ -1,8 +1,6 @@ package services import ( - "encoding/json" - "github.com/mesg-foundation/core/service" ) @@ -18,6 +16,5 @@ func Get(id string) (*service.Service, error) { err = handleErrorNotFound(err, id) return nil, err } - s := &service.Service{} - return s, json.Unmarshal(bytes, s) + return decode(id, bytes) } diff --git a/database/services/save.go b/database/services/save.go index 897b57130..7252690ad 100644 --- a/database/services/save.go +++ b/database/services/save.go @@ -1,14 +1,12 @@ package services import ( - "encoding/json" - "github.com/mesg-foundation/core/service" ) // Save stores a service in the database. func Save(service *service.Service) error { - bytes, err := json.Marshal(service) + bytes, err := encode(service) if err != nil { return err } From e9a3ca19b1c2a96c7a2a9d2edc3851611a71705b Mon Sep 17 00:00:00 2001 From: Nicolas Mahe Date: Wed, 19 Sep 2018 16:57:41 +0700 Subject: [PATCH 2/2] Warn decodeError in function database.service.all instead of returning it to not break the app when decoding deprecated service --- database/services/all.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/database/services/all.go b/database/services/all.go index f7c420d66..b4a5d89fd 100644 --- a/database/services/all.go +++ b/database/services/all.go @@ -2,6 +2,7 @@ package services import ( "github.com/mesg-foundation/core/service" + "github.com/sirupsen/logrus" ) // All returns all deployed services. @@ -14,11 +15,17 @@ func All() ([]*service.Service, error) { var services []*service.Service iter := db.NewIterator(nil, nil) for iter.Next() { - return nil, err service, err := decode(string(iter.Key()), iter.Value()) if err != nil { + // Ignore all decode errors (possibly due to a service structure change or database corruption) + if decodeErr, ok := err.(*DecodeError); ok { + logrus.WithField("service", decodeErr.Hash).Warning(decodeErr.Error()) + } else { + return nil, err + } + } else { + services = append(services, service) } - services = append(services, &service) } iter.Release() return services, iter.Error()