1
0
mirror of https://shylinux.com/x/ContextOS synced 2025-04-25 16:58:06 +08:00

add m.Cmdp

This commit is contained in:
shaoying 2019-06-16 18:31:12 +08:00
parent 78df5d2ba3
commit b3486b5e37
12 changed files with 391 additions and 748 deletions

View File

@ -34,8 +34,10 @@ install() {
"armv7l") GOARCH=arm;;
esac
target=system && [ -n "$2" ] && target=$2
wget -O ${ctx_app} "$ctx_dev/publish/${ctx_app}?GOOS=$GOOS&GOARCH=$GOARCH" && chmod a+x ${ctx_app} \
&& ./${ctx_app} upgrade system && ${md5} ${ctx_app} \
&& ./${ctx_app} upgrade ${target} && ${md5} ${ctx_app} \
&& mv ${ctx_app} bin/${ctx_app}
}
main() {

View File

@ -1,11 +1,11 @@
~cli
config load var/tmp/runtime.json runtime
config load tmp/runtime.json runtime
~aaa
config load var/tmp/auth.json auth
config load tmp/auth.json auth
~ssh
config load var/tmp/cert.json work flow trust
config load tmp/cert.json work flow trust
~wiki
config load var/tmp/wiki.json wiki_visit
config load tmp/wiki.json wiki_visit
source etc/common.shy
~ssh
remote auto

View File

@ -130,6 +130,20 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
"daemon": &ctx.Config{Name: "daemon", Value: map[string]interface{}{}, Help: "守护任务"},
"action": &ctx.Config{Name: "action", Value: map[string]interface{}{}, Help: "交互任务"},
"project": &ctx.Config{Name: "project", Value: map[string]interface{}{
"github": "https://github.com/shylinux/context",
"env": map[string]interface{}{
"GOPATH": "https://github.com/shylinux/context",
},
"import": []interface{}{
"github.com/nsf/termbox-go",
"github.com/skip2/go-qrcode",
"github.com/go-sql-driver/mysql",
"github.com/gomarkdown/markdown",
"github.com/PuerkitoBio/goquery",
"github.com/go-cas/cas",
},
}, Help: "运行环境"},
"compile": &ctx.Config{Name: "compile", Value: map[string]interface{}{
"bench": "src/examples/app/bench.go",
"env": []interface{}{"GOPATH", "PATH"},
@ -216,6 +230,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
if name, e := os.Getwd(); e == nil {
_, file := path.Split(kit.Select(name, os.Getenv("PWD")))
m.Conf("runtime", "boot.pathname", file)
m.Conf("runtime", "boot.ctx_path", name)
}
return
}},
@ -501,6 +516,28 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
return
}},
"project": &ctx.Command{Name: "project", Help: "", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
switch arg[0] {
case "init":
m.Cmdp(time.Second, []string{"git init"}, []string{"cli.system", "git"}, [][]string{
[]string{"git", "init"},
[]string{"git", "remote", "add", kit.Select("origin", arg, 1), kit.Select(m.Conf("project", "github"), arg, 2)},
[]string{"git", "stash"},
[]string{"git", "pull"},
[]string{"git", "checkout", "-f", "master"},
[]string{"git", "stash", "pop"},
})
list := [][]string{}
m.Confm("project", "import", func(index int, value string) {
list = append(list, []string{value})
})
m.Cmdp(time.Second, []string{"go init"}, []string{"cli.system", "go", "get",
"cmd_env", "GOPATH", m.Conf("runtime", "boot.ctx_path")}, list)
}
return
}},
"compile": &ctx.Command{Name: "compile [OS [ARCH]]", Help: "解析脚本, script: 脚本文件, stdio: 命令终端, snippet: 代码片段", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
if len(arg) > 0 && arg[0] == "self" {
if m.Cmdy("cli.system", "go", "install", m.Cmdx("nfs.path", m.Conf("compile", "bench"))); m.Result(0) == "" {
@ -510,13 +547,14 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
}
if len(arg) > 0 && arg[0] == "all" {
m.Cmdy("cli.compile", "linux", "386")
m.Cmdy("cli.compile", "linux", "amd64")
m.Cmdy("cli.compile", "linux", "arm")
m.Cmdy("cli.compile", "windows", "386")
m.Cmdy("cli.compile", "windows", "amd64")
m.Cmdy("cli.compile", "darwin", "amd64")
m.Set("result").Table()
m.Cmdp(time.Second, []string{"go build"}, []string{"cli.compile"}, [][]string{
[]string{"linux", "386"},
[]string{"linux", "amd64"},
[]string{"linux", "arm"},
[]string{"windows", "386"},
[]string{"windows", "amd64"},
[]string{"darwin", "amd64"},
})
return
}
@ -547,7 +585,17 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
dir := m.Conf("publish", "path")
m.Assert(os.MkdirAll(dir, 0777))
if len(arg) == 0 {
list := [][]string{}
m.Confm("publish", "list", func(key string, value string) {
list = append(list, []string{key})
})
m.Cmdp(time.Second, []string{"copy"}, []string{"cli.publish"}, list)
return
}
for _, key := range arg {
value := m.Conf("publish", []string{"list", key})
p := m.Cmdx("nfs.path", value)
if s, e := os.Stat(p); e == nil {
if s.IsDir() {
@ -555,18 +603,24 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
} else {
m.Cmd("nfs.copy", path.Join(dir, key), p)
}
return
}
})
m.Cmdy("nfs.dir", dir, "dir_sort", "time", "time_r")
}
// m.Cmdy("nfs.dir", dir, "dir_sort", "time", "time_r")
return
}},
"upgrade": &ctx.Command{Name: "upgrade bench|system|extend|plugin|portal|client|script", Help: "服务升级", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
"upgrade": &ctx.Command{Name: "upgrade bench|system|extend|plugin|portal|client|script|project", Help: "服务升级", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
if len(arg) == 0 {
m.Cmdy("ctx.config", "upgrade")
return
}
if len(arg) > 0 && arg[0] == "project" {
m.Cmd("cli.project", "init")
m.Cmd("cli.compile", "all")
m.Cmd("cli.publish")
return
}
restart := false
for _, link := range kit.View([]string{arg[0]}, m.Confm("upgrade")) {

View File

@ -1230,6 +1230,14 @@ func (m *Message) Log(action string, str string, arg ...interface{}) *Message {
return m
}
func (m *Message) Show(args ...interface{}) *Message {
if m.Option("cli.modal") == "action" {
fmt.Printf(kit.Format(args...))
} else if kit.STDIO != nil {
kit.STDIO.Show(args...)
}
return m
}
func (m *Message) Assert(e interface{}, msg ...string) bool {
switch v := e.(type) {
case nil:
@ -1541,6 +1549,19 @@ func (m *Message) Free(cbs ...func(msg *Message) (done bool)) *Message {
return m
}
func (m *Message) Cmdp(t time.Duration, head []string, prefix []string, suffix [][]string) *Message {
if head != nil && len(head) > 0 {
m.Show(strings.Join(head, " "), "...\n")
}
for i, v := range suffix {
m.Show(fmt.Sprintf("%v/%v %v...\n", i+1, len(suffix), v))
m.Cmd(prefix, v)
time.Sleep(t)
}
m.Show("\n")
return m
}
func (m *Message) Cmdm(args ...interface{}) *Message {
m.Log("info", "current: %v", m.Magic("session", "current"))

View File

@ -151,7 +151,9 @@ var Index = &ctx.Context{Name: "log", Help: "日志中心",
"search": map[string]interface{}{"value": []interface{}{"debug"}},
"call": map[string]interface{}{"value": []interface{}{"debug"}},
"back": map[string]interface{}{"value": []interface{}{"debug"}},
"send": map[string]interface{}{"value": []interface{}{"debug"}},
"recv": map[string]interface{}{"value": []interface{}{"debug"}},
"bench": map[string]interface{}{"value": []interface{}{"bench"}},
"begin": map[string]interface{}{"value": []interface{}{"bench", "red"}},

View File

@ -784,6 +784,10 @@ func (nfs *NFS) printf(arg ...interface{}) *NFS {
}
return nfs
}
func (nfs *NFS) Show(arg ...interface{}) bool {
nfs.prompt(arg...)
return true
}
func (nfs *NFS) Recv(line string) (field string, value string) {
m := nfs.Context.Message()
@ -885,6 +889,7 @@ func (nfs *NFS) Start(m *ctx.Message, arg ...string) bool {
// 终端控制
if nfs.in = m.Optionv("in").(*os.File); m.Has("out") {
if nfs.out = m.Optionv("out").(*os.File); m.Cap("goos") != "windows" && !m.Options("daemon") {
kit.STDIO = nfs
nfs.Term(m, "init")
defer nfs.Term(m, "exit")
}

View File

@ -768,6 +768,15 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心",
return
}},
"brow": &ctx.Command{Name: "brow url", Help: "浏览网页", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
if len(arg) == 0 {
m.Cmd("tcp.ifconfig").Table(func(index int, value map[string]string) {
m.Append("index", index)
m.Append("site", fmt.Sprintf("%s://%s%s", m.Conf("serve", "protocol"), value["ip"], m.Conf("runtime", "boot.web_port")))
})
m.Table()
return
}
switch runtime.GOOS {
case "windows":
m.Cmd("cli.system", "explorer", arg[0])
@ -1113,6 +1122,22 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心",
m.Cmdy("web.get", "which", fields[2], "method", fields[3], strings.Join(fields, "/"))
return
}},
"/publish/": &ctx.Command{Name: "/publish/", Help: "下载文件", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
key = strings.TrimPrefix(key, "/publish/")
if strings.HasSuffix(key, "bench") {
key = key + "." + m.Option("GOOS") + "." + m.Option("GOARCH")
}
key = strings.Replace(key, ".", "_", -1)
p := m.Cmdx("nfs.path", path.Join(m.Conf("publish", "path"), key))
if p == "" {
p = m.Cmdx("nfs.path", m.Conf("publish", []string{"list", key}))
}
m.Log("info", "publish %s %s", kit.Hashs(p), p)
http.ServeFile(m.Optionv("response").(http.ResponseWriter), m.Optionv("request").(*http.Request), p)
return
}},
"/shadow": &ctx.Command{Name: "/shadow", Help: "暗网", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
m.Confm("runtime", "node.port", func(index int, value string) {
m.Add("append", "ports", value)
@ -1149,22 +1174,6 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心",
}
return
}},
"/publish/": &ctx.Command{Name: "/publish/", Help: "下载文件", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
key = strings.TrimPrefix(key, "/publish/")
if strings.HasSuffix(key, "bench") {
key = key + "." + m.Option("GOOS") + "." + m.Option("GOARCH")
}
key = strings.Replace(key, ".", "_", -1)
p := m.Cmdx("nfs.path", path.Join(m.Conf("publish", "path"), key))
if p == "" {
p = m.Cmdx("nfs.path", m.Conf("publish", []string{"list", key}))
}
m.Log("info", "publish %s %s", kit.Hashs(p), p)
http.ServeFile(m.Optionv("response").(http.ResponseWriter), m.Optionv("request").(*http.Request), p)
return
}},
},
}

View File

@ -22,7 +22,8 @@ var Index = &ctx.Context{Name: "code", Help: "代码中心",
map[string]interface{}{"name": "viewport", "content": "width=device-width, initial-scale=0.7, user-scalable=no"},
}, "favicon": "favicon.ico", "styles": []interface{}{"example.css", "code.css"}},
map[string]interface{}{"componet_name": "login", "componet_help": "login", "componet_tmpl": "componet",
map[string]interface{}{"componet_name": "login", "componet_help": "login",
"componet_tmpl": "componet", "componet_init": "initLogin",
"componet_ctx": "aaa", "componet_cmd": "auth", "componet_args": []interface{}{"@sessid", "ship", "username", "@username", "password", "@password"}, "inputs": []interface{}{
map[string]interface{}{"type": "text", "name": "username", "value": "", "label": "username"},
map[string]interface{}{"type": "password", "name": "password", "value": "", "label": "password"},

View File

@ -16,6 +16,12 @@ import (
"time"
)
type TERM interface {
Show(...interface{}) bool
}
var STDIO TERM
var DisableLog = false
var EnableDebug = false

View File

@ -1,609 +1,4 @@
var page = Page({
initComList: function(page, field, option, append, result) {
return
},
initScheduleText: function(page, field, option, append, result) {
option.ondaemon = function(msg) {
page.reload()
}
},
initScheduleList: function(page, field, option) {
ctx.Runs(page, option)
},
initFlashText: function(page, field, option, append, result) {
option.ondaemon = function(msg) {
page.reload()
}
},
initFlashList: function(page, field, option) {
option.dataset.flash_index = ctx.Search("flash_index")
option.ondaemon = function(msg) {
page.showFlashList(msg, field, option)
}
ctx.Runs(page, option)
},
showFlashList: function(msg, field, option) {
var page = this
var result = field.querySelector("div.result")
result.innerHTML = ""
ctx.Table(msg, function(tip) {
var ui = kit.AppendChild(result, [{"list": [
{"text": [tip.text, "div", "detail"]},
{"code": [tip.code, "result", "result"]},
{"view": ["action"], "list": [
{"button": ["查看详情", function(event) {
ctx.Search("flash_index", tip.index)
}]},
{"button": ["执行代码", function(event) {
tip.code && ctx.Run(page, option.dataset, [tip.index, "run"], function(msg) {
ui.output.innerText = msg.result
})
}]},
{"button": ["清空结果", function(event) {
ui.output.innerText = ""
}]},
]},
{"code": [tip.output, "output", "output"]},
]}])
})
},
initKitList: function(page, field, option, append, result) {
var ui = kit.AppendChild(field, [
{"styles": {
"fieldset.KitList": {
"top": conf.toolkit_view.top, "left": conf.toolkit_view.left,
},
"fieldset.KitList:hover, fieldset.KitList.max": {
"width": conf.toolkit_view.width, "height": conf.toolkit_view.height,
},
}},
{"type": "ul", "list": [
{"fork": ["粘贴板", [
{"leaf": ["+ 保存粘贴板(Ctrl+S)", function(event) {
console.log("save_txt")
}]},
{"leaf": ["+ 添加粘贴板(Ctrl+Y)", function(event) {
console.log("create_txt")
}]},
{"leaf": ["+ 快捷粘贴板(Ctrl+P)", function(event) {
console.log("quick_txt")
}]},
]]},
{"fork": ["命令行", [
{"leaf": ["+ 折叠命令行(Ctrl+Z)", function(event, target) {
target.className = page.conf.show_result? "": "stick"
page.showResult(page)
}]},
{"leaf": ["+ 添加命令行(Ctrl+M)", function(event) {
page.addCmdList("cmd", page.conf.ncommand++)
}]},
]]},
{"fork": ["工作流", [
{"leaf": ["+ 刷新工作流(Ctrl+R)", function(event) {
console.log("refresh_fly")
}]},
{"leaf": ["+ 添加工作流(Ctrl+T)", function(event) {
console.log("create_fly")
}]},
{"leaf": ["+ 命名工作流", function(event) {
console.log("rename_fly")
}]},
{"leaf": ["+ 删除工作流", function(event) {
console.log("remove_fly")
}]},
]]},
]},
])
/*
<li><div>命令行</div>
<ul class="cmd">
{{range $name, $cmd := conf . "toolkit"}}
<li>{{$name}} <input type="text" data-cmd="{{$name}}" onkeyup="onaction(event, 'toolkit')"><label class="result"></label></li>
{{end}}
<li class="stick" data-action="shrink_cmd">+ 折叠命令行(Ctrl+Z)</li>
<li data-action="create_cmd">+ 添加命令行(Ctrl+M)</li>
{{range $index, $cmd := index $bench_data "commands"}}
<li class="cmd{{$index}}" data-cmd="{{$index}}">{{index $cmd "now"|option}} {{$index}}: {{index $cmd "cmd"|option}}</li>
{{end}}
</ul>
</li>
<li><div>工作流</div>
<ul class="fly">
<li data-action="refresh_fly">+ 刷新工作流(Ctrl+R)</li>
<li data-action="create_fly">+ 添加工作流(Ctrl+T)</li>
{{range $key, $item := work .}}
<li data-key="{{$key}}">{{index $item "create_time"}} {{index $item "data" "name"}}({{slice $key 0 6}})</li>
{{end}}
<li data-action="rename_fly">+ 命名工作流</li>
<li data-action="remove_fly">+ 删除工作流</li>
</ul>
</li>
*/
return
text = JSON.parse(bench_data.clipstack || "[]")
for (var i = 0; i < text.length; i++) {
copy_to_clipboard(text[i])
}
bench_data.board = bench_data.board || {}
document.querySelectorAll("div.workflow").forEach(function(workflow) {
// 移动面板
workflow.style.left = context.Cookie("toolkit_left")
workflow.style.top = context.Cookie("toolkit_top")
var moving = false, left0 = 0, top0 = 0, x0 = 0, y0 = 0
workflow.onclick = function(event) {
if (event.target != workflow) {
return
}
moving = !moving
if (moving) {
left0 = workflow.offsetLeft
top0 = workflow.offsetTop
x0 = event.clientX
y0 = event.clientY
}
}
workflow.onmousemove = function(event) {
if (moving) {
workflow.style.left = (left0+(event.clientX-x0))+"px"
workflow.style.top = (top0+(event.clientY-y0))+"px"
context.Cookie("toolkit_left", workflow.style.left)
context.Cookie("toolkit_top", workflow.style.top)
}
}
// 固定面板
if (context.Cookie("toolkit_class")) {
workflow.className = context.Cookie("toolkit_class")
}
var head = workflow.querySelector("div")
head.onclick = function(event) {
head.dataset["show"] = !right(head.dataset["show"])
workflow.className = right(head.dataset["show"])? "workflow max": "workflow"
context.Cookie("toolkit_class", workflow.className)
}
// 折叠目录
var toolkit = workflow.querySelector("ul.toolkit")
toolkit.querySelectorAll("li>div").forEach(function(menu) {
menu.onclick = function(event) {
menu.dataset["hide"] = !right(menu.dataset["hide"])
menu.nextElementSibling.style.display = right(menu.dataset["hide"])? "none": ""
}
})
// 事件
toolkit.querySelectorAll("li>ul>li").forEach(function(item) {
// if (bench_data.board["key"] == item.dataset["key"]) {
// // item.className = "stick"
// }
item.onclick = function(event) {
var target = event.target
var data = item.dataset
switch (data["action"]) {
case "quick_txt":
code.quick_txt = !code.quick_txt
target.className= code.quick_txt? "stick": ""
break
case "copy_txt":
if (event.altKey) {
target.parentElement.removeChild(target)
return
}
if (event.shiftKey) {
var cmd = document.querySelector("form.option.cmd"+code.current_cmd+" input[name=cmd]")
cmd && (cmd.value += " "+text)
return
}
copy_to_clipboard(data["text"], true)
break
case "save_txt":
save_clipboard(item)
return
case "create_txt":
var text = prompt("text")
text && copy_to_clipboard(text)
return
case "refresh_fly":
location.reload()
return
case "create_fly":
context.Command(["sess", "bench", "create"], function(msg) {
context.Search("bench", msg.result[0])
})
return
case "rename_fly":
context.Command(["work", context.Search("bench"), "rename", prompt("name")], function() {
location.reload()
})
return
case "remove_fly":
var b = ""
document.querySelectorAll("div.workflow>ul.toolkit>li>ul.fly>li[data-key]").forEach(function(item){
if (!b && item.dataset["key"] != context.Search("bench")) {
b = item.dataset["key"]
}
})
context.Search("bench", b)
context.Command(["work", context.Search("bench"), "delete"])
return
}
// 切换工作流
if (data["key"] && data["key"] != context.Search("bench")) {
context.Search("bench", data["key"])
return
}
// 切换命令行
var cmd = document.querySelector("form.option.cmd"+data["cmd"]+" input[name=cmd]")
cmd && cmd.focus()
}
})
})
return
},
initDirList: function(page, field, option, append, result) {
var history = []
function change(value) {
return page.setCurrent(page, option, "dir", value)
}
function brow(value, dir, event) {
page.setCurrent(page, option, "dir", value)
page.setCurrent(page, option, "dir", dir)
}
return {
"button": ["root", "back"], "action": function(value) {
switch (value) {
case "back": history.length > -1 && change(history.pop() || "/"); break
case "root": change("/"); break
}
},
"table": {"filename": function(value, key, row, index, event) {
var dir = option.dir.value
var file = dir + ((dir && !dir.endsWith("/"))? "/": "") + value
file.endsWith("/")? history.push(change(file)): brow(file, dir, event)
}},
}
},
initPodList: function(page, field, option, append, result) {
return {"button": ["local"], "action": function(value) {
value == "local" && (value = "''")
page.setCurrent(page, option, "pod", value)
}, "table": {"key": function(value) {
page.setCurrent(page, option, "pod", value)
}}}
},
initCtxList: function(page, field, option, append, result) {
return {"button": ["ctx", "shy", "web", "mdb"], "action": function(value) {
page.setCurrent(page, option, "ctx", value)
}, "table": {"names": function(value) {
page.setCurrent(page, option, "ctx", value)
}}}
},
setCurrent: function(page, option, type, value) {
option[type].value = ctx.Current(type, value)
page.History.add(type, value)
ctx.Runs(page, option)
return value
},
initCmdList: function(page, field, option, append, result) {
option.dataset["componet_name_alias"] = "cmd"
option.dataset["componet_name_order"] = 0
var cmd = option.querySelector("input[name=cmd]")
cmd.onkeyup = function(event) {
page.onCmdList(event, cmd, "input", field, option, append, result)
}
var action = conf.bench_data.action
action && action["cmd"] && page.runCmdList(page, option, cmd, action["cmd"].cmd[1])
var max = 0
for (var k in action) {
var order = parseInt(action[k].order)
order > max && (max = order)
}
for (var i = 1; i <= max; i++) {
var ui = page.addCmdList("cmd", i)
action["cmd"+i] && page.runCmdList(page, ui.option, ui.cmd, action["cmd"+i].cmd[1])
}
page.conf.ncommand = i
return
},
runCmdList: function(page, option, target, value) {
target.value = value
target.dataset.history_last = kit.History.add("cmd", target.value)
ctx.Runs(page, option)
},
getCmdList: function(input, step, cmd) {
var history = kit.History.get("cmd")
var length = history.length
var last = (parseInt(input.dataset["history_last"]||length)+step+length)%length
if (0 <= last && last < length) {
input.dataset["history_last"] = last
cmd = history[last].data
}
return cmd
},
addCmdList: function(name, order) {
var page = this
var alias = name+order
var ui = kit.AppendChild(document.body, [{"view": ["CmdList", "fieldset"], "list": [
{"text": [alias, "legend"]},
{"view": ["option "+alias, "form", "", "option"],
"data": {"dataset": {
"componet_group": "index", "componet_name": name, "componet_name_alias": alias, "componet_name_order": order,
}},
"list": [
{"type": "input", "data": {"style": {"display": "none"}}},
{"name": "cmd", "type": "input", "data": {"name": "cmd", "className": "cmd", "onkeyup": function(event) {
page.onCmdList(event, ui.cmd, "input", ui.field, ui.option, ui.append, ui.result)
}}},
]
},
{"view": ["append "+alias, "table", "", "append"]},
{"code": ["", "result", "result "+alias]},
]}])
kit.OrderForm(page, ui.field, ui.option, ui.append, ui.result)
kit.OrderTable(ui.append)
kit.OrderCode(ui.result)
ui.cmd.focus()
return ui
},
delCmdList: function(name, order) {
var option = document.querySelector("form.option.cmd"+order)
option && document.body.removeChild(option.parentElement)
for (;order < page.conf.ncommand; order++) {
var input = document.querySelector("form.option.cmd"+order+" input[name=cmd]")
if (input) {
input.focus()
return
}
}
for (;order >= 0; order--) {
var input = document.querySelector("form.option.cmd"+(order? order: "")+" input[name=cmd]")
page.conf.ncommand = order+1
if (input) {
input.focus()
return
}
}
},
onCmdList: function(event, target, action, field, option, append, result) {
var page = this
var order = option.dataset.componet_name_order
var prev_order = (parseInt(order)-1+page.conf.ncommand)%page.conf.ncommand||""
var next_order = (parseInt(order)+1)%page.conf.ncommand||""
switch (action) {
case "input":
kit.History.add("key", (event.ctrlKey? "Control+": "")+(event.shiftKey? "Shift+": "")+event.key)
if (event.key == "Escape") {
target.blur()
} else if (event.key == "Enter") {
page.runCmdList(page, option, target, target.value)
} else if (event.ctrlKey) {
switch (event.key) {
case "0":
var pre_pre = document.querySelector("code.result.cmd"+(event.shiftKey? next_order: prev_order)+" pre")
pre_pre && (target.value += pre_pre.innerText)
break
case "1":
case "2":
case "3":
case "4":
case "5":
case "6":
case "7":
case "8":
case "9":
if (code.quick_txt) {
var item = document.querySelectorAll("div.workflow>ul>li>ul.txt>li[data-text]")
target.value += item[parseInt(event.key)-1].dataset["text"]
} else {
var item = document.querySelectorAll("table.append.cmd"+(event.shiftKey? next_order: prev_order)+" td")
target.value += item[parseInt(event.key)-1].innerText
}
break
case "p":
target.value = page.getCmdList(target, -1, target.value)
break
case "n":
target.value = page.getCmdList(target, 1, target.value)
break
case "g":
var value = target.value.substr(0, target.selectionStart)
var last = parseInt(target.dataset.search_last || kit.History.get("cmd").length-1)
for (var i = last; i >= 0; i--) {
var cmd = kit.History.get("cmd", i).data
if (cmd.startsWith(value)) {
target.value = cmd
target.dataset.search_last = i-1
target.setSelectionRange(value.length, cmd.length)
break
}
}
target.dataset.search_last = ""
break
case "y":
case "v":
case "s":
case "t":
break
case "a":
case "e":
case "f":
case "b":
case "h":
case "d":
break
case "k":
kit.DelText(target, target.selectionStart)
break
case "u":
kit.DelText(target, 0, target.selectionEnd)
break
case "w":
var start = target.selectionStart-2
var end = target.selectionEnd-1
for (var i = start; i >= 0; i--) {
if (target.value[end] == " " && target.value[i] != " ") {
break
}
if (target.value[end] != " " && target.value[i] == " ") {
break
}
}
kit.DelText(target, i+1, end-i)
break
case "c":
append.innerHTML = ""
result.innerHTML = ""
break
case "r":
append.innerHTML = ""
result.innerHTML = ""
case "j":
page.runCmdList(page, option, target, target.value)
break
case "l":
window.scrollTo(0, option.parentElement.offsetTop)
break
case "m":
page.addCmdList("cmd", page.conf.ncommand++)
break
case "i":
var input = document.querySelector("form.option.cmd"+next_order+" input[name=cmd]")
input && input.focus()
break
case "o":
var input = document.querySelector("form.option.cmd"+prev_order+" input[name=cmd]")
input && input.focus()
break
case "x":
result.style.height = result.style.height? "": page.conf.hide_height
break
case "z":
result.style.height = result.style.height? "": page.conf.show_height
break
case "q":
page.delCmdList("cmd", order)
break
default:
return
}
} else {
if (kit.HitText(target, "jk")) {
kit.DelText(target, target.selectionStart-2, 2)
target.blur()
}
}
event.stopPropagation()
}
},
onaction: function(event, target, action) {
var page = this
switch (action) {
case "scroll":
break
case "keymap":
if (event.key == "Escape") {
} else if (event.key == "Enter") {
} else if (event.ctrlKey) {
switch (event.key) {
case "m":
page.addCmdList("cmd", page.conf.ncommand++)
break
case "z":
page.showResult(page)
break
case "0":
case "1":
case "2":
case "3":
case "4":
case "5":
case "6":
case "7":
case "8":
case "9":
document.querySelector("form.option.cmd"+(event.key||"")+" input[name=cmd]").focus()
break
}
}
}
},
showResult: function(page, type) {
page.conf.show_result = !page.conf.show_result
document.querySelectorAll("body>fieldset>code.result>pre").forEach(function(result) {
result.style.height = (page.conf.show_result || result.innerText=="")? "": page.conf.show_height
})
},
init: function(exp) {
var page = this
var body = document.body
body.onkeyup = function(event) {
page.onaction(event, body, "keymap")
}
document.querySelectorAll("body>fieldset").forEach(function(field) {
var option = field.querySelector("form.option")
var append = field.querySelector("table.append")
var result = field.querySelector("code.result pre")
kit.OrderForm(page, field, option, append, result)
append && kit.OrderTable(append)
result && kit.OrderCode(result)
var init = page[field.dataset.init]
if (typeof init == "function") {
var conf = init(page, field, option, append, result)
if (conf && conf["button"]) {
var buttons = []
conf.button.forEach(function(value, index) {
buttons.push({"button": [value, function(event) {
typeof conf["action"] == "function" && conf["action"](value, event)
}]})
})
kit.InsertChild(field, append, "div", buttons)
}
if (conf && conf["table"]) {
option.daemon_action = conf["table"]
ctx.Runs(page, option)
}
}
})
},
conf: {
scroll_x: 50,
scroll_y: 50,
ncommand: 1,
show_result: true,
show_height: "30px",
hide_height: "14px",
quick_txt: false,
page({
init: function() {
},
})

View File

@ -5,7 +5,7 @@ ctx = context = {
option[k] = dataset[k].split(",")
}
this.GET("", option, function(msg) {
msg = msg && msg[0]
msg[0] && (msg = msg[0])
// msg && (msg.__proto__ = (page || {}))
msg.Result = msg.result? msg.result.join(""): ""
msg.Results = function() {

View File

@ -2,26 +2,271 @@
context是一种新的应用框架通过模块化、集群化、自动化实现软件的快速开发快速共享快速使用。
### 下载安装
在Linux或Mac上可以直接用脚本下载在Windows上可以先安装[GitBash](https://www.git-scm.com/download/),然后下载。
## 下载安装
在Linux或Mac上可以直接用脚本下载
在Windows上可以先安装[GitBash](https://www.git-scm.com/download/)然后在GitBash中执行命令下载。
```
$ mkdir context && cd context
$ curl https://shylinux.com/publish/boot.sh | bash -s install
$ curl https://shylinux.com/publish/boot.sh | bash -s install context
```
### 使用方式
install后面的参数context就是指定的下载目录
进入下载目录,可以看到的有六个文件。
在bin目录下就是各种执行文件
- bin/benchcontext的执行程序
- bin/boot.shcontext的启动脚本
- bin/node.sh简化版的启动脚本
context内部实现了语法解析通过自定义的脚本语言实现功能的灵活控制。
在etc目录下就是context执行过程中用到的脚本。
- etc/init.shy启动时加载的脚本
- etc/exit.shy结束时运行的脚本
- etc/common.shyinit.shy调用到的脚本
## 使用方式
context内部实现了很多功能模块每个模块下有很多命令每条命令就是一种应用。
#### 命令模式
context的使用方式有很多种
- 可以直接调用像Shell一样去解析一条命令
- 可以启动cli服务像MySQL一样交互式使用格式化命令
- 可以启动web服务像LabView一样可以自定义各种图形界面
- 可以自动组网,将任意台设备组合在一起,实现分布式应用
- 可以自动建群,在群聊场景中,实现多用户、多会话、多任务、多设备的使用
### 命令模式
如果只是使用一条命令,或是写在脚本文件中,可以使用这种方式。
例如dir命令就是查看目录
```
$ bin/bench dir
time size line filename
2019-06-16 10:35:18 324 11 common.shy
2019-06-16 10:35:18 201 9 exit.shy
2019-06-16 10:35:18 261 13 init.shy
```
还可以加更多参数dir_deep递归查询目录dir_type文件类型过滤dir_sort输出表排序。
```
$ bin/bench dir ../ dir_deep dir_type file dir_sort line int_r
time size line filename
2019-06-16 10:22:52 13256968 91314 bench
2019-06-16 11:10:16 1535 66 boot.sh
2019-06-16 11:10:16 613 31 node.sh
2019-06-16 11:10:16 261 13 init.shy
2019-06-16 11:10:16 324 11 common.shy
2019-06-16 11:10:16 201 9 exit.shy
```
#### 交互模式
### 交互模式
启动服务,可以提供更丰富的命令与环境。
```
$ bin/bench
0[11:35:46]ssh> dir
time size line filename
2019-06-16 11:35:06 160 3 log/
2019-06-16 11:35:06 96 1 run/
2019-06-16 11:35:44 192 4 tmp/
1[11:35:46]ssh>
```
如果集中管理,命令越多,系统只会越复杂,学习成本越高,使用越低效,开发越困难。
所以通过模块化,分而治之,更高效的管理丰富的命令。
context命令就是用来管理模块没有参数时直接查看当前模块的信息。
如下,第二行是当前模块,第一行是当前模块的父模块,其它行都是当前模块的子模块。
```
1[11:39:01]ssh> context
names ctx msg status stream helps
ctx 0 start shy 模块中心
ssh ctx 10 begin ctx.nfs.file3 集群中心
```
context第一个参数可以指定当前模块
如下切换到nfs模块然后查看各种IO模块
切换到ctx根模块查看所有模块。
```
2[11:43:57]ssh> context nfs
3[11:43:58]nfs> context
names ctx msg status stream helps
ctx 0 start shy 模块中心
nfs ctx 9 begin 存储中心
stdio nfs 1174 start stdio scan stdio
4[11:44:22]ssh> context ctx
5[11:45:17]ctx> context
names ctx msg status stream helps
ctx 0 start shy 模块中心
aaa ctx 3 begin 认证中心
cli ctx 4 begin 管理中心
gdb ctx 232 start 调试中心
lex ctx 6 begin 词法中心
log ctx 31 start bench 日志中心
mdb ctx 8 begin 数据中心
nfs ctx 9 begin 存储中心
ssh ctx 10 begin 集群中心
tcp ctx 11 begin 网络中心
web ctx 1094 start :9094 应用中心
yac ctx 13 begin 35,14,23 语法中心
shy cli 1171 start engine shell
matrix1 lex 34 start 76,28,2 matrix
stdio nfs 1174 start stdio scan stdio
chat web 14 begin 会议中心
code web 15 begin 代码中心
wiki web 16 begin 文档中心
engine yac 1173 start stdio parse
```
command命令就是用来管理当前模块的命令
```
17[11:52:02]nfs> context nfs
17[11:52:02]nfs> command
key name
_init _init
action action cmd
copy copy to from
dir dir [path [fields...]]
export export filename
git git sum
hash hash filename
import import filename [index]
json json str
load load file [buf_size [pos]]
open open file
path path filename
printf printf arg
prompt prompt arg
pwd pwd [all] | [[index] path]
read read [buf_size [pos]]
remote remote listen|dial args...
save save file string...
scan scan file name
send send [file] args...
temp temp data
term term action args...
trash trash file
write write string [pos]
```
help子命令查看命令帮助信息。
```
18[11:59:19]nfs> command help dir
dir: dir [path [fields...]]
查看目录, path: 路径, fields...: 查询字段, time|type|full|path|tree|filename|size|line|hash
dir_deep: 递归查询
dir_type both|file|dir|all: 文件类型
dir_reg reg: 正则表达式
dir_sort field order: 排序
```
### 集群模式
context提供自动化集群的功能可以自动组网、自动认证。从而快速实现多台设备的协同工作。
#### 启动服务节点
```
$ bin/boot.sh
0[11:35:12]ssh>
```
#### 启动工作节点
新打开一个终端启动工作节点执行remote命令查看上级节点
```
$ bin/boot.sh create app/demo
0[15:15:30]ssh> remote
key type module create_time
mac master ctx.nfs.file3 2019-06-16 15:15:23
```
回到服务节点终端执行remote命令可以查看到所有远程节点。
```
2[15:15:31]ssh> remote
key type module create_time
com master ctx.nfs.file4 2019-06-16 14:25:10
demo worker ctx.nfs.file7 2019-06-16 15:15:23
```
默认配置中,子节点信任父,所以父节点可以调用子节点的命令。还有更复杂的认证机制,可以灵活配置。
远程命令和本地命令一样没有任何区别。如下调用demo节点的pwd命令。还支持更复杂的多节点命令可以更快速的同时管理多台设备。
```
2[15:15:31]ssh> remote demo pwd
/Users/shaoying/context/app/demo/var
```
#### 启动分机节点
在服务节点的终端,查看服务地址
```
3[15:49:00]ssh> web.brow
index site
0 http://192.168.199.139:9094
```
同样在另一台设备上下载context然后启动服务节点。
通过环境变量ctx_dev指定上级节点。
```
$ ctx_dev="http://192.168.199.139:9094" bin/boot.sh
0[15:49:00]ssh> remote
key type module create_time
mac master ctx.nfs.file3 2019-06-16 15:15:23
```
回到服务节点终端执行remote命令可以查看到新添加了一个服务子节点。
```
2[15:15:31]ssh> remote
key type module create_time
com master ctx.nfs.file4 2019-06-16 14:25:10
demo worker ctx.nfs.file7 2019-06-16 15:15:23
sub server ctx.nfs.file8 2019-06-16 16:15:23
```
同样可以远程调用命令。
```
2[15:15:31]ssh> remote sub pwd
/Users/shaoying/context/app/sub/var
```
### 开源模式
context是一种通用的应用框架可以快速开发出各种工具。
```
2[15:15:31]ssh> project init
done
2[15:15:31]ssh> project init
```
### 网页模式
### 工具链
### 知识库
### 信息流
```
$ bin/bench
19[11:59:19]nfs> upgrade portal
hash file
ef1998b38af0888cb56dd5e1448a68ad usr/template.tar.gz
6_043a93fa03273744be42c7ab898b2 usr/librarys.tar.gz
19[11:59:19]nfs> upgrade portal
```
#### 集群模式
#### 完整版
如果对源码有兴趣,使用更丰富的功能,可以直接下载源码,
@ -109,103 +354,6 @@ index name ip mask hard
5 en0 192.168.0.106 24 c4:b3:01:cf:0b:51
```
### 组建集群
context不仅只是一个shell还可以用来组建集群。
#### 启动服务节点
启动服务节点使用脚本boot.sh
与node.sh不同的是boot.sh启动的context
会启动web模块监听9094端口会启动ssh模块监听9090端口。
```
$ cd context
$ bin/boot.sh
0[11:23:03]ssh>
```
#### 启动工作节点
启动工作节点使用脚本node.sh
它启动的context会主动连接本地9090端口向服务节点注册自己。
如下新打开一个终端调用boot.sh创建并启动服务节点demo。
```
$ cd context
$ bin/node.sh create app/demo
0[11:23:03]ssh>
```
如下再打开一个终端调用boot.sh创建并启动服务节点led。
```
$ cd context
$ bin/node.sh create app/led
0[11:23:03]ssh>
```
#### 调用远程命令
如下回到服务节点终端执行remote命令可以查看到所有远程节点。
```
22[11:35:12]ssh> remote
key create_time module name type
com 2019-05-09 20:57:21 ctx.nfs.file4 com master
led 2019-05-09 20:59:28 ctx.nfs.file5 led worker
demo 2019-05-09 20:59:28 ctx.nfs.file5 demo worker
```
远程命令只需要在命令前加上节点名与冒号即可。
如下远程调用led节点的命令。
```
24[11:41:15]ssh> led:pwd
/Users/shaoying/context/app/led/var
```
如下远程调用demo节点的命令。
```
24[11:41:15]ssh> demo:pwd
/Users/shaoying/context/app/demo/var
```
如下,远程调用所有子节点的命令。
```
29[11:44:09]ssh> *:pwd
/Users/shaoying/context/app/led/var
/Users/shaoying/context/app/demo/var
```
#### 启动分机服务
boot.sh不仅可以用来启动本地服务还可以将不同的主机组建在一起。
在另外一台计算机上重新下载安装一下context然后启动服务节点。
其中环境变量ctx_dev用来指定上级服务节点。
```
$ cd context
$ ctx_dev=http://192.168.0.106:9094 boot.sh
0[11:53:11]ssh>
```
回到原主机的服务节点终端,
使用remote命令可以查看到新加的从机节点。
```
30[11:55:38]ssh> remote
key create_time module name type
com 2019-05-09 20:57:21 ctx.nfs.file4 com master
mac 2019-05-10 10:53:00 ctx.nfs.file13 mac server
led 2019-05-09 20:59:28 ctx.nfs.file5 led worker
demo 2019-05-09 20:59:28 ctx.nfs.file5 demo worker
```
当然也可以在本地启动多个服务节点根据ctx_dev指定不同的上级节点可以级联也可以并联。
```
$ cd context
$ ctx_dev=http://localhost:9094 boot.sh create app/sub
```
***注意不指定ctx_dev时默认连接 https://shylinux.com 如果不信任此主机记得设置ctx_dev***
### 网页服务
下载完整版的context启动的服务节点就会带有前端网页服务。