You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

122 lines
3.0 KiB

  1. package command
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/seaweedfs/seaweedfs/weed/filer"
  6. "github.com/seaweedfs/seaweedfs/weed/pb"
  7. "github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
  8. "github.com/seaweedfs/seaweedfs/weed/wdclient"
  9. "google.golang.org/grpc"
  10. "net/url"
  11. "os"
  12. "strings"
  13. "github.com/seaweedfs/seaweedfs/weed/security"
  14. "github.com/seaweedfs/seaweedfs/weed/util"
  15. )
  16. var (
  17. filerCat FilerCatOptions
  18. )
  19. type FilerCatOptions struct {
  20. grpcDialOption grpc.DialOption
  21. filerAddress pb.ServerAddress
  22. filerClient filer_pb.SeaweedFilerClient
  23. output *string
  24. }
  25. func (fco *FilerCatOptions) GetLookupFileIdFunction() wdclient.LookupFileIdFunctionType {
  26. return func(fileId string) (targetUrls []string, err error) {
  27. vid := filer.VolumeId(fileId)
  28. resp, err := fco.filerClient.LookupVolume(context.Background(), &filer_pb.LookupVolumeRequest{
  29. VolumeIds: []string{vid},
  30. })
  31. if err != nil {
  32. return nil, err
  33. }
  34. locations := resp.LocationsMap[vid]
  35. for _, loc := range locations.Locations {
  36. targetUrls = append(targetUrls, fmt.Sprintf("http://%s/%s", loc.Url, fileId))
  37. }
  38. return
  39. }
  40. }
  41. func init() {
  42. cmdFilerCat.Run = runFilerCat // break init cycle
  43. filerCat.output = cmdFilerCat.Flag.String("o", "", "write to file instead of stdout")
  44. }
  45. var cmdFilerCat = &Command{
  46. UsageLine: "filer.cat [-o <file>] http://localhost:8888/path/to/file",
  47. Short: "copy one file to local",
  48. Long: `read one file to stdout or write to a file
  49. `,
  50. }
  51. func runFilerCat(cmd *Command, args []string) bool {
  52. util.LoadConfiguration("security", false)
  53. if len(args) == 0 {
  54. return false
  55. }
  56. filerSource := args[len(args)-1]
  57. filerUrl, err := url.Parse(filerSource)
  58. if err != nil {
  59. fmt.Printf("The last argument should be a URL on filer: %v\n", err)
  60. return false
  61. }
  62. urlPath := filerUrl.Path
  63. if strings.HasSuffix(urlPath, "/") {
  64. fmt.Printf("The last argument should be a file: %v\n", err)
  65. return false
  66. }
  67. filerCat.filerAddress = pb.ServerAddress(filerUrl.Host)
  68. filerCat.grpcDialOption = security.LoadClientTLS(util.GetViper(), "grpc.client")
  69. dir, name := util.FullPath(urlPath).DirAndName()
  70. writer := os.Stdout
  71. if *filerCat.output != "" {
  72. fmt.Printf("saving %s to %s\n", filerSource, *filerCat.output)
  73. f, err := os.OpenFile(*filerCat.output, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)
  74. if err != nil {
  75. fmt.Printf("open file %s: %v\n", *filerCat.output, err)
  76. return false
  77. }
  78. defer f.Close()
  79. writer = f
  80. }
  81. pb.WithFilerClient(false, filerCat.filerAddress, filerCat.grpcDialOption, func(client filer_pb.SeaweedFilerClient) error {
  82. request := &filer_pb.LookupDirectoryEntryRequest{
  83. Name: name,
  84. Directory: dir,
  85. }
  86. respLookupEntry, err := filer_pb.LookupEntry(client, request)
  87. if err != nil {
  88. return err
  89. }
  90. if len(respLookupEntry.Entry.Content) > 0 {
  91. _, err = writer.Write(respLookupEntry.Entry.Content)
  92. return err
  93. }
  94. filerCat.filerClient = client
  95. return filer.StreamContent(&filerCat, writer, respLookupEntry.Entry.GetChunks(), 0, int64(filer.FileSize(respLookupEntry.Entry)))
  96. })
  97. return true
  98. }