Skip to content

Commit

Permalink
Merge pull request #41 from leonidasdeim/get-cfg-as-string
Browse files Browse the repository at this point in the history
Add String() method with masking
  • Loading branch information
leodeim authored Dec 21, 2023
2 parents 62d086d + 50adbe8 commit c7cc35a
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 15 deletions.
43 changes: 28 additions & 15 deletions cog.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cog

import (
"encoding/json"
"fmt"
"strconv"
"sync"
Expand All @@ -12,9 +13,10 @@ import (

type Subscriber[T any] func(T) error
type Callback[T any] func(T)
type MaskFn[T any] func(T) T

type C[T any] struct {
sync.Mutex
lock sync.Mutex
config T
timestamp string
handler ConfigHandler
Expand Down Expand Up @@ -59,8 +61,8 @@ func Init[T any](handler ...ConfigHandler) (*C[T], error) {

// Update configuration data. After update subscribers will be notified.
func (cog *C[T]) Update(new T) error {
cog.Lock()
defer cog.Unlock()
cog.lock.Lock()
defer cog.lock.Unlock()

if err := validate(new); err != nil {
return err
Expand All @@ -82,8 +84,8 @@ func (cog *C[T]) Update(new T) error {
// Register new callback function. It will be called after config update in non blocking goroutine.
// This method returns callback id (int). It can be used to remove callback by calling cog.RemoveCallback(id).
func (cog *C[T]) AddCallback(f Callback[T]) int {
cog.Lock()
defer cog.Unlock()
cog.lock.Lock()
defer cog.lock.Unlock()

l := len(cog.callbacks) + 1
cog.callbacks[l] = f
Expand All @@ -93,8 +95,8 @@ func (cog *C[T]) AddCallback(f Callback[T]) int {

// Remove callback by id.
func (cog *C[T]) RemoveCallback(id int) error {
cog.Lock()
defer cog.Unlock()
cog.lock.Lock()
defer cog.lock.Unlock()

if _, ok := cog.callbacks[id]; ok {
delete(cog.callbacks, id)
Expand All @@ -108,8 +110,8 @@ func (cog *C[T]) RemoveCallback(id int) error {
// If at least one subscriber returns an error, update stops and rollback is initiated for all updated subscribers.
// This method returns subscriber id (int). It can be used to remove subscriber by calling cog.RemoveSubscriber(id).
func (cog *C[T]) AddSubscriber(f Subscriber[T]) int {
cog.Lock()
defer cog.Unlock()
cog.lock.Lock()
defer cog.lock.Unlock()

l := len(cog.subscribers) + 1
cog.subscribers[l] = f
Expand All @@ -119,8 +121,8 @@ func (cog *C[T]) AddSubscriber(f Subscriber[T]) int {

// Remove subscriber by id.
func (cog *C[T]) RemoveSubscriber(id int) error {
cog.Lock()
defer cog.Unlock()
cog.lock.Lock()
defer cog.lock.Unlock()

if _, ok := cog.subscribers[id]; ok {
delete(cog.subscribers, id)
Expand All @@ -132,20 +134,31 @@ func (cog *C[T]) RemoveSubscriber(id int) error {

// Get timestamp of the configuration. It reflects when configuration has been updated or loaded last time.
func (cog *C[T]) GetTimestamp() string {
cog.Lock()
defer cog.Unlock()
cog.lock.Lock()
defer cog.lock.Unlock()

return cog.timestamp
}

// Get configuration data.
func (cog *C[T]) Config() T {
cog.Lock()
defer cog.Unlock()
cog.lock.Lock()
defer cog.lock.Unlock()

return cog.config
}

func (cog *C[T]) String(mask ...MaskFn[T]) (string, error) {
data := cog.Config()

if len(mask) > 0 {
data = mask[0](data)
}

b, err := json.MarshalIndent(data, "", " ")
return string(b), err
}

func (cog *C[T]) load() {
if err := cog.handler.Load(&cog.config); err != nil {
cog.config = *new(T)
Expand Down
22 changes: 22 additions & 0 deletions cog_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -470,3 +470,25 @@ func (s *testSuite) TestFileHandlerUpdateFail() {
require.Errorf(s.T(), err, "filehandler should return error")
assert.ErrorContainsf(s.T(), err, "filehandler error", "not a filehandler error")
}

func (s *testSuite) TestStringMask() {
c, err := setup(s.T(), fmt.Sprintf(defaultConfig, string(s.testCase.Type)), "", s.testCase.Type, s.testCase.TestString)
require.NoErrorf(s.T(), err, testSetupErrorMsg)

got := c.Config()
assert.Equalf(s.T(), testData, got, expectedResultErrorMsg)

str, err := c.String(func(tc testConfig) testConfig {
tc.Name = "[masked]"
return tc
})
require.NoErrorf(s.T(), err, "filehandler should not return error")

strExpected := `{
"Name": "[masked]",
"Version": 123,
"IsPrefork": true
}`

assert.Equal(s.T(), strExpected, str)
}

0 comments on commit c7cc35a

Please sign in to comment.