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.

io.go 6.2 kB

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. package grpc
  2. import (
  3. "context"
  4. "fmt"
  5. "io"
  6. "time"
  7. "gitlink.org.cn/cloudream/common/pkgs/logger"
  8. "gitlink.org.cn/cloudream/common/utils/io2"
  9. "gitlink.org.cn/cloudream/common/utils/serder"
  10. agtrpc "gitlink.org.cn/cloudream/storage/common/pkgs/grpc/agent"
  11. "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch"
  12. )
  13. func (s *Service) ExecuteIOPlan(ctx context.Context, req *agtrpc.ExecuteIOPlanReq) (*agtrpc.ExecuteIOPlanResp, error) {
  14. plan, err := serder.JSONToObjectEx[ioswitch.Plan]([]byte(req.Plan))
  15. if err != nil {
  16. return nil, fmt.Errorf("deserializing plan: %w", err)
  17. }
  18. logger.WithField("PlanID", plan.ID).Infof("begin execute io plan")
  19. defer logger.WithField("PlanID", plan.ID).Infof("plan finished")
  20. sw := ioswitch.NewSwitch(plan)
  21. s.swMgr.Add(sw)
  22. defer s.swMgr.Remove(sw)
  23. err = sw.Run(ctx)
  24. if err != nil {
  25. return nil, fmt.Errorf("running io plan: %w", err)
  26. }
  27. return &agtrpc.ExecuteIOPlanResp{}, nil
  28. }
  29. func (s *Service) SendStream(server agtrpc.Agent_SendStreamServer) error {
  30. msg, err := server.Recv()
  31. if err != nil {
  32. return fmt.Errorf("recving stream id packet: %w", err)
  33. }
  34. if msg.Type != agtrpc.StreamDataPacketType_SendArgs {
  35. return fmt.Errorf("first packet must be a SendArgs packet")
  36. }
  37. logger.
  38. WithField("PlanID", msg.PlanID).
  39. WithField("VarID", msg.VarID).
  40. Debugf("receive stream")
  41. // 同一批Plan中每个节点的Plan的启动时间有先后,但最多不应该超过30秒
  42. ctx, cancel := context.WithTimeout(server.Context(), time.Second*30)
  43. defer cancel()
  44. sw := s.swMgr.FindByIDContexted(ctx, ioswitch.PlanID(msg.PlanID))
  45. if sw == nil {
  46. return fmt.Errorf("plan not found")
  47. }
  48. pr, pw := io.Pipe()
  49. varID := ioswitch.VarID(msg.VarID)
  50. sw.PutVars(&ioswitch.StreamVar{
  51. ID: varID,
  52. Stream: pr,
  53. })
  54. // 然后读取文件数据
  55. var recvSize int64
  56. for {
  57. msg, err := server.Recv()
  58. // 读取客户端数据失败
  59. // 即使err是io.EOF,只要没有收到客户端包含EOF数据包就被断开了连接,就认为接收失败
  60. if err != nil {
  61. // 关闭文件写入
  62. pw.CloseWithError(io.ErrClosedPipe)
  63. logger.WithField("ReceiveSize", recvSize).
  64. WithField("VarID", varID).
  65. Warnf("recv message failed, err: %s", err.Error())
  66. return fmt.Errorf("recv message failed, err: %w", err)
  67. }
  68. err = io2.WriteAll(pw, msg.Data)
  69. if err != nil {
  70. // 关闭文件写入
  71. pw.CloseWithError(io.ErrClosedPipe)
  72. logger.Warnf("write data to file failed, err: %s", err.Error())
  73. return fmt.Errorf("write data to file failed, err: %w", err)
  74. }
  75. recvSize += int64(len(msg.Data))
  76. if msg.Type == agtrpc.StreamDataPacketType_EOF {
  77. // 客户端明确说明文件传输已经结束,那么结束写入,获得文件Hash
  78. err := pw.Close()
  79. if err != nil {
  80. logger.Warnf("finish writing failed, err: %s", err.Error())
  81. return fmt.Errorf("finish writing failed, err: %w", err)
  82. }
  83. // 并将结果返回到客户端
  84. err = server.SendAndClose(&agtrpc.SendStreamResp{})
  85. if err != nil {
  86. logger.Warnf("send response failed, err: %s", err.Error())
  87. return fmt.Errorf("send response failed, err: %w", err)
  88. }
  89. return nil
  90. }
  91. }
  92. }
  93. func (s *Service) GetStream(req *agtrpc.GetStreamReq, server agtrpc.Agent_GetStreamServer) error {
  94. logger.
  95. WithField("PlanID", req.PlanID).
  96. WithField("VarID", req.VarID).
  97. Debugf("send stream")
  98. // 同上
  99. ctx, cancel := context.WithTimeout(server.Context(), time.Second*30)
  100. defer cancel()
  101. sw := s.swMgr.FindByIDContexted(ctx, ioswitch.PlanID(req.PlanID))
  102. if sw == nil {
  103. return fmt.Errorf("plan not found")
  104. }
  105. strVar := &ioswitch.StreamVar{
  106. ID: ioswitch.VarID(req.VarID),
  107. }
  108. err := sw.BindVars(server.Context(), strVar)
  109. if err != nil {
  110. return fmt.Errorf("binding vars: %w", err)
  111. }
  112. reader := strVar.Stream
  113. defer reader.Close()
  114. buf := make([]byte, 1024*64)
  115. readAllCnt := 0
  116. for {
  117. readCnt, err := reader.Read(buf)
  118. if readCnt > 0 {
  119. readAllCnt += readCnt
  120. err = server.Send(&agtrpc.StreamDataPacket{
  121. Type: agtrpc.StreamDataPacketType_Data,
  122. Data: buf[:readCnt],
  123. })
  124. if err != nil {
  125. logger.
  126. WithField("PlanID", req.PlanID).
  127. WithField("VarID", req.VarID).
  128. Warnf("send stream data failed, err: %s", err.Error())
  129. return fmt.Errorf("send stream data failed, err: %w", err)
  130. }
  131. }
  132. // 文件读取完毕
  133. if err == io.EOF {
  134. logger.
  135. WithField("PlanID", req.PlanID).
  136. WithField("VarID", req.VarID).
  137. Debugf("send data size %d", readAllCnt)
  138. // 发送EOF消息
  139. server.Send(&agtrpc.StreamDataPacket{
  140. Type: agtrpc.StreamDataPacketType_EOF,
  141. })
  142. return nil
  143. }
  144. // io.ErrUnexpectedEOF没有读满整个buf就遇到了EOF,此时正常发送剩余数据即可。除了这两个错误之外,其他错误都中断操作
  145. if err != nil && err != io.ErrUnexpectedEOF {
  146. logger.
  147. WithField("PlanID", req.PlanID).
  148. WithField("VarID", req.VarID).
  149. Warnf("reading stream data: %s", err.Error())
  150. return fmt.Errorf("reading stream data: %w", err)
  151. }
  152. }
  153. }
  154. func (s *Service) SendVar(ctx context.Context, req *agtrpc.SendVarReq) (*agtrpc.SendVarResp, error) {
  155. ctx, cancel := context.WithTimeout(ctx, time.Second*30)
  156. defer cancel()
  157. sw := s.swMgr.FindByIDContexted(ctx, ioswitch.PlanID(req.PlanID))
  158. if sw == nil {
  159. return nil, fmt.Errorf("plan not found")
  160. }
  161. v, err := serder.JSONToObjectEx[ioswitch.Var]([]byte(req.Var))
  162. if err != nil {
  163. return nil, fmt.Errorf("deserializing var: %w", err)
  164. }
  165. sw.PutVars(v)
  166. return &agtrpc.SendVarResp{}, nil
  167. }
  168. func (s *Service) GetVar(ctx context.Context, req *agtrpc.GetVarReq) (*agtrpc.GetVarResp, error) {
  169. ctx2, cancel := context.WithTimeout(ctx, time.Second*30)
  170. defer cancel()
  171. sw := s.swMgr.FindByIDContexted(ctx2, ioswitch.PlanID(req.PlanID))
  172. if sw == nil {
  173. return nil, fmt.Errorf("plan not found")
  174. }
  175. v, err := serder.JSONToObjectEx[ioswitch.Var]([]byte(req.Var))
  176. if err != nil {
  177. return nil, fmt.Errorf("deserializing var: %w", err)
  178. }
  179. err = sw.BindVars(ctx, v)
  180. if err != nil {
  181. return nil, fmt.Errorf("binding vars: %w", err)
  182. }
  183. vd, err := serder.ObjectToJSONEx(v)
  184. if err != nil {
  185. return nil, fmt.Errorf("serializing var: %w", err)
  186. }
  187. return &agtrpc.GetVarResp{
  188. Var: string(vd),
  189. }, nil
  190. }

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