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.
		
		
		
		
		
			
		
			
				
					
					
						
							139 lines
						
					
					
						
							3.6 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							139 lines
						
					
					
						
							3.6 KiB
						
					
					
				| package command | |
| 
 | |
| import ( | |
| 	"context" | |
| 	"fmt" | |
| 	"io" | |
| 	"net/http" | |
| 	"os" | |
| 	"path" | |
| 	"strings" | |
| 
 | |
| 	"google.golang.org/grpc" | |
| 
 | |
| 	"github.com/seaweedfs/seaweedfs/weed/operation" | |
| 	"github.com/seaweedfs/seaweedfs/weed/pb" | |
| 	"github.com/seaweedfs/seaweedfs/weed/security" | |
| 	"github.com/seaweedfs/seaweedfs/weed/util" | |
| 	util_http "github.com/seaweedfs/seaweedfs/weed/util/http" | |
| ) | |
| 
 | |
| var ( | |
| 	d DownloadOptions | |
| ) | |
| 
 | |
| type DownloadOptions struct { | |
| 	server *string | |
| 	dir    *string | |
| } | |
| 
 | |
| func init() { | |
| 	cmdDownload.Run = runDownload // break init cycle | |
| 	d.server = cmdDownload.Flag.String("server", "localhost:9333", "SeaweedFS master location") | |
| 	d.dir = cmdDownload.Flag.String("dir", ".", "Download the whole folder recursively if specified.") | |
| } | |
| 
 | |
| var cmdDownload = &Command{ | |
| 	UsageLine: "download -server=localhost:9333 -dir=one_directory fid1 [fid2 fid3 ...]", | |
| 	Short:     "download files by file id", | |
| 	Long: `download files by file id. | |
|  | |
|   Usually you just need to use curl to lookup the file's volume server, and then download them directly. | |
|   This download tool combine the two steps into one. | |
|  | |
|   What's more, if you use "weed upload -maxMB=..." option to upload a big file divided into chunks, you can | |
|   use this tool to download the chunks and merge them automatically. | |
|  | |
|   `, | |
| } | |
| 
 | |
| func runDownload(cmd *Command, args []string) bool { | |
| 	util.LoadSecurityConfiguration() | |
| 	grpcDialOption := security.LoadClientTLS(util.GetViper(), "grpc.client") | |
| 
 | |
| 	for _, fid := range args { | |
| 		if e := downloadToFile(func(_ context.Context) pb.ServerAddress { return pb.ServerAddress(*d.server) }, grpcDialOption, fid, util.ResolvePath(*d.dir)); e != nil { | |
| 			fmt.Println("Download Error: ", fid, e) | |
| 		} | |
| 	} | |
| 	return true | |
| } | |
| 
 | |
| func downloadToFile(masterFn operation.GetMasterFn, grpcDialOption grpc.DialOption, fileId, saveDir string) error { | |
| 	fileUrl, jwt, lookupError := operation.LookupFileId(masterFn, grpcDialOption, fileId) | |
| 	if lookupError != nil { | |
| 		return lookupError | |
| 	} | |
| 	filename, _, rc, err := util_http.DownloadFile(fileUrl, jwt) | |
| 	if err != nil { | |
| 		return err | |
| 	} | |
| 	defer util_http.CloseResponse(rc) | |
| 	if filename == "" { | |
| 		filename = fileId | |
| 	} | |
| 	isFileList := false | |
| 	if strings.HasSuffix(filename, "-list") { | |
| 		// old command compatible | |
| 		isFileList = true | |
| 		filename = filename[0 : len(filename)-len("-list")] | |
| 	} | |
| 	f, err := os.OpenFile(path.Join(saveDir, filename), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.ModePerm) | |
| 	if err != nil { | |
| 		return err | |
| 	} | |
| 	defer f.Close() | |
| 	if isFileList { | |
| 		content, err := io.ReadAll(rc.Body) | |
| 		if err != nil { | |
| 			return err | |
| 		} | |
| 		fids := strings.Split(string(content), "\n") | |
| 		for _, partId := range fids { | |
| 			var n int | |
| 			_, part, err := fetchContent(masterFn, grpcDialOption, partId) | |
| 			if err == nil { | |
| 				n, err = f.Write(part) | |
| 			} | |
| 			if err == nil && n < len(part) { | |
| 				err = io.ErrShortWrite | |
| 			} | |
| 			if err != nil { | |
| 				return err | |
| 			} | |
| 		} | |
| 	} else { | |
| 		if _, err = io.Copy(f, rc.Body); err != nil { | |
| 			return err | |
| 		} | |
| 
 | |
| 	} | |
| 	return nil | |
| } | |
| 
 | |
| func fetchContent(masterFn operation.GetMasterFn, grpcDialOption grpc.DialOption, fileId string) (filename string, content []byte, e error) { | |
| 	fileUrl, jwt, lookupError := operation.LookupFileId(masterFn, grpcDialOption, fileId) | |
| 	if lookupError != nil { | |
| 		return "", nil, lookupError | |
| 	} | |
| 	var rc *http.Response | |
| 	if filename, _, rc, e = util_http.DownloadFile(fileUrl, jwt); e != nil { | |
| 		return "", nil, e | |
| 	} | |
| 	defer util_http.CloseResponse(rc) | |
| 	content, e = io.ReadAll(rc.Body) | |
| 	return | |
| } | |
| 
 | |
| func WriteFile(filename string, data []byte, perm os.FileMode) error { | |
| 	f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm) | |
| 	if err != nil { | |
| 		return err | |
| 	} | |
| 	n, err := f.Write(data) | |
| 	f.Close() | |
| 	if err == nil && n < len(data) { | |
| 		err = io.ErrShortWrite | |
| 	} | |
| 	return err | |
| }
 |