[#1223] lens/tui: Fix subhandlers using same result to decode
Signed-off-by: Aleksey Savchuk <a.savchuk@yadro.com>
This commit is contained in:
parent
c72bc6596a
commit
22170f05e9
6 changed files with 139 additions and 57 deletions
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
|
18
cmd/frostfs-lens/internal/schema/types/common/raw.go
Normal file
18
cmd/frostfs-lens/internal/schema/types/common/raw.go
Normal 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)
|
||||
}
|
7
cmd/frostfs-lens/internal/schema/types/record/string.go
Normal file
7
cmd/frostfs-lens/internal/schema/types/record/string.go
Normal file
|
@ -0,0 +1,7 @@
|
|||
package record
|
||||
|
||||
import "fmt"
|
||||
|
||||
func (r *Object) String() string {
|
||||
return r.id.String() + " | " + fmt.Sprintf("%v", r.object)
|
||||
}
|
|
@ -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)
|
||||
|
|
33
cmd/frostfs-lens/internal/tuiutil/component.go
Normal file
33
cmd/frostfs-lens/internal/tuiutil/component.go
Normal 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)
|
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue