From 0eeac3b96618d3eb7e64adaf809a929e16c42b12 Mon Sep 17 00:00:00 2001 From: Weiguang Date: Fri, 22 Nov 2019 01:15:18 +0800 Subject: [PATCH] chore: split up GhaFS into separate file (#4) --- ghafs.go | 150 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ main.go | 138 -------------------------------------------------- 2 files changed, 150 insertions(+), 138 deletions(-) create mode 100644 ghafs.go diff --git a/ghafs.go b/ghafs.go new file mode 100644 index 0000000..98ce2b0 --- /dev/null +++ b/ghafs.go @@ -0,0 +1,150 @@ +package main + +import ( + "context" + "io/ioutil" + "log" + "net/http" + "os" + + "bazil.org/fuse" + "bazil.org/fuse/fs" + "github.com/google/go-github/v28/github" +) + +type ReleaseAssets struct { + release *github.RepositoryRelease + assets []*github.ReleaseAsset +} + +type ReleaseAssetsMap map[string]ReleaseAssets + +func rasToDirents(rasm *ReleaseAssetsMap) []fuse.Dirent { + dirents := make([]fuse.Dirent, len(*rasm)) + + i := 0 + for tag, ras := range *rasm { + dirents[i] = fuse.Dirent{ + Inode: uint64(ras.release.GetID()), + Name: tag, + Type: fuse.DT_Dir, + } + i++ + } + return dirents +} + +func assetsToDirents(assets []*github.ReleaseAsset) []fuse.Dirent { + dirents := make([]fuse.Dirent, len(assets)) + + for i, asset := range assets { + dirents[i] = fuse.Dirent{ + Inode: uint64(asset.GetID()), + Name: asset.GetName(), + Type: fuse.DT_File, + } + } + return dirents +} + +// ghaFS implements the GitHub Release Assets file system. +type ghaFS struct { + rasm *ReleaseAssetsMap + token *string +} + +func NewGhaFS(rasm *ReleaseAssetsMap, token *string) ghaFS { + return ghaFS{rasm, token} +} + +func (g ghaFS) Root() (fs.Node, error) { + return root{rasm: g.rasm, token: g.token}, nil +} + +// root implements both Node and Handle for the root directory. +type root struct { + rasm *ReleaseAssetsMap + token *string +} + +func (root) Attr(ctx context.Context, a *fuse.Attr) error { + a.Inode = 1 + a.Mode = os.ModeDir | 0555 + return nil +} + +func (r root) Lookup(ctx context.Context, name string) (fs.Node, error) { + for tag, ras := range *r.rasm { + if name == tag { + return tagDir{ras: &ras, token: r.token}, nil + } + } + + return nil, fuse.ENOENT +} + +func (r root) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) { + return rasToDirents(r.rasm), nil +} + +// tagDir implements both Node and Handle for the root directory. +type tagDir struct { + ras *ReleaseAssets + token *string +} + +func (t tagDir) Attr(ctx context.Context, a *fuse.Attr) error { + a.Inode = uint64(t.ras.release.GetID()) + a.Mode = os.ModeDir | 0555 + return nil +} + +func (t tagDir) Lookup(ctx context.Context, name string) (fs.Node, error) { + for _, asset := range t.ras.assets { + if name == asset.GetName() { + return assetFile{ra: asset, token: t.token}, nil + } + } + return nil, fuse.ENOENT +} + +func (t tagDir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) { + return assetsToDirents(t.ras.assets), nil +} + +// assetFile implements both Node and Handle for the hello file. +type assetFile struct { + ra *github.ReleaseAsset + token *string +} + +func (f assetFile) Attr(ctx context.Context, a *fuse.Attr) error { + a.Inode = uint64(f.ra.GetID()) + a.Mode = 0444 + a.Size = uint64(f.ra.GetSize()) + return nil +} + +func (f assetFile) ReadAll(ctx context.Context) ([]byte, error) { + client := &http.Client{} + req, err := http.NewRequest("GET", f.ra.GetURL(), nil) + req.Header.Add("Accept", "application/octet-stream") + + if f.token != nil { + req.Header.Add("Authorization", "token "+*f.token) + } + + resp, err := client.Do(req) + if err != nil { + return nil, err + } + + log.Printf("Asset URL: %v, Content-Length: %v", f.ra.GetURL(), resp.ContentLength) + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + return body, nil +} diff --git a/main.go b/main.go index 009e6ad..0eb6ad5 100644 --- a/main.go +++ b/main.go @@ -4,7 +4,6 @@ import ( "context" "flag" "fmt" - "io/ioutil" "log" "net/http" "os" @@ -99,140 +98,3 @@ func main() { log.Fatal(err) } } - -type ReleaseAssets struct { - release *github.RepositoryRelease - assets []*github.ReleaseAsset -} - -type ReleaseAssetsMap map[string]ReleaseAssets - -func rasToDirents(rasm *ReleaseAssetsMap) []fuse.Dirent { - dirents := make([]fuse.Dirent, len(*rasm)) - - i := 0 - for tag, ras := range *rasm { - dirents[i] = fuse.Dirent{ - Inode: uint64(ras.release.GetID()), - Name: tag, - Type: fuse.DT_Dir, - } - i++ - } - return dirents -} - -func assetsToDirents(assets []*github.ReleaseAsset) []fuse.Dirent { - dirents := make([]fuse.Dirent, len(assets)) - - for i, asset := range assets { - dirents[i] = fuse.Dirent{ - Inode: uint64(asset.GetID()), - Name: asset.GetName(), - Type: fuse.DT_File, - } - } - return dirents -} - -// GhaFS implements the GitHub Release Assets file system. -type GhaFS struct { - rasm *ReleaseAssetsMap - token *string -} - -func NewGhaFS(rasm *ReleaseAssetsMap, token *string) GhaFS { - return GhaFS{rasm, token} -} - -func (g GhaFS) Root() (fs.Node, error) { - return RootDir{rasm: g.rasm, token: g.token}, nil -} - -// RootDir implements both Node and Handle for the root directory. -type RootDir struct { - rasm *ReleaseAssetsMap - token *string -} - -func (RootDir) Attr(ctx context.Context, a *fuse.Attr) error { - a.Inode = 1 - a.Mode = os.ModeDir | 0555 - return nil -} - -func (r RootDir) Lookup(ctx context.Context, name string) (fs.Node, error) { - for tag, ras := range *r.rasm { - if name == tag { - return TagDir{ras: &ras, token: r.token}, nil - } - } - - return nil, fuse.ENOENT -} - -func (r RootDir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) { - return rasToDirents(r.rasm), nil -} - -// TagDir implements both Node and Handle for the root directory. -type TagDir struct { - ras *ReleaseAssets - token *string -} - -func (t TagDir) Attr(ctx context.Context, a *fuse.Attr) error { - a.Inode = uint64(t.ras.release.GetID()) - a.Mode = os.ModeDir | 0555 - return nil -} - -func (t TagDir) Lookup(ctx context.Context, name string) (fs.Node, error) { - for _, asset := range t.ras.assets { - if name == asset.GetName() { - return File{ra: asset, token: t.token}, nil - } - } - return nil, fuse.ENOENT -} - -func (t TagDir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) { - return assetsToDirents(t.ras.assets), nil -} - -// File implements both Node and Handle for the hello file. -type File struct { - ra *github.ReleaseAsset - token *string -} - -func (f File) Attr(ctx context.Context, a *fuse.Attr) error { - a.Inode = uint64(f.ra.GetID()) - a.Mode = 0444 - a.Size = uint64(f.ra.GetSize()) - return nil -} - -func (f File) ReadAll(ctx context.Context) ([]byte, error) { - client := &http.Client{} - req, err := http.NewRequest("GET", f.ra.GetURL(), nil) - req.Header.Add("Accept", "application/octet-stream") - - if f.token != nil { - req.Header.Add("Authorization", "token "+*f.token) - } - - resp, err := client.Do(req) - if err != nil { - return nil, err - } - - log.Printf("Asset URL: %v, Content-Length: %v", f.ra.GetURL(), resp.ContentLength) - - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, err - } - - return body, nil -}