[#1223] lens/tui: Make parsers for each bucket/record type
Signed-off-by: Aleksey Savchuk <a.savchuk@yadro.com>
This commit is contained in:
parent
22170f05e9
commit
1da1824d15
13 changed files with 621 additions and 756 deletions
|
@ -2,137 +2,299 @@ package schema
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"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"
|
||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
)
|
||||
|
||||
type HandlerOption struct {
|
||||
Factory func() common.Result
|
||||
Next Handler
|
||||
}
|
||||
|
||||
type HandlerOutput struct {
|
||||
Result common.Result
|
||||
Next Handler
|
||||
}
|
||||
|
||||
type Handler func(key, val []byte) (HandlerOutput, error)
|
||||
|
||||
func NewHandler(options ...HandlerOption) Handler {
|
||||
return func(key, val []byte) (HandlerOutput, error) {
|
||||
for _, opt := range options {
|
||||
result := opt.Factory()
|
||||
if err := common.TryDecode(key, val, result); err == nil {
|
||||
if opt.Next == nil {
|
||||
opt.Next = NewHandler()
|
||||
}
|
||||
return HandlerOutput{Result: result, Next: opt.Next}, nil
|
||||
}
|
||||
}
|
||||
return HandlerOutput{}, errors.New("no handler matched")
|
||||
}
|
||||
}
|
||||
|
||||
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{
|
||||
{
|
||||
Factory: func() common.Result { return &bucket.Graveyard{} },
|
||||
},
|
||||
{
|
||||
Factory: func() common.Result { return &bucket.Garbage{} },
|
||||
},
|
||||
{
|
||||
Factory: func() common.Result { return &bucket.ContainerVolume{} },
|
||||
},
|
||||
{
|
||||
Factory: func() common.Result { return &bucket.Locked{} },
|
||||
Next: NewHandler(
|
||||
HandlerOption{Factory: func() common.Result { return &bucket.LockedSubbucket{} }},
|
||||
),
|
||||
},
|
||||
{
|
||||
Factory: func() common.Result { return &bucket.ShardInfo{} },
|
||||
},
|
||||
{
|
||||
Factory: func() common.Result { return &bucket.Object{} },
|
||||
Next: NewHandler(
|
||||
HandlerOption{Factory: func() common.Result { return &record.Object{} }},
|
||||
),
|
||||
},
|
||||
{
|
||||
Factory: func() common.Result { return &bucket.Small{} },
|
||||
},
|
||||
{
|
||||
Factory: func() common.Result { return &bucket.Root{} },
|
||||
},
|
||||
{
|
||||
Factory: func() common.Result { return &bucket.Owner{} },
|
||||
Next: NewHandler(
|
||||
HandlerOption{Factory: func() common.Result { return &bucket.OwnerSubbucket{} }},
|
||||
),
|
||||
},
|
||||
{
|
||||
Factory: func() common.Result { return &bucket.Attribute{} },
|
||||
Next: NewHandler(
|
||||
HandlerOption{Factory: func() common.Result { return &bucket.AttributeSubbucket{} }},
|
||||
),
|
||||
},
|
||||
{
|
||||
Factory: func() common.Result { return &bucket.PayloadHash{} },
|
||||
},
|
||||
{
|
||||
Factory: func() common.Result { return &bucket.Parent{} },
|
||||
},
|
||||
{
|
||||
Factory: func() common.Result { return &bucket.Split{} },
|
||||
},
|
||||
{
|
||||
Factory: func() common.Result { return &bucket.ContainerCounters{} },
|
||||
},
|
||||
{
|
||||
Factory: func() common.Result { return &bucket.ECInfo{} },
|
||||
},
|
||||
}
|
||||
|
||||
func Start() Handler {
|
||||
return WithFallback(
|
||||
NewHandler(x...),
|
||||
RawHandler,
|
||||
func Start() Parser {
|
||||
return Any(
|
||||
GraveyardParser,
|
||||
GarbageParser,
|
||||
ContainerVolumeParser,
|
||||
LockedParser,
|
||||
ShardInfoParser,
|
||||
PrimaryParser,
|
||||
LockersParser,
|
||||
TombstoneParser,
|
||||
SmallParser,
|
||||
RootParser,
|
||||
OwnerParser,
|
||||
UserAttributeParser,
|
||||
PayloadHashParser,
|
||||
ParentParser,
|
||||
SplitParser,
|
||||
ContainerCountersParser,
|
||||
ECInfoParser,
|
||||
)
|
||||
}
|
||||
|
||||
var (
|
||||
GraveyardParser = NewPrefixBucketParser(common.Graveyard, GraveyardRecordParser, Resolvers{
|
||||
cidResolver: LenientResolver,
|
||||
oidResolver: LenientResolver,
|
||||
})
|
||||
|
||||
GarbageParser = NewPrefixBucketParser(common.Garbage, GarbageRecordParser, Resolvers{
|
||||
cidResolver: LenientResolver,
|
||||
oidResolver: LenientResolver,
|
||||
})
|
||||
|
||||
ContainerVolumeParser = NewPrefixBucketParser(common.ContainerVolume, ContainerVolumeRecordParser, Resolvers{
|
||||
cidResolver: StrictResolver,
|
||||
oidResolver: StrictResolver,
|
||||
})
|
||||
|
||||
LockedParser = NewPrefixBucketParser(common.Locked, nil, Resolvers{
|
||||
cidResolver: LenientResolver,
|
||||
oidResolver: LenientResolver,
|
||||
})
|
||||
|
||||
ShardInfoParser = NewPrefixBucketParser(common.ShardInfo, ShardInfoRecordParser, Resolvers{
|
||||
cidResolver: StrictResolver,
|
||||
oidResolver: StrictResolver,
|
||||
})
|
||||
|
||||
PrimaryParser = NewPrefixContainerBucketParser(common.Primary, ObjectRecordParser, Resolvers{
|
||||
cidResolver: StrictResolver,
|
||||
oidResolver: LenientResolver,
|
||||
})
|
||||
|
||||
LockersParser = NewPrefixContainerBucketParser(common.Lockers, ObjectRecordParser, Resolvers{
|
||||
cidResolver: StrictResolver,
|
||||
oidResolver: LenientResolver,
|
||||
})
|
||||
|
||||
TombstoneParser = NewPrefixContainerBucketParser(common.Tombstone, ObjectRecordParser, Resolvers{
|
||||
cidResolver: StrictResolver,
|
||||
oidResolver: LenientResolver,
|
||||
})
|
||||
|
||||
SmallParser = NewPrefixContainerBucketParser(common.Small, nil, Resolvers{
|
||||
cidResolver: StrictResolver,
|
||||
oidResolver: LenientResolver,
|
||||
})
|
||||
|
||||
RootParser = NewPrefixContainerBucketParser(common.Root, nil, Resolvers{
|
||||
cidResolver: StrictResolver,
|
||||
oidResolver: LenientResolver,
|
||||
})
|
||||
|
||||
OwnerParser = NewPrefixContainerBucketParser(common.Owner, nil, Resolvers{
|
||||
cidResolver: StrictResolver,
|
||||
oidResolver: LenientResolver,
|
||||
})
|
||||
|
||||
UserAttributeParser = NewPrefixContainerKeyBucketParser(common.UserAttribute, nil, Resolvers{
|
||||
cidResolver: StrictResolver,
|
||||
oidResolver: LenientResolver,
|
||||
})
|
||||
|
||||
PayloadHashParser = NewPrefixContainerBucketParser(common.PayloadHash, PayloadHashRecordParser, Resolvers{
|
||||
cidResolver: StrictResolver,
|
||||
oidResolver: StrictResolver,
|
||||
})
|
||||
|
||||
ParentParser = NewPrefixContainerBucketParser(common.Parent, nil, Resolvers{
|
||||
cidResolver: StrictResolver,
|
||||
oidResolver: LenientResolver,
|
||||
})
|
||||
|
||||
SplitParser = NewPrefixContainerBucketParser(common.Split, nil, Resolvers{
|
||||
cidResolver: StrictResolver,
|
||||
oidResolver: StrictResolver,
|
||||
})
|
||||
|
||||
ContainerCountersParser = NewPrefixBucketParser(common.ContainerCounters, nil, Resolvers{
|
||||
cidResolver: StrictResolver,
|
||||
oidResolver: StrictResolver,
|
||||
})
|
||||
|
||||
ECInfoParser = NewPrefixContainerBucketParser(common.ECInfo, nil, Resolvers{
|
||||
cidResolver: StrictResolver,
|
||||
oidResolver: LenientResolver,
|
||||
})
|
||||
)
|
||||
|
||||
type (
|
||||
PrefixBucket struct {
|
||||
prefix common.Prefix
|
||||
resolvers Resolvers
|
||||
}
|
||||
|
||||
PrefixContainerBucket struct {
|
||||
prefix common.Prefix
|
||||
id cid.ID
|
||||
resolvers Resolvers
|
||||
}
|
||||
|
||||
PrefixContainerKeyBucket struct {
|
||||
prefix common.Prefix
|
||||
id cid.ID
|
||||
key string
|
||||
resolvers Resolvers
|
||||
}
|
||||
)
|
||||
|
||||
type SchemaEntry interface {
|
||||
String() string
|
||||
Filter(typ string, val any) FilterResult
|
||||
}
|
||||
|
||||
type Parser func(key, value []byte) (SchemaEntry, Parser, error)
|
||||
|
||||
func Any(parsers ...Parser) Parser {
|
||||
return func(key, value []byte) (SchemaEntry, Parser, error) {
|
||||
errs := fmt.Errorf("try parse %v %v", key, value)
|
||||
for _, p := range parsers {
|
||||
ret, next, err := p(key, value)
|
||||
if err == nil {
|
||||
return ret, next, nil
|
||||
}
|
||||
errs = errors.Join(errs, err)
|
||||
}
|
||||
return nil, nil, fmt.Errorf("no parser succeded: %w", errs)
|
||||
}
|
||||
}
|
||||
|
||||
type FilterResult int
|
||||
|
||||
const (
|
||||
Yes FilterResult = iota
|
||||
No
|
||||
Maybe
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNotBucket = errors.New("not a bucket")
|
||||
ErrNotRecord = errors.New("not a record")
|
||||
ErrInvalidKeyLength = errors.New("invalid key length")
|
||||
ErrInvalidValueLength = errors.New("invalid value length")
|
||||
ErrInvalidPrefix = errors.New("invalid prefix")
|
||||
)
|
||||
|
||||
func NewPrefixBucketParser(prefix common.Prefix, next Parser, resolvers Resolvers) Parser {
|
||||
return func(key, value []byte) (SchemaEntry, Parser, error) {
|
||||
if value != nil {
|
||||
return nil, nil, ErrNotBucket
|
||||
}
|
||||
if len(key) != 1 {
|
||||
return nil, nil, ErrInvalidKeyLength
|
||||
}
|
||||
var b PrefixBucket
|
||||
if b.prefix = common.Prefix(key[0]); b.prefix != prefix {
|
||||
return nil, nil, ErrInvalidPrefix
|
||||
}
|
||||
b.resolvers = resolvers
|
||||
return &b, next, nil
|
||||
}
|
||||
}
|
||||
|
||||
func NewPrefixContainerBucketParser(prefix common.Prefix, next Parser, resolvers Resolvers) Parser {
|
||||
return func(key, value []byte) (SchemaEntry, Parser, error) {
|
||||
if value != nil {
|
||||
return nil, nil, ErrNotBucket
|
||||
}
|
||||
if len(key) != 33 {
|
||||
return nil, nil, ErrInvalidKeyLength
|
||||
}
|
||||
var b PrefixContainerBucket
|
||||
if b.prefix = common.Prefix(key[0]); b.prefix != prefix {
|
||||
return nil, nil, ErrInvalidPrefix
|
||||
}
|
||||
if err := b.id.Decode(key[1:]); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
b.resolvers = resolvers
|
||||
return &b, next, nil
|
||||
}
|
||||
}
|
||||
|
||||
func NewPrefixContainerKeyBucketParser(prefix common.Prefix, next Parser, resolvers Resolvers) Parser {
|
||||
return func(key, value []byte) (SchemaEntry, Parser, error) {
|
||||
if value != nil {
|
||||
return nil, nil, ErrNotBucket
|
||||
}
|
||||
if len(key) < 34 {
|
||||
return nil, nil, ErrInvalidKeyLength
|
||||
}
|
||||
var b PrefixContainerKeyBucket
|
||||
if b.prefix = common.Prefix(key[0]); b.prefix != prefix {
|
||||
return nil, nil, ErrInvalidPrefix
|
||||
}
|
||||
if err := b.id.Decode(key[1:33]); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
b.key = string(key[33:])
|
||||
b.resolvers = resolvers
|
||||
return &b, next, nil
|
||||
}
|
||||
}
|
||||
|
||||
func IfThenElse(condition bool, onSuccess, onFailure FilterResult) FilterResult {
|
||||
if condition {
|
||||
return onSuccess
|
||||
} else {
|
||||
return onFailure
|
||||
}
|
||||
}
|
||||
|
||||
type FilterResolver = func(result bool) FilterResult
|
||||
|
||||
type Resolvers struct {
|
||||
cidResolver FilterResolver
|
||||
oidResolver FilterResolver
|
||||
}
|
||||
|
||||
var (
|
||||
StrictResolver = func(x bool) FilterResult { return IfThenElse(x, Yes, No) }
|
||||
LenientResolver = func(x bool) FilterResult { return IfThenElse(x, Yes, Maybe) }
|
||||
)
|
||||
|
||||
func (b *PrefixBucket) String() string {
|
||||
return b.prefix.String()
|
||||
}
|
||||
|
||||
func (b *PrefixBucket) Filter(typ string, val any) FilterResult {
|
||||
switch typ {
|
||||
case "cid":
|
||||
return b.resolvers.cidResolver(false)
|
||||
case "oid":
|
||||
return b.resolvers.oidResolver(false)
|
||||
default:
|
||||
return No
|
||||
}
|
||||
}
|
||||
|
||||
func (b *PrefixContainerBucket) String() string {
|
||||
return fmt.Sprintf("%s CID %s", b.prefix, b.id)
|
||||
}
|
||||
|
||||
func (b *PrefixContainerBucket) Filter(typ string, val any) FilterResult {
|
||||
switch typ {
|
||||
case "cid":
|
||||
id := val.(cid.ID)
|
||||
return b.resolvers.cidResolver(b.id.Equals(id))
|
||||
case "oid":
|
||||
return b.resolvers.oidResolver(false)
|
||||
default:
|
||||
return No
|
||||
}
|
||||
}
|
||||
|
||||
func (b *PrefixContainerKeyBucket) String() string {
|
||||
return fmt.Sprintf("%s CID %s %s", b.prefix, b.id, b.key)
|
||||
}
|
||||
|
||||
func (b *PrefixContainerKeyBucket) Filter(typ string, val any) FilterResult {
|
||||
switch typ {
|
||||
case "cid":
|
||||
id := val.(cid.ID)
|
||||
return b.resolvers.cidResolver(b.id.Equals(id))
|
||||
case "oid":
|
||||
return b.resolvers.oidResolver(false)
|
||||
default:
|
||||
return No
|
||||
}
|
||||
}
|
||||
|
|
277
cmd/frostfs-lens/internal/schema/types.go
Normal file
277
cmd/frostfs-lens/internal/schema/types.go
Normal file
|
@ -0,0 +1,277 @@
|
|||
package schema
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-lens/internal/schema/types/common"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/checksum"
|
||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
||||
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type Record interface {
|
||||
Decode(key []byte, val []byte) (err error)
|
||||
}
|
||||
|
||||
type (
|
||||
GraveyardRecord struct {
|
||||
object, tombstone oid.Address
|
||||
}
|
||||
|
||||
GarbageRecord struct {
|
||||
addr oid.Address
|
||||
}
|
||||
|
||||
ContainerVolumeRecord struct {
|
||||
id cid.ID
|
||||
volume uint64
|
||||
}
|
||||
|
||||
LockedRecord struct {
|
||||
id oid.ID
|
||||
ids []oid.ID
|
||||
}
|
||||
|
||||
ShardInfoRecord struct {
|
||||
label string
|
||||
value uint64
|
||||
}
|
||||
|
||||
ObjectRecord struct {
|
||||
id oid.ID
|
||||
object objectSDK.Object
|
||||
}
|
||||
|
||||
SmallRecord struct {
|
||||
id oid.ID
|
||||
storageID *string // optional
|
||||
}
|
||||
|
||||
RootRecord struct {
|
||||
id oid.ID
|
||||
info *objectSDK.SplitInfo // optional
|
||||
}
|
||||
|
||||
OwnerRecord struct {
|
||||
id oid.ID
|
||||
}
|
||||
|
||||
UserAttributeRecord struct {
|
||||
id oid.ID
|
||||
}
|
||||
|
||||
PayloadHashRecord struct {
|
||||
checksum checksum.Checksum
|
||||
ids []oid.ID
|
||||
}
|
||||
|
||||
ParentRecord struct {
|
||||
parent oid.ID
|
||||
ids []oid.ID
|
||||
}
|
||||
|
||||
SplitRecord struct {
|
||||
id uuid.UUID
|
||||
ids []oid.ID
|
||||
}
|
||||
|
||||
ContainerCountersRecord struct {
|
||||
logical, physical, user uint64
|
||||
}
|
||||
|
||||
ECInfoRecord struct {
|
||||
id oid.ID
|
||||
ids []oid.ID
|
||||
}
|
||||
)
|
||||
|
||||
func GraveyardRecordParser(key, value []byte) (SchemaEntry, Parser, error) {
|
||||
if len(key) != 64 {
|
||||
return nil, nil, ErrInvalidKeyLength
|
||||
}
|
||||
if len(value) != 64 {
|
||||
return nil, nil, ErrInvalidValueLength
|
||||
}
|
||||
var (
|
||||
cnr cid.ID
|
||||
obj oid.ID
|
||||
r GraveyardRecord
|
||||
)
|
||||
|
||||
_ = cnr.Decode(key[:32])
|
||||
_ = obj.Decode(key[32:])
|
||||
|
||||
r.object.SetContainer(cnr)
|
||||
r.object.SetObject(obj)
|
||||
|
||||
_ = cnr.Decode(value[:32])
|
||||
_ = obj.Decode(value[32:])
|
||||
|
||||
r.tombstone.SetContainer(cnr)
|
||||
r.tombstone.SetObject(obj)
|
||||
|
||||
return &r, nil, nil
|
||||
}
|
||||
|
||||
func GarbageRecordParser(key, value []byte) (SchemaEntry, Parser, error) {
|
||||
if len(key) != 64 {
|
||||
return nil, nil, ErrInvalidKeyLength
|
||||
}
|
||||
if len(value) != 0 {
|
||||
return nil, nil, ErrInvalidValueLength
|
||||
}
|
||||
var (
|
||||
cnr cid.ID
|
||||
obj oid.ID
|
||||
r GarbageRecord
|
||||
)
|
||||
|
||||
_ = cnr.Decode(key[:32])
|
||||
_ = obj.Decode(key[32:])
|
||||
|
||||
r.addr.SetContainer(cnr)
|
||||
r.addr.SetObject(obj)
|
||||
|
||||
return &r, nil, nil
|
||||
}
|
||||
|
||||
func ContainerVolumeRecordParser(key, value []byte) (SchemaEntry, Parser, error) {
|
||||
if len(key) != 32 {
|
||||
return nil, nil, ErrInvalidKeyLength
|
||||
}
|
||||
if len(value) != 8 {
|
||||
return nil, nil, ErrInvalidValueLength
|
||||
}
|
||||
var r ContainerVolumeRecord
|
||||
|
||||
_ = r.id.Decode(key)
|
||||
r.volume = binary.LittleEndian.Uint64(value)
|
||||
|
||||
return &r, nil, nil
|
||||
}
|
||||
|
||||
func ShardInfoRecordParser(key, value []byte) (SchemaEntry, Parser, error) {
|
||||
if len(key) == 0 {
|
||||
return nil, nil, ErrInvalidKeyLength
|
||||
}
|
||||
if len(value) != 8 {
|
||||
return nil, nil, ErrInvalidValueLength
|
||||
}
|
||||
var r ShardInfoRecord
|
||||
|
||||
r.label = string(key)
|
||||
r.value = binary.LittleEndian.Uint64(value)
|
||||
|
||||
return &r, nil, nil
|
||||
}
|
||||
|
||||
func ObjectRecordParser(key, value []byte) (SchemaEntry, Parser, error) {
|
||||
if len(key) != 32 {
|
||||
return nil, nil, ErrInvalidKeyLength
|
||||
}
|
||||
var r ObjectRecord
|
||||
|
||||
_ = r.id.Decode(key)
|
||||
if err := r.object.Unmarshal(value); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return &r, nil, nil
|
||||
}
|
||||
|
||||
func PayloadHashRecordParser(key, value []byte) (SchemaEntry, Parser, error) {
|
||||
if len(key) != 32 {
|
||||
return nil, nil, ErrInvalidKeyLength
|
||||
}
|
||||
var (
|
||||
err error
|
||||
r PayloadHashRecord
|
||||
)
|
||||
|
||||
r.checksum.SetSHA256([32]byte(key))
|
||||
if r.ids, err = common.DecodeOIDs(value); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return &r, nil, nil
|
||||
}
|
||||
|
||||
func (r *GraveyardRecord) String() string {
|
||||
return fmt.Sprintf("%s %s", r.object, r.tombstone)
|
||||
}
|
||||
|
||||
func (r *GraveyardRecord) Filter(typ string, val any) FilterResult {
|
||||
switch typ {
|
||||
case "cid":
|
||||
id := val.(cid.ID)
|
||||
return IfThenElse(r.object.Container().Equals(id), Yes, No)
|
||||
case "oid":
|
||||
id := val.(oid.ID)
|
||||
return IfThenElse(r.object.Object().Equals(id), Yes, No)
|
||||
default:
|
||||
return No
|
||||
}
|
||||
}
|
||||
|
||||
func (r *GarbageRecord) String() string {
|
||||
return r.addr.String()
|
||||
}
|
||||
|
||||
func (r *GarbageRecord) Filter(typ string, val any) FilterResult {
|
||||
switch typ {
|
||||
case "cid":
|
||||
id := val.(cid.ID)
|
||||
return IfThenElse(r.addr.Container().Equals(id), Yes, No)
|
||||
case "oid":
|
||||
id := val.(oid.ID)
|
||||
return IfThenElse(r.addr.Object().Equals(id), Yes, No)
|
||||
default:
|
||||
return No
|
||||
}
|
||||
}
|
||||
|
||||
func (r *ContainerVolumeRecord) String() string {
|
||||
return fmt.Sprintf("%s %d", r.id, r.volume)
|
||||
}
|
||||
|
||||
func (r *ContainerVolumeRecord) Filter(typ string, val any) FilterResult {
|
||||
switch typ {
|
||||
case "cid":
|
||||
id := val.(cid.ID)
|
||||
return IfThenElse(r.id.Equals(id), Yes, No)
|
||||
default:
|
||||
return No
|
||||
}
|
||||
}
|
||||
|
||||
func (r *ShardInfoRecord) String() string {
|
||||
return fmt.Sprintf("%s %d", r.label, r.value)
|
||||
}
|
||||
|
||||
func (r *ShardInfoRecord) Filter(_ string, _ any) FilterResult {
|
||||
return No
|
||||
}
|
||||
|
||||
func (r *ObjectRecord) String() string {
|
||||
return fmt.Sprintf("%s %+v", r.id, r.object)
|
||||
}
|
||||
|
||||
func (r *ObjectRecord) Filter(typ string, val any) FilterResult {
|
||||
switch typ {
|
||||
case "oid":
|
||||
id := val.(oid.ID)
|
||||
return IfThenElse(r.id.Equals(id), Yes, No)
|
||||
default:
|
||||
return No
|
||||
}
|
||||
}
|
||||
|
||||
func (r *PayloadHashRecord) String() string {
|
||||
return fmt.Sprintf("%s [...]", r.checksum)
|
||||
}
|
||||
|
||||
func (r *PayloadHashRecord) Filter(_ string, _ any) FilterResult {
|
||||
return No
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
package bucket
|
||||
|
||||
import (
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-lens/internal/schema/types/filter"
|
||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
)
|
||||
|
||||
var (
|
||||
_ (filter.HasCID) = (*Object)(nil)
|
||||
_ (filter.HasCID) = (*Small)(nil)
|
||||
_ (filter.HasCID) = (*Root)(nil)
|
||||
_ (filter.HasCID) = (*PayloadHash)(nil)
|
||||
_ (filter.HasCID) = (*Parent)(nil)
|
||||
_ (filter.HasCID) = (*Split)(nil)
|
||||
_ (filter.HasCID) = (*ECInfo)(nil)
|
||||
)
|
||||
|
||||
func (b *Object) HasCID(id cid.ID) bool {
|
||||
return b.id.Equals(id)
|
||||
}
|
||||
|
||||
func (b *Small) HasCID(id cid.ID) bool {
|
||||
return b.id.Equals(id)
|
||||
}
|
||||
|
||||
func (b *Root) HasCID(id cid.ID) bool {
|
||||
return b.id.Equals(id)
|
||||
}
|
||||
|
||||
func (b *PayloadHash) HasCID(id cid.ID) bool {
|
||||
return b.id.Equals(id)
|
||||
}
|
||||
|
||||
func (b *Parent) HasCID(id cid.ID) bool {
|
||||
return b.id.Equals(id)
|
||||
}
|
||||
|
||||
func (b *Split) HasCID(id cid.ID) bool {
|
||||
return b.id.Equals(id)
|
||||
}
|
||||
|
||||
func (b *ECInfo) HasCID(id cid.ID) bool {
|
||||
return b.id.Equals(id)
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
package bucket
|
||||
|
||||
import "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-lens/internal/schema/types/common"
|
||||
|
||||
func (b *Graveyard) String() string {
|
||||
return b.prefix.String()
|
||||
}
|
||||
|
||||
func (b *Garbage) String() string {
|
||||
return b.prefix.String()
|
||||
}
|
||||
|
||||
func (b *ContainerVolume) String() string {
|
||||
return b.prefix.String()
|
||||
}
|
||||
|
||||
func (b *Locked) String() string {
|
||||
return b.prefix.String()
|
||||
}
|
||||
|
||||
func (b *LockedSubbucket) String() string {
|
||||
return b.id.String()
|
||||
}
|
||||
|
||||
func (b *ShardInfo) String() string {
|
||||
return b.prefix.String()
|
||||
}
|
||||
|
||||
func (b *Object) String() string {
|
||||
return common.JoinWithSpace(b.prefix, b.id)
|
||||
}
|
||||
|
||||
func (b *Small) String() string {
|
||||
return common.JoinWithSpace(b.prefix, b.id)
|
||||
}
|
||||
|
||||
func (b *Root) String() string {
|
||||
return common.JoinWithSpace(b.prefix, b.id)
|
||||
}
|
||||
|
||||
func (b *Owner) String() string {
|
||||
return common.JoinWithSpace(b.prefix, b.id)
|
||||
}
|
||||
|
||||
func (b *OwnerSubbucket) String() string {
|
||||
return b.id.String()
|
||||
}
|
||||
|
||||
func (b *Attribute) String() string {
|
||||
return common.JoinWithSpace(b.prefix, b.id, b.key)
|
||||
}
|
||||
|
||||
func (b *AttributeSubbucket) String() string {
|
||||
return b.val
|
||||
}
|
||||
|
||||
func (b *PayloadHash) String() string {
|
||||
return common.JoinWithSpace(b.prefix, b.id)
|
||||
}
|
||||
|
||||
func (b *Parent) String() string {
|
||||
return common.JoinWithSpace(b.prefix, b.id)
|
||||
}
|
||||
|
||||
func (b *Split) String() string {
|
||||
return common.JoinWithSpace(b.prefix, b.id)
|
||||
}
|
||||
|
||||
func (b *ContainerCounters) String() string {
|
||||
return b.prefix.String()
|
||||
}
|
||||
|
||||
func (b *ECInfo) String() string {
|
||||
return common.JoinWithSpace(b.prefix, b.id)
|
||||
}
|
|
@ -1,322 +0,0 @@
|
|||
package bucket
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-lens/internal/schema/types/common"
|
||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
||||
"github.com/mr-tron/base58"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidLength = errors.New("invalid name length")
|
||||
ErrInvalidPrefix = errors.New("invalid name prefix")
|
||||
)
|
||||
|
||||
type (
|
||||
Graveyard struct {
|
||||
prefix common.Prefix
|
||||
}
|
||||
|
||||
Garbage struct {
|
||||
prefix common.Prefix
|
||||
}
|
||||
|
||||
ContainerVolume struct {
|
||||
prefix common.Prefix
|
||||
}
|
||||
|
||||
Locked struct {
|
||||
prefix common.Prefix
|
||||
}
|
||||
|
||||
LockedSubbucket struct {
|
||||
id cid.ID
|
||||
}
|
||||
|
||||
ShardInfo struct {
|
||||
prefix common.Prefix
|
||||
}
|
||||
|
||||
Object struct {
|
||||
prefix common.Prefix
|
||||
id cid.ID
|
||||
}
|
||||
|
||||
Small struct {
|
||||
prefix common.Prefix
|
||||
id cid.ID
|
||||
}
|
||||
|
||||
Root struct {
|
||||
prefix common.Prefix
|
||||
id cid.ID
|
||||
}
|
||||
|
||||
Owner struct {
|
||||
prefix common.Prefix
|
||||
id cid.ID
|
||||
}
|
||||
|
||||
OwnerSubbucket struct {
|
||||
id user.ID
|
||||
}
|
||||
|
||||
Attribute struct {
|
||||
prefix common.Prefix
|
||||
id cid.ID
|
||||
key string
|
||||
}
|
||||
|
||||
AttributeSubbucket struct {
|
||||
val string
|
||||
}
|
||||
|
||||
PayloadHash struct {
|
||||
prefix common.Prefix
|
||||
id cid.ID
|
||||
}
|
||||
|
||||
Parent struct {
|
||||
prefix common.Prefix
|
||||
id cid.ID
|
||||
}
|
||||
|
||||
Split struct {
|
||||
prefix common.Prefix
|
||||
id cid.ID
|
||||
}
|
||||
|
||||
ContainerCounters struct {
|
||||
prefix common.Prefix
|
||||
}
|
||||
|
||||
ECInfo struct {
|
||||
prefix common.Prefix
|
||||
id cid.ID
|
||||
}
|
||||
)
|
||||
|
||||
func (b *Graveyard) Decode(name, _ []byte) (err error) {
|
||||
if len(name) != 1 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
|
||||
if b.prefix = common.Prefix(name[0]); b.prefix != common.Graveyard {
|
||||
return ErrInvalidPrefix
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Garbage) Decode(name, _ []byte) (err error) {
|
||||
if len(name) != 1 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
|
||||
if b.prefix = common.Prefix(name[0]); b.prefix != common.Garbage {
|
||||
return ErrInvalidPrefix
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *ContainerVolume) Decode(name, _ []byte) (err error) {
|
||||
if len(name) != 1 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
|
||||
if b.prefix = common.Prefix(name[0]); b.prefix != common.ContainerVolume {
|
||||
return ErrInvalidPrefix
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Locked) Decode(name, _ []byte) (err error) {
|
||||
if len(name) != 1 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
|
||||
if b.prefix = common.Prefix(name[0]); b.prefix != common.Locked {
|
||||
return ErrInvalidPrefix
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *LockedSubbucket) Decode(name, _ []byte) (err error) {
|
||||
if len(name) != 32 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
|
||||
if err = b.id.Decode(name); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *ShardInfo) Decode(name, _ []byte) (err error) {
|
||||
if len(name) != 1 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
|
||||
if b.prefix = common.Prefix(name[0]); b.prefix != common.ShardInfo {
|
||||
return ErrInvalidPrefix
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Object) Decode(name, _ []byte) (err error) {
|
||||
if len(name) != 33 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
|
||||
switch b.prefix = common.Prefix(name[0]); b.prefix {
|
||||
case common.Primary:
|
||||
case common.Lockers:
|
||||
case common.Tombstone:
|
||||
default:
|
||||
return ErrInvalidPrefix
|
||||
}
|
||||
if err = b.id.Decode(name[1:]); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Small) Decode(name, _ []byte) (err error) {
|
||||
if len(name) != 33 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
|
||||
if b.prefix = common.Prefix(name[0]); b.prefix != common.Small {
|
||||
return ErrInvalidPrefix
|
||||
}
|
||||
if err = b.id.Decode(name[1:]); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Root) Decode(name, _ []byte) (err error) {
|
||||
if len(name) != 33 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
|
||||
if b.prefix = common.Prefix(name[0]); b.prefix != common.Root {
|
||||
return ErrInvalidPrefix
|
||||
}
|
||||
if err = b.id.Decode(name[1:]); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Owner) Decode(name, _ []byte) (err error) {
|
||||
if len(name) != 33 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
|
||||
if b.prefix = common.Prefix(name[0]); b.prefix != common.Owner {
|
||||
return ErrInvalidPrefix
|
||||
}
|
||||
if err = b.id.Decode(name[1:]); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *OwnerSubbucket) Decode(name, _ []byte) (err error) {
|
||||
if err = b.id.DecodeString(base58.Encode(name)); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Attribute) Decode(name, _ []byte) (err error) {
|
||||
if len(name) < 34 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
|
||||
if b.prefix = common.Prefix(name[0]); b.prefix != common.UserAttribute {
|
||||
return ErrInvalidPrefix
|
||||
}
|
||||
if err = b.id.Decode(name[1:33]); err != nil {
|
||||
return err
|
||||
}
|
||||
b.key = string(name[33:])
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *AttributeSubbucket) Decode(name, _ []byte) (err error) {
|
||||
if len(name) == 0 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
b.val = string(name)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *PayloadHash) Decode(name, _ []byte) (err error) {
|
||||
if len(name) != 33 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
|
||||
if b.prefix = common.Prefix(name[0]); b.prefix != common.PayloadHash {
|
||||
return ErrInvalidPrefix
|
||||
}
|
||||
if err = b.id.Decode(name[1:]); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Parent) Decode(name, _ []byte) (err error) {
|
||||
if len(name) != 33 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
|
||||
if b.prefix = common.Prefix(name[0]); b.prefix != common.Parent {
|
||||
return ErrInvalidPrefix
|
||||
}
|
||||
if err = b.id.Decode(name[1:]); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Split) Decode(name, _ []byte) (err error) {
|
||||
if len(name) != 33 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
|
||||
if b.prefix = common.Prefix(name[0]); b.prefix != common.Split {
|
||||
return ErrInvalidPrefix
|
||||
}
|
||||
if err = b.id.Decode(name[1:]); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *ContainerCounters) Decode(name, _ []byte) (err error) {
|
||||
if len(name) != 1 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
|
||||
if b.prefix = common.Prefix(name[0]); b.prefix != common.ContainerCounters {
|
||||
return ErrInvalidPrefix
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *ECInfo) Decode(name, _ []byte) (err error) {
|
||||
if len(name) != 33 {
|
||||
return ErrInvalidLength
|
||||
}
|
||||
|
||||
if b.prefix = common.Prefix(name[0]); b.prefix != common.ECInfo {
|
||||
return ErrInvalidPrefix
|
||||
}
|
||||
if err = b.id.Decode(name[1:]); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
package common
|
||||
|
||||
type Result interface {
|
||||
String() string
|
||||
// DetailedString() string
|
||||
|
||||
Decode(key, value []byte) error
|
||||
}
|
||||
|
||||
func TryDecode[T Result](key, value []byte, x T) error {
|
||||
if err := x.Decode(key, value); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
package filter
|
||||
|
||||
import (
|
||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
||||
)
|
||||
|
||||
type HasCID interface {
|
||||
HasCID(id cid.ID) bool
|
||||
}
|
||||
|
||||
type HasOID interface {
|
||||
HasOID(id oid.ID) bool
|
||||
}
|
||||
|
||||
type HasAttrKey interface {
|
||||
HasAttrKey(key string) bool
|
||||
}
|
||||
|
||||
type HasAttrVal interface {
|
||||
HasAttrVal(val string) bool
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
package record
|
||||
|
||||
import (
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-lens/internal/schema/types/filter"
|
||||
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
||||
)
|
||||
|
||||
var _ (filter.HasOID) = (*Object)(nil)
|
||||
|
||||
func (r *Object) HasOID(id oid.ID) bool {
|
||||
return r.id.Equals(id)
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
package record
|
||||
|
||||
import "fmt"
|
||||
|
||||
func (r *Object) String() string {
|
||||
return r.id.String() + " | " + fmt.Sprintf("%v", r.object)
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
package record
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-lens/internal/schema/types/common"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/checksum"
|
||||
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
||||
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
||||
)
|
||||
|
||||
type Record interface {
|
||||
Decode(key []byte, val []byte) (err error)
|
||||
}
|
||||
|
||||
var (
|
||||
ErrInvalidKeyLength = errors.New("invalid key length")
|
||||
ErrInvalidValLength = errors.New("invalid value length")
|
||||
)
|
||||
|
||||
type (
|
||||
Object struct {
|
||||
id oid.ID
|
||||
object objectSDK.Object
|
||||
}
|
||||
|
||||
PayloadHash struct {
|
||||
checksum checksum.Checksum
|
||||
ids []oid.ID
|
||||
}
|
||||
)
|
||||
|
||||
func (r *Object) Decode(key []byte, val []byte) (err error) {
|
||||
if len(key) != 32 {
|
||||
return ErrInvalidKeyLength
|
||||
}
|
||||
|
||||
if err = r.id.Decode(key); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = r.object.Unmarshal(val); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *PayloadHash) Decode(key []byte, val []byte) (err error) {
|
||||
if len(key) != 32 {
|
||||
return ErrInvalidKeyLength
|
||||
}
|
||||
|
||||
r.checksum.SetSHA256([32]byte(key))
|
||||
if r.ids, err = common.DecodeOIDs(val); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -5,7 +5,6 @@ import (
|
|||
"fmt"
|
||||
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-lens/internal/schema"
|
||||
"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-lens/internal/schema/types/common"
|
||||
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
||||
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
|
@ -21,20 +20,22 @@ import (
|
|||
// 6E6b24qy32p3L3wjRSUEGNFHMxkUsaqj7udwWVKLzkU
|
||||
// 1GcnNjFnPof2YbPi2RBi3Sjy3qeR2cymc9BR6i9U2Kt
|
||||
|
||||
// 9wynaSKbhrkpQe7knLZvX8XQDW2hk3ZHJnjaLpXsWHtz
|
||||
// h9MW74svQ8hufDVcaAdyYiaSDZWeTEWo32aqKbTUqAu
|
||||
|
||||
type Bucket struct {
|
||||
name []byte
|
||||
path [][]byte
|
||||
|
||||
nextHandler schema.Handler
|
||||
result common.Result
|
||||
nextHandler schema.Parser
|
||||
result schema.SchemaEntry
|
||||
}
|
||||
|
||||
type Record struct {
|
||||
key []byte
|
||||
value []byte
|
||||
path [][]byte
|
||||
// nextHandler handlers.Handler
|
||||
result common.Result
|
||||
key []byte
|
||||
value []byte
|
||||
path [][]byte
|
||||
result schema.SchemaEntry
|
||||
}
|
||||
|
||||
type Application struct {
|
||||
|
|
|
@ -10,19 +10,23 @@ import (
|
|||
"github.com/rivo/tview"
|
||||
)
|
||||
|
||||
func (a *Application) newBucketsView(ctx context.Context, _ *cid.ID, _ *oid.ID) (tview.Primitive, error) {
|
||||
func (a *Application) newBucketsView(ctx context.Context, cnr *cid.ID, obj *oid.ID) (tview.Primitive, error) {
|
||||
tree := tview.NewTreeView()
|
||||
tree.
|
||||
SetBorder(true).
|
||||
SetTitle(a.db.Path())
|
||||
|
||||
// var filters []handlers.Filter
|
||||
// if cnr != nil {
|
||||
// filters = append(filters, handlers.WithCID(*cnr))
|
||||
// }
|
||||
// if obj != nil {
|
||||
// filters = append(filters, handlers.WithOID(*obj))
|
||||
// }
|
||||
pred := func(schema.SchemaEntry) schema.FilterResult {
|
||||
return schema.Yes
|
||||
}
|
||||
if cnr != nil && obj != nil {
|
||||
pred = func(x schema.SchemaEntry) schema.FilterResult {
|
||||
if x.Filter("cid", *cnr) == schema.No {
|
||||
return schema.No
|
||||
}
|
||||
return schema.Yes
|
||||
}
|
||||
}
|
||||
|
||||
handler := schema.Start()
|
||||
|
||||
|
@ -32,11 +36,7 @@ func (a *Application) newBucketsView(ctx context.Context, _ *cid.ID, _ *oid.ID)
|
|||
SetExpanded(true).
|
||||
SetReference(&Bucket{nextHandler: handler})
|
||||
|
||||
// if len(filters) == 0 {
|
||||
err := a.getChildren(ctx, root, true)
|
||||
// } else {
|
||||
// err = a.getChildren(ctx, root, false)
|
||||
// }
|
||||
_, err := a.getChildren(ctx, root, pred)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -51,14 +51,14 @@ func (a *Application) newBucketsView(ctx context.Context, _ *cid.ID, _ *oid.ID)
|
|||
|
||||
switch event.Key() {
|
||||
case tcell.KeyEnter:
|
||||
if node.IsExpanded() {
|
||||
node.ClearChildren()
|
||||
} else {
|
||||
if len(node.GetChildren()) == 0 {
|
||||
err := a.getChildren(ctx, node, true)
|
||||
a.stopOnErr(err)
|
||||
}
|
||||
}
|
||||
// if node.IsExpanded() {
|
||||
// node.ClearChildren()
|
||||
// } else {
|
||||
// if len(node.GetChildren()) == 0 {
|
||||
// err := a.getChildren(ctx, node, true)
|
||||
// a.stopOnErr(err)
|
||||
// }
|
||||
// }
|
||||
node.SetExpanded(!node.IsExpanded())
|
||||
case tcell.KeyTab:
|
||||
err := a.nav.Push(ctx, func(ctx context.Context) (tview.Primitive, error) {
|
||||
|
@ -76,7 +76,11 @@ func (a *Application) newBucketsView(ctx context.Context, _ *cid.ID, _ *oid.ID)
|
|||
return tree, nil
|
||||
}
|
||||
|
||||
func (a *Application) getChildren(ctx context.Context, parent *tview.TreeNode, lazy bool) error {
|
||||
func (a *Application) getChildren(
|
||||
ctx context.Context,
|
||||
parent *tview.TreeNode,
|
||||
pred func(schema.SchemaEntry) schema.FilterResult,
|
||||
) (any, error) {
|
||||
parentBucket := parent.GetReference().(*Bucket)
|
||||
|
||||
path := parentBucket.path
|
||||
|
@ -84,60 +88,35 @@ func (a *Application) getChildren(ctx context.Context, parent *tview.TreeNode, l
|
|||
|
||||
buffer, err := LoadBuckets(ctx, a.db, path)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for bucket := range buffer {
|
||||
res, err := handler(bucket.name, nil)
|
||||
// if errors.Is(err, handlers.ErrFilter) {
|
||||
// continue
|
||||
// }
|
||||
res, next, err := handler(bucket.name, nil)
|
||||
if err != nil {
|
||||
continue
|
||||
// return err
|
||||
return nil, err
|
||||
}
|
||||
bucket.nextHandler = res.Next
|
||||
bucket.result = res.Result
|
||||
|
||||
child := tview.NewTreeNode(res.Result.String())
|
||||
if pred(res) == schema.No {
|
||||
continue
|
||||
}
|
||||
|
||||
bucket.nextHandler = next
|
||||
bucket.result = res
|
||||
|
||||
child := tview.NewTreeNode(res.String())
|
||||
|
||||
child.SetSelectable(true)
|
||||
child.SetExpanded(false)
|
||||
child.SetReference(bucket)
|
||||
|
||||
if lazy {
|
||||
parent.AddChild(child)
|
||||
continue
|
||||
}
|
||||
// _, err = LoadRecords(ctx, a.db, bucket.path)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
|
||||
records, err := LoadRecords(ctx, a.db, bucket.path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
found := false
|
||||
for record := range records {
|
||||
_, err = res.Next(record.key, record.value)
|
||||
// if errors.Is(err, handlers.ErrFilter) {
|
||||
// continue
|
||||
// }
|
||||
if err != nil {
|
||||
continue
|
||||
// return err
|
||||
}
|
||||
found = true
|
||||
break
|
||||
}
|
||||
|
||||
err = a.getChildren(ctx, child, lazy)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if found || len(child.GetChildren()) != 0 {
|
||||
parent.AddChild(child)
|
||||
}
|
||||
parent.AddChild(child)
|
||||
}
|
||||
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ func (a *Application) newRecordsView(ctx context.Context, bkt *Bucket) (tview.Pr
|
|||
defer close(records)
|
||||
|
||||
for record := range temp {
|
||||
res, err := bkt.nextHandler(record.key, record.value)
|
||||
res, _, err := bkt.nextHandler(record.key, record.value)
|
||||
// if errors.Is(err, handlers.ErrFilter) {
|
||||
// continue
|
||||
// }
|
||||
|
@ -32,7 +32,7 @@ func (a *Application) newRecordsView(ctx context.Context, bkt *Bucket) (tview.Pr
|
|||
// return
|
||||
}
|
||||
// record.nextHandler = next
|
||||
record.result = res.Result
|
||||
record.result = res
|
||||
records <- record
|
||||
}
|
||||
}()
|
||||
|
|
Loading…
Reference in a new issue