From dc2800fa5461de76f35e12a12c361c9e20a18ea1 Mon Sep 17 00:00:00 2001 From: Marc Di Luzio Date: Fri, 10 Jul 2020 17:09:47 +0100 Subject: [PATCH] Move Accountant behind an interface --- cmd/rove-server/internal/server.go | 4 +- pkg/accounts/accounts.go | 93 +++++------------------------- pkg/accounts/accounts_test.go | 9 +-- pkg/accounts/simpleAccountant.go | 90 +++++++++++++++++++++++++++++ 4 files changed, 111 insertions(+), 85 deletions(-) create mode 100644 pkg/accounts/simpleAccountant.go diff --git a/cmd/rove-server/internal/server.go b/cmd/rove-server/internal/server.go index ff98f76..a38e20d 100644 --- a/cmd/rove-server/internal/server.go +++ b/cmd/rove-server/internal/server.go @@ -29,7 +29,7 @@ type Server struct { world *game.World // Accountant - accountant *accounts.Accountant + accountant accounts.Accountant // gRPC server netListener net.Listener @@ -81,7 +81,7 @@ func NewServer(opts ...ServerOption) *Server { persistence: EphemeralData, schedule: cron.New(), world: game.NewWorld(32), - accountant: accounts.NewAccountant(), + accountant: accounts.NewSimpleAccountant(), } // Apply all options diff --git a/pkg/accounts/accounts.go b/pkg/accounts/accounts.go index 08f3ee3..69508c0 100644 --- a/pkg/accounts/accounts.go +++ b/pkg/accounts/accounts.go @@ -1,11 +1,22 @@ package accounts -import ( - "fmt" - "time" +// Accountant decribes something that stores accounts and account values +type Accountant interface { + // RegisterAccount will register a new account and return it's info + RegisterAccount(name string) (acc Account, err error) - "github.com/google/uuid" -) + // AssignData stores a custom account key value pair + AssignData(account string, key string, value string) error + + // GetValue returns custom account data for a specific key + GetValue(account string, key string) (string, error) + + // VerifySecret will verify whether the account secret matches with the + VerifySecret(account string, secret string) (bool, error) + + // GetSecret gets the secret associated with an account + GetSecret(account string) (string, error) +} // Account represents a registered user type Account struct { @@ -15,75 +26,3 @@ type Account struct { // Data represents internal account data Data map[string]string `json:"data"` } - -// Accountant manages a set of accounts -type Accountant struct { - Accounts map[string]Account `json:"accounts"` -} - -// NewAccountant creates a new accountant -func NewAccountant() *Accountant { - return &Accountant{ - Accounts: make(map[string]Account), - } -} - -// RegisterAccount adds an account to the set of internal accounts -func (a *Accountant) RegisterAccount(name string) (acc Account, err error) { - - // Set up the account info - acc.Name = name - acc.Data = make(map[string]string) - - // Verify this acount isn't already registered - for _, a := range a.Accounts { - if a.Name == acc.Name { - return Account{}, fmt.Errorf("account name already registered: %s", a.Name) - } - } - - // Set the creation time - acc.Data["created"] = time.Now().String() - - // Create a secret - acc.Data["secret"] = uuid.New().String() - - // Simply add the account to the map - a.Accounts[acc.Name] = acc - - return -} - -// VerifySecret verifies if an account secret is correct -func (a *Accountant) VerifySecret(account string, secret string) (bool, error) { - // Find the account matching the ID - if this, ok := a.Accounts[account]; ok { - return this.Data["secret"] == secret, nil - } - - return false, fmt.Errorf("no account found for id: %s", account) -} - -// AssignData assigns data to an account -func (a *Accountant) AssignData(account string, key string, value string) error { - - // Find the account matching the ID - if this, ok := a.Accounts[account]; ok { - this.Data[key] = value - a.Accounts[account] = this - } else { - return fmt.Errorf("no account found for id: %s", account) - } - - return nil -} - -// GetValue gets the rover rover for the account -func (a *Accountant) GetValue(account string, key string) (string, error) { - // Find the account matching the ID - this, ok := a.Accounts[account] - if !ok { - return "", fmt.Errorf("no account found for id: %s", account) - } - return this.Data[key], nil -} diff --git a/pkg/accounts/accounts_test.go b/pkg/accounts/accounts_test.go index 893c57d..bd2416f 100644 --- a/pkg/accounts/accounts_test.go +++ b/pkg/accounts/accounts_test.go @@ -8,7 +8,7 @@ import ( func TestNewAccountant(t *testing.T) { // Very basic verify here for now - accountant := NewAccountant() + accountant := NewSimpleAccountant() if accountant == nil { t.Error("Failed to create accountant") } @@ -16,7 +16,7 @@ func TestNewAccountant(t *testing.T) { func TestAccountant_RegisterAccount(t *testing.T) { - accountant := NewAccountant() + accountant := NewSimpleAccountant() // Start by making two accounts @@ -44,10 +44,7 @@ func TestAccountant_RegisterAccount(t *testing.T) { } func TestAccountant_AssignGetData(t *testing.T) { - accountant := NewAccountant() - if len(accountant.Accounts) != 0 { - t.Error("New accountant created with non-zero account number") - } + accountant := NewSimpleAccountant() name := uuid.New().String() a, err := accountant.RegisterAccount(name) diff --git a/pkg/accounts/simpleAccountant.go b/pkg/accounts/simpleAccountant.go new file mode 100644 index 0000000..023fe2f --- /dev/null +++ b/pkg/accounts/simpleAccountant.go @@ -0,0 +1,90 @@ +package accounts + +import ( + "fmt" + "time" + + "github.com/google/uuid" +) + +// SimpleAccountant manages a set of accounts +type SimpleAccountant struct { + Accounts map[string]Account `json:"accounts"` +} + +// NewSimpleAccountant creates a new accountant +func NewSimpleAccountant() Accountant { + return &SimpleAccountant{ + Accounts: make(map[string]Account), + } +} + +// RegisterAccount adds an account to the set of internal accounts +func (a *SimpleAccountant) RegisterAccount(name string) (acc Account, err error) { + + // Set up the account info + acc.Name = name + acc.Data = make(map[string]string) + + // Verify this acount isn't already registered + for _, a := range a.Accounts { + if a.Name == acc.Name { + return Account{}, fmt.Errorf("account name already registered: %s", a.Name) + } + } + + // Set the creation time + acc.Data["created"] = time.Now().String() + + // Create a secret + acc.Data["secret"] = uuid.New().String() + + // Simply add the account to the map + a.Accounts[acc.Name] = acc + + return +} + +// VerifySecret verifies if an account secret is correct +func (a *SimpleAccountant) VerifySecret(account string, secret string) (bool, error) { + // Find the account matching the ID + if this, ok := a.Accounts[account]; ok { + return this.Data["secret"] == secret, nil + } + + return false, fmt.Errorf("no account found for id: %s", account) +} + +// GetSecret gets the internal secret +func (a *SimpleAccountant) GetSecret(account string) (string, error) { + // Find the account matching the ID + if this, ok := a.Accounts[account]; ok { + return this.Data["secret"], nil + } + + return "", fmt.Errorf("no account found for id: %s", account) +} + +// AssignData assigns data to an account +func (a *SimpleAccountant) AssignData(account string, key string, value string) error { + + // Find the account matching the ID + if this, ok := a.Accounts[account]; ok { + this.Data[key] = value + a.Accounts[account] = this + } else { + return fmt.Errorf("no account found for id: %s", account) + } + + return nil +} + +// GetValue gets the rover rover for the account +func (a *SimpleAccountant) GetValue(account string, key string) (string, error) { + // Find the account matching the ID + this, ok := a.Accounts[account] + if !ok { + return "", fmt.Errorf("no account found for id: %s", account) + } + return this.Data[key], nil +}