From ab05ddc76d69a43390059248d8725b526d07ff95 Mon Sep 17 00:00:00 2001 From: harveyshao Date: Sun, 24 Jul 2022 19:57:11 +0800 Subject: [PATCH] add hash.lock --- base/mdb/hash.go | 80 ++++++++++++++++++++++++++++++--------------- base/mdb/mdb.go | 3 ++ base/web/serve.go | 4 ++- core/code/xterm.go | 64 ++++++++++++++++++++++++------------ core/code/xterm.shy | 7 ++++ lock.go | 42 ++++++++++++++++++++++++ 6 files changed, 152 insertions(+), 48 deletions(-) create mode 100644 core/code/xterm.shy create mode 100644 lock.go diff --git a/base/mdb/hash.go b/base/mdb/hash.go index 856b7303..6007cb79 100644 --- a/base/mdb/hash.go +++ b/base/mdb/hash.go @@ -14,6 +14,8 @@ func _hash_fields(m *ice.Message) []string { return kit.Split(kit.Select("time,hash,type,name,text", m.OptionFields())) } func _hash_inputs(m *ice.Message, prefix, chain string, field, value string) { + defer m.RLock(prefix, chain)() + list := map[string]int{} m.Richs(prefix, chain, FOREACH, func(key string, val ice.Map) { if val = kit.GetMeta(val); kit.Format(val[COUNT]) != "" { @@ -29,6 +31,8 @@ func _hash_inputs(m *ice.Message, prefix, chain string, field, value string) { m.SortIntR(COUNT) } func _hash_insert(m *ice.Message, prefix, chain string, arg ...string) { + defer m.Lock(prefix, chain)() + if m.Option(ice.MSG_DOMAIN) != "" { m.Conf(prefix, kit.Keys(chain, kit.Keym(SHORT)), m.Conf(prefix, kit.Keym(SHORT))) } @@ -40,6 +44,8 @@ func _hash_insert(m *ice.Message, prefix, chain string, arg ...string) { m.Echo(m.Rich(prefix, chain, kit.Data(arg))) } func _hash_delete(m *ice.Message, prefix, chain, field, value string) { + defer m.Lock(prefix, chain)() + if field != HASH { field, value = HASH, kit.Select(kit.Hashs(value), m.Option(HASH)) } @@ -49,6 +55,8 @@ func _hash_delete(m *ice.Message, prefix, chain, field, value string) { }) } func _hash_modify(m *ice.Message, prefix, chain string, field, value string, arg ...string) { + defer m.Lock(prefix, chain)() + m.Richs(prefix, chain, value, func(key string, val ice.Map) { val = kit.GetMeta(val) m.Log_MODIFY(KEY, path.Join(prefix, chain), field, value, arg) @@ -61,6 +69,8 @@ func _hash_modify(m *ice.Message, prefix, chain string, field, value string, arg }) } func _hash_select(m *ice.Message, prefix, chain, field, value string) { + defer m.RLock(prefix, chain)() + if field == HASH && value == RANDOM { value = RANDOMS } @@ -83,7 +93,29 @@ func _hash_select(m *ice.Message, prefix, chain, field, value string) { m.SortTimeR(TIME) } } +func _hash_prunes(m *ice.Message, prefix, chain string, arg ...string) { + defer m.RLock(prefix, chain)() + + fields := _hash_fields(m) + m.Richs(prefix, chain, FOREACH, func(key string, val ice.Map) { + switch val = kit.GetMeta(val); cb := m.OptionCB(PRUNES).(type) { + case func(string, ice.Map) bool: + if !cb(key, val) { + return + } + default: + for i := 0; i < len(arg)-1; i += 2 { + if val[arg[i]] != arg[i+1] && kit.Value(val, arg[i]) != arg[i+1] { + return + } + } + } + m.Push(key, val, fields) + }) +} func _hash_export(m *ice.Message, prefix, chain, file string) { + defer m.Lock(prefix, chain)() + f, p, e := kit.Create(kit.Keys(file, JSON)) m.Assert(e) defer f.Close() @@ -97,6 +129,8 @@ func _hash_export(m *ice.Message, prefix, chain, file string) { m.Echo(p) } func _hash_import(m *ice.Message, prefix, chain, file string) { + defer m.Lock(prefix, chain)() + f, e := os.Open(kit.Keys(file, JSON)) if m.Warn(e) { return @@ -122,27 +156,6 @@ func _hash_import(m *ice.Message, prefix, chain, file string) { m.Log_IMPORT(KEY, path.Join(prefix, chain), COUNT, count) m.Echo("%d", count) } -func _hash_prunes(m *ice.Message, prefix, chain string, arg ...string) { - fields := _hash_fields(m) - m.Richs(prefix, chain, FOREACH, func(key string, val ice.Map) { - switch val = kit.GetMeta(val); cb := m.OptionCB(PRUNES).(type) { - case func(string, ice.Map) bool: - if !cb(key, val) { - return - } - default: - for i := 0; i < len(arg)-1; i += 2 { - if val[arg[i]] != arg[i+1] && kit.Value(val, arg[i]) != arg[i+1] { - return - } - } - } - m.Push(key, val, fields) - }) - m.Table(func(index int, value ice.Maps, head []string) { - _hash_delete(m, prefix, chain, HASH, value[HASH]) - }) -} const HASH = "hash" @@ -209,6 +222,12 @@ func HashAction(args ...ice.Any) ice.Actions { } m.Cmdy(MODIFY, m.PrefixKey(), "", HASH, m.OptionSimple(_key(m)), arg) }}, + SELECT: &ice.Action{Name: "select hash auto", Help: "列表", Hand: func(m *ice.Message, arg ...string) { + HashSelect(m, arg...) + }}, + PRUNES: &ice.Action{Name: "prunes before@date", Help: "清理", Hand: func(m *ice.Message, arg ...string) { + HashPrunes(m, nil) + }}, EXPORT: {Name: "export", Help: "导出", Hand: func(m *ice.Message, arg ...string) { m.OptionFields(m.Config(FIELD)) m.Cmdy(EXPORT, m.PrefixKey(), "", HASH, arg) @@ -216,12 +235,6 @@ func HashAction(args ...ice.Any) ice.Actions { IMPORT: {Name: "import", Help: "导入", Hand: func(m *ice.Message, arg ...string) { m.Cmdy(IMPORT, m.PrefixKey(), "", HASH, arg) }}, - PRUNES: &ice.Action{Name: "prunes before@date", Help: "清理", Hand: func(m *ice.Message, arg ...string) { - HashPrunes(m, nil) - }}, - SELECT: &ice.Action{Name: "select hash auto", Help: "列表", Hand: func(m *ice.Message, arg ...string) { - HashSelect(m, arg...) - }}, } } func HashActionStatus(args ...ice.Any) ice.Actions { @@ -233,12 +246,19 @@ func HashActionStatus(args ...ice.Any) ice.Actions { }} return list } + +func HashInputs(m *ice.Message, arg ...ice.Any) *ice.Message { + return m.Cmd(INPUTS, m.PrefixKey(), "", HASH, kit.Simple(arg...)) +} func HashCreate(m *ice.Message, arg ...ice.Any) *ice.Message { return m.Cmd(INSERT, m.PrefixKey(), "", HASH, kit.Simple(arg...)) } func HashRemove(m *ice.Message, arg ...ice.Any) *ice.Message { return m.Cmd(DELETE, m.PrefixKey(), "", HASH, kit.Simple(arg...)) } +func HashModify(m *ice.Message, arg ...ice.Any) *ice.Message { + return m.Cmd(MODIFY, m.PrefixKey(), "", HASH, kit.Simple(arg...)) +} func HashSelect(m *ice.Message, arg ...string) *ice.Message { m.Fields(len(arg), m.Config(FIELD)) m.Cmdy(SELECT, m.PrefixKey(), "", HASH, m.Config(SHORT), arg) @@ -266,3 +286,9 @@ func HashPrunes(m *ice.Message, cb func(ice.Maps) bool) *ice.Message { }) return m } +func HashExport(m *ice.Message, arg ...ice.Any) *ice.Message { + return m.Cmd(EXPORT, m.PrefixKey(), "", HASH, kit.Simple(arg...)) +} +func HashImport(m *ice.Message, arg ...ice.Any) *ice.Message { + return m.Cmd(IMPORT, m.PrefixKey(), "", HASH, kit.Simple(arg...)) +} diff --git a/base/mdb/mdb.go b/base/mdb/mdb.go index 753a3e99..62636cbe 100644 --- a/base/mdb/mdb.go +++ b/base/mdb/mdb.go @@ -211,6 +211,9 @@ var Index = &ice.Context{Name: MDB, Help: "数据模块", Commands: ice.Commands _list_prunes(m, arg[0], _domain_chain(m, kit.Keys(arg[1], kit.KeyHash(arg[3]))), arg[4:]...) case HASH: _hash_prunes(m, arg[0], _domain_chain(m, arg[1]), arg[3:]...) + m.Tables(func(value ice.Maps) { + _hash_delete(m, arg[0], _domain_chain(m, arg[1]), HASH, value[HASH]) + }) case LIST: _list_prunes(m, arg[0], _domain_chain(m, arg[1]), arg[3:]...) } diff --git a/base/web/serve.go b/base/web/serve.go index 50b84b97..c23058d4 100644 --- a/base/web/serve.go +++ b/base/web/serve.go @@ -393,7 +393,9 @@ func init() { }}, "/require/node_modules/": {Name: "/require/node_modules/", Help: "依赖库", Hand: func(m *ice.Message, arg ...string) { p := path.Join(ice.USR_VOLCANOS, "node_modules", path.Join(arg...)) - if _, e := os.Stat(p); e != nil { + if b, ok := ice.Info.Pack[p]; ok && len(b) > 0 { + + } else if _, e := os.Stat(p); e != nil { m.Cmd(cli.SYSTEM, "npm", "install", arg[0], kit.Dict(cli.CMD_DIR, ice.USR_VOLCANOS)) } m.RenderDownload(p) diff --git a/core/code/xterm.go b/core/code/xterm.go index 7f98dc94..bf74c9a9 100644 --- a/core/code/xterm.go +++ b/core/code/xterm.go @@ -4,11 +4,13 @@ import ( "encoding/base64" "os" "os/exec" + "strings" "sync" "time" pty "shylinux.com/x/creackpty" ice "shylinux.com/x/icebergs" + "shylinux.com/x/icebergs/base/ctx" "shylinux.com/x/icebergs/base/mdb" kit "shylinux.com/x/toolkits" ) @@ -18,8 +20,9 @@ const XTERM = "xterm" func init() { cache := sync.Map{} add := func(m *ice.Message, key string) string { - cmd := exec.Command("/bin/sh") + cmd := exec.Command(kit.Select("/bin/sh", m.Option(mdb.TYPE))) cmd.Env = append(os.Environ(), "TERM=xterm") + tty, err := pty.Start(cmd) m.Assert(err) cache.Store(key, tty) @@ -27,11 +30,11 @@ func init() { m.Go(func() { defer m.Cmd(m.PrefixKey(), mdb.PRUNES) defer cache.Delete(key) - buf := make([]byte, 1024) + buf := make([]byte, ice.MOD_BUFS) for { if n, e := tty.Read(buf); !m.Warn(e) { - m.Optionv(ice.MSG_OPTS, kit.Simple("hash")) m.Option(mdb.HASH, key) + m.Optionv(ice.MSG_OPTS, kit.Simple(mdb.HASH)) m.Option(ice.MSG_DAEMON, m.Conf(m.PrefixKey(), kit.Keys(mdb.HASH, key, mdb.META, mdb.TEXT))) m.PushNoticeGrow(kit.Format(kit.Dict(mdb.TYPE, "data", mdb.TEXT, base64.StdEncoding.EncodeToString(buf[:n])))) } else { @@ -58,34 +61,55 @@ func init() { } Index.MergeCommands(ice.Commands{ - XTERM: {Name: "xterm hash id auto prunes", Help: "终端", Actions: ice.MergeAction(ice.Actions{ + XTERM: {Name: "xterm hash id auto", Help: "终端", Actions: ice.MergeAction(ice.Actions{ + mdb.INPUTS: {Name: "inputs", Help: "补全", Hand: func(m *ice.Message, arg ...string) { + if mdb.HashInputs(m, arg); arg[0] == mdb.TYPE { + m.Push(mdb.TYPE, "/usr/bin/python") + m.Push(mdb.TYPE, "/usr/bin/node") + m.Push(mdb.TYPE, "/bin/bash") + m.Push(mdb.TYPE, "/bin/sh") + } + }}, mdb.CREATE: {Name: "create type name", Help: "创建", Hand: func(m *ice.Message, arg ...string) { if m.Option(mdb.TEXT, m.Option(ice.MSG_DAEMON)) != "" { - m.Echo(add(m, m.Cmdx(mdb.INSERT, m.PrefixKey(), "", mdb.HASH, m.OptionSimple("type,name,text")))) + m.Echo(add(m, mdb.HashCreate(m, m.OptionSimple("type,name,text")).Result())) } }}, + mdb.REMOVE: {Name: "remove", Help: "删除", Hand: func(m *ice.Message, arg ...string) { + if w, ok := cache.Load(m.Option(mdb.HASH)); ok { + if w, ok := w.(*os.File); ok { + w.Close() + } + cache.Delete(m.Option(mdb.HASH)) + } + mdb.HashRemove(m, m.OptionSimple(mdb.HASH)) + }}, + mdb.MODIFY: {Name: "modify", Help: "编辑", Hand: func(m *ice.Message, arg ...string) { + mdb.HashModify(m, m.OptionSimple(mdb.HASH), arg) + }}, + mdb.PRUNES: {Name: "prunes", Help: "清理", Hand: func(m *ice.Message, arg ...string) { + mdb.HashSelect(m).Tables(func(value ice.Maps) { + if _, ok := cache.Load(value[mdb.HASH]); !ok || kit.Time(m.Time())-kit.Time(value[mdb.TIME]) > int64(time.Hour) { + m.Cmd(m.PrefixKey(), mdb.REMOVE, kit.Dict(value)) + } + }) + }}, "resize": {Name: "resize", Help: "大小", Hand: func(m *ice.Message, arg ...string) { pty.Setsize(get(m, m.Option(mdb.HASH)), &pty.Winsize{Rows: uint16(kit.Int(m.Option("rows"))), Cols: uint16(kit.Int(m.Option("cols")))}) }}, + "rename": {Name: "rename", Help: "重命名", Hand: func(m *ice.Message, arg ...string) { + mdb.HashModify(m, m.OptionSimple(mdb.HASH), arg) + }}, "select": {Name: "select", Help: "连接", Hand: func(m *ice.Message, arg ...string) { - m.Cmd(mdb.MODIFY, m.PrefixKey(), "", mdb.HASH, m.OptionSimple(mdb.HASH), mdb.TEXT, m.Option(ice.MSG_DAEMON)) + mdb.HashModify(m, m.OptionSimple(mdb.HASH), mdb.TEXT, m.Option(ice.MSG_DAEMON)) + m.Cmd(m.PrefixKey(), "input", arg) }}, "input": {Name: "input", Help: "输入", Hand: func(m *ice.Message, arg ...string) { - m.Cmd(mdb.MODIFY, m.PrefixKey(), "", mdb.HASH, m.OptionSimple(mdb.HASH), mdb.TIME, m.Time()) - get(m, m.Option(mdb.HASH)).Write([]byte(arg[0])) + mdb.HashModify(m, m.OptionSimple(mdb.HASH), mdb.TIME, m.Time()) + get(m, m.Option(mdb.HASH)).Write([]byte(strings.Join(arg, ""))) }}, - mdb.PRUNES: {Name: "prunes", Help: "清理", Hand: func(m *ice.Message, arg ...string) { - m.Cmd(m.CommandKey()).Tables(func(value ice.Maps) { - if _, ok := cache.Load(value[mdb.HASH]); !ok || kit.Time(m.Time())-kit.Time(value[mdb.TIME]) > int64(time.Hour) { - m.Cmdy(mdb.DELETE, m.PrefixKey(), "", mdb.HASH, mdb.HASH, value[mdb.HASH]) - } - }) - }}, - }, mdb.ZoneAction(mdb.FIELD, "time,id,type,name,text")), Hand: func(m *ice.Message, arg ...string) { - if len(arg) == 0 { - m.OptionFields("time,hash,type,name,text") - } - mdb.ZoneSelect(m, kit.Slice(arg, 0, 2)...) + }, mdb.HashAction(mdb.FIELD, "time,hash,type,name,text,extra"), ctx.CmdAction()), Hand: func(m *ice.Message, arg ...string) { + mdb.HashSelect(m, kit.Slice(arg, 0, 1)...) m.DisplayLocal("") }}, }) diff --git a/core/code/xterm.shy b/core/code/xterm.shy new file mode 100644 index 00000000..d61e56c0 --- /dev/null +++ b/core/code/xterm.shy @@ -0,0 +1,7 @@ +section "xterm.js" +refer ` +官网 https://xtermjs.org/ +源码 https://github.com/xtermjs/xterm.js +文档 https://xtermjs.org/docs/api/terminal/classes/terminal/ +接口 https://github.com/xtermjs/xterm.js/blob/4.14.1/typings/xterm.d.ts#L619 +` diff --git a/lock.go b/lock.go new file mode 100644 index 00000000..db962d3b --- /dev/null +++ b/lock.go @@ -0,0 +1,42 @@ +package ice + +import ( + "sync" + + kit "shylinux.com/x/toolkits" +) + +var lock = map[string]*sync.RWMutex{} +var _lock = sync.Mutex{} + +func _get_lock(key string) (*sync.RWMutex, string) { + _lock.Lock() + defer _lock.Unlock() + + l, ok := lock[key] + if !ok { + l = &sync.RWMutex{} + lock[key] = l + } + return l, key +} +func (m *Message) Lock(arg ...Any) func() { + l, key := _get_lock(kit.Keys(arg...)) + m.Debug("before lock %v", key) + l.Lock() + m.Debug("success lock %v", key) + return func() { + l.Unlock() + m.Debug("success unlock %v", key) + } +} +func (m *Message) RLock(arg ...Any) func() { + l, key := _get_lock(kit.Keys(arg...)) + m.Debug("before rlock %v", key) + l.RLock() + m.Debug("success rlock %v", key) + return func() { + l.RUnlock() + m.Debug("success runlock %v", key) + } +}