commit bc5c7d6f9ebd01876c24261fedc8e49e150c0d39 Author: kekskurse Date: Mon Mar 4 11:20:04 2024 +0100 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..723ef36 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea \ No newline at end of file diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..fab5689 --- /dev/null +++ b/Readme.md @@ -0,0 +1,18 @@ +# State +From time to time i need some small state persistens like e.g. for a bot how count the numbers of messages with a special value. I want to store them somewhere to not cound double without thin king about it so i store a struct as json. + +This pkg will provice Methodes to store (read and write) structs to the hdd. + +Idear for later: +* Store in S3 as well +* Function for dealing with lists on store. Like add to list, chcik if exists in list and so on + +# Working with State + +## Write State to HDD +``` +state, err := NewLocaleFilesystem("data/") +if err != nil { + panic(err) +} +``` \ No newline at end of file diff --git a/error.go b/error.go new file mode 100644 index 0000000..2a05c6b --- /dev/null +++ b/error.go @@ -0,0 +1,7 @@ +package state + +import "errors" + +var ErrLocaleFilesystemCantCreateFolder = errors.New("cant create folder for state") +var ErrLocaleFilesystemCantStoreState = errors.New("cant store state") +var ErrLocaleFilesystemCantReadState = errors.New("cant read state") diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..0826695 --- /dev/null +++ b/go.mod @@ -0,0 +1,14 @@ +module state + +go 1.21 + +require ( + github.com/google/uuid v1.6.0 + github.com/stretchr/testify v1.8.4 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..fcca6d1 --- /dev/null +++ b/go.sum @@ -0,0 +1,12 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/state.go b/state.go new file mode 100644 index 0000000..ce1ad5e --- /dev/null +++ b/state.go @@ -0,0 +1,58 @@ +package state + +import ( + "encoding/json" + "fmt" + "os" +) + +type StateStore interface { + StoreState(key string, object interface{}) error + GetState(key string, object any) error +} + +func NewLocaleFilesystem(path string) (StateStore, error) { + l := localeFilesystem{} + l.path = path + + if _, err := os.Stat(l.path); os.IsNotExist(err) { + err = os.MkdirAll(l.path, 0744) + if err != nil { + return nil, fmt.Errorf("%e: %s", ErrLocaleFilesystemCantCreateFolder, err) + } + } + return l, nil +} + +type localeFilesystem struct { + path string +} + +func (s localeFilesystem) GetState(key string, object any) error { + data, err := os.ReadFile(fmt.Sprintf("%v/%v.json", s.path, key)) + if err != nil { + return fmt.Errorf("%e: %v", ErrLocaleFilesystemCantReadState, err) + } + + err = json.Unmarshal(data, object) + + if err != nil { + return fmt.Errorf("%e: %v", ErrLocaleFilesystemCantReadState, err) + } + + return nil +} + +func (s localeFilesystem) StoreState(key string, object any) error { + data, err := json.Marshal(object) + if err != nil { + return fmt.Errorf("%e: %v", ErrLocaleFilesystemCantStoreState, err) + } + + err = os.WriteFile(fmt.Sprintf("%v/%v.json", s.path, key), data, 0644) + if err != nil { + return fmt.Errorf("%e: %v", ErrLocaleFilesystemCantStoreState, err) + } + + return nil +} diff --git a/state_test.go b/state_test.go new file mode 100644 index 0000000..01ab981 --- /dev/null +++ b/state_test.go @@ -0,0 +1,71 @@ +package state + +import ( + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "os" + "testing" +) + +func TestStoreStateAsJsonToHDD(t *testing.T) { + data := struct { + Name string + Test string `json:"-"` + Age int + something string + }{ + Name: "Max", + Test: "foo", + Age: 1337, + something: "nothing", + } + + store, err := NewLocaleFilesystem("/tmp/statetest") + defer os.RemoveAll("/tmp/statetest") + assert.Nil(t, err, "should be able to create filesystem store without error") + + err = store.StoreState("geheim", data) + assert.Nil(t, err, "should be store data without error") + + if _, err := os.Stat("/tmp/statetest/geheim.json"); os.IsNotExist(err) { + t.Error("state file does not exists") + } + + databyte, err := os.ReadFile("/tmp/statetest/geheim.json") + assert.Nil(t, err, "should be able to read file without error") + + assert.Equal(t, "{\"Name\":\"Max\",\"Age\":1337}", string(databyte), "json should match") +} + +func TestStoreStateFromHDD(t *testing.T) { + data := struct { + Name string + Test string `json:"-"` + Age int + something string + }{} + + result := struct { + Name string + Test string `json:"-"` + Age int + something string + }{ + Name: "Max", + Test: "", + Age: 1337, + something: "", + } + + store, err := NewLocaleFilesystem("/tmp/statetest") + defer os.RemoveAll("/tmp/statetest") + assert.Nil(t, err, "should be able to create filesystem store without error") + + key := uuid.NewString() + + os.WriteFile("/tmp/statetest/"+key+".json", []byte("{\"Name\":\"Max\",\"Age\":1337}"), 0744) + + store.GetState(key, &data) + + assert.Equal(t, result, data, "should get same data from hdd") +}