mirror of
https://shylinux.com/x/ContextOS
synced 2025-04-25 16:58:06 +08:00
242 lines
6.9 KiB
Go
242 lines
6.9 KiB
Go
package ssh // {{{
|
|
// }}}
|
|
import ( // {{{
|
|
"bufio"
|
|
"contexts"
|
|
"fmt"
|
|
"net"
|
|
"net/url"
|
|
"strings"
|
|
)
|
|
|
|
// }}}
|
|
|
|
type SSH struct {
|
|
send map[string]*ctx.Message
|
|
*bufio.Writer
|
|
*bufio.Reader
|
|
net.Conn
|
|
|
|
*ctx.Context
|
|
}
|
|
|
|
func (ssh *SSH) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server { // {{{
|
|
c.Caches = map[string]*ctx.Cache{
|
|
"nsend": &ctx.Cache{Name: "消息发送数量", Value: "0", Help: "消息发送数量"},
|
|
"nrecv": &ctx.Cache{Name: "消息接收数量", Value: "0", Help: "消息接收数量"},
|
|
"target": &ctx.Cache{Name: "消息接收模块", Value: "ssh", Help: "消息接收模块"},
|
|
"result": &ctx.Cache{Name: "前一条指令执行结果", Value: "", Help: "前一条指令执行结果"},
|
|
"sessid": &ctx.Cache{Name: "会话令牌", Value: "", Help: "会话令牌"},
|
|
}
|
|
c.Configs = map[string]*ctx.Config{}
|
|
|
|
s := new(SSH)
|
|
s.Context = c
|
|
return s
|
|
}
|
|
|
|
// }}}
|
|
func (ssh *SSH) Begin(m *ctx.Message, arg ...string) ctx.Server { // {{{
|
|
if ssh.Context == Index {
|
|
Pulse = m
|
|
}
|
|
return ssh
|
|
}
|
|
|
|
// }}}
|
|
func (ssh *SSH) Start(m *ctx.Message, arg ...string) bool { // {{{
|
|
return false
|
|
|
|
ssh.Group = ""
|
|
ssh.Owner = nil
|
|
ssh.Conn = m.Data["io"].(net.Conn)
|
|
ssh.Reader = bufio.NewReader(ssh.Conn)
|
|
ssh.Writer = bufio.NewWriter(ssh.Conn)
|
|
ssh.send = make(map[string]*ctx.Message)
|
|
m.Log("info", nil, "%s connect %v <-> %v", Pulse.Cap("nhost"), ssh.Conn.LocalAddr(), ssh.Conn.RemoteAddr())
|
|
|
|
target, msg := m.Target(), m.Spawn(m.Target())
|
|
|
|
for {
|
|
line, e := ssh.Reader.ReadString('\n')
|
|
m.Assert(e)
|
|
|
|
if line = strings.TrimSpace(line); len(line) == 0 {
|
|
if msg.Log("info", nil, "remote: %v", msg.Meta["option"]); msg.Has("detail") {
|
|
msg.Log("info", nil, "%d exec: %v", m.Capi("nrecv", 1), msg.Meta["detail"])
|
|
|
|
msg.Cmd(msg.Meta["detail"])
|
|
target = msg.Target()
|
|
m.Cap("target", target.Name)
|
|
|
|
for _, v := range msg.Meta["result"] {
|
|
fmt.Fprintf(ssh.Writer, "result: %s\n", url.QueryEscape(v))
|
|
}
|
|
|
|
fmt.Fprintf(ssh.Writer, "nsend: %s\n", msg.Get("nrecv"))
|
|
for _, k := range msg.Meta["append"] {
|
|
for _, v := range msg.Meta[k] {
|
|
fmt.Fprintf(ssh.Writer, "%s: %s\n", k, v)
|
|
}
|
|
}
|
|
fmt.Fprintf(ssh.Writer, "\n")
|
|
ssh.Writer.Flush()
|
|
} else {
|
|
msg.Log("info", nil, "%s echo: %v", msg.Get("nsend"), msg.Meta["result"])
|
|
|
|
m.Cap("result", msg.Get("result"))
|
|
msg.Meta["append"] = msg.Meta["option"]
|
|
send := ssh.send[msg.Get("nsend")]
|
|
send.Meta = msg.Meta
|
|
send.Recv <- true
|
|
}
|
|
msg = m.Spawn(target)
|
|
continue
|
|
}
|
|
|
|
ls := strings.SplitN(line, ":", 2)
|
|
ls[0] = strings.TrimSpace(ls[0])
|
|
ls[1], e = url.QueryUnescape(strings.TrimSpace(ls[1]))
|
|
m.Assert(e)
|
|
msg.Add("option", ls[0], ls[1])
|
|
}
|
|
return false
|
|
}
|
|
|
|
// }}}
|
|
func (ssh *SSH) Close(m *ctx.Message, arg ...string) bool { // {{{
|
|
switch ssh.Context {
|
|
case m.Target():
|
|
case m.Source():
|
|
}
|
|
return true
|
|
}
|
|
|
|
// }}}
|
|
|
|
var Pulse *ctx.Message
|
|
var Index = &ctx.Context{Name: "ssh", Help: "集群中心",
|
|
Caches: map[string]*ctx.Cache{
|
|
"nhost": &ctx.Cache{Name: "主机数量", Value: "0", Help: "主机数量"},
|
|
"route": &ctx.Cache{Name: "route", Value: "ssh", Help: "主机数量"},
|
|
},
|
|
Configs: map[string]*ctx.Config{
|
|
"route": &ctx.Config{Name: "route", Value: "com", Help: "主机数量"},
|
|
},
|
|
Commands: map[string]*ctx.Command{
|
|
"listen": &ctx.Command{Name: "listen address protocol", Help: "监听连接", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
|
msg := m.Sess("file", "nfs")
|
|
msg.Call(func(ok bool) (done bool, up bool) {
|
|
if ok {
|
|
sub := msg.Spawn(m.Target())
|
|
sub.Start(fmt.Sprintf("host%d", Pulse.Capi("nhost", 1)), "打开文件", sub.Meta["detail"]...)
|
|
sub.Cap("stream", msg.Target().Name)
|
|
sub.Target().Sessions["file"] = msg
|
|
sub.Echo(sub.Target().Name)
|
|
sub.Spawn(sub.Target()).Cmd("send", "context", "ssh")
|
|
sub.Spawn(sub.Target()).Cmd("send", "route", sub.Target().Name, msg.Cap("route"))
|
|
}
|
|
return false, true
|
|
}, false).Cmd(m.Meta["detail"])
|
|
|
|
}},
|
|
"dial": &ctx.Command{Name: "dial address protocol", Help: "建立连接", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
|
msg := m.Sess("file", "nfs")
|
|
msg.Call(func(ok bool) (done bool, up bool) {
|
|
if ok {
|
|
m.Sess("file").Cmd("send", "context", "ssh")
|
|
m.Cap("stream", msg.Target().Name)
|
|
return true, true
|
|
}
|
|
return false, false
|
|
}, false).Cmd(m.Meta["detail"])
|
|
|
|
}},
|
|
"send": &ctx.Command{Name: "send arg...", Help: "打开连接", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
|
msg := m.Sess("file")
|
|
msg.Copy(m, "detail").Call(func(ok bool) (done bool, up bool) {
|
|
return ok, ok
|
|
}, false).Cmd()
|
|
m.Copy(msg, "result")
|
|
}},
|
|
"pwd": &ctx.Command{Name: "pwd", Help: "远程执行", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
|
m.Echo(m.Cap("route"))
|
|
}},
|
|
"route": &ctx.Command{Name: "route", Help: "远程执行", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
|
m.Conf("route", arg[0])
|
|
m.Cap("route", arg[1]+"."+arg[0])
|
|
}},
|
|
"search": &ctx.Command{Name: "search route cmd arg...", Help: "远程执行", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
|
if _, ok := m.Target().Server.(*SSH); m.Assert(ok) {
|
|
if len(arg[0]) == 0 {
|
|
msg := m.Spawn(m.Target()).Cmd(arg[1:])
|
|
m.Copy(msg, "result")
|
|
return
|
|
}
|
|
|
|
miss := true
|
|
target := strings.Split(arg[0], ".")
|
|
m.Travel(m.Target(), func(m *ctx.Message) bool {
|
|
if m.Target().Name == target[0] {
|
|
msg := m.Spawn(m.Target())
|
|
msg.Call(func(ok bool) (done bool, up bool) {
|
|
m.Copy(msg, "result")
|
|
return ok, ok
|
|
}, false).Cmd("send", "search", strings.Join(target[1:], "."), arg[1:])
|
|
|
|
miss = false
|
|
}
|
|
return miss
|
|
})
|
|
|
|
if miss {
|
|
msg := m.Spawn(c)
|
|
msg.Call(func(ok bool) (done bool, up bool) {
|
|
m.Copy(msg, "result")
|
|
return ok, ok
|
|
}, false).Cmd("send", "search", arg)
|
|
}
|
|
}
|
|
}},
|
|
"dispatch": &ctx.Command{Name: "dispatch route cmd arg...", Help: "远程执行", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
|
m.Travel(m.Target(), func(m *ctx.Message) bool {
|
|
|
|
msg := m.Spawn(m.Target())
|
|
msg.Cmd("send", arg)
|
|
return true
|
|
})
|
|
}},
|
|
"register": &ctx.Command{Name: "remote detail...", Help: "远程执行", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
|
|
ssh, ok := m.Target().Server.(*SSH)
|
|
m.Assert(ok)
|
|
|
|
m.Capi("nsend", 1)
|
|
m.Add("option", "nrecv", m.Cap("nsend"))
|
|
ssh.send[m.Cap("nsend")] = m
|
|
|
|
for _, v := range arg {
|
|
fmt.Fprintf(ssh.Writer, "detail: %v\n", v)
|
|
}
|
|
for _, k := range m.Meta["option"] {
|
|
if k == "args" {
|
|
continue
|
|
}
|
|
for _, v := range m.Meta[k] {
|
|
fmt.Fprintf(ssh.Writer, "%s: %s\n", k, v)
|
|
}
|
|
}
|
|
fmt.Fprintf(ssh.Writer, "\n")
|
|
ssh.Writer.Flush()
|
|
|
|
m.Recv = make(chan bool)
|
|
<-m.Recv
|
|
}},
|
|
},
|
|
}
|
|
|
|
func init() {
|
|
ssh := &SSH{}
|
|
ssh.Context = Index
|
|
ctx.Index.Register(Index, ssh)
|
|
}
|