From 672622b71fbcc79d70d46448d74ef0f0956ff88a Mon Sep 17 00:00:00 2001 From: shylinux Date: Tue, 25 Jun 2019 23:50:04 +0800 Subject: [PATCH] add meta.go --- src/contexts/ctx/meta.go | 1932 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 1932 insertions(+) create mode 100644 src/contexts/ctx/meta.go diff --git a/src/contexts/ctx/meta.go b/src/contexts/ctx/meta.go new file mode 100644 index 00000000..66353bf5 --- /dev/null +++ b/src/contexts/ctx/meta.go @@ -0,0 +1,1932 @@ +package ctx + +import ( + "fmt" + "log" + "math/rand" + "regexp" + "runtime" + "strconv" + "strings" + + "errors" + "io" + "sort" + "time" + "toolkit" +) + +type Cache struct { + Value string + Name string + Help string + Hand func(m *Message, x *Cache, arg ...string) string +} +type Config struct { + Value interface{} + Name string + Help string + Hand func(m *Message, x *Config, arg ...string) string +} +type Command struct { + Form map[string]int + Name string + Help interface{} + Auto func(m *Message, c *Context, key string, arg ...string) (ok bool) + Hand func(m *Message, c *Context, key string, arg ...string) (e error) +} +type Server interface { + Spawn(m *Message, c *Context, arg ...string) Server + Begin(m *Message, arg ...string) Server + Start(m *Message, arg ...string) bool + Close(m *Message, arg ...string) bool +} +type Context struct { + Name string + Help string + + Caches map[string]*Cache + Configs map[string]*Config + Commands map[string]*Command + + message *Message + requests []*Message + sessions []*Message + + contexts map[string]*Context + context *Context + root *Context + + exit chan bool + Server +} + +func (c *Context) Register(s *Context, x Server, args ...interface{}) { + force := false + if len(args) > 0 { + switch arg := args[0].(type) { + case bool: + force = arg + } + } + + if c.contexts == nil { + c.contexts = make(map[string]*Context) + } + if x, ok := c.contexts[s.Name]; ok && !force { + panic(errors.New(c.Name + "上下文中已存在模块:" + x.Name)) + } + + c.contexts[s.Name] = s + s.context = c + s.Server = x +} +func (c *Context) Spawn(m *Message, name string, help string) *Context { + s := &Context{Name: name, Help: help, root: c.root, context: c, message: m, + Caches: map[string]*Cache{}, + Configs: map[string]*Config{}, + Commands: map[string]*Command{}, + } + + if m.target = s; c.Server != nil { + c.Register(s, c.Server.Spawn(m, s, m.Meta["detail"]...)) + } else { + c.Register(s, nil) + } + return s +} +func (c *Context) Begin(m *Message, arg ...string) *Context { + if len(arg) > 0 { + m.Set("detail", arg) + } + + module := c.Name + if c.context != nil && c.context.Caches != nil && c.context.Caches["module"] != nil { + module = c.context.Caches["module"].Value + "." + c.Name + } + + c.Caches["module"] = &Cache{Name: "module", Value: module, Help: "模块域名"} + c.Caches["status"] = &Cache{Name: "status(begin/start/close)", Value: "begin", Help: "模块状态, begin: 初始完成, start: 正在运行, close: 运行结束"} + c.Caches["stream"] = &Cache{Name: "stream", Value: "", Help: "模块数据"} + + c.message = m + c.requests = append(c.requests, m) + m.source.sessions = append(m.source.sessions, m) + c.exit = make(chan bool, 3) + + /* + m.Log("begin", "%d context %v %v", m.Capi("ncontext", 1), m.Meta["detail"], m.Meta["option"]) + for k, x := range c.Configs { + if x.Hand != nil { + m.Log("begin", "%s config %v", k, m.Conf(k, x.Value)) + } + } + */ + + if c.Server != nil { + c.Server.Begin(m, m.Meta["detail"]...) + } + return c +} +func (c *Context) Start(m *Message, arg ...string) bool { + sync := false + if len(arg) > 0 && arg[0] == "sync" { + sync, arg = true, arg[1:] + } + if len(arg) > 0 { + m.Set("detail", arg) + } + + c.requests = append(c.requests, m) + m.source.sessions = append(m.source.sessions, m) + + if m.Hand = true; m.Cap("status") == "start" { + return true + } + + m.GoFunc(m, func(m *Message) { + m.Log(m.Cap("status", "start"), "%d server %v %v", m.Capi("nserver", 1), m.Meta["detail"], m.Meta["option"]) + + c.message = m + if c.exit <- false; c.Server == nil || c.Server.Start(m, m.Meta["detail"]...) { + c.Close(m, m.Meta["detail"]...) + c.exit <- true + } + }, func(m *Message) { + c.Close(m, m.Meta["detail"]...) + c.exit <- true + }) + + if sync { + for !<-c.exit { + } + return true + } + return <-c.exit +} +func (c *Context) Close(m *Message, arg ...string) bool { + if len(c.requests) == 0 { + return true + } + + if m.target == c { + for i := len(c.requests) - 1; i >= 0; i-- { + if msg := c.requests[i]; msg.code == m.code { + if c.Server == nil || c.Server.Close(m, arg...) { + m.Log("close", "request %d/%d", i, len(c.requests)-1) + msg.Free() + for j := i; j < len(c.requests)-1; j++ { + c.requests[j] = c.requests[j+1] + } + c.requests = c.requests[:len(c.requests)-1] + } + } + } + } + + if len(c.requests) > 0 { + return false + } + + if m.Cap("status") == "start" { + m.Log(m.Cap("status", "close"), "%d server %v", m.root.Capi("nserver", -1), arg) + for _, msg := range c.sessions { + if msg.Cap("status") != "close" { + msg.target.Close(msg, arg...) + } + } + } + + if c.context != nil { + m.Log("close", "%d context %v", m.root.Capi("ncontext", -1), arg) + delete(c.context.contexts, c.Name) + c.exit <- true + } + return true +} + +func (c *Context) Context() *Context { + return c.context +} +func (c *Context) Message() *Message { + return c.message +} +func (c *Context) Has(key ...string) bool { + switch len(key) { + case 2: + if _, ok := c.Commands[key[0]]; ok && key[1] == "command" { + return true + } + if _, ok := c.Configs[key[0]]; ok && key[1] == "config" { + return true + } + if _, ok := c.Caches[key[0]]; ok && key[1] == "cache" { + return true + } + case 1: + if _, ok := c.Commands[key[0]]; ok { + return true + } + if _, ok := c.Configs[key[0]]; ok { + return true + } + if _, ok := c.Caches[key[0]]; ok { + return true + } + } + return false +} +func (c *Context) Sub(key string) *Context { + return c.contexts[key] +} +func (c *Context) Travel(m *Message, hand func(m *Message, n int) (stop bool)) *Context { + if c == nil { + return nil + } + target := m.target + + cs := []*Context{c} + for i := 0; i < len(cs); i++ { + if m.target = cs[i]; hand(m, i) { + return cs[i] + } + + keys := []string{} + for k, _ := range cs[i].contexts { + keys = append(keys, k) + } + sort.Strings(keys) + for _, k := range keys { + cs = append(cs, cs[i].contexts[k]) + } + } + + m.target = target + return target +} +func (c *Context) BackTrace(m *Message, hand func(m *Message) (stop bool)) *Context { + target := m.target + + for s := m.target; s != nil; s = s.context { + if m.target = s; hand(m) { + return s + } + } + + m.target = target + return target +} + +func (c *Context) Plugin(args []string) string { + m := &Message{code: 0, time: time.Now(), source: c, target: c, Meta: map[string][]string{}} + if len(args) == 0 { + m.Echo("%s: %s\n", c.Name, c.Help) + for k, v := range c.Commands { + m.Echo("%s: %s %v\n", k, v.Name, v.Help) + } + } else if cs, ok := c.Commands[args[0]]; ok { + h := cs.Hand + if e := h(m, c, args[0], args[1:]...); e != nil { + m.Echo("error: ").Echo("%v\n", e) + } + } else { + m.Echo("error: ").Echo("not found: %v\n", args[0]) + } + return strings.Join(m.Meta["result"], "") +} + +type DEBUG interface { + Wait(*Message, ...interface{}) interface{} + Goon(interface{}, ...interface{}) +} +type LOGGER interface { + Log(*Message, string, string, ...interface{}) +} +type Message struct { + time time.Time + code int + + source *Context + target *Context + + Meta map[string][]string + Data map[string]interface{} + + callback func(msg *Message) (sub *Message) + freedoms []func(msg *Message) (done bool) + Sessions map[string]*Message + + messages []*Message + message *Message + root *Message + + Remote chan bool + Hand bool +} + +func (m *Message) Spawn(arg ...interface{}) *Message { + temp := false + c := m.target + if len(arg) > 0 { + switch v := arg[0].(type) { + case *Context: + c = v + case *Message: + c = v.target + case string: + temp = kit.Right(v) + } + } + + msg := &Message{ + time: time.Now(), + code: m.Capi("nmessage", 1), + source: m.target, + target: c, + message: m, + root: m.root, + } + + if temp { + return msg + } + + m.messages = append(m.messages, msg) + return msg +} +func (m *Message) Time(arg ...interface{}) string { + t := m.time + + if len(arg) > 0 { + if d, e := time.ParseDuration(arg[0].(string)); e == nil { + arg = arg[1:] + t.Add(d) + } + } + + str := m.Conf("time_format") + if len(arg) > 1 { + str = fmt.Sprintf(arg[0].(string), arg[1:]...) + } else if len(arg) > 0 { + str = fmt.Sprintf("%v", arg[0]) + } + if str == "stamp" { + return kit.Format(t.Unix()) + } + return t.Format(str) +} +func (m *Message) Code() int { + return m.code +} +func (m *Message) Source() *Context { + return m.source +} +func (m *Message) Target() *Context { + return m.target +} +func (m *Message) Message() *Message { + return m.message +} +func (m *Message) Format(arg ...interface{}) string { + if len(arg) == 0 { + arg = append(arg, "time", "ship") + } + + meta := []string{} + for _, v := range arg { + switch kit.Format(v) { + case "summary": + msg := arg[1].(*Message) + ms := make([]*Message, 0, 1024) + ms = append(ms, msg.message, msg) + + for i := 0; i < len(ms); i++ { + msg := ms[i] + if m.Add("append", "index", i); msg == nil { + m.Add("append", "message", "") + m.Add("append", "time", "") + m.Add("append", "code", "") + m.Add("append", "source", "") + m.Add("append", "target", "") + m.Add("append", "details", "") + m.Add("append", "options", "") + continue + } + + if msg.message != nil { + m.Add("append", "message", msg.message.code) + } else { + m.Add("append", "message", "") + } + m.Add("append", "time", msg.time.Format("15:04:05")) + m.Add("append", "code", msg.code) + m.Add("append", "source", msg.source.Name) + m.Add("append", "target", msg.target.Name) + m.Add("append", "details", fmt.Sprintf("%v", msg.Meta["detail"])) + m.Add("append", "options", fmt.Sprintf("%v", msg.Meta["option"])) + + if i == 0 { + continue + } + + if len(ms) < 30 && len(arg) > 2 && arg[2] == "deep" { + ms = append(ms, ms[i].messages...) + } + } + m.Table() + case "time": + meta = append(meta, m.Time()) + case "code": + meta = append(meta, kit.Format(m.code)) + case "ship": + meta = append(meta, fmt.Sprintf("%s:%d(%s->%s)", m.Option("routine"), m.code, m.source.Name, m.target.Name)) + case "source": + target := m.target + m.target = m.source + meta = append(meta, m.Cap("module")) + m.target = target + case "target": + meta = append(meta, m.Cap("module")) + + case "detail": + meta = append(meta, fmt.Sprintf("%v", m.Meta["detail"])) + case "option": + meta = append(meta, fmt.Sprintf("%v", m.Meta["option"])) + case "append": + meta = append(meta, fmt.Sprintf("%v", m.Meta["append"])) + case "result": + meta = append(meta, fmt.Sprintf("%v", m.Meta["result"])) + + case "full": + case "chain": + ms := []*Message{} + if v == "full" { + ms = append(ms, m) + } else { + for msg := m; msg != nil; msg = msg.message { + ms = append(ms, msg) + } + } + + meta = append(meta, "\n") + for i := len(ms) - 1; i >= 0; i-- { + msg := ms[i] + + meta = append(meta, fmt.Sprintf("%s\n", msg.Format("time", "ship"))) + if len(msg.Meta["detail"]) > 0 { + meta = append(meta, fmt.Sprintf(" detail: %d %v\n", len(msg.Meta["detail"]), msg.Meta["detail"])) + } + if len(msg.Meta["option"]) > 0 { + meta = append(meta, fmt.Sprintf(" option: %d %v\n", len(msg.Meta["option"]), msg.Meta["option"])) + for _, k := range msg.Meta["option"] { + if v, ok := msg.Data[k]; ok { + meta = append(meta, fmt.Sprintf(" %s: %v\n", k, kit.Format(v))) + } else if v, ok := msg.Meta[k]; ok { + meta = append(meta, fmt.Sprintf(" %s: %d %v\n", k, len(v), v)) + } + } + } + if len(msg.Meta["append"]) > 0 { + meta = append(meta, fmt.Sprintf(" append: %d %v\n", len(msg.Meta["append"]), msg.Meta["append"])) + for _, k := range msg.Meta["append"] { + if v, ok := msg.Data[k]; ok { + meta = append(meta, fmt.Sprintf(" %s: %v\n", k, kit.Format(v))) + } else if v, ok := msg.Meta[k]; ok { + meta = append(meta, fmt.Sprintf(" %s: %d %v\n", k, len(v), v)) + } + } + } + if len(msg.Meta["result"]) > 0 { + meta = append(meta, fmt.Sprintf(" result: %d %v\n", len(msg.Meta["result"]), msg.Meta["result"])) + } + } + case "stack": + pc := make([]uintptr, 100) + pc = pc[:runtime.Callers(6, pc)] + frames := runtime.CallersFrames(pc) + + for { + frame, more := frames.Next() + file := strings.Split(frame.File, "/") + name := strings.Split(frame.Function, "/") + meta = append(meta, fmt.Sprintf("\n%s:%d\t%s", file[len(file)-1], frame.Line, name[len(name)-1])) + if !more { + break + } + } + + default: + meta = append(meta, kit.FileName(kit.Format(v), "time")) + } + } + return strings.Join(meta, " ") +} +func (m *Message) Tree(code int) *Message { + ms := []*Message{m} + for i := 0; i < len(ms); i++ { + if ms[i].Code() == code { + return ms[i] + } + ms = append(ms, ms[i].messages...) + } + return nil +} + +func (m *Message) Add(meta string, key string, value ...interface{}) *Message { + if m.Meta == nil { + m.Meta = make(map[string][]string) + } + if _, ok := m.Meta[meta]; !ok { + m.Meta[meta] = make([]string, 0, 3) + } + + switch meta { + case "detail", "result": + m.Meta[meta] = append(m.Meta[meta], key) + m.Meta[meta] = append(m.Meta[meta], kit.Trans(value...)...) + + case "option", "append": + if _, ok := m.Meta[key]; !ok { + m.Meta[key] = make([]string, 0, 3) + } + m.Meta[key] = append(m.Meta[key], kit.Trans(value...)...) + + for _, v := range m.Meta[meta] { + if v == key { + return m + } + } + m.Meta[meta] = append(m.Meta[meta], key) + + default: + m.Log("error", "add meta error %s %s %v", meta, key, value) + } + + return m +} +func (m *Message) Set(meta string, arg ...interface{}) *Message { + switch meta { + case "detail", "result": + if m != nil && m.Meta != nil { + delete(m.Meta, meta) + } + case "option", "append": + if len(arg) > 0 { + delete(m.Meta, kit.Format(arg[0])) + } else { + for _, k := range m.Meta[meta] { + delete(m.Data, k) + delete(m.Meta, k) + } + delete(m.Meta, meta) + } + default: + m.Log("error", "set meta error %s %s %v", meta, arg) + } + + if args := kit.Trans(arg...); len(args) > 0 { + m.Add(meta, args[0], args[1:]) + } + return m +} +func (m *Message) Put(meta string, key string, value interface{}) *Message { + switch meta { + case "option", "append": + if m.Set(meta, key); m.Data == nil { + m.Data = make(map[string]interface{}) + } + m.Data[key] = value + + default: + m.Log("error", "put data error %s %s %v", meta, key, value) + } + return m +} +func (m *Message) Get(key string, arg ...interface{}) string { + if meta, ok := m.Meta[key]; ok && len(meta) > 0 { + index := 0 + if len(arg) > 0 { + index = kit.Int(arg[0]) + } + + index = (index+2)%(len(meta)+2) - 2 + if index >= 0 && index < len(meta) { + return meta[index] + } + } + return "" +} +func (m *Message) Has(key ...string) bool { + switch len(key) { + case 1: + if _, ok := m.Data[key[0]]; ok { + return true + } + if _, ok := m.Meta[key[0]]; ok { + return true + } + } + return false +} +func (m *Message) CopyTo(msg *Message, arg ...string) *Message { + msg.Copy(m, "append").Copy(m, "result") + return m +} +func (m *Message) Copy(msg *Message, arg ...string) *Message { + if msg == nil || m == msg { + return m + } + + for i := 0; i < len(arg); i++ { + meta := arg[i] + + switch meta { + case "target": + m.target = msg.target + case "callback": + m.callback = msg.callback + case "detail", "result": + if len(msg.Meta[meta]) > 0 { + m.Add(meta, msg.Meta[meta][0], msg.Meta[meta][1:]) + } + case "option", "append": + if msg.Meta == nil { + msg.Meta = map[string][]string{} + } + if msg.Meta[meta] == nil { + break + } + if i == len(arg)-1 { + arg = append(arg, msg.Meta[meta]...) + } + + for i++; i < len(arg); i++ { + if v, ok := msg.Data[arg[i]]; ok { + m.Put(meta, arg[i], v) + } else if v, ok := msg.Meta[arg[i]]; ok { + m.Set(meta, arg[i], v) // TODO fuck Add + } + } + default: + if msg.Hand { + meta = "append" + } else { + meta = "option" + } + + if v, ok := msg.Data[arg[i]]; ok { + m.Put(meta, arg[i], v) + } + if v, ok := msg.Meta[arg[i]]; ok { + m.Add(meta, arg[i], v) + } + } + } + + return m +} +func (m *Message) CopyFuck(msg *Message, arg ...string) *Message { + if m == msg { + return m + } + + for i := 0; i < len(arg); i++ { + meta := arg[i] + + switch meta { + case "target": + m.target = msg.target + case "callback": + m.callback = msg.callback + case "detail", "result": + if len(msg.Meta[meta]) > 0 { + m.Add(meta, msg.Meta[meta][0], msg.Meta[meta][1:]) + } + case "option", "append": + if msg.Meta == nil { + msg.Meta = map[string][]string{} + } + if msg.Meta[meta] == nil { + break + } + if i == len(arg)-1 { + arg = append(arg, msg.Meta[meta]...) + } + + for i++; i < len(arg); i++ { + if v, ok := msg.Data[arg[i]]; ok { + m.Put(meta, arg[i], v) + } else if v, ok := msg.Meta[arg[i]]; ok { + m.Add(meta, arg[i], v) // TODO fuck Add + } + } + default: + if msg.Hand { + meta = "append" + } else { + meta = "option" + } + + if v, ok := msg.Data[arg[i]]; ok { + m.Put(meta, arg[i], v) + } + if v, ok := msg.Meta[arg[i]]; ok { + m.Add(meta, arg[i], v) + } + } + } + + return m +} +func (m *Message) Echo(str string, arg ...interface{}) *Message { + if len(arg) > 0 { + return m.Add("result", fmt.Sprintf(str, arg...)) + } + return m.Add("result", str) +} +func (m *Message) Auto(arg ...string) *Message { + for i := 0; i < len(arg); i += 3 { + m.Add("append", "value", arg[i]) + m.Add("append", "name", arg[i+1]) + m.Add("append", "help", arg[i+2]) + } + return m +} + +func (m *Message) Insert(meta string, index int, arg ...interface{}) string { + if m.Meta == nil { + m.Meta = make(map[string][]string) + } + m.Meta[meta] = kit.Array(m.Meta[meta], index, arg) + + if -1 < index && index < len(m.Meta[meta]) { + return m.Meta[meta][index] + } + return "" +} +func (m *Message) Detail(arg ...interface{}) string { + noset, index := true, 0 + if len(arg) > 0 { + switch v := arg[0].(type) { + case int: + noset, index, arg = false, v, arg[1:] + } + } + if noset && len(arg) > 0 { + index = -2 + } + + return m.Insert("detail", index, arg...) +} +func (m *Message) Detaili(arg ...interface{}) int { + return kit.Int(m.Detail(arg...)) +} +func (m *Message) Details(arg ...interface{}) bool { + return kit.Right(m.Detail(arg...)) +} +func (m *Message) Result(arg ...interface{}) string { + noset, index := true, 0 + if len(arg) > 0 { + switch v := arg[0].(type) { + case int: + noset, index, arg = false, v, arg[1:] + } + } + if noset && len(arg) > 0 { + index = -2 + } + + return m.Insert("result", index, arg...) +} +func (m *Message) Resulti(arg ...interface{}) int { + return kit.Int(m.Result(arg...)) +} +func (m *Message) Results(arg ...interface{}) bool { + return kit.Right(m.Result(arg...)) +} +func (m *Message) Option(key string, arg ...interface{}) string { + if len(arg) > 0 { + m.Insert(key, 0, arg...) + if _, ok := m.Meta[key]; ok { + m.Add("option", key) + } + } + + for msg := m; msg != nil; msg = msg.message { + if !msg.Has(key) { + continue + } + for _, k := range msg.Meta["option"] { + if k == key { + return msg.Get(key) + } + } + } + return "" +} +func (m *Message) Optioni(key string, arg ...interface{}) int { + return kit.Int(m.Option(key, arg...)) + +} +func (m *Message) Options(key string, arg ...interface{}) bool { + return kit.Right(m.Option(key, arg...)) +} +func (m *Message) Optionv(key string, arg ...interface{}) interface{} { + if len(arg) > 0 { + switch arg[0].(type) { + case nil: + // case []string: + // m.Option(key, v...) + // case string: + // m.Option(key, v) + default: + m.Put("option", key, arg[0]) + } + } + + for msg := m; msg != nil; msg = msg.message { + if msg.Meta == nil || !msg.Has(key) { + continue + } + for _, k := range msg.Meta["option"] { + if k == key { + if v, ok := msg.Data[key]; ok { + return v + } + return msg.Meta[key] + } + } + } + return nil +} +func (m *Message) Optionx(key string, arg ...string) interface{} { + value := m.Conf(key) + if value == "" { + value = m.Option(key) + } + + if len(arg) > 0 { + value = fmt.Sprintf(arg[0], value) + } + return value +} +func (m *Message) Magic(begin string, chain interface{}, args ...interface{}) interface{} { + auth := []string{"bench", "session", "user", "role", "componet", "command"} + key := []string{"bench", "sessid", "username", "role", "componet", "command"} + aaa := m.Sess("aaa", false) + for i, v := range auth { + if v == begin { + h := m.Option(key[i]) + if v == "user" { + h, _ = kit.Hash("username", m.Option("username")) + } + + data := aaa.Confv("auth", []string{h, "data"}) + + if kit.Format(chain) == "" { + return data + } + + if len(args) > 0 { + value := kit.Chain(data, chain, args[0]) + aaa.Conf("auth", []string{m.Option(key[i]), "data"}, value) + return value + } + + value := kit.Chain(data, chain) + if value != nil { + return value + } + + if i < len(auth)-1 { + begin = auth[i+1] + } + } + } + return nil +} +func (m *Message) Current(text string) string { + cs := []string{} + if pod := kit.Format(m.Magic("session", "current.pod")); pod != "" { + cs = append(cs, "context", "ssh", "remote", "'"+pod+"'") + } + if ctx := kit.Format(m.Magic("session", "current.ctx")); ctx != "" { + cs = append(cs, "context", ctx) + } + if cmd := kit.Format(m.Magic("session", "current.cmd")); cmd != "" { + cs = append(cs, cmd) + } + m.Log("info", "%s %s current %v", m.Option("username"), m.Option("sessid"), cs) + cs = append(cs, text) + return strings.Join(cs, " ") +} +func (m *Message) Append(key string, arg ...interface{}) string { + if len(arg) > 0 { + m.Insert(key, 0, arg...) + if _, ok := m.Meta[key]; ok { + m.Add("append", key) + } + } + + ms := []*Message{m} + for i := 0; i < len(ms); i++ { + ms = append(ms, ms[i].messages...) + if !ms[i].Has(key) { + continue + } + for _, k := range ms[i].Meta["append"] { + if k == key { + return ms[i].Get(key) + } + } + } + return "" +} +func (m *Message) Appendi(key string, arg ...interface{}) int64 { + i, _ := strconv.ParseInt(m.Append(key, arg...), 10, 64) + return i +} +func (m *Message) Appends(key string, arg ...interface{}) bool { + return kit.Right(m.Append(key, arg...)) +} +func (m *Message) Appendv(key string, arg ...interface{}) interface{} { + if len(arg) > 0 { + m.Put("append", key, arg[0]) + } + + ms := []*Message{m} + for i := 0; i < len(ms); i++ { + ms = append(ms, ms[i].messages...) + if !ms[i].Has(key) { + continue + } + for _, k := range ms[i].Meta["append"] { + if k == key { + if v, ok := ms[i].Data[key]; ok { + return v + } + return ms[i].Meta[key] + } + } + } + return nil +} +func (m *Message) Table(cbs ...interface{}) *Message { + if len(m.Meta["append"]) == 0 { + return m + } + + // 遍历函数 + if len(cbs) > 0 { + switch cb := cbs[0].(type) { + case func(map[string]string) bool: + nrow := len(m.Meta[m.Meta["append"][0]]) + line := map[string]string{} + for i := 0; i < nrow; i++ { + for _, k := range m.Meta["append"] { + line[k] = m.Meta[k][i] + } + if !cb(line) { + break + } + } + return m + case func(map[string]string): + nrow := len(m.Meta[m.Meta["append"][0]]) + for i := 0; i < nrow; i++ { + line := map[string]string{} + for _, k := range m.Meta["append"] { + line[k] = m.Meta[k][i] + } + cb(line) + } + return m + case func(int, map[string]string): + nrow := len(m.Meta[m.Meta["append"][0]]) + for i := 0; i < nrow; i++ { + line := map[string]string{} + for _, k := range m.Meta["append"] { + line[k] = m.Meta[k][i] + } + cb(i, line) + } + return m + } + } + + //计算列宽 + space := m.Confx("table_space") + depth, width := 0, map[string]int{} + for _, k := range m.Meta["append"] { + if len(m.Meta[k]) > depth { + depth = len(m.Meta[k]) + } + width[k] = kit.Width(k, len(space)) + for _, v := range m.Meta[k] { + if kit.Width(v, len(space)) > width[k] { + width[k] = kit.Width(v, len(space)) + } + } + } + + // 回调函数 + var cb func(maps map[string]string, list []string, line int) (goon bool) + if len(cbs) > 0 { + cb = cbs[0].(func(maps map[string]string, list []string, line int) (goon bool)) + } else { + row := m.Confx("table_row_sep") + col := m.Confx("table_col_sep") + compact := kit.Right(m.Confx("table_compact")) + cb = func(maps map[string]string, lists []string, line int) bool { + for i, v := range lists { + if k := m.Meta["append"][i]; compact { + v = maps[k] + } + + if m.Echo(v); i < len(lists)-1 { + m.Echo(col) + } + } + m.Echo(row) + return true + } + } + + // 输出表头 + row := map[string]string{} + wor := []string{} + for _, k := range m.Meta["append"] { + row[k], wor = k, append(wor, k+strings.Repeat(space, width[k]-kit.Width(k, len(space)))) + } + if !cb(row, wor, -1) { + return m + } + + // 输出数据 + for i := 0; i < depth; i++ { + row := map[string]string{} + wor := []string{} + for _, k := range m.Meta["append"] { + data := "" + if i < len(m.Meta[k]) { + data = m.Meta[k][i] + } + + row[k], wor = data, append(wor, data+strings.Repeat(space, width[k]-kit.Width(data, len(space)))) + } + if !cb(row, wor, i) { + break + } + } + + return m +} +func (m *Message) Sort(key string, arg ...string) *Message { + cmp := "str" + if len(arg) > 0 { + cmp = arg[0] + } + + number := map[int]int{} + table := []map[string]string{} + m.Table(func(line map[string]string, lists []string, index int) bool { + if index != -1 { + table = append(table, line) + switch cmp { + case "int": + number[index] = kit.Int(line[key]) + case "int_r": + number[index] = -kit.Int(line[key]) + case "time": + number[index] = kit.Time(line[key]) + case "time_r": + number[index] = -kit.Time(line[key]) + } + } + return true + }) + + for i := 0; i < len(table)-1; i++ { + for j := i + 1; j < len(table); j++ { + result := false + switch cmp { + case "str": + if table[i][key] > table[j][key] { + result = true + } + case "str_r": + if table[i][key] < table[j][key] { + result = true + } + default: + if number[i] > number[j] { + result = true + } + } + + if result { + table[i], table[j] = table[j], table[i] + number[i], number[j] = number[j], number[i] + } + } + } + + for _, k := range m.Meta["append"] { + delete(m.Meta, k) + } + + for _, v := range table { + for _, k := range m.Meta["append"] { + m.Add("append", k, v[k]) + } + } + return m +} +func (m *Message) Parse(arg interface{}) string { + switch str := arg.(type) { + case string: + if len(str) > 1 && str[0] == '$' { + return m.Cap(str[1:]) + } + if len(str) > 1 && str[0] == '@' { + if v := m.Option(str[1:]); v != "" { + return v + } + if v := kit.Format(m.Magic("bench", str[1:])); v != "" { + return v + } + v := m.Conf(str[1:]) + return v + } + return str + } + return "" +} +func (m *Message) ToHTML(style string) string { + cmd := strings.Join(m.Meta["detail"], " ") + result := []string{} + if len(m.Meta["append"]) > 0 { + result = append(result, fmt.Sprintf("", style)) + result = append(result, "") + m.Table(func(maps map[string]string, list []string, line int) bool { + if line == -1 { + result = append(result, "") + for _, v := range list { + result = append(result, "") + } + result = append(result, "") + return true + } + result = append(result, "") + for _, v := range list { + result = append(result, "") + } + result = append(result, "") + return true + }) + result = append(result, "
", cmd, "
", v, "
", v, "
") + } else { + result = append(result, "
")
+		result = append(result, fmt.Sprintf("%s", m.Find("shy", false).Conf("prompt")), cmd, "\n")
+		result = append(result, m.Meta["result"]...)
+		result = append(result, "
") + } + return strings.Join(result, "") +} + +func (m *Message) Gdb(arg ...interface{}) interface{} { + if g := m.Sess("gdb", false); g != nil { + if gdb, ok := g.target.Server.(DEBUG); ok { + return gdb.Wait(m, arg...) + } + } + return nil +} +func (m *Message) Log(action string, str string, arg ...interface{}) *Message { + if m.Options("log.disable") { + return m + } + + if l := m.Sess("log", false); l != nil { + if log, ok := l.target.Server.(LOGGER); ok { + if action == "error" { + log.Log(m, "error", "chain: %s", m.Format("chain")) + } + log.Log(m, action, str, arg...) + if action == "error" { + log.Log(m, "error", "stack: %s", m.Format("stack")) + } + return m + } + } else { + log.Printf(str, arg...) + } + + if action == "error" { + kit.Log("error", fmt.Sprintf("chain: %s", m.Format("chain"))) + kit.Log("error", fmt.Sprintf("%s %s %s", m.Format(), action, fmt.Sprintf(str, arg...))) + kit.Log("error", fmt.Sprintf("stack: %s", m.Format("stack"))) + } + + return m +} +func (m *Message) Show(args ...interface{}) *Message { + if m.Option("cli.modal") == "action" { + fmt.Printf(kit.Format(args...)) + } else if kit.STDIO != nil { + kit.STDIO.Show(args...) + } + return m +} +func (m *Message) Assert(e interface{}, msg ...string) bool { + switch v := e.(type) { + case nil: + return true + case *Message: + if v.Result(0) != "error: " { + return true + } + e = v.Result(1) + e = errors.New(v.Result(1)) + default: + if kit.Right(v) { + return true + } + } + + switch e.(type) { + case error: + default: + e = errors.New(kit.Format(msg)) + } + + m.Log("error", "%v", e) + panic(e) +} +func (m *Message) TryCatch(msg *Message, safe bool, hand ...func(msg *Message)) *Message { + defer func() { + switch e := recover(); e { + case io.EOF: + case nil: + default: + m.Log("bench", "chain: %s", msg.Format("chain")) + m.Log("bench", "catch: %s", e) + m.Log("bench", "stack: %s", msg.Format("stack")) + + if m.Log("error", "catch: %s", e); len(hand) > 1 { + m.TryCatch(msg, safe, hand[1:]...) + } else if !safe { + msg.Assert(e) + } + } + }() + + if len(hand) > 0 { + hand[0](msg) + } + return m +} +func (m *Message) GoFunc(msg *Message, hand ...func(msg *Message)) *Message { + go func() { + msg.Option("routine", m.Capi("ngo", 1)) + // msg.Log("info", "%v safe go begin", ngo) + // kit.Log("error", "%s ngo %s start", msg.Format(), ngo) + m.TryCatch(msg, true, hand...) + // kit.Log("error", "%s ngo %s end", msg.Format(), ngo) + // msg.Log("info", "%v safe go end", ngo) + }() + return m +} +func (m *Message) GoLoop(msg *Message, hand ...func(msg *Message)) *Message { + m.GoFunc(msg, func(msg *Message) { + for { + hand[0](msg) + } + }) + return m +} +func (m *Message) Start(name string, help string, arg ...string) bool { + return m.Set("detail", arg).target.Spawn(m, name, help).Begin(m).Start(m) +} +func (m *Message) Close(arg ...string) bool { + return m.Target().Close(m, arg...) +} +func (m *Message) Wait() bool { + if m.target.exit != nil { + return <-m.target.exit + } + return true +} + +func (m *Message) Find(name string, root ...bool) *Message { + if name == "" { + return m.Spawn() + } + target := m.target.root + if len(root) > 0 && !root[0] { + target = m.target + } + + cs := target.contexts + for _, v := range strings.Split(name, ".") { + if x, ok := cs[v]; ok { + target, cs = x, x.contexts + } else if target.Name == v { + continue + } else { + m.Log("error", "context not find %s", name) + return nil + } + } + + if len(root) > 1 && root[1] { + m.target = target + return m + } + + return m.Spawn(target) +} +func (m *Message) Search(key string, root ...bool) []*Message { + reg, e := regexp.Compile(key) + m.Assert(e) + + target := m.target + if target == nil { + return []*Message{nil} + } + if len(root) > 0 && root[0] { + target = m.target.root + } + + cs := make([]*Context, 0, 3) + target.Travel(m, func(m *Message, i int) bool { + if reg.MatchString(m.target.Name) || reg.FindString(m.target.Help) != "" { + m.Log("search", "%d %s match [%s]", len(cs), m.target.Name, key) + cs = append(cs, m.target) + } + return false + }) + + ms := make([]*Message, len(cs)) + for i := 0; i < len(cs); i++ { + ms[i] = m.Spawn(cs[i]) + } + if len(ms) == 0 { + ms = append(ms, nil) + } + + return ms +} +func (m *Message) Sess(key string, arg ...interface{}) *Message { + if key == "" { + return m.Spawn() + } + + spawn := true + if len(arg) > 0 { + switch v := arg[0].(type) { + case bool: + spawn, arg = v, arg[1:] + } + } + + if len(arg) > 0 { + if m.Sessions == nil { + m.Sessions = make(map[string]*Message) + } + + switch value := arg[0].(type) { + case *Message: + m.Sessions[key] = value + return m.Sessions[key] + case *Context: + m.Sessions[key] = m.Spawn(value) + return m.Sessions[key] + case string: + root := len(arg) < 3 || kit.Right(arg[2]) + + method := "find" + if len(arg) > 1 { + method = kit.Format(arg[1]) + } + + switch method { + case "find": + m.Sessions[key] = m.Find(value, root) + case "search": + m.Sessions[key] = m.Search(value, root)[0] + } + return m.Sessions[key] + case nil: + delete(m.Sessions, key) + return nil + } + } + + for msg := m; msg != nil; msg = msg.message { + if x, ok := msg.Sessions[key]; ok { + if spawn { + x = m.Spawn(x.target) + x.callback = func(sub *Message) *Message { return sub } + } + return x + } + } + + return nil +} +func (m *Message) Match(key string, spawn bool, hand func(m *Message, s *Context, c *Context, key string) bool) *Message { + if m == nil { + return m + } + + context := []*Context{m.target} + for _, v := range []string{"aaa", "ssh", "cli", "nfs"} { + if msg := m.Sess(v, false); msg != nil && msg.target != nil { + context = append(context, msg.target) + } + } + // if m.target.root != nil && m.target.root.Configs != nil && m.target.root.Configs["search"] != nil && m.target.root.Configs["search"].Value != nil { + // target := m.target + // for _, v := range kit.Trans(kit.Chain(m.target.root.Configs["search"].Value, "context")) { + // if t := m.Find(v, true, true); t != nil { + // kit.Log("error", "%v", t) + // // // context = append(context, t.target) + // } + // } + // m.target = target + // } + + context = append(context, m.source) + + for _, s := range context { + for c := s; c != nil; c = c.context { + if hand(m, s, c, key) { + return m + } + } + } + return m +} +func (m *Message) Call(cb func(msg *Message) (sub *Message), arg ...interface{}) *Message { + if m == nil { + return m + } + if m.callback = cb; len(arg) > 0 || len(m.Meta["detail"]) > 0 { + m.Log("call", m.Format("detail", "option")) + m.Cmd(arg...) + } + return m +} +func (m *Message) Back(ms ...*Message) *Message { + if m.callback == nil { + return m + } + + if len(ms) == 0 { + ms = append(ms, m.Spawn(m.source).Copy(m, "append").Copy(m, "result")) + } + + ns := []*Message{} + + for _, msg := range ms { + if msg.Hand { + m.Log("back", msg.Format("ship", "result", "append")) + } else { + m.Log("back", msg.Format("ship", "detail", "option")) + } + + if sub := m.callback(msg); sub != nil && m.message != nil && m.message != m { + ns = append(ns, sub) + } + } + + if len(ns) > 0 { + m.message.Back(ns...) + } + return m +} +func (m *Message) Backs(msg *Message) *Message { + m.Back(msg) + return msg +} +func (m *Message) CallBack(sync bool, cb func(msg *Message) (sub *Message), arg ...interface{}) *Message { + if !sync { + return m.Call(cb, arg...) + } + + wait := make(chan *Message, 10) + // m.GoFunc(m, func(m *Message) { + m.Call(func(sub *Message) *Message { + msg := cb(sub) + m.Log("sync", m.Format("done", "result", "append")) + wait <- m + return msg + }, arg...) + // }) + + m.Log("sync", m.Format("wait", "result", "append")) + select { + case <-time.After(kit.Duration(m.Conf("call_timeout"))): + m.Log("sync", m.Format("timeout", "result", "append")) + case <-wait: + } + return m +} +func (m *Message) Free(cbs ...func(msg *Message) (done bool)) *Message { + if len(cbs) == 0 { + for i := len(m.freedoms) - 1; i >= 0; i-- { + m.Log("free", "%d/%d", i, len(m.freedoms)-1) + if !m.freedoms[i](m) { + break + } + m.freedoms = m.freedoms[:i] + } + return m + } + + m.freedoms = append(m.freedoms, cbs...) + return m +} + +func (m *Message) Cmdp(t time.Duration, head []string, prefix []string, suffix [][]string) *Message { + if head != nil && len(head) > 0 { + m.Show(strings.Join(head, " "), "...\n") + } + + for i, v := range suffix { + m.Show(fmt.Sprintf("%v/%v %v...\n", i+1, len(suffix), v)) + m.CopyFuck(m.Cmd(prefix, v), "append") + time.Sleep(t) + } + m.Show("\n") + m.Table() + return m +} +func (m *Message) Cmdm(args ...interface{}) *Message { + m.Log("info", "current: %v", m.Magic("session", "current")) + + arg := []string{} + if pod := kit.Format(m.Magic("session", "current.pod")); pod != "" { + arg = append(arg, "context", "ssh", "remote", pod) + } + if ctx := kit.Format(m.Magic("session", "current.ctx")); ctx != "" { + arg = append(arg, "context", ctx) + } + arg = append(arg, kit.Trans(args...)...) + + // 执行命令 + m.Spawn().Cmd(arg).CopyTo(m) + // m.Magic("session", "current.ctx", msg.target.Name) + return m +} +func (m *Message) Cmdy(args ...interface{}) *Message { + m.Cmd(args...).CopyTo(m) + return m +} +func (m *Message) Cmdx(args ...interface{}) string { + msg := m.Cmd(args...) + if msg.Result(0) == "error: " { + return msg.Result(1) + } + return msg.Result(0) +} +func (m *Message) Cmds(args ...interface{}) bool { + return m.Cmd(args...).Results(0) +} +func (m *Message) Cmd(args ...interface{}) *Message { + if m == nil { + return m + } + + if len(args) > 0 { + m.Set("detail", kit.Trans(args...)) + } + key, arg := m.Meta["detail"][0], m.Meta["detail"][1:] + + msg := m + if strings.Contains(key, ":") { + ps := strings.Split(key, ":") + msg, key, arg = msg.Sess("ssh"), "_route", append([]string{"sync", ps[0], ps[1]}, arg...) + defer func() { m.Copy(msg, "append").Copy(msg, "result") }() + m.Hand = true + + } else if strings.Contains(key, ".") { + arg := strings.Split(key, ".") + msg, key = msg.Sess(arg[0]), arg[1] + msg.Option("remote_code", "") + } + if msg == nil { + return msg + } + + msg = msg.Match(key, true, func(msg *Message, s *Context, c *Context, key string) bool { + msg.Hand = false + if x, ok := c.Commands[key]; ok && x.Hand != nil { + msg.TryCatch(msg, true, func(msg *Message) { + msg.Log("cmd", "%s %s %v %v", c.Name, key, arg, msg.Meta["option"]) + + for _, form := range []map[string]int{map[string]int{"page.limit": 1, "page.offset": 1}, x.Form} { + + if args := []string{}; form != nil { + for i := 0; i < len(arg); i++ { + if n, ok := form[arg[i]]; ok { + if n < 0 { + n += len(arg) - i + } + for j := i + 1; j <= i+n && j < len(arg); j++ { + if _, ok := form[arg[j]]; ok { + n = j - i - 1 + } + } + if i+1+n > len(arg) { + msg.Add("option", arg[i], arg[i+1:]) + } else { + msg.Add("option", arg[i], arg[i+1:i+1+n]) + } + i += n + } else { + args = append(args, arg[i]) + } + } + arg = args + } + } + + target := msg.target + msg.target = s + + msg.Hand = true + switch v := msg.Gdb("command", key, arg).(type) { + case string: + msg.Echo(v) + case nil: + if msg.Options("auto_cmd") { + if x.Auto != nil { + x.Auto(msg, c, key, arg...) + } + } else { + x.Hand(msg, c, key, arg...) + } + } + if msg.target == s { + msg.target = target + } + }) + } + return msg.Hand + }) + + if !msg.Hand { + msg.Log("error", "cmd run error %s", msg.Format()) + } + return msg +} + +func (m *Message) Confm(key string, args ...interface{}) map[string]interface{} { + random := "" + var chain interface{} + if len(args) > 0 { + switch arg := args[0].(type) { + case []interface{}: + chain, args = arg, args[1:] + case []string: + chain, args = arg, args[1:] + case string: + switch arg { + case "%", "*": + random, args = arg, args[1:] + default: + chain, args = arg, args[1:] + } + } + } + + var v interface{} + if chain == nil { + v = m.Confv(key) + } else { + v = m.Confv(key, chain) + } + + table, _ := v.([]interface{}) + value, _ := v.(map[string]interface{}) + if len(args) == 0 { + return value + } + + switch fun := args[0].(type) { + case func(int, string): + for i, v := range table { + fun(i, kit.Format(v)) + } + case func(int, string) bool: + for i, v := range table { + if fun(i, kit.Format(v)) { + break + } + } + case func(string, string): + for k, v := range value { + fun(k, kit.Format(v)) + } + case func(string, string) bool: + for k, v := range value { + if fun(k, kit.Format(v)) { + break + } + } + case func(map[string]interface{}): + if len(value) == 0 { + return nil + } + fun(value) + case func(string, map[string]interface{}): + switch random { + case "%": + n, i := rand.Intn(len(value)), 0 + for k, v := range value { + if val, ok := v.(map[string]interface{}); i == n && ok { + fun(k, val) + break + } + i++ + } + case "*": + fallthrough + default: + for k, v := range value { + if val, ok := v.(map[string]interface{}); ok { + fun(k, val) + } + } + } + case func(string, int, map[string]interface{}): + for k, v := range value { + if val, ok := v.([]interface{}); ok { + for i, v := range val { + if val, ok := v.(map[string]interface{}); ok { + fun(k, i, val) + } + } + } + } + + case func(string, map[string]interface{}) bool: + for k, v := range value { + if val, ok := v.(map[string]interface{}); ok { + if fun(k, val) { + break + } + } + } + case func(int, map[string]interface{}): + for i := m.Optioni("page.begin"); i < len(table); i++ { + if val, ok := table[i].(map[string]interface{}); ok { + fun(i, val) + } + } + } + return value +} +func (m *Message) Confx(key string, args ...interface{}) string { + value := kit.Select(m.Conf(key), m.Option(key)) + if len(args) == 0 { + return value + } + + switch arg := args[0].(type) { + case []string: + if len(args) > 1 { + value = kit.Select(value, arg, args[1]) + } else { + value = kit.Select(value, arg) + } + args = args[1:] + case map[string]interface{}: + value = kit.Select(value, kit.Format(arg[key])) + case string: + value = kit.Select(value, arg) + case nil: + default: + value = kit.Select(value, args[0]) + } + + format := "%s" + if args = args[1:]; len(args) > 0 { + format, args = kit.Format(args[0]), args[1:] + } + arg := []interface{}{format, value} + for _, v := range args { + arg = append(arg, v) + } + + return kit.Format(arg...) +} +func (m *Message) Confs(key string, arg ...interface{}) bool { + return kit.Right(m.Confv(key, arg...)) +} +func (m *Message) Confi(key string, arg ...interface{}) int { + return kit.Int(m.Confv(key, arg...)) +} +func (m *Message) Confv(key string, args ...interface{}) interface{} { + if strings.Contains(key, ".") { + target := m.target + defer func() { m.target = target }() + + ps := strings.Split(key, ".") + if msg := m.Sess(ps[0], false); msg != nil { + m.target, key = msg.target, ps[1] + } + } + + var config *Config + m.Match(key, false, func(m *Message, s *Context, c *Context, key string) bool { + if x, ok := c.Configs[key]; ok { + config = x + return true + } + return false + }) + + if len(args) == 0 { + if config == nil { + return nil + } + return config.Value + } + + if config == nil { + config = &Config{} + m.target.Configs[key] = config + } + + switch config.Value.(type) { + case string: + config.Value = kit.Format(args...) + case bool: + config.Value = kit.Right(args...) + case int: + config.Value = kit.Int(args...) + case nil: + config.Value = args[0] + default: + for i := 0; i < len(args); i += 2 { + if i < len(args)-1 { + config.Value = kit.Chain(config.Value, args[i], args[i+1]) + } else { + return kit.Chain(config.Value, args[i]) + } + } + } + + return config.Value +} +func (m *Message) Conf(key string, args ...interface{}) string { + return kit.Format(m.Confv(key, args...)) +} +func (m *Message) Caps(key string, arg ...interface{}) bool { + if len(arg) > 0 { + return kit.Right(m.Cap(key, arg...)) + } + return kit.Right(m.Cap(key)) +} +func (m *Message) Capi(key string, arg ...interface{}) int { + n := kit.Int(m.Cap(key)) + if len(arg) > 0 { + return kit.Int(m.Cap(key, n+kit.Int(arg...))) + } + return n +} +func (m *Message) Cap(key string, arg ...interface{}) string { + var cache *Cache + m.Match(key, false, func(m *Message, s *Context, c *Context, key string) bool { + if x, ok := c.Caches[key]; ok { + cache = x + return true + } + return false + }) + + if len(arg) == 0 { + if cache == nil { + return "" + } + if cache.Hand != nil { + return cache.Hand(m, cache) + } + return cache.Value + } + + if cache == nil { + cache = &Cache{} + m.target.Caches[key] = cache + } + + if cache.Hand != nil { + cache.Value = cache.Hand(m, cache, kit.Format(arg...)) + } else { + cache.Value = kit.Format(arg...) + } + return cache.Value +}