package ops2 import ( "fmt" "io" "gitlink.org.cn/cloudream/common/pkgs/future" "gitlink.org.cn/cloudream/common/pkgs/logger" "gitlink.org.cn/cloudream/common/utils/io2" "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/ioswitch/dag" "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/ioswitch/exec" "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/ioswitchlrc" "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/storage/pool" stgtypes "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/storage/types" jcstypes "gitlink.org.cn/cloudream/jcs-pub/common/types" ) func init() { exec.UseOp[*BaseWrite]() exec.UseOp[*BaseRead]() exec.UseOp[*BaseReadDyn]() } type BaseRead struct { Output exec.VarID UserSpace jcstypes.UserSpaceDetail Path jcstypes.JPath Option stgtypes.OpenOption } func (o *BaseRead) Execute(ctx *exec.ExecContext, e *exec.Executor) error { logger. WithField("Output", o.Output). WithField("UserSpace", o.UserSpace). WithField("Path", o.Path). Debug("base read") defer logger.Debug("base read end") stgPool, err := exec.GetValueByType[*pool.Pool](ctx) if err != nil { return fmt.Errorf("getting storage pool: %w", err) } store, err := stgPool.GetBaseStore(&o.UserSpace) if err != nil { return fmt.Errorf("getting base store of storage %v: %w", o.UserSpace, err) } stream, err := store.Read(o.Path, o.Option) if err != nil { return fmt.Errorf("reading object %v: %w", o.Path, err) } fut := future.NewSetVoid() output := &exec.StreamValue{ Stream: io2.AfterReadClosed(stream, func(closer io.ReadCloser) { fut.SetVoid() }), } e.PutVar(o.Output, output) return fut.Wait(ctx.Context) } func (o *BaseRead) String() string { return fmt.Sprintf("PublicRead %v:%v -> %v", o.UserSpace, o.Path, o.Output) } type BaseReadDyn struct { UserSpace jcstypes.UserSpaceDetail Output exec.VarID Path exec.VarID Option stgtypes.OpenOption } func (o *BaseReadDyn) Execute(ctx *exec.ExecContext, e *exec.Executor) error { logger. WithField("Output", o.Output). WithField("UserSpace", o.UserSpace). WithField("Path", o.Path). Debug("base read") defer logger.Debug("base read end") stgPool, err := exec.GetValueByType[*pool.Pool](ctx) if err != nil { return fmt.Errorf("getting storage pool: %w", err) } path, err := exec.BindVar[*FileInfoValue](e, ctx.Context, o.Path) if err != nil { return err } store, err := stgPool.GetBaseStore(&o.UserSpace) if err != nil { return fmt.Errorf("getting base store of storage %v: %w", o.UserSpace, err) } stream, err := store.Read(path.Path, o.Option) if err != nil { return fmt.Errorf("reading object %v: %w", o.Path, err) } fut := future.NewSetVoid() output := &exec.StreamValue{ Stream: io2.AfterReadClosed(stream, func(closer io.ReadCloser) { fut.SetVoid() }), } e.PutVar(o.Output, output) return fut.Wait(ctx.Context) } func (o *BaseReadDyn) String() string { return fmt.Sprintf("BaseReadPathVar %v:%v -> %v", o.UserSpace, o.Path, o.Output) } type BaseWrite struct { Input exec.VarID UserSpace jcstypes.UserSpaceDetail Path jcstypes.JPath WriteResult exec.VarID Option stgtypes.WriteOption } func (o *BaseWrite) Execute(ctx *exec.ExecContext, e *exec.Executor) error { logger. WithField("Input", o.Input). Debugf("write file to base store") defer logger.Debugf("write file to base store finished") stgPool, err := exec.GetValueByType[*pool.Pool](ctx) if err != nil { return fmt.Errorf("getting storage pool: %w", err) } store, err := stgPool.GetBaseStore(&o.UserSpace) if err != nil { return fmt.Errorf("getting base store of storage %v: %w", o.UserSpace, err) } input, err := exec.BindVar[*exec.StreamValue](e, ctx.Context, o.Input) if err != nil { return err } defer input.Stream.Close() ret, err := store.Write(o.Path, input.Stream, o.Option) if err != nil { return err } e.PutVar(o.WriteResult, &FileInfoValue{ FileInfo: ret, }) return nil } func (o *BaseWrite) String() string { return fmt.Sprintf("PublicWrite %v -> %v:%v", o.Input, o.UserSpace, o.Path) } type BaseReadNode struct { dag.NodeBase From ioswitchlrc.From UserSpace jcstypes.UserSpaceDetail Path jcstypes.JPath Option stgtypes.OpenOption } func (b *GraphNodeBuilder) NewBaseRead(from ioswitchlrc.From, userSpace jcstypes.UserSpaceDetail, path jcstypes.JPath, opt stgtypes.OpenOption) *BaseReadNode { node := &BaseReadNode{ From: from, UserSpace: userSpace, Path: path, Option: opt, } b.AddNode(node) node.OutputStreams().Init(node, 1) return node } func (t *BaseReadNode) GetFrom() ioswitchlrc.From { return t.From } func (t *BaseReadNode) Output() dag.StreamOutputSlot { return dag.StreamOutputSlot{ Node: t, Index: 0, } } func (t *BaseReadNode) GenerateOp() (exec.Op, error) { return &BaseRead{ Output: t.Output().Var().VarID, UserSpace: t.UserSpace, Path: t.Path, Option: t.Option, }, nil } type BaseReadDynNode struct { dag.NodeBase From ioswitchlrc.From UserSpace jcstypes.UserSpaceDetail Option stgtypes.OpenOption } func (b *GraphNodeBuilder) NewBaseReadDyn(from ioswitchlrc.From, userSpace jcstypes.UserSpaceDetail, opt stgtypes.OpenOption) *BaseReadDynNode { node := &BaseReadDynNode{ From: from, UserSpace: userSpace, Option: opt, } b.AddNode(node) node.OutputStreams().Init(node, 1) node.InputValues().Init(1) return node } func (t *BaseReadDynNode) GetFrom() ioswitchlrc.From { return t.From } func (t *BaseReadDynNode) Output() dag.StreamOutputSlot { return dag.StreamOutputSlot{ Node: t, Index: 0, } } func (t *BaseReadDynNode) PathVar() dag.ValueInputSlot { return dag.ValueInputSlot{ Node: t, Index: 0, } } func (t *BaseReadDynNode) GenerateOp() (exec.Op, error) { return &BaseReadDyn{ UserSpace: t.UserSpace, Output: t.Output().Var().VarID, Path: t.PathVar().Var().VarID, Option: t.Option, }, nil } type BaseWriteNode struct { dag.NodeBase To ioswitchlrc.To UserSpace jcstypes.UserSpaceDetail Path jcstypes.JPath Option stgtypes.WriteOption } func (b *GraphNodeBuilder) NewBaseWrite(to ioswitchlrc.To, userSpace jcstypes.UserSpaceDetail, path jcstypes.JPath, opt stgtypes.WriteOption) *BaseWriteNode { node := &BaseWriteNode{ To: to, UserSpace: userSpace, Path: path, Option: opt, } b.AddNode(node) node.InputStreams().Init(1) node.OutputValues().Init(node, 1) return node } func (t *BaseWriteNode) GetTo() ioswitchlrc.To { return t.To } func (t *BaseWriteNode) Input() dag.StreamInputSlot { return dag.StreamInputSlot{ Node: t, Index: 0, } } func (t *BaseWriteNode) FileInfoVar() dag.ValueOutputSlot { return dag.ValueOutputSlot{ Node: t, Index: 0, } } func (t *BaseWriteNode) GenerateOp() (exec.Op, error) { return &BaseWrite{ Input: t.InputStreams().Get(0).VarID, UserSpace: t.UserSpace, Path: t.Path, WriteResult: t.FileInfoVar().Var().VarID, Option: t.Option, }, nil }