1
0
mirror of https://shylinux.com/x/icebergs synced 2025-04-28 10:12:02 +08:00
This commit is contained in:
harveyshao 2022-08-16 14:38:36 +08:00
parent 4bbdd8d9e4
commit bf34e9ceee
9 changed files with 101 additions and 141 deletions

View File

@ -62,6 +62,10 @@ func _hash_delete(m *ice.Message, prefix, chain, field, value string) {
defer Lock(m, prefix, chain)() defer Lock(m, prefix, chain)()
Richs(m, prefix, chain, value, func(key string, val Map) { Richs(m, prefix, chain, value, func(key string, val Map) {
if target, ok := kit.GetMeta(val)[TARGET].(io.Closer); ok {
m.Logs("close", target)
target.Close()
}
m.Logs(DELETE, KEY, path.Join(prefix, chain), field, value, VALUE, kit.Format(val)) m.Logs(DELETE, KEY, path.Join(prefix, chain), field, value, VALUE, kit.Format(val))
m.Conf(prefix, kit.Keys(chain, HASH, key), "") m.Conf(prefix, kit.Keys(chain, HASH, key), "")
}) })

View File

@ -182,9 +182,9 @@ func ZoneCreate(m *ice.Message, arg ...Any) {
m.Cmdy(INSERT, m.PrefixKey(), "", HASH, arg) m.Cmdy(INSERT, m.PrefixKey(), "", HASH, arg)
} }
func ZoneRemove(m *ice.Message, arg ...Any) { func ZoneRemove(m *ice.Message, arg ...Any) {
args := kit.Simple(arg) args := kit.Simple(arg...)
if len(args) == 0 { if len(args) == 0 {
args = m.OptionSimple(ZoneShort(m)) args = m.OptionSimple(ZoneShort(m), HASH)
} else if len(args) == 1 { } else if len(args) == 1 {
args = []string{ZoneShort(m), args[0]} args = []string{ZoneShort(m), args[0]}
} }

View File

@ -87,6 +87,7 @@ const (
) )
const DEFS = "defs" const DEFS = "defs"
const SAVE = "save" const SAVE = "save"
const LOAD = "load"
const PUSH = "push" const PUSH = "push"
const COPY = "copy" const COPY = "copy"
const LINK = "link" const LINK = "link"

View File

@ -5,14 +5,15 @@ import (
"io" "io"
"net" "net"
"os" "os"
"path"
"strings" "strings"
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/terminal" "golang.org/x/crypto/ssh/terminal"
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/aaa" "shylinux.com/x/icebergs/base/aaa"
"shylinux.com/x/icebergs/base/cli" "shylinux.com/x/icebergs/base/cli"
"shylinux.com/x/icebergs/base/ctx"
"shylinux.com/x/icebergs/base/gdb" "shylinux.com/x/icebergs/base/gdb"
"shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/mdb"
"shylinux.com/x/icebergs/base/nfs" "shylinux.com/x/icebergs/base/nfs"
@ -44,10 +45,10 @@ func _ssh_open(m *ice.Message, arg ...string) {
}, arg...) }, arg...)
} }
func _ssh_dial(m *ice.Message, cb func(net.Conn), arg ...string) { func _ssh_dial(m *ice.Message, cb func(net.Conn), arg ...string) {
p := path.Join(kit.Env(cli.HOME), ".ssh/", fmt.Sprintf("%s@%s:%s", m.Option(aaa.USERNAME), m.Option(tcp.HOST), m.Option(tcp.PORT))) p := kit.HomePath(".ssh", fmt.Sprintf("%s@%s:%s", m.Option(aaa.USERNAME), m.Option(tcp.HOST), m.Option(tcp.PORT)))
if nfs.FileExists(m, p) { if nfs.ExistsFile(m, p) {
if c, e := net.Dial("unix", p); e == nil { if c, e := net.Dial("unix", p); e == nil {
cb(c) // 会话连接 cb(c) // 会话复用
return return
} }
nfs.Remove(m, p) nfs.Remove(m, p)
@ -75,28 +76,21 @@ func _ssh_dial(m *ice.Message, cb func(net.Conn), arg ...string) {
m.Go(func() { m.Go(func() {
defer c.Close() defer c.Close()
session, e := client.NewSession() s, e := client.NewSession()
if e != nil { if e != nil {
return return
} }
session.Stdin = c s.Stdin, s.Stdout, s.Stderr = c, c, c
session.Stdout = c s.RequestPty(kit.Env(cli.TERM), h, w, ssh.TerminalModes{ssh.ECHO: 1, ssh.TTY_OP_ISPEED: 14400, ssh.TTY_OP_OSPEED: 14400})
session.Stderr = c defer s.Wait()
session.RequestPty(kit.Env("TERM"), h, w, ssh.TerminalModes{
ssh.ECHO: 1,
ssh.TTY_OP_ISPEED: 14400,
ssh.TTY_OP_OSPEED: 14400,
})
gdb.SignalNotify(m, 28, func() { gdb.SignalNotify(m, 28, func() {
w, h, _ := terminal.GetSize(int(os.Stdin.Fd())) w, h, _ := terminal.GetSize(int(os.Stdin.Fd()))
session.WindowChange(h, w) s.WindowChange(h, w)
}) })
session.Shell() s.Shell()
session.Wait()
}) })
}(c) }(c)
} }
@ -118,7 +112,6 @@ func _ssh_conn(m *ice.Message, cb func(*ssh.Client), arg ...string) {
if verify := m.Option("verify"); verify == "" { if verify := m.Option("verify"); verify == "" {
fmt.Printf(q) fmt.Printf(q)
fmt.Scanf("%s\n", &verify) fmt.Scanf("%s\n", &verify)
res = append(res, verify) res = append(res, verify)
} else { } else {
res = append(res, aaa.TOTP_GET(verify, 6, 30)) res = append(res, aaa.TOTP_GET(verify, 6, 30))
@ -131,24 +124,21 @@ func _ssh_conn(m *ice.Message, cb func(*ssh.Client), arg ...string) {
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(kit.Env(cli.HOME), m.Option(PRIVATE))))) key, err := ssh.ParsePrivateKey([]byte(m.Cmdx(nfs.CAT, kit.HomePath(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
})) }))
m.OptionCB(tcp.CLIENT, func(c net.Conn) { m.Cmdy(tcp.CLIENT, tcp.DIAL, mdb.TYPE, SSH, mdb.NAME, m.Option(tcp.HOST), m.OptionSimple(tcp.HOST, tcp.PORT), arg, func(c net.Conn) {
conn, chans, reqs, err := ssh.NewClientConn(c, m.Option(tcp.HOST)+":"+m.Option(tcp.PORT), &ssh.ClientConfig{ 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 }, 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 }, HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error { return nil },
}) })
m.Assert(err) m.Assert(err)
cb(ssh.NewClient(conn, chans, reqs)) cb(ssh.NewClient(conn, chans, reqs))
}) })
m.Cmdy(tcp.CLIENT, tcp.DIAL, mdb.TYPE, SSH, mdb.NAME, m.Option(tcp.HOST),
tcp.PORT, m.Option(tcp.PORT), tcp.HOST, m.Option(tcp.HOST), arg)
} }
const SSH = "ssh" const SSH = "ssh"
@ -160,52 +150,36 @@ func init() {
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) {
aaa.UserRoot(m) aaa.UserRoot(m)
_ssh_open(nfs.OptionLoad(m, m.Option("authfile")), arg...) _ssh_open(nfs.OptionLoad(m, m.Option("authfile")), arg...)
m.Echo("exit %v@%v:%v\n", m.Option(aaa.USERNAME), m.Option(tcp.HOST), m.Option(tcp.PORT)) m.Echo("exit %s@%s:%s\n", m.Option(aaa.USERNAME), m.Option(tcp.HOST), m.Option(tcp.PORT))
}}, }},
tcp.DIAL: {Name: "dial name=shylinux username=shy host=shylinux.com port=22 private=.ssh/id_rsa", Help: "添加", Hand: func(m *ice.Message, arg ...string) { tcp.DIAL: {Name: "dial name=shylinux host=shylinux.com port=22 username=shy private=.ssh/id_rsa", Help: "添加", Hand: func(m *ice.Message, arg ...string) {
m.Go(func() { m.Go(func() {
_ssh_conn(m, func(client *ssh.Client) { _ssh_conn(m, func(client *ssh.Client) {
mdb.Rich(m, CONNECT, "", kit.Dict( mdb.HashCreate(m.Spawn(), m.OptionSimple(mdb.NAME, tcp.HOST, tcp.PORT, aaa.USERNAME), mdb.STATUS, tcp.OPEN, kit.Dict(mdb.TARGET, client))
mdb.NAME, m.Option(mdb.NAME), m.Cmd("", SESSION, m.OptionSimple(mdb.NAME))
aaa.USERNAME, m.Option(aaa.USERNAME),
tcp.HOST, m.Option(tcp.HOST), tcp.PORT, m.Option(tcp.PORT),
mdb.STATUS, tcp.OPEN, CONNECT, client,
))
m.Cmd(CONNECT, SESSION, mdb.NAME, m.Option(mdb.NAME))
}, arg...) }, arg...)
}) })
m.ProcessRefresh3s() m.Sleep300ms()
}}, }},
SESSION: {Name: "session name", Help: "会话", Hand: func(m *ice.Message, arg ...string) { SESSION: {Name: "session", Help: "会话", Hand: func(m *ice.Message, arg ...string) {
var client *ssh.Client if c, e := _ssh_session(m, mdb.HashTarget(m, m.Option(mdb.NAME), nil).(*ssh.Client)); m.Assert(e) {
mdb.Richs(m, CONNECT, "", m.Option(mdb.NAME), func(key string, value ice.Map) { defer c.Wait()
client, _ = value[CONNECT].(*ssh.Client) c.Shell()
})
h := mdb.Rich(m, SESSION, "", kit.Data(mdb.NAME, m.Option(mdb.NAME), mdb.STATUS, tcp.OPEN, CONNECT, m.Option(mdb.NAME)))
if session, e := _ssh_session(m, h, client); m.Assert(e) {
session.Shell()
session.Wait()
} }
m.Echo(h)
}}, }},
"command": {Name: "command cmd=pwd", Help: "命令", Hand: func(m *ice.Message, arg ...string) { ctx.COMMAND: {Name: "command cmd=pwd", Help: "命令", Hand: func(m *ice.Message, arg ...string) {
mdb.Richs(m, CONNECT, "", m.Option(mdb.NAME), func(key string, value ice.Map) { client := mdb.HashTarget(m, m.Option(mdb.NAME), nil).(*ssh.Client)
if client, ok := value[CONNECT].(*ssh.Client); ok { if s, e := client.NewSession(); m.Assert(e) {
if session, e := client.NewSession(); m.Assert(e) { defer s.Close()
defer session.Close() if b, e := s.CombinedOutput(m.Option(ice.CMD)); m.Assert(e) {
if b, e := session.CombinedOutput(m.Option("cmd")); m.Assert(e) { m.Echo(string(b))
m.Echo(string(b))
}
}
} }
}) }
}}, }},
}, mdb.HashStatusAction(mdb.SHORT, "name", mdb.FIELD, "time,name,status,username,host,port")), Hand: func(m *ice.Message, arg ...string) { }, mdb.HashStatusAction(mdb.SHORT, "name", mdb.FIELD, "time,name,status,username,host,port")), Hand: func(m *ice.Message, arg ...string) {
mdb.HashSelect(m, arg...).Tables(func(value ice.Maps) { if mdb.HashSelect(m, arg...).Tables(func(value ice.Maps) {
m.PushButton(kit.Select("", "command,session", value[mdb.STATUS] == tcp.OPEN), mdb.REMOVE) m.PushButton(kit.Select("", "command,session", value[mdb.STATUS] == tcp.OPEN), mdb.REMOVE)
}) }); len(arg) == 0 {
if len(arg) == 0 {
m.Action(tcp.DIAL) m.Action(tcp.DIAL)
} }
}}, }},

View File

@ -6,7 +6,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"net" "net"
"path"
"strings" "strings"
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
@ -17,6 +16,7 @@ import (
"shylinux.com/x/icebergs/base/nfs" "shylinux.com/x/icebergs/base/nfs"
psh "shylinux.com/x/icebergs/base/ssh" psh "shylinux.com/x/icebergs/base/ssh"
"shylinux.com/x/icebergs/base/tcp" "shylinux.com/x/icebergs/base/tcp"
"shylinux.com/x/icebergs/base/web"
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
) )
@ -27,11 +27,11 @@ func _ssh_config(m *ice.Message, h string) *ssh.ServerConfig {
config := &ssh.ServerConfig{ config := &ssh.ServerConfig{
PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) { PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
meta, err := _ssh_meta(conn), errors.New(ice.ErrNotRight) meta, err := _ssh_meta(conn), errors.New(ice.ErrNotRight)
if tcp.IsLocalHost(m, strings.Split(conn.RemoteAddr().String(), ":")[0]) { if tcp.IsLocalHost(m, strings.Split(conn.RemoteAddr().String(), ice.DF)[0]) {
m.Logs(ice.LOG_AUTH, tcp.HOSTPORT, conn.RemoteAddr(), aaa.USERNAME, conn.User()) m.Logs(ice.LOG_AUTH, tcp.HOSTPORT, conn.RemoteAddr(), aaa.USERNAME, conn.User())
err = nil // 本机用户 err = nil // 本机用户
} else { } else {
m.Cmd(mdb.SELECT, SERVICE, kit.Keys(mdb.HASH, h), mdb.LIST, func(value ice.Maps) { mdb.ZoneSelectCB(m, h, func(value ice.Maps) {
if !strings.HasPrefix(value[mdb.NAME], conn.User()+"@") { if !strings.HasPrefix(value[mdb.NAME], conn.User()+"@") {
return return
} }
@ -57,14 +57,13 @@ func _ssh_config(m *ice.Message, h string) *ssh.ServerConfig {
} }
return &ssh.Permissions{Extensions: meta}, err return &ssh.Permissions{Extensions: meta}, err
}, },
BannerCallback: func(conn ssh.ConnMetadata) string { BannerCallback: func(conn ssh.ConnMetadata) string {
m.Logs(ice.LOG_AUTH, tcp.HOSTPORT, conn.RemoteAddr(), aaa.USERNAME, conn.User()) m.Logs(ice.LOG_AUTH, tcp.HOSTPORT, conn.RemoteAddr(), aaa.USERNAME, conn.User())
return m.Conf(SERVICE, kit.Keym(WELCOME)) return m.Config(WELCOME)
}, },
} }
if key, err := ssh.ParsePrivateKey([]byte(m.Cmdx(nfs.CAT, path.Join(kit.Env(cli.HOME), m.Option(PRIVATE))))); m.Assert(err) { if key, err := ssh.ParsePrivateKey([]byte(m.Cmdx(nfs.CAT, kit.HomePath(m.Option(PRIVATE))))); m.Assert(err) {
config.AddHostKey(key) config.AddHostKey(key)
} }
return config return config
@ -100,30 +99,30 @@ const SERVICE = "service"
func init() { func init() {
psh.Index.Merge(&ice.Context{Configs: ice.Configs{ psh.Index.Merge(&ice.Context{Configs: ice.Configs{
SERVICE: {Name: SERVICE, Help: "服务", Value: kit.Data( SERVICE: {Name: SERVICE, Help: "服务", Value: kit.Data(
WELCOME, "\r\nwelcome to context world\r\n", GOODBYE, "\r\ngoodbye of context world\r\n",
mdb.SHORT, tcp.PORT, mdb.FIELD, "time,port,status,private,authkey,count", mdb.SHORT, tcp.PORT, mdb.FIELD, "time,port,status,private,authkey,count",
WELCOME, "\r\nwelcome to contexts world\r\n", GOODBYE, "\r\ngoodbye of contexts world\r\n",
)}, )},
}, Commands: ice.Commands{ }, Commands: ice.Commands{
SERVICE: {Name: "service port id auto listen prunes", Help: "服务", Actions: ice.MergeActions(ice.Actions{ SERVICE: {Name: "service port id auto listen prunes", Help: "服务", Actions: ice.MergeActions(ice.Actions{
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
mdb.Richs(m, SERVICE, "", mdb.FOREACH, func(key string, value ice.Map) { mdb.HashSelect(m).Tables(func(value ice.Maps) {
if value = kit.GetMeta(value); kit.Value(value, mdb.STATUS) == tcp.OPEN { if value[mdb.STATUS] == tcp.OPEN {
m.Cmd(SERVICE, tcp.LISTEN, tcp.PORT, value[tcp.PORT], value) m.Cmd(SERVICE, tcp.LISTEN, tcp.PORT, value[tcp.PORT], value)
} }
}) })
}}, }},
tcp.LISTEN: {Name: "listen port=9030 private=.ssh/id_rsa authkey=.ssh/authorized_keys", Help: "添加", Hand: func(m *ice.Message, arg ...string) { tcp.LISTEN: {Name: "listen port=9030 private=.ssh/id_rsa authkey=.ssh/authorized_keys", Help: "添加", Hand: func(m *ice.Message, arg ...string) {
if mdb.Richs(m, SERVICE, "", m.Option(tcp.PORT), func(key string, value ice.Map) { if mdb.HashSelect(m, m.Option(tcp.PORT)).Length() > 0 {
kit.Value(value, kit.Keym(mdb.STATUS), tcp.OPEN) mdb.HashModify(m, m.Option(tcp.PORT), mdb.STATUS, tcp.OPEN)
}) == nil { } else {
m.Cmd(mdb.INSERT, SERVICE, "", mdb.HASH, tcp.PORT, m.Option(tcp.PORT), mdb.HashCreate(m, mdb.STATUS, tcp.OPEN, arg)
PRIVATE, m.Option(PRIVATE), AUTHKEY, m.Option(AUTHKEY), mdb.STATUS, tcp.OPEN, arg) m.Cmd("", nfs.LOAD, m.OptionSimple(AUTHKEY))
m.Cmd(SERVICE, mdb.IMPORT, AUTHKEY, m.Option(AUTHKEY))
} }
m.OptionCB(tcp.SERVER, func(c net.Conn) { m.Go(func() { _ssh_accept(m, kit.Hashs(m.Option(tcp.PORT)), c) }) })
m.Go(func() { m.Go(func() {
m.Cmdy(tcp.SERVER, tcp.LISTEN, mdb.TYPE, SSH, mdb.NAME, tcp.PORT, tcp.PORT, m.Option(tcp.PORT)) m.Cmdy(tcp.SERVER, tcp.LISTEN, mdb.TYPE, SSH, mdb.NAME, tcp.PORT, m.OptionSimple(tcp.PORT), func(c net.Conn) {
m.Go(func() { _ssh_accept(m, kit.Hashs(m.Option(tcp.PORT)), c) })
})
}) })
}}, }},
@ -133,36 +132,29 @@ func init() {
mdb.TYPE, ls[0], mdb.NAME, ls[len(ls)-1], mdb.TEXT, strings.Join(ls[1:len(ls)-1], "+")) mdb.TYPE, ls[0], mdb.NAME, ls[len(ls)-1], mdb.TEXT, strings.Join(ls[1:len(ls)-1], "+"))
} }
}}, }},
mdb.EXPORT: {Name: "export authkey=.ssh/authorized_keys", Help: "导出", Hand: func(m *ice.Message, arg ...string) { nfs.LOAD: {Name: "load authkey=.ssh/authorized_keys", Help: "加载", Hand: func(m *ice.Message, arg ...string) {
m.Cmd(nfs.CAT, kit.HomePath(m.Option(AUTHKEY)), func(pub string) {
m.Cmd(SERVICE, mdb.INSERT, mdb.TEXT, pub)
})
}},
nfs.SAVE: {Name: "save authkey=.ssh/authorized_keys", Help: "保存", Hand: func(m *ice.Message, arg ...string) {
list := []string{} list := []string{}
m.Cmd(mdb.SELECT, SERVICE, kit.Keys(mdb.HASH, kit.Hashs(m.Option(tcp.PORT))), mdb.LIST, func(value ice.Maps) { mdb.ZoneSelectCB(m, m.Option(tcp.PORT), func(value ice.Maps) {
list = append(list, fmt.Sprintf("%s %s %s", value[mdb.TYPE], value[mdb.TEXT], value[mdb.NAME])) list = append(list, fmt.Sprintf("%s %s %s", value[mdb.TYPE], value[mdb.TEXT], value[mdb.NAME]))
}) })
if len(list) > 0 { if len(list) > 0 {
m.Cmdy(nfs.SAVE, path.Join(kit.Env(cli.HOME), m.Option(AUTHKEY)), strings.Join(list, ice.NL)+ice.NL) m.Cmdy(nfs.SAVE, kit.HomePath(m.Option(AUTHKEY)), strings.Join(list, ice.NL)+ice.NL)
} }
}}, }},
mdb.IMPORT: {Name: "import authkey=.ssh/authorized_keys", Help: "导入", Hand: func(m *ice.Message, arg ...string) {
p := path.Join(kit.Env(cli.HOME), m.Option(AUTHKEY))
for _, pub := range strings.Split(strings.TrimSpace(m.Cmdx(nfs.CAT, p)), ice.NL) {
m.Cmd(SERVICE, mdb.INSERT, mdb.TEXT, pub)
}
m.Echo(p)
}},
aaa.INVITE: {Name: "invite", Help: "邀请", Hand: func(m *ice.Message, arg ...string) { aaa.INVITE: {Name: "invite", Help: "邀请", Hand: func(m *ice.Message, arg ...string) {
u := kit.ParseURL(m.Option(ice.MSG_USERWEB)) m.Option(cli.HOSTNAME, web.OptionUserWeb(m).Hostname())
m.Option(cli.HOSTNAME, strings.Split(u.Host, ":")[0])
m.ProcessInner()
if buf, err := kit.Render(`ssh -p {{.Option "port"}} {{.Option "user.name"}}@{{.Option "hostname"}}`, m); err == nil { if buf, err := kit.Render(`ssh -p {{.Option "port"}} {{.Option "user.name"}}@{{.Option "hostname"}}`, m); err == nil {
m.EchoScript(string(buf)) m.EchoScript(string(buf))
} }
}}, }},
}, mdb.HashStatusAction()), Hand: func(m *ice.Message, arg ...string) { }, mdb.HashStatusAction()), Hand: func(m *ice.Message, arg ...string) {
if len(arg) == 0 { // 服务列表 if len(arg) == 0 { // 服务列表
mdb.HashSelect(m, arg...) mdb.HashSelect(m, arg...).PushAction(aaa.INVITE, mdb.INSERT, nfs.LOAD, nfs.SAVE)
m.PushAction(mdb.IMPORT, mdb.INSERT, mdb.EXPORT, aaa.INVITE)
return return
} }

View File

@ -7,8 +7,9 @@ import (
"syscall" "syscall"
"unsafe" "unsafe"
pty "shylinux.com/x/creackpty"
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
pty "shylinux.com/x/creackpty"
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/cli" "shylinux.com/x/icebergs/base/cli"
"shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/mdb"
@ -33,7 +34,7 @@ func _ssh_handle(m *ice.Message, meta ice.Maps, c net.Conn, channel ssh.Channel,
m.Logs(CHANNEL, tcp.HOSTPORT, c.RemoteAddr(), "->", c.LocalAddr()) m.Logs(CHANNEL, tcp.HOSTPORT, c.RemoteAddr(), "->", c.LocalAddr())
defer m.Logs("dischan", tcp.HOSTPORT, c.RemoteAddr(), "->", c.LocalAddr()) defer m.Logs("dischan", tcp.HOSTPORT, c.RemoteAddr(), "->", c.LocalAddr())
shell := kit.Select("bash", kit.Env("SHELL")) shell := kit.Select("bash", kit.Env(cli.SHELL))
list := []string{cli.PATH + "=" + kit.Env(cli.PATH)} list := []string{cli.PATH + "=" + kit.Env(cli.PATH)}
pty, tty, err := pty.Open() pty, tty, err := pty.Open()

View File

@ -4,6 +4,7 @@ import (
"io" "io"
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
ice "shylinux.com/x/icebergs" ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/ctx" "shylinux.com/x/icebergs/base/ctx"
"shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/mdb"
@ -12,35 +13,27 @@ import (
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
) )
func _ssh_session(m *ice.Message, h string, client *ssh.Client) (*ssh.Session, error) { func _ssh_session(m *ice.Message, client *ssh.Client) (*ssh.Session, error) {
session, e := client.NewSession() s, e := client.NewSession()
m.Assert(e)
out, e := s.StdoutPipe()
m.Assert(e)
in, e := s.StdinPipe()
m.Assert(e) m.Assert(e)
out, e := session.StdoutPipe() h := m.Cmdx(SESSION, mdb.CREATE, mdb.STATUS, tcp.OPEN, CONNECT, m.Option(mdb.NAME), kit.Dict(mdb.TARGET, in))
m.Assert(e)
in, e := session.StdinPipe()
m.Assert(e)
m.Go(func() { m.Go(func() {
buf := make([]byte, ice.MOD_BUFS) buf := make([]byte, ice.MOD_BUFS)
for { for {
n, e := out.Read(buf) if n, e := out.Read(buf); e != nil {
if e != nil {
break break
} else {
m.Cmd(SESSION, mdb.INSERT, mdb.HASH, h, mdb.TYPE, RES, mdb.TEXT, string(buf[:n]))
} }
mdb.Grow(m, SESSION, kit.Keys(mdb.HASH, h), kit.Dict(
mdb.TYPE, RES, mdb.TEXT, string(buf[:n]),
))
} }
}) })
return s, nil
mdb.Richs(m, SESSION, "", h, func(key string, value ice.Map) {
kit.Value(value, kit.Keym(OUTPUT), out, kit.Keym(INPUT), in)
})
return session, nil
} }
const ( const (
@ -59,20 +52,17 @@ const SESSION = "session"
func init() { func init() {
psh.Index.MergeCommands(ice.Commands{ psh.Index.MergeCommands(ice.Commands{
SESSION: {Name: "session name id auto", Help: "会话", Actions: ice.MergeActions(ice.Actions{ SESSION: {Name: "session hash id auto", Help: "会话", Actions: ice.MergeActions(ice.Actions{
mdb.REPEAT: {Name: "repeat", Help: "执行", Hand: func(m *ice.Message, arg ...string) { mdb.REPEAT: {Name: "repeat", Help: "执行", Hand: func(m *ice.Message, arg ...string) {
m.Cmdy(SESSION, ctx.ACTION, ctx.COMMAND, CMD, m.Option(mdb.TEXT)) m.Cmdy("", ctx.COMMAND, CMD, m.Option(mdb.TEXT))
}}, }},
ctx.COMMAND: {Name: "command cmd=pwd", Help: "命令", Hand: func(m *ice.Message, arg ...string) { ctx.COMMAND: {Name: "command cmd=pwd", Help: "命令", Hand: func(m *ice.Message, arg ...string) {
mdb.Richs(m, SESSION, "", m.Option(mdb.NAME), func(key string, value ice.Map) { m.Cmd("", mdb.INSERT, m.OptionSimple(mdb.HASH), mdb.TYPE, CMD, mdb.TEXT, m.Option(CMD))
if w, ok := kit.Value(value, kit.Keym(INPUT)).(io.Writer); ok { w := mdb.HashTarget(m, m.Option(mdb.HASH), nil).(io.Writer)
mdb.Grow(m, SESSION, kit.Keys(mdb.HASH, key), kit.Dict(mdb.TYPE, CMD, mdb.TEXT, m.Option(CMD))) w.Write([]byte(m.Option(CMD) + ice.NL))
w.Write([]byte(m.Option(CMD) + ice.NL)) m.Sleep300ms()
}
})
m.ProcessRefresh300ms()
}}, }},
}, mdb.ZoneAction(mdb.SHORT, "name", mdb.FIELD, "time,name,status,count,connect")), Hand: func(m *ice.Message, arg ...string) { }, mdb.ZoneAction(mdb.FIELD, "time,hash,count,status,connect")), Hand: func(m *ice.Message, arg ...string) {
if len(arg) == 0 { if len(arg) == 0 {
mdb.HashSelect(m, arg...).Tables(func(value ice.Maps) { mdb.HashSelect(m, arg...).Tables(func(value ice.Maps) {
m.PushButton(kit.Select("", ctx.COMMAND, value[mdb.STATUS] == tcp.OPEN), mdb.REMOVE) m.PushButton(kit.Select("", ctx.COMMAND, value[mdb.STATUS] == tcp.OPEN), mdb.REMOVE)

View File

@ -6,7 +6,7 @@ refer `
` `
field "连接" ssh.connect field "连接" ssh.connect
field "通道" ssh.channel
field "会话" ssh.session field "会话" ssh.session
field "服务" ssh.service field "服务" ssh.service
field "通道" ssh.channel

View File

@ -8,8 +8,8 @@ import (
) )
type WebView struct { type WebView struct {
Source string webview.WebView
WebView webview.WebView Source string
} }
func (w WebView) Menu() bool { func (w WebView) Menu() bool {
@ -20,31 +20,29 @@ func (w WebView) Menu() bool {
w.WebView.Bind(ls[0], func() { w.navigate(ls[1]) }) w.WebView.Bind(ls[0], func() { w.navigate(ls[1]) })
} }
}) })
if len(list) == 0 { if len(list) == 0 {
return false return false
} }
w.WebView.SetTitle("contexts") w.WebView.SetTitle(ice.CONTEXTS)
w.WebView.SetSize(200, 60*len(list), webview.HintNone) w.WebView.SetSize(200, 60*len(list), webview.HintNone)
w.WebView.Navigate(kit.Format(`data:text/html, w.WebView.Navigate(kit.Format(`data:text/html,
<!doctype html> <!doctype html>
<html> <html>
<head> <head>
<style>button { font-size:24px; font-family:monospace; margin:10px; width:-webkit-fill-available; display:block; clear:both; }</style> <style>button { font-size:24px; font-family:monospace; margin:10px; width:-webkit-fill-available; display:block; clear:both; }</style>
</head>
<body>%s</body>
<script> <script>
document.body.onkeydown = function(event) { document.body.onkeydown = function(event) {
if (event.metaKey) { if (event.metaKey) {
switch (event.key) { switch (event.key) {
case "q": window.terminate(); break case "q": window.terminate(); break
}
} }
} }
}
</script> </script>
</html>`, kit.Join(list, ice.NL))) </head>
<body>%s</body>
</html>`, kit.Join(list, ice.NL)))
return true return true
} }
func (w WebView) Title(text string) { w.WebView.SetTitle(text) } func (w WebView) Title(text string) { w.WebView.SetTitle(text) }