init
This commit is contained in:
commit
bc5c7d6f9e
7 changed files with 181 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
.idea
|
18
Readme.md
Normal file
18
Readme.md
Normal file
|
@ -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)
|
||||||
|
}
|
||||||
|
```
|
7
error.go
Normal file
7
error.go
Normal file
|
@ -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")
|
14
go.mod
Normal file
14
go.mod
Normal file
|
@ -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
|
||||||
|
)
|
12
go.sum
Normal file
12
go.sum
Normal file
|
@ -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=
|
58
state.go
Normal file
58
state.go
Normal file
|
@ -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
|
||||||
|
}
|
71
state_test.go
Normal file
71
state_test.go
Normal file
|
@ -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")
|
||||||
|
}
|
Reference in a new issue