forked from x/icebergs
262 lines
8.4 KiB
Go
262 lines
8.4 KiB
Go
package ice
|
|
|
|
import (
|
|
"errors"
|
|
"io"
|
|
"reflect"
|
|
"strings"
|
|
"time"
|
|
|
|
"shylinux.com/x/icebergs/base/web/html"
|
|
kit "shylinux.com/x/toolkits"
|
|
"shylinux.com/x/toolkits/logs"
|
|
"shylinux.com/x/toolkits/task"
|
|
)
|
|
|
|
func (m *Message) TryCatch(catch bool, cb ...func(*Message)) {
|
|
defer func() {
|
|
switch e := recover(); e {
|
|
case io.EOF, nil:
|
|
default:
|
|
fileline := m.FormatStack(2, 1)
|
|
m.Log(LOG_WARN, "catch: %s %s", e, fileline).Log("chain", "\n"+m.FormatChain())
|
|
m.Log(LOG_WARN, "catch: %s %s", e, kit.FileLine(4, 10)).Log("stack", "\n"+m.FormatStack(2, 1000))
|
|
m.Log(LOG_WARN, "catch: %s %s", e, fileline).Result(ErrWarn, e, SP, m.FormatStack(2, 5))
|
|
if len(cb) > 1 {
|
|
m.TryCatch(catch, cb[1:]...)
|
|
} else if !catch {
|
|
m.Assert(e)
|
|
}
|
|
}
|
|
}()
|
|
kit.If(len(cb) > 0, func() { cb[0](m) })
|
|
}
|
|
func (m *Message) Assert(expr Any) bool {
|
|
switch e := expr.(type) {
|
|
case nil:
|
|
return true
|
|
case string:
|
|
if expr != "" {
|
|
return true
|
|
}
|
|
case bool:
|
|
if e == true {
|
|
return true
|
|
}
|
|
case error:
|
|
default:
|
|
expr = errors.New(kit.Format("error: %v", e))
|
|
}
|
|
m.Result(ErrWarn, expr, logs.FileLine(2))
|
|
panic(expr)
|
|
}
|
|
func (m *Message) Sleep(d Any, arg ...Any) *Message {
|
|
defer kit.If(len(arg) > 0, func() { m.Cmdy(arg...) })
|
|
time.Sleep(kit.Duration(d))
|
|
return m
|
|
}
|
|
func (m *Message) Sleep300ms(arg ...Any) *Message { return m.Sleep("300ms", arg...) }
|
|
func (m *Message) Sleep30ms(arg ...Any) *Message { return m.Sleep("30ms", arg...) }
|
|
func (m *Message) Sleep3s(arg ...Any) *Message { return m.Sleep("3s", arg...) }
|
|
func (m *Message) GoSleep(t string, cb func(), arg ...Any) *Message {
|
|
return m.Go(func() { m.Spawn(kit.Dict(MSG_COUNT, "0")).Sleep(t); cb() })
|
|
}
|
|
func (m *Message) GoSleep300ms(cb func(), arg ...Any) { m.GoSleep("300ms", cb, arg...) }
|
|
func (m *Message) GoSleep30ms(cb func(), arg ...Any) { m.GoSleep("30ms", cb, arg...) }
|
|
func (m *Message) GoSleep3s(cb func(), arg ...Any) { m.GoSleep("3s", cb, arg...) }
|
|
func (m *Message) Go(cb func(), arg ...Any) *Message {
|
|
meta := m.FormatTaskMeta()
|
|
meta.FileLine = kit.FileLine(2, 3)
|
|
kit.If(len(arg) > 0, func() { meta.FileLine = kit.Format(arg[0]) })
|
|
task.Put(meta, nil, func(task *task.Task) {
|
|
m.TryCatch(true, func(m *Message) {
|
|
m.Option("work.id", kit.Format(task.WorkId()))
|
|
m.Option("task.id", kit.Format(task.TaskId()))
|
|
cb()
|
|
})
|
|
})
|
|
return m
|
|
}
|
|
func (m *Message) GoWait(cb func(func()), arg ...Any) *Message {
|
|
res := make(chan bool, 2)
|
|
defer func() { <-res }()
|
|
return m.Go(func() { cb(func() { res <- true }) }, arg...)
|
|
}
|
|
func (m *Message) Wait(d string, cb ...Handler) (wait func() bool, done Handler) {
|
|
if d == "" {
|
|
return nil, nil
|
|
}
|
|
sync := make(chan bool, 2)
|
|
t := time.AfterFunc(kit.Duration(d), func() { sync <- false })
|
|
return func() bool { return <-sync }, func(msg *Message, arg ...string) {
|
|
defer func() { t.Stop(); sync <- true }()
|
|
kit.If(len(cb) > 0 && cb[0] != nil, func() { cb[0](msg, arg...) }, func() { m.Copy(msg) })
|
|
}
|
|
}
|
|
|
|
func (m *Message) Cmd(arg ...Any) *Message { return m._command(arg...) }
|
|
func (m *Message) Cmds(arg ...Any) *Message { return m.Cmd(append(arg, OptionFields(""))...) }
|
|
func (m *Message) Cmdv(arg ...Any) string {
|
|
args := kit.Simple(arg...)
|
|
field := kit.Slice(args, -1)[0]
|
|
return m._command(kit.Slice(args, 0, -1), OptionFields(field)).Append(field)
|
|
}
|
|
func (m *Message) Cmdx(arg ...Any) string {
|
|
res := strings.TrimSpace(m._command(arg...).index(MSG_RESULT, 0))
|
|
return kit.Select("", res, res != strings.TrimSpace(ErrWarn))
|
|
}
|
|
func (m *Message) Cmdy(arg ...Any) *Message { return m.Copy(m._command(arg...)) }
|
|
func (m *Message) CmdList(arg ...string) []string {
|
|
msg, list := m._command(arg), []string{}
|
|
kit.For(msg._cmd.List, func(value Map) {
|
|
kit.If(!kit.IsIn(kit.Format(kit.Value(value, TYPE)), html.BUTTON), func() { list = append(list, kit.Format(kit.Value(value, NAME))) })
|
|
})
|
|
return msg.Appendv(kit.Select(kit.Select("", list, 0), list, len(arg)-1))
|
|
}
|
|
func (m *Message) CmdHand(cmd *Command, key string, arg ...string) *Message {
|
|
if m._cmd, m._key, m._sub = cmd, key, LIST; cmd == nil {
|
|
return m
|
|
}
|
|
if m._target = cmd.FileLines(); key == SELECT {
|
|
m.Log(LOG_CMDS, "%s.%s %v %v", m.Target().Name, key, formatArg(arg...), m.Optionv(MSG_FIELDS), logs.FileLineMeta(m._fileline()))
|
|
} else {
|
|
m.Log(LOG_CMDS, "%s.%s %v", m.Target().Name, key, formatArg(arg...), logs.FileLineMeta(m._fileline()))
|
|
}
|
|
if cmd.Hand != nil {
|
|
cmd.Hand(m, arg...)
|
|
} else if cmd.Actions != nil && cmd.Actions[SELECT] != nil {
|
|
m._sub = SELECT
|
|
cmd.Actions[SELECT].Hand(m, arg...)
|
|
}
|
|
return m
|
|
}
|
|
func (m *Message) ActionHand(cmd *Command, key, sub string, arg ...string) *Message {
|
|
if action, ok := cmd.Actions[sub]; !m.WarnNotFoundIndex(!ok, sub, cmd.FileLines()) {
|
|
return m.Target()._action(m, cmd, key, sub, action, arg...)
|
|
}
|
|
return m
|
|
}
|
|
func (m *Message) _command(arg ...Any) *Message {
|
|
args, opts, cbs, _source := []Any{}, Map{}, kit.Value(nil), logs.FileLine(3)
|
|
for _, v := range arg {
|
|
switch val := v.(type) {
|
|
case nil:
|
|
case string:
|
|
args = append(args, v)
|
|
case Maps:
|
|
kit.For(val, func(k, v string) { opts[k] = v })
|
|
case Map:
|
|
kit.For(kit.KeyValue(nil, "", val), func(k string, v Any) { opts[k] = v })
|
|
case Option:
|
|
opts[val.Name] = val.Value
|
|
case logs.Meta:
|
|
kit.If(val.Key == "fileline", func() { _source = val.Value })
|
|
case func(int, Maps, []string):
|
|
defer func() { m.Table(val) }()
|
|
case func(Maps):
|
|
defer func() { m.Table(val) }()
|
|
default:
|
|
if reflect.TypeOf(val).Kind() == reflect.Func {
|
|
cbs = val
|
|
} else {
|
|
args = append(args, v)
|
|
}
|
|
}
|
|
}
|
|
if count := kit.Int(m.Option(MSG_COUNT, kit.Format(kit.Int(m.Option(MSG_COUNT))+1))); m.Warn(count > 3000, ErrTooDeepCount) {
|
|
panic(count)
|
|
}
|
|
list := kit.Simple(args...)
|
|
kit.If(len(list) == 0, func() { list = m.value(MSG_DETAIL) })
|
|
if len(list) == 0 {
|
|
return m
|
|
}
|
|
ok := false
|
|
run := func(msg *Message, ctx *Context, cmd *Command, key string, arg ...string) {
|
|
ok, msg._source = true, _source
|
|
key = kit.Slice(strings.Split(key, PT), -1)[0]
|
|
kit.If(cbs, func() { msg.OptionCB(key, cbs) })
|
|
kit.For(opts, func(k string, v Any) { msg.Option(k, v) })
|
|
m = ctx._command(msg, cmd, key, arg...)
|
|
}
|
|
if list[0] == "" {
|
|
run(m.Spawn(), m.target, m._cmd, m._key, list[1:]...)
|
|
} else {
|
|
_target, _key := m.target, m._key
|
|
m.Search(list[0], func(p *Context, s *Context, key string, cmd *Command) {
|
|
m.target, m._key = _target, _key
|
|
run(m.Spawn(s), s, cmd, key, list[1:]...)
|
|
})
|
|
}
|
|
m.WarnNotFoundIndex(!ok, kit.Format(list))
|
|
return m
|
|
}
|
|
func (c *Context) _command(m *Message, cmd *Command, key string, arg ...string) *Message {
|
|
if m._cmd, m._key = cmd, key; cmd == nil {
|
|
return m
|
|
}
|
|
if m.value(MSG_DETAIL, kit.Simple(m.ShortKey(), arg)...); cmd.Actions != nil {
|
|
if len(arg) > 1 && arg[0] == ACTION {
|
|
if h, ok := cmd.Actions[arg[1]]; ok {
|
|
return c._action(m, cmd, key, arg[1], h, arg[2:]...)
|
|
}
|
|
} else if len(arg) > 0 {
|
|
if h, ok := cmd.Actions[arg[0]]; ok {
|
|
return c._action(m, cmd, key, arg[0], h, arg[1:]...)
|
|
}
|
|
}
|
|
}
|
|
if len(arg) > 0 && arg[0] == ACTION && arg[1] == INPUTS {
|
|
return m
|
|
}
|
|
return m.CmdHand(cmd, key, arg...)
|
|
}
|
|
func (c *Context) _action(m *Message, cmd *Command, key string, sub string, h *Action, arg ...string) *Message {
|
|
if h.Hand == nil {
|
|
return m.Cmdy(kit.Split(kit.Select(sub, h.Name)), arg)
|
|
}
|
|
if m._cmd, m._key, m._sub = cmd, key, sub; len(h.List) > 0 && sub != SEARCH {
|
|
order := false
|
|
for i, v := range h.List {
|
|
name := kit.Format(kit.Value(v, NAME))
|
|
if i == 0 {
|
|
if len(arg) > 0 && arg[0] == name {
|
|
kit.For(arg, func(k, v string) { m.Option(k, v) })
|
|
} else {
|
|
order = true
|
|
}
|
|
}
|
|
kit.If(order && i < len(arg), func() { m.Option(name, arg[i]) })
|
|
if m.WarnNotValid(m.OptionDefault(name, kit.Format(kit.Value(v, VALUE))) == "" && kit.Value(v, "need") == "must", name, key, sub) {
|
|
return m
|
|
}
|
|
}
|
|
}
|
|
m._target = kit.Select(logs.FileLine(h.Hand), cmd.FileLines(), cmd.RawHand != nil)
|
|
m.Log(LOG_CMDS, "%s.%s %s %v", c.Name, key, sub, formatArg(arg...), logs.FileLineMeta(m._fileline()))
|
|
h.Hand(m, arg...)
|
|
return m
|
|
}
|
|
func formatArg(arg ...string) string {
|
|
return kit.Format("%d %v", len(arg), kit.ReplaceAll(kit.Format("%v", arg), "\r\n", "\\r\\n", "\t", "\\t", "\n", "\\n"))
|
|
}
|
|
func (c *Command) FileLines() string {
|
|
return kit.Join(kit.Slice(kit.Split(c.FileLine(), PS), -2), PS)
|
|
}
|
|
func (c *Command) FileLine() string {
|
|
if c == nil {
|
|
return ""
|
|
} else if c.RawHand != nil {
|
|
switch h := c.RawHand.(type) {
|
|
case string:
|
|
return h
|
|
default:
|
|
return logs.FileLines(c.RawHand)
|
|
}
|
|
} else if c.Hand != nil {
|
|
return logs.FileLines(c.Hand)
|
|
} else {
|
|
return ""
|
|
}
|
|
}
|