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

2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. package grpc
  2. import (
  3. "fmt"
  4. "io"
  5. "gitlink.org.cn/cloudream/common/pkgs/logger"
  6. myio "gitlink.org.cn/cloudream/common/utils/io"
  7. agentserver "gitlink.org.cn/cloudream/storage/common/pkgs/grpc/agent"
  8. "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch"
  9. )
  10. func (s *Service) SendStream(server agentserver.Agent_SendStreamServer) error {
  11. msg, err := server.Recv()
  12. if err != nil {
  13. return fmt.Errorf("recving stream id packet: %w", err)
  14. }
  15. if msg.Type != agentserver.StreamDataPacketType_SendArgs {
  16. return fmt.Errorf("first packet must be a SendArgs packet")
  17. }
  18. logger.
  19. WithField("PlanID", msg.PlanID).
  20. WithField("StreamID", msg.StreamID).
  21. Debugf("receive stream from grpc")
  22. pr, pw := io.Pipe()
  23. s.sw.StreamReady(ioswitch.PlanID(msg.PlanID), ioswitch.NewStream(ioswitch.StreamID(msg.StreamID), pr))
  24. // 然后读取文件数据
  25. var recvSize int64
  26. for {
  27. msg, err := server.Recv()
  28. // 读取客户端数据失败
  29. // 即使err是io.EOF,只要没有收到客户端包含EOF数据包就被断开了连接,就认为接收失败
  30. if err != nil {
  31. // 关闭文件写入,不需要返回的hash和error
  32. pw.CloseWithError(io.ErrClosedPipe)
  33. logger.WithField("ReceiveSize", recvSize).
  34. Warnf("recv message failed, err: %s", err.Error())
  35. return fmt.Errorf("recv message failed, err: %w", err)
  36. }
  37. err = myio.WriteAll(pw, msg.Data)
  38. if err != nil {
  39. // 关闭文件写入,不需要返回的hash和error
  40. pw.CloseWithError(io.ErrClosedPipe)
  41. logger.Warnf("write data to file failed, err: %s", err.Error())
  42. return fmt.Errorf("write data to file failed, err: %w", err)
  43. }
  44. recvSize += int64(len(msg.Data))
  45. if msg.Type == agentserver.StreamDataPacketType_EOF {
  46. // 客户端明确说明文件传输已经结束,那么结束写入,获得文件Hash
  47. err := pw.Close()
  48. if err != nil {
  49. logger.Warnf("finish writing failed, err: %s", err.Error())
  50. return fmt.Errorf("finish writing failed, err: %w", err)
  51. }
  52. // 并将结果返回到客户端
  53. err = server.SendAndClose(&agentserver.SendStreamResp{})
  54. if err != nil {
  55. logger.Warnf("send response failed, err: %s", err.Error())
  56. return fmt.Errorf("send response failed, err: %w", err)
  57. }
  58. return nil
  59. }
  60. }
  61. }
  62. func (s *Service) FetchStream(req *agentserver.FetchStreamReq, server agentserver.Agent_FetchStreamServer) error {
  63. logger.
  64. WithField("PlanID", req.PlanID).
  65. WithField("StreamID", req.StreamID).
  66. Debugf("send stream by grpc")
  67. strs, err := s.sw.WaitStreams(ioswitch.PlanID(req.PlanID), ioswitch.StreamID(req.StreamID))
  68. if err != nil {
  69. logger.
  70. WithField("PlanID", req.PlanID).
  71. WithField("StreamID", req.StreamID).
  72. Warnf("watting stream: %s", err.Error())
  73. return fmt.Errorf("watting stream: %w", err)
  74. }
  75. reader := strs[0].Stream
  76. defer reader.Close()
  77. buf := make([]byte, 4096)
  78. readAllCnt := 0
  79. for {
  80. readCnt, err := reader.Read(buf)
  81. if readCnt > 0 {
  82. readAllCnt += readCnt
  83. err = server.Send(&agentserver.StreamDataPacket{
  84. Type: agentserver.StreamDataPacketType_Data,
  85. Data: buf[:readCnt],
  86. })
  87. if err != nil {
  88. logger.
  89. WithField("PlanID", req.PlanID).
  90. WithField("StreamID", req.StreamID).
  91. Warnf("send stream data failed, err: %s", err.Error())
  92. return fmt.Errorf("send stream data failed, err: %w", err)
  93. }
  94. }
  95. // 文件读取完毕
  96. if err == io.EOF {
  97. logger.
  98. WithField("PlanID", req.PlanID).
  99. WithField("StreamID", req.StreamID).
  100. Debugf("send data size %d", readAllCnt)
  101. // 发送EOF消息
  102. server.Send(&agentserver.StreamDataPacket{
  103. Type: agentserver.StreamDataPacketType_EOF,
  104. })
  105. return nil
  106. }
  107. // io.ErrUnexpectedEOF没有读满整个buf就遇到了EOF,此时正常发送剩余数据即可。除了这两个错误之外,其他错误都中断操作
  108. if err != nil && err != io.ErrUnexpectedEOF {
  109. logger.
  110. WithField("PlanID", req.PlanID).
  111. WithField("StreamID", req.StreamID).
  112. Warnf("reading stream data: %s", err.Error())
  113. return fmt.Errorf("reading stream data: %w", err)
  114. }
  115. }
  116. }

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