package ctx // {{{ // }}} import ( // {{{ "crypto/md5" "encoding/hex" "errors" "fmt" "io" "log" "math/rand" "os" "path" "regexp" "runtime/debug" "strconv" "strings" "time" ) // }}} func Right(str string) bool { return str != "" && str != "0" && str != "false" } type Cache struct { Name string Value string Help string Hand func(m *Message, x *Cache, arg ...string) string } type Config struct { Name string Value string Help string Hand func(m *Message, x *Config, arg ...string) string } type Command struct { Name string Help string Formats map[string]int Options map[string]string Appends map[string]string Hand func(m *Message, c *Context, key string, arg ...string) } 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 root *Context context *Context contexts map[string]*Context master *Context messages chan *Message Pulse *Message Requests []*Message Historys []*Message Sessions map[string]*Message Exit chan bool Index map[string]*Context Groups map[string]*Context Owner *Context Group string password string Server } func (c *Context) Password(meta string) string { // {{{ bs := md5.Sum([]byte(fmt.Sprintln("%d%d%s", time.Now().Unix(), rand.Int(), meta))) sessid := hex.EncodeToString(bs[:]) return sessid } // }}} func (c *Context) Register(s *Context, x Server) (password string) { // {{{ if c.contexts == nil { c.contexts = make(map[string]*Context) } if x, ok := c.contexts[s.Name]; ok { panic(errors.New(c.Name + "上下文中已存在模块:" + x.Name)) } c.contexts[s.Name] = s s.context = c s.Server = x s.password = c.Password(s.Name) return s.password } // }}} func (c *Context) Spawn(m *Message, name string, help string) *Context { // {{{ s := &Context{Name: name, Help: help, root: c.root, context: c} if m.target = s; c.Server != nil { c.Register(s, c.Server.Spawn(m, s, m.Meta["detail"]...)) } else { c.Register(s, nil) } if m.Template != nil { m.Template.source = s } return s } // }}} func (c *Context) Begin(m *Message) *Context { // {{{ c.Caches["status"] = &Cache{Name: "服务状态(begin/start/close)", Value: "begin", Help: "服务状态,begin:初始完成,start:正在运行,close:未在运行"} c.Caches["stream"] = &Cache{Name: "服务数据", Value: "", Help: "服务数据"} m.Index = 1 c.Pulse = m c.Requests = []*Message{m} c.Historys = []*Message{m} c.Sessions = map[string]*Message{} c.master = m.master.master c.Owner = m.master.Owner c.Group = m.master.Group m.Log("begin", nil, "%d context %v %v", m.root.Capi("ncontext", 1), m.Meta["detail"], m.Meta["option"]) for k, x := range c.Configs { if x.Hand != nil { m.Conf(k, x.Value) } } if c.Server != nil { c.Server.Begin(m, m.Meta["detail"]...) } return c } // }}} func (c *Context) Start(m *Message) bool { // {{{ m.Hand = true if m != c.Requests[0] { c.Requests, m.Index = append(c.Requests, m), len(c.Requests)+1 } if m.Cap("status") != "start" { running := make(chan bool) go m.AssertOne(m, true, func(m *Message) { m.Log(m.Cap("status", "start"), nil, "%d server %v %v", m.root.Capi("nserver", 1), m.Meta["detail"], m.Meta["option"]) if running <- true; c.Server != nil && c.Server.Start(m, m.Meta["detail"]...) { c.Close(m, m.Meta["detail"]...) } }) <-running } return true } // }}} func (c *Context) Close(m *Message, arg ...string) bool { // {{{ m.Log("close", c, "%d:%d %v", len(m.source.Sessions), len(m.target.Historys), arg) if m.target == c { if m.Index == 0 { for i := len(c.Requests) - 1; i >= 0; i-- { v := c.Requests[i] if v.Index = -1; v.source != c && !v.source.Close(v, arg...) { v.Index = i return false } c.Requests = c.Requests[:i] } } else if m.Index > 0 { for i := m.Index - 1; i < len(c.Requests)-1; i++ { c.Requests[i] = c.Requests[i+1] } c.Requests = c.Requests[:len(c.Requests)-1] } } if c.Server != nil && !c.Server.Close(m, arg...) { return false } if m.source == c && m.target != c { if _, ok := c.Sessions[m.Name]; ok { delete(c.Sessions, m.Name) } return true } if len(c.Requests) > 1 { return false } if m.Cap("status") == "start" { m.Log(m.Cap("status", "close"), nil, "%d server %v", m.root.Capi("nserver", -1)+1, arg) for _, v := range c.Sessions { if v.target != c { v.target.Close(v, arg...) } } } // if m.Index == 0 && c.context != nil && len(c.contexts) == 0 { if c.context != nil { m.Log("close", nil, "%d context %v", m.root.Capi("ncontext", -1)+1, arg) delete(c.context.contexts, c.Name) c.context = nil if c.Exit != nil { c.Exit <- true } } return true } // }}} func (c *Context) Context() *Context { // {{{ return c.context } // }}} func (c *Context) Master(s ...*Context) *Context { // {{{ if len(s) > 0 { switch s[0] { case nil, c: c.master = s[0] } } return c.master } // }}} func (c *Context) Has(key ...string) bool { // {{{ switch len(key) { case 1: if _, ok := c.Caches[key[0]]; ok { return true } if _, ok := c.Configs[key[0]]; ok { return true } case 2: if _, ok := c.Caches[key[0]]; ok && key[1] == "cache" { return true } if _, ok := c.Configs[key[0]]; ok && key[1] == "config" { return true } if _, ok := c.Commands[key[0]]; ok && key[1] == "command" { return true } } return false } // }}} type Message struct { time time.Time code int Hand bool Recv chan bool Wait chan bool Meta map[string][]string Data map[string]interface{} messages []*Message message *Message root *Message Name string source *Context master *Context target *Context Index int ncallback int callback func() bool Template *Message } func (m *Message) Code() int { // {{{ return m.code } // }}} func (m *Message) Message() *Message { // {{{ return m.message } // }}} func (m *Message) Source(s ...*Context) *Context { // {{{ if len(s) > 0 { m.source = s[0] } return m.source } // }}} func (m *Message) Master(s ...*Context) *Context { // {{{ if len(s) > 0 && s[0] == m.source { m.master = m.source } return m.master } // }}} func (m *Message) Target(s ...*Context) *Context { // {{{ if len(s) > 0 { m.target = s[0] } return m.target } // }}} var i = 0 func (m *Message) Log(action string, ctx *Context, str string, arg ...interface{}) { // {{{ if !m.Confs("bench.log") { return } if !m.Options("log") { return } if l := m.Sess("log"); l != nil { if i++; i > 80000 { debug.PrintStack() os.Exit(1) } // l.Wait = nil l.Options("log", false) l.Cmd("log", action, fmt.Sprintf(str, arg...)) } else { log.Printf(str, arg...) return } } // }}} func (m *Message) Gdb(action string) { // {{{ } // }}} func (m *Message) Check(s *Context, arg ...string) bool { // {{{ return true if s.Owner == nil { return true } if m.master.Owner == s.Owner { return true } if m.master.Owner == s.root.Owner { return true } g, ok := s.Index[m.master.Group] gg, gok := s.Index["void"] if len(arg) < 2 { if ok && g != nil { return true } m.Log("debug", s, "not auth: %s(%s)", m.master.Name, m.master.Group) if gok && gg != nil { return true } m.Log("debug", s, "not auth: %s(void)", m.master.Name) return false } ok, gok = false, false switch arg[0] { case "commands": if g != nil { _, ok = g.Commands[arg[1]] } if gg != nil { _, gok = gg.Commands[arg[1]] } case "configs": if g != nil { _, ok = g.Configs[arg[1]] } if gg != nil { _, gok = gg.Configs[arg[1]] } case "caches": if g != nil { _, ok = g.Caches[arg[1]] } if gg != nil { _, gok = gg.Caches[arg[1]] } } if ok { return true } if g != nil { m.Log("debug", s, "%s:%s not auth: %s(%s)", arg[0], arg[1], m.master.Name, m.master.Group) } if gok { return true } m.Log("debug", s, "%s:%s not auth: %s(void)", arg[0], arg[1], m.master.Name) return false } // }}} func (m *Message) Assert(e interface{}, msg ...string) bool { // {{{ switch e := e.(type) { case error: case bool: if e { return true } case string: if e != "error: " { return true } case *Context: if m.Check(e, msg...) { return true } if len(msg) > 2 { msg = msg[2:] } case *Message: if result, ok := e.Meta["result"]; ok && len(result) > 0 && result[0] == "error: " { panic(e) } return true default: return true } if len(msg) > 1 { arg := make([]interface{}, 0, len(msg)-1) for _, m := range msg[1:] { arg = append(arg, m) } e = errors.New(fmt.Sprintf(msg[0], arg...)) } else if len(msg) > 0 { e = errors.New(msg[0]) } if _, ok := e.(error); !ok { e = errors.New("error") } m.Set("result", "error: ", fmt.Sprintln(e), "\n") panic(e) } // }}} func (m *Message) AssertOne(msg *Message, safe bool, hand ...func(msg *Message)) *Message { // {{{ defer func() { if e := recover(); e != nil { switch e.(type) { case *Message: panic(e) } msg.Log("error", nil, "error: %v", e) if msg.root.Conf("debug") == "on" && e != io.EOF { fmt.Printf("\n\033[31m%s error: %v\033[0m\n", msg.target.Name, e) debug.PrintStack() fmt.Printf("\033[31m%s error: %v\033[0m\n\n", msg.target.Name, e) } if len(hand) > 1 { m.AssertOne(msg, safe, hand[1:]...) } else if !safe { msg.Assert(e) } } }() if len(hand) > 0 { hand[0](msg) } return m } // }}} func (m *Message) Spawn(c *Context, key ...string) *Message { // {{{ msg := &Message{ code: m.root.Capi("nmessage", 1), time: time.Now(), message: m, root: m.root, source: m.target, master: m.target, target: c, } if m.messages == nil { m.messages = make([]*Message, 0, 10) } m.messages = append(m.messages, msg) msg.Wait = make(chan bool) if len(key) == 0 { return msg } if msg.source.Sessions == nil { msg.source.Sessions = make(map[string]*Message) } msg.source.Sessions[key[0]] = msg msg.Name = key[0] return msg } // }}} func (m *Message) Reply(key ...string) *Message { // {{{ if m.Template == nil { m.Template = m.Spawn(m.source, key...) } msg := m.Template if len(key) == 0 { return msg } if msg.source.Sessions == nil { msg.source.Sessions = make(map[string]*Message) } msg.source.Sessions[key[0]] = msg msg.Name = key[0] return msg } // }}} func (m *Message) Format() string { // {{{ name := fmt.Sprintf("%s->%s", m.source.Name, m.target.Name) if m.Name != "" { name = fmt.Sprintf("%s.%s->%s.%d", m.source.Name, m.Name, m.target.Name, m.Index) } return fmt.Sprintf("%d(%s): %s %v", m.code, name, m.time.Format("15:04:05"), m.Meta["detail"]) } // }}} func (m *Message) BackTrace(hand func(m *Message) bool) { // {{{ target := m.target for s := target; s != nil; s = s.context { if m.target = s; m.Check(s) && !hand(m) { break } } m.target = target } // }}} func (m *Message) Travel(c *Context, hand func(m *Message) bool) { // {{{ if c == nil { c = m.target } target := m.target cs := []*Context{c} for i := 0; i < len(cs); i++ { if m.target = cs[i]; m.Check(cs[i]) && !hand(m) { break } for _, v := range cs[i].contexts { cs = append(cs, v) } } m.target = target } // }}} func (m *Message) Search(key string, root ...bool) []*Message { // {{{ reg, e := regexp.Compile(key) m.Assert(e) target := m.target if len(root) > 0 && root[0] { target = m.target.root } cs := make([]*Context, 0, 3) m.Travel(target, func(m *Message) bool { if reg.MatchString(m.target.Name) || reg.FindString(m.target.Help) != "" { m.Log("search", nil, "%d match [%s]", len(cs)+1, key) cs = append(cs, m.target) } return true }) ms := make([]*Message, len(cs)) for i := 0; i < len(cs); i++ { ms[i] = m.Spawn(cs[i]) } return ms } // }}} func (m *Message) Find(name string, root ...bool) *Message { // {{{ 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 { m.Log("find", target, "not find %s", v) return nil } } m.Log("find", nil, "find %s", name) return m.Spawn(target) } // }}} func (m *Message) Sess(key string, arg ...string) *Message { // {{{ if _, ok := m.target.Sessions[key]; !ok && len(arg) > 0 { root := true if len(arg) > 2 { root = Right(arg[2]) } method := "find" if len(arg) > 1 { method = arg[1] } switch method { case "find": m.target.Sessions[key] = m.Find(arg[0], root) case "search": m.target.Sessions[key] = m.Search(arg[0], root)[0] } return m.target.Sessions[key] } for msg := m; msg != nil; msg = msg.message { if x, ok := msg.target.Sessions[key]; ok { return m.Spawn(x.target) } } return nil } // }}} 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) Add(meta string, key string, value ...string) *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], value...) case "option", "append": if _, ok := m.Meta[key]; !ok { m.Meta[key] = make([]string, 0, 3) } m.Meta[key] = append(m.Meta[key], value...) for _, v := range m.Meta[meta] { if v == key { return m } } m.Meta[meta] = append(m.Meta[meta], key) default: m.Log("error", nil, "%s 消息参数错误", meta) } return m } // }}} func (m *Message) Set(meta string, arg ...string) *Message { // {{{ if m.Meta == nil { m.Meta = make(map[string][]string) } switch meta { case "detail", "result": delete(m.Meta, meta) case "option", "append": if len(arg) > 0 { delete(m.Meta, arg[0]) } else { for _, k := range m.Meta[meta] { delete(m.Meta, k) delete(m.Data, k) } delete(m.Meta, meta) } default: m.Log("error", nil, "%s 消息参数错误", meta) } if len(arg) > 0 { m.Add(meta, arg[0], arg[1:]...) } return m } // }}} func (m *Message) Put(meta string, key string, value interface{}) *Message { // {{{ if m.Meta == nil { m.Meta = make(map[string][]string) } switch meta { case "option", "append": if m.Data == nil { m.Data = make(map[string]interface{}) } m.Data[key] = value if _, ok := m.Meta[meta]; !ok { m.Meta[meta] = make([]string, 0, 3) } for _, v := range m.Meta[meta] { if v == key { return m } } m.Meta[meta] = append(m.Meta[meta], key) default: m.Log("error", nil, "%s 消息参数错误", meta) } return m } // }}} 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 && len(meta) > 0 { return meta[0] } return "" } // }}} func (m *Message) Geti(key string) int { // {{{ n, e := strconv.Atoi(m.Get(key)) m.Assert(e) return n } // }}} func (m *Message) Gets(key string) bool { // {{{ return Right(m.Get(key)) } // }}} func (m *Message) Echo(str string, arg ...interface{}) *Message { // {{{ return m.Add("result", fmt.Sprintf(str, arg...)) } // }}} func (m *Message) Copy(msg *Message, meta string, arg ...string) *Message { // {{{ switch meta { case "detail", "result": m.Meta[meta] = append(m.Meta[meta][:0], msg.Meta[meta]...) case "option", "append": if len(arg) == 0 { arg = msg.Meta[meta] } for _, k := range arg { if v, ok := msg.Meta[k]; ok { m.Set(meta, k).Add(meta, k, v...) } if v, ok := msg.Data[k]; ok { m.Put(meta, k, v) } } } return m } // }}} func (m *Message) Insert(meta string, index int, arg ...interface{}) string { // {{{ if m.Meta == nil { m.Meta = make(map[string][]string) } str := []string{} for _, v := range arg { switch s := v.(type) { case string: str = append(str, s) case []string: str = append(str, s...) case []int: for _, v := range s { str = append(str, fmt.Sprintf("%d", v)) } case []bool: for _, v := range s { str = append(str, fmt.Sprintf("%t", v)) } default: str = append(str, fmt.Sprintf("%v", s)) } } if index == -1 { index, m.Meta[meta] = 0, append(str, m.Meta[meta]...) } else if index == -2 { index, m.Meta[meta] = len(m.Meta[meta]), append(m.Meta[meta], str...) } else { if index < -2 { index += len(m.Meta[meta]) + 2 } if index < 0 { index = 0 } for i := len(m.Meta[meta]); i < index+len(str); i++ { m.Meta[meta] = append(m.Meta[meta], "") } for i := 0; i < len(str); i++ { m.Meta[meta][index+i] = str[i] } } if -1 < index && index < len(m.Meta[meta]) { return m.Meta[meta][index] } return "" } // }}} func (m *Message) Detail(index int, arg ...interface{}) string { // {{{ return m.Insert("detail", index, arg...) } // }}} func (m *Message) Detaili(index int, arg ...int) int { // {{{ i, e := strconv.Atoi(m.Insert("detail", index, arg)) m.Assert(e) return i } // }}} func (m *Message) Details(index int, arg ...bool) bool { // {{{ return Right(m.Insert("detail", index, arg)) } // }}} func (m *Message) Result(index int, arg ...interface{}) string { // {{{ return m.Insert("result", index, arg...) } // }}} func (m *Message) Resulti(index int, arg ...int) int { // {{{ i, e := strconv.Atoi(m.Insert("result", index, arg)) m.Assert(e) return i } // }}} func (m *Message) Results(index int, arg ...bool) bool { // {{{ return Right(m.Insert("result", index, arg)) } // }}} func (m *Message) Option(key string, arg ...interface{}) string { // {{{ 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) { return msg.Get(key) } } return "" } // }}} func (m *Message) Optioni(key string, arg ...int) int { // {{{ i, e := strconv.Atoi(m.Option(key, arg)) m.Assert(e) return i } // }}} func (m *Message) Options(key string, arg ...bool) bool { // {{{ return Right(m.Option(key, arg)) } // }}} func (m *Message) Append(key string, arg ...interface{}) string { // {{{ m.Insert(key, 0, arg...) if _, ok := m.Meta[key]; ok { m.Add("append", key) } for msg := m; msg != nil; msg = msg.message { if m.Has(key) { return m.Get(key) } } return "" } // }}} func (m *Message) Appendi(key string, arg ...int) int { // {{{ i, e := strconv.Atoi(m.Append(key, arg)) m.Assert(e) return i } // }}} func (m *Message) Appends(key string, arg ...bool) bool { // {{{ return Right(m.Append(key, arg)) } // }}} func (m *Message) Exec(key string, arg ...string) string { // {{{ for _, c := range []*Context{m.target, m.target.master, m.target.Owner, m.source, m.source.master, m.source.Owner} { for s := c; s != nil; s = s.context { m.master = m.source if x, ok := s.Commands[key]; ok && x.Hand != nil && m.Check(c, "commands", key) { m.AssertOne(m, true, func(m *Message) { m.Log("cmd", s, "%d %s %v %v", len(m.target.Historys), key, arg, m.Meta["option"]) if x.Options != nil { for _, v := range m.Meta["option"] { if _, ok := x.Options[v]; !ok { panic(errors.New(fmt.Sprintf("未知参数: %s", v))) } } } if m.Has("args") { m.Meta["args"] = nil } if x.Formats != nil { for i := 0; i < len(arg); i++ { n, ok := x.Formats[arg[i]] if !ok { m.Add("option", "args", arg[i]) continue } if n < 0 { n += len(arg) - i } if x, ok := m.Meta[arg[i]]; ok && len(x) == n { m.Add("option", "args", arg[i]) continue } m.Add("option", arg[i], arg[i+1:i+1+n]...) i += n } arg = m.Meta["args"] } m.Hand = true x.Hand(m.Set("result").Set("append"), s, key, arg...) if x.Appends != nil { for _, v := range m.Meta["append"] { if _, ok := x.Appends[v]; !ok { panic(errors.New(fmt.Sprintf("未知参数: %s", v))) } } } if m.target.Historys == nil { m.target.Historys = make([]*Message, 0, 10) } m.target.Historys = append(m.target.Historys, m) m.Back() }) return m.Get("result") } } } return "" } // }}} func (m *Message) Deal(pre func(msg *Message, arg ...string) bool, post func(msg *Message, arg ...string) bool) { // {{{ if m.target.messages == nil { m.target.messages = make(chan *Message, m.Confi("MessageQueueSize")) } for run := true; run; { m.AssertOne(<-m.target.messages, true, func(msg *Message) { defer func() { if msg.Wait != nil { msg.Wait <- true } }() if len(msg.Meta["detail"]) == 0 { return } if pre == nil || pre(msg, msg.Meta["detail"]...) { msg.Exec(msg.Meta["detail"][0], msg.Meta["detail"][1:]...) } if post != nil && !post(msg, msg.Meta["result"]...) { run = false return } }) } } // }}} func (m *Message) Post(s *Context, async ...bool) string { // {{{ if s == nil { s = m.target.master } if s != nil && s.messages != nil { if s.messages <- m; m.Wait != nil { <-m.Wait } return m.Get("result") } return m.Exec(m.Meta["detail"][0], m.Meta["detail"][1:]...) } // }}} func (m *Message) Cmd(arg ...interface{}) *Message { // {{{ if m.Hand { if m.message != nil { m = m.message.Spawn(m.target) } else { msg := m.Spawn(m.target) msg.source = m.source m = msg } } if len(arg) > 0 { m.Set("detail") m.Detail(0, arg...) } if s := m.target.master; s != nil && s != m.source.master { m.Post(s) } else { m.Exec(m.Meta["detail"][0], m.Meta["detail"][1:]...) } return m } // }}} func (m *Message) Call(cb func() bool) { // {{{ m.callback = cb m.message.ncallback++ m.Wait = nil m.Cmd() } // }}} func (m *Message) Back() { // {{{ if m.callback == nil { return } if m.callback() { m.callback = nil m.message.ncallback-- } if m.message.ncallback == 0 { m.message.Back() } } // }}} func (m *Message) Confs(key string, arg ...bool) bool { // {{{ if len(arg) > 0 { if arg[0] { m.Conf(key, "1") } else { m.Conf(key, "0") } } b := m.Conf(key) return b != "" && b != "0" && b != "false" } // }}} func (m *Message) Confi(key string, arg ...int) int { // {{{ n, e := strconv.Atoi(m.Conf(key)) m.Assert(e) if len(arg) > 0 { n, e = strconv.Atoi(m.Conf(key, fmt.Sprintf("%d", arg[0]))) m.Assert(e) } return n } // }}} func (m *Message) Conf(key string, arg ...string) string { // {{{ var hand func(m *Message, x *Config, arg ...string) string for _, c := range []*Context{m.target, m.target.master, m.target.Owner, m.source, m.source.master, m.source.Owner} { for s := c; s != nil; s = s.context { if x, ok := s.Configs[key]; ok { if !m.Check(s, "configs", key) { continue } switch len(arg) { case 3: if hand == nil { hand = x.Hand } case 1: if x.Hand != nil { x.Value = x.Hand(m, x, arg[0]) } else { x.Value = arg[0] } // m.Log("conf", s, "%s %v", x.Name, x.Value) return x.Value case 0: if x.Hand != nil { return x.Hand(m, x) } return x.Value } } } } if len(arg) == 3 && m.Check(m.target, "configs", key) { if m.target.Configs == nil { m.target.Configs = make(map[string]*Config) } m.target.Configs[key] = &Config{Name: arg[0], Value: arg[1], Help: arg[2], Hand: hand} m.Log("conf", nil, "%s %v", key, arg) return m.Conf(key, arg[1]) } m.Log("error", nil, "%s 配置项不存在", key) return "" } // }}} func (m *Message) Caps(key string, arg ...bool) bool { // {{{ if len(arg) > 0 { if arg[0] { m.Cap(key, "1") } else { m.Cap(key, "0") } } b := m.Cap(key) return b != "" && b != "0" && b != "false" } // }}} func (m *Message) Capi(key string, arg ...int) int { // {{{ n, e := strconv.Atoi(m.Cap(key)) m.Assert(e) for _, i := range arg { if i == 0 { i = -n } n, e = strconv.Atoi(m.Cap(key, fmt.Sprintf("%d", n+i))) m.Assert(e) } return n } // }}} func (m *Message) Cap(key string, arg ...string) string { // {{{ var hand func(m *Message, x *Cache, arg ...string) string for _, c := range []*Context{m.target, m.target.master, m.target.Owner, m.source, m.source.master, m.source.Owner} { for s := c; s != nil; s = s.context { if x, ok := s.Caches[key]; ok { if !m.Check(s, "caches", key) { continue } switch len(arg) { case 3: if hand == nil { hand = x.Hand } case 1: if x.Hand != nil { x.Value = x.Hand(m, x, arg[0]) } else { x.Value = arg[0] } // m.Log("debug", s, "%s %s", x.Name, x.Value) return x.Value case 0: // m.Log("debug", s, "%s %s", x.Name, x.Value) if x.Hand != nil { return x.Hand(m, x) } return x.Value } } } } if len(arg) == 3 && m.Check(m.target, "caches", key) { if m.target.Caches == nil { m.target.Caches = make(map[string]*Cache) } m.target.Caches[key] = &Cache{Name: arg[0], Value: arg[1], Help: arg[2], Hand: hand} m.Log("cap", nil, "%s %v", key, arg) return m.Cap(key, arg[1]) } m.Log("error", nil, "%s 缓存项不存在", key) return "" } // }}} var Pulse = &Message{code: 0, time: time.Now(), Wait: make(chan bool), source: Index, master: Index, target: Index} var Index = &Context{Name: "ctx", Help: "模块中心", Caches: map[string]*Cache{ "debug": &Cache{Name: "服务数量", Value: "true", Help: "显示已经启动运行模块的数量"}, "nserver": &Cache{Name: "服务数量", Value: "0", Help: "显示已经启动运行模块的数量"}, "ncontext": &Cache{Name: "模块数量", Value: "0", Help: "显示功能树已经注册模块的数量"}, "nmessage": &Cache{Name: "消息数量", Value: "0", Help: "显示模块启动时所创建消息的数量"}, }, Configs: map[string]*Config{ "debug": &Config{Name: "调试模式(true/false)", Value: "true", Help: "是否打印错误信息,off:不打印,on:打印)"}, "default": &Config{Name: "默认的搜索起点(root/back/home)", Value: "root", Help: "模块搜索的默认起点,root:从根模块,back:从父模块,home:从当前模块"}, "start": &Config{Name: "启动模块", Value: "cli", Help: "启动时自动运行的模块"}, "init.shy": &Config{Name: "启动脚本", Value: "etc/init.shy", Help: "模块启动时自动运行的脚本"}, "bench.log": &Config{Name: "日志文件", Value: "var/bench.log", Help: "模块日志输出的文件", Hand: func(m *Message, x *Config, arg ...string) string { if len(arg) > 0 { // {{{ // if e := os.MkdirAll(path.Dir(arg[0]), os.ModePerm); e == nil { if l, e := os.Create(x.Value); e == nil { log.SetOutput(l) return arg[0] } return "" // } } return x.Value // }}} }}, "root": &Config{Name: "工作目录", Value: ".", Help: "所有模块的当前目录", Hand: func(m *Message, x *Config, arg ...string) string { if len(arg) > 0 { // {{{ if !path.IsAbs(x.Value) { wd, e := os.Getwd() m.Assert(e) x.Value = path.Join(wd, x.Value) } if e := os.MkdirAll(x.Value, os.ModePerm); e != nil { fmt.Println(e) } if e := os.Chdir(x.Value); e != nil { fmt.Println(e) } return arg[0] } return x.Value // }}} }}, "ContextRequestSize": &Config{Name: "请求队列长度", Value: "10", Help: "每个模块可以被其它模块引用的的数量"}, "ContextSessionSize": &Config{Name: "会话队列长度", Value: "10", Help: "每个模块可以启动其它模块的数量"}, "MessageQueueSize": &Config{Name: "消息队列长度", Value: "10", Help: "每个模块接收消息的队列长度"}, "cert": &Config{Name: "证书文件", Value: "etc/cert.pem", Help: "证书文件"}, "key": &Config{Name: "私钥文件", Value: "etc/key.pem", Help: "私钥文件"}, }, Commands: map[string]*Command{ "server": &Command{Name: "server [start|exit|switch][args]", Help: "服务启动停止切换", Hand: func(m *Message, c *Context, key string, arg ...string) { switch len(arg) { // {{{ case 0: m.Travel(m.target.root, func(m *Message) bool { if x, ok := m.target.Caches["status"]; ok { m.Echo("%s(%s): %s\n", m.target.Name, x.Value, m.target.Help) } return true }) default: switch arg[0] { case "start": m.Meta = nil m.Set("detail", arg[1:]...).target.Start(m) case "stop": m.Set("detail", arg[1:]...).target.Close(m) case "switch": } } // }}} }}, "message": &Command{Name: "message code meta index", Help: "查看消息", Hand: func(m *Message, c *Context, key string, arg ...string) { switch len(arg) { // {{{ case 0: m.Echo("\033[31mrequests:\033[0m\n") for i, v := range m.target.Requests { m.Echo("%d %s\n", i, v.Format()) for i, v := range v.messages { m.Echo(" %d %s\n", i, v.Format()) } } m.Echo("\033[32msessions:\033[0m\n") for k, v := range m.target.Sessions { m.Echo("%s %s\n", k, v.Format()) } m.Echo("\033[33mhistorys:\033[0m\n") for i, v := range m.target.Historys { m.Echo("%d %s\n", i, v.Format()) for i, v := range v.messages { m.Echo(" %d %s\n", i, v.Format()) } } case 1: n, e := strconv.Atoi(arg[0]) m.Assert(e) ms := []*Message{m.root} for i := 0; i < len(ms); i++ { if ms[i].code == n { if ms[i].message != nil { m.Echo("message: %d\n", ms[i].message.code) } m.Echo("%s\n", ms[i].Format()) if len(ms[i].Meta["option"]) > 0 { m.Echo("option: %v\n", ms[i].Meta["option"]) } for _, k := range ms[i].Meta["option"] { m.Echo(" %s: %v\n", k, ms[i].Meta[k]) } if len(ms[i].Meta["result"]) > 0 { m.Echo("result: %v\n", ms[i].Meta["result"]) } if len(ms[i].Meta["append"]) > 0 { m.Echo("append: %v\n", ms[i].Meta["append"]) } for _, k := range ms[i].Meta["append"] { m.Echo(" %s: %v\n", k, ms[i].Meta[k]) } if len(ms[i].messages) > 0 { m.Echo("messages: %d\n", len(ms[i].messages)) } for _, v := range ms[i].messages { m.Echo(" %s\n", v.Format()) } break } ms = append(ms, ms[i].messages...) } case 2, 3: index := 0 if len(arg) == 3 { n, e := strconv.Atoi(arg[2]) m.Assert(e) index = n } n, e := strconv.Atoi(arg[0]) m.Assert(e) ms := []*Message{m.root} for i := 0; i < len(ms); i++ { if ms[i].code == n { if meta, ok := ms[i].Meta[arg[1]]; ok { m.Echo(meta[index]) } } ms = append(ms, ms[i].messages...) } } // }}} }}, "context": &Command{Name: "context back|[[home] [find|search] name] [info|list|show|spawn|start|switch|close][args]", Help: "查找并操作模块,\n查找起点root:根模块、back:父模块、home:本模块,\n查找方法find:路径匹配、search:模糊匹配,\n查找对象name:支持点分和正则,\n操作类型show:显示信息、switch:切换为当前、start:启动模块、spawn:分裂子模块,args:启动参数", Formats: map[string]int{"back": 0, "home": 0, "find": 1, "search": 1, "info": 1, "list": 0, "show": 0, "close": 0, "switch": 0, "start": 0, "spawn": 0}, Hand: func(m *Message, c *Context, key string, arg ...string) { if m.Has("back") { // {{{ m.target = m.source return } root := !m.Has("home") ms := []*Message{} switch { case m.Has("search"): if s := m.Search(m.Get("search"), root); len(s) > 0 { ms = append(ms, s...) } case m.Has("find"): if msg := m.Find(m.Get("find"), root); msg != nil { ms = append(ms, msg) } case m.Has("args"): if s := m.Search(m.Get("args"), root); len(s) > 0 { ms = append(ms, s...) arg = arg[1:] break } fallthrough default: ms = append(ms, m) } for _, v := range ms { // v.Meta = m.Meta // v.Data = m.Data switch { case m.Has("switch"), m.Has("back"): m.target = v.target case m.Has("spawn"): v.Set("detail", arg[2:]...).target.Spawn(v, arg[0], arg[1]).Begin(v) m.target = v.target case m.Has("start"): v.Set("detail", arg...).target.Start(v) m.target = v.target case m.Has("close"): v.target.Close(v) case m.Has("show"): m.Echo("%s(%s): %s\n", v.target.Name, v.target.Owner.Name, v.target.Help) if len(v.target.Requests) > 0 { m.Echo("模块资源:\n") for i, v := range v.target.Requests { m.Echo(" %d: <- %s %s\n", i, v.source.Name, v.Meta["detail"]) // for i, v := range v.Messages { // m.Echo(" %d: -> %s %s\n", i, v.source.Name, v.Meta["detail"]) // } } } if len(v.target.Sessions) > 0 { m.Echo("模块引用:\n") for k, v := range v.target.Sessions { m.Echo(" %s: -> %s %v\n", k, v.target.Name, v.Meta["detail"]) } } case m.Has("info"): switch m.Get("info") { case "name": m.Echo("%s", v.target.Name) case "owner": m.Echo("%s", v.target.Owner.Name) default: m.Echo("%s(%s): %s\n", v.target.Name, v.target.Owner.Name, v.target.Help) } case m.Has("list") || len(m.Meta["detail"]) == 1: m.Travel(v.target, func(msg *Message) bool { target := msg.target m.Echo("%s(", target.Name) if target.context != nil { m.Echo("%s", target.context.Name) } m.Echo(":") if target.master != nil { m.Echo("%s", target.master.Name) } m.Echo(":") if target.Owner != nil { m.Echo("%s", target.Owner.Name) } m.Echo(":") msg.target = msg.target.Owner if msg.target != nil && msg.Check(msg.target, "caches", "username") && msg.Check(msg.target, "caches", "group") { m.Echo("%s:%s", msg.Cap("username"), msg.Cap("group")) } m.Echo("): ") msg.target = target if msg.Check(msg.target, "caches", "status") && msg.Check(msg.target, "caches", "stream") { m.Echo("%s(%s) ", msg.Cap("status"), msg.Cap("stream")) } m.Echo("%s\n", target.Help) return true }) case len(arg) > 0 && v != m: v.Meta = m.Meta v.Cmd(arg) m.Meta = v.Meta default: m.target = v.target } } // }}} }}, "command": &Command{Name: "command [all] [key [name help]]", Help: "查看或修改命令", Formats: map[string]int{"all": 0, "delete": 0, "void": 0}, Hand: func(m *Message, c *Context, key string, arg ...string) { all := m.Has("all") // {{{ switch len(arg) { case 0: m.BackTrace(func(m *Message) bool { if all { m.Echo("%s comands:\n", m.target.Name) } for k, x := range m.target.Commands { if m.Check(m.target, "commands", k) { if all { m.Echo(" ") } m.Echo("%s: %s\n", k, x.Name) } } return all }) case 1: switch { case m.Has("delete"): if _, ok := m.target.Commands[arg[0]]; ok { if m.target.Owner == nil || m.master.Owner == m.target.Owner { delete(m.target.Commands, arg[0]) } } case m.Has("void"): if x, ok := m.target.Commands[arg[0]]; ok { if m.target.Owner == nil || m.master.Owner == m.target.Owner { x.Hand = nil } } default: msg := m.Spawn(m.Target()).Cmd(arg) msg.Option("nrecv", m.Option("nrecv")) m.Meta = msg.Meta } return m.BackTrace(func(m *Message) bool { if all { m.Echo("%s commands:\n", m.target.Name) } if x, ok := m.target.Commands[arg[0]]; ok { if all { m.Echo(" ") } if m.Check(m.target, "commands", arg[0]) { m.Echo("%s\n %s\n", x.Name, x.Help) } } return all }) m.Assert(m.Has("result"), "%s 命令不存在", arg[0]) default: msg := m.Spawn(m.Target()).Cmd(arg) msg.Option("nrecv", m.Option("nrecv")) m.Meta = msg.Meta /* case 3: cmd := &Command{} m.BackTrace(func(m *Message) bool { if x, ok := m.target.Commands[arg[0]]; ok && x.Hand != nil { *cmd = *x } return all }) if m.Check(m.target, "commands", arg[0]) { if x, ok := m.target.Commands[arg[0]]; ok { if m.target.Owner == nil || m.master.Owner == m.target.Owner { x.Name = arg[1] x.Help = arg[2] m.Echo("%s\n %s\n", x.Name, x.Help) } } else { if m.target.Commands == nil { m.target.Commands = map[string]*Command{} } cmd.Name = arg[1] cmd.Help = arg[2] m.target.Commands[arg[0]] = cmd } } */ } // }}} }}, "config": &Command{Name: "config [all] [[delete|void] key [value]|[name value help]]", Help: "删除、置空、查看、修改或添加配置", Formats: map[string]int{"all": 0, "delete": 0, "void": 0}, Hand: func(m *Message, c *Context, key string, arg ...string) { all := m.Has("all") // {{{ switch len(arg) { case 0: m.BackTrace(func(m *Message) bool { if all { m.Echo("%s configs:\n", m.target.Name) } for k, x := range m.target.Configs { if m.Check(m.target, "configs", k) { if all { m.Echo(" ") } m.Echo("%s(%s): %s\n", k, x.Value, x.Name) } } return all }) case 1: switch { case m.Has("delete"): if _, ok := m.target.Configs[arg[0]]; ok { if m.target.Owner == nil || m.master.Owner == m.target.Owner { delete(m.target.Configs, arg[0]) } } case m.Has("void"): m.Conf(arg[0], "") } m.BackTrace(func(m *Message) bool { // if all { // m.Echo("%s config:\n", m.target.Name) // } if x, ok := m.target.Configs[arg[0]]; ok { if m.Check(m.target, "configs", arg[0]) { // if all { // m.Echo(" ") // } // m.Echo("%s: %s\n", x.Name, x.Help) m.Echo("%s", x.Value) return false } } return true // return all }) case 2: m.Conf(arg[0], arg[1]) case 3: m.Conf(arg[0], arg[2]) case 4: m.Conf(arg[0], arg[1:]...) } // }}} }}, "cache": &Command{Name: "cache [all] [[delete|void] key [value]|[name value help]]", Help: "删除、置空、查看、修改或添加缓存", Formats: map[string]int{"all": 0, "delete": 0, "void": 0}, Hand: func(m *Message, c *Context, key string, arg ...string) { all := m.Has("all") // {{{ switch len(arg) { case 0: m.BackTrace(func(m *Message) bool { if all { m.Echo("%s configs:\n", m.target.Name) } for k, x := range m.target.Caches { if m.Check(m.target, "caches", k) { if all { m.Echo(" ") } m.Echo("%s(%s): %s\n", k, m.Cap(k), x.Name) } } return all }) case 1: switch { case m.Has("delete"): if _, ok := m.target.Caches[arg[0]]; ok { if m.target.Owner == nil || m.master.Owner == m.target.Owner { delete(m.target.Caches, arg[0]) } } case m.Has("void"): m.Cap(arg[0], "") } if m.source == m.source.master { m.source, m.target = m.target, m.source } m.Echo("%s", m.Cap(arg[0])) case 2: if m.source == m.source.master { m.source, m.target = m.target, m.source } m.Cap(arg[0], arg[1]) case 3: if m.source == m.source.master { m.source, m.target = m.target, m.source } m.Cap(arg[0], arg[2]) case 4: m.Cap(arg[0], arg[1:]...) } // }}} }}, "group": &Command{ Name: "group current [add|del group [cache|config|command item]]", Help: "用户组管理,查看、添加、删除用户组或是接口", Formats: map[string]int{"add": 0, "del": 0, "cache": 0, "config": 0, "command": 0}, Hand: func(m *Message, c *Context, key string, arg ...string) { index := m.Target().Index // {{{ current := m.Target() if len(arg) > 0 && arg[0] != "root" { current = index[arg[0]] if current == nil { return } } group := current if len(arg) > 1 { group = current.Index[arg[1]] } item := "" if len(arg) > 2 { item = arg[2] } switch { case m.Has("add"): if group == nil { if _, ok := index[arg[1]]; ok { break } group = &Context{Name: arg[1]} } switch { case m.Has("cache"): if x, ok := current.Caches[item]; ok { if group.Caches == nil { group.Caches = map[string]*Cache{} } group.Caches[item] = x } case m.Has("config"): if x, ok := current.Configs[item]; ok { if group.Configs == nil { group.Configs = map[string]*Config{} } group.Configs[item] = x } case m.Has("command"): if x, ok := current.Commands[item]; ok { if group.Commands == nil { group.Commands = map[string]*Command{} } group.Commands[item] = x } } if current.Index == nil { current.Index = map[string]*Context{} } current.Index[arg[1]] = group index[arg[1]] = group case m.Has("del"): if group == nil { break } gs := []*Context{group} for i := 0; i < len(gs); i++ { for _, g := range gs[i].Index { gs = append(gs, g) } switch { case m.Has("cache"): delete(gs[i].Caches, item) case m.Has("config"): delete(gs[i].Configs, item) case m.Has("command"): delete(gs[i].Commands, item) default: delete(index, gs[i].Name) delete(current.Index, gs[i].Name) } } default: m.Echo("%s:caches\n", current.Name) for k, c := range current.Caches { m.Echo(" %s: %s\n", k, c.Value) } m.Echo("%s:configs\n", current.Name) for k, c := range current.Configs { m.Echo(" %s: %s\n", k, c.Value) } m.Echo("%s:commands\n", current.Name) for k, c := range current.Commands { m.Echo(" %s: %s\n", k, c.Name) } m.Echo("%s:contexts\n", current.Name) for k, c := range current.Index { m.Echo(" %s: %s\n", k, c.Name) } } // }}} }}, "pulse": &Command{Name: "arg name", Help: "查看日志", Hand: func(m *Message, c *Context, key string, arg ...string) { p := m.Target().Pulse m.Echo("%d\n", p.code) m.Echo("%v\n", p.Meta["detail"]) m.Echo("%v\n", p.Meta["option"]) }}, }, Index: map[string]*Context{ "void": &Context{Name: "void", Caches: map[string]*Cache{}, Configs: map[string]*Config{ "bench.log": &Config{}, }, Commands: map[string]*Command{ "message": &Command{}, "context": &Command{}, "command": &Command{}, "config": &Command{}, "cache": &Command{}, }, }, }, } func init() { Pulse.root = Pulse Index.root = Index } func Start(args ...string) { if len(args) > 0 { Pulse.Conf("start", args[0]) } if len(args) > 1 { Pulse.Conf("init.shy", args[1]) } if len(args) > 2 { Pulse.Conf("bench.log", args[2]) } else { Pulse.Conf("bench.log", Pulse.Conf("bench.log")) } if len(args) > 3 { Pulse.Conf("root", args[3]) } Pulse.Options("log", true) // log.Println("\n\n") Index.Group = "root" Index.Owner = Index.contexts["aaa"] Index.master = Index.contexts["cli"] for _, m := range Pulse.Search("") { m.target.root = Index m.target.Begin(m) } // log.Println() Pulse.Sess("log", "log").Conf("bench.log", "var/bench.log") for _, m := range Pulse.Search(Pulse.Conf("start")) { m.Set("detail", Pulse.Conf("init.shy")).Set("option", "stdio").target.Start(m) } <-Index.master.Exit }