diff --git a/go/filer/client_operations.go b/go/filer/client_operations.go new file mode 100644 index 000000000..2eb5c399d --- /dev/null +++ b/go/filer/client_operations.go @@ -0,0 +1,71 @@ +package filer + +import () + +import ( + "code.google.com/p/weed-fs/go/util" + "encoding/json" + "errors" + "fmt" + "net/url" +) + +type ApiRequest struct { + Command string //"listFiles", "listDirectories" + DirectoryId DirectoryId + FileName string +} + +type ListFilesResult struct { + Files []FileEntry + Error string `json:"error,omitempty"` +} + +func ListFiles(server string, directoryId DirectoryId, fileName string) (*ListFilesResult, error) { + var ret ListFilesResult + if err := call(server, ApiRequest{Command: "listFiles", DirectoryId: directoryId, FileName: fileName}, &ret); err == nil { + if ret.Error != "" { + return nil, errors.New(ret.Error) + } + return &ret, nil + } else { + return nil, err + } +} + +type ListDirectoriesResult struct { + Directories []DirectoryEntry + Error string `json:"error,omitempty"` +} + +func ListDirectories(server string, directoryId DirectoryId) (*ListDirectoriesResult, error) { + var ret ListDirectoriesResult + if err := call(server, ApiRequest{Command: "listDirectories", DirectoryId: directoryId}, &ret); err == nil { + if ret.Error != "" { + return nil, errors.New(ret.Error) + } + return &ret, nil + } else { + return nil, err + } +} + +func call(server string, request ApiRequest, ret interface{}) error { + b, err := json.Marshal(request) + if err != nil { + fmt.Println("error:", err) + return nil + } + values := make(url.Values) + values.Add("request", string(b)) + jsonBlob, err := util.Post("http://"+server+"/__api__", values) + if err != nil { + return err + } + err = json.Unmarshal(jsonBlob, ret) + if err != nil { + return err + } + return nil +} + diff --git a/go/filer/operations.go b/go/filer/operations.go deleted file mode 100644 index 7e89b534d..000000000 --- a/go/filer/operations.go +++ /dev/null @@ -1,58 +0,0 @@ -package filer - -import () - -import ( - "code.google.com/p/weed-fs/go/util" - "encoding/json" - "errors" - _ "fmt" - "net/url" - "strconv" -) - -type ListFilesResult struct { - Files []FileEntry - Error string `json:"error,omitempty"` -} - -func ListFiles(server string, directoryId DirectoryId, fileName string) (*ListFilesResult, error) { - values := make(url.Values) - values.Add("directoryId", strconv.Itoa(int(directoryId))) - jsonBlob, err := util.Post("http://"+server+"/dir/lookup", values) - if err != nil { - return nil, err - } - var ret ListFilesResult - err = json.Unmarshal(jsonBlob, &ret) - if err != nil { - return nil, err - } - if ret.Error != "" { - return nil, errors.New(ret.Error) - } - return &ret, nil -} - -type ListDirectoriesResult struct { - Directories []DirectoryEntry - Error string `json:"error,omitempty"` -} - -func ListDirectories(server string, directoryId DirectoryId) (*ListDirectoriesResult, error) { - values := make(url.Values) - values.Add("directoryId", strconv.Itoa(int(directoryId))) - jsonBlob, err := util.Post("http://"+server+"/dir/lookup", values) - if err != nil { - return nil, err - } - var ret ListDirectoriesResult - err = json.Unmarshal(jsonBlob, &ret) - if err != nil { - return nil, err - } - if ret.Error != "" { - return nil, errors.New(ret.Error) - } - return &ret, nil -} diff --git a/go/util/constants.go b/go/util/constants.go index cd8cf72c9..5b7c1ee91 100644 --- a/go/util/constants.go +++ b/go/util/constants.go @@ -3,5 +3,5 @@ package util import () const ( - VERSION = "0.57 beta" + VERSION = "0.58" ) diff --git a/go/weed/mount.go b/go/weed/mount.go index 51b5e6919..23f85f567 100644 --- a/go/weed/mount.go +++ b/go/weed/mount.go @@ -1,16 +1,6 @@ package main import ( - "bazil.org/fuse" - "bazil.org/fuse/fs" - "code.google.com/p/weed-fs/go/filer" - "code.google.com/p/weed-fs/go/glog" - "code.google.com/p/weed-fs/go/storage" - "code.google.com/p/weed-fs/go/util" - "fmt" - "os" - "os/signal" - "runtime" ) type MountOptions struct { @@ -40,105 +30,9 @@ var cmdMount = &Command{ These 2 requirements can be achieved with one command "weed server -filer=true" This uses bazil.org/fuse, whichenables writing FUSE file systems on - FreeBSD, Linux, and OS X. + Linux, and OS X. On OS X, it requires OSXFUSE (http://osxfuse.github.com/). `, } - -func runMount(cmd *Command, args []string) bool { - fmt.Printf("This is Weed File System version %s %s %s\n", util.VERSION, runtime.GOOS, runtime.GOARCH) - if *mountOptions.dir == "" { - fmt.Printf("Please specify the mount directory via \"-dir\"") - return false - } - - c, err := fuse.Mount(*mountOptions.dir) - if err != nil { - glog.Fatal(err) - return false - } - - signalChan := make(chan os.Signal, 1) - signal.Notify(signalChan, os.Interrupt) - go func() { - for _ = range signalChan { - // sig is a ^C, handle it - fuse.Unmount(*mountOptions.dir) - c.Close() - os.Exit(0) - } - }() - - err = fs.Serve(c, WFS{}) - if err != nil { - fuse.Unmount(*mountOptions.dir) - } - - // check if the mount process has an error to report - <-c.Ready - if err := c.MountError; err != nil { - glog.Fatal(err) - } - - return true -} - -type File struct { - FileId filer.FileId - Name string -} - -func (File) Attr() fuse.Attr { - return fuse.Attr{Mode: 0444} -} -func (File) ReadAll(intr fs.Intr) ([]byte, fuse.Error) { - return []byte("hello, world\n"), nil -} - -type Dir struct { - DirectoryId filer.DirectoryId - Name string -} - -func (dir Dir) Attr() fuse.Attr { - return fuse.Attr{Inode: 1, Mode: os.ModeDir | 0555} -} - -func (dir Dir) Lookup(name string, intr fs.Intr) (fs.Node, fuse.Error) { - files_result, e := filer.ListFiles(*mountOptions.filer, dir.DirectoryId, name) - if e != nil { - return nil, fuse.ENOENT - } - if len(files_result.Files) > 0 { - return File{files_result.Files[0].Id, files_result.Files[0].Name}, nil - } - return nil, fmt.Errorf("File Not Found for %s", name) -} - -type WFS struct{} - -func (WFS) Root() (fs.Node, fuse.Error) { - return Dir{}, nil -} - -func (dir *Dir) ReadDir(intr fs.Intr) ([]fuse.Dirent, fuse.Error) { - ret := make([]fuse.Dirent, 0) - if dirs, e := filer.ListDirectories(*mountOptions.filer, dir.DirectoryId); e == nil { - for _, d := range dirs.Directories { - dirId := uint64(d.Id) - ret = append(ret, fuse.Dirent{Inode: dirId, Name: d.Name, Type: fuse.DT_Dir}) - } - } - if files, e := filer.ListFiles(*mountOptions.filer, dir.DirectoryId, ""); e == nil { - for _, f := range files.Files { - if fileId, e := storage.ParseFileId(string(f.Id)); e == nil { - fileInode := uint64(fileId.VolumeId)<<32 + fileId.Key - ret = append(ret, fuse.Dirent{Inode: fileInode, Name: f.Name, Type: fuse.DT_File}) - } - - } - } - return ret, nil -} diff --git a/go/weed/mount_notsupported.go b/go/weed/mount_notsupported.go new file mode 100644 index 000000000..bc77ffa16 --- /dev/null +++ b/go/weed/mount_notsupported.go @@ -0,0 +1,15 @@ +// +build !linux +// +build !darwin + +package main + +import ( + "fmt" + "runtime" +) + +func runMount(cmd *Command, args []string) bool { + fmt.Printf("Mount is not supported on %s %s\n", runtime.GOOS, runtime.GOARCH) + + return true +} diff --git a/go/weed/mount_std.go b/go/weed/mount_std.go new file mode 100644 index 000000000..5d01a0f87 --- /dev/null +++ b/go/weed/mount_std.go @@ -0,0 +1,112 @@ +// +build linux darwin + +package main + +import ( + "bazil.org/fuse" + "bazil.org/fuse/fs" + "code.google.com/p/weed-fs/go/filer" + "code.google.com/p/weed-fs/go/glog" + "code.google.com/p/weed-fs/go/storage" + "code.google.com/p/weed-fs/go/util" + "fmt" + "os" + "os/signal" + "runtime" +) + +func runMount(cmd *Command, args []string) bool { + fmt.Printf("This is Weed File System version %s %s %s\n", util.VERSION, runtime.GOOS, runtime.GOARCH) + if *mountOptions.dir == "" { + fmt.Printf("Please specify the mount directory via \"-dir\"") + return false + } + + c, err := fuse.Mount(*mountOptions.dir) + if err != nil { + glog.Fatal(err) + return false + } + + signalChan := make(chan os.Signal, 1) + signal.Notify(signalChan, os.Interrupt) + go func() { + for _ = range signalChan { + // sig is a ^C, handle it + fuse.Unmount(*mountOptions.dir) + c.Close() + os.Exit(0) + } + }() + + err = fs.Serve(c, WFS{}) + if err != nil { + fuse.Unmount(*mountOptions.dir) + } + + // check if the mount process has an error to report + <-c.Ready + if err := c.MountError; err != nil { + glog.Fatal(err) + } + + return true +} + +type File struct { + FileId filer.FileId + Name string +} + +func (File) Attr() fuse.Attr { + return fuse.Attr{Mode: 0444} +} +func (File) ReadAll(intr fs.Intr) ([]byte, fuse.Error) { + return []byte("hello, world\n"), nil +} + +type Dir struct { + DirectoryId filer.DirectoryId + Name string +} + +func (dir Dir) Attr() fuse.Attr { + return fuse.Attr{Inode: 1, Mode: os.ModeDir | 0555} +} + +func (dir Dir) Lookup(name string, intr fs.Intr) (fs.Node, fuse.Error) { + files_result, e := filer.ListFiles(*mountOptions.filer, dir.DirectoryId, name) + if e != nil { + return nil, fuse.ENOENT + } + if len(files_result.Files) > 0 { + return File{files_result.Files[0].Id, files_result.Files[0].Name}, nil + } + return nil, fmt.Errorf("File Not Found for %s", name) +} + +type WFS struct{} + +func (WFS) Root() (fs.Node, fuse.Error) { + return Dir{}, nil +} + +func (dir *Dir) ReadDir(intr fs.Intr) ([]fuse.Dirent, fuse.Error) { + ret := make([]fuse.Dirent, 0) + if dirs, e := filer.ListDirectories(*mountOptions.filer, dir.DirectoryId); e == nil { + for _, d := range dirs.Directories { + dirId := uint64(d.Id) + ret = append(ret, fuse.Dirent{Inode: dirId, Name: d.Name, Type: fuse.DT_Dir}) + } + } + if files, e := filer.ListFiles(*mountOptions.filer, dir.DirectoryId, ""); e == nil { + for _, f := range files.Files { + if fileId, e := storage.ParseFileId(string(f.Id)); e == nil { + fileInode := uint64(fileId.VolumeId)<<48 + fileId.Key + ret = append(ret, fuse.Dirent{Inode: fileInode, Name: f.Name, Type: fuse.DT_File}) + } + + } + } + return ret, nil +} diff --git a/go/weed/weed_server/filer_server.go b/go/weed/weed_server/filer_server.go index 996de5020..94b4a501d 100644 --- a/go/weed/weed_server/filer_server.go +++ b/go/weed/weed_server/filer_server.go @@ -26,6 +26,7 @@ func NewFilerServer(r *http.ServeMux, port int, master string, dir string, colle return } + r.HandleFunc("/__api__", fs.filerApiHandler) r.HandleFunc("/", fs.filerHandler) return fs, nil diff --git a/go/weed/weed_server/filer_server_handlers_api.go b/go/weed/weed_server/filer_server_handlers_api.go new file mode 100644 index 000000000..62b51ed1d --- /dev/null +++ b/go/weed/weed_server/filer_server_handlers_api.go @@ -0,0 +1,20 @@ +package weed_server + +import ( + "net/http" +) + +func (fs *FilerServer) filerApiHandler(w http.ResponseWriter, r *http.Request) { + switch r.Method { + case "GET": + fs.GetOrHeadHandler(w, r, true) + case "HEAD": + fs.GetOrHeadHandler(w, r, false) + case "DELETE": + fs.DeleteHandler(w, r) + case "PUT": + fs.PostHandler(w, r) + case "POST": + fs.PostHandler(w, r) + } +}