From f9302ca4108b933581abc8a6e4760f445d1af1b8 Mon Sep 17 00:00:00 2001 From: harveyshao Date: Wed, 2 Jun 2021 10:46:21 +0800 Subject: [PATCH] opt ssh --- base/ssh/channel.go | 30 ++++-- base/ssh/connect.go | 182 +++++++++++++++++------------------- base/ssh/scripts.go | 34 +++++-- base/ssh/service.go | 4 +- base/ssh/service_darwin.go | 2 + base/ssh/service_linux.go | 8 +- base/ssh/service_windows.go | 2 + base/ssh/session.go | 19 ++-- base/ssh/ssh.go | 21 ++--- base/ssh/ssh.shy | 5 +- misc.go | 13 +++ type.go | 2 +- 12 files changed, 180 insertions(+), 142 deletions(-) diff --git a/base/ssh/channel.go b/base/ssh/channel.go index f1753b92..d9e105c3 100644 --- a/base/ssh/channel.go +++ b/base/ssh/channel.go @@ -8,22 +8,21 @@ import ( ice "github.com/shylinux/icebergs" "github.com/shylinux/icebergs/base/aaa" + "github.com/shylinux/icebergs/base/ctx" "github.com/shylinux/icebergs/base/mdb" "github.com/shylinux/icebergs/base/tcp" kit "github.com/shylinux/toolkits" "golang.org/x/crypto/ssh" ) -type Winsize struct{ Height, Width, x, y uint16 } - -func _ssh_exec(m *ice.Message, cmd string, arg []string, env []string, tty io.ReadWriter, done func()) { +func _ssh_exec(m *ice.Message, cmd string, arg []string, env []string, input io.Reader, output io.Writer, done func()) { m.Log_IMPORT(CMD, cmd, ARG, arg, ENV, env) c := exec.Command(cmd, arg...) // c.Env = env - c.Stdin = tty - c.Stdout = tty - c.Stderr = tty + c.Stdin = input + c.Stdout = output + c.Stderr = output m.Assert(c.Start()) @@ -41,7 +40,7 @@ func _ssh_watch(m *ice.Message, meta map[string]string, h string, input io.Reade bio := io.TeeReader(input, w) m.Go(func() { io.Copy(output, r) }) - i, buf := 0, make([]byte, 4096) + i, buf := 0, make([]byte, ice.MOD_BUFS) m.Go(func() { for { n, e := bio.Read(buf[i:]) @@ -72,7 +71,7 @@ func init() { CHANNEL: {Name: "channel", Help: "通道", Value: kit.Data()}, }, Commands: map[string]*ice.Command{ - CHANNEL: {Name: "channel hash id auto prunes", Help: "通道", Action: map[string]*ice.Action{ + CHANNEL: {Name: "channel 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, CHANNEL, "", mdb.HASH, kit.MDB_HASH, m.Option(kit.MDB_HASH)) }}, @@ -81,12 +80,24 @@ func init() { m.Cmdy(mdb.PRUNES, SERVICE, "", mdb.HASH, kit.MDB_STATUS, tcp.ERROR) m.Cmdy(mdb.PRUNES, CHANNEL, "", mdb.HASH, kit.MDB_STATUS, tcp.CLOSE) }}, + ctx.COMMAND: {Name: "command cmd=pwd", Help: "命令", Hand: func(m *ice.Message, arg ...string) { + m.Cmdy(mdb.INSERT, CHANNEL, kit.Keys(kit.MDB_HASH, m.Option(kit.MDB_HASH)), mdb.LIST, kit.MDB_TYPE, CMD, kit.MDB_TEXT, m.Option(CMD)) + m.Richs(CHANNEL, "", m.Option(kit.MDB_HASH), func(key string, value map[string]interface{}) { + if w, ok := kit.Value(value, kit.Keym(INPUT)).(io.Writer); ok { + w.Write([]byte(m.Option(CMD) + "\n")) + } + }) + m.ProcessRefresh("300ms") + }}, + "repeat": {Name: "repeat", Help: "执行", Hand: func(m *ice.Message, arg ...string) { + m.Cmdy(CHANNEL, kit.MDB_ACTION, ctx.COMMAND, CMD, m.Option("text")) + }}, }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { if len(arg) == 0 { // 通道列表 m.Fields(len(arg) == 0, "time,hash,status,username,hostport,tty,count") if m.Cmdy(mdb.SELECT, CHANNEL, "", mdb.HASH); len(arg) == 0 { m.Table(func(index int, value map[string]string, head []string) { - m.PushButton(kit.Select("", mdb.REMOVE, value[kit.MDB_STATUS] == tcp.CLOSE)) + m.PushButton(kit.Select("", ctx.COMMAND, value[kit.MDB_STATUS] == tcp.OPEN), mdb.REMOVE) }) } return @@ -95,6 +106,7 @@ func init() { // 通道命令 m.Fields(len(arg) == 1, "time,id,type,text") m.Cmdy(mdb.SELECT, CHANNEL, kit.Keys(kit.MDB_HASH, arg[0]), mdb.LIST, kit.MDB_ID, arg[1:]) + m.PushAction("repeat") }}, }, }) diff --git a/base/ssh/connect.go b/base/ssh/connect.go index 3bf4df65..96c9388c 100644 --- a/base/ssh/connect.go +++ b/base/ssh/connect.go @@ -1,7 +1,6 @@ package ssh import ( - "encoding/json" "fmt" "io" "net" @@ -22,16 +21,6 @@ import ( ) 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 interface{}) { m.Option(key, kit.Simple(value)) }) - } - _ssh_dial(m, func(c net.Conn) { // 保存界面 fd := int(os.Stdin.Fd()) @@ -44,13 +33,12 @@ func _ssh_open(m *ice.Message, arg ...string) { c.Write([]byte(fmt.Sprintf("height:%d,width:%d\n", h, w))) // 初始命令 - for _, item := range kit.Simple(m.Optionv("list")) { + for _, item := range kit.Simple(m.Optionv(kit.MDB_LIST)) { m.Sleep("500ms") c.Write([]byte(item + "\n")) } m.Go(func() { io.Copy(c, os.Stdin) }) - io.Copy(os.Stdout, c) }, arg...) } @@ -64,67 +52,62 @@ func _ssh_dial(m *ice.Message, cb func(net.Conn), arg ...string) { 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() + _ssh_conn(m, func(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() - if e != nil { - break - } - - 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() { + for { + c, e := l.Accept() + if e != nil { + break } - m.Go(func() { - defer c.Close() - - session, e := client.NewSession() - if e != nil { - return + 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) } - session.Stdin = c - session.Stdout = c - session.Stderr = c + m.Go(func() { + defer c.Close() - session.RequestPty(os.Getenv("TERM"), h, w, ssh.TerminalModes{ - ssh.ECHO: 1, - ssh.TTY_OP_ISPEED: 14400, - ssh.TTY_OP_OSPEED: 14400, + session, e := client.NewSession() + if e != nil { + return + } + + 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() }) - - 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)) + }(c) + } + }) + } if c, e := net.Dial("unix", p); e == nil { cb(c) // 会话连接 } - }) - 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) + }, arg...) } -func _ssh_conn(m *ice.Message, conn net.Conn, username, hostport string) *ssh.Client { +func _ssh_conn(m *ice.Message, cb func(*ssh.Client), arg ...string) { methods := []ssh.AuthMethod{} methods = append(methods, ssh.KeyboardInteractive(func(user, instruction string, questions []string, echos []bool) (res []string, err error) { for _, q := range questions { @@ -146,22 +129,25 @@ func _ssh_conn(m *ice.Message, conn net.Conn, username, hostport string) *ssh.Cl } return })) - methods = append(methods, ssh.PublicKeysCallback(func() ([]ssh.Signer, error) { - key, err := ssh.ParsePrivateKey([]byte(m.Cmdx(nfs.CAT, path.Join(os.Getenv(cli.HOME), m.Option("private"))))) + key, err := ssh.ParsePrivateKey([]byte(m.Cmdx(nfs.CAT, path.Join(os.Getenv(cli.HOME), m.Option(PRIVATE))))) return []ssh.Signer{key}, err })) methods = append(methods, ssh.PasswordCallback(func() (string, error) { return m.Option(aaa.PASSWORD), nil })) - c, chans, reqs, err := ssh.NewClientConn(conn, hostport, &ssh.ClientConfig{ - User: username, Auth: methods, BannerCallback: func(message string) error { return nil }, - HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error { return nil }, - }) + m.Option(kit.Keycb(tcp.DIAL), func(c net.Conn) { + conn, chans, reqs, err := ssh.NewClientConn(c, m.Option(tcp.HOST)+":"+m.Option(tcp.PORT), &ssh.ClientConfig{ + User: m.Option(aaa.USERNAME), Auth: methods, BannerCallback: func(message string) error { return nil }, + HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error { return nil }, + }) - m.Assert(err) - return ssh.NewClient(c, chans, reqs) + m.Assert(err) + cb(ssh.NewClient(conn, chans, reqs)) + }) + 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) } const CONNECT = "connect" @@ -175,59 +161,61 @@ func init() { ice.CTX_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { m.Richs(CONNECT, "", kit.MDB_FOREACH, func(key string, value map[string]interface{}) { if value = kit.GetMeta(value); kit.Value(value, kit.MDB_STATUS) == tcp.OPEN { - m.Cmd(CONNECT, tcp.DIAL, aaa.USERNAME, value[aaa.USERNAME], value) + m.Cmd(CONNECT, tcp.DIAL, aaa.USERNAME, value[aaa.USERNAME], kit.MDB_HASH, key, value) } }) }}, 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...) + _ssh_open(m.OptionLoad(m.Option("authfile")), arg...) m.Echo("exit %v:%v\n", m.Option(tcp.HOST), m.Option(tcp.PORT)) }}, 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)), - kit.Select("shylinux.com", m.Option(tcp.HOST))+":"+kit.Select("22", m.Option(tcp.PORT)), - ) - - h := m.Rich(CONNECT, "", kit.Dict( - aaa.USERNAME, m.Option(aaa.USERNAME), - tcp.HOST, m.Option(tcp.HOST), tcp.PORT, m.Option(tcp.PORT), - kit.MDB_STATUS, tcp.OPEN, CONNECT, client, - )) - m.Cmd(CONNECT, SESSION, kit.MDB_HASH, h) - m.Echo(h) + m.Go(func() { + _ssh_conn(m, func(client *ssh.Client) { + h := m.Option(kit.MDB_HASH) + if h == "" { + h = m.Rich(CONNECT, "", kit.Dict( + aaa.USERNAME, m.Option(aaa.USERNAME), + tcp.HOST, m.Option(tcp.HOST), tcp.PORT, m.Option(tcp.PORT), + kit.MDB_STATUS, tcp.OPEN, CONNECT, client, + )) + } else { + m.Conf(CONNECT, kit.Keys(kit.MDB_HASH, h, CONNECT), client) + } + m.Cmd(CONNECT, SESSION, kit.MDB_HASH, h) + }, arg...) }) - - 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)) + m.ProcessRefresh("300ms") }}, 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)) }}, mdb.PRUNES: {Name: "prunes", Help: "清理", Hand: func(m *ice.Message, arg ...string) { + m.Option(mdb.FIELDS, "time,hash,status,username,host,port") m.Cmdy(mdb.PRUNES, CONNECT, "", mdb.HASH, kit.MDB_STATUS, tcp.ERROR) m.Cmdy(mdb.PRUNES, CONNECT, "", mdb.HASH, kit.MDB_STATUS, tcp.CLOSE) }}, SESSION: {Name: "session hash", Help: "会话", Hand: func(m *ice.Message, arg ...string) { + var client *ssh.Client m.Richs(CONNECT, "", m.Option(kit.MDB_HASH), func(key string, value map[string]interface{}) { - client, ok := value[CONNECT].(*ssh.Client) - m.Assert(ok) - - h := m.Rich(SESSION, "", kit.Data(kit.MDB_STATUS, tcp.OPEN, CONNECT, key)) - - if session, e := _ssh_session(m, h, client); m.Assert(e) { - session.Shell() - session.Wait() - } + client, _ = value[CONNECT].(*ssh.Client) }) + m.Debug("what %v", client) + + h := m.Rich(SESSION, "", kit.Data(kit.MDB_STATUS, tcp.OPEN, CONNECT, m.Option(kit.MDB_HASH))) + if session, e := _ssh_session(m, h, client); m.Assert(e) { + session.Shell() + session.Wait() + } + m.Echo(h) }}, }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { m.Fields(len(arg) == 0, "time,hash,status,username,host,port") if m.Cmdy(mdb.SELECT, CONNECT, "", mdb.HASH, kit.MDB_HASH, arg); len(arg) == 0 { m.Table(func(index int, value map[string]string, head []string) { - m.PushButton(kit.Select("", mdb.REMOVE, value[kit.MDB_STATUS] == tcp.CLOSE)) + m.PushButton(kit.Select("", SESSION, value[kit.MDB_STATUS] == tcp.OPEN), mdb.REMOVE) }) } }}, diff --git a/base/ssh/scripts.go b/base/ssh/scripts.go index 122cc8f6..07ab4aef 100644 --- a/base/ssh/scripts.go +++ b/base/ssh/scripts.go @@ -17,14 +17,21 @@ import ( kit "github.com/shylinux/toolkits" ) -func Render(msg *ice.Message, cmd string, args ...interface{}) { +func Render(msg *ice.Message, cmd string, args ...interface{}) string { switch arg := kit.Simple(args...); cmd { case ice.RENDER_VOID: case ice.RENDER_RESULT: + // 转换结果 if len(arg) > 0 { msg.Resultv(arg) } - fmt.Fprint(msg.O, msg.Result()) + res := msg.Result() + + // 输出结果 + if fmt.Fprint(msg.O, res); !strings.HasSuffix(res, "\n") { + fmt.Fprint(msg.O, "\n") + } + return res default: // 转换结果 @@ -37,7 +44,9 @@ func Render(msg *ice.Message, cmd string, args ...interface{}) { if fmt.Fprint(msg.O, res); !strings.HasSuffix(res, "\n") { fmt.Fprint(msg.O, "\n") } + return res } + return "" } func Script(m *ice.Message, name string) io.Reader { if strings.Contains(m.Option(ice.MSG_SCRIPT), "/") { @@ -92,6 +101,7 @@ type Frame struct { pipe io.Writer count int + last string ps1 []string ps2 []string @@ -223,7 +233,7 @@ func (f *Frame) parse(m *ice.Message, line string) string { // 渲染引擎 _args, _ := msg.Optionv(ice.MSG_ARGS).([]interface{}) - Render(msg, msg.Option(ice.MSG_OUTPUT), _args...) + f.last = Render(msg, msg.Option(ice.MSG_OUTPUT), _args...) } return "" } @@ -312,10 +322,16 @@ func (f *Frame) Start(m *ice.Message, arg ...string) bool { // 解析脚本 if f.count = 1; f.source == STDIO { - f.count = kit.Int(m.Conf(SOURCE, kit.Keys("hash.stdio.meta.count"))) + 1 + m.Conf(SOURCE, kit.Keys(kit.MDB_HASH, STDIO, kit.MDB_META, kit.MDB_NAME), STDIO) + m.Conf(SOURCE, kit.Keys(kit.MDB_HASH, STDIO, kit.MDB_META, kit.MDB_TIME), m.Time()) + + f.count = kit.Int(m.Conf(SOURCE, kit.Keys(kit.MDB_HASH, STDIO, kit.Keym(kit.MDB_COUNT)))) + 1 f.scan(m, STDIO, "") } else { h := m.Cmdx(mdb.INSERT, SOURCE, "", mdb.HASH, kit.MDB_NAME, f.source) + m.Conf(SOURCE, kit.Keys(kit.MDB_HASH, h, kit.Keym(kit.MDB_COUNT)), 0) + m.Conf(SOURCE, kit.Keys(kit.MDB_HASH, h, kit.MDB_LIST), "") + f.scan(m, h, "") } return true @@ -349,7 +365,12 @@ func init() { )}, }, Commands: map[string]*ice.Command{ - SOURCE: {Name: "source hash id limit offend auto", Help: "脚本解析", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + SOURCE: {Name: "source hash id limit offend auto", Help: "脚本解析", Action: map[string]*ice.Action{ + "repeat": {Name: "repeat", Help: "执行", Hand: func(m *ice.Message, arg ...string) { + m.Cmdy(SCREEN, m.Option("text")) + m.ProcessInner() + }}, + }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { if len(arg) > 0 && kit.Ext(arg[0]) == "shy" { // 解析脚本 m.Starts(strings.Replace(arg[0], ".", "_", -1), arg[0], arg[0:]...) return @@ -371,6 +392,7 @@ func init() { // 命令列表 m.Fields(len(arg) == 1 || arg[1] == "", "time,id,text") m.Cmdy(mdb.SELECT, SOURCE, kit.Keys(kit.MDB_HASH, arg[0]), mdb.LIST, kit.MDB_ID, arg[1:]) + m.PushAction("repeat") }}, TARGET: {Name: "target name 执行:button", Help: "当前模块", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { f := m.Target().Server().(*Frame) @@ -396,7 +418,7 @@ func init() { fmt.Fprintf(f.pipe, line+"\n") m.Sleep("300ms") } - m.Echo(arg[0]) + m.Echo(f.last) }}, RETURN: {Name: "return", Help: "结束脚本", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { switch cb := m.Optionv(kit.Keycb(RETURN)).(type) { diff --git a/base/ssh/service.go b/base/ssh/service.go index b8ec43cd..42061298 100644 --- a/base/ssh/service.go +++ b/base/ssh/service.go @@ -70,7 +70,7 @@ func _ssh_config(m *ice.Message, h string) *ssh.ServerConfig { return config } func _ssh_accept(m *ice.Message, h string, c net.Conn) { - sc, chans, reqs, err := ssh.NewServerConn(c, _ssh_config(m, h)) + conn, chans, reqs, err := ssh.NewServerConn(c, _ssh_config(m, h)) if m.Warn(err != nil, err) { return } @@ -84,7 +84,7 @@ func _ssh_accept(m *ice.Message, h string, c net.Conn) { } func(channel ssh.Channel, requests <-chan *ssh.Request) { - m.Go(func() { _ssh_handle(m, sc.Permissions.Extensions, c, channel, requests) }) + m.Go(func() { _ssh_handle(m, conn.Permissions.Extensions, c, channel, requests) }) }(channel, requests) } } diff --git a/base/ssh/service_darwin.go b/base/ssh/service_darwin.go index 272b1f8e..0fe1d156 100644 --- a/base/ssh/service_darwin.go +++ b/base/ssh/service_darwin.go @@ -10,6 +10,8 @@ import ( "golang.org/x/crypto/ssh" ) +type Winsize struct{ Height, Width, x, y uint16 } + func _ssh_size(fd uintptr, b []byte) { w := binary.BigEndian.Uint32(b) h := binary.BigEndian.Uint32(b[4:]) diff --git a/base/ssh/service_linux.go b/base/ssh/service_linux.go index 1a10e557..938ffa25 100644 --- a/base/ssh/service_linux.go +++ b/base/ssh/service_linux.go @@ -17,6 +17,8 @@ import ( "golang.org/x/crypto/ssh" ) +type Winsize struct{ Height, Width, x, y uint16 } + func _ssh_size(fd uintptr, b []byte) { w := binary.BigEndian.Uint32(b) h := binary.BigEndian.Uint32(b[4:]) @@ -37,7 +39,7 @@ func _ssh_handle(m *ice.Message, meta map[string]string, c net.Conn, channel ssh } defer tty.Close() - h := m.Rich(CHANNEL, "", kit.Data(kit.MDB_STATUS, tcp.OPEN, TTY, tty.Name(), meta)) + h := m.Rich(CHANNEL, "", kit.Data(kit.MDB_STATUS, tcp.OPEN, TTY, tty.Name(), INPUT, pty, OUTPUT, tty, meta)) meta[CHANNEL] = h for request := range requests { @@ -61,13 +63,13 @@ func _ssh_handle(m *ice.Message, meta map[string]string, c net.Conn, channel ssh list = append(list, env.Name+"="+env.Value) case "exec": - _ssh_exec(m, shell, []string{"-c", string(request.Payload[4 : request.Payload[3]+4])}, list, channel, func() { + _ssh_exec(m, shell, []string{"-c", string(request.Payload[4 : request.Payload[3]+4])}, list, channel, channel, func() { channel.Close() }) case "shell": m.Go(func() { io.Copy(channel, pty) }) - _ssh_exec(m, shell, nil, list, tty, func() { + _ssh_exec(m, shell, nil, list, tty, tty, func() { defer m.Cmd(mdb.MODIFY, CHANNEL, "", mdb.HASH, kit.MDB_HASH, h, kit.MDB_STATUS, tcp.CLOSE) _ssh_close(m, c, channel) }) diff --git a/base/ssh/service_windows.go b/base/ssh/service_windows.go index 5d1e3495..c21ad076 100644 --- a/base/ssh/service_windows.go +++ b/base/ssh/service_windows.go @@ -7,6 +7,8 @@ import ( "golang.org/x/crypto/ssh" ) +type Winsize struct{ Height, Width, x, y uint16 } + func _ssh_size(fd uintptr, b []byte) { } func _ssh_handle(m *ice.Message, meta map[string]string, c net.Conn, channel ssh.Channel, requests <-chan *ssh.Request) { diff --git a/base/ssh/session.go b/base/ssh/session.go index c6bfc40d..df48c958 100644 --- a/base/ssh/session.go +++ b/base/ssh/session.go @@ -22,7 +22,7 @@ func _ssh_session(m *ice.Message, h string, client *ssh.Client) (*ssh.Session, e m.Assert(e) m.Go(func() { - buf := make([]byte, 4096) + buf := make([]byte, ice.MOD_BUFS) for { n, e := out.Read(buf) if e != nil { @@ -36,8 +36,7 @@ func _ssh_session(m *ice.Message, h string, client *ssh.Client) (*ssh.Session, e }) m.Richs(SESSION, "", h, func(key string, value map[string]interface{}) { - kit.Value(value, kit.Keym(OUTPUT), out) - kit.Value(value, kit.Keym(INPUT), in) + kit.Value(value, kit.Keym(OUTPUT), out, kit.Keym(INPUT), in) }) return session, nil @@ -68,6 +67,7 @@ func init() { 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.Option(mdb.FIELDS, "time,hash,status,count,connect") m.Cmdy(mdb.PRUNES, SESSION, "", mdb.HASH, kit.MDB_STATUS, tcp.ERROR) m.Cmdy(mdb.PRUNES, SESSION, "", mdb.HASH, kit.MDB_STATUS, tcp.CLOSE) }}, @@ -75,18 +75,20 @@ func init() { m.Richs(SESSION, "", m.Option(kit.MDB_HASH), func(key string, value map[string]interface{}) { 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) + w.Write([]byte(m.Option(CMD) + "\n")) } }) m.ProcessRefresh("300ms") }}, + "repeat": {Name: "repeat", Help: "执行", Hand: func(m *ice.Message, arg ...string) { + m.Cmdy(SESSION, kit.MDB_ACTION, ctx.COMMAND, CMD, m.Option("text")) + }}, }, 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") + m.Fields(len(arg) == 0, "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("", mdb.REMOVE, value[kit.MDB_STATUS] == tcp.CLOSE)) + m.PushButton(kit.Select("", ctx.COMMAND, value[kit.MDB_STATUS] == tcp.OPEN), mdb.REMOVE) }) } return @@ -94,6 +96,9 @@ func init() { 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.Table(func(index int, value map[string]string, head []string) { + m.PushButton(kit.Select("", "repeat", value["type"] == "cmd")) + }) }}, }, }) diff --git a/base/ssh/ssh.go b/base/ssh/ssh.go index 246d81c3..6faf1778 100644 --- a/base/ssh/ssh.go +++ b/base/ssh/ssh.go @@ -11,24 +11,17 @@ const SSH = "ssh" var Index = &ice.Context{Name: SSH, Help: "终端模块", Commands: map[string]*ice.Command{ ice.CTX_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { m.Load() - m.Conf(SOURCE, kit.Keys(kit.MDB_HASH, STDIO, kit.MDB_META, kit.MDB_NAME), STDIO) - m.Conf(SOURCE, kit.Keys(kit.MDB_HASH, STDIO, kit.MDB_META, kit.MDB_TIME), m.Time()) + m.Richs(SESSION, "", kit.MDB_FOREACH, func(key string, value map[string]interface{}) { + kit.Value(value, kit.Keym(kit.MDB_STATUS), tcp.CLOSE) + }) + m.Richs(CHANNEL, "", kit.MDB_FOREACH, func(key string, value map[string]interface{}) { + kit.Value(value, kit.Keym(kit.MDB_STATUS), tcp.CLOSE) + }) }}, ice.CTX_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { if _, ok := m.Target().Server().(*Frame); ok { m.Done(true) } - m.Richs(CHANNEL, "", kit.MDB_FOREACH, func(key string, value map[string]interface{}) { - kit.Value(value, kit.Keym(kit.MDB_STATUS), tcp.CLOSE) - }) - m.Richs(SESSION, "", kit.MDB_FOREACH, func(key string, value map[string]interface{}) { - kit.Value(value, kit.Keym(kit.MDB_STATUS), tcp.CLOSE) - }) - - m.Richs(SOURCE, "", STDIO, func(key string, value map[string]interface{}) { - m.Conf(SOURCE, kit.Keys(kit.MDB_HASH), "") - m.Conf(SOURCE, kit.Keys(kit.MDB_HASH, key), value) - }) m.Save() }}, }} @@ -36,6 +29,6 @@ var Index = &ice.Context{Name: SSH, Help: "终端模块", Commands: map[string]* func init() { ice.Index.Register(Index, &Frame{}, CONNECT, SESSION, SERVICE, CHANNEL, - SOURCE, TARGET, PROMPT, RETURN, + SOURCE, TARGET, PROMPT, PRINTF, SCREEN, RETURN, ) } diff --git a/base/ssh/ssh.shy b/base/ssh/ssh.shy index 0f756872..4e3fac25 100644 --- a/base/ssh/ssh.shy +++ b/base/ssh/ssh.shy @@ -5,10 +5,10 @@ refer ` 源码 https://github.com/openssh/openssh-portable ` -field "服务" ssh.service -field "通道" ssh.channel field "连接" ssh.connect field "会话" ssh.session +field "服务" ssh.service +field "通道" ssh.channel field "脚本" ssh.source field "模块" ssh.target @@ -16,4 +16,3 @@ field "提示" ssh.prompt field "输出" ssh.printf field "屏显" ssh.screen - diff --git a/misc.go b/misc.go index 500df056..38b96b0d 100644 --- a/misc.go +++ b/misc.go @@ -1,8 +1,10 @@ package ice import ( + "encoding/json" "fmt" "net/url" + "os" "path" "strings" "time" @@ -345,3 +347,14 @@ func (m *Message) Upload(dir string) { } func (m *Message) OptionFields(str string) { m.Option("fields", str) } +func (m *Message) OptionLoad(file string) *Message { + if f, e := os.Open(file); e == nil { + defer f.Close() + + var data interface{} + json.NewDecoder(f).Decode(&data) + + kit.Fetch(data, func(key string, value interface{}) { m.Option(key, kit.Simple(value)) }) + } + return m +} diff --git a/type.go b/type.go index 80f23545..69886750 100644 --- a/type.go +++ b/type.go @@ -116,7 +116,7 @@ func (c *Context) cmd(m *Message, cmd *Command, key string, arg ...string) *Mess } m.meta[MSG_DETAIL] = kit.Simple(key, arg) - if m.Hand = true; len(arg) > 1 && arg[0] == "action" && cmd.Action != nil { + if m.Hand = true; len(arg) > 1 && arg[0] == kit.MDB_ACTION && cmd.Action != nil { if h, ok := cmd.Action[arg[1]]; ok { return c._hand(m, cmd, key, arg[1], h, arg[2:]...) }