1
0
mirror of https://shylinux.com/x/ContextOS synced 2025-04-25 08:48:06 +08:00

创建上下文,支持消息处理、服务启动、自动级联、路径搜索

This commit is contained in:
shaoying 2017-11-01 00:08:08 +08:00
commit c4e8a4b718
9 changed files with 1504 additions and 0 deletions

20
bench.go Normal file
View File

@ -0,0 +1,20 @@
package main
import (
_ "context"
"context/cli"
_ "context/ssh"
"os"
)
func main() {
if len(os.Args) > 1 {
cli.Index.Conf("log", os.Args[1])
}
if len(os.Args) > 2 {
cli.Index.Conf("init.sh", os.Args[2])
}
cli.Index.Start()
}

18
etc/cert.pem Normal file
View File

@ -0,0 +1,18 @@
-----BEGIN CERTIFICATE-----
MIIC9TCCAl4CCQCHSqshz+HyLTANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC
R0IxHzAdBgNVBAgTFlRlc3QgU3RhdGUgb3IgUHJvdmluY2UxFjAUBgNVBAcTDVRl
c3QgTG9jYWxpdHkxGjAYBgNVBAoTEU9yZ2FuaXphdGlvbiBOYW1lMSEwHwYDVQQL
ExhPcmdhbml6YXRpb25hbCBVbml0IE5hbWUxFDASBgNVBAMTC0NvbW1vbiBOYW1l
MSEwHwYJKoZIhvcNAQkBFhJ0ZXN0QGVtYWlsLmFkZHJlc3MwHhcNMTcxMDMxMTYw
NDM5WhcNMTcxMTMwMTYwNDM5WjCBvjELMAkGA1UEBhMCR0IxHzAdBgNVBAgTFlRl
c3QgU3RhdGUgb3IgUHJvdmluY2UxFjAUBgNVBAcTDVRlc3QgTG9jYWxpdHkxGjAY
BgNVBAoTEU9yZ2FuaXphdGlvbiBOYW1lMSEwHwYDVQQLExhPcmdhbml6YXRpb25h
bCBVbml0IE5hbWUxFDASBgNVBAMTC0NvbW1vbiBOYW1lMSEwHwYJKoZIhvcNAQkB
FhJ0ZXN0QGVtYWlsLmFkZHJlc3MwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGB
AOw3gvdtfKWkSEl2l30V7irBhkrD6IVd6AzxaAYL97giDglPvu7ng2PXYlF5pjjf
mxDYtjAGuq1itnN0LKRe6CjUOuGtC2KMlZ8121fQCNw8M6TLPSpDjVuzysaUb2ds
+OClb0uC8SmSy3bOCGsicI77yXvEuKFkm43ikyVounmRAgMBAAEwDQYJKoZIhvcN
AQELBQADgYEAkOk7DVR/XgJdMSXXGd/OtWmTfVp2sIyyy37zSoc4uRFWwPqbzLPf
NgUKGNHEYvJY7/bWQ3p2D+u1U2PUfv/t6SQcAu3Nkw7sd7PoeeDZcRau84NevgoR
HfQKirJQgZd0hKFwiBnDspYbi8IL2mHEJOlzw1priY9v8MVIscyFVbE=
-----END CERTIFICATE-----

9
etc/he.sh Normal file
View File

@ -0,0 +1,9 @@
alias ~ context
alias ! history
alias @ config
alias $ cache
alias & server
alias * message
~ssh
&

10
etc/hi.sh Normal file
View File

@ -0,0 +1,10 @@
alias ~ context
alias ! history
alias @ config
alias $ cache
alias & server
alias * message
~ssh
@client no
&

15
etc/key.pem Normal file
View File

@ -0,0 +1,15 @@
-----BEGIN RSA PRIVATE KEY-----
MIICXwIBAAKBgQDsN4L3bXylpEhJdpd9Fe4qwYZKw+iFXegM8WgGC/e4Ig4JT77u
54Nj12JReaY435sQ2LYwBrqtYrZzdCykXugo1DrhrQtijJWfNdtX0AjcPDOkyz0q
Q41bs8rGlG9nbPjgpW9LgvEpkst2zghrInCO+8l7xLihZJuN4pMlaLp5kQIDAQAB
AoGBAOasYwG68pFTN6A95jupsdYg/EKAw82RYa1aBUp6X2N6JhjjvkHQ5ZcXWxTT
ZgZ+HhC6gFewCpaNIjzmwz2UzMJJ4empijEbJFuwZCq4M/Adca2BhduV2YIwqvi8
MHGmHMB81zYKA0E4j+vahJnn8aAqSoPnaM9MBw5vhggU5YodAkEA/IwRTVNOHmIm
1XCfvPoSpDBpSJh6V1mPyBuPs/2Fr52j+L+6qOhNML0O063az44/dR8RZytcaGYQ
7EByYbeCZwJBAO9ySW4TbDLRejSmFWHmflrnjV7s4DqE6OBbCRJF3aIleELYaTPC
Q0kOKRZTCr1PwopIdAOOOgaSWgsX75zU2UcCQQDMCwb3qLTXC4pArMwCzTE+gvat
drRx2qS2kr4aOF1ItF8E3TOcwIONO1K9aBv/0fgnUsCm0HvKxZwqpS9FEBVFAkEA
ntgeRlu0J3I3s72J6cxSflOlwRc7GRcatdsuhWS7xtk8knumLqPspwYx05F7SmMj
F0FBVSqA6+MiwME8P7oj+QJBAJFv2HKAaGElXkaJJzmQPHGJdGLUMb9oHXPtzcpz
HLtT2kHK1LlQqsOEacivPCKtnnLkX6Xsl8pMpe8EV43t718=
-----END RSA PRIVATE KEY-----

513
src/context/cli/cli.go Normal file
View File

@ -0,0 +1,513 @@
package cli // {{{
// }}}
import ( // {{{
"bufio"
"context"
"fmt"
"io"
"log"
"os"
"os/exec"
"strconv"
"strings"
"time"
"unicode"
)
// }}}
type CLI struct {
in *os.File
ins []*os.File
bio *bufio.Reader
bios []*bufio.Reader
out *os.File
index int
history []map[string]string
alias map[string]string
next string
loop int
target *ctx.Context
exit chan bool
*ctx.Context
}
func (cli *CLI) push(f *os.File) { // {{{
if cli.ins == nil || cli.bios == nil {
cli.ins = make([]*os.File, 0, 3)
cli.bios = make([]*bufio.Reader, 0, 3)
}
cli.in = f
cli.ins = append(cli.ins, cli.in)
cli.bio = bufio.NewReader(f)
cli.bios = append(cli.bios, cli.bio)
}
// }}}
func (cli *CLI) parse() bool { // {{{
if len(cli.ins) == 1 {
cli.echo(cli.Conf("PS1"))
}
line := ""
if cli.next == "" {
l, e := cli.bio.ReadString('\n')
if e == io.EOF {
l := len(cli.ins)
if l == 1 {
if cli.Conf("slient") != "yes" {
cli.echo("\n")
cli.echo(cli.Conf("结束语"))
}
cli.echo("\n")
cli.exit <- true
return false
} else {
cli.ins = cli.ins[:l-1]
cli.bios = cli.bios[:l-1]
cli.in = cli.ins[l-2]
cli.bio = cli.bios[l-2]
return true
}
}
cli.Check(e)
line = l
} else {
line = cli.next
if len(cli.ins) == 1 {
cli.echo(line)
cli.echo("\n")
}
}
if len(cli.ins) > 1 {
cli.echo(cli.Conf("PS1"))
cli.echo(line)
}
cli.next = ""
if len(line) == 1 {
return true
}
line = strings.TrimSpace(line)
if line[0] == '#' {
return true
}
ls := strings.Split(line, " ")
msg := &ctx.Message{Wait: make(chan bool)}
msg.Context = cli.Context
r := rune(ls[0][0])
if !unicode.IsNumber(r) || !unicode.IsLetter(r) || r == '$' || r == '_' {
if _, ok := cli.alias[string(r)]; ok {
msg.Add("detail", ls[0][:1])
if len(ls[0]) > 1 {
ls[0] = ls[0][1:]
} else {
if len(ls) > 1 {
ls = ls[1:]
} else {
ls = nil
}
}
}
}
for i := 0; i < len(ls); i++ {
ls[i] = strings.TrimSpace(ls[i])
if ls[i][0] == '#' {
break
}
if ls[i] != "" {
msg.Add("detail", ls[i])
}
}
cli.Context.Messages <- msg
<-msg.Wait
for _, v := range msg.Meta["result"] {
cli.echo(v)
}
return true
}
// }}}
func (cli *CLI) deal(msg *ctx.Message) bool { // {{{
defer func() {
if e := recover(); e != nil {
msg.Echo("%s", e)
log.Println(e)
}
}()
detail := msg.Meta["detail"]
switch cli.Conf("mode") {
case "local":
if a, ok := cli.alias[detail[0]]; ok {
detail[0] = a
}
if _, ok := cli.Commands[detail[0]]; ok {
cli.loop = 0
cli.next = cli.Cmd(msg, detail...)
} else if _, ok := cli.target.Commands[detail[0]]; ok {
cli.loop = 0
cli.target.Message = msg
cli.next = cli.target.Cmd(msg, detail...)
} else {
cmd := exec.Command(detail[0], detail[1:]...)
v, e := cmd.CombinedOutput()
if e != nil && cli.loop < 1 {
cli.next = cli.Conf("default") + " " + strings.Join(detail, " ")
cli.loop++
}
msg.Echo(string(v))
log.Println(cli.Name, "command:", detail)
}
}
cli.history = append(cli.history, map[string]string{
"time": time.Now().Format("15:04:05"),
"index": fmt.Sprintf("%d", cli.index),
"cli": strings.Join(detail, " "),
})
cli.index++
return true
}
// }}}
func (cli *CLI) echo(str string, arg ...interface{}) { // {{{
if len(cli.ins) == 1 || cli.Conf("slient") != "yes" {
fmt.Fprintf(cli.out, str, arg...)
}
}
// }}}
func (cli *CLI) Begin() bool { // {{{
// cli.Conf("log", cli.Conf("log"))
for k, v := range cli.Configs {
cli.Conf(k, v.Value)
}
if cli.Conf("slient") != "yes" {
cli.echo("\n")
cli.echo(cli.Conf("开场白"))
cli.echo("\n")
}
cli.exit = make(chan bool)
cli.target = cli.Context
cli.history = make([]map[string]string, 0, 100)
cli.alias = make(map[string]string, 10)
if f, e := os.Open(cli.Conf("init.sh")); e == nil {
cli.push(f)
}
return true
}
// }}}
func (cli *CLI) Start() bool { // {{{
cli.Begin()
go func() {
for cli.parse() {
}
}()
for {
select {
case cli.Message = <-cli.Messages:
cli.deal(cli.Message)
if cli.Message.Wait != nil {
cli.Message.Wait <- true
}
case <-cli.exit:
return true
}
}
return true
}
// }}}
func (cli *CLI) Fork(c *ctx.Context, key string) ctx.Server { // {{{
s := new(CLI)
s.Context = c
return s
}
// }}}
func (cli *CLI) Spawn(c *ctx.Context, key string) ctx.Server { // {{{
s := new(CLI)
s.Context = c
return s
}
// }}}
var Index = &ctx.Context{Name: "cli", Help: "命文",
Caches: map[string]*ctx.Cache{},
Configs: map[string]*ctx.Config{
"开场白": &ctx.Config{"开场白", "你好,命令行", "开场白", nil},
"结束语": &ctx.Config{"结束语", "再见,命令行", "结束语", nil},
"mode": &ctx.Config{"mode", "local", "命令执行模式", nil},
"io": &ctx.Config{"io", "stdout", "输入输出", func(c *ctx.Context, arg string) string {
cli := c.Server.(*CLI) // {{{
cli.out = os.Stdout
cli.push(os.Stdin)
return arg
// }}}
}},
"slient": &ctx.Config{"slient", "yes", "静默启动", nil},
"init.sh": &ctx.Config{"init.sh", "etc/hi.sh", "启动脚本", nil},
"default": &ctx.Config{"default", "get", "默认命令", nil},
"log": &ctx.Config{"log", "var/bench.log", "日志文件", func(c *ctx.Context, arg string) string {
if l, e := os.Create(arg); e == nil { // {{{
log.SetOutput(l)
} else {
log.Println("log", arg, "create error")
}
return arg
// }}}
}},
"PS1": &ctx.Config{"PS1", "etcvpn>", "命令行提示符", func(c *ctx.Context, arg string) string {
cli := c.Server.(*CLI)
self := c.Server.(*CLI) // {{{
if cli != nil && cli.target != nil {
arg = cli.target.Name + ">"
}
return fmt.Sprintf("%d[%s]\033[32m%s\033[0m ", self.index, time.Now().Format("15:04:05"), arg)
// }}}
}},
},
Commands: map[string]*ctx.Command{
"cache": &ctx.Command{"cache [name [value [help]]]", "查看修改添加配置", func(c *ctx.Context, msg *ctx.Message, arg ...string) string {
cli := c.Server.(*CLI) // {{{
switch len(arg) {
case 1:
for k, v := range cli.target.Caches {
msg.Echo("%s(%s): %s\n", k, v.Value, v.Help)
}
case 2:
if v, ok := cli.target.Caches[arg[1]]; ok {
msg.Echo("%s: %s\n", v.Name, v.Help)
}
case 3:
switch arg[1] {
case "delete":
if _, ok := cli.target.Caches[arg[2]]; ok {
delete(cli.target.Caches, arg[2])
}
default:
if _, ok := cli.target.Caches[arg[1]]; ok {
msg.Echo("%s: %s\n", arg[1], cli.target.Cap(arg[1:]...))
}
}
case 5:
cli.target.Cap(arg[1:]...)
}
return ""
// }}}
}},
"config": &ctx.Command{"config [name [value [help]]]", "查看修改添加配置", func(c *ctx.Context, msg *ctx.Message, arg ...string) string {
cli := c.Server.(*CLI) // {{{
switch len(arg) {
case 1:
for k, v := range cli.target.Configs {
msg.Echo("%s(%s): %s\n", k, v.Value, v.Help)
}
case 2:
if v, ok := cli.target.Configs[arg[1]]; ok {
msg.Echo("%s: %s\n", v.Name, v.Help)
}
case 3:
switch arg[1] {
case "delete":
if _, ok := cli.target.Configs[arg[2]]; ok {
delete(cli.target.Configs, arg[2])
}
default:
if _, ok := cli.target.Configs[arg[1]]; ok {
cli.target.Conf(arg[1:]...)
}
}
case 5:
cli.target.Conf(arg[1:]...)
}
return ""
// }}}
}},
"command": &ctx.Command{"command [name [value [help]]]", "查看修改添加配置", func(c *ctx.Context, msg *ctx.Message, arg ...string) string {
cli := c.Server.(*CLI) // {{{
switch len(arg) {
case 1:
for k, v := range cli.target.Commands {
msg.Echo("%s: %s\n", k, v.Help)
}
case 2:
if v, ok := cli.target.Commands[arg[1]]; ok {
msg.Echo("%s: %s\n", v.Name, v.Help)
}
case 3:
switch arg[1] {
case "delete":
if _, ok := cli.target.Commands[arg[2]]; ok {
delete(cli.target.Commands, arg[2])
}
}
}
msg.Echo("\n")
return ""
// }}}
}},
"source": &ctx.Command{"source file", "运行脚本", func(c *ctx.Context, msg *ctx.Message, arg ...string) string {
cli := c.Server.(*CLI) // {{{
f, e := os.Open(arg[1])
c.Check(e)
cli.push(f)
return ""
// }}}
}},
"alias": &ctx.Command{"alias [short [long]]", "查看日志", func(c *ctx.Context, msg *ctx.Message, arg ...string) string {
cli := c.Server.(*CLI) // {{{
switch len(arg) {
case 1:
for k, v := range cli.alias {
msg.Echo("%s: %s\n", k, v)
}
case 3:
switch arg[1] {
case "delete":
delete(cli.alias, arg[2])
default:
cli.alias[arg[1]] = arg[2]
msg.Echo("%s: %s\n", arg[1], cli.alias[arg[1]])
}
}
return ""
// }}}
}},
"history": &ctx.Command{"history number", "查看日志", func(c *ctx.Context, msg *ctx.Message, arg ...string) string {
cli := c.Server.(*CLI) // {{{
switch len(arg) {
case 1:
for i, v := range cli.history {
msg.Echo("%d %s %s\n", i, v["time"], v["cli"])
}
case 2:
n, e := strconv.Atoi(arg[1])
if e == nil && 0 <= n && n < len(cli.history) {
return cli.history[n]["cli"]
}
}
return ""
// }}}
}},
"message": &ctx.Command{"message [find|search name [switch]]|root|back|home", "查看上下文", func(c *ctx.Context, msg *ctx.Message, arg ...string) string {
return ""
}},
"server": &ctx.Command{"server start|stop|switch", "服务启动停止切换", func(c *ctx.Context, msg *ctx.Message, arg ...string) string {
cli := c.Server.(*CLI)
switch len(arg) {
case 1:
go cli.target.Start()
case 2:
switch arg[1] {
case "start":
go cli.target.Start()
msg.Echo("\n")
case "stop":
case "switch":
}
}
return ""
}},
"context": &ctx.Command{"context [find|search name [switch]]|root|back|home", "查看上下文", func(c *ctx.Context, msg *ctx.Message, arg ...string) string {
cli := c.Server.(*CLI) // {{{
switch len(arg) {
case 1:
cs := []*ctx.Context{cli.target}
for i := 0; i < len(cs); i++ {
if len(cs[i].Contexts) > 0 {
msg.Echo("%s: ", cs[i].Name)
for k, v := range cs[i].Contexts {
cs = append(cs, v)
msg.Echo("%s, ", k)
}
msg.Echo("\n")
}
}
case 2, 3, 4, 5:
switch arg[1] {
case "root":
cli.target = cli.Context.Root
case "back":
if cli.Context.Context != nil {
cli.target = cli.Context.Context
}
case "home":
cli.target = cli.Context
case "find":
cs := c.Root.Find(strings.Split(arg[2], "."))
msg.Echo("%s: %s\n", cs.Name, cs.Help)
if len(arg) == 4 {
cli.target = cs
}
case "search":
cs := c.Root.Search(arg[2])
for i, v := range cs {
msg.Echo("[%d] %s: %s\n", i, v.Name, v.Help)
}
if len(arg) == 5 {
n, e := strconv.Atoi(arg[4])
if 0 <= n && n < len(cs) && e == nil {
cli.target = cs[0]
} else {
msg.Echo("参数错误(0<=n<%s)", len(cs))
}
}
if len(arg) == 4 {
cli.target = cs[0]
}
default:
cs := c.Root.Find(strings.Split(arg[1], "."))
msg.Echo("%s: %s\n", cs.Name, cs.Help)
if cs != nil {
cli.target = cs
}
}
}
msg.Echo("\ncurr: %s(%s)\n", cli.target.Name, cli.target.Help)
return ""
// }}}
}},
},
Messages: make(chan *ctx.Message, 10),
}
func init() {
self := &CLI{}
self.Context = Index
ctx.Index.Register(Index, self)
}

538
src/context/ctx.go Normal file
View File

@ -0,0 +1,538 @@
package ctx // {{{
// }}}
import ( // {{{
"errors"
"fmt"
"log"
"runtime/debug"
"strconv"
)
// }}}
type Cache struct { // {{{
Name string
Value string
Help string
Hand func(c *Context, arg string) string
}
// }}}
type Config struct { // {{{
Name string
Value string
Help string
Hand func(c *Context, arg string) string
}
// }}}
type Command struct { // {{{
Name string
Help string
Hand func(c *Context, m *Message, arg ...string) string
}
// }}}
type Message struct { // {{{
Meta map[string][]string
Data map[string]interface{}
Wait chan bool
*Context
}
func (m *Message) Add(key string, value ...string) string { // {{{
if m.Meta == nil {
m.Meta = make(map[string][]string)
}
if _, ok := m.Meta[key]; !ok {
m.Meta[key] = []string{}
}
m.Meta[key] = append(m.Meta[key], value...)
return value[0]
}
// }}}
func (m *Message) Put(key string, value interface{}) interface{} { // {{{
if m.Data == nil {
m.Data = make(map[string]interface{})
}
m.Data[key] = value
return value
}
// }}}
func (m *Message) Has(key string) bool { // {{{
if _, ok := m.Meta[key]; ok {
return true
}
if _, ok := m.Data[key]; ok {
return true
}
return false
}
// }}}
func (m *Message) Get(key string) string { // {{{
if meta, ok := m.Meta[key]; ok {
return meta[0]
}
return ""
}
// }}}
func (m *Message) Echo(str string, arg ...interface{}) string { // {{{
if m.Meta == nil {
m.Meta = make(map[string][]string)
}
if _, ok := m.Meta["result"]; !ok {
m.Meta["result"] = []string{}
}
s := fmt.Sprintf(str, arg...)
m.Meta["result"] = append(m.Meta["result"], s)
return s
}
// }}}
// }}}
type Server interface { // {{{
Begin() bool
Start() bool
Fork(c *Context, key string) Server
Spawn(c *Context, key string) Server
}
// }}}
type Context struct { // {{{
Name string
Help string
Caches map[string]*Cache
Configs map[string]*Config
Commands map[string]*Command
Messages chan *Message
Message *Message
Server
Root *Context
Context *Context
Contexts map[string]*Context
Index map[string]*Context
Shadows map[string]*Context
}
func (c *Context) Check(e error) bool { // {{{
if e != nil {
log.Println(c.Name, "error:", e)
debug.PrintStack()
panic(e)
}
return true
}
// }}}
func (c *Context) Find(name []string) *Context { // {{{
if x, ok := c.Contexts[name[0]]; ok {
if len(name) == 1 {
return x
}
return x.Find(name[1:])
}
return nil
}
// }}}
func (c *Context) Search(name string) []*Context { // {{{
ps := make([]*Context, 0, 3)
cs := []*Context{c.Root}
for i := 0; i < len(cs); i++ {
for _, v := range cs[i].Contexts {
cs = append(cs, v)
}
if cs[i].Name == name {
ps = append(ps, cs[i])
}
}
return ps
}
// }}}
func (c *Context) Register(s *Context, self Server) bool { // {{{
if c.Contexts == nil {
c.Contexts = make(map[string]*Context)
}
if x, ok := c.Contexts[s.Name]; ok {
panic(errors.New(x.Name + "上下文已存在"))
}
c.Contexts[s.Name] = s
s.Root = c.Root
s.Context = c
s.Server = self
return true
}
// }}}
func (c *Context) Init(arg ...string) { // {{{
if c.Root == nil {
c.Root = c
cs := []*Context{c}
for i := 0; i < len(cs); i++ {
for _, v := range cs[i].Contexts {
cs = append(cs, v)
}
cs[i].Init()
}
cs = c.Search(arg[0])
cs[0].Begin()
cs[0].Start()
} else {
for _, v := range c.Contexts {
v.Root = c.Root
v.Context = c
}
}
}
// }}}
func (c *Context) Fork(key string) { // {{{
cs := []*Context{new(Context)}
*cs[0] = *c
for i := 0; i < len(cs); i++ {
cs[i].Name = cs[i].Name + key
cs[i].Messages = make(chan *Message, len(cs[i].Messages))
cs[i].Context.Register(cs[i], cs[i].Server.Fork(cs[i], key))
for _, v := range cs[i].Contexts {
s := new(Context)
*s = *v
s.Context = cs[i]
cs = append(cs, s)
}
}
}
// }}}
func (c *Context) Spawn(key string) *Context { // {{{
s := new(Context)
s.Name = c.Name + key
s.Help = c.Help
s.Caches = make(map[string]*Cache)
s.Configs = make(map[string]*Config)
s.Commands = make(map[string]*Command)
s.Messages = make(chan *Message, len(c.Messages))
c.Register(s, c.Server.Spawn(s, key))
log.Println(c.Name, "spawn", c.Contexts[s.Name].Name)
return s
}
// }}}
func (c *Context) Cap(arg ...string) string { // {{{
switch len(arg) {
case 1:
if v, ok := c.Caches[arg[0]]; ok {
if v.Hand != nil {
v.Value = v.Hand(c, v.Value)
}
log.Println(c.Name, "cache:", arg)
return v.Value
}
if c.Context != nil {
return c.Context.Cap(arg...)
}
case 2:
if v, ok := c.Caches[arg[0]]; ok {
v.Value = arg[1]
if v.Hand != nil {
v.Value = v.Hand(c, v.Value)
}
return v.Value
}
if c.Context != nil {
return c.Context.Cap(arg...)
}
case 3:
if v, ok := c.Caches[arg[0]]; ok {
panic(errors.New(v.Name + "缓存项已存在"))
}
c.Caches[arg[0]] = &Cache{arg[0], arg[1], arg[2], nil}
log.Println(c.Name, "cache:", arg)
return arg[1]
default:
panic(errors.New(arg[0] + "缓存项参数错误"))
}
panic(errors.New(arg[0] + "缓存项不存在"))
}
// }}}
func (c *Context) Conf(arg ...string) string { // {{{
switch len(arg) {
case 1:
if v, ok := c.Configs[arg[0]]; ok {
if v.Hand != nil {
return v.Hand(c, v.Value)
}
return v.Value
}
if c.Context != nil {
return c.Context.Conf(arg...)
}
case 2:
if v, ok := c.Configs[arg[0]]; ok {
v.Value = arg[1]
if v.Hand != nil {
v.Hand(c, v.Value)
}
log.Println(c.Name, "config:", arg)
return v.Value
}
if c.Context != nil {
return c.Context.Conf(arg...)
}
case 4:
if v, ok := c.Configs[arg[0]]; ok {
panic(errors.New(v.Name + "配置项已存在"))
}
c.Configs[arg[0]] = &Config{arg[1], arg[2], arg[3], nil}
log.Println(c.Name, "config:", arg)
return arg[2]
default:
panic(errors.New(arg[0] + "配置项参数错误"))
}
panic(errors.New(arg[0] + "配置项不存在"))
}
// }}}
func (c *Context) Confi(arg ...string) int { // {{{
n, e := strconv.Atoi(c.Conf(arg...))
c.Check(e)
return n
}
// }}}
func (c *Context) Cmd(m *Message, arg ...string) string { // {{{
if x, ok := c.Commands[arg[0]]; ok {
log.Println(c.Name, "command:", arg)
return x.Hand(c, m, arg...)
}
if c.Context != nil {
return c.Context.Cmd(m, arg...)
}
panic(errors.New(fmt.Sprintf(arg[0] + "命令项不存在")))
}
// }}}
func (c *Context) Post(m *Message) bool { // {{{
if c.Messages == nil {
c.Messages = make(chan *Message, 10)
}
c.Messages <- m
if m.Wait != nil {
return <-m.Wait
}
log.Println(c.Context.Name, "message", m.Meta["detail"])
return true
}
// }}}
func (c *Context) Add(arg ...string) { // {{{
switch arg[0] {
case "context":
if len(arg) != 4 {
panic(errors.New("参数错误"))
}
if c.Index == nil {
panic(errors.New("索引表不存在"))
}
if v, ok := c.Index[arg[1]]; ok {
panic(errors.New(v.Name + "上下文已存在"))
}
if c.Shadows == nil {
c.Shadows = make(map[string]*Context)
}
c.Shadows[arg[1]] = &Context{Name: arg[2], Help: arg[3], Index: c.Index}
c.Index[arg[1]] = c.Shadows[arg[1]]
log.Println(c.Name, "add context:", arg[1:])
case "command":
if len(arg) != 3 {
panic(errors.New("参数错误"))
}
if v, ok := c.Shadows[arg[1]]; ok {
if v.Commands == nil {
v.Commands = make(map[string]*Command)
}
if x, ok := v.Commands[arg[2]]; ok {
panic(errors.New(x.Name + "命令已存在"))
}
if x, ok := c.Commands[arg[2]]; ok {
log.Println(v.Name, "add command:", arg[2])
v.Commands[arg[2]] = x
} else {
panic(errors.New(arg[2] + "命令不存在"))
}
} else {
panic(errors.New(arg[1] + "上下文不存在"))
}
case "config":
if len(arg) != 3 {
panic(errors.New("参数错误"))
}
if v, ok := c.Shadows[arg[1]]; ok {
if v.Configs == nil {
v.Configs = make(map[string]*Config)
}
if x, ok := v.Configs[arg[2]]; ok {
panic(errors.New(x.Name + "配置项已存在"))
}
if x, ok := c.Configs[arg[2]]; ok {
log.Println(v.Name, "add config:", arg[2])
v.Configs[arg[2]] = x
} else {
panic(errors.New(arg[2] + "配置项不存在"))
}
} else {
panic(errors.New(arg[1] + "上下文不存在"))
}
case "cache":
if len(arg) != 3 {
panic(errors.New("参数错误"))
}
if v, ok := c.Shadows[arg[1]]; ok {
if v.Caches == nil {
v.Caches = make(map[string]*Cache)
}
if x, ok := v.Caches[arg[2]]; ok {
panic(errors.New(x.Name + "缓存项已存在"))
}
if x, ok := c.Caches[arg[2]]; ok {
log.Println(v.Name, "add cache:", arg[2])
v.Caches[arg[2]] = x
} else {
panic(errors.New(arg[2] + "缓存项不存在"))
}
} else {
panic(errors.New(arg[1] + "上下文不存在"))
}
}
}
// }}}
func (c *Context) Del(arg ...string) { // {{{
cs := make([]*Context, 0, 5)
switch arg[0] {
case "context":
if len(arg) != 2 {
panic(errors.New("参数错误"))
}
if v, ok := c.Shadows[arg[1]]; ok {
cs = append(cs, v)
delete(c.Index, arg[1])
delete(c.Shadows, arg[1])
log.Println(c.Name, "del context:", arg[1])
}
for i := 0; i < len(cs); i++ {
for k, v := range cs[i].Shadows {
cs = append(cs, v)
delete(c.Index, k)
log.Println(c.Name, "del context:", k)
}
}
case "command":
if len(arg) != 3 {
panic(errors.New("参数错误"))
}
if v, ok := c.Shadows[arg[1]]; ok {
cs = append(cs, v)
delete(v.Commands, arg[2])
log.Println(v.Name, "del command:", arg[2])
}
for i := 0; i < len(cs); i++ {
for _, v := range cs[i].Shadows {
cs = append(cs, v)
delete(v.Commands, arg[2])
log.Println(v.Name, "del command:", arg[2])
}
}
case "config":
if len(arg) != 3 {
panic(errors.New("参数错误"))
}
if v, ok := c.Shadows[arg[1]]; ok {
cs = append(cs, v)
delete(v.Configs, arg[2])
log.Println(v.Name, "del config:", arg[2])
}
for i := 0; i < len(cs); i++ {
for _, v := range cs[i].Shadows {
cs = append(cs, v)
delete(v.Configs, arg[2])
log.Println(v.Name, "del config:", arg[2])
}
}
case "cache":
if len(arg) != 3 {
panic(errors.New("参数错误"))
}
if v, ok := c.Shadows[arg[1]]; ok {
cs = append(cs, v)
delete(v.Caches, arg[2])
log.Println(v.Name, "del cache:", arg[2])
}
for i := 0; i < len(cs); i++ {
for _, v := range cs[i].Shadows {
cs = append(cs, v)
delete(v.Caches, arg[2])
log.Println(v.Name, "del cache:", arg[2])
}
}
}
}
// }}}
// }}}
var Index = &Context{Name: "ctx", Help: "根文",
Caches: map[string]*Cache{},
Configs: map[string]*Config{
"开场白": &Config{"开场白", "你好,上下文", "开场白", nil},
"结束语": &Config{"结束语", "再见,上下文", "结束语", nil},
},
Commands: map[string]*Command{},
}
func init() {
Index.Root = Index
}

115
src/context/ctx_test.go Normal file
View File

@ -0,0 +1,115 @@
package ctx
import (
"fmt"
"testing"
)
func TestCtx(t *testing.T) {
context := Context{Name: "root", Help: "默认",
Caches: map[string]*Cache{
"nclient": &Cache{"nclient", "10", "连接数量", func(c *Context) string {
return "10"
}},
},
Configs: map[string]*Config{
"limit": &Config{"limit", "10", "最大连接数", func(c *Context, arg string) {
}},
},
Commands: map[string]*Command{
"session": &Command{"session", "会话管理", func(c *Context, arg ...string) string {
return "ok"
}},
},
}
context.Index = map[string]*Context{"root": &context}
ctx := context.Index["root"]
ctx.Add("context", "hi", "hi", "nice")
if _, ok := context.Contexts["hi"]; !ok {
t.Fatal("root.ctxs add error")
}
if c, ok := context.Index["hi"]; ok {
ctx.Add("command", "hi", "session")
if _, ok := c.Commands["session"]; ok {
if c.Cmd("session") != "ok" {
t.Fatal("hi.cmds.session: run error")
}
} else {
t.Fatal("hi.cmds: add error")
}
ctx.Add("config", "hi", "limit")
ctx.Add("cache", "hi", "nclient")
} else {
t.Fatal("root.index add error")
}
return
if true {
ctx := context.Index["hi"]
if ctx.Cmd("session", "nice") == "ok" {
t.Log("hi.cmds.session: run")
} else {
t.Fatal("hi.cmds.session: run error")
}
t.Log()
ctx.Add("context", "he", "he", "nice")
for k, v := range ctx.Contexts {
t.Log("hi.ctxs", k, v.Name, v.Help)
}
if len(ctx.Contexts) != 1 {
t.Fatal("hi.ctxs: add error")
}
for k, v := range ctx.Index {
t.Log("hi.index:", k, v.Name, v.Help)
}
if len(ctx.Index) != 3 {
t.Fatal("hi.index: add error")
}
t.Log()
ctx.Add("command", "he", "session")
for k, v := range ctx.Contexts["he"].Commands {
t.Log("he.cmds:", k, v.Name, v.Help)
}
if len(ctx.Contexts["he"].Commands) != 1 {
t.Fatal("he.cmds: add error")
}
}
for k, v := range ctx.Index {
t.Log("root.index:", k, v.Name, v.Help)
}
if len(ctx.Index) != 3 {
t.Fatal("root.index add error")
}
t.Log()
for k, v := range ctx.Index {
t.Log(fmt.Sprintf("root.index.%s.cmds: %d", k, len(v.Commands)))
}
t.Log()
ctx.Del("command", "hi", "session")
for k, v := range ctx.Index {
t.Log(fmt.Sprintf("root.index.%s.cmds: %d", k, len(v.Commands)))
}
t.Log()
ctx.Del("context", "hi")
for k, v := range ctx.Contexts {
t.Log("root.ctxs:", k, v.Name, v.Help)
}
if len(ctx.Contexts) != 0 {
t.Fatal("root.ctxs: del error")
}
for k, v := range ctx.Index {
t.Log("root.index:", k, v.Name, v.Help)
}
if len(ctx.Index) != 1 {
t.Fatal("root.index del error")
}
}

266
src/context/ssh/ssh.go Normal file
View File

@ -0,0 +1,266 @@
package ssh // {{{
// }}}
import ( // {{{
"bufio"
"context"
"crypto/tls"
"fmt"
"io"
"log"
"strings"
)
// }}}
type SSH struct {
w io.WriteCloser
bio *bufio.Reader
meta map[string][]string
data []byte
head map[string][]string
body []string
len int
*ctx.Context
}
func (ssh *SSH) Scan() bool { // {{{
if ssh.meta != nil {
return false
}
meta := make(map[string][]string)
for {
l, e := ssh.bio.ReadString('\n')
ssh.Check(e)
log.Printf("%s >> %s", ssh.Name, l)
if len(l) == 1 {
break
}
ls := strings.SplitN(l, ":", 2)
ls[0] = strings.TrimSpace(ls[0])
ls[1] = strings.TrimSpace(ls[1])
if m, ok := meta[ls[0]]; ok {
meta[ls[0]] = append(m, ls[1])
} else {
meta[ls[0]] = []string{ls[1]}
}
}
ssh.meta = meta
return true
}
// }}}
func (ssh *SSH) Has(field string) bool { // {{{
_, ok := ssh.meta[field]
return ok
}
// }}}
func (ssh *SSH) Get(field string) string { // {{{
if m, ok := ssh.meta[field]; ok {
return m[0]
}
return ""
}
// }}}
func (ssh *SSH) Echo(name string, value interface{}) { // {{{
fmt.Fprintln(ssh.w, name+":", value)
log.Println(ssh.Name, "<<", name+":", value)
}
// }}}
func (ssh *SSH) Print(str string, arg ...interface{}) { // {{{
if ssh.body == nil {
ssh.body = make([]string, 0, 3)
}
s := fmt.Sprintf(str, arg...)
ssh.body = append(ssh.body, s)
ssh.len += len(s)
}
// }}}
func (ssh *SSH) End() { // {{{
ssh.Echo("len", ssh.len)
fmt.Fprintln(ssh.w)
log.Println(ssh.Name, "<<")
if ssh.len > 0 {
for i, v := range ssh.body {
n, e := fmt.Fprintf(ssh.w, v)
log.Println(ssh.Name, "<<", i, n, v)
ssh.Check(e)
}
}
// ssh.Check(ssh.w.Flush())
log.Println("\n")
ssh.meta = nil
ssh.body = nil
ssh.len = 0
}
// }}}
func (ssh *SSH) Begin() bool { // {{{
// ssh.Conf("log", ssh.Conf("log"))
for k, v := range ssh.Configs {
ssh.Conf(k, v.Value)
}
return true
}
// }}}
func (ssh *SSH) Start() bool { // {{{
ssh.Begin()
if ssh.Cap("status") == "start" {
return false
}
defer ssh.Cap("status", "stop")
if ssh.Conf("client") == "yes" {
conn, e := tls.Dial("tcp", ssh.Conf("address"), &tls.Config{InsecureSkipVerify: true})
ssh.Check(e)
ssh.w = conn
ssh.bio = bufio.NewReader(conn)
log.Println(ssh.Name, "->", conn.RemoteAddr(), "connect")
ssh.Cap("status", "start")
ssh.Echo("master", ssh.Conf("master"))
ssh.End()
ssh.Scan()
if ssh.Get("master") == "yes" {
ssh.Conf("master", "no")
} else {
ssh.Conf("master", "yes")
}
log.Println("fuck")
ssh.End()
if ssh.Conf("master") == "yes" {
} else {
for ssh.Scan() {
m := &ctx.Message{Meta: ssh.meta}
m.Context = ssh.Context
ssh.Root.Find([]string{"cli"}).Post(m)
ssh.End()
}
}
} else {
pair, e := tls.LoadX509KeyPair(ssh.Conf("cert"), ssh.Conf("key"))
ssh.Check(e)
ls, e := tls.Listen("tcp", ssh.Conf("address"), &tls.Config{Certificates: []tls.Certificate{pair}})
ssh.Check(e)
ssh.Cap("status", "start")
for {
conn, e := ls.Accept()
ssh.Check(e)
log.Println(ssh.Name, "<-", conn.RemoteAddr(), "connect")
go func() {
s := ssh.Context.Spawn(conn.RemoteAddr().String())
psh := s.Server.(*SSH)
psh.w = conn
psh.bio = bufio.NewReader(conn)
psh.Scan()
if psh.Get("master") == "yes" {
psh.Conf("master", "master", "no", "主控或被控")
} else {
psh.Conf("master", "master", "yes", "主控或被控")
}
psh.Echo("master", psh.Conf("master"))
psh.End()
psh.Scan()
if psh.Conf("master") == "yes" {
} else {
psh.meta = nil
for psh.Scan() {
m := &ctx.Message{Meta: psh.meta, Wait: make(chan bool)}
psh.Root.Find([]string{"cli"}).Post(m)
for _, v := range m.Meta["result"] {
psh.Echo("result", v)
}
psh.End()
}
}
}()
}
}
return true
}
// }}}
func (ssh *SSH) Fork(c *ctx.Context, key string) ctx.Server { // {{{
s := new(SSH)
s.Context = c
return s
}
// }}}
func (ssh *SSH) Spawn(c *ctx.Context, key string) ctx.Server { // {{{
s := new(SSH)
s.Context = c
return s
}
// }}}
var Index = &ctx.Context{Name: "ssh", Help: "运程连接",
Caches: map[string]*ctx.Cache{
"status": &ctx.Cache{"status", "stop", "服务器状态", nil},
},
Configs: map[string]*ctx.Config{
"master": &ctx.Config{"master", "yes", "主控或被控", nil},
"client": &ctx.Config{"client", "yes", "连接或监听", nil},
"address": &ctx.Config{"address", ":9090", "连接或监听的地址", nil},
"cert": &ctx.Config{"cert", "etc/cert.pem", "证书文件", nil},
"key": &ctx.Config{"key", "etc/key.pem", "私钥文件", nil},
},
Commands: map[string]*ctx.Command{
"remote": &ctx.Command{"remote", "远程命令", func(c *ctx.Context, msg *ctx.Message, arg ...string) string {
ssh := c.Server.(*SSH) // {{{
if c.Conf("master") == "yes" {
for _, v := range arg[1:] {
ssh.Echo("detail", v)
}
ssh.End()
}
ssh.Scan()
for _, v := range ssh.meta["result"] {
msg.Echo(v)
}
msg.Echo("\n")
return ""
// }}}
}},
},
}
func init() {
ssh := &SSH{}
ssh.Context = Index
ctx.Index.Register(Index, ssh)
}