From 122c3295ff80250e0784d318bf1e1ccbf1f14e96 Mon Sep 17 00:00:00 2001 From: shaoying Date: Tue, 1 Jun 2021 01:09:52 +0800 Subject: [PATCH] opt ssh.connect --- base/aaa/totp.go | 2 +- base/cli/cli.go | 67 ++++++++----- base/cli/daemon.go | 21 ++--- base/cli/runtime.go | 5 +- base/gdb/gdb.go | 5 +- base/gdb/signal.go | 16 +++- base/gdb/timer.go | 20 ++-- base/mdb/mdb.go | 14 +-- base/nfs/dir.go | 2 +- base/nfs/tail.go | 5 +- base/nfs/trash.go | 4 +- base/ssh/connect.go | 223 ++++++++++++++++++-------------------------- base/ssh/session.go | 67 ++++--------- conf.go | 1 + exec.go | 6 +- 15 files changed, 211 insertions(+), 247 deletions(-) diff --git a/base/aaa/totp.go b/base/aaa/totp.go index 081e4180..f3d45f01 100644 --- a/base/aaa/totp.go +++ b/base/aaa/totp.go @@ -85,7 +85,7 @@ func init() { m.Push("code", _totp_get(value[SECRET], kit.Int(value[NUMBER]), period)) if len(arg) > 0 { - m.PushQRCode("show", kit.Format(m.Conf(TOTP, kit.Keym(kit.MDB_LINK)), value[kit.MDB_NAME], value[SECRET])) + m.PushQRCode("scan", kit.Format(m.Conf(TOTP, kit.Keym(kit.MDB_LINK)), value[kit.MDB_NAME], value[SECRET])) m.Echo(_totp_get(value[SECRET], kit.Int(value[NUMBER]), kit.Int64(value[PERIOD]))) } }) diff --git a/base/cli/cli.go b/base/cli/cli.go index 0d390a05..7240147c 100644 --- a/base/cli/cli.go +++ b/base/cli/cli.go @@ -13,12 +13,33 @@ import ( func NodeInfo(m *ice.Message, kind, name string) { name = strings.ReplaceAll(name, ".", "_") - m.Conf(RUNTIME, "node.type", kind) - m.Conf(RUNTIME, "node.name", name) + m.Conf(RUNTIME, kit.Keys(NODE, kit.MDB_TYPE), kind) + m.Conf(RUNTIME, kit.Keys(NODE, kit.MDB_NAME), name) ice.Info.NodeName = name ice.Info.NodeType = kind } +const ( + MAKE = "make" + CONF = "conf" + HOST = "host" + BOOT = "boot" + NODE = "node" +) +const ( + HOSTNAME = "hostname" + PATHNAME = "pathname" + USERNAME = "username" +) +const ( + CTX_SELF = "ctx_self" + CTX_DEV = "ctx_dev" + CTX_SHY = "ctx_shy" + CTX_PID = "ctx_pid" + CTX_USER = "ctx_user" + CTX_SHARE = "ctx_share" + CTX_RIVER = "ctx_river" +) const CLI = "cli" var Index = &ice.Context{Name: CLI, Help: "命令模块", @@ -27,18 +48,18 @@ var Index = &ice.Context{Name: CLI, Help: "命令模块", m.Load() // 启动配置 - for _, k := range []string{"ctx_self", "ctx_dev", "ctx_shy", "ctx_pid", "ctx_user", "ctx_share", "ctx_river"} { - m.Conf(RUNTIME, kit.Keys("conf", k), os.Getenv(k)) + for _, k := range []string{CTX_SELF, CTX_DEV, CTX_SHY, CTX_PID, CTX_USER, CTX_SHARE, CTX_RIVER} { + m.Conf(RUNTIME, kit.Keys(CONF, k), os.Getenv(k)) } // 主机信息 - m.Conf(RUNTIME, "host.GOARCH", runtime.GOARCH) - m.Conf(RUNTIME, "host.GOOS", runtime.GOOS) - m.Conf(RUNTIME, "host.pid", os.Getpid()) + m.Conf(RUNTIME, kit.Keys(HOST, "GOARCH"), runtime.GOARCH) + m.Conf(RUNTIME, kit.Keys(HOST, "GOOS"), runtime.GOOS) + m.Conf(RUNTIME, kit.Keys(HOST, "pid"), os.Getpid()) // 启动信息 if name, e := os.Hostname(); e == nil { - m.Conf(RUNTIME, "boot.hostname", kit.Select(name, os.Getenv("HOSTNAME"))) + m.Conf(RUNTIME, kit.Keys(BOOT, HOSTNAME), kit.Select(name, os.Getenv("HOSTNAME"))) } if name, e := os.Getwd(); e == nil { name = path.Base(kit.Select(name, os.Getenv("PWD"))) @@ -46,36 +67,36 @@ var Index = &ice.Context{Name: CLI, Help: "命令模块", name = ls[len(ls)-1] ls = strings.Split(name, "\\") name = ls[len(ls)-1] - m.Conf(RUNTIME, "boot.pathname", name) + m.Conf(RUNTIME, kit.Keys(BOOT, PATHNAME), name) } - if m.Conf(RUNTIME, "boot.username", kit.Select(os.Getenv("USER"), os.Getenv("ctx_user"))) == "" { + if m.Conf(RUNTIME, kit.Keys(BOOT, USERNAME), kit.Select(os.Getenv(USER), os.Getenv(CTX_USER))) == "" { if user, e := user.Current(); e == nil && user.Name != "" { - m.Conf(RUNTIME, "boot.username", kit.Select(user.Name, os.Getenv("ctx_user"))) + m.Conf(RUNTIME, kit.Keys(BOOT, USERNAME), kit.Select(user.Name, os.Getenv(CTX_USER))) } } - ice.Info.HostName = m.Conf(RUNTIME, "boot.hostname") - ice.Info.PathName = m.Conf(RUNTIME, "boot.pathname") - ice.Info.UserName = m.Conf(RUNTIME, "boot.username") + ice.Info.HostName = m.Conf(RUNTIME, kit.Keys(BOOT, HOSTNAME)) + ice.Info.PathName = m.Conf(RUNTIME, kit.Keys(BOOT, PATHNAME)) + ice.Info.UserName = m.Conf(RUNTIME, kit.Keys(BOOT, USERNAME)) - ice.Info.CtxShare = m.Conf(RUNTIME, "conf.ctx_share") - ice.Info.CtxRiver = m.Conf(RUNTIME, "conf.ctx_river") + ice.Info.CtxShare = m.Conf(RUNTIME, kit.Keys(CONF, CTX_SHARE)) + ice.Info.CtxRiver = m.Conf(RUNTIME, kit.Keys(CONF, CTX_RIVER)) // 启动次数 - count := kit.Int(m.Conf(RUNTIME, "boot.count")) + 1 - m.Conf(RUNTIME, "boot.count", count) + count := kit.Int(m.Conf(RUNTIME, kit.Keys(BOOT, kit.MDB_COUNT))) + 1 + m.Conf(RUNTIME, kit.Keys(BOOT, kit.MDB_COUNT), count) // 节点信息 - m.Conf(RUNTIME, "node.time", m.Time()) - NodeInfo(m, "worker", m.Conf(RUNTIME, "boot.pathname")) + m.Conf(RUNTIME, kit.Keys(NODE, kit.MDB_TIME), m.Time()) + NodeInfo(m, "worker", m.Conf(RUNTIME, kit.Keys(BOOT, PATHNAME))) m.Info("runtime %v", kit.Formats(m.Confv(RUNTIME))) - n := kit.Int(kit.Select("1", m.Conf(RUNTIME, "host.GOMAXPROCS"))) - m.Logs("host", "gomaxprocs", n) + n := kit.Int(kit.Select("1", m.Conf(RUNTIME, kit.Keys(HOST, "GOMAXPROCS")))) + m.Logs(HOST, "GOMAXPROCS", n) runtime.GOMAXPROCS(n) // 版本信息 kit.Fetch(kit.UnMarshal(kit.Format(ice.Info.Build)), func(key string, value interface{}) { - m.Conf(RUNTIME, kit.Keys("make", strings.ToLower(key)), value) + m.Conf(RUNTIME, kit.Keys(MAKE, strings.ToLower(key)), value) }) }}, ice.CTX_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { diff --git a/base/cli/daemon.go b/base/cli/daemon.go index e53dd33d..969a0820 100644 --- a/base/cli/daemon.go +++ b/base/cli/daemon.go @@ -37,7 +37,7 @@ func _daemon_show(m *ice.Message, cmd *exec.Cmd, out, err string) { m.Go(func() { h := m.Cmdx(mdb.INSERT, DAEMON, "", mdb.HASH, - kit.MDB_STATUS, Status.Start, kit.SSH_PID, cmd.Process.Pid, + kit.MDB_STATUS, START, kit.SSH_PID, cmd.Process.Pid, kit.SSH_CMD, strings.Join(cmd.Args, " "), kit.SSH_DIR, cmd.Dir, kit.SSH_ENV, kit.Select("", cmd.Env), mdb.CACHE_CLEAR_ON_EXIT, m.Option(mdb.CACHE_CLEAR_ON_EXIT), @@ -46,11 +46,11 @@ func _daemon_show(m *ice.Message, cmd *exec.Cmd, out, err string) { if e := cmd.Wait(); m.Warn(e != nil, cmd.Args, " ", e) { m.Cmd(mdb.MODIFY, DAEMON, "", mdb.HASH, kit.MDB_HASH, h, - kit.MDB_STATUS, Status.Error, kit.MDB_ERROR, e) + kit.MDB_STATUS, ERROR, kit.MDB_ERROR, e) } else { m.Cost("args", cmd.Args, "code", cmd.ProcessState.ExitCode()) m.Cmd(mdb.MODIFY, DAEMON, "", mdb.HASH, kit.MDB_HASH, h, - kit.MDB_STATUS, Status.Stop) + kit.MDB_STATUS, STOP) } if w, ok := m.Optionv(CMD_OUTPUT).(io.Closer); ok { @@ -62,12 +62,6 @@ func _daemon_show(m *ice.Message, cmd *exec.Cmd, out, err string) { }) } -var Status = struct{ Error, Start, Stop string }{ - Error: "error", - Start: "start", - Stop: "stop", -} - const ( DIR = "dir" ENV = "env" @@ -80,6 +74,7 @@ const ( const ( RESTART = "restart" START = "start" + ERROR = "error" STOP = "stop" ) @@ -120,7 +115,7 @@ func init() { STOP: {Name: "stop", Help: "停止", Hand: func(m *ice.Message, arg ...string) { m.Option(mdb.FIELDS, "time,hash,status,pid,cmd,dir,env") m.Cmd(mdb.SELECT, DAEMON, "", mdb.HASH, kit.MDB_HASH, m.Option(kit.MDB_HASH)).Table(func(index int, value map[string]string, head []string) { - m.Cmd(mdb.MODIFY, DAEMON, "", mdb.HASH, kit.MDB_HASH, m.Option(kit.MDB_HASH), kit.MDB_STATUS, Status.Stop) + m.Cmd(mdb.MODIFY, DAEMON, "", mdb.HASH, kit.MDB_HASH, m.Option(kit.MDB_HASH), kit.MDB_STATUS, STOP) m.Cmdy(SYSTEM, "kill", "-9", value[kit.SSH_PID]) }) }}, @@ -129,8 +124,8 @@ func init() { }}, mdb.PRUNES: {Name: "prunes", Help: "清理", Hand: func(m *ice.Message, arg ...string) { m.Option(mdb.FIELDS, "time,hash,status,pid,cmd,dir,env") - m.Cmdy(mdb.PRUNES, DAEMON, "", mdb.HASH, kit.MDB_STATUS, Status.Error) - m.Cmdy(mdb.PRUNES, DAEMON, "", mdb.HASH, kit.MDB_STATUS, Status.Stop) + m.Cmdy(mdb.PRUNES, DAEMON, "", mdb.HASH, kit.MDB_STATUS, ERROR) + m.Cmdy(mdb.PRUNES, DAEMON, "", mdb.HASH, kit.MDB_STATUS, STOP) }}, }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { if len(arg) == 0 { // 进程列表 @@ -138,7 +133,7 @@ func init() { m.Cmdy(mdb.SELECT, DAEMON, "", mdb.HASH) m.Table(func(index int, value map[string]string, head []string) { switch value[kit.MDB_STATUS] { - case Status.Start: + case START: m.PushButton(RESTART, STOP) default: m.PushButton(mdb.REMOVE) diff --git a/base/cli/runtime.go b/base/cli/runtime.go index a736692b..e309318d 100644 --- a/base/cli/runtime.go +++ b/base/cli/runtime.go @@ -14,7 +14,6 @@ import ( const ( DISKINFO = "diskinfo" IFCONFIG = "ifconfig" - HOSTNAME = "hostname" HOSTINFO = "hostinfo" USERINFO = "userinfo" PROCINFO = "procinfo" @@ -41,8 +40,8 @@ func init() { }}, HOSTNAME: {Name: "hostname", Help: "主机域名", Hand: func(m *ice.Message, arg ...string) { if len(arg) > 0 { - m.Conf(RUNTIME, "boot.hostname", arg[0]) - m.Conf(RUNTIME, "node.name", arg[0]) + m.Conf(RUNTIME, kit.Keys(NODE, kit.MDB_NAME), arg[0]) + m.Conf(RUNTIME, kit.Keys(BOOT, HOSTNAME), arg[0]) ice.Info.HostName = arg[0] } m.Echo(ice.Info.HostName) diff --git a/base/gdb/gdb.go b/base/gdb/gdb.go index f4420723..d4d79006 100644 --- a/base/gdb/gdb.go +++ b/base/gdb/gdb.go @@ -20,7 +20,7 @@ func (f *Frame) Spawn(m *ice.Message, c *ice.Context, arg ...string) ice.Server return &Frame{} } func (f *Frame) Begin(m *ice.Message, arg ...string) ice.Server { - f.t = time.Tick(kit.Duration(m.Cap(ice.CTX_STREAM, ice.MOD_TICK))) + f.t = time.Tick(kit.Duration(m.Conf(TIMER, kit.Keym("tick")))) f.s = make(chan os.Signal, ice.MOD_CHAN) f.e = make(chan bool, 1) return f @@ -65,7 +65,8 @@ const GDB = "gdb" var Index = &ice.Context{Name: GDB, Help: "事件模块", Commands: map[string]*ice.Command{ ice.CTX_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - m.Cmd(nfs.SAVE, kit.Select(m.Conf(SIGNAL, kit.META_PATH), m.Conf(cli.RUNTIME, "conf.ctx_pid")), m.Conf(cli.RUNTIME, "host.pid")) + m.Cmd(nfs.SAVE, kit.Select(m.Conf(SIGNAL, kit.META_PATH), m.Conf(cli.RUNTIME, kit.Keys(cli.CONF, cli.CTX_PID))), + m.Conf(cli.RUNTIME, kit.Keys(cli.HOST, "pid"))) m.Cmd(SIGNAL, LISTEN, SIGNAL, "3", kit.MDB_NAME, "退出", kit.SSH_CMD, "exit 0") m.Cmd(SIGNAL, LISTEN, SIGNAL, "2", kit.MDB_NAME, "重启", kit.SSH_CMD, "exit 1") diff --git a/base/gdb/signal.go b/base/gdb/signal.go index 2eecb441..548bfca4 100644 --- a/base/gdb/signal.go +++ b/base/gdb/signal.go @@ -1,7 +1,9 @@ package gdb import ( + "os" "os/signal" + "path" "syscall" ice "github.com/shylinux/icebergs" @@ -23,6 +25,18 @@ func _signal_action(m *ice.Message, s int) { }) } +func SignalNotify(m *ice.Message, sig int, cb func()) { + ch := make(chan os.Signal) + signal.Notify(ch, syscall.Signal(sig)) + m.Go(func() { + for { + if _, ok := <-ch; ok { + cb() + } + } + }) +} + const ( LISTEN = "listen" ACTION = "action" @@ -33,7 +47,7 @@ func init() { Index.Merge(&ice.Context{ Configs: map[string]*ice.Config{ SIGNAL: {Name: SIGNAL, Help: "信号器", Value: kit.Data( - kit.MDB_PATH, "var/run/ice.pid", kit.MDB_SHORT, SIGNAL, + kit.MDB_PATH, path.Join(ice.VAR_RUN, "ice.pid"), kit.MDB_SHORT, SIGNAL, )}, }, Commands: map[string]*ice.Command{ diff --git a/base/gdb/timer.go b/base/gdb/timer.go index 83488e2c..c564050f 100644 --- a/base/gdb/timer.go +++ b/base/gdb/timer.go @@ -9,7 +9,7 @@ import ( ) func _timer_create(m *ice.Message, arg ...string) { - m.Cmdy(mdb.INSERT, TIMER, "", mdb.HASH, "delay", "10ms", "interval", "10m", "order", 1, "next", m.Time(m.Option("delay")), arg) + m.Cmdy(mdb.INSERT, TIMER, "", mdb.HASH, DELAY, "10ms", INTERVAL, "10m", ORDER, 1, NEXT, m.Time(m.Option(DELAY)), arg) } func _timer_action(m *ice.Message, arg ...string) { now := time.Now().UnixNano() @@ -20,19 +20,25 @@ func _timer_action(m *ice.Message, arg ...string) { return } - order := kit.Int(value["order"]) - if n := kit.Time(kit.Format(value["next"])); now > n && order > 0 { - m.Logs(TIMER, "key", key, "order", order) + order := kit.Int(value[ORDER]) + if n := kit.Time(kit.Format(value[NEXT])); now > n && order > 0 { + m.Logs(TIMER, kit.MDB_KEY, key, ORDER, order) msg := m.Cmd(value[kit.SSH_CMD]) m.Grow(TIMER, kit.Keys(kit.MDB_HASH, key), kit.Dict("res", msg.Result())) - if value["order"] = kit.Format(order - 1); order > 1 { - value["next"] = msg.Time(value["interval"]) + if value[ORDER] = kit.Format(order - 1); order > 1 { + value[NEXT] = msg.Time(value[INTERVAL]) } } }) } +const ( + DELAY = "delay" + INTERVAL = "interval" + ORDER = "order" + NEXT = "next" +) const TIMER = "timer" func init() { @@ -53,7 +59,7 @@ func init() { }}, mdb.PRUNES: {Name: "prunes", Help: "清理", Hand: func(m *ice.Message, arg ...string) { m.Option(mdb.FIELDS, "time,hash,delay,interval,order,next,cmd") - m.Cmdy(mdb.PRUNES, TIMER, "", mdb.HASH, "order", 0) + m.Cmdy(mdb.PRUNES, TIMER, "", mdb.HASH, ORDER, 0) }}, ACTION: {Name: "action", Help: "执行", Hand: func(m *ice.Message, arg ...string) { diff --git a/base/mdb/mdb.go b/base/mdb/mdb.go index 78d1fe49..1f2f4e08 100644 --- a/base/mdb/mdb.go +++ b/base/mdb/mdb.go @@ -13,7 +13,7 @@ import ( ) func _file_name(m *ice.Message, arg ...string) string { - return kit.Select(path.Join(m.Option(ice.MSG_LOCAL), "usr/local/export", path.Join(arg[:2]...), arg[2]), arg, 3) + return kit.Select(path.Join(m.Option(ice.MSG_LOCAL), ice.USR_LOCAL, EXPORT, path.Join(arg[:2]...), arg[2]), arg, 3) } func _domain_chain(m *ice.Message, chain string) string { return kit.Keys(m.Option(ice.MSG_DOMAIN), chain) @@ -157,7 +157,7 @@ func _list_select(m *ice.Message, prefix, chain, field, value string) { } fields := _list_fields(m) cb := m.Optionv(kit.Keycb(SELECT)) - m.Grows(prefix, chain, kit.Select(m.Option("cache.field"), field), kit.Select(m.Option(CACHE_VALUE), value), func(index int, val map[string]interface{}) { + m.Grows(prefix, chain, kit.Select(m.Option(CACHE_FIELD), field), kit.Select(m.Option(CACHE_VALUE), value), func(index int, val map[string]interface{}) { val = kit.GetMeta(val) switch cb := cb.(type) { case func(fields []string, value map[string]interface{}): @@ -263,7 +263,7 @@ func _list_inputs(m *ice.Message, prefix, chain string, field, value string) { m.Push(field, k) m.Push(kit.MDB_COUNT, i) } - m.Sort(kit.MDB_COUNT, "int_r") + m.SortIntR(kit.MDB_COUNT) } func _zone_fields(m *ice.Message) []string { @@ -404,6 +404,7 @@ const ( SELECT = "select" DELETE = "delete" REMOVE = "remove" + REVERT = "revert" EXPORT = "export" IMPORT = "import" @@ -412,14 +413,9 @@ const ( ) const ( CACHE_LIMIT = "cache.limit" - CACHE_FILED = "cache.field" + CACHE_FIELD = "cache.field" CACHE_VALUE = "cache.value" - CACHE_STATUS = "cache.status" - CACHE_ACTION = "cache.action" - CACHE_BEGIN = "cache.begin" - CACHE_HASH = "cache.hash" - CACHE_CLEAR_ON_EXIT = "cache.clear.on.exit" ) diff --git a/base/nfs/dir.go b/base/nfs/dir.go index 10f26504..1b33bd3b 100644 --- a/base/nfs/dir.go +++ b/base/nfs/dir.go @@ -178,7 +178,7 @@ func init() { _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)), + _dir_show(m, arg[2], arg[1], 0, m.Option(DIR_DEEP) == ice.TRUE, kit.Select(TYPE_BOTH, m.Option(DIR_TYPE)), nil, kit.Split("time,size,type,path")) }}, diff --git a/base/nfs/tail.go b/base/nfs/tail.go index f13cfc7d..b967fcbc 100644 --- a/base/nfs/tail.go +++ b/base/nfs/tail.go @@ -28,7 +28,7 @@ func _tail_create(m *ice.Message, arg ...string) { m.Option(cli.CMD_OUTPUT, w) m.Option(cli.CMD_ERRPUT, w) - m.Option(mdb.CACHE_CLEAR_ON_EXIT, "true") + m.Option(mdb.CACHE_CLEAR_ON_EXIT, ice.TRUE) m.Cmd(cli.DAEMON, TAIL, "-n", "0", "-f", file) }) } @@ -55,7 +55,6 @@ func init() { offend = total - kit.Int(kit.Select("10", arg, 2)) m.Toast("已经是最后一页啦!") } - m.ProcessRewrite("offend", offend) }}, "next": {Name: "next", Help: "下一页", Hand: func(m *ice.Message, arg ...string) { @@ -68,7 +67,7 @@ func init() { }}, }, 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 && arg[1] != ""), len(arg) > 0)) - m.Option("cache.limit", kit.Select("10", arg, 2)) + m.Option(mdb.CACHE_LIMIT, kit.Select("10", arg, 2)) m.Option("cache.offend", kit.Select("0", arg, 3)) if m.Cmdy(mdb.SELECT, TAIL, "", mdb.ZONE, arg); len(arg) == 0 { diff --git a/base/nfs/trash.go b/base/nfs/trash.go index 2b316c9f..ebc9fbbf 100644 --- a/base/nfs/trash.go +++ b/base/nfs/trash.go @@ -44,7 +44,7 @@ func init() { }, Commands: map[string]*ice.Command{ TRASH: {Name: "trash file auto prunes", Help: "回收站", Action: map[string]*ice.Action{ - "recover": {Name: "recover", Help: "恢复", Hand: func(m *ice.Message, arg ...string) { + mdb.REVERT: {Name: "revert", Help: "恢复", Hand: func(m *ice.Message, arg ...string) { os.Rename(m.Option(kit.MDB_FILE), m.Option(kit.MDB_FROM)) m.Cmd(mdb.DELETE, TRASH, "", mdb.HASH, kit.MDB_HASH, m.Option(kit.MDB_HASH)) }}, @@ -59,7 +59,7 @@ func init() { if len(arg) == 0 { m.Option(mdb.FIELDS, "time,hash,file,from") m.Cmdy(mdb.SELECT, TRASH, "", mdb.HASH) - m.PushAction("recover", mdb.REMOVE) + m.PushAction(mdb.REVERT, mdb.REMOVE) return } _trash_create(m, arg[0]) diff --git a/base/ssh/connect.go b/base/ssh/connect.go index 2ca212bb..7b81bbc9 100644 --- a/base/ssh/connect.go +++ b/base/ssh/connect.go @@ -8,11 +8,11 @@ import ( "os" "path" "strings" - "time" ice "github.com/shylinux/icebergs" "github.com/shylinux/icebergs/base/aaa" "github.com/shylinux/icebergs/base/cli" + "github.com/shylinux/icebergs/base/gdb" "github.com/shylinux/icebergs/base/mdb" "github.com/shylinux/icebergs/base/nfs" "github.com/shylinux/icebergs/base/tcp" @@ -21,72 +21,103 @@ import ( "golang.org/x/crypto/ssh/terminal" ) -func _ssh_tick(m *ice.Message, pw io.Writer) { - if m.Option("tick") == "" { - return - } - m.Go(func() { - for { - m.Sleep(m.Option("tick")) - pw.Write([]byte("# " + time.Now().Format(ice.MOD_TIME) + "\n")) - } - }) -} -func _ssh_password(m *ice.Message, file string) { - if f, e := os.Open(file); e == nil { +func _ssh_open(m *ice.Message, arg ...string) { + // 加载配置 + if f, e := os.Open(m.Option("authfile")); e == nil { defer f.Close() var data interface{} json.NewDecoder(f).Decode(&data) - kit.Fetch(data, func(key string, value string) { m.Option(key, value) }) + kit.Fetch(data, func(key string, value interface{}) { m.Option(key, kit.Simple(value)) }) } + + _ssh_dial(m, func(c net.Conn) { + // 保存界面 + fd := int(os.Stdin.Fd()) + if oldState, err := terminal.MakeRaw(fd); err == nil { + defer terminal.Restore(fd, oldState) + } + + // 设置宽高 + w, h, _ := terminal.GetSize(fd) + c.Write([]byte(fmt.Sprintf("height:%d,width:%d\n", h, w))) + + // 初始命令 + for _, item := range kit.Simple(m.Optionv("list")) { + m.Sleep("10ms") + c.Write([]byte(item + "\n")) + } + + m.Go(func() { io.Copy(os.Stdout, c) }) + io.Copy(c, os.Stdin) + }, arg...) } -func _ssh_stream(m *ice.Message, stdin *os.File) (io.Reader, io.Writer) { - pr, pw := io.Pipe() - m.Go(func() { - buf := make([]byte, 1024) - for { - if n, e := stdin.Read(buf); m.Assert(e) { - pw.Write(buf[:n]) +func _ssh_dial(m *ice.Message, cb func(net.Conn), arg ...string) { + p := path.Join(os.Getenv(cli.HOME), ".ssh/", fmt.Sprintf("%s@%s:%s", m.Option(aaa.USERNAME), m.Option(tcp.HOST), m.Option(tcp.PORT))) + if _, e := os.Stat(p); e == nil { + if c, e := net.Dial("unix", p); e == nil { + cb(c) // 会话连接 + return + } + os.Remove(p) + } + + var client *ssh.Client + if l, e := net.Listen("unix", p); m.Assert(e) { + defer func() { os.Remove(p) }() + defer l.Close() + + m.Go(func() { + for { + c, e := l.Accept() + m.Assert(e) + + func(c net.Conn) { + w, h, _ := terminal.GetSize(int(os.Stdin.Fd())) + buf := make([]byte, ice.MOD_BUFS) + if n, e := c.Read(buf); m.Assert(e) { + fmt.Sscanf(string(buf[:n]), "height:%d,width:%d", &h, &w) + } + + m.Go(func() { + defer c.Close() + + session, e := client.NewSession() + m.Assert(e) + + session.Stdin = c + session.Stdout = c + session.Stderr = c + + session.RequestPty(os.Getenv("TERM"), h, w, ssh.TerminalModes{ + ssh.ECHO: 1, + ssh.TTY_OP_ISPEED: 14400, + ssh.TTY_OP_OSPEED: 14400, + }) + + gdb.SignalNotify(m, 28, func() { + w, h, _ := terminal.GetSize(int(os.Stdin.Fd())) + session.WindowChange(h, w) + }) + + session.Shell() + session.Wait() + }) + }(c) } + }) + } + + m.Option(kit.Keycb(tcp.DIAL), func(c net.Conn) { + client = _ssh_conn(m, c, m.Option(aaa.USERNAME), m.Option(tcp.HOST)+":"+m.Option(tcp.PORT)) + + if c, e := net.Dial("unix", p); e == nil { + cb(c) // 会话连接 } }) - return pr, pw -} -func _ssh_store(stdio *os.File) func() { - fd := int(stdio.Fd()) - oldState, err := terminal.MakeRaw(fd) - if err != nil { - panic(err) - } - return func() { terminal.Restore(fd, oldState) } -} - -func _ssh_session(m *ice.Message, client *ssh.Client, w, h int, stdin io.Reader, stdout, stderr io.Writer) *ssh.Session { - session, e := client.NewSession() - m.Assert(e) - - session.Stdin = stdin - session.Stdout = stdout - session.Stderr = stderr - - modes := ssh.TerminalModes{ - ssh.ECHO: 1, - ssh.TTY_OP_ISPEED: 14400, - ssh.TTY_OP_OSPEED: 14400, - } - - session.RequestPty(os.Getenv("TERM"), h, w, modes) - session.Shell() - return session -} -func _ssh_init(m *ice.Message, pw io.Writer) { - for _, k := range []string{"one", "two"} { - if m.Sleep("100ms"); m.Option(k) != "" { - pw.Write([]byte(m.Option(k) + "\n")) - } - } + m.Cmdy(tcp.CLIENT, tcp.DIAL, kit.MDB_TYPE, SSH, kit.MDB_NAME, m.Option(tcp.HOST), + tcp.PORT, m.Option(tcp.PORT), tcp.HOST, m.Option(tcp.HOST), arg) } func _ssh_conn(m *ice.Message, conn net.Conn, username, hostport string) *ssh.Client { methods := []ssh.AuthMethod{} @@ -128,76 +159,6 @@ func _ssh_conn(m *ice.Message, conn net.Conn, username, hostport string) *ssh.Cl return ssh.NewClient(c, chans, reqs) } -func _ssh_open(m *ice.Message, arg ...string) { - var client *ssh.Client - w, h, _ := terminal.GetSize(int(os.Stdin.Fd())) - - _ssh_password(m, m.Option("authfile")) - p := path.Join(os.Getenv("HOME"), ".ssh/", fmt.Sprintf("%s@%s", m.Option("username"), m.Option("host"))) - if _, e := os.Stat(p); e == nil { - if c, e := net.Dial("unix", p); e == nil { - - pr, pw := _ssh_stream(m, os.Stdin) - defer _ssh_store(os.Stdout)() - defer _ssh_store(os.Stdin)() - - c.Write([]byte(fmt.Sprintf("height:%d,width:%d\n", h, w))) - - m.Go(func() { io.Copy(c, pr) }) - _ssh_init(m, pw) - m.Echo("logout\n") - io.Copy(os.Stdout, c) - return - } else { - os.Remove(p) - } - } - - if l, e := net.Listen("unix", p); m.Assert(e) { - defer func() { os.Remove(p) }() - defer l.Close() - - m.Go(func() { - for { - if c, e := l.Accept(); e == nil { - buf := make([]byte, 1024) - if n, e := c.Read(buf); m.Assert(e) { - fmt.Sscanf(string(buf[:n]), "height:%d,width:%d", &h, &w) - } - - session := _ssh_session(m, client, w, h, c, c, c) - func(session *ssh.Session) { - m.Go(func() { - defer c.Close() - session.Wait() - }) - }(session) - } else { - break - } - } - }) - } - - m.Option(kit.Keycb(tcp.DIAL), func(c net.Conn) { - client = _ssh_conn(m, c, m.Option(aaa.USERNAME), m.Option(tcp.HOST)+":"+m.Option(tcp.PORT)) - - pr, pw := _ssh_stream(m, os.Stdin) - defer _ssh_store(os.Stdout)() - defer _ssh_store(os.Stdin)() - - session := _ssh_session(m, client, w, h, pr, os.Stdout, os.Stderr) - _ssh_init(m, pw) - _ssh_tick(m, pw) - session.Wait() - }) - - m.Cmdy(tcp.CLIENT, tcp.DIAL, kit.MDB_TYPE, "ssh", kit.MDB_NAME, m.Option(tcp.HOST), - tcp.PORT, m.Option(tcp.PORT), tcp.HOST, m.Option(tcp.HOST), arg) - - m.Echo("exit %s\n", m.Option(tcp.HOST)) -} - const CONNECT = "connect" func init() { @@ -207,6 +168,9 @@ func init() { }, Commands: map[string]*ice.Command{ CONNECT: {Name: "connect hash auto dial prunes", Help: "连接", Action: map[string]*ice.Action{ + tcp.OPEN: {Name: "open authfile= username=shy password= verfiy= host=shylinux.com port=22 private=.ssh/id_rsa", Help: "终端", Hand: func(m *ice.Message, arg ...string) { + _ssh_open(m, arg...) + }}, tcp.DIAL: {Name: "dial username=shy host=shylinux.com port=22 private=.ssh/id_rsa", Help: "添加", Hand: func(m *ice.Message, arg ...string) { m.Option(kit.Keycb(tcp.DIAL), func(c net.Conn) { client := _ssh_conn(m, c, kit.Select("shy", m.Option(aaa.USERNAME)), @@ -225,9 +189,6 @@ func init() { m.Cmds(tcp.CLIENT, tcp.DIAL, kit.MDB_TYPE, SSH, kit.MDB_NAME, m.Option(aaa.USERNAME), tcp.PORT, m.Option(tcp.PORT), tcp.HOST, m.Option(tcp.HOST)) }}, - tcp.OPEN: {Name: "open authfile= username=shy password= verfiy= host=shylinux.com port=22 private=.ssh/id_rsa tick=", Help: "终端", Hand: func(m *ice.Message, arg ...string) { - _ssh_open(m, arg...) - }}, mdb.REMOVE: {Name: "remove", Help: "删除", Hand: func(m *ice.Message, arg ...string) { m.Cmdy(mdb.DELETE, CONNECT, "", mdb.HASH, kit.MDB_HASH, m.Option(kit.MDB_HASH)) }}, @@ -243,7 +204,7 @@ func init() { h := m.Rich(SESSION, "", kit.Data(kit.MDB_STATUS, tcp.OPEN, CONNECT, key)) - if session, e := _ssh_sess(m, h, client); m.Assert(e) { + if session, e := _ssh_session(m, h, client); m.Assert(e) { session.Shell() session.Wait() } diff --git a/base/ssh/session.go b/base/ssh/session.go index a6b2126f..955ff982 100644 --- a/base/ssh/session.go +++ b/base/ssh/session.go @@ -3,7 +3,6 @@ package ssh import ( "golang.org/x/crypto/ssh" "io" - "os" ice "github.com/shylinux/icebergs" "github.com/shylinux/icebergs/base/ctx" @@ -12,7 +11,7 @@ import ( kit "github.com/shylinux/toolkits" ) -func _ssh_sess(m *ice.Message, h string, client *ssh.Client) (*ssh.Session, error) { +func _ssh_session(m *ice.Message, h string, client *ssh.Client) (*ssh.Session, error) { session, e := client.NewSession() m.Assert(e) @@ -23,14 +22,13 @@ func _ssh_sess(m *ice.Message, h string, client *ssh.Client) (*ssh.Session, erro m.Assert(e) m.Go(func() { + buf := make([]byte, 4096) for { - buf := make([]byte, 4096) n, e := out.Read(buf) if e != nil { break } - m.Debug(string(buf[:n])) m.Grow(SESSION, kit.Keys(kit.MDB_HASH, h), kit.Dict( kit.MDB_TYPE, RES, kit.MDB_TEXT, string(buf[:n]), )) @@ -38,35 +36,24 @@ func _ssh_sess(m *ice.Message, h string, client *ssh.Client) (*ssh.Session, erro }) m.Richs(SESSION, "", h, func(key string, value map[string]interface{}) { - kit.Value(value, "meta.output", out) - kit.Value(value, "meta.input", in) + kit.Value(value, kit.Keym(OUTPUT), out) + kit.Value(value, kit.Keym(INPUT), in) }) return session, nil } -func _watch(m *ice.Message, from io.Reader, to io.Writer, cb func([]byte)) { - m.Go(func() { - buf := make([]byte, 1024) - for { - n, e := from.Read(buf) - if e != nil { - cb(nil) - break - } - cb(buf[:n]) - to.Write(buf[:n]) - } - }) -} - const ( TTY = "tty" ENV = "env" - ARG = "arg" CMD = "cmd" + ARG = "arg" RES = "res" ) +const ( + INPUT = "input" + OUTPUT = "output" +) const SESSION = "session" @@ -77,9 +64,16 @@ func init() { }, Commands: map[string]*ice.Command{ SESSION: {Name: "session hash id auto command prunes", Help: "会话", Action: map[string]*ice.Action{ + mdb.REMOVE: {Name: "remove", Help: "删除", Hand: func(m *ice.Message, arg ...string) { + m.Cmdy(mdb.DELETE, SESSION, "", mdb.HASH, kit.MDB_HASH, m.Option(kit.MDB_HASH)) + }}, + mdb.PRUNES: {Name: "prunes", Help: "清理", Hand: func(m *ice.Message, arg ...string) { + m.Cmdy(mdb.PRUNES, SESSION, "", mdb.HASH, kit.MDB_STATUS, tcp.ERROR) + m.Cmdy(mdb.PRUNES, SESSION, "", mdb.HASH, kit.MDB_STATUS, tcp.CLOSE) + }}, ctx.COMMAND: {Name: "command cmd=pwd", Help: "命令", Hand: func(m *ice.Message, arg ...string) { m.Richs(SESSION, "", m.Option(kit.MDB_HASH), func(key string, value map[string]interface{}) { - if w, ok := kit.Value(value, "meta.input").(io.Writer); ok { + if w, ok := kit.Value(value, kit.Keym(INPUT)).(io.Writer); ok { m.Grow(SESSION, kit.Keys(kit.MDB_HASH, key), kit.Dict(kit.MDB_TYPE, CMD, kit.MDB_TEXT, m.Option(CMD))) n, e := w.Write([]byte(m.Option(CMD) + "\n")) m.Debug("%v %v", n, e) @@ -87,42 +81,19 @@ func init() { }) m.ProcessRefresh("300ms") }}, - "bind": {Name: "bind", Help: "绑定", Hand: func(m *ice.Message, arg ...string) { - m.Richs(SESSION, "", m.Option(kit.MDB_HASH), func(key string, value map[string]interface{}) { - value = kit.GetMeta(value) - - input := value["input"].(io.Writer) - _watch(m, os.Stdin, input, func(buf []byte) { - m.Debug("input %v", string(buf)) - }) - - output := value["output"].(io.Reader) - _watch(m, output, os.Stdout, func(buf []byte) { - m.Debug("output %v", string(buf)) - }) - }) - }}, - - mdb.REMOVE: {Name: "remove", Help: "删除", Hand: func(m *ice.Message, arg ...string) { - m.Cmdy(mdb.DELETE, SESSION, "", mdb.HASH, kit.MDB_HASH, m.Option(kit.MDB_HASH)) - }}, - mdb.PRUNES: {Name: "prunes", Help: "清理", Hand: func(m *ice.Message, arg ...string) { - m.Cmdy(mdb.PRUNES, SESSION, "", mdb.HASH, kit.MDB_STATUS, tcp.CLOSE) - }}, }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { if len(arg) == 0 { m.Option(mdb.FIELDS, "time,hash,status,count,connect") if m.Cmdy(mdb.SELECT, SESSION, "", mdb.HASH, kit.MDB_HASH, arg); len(arg) == 0 { m.Table(func(index int, value map[string]string, head []string) { - m.PushButton(kit.Select("bind", mdb.REMOVE, value[kit.MDB_STATUS] == tcp.CLOSE)) + m.PushButton(kit.Select("", mdb.REMOVE, value[kit.MDB_STATUS] == tcp.CLOSE)) }) } return } - m.Option(mdb.FIELDS, kit.Select("time,id,type,text", mdb.DETAIL, len(arg) > 1)) + m.Fields(len(arg) == 1, "time,id,type,text") m.Cmdy(mdb.SELECT, SESSION, kit.Keys(kit.MDB_HASH, arg[0]), mdb.LIST, kit.MDB_ID, arg[1:]) - m.Sort(kit.MDB_ID) }}, }, }) diff --git a/conf.go b/conf.go index 6ddb3773..6fcae4e6 100644 --- a/conf.go +++ b/conf.go @@ -40,6 +40,7 @@ const ( // DIR INDEX_SH = "index.sh" VAR_TMP = "var/tmp" + VAR_RUN = "var/run" VAR_LOG = "var/log" VAR_CONF = "var/conf" VAR_DATA = "var/data" diff --git a/exec.go b/exec.go index a886070e..d7d5885a 100644 --- a/exec.go +++ b/exec.go @@ -1,13 +1,13 @@ package ice import ( - kit "github.com/shylinux/toolkits" - "github.com/shylinux/toolkits/task" - "errors" "fmt" "io" "time" + + kit "github.com/shylinux/toolkits" + "github.com/shylinux/toolkits/task" ) func (m *Message) TryCatch(msg *Message, safe bool, hand ...func(msg *Message)) *Message {