Skip to content

Commit

Permalink
Merge pull request #5 from arwos/develop
Browse files Browse the repository at this point in the history
upgrade
  • Loading branch information
markus621 authored Dec 25, 2023
2 parents f22b8f7 + 801e534 commit 4fc0af2
Show file tree
Hide file tree
Showing 36 changed files with 948 additions and 282 deletions.
6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ pre-commite: setup lint build tests
ci: install setup lint build tests

run_local_server:
go run cmd/loop/main.go --config=config/config.dev.yaml
go run cmd/loop/main.go -race --config=config/config.dev.yaml

run_local_cli:
go run cmd/loopcli/main.go --server=127.0.0.1:9500 kv set "k1/k2/k3" "{\"data\":\"aaa\"}"
Expand All @@ -51,9 +51,9 @@ run_local_cli:
go run cmd/loopcli/main.go --server=127.0.0.1:9500 kv list "k1/bbb/"
go run cmd/loopcli/main.go --server=127.0.0.1:9500 kv list "users/"

run_local_cli_watch:
run_local_template:
go run cmd/loopcli/main.go --server=127.0.0.1:9500 kv set "users/demo" "Mike"
go run cmd/loopcli/main.go --server=127.0.0.1:9500 template \
go run cmd/loopcli/main.go -race --server=127.0.0.1:9500 template \
test_data/template.tmpl:test_data/template.out
run_local_cli_watch_data:
go run cmd/loopcli/main.go --server=127.0.0.1:9500 kv set "users/demo" "Mike1"
Expand Down
68 changes: 67 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,67 @@
# loopy
# Loopy

Loopy is designed to store and manage keys and values that are used by various services and applications. It provides a reliable system for tracking changes and updating text templates in real time.

## Install with go

```shell
go install github.com/arwos/loopy/...@latest
```

## Server

Run server:

```shell
loppy --config=./config.yaml
```

## Console client

### Work with template

```shell
loopcli --server=127.0.0.1:9500 template \
test_data/template.tmpl:test_data/template.out \
test_data/template2.tmpl:test_data/template2.out
```

#### Template functions:

* __key__ - returns the key value or an empty string
```json
{{key "key/name"}}
```
* __key_or_default__ - returns the key value or default value
```json
{{key_or_default "key/name" "default value"}}
```
* __tree__ - returns a list of keys and value by prefix
```json
{{range $index, $data := tree "key/"}}
index: {{$index}} key: {{$data.Key}} val: {{$data.Value}}
{{end}}
```

### Work with keys

* Set key
```shell
loopcli --server=127.0.0.1:9500 kv set "key/name" "key_value"
```
* Get key
```shell
loopcli --server=127.0.0.1:9500 kv get "key/name"
```
* Delete key
```shell
loopcli --server=127.0.0.1:9500 kv del "key/name"
```
* List key by prefix (with empty value)
```shell
loopcli --server=127.0.0.1:9500 kv list "key/"
```
* Search key by prefix (without empty value)
```shell
loopcli --server=127.0.0.1:9500 kv search "key/"
```
14 changes: 7 additions & 7 deletions api/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ import (
"net/http"
"net/url"

"go.osspkg.com/goppy/sdk/webutil"
"go.osspkg.com/goppy/web"
)

type (
_client struct {
conf *Config
cli *webutil.ClientHttp
cli *web.ClientHttp
}
Client interface {
Get(ctx context.Context, key string) (string, error)
Expand All @@ -30,12 +30,12 @@ type (
)

func NewKV(c *Config) (Client, error) {
opts := make([]webutil.ClientHttpOption, 0, 2)
opts := make([]web.ClientHttpOption, 0, 2)
if len(c.AuthToken) > 0 {
opts = append(opts, webutil.ClientHttpOptionHeaders(AuthTokenHeaderName, c.AuthToken))
opts = append(opts, web.ClientHttpOptionHeaders(AuthTokenHeaderName, c.AuthToken))
}
opts = append(opts, clientHttpOptionCodec())
cli := webutil.NewClientHttp(opts...)
cli := web.NewClientHttp(opts...)

if err := c.Validate(); err != nil {
return nil, err
Expand All @@ -59,8 +59,8 @@ func (v *_client) buildUri(path string) string {
return uri.String()
}

func clientHttpOptionCodec() webutil.ClientHttpOption {
return webutil.ClientHttpOptionCodec(
func clientHttpOptionCodec() web.ClientHttpOption {
return web.ClientHttpOptionCodec(
func(in interface{}) (body []byte, contentType string, err error) {
switch v := in.(type) {
case []byte:
Expand Down
6 changes: 3 additions & 3 deletions api/client_keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ func (v *_client) Get(ctx context.Context, key string) (string, error) {
if len(data) == 0 {
return "", errRequestEmpty
}
return data[0].Value.String(), nil
return data[0].ValueStrOrNull(), nil
}

func (v *_client) Set(ctx context.Context, key, value string) error {
data := make(EntitiesKV, 0, 1)
data = append(data, EntityKV{
Key: key,
Value: []byte(value),
Key: key,
Val: &value,
})
return v.cli.Call(ctx, http.MethodPut, v.buildUri(PathApiV1KV), &data, nil)
}
Expand Down
6 changes: 3 additions & 3 deletions api/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
package api

import (
"go.osspkg.com/goppy/sdk/errors"
"go.osspkg.com/goppy/sdk/netutil/websocket"
"go.osspkg.com/goppy/errors"
"go.osspkg.com/goppy/ws/event"
)

const (
Expand All @@ -25,7 +25,7 @@ const (
)

const (
EventKVGet websocket.EventID = iota + 1
EventKVGet event.Id = iota + 1
EventKVSet
EventKVDel
EventKVWatch
Expand Down
18 changes: 12 additions & 6 deletions api/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,20 @@ go 1.20

require (
github.com/mailru/easyjson v0.7.7
go.osspkg.com/goppy v0.14.1
go.osspkg.com/goppy/errors v0.1.0
go.osspkg.com/goppy/web v0.1.5
go.osspkg.com/goppy/ws v0.1.6
go.osspkg.com/goppy/xlog v0.1.4
)

require (
github.com/gorilla/websocket v1.5.0 // indirect
github.com/gorilla/websocket v1.5.1 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/rogpeppe/go-internal v1.11.0 // indirect
go.osspkg.com/algorithms v1.3.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
go.osspkg.com/goppy/iosync v0.1.2 // indirect
go.osspkg.com/goppy/ioutil v0.1.0 // indirect
go.osspkg.com/goppy/plugins v0.1.1 // indirect
go.osspkg.com/goppy/xc v0.1.0 // indirect
go.osspkg.com/goppy/xnet v0.1.1 // indirect
go.osspkg.com/static v1.4.0 // indirect
golang.org/x/net v0.17.0 // indirect
)
38 changes: 25 additions & 13 deletions api/go.sum
Original file line number Diff line number Diff line change
@@ -1,21 +1,33 @@
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
go.osspkg.com/algorithms v1.3.0 h1:rrKO440aNTofYJwGnOVsW00w0VRtZtu+BQrgXMXw7j4=
go.osspkg.com/algorithms v1.3.0/go.mod h1:J2SXxHdqBK9ALGYJomA9XGvTOhIwMK0fvVw+KusYyoo=
go.osspkg.com/goppy v0.14.1 h1:bPYGep07AlvABuEcJIz6ySF7kMJYhticodycz6DNIOE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
go.osspkg.com/goppy/errors v0.1.0 h1:2q8gdRZMEEDk7y/sneblQxpHhsi3pqF1BbFFHS7+FnE=
go.osspkg.com/goppy/errors v0.1.0/go.mod h1:SvA8dgErO9e2i3TR8hgJV4uMAzs4TkL4FxXBSnw2UG4=
go.osspkg.com/goppy/iosync v0.1.2 h1:w0BxqBa7PAdxFM2P8pZn3ToHK6ilX5IG+1nwIXJEoGg=
go.osspkg.com/goppy/iosync v0.1.2/go.mod h1:huJpHhpIQ2DgzY3wVt72RUsJaje0uqYiUvMRovb1/Dg=
go.osspkg.com/goppy/ioutil v0.1.0 h1:Z9CF1nzrjbcHJV1EIcLqOPAotePScuCjmTSyU7BoLzk=
go.osspkg.com/goppy/ioutil v0.1.0/go.mod h1:WpZGj1HpuBlDDH5k8mn+2QwPssMP83jKj59U8qLsBoU=
go.osspkg.com/goppy/plugins v0.1.1 h1:ly/g8LyGQNhT9BLKLbhHejUuPho5atd4uJmitorQyvM=
go.osspkg.com/goppy/plugins v0.1.1/go.mod h1:oolaNTq9VCWBAApLUFCHvWZ/7tMUhzLaqQEIxmLviNQ=
go.osspkg.com/goppy/web v0.1.5 h1:Q9ySetPvN5o8Pj5uiUl5pXMNnxSUxqq1B7kI1UU6SMw=
go.osspkg.com/goppy/web v0.1.5/go.mod h1:e0XC5Kk+d+mFrOj2eViXsPooKc2SSc/9CWWXUJ9MWXY=
go.osspkg.com/goppy/ws v0.1.6 h1:6xuu9NZsB5YlrWidDIOy/4UMlzddXbD2gI8TczxFt7U=
go.osspkg.com/goppy/ws v0.1.6/go.mod h1:5jsI1DdoNUVchcylaHGCrw5+qFObf9lQ2qWAXYiB//c=
go.osspkg.com/goppy/xc v0.1.0 h1:e2231FumnLEf1OjqEtbRaUxz3FT9M8pZVKg0C0aTf7g=
go.osspkg.com/goppy/xc v0.1.0/go.mod h1:ocKrJbO+EADhuClTbOqzDfCqnUO9+ikEW0M7pqLl1Y4=
go.osspkg.com/goppy/xlog v0.1.4 h1:3+o71O3Jb8UgfSA6nfpfQHfhHLIploHhlQ4p+Yfj5So=
go.osspkg.com/goppy/xlog v0.1.4/go.mod h1:AtYBxgKaxQxFWmb/SbmLvYp7ysuE2i1YYSE3Pu29nNQ=
go.osspkg.com/goppy/xnet v0.1.1 h1:nysNyS5O7nHXIN/IjP9HGfa6Qh5BTTSYLULijk+Sv9M=
go.osspkg.com/goppy/xnet v0.1.1/go.mod h1:eB5pFfZTCrcaIOHzt4RlTgBVF5dRUV/u52qz/2hY3qk=
go.osspkg.com/goppy/xtest v0.1.2 h1:rbUzEnWZW9vkGa24owydA9icQcfOaROJWSym1l0mCtU=
go.osspkg.com/static v1.4.0 h1:2uy4/11c0QP+QLMucKQZbAU+e6lhVHKw5dWJPTk/DBg=
go.osspkg.com/static v1.4.0/go.mod h1:94YydVU3qUtb1J534486lpm+qg6CviQjqtxKlkpSppM=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
55 changes: 14 additions & 41 deletions api/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,54 +5,27 @@

package api

import (
"bytes"
"fmt"
)

//go:generate easyjson

//easyjson:json
type EntityKV struct {
Key string `json:"k"`
Value RawValue `json:"v,omitempty"`
}

//easyjson:json
type EntitiesKV []EntityKV

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

var (
esc = []byte("\\\"")
unesc = []byte("\"")
)

type RawValue []byte

func (m RawValue) MarshalJSON() ([]byte, error) {
if m == nil {
return []byte("null"), nil
type (
EntitiesKV []EntityKV
EntityKV struct {
Key string `json:"k"`
Val *string `json:"v"`
}
buf := bytes.NewBuffer(nil)
buf.WriteString("\"")
buf.Write(bytes.ReplaceAll(m, unesc, esc))
buf.WriteString("\"")
return buf.Bytes(), nil
}
)

func (m *RawValue) UnmarshalJSON(data []byte) error {
if m == nil {
return fmt.Errorf("json.RawMessage: UnmarshalJSON on nil pointer")
func (v EntityKV) ValueStrOrNull() string {
if v.Val == nil {
return "null"
}
out := bytes.ReplaceAll(data[1:len(data)-1], esc, unesc)
*m = append((*m)[0:0], out...)
return nil
return *v.Val
}

func (m RawValue) String() string {
if m == nil {
return "null"
func (v EntityKV) Value() string {
if v.Val == nil {
return ""
}
return string(m)
return *v.Val
}
20 changes: 15 additions & 5 deletions api/models_easyjson.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 4fc0af2

Please sign in to comment.