1
0
forked from x/ContextOS
2018-04-09 20:55:56 +08:00

1965 lines
44 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}