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.

grpc_service.go 3.7 kB

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

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