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.7 kB

1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. package ops2
  2. import (
  3. "fmt"
  4. "time"
  5. "gitlink.org.cn/cloudream/common/pkgs/ioswitch/dag"
  6. "gitlink.org.cn/cloudream/common/pkgs/ioswitch/exec"
  7. log "gitlink.org.cn/cloudream/common/pkgs/logger"
  8. cdssdk "gitlink.org.cn/cloudream/common/sdks/storage"
  9. stgmod "gitlink.org.cn/cloudream/storage/common/models"
  10. "gitlink.org.cn/cloudream/storage/common/pkgs/storage/factory"
  11. "gitlink.org.cn/cloudream/storage/common/pkgs/storage/svcmgr"
  12. "gitlink.org.cn/cloudream/storage/common/pkgs/storage/types"
  13. )
  14. func init() {
  15. exec.UseOp[*MultipartInitiator]()
  16. exec.UseOp[*MultipartUpload]()
  17. exec.UseVarValue[*MultipartUploadArgsValue]()
  18. exec.UseVarValue[*UploadedPartInfoValue]()
  19. }
  20. type MultipartUploadArgsValue struct {
  21. Key string
  22. InitState types.MultipartInitState
  23. }
  24. func (v *MultipartUploadArgsValue) Clone() exec.VarValue {
  25. return &MultipartUploadArgsValue{
  26. InitState: v.InitState,
  27. }
  28. }
  29. type UploadedPartInfoValue struct {
  30. types.UploadedPartInfo
  31. }
  32. func (v *UploadedPartInfoValue) Clone() exec.VarValue {
  33. return &UploadedPartInfoValue{
  34. UploadedPartInfo: v.UploadedPartInfo,
  35. }
  36. }
  37. type MultipartInitiator struct {
  38. StorageID cdssdk.StorageID
  39. UploadArgs exec.VarID
  40. UploadedParts []exec.VarID
  41. BypassFileOutput exec.VarID // 分片上传之后的临时文件的路径
  42. BypassCallback exec.VarID // 临时文件使用结果,用于告知Initiator如何处理临时文件
  43. }
  44. func (o *MultipartInitiator) Execute(ctx *exec.ExecContext, e *exec.Executor) error {
  45. stgMgr, err := exec.GetValueByType[*svcmgr.Manager](ctx)
  46. if err != nil {
  47. return err
  48. }
  49. tempStore, err := svcmgr.GetComponent[types.TempStore](stgMgr, o.StorageID)
  50. if err != nil {
  51. return err
  52. }
  53. objName := tempStore.CreateTemp()
  54. defer tempStore.Drop(objName)
  55. initiator, err := svcmgr.GetComponent[types.MultipartInitiator](stgMgr, o.StorageID)
  56. if err != nil {
  57. return err
  58. }
  59. // 启动一个新的上传任务
  60. initState, err := initiator.Initiate(ctx.Context, objName)
  61. if err != nil {
  62. return err
  63. }
  64. // 分发上传参数
  65. e.PutVar(o.UploadArgs, &MultipartUploadArgsValue{
  66. Key: objName,
  67. InitState: initState,
  68. })
  69. // 收集分片上传结果
  70. partInfoValues, err := exec.BindArray[*UploadedPartInfoValue](e, ctx.Context, o.UploadedParts)
  71. if err != nil {
  72. return fmt.Errorf("getting uploaded parts: %v", err)
  73. }
  74. partInfos := make([]types.UploadedPartInfo, len(partInfoValues))
  75. for i, v := range partInfoValues {
  76. partInfos[i] = v.UploadedPartInfo
  77. }
  78. // 完成分片上传
  79. compInfo, err := initiator.Complete(ctx.Context, partInfos)
  80. if err != nil {
  81. return fmt.Errorf("completing multipart upload: %v", err)
  82. }
  83. // 告知后续Op临时文件的路径
  84. e.PutVar(o.BypassFileOutput, &BypassFileInfoValue{
  85. BypassFileInfo: types.BypassFileInfo{
  86. TempFilePath: objName,
  87. FileHash: compInfo.FileHash,
  88. },
  89. })
  90. // 等待后续Op处理临时文件
  91. cb, err := exec.BindVar[*BypassHandleResultValue](e, ctx.Context, o.BypassCallback)
  92. if err != nil {
  93. return fmt.Errorf("getting temp file callback: %v", err)
  94. }
  95. if cb.Commited {
  96. tempStore.Commited(objName)
  97. }
  98. return nil
  99. }
  100. func (o *MultipartInitiator) String() string {
  101. return "MultipartInitiator"
  102. }
  103. type MultipartUpload struct {
  104. Storage stgmod.StorageDetail
  105. UploadArgs exec.VarID
  106. UploadResult exec.VarID
  107. PartStream exec.VarID
  108. PartNumber int
  109. PartSize int64
  110. }
  111. func (o *MultipartUpload) Execute(ctx *exec.ExecContext, e *exec.Executor) error {
  112. uploadArgs, err := exec.BindVar[*MultipartUploadArgsValue](e, ctx.Context, o.UploadArgs)
  113. if err == nil {
  114. return err
  115. }
  116. partStr, err := exec.BindVar[*exec.StreamValue](e, ctx.Context, o.PartStream)
  117. if err != nil {
  118. return err
  119. }
  120. defer partStr.Stream.Close()
  121. uploader, err := factory.CreateComponent[types.MultipartUploader](o.Storage)
  122. if err != nil {
  123. return err
  124. }
  125. startTime := time.Now()
  126. uploadedInfo, err := uploader.UploadPart(ctx.Context, uploadArgs.InitState, uploadArgs.Key, o.PartSize, o.PartNumber, partStr.Stream)
  127. log.Debugf("upload finished in %v", time.Since(startTime))
  128. if err != nil {
  129. return err
  130. }
  131. e.PutVar(o.UploadResult, &UploadedPartInfoValue{
  132. uploadedInfo,
  133. })
  134. return nil
  135. }
  136. func (o *MultipartUpload) String() string {
  137. return fmt.Sprintf("MultipartUpload[PartNumber=%v,PartSize=%v] Args: %v, Result: %v, Stream: %v", o.PartNumber, o.PartSize, o.UploadArgs, o.UploadResult, o.PartStream)
  138. }
  139. type MultipartInitiatorNode struct {
  140. dag.NodeBase
  141. StorageID cdssdk.StorageID `json:"storageID"`
  142. }
  143. func (b *GraphNodeBuilder) NewMultipartInitiator(storageID cdssdk.StorageID) *MultipartInitiatorNode {
  144. node := &MultipartInitiatorNode{
  145. StorageID: storageID,
  146. }
  147. b.AddNode(node)
  148. node.OutputValues().Init(node, 2)
  149. node.InputValues().Init(1)
  150. return node
  151. }
  152. func (n *MultipartInitiatorNode) UploadArgsVar() *dag.ValueVar {
  153. return n.OutputValues().Get(0)
  154. }
  155. func (n *MultipartInitiatorNode) BypassFileInfoVar() *dag.ValueVar {
  156. return n.OutputValues().Get(1)
  157. }
  158. func (n *MultipartInitiatorNode) BypassCallbackSlot() dag.ValueInputSlot {
  159. return dag.ValueInputSlot{
  160. Node: n,
  161. Index: 0,
  162. }
  163. }
  164. func (n *MultipartInitiatorNode) AppendPartInfoSlot() dag.ValueInputSlot {
  165. return dag.ValueInputSlot{
  166. Node: n,
  167. Index: n.InputStreams().EnlargeOne(),
  168. }
  169. }
  170. func (n *MultipartInitiatorNode) GenerateOp() (exec.Op, error) {
  171. return &MultipartInitiator{
  172. StorageID: n.StorageID,
  173. UploadArgs: n.UploadArgsVar().VarID,
  174. UploadedParts: n.InputValues().GetVarIDsStart(1),
  175. BypassFileOutput: n.BypassFileInfoVar().VarID,
  176. BypassCallback: n.BypassCallbackSlot().Var().VarID,
  177. }, nil
  178. }
  179. type MultipartUploadNode struct {
  180. dag.NodeBase
  181. Storage stgmod.StorageDetail
  182. PartNumber int
  183. PartSize int64
  184. }
  185. func (b *GraphNodeBuilder) NewMultipartUpload(stg stgmod.StorageDetail, partNumber int, partSize int64) *MultipartUploadNode {
  186. node := &MultipartUploadNode{
  187. Storage: stg,
  188. PartNumber: partNumber,
  189. PartSize: partSize,
  190. }
  191. b.AddNode(node)
  192. node.InputValues().Init(1)
  193. node.OutputValues().Init(node, 1)
  194. node.InputStreams().Init(1)
  195. return node
  196. }
  197. func (n *MultipartUploadNode) UploadArgsSlot() dag.ValueInputSlot {
  198. return dag.ValueInputSlot{
  199. Node: n,
  200. Index: 0,
  201. }
  202. }
  203. func (n *MultipartUploadNode) UploadResultVar() *dag.ValueVar {
  204. return n.OutputValues().Get(0)
  205. }
  206. func (n *MultipartUploadNode) PartStreamSlot() dag.ValueInputSlot {
  207. return dag.ValueInputSlot{
  208. Node: n,
  209. Index: 0,
  210. }
  211. }
  212. func (n *MultipartUploadNode) GenerateOp() (exec.Op, error) {
  213. return &MultipartUpload{
  214. Storage: n.Storage,
  215. UploadArgs: n.UploadArgsSlot().Var().VarID,
  216. UploadResult: n.UploadResultVar().VarID,
  217. PartStream: n.PartStreamSlot().Var().VarID,
  218. PartNumber: n.PartNumber,
  219. PartSize: n.PartSize,
  220. }, nil
  221. }

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