From 62d614d321ff6422fbd720585f3749f288b8da97 Mon Sep 17 00:00:00 2001 From: shaoying Date: Thu, 25 Feb 2021 18:38:49 +0800 Subject: [PATCH] opt nfs --- base/nfs/cat.go | 103 ++++++++++++++++++++++++ base/nfs/dir.go | 196 ++++++++++++++++++++++++++++++++++++++++++++++ base/nfs/save.go | 106 +++++++++++++++++++++++++ base/nfs/tail.go | 62 +++++++++++++++ base/nfs/trash.go | 56 +++++++++++++ 5 files changed, 523 insertions(+) create mode 100644 base/nfs/cat.go create mode 100644 base/nfs/dir.go create mode 100644 base/nfs/save.go create mode 100644 base/nfs/tail.go create mode 100644 base/nfs/trash.go diff --git a/base/nfs/cat.go b/base/nfs/cat.go new file mode 100644 index 00000000..13e241c1 --- /dev/null +++ b/base/nfs/cat.go @@ -0,0 +1,103 @@ +package nfs + +import ( + ice "github.com/shylinux/icebergs" + "github.com/shylinux/icebergs/base/aaa" + "github.com/shylinux/icebergs/base/mdb" + kit "github.com/shylinux/toolkits" + + "bufio" + "bytes" + "os" + "path" + "strings" +) + +func _cat_ext(name string) string { + return strings.ToLower(kit.Select(path.Base(name), strings.TrimPrefix(path.Ext(name), "."))) +} +func _cat_right(m *ice.Message, name string) bool { + switch strings.Split(name, "/")[0] { + case kit.SSH_ETC, kit.SSH_VAR: + if m.Warn(m.Option(ice.MSG_USERROLE) == aaa.VOID, ice.ErrNotRight, "of", name) { + return false + } + } + return true +} +func _cat_show(m *ice.Message, name string) { + if !_cat_right(m, name) { + return // 没有权限 + } + + // 本地文件 + if f, e := os.Open(path.Join(m.Option(DIR_ROOT), name)); e == nil { + defer f.Close() + + switch cb := m.Optionv(kit.Keycb(CAT)).(type) { + case func(string, int): + bio := bufio.NewScanner(f) + for i := 0; bio.Scan(); i++ { + cb(bio.Text(), i) + } + + default: + if s, e := f.Stat(); m.Assert(e) { + buf := make([]byte, s.Size()) + if n, e := f.Read(buf); m.Assert(e) { + m.Log_IMPORT(kit.MDB_FILE, name, kit.MDB_SIZE, n) + m.Echo(string(buf[:n])) + } + } + } + return + } + + // 打包文件 + if b, ok := ice.BinPack[name]; ok { + m.Logs("binpack", name, kit.MDB_SIZE, len(b)) + m.Echo(string(b)) + return + } + + // 远程文件 + switch cb := m.Optionv(kit.Keycb(CAT)).(type) { + case func(string, int): + bio := bufio.NewScanner(bytes.NewBufferString(m.Cmdx("web.spide", "dev", "raw", "GET", path.Join("/share/local/", name)))) + for i := 0; bio.Scan(); i++ { + cb(bio.Text(), i) + } + default: + m.Cmdy("web.spide", "dev", "raw", "GET", path.Join("/share/local/", name)) + } +} + +const CAT = "cat" + +func init() { + Index.Merge(&ice.Context{ + Configs: map[string]*ice.Config{ + CAT: {Name: CAT, Help: "文件", Value: kit.Data( + kit.SSH_SOURCE, kit.Dict( + "sh", "true", "shy", "true", "py", "true", + "go", "true", "vim", "true", "js", "true", + "conf", "true", "json", "true", + "makefile", "true", + ), + )}, + }, + Commands: map[string]*ice.Command{ + CAT: {Name: "cat path auto", Help: "文件", Action: map[string]*ice.Action{ + mdb.RENDER: {Name: "render type name text", Help: "渲染", Hand: func(m *ice.Message, arg ...string) { + _cat_show(m, path.Join(arg[2], arg[1])) + }}, + }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + if len(arg) == 0 || strings.HasSuffix(arg[0], "/") { + m.Cmdy(DIR, arg) + return + } + _cat_show(m, arg[0]) + }}, + }, + }) +} diff --git a/base/nfs/dir.go b/base/nfs/dir.go new file mode 100644 index 00000000..a1f42bc4 --- /dev/null +++ b/base/nfs/dir.go @@ -0,0 +1,196 @@ +package nfs + +import ( + ice "github.com/shylinux/icebergs" + "github.com/shylinux/icebergs/base/mdb" + kit "github.com/shylinux/toolkits" + + "bufio" + "crypto/sha1" + "encoding/hex" + "fmt" + "io/ioutil" + "os" + "path" + "regexp" + "sort" + "strings" +) + +func _dir_show(m *ice.Message, root string, name string, level int, deep bool, dir_type string, dir_reg *regexp.Regexp, fields []string) *ice.Message { + if !_cat_right(m, name) { + return m // 没有权限 + } + + fs, e := ioutil.ReadDir(path.Join(root, name)) + if e != nil { // 单个文件 + ls, _ := ioutil.ReadDir(path.Dir(path.Join(root, name))) + for _, k := range ls { + if k.Name() == path.Base(name) { + fs = append(fs, k) + } + } + name = path.Dir(name) + } + + for _, f := range fs { + if f.Name() == "." || f.Name() == ".." { + continue + } + if strings.HasPrefix(f.Name(), ".") && dir_type != TYPE_ALL { + continue + } + + p := path.Join(root, name, f.Name()) + if !(dir_type == TYPE_CAT && f.IsDir() || dir_type == TYPE_DIR && !f.IsDir()) && (dir_reg == nil || dir_reg.MatchString(f.Name())) { + for _, field := range fields { + switch field { + case kit.MDB_TIME: + m.Push(field, f.ModTime().Format(ice.MOD_TIME)) + case kit.MDB_TYPE: + m.Push(field, kit.Select(CAT, DIR, f.IsDir())) + + case "tree": + if level == 0 { + m.Push(field, f.Name()) + } else { + m.Push(field, strings.Repeat("| ", level-1)+"|-"+f.Name()) + } + case "full": + m.Push(field, path.Join(root, name, f.Name())+kit.Select("", "/", f.IsDir())) + + case kit.MDB_PATH: + m.Push(field, path.Join(name, f.Name())+kit.Select("", "/", f.IsDir())) + case kit.MDB_FILE: + m.Push(field, f.Name()+kit.Select("", "/", f.IsDir())) + case kit.MDB_NAME: + m.Push(field, f.Name()) + + case kit.MDB_LINK: + m.PushDownload(kit.MDB_LINK, kit.Select("", f.Name(), !f.IsDir()), path.Join(root, name, f.Name())) + + case kit.MDB_SIZE: + if f.IsDir() { + if ls, e := ioutil.ReadDir(path.Join(root, name, f.Name())); e == nil { + m.Push(field, len(ls)) + } else { + m.Push(field, 0) + } + } else { + m.Push(field, kit.FmtSize(f.Size())) + } + case kit.MDB_LINE: + if f.IsDir() { + if ls, e := ioutil.ReadDir(path.Join(root, name, f.Name())); e == nil { + m.Push(field, len(ls)) + } else { + m.Push(field, 0) + } + } else { + nline := 0 + if f, e := os.Open(p); m.Assert(e) { + defer f.Close() + for bio := bufio.NewScanner(f); bio.Scan(); nline++ { + bio.Text() + } + } + m.Push(field, nline) + } + case kit.MDB_HASH, "hashs": + var h [20]byte + if f.IsDir() { + if d, e := ioutil.ReadDir(p); m.Assert(e) { + meta := []string{} + for _, v := range d { + meta = append(meta, fmt.Sprintf("%s%d%s", v.Name(), v.Size(), v.ModTime())) + } + sort.Strings(meta) + h = sha1.Sum([]byte(strings.Join(meta, ""))) + } + } else { + if f, e := ioutil.ReadFile(path.Join(name, f.Name())); m.Assert(e) { + h = sha1.Sum(f) + } + } + + m.Push(kit.MDB_HASH, kit.Select(hex.EncodeToString(h[:6]), hex.EncodeToString(h[:]), field == kit.MDB_HASH)) + default: + m.Push(field, "") + } + } + } + + if f.IsDir() && deep { + _dir_show(m, root, path.Join(name, f.Name()), level+1, deep, dir_type, dir_reg, fields) + } + } + return m +} +func _dir_search(m *ice.Message, kind, name string) { + if kind == kit.MDB_FOREACH { + return + } + + msg := _dir_show(m.Spawn(), "./", "", 0, true, TYPE_BOTH, nil, strings.Split("time,type,name,text", ",")) + msg.Table(func(index int, value map[string]string, head []string) { + if !strings.Contains(value[kit.MDB_NAME], name) { + return + } + + if value[kit.MDB_TYPE] == CAT { + value[kit.MDB_TYPE] = _cat_ext(value[kit.MDB_NAME]) + } + + m.PushSearch(kit.SSH_CMD, CAT, value) + }) +} + +const ( + TYPE_ALL = "all" + TYPE_DIR = "dir" + TYPE_CAT = "cat" + TYPE_BOTH = "both" +) +const ( + DIR_ROOT = "dir_root" + DIR_TYPE = "dir_type" + DIR_DEEP = "dir_deep" + DIR_REG = "dir_reg" +) +const DIR = "dir" + +func init() { + Index.Merge(&ice.Context{ + Configs: map[string]*ice.Config{ + DIR: {Name: DIR, Help: "目录", Value: kit.Data()}, + }, + Commands: map[string]*ice.Command{ + DIR: {Name: "dir path field... auto upload", Help: "目录", Action: map[string]*ice.Action{ + mdb.SEARCH: {Name: "search type name", Help: "搜索", Hand: func(m *ice.Message, arg ...string) { + _dir_search(m, arg[0], arg[1]) + }}, + mdb.RENDER: {Name: "render type name text", Help: "渲染", Hand: func(m *ice.Message, arg ...string) { + _dir_show(m, arg[2], arg[1], 0, m.Option(DIR_DEEP) == "true", kit.Select(TYPE_BOTH, m.Option(DIR_TYPE)), + nil, kit.Split("time,size,type,path")) + }}, + + mdb.UPLOAD: {Name: "upload", Help: "上传", Hand: func(m *ice.Message, arg ...string) { + up := kit.Simple(m.Optionv(ice.MSG_UPLOAD)) + if p := path.Join(m.Option(kit.MDB_PATH), up[1]); m.Option(ice.MSG_USERPOD) == "" { + m.Cmdy("cache", "watch", up[0], p) + } else { + m.Cmdy("spide", "dev", "save", p, "GET", kit.MergeURL2(m.Option(ice.MSG_USERWEB), "/share/cache/"+up[0])) + } + }}, + }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + if len(arg) == 0 { + arg = append(arg, "") + } + _dir_show(m, kit.Select("./", m.Option(DIR_ROOT)), arg[0], + 0, m.Options(DIR_DEEP), kit.Select(TYPE_BOTH, m.Option(DIR_TYPE)), kit.Regexp(m.Option(DIR_REG)), + kit.Split(kit.Select("time,size,path", strings.Join(arg[1:], ",")))) + m.SortTimeR(kit.MDB_TIME) + }}, + }, + }) +} diff --git a/base/nfs/save.go b/base/nfs/save.go new file mode 100644 index 00000000..36eba5f8 --- /dev/null +++ b/base/nfs/save.go @@ -0,0 +1,106 @@ +package nfs + +import ( + ice "github.com/shylinux/icebergs" + kit "github.com/shylinux/toolkits" + + "io" + "os" + "path" + "strings" +) + +func _save_file(m *ice.Message, name string, text ...string) { + if f, p, e := kit.Create(path.Join(m.Option(DIR_ROOT), name)); m.Assert(e) { + defer f.Close() + + for _, v := range text { + if n, e := f.WriteString(v); m.Assert(e) { + m.Log_EXPORT(kit.MDB_FILE, p, kit.MDB_SIZE, n) + } + } + m.Echo(p) + } +} +func _push_file(m *ice.Message, name string, text ...string) { + p := path.Join(m.Option(DIR_ROOT), name) + if strings.Contains(p, "/") { + os.MkdirAll(path.Dir(p), ice.MOD_DIR) + } + + if f, e := os.OpenFile(p, os.O_WRONLY|os.O_APPEND|os.O_CREATE, ice.MOD_FILE); m.Assert(e) { + defer f.Close() + + for _, k := range text { + if n, e := f.WriteString(k); m.Assert(e) { + m.Log_EXPORT(kit.MDB_FILE, p, kit.MDB_SIZE, n) + } + } + m.Echo(p) + } +} +func _copy_file(m *ice.Message, name string, from ...string) { + if f, p, e := kit.Create(path.Join(m.Option(DIR_ROOT), name)); m.Assert(e) { + defer f.Close() + + for _, v := range from { + if s, e := os.Open(v); !m.Warn(e != nil, e) { + defer s.Close() + + if n, e := io.Copy(f, s); !m.Warn(e != nil, e) { + m.Log_IMPORT(kit.MDB_FILE, v, kit.MDB_SIZE, n) + m.Log_EXPORT(kit.MDB_FILE, p, kit.MDB_SIZE, n) + } + } + } + m.Echo(p) + } +} +func _link_file(m *ice.Message, name string, from string) { + if from == "" { + return + } + os.Remove(name) + os.MkdirAll(path.Dir(name), ice.MOD_DIR) + os.Link(from, name) + m.Echo(name) +} +func _defs_file(m *ice.Message, name string, text ...string) { + if _, e := os.Stat(path.Join(m.Option(DIR_ROOT), name)); os.IsNotExist(e) { + _save_file(m, name, text...) + } +} + +const SAVE = "save" +const PUSH = "push" +const COPY = "copy" +const LINK = "link" +const DEFS = "defs" + +func init() { + Index.Merge(&ice.Context{ + Commands: map[string]*ice.Command{ + SAVE: {Name: "save file text...", Help: "保存", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + if len(arg) == 1 { + arg = append(arg, m.Option(kit.MDB_CONTENT)) + } + _save_file(m, arg[0], arg[1:]...) + }}, + PUSH: {Name: "push file text...", Help: "追加", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + if len(arg) == 1 { + arg = append(arg, m.Option(kit.MDB_CONTENT)) + } + _push_file(m, arg[0], arg[1:]...) + }}, + COPY: {Name: "copy file from...", Help: "复制", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + _copy_file(m, arg[0], arg[1:]...) + }}, + LINK: {Name: "link file from", Help: "链接", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + _link_file(m, arg[0], arg[1]) + }}, + DEFS: {Name: "defs file text...", Help: "默认", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + _defs_file(m, arg[0], arg[1:]...) + }}, + }, + }) +} diff --git a/base/nfs/tail.go b/base/nfs/tail.go new file mode 100644 index 00000000..8f923f72 --- /dev/null +++ b/base/nfs/tail.go @@ -0,0 +1,62 @@ +package nfs + +import ( + ice "github.com/shylinux/icebergs" + "github.com/shylinux/icebergs/base/cli" + "github.com/shylinux/icebergs/base/mdb" + kit "github.com/shylinux/toolkits" + + "bufio" + "io" +) + +func _tail_create(m *ice.Message, arg ...string) { + if m.Option(kit.MDB_HASH) == "" { + m.Option(kit.MDB_HASH, m.Cmdx(mdb.INSERT, TAIL, "", mdb.HASH, arg)) + } + + kit.ForEach(kit.Split(m.Option(kit.MDB_FILE), ","), func(file string) { + r, w := io.Pipe() + m.Go(func() { + for bio := bufio.NewScanner(r); bio.Scan(); { + m.Log_IMPORT(kit.MDB_FILE, file, kit.MDB_SIZE, len(bio.Text())) + m.Grow(TAIL, kit.Keys(kit.MDB_HASH, m.Option(kit.MDB_HASH)), kit.Dict( + kit.MDB_FILE, file, kit.MDB_SIZE, len(bio.Text()), kit.MDB_TEXT, bio.Text(), + )) + } + }) + + m.Option(cli.CMD_STDOUT, w) + m.Option(cli.CMD_STDERR, w) + m.Option(mdb.CACHE_CLEAR_ON_EXIT, "true") + m.Cmd(cli.DAEMON, TAIL, "-n", "0", "-f", file) + }) +} + +const TAIL = "tail" + +func init() { + Index.Merge(&ice.Context{ + Configs: map[string]*ice.Config{ + TAIL: {Name: TAIL, Help: "跟踪", Value: kit.Data()}, + }, + Commands: map[string]*ice.Command{ + TAIL: {Name: "tail hash id auto create", Help: "跟踪", Action: map[string]*ice.Action{ + mdb.CREATE: {Name: "create file name", Help: "创建", Hand: func(m *ice.Message, arg ...string) { + _tail_create(m, arg...) + }}, + mdb.REMOVE: {Name: "remove", Help: "删除", Hand: func(m *ice.Message, arg ...string) { + m.Cmdy(mdb.DELETE, TAIL, "", mdb.HASH, kit.MDB_HASH, m.Option(kit.MDB_HASH)) + }}, + }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + m.Option(mdb.FIELDS, kit.Select("time,hash,count,name,file", kit.Select("time,id,file,text", mdb.DETAIL, len(arg) > 1), len(arg) > 0)) + + if m.Cmdy(mdb.SELECT, TAIL, "", mdb.ZONE, arg); len(arg) == 0 { + m.PushAction(mdb.REMOVE) + } else if len(arg) == 1 { + m.Option(ice.MSG_CONTROL, ice.CONTROL_PAGE) + } + }}, + }, + }) +} diff --git a/base/nfs/trash.go b/base/nfs/trash.go new file mode 100644 index 00000000..71f91822 --- /dev/null +++ b/base/nfs/trash.go @@ -0,0 +1,56 @@ +package nfs + +import ( + ice "github.com/shylinux/icebergs" + "github.com/shylinux/icebergs/base/cli" + "github.com/shylinux/icebergs/base/mdb" + kit "github.com/shylinux/toolkits" + + "os" + "path" +) + +func _trash_create(m *ice.Message, name string) { + if s, e := os.Stat(name); e == nil { + if s.IsDir() { + tar := path.Base(name) + ".tar.gz" + m.Cmd(cli.SYSTEM, "tar", "zcf", tar, name) + name = tar + } + + if f, e := os.Open(name); m.Assert(e) { + defer f.Close() + + h := kit.Hashs(f) + p := path.Join(m.Conf(TRASH, kit.META_PATH), h[:2], h) + os.MkdirAll(path.Dir(p), ice.MOD_DIR) + os.Rename(name, p) + m.Cmdy(mdb.INSERT, TRASH, "", mdb.LIST, kit.MDB_FILE, p, kit.MDB_FROM, name) + } + } +} + +const TRASH = "trash" + +func init() { + Index.Merge(&ice.Context{ + Configs: map[string]*ice.Config{ + TRASH: {Name: TRASH, Help: "删除", Value: kit.Data(kit.MDB_PATH, "var/trash")}, + }, + Commands: map[string]*ice.Command{ + TRASH: {Name: "trash file auto", Help: "删除", Action: map[string]*ice.Action{ + "recover": {Name: "recover", Help: "恢复", Hand: func(m *ice.Message, arg ...string) { + os.Rename(m.Option(kit.MDB_FILE), m.Option(kit.MDB_FROM)) + }}, + }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + if len(arg) == 0 { + m.Option(mdb.FIELDS, "time,id,file,from") + m.Cmdy(mdb.SELECT, TRASH, "", mdb.LIST) + m.PushAction("recover") + return + } + _trash_create(m, arg[0]) + }}, + }, + }) +}