You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

multipart.go 6.1 kB

10 months ago
10 months ago
10 months ago
10 months ago
1 year ago
10 months ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. package ops2
  2. import (
  3. "fmt"
  4. "time"
  5. log "gitlink.org.cn/cloudream/common/pkgs/logger"
  6. "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/ioswitch/dag"
  7. "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/ioswitch/exec"
  8. "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/storage/pool"
  9. stgtypes "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/storage/types"
  10. jcstypes "gitlink.org.cn/cloudream/jcs-pub/common/types"
  11. )
  12. func init() {
  13. exec.UseOp[*MultipartInitiator]()
  14. exec.UseOp[*MultipartUpload]()
  15. exec.UseVarValue[*MultipartUploadArgsValue]()
  16. exec.UseVarValue[*UploadedPartInfoValue]()
  17. }
  18. type MultipartUploadArgsValue struct {
  19. InitState stgtypes.MultipartInitState
  20. }
  21. func (v *MultipartUploadArgsValue) Clone() exec.VarValue {
  22. return &MultipartUploadArgsValue{
  23. InitState: v.InitState,
  24. }
  25. }
  26. type UploadedPartInfoValue struct {
  27. stgtypes.UploadedPartInfo
  28. }
  29. func (v *UploadedPartInfoValue) Clone() exec.VarValue {
  30. return &UploadedPartInfoValue{
  31. UploadedPartInfo: v.UploadedPartInfo,
  32. }
  33. }
  34. type MultipartInitiator struct {
  35. UserSpace jcstypes.UserSpaceDetail
  36. UploadArgs exec.VarID
  37. UploadedParts []exec.VarID
  38. FileOutput exec.VarID // 分片上传之后的临时文件的路径
  39. }
  40. func (o *MultipartInitiator) Execute(ctx *exec.ExecContext, e *exec.Executor) error {
  41. stgPool, err := exec.GetValueByType[*pool.Pool](ctx)
  42. if err != nil {
  43. return fmt.Errorf("getting storage pool: %w", err)
  44. }
  45. multi, err := stgPool.GetMultiparter(&o.UserSpace)
  46. if err != nil {
  47. return err
  48. }
  49. // 启动一个新的上传任务W
  50. multiTask, err := multi.Initiate(ctx.Context)
  51. if err != nil {
  52. return err
  53. }
  54. defer multiTask.Close()
  55. // 分发上传参数
  56. e.PutVar(o.UploadArgs, &MultipartUploadArgsValue{
  57. InitState: multiTask.InitState(),
  58. })
  59. // 收集分片上传结果
  60. partInfoValues, err := exec.BindArray[*UploadedPartInfoValue](e, ctx.Context, o.UploadedParts)
  61. if err != nil {
  62. return fmt.Errorf("getting uploaded parts: %v", err)
  63. }
  64. partInfos := make([]stgtypes.UploadedPartInfo, len(partInfoValues))
  65. for i, v := range partInfoValues {
  66. partInfos[i] = v.UploadedPartInfo
  67. }
  68. // 合并分片
  69. fileInfo, err := multiTask.JoinParts(ctx.Context, partInfos)
  70. if err != nil {
  71. return fmt.Errorf("completing multipart upload: %v", err)
  72. }
  73. // 告知后续Op临时文件的路径
  74. e.PutVar(o.FileOutput, &FileInfoValue{
  75. FileInfo: fileInfo,
  76. })
  77. return nil
  78. }
  79. func (o *MultipartInitiator) String() string {
  80. return fmt.Sprintf("MultipartInitiator Args: %v, Parts: %v, BypassFileOutput: %v", o.UploadArgs, o.UploadedParts, o.FileOutput)
  81. }
  82. type MultipartUpload struct {
  83. UserSpace jcstypes.UserSpaceDetail
  84. UploadArgs exec.VarID
  85. UploadResult exec.VarID
  86. PartStream exec.VarID
  87. PartNumber int
  88. PartSize int64
  89. }
  90. func (o *MultipartUpload) Execute(ctx *exec.ExecContext, e *exec.Executor) error {
  91. stgPool, err := exec.GetValueByType[*pool.Pool](ctx)
  92. if err != nil {
  93. return fmt.Errorf("getting storage pool: %w", err)
  94. }
  95. uploadArgs, err := exec.BindVar[*MultipartUploadArgsValue](e, ctx.Context, o.UploadArgs)
  96. if err != nil {
  97. return err
  98. }
  99. partStr, err := exec.BindVar[*exec.StreamValue](e, ctx.Context, o.PartStream)
  100. if err != nil {
  101. return err
  102. }
  103. defer partStr.Stream.Close()
  104. multi, err := stgPool.GetMultiparter(&o.UserSpace)
  105. if err != nil {
  106. return err
  107. }
  108. startTime := time.Now()
  109. uploadedInfo, err := multi.UploadPart(ctx.Context, uploadArgs.InitState, o.PartSize, o.PartNumber, partStr.Stream)
  110. if err != nil {
  111. return err
  112. }
  113. log.Debugf("upload finished in %v", time.Since(startTime))
  114. e.PutVar(o.UploadResult, &UploadedPartInfoValue{
  115. uploadedInfo,
  116. })
  117. return nil
  118. }
  119. func (o *MultipartUpload) String() string {
  120. return fmt.Sprintf("MultipartUpload[PartNumber=%v,PartSize=%v] Args: %v, Result: %v, Stream: %v", o.PartNumber, o.PartSize, o.UploadArgs, o.UploadResult, o.PartStream)
  121. }
  122. type MultipartInitiatorNode struct {
  123. dag.NodeBase
  124. UserSpace jcstypes.UserSpaceDetail
  125. }
  126. func (b *GraphNodeBuilder) NewMultipartInitiator(userSpace jcstypes.UserSpaceDetail) *MultipartInitiatorNode {
  127. node := &MultipartInitiatorNode{
  128. UserSpace: userSpace,
  129. }
  130. b.AddNode(node)
  131. node.OutputValues().Init(node, 2)
  132. return node
  133. }
  134. func (n *MultipartInitiatorNode) UploadArgsVar() dag.ValueOutputSlot {
  135. return dag.ValueOutputSlot{
  136. Node: n,
  137. Index: 0,
  138. }
  139. }
  140. func (n *MultipartInitiatorNode) FileInfoVar() dag.ValueOutputSlot {
  141. return dag.ValueOutputSlot{
  142. Node: n,
  143. Index: 1,
  144. }
  145. }
  146. func (n *MultipartInitiatorNode) PartInfoSlot() dag.ValueInputSlot {
  147. return dag.ValueInputSlot{
  148. Node: n,
  149. Index: n.InputValues().EnlargeOne(),
  150. }
  151. }
  152. func (n *MultipartInitiatorNode) GenerateOp() (exec.Op, error) {
  153. return &MultipartInitiator{
  154. UserSpace: n.UserSpace,
  155. UploadArgs: n.UploadArgsVar().Var().VarID,
  156. UploadedParts: n.InputValues().GetVarIDs(),
  157. FileOutput: n.FileInfoVar().Var().VarID,
  158. }, nil
  159. }
  160. type MultipartUploadNode struct {
  161. dag.NodeBase
  162. UserSpace jcstypes.UserSpaceDetail
  163. PartNumber int
  164. PartSize int64
  165. }
  166. func (b *GraphNodeBuilder) NewMultipartUpload(userSpace jcstypes.UserSpaceDetail, partNumber int, partSize int64) *MultipartUploadNode {
  167. node := &MultipartUploadNode{
  168. UserSpace: userSpace,
  169. PartNumber: partNumber,
  170. PartSize: partSize,
  171. }
  172. b.AddNode(node)
  173. node.InputValues().Init(1)
  174. node.OutputValues().Init(node, 1)
  175. node.InputStreams().Init(1)
  176. return node
  177. }
  178. func (n *MultipartUploadNode) UploadArgsSlot() dag.ValueInputSlot {
  179. return dag.ValueInputSlot{
  180. Node: n,
  181. Index: 0,
  182. }
  183. }
  184. func (n *MultipartUploadNode) UploadResultVar() dag.ValueOutputSlot {
  185. return dag.ValueOutputSlot{
  186. Node: n,
  187. Index: 0,
  188. }
  189. }
  190. func (n *MultipartUploadNode) PartStreamSlot() dag.StreamInputSlot {
  191. return dag.StreamInputSlot{
  192. Node: n,
  193. Index: 0,
  194. }
  195. }
  196. func (n *MultipartUploadNode) GenerateOp() (exec.Op, error) {
  197. return &MultipartUpload{
  198. UserSpace: n.UserSpace,
  199. UploadArgs: n.UploadArgsSlot().Var().VarID,
  200. UploadResult: n.UploadResultVar().Var().VarID,
  201. PartStream: n.PartStreamSlot().Var().VarID,
  202. PartNumber: n.PartNumber,
  203. PartSize: n.PartSize,
  204. }, nil
  205. }

本项目旨在将云际存储公共基础设施化,使个人及企业可低门槛使用高效的云际存储服务(安装开箱即用云际存储客户端即可,无需关注其他组件的部署),同时支持用户灵活便捷定制云际存储的功能细节。