1
0
forked from x/ContextOS
2017-12-24 22:25:05 +08:00

154 lines
4.2 KiB
Go

package ssh
import (
"bufio"
"context"
"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 {
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: "主机数量"},
},
Configs: map[string]*ctx.Config{},
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) {
m.Find("tcp").Cmd(m.Meta["detail"]...)
}},
"dial": &ctx.Command{Name: "dial address protocol", Help: "建立连接", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
m.Find("tcp").Cmd(m.Meta["detail"]...)
}},
"open": &ctx.Command{Name: "open", Help: "打开连接", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
m.Start(fmt.Sprintf("host%d", Pulse.Capi("nhost", 1)), "主机连接")
}},
"remote": &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"] {
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)
}