1
0
mirror of https://shylinux.com/x/icebergs synced 2025-06-26 02:17:30 +08:00
This commit is contained in:
IT 老营长 @云轩领航-创始人 2023-10-11 20:30:53 +08:00
parent 15a3f015c7
commit 50e99b9fed
11 changed files with 143 additions and 109 deletions

View File

@ -68,6 +68,7 @@ const (
) )
const ( const (
LISTEN = "listen" LISTEN = "listen"
UNIX = "unix"
) )
const SERVER = "server" const SERVER = "server"

View File

@ -129,7 +129,7 @@ func ToastProcess(m *ice.Message, arg ...ice.Any) func() {
Toast(m, toastContent(m, ice.PROCESS), arg...) Toast(m, toastContent(m, ice.PROCESS), arg...)
return func() { Toast(m, toastContent(m, ice.SUCCESS)) } return func() { Toast(m, toastContent(m, ice.SUCCESS)) }
} }
func GoToast(m *ice.Message, title string, cb func(toast func(string, int, int)) []string) { func GoToast(m *ice.Message, title string, cb func(toast func(string, int, int)) []string) *ice.Message {
_total := 0 _total := 0
toast := func(name string, count, total int) { toast := func(name string, count, total int) {
kit.If(total == 0, func() { total = 1 }) kit.If(total == 0, func() { total = 1 })
@ -144,4 +144,5 @@ func GoToast(m *ice.Message, title string, cb func(toast func(string, int, int))
} else { } else {
toast(ice.SUCCESS, _total, _total) toast(ice.SUCCESS, _total, _total)
} }
return m
} }

View File

@ -41,7 +41,7 @@ func _xterm_get(m *ice.Message, h string) xterm.XTerm {
for { for {
if n, e := term.Read(buf); !m.Warn(e) && e == nil { if n, e := term.Read(buf); !m.Warn(e) && e == nil {
if _xterm_echo(m, h, string(buf[:n])); len(text) > 0 { if _xterm_echo(m, h, string(buf[:n])); len(text) > 0 {
kit.If(text[0], func(cmd string) { m.Go(func() { m.Sleep30ms(); term.Writeln(cmd) }) }) kit.If(text[0], func(cmd string) { m.Go(func() { m.Sleep30ms(); term.Write([]byte(cmd + lex.NL)) }) })
text = text[1:] text = text[1:]
} }
} else { } else {
@ -54,11 +54,12 @@ func _xterm_get(m *ice.Message, h string) xterm.XTerm {
}).(xterm.XTerm) }).(xterm.XTerm)
} }
func _xterm_echo(m *ice.Message, h string, str string) { func _xterm_echo(m *ice.Message, h string, str string) {
m.Options(ice.MSG_COUNT, "0", ice.LOG_DISABLE, ice.TRUE, "__target", "", ice.MSG_DAEMON, mdb.HashSelectField(m, h, cli.DAEMON)) m.Options(ice.MSG_DAEMON, mdb.HashSelectField(m, h, cli.DAEMON), ice.MSG_COUNT, "0", "__target", "")
m.Options(ice.LOG_DISABLE, ice.TRUE)
web.PushNoticeGrow(m, h, str) web.PushNoticeGrow(m, h, str)
} }
func _xterm_cmds(m *ice.Message, h string, cmd string, arg ...ice.Any) { func _xterm_cmds(m *ice.Message, h string, cmd string, arg ...ice.Any) {
kit.If(cmd != "", func() { _xterm_get(m, h).Writeln(cmd, arg...) }) kit.If(cmd != "", func() { _xterm_get(m, h).Write([]byte(kit.Format(cmd, arg...) + lex.NL)) })
m.ProcessHold() m.ProcessHold()
} }

View File

@ -65,6 +65,11 @@ func (m *Message) Go(cb func(), arg ...Any) *Message {
task.Put(m.FormatTaskMeta(), arg[0], func(task *task.Task) { m.TryCatch(true, func(m *Message) { cb() }) }) task.Put(m.FormatTaskMeta(), arg[0], func(task *task.Task) { m.TryCatch(true, func(m *Message) { cb() }) })
return m return m
} }
func (m *Message) GoWait(cb func(func()), arg ...Any) *Message {
res := make(chan bool, 2)
defer func() { <-res }()
return m.Go(func() { cb(func() { res <- true }) }, arg...)
}
func (m *Message) Wait(d string, cb ...Handler) (wait func() bool, done Handler) { func (m *Message) Wait(d string, cb ...Handler) (wait func() bool, done Handler) {
sync := make(chan bool, 2) sync := make(chan bool, 2)
t := time.AfterFunc(kit.Duration(d), func() { sync <- false }) t := time.AfterFunc(kit.Duration(d), func() { sync <- false })

View File

@ -4,9 +4,9 @@ websocket
webview webview
qrcode qrcode
xterm xterm
git git
ssh ssh
vim vim
bash bash
tmux tmux

View File

@ -20,6 +20,9 @@ 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"
"shylinux.com/x/icebergs/core/code"
"shylinux.com/x/icebergs/misc/xterm"
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
) )
@ -30,26 +33,26 @@ func _ssh_open(m *ice.Message, arg ...string) {
defer terminal.Restore(fd, oldState) defer terminal.Restore(fd, oldState)
} }
w, h, _ := terminal.GetSize(fd) w, h, _ := terminal.GetSize(fd)
c.Write([]byte(fmt.Sprintf("#height:%d,width:%d\n", h, w))) c.Write([]byte(fmt.Sprintf("#height:%d,width:%d"+lex.NL, h, w)))
for _, item := range kit.Simple(m.Optionv(ice.INIT)) { kit.For(kit.Simple(m.Optionv(ice.INIT)), func(cmd string) {
defer c.Write([]byte(cmd + lex.NL))
m.Sleep300ms() m.Sleep300ms()
c.Write([]byte(item + lex.NL)) })
} m.Go(func() { io.Copy(os.Stdout, c) })
m.Go(func() { io.Copy(c, os.Stdin) }) io.Copy(c, os.Stdin)
io.Copy(os.Stdout, c)
}, 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 := kit.HomePath(".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.Exists(m, p) { if nfs.Exists(m, p) {
if c, e := net.Dial("unix", p); e == nil { if c, e := net.Dial(tcp.UNIX, p); e == nil {
cb(c) cb(c)
return return
} }
nfs.Remove(m, p) nfs.Remove(m, p)
} }
_ssh_conn(m, func(client *ssh.Client) { _ssh_conn(m, func(client *ssh.Client) {
if l, e := net.Listen("unix", p); !m.Warn(e, ice.ErrNotValid) { if l, e := net.Listen(tcp.UNIX, p); !m.Warn(e, ice.ErrNotValid) {
defer func() { nfs.Remove(m, p) }() defer func() { nfs.Remove(m, p) }()
defer l.Close() defer l.Close()
m.Go(func() { m.Go(func() {
@ -72,18 +75,15 @@ func _ssh_dial(m *ice.Message, cb func(net.Conn), arg ...string) {
} }
s.Stdin, s.Stdout, s.Stderr = c, c, c s.Stdin, s.Stdout, s.Stderr = c, c, c
s.RequestPty(kit.Env(cli.TERM), h, w, ssh.TerminalModes{ssh.ECHO: 1, ssh.TTY_OP_ISPEED: 14400, ssh.TTY_OP_OSPEED: 14400}) s.RequestPty(kit.Env(cli.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())); s.WindowChange(h, w) })
defer s.Wait() defer s.Wait()
gdb.SignalNotify(m, 28, func() {
w, h, _ := terminal.GetSize(int(os.Stdin.Fd()))
s.WindowChange(h, w)
})
s.Shell() s.Shell()
}) })
}(c) }(c)
} }
}) })
} }
if c, e := net.Dial("unix", p); e == nil { if c, e := net.Dial(tcp.UNIX, p); !m.Warn(e) {
cb(c) cb(c)
} }
}, arg...) }, arg...)
@ -109,7 +109,6 @@ func _ssh_conn(m *ice.Message, cb func(*ssh.Client), arg ...string) {
} }
case strings.HasSuffix(p, "password:"): case strings.HasSuffix(p, "password:"):
res = append(res, m.Option(aaa.PASSWORD)) res = append(res, m.Option(aaa.PASSWORD))
default:
} }
} }
return return
@ -124,54 +123,108 @@ func _ssh_conn(m *ice.Message, cb func(*ssh.Client), arg ...string) {
} }
}) })
} }
func _ssh_hold(m *ice.Message, c *ssh.Client) {
if s, e := _ssh_session(m, c); !m.Warn(e, ice.ErrNotValid) {
defer s.Wait()
s.Shell()
}
}
func _ssh_target(m *ice.Message, name string) *ssh.Client {
return mdb.HashSelectTarget(m, name, func(value ice.Maps) (res ice.Any) {
m.GoWait(func(done func()) {
_ssh_conn(m.Spawn(value), func(c *ssh.Client) {
defer _ssh_hold(m, c)
defer done()
res = c
})
})
return
}).(*ssh.Client)
}
const SSH = "ssh" const SSH = "ssh"
const (
DIRECT = "direct"
)
const CONNECT = "connect" const CONNECT = "connect"
func init() { func init() {
psh.Index.MergeCommands(ice.Commands{ psh.Index.MergeCommands(ice.Commands{
CONNECT: {Name: "connect name auto", Help: "连接", Actions: ice.MergeActions(ice.Actions{ CONNECT: {Help: "连接", Actions: ice.MergeActions(ice.Actions{
ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) {
mdb.HashSelect(m).Table(func(value ice.Maps) {
if value[mdb.STATUS] == tcp.OPEN {
m.Cmd("", tcp.DIAL, mdb.NAME, value[mdb.NAME], value)
}
})
}},
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) {
defer nfs.OptionLoad(m, m.Option("authfile")).Echo("exit %s@%s:%s\n", m.Option(aaa.USERNAME), m.Option(tcp.HOST), m.Option(tcp.PORT)) defer nfs.OptionLoad(m, m.Option("authfile")).Echo("exit %s@%s:%s\n", m.Option(aaa.USERNAME), m.Option(tcp.HOST), m.Option(tcp.PORT))
_ssh_open(m, arg...) _ssh_open(m, arg...)
}}, }},
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) { 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) { msg := m.Spawn()
mdb.HashCreate(m.Spawn(), m.OptionSimple(mdb.NAME, tcp.HOST, tcp.PORT, aaa.USERNAME), mdb.STATUS, tcp.OPEN, kit.Dict(mdb.TARGET, client)) _ssh_conn(m, func(c *ssh.Client) {
m.Cmd("", SESSION, m.OptionSimple(mdb.NAME)) defer _ssh_hold(m, c)
mdb.HashCreate(msg, m.OptionSimple(mdb.NAME, tcp.HOST, tcp.PORT, aaa.USERNAME, PRIVATE), kit.Dict(mdb.TARGET, c))
}, arg...) }, arg...)
}) }).Sleep3s()
m.Sleep300ms()
}}, }},
SESSION: {Help: "会话", Hand: func(m *ice.Message, arg ...string) { SESSION: {Help: "会话", Hand: func(m *ice.Message, arg ...string) { _ssh_hold(m, _ssh_target(m, m.Option(mdb.NAME))) }},
if c, e := _ssh_session(m, mdb.HashSelectTarget(m, m.Option(mdb.NAME), nil).(*ssh.Client)); !m.Warn(e, ice.ErrNotValid) { DIRECT: {Name: "direct cmd=pwd", Help: "命令", Hand: func(m *ice.Message, arg ...string) {
defer c.Wait() if m.Option(mdb.NAME) == "" {
c.Shell() msg := m.Cmds("")
} web.GoToast(m, m.Option(ice.CMD), func(toast func(string, int, int)) []string {
}}, count, total := 0, msg.Length()
ctx.COMMAND: {Name: "command cmd=pwd", Help: "命令", Hand: func(m *ice.Message, arg ...string) { toast("", count, total)
client := mdb.HashSelectTarget(m, m.Option(mdb.NAME), nil).(*ssh.Client) msg.Table(func(value ice.Maps) {
if s, e := client.NewSession(); !m.Warn(e, ice.ErrNotValid) { toast(value[mdb.NAME], count, total)
msg := m.Cmds("", m.ActionKey(), value)
kit.If(len(msg.Resultv()) == 0, func() { msg.TableEcho() })
m.Push(mdb.TIME, msg.Time())
m.Push(mdb.NAME, value[mdb.NAME])
m.Push(cli.COST, m.FormatCost())
m.Push(RES, msg.Result())
count++
})
return nil
}).ProcessInner()
} else if s, e := _ssh_target(m, m.Option(mdb.NAME)).NewSession(); !m.Warn(e, ice.ErrNotValid) {
defer s.Close() defer s.Close()
if b, e := s.CombinedOutput(m.Option(ice.CMD)); !m.Warn(e, ice.ErrNotValid) { if b, e := s.CombinedOutput(m.Option(ice.CMD)); !m.Warn(e, ice.ErrNotValid) {
m.Echo(string(b)) m.Echo(string(b)).ProcessInner()
} }
} else {
mdb.HashSelectUpdate(m, m.Option(mdb.NAME), func(value ice.Map) { delete(value, mdb.TARGET) })
} }
}}, }},
}, mdb.StatusHashAction(mdb.SHORT, mdb.NAME, mdb.FIELD, "time,name,status,username,host,port")), Hand: func(m *ice.Message, arg ...string) { code.XTERM: {Hand: func(m *ice.Message, arg ...string) {
if mdb.HashSelect(m, arg...).Table(func(value ice.Maps) { ctx.Process(m, code.XTERM, []string{SSH + lex.SP + m.Option(mdb.NAME)}, arg...)
m.PushButton(kit.Select("", "command,session", value[mdb.STATUS] == tcp.OPEN), mdb.REMOVE) }},
}); len(arg) == 0 { }, mdb.StatusHashAction(mdb.SHORT, mdb.NAME, mdb.FIELD, "time,name,username,private,host,port"), mdb.ImportantHashAction()), Hand: func(m *ice.Message, arg ...string) {
m.Action(tcp.DIAL) if mdb.HashSelect(m, arg...).PushAction(code.XTERM, DIRECT, SESSION, mdb.REMOVE); len(arg) == 0 {
m.Sort(mdb.NAME).Action(tcp.DIAL, DIRECT)
} }
}}, }},
}) })
} }
type session struct {
name string
sess *ssh.Session
pty *os.File
}
func NewSession(m *ice.Message, arg ...string) (xterm.XTerm, error) {
sess := &session{name: arg[0]}
m.GoWait(func(done func()) {
m.Cmd("ssh.connect", SESSION, kit.Dict(mdb.NAME, arg[0]), func(s *ssh.Session) {
defer done()
pty, tty, _ := xterm.Open()
sess.sess, sess.pty = s, pty
s.Stdin, s.Stdout, s.Stderr = tty, tty, tty
s.RequestPty(kit.Env(cli.TERM), 24, 80, ssh.TerminalModes{ssh.ECHO: 0, ssh.TTY_OP_ISPEED: 14400, ssh.TTY_OP_OSPEED: 14400})
})
})
return sess, nil
}
func (s session) Setsize(h, w string) error { return s.sess.WindowChange(kit.Int(h), kit.Int(w)) }
func (s session) Write(buf []byte) (int, error) { return s.pty.Write(buf) }
func (s session) Read(buf []byte) (int, error) { return s.pty.Read(buf) }
func (s session) Close() error { return s.sess.Close() }
func init() { xterm.AddCommand(SSH, NewSession) }

View File

@ -1,14 +1,12 @@
package ssh package ssh
import ( import (
"crypto"
"crypto/rand" "crypto/rand"
"crypto/rsa" "crypto/rsa"
"crypto/sha256"
"crypto/x509" "crypto/x509"
"encoding/hex"
"encoding/pem" "encoding/pem"
"path" "path"
"strings"
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
@ -21,10 +19,8 @@ import (
) )
const ( const (
PUBLIC = "public"
PRIVATE = "private" PRIVATE = "private"
VERIFY = "verify" PUBLIC = "public"
SIGN = "sign"
) )
const RSA = "rsa" const RSA = "rsa"
@ -46,7 +42,8 @@ func init() {
mdb.CREATE: {Name: "create bits=2048,4096 title=some", Hand: func(m *ice.Message, arg ...string) { mdb.CREATE: {Name: "create bits=2048,4096 title=some", Hand: func(m *ice.Message, arg ...string) {
if key, err := rsa.GenerateKey(rand.Reader, kit.Int(m.Option(BITS))); !m.Warn(err, ice.ErrNotValid) { if key, err := rsa.GenerateKey(rand.Reader, kit.Int(m.Option(BITS))); !m.Warn(err, ice.ErrNotValid) {
if pub, err := ssh.NewPublicKey(key.Public()); !m.Warn(err, ice.ErrNotValid) { if pub, err := ssh.NewPublicKey(key.Public()); !m.Warn(err, ice.ErrNotValid) {
mdb.HashCreate(m, m.OptionSimple(TITLE), PUBLIC, string(ssh.MarshalAuthorizedKey(pub))+lex.SP+m.Option(TITLE), mdb.HashCreate(m, m.OptionSimple(TITLE),
PUBLIC, strings.TrimSpace(string(ssh.MarshalAuthorizedKey(pub)))+lex.SP+strings.TrimSpace(m.Option(TITLE)),
PRIVATE, string(pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)})), PRIVATE, string(pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)})),
) )
} }
@ -65,46 +62,6 @@ func init() {
PUBLIC, m.Cmdx(nfs.CAT, kit.HomePath(m.Option(PUB))), PUBLIC, m.Cmdx(nfs.CAT, kit.HomePath(m.Option(PUB))),
)) ))
}}, }},
SIGN: {Hand: func(m *ice.Message, arg ...string) {
if !nfs.Exists(m, "etc/id_rsa") {
if key, err := rsa.GenerateKey(rand.Reader, kit.Int("2048")); !m.Warn(err, ice.ErrNotValid) {
m.Cmd(nfs.SAVE, "etc/id_rsa", string(pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)})))
m.Cmd(nfs.SAVE, "etc/id_rsa.pub", string(pem.EncodeToMemory(&pem.Block{Type: "RSA PUBLIC KEY", Bytes: x509.MarshalPKCS1PublicKey(key.Public().(*rsa.PublicKey))})))
}
}
block, _ := pem.Decode([]byte(m.Cmdx(nfs.CAT, "etc/id_rsa")))
key, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if m.Warn(err) {
return
}
hash := sha256.New()
if _, err := hash.Write([]byte(arg[0])); m.Warn(err) {
return
}
signature, err := rsa.SignPSS(rand.Reader, key, crypto.SHA256, hash.Sum(nil), nil)
if m.Warn(err) {
return
}
m.Echo(hex.EncodeToString(signature))
}},
VERIFY: {Hand: func(m *ice.Message, arg ...string) {
block, _ := pem.Decode([]byte(m.Cmdx(nfs.CAT, "etc/id_rsa.pub")))
pub, err := x509.ParsePKCS1PublicKey(block.Bytes)
if m.Warn(err) {
return
}
signature, err := hex.DecodeString(arg[1])
if m.Warn(err) {
return
}
hash := sha256.New()
if _, err := hash.Write([]byte(arg[0])); m.Warn(err) {
return
}
if !m.Warn(rsa.VerifyPSS(pub, crypto.SHA256, hash.Sum(nil), signature, nil)) {
m.Echo(ice.OK)
}
}},
}, mdb.HashAction(mdb.SHORT, PRIVATE, mdb.FIELD, "time,hash,title,public,private")), Hand: func(m *ice.Message, arg ...string) { }, mdb.HashAction(mdb.SHORT, PRIVATE, mdb.FIELD, "time,hash,title,public,private")), Hand: func(m *ice.Message, arg ...string) {
if mdb.HashSelect(m, arg...).PushAction(mdb.EXPORT, mdb.REMOVE); len(arg) == 0 { if mdb.HashSelect(m, arg...).PushAction(mdb.EXPORT, mdb.REMOVE); len(arg) == 0 {
m.Action(mdb.CREATE, mdb.IMPORT) m.Action(mdb.CREATE, mdb.IMPORT)

View File

@ -145,7 +145,7 @@ const SERVICE = "service"
func init() { func init() {
psh.Index.MergeCommands(ice.Commands{ psh.Index.MergeCommands(ice.Commands{
SERVICE: {Name: "service port id auto listen prunes", Icon: "ssh.png", Help: "服务", Actions: ice.MergeActions(ice.Actions{ SERVICE: {Name: "service port id auto", Icon: "ssh.png", 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.HashSelect(m).Table(func(value ice.Maps) { mdb.HashSelect(m).Table(func(value ice.Maps) {
if value[mdb.STATUS] == tcp.OPEN { if value[mdb.STATUS] == tcp.OPEN {
@ -190,16 +190,14 @@ func init() {
}}, }},
aaa.INVITE: {Help: "邀请", Hand: func(m *ice.Message, arg ...string) { aaa.INVITE: {Help: "邀请", Hand: func(m *ice.Message, arg ...string) {
m.Option(cli.HOSTNAME, tcp.PublishLocalhost(m, web.UserWeb(m).Hostname())) m.Option(cli.HOSTNAME, tcp.PublishLocalhost(m, web.UserWeb(m).Hostname()))
if buf, err := kit.Render(`ssh -p {{.Option "port"}} {{.Option "user.name"}}@{{.Option "hostname"}}`, m); err == nil { m.EchoScript(kit.Renders(`ssh -p {{.Option "port"}} {{.Option "user.name"}}@{{.Option "hostname"}}`, m))
m.EchoScript(string(buf))
}
}}, }},
}, mdb.StatusHashAction( }, mdb.StatusHashAction(
mdb.SHORT, tcp.PORT, mdb.FIELD, "time,port,status,private,authkey,count", mdb.FIELDS, "time,id,type,name,text", mdb.SHORT, tcp.PORT, mdb.FIELD, "time,port,status,private,authkey,count", mdb.FIELDS, "time,id,type,name,text",
WELCOME, "welcome to contexts world\r\n", GOODBYE, "goodbye of contexts world\r\n", WELCOME, "welcome to contexts world\r\n", GOODBYE, "goodbye of contexts world\r\n",
)), Hand: func(m *ice.Message, arg ...string) { )), Hand: func(m *ice.Message, arg ...string) {
if mdb.ZoneSelect(m, arg...); len(arg) == 0 { if mdb.ZoneSelect(m, arg...).PushAction(aaa.INVITE, mdb.INSERT, ctx.LOAD, ctx.SAVE, mdb.REMOVE); len(arg) == 0 {
m.PushAction(aaa.INVITE, mdb.INSERT, ctx.LOAD, ctx.SAVE, mdb.REMOVE) m.Action(tcp.LISTEN)
} }
}}, }},
}) })

View File

@ -11,16 +11,27 @@ import (
"shylinux.com/x/icebergs/base/mdb" "shylinux.com/x/icebergs/base/mdb"
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/core/code"
kit "shylinux.com/x/toolkits" kit "shylinux.com/x/toolkits"
) )
func _ssh_session(m *ice.Message, client *ssh.Client) (*ssh.Session, error) { func _ssh_session(m *ice.Message, c *ssh.Client) (*ssh.Session, error) {
s, e := client.NewSession() s, e := c.NewSession()
m.Assert(e) m.Assert(e)
switch cb := m.OptionCB("").(type) {
case func(s *ssh.Session):
cb(s)
return s, nil
}
out, e := s.StdoutPipe() out, e := s.StdoutPipe()
m.Assert(e) m.Assert(e)
in, e := s.StdinPipe() in, e := s.StdinPipe()
m.Assert(e) m.Assert(e)
switch cb := m.OptionCB("").(type) {
case func(s *ssh.Session, in io.Writer, out io.Reader):
cb(s, in, out)
return s, nil
}
h := m.Cmdx(SESSION, mdb.CREATE, mdb.STATUS, tcp.OPEN, CONNECT, m.Option(mdb.NAME), kit.Dict(mdb.TARGET, in)) h := m.Cmdx(SESSION, mdb.CREATE, mdb.STATUS, tcp.OPEN, CONNECT, m.Option(mdb.NAME), kit.Dict(mdb.TARGET, in))
m.Go(func() { m.Go(func() {
buf := make([]byte, ice.MOD_BUFS) buf := make([]byte, ice.MOD_BUFS)
@ -28,7 +39,7 @@ func _ssh_session(m *ice.Message, client *ssh.Client) (*ssh.Session, error) {
if n, e := out.Read(buf); e != nil { if n, e := out.Read(buf); e != nil {
break break
} else { } else {
m.Cmd(SESSION, mdb.INSERT, mdb.HASH, h, mdb.TYPE, RES, mdb.TEXT, string(buf[:n])) m.Cmd(SESSION, mdb.INSERT, mdb.ZONE, h, mdb.TYPE, RES, mdb.TEXT, string(buf[:n]))
} }
} }
}) })
@ -51,7 +62,7 @@ const SESSION = "session"
func init() { func init() {
psh.Index.MergeCommands(ice.Commands{ psh.Index.MergeCommands(ice.Commands{
SESSION: {Name: "session hash id auto", Help: "会话", Actions: ice.MergeActions(ice.Actions{ SESSION: {Help: "会话", Actions: ice.MergeActions(ice.Actions{
mdb.REPEAT: {Help: "执行", Hand: func(m *ice.Message, arg ...string) { m.Cmdy("", ctx.ACTION, ctx.COMMAND, CMD, m.Option(mdb.TEXT)) }}, mdb.REPEAT: {Help: "执行", Hand: func(m *ice.Message, arg ...string) { m.Cmdy("", ctx.ACTION, 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.ZoneInsert(m, m.OptionSimple(mdb.HASH), mdb.TYPE, CMD, mdb.TEXT, m.Option(CMD)) mdb.ZoneInsert(m, m.OptionSimple(mdb.HASH), mdb.TYPE, CMD, mdb.TEXT, m.Option(CMD))
@ -59,7 +70,9 @@ func init() {
w.Write([]byte(m.Option(CMD) + lex.NL)) w.Write([]byte(m.Option(CMD) + lex.NL))
m.Sleep300ms() m.Sleep300ms()
} }
m.ProcessRefresh()
}}, }},
code.XTERM: {},
}, mdb.PageZoneAction(mdb.SHORT, mdb.UNIQ, mdb.FIELD, "time,hash,count,status,connect", mdb.FIELDS, "time,id,type,text")), Hand: func(m *ice.Message, arg ...string) { }, mdb.PageZoneAction(mdb.SHORT, mdb.UNIQ, mdb.FIELD, "time,hash,count,status,connect", mdb.FIELDS, "time,id,type,text")), Hand: func(m *ice.Message, arg ...string) {
if mdb.PageZoneSelect(m, arg...); len(arg) == 0 { if mdb.PageZoneSelect(m, arg...); len(arg) == 0 {
m.Table(func(value ice.Maps) { m.Table(func(value ice.Maps) {

View File

@ -35,7 +35,8 @@ type iterm struct {
*idata *idata
} }
func NewITerm(m *ice.Message) (XTerm, error) { func init() { AddCommand("ish", NewITerm) }
func NewITerm(m *ice.Message, arg ...string) (XTerm, error) {
r, w, e := os.Pipe() r, w, e := os.Pipe()
return &iterm{m: m, r: r, w: w, idata: &idata{cmds: kit.Simple( return &iterm{m: m, r: r, w: w, idata: &idata{cmds: kit.Simple(
kit.SortedKey(ice.Info.Index), kit.SortedKey(ice.Info.Index),

View File

@ -20,7 +20,6 @@ type Winsize struct {
type XTerm interface { type XTerm interface {
Setsize(rows, cols string) error Setsize(rows, cols string) error
Writeln(data string, arg ...ice.Any)
Write(buf []byte) (int, error) Write(buf []byte) (int, error)
Read(buf []byte) (int, error) Read(buf []byte) (int, error)
Close() error Close() error
@ -38,11 +37,16 @@ func (s xterm) Write(buf []byte) (int, error) { return s.File.Write(buf) }
func (s xterm) Read(buf []byte) (int, error) { return s.File.Read(buf) } func (s xterm) Read(buf []byte) (int, error) { return s.File.Read(buf) }
func (s xterm) Close() error { return s.Cmd.Process.Kill() } func (s xterm) Close() error { return s.Cmd.Process.Kill() }
type handler func(m *ice.Message, arg ...string) (XTerm, error)
var list = map[string]handler{}
func AddCommand(key string, cb handler) { list[key] = cb }
func Command(m *ice.Message, dir string, cli string, arg ...string) (XTerm, error) { func Command(m *ice.Message, dir string, cli string, arg ...string) (XTerm, error) {
if path.Base(cli) == "ish" { if cb, ok := list[path.Base(cli)]; ok {
return NewITerm(m) return cb(m.Spawn(), arg...)
} }
m.Debug("command %v %v", cli, arg)
cmd := exec.Command(cli, arg...) cmd := exec.Command(cli, arg...)
cmd.Dir = nfs.MkdirAll(m, kit.Path(dir)) cmd.Dir = nfs.MkdirAll(m, kit.Path(dir))
cmd.Env = append(cmd.Env, os.Environ()...) cmd.Env = append(cmd.Env, os.Environ()...)