1
0
mirror of https://shylinux.com/x/icebergs synced 2025-04-28 18:22:02 +08:00
This commit is contained in:
harveyshao 2021-06-02 10:46:21 +08:00
parent 545ec26ea8
commit f9302ca410
12 changed files with 180 additions and 142 deletions

View File

@ -8,22 +8,21 @@ import (
ice "github.com/shylinux/icebergs" ice "github.com/shylinux/icebergs"
"github.com/shylinux/icebergs/base/aaa" "github.com/shylinux/icebergs/base/aaa"
"github.com/shylinux/icebergs/base/ctx"
"github.com/shylinux/icebergs/base/mdb" "github.com/shylinux/icebergs/base/mdb"
"github.com/shylinux/icebergs/base/tcp" "github.com/shylinux/icebergs/base/tcp"
kit "github.com/shylinux/toolkits" kit "github.com/shylinux/toolkits"
"golang.org/x/crypto/ssh" "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, input io.Reader, output io.Writer, done func()) {
func _ssh_exec(m *ice.Message, cmd string, arg []string, env []string, tty io.ReadWriter, done func()) {
m.Log_IMPORT(CMD, cmd, ARG, arg, ENV, env) m.Log_IMPORT(CMD, cmd, ARG, arg, ENV, env)
c := exec.Command(cmd, arg...) c := exec.Command(cmd, arg...)
// c.Env = env // c.Env = env
c.Stdin = tty c.Stdin = input
c.Stdout = tty c.Stdout = output
c.Stderr = tty c.Stderr = output
m.Assert(c.Start()) 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) bio := io.TeeReader(input, w)
m.Go(func() { io.Copy(output, r) }) m.Go(func() { io.Copy(output, r) })
i, buf := 0, make([]byte, 4096) i, buf := 0, make([]byte, ice.MOD_BUFS)
m.Go(func() { m.Go(func() {
for { for {
n, e := bio.Read(buf[i:]) n, e := bio.Read(buf[i:])
@ -72,7 +71,7 @@ func init() {
CHANNEL: {Name: "channel", Help: "通道", Value: kit.Data()}, CHANNEL: {Name: "channel", Help: "通道", Value: kit.Data()},
}, },
Commands: map[string]*ice.Command{ 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) { 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)) 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, SERVICE, "", mdb.HASH, kit.MDB_STATUS, tcp.ERROR)
m.Cmdy(mdb.PRUNES, CHANNEL, "", mdb.HASH, kit.MDB_STATUS, tcp.CLOSE) 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) { }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(arg) == 0 { // 通道列表 if len(arg) == 0 { // 通道列表
m.Fields(len(arg) == 0, "time,hash,status,username,hostport,tty,count") m.Fields(len(arg) == 0, "time,hash,status,username,hostport,tty,count")
if m.Cmdy(mdb.SELECT, CHANNEL, "", mdb.HASH); len(arg) == 0 { if m.Cmdy(mdb.SELECT, CHANNEL, "", mdb.HASH); len(arg) == 0 {
m.Table(func(index int, value map[string]string, head []string) { 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 return
@ -95,6 +106,7 @@ func init() {
// 通道命令 // 通道命令
m.Fields(len(arg) == 1, "time,id,type,text") 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.Cmdy(mdb.SELECT, CHANNEL, kit.Keys(kit.MDB_HASH, arg[0]), mdb.LIST, kit.MDB_ID, arg[1:])
m.PushAction("repeat")
}}, }},
}, },
}) })

View File

@ -1,7 +1,6 @@
package ssh package ssh
import ( import (
"encoding/json"
"fmt" "fmt"
"io" "io"
"net" "net"
@ -22,16 +21,6 @@ import (
) )
func _ssh_open(m *ice.Message, arg ...string) { 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) { _ssh_dial(m, func(c net.Conn) {
// 保存界面 // 保存界面
fd := int(os.Stdin.Fd()) 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))) 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") m.Sleep("500ms")
c.Write([]byte(item + "\n")) c.Write([]byte(item + "\n"))
} }
m.Go(func() { io.Copy(c, os.Stdin) }) m.Go(func() { io.Copy(c, os.Stdin) })
io.Copy(os.Stdout, c) io.Copy(os.Stdout, c)
}, arg...) }, arg...)
} }
@ -64,67 +52,62 @@ func _ssh_dial(m *ice.Message, cb func(net.Conn), arg ...string) {
os.Remove(p) os.Remove(p)
} }
var client *ssh.Client _ssh_conn(m, func(client *ssh.Client) {
if l, e := net.Listen("unix", p); m.Assert(e) { if l, e := net.Listen("unix", p); m.Assert(e) {
defer func() { os.Remove(p) }() defer func() { os.Remove(p) }()
defer l.Close() defer l.Close()
m.Go(func() { m.Go(func() {
for { for {
c, e := l.Accept() c, e := l.Accept()
if e != nil { if e != nil {
break 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() { func(c net.Conn) {
defer c.Close() w, h, _ := terminal.GetSize(int(os.Stdin.Fd()))
buf := make([]byte, ice.MOD_BUFS)
session, e := client.NewSession() if n, e := c.Read(buf); m.Assert(e) {
if e != nil { fmt.Sscanf(string(buf[:n]), "height:%d,width:%d", &h, &w)
return
} }
session.Stdin = c m.Go(func() {
session.Stdout = c defer c.Close()
session.Stderr = c
session.RequestPty(os.Getenv("TERM"), h, w, ssh.TerminalModes{ session, e := client.NewSession()
ssh.ECHO: 1, if e != nil {
ssh.TTY_OP_ISPEED: 14400, return
ssh.TTY_OP_OSPEED: 14400, }
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)
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 { if c, e := net.Dial("unix", p); e == nil {
cb(c) // 会话连接 cb(c) // 会话连接
} }
}) }, arg...)
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 { func _ssh_conn(m *ice.Message, cb func(*ssh.Client), arg ...string) {
methods := []ssh.AuthMethod{} methods := []ssh.AuthMethod{}
methods = append(methods, ssh.KeyboardInteractive(func(user, instruction string, questions []string, echos []bool) (res []string, err error) { methods = append(methods, ssh.KeyboardInteractive(func(user, instruction string, questions []string, echos []bool) (res []string, err error) {
for _, q := range questions { for _, q := range questions {
@ -146,22 +129,25 @@ func _ssh_conn(m *ice.Message, conn net.Conn, username, hostport string) *ssh.Cl
} }
return return
})) }))
methods = append(methods, ssh.PublicKeysCallback(func() ([]ssh.Signer, error) { 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 return []ssh.Signer{key}, err
})) }))
methods = append(methods, ssh.PasswordCallback(func() (string, error) { methods = append(methods, ssh.PasswordCallback(func() (string, error) {
return m.Option(aaa.PASSWORD), nil return m.Option(aaa.PASSWORD), nil
})) }))
c, chans, reqs, err := ssh.NewClientConn(conn, hostport, &ssh.ClientConfig{ m.Option(kit.Keycb(tcp.DIAL), func(c net.Conn) {
User: username, Auth: methods, BannerCallback: func(message string) error { return nil }, conn, chans, reqs, err := ssh.NewClientConn(c, m.Option(tcp.HOST)+":"+m.Option(tcp.PORT), &ssh.ClientConfig{
HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error { return nil }, 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) m.Assert(err)
return ssh.NewClient(c, chans, reqs) 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" const CONNECT = "connect"
@ -175,59 +161,61 @@ func init() {
ice.CTX_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { 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{}) { 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 { 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{ 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) { 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)) 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) { 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) { m.Go(func() {
client := _ssh_conn(m, c, kit.Select("shy", m.Option(aaa.USERNAME)), _ssh_conn(m, func(client *ssh.Client) {
kit.Select("shylinux.com", m.Option(tcp.HOST))+":"+kit.Select("22", m.Option(tcp.PORT)), h := m.Option(kit.MDB_HASH)
) if h == "" {
h = m.Rich(CONNECT, "", kit.Dict(
h := m.Rich(CONNECT, "", kit.Dict( aaa.USERNAME, m.Option(aaa.USERNAME),
aaa.USERNAME, m.Option(aaa.USERNAME), tcp.HOST, m.Option(tcp.HOST), tcp.PORT, m.Option(tcp.PORT),
tcp.HOST, m.Option(tcp.HOST), tcp.PORT, m.Option(tcp.PORT), kit.MDB_STATUS, tcp.OPEN, CONNECT, client,
kit.MDB_STATUS, tcp.OPEN, CONNECT, client, ))
)) } else {
m.Cmd(CONNECT, SESSION, kit.MDB_HASH, h) m.Conf(CONNECT, kit.Keys(kit.MDB_HASH, h, CONNECT), client)
m.Echo(h) }
m.Cmd(CONNECT, SESSION, kit.MDB_HASH, h)
}, arg...)
}) })
m.ProcessRefresh("300ms")
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))
}}, }},
mdb.REMOVE: {Name: "remove", Help: "删除", Hand: func(m *ice.Message, arg ...string) { 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)) 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) { 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.ERROR)
m.Cmdy(mdb.PRUNES, CONNECT, "", mdb.HASH, kit.MDB_STATUS, tcp.CLOSE) m.Cmdy(mdb.PRUNES, CONNECT, "", mdb.HASH, kit.MDB_STATUS, tcp.CLOSE)
}}, }},
SESSION: {Name: "session hash", Help: "会话", Hand: func(m *ice.Message, arg ...string) { 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{}) { m.Richs(CONNECT, "", m.Option(kit.MDB_HASH), func(key string, value map[string]interface{}) {
client, ok := value[CONNECT].(*ssh.Client) client, _ = 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()
}
}) })
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) { }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
m.Fields(len(arg) == 0, "time,hash,status,username,host,port") 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 { 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.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)
}) })
} }
}}, }},

View File

@ -17,14 +17,21 @@ import (
kit "github.com/shylinux/toolkits" 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 { switch arg := kit.Simple(args...); cmd {
case ice.RENDER_VOID: case ice.RENDER_VOID:
case ice.RENDER_RESULT: case ice.RENDER_RESULT:
// 转换结果
if len(arg) > 0 { if len(arg) > 0 {
msg.Resultv(arg) 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: default:
// 转换结果 // 转换结果
@ -37,7 +44,9 @@ func Render(msg *ice.Message, cmd string, args ...interface{}) {
if fmt.Fprint(msg.O, res); !strings.HasSuffix(res, "\n") { if fmt.Fprint(msg.O, res); !strings.HasSuffix(res, "\n") {
fmt.Fprint(msg.O, "\n") fmt.Fprint(msg.O, "\n")
} }
return res
} }
return ""
} }
func Script(m *ice.Message, name string) io.Reader { func Script(m *ice.Message, name string) io.Reader {
if strings.Contains(m.Option(ice.MSG_SCRIPT), "/") { if strings.Contains(m.Option(ice.MSG_SCRIPT), "/") {
@ -92,6 +101,7 @@ type Frame struct {
pipe io.Writer pipe io.Writer
count int count int
last string
ps1 []string ps1 []string
ps2 []string ps2 []string
@ -223,7 +233,7 @@ func (f *Frame) parse(m *ice.Message, line string) string {
// 渲染引擎 // 渲染引擎
_args, _ := msg.Optionv(ice.MSG_ARGS).([]interface{}) _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 "" return ""
} }
@ -312,10 +322,16 @@ func (f *Frame) Start(m *ice.Message, arg ...string) bool {
// 解析脚本 // 解析脚本
if f.count = 1; f.source == STDIO { 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, "") f.scan(m, STDIO, "")
} else { } else {
h := m.Cmdx(mdb.INSERT, SOURCE, "", mdb.HASH, kit.MDB_NAME, f.source) 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, "") f.scan(m, h, "")
} }
return true return true
@ -349,7 +365,12 @@ func init() {
)}, )},
}, },
Commands: map[string]*ice.Command{ 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" { // 解析脚本 if len(arg) > 0 && kit.Ext(arg[0]) == "shy" { // 解析脚本
m.Starts(strings.Replace(arg[0], ".", "_", -1), arg[0], arg[0:]...) m.Starts(strings.Replace(arg[0], ".", "_", -1), arg[0], arg[0:]...)
return return
@ -371,6 +392,7 @@ func init() {
// 命令列表 // 命令列表
m.Fields(len(arg) == 1 || arg[1] == "", "time,id,text") 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.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) { TARGET: {Name: "target name 执行:button", Help: "当前模块", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
f := m.Target().Server().(*Frame) f := m.Target().Server().(*Frame)
@ -396,7 +418,7 @@ func init() {
fmt.Fprintf(f.pipe, line+"\n") fmt.Fprintf(f.pipe, line+"\n")
m.Sleep("300ms") 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) { RETURN: {Name: "return", Help: "结束脚本", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
switch cb := m.Optionv(kit.Keycb(RETURN)).(type) { switch cb := m.Optionv(kit.Keycb(RETURN)).(type) {

View File

@ -70,7 +70,7 @@ func _ssh_config(m *ice.Message, h string) *ssh.ServerConfig {
return config return config
} }
func _ssh_accept(m *ice.Message, h string, c net.Conn) { 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) { if m.Warn(err != nil, err) {
return return
} }
@ -84,7 +84,7 @@ func _ssh_accept(m *ice.Message, h string, c net.Conn) {
} }
func(channel ssh.Channel, requests <-chan *ssh.Request) { 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) }(channel, requests)
} }
} }

View File

@ -10,6 +10,8 @@ import (
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
) )
type Winsize struct{ Height, Width, x, y uint16 }
func _ssh_size(fd uintptr, b []byte) { func _ssh_size(fd uintptr, b []byte) {
w := binary.BigEndian.Uint32(b) w := binary.BigEndian.Uint32(b)
h := binary.BigEndian.Uint32(b[4:]) h := binary.BigEndian.Uint32(b[4:])

View File

@ -17,6 +17,8 @@ import (
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
) )
type Winsize struct{ Height, Width, x, y uint16 }
func _ssh_size(fd uintptr, b []byte) { func _ssh_size(fd uintptr, b []byte) {
w := binary.BigEndian.Uint32(b) w := binary.BigEndian.Uint32(b)
h := binary.BigEndian.Uint32(b[4:]) 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() 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 meta[CHANNEL] = h
for request := range requests { 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) list = append(list, env.Name+"="+env.Value)
case "exec": 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() channel.Close()
}) })
case "shell": case "shell":
m.Go(func() { io.Copy(channel, pty) }) 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) defer m.Cmd(mdb.MODIFY, CHANNEL, "", mdb.HASH, kit.MDB_HASH, h, kit.MDB_STATUS, tcp.CLOSE)
_ssh_close(m, c, channel) _ssh_close(m, c, channel)
}) })

View File

@ -7,6 +7,8 @@ import (
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
) )
type Winsize struct{ Height, Width, x, y uint16 }
func _ssh_size(fd uintptr, b []byte) { 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) { func _ssh_handle(m *ice.Message, meta map[string]string, c net.Conn, channel ssh.Channel, requests <-chan *ssh.Request) {

View File

@ -22,7 +22,7 @@ func _ssh_session(m *ice.Message, h string, client *ssh.Client) (*ssh.Session, e
m.Assert(e) m.Assert(e)
m.Go(func() { m.Go(func() {
buf := make([]byte, 4096) buf := make([]byte, ice.MOD_BUFS)
for { for {
n, e := out.Read(buf) n, e := out.Read(buf)
if e != nil { 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{}) { m.Richs(SESSION, "", h, func(key string, value map[string]interface{}) {
kit.Value(value, kit.Keym(OUTPUT), out) kit.Value(value, kit.Keym(OUTPUT), out, kit.Keym(INPUT), in)
kit.Value(value, kit.Keym(INPUT), in)
}) })
return session, nil return session, nil
@ -68,6 +67,7 @@ func init() {
m.Cmdy(mdb.DELETE, SESSION, "", mdb.HASH, kit.MDB_HASH, m.Option(kit.MDB_HASH)) 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) { 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.ERROR)
m.Cmdy(mdb.PRUNES, SESSION, "", mdb.HASH, kit.MDB_STATUS, tcp.CLOSE) 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{}) { 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 { 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))) 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")) w.Write([]byte(m.Option(CMD) + "\n"))
m.Debug("%v %v", n, e)
} }
}) })
m.ProcessRefresh("300ms") 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) { }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(arg) == 0 { 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 { 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.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 return
@ -94,6 +96,9 @@ func init() {
m.Fields(len(arg) == 1, "time,id,type,text") 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.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"))
})
}}, }},
}, },
}) })

View File

@ -11,24 +11,17 @@ const SSH = "ssh"
var Index = &ice.Context{Name: SSH, Help: "终端模块", Commands: map[string]*ice.Command{ 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) { ice.CTX_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
m.Load() m.Load()
m.Conf(SOURCE, kit.Keys(kit.MDB_HASH, STDIO, kit.MDB_META, kit.MDB_NAME), STDIO) m.Richs(SESSION, "", kit.MDB_FOREACH, func(key string, value map[string]interface{}) {
m.Conf(SOURCE, kit.Keys(kit.MDB_HASH, STDIO, kit.MDB_META, kit.MDB_TIME), m.Time()) 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) { ice.CTX_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if _, ok := m.Target().Server().(*Frame); ok { if _, ok := m.Target().Server().(*Frame); ok {
m.Done(true) 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() m.Save()
}}, }},
}} }}
@ -36,6 +29,6 @@ var Index = &ice.Context{Name: SSH, Help: "终端模块", Commands: map[string]*
func init() { func init() {
ice.Index.Register(Index, &Frame{}, ice.Index.Register(Index, &Frame{},
CONNECT, SESSION, SERVICE, CHANNEL, CONNECT, SESSION, SERVICE, CHANNEL,
SOURCE, TARGET, PROMPT, RETURN, SOURCE, TARGET, PROMPT, PRINTF, SCREEN, RETURN,
) )
} }

View File

@ -5,10 +5,10 @@ refer `
源码 https://github.com/openssh/openssh-portable 源码 https://github.com/openssh/openssh-portable
` `
field "服务" ssh.service
field "通道" ssh.channel
field "连接" ssh.connect field "连接" ssh.connect
field "会话" ssh.session field "会话" ssh.session
field "服务" ssh.service
field "通道" ssh.channel
field "脚本" ssh.source field "脚本" ssh.source
field "模块" ssh.target field "模块" ssh.target
@ -16,4 +16,3 @@ field "提示" ssh.prompt
field "输出" ssh.printf field "输出" ssh.printf
field "屏显" ssh.screen field "屏显" ssh.screen

13
misc.go
View File

@ -1,8 +1,10 @@
package ice package ice
import ( import (
"encoding/json"
"fmt" "fmt"
"net/url" "net/url"
"os"
"path" "path"
"strings" "strings"
"time" "time"
@ -345,3 +347,14 @@ func (m *Message) Upload(dir string) {
} }
func (m *Message) OptionFields(str string) { m.Option("fields", str) } 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
}

View File

@ -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) 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 { if h, ok := cmd.Action[arg[1]]; ok {
return c._hand(m, cmd, key, arg[1], h, arg[2:]...) return c._hand(m, cmd, key, arg[1], h, arg[2:]...)
} }