[#1223] lens/tui: Fix subhandlers using same result to decode

Signed-off-by: Aleksey Savchuk <a.savchuk@yadro.com>
This commit is contained in:
Aleksey Savchuk 2024-07-31 15:34:03 +03:00
parent c72bc6596a
commit 22170f05e9
No known key found for this signature in database
6 changed files with 139 additions and 57 deletions

View file

@ -5,8 +5,14 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-lens/internal/schema/types/bucket"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-lens/internal/schema/types/common"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-lens/internal/schema/types/record"
)
type HandlerOption struct {
Factory func() common.Result
Next Handler
}
type HandlerOutput struct {
Result common.Result
Next Handler
@ -14,93 +20,119 @@ type HandlerOutput struct {
type Handler func(key, val []byte) (HandlerOutput, error)
func NewHandler(options ...HandlerOutput) Handler {
func NewHandler(options ...HandlerOption) Handler {
return func(key, val []byte) (HandlerOutput, error) {
for _, opt := range options {
if err := common.TryDecode(key, val, opt.Result); err == nil {
result := opt.Factory()
if err := common.TryDecode(key, val, result); err == nil {
if opt.Next == nil {
opt.Next = NewHandler()
}
return opt, nil
return HandlerOutput{Result: result, Next: opt.Next}, nil
}
}
return HandlerOutput{}, errors.New("no handler matched")
}
}
var x = []HandlerOutput{
func RawHandler(key, val []byte) (HandlerOutput, error) {
r := &common.RawResult{}
if err := r.Decode(key, val); err != nil {
return HandlerOutput{}, err
}
return HandlerOutput{Result: r, Next: RawHandler}, nil
}
func WithFallback(handler Handler, fallback Handler) Handler {
if handler == nil {
return fallback
}
return func(key, val []byte) (HandlerOutput, error) {
out, err := handler(key, val)
if err == nil {
return HandlerOutput{
Result: out.Result,
Next: WithFallback(out.Next, fallback),
}, nil
}
out, err = fallback(key, val)
if err == nil {
return HandlerOutput{
Result: out.Result,
Next: WithFallback(out.Next, fallback),
}, nil
}
panic("fallback handler returned an error")
}
}
var x = []HandlerOption{
{
Result: &bucket.Graveyard{},
Factory: func() common.Result { return &bucket.Graveyard{} },
},
{
Result: &bucket.Garbage{},
Factory: func() common.Result { return &bucket.Garbage{} },
},
{
Result: &bucket.ContainerVolume{},
Factory: func() common.Result { return &bucket.ContainerVolume{} },
},
{
Result: &bucket.Locked{},
Factory: func() common.Result { return &bucket.Locked{} },
Next: NewHandler(
HandlerOutput{
Result: &bucket.LockedSubbucket{},
},
HandlerOption{Factory: func() common.Result { return &bucket.LockedSubbucket{} }},
),
},
{
Result: &bucket.ShardInfo{},
Factory: func() common.Result { return &bucket.ShardInfo{} },
},
{
Result: &bucket.Object{},
// Next: NewHandler(
// HandlerOutput{
// Result: &record.Object{},
// },
// ),
},
{
Result: &bucket.Small{},
},
{
Result: &bucket.Root{},
},
{
Result: &bucket.Owner{},
Factory: func() common.Result { return &bucket.Object{} },
Next: NewHandler(
HandlerOutput{
Result: &bucket.OwnerSubbucket{},
},
HandlerOption{Factory: func() common.Result { return &record.Object{} }},
),
},
{
Result: &bucket.Attribute{},
Factory: func() common.Result { return &bucket.Small{} },
},
{
Factory: func() common.Result { return &bucket.Root{} },
},
{
Factory: func() common.Result { return &bucket.Owner{} },
Next: NewHandler(
HandlerOutput{
Result: &bucket.AttributeSubbucket{},
},
HandlerOption{Factory: func() common.Result { return &bucket.OwnerSubbucket{} }},
),
},
{
Result: &bucket.PayloadHash{},
// Next: NewHandler(
// HandlerOutput{
// Result: &record.PayloadHash{},
// },
// ),
Factory: func() common.Result { return &bucket.Attribute{} },
Next: NewHandler(
HandlerOption{Factory: func() common.Result { return &bucket.AttributeSubbucket{} }},
),
},
{
Result: &bucket.Parent{},
Factory: func() common.Result { return &bucket.PayloadHash{} },
},
{
Result: &bucket.Split{},
Factory: func() common.Result { return &bucket.Parent{} },
},
{
Result: &bucket.ContainerCounters{},
Factory: func() common.Result { return &bucket.Split{} },
},
{
Result: &bucket.ECInfo{},
Factory: func() common.Result { return &bucket.ContainerCounters{} },
},
{
Factory: func() common.Result { return &bucket.ECInfo{} },
},
}
func Start() Handler {
return NewHandler(x...)
return WithFallback(
NewHandler(x...),
RawHandler,
)
}

View file

@ -0,0 +1,18 @@
package common
import "fmt"
type RawResult struct {
key []byte
val []byte
}
func (r *RawResult) Decode(key, val []byte) error {
r.key = key[:]
r.val = val[:]
return nil
}
func (r *RawResult) String() string {
return fmt.Sprintf("%+v %+v", r.key, r.val)
}

View file

@ -0,0 +1,7 @@
package record
import "fmt"
func (r *Object) String() string {
return r.id.String() + " | " + fmt.Sprintf("%v", r.object)
}

View file

@ -2,7 +2,6 @@ package tuiutil
import (
"context"
"fmt"
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-lens/internal/schema"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
@ -33,9 +32,8 @@ func (a *Application) newBucketsView(ctx context.Context, _ *cid.ID, _ *oid.ID)
SetExpanded(true).
SetReference(&Bucket{nextHandler: handler})
var err error
// if len(filters) == 0 {
err = a.getChildren(ctx, root, true)
err := a.getChildren(ctx, root, true)
// } else {
// err = a.getChildren(ctx, root, false)
// }
@ -101,13 +99,7 @@ func (a *Application) getChildren(ctx context.Context, parent *tview.TreeNode, l
bucket.nextHandler = res.Next
bucket.result = res.Result
var child *tview.TreeNode
switch z := res.Result.(type) {
case fmt.Stringer:
child = tview.NewTreeNode(z.String())
default:
child = tview.NewTreeNode(fmt.Sprintf("%T", res.Result))
}
child := tview.NewTreeNode(res.Result.String())
child.SetSelectable(true)
child.SetExpanded(false)

View file

@ -0,0 +1,33 @@
package tuiutil
import (
"context"
"sync/atomic"
"github.com/gdamore/tcell/v2"
"github.com/rivo/tview"
)
type Primitive interface {
tview.Primitive
Init(ctx context.Context)
Load(ctx context.Context)
Draw(screen tcell.Screen)
}
type BoxWithDelay struct {
*tview.Box
shouldLoad atomic.Bool
}
func NewBoxWithDelay() *BoxWithDelay {
b := &BoxWithDelay{
Box: tview.NewBox(),
}
b.shouldLoad.Store(true)
return b
}
// func (b *B)

View file

@ -39,7 +39,7 @@ func (a *Application) newRecordsView(ctx context.Context, bkt *Bucket) (tview.Pr
box := tview.NewBox().
SetBorder(true).
SetTitle(fmt.Sprintf("%T", bkt.result))
SetTitle(bkt.result.String())
return &RecordsView{
Box: box,
@ -115,7 +115,7 @@ func (v *RecordsView) draw(screen tcell.Screen) {
v.DrawForSubclass(screen, v)
for index := v.firstRecordIndex; index < v.lastRecordIndex; index++ {
result := v.records[index].result
text := fmt.Sprintf("%s | %s", fmt.Sprintf("%T", result), "some val")
text := result.String()
if index == v.selectedRecordIndex {
text = fmt.Sprintf("[:white]%s[:black]", text)
}