go-vise

Constrained Size Output Virtual Machine
Info | Log | Files | Refs | README | LICENSE

commit 0f5b1195d745e627f20adc6aa727b82fe8d54ee3
parent 6c3cb1731bb08eebdb29674c58a4530508dbb2b2
Author: lash <dev@holbrook.no>
Date:   Fri, 30 Aug 2024 20:55:04 +0100

Implement db backend for resource

Diffstat:
Mdb/db.go | 22++++++++++++++++------
Aresource/db.go | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aresource/db_test.go | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mresource/mem.go | 2+-
Mresource/mem_test.go | 5+++--
Mresource/resource.go | 9+++++----
6 files changed, 171 insertions(+), 13 deletions(-)

diff --git a/db/db.go b/db/db.go @@ -8,11 +8,16 @@ import ( ) const ( - DATATYPE_UNKNOWN = iota - DATATYPE_BIN - DATATYPE_TEMPLATE - DATATYPE_STATE - DATATYPE_USERSTART + DATATYPE_UNKNOWN = 0 + DATATYPE_BIN = 1 + DATATYPE_MENU = 2 + DATATYPE_TEMPLATE = 4 + DATATYPE_STATE = 8 + DATATYPE_USERSTART = 16 +) + +const ( + datatype_sessioned_threshold = DATATYPE_TEMPLATE ) // Db abstracts all data storage and retrieval as a key-value store @@ -63,9 +68,14 @@ func(db *BaseDb) SetSession(sessionId string) { // ToKey creates a DbKey within the current session context. func(db *BaseDb) ToKey(key []byte) ([]byte, error) { + var b []byte if db.pfx == DATATYPE_UNKNOWN { return nil, errors.New("datatype prefix cannot be UNKNOWN") } - b := append(db.sid, key...) + if (db.pfx > datatype_sessioned_threshold) { + b = append(db.sid, key...) + } else { + b = key + } return ToDbKey(db.pfx, b, nil), nil } diff --git a/resource/db.go b/resource/db.go @@ -0,0 +1,68 @@ +package resource + +import ( + "context" + "errors" + "fmt" + + "git.defalsify.org/vise.git/db" +) + +const ( + resource_max_datatype = db.DATATYPE_TEMPLATE +) + +type dbGetter struct { + typs uint8 + db db.Db +} + +func NewDbFuncGetter(store db.Db, typs... uint8) (*dbGetter, error) { + var v uint8 + g := &dbGetter{ + db: store, + } + for _, v = range(typs) { + if v > resource_max_datatype { + return nil, fmt.Errorf("datatype %d is not a resource", v) + } + g.typs |= v + } + return g, nil +} + +func(g *dbGetter) fn(ctx context.Context, sym string) ([]byte, error) { + return g.db.Get(ctx, []byte(sym)) +} + +func(g *dbGetter) sfn(ctx context.Context, sym string) (string, error) { + b, err := g.fn(ctx, sym) + if err != nil { + return "", err + } + return string(b), nil +} + +func(g *dbGetter) GetTemplate(ctx context.Context, sym string) (string, error) { + if g.typs & db.DATATYPE_TEMPLATE == 0{ + return "", errors.New("not a template getter") + } + g.db.SetPrefix(db.DATATYPE_TEMPLATE) + return g.sfn(ctx, sym) +} + +func(g *dbGetter) GetMenu(ctx context.Context, sym string) (string, error) { + if g.typs & db.DATATYPE_MENU == 0{ + return "", errors.New("not a menu getter") + } + g.db.SetPrefix(db.DATATYPE_MENU) + return g.sfn(ctx, sym) +} + +func(g *dbGetter) GetCode(ctx context.Context, sym string) ([]byte, error) { + if g.typs & db.DATATYPE_BIN == 0{ + return nil, errors.New("not a code getter") + } + g.db.SetPrefix(db.DATATYPE_BIN) + return g.fn(ctx, sym) +} diff --git a/resource/db_test.go b/resource/db_test.go @@ -0,0 +1,78 @@ +package resource + +import ( + "bytes" + "context" + "testing" + + "git.defalsify.org/vise.git/db" +) + +func TestDb(t *testing.T) { + ctx := context.Background() + store := db.NewMemDb(ctx) + tg, err := NewDbFuncGetter(store, db.DATATYPE_TEMPLATE) + if err != nil { + t.Fatal(err) + } + rs := NewMenuResource() + rs.WithTemplateGetter(tg.GetTemplate) + + s, err := rs.GetTemplate(ctx, "foo") + if err == nil { + t.Fatal("expected error") + } + + store.SetPrefix(db.DATATYPE_TEMPLATE) + err = store.Put(ctx, []byte("foo"), []byte("bar")) + if err != nil { + t.Fatal(err) + } + s, err = rs.GetTemplate(ctx, "foo") + if err != nil { + t.Fatal(err) + } + if s != "bar" { + t.Fatalf("expected 'bar', got %s", s) + } + + // test support check + store.SetPrefix(db.DATATYPE_BIN) + err = store.Put(ctx, []byte("xyzzy"), []byte("deadbeef")) + if err != nil { + t.Fatal(err) + } + + rs.WithCodeGetter(tg.GetCode) + b, err := rs.GetCode(ctx, "xyzzy") + if err == nil { + t.Fatal("expected error") + } + + tg, err = NewDbFuncGetter(store, db.DATATYPE_TEMPLATE, db.DATATYPE_BIN) + if err != nil { + t.Fatal(err) + } + rs.WithTemplateGetter(tg.GetTemplate) + + rs.WithCodeGetter(tg.GetCode) + b, err = rs.GetCode(ctx, "xyzzy") + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(b, []byte("deadbeef")) { + t.Fatalf("expected 'deadbeef', got %x", b) + } + + tg, err = NewDbFuncGetter(store, db.DATATYPE_TEMPLATE, db.DATATYPE_BIN, db.DATATYPE_MENU) + if err != nil { + t.Fatal(err) + } + store.SetPrefix(db.DATATYPE_MENU) + err = store.Put(ctx, []byte("inky"), []byte("pinky")) + if err != nil { + t.Fatal(err) + } + rs.WithMenuGetter(tg.GetMenu) + +} diff --git a/resource/mem.go b/resource/mem.go @@ -34,7 +34,7 @@ func(mr MemResource) getTemplate(ctx context.Context, sym string) (string, error return r, nil } -func(mr MemResource) getCode(sym string) ([]byte, error) { +func(mr MemResource) getCode(ctx context.Context, sym string) ([]byte, error) { r, ok := mr.bytecodes[sym] if !ok { return nil, fmt.Errorf("unknown bytecode: %s", sym) diff --git a/resource/mem_test.go b/resource/mem_test.go @@ -36,7 +36,8 @@ func TestMemResourceCode(t *testing.T) { rs := NewMemResource() rs.AddBytecode("foo", []byte("bar")) - r, err := rs.GetCode("foo") + ctx := context.Background() + r, err := rs.GetCode(ctx, "foo") if err != nil { t.Fatal(err) } @@ -44,7 +45,7 @@ func TestMemResourceCode(t *testing.T) { fmt.Errorf("expected 'bar', got %x", r) } - _, err = rs.GetCode("bar") + _, err = rs.GetCode(ctx, "bar") if err == nil { t.Fatalf("expected error") } diff --git a/resource/resource.go b/resource/resource.go @@ -4,6 +4,7 @@ import ( "context" ) + // Result contains the results of an external code operation. type Result struct { Content string // content value for symbol after execution. @@ -14,7 +15,7 @@ type Result struct { // EntryFunc is a function signature for retrieving value for a key type EntryFunc func(ctx context.Context, sym string, input []byte) (Result, error) -type CodeFunc func(sym string) ([]byte, error) +type CodeFunc func(ctx context.Context, sym string) ([]byte, error) type MenuFunc func(ctx context.Context, sym string) (string, error) type TemplateFunc func(ctx context.Context, sym string) (string, error) type FuncForFunc func(sym string) (EntryFunc, error) @@ -22,7 +23,7 @@ type FuncForFunc func(sym string) (EntryFunc, error) // Resource implementation are responsible for retrieving values and templates for symbols, and can render templates from value dictionaries. type Resource interface { GetTemplate(ctx context.Context, sym string) (string, error) // Get the template for a given symbol. - GetCode(sym string) ([]byte, error) // Get the bytecode for the given symbol. + GetCode(ctx context.Context, sym string) ([]byte, error) // Get the bytecode for the given symbol. GetMenu(ctx context.Context, sym string) (string, error) // Receive menu test for menu symbol. FuncFor(sym string) (EntryFunc, error) // Resolve symbol content point for. } @@ -73,8 +74,8 @@ func(m MenuResource) FuncFor(sym string) (EntryFunc, error) { } // GetCode implements Resource interface -func(m MenuResource) GetCode(sym string) ([]byte, error) { - return m.codeFunc(sym) +func(m MenuResource) GetCode(ctx context.Context, sym string) ([]byte, error) { + return m.codeFunc(ctx, sym) } // GetTemplate implements Resource interface