send.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. package send
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/gogf/gf/v2/frame/g"
  6. "github.com/pkg/sftp"
  7. "golang.org/x/crypto/ssh"
  8. "io"
  9. "io/fs"
  10. "os"
  11. "path/filepath"
  12. "time"
  13. )
  14. func UpLoadFilesToSftp(ctx context.Context, dir string) (int, []string) {
  15. // SFTP 连接配置
  16. var (
  17. config = &ssh.ClientConfig{
  18. User: g.Cfg().MustGet(ctx, "sftp.user").String(), // 替换为你的用户名
  19. Auth: []ssh.AuthMethod{
  20. ssh.Password(g.Cfg().MustGet(ctx, "sftp.pwd").String()), // 替换为你的密码
  21. },
  22. HostKeyCallback: ssh.InsecureIgnoreHostKey(), // 生产环境应使用 ssh.FixedHostKey
  23. Timeout: 30 * time.Second,
  24. }
  25. successNum int
  26. failPath []string
  27. )
  28. // 使用 fs.WalkDir
  29. fs.WalkDir(os.DirFS(dir), ".", func(path string, d fs.DirEntry, err error) error {
  30. if err != nil {
  31. g.Log().Infof(ctx, "访问路径 %q 失败: %v", path, err)
  32. return nil
  33. }
  34. if !d.IsDir() {
  35. // 获取文件信息
  36. info, err := d.Info()
  37. if err != nil {
  38. g.Log().Infof(ctx, "获取文件信息失败: %v", err)
  39. return nil
  40. }
  41. fullPath := filepath.Join(dir, path)
  42. g.Log().Infof(ctx, "文件: %s (大小: %d bytes)", fullPath, info.Size())
  43. // 上传文件
  44. uploadErr := uploadToSFTP(config, g.Cfg().MustGet(ctx, "sftp.addr").String(), fullPath, fullPath)
  45. if uploadErr != nil {
  46. failPath = append(failPath, fullPath)
  47. g.Log().Errorf(ctx, "%s 文件上传失败: %s", fullPath, uploadErr.Error())
  48. } else {
  49. successNum++
  50. g.Log().Infof(ctx, "%s 文件上传成功!", fullPath)
  51. }
  52. }
  53. return nil
  54. })
  55. return successNum, failPath
  56. }
  57. // 上传文件到SFTP服务器
  58. func uploadToSFTP(config *ssh.ClientConfig, addr, localPath, remotePath string) error {
  59. // 1. 建立SSH连接
  60. sshClient, err := ssh.Dial("tcp", addr, config)
  61. if err != nil {
  62. return fmt.Errorf("SSH连接失败: %w", err)
  63. }
  64. defer sshClient.Close()
  65. // 2. 创建SFTP客户端
  66. sftpClient, err := sftp.NewClient(sshClient)
  67. if err != nil {
  68. return fmt.Errorf("创建SFTP客户端失败: %w", err)
  69. }
  70. defer sftpClient.Close()
  71. // 3. 打开本地文件
  72. localFile, err := os.Open(localPath)
  73. if err != nil {
  74. return fmt.Errorf("打开本地文件失败: %w", err)
  75. }
  76. defer localFile.Close()
  77. // 4. 确保远程目录存在
  78. remoteDir := filepath.Dir(remotePath)
  79. if err := sftpClient.MkdirAll(remoteDir); err != nil {
  80. return fmt.Errorf("创建远程目录失败: %w", err)
  81. }
  82. // 5. 创建远程文件
  83. remoteFile, err := sftpClient.Create(remotePath)
  84. if err != nil {
  85. return fmt.Errorf("创建远程文件失败: %w", err)
  86. }
  87. defer remoteFile.Close()
  88. // 6. 复制文件内容
  89. if _, err := io.Copy(remoteFile, localFile); err != nil {
  90. return fmt.Errorf("复制文件内容失败: %w", err)
  91. }
  92. return nil
  93. }