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.

service.go 4.1 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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. package grpc
  2. import (
  3. "fmt"
  4. "io"
  5. log "gitlink.org.cn/cloudream/common/pkgs/logger"
  6. myio "gitlink.org.cn/cloudream/common/utils/io"
  7. stgglb "gitlink.org.cn/cloudream/storage/common/globals"
  8. agentserver "gitlink.org.cn/cloudream/storage/common/pkgs/grpc/agent"
  9. "gitlink.org.cn/cloudream/storage/common/pkgs/ioswitch"
  10. )
  11. type Service struct {
  12. agentserver.AgentServer
  13. sw *ioswitch.Switch
  14. }
  15. func NewService(sw *ioswitch.Switch) *Service {
  16. return &Service{
  17. sw: sw,
  18. }
  19. }
  20. func (s *Service) SendIPFSFile(server agentserver.Agent_SendIPFSFileServer) error {
  21. log.Debugf("client upload file")
  22. ipfsCli, err := stgglb.IPFSPool.Acquire()
  23. if err != nil {
  24. log.Warnf("new ipfs client: %s", err.Error())
  25. return fmt.Errorf("new ipfs client: %w", err)
  26. }
  27. defer ipfsCli.Close()
  28. writer, err := ipfsCli.CreateFileStream()
  29. if err != nil {
  30. log.Warnf("create file failed, err: %s", err.Error())
  31. return fmt.Errorf("create file failed, err: %w", err)
  32. }
  33. // 然后读取文件数据
  34. var recvSize int64
  35. for {
  36. msg, err := server.Recv()
  37. // 读取客户端数据失败
  38. // 即使err是io.EOF,只要没有收到客户端包含EOF数据包就被断开了连接,就认为接收失败
  39. if err != nil {
  40. // 关闭文件写入,不需要返回的hash和error
  41. writer.Abort(io.ErrClosedPipe)
  42. log.WithField("ReceiveSize", recvSize).
  43. Warnf("recv message failed, err: %s", err.Error())
  44. return fmt.Errorf("recv message failed, err: %w", err)
  45. }
  46. err = myio.WriteAll(writer, msg.Data)
  47. if err != nil {
  48. // 关闭文件写入,不需要返回的hash和error
  49. writer.Abort(io.ErrClosedPipe)
  50. log.Warnf("write data to file failed, err: %s", err.Error())
  51. return fmt.Errorf("write data to file failed, err: %w", err)
  52. }
  53. recvSize += int64(len(msg.Data))
  54. if msg.Type == agentserver.StreamDataPacketType_EOF {
  55. // 客户端明确说明文件传输已经结束,那么结束写入,获得文件Hash
  56. hash, err := writer.Finish()
  57. if err != nil {
  58. log.Warnf("finish writing failed, err: %s", err.Error())
  59. return fmt.Errorf("finish writing failed, err: %w", err)
  60. }
  61. // 并将结果返回到客户端
  62. err = server.SendAndClose(&agentserver.SendIPFSFileResp{
  63. FileHash: hash,
  64. })
  65. if err != nil {
  66. log.Warnf("send response failed, err: %s", err.Error())
  67. return fmt.Errorf("send response failed, err: %w", err)
  68. }
  69. log.Debugf("%d bytes received ", recvSize)
  70. return nil
  71. }
  72. }
  73. }
  74. func (s *Service) GetIPFSFile(req *agentserver.GetIPFSFileReq, server agentserver.Agent_GetIPFSFileServer) error {
  75. log.WithField("FileHash", req.FileHash).Debugf("client download file")
  76. ipfsCli, err := stgglb.IPFSPool.Acquire()
  77. if err != nil {
  78. log.Warnf("new ipfs client: %s", err.Error())
  79. return fmt.Errorf("new ipfs client: %w", err)
  80. }
  81. defer ipfsCli.Close()
  82. reader, err := ipfsCli.OpenRead(req.FileHash)
  83. if err != nil {
  84. log.Warnf("open file %s to read failed, err: %s", req.FileHash, err.Error())
  85. return fmt.Errorf("open file to read failed, err: %w", err)
  86. }
  87. defer reader.Close()
  88. buf := make([]byte, 1024)
  89. readAllCnt := 0
  90. for {
  91. readCnt, err := reader.Read(buf)
  92. if readCnt > 0 {
  93. readAllCnt += readCnt
  94. err = server.Send(&agentserver.FileDataPacket{
  95. Type: agentserver.StreamDataPacketType_Data,
  96. Data: buf[:readCnt],
  97. })
  98. if err != nil {
  99. log.WithField("FileHash", req.FileHash).
  100. Warnf("send file data failed, err: %s", err.Error())
  101. return fmt.Errorf("send file data failed, err: %w", err)
  102. }
  103. }
  104. // 文件读取完毕
  105. if err == io.EOF {
  106. log.WithField("FileHash", req.FileHash).Debugf("send data size %d", readAllCnt)
  107. // 发送EOF消息
  108. server.Send(&agentserver.FileDataPacket{
  109. Type: agentserver.StreamDataPacketType_EOF,
  110. })
  111. return nil
  112. }
  113. // io.ErrUnexpectedEOF没有读满整个buf就遇到了EOF,此时正常发送剩余数据即可。除了这两个错误之外,其他错误都中断操作
  114. if err != nil && err != io.ErrUnexpectedEOF {
  115. log.Warnf("read file %s data failed, err: %s", req.FileHash, err.Error())
  116. return fmt.Errorf("read file data failed, err: %w", err)
  117. }
  118. }
  119. }

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