Skip to content

Commit fde29ca

Browse files
committed
refactor(go-examples): align with Rust, simplify
Signed-off-by: Roman Volosatovs <rvolosatovs@riseup.net>
1 parent 0f75d95 commit fde29ca

File tree

4 files changed

+145
-94
lines changed
  • examples/go
    • hello-client/cmd/hello-client-nats
    • streams-client/cmd/streams-client-nats
    • wasi-keyvalue-nats-client/cmd/wasi-keyvalue-nats-client
    • wasi-keyvalue-nats-server/cmd/wasi-keyvalue-nats-server

4 files changed

+145
-94
lines changed

examples/go/hello-client/cmd/hello-client-nats/main.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,11 @@ func run() (err error) {
2727
}
2828
}
2929
}()
30-
31-
for _, prefix := range os.Args[1:] {
30+
prefixes := os.Args[1:]
31+
if len(prefixes) == 0 {
32+
prefixes = []string{"go"}
33+
}
34+
for _, prefix := range prefixes {
3235
client := wrpcnats.NewClient(nc, wrpcnats.WithPrefix(prefix))
3336
greeting, err := handler.Hello(context.Background(), client)
3437
if err != nil {

examples/go/streams-client/cmd/streams-client-nats/main.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,11 @@ func run() (err error) {
7373
}
7474
}
7575
}()
76-
77-
for _, prefix := range os.Args[1:] {
76+
prefixes := os.Args[1:]
77+
if len(prefixes) == 0 {
78+
prefixes = []string{"go"}
79+
}
80+
for _, prefix := range prefixes {
7881
client := wrpcnats.NewClient(nc, wrpcnats.WithPrefix(prefix))
7982
numbers, bytes, errCh, err := handler.Echo(context.Background(), client, &handler.Req{
8083
Numbers: &ThrottleStream[uint64]{

examples/go/wasi-keyvalue-nats-client/cmd/wasi-keyvalue-nats-client/main.go

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package main
22

33
import (
44
"context"
5+
"errors"
56
"fmt"
67
"log"
78
"log/slog"
@@ -27,36 +28,60 @@ func run() (err error) {
2728
}
2829
}
2930
}()
30-
31-
for _, prefix := range os.Args[1:] {
31+
prefixes := os.Args[1:]
32+
if len(prefixes) == 0 {
33+
prefixes = []string{"go"}
34+
}
35+
for _, prefix := range prefixes {
3236
client := wrpcnats.NewClient(nc, wrpcnats.WithPrefix(prefix))
33-
result, err := store.Open(context.Background(), client, "example")
34-
if err != nil || result.Err != nil {
35-
return fmt.Errorf("failed to call `wrpc-examples:keyvalue/store.open`: %w", err)
37+
open, err := store.Open(context.Background(), client, "example")
38+
if err != nil {
39+
return fmt.Errorf("failed to invoke `wrpc-examples:keyvalue/store.open`: %w", err)
40+
}
41+
if open.Err != nil {
42+
return fmt.Errorf("failed to open `example` bucket: %w", open.Err)
3643
}
37-
bucket := result.Ok
44+
bucket := open.Ok
3845

39-
_, err = store.Bucket_Set(context.Background(), client, bucket.Borrow(), "foo", []byte("bar"))
46+
set, err := store.Bucket_Set(context.Background(), client, bucket.Borrow(), "foo", []byte("bar"))
4047
if err != nil {
41-
return fmt.Errorf("failed to call `wrpc-examples:keyvalue/store.bucket.set`: %w", err)
48+
return fmt.Errorf("failed to invoke `wrpc-examples:keyvalue/store.bucket.set`: %w", err)
4249
}
43-
exist, err := store.Bucket_Exists(context.Background(), client, bucket.Borrow(), "foo")
50+
if set.Err != nil {
51+
return fmt.Errorf("failed to set `foo`: %w", set.Err)
52+
}
53+
54+
exists, err := store.Bucket_Exists(context.Background(), client, bucket.Borrow(), "foo")
4455
if err != nil {
45-
return fmt.Errorf("failed to call `wrpc-examples:keyvalue/store.bucket.exists`: %w", err)
46-
} else {
47-
fmt.Printf("%s exists: %t\n", prefix, *exist.Ok)
56+
return fmt.Errorf("failed to invoke `wrpc-examples:keyvalue/store.bucket.exists`: %w", err)
57+
}
58+
if exists.Err != nil {
59+
return fmt.Errorf("failed to check if `foo` exists: %w", exists.Err)
4860
}
49-
value, err := store.Bucket_Get(context.Background(), client, bucket.Borrow(), "foo")
61+
if !*exists.Ok {
62+
return errors.New("key `foo` does not exist in bucket")
63+
}
64+
65+
get, err := store.Bucket_Get(context.Background(), client, bucket.Borrow(), "foo")
5066
if err != nil {
51-
return fmt.Errorf("failed to call `wrpc-examples:keyvalue/store.bucket.get`: %w", err)
52-
} else {
53-
fmt.Printf("%s get: %s\n", prefix, *value.Ok)
67+
return fmt.Errorf("failed to invoke `wrpc-examples:keyvalue/store.bucket.get`: %w", err)
68+
}
69+
if get.Err != nil {
70+
return fmt.Errorf("failed to get `foo`: %w", get.Err)
71+
}
72+
if string(*get.Ok) != "bar" {
73+
return errors.New("key `foo` value is not `bar`")
5474
}
55-
keys, err := store.Bucket_ListKeys(context.Background(), client, bucket.Borrow(), nil)
75+
76+
listKeys, err := store.Bucket_ListKeys(context.Background(), client, bucket.Borrow(), nil)
5677
if err != nil {
57-
return fmt.Errorf("failed to call `wrpc-examples:keyvalue/store.bucket.list-keys`: %w", err)
58-
} else {
59-
fmt.Printf("%s keys: %v\n", prefix, (*keys.Ok).Keys)
78+
return fmt.Errorf("failed to invoke `wrpc-examples:keyvalue/store.bucket.list-keys`: %w", err)
79+
}
80+
if listKeys.Err != nil {
81+
return fmt.Errorf("failed to list keys: %w", listKeys.Err)
82+
}
83+
for _, key := range listKeys.Ok.Keys {
84+
fmt.Printf("%s key: %s\n", prefix, key)
6085
}
6186
}
6287
return nil

examples/go/wasi-keyvalue-nats-server/cmd/wasi-keyvalue-nats-server/main.go

Lines changed: 90 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -17,99 +17,119 @@ import (
1717
wrpcnats "wrpc.io/go/nats"
1818
)
1919

20-
var _ store.Handler = &Handler{}
20+
var (
21+
errNoSuchStore = store.NewErrorNoSuchStore()
22+
errInvalidDataType = store.NewErrorOther("invalid data type stored in map")
23+
)
2124

2225
type Handler struct {
23-
data map[Bucket]map[string][]uint8
24-
lock sync.Mutex
26+
sync.Map
2527
}
2628

27-
type Bucket string
29+
func Ok[T any](v T) *wrpc.Result[T, store.Error] {
30+
return wrpc.Ok[store.Error](v)
31+
}
2832

2933
func (h *Handler) Open(ctx context.Context, identifier string) (*wrpc.Result[wrpc.Own[store.Bucket], store.Error], error) {
30-
h.lock.Lock()
31-
defer h.lock.Unlock()
34+
slog.InfoContext(ctx, "handling `wasi:keyvalue/store.open`", "identifier", identifier)
35+
h.LoadOrStore(string(identifier), &sync.Map{})
36+
return Ok(wrpc.Own[store.Bucket](identifier)), nil
37+
}
3238

33-
if h.data == nil {
34-
h.data = make(map[Bucket]map[string][]uint8)
39+
func (h *Handler) Bucket_Get(ctx context.Context, bucket wrpc.Borrow[store.Bucket], key string) (*wrpc.Result[[]byte, store.Error], error) {
40+
slog.InfoContext(ctx, "handling `wasi:keyvalue/store.bucket.get`", "bucket", bucket, "key", key)
41+
v, ok := h.Load(string(bucket))
42+
if !ok {
43+
return wrpc.Err[[]byte](*errNoSuchStore), nil
3544
}
36-
bucket := (Bucket)(identifier)
37-
if _, ok := h.data[bucket]; !ok {
38-
h.data[bucket] = make(map[string][]uint8)
45+
b, ok := v.(*sync.Map)
46+
if !ok {
47+
return wrpc.Err[[]byte](*errInvalidDataType), nil
3948
}
40-
return wrpc.Ok[store.Error, wrpc.Own[store.Bucket]](wrpc.Own[store.Bucket](bucket)), nil
41-
}
42-
43-
func (h *Handler) Bucket_Get(ctx__ context.Context, self wrpc.Borrow[store.Bucket], key string) (*wrpc.Result[[]uint8, store.Error], error) {
44-
h.lock.Lock()
45-
defer h.lock.Unlock()
46-
47-
bucket := (Bucket)(self)
48-
if _, ok := h.data[bucket]; !ok {
49-
err := store.NewErrorNoSuchStore()
50-
return wrpc.Err[[]uint8, store.Error](*err), err
49+
v, ok = b.Load(key)
50+
if !ok {
51+
return Ok([]byte(nil)), nil
5152
}
52-
value, ok := h.data[bucket][key]
53+
buf, ok := v.([]byte)
5354
if !ok {
54-
return wrpc.Ok[store.Error, []uint8](nil), nil
55+
return wrpc.Err[[]byte](*errInvalidDataType), nil
5556
}
56-
return wrpc.Ok[store.Error, []uint8](value), nil
57+
return Ok(buf), nil
5758
}
5859

59-
func (h *Handler) Bucket_Set(ctx__ context.Context, self wrpc.Borrow[store.Bucket], key string, value []uint8) (*wrpc.Result[struct{}, store.Error], error) {
60-
h.lock.Lock()
61-
defer h.lock.Unlock()
62-
63-
bucket := (Bucket)(self)
64-
if _, ok := h.data[bucket]; !ok {
65-
err := store.NewErrorNoSuchStore()
66-
return wrpc.Err[struct{}, store.Error](*err), err
60+
func (h *Handler) Bucket_Set(ctx context.Context, bucket wrpc.Borrow[store.Bucket], key string, value []byte) (*wrpc.Result[struct{}, store.Error], error) {
61+
slog.InfoContext(ctx, "handling `wrpc:keyvalue/store.bucket.set`", "bucket", bucket, "key", key, "value", value)
62+
v, ok := h.Load(string(bucket))
63+
if !ok {
64+
return wrpc.Err[struct{}](*errNoSuchStore), nil
6765
}
68-
h.data[bucket][key] = value
69-
return wrpc.Ok[store.Error, struct{}](struct{}{}), nil
66+
b, ok := v.(*sync.Map)
67+
if !ok {
68+
return wrpc.Err[struct{}](*errInvalidDataType), nil
69+
}
70+
b.Store(key, value)
71+
return Ok(struct{}{}), nil
7072
}
7173

72-
func (h *Handler) Bucket_Delete(ctx__ context.Context, self wrpc.Borrow[store.Bucket], key string) (*wrpc.Result[struct{}, store.Error], error) {
73-
h.lock.Lock()
74-
defer h.lock.Unlock()
75-
76-
bucket := (Bucket)(self)
77-
if _, ok := h.data[bucket]; !ok {
78-
err := store.NewErrorNoSuchStore()
79-
return wrpc.Err[struct{}, store.Error](*err), err
74+
func (h *Handler) Bucket_Delete(ctx context.Context, bucket wrpc.Borrow[store.Bucket], key string) (*wrpc.Result[struct{}, store.Error], error) {
75+
slog.InfoContext(ctx, "handling `wrpc:keyvalue/store.bucket.delete`", "bucket", bucket, "key", key)
76+
v, ok := h.Load(string(bucket))
77+
if !ok {
78+
return wrpc.Err[struct{}](*errNoSuchStore), nil
8079
}
81-
delete(h.data[bucket], key)
82-
83-
return wrpc.Ok[store.Error, struct{}](struct{}{}), nil
80+
b, ok := v.(*sync.Map)
81+
if !ok {
82+
return wrpc.Err[struct{}](*errInvalidDataType), nil
83+
}
84+
b.Delete(key)
85+
return Ok(struct{}{}), nil
8486
}
8587

86-
func (h *Handler) Bucket_Exists(ctx__ context.Context, self wrpc.Borrow[store.Bucket], key string) (*wrpc.Result[bool, store.Error], error) {
87-
h.lock.Lock()
88-
defer h.lock.Unlock()
89-
90-
bucket := (Bucket)(self)
91-
if _, ok := h.data[bucket]; !ok {
92-
err := store.NewErrorNoSuchStore()
93-
return wrpc.Err[bool, store.Error](*err), err
88+
func (h *Handler) Bucket_Exists(ctx context.Context, bucket wrpc.Borrow[store.Bucket], key string) (*wrpc.Result[bool, store.Error], error) {
89+
slog.InfoContext(ctx, "handling `wrpc:keyvalue/store.bucket.exists`", "bucket", bucket, "key", key)
90+
v, ok := h.Load(string(bucket))
91+
if !ok {
92+
return wrpc.Err[bool](*errNoSuchStore), nil
93+
}
94+
b, ok := v.(*sync.Map)
95+
if !ok {
96+
return wrpc.Err[bool](*errInvalidDataType), nil
9497
}
95-
_, ok := h.data[bucket][key]
96-
return wrpc.Ok[store.Error, bool](ok), nil
98+
_, ok = b.Load(key)
99+
return Ok(ok), nil
97100
}
98101

99-
func (h *Handler) Bucket_ListKeys(ctx__ context.Context, self wrpc.Borrow[store.Bucket], cursor *uint64) (*wrpc.Result[store.KeyResponse, store.Error], error) {
100-
h.lock.Lock()
101-
defer h.lock.Unlock()
102-
103-
bucket := (Bucket)(self)
104-
if _, ok := h.data[bucket]; !ok {
105-
err := store.NewErrorNoSuchStore()
106-
return wrpc.Err[store.KeyResponse, store.Error](*err), err
102+
func (h *Handler) Bucket_ListKeys(ctx context.Context, bucket wrpc.Borrow[store.Bucket], cursor *uint64) (*wrpc.Result[store.KeyResponse, store.Error], error) {
103+
slog.InfoContext(ctx, "handling `wrpc:keyvalue/store.bucket.list-keys`", "bucket", bucket, "cursor", cursor)
104+
if cursor != nil {
105+
return wrpc.Err[store.KeyResponse](*store.NewErrorOther("cursors are not supported")), nil
106+
}
107+
v, ok := h.Load(string(bucket))
108+
if !ok {
109+
return wrpc.Err[store.KeyResponse](*errNoSuchStore), nil
107110
}
108-
keyResponse := store.KeyResponse{Keys: []string{}}
109-
for k := range h.data[bucket] {
110-
keyResponse.Keys = append(keyResponse.Keys, k)
111+
b, ok := v.(*sync.Map)
112+
if !ok {
113+
return wrpc.Err[store.KeyResponse](*errInvalidDataType), nil
114+
}
115+
var keys []string
116+
var err *store.Error
117+
b.Range(func(k, _ any) bool {
118+
s, ok := k.(string)
119+
if !ok {
120+
err = errInvalidDataType
121+
return false
122+
}
123+
keys = append(keys, s)
124+
return true
125+
})
126+
if err != nil {
127+
return wrpc.Err[store.KeyResponse](*err), nil
111128
}
112-
return wrpc.Ok[store.Error, store.KeyResponse](keyResponse), nil
129+
return Ok(store.KeyResponse{
130+
Keys: keys,
131+
Cursor: nil,
132+
}), nil
113133
}
114134

115135
func run() error {
@@ -131,15 +151,15 @@ func run() error {
131151
client := wrpcnats.NewClient(nc, wrpcnats.WithPrefix("go"))
132152
stop, err := server.Serve(client, &Handler{})
133153
if err != nil {
134-
return fmt.Errorf("failed to serve `keyvalue` world: %w", err)
154+
return fmt.Errorf("failed to serve `server` world: %w", err)
135155
}
136156

137157
signalCh := make(chan os.Signal, 1)
138158
signal.Notify(signalCh, syscall.SIGINT)
139159
<-signalCh
140160

141161
if err = stop(); err != nil {
142-
return fmt.Errorf("failed to stop `keyvalue` world: %w", err)
162+
return fmt.Errorf("failed to stop `server` world: %w", err)
143163
}
144164
return nil
145165
}

0 commit comments

Comments
 (0)