keystore.gno
4.11 Kb ยท 184 lines
1package keystore
2
3import (
4 "std"
5 "strings"
6
7 "gno.land/p/demo/avl"
8 "gno.land/p/demo/ufmt"
9)
10
11var data avl.Tree
12
13const (
14 BaseURL = "/r/demo/keystore"
15 StatusOK = "ok"
16 StatusNoUser = "user not found"
17 StatusNotFound = "key not found"
18 StatusNoWriteAccess = "no write access"
19 StatusCouldNotExecute = "could not execute"
20 StatusNoDatabases = "no databases"
21)
22
23func init() {
24 data = avl.Tree{} // user -> avl.Tree
25}
26
27// KeyStore stores the owner-specific avl.Tree
28type KeyStore struct {
29 Owner std.Address
30 Data avl.Tree
31}
32
33// Set will set a value to a key
34// requires write-access (original caller must be caller)
35func Set(k, v string) string {
36 origOwner := std.OriginCaller()
37 return set(origOwner.String(), k, v)
38}
39
40// set (private) will set a key to value
41// requires write-access (original caller must be caller)
42func set(owner, k, v string) string {
43 origOwner := std.OriginCaller()
44 if origOwner.String() != owner {
45 return StatusNoWriteAccess
46 }
47 var keystore *KeyStore
48 keystoreInterface, exists := data.Get(owner)
49 if !exists {
50 keystore = &KeyStore{
51 Owner: origOwner,
52 Data: avl.Tree{},
53 }
54 data.Set(owner, keystore)
55 } else {
56 keystore = keystoreInterface.(*KeyStore)
57 }
58 keystore.Data.Set(k, v)
59 return StatusOK
60}
61
62// Remove removes a key
63// requires write-access (original owner must be caller)
64func Remove(k string) string {
65 origOwner := std.OriginCaller()
66 return remove(origOwner.String(), k)
67}
68
69// remove (private) removes a key
70// requires write-access (original owner must be caller)
71func remove(owner, k string) string {
72 origOwner := std.OriginCaller()
73 if origOwner.String() != owner {
74 return StatusNoWriteAccess
75 }
76 var keystore *KeyStore
77 keystoreInterface, exists := data.Get(owner)
78 if !exists {
79 keystore = &KeyStore{
80 Owner: origOwner,
81 Data: avl.Tree{},
82 }
83 data.Set(owner, keystore)
84 } else {
85 keystore = keystoreInterface.(*KeyStore)
86 }
87 _, removed := keystore.Data.Remove(k)
88 if !removed {
89 return StatusCouldNotExecute
90 }
91 return StatusOK
92}
93
94// Get returns a value for a key
95// read-only
96func Get(k string) string {
97 origOwner := std.OriginCaller()
98 return remove(origOwner.String(), k)
99}
100
101// get (private) returns a value for a key
102// read-only
103func get(owner, k string) string {
104 keystoreInterface, exists := data.Get(owner)
105 if !exists {
106 return StatusNoUser
107 }
108 keystore := keystoreInterface.(*KeyStore)
109 val, found := keystore.Data.Get(k)
110 if !found {
111 return StatusNotFound
112 }
113 return val.(string)
114}
115
116// Size returns size of database
117// read-only
118func Size() string {
119 origOwner := std.OriginCaller()
120 return size(origOwner.String())
121}
122
123func size(owner string) string {
124 keystoreInterface, exists := data.Get(owner)
125 if !exists {
126 return StatusNoUser
127 }
128 keystore := keystoreInterface.(*KeyStore)
129 return ufmt.Sprintf("%d", keystore.Data.Size())
130}
131
132// Render provides read-only url access to the functions of the keystore
133// "" -> show all keystores listed by owner
134// "owner" -> show all keys for that owner's keystore
135// "owner:size" -> returns size of owner's keystore
136// "owner:get:key" -> show value for that key in owner's keystore
137func Render(p string) string {
138 var response string
139 args := strings.Split(p, ":")
140 numArgs := len(args)
141 if p == "" {
142 numArgs = 0
143 }
144 switch numArgs {
145 case 0:
146 if data.Size() == 0 {
147 return StatusNoDatabases
148 }
149 data.Iterate("", "", func(key string, value any) bool {
150 ks := value.(*KeyStore)
151 response += ufmt.Sprintf("- [%s](%s:%s) (%d keys)\n", ks.Owner, BaseURL, ks.Owner, ks.Data.Size())
152 return false
153 })
154 case 1:
155 owner := args[0]
156 keystoreInterface, exists := data.Get(owner)
157 if !exists {
158 return StatusNoUser
159 }
160 ks := keystoreInterface.(*KeyStore)
161 i := 0
162 response += ufmt.Sprintf("# %s database\n\n", ks.Owner)
163 ks.Data.Iterate("", "", func(key string, value any) bool {
164 response += ufmt.Sprintf("- %d [%s](%s:%s:get:%s)\n", i, key, BaseURL, ks.Owner, key)
165 i++
166 return false
167 })
168 case 2:
169 owner := args[0]
170 cmd := args[1]
171 if cmd == "size" {
172 return size(owner)
173 }
174 case 3:
175 owner := args[0]
176 cmd := args[1]
177 key := args[2]
178 if cmd == "get" {
179 return get(owner, key)
180 }
181 }
182
183 return response
184}