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

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. package grpc
  2. import (
  3. "fmt"
  4. "io"
  5. log "gitlink.org.cn/cloudream/common/pkgs/logger"
  6. "gitlink.org.cn/cloudream/common/utils/io2"
  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. // Service 类定义了与agent服务相关的操作
  12. type Service struct {
  13. agentserver.AgentServer
  14. sw *ioswitch.Switch
  15. }
  16. // NewService 创建并返回一个新的Service实例
  17. func NewService(sw *ioswitch.Switch) *Service {
  18. return &Service{
  19. sw: sw,
  20. }
  21. }
  22. // SendIPFSFile 处理客户端上传文件到IPFS的请求
  23. func (s *Service) SendIPFSFile(server agentserver.Agent_SendIPFSFileServer) error {
  24. log.Debugf("client upload file")
  25. ipfsCli, err := stgglb.IPFSPool.Acquire() // 获取一个IPFS客户端实例
  26. if err != nil {
  27. log.Warnf("new ipfs client: %s", err.Error())
  28. return fmt.Errorf("new ipfs client: %w", err)
  29. }
  30. defer ipfsCli.Close()
  31. writer, err := ipfsCli.CreateFileStream() // 在IPFS上创建一个文件流
  32. if err != nil {
  33. log.Warnf("create file failed, err: %s", err.Error())
  34. return fmt.Errorf("create file failed, err: %w", err)
  35. }
  36. var recvSize int64
  37. for {
  38. msg, err := server.Recv() // 接收客户端发送的文件数据
  39. if err != nil {
  40. writer.Abort(io.ErrClosedPipe) // 出错时关闭文件写入
  41. log.WithField("ReceiveSize", recvSize).
  42. Warnf("recv message failed, err: %s", err.Error())
  43. return fmt.Errorf("recv message failed, err: %w", err)
  44. }
  45. err = io2.WriteAll(writer, msg.Data)
  46. if err != nil {
  47. writer.Abort(io.ErrClosedPipe) // 写入出错时关闭文件写入
  48. log.Warnf("write data to file failed, err: %s", err.Error())
  49. return fmt.Errorf("write data to file failed, err: %w", err)
  50. }
  51. recvSize += int64(len(msg.Data))
  52. if msg.Type == agentserver.StreamDataPacketType_EOF { // 当接收到EOF标志时,结束文件写入并返回文件Hash
  53. hash, err := writer.Finish()
  54. if err != nil {
  55. log.Warnf("finish writing failed, err: %s", err.Error())
  56. return fmt.Errorf("finish writing failed, err: %w", err)
  57. }
  58. err = server.SendAndClose(&agentserver.SendIPFSFileResp{
  59. FileHash: hash,
  60. })
  61. if err != nil {
  62. log.Warnf("send response failed, err: %s", err.Error())
  63. return fmt.Errorf("send response failed, err: %w", err)
  64. }
  65. log.Debugf("%d bytes received ", recvSize)
  66. return nil
  67. }
  68. }
  69. }
  70. // GetIPFSFile 处理客户端从IPFS下载文件的请求
  71. func (s *Service) GetIPFSFile(req *agentserver.GetIPFSFileReq, server agentserver.Agent_GetIPFSFileServer) error {
  72. log.WithField("FileHash", req.FileHash).Debugf("client download file")
  73. ipfsCli, err := stgglb.IPFSPool.Acquire() // 获取一个IPFS客户端实例
  74. if err != nil {
  75. log.Warnf("new ipfs client: %s", err.Error())
  76. return fmt.Errorf("new ipfs client: %w", err)
  77. }
  78. defer ipfsCli.Close()
  79. reader, err := ipfsCli.OpenRead(req.FileHash) // 通过文件Hash打开一个读取流
  80. if err != nil {
  81. log.Warnf("open file %s to read failed, err: %s", req.FileHash, err.Error())
  82. return fmt.Errorf("open file to read failed, err: %w", err)
  83. }
  84. defer reader.Close()
  85. buf := make([]byte, 1024)
  86. readAllCnt := 0
  87. for {
  88. readCnt, err := reader.Read(buf) // 从IPFS读取数据
  89. if readCnt > 0 {
  90. readAllCnt += readCnt
  91. err = server.Send(&agentserver.FileDataPacket{
  92. Type: agentserver.StreamDataPacketType_Data,
  93. Data: buf[:readCnt],
  94. })
  95. if err != nil {
  96. log.WithField("FileHash", req.FileHash).
  97. Warnf("send file data failed, err: %s", err.Error())
  98. return fmt.Errorf("send file data failed, err: %w", err)
  99. }
  100. }
  101. if err == io.EOF { // 当读取完毕时,发送EOF标志并返回
  102. log.WithField("FileHash", req.FileHash).Debugf("send data size %d", readAllCnt)
  103. server.Send(&agentserver.FileDataPacket{
  104. Type: agentserver.StreamDataPacketType_EOF,
  105. })
  106. return nil
  107. }
  108. if err != nil && err != io.ErrUnexpectedEOF { // 遇到除EOF和ErrUnexpectedEOF外的其他错误,中断操作
  109. log.Warnf("read file %s data failed, err: %s", req.FileHash, err.Error())
  110. return fmt.Errorf("read file data failed, err: %w", err)
  111. }
  112. }
  113. }

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