Chris Lu
9 years ago
8 changed files with 217 additions and 10 deletions
-
1weed/command/command.go
-
147weed/command/copy.go
-
3weed/command/server.go
-
10weed/command/upload.go
-
31weed/operation/filer/register.go
-
12weed/server/filer_server.go
-
12weed/server/filer_server_handlers_admin.go
-
11weed/util/http_util.go
@ -0,0 +1,147 @@ |
|||
package command |
|||
|
|||
import ( |
|||
"fmt" |
|||
"io/ioutil" |
|||
"net/url" |
|||
"os" |
|||
"path/filepath" |
|||
"strings" |
|||
|
|||
"github.com/chrislusf/seaweedfs/weed/operation" |
|||
filer_operation "github.com/chrislusf/seaweedfs/weed/operation/filer" |
|||
"github.com/chrislusf/seaweedfs/weed/security" |
|||
) |
|||
|
|||
var ( |
|||
copy CopyOptions |
|||
) |
|||
|
|||
type CopyOptions struct { |
|||
master *string |
|||
include *string |
|||
replication *string |
|||
collection *string |
|||
ttl *string |
|||
maxMB *int |
|||
secretKey *string |
|||
|
|||
secret security.Secret |
|||
} |
|||
|
|||
func init() { |
|||
cmdCopy.Run = runCopy // break init cycle
|
|||
cmdCopy.IsDebug = cmdCopy.Flag.Bool("debug", false, "verbose debug information") |
|||
copy.master = cmdCopy.Flag.String("master", "localhost:9333", "SeaweedFS master location") |
|||
copy.include = cmdCopy.Flag.String("include", "", "pattens of files to copy, e.g., *.pdf, *.html, ab?d.txt, works together with -dir") |
|||
copy.replication = cmdCopy.Flag.String("replication", "", "replication type") |
|||
copy.collection = cmdCopy.Flag.String("collection", "", "optional collection name") |
|||
copy.ttl = cmdCopy.Flag.String("ttl", "", "time to live, e.g.: 1m, 1h, 1d, 1M, 1y") |
|||
copy.maxMB = cmdCopy.Flag.Int("maxMB", 0, "split files larger than the limit") |
|||
copy.secretKey = cmdCopy.Flag.String("secure.secret", "", "secret to encrypt Json Web Token(JWT)") |
|||
} |
|||
|
|||
var cmdCopy = &Command{ |
|||
UsageLine: "copy file_or_dir1 [file_or_dir2 file_or_dir3] http://localhost:8888/path/to/a/folder/", |
|||
Short: "copy one or a list of files to a filer folder", |
|||
Long: `copy one or a list of files, or batch copy one whole folder recursively, to a filer folder |
|||
|
|||
It can copy one or a list of files or folders. |
|||
|
|||
If copying a whole folder recursively: |
|||
All files under the folder and subfolders will be copyed. |
|||
Optional parameter "-include" allows you to specify the file name patterns. |
|||
|
|||
If any file has a ".gz" extension, the content are considered gzipped already, and will be stored as is. |
|||
This can save volume server's gzipped processing and allow customizable gzip compression level. |
|||
The file name will strip out ".gz" and stored. For example, "jquery.js.gz" will be stored as "jquery.js". |
|||
|
|||
If "maxMB" is set to a positive number, files larger than it would be split into chunks and copyed separatedly. |
|||
The list of file ids of those chunks would be stored in an additional chunk, and this additional chunk's file id would be returned. |
|||
|
|||
`, |
|||
} |
|||
|
|||
func runCopy(cmd *Command, args []string) bool { |
|||
copy.secret = security.Secret(*copy.secretKey) |
|||
if len(args) <= 1 { |
|||
return false |
|||
} |
|||
filerDestination := args[len(args)-1] |
|||
fileOrDirs := args[0 : len(args)-1] |
|||
|
|||
filerUrl, err := url.Parse(filerDestination) |
|||
if err != nil { |
|||
fmt.Printf("The last argument should be a URL on filer: %v\n", err) |
|||
return false |
|||
} |
|||
if len(fileOrDirs) > 1 && !strings.HasSuffix(filerUrl.Path, "/") { |
|||
fmt.Println("Can not copy multiple items to a file. The last argument must be a folder ended with \"/\"") |
|||
return false |
|||
} |
|||
|
|||
for _, fileOrDir := range fileOrDirs { |
|||
if !doEachCopy(fileOrDir, filerUrl.Host, filerUrl.Path) { |
|||
return false |
|||
} |
|||
} |
|||
return true |
|||
} |
|||
|
|||
func doEachCopy(fileOrDir string, host string, path string) bool { |
|||
f, err := os.Open(fileOrDir) |
|||
if err != nil { |
|||
fmt.Printf("Failed to open file %s: %v", fileOrDir, err) |
|||
return false |
|||
} |
|||
defer f.Close() |
|||
|
|||
fi, err := f.Stat() |
|||
if err != nil { |
|||
fmt.Printf("Failed to get stat for file %s: %v", fileOrDir, err) |
|||
return false |
|||
} |
|||
|
|||
mode := fi.Mode() |
|||
if mode.IsDir() { |
|||
files, _ := ioutil.ReadDir(fileOrDir) |
|||
for _, subFileOrDir := range files { |
|||
if !doEachCopy(fileOrDir+"/"+subFileOrDir.Name(), host, path+fi.Name()+"/") { |
|||
return false |
|||
} |
|||
} |
|||
return true |
|||
} |
|||
|
|||
// this is a regular file
|
|||
if *copy.include != "" { |
|||
if ok, _ := filepath.Match(*copy.include, filepath.Base(fileOrDir)); !ok { |
|||
return true |
|||
} |
|||
} |
|||
|
|||
parts, err := operation.NewFileParts([]string{fileOrDir}) |
|||
if err != nil { |
|||
fmt.Printf("Failed to read file %s: %v", fileOrDir, err) |
|||
} |
|||
|
|||
results, err := operation.SubmitFiles(*copy.master, parts, |
|||
*copy.replication, *copy.collection, |
|||
*copy.ttl, *copy.maxMB, copy.secret) |
|||
if err != nil { |
|||
fmt.Printf("Failed to submit file %s: %v", fileOrDir, err) |
|||
} |
|||
|
|||
if strings.HasSuffix(path, "/") { |
|||
path = path + fi.Name() |
|||
} |
|||
|
|||
if err = filer_operation.RegisterFile(host, path, results[0].Fid, copy.secret); err != nil { |
|||
fmt.Printf("Failed to register file %s on %s: %v", fileOrDir, host, err) |
|||
return false |
|||
} |
|||
|
|||
fmt.Printf("Copy %s => http://%s/%s\n", fileOrDir, host, path) |
|||
|
|||
return true |
|||
} |
@ -0,0 +1,31 @@ |
|||
package operation |
|||
|
|||
import ( |
|||
"fmt" |
|||
"net/url" |
|||
|
|||
"github.com/chrislusf/seaweedfs/weed/security" |
|||
"github.com/chrislusf/seaweedfs/weed/util" |
|||
) |
|||
|
|||
type SubmitResult struct { |
|||
FileName string `json:"fileName,omitempty"` |
|||
FileUrl string `json:"fileUrl,omitempty"` |
|||
Fid string `json:"fid,omitempty"` |
|||
Size uint32 `json:"size,omitempty"` |
|||
Error string `json:"error,omitempty"` |
|||
} |
|||
|
|||
func RegisterFile(filer string, path string, fileId string, secret security.Secret) error { |
|||
// TODO: jwt need to be used
|
|||
_ = security.GenJwt(secret, fileId) |
|||
|
|||
values := make(url.Values) |
|||
values.Add("path", path) |
|||
values.Add("fileId", fileId) |
|||
_, err := util.Post("http://"+filer+"/admin/register", values) |
|||
if err != nil { |
|||
return fmt.Errorf("Failed to register path:%s on filer:%s to file id:%s", path, filer, fileId) |
|||
} |
|||
return nil |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue