From 76fc21dddf23c22e97be644e26a156d2995afc0f Mon Sep 17 00:00:00 2001 From: shaoying Date: Fri, 19 Oct 2018 09:37:54 +0800 Subject: [PATCH 1/2] mac add web.template --- src/contexts/cli/cli.go | 1 + src/contexts/ctx/ctx.go | 2 +- src/contexts/web/web.go | 1101 ++++--------------------------------- src/examples/code/code.go | 628 ++++++++++++++++++++- src/examples/wiki/wiki.go | 277 +++++++++- 5 files changed, 1014 insertions(+), 995 deletions(-) diff --git a/src/contexts/cli/cli.go b/src/contexts/cli/cli.go index 559b83f1..09596344 100644 --- a/src/contexts/cli/cli.go +++ b/src/contexts/cli/cli.go @@ -769,6 +769,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", msg.Copy(m, "target").Detail(-1, "system") msg.Cmd() } + m.Target().Message().Set("result").Set("append").Copy(msg, "result").Copy(msg, "append") m.Copy(msg, "result").Copy(msg, "append") m.Capi("last_msg", 0, msg.Code()) m.Capi("ps_count", 1) diff --git a/src/contexts/ctx/ctx.go b/src/contexts/ctx/ctx.go index c85a072f..2544921a 100644 --- a/src/contexts/ctx/ctx.go +++ b/src/contexts/ctx/ctx.go @@ -2327,7 +2327,7 @@ var Index = &Context{Name: "ctx", Help: "模块中心", m.Color(31, "option(%d): %v\n", len(msg.Meta["option"]), msg.Meta["option"]) for _, k := range msg.Meta["option"] { if v, ok := msg.Data[k]; ok { - m.Echo(" %s: %v\n", k, v) + m.Echo(" %s: %#v\n", k, v) } else { m.Echo(" %s(%d): %v\n", k, len(msg.Meta[k]), msg.Meta[k]) } diff --git a/src/contexts/web/web.go b/src/contexts/web/web.go index 85bf1cf8..4d9c22d7 100644 --- a/src/contexts/web/web.go +++ b/src/contexts/web/web.go @@ -12,24 +12,23 @@ import ( "net/http" "net/url" "os" - "os/exec" "path" "path/filepath" "runtime" "strings" - "time" ) type MUX interface { Handle(string, http.Handler) HandleFunc(string, func(http.ResponseWriter, *http.Request)) - HandleCmd(*ctx.Message, string, func(*ctx.Message, *ctx.Context, string, ...string)) + HandleCmd(*ctx.Message, string, *ctx.Command) ServeHTTP(http.ResponseWriter, *http.Request) } type WEB struct { - client *http.Client + *http.Client *http.ServeMux *http.Server + *template.Template *ctx.Context } @@ -76,44 +75,13 @@ func (web *WEB) Merge(m *ctx.Message, uri string, arg ...string) string { return strings.Join(adds, "") } -func (web *WEB) HandleCmd(m *ctx.Message, key string, hand func(*ctx.Message, *ctx.Context, string, ...string)) { +func (web *WEB) HandleCmd(m *ctx.Message, key string, cmd *ctx.Command) { web.HandleFunc(key, func(w http.ResponseWriter, r *http.Request) { - msg := m.Spawn() - msg.TryCatch(msg, true, func(msg *ctx.Message) { - msg.Option("method", r.Method) - msg.Option("path", r.URL.Path) + m.TryCatch(m.Spawn(), true, func(msg *ctx.Message) { + msg.Add("option", "method", r.Method).Add("option", "path", r.URL.Path) + msg.Option("referer", r.Header.Get("Referer")) - remote := r.RemoteAddr - if r.Header.Get("X-Real-Ip") != "" { - remote = r.Header.Get("X-Real-Ip") - } - - count := 1 - if m.Confv("record", []interface{}{r.URL.Path}) == nil { - m.Confv("record", []interface{}{r.URL.Path}, map[string]interface{}{ - "remote": map[string]interface{}{remote: map[string]interface{}{"time": time.Now().Format("2006/01/02 15:04:05")}}, - "count": count, - }) - } else { - switch v := m.Confv("record", []interface{}{r.URL.Path, "count"}).(type) { - case int: - count = v - case float64: - count = int(v) - default: - count = 0 - } - - if m.Confv("record", []interface{}{r.URL.Path, "remote", remote}) == nil { - m.Confv("record", []interface{}{r.URL.Path, "count"}, count+1) - } else { - msg.Option("last_record_time", m.Confv("record", []interface{}{r.URL.Path, "remote", remote, "time"})) - } - m.Confv("record", []interface{}{r.URL.Path, "remote", remote}, map[string]interface{}{"time": time.Now().Format("2006/01/02 15:04:05")}) - } - msg.Option("record_count", count) - if r.ParseForm(); len(r.PostForm) > 0 { for k, v := range r.PostForm { m.Log("info", "%s: %v", k, v) @@ -129,7 +97,7 @@ func (web *WEB) HandleCmd(m *ctx.Message, key string, hand func(*ctx.Message, *c msg.Log("cmd", "%s [] %v", key, msg.Meta["option"]) msg.Put("option", "request", r).Put("option", "response", w) - hand(msg, msg.Target(), msg.Option("path")) + cmd.Hand(msg, msg.Target(), msg.Option("path")) switch { case msg.Has("redirect"): @@ -139,7 +107,25 @@ func (web *WEB) HandleCmd(m *ctx.Message, key string, hand func(*ctx.Message, *c case msg.Has("template"): msg.Spawn().Cmd("/render", msg.Meta["template"]) case msg.Has("append"): - msg.Spawn().Copy(msg, "result").Copy(msg, "append").Cmd("/json") + meta := map[string]interface{}{} + if len(msg.Meta["result"]) > 0 { + meta["result"] = msg.Meta["result"] + } + if len(msg.Meta["append"]) > 0 { + meta["append"] = msg.Meta["append"] + for _, v := range msg.Meta["append"] { + if _, ok := msg.Data[v]; ok { + meta[v] = msg.Data[v] + } else if _, ok := msg.Meta[v]; ok { + meta[v] = msg.Meta[v] + } + } + } + + if b, e := json.Marshal(meta); msg.Assert(e) { + w.Header().Set("Content-Type", "application/javascript") + w.Write(b) + } default: for _, v := range msg.Meta["result"] { w.Write([]byte(v)) @@ -181,8 +167,8 @@ func (web *WEB) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server return s } func (web *WEB) Begin(m *ctx.Message, arg ...string) ctx.Server { + web.Configs["root_index"] = &ctx.Config{Name: "root_index", Value: "", Help: "默认路由"} web.Configs["logheaders"] = &ctx.Config{Name: "logheaders(yes/no)", Value: "no", Help: "日志输出报文头"} - web.Configs["root_index"] = &ctx.Config{Name: "root_index", Value: "/wiki/", Help: "默认路由"} web.Caches["directory"] = &ctx.Cache{Name: "directory", Value: m.Confx("directory", arg, 0), Help: "服务目录"} web.Caches["route"] = &ctx.Cache{Name: "route", Value: "/" + web.Context.Name + "/", Help: "模块路由"} web.Caches["register"] = &ctx.Cache{Name: "register(yes/no)", Value: "no", Help: "是否已初始化"} @@ -206,7 +192,7 @@ func (web *WEB) Start(m *ctx.Message, arg ...string) bool { for k, x := range m.Target().Commands { if k[0] == '/' { m.Log("info", "route: %s", k) - h.HandleCmd(m, k, x.Hand) + h.HandleCmd(m, k, x) m.Capi("nroute", 1) } } @@ -219,30 +205,6 @@ func (web *WEB) Start(m *ctx.Message, arg ...string) bool { return true }) - web.Configs["library_dir"] = &ctx.Config{Name: "library_dir", Value: "usr", Help: "通用模板路径"} - web.Configs["template_dir"] = &ctx.Config{Name: "template_dir", Value: "usr/template/", Help: "通用模板路径"} - web.Configs["common_tmpl"] = &ctx.Config{Name: "common_tmpl", Value: "common/*.html", Help: "通用模板路径"} - web.Configs["common_main"] = &ctx.Config{Name: "common_main", Value: "main.html", Help: "通用模板框架"} - web.Configs["upload_tmpl"] = &ctx.Config{Name: "upload_tmpl", Value: "upload.html", Help: "上传文件模板"} - web.Configs["upload_main"] = &ctx.Config{Name: "upload_main", Value: "main.html", Help: "上传文件框架"} - web.Configs["travel_tmpl"] = &ctx.Config{Name: "travel_tmpl", Value: "travel.html", Help: "浏览模块模板"} - web.Configs["travel_main"] = &ctx.Config{Name: "travel_main", Value: "main.html", Help: "浏览模块框架"} - - // yac := m.Sess("tags", m.Sess("yac").Cmd("scan")) - // yac.Cmd("train", "void", "void", "[\t ]+") - // yac.Cmd("train", "other", "other", "[^\n]+") - // yac.Cmd("train", "key", "key", "[A-Za-z_][A-Za-z_0-9]*") - // yac.Cmd("train", "code", "def", "def", "key", "(", "other") - // yac.Cmd("train", "code", "def", "class", "key", "other") - // yac.Cmd("train", "code", "struct", "struct", "key", "\\{") - // yac.Cmd("train", "code", "struct", "\\}", "key", ";") - // yac.Cmd("train", "code", "struct", "typedef", "struct", "key", "key", ";") - // yac.Cmd("train", "code", "function", "key", "\\*", "key", "(", "other") - // yac.Cmd("train", "code", "function", "key", "key", "(", "other") - // yac.Cmd("train", "code", "variable", "struct", "key", "key", "other") - // yac.Cmd("train", "code", "define", "#define", "key", "other") - // - web.Caches["protocol"] = &ctx.Cache{Name: "protocol", Value: m.Confx("protocol", arg, 2), Help: "服务协议"} web.Caches["address"] = &ctx.Cache{Name: "address", Value: m.Confx("address", arg, 1), Help: "服务地址"} m.Log("info", "%d %s://%s", m.Capi("nserve", 1), m.Cap("protocol"), m.Cap("stream", m.Cap("address"))) @@ -282,178 +244,16 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心", "cert": &ctx.Config{Name: "cert", Value: "etc/cert.pem", Help: "路由数量"}, "key": &ctx.Config{Name: "key", Value: "etc/key.pem", Help: "路由数量"}, - "record": &ctx.Config{Name: "record", Value: map[string]interface{}{}, Help: "访问记录"}, - "auto_create": &ctx.Config{Name: "auto_create(true/false)", Value: "true", Help: "路由数量"}, - "refresh_time": &ctx.Config{Name: "refresh_time(ms)", Value: "1000", Help: "路由数量"}, - "define": &ctx.Config{Name: "define", Value: map[string]interface{}{ - "ngx_command_t": map[string]interface{}{ - "position": []interface{}{map[string]interface{}{ - "file": "nginx-1.15.2/src/core/ngx_core.h", - "line": "22", - }}, - }, - "ngx_command_s": map[string]interface{}{ - "position": map[string]interface{}{ - "file": "nginx-1.15.2/src/core/ngx_conf_file.h", - "line": "77", + "template_dir": &ctx.Config{Name: "template_dir", Value: "usr/template", Help: "路由数量"}, + "template_file": &ctx.Config{Name: "template_file", Value: "usr/template", Help: "路由数量"}, + "template": &ctx.Config{Name: "template", Value: map[string]interface{}{ + "index": []interface{}{ + map[string]interface{}{ + "name": "message", "title": "message", + "context": "nfs", "command": "pwd", }, }, }, Help: "路由数量"}, - "check": &ctx.Config{Name: "check", Value: map[string]interface{}{ - "login": []interface{}{ - map[string]interface{}{ - "session": "aaa", - "module": "aaa", "command": "login", - "variable": []interface{}{"$sessid"}, - "template": "login", "title": "login", - }, - map[string]interface{}{ - "module": "aaa", "command": "login", - "variable": []interface{}{"$username", "$password"}, - "template": "login", "title": "login", - }, - }, - "right": []interface{}{ - map[string]interface{}{ - "module": "web", "command": "right", - "variable": []interface{}{"$username", "check", "command", "/index", "dir", "$dir"}, - "template": "notice", "title": "notice", - }, - map[string]interface{}{ - "module": "aaa", "command": "login", - "variable": []interface{}{"username", "password"}, - "template": "login", "title": "login", - }, - }, - }, Help: "执行条件"}, - "index": &ctx.Config{Name: "index", Value: map[string]interface{}{ - "duyu": []interface{}{ - map[string]interface{}{ - "template": "userinfo", "title": "userinfo", - }, - map[string]interface{}{ - "from": "root", "to": []interface{}{}, - "module": "aaa", "command": "lark", - "argument": []interface{}{}, - "template": "append", "title": "lark_friend", - }, - map[string]interface{}{ - "module": "aaa", "detail": []interface{}{"lark"}, - "template": "detail", "title": "send_lark", - "option": map[string]interface{}{"ninput": 2}, - }, - map[string]interface{}{ - "module": "aaa", "command": "lark", - "argument": []interface{}{"duyu"}, - "template": "append", "title": "lark", - }, - map[string]interface{}{ - "module": "nfs", "command": "dir", - "argument": []interface{}{"dir_type", "all", "dir_deep", "false", "dir_field", "time size line filename", "sort_field", "time", "sort_order", "time_r"}, - "template": "append", "title": "", - }, - }, - "shy": []interface{}{ - map[string]interface{}{ - "from": "root", "to": []interface{}{}, - "template": "userinfo", "title": "userinfo", - }, - //文件服务 - map[string]interface{}{ - "from": "root", "to": []interface{}{}, - "module": "nfs", "command": "dir", - "argument": []interface{}{"dir_type", "all", "dir_deep", "false", "dir_field", "time size line filename", "sort_field", "time", "sort_order", "time_r"}, - "template": "append", "title": "", - }, - map[string]interface{}{ - "from": "root", "to": []interface{}{}, - "template": "upload", "title": "upload", - }, - map[string]interface{}{ - "from": "root", "to": []interface{}{}, - "template": "create", "title": "create", - }, - //会话服务 - map[string]interface{}{ - "from": "root", "to": []interface{}{}, - "module": "cli", "command": "system", - "argument": []interface{}{"tmux", "show-buffer"}, - "template": "result", "title": "buffer", - }, - map[string]interface{}{ - "from": "root", "to": []interface{}{}, - "module": "cli", "command": "system", - "argument": []interface{}{"tmux", "list-clients"}, - "template": "result", "title": "client", - }, - map[string]interface{}{ - "from": "root", "to": []interface{}{}, - "module": "cli", "command": "system", - "argument": []interface{}{"tmux", "list-sessions"}, - "template": "result", "title": "session", - }, - //格式转换 - map[string]interface{}{ - "from": "root", "to": []interface{}{}, - "module": "cli", "detail": []interface{}{"time"}, - "template": "detail", "title": "time", - "option": map[string]interface{}{"refresh": true, "ninput": 1}, - }, - map[string]interface{}{ - "from": "root", "to": []interface{}{}, - "module": "nfs", "detail": []interface{}{"json"}, - "template": "detail", "title": "json", - "option": map[string]interface{}{"ninput": 1}, - }, - map[string]interface{}{ - "from": "root", "to": []interface{}{}, - "module": "nfs", "detail": []interface{}{"pwd"}, - "template": "detail", "title": "pwd", - "option": map[string]interface{}{"refresh": true}, - }, - map[string]interface{}{ - "from": "root", "to": []interface{}{}, - "module": "nfs", "command": "git", - "argument": []interface{}{}, - "template": "result", "title": "git", - }, - map[string]interface{}{ - "from": "root", "to": []interface{}{}, - "module": "web", "command": "/share", - "argument": []interface{}{}, - "template": "share", "title": "share", - }, - }, - "notice": []interface{}{ - map[string]interface{}{ - "template": "userinfo", "title": "userinfo", - }, - map[string]interface{}{ - "template": "notice", "title": "notice", - }, - }, - "login": []interface{}{ - map[string]interface{}{ - "template": "login", "title": "login", - }, - }, - "wiki": []interface{}{ - map[string]interface{}{ - "template": "wiki_head", "title": "wiki_head", - }, - map[string]interface{}{ - "template": "wiki_menu", "title": "wiki_menu", - }, - map[string]interface{}{ - "module": "web", "command": "/wiki_list", - "template": "wiki_list", "title": "wiki_list", - }, - map[string]interface{}{ - "module": "web", "command": "/wiki_body", - "template": "wiki_body", "title": "wiki_body", - }, - }, - }, Help: "资源列表"}, }, Commands: map[string]*ctx.Command{ "client": &ctx.Command{Name: "client address [output [editor]]", Help: "添加浏览器配置, address: 默认地址, output: 输出路径, editor: 编辑器", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { @@ -549,10 +349,10 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心", m.Log("fuck", "%s: %s", k, v) } - if web.client == nil { - web.client = &http.Client{} + if web.Client == nil { + web.Client = &http.Client{} } - res, e := web.client.Do(req) + res, e := web.Client.Do(req) m.Assert(e) for _, v := range res.Cookies() { @@ -662,781 +462,112 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心", "serve": &ctx.Command{Name: "serve [directory [address [protocol [cert [key]]]]", Help: "启动服务, directory: 服务路径, address: 服务地址, protocol: 服务协议(https/http), cert: 服务证书, key: 服务密钥", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { m.Set("detail", arg...).Target().Start(m) }}, - "route": &ctx.Command{Name: "route script|template|directory route content", Help: "添加响应, script: 脚本响应, template: 模板响应, directory: 目录响应, route: 请求路由, content: 响应内容", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + "route": &ctx.Command{Name: "route index content [help]", Help: "添加路由响应, index: 路由, context: 响应, help: 说明", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { if mux, ok := m.Target().Server.(MUX); m.Assert(ok) { switch len(arg) { case 0: for k, v := range m.Target().Commands { if k[0] == '/' { - m.Echo("%s: %s\n", k, v.Name) + m.Add("append", "route", k) + m.Add("append", "name", v.Name) } } + m.Sort("route").Table() case 1: for k, v := range m.Target().Commands { if k == arg[0] { m.Echo("%s: %s\n%s", k, v.Name, v.Help) } } - case 3: - switch arg[0] { - case "script": - mux.HandleCmd(m, arg[1], func(m *ctx.Message, c *ctx.Context, key string, a ...string) { - msg := m.Sess("cli").Cmd("source", arg[2]) - m.Copy(msg, "result").Copy(msg, "append") - }) - case "template": - mux.HandleCmd(m, arg[1], func(m *ctx.Message, c *ctx.Context, key string, a ...string) { - w := m.Optionv("response").(http.ResponseWriter) - if _, e := os.Stat(arg[2]); e == nil { - template.Must(template.ParseGlob(arg[2])).Execute(w, m) - } else { - template.Must(template.New("temp").Parse(arg[2])).Execute(w, m) + default: + help := "dynamic route" + if len(arg) > 2 { + help = arg[2] + } + hand := func(m *ctx.Message, c *ctx.Context, key string, a ...string) { + w := m.Optionv("response").(http.ResponseWriter) + template.Must(template.New("temp").Parse(arg[1])).Execute(w, m) + } + + if s, e := os.Stat(arg[1]); e == nil { + if s.IsDir() { + mux.Handle(arg[0]+"/", http.StripPrefix(arg[0], http.FileServer(http.Dir(arg[1])))) + } else if strings.HasSuffix(arg[1], ".shy") { + hand = func(m *ctx.Message, c *ctx.Context, key string, a ...string) { + msg := m.Sess("cli").Cmd("source", arg[1]) + m.Copy(msg, "result").Copy(msg, "append") } - }) - case "directory": - mux.Handle(arg[1]+"/", http.StripPrefix(arg[1], http.FileServer(http.Dir(arg[2])))) - } - } - } - }}, - "upload": &ctx.Command{Name: "upload file", Help: "上传文件", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - msg := m.Spawn(m.Target()) - msg.Cmd("get", "/upload", "method", "POST", "file", "file", arg[0]) - m.Copy(msg, "result") - - }}, - "/library/": &ctx.Command{Name: "/library", Help: "网页门户", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - r := m.Optionv("request").(*http.Request) - w := m.Optionv("response").(http.ResponseWriter) - dir := path.Join(m.Conf("library_dir"), m.Option("path")) - if s, e := os.Stat(dir); e == nil && !s.IsDir() { - http.ServeFile(w, r, dir) - return - } - - }}, - "/travel": &ctx.Command{Name: "/travel", Help: "文件上传", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - // r := m.Optionv("request").(*http.Request) - // w := m.Optionv("response").(http.ResponseWriter) - - if !m.Options("dir") { - m.Option("dir", "ctx") - } - - check := m.Spawn().Cmd("/share", "/travel", "dir", m.Option("dir")) - if !check.Results(0) { - m.Copy(check, "append") - return - } - - // 权限检查 - if m.Option("method") == "POST" { - if m.Options("domain") { - msg := m.Find("ssh", true) - msg.Detail(0, "send", "domain", m.Option("domain"), "context", "find", m.Option("dir")) - if m.Option("name") != "" { - msg.Add("detail", m.Option("name")) - } - if m.Options("value") { - value := []string{} - json.Unmarshal([]byte(m.Option("value")), &value) - if len(value) > 0 { - msg.Add("detail", value[0], value[1:]) - } - } - - msg.CallBack(true, func(sub *ctx.Message) *ctx.Message { - m.Copy(sub, "result").Copy(sub, "append") - return nil - }) - return - } - - msg := m.Find(m.Option("dir"), true) - if msg == nil { - return - } - - switch m.Option("ccc") { - case "cache": - m.Echo(msg.Cap(m.Option("name"))) - case "config": - if m.Has("value") { - m.Echo(msg.Conf(m.Option("name"), m.Option("value"))) - } else { - m.Echo(msg.Conf(m.Option("name"))) - } - case "command": - msg = msg.Spawn(msg.Target()) - msg.Detail(0, m.Option("name")) - if m.Options("value") { - value := []string{} - json.Unmarshal([]byte(m.Option("value")), &value) - if len(value) > 0 { - msg.Add("detail", value[0], value[1:]) - } - } - - msg.Cmd() - m.Copy(msg, "result").Copy(msg, "append") - } - return - } - - // 解析模板 - m.Set("append", "tmpl", "userinfo", "share") - msg := m - for _, v := range []string{"cache", "config", "command", "module", "domain"} { - if m.Options("domain") { - msg = m.Find("ssh", true) - msg.Detail(0, "send", "domain", m.Option("domain"), "context", "find", m.Option("dir"), "list", v) - msg.CallBack(true, func(sub *ctx.Message) *ctx.Message { - msg.Copy(sub, "result").Copy(sub, "append") - return nil - }) - } else { - msg = m.Spawn() - msg.Cmd("context", "find", msg.Option("dir"), "list", v) - } - - if len(msg.Meta["append"]) > 0 { - msg.Option("current_module", m.Option("dir")) - msg.Option("current_domain", m.Option("domain")) - m.Add("option", "tmpl", v) - m.Sess(v, msg) - } - } - m.Append("template", m.Conf("travel_main"), m.Conf("travel_tmpl")) - - }}, - "/index/": &ctx.Command{Name: "/index", Help: "网页门户", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - r := m.Optionv("request").(*http.Request) - w := m.Optionv("response").(http.ResponseWriter) - - if login := m.Spawn().Cmd("/login"); login.Has("template") { - m.Echo("no").Copy(login, "append") - return - } - m.Option("username", m.Append("username")) - - //权限检查 - dir := m.Option("dir", path.Join(m.Cap("directory"), "local", m.Option("username"), m.Option("dir", strings.TrimPrefix(m.Option("path"), "/index")))) - // if check := m.Spawn(c).Cmd("/check", "command", "/index/", "dir", dir); !check.Results(0) { - // m.Copy(check, "append") - // return - // } - - //执行命令 - if m.Has("details") { - if m.Confs("check_right") { - if check := m.Spawn().Cmd("/check", "target", m.Option("module"), "command", m.Option("details")); !check.Results(0) { - m.Copy(check, "append") - return - } - } - - msg := m.Find(m.Option("module")).Cmd(m.Optionv("details")) - m.Copy(msg, "result").Copy(msg, "append") - return - } - - //下载文件 - if s, e := os.Stat(dir); e == nil && !s.IsDir() { - http.ServeFile(w, r, dir) - return - } - - if !m.Options("module") { - m.Option("module", "web") - } - //浏览目录 - m.Append("template", m.Append("username")) - m.Option("page_title", "index") - - }}, - "/create": &ctx.Command{Name: "/create", Help: "创建目录或文件", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - // if check := m.Spawn().Cmd("/share", "/upload", "dir", m.Option("dir")); !check.Results(0) { - // m.Copy(check, "append") - // return - // } - - r := m.Optionv("request").(*http.Request) - if m.Option("method") == "POST" { - if m.Options("filename") { //添加文件或目录 - name := path.Join(m.Option("dir"), m.Option("filename")) - if _, e := os.Stat(name); e != nil { - if m.Options("content") { - f, e := os.Create(name) - m.Assert(e) - defer f.Close() - - _, e = f.WriteString(m.Option("content")) - m.Assert(e) } else { - e = os.Mkdir(name, 0766) - m.Assert(e) + hand = func(m *ctx.Message, c *ctx.Context, key string, a ...string) { + w := m.Optionv("response").(http.ResponseWriter) + template.Must(template.ParseGlob(arg[1])).Execute(w, m) + } } - m.Append("message", name, " create success!") - } else { - m.Append("message", name, " already exist!") } - } else { //上传文件 - file, header, e := r.FormFile("file") - m.Assert(e) - name := path.Join(m.Option("dir"), header.Filename) - - if _, e := os.Stat(name); e != nil { - f, e := os.Create(name) - m.Assert(e) - defer f.Close() - - _, e = io.Copy(f, file) - m.Assert(e) - m.Append("message", name, " upload success!") + if _, ok := m.Target().Commands[arg[0]]; ok { + m.Target().Commands[arg[0]].Help = help + m.Target().Commands[arg[0]].Name = arg[1] + m.Target().Commands[arg[0]].Hand = hand } else { - m.Append("message", name, " already exist!") + cmd := &ctx.Command{Name: arg[1], Help: help, Hand: hand} + m.Target().Commands[arg[0]] = cmd + mux.HandleCmd(m, arg[0], cmd) } } } - m.Append("redirect", m.Option("referer")) - }}, - "/share": &ctx.Command{Name: "/share arg...", Help: "资源共享", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - if check := m.Spawn().Cmd("/check", "target", m.Option("module"), m.Optionv("share")); !check.Results(0) { - m.Copy(check, "append") - return - } - m.Option("username", m.Append("username")) - - // if m.Options("friend") && m.Options("module") { - // m.Copy(m.Appendv("aaa").(*ctx.Message).Find(m.Option("module")).Cmd("right", m.Option("friend"), m.Option("action"), m.Optionv("share")), "result") - // if m.Confv("index", m.Option("friend")) == nil { - // m.Confv("index", m.Option("friend"), m.Confv("index", m.Append("username"))) - // } - // return - // } - // - // msg := m.Spawn().Cmd("right", "target", m.Option("module"), m.Append("username"), "show", "context") - // m.Copy(msg, "append") - if m.Options("friend") && m.Options("template") && m.Options("title") { - for i, v := range m.Confv("index", m.Option("username")).([]interface{}) { - if v == nil { - continue + "/demo": &ctx.Command{Name: "/demo template", Help: "渲染模板, template: 模板名称", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + m.Append("template", "index") + }}, + "template": &ctx.Command{Name: "template [file directory]|[name content]", Help: "添加模块, content: 模板内容, directory: 模板目录", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + if web, ok := m.Target().Server.(*WEB); m.Assert(ok) { + if len(arg) == 0 { + for _, v := range web.Template.Templates() { + m.Add("append", "name", v.Name()) } + m.Sort("name").Table() + return + } + + if web.Template == nil { + web.Template = template.New("render").Funcs(ctx.CGI) + } + + dir := path.Join(m.Confx("template_dir", arg, 1), arg[0]) + if t, e := web.Template.ParseGlob(dir); e == nil { + web.Template = t + } else { + if len(arg) > 1 { + web.Template = template.Must(web.Template.New(arg[0]).Parse(arg[1])) + } else { + buf := bytes.NewBuffer(make([]byte, 1024)) + tmpl, e := web.Template.Clone() + m.Assert(e) + tmpl.ExecuteTemplate(buf, arg[0], m) + m.Echo(string(buf.Bytes())) + } + } + } + }}, + "/render": &ctx.Command{Name: "/render template", Help: "渲染模板, template: 模板名称", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + if web, ok := m.Target().Server.(*WEB); m.Assert(ok) { + w := m.Optionv("response").(http.ResponseWriter) + w.Header().Add("Content-Type", "text/html") + tmpl, e := web.Template.Clone() + m.Assert(e) + + for _, v := range m.Confv("template", arg[0]).([]interface{}) { + //执行命令 val := v.(map[string]interface{}) - if val["template"].(string) == m.Option("template") && val["title"].(string) == m.Option("title") { - if m.Option("action") == "del" { - friends := m.Confv("index", strings.Join([]string{m.Option("username"), fmt.Sprintf("%d", i), "to"}, ".")).([]interface{}) - for j, x := range friends { - if x.(string) == m.Option("friend") { - m.Confv("index", strings.Join([]string{m.Option("username"), fmt.Sprintf("%d", i), "to", fmt.Sprintf("%d", j)}, "."), nil) - } - } - - temps := m.Confv("index", strings.Join([]string{m.Option("friend")}, ".")).([]interface{}) - for j, x := range temps { - if x == nil { - continue - } - val = x.(map[string]interface{}) - if val["template"].(string) == m.Option("template") && val["title"].(string) == m.Option("title") { - m.Confv("index", strings.Join([]string{m.Option("friend"), fmt.Sprintf("%d", j)}, "."), nil) - } - } - - break - } - - if m.Confv("index", m.Option("friend")) == nil && !m.Confs("auto_create") { - break - } - m.Confv("index", strings.Join([]string{m.Option("username"), fmt.Sprintf("%d", i), "to", "-2"}, "."), m.Option("friend")) - - item := map[string]interface{}{ - "template": val["template"], - "title": val["title"], - "from": m.Option("username"), - } - if val["command"] != nil { - item["module"] = val["module"] - item["command"] = val["command"] - item["argument"] = val["argument"] - } else if val["detail"] != nil { - item["module"] = val["module"] - item["detail"] = val["detail"] - item["option"] = val["option"] - } - - m.Confv("index", strings.Join([]string{m.Option("friend"), fmt.Sprintf("%d", -2)}, "."), item) - m.Appendv("aaa").(*ctx.Message).Spawn(c).Cmd("right", m.Option("friend"), "add", "command", "/index/", "dir", m.Cap("directory")) - os.Mkdir(path.Join(m.Cap("directory"), m.Option("friend")), 0666) - break + if _, ok := val["command"]; ok { + msg := m.Find(val["context"].(string)).Cmd(val["command"], val["argument"]) + msg.Option("title", val["title"]) + m.Assert(tmpl.ExecuteTemplate(w, val["name"].(string), msg)) } } - return - } - for _, v := range m.Confv("index", m.Option("username")).([]interface{}) { - val := v.(map[string]interface{}) - m.Add("append", "template", val["template"]) - m.Add("append", "titles", val["title"]) - m.Add("append", "from", val["from"]) - m.Add("append", "to", "") - if val["to"] == nil { - continue - } - for _, u := range val["to"].([]interface{}) { - m.Add("append", "template", val["template"]) - m.Add("append", "titles", val["title"]) - m.Add("append", "from", val["from"]) - m.Add("append", "to", u) - } - } - - }}, - "/check": &ctx.Command{Name: "/check arg...", Help: "权限检查, cache|config|command: 接口类型, name: 接口名称, args: 其它参数", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - if login := m.Spawn().Cmd("/login"); login.Has("template") { - m.Echo("no").Copy(login, "append") - return - } - - if msg := m.Spawn().Cmd("right", m.Append("username"), "check", arg); !msg.Results(0) { - m.Echo("no").Append("message", "no right, please contact manager") - return - } - - m.Echo("ok") - - }}, - "/login": &ctx.Command{Name: "/login", Help: "用户登录", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - if m.Options("sessid") { - if aaa := m.Sess("aaa").Cmd("login", m.Option("sessid")); aaa.Results(0) { - m.Append("redirect", m.Option("referer")) - m.Append("username", aaa.Result(0)) - return - } - } - - w := m.Optionv("response").(http.ResponseWriter) - if m.Options("username") && m.Options("password") { - if aaa := m.Sess("aaa").Cmd("login", m.Option("username"), m.Option("password")); aaa.Results(0) { - http.SetCookie(w, &http.Cookie{Name: "sessid", Value: aaa.Result(0)}) - m.Append("redirect", m.Option("referer")) - m.Append("username", m.Option("username")) - return - } - } - - w.WriteHeader(http.StatusUnauthorized) - m.Append("template", "login") - - }}, - "/render": &ctx.Command{Name: "/render index", Help: "模板响应, main: 模板入口, tmpl: 附加模板", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - w := m.Optionv("response").(http.ResponseWriter) - w.Header().Add("Content-Type", "text/html") - m.Optioni("ninput", 0) - - tpl := template.New("render").Funcs(ctx.CGI) - tpl = template.Must(tpl.ParseGlob(path.Join(m.Conf("template_dir"), m.Conf("common_tmpl")))) - tpl = template.Must(tpl.ParseGlob(path.Join(m.Conf("template_dir"), m.Conf("upload_tmpl")))) - - replace := [][]byte{ - []byte{27, 91, 51, 50, 109}, []byte(""), - []byte{27, 91, 51, 49, 109}, []byte(""), - []byte{27, 91, 109}, []byte(""), - } - - if m.Confv("index", arg[0]) == nil { - arg[0] = "notice" - } - - m.Assert(tpl.ExecuteTemplate(w, "head", m)) - for _, v := range m.Confv("index", arg[0]).([]interface{}) { - if v == nil { - continue - } - val := v.(map[string]interface{}) - //命令模板 - if detail, ok := val["detail"].([]interface{}); ok { - msg := m.Spawn().Add("detail", detail[0].(string), detail[1:]) - msg.Option("module", val["module"]) - msg.Option("title", val["title"]) - if option, ok := val["option"].(map[string]interface{}); ok { - for k, v := range option { - msg.Option(k, v) - } - } - - m.Assert(tpl.ExecuteTemplate(w, val["template"].(string), msg)) - continue - } - - //执行命令 - if _, ok := val["command"]; ok { - msg := m.Find(val["module"].(string)).Cmd(val["command"], val["argument"]) - for i, v := range msg.Meta["result"] { - b := []byte(v) - for i := 0; i < len(replace)-1; i += 2 { - b = bytes.Replace(b, replace[i], replace[i+1], -1) - } - msg.Meta["result"][i] = string(b) - } - if msg.Option("title", val["title"]) == "" { - msg.Option("title", m.Option("dir")) - } - m.Assert(tpl.ExecuteTemplate(w, val["template"].(string), msg)) - continue - } - - //解析模板 - if _, ok := val["template"]; ok { - m.Assert(tpl.ExecuteTemplate(w, val["template"].(string), m)) - } - } - m.Assert(tpl.ExecuteTemplate(w, "tail", m)) - - }}, - "/json": &ctx.Command{Name: "/json", Help: "json响应", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - w := m.Optionv("response").(http.ResponseWriter) - - meta := map[string]interface{}{} - if len(m.Meta["result"]) > 0 { - meta["result"] = m.Meta["result"] - } - if len(m.Meta["append"]) > 0 { - meta["append"] = m.Meta["append"] - for _, v := range m.Meta["append"] { - if _, ok := m.Data[v]; ok { - meta[v] = m.Data[v] - } else if _, ok := m.Meta[v]; ok { - meta[v] = m.Meta[v] - } - } - } - - if b, e := json.Marshal(meta); m.Assert(e) { - w.Header().Set("Content-Type", "application/javascript") - w.Write(b) } }}, - "/paste": &ctx.Command{Name: "/paste", Help: "应用示例", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - if login := m.Spawn().Cmd("/login"); login.Has("redirect") { - m.Sess("cli").Cmd("system", "tmux", "set-buffer", "-b", "0", m.Option("content")) - } - - }}, - "/upload": &ctx.Command{Name: "/upload", Help: "应用示例", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - r := m.Optionv("request").(*http.Request) - f, h, e := r.FormFile("file") - lf, e := os.Create(fmt.Sprintf("tmp/%s", h.Filename)) - m.Assert(e) - io.Copy(lf, f) - }}, - "user": &ctx.Command{Name: "user", Help: "应用示例", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - aaa := m.Sess("aaa") - m.Spawn().Cmd("get", fmt.Sprintf("%suser/get", aaa.Conf("wx_api")), "access_token", aaa.Cap("access_token")) - }}, - "temp": &ctx.Command{Name: "temp", Help: "应用示例", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - msg := m.Spawn(m.Target()) - question := []string{} - for i := 1; i < 21; i++ { - question = append(question, fmt.Sprintf("{\"type\":\"1001\",\"title\":{\"text\":\"第%d题\"}}", i)) - } - qs := "[" + strings.Join(question, ",") + "]" - - msg.Cmd("get", "method", "POST", "evaluating_add/", "questions", qs) - m.Add("append", "hi", "hello") - }}, - "/lookup": &ctx.Command{Name: "user", Help: "应用示例", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - if len(arg) > 0 { - m.Option("service", arg[0]) - } - msg := m.Sess("cli").Cmd("system", "sd", "lookup", m.Option("service")) - - rs := strings.Split(msg.Result(0), "\n") - i := 0 - for ; i < len(rs); i++ { - if len(rs[i]) == 0 { - break - } - fields := strings.SplitN(rs[i], ": ", 2) - m.Append(fields[0], fields[1]) - } - - lists := []interface{}{} - for i += 2; i < len(rs); i++ { - fields := strings.SplitN(rs[i], " ", 3) - if len(fields) < 3 { - break - } - lists = append(lists, map[string]interface{}{ - "ip": fields[0], - "port": fields[1], - "tags": fields[2], - }) - } - - m.Appendv("lists", lists) - m.Log("log", "%v", lists) - }}, - "old_get": &ctx.Command{ - Name: "get [method GET|POST] [file name filename] url arg...", - Help: "访问服务, method: 请求方法, file: 发送文件, url: 请求地址, arg: 请求参数", - Form: map[string]int{"method": 1, "content_type": 1, "headers": 2, "file": 2, "body_type": 1, "body": 1, "fields": 1, "value": 1, "json_route": 1, "json_key": 1}, - Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - if web, ok := m.Target().Server.(*WEB); m.Assert(ok) { - if web.client == nil { - web.client = &http.Client{} - } - - if m.Has("value") { - args := strings.Split(m.Option("value"), " ") - values := []interface{}{} - for _, v := range args { - if len(v) > 1 && v[0] == '$' { - values = append(values, m.Cap(v[1:])) - } else { - values = append(values, v) - } - } - arg[0] = fmt.Sprintf(arg[0], values...) - } - - method := m.Confx("method") - uri := web.Merge(m, arg[0], arg[1:]...) - m.Log("info", "%s %s", method, uri) - m.Echo("%s: %s\n", method, uri) - - var body io.Reader - index := strings.Index(uri, "?") - content_type := "" - - switch method { - case "POST": - if m.Options("file") { - file, e := os.Open(m.Meta["file"][1]) - m.Assert(e) - defer file.Close() - - if m.Option("body_type") == "json" { - content_type = "application/json" - body = file - break - } - buf := &bytes.Buffer{} - writer := multipart.NewWriter(buf) - - part, e := writer.CreateFormFile(m.Option("file"), filepath.Base(m.Meta["file"][1])) - m.Assert(e) - io.Copy(part, file) - - for i := 0; i < len(arg)-1; i += 2 { - value := arg[i+1] - if len(arg[i+1]) > 1 { - switch arg[i+1][0] { - case '$': - value = m.Cap(arg[i+1][1:]) - case '@': - value = m.Conf(arg[i+1][1:]) - } - } - writer.WriteField(arg[i], value) - } - - content_type = writer.FormDataContentType() - body = buf - writer.Close() - } else if m.Option("body_type") == "json" { - if m.Options("body") { - data := []interface{}{} - for _, v := range arg[1:] { - if len(v) > 1 && v[0] == '$' { - v = m.Cap(v[1:]) - } - data = append(data, v) - } - body = strings.NewReader(fmt.Sprintf(m.Option("body"), data...)) - } else { - data := map[string]interface{}{} - for i := 1; i < len(arg)-1; i += 2 { - switch arg[i+1] { - case "false": - data[arg[i]] = false - case "true": - data[arg[i]] = true - default: - if len(arg[i+1]) > 1 && arg[i+1][0] == '$' { - data[arg[i]] = m.Cap(arg[i+1][1:]) - } else { - data[arg[i]] = arg[i+1] - } - } - } - - b, e := json.Marshal(data) - m.Assert(e) - body = bytes.NewReader(b) - } - - content_type = "application/json" - if index > -1 { - uri = uri[:index] - } - - } else if index > 0 { - content_type = "application/x-www-form-urlencoded" - body = strings.NewReader(uri[index+1:]) - uri = uri[:index] - } - } - - req, e := http.NewRequest(method, uri, body) - m.Assert(e) - for i := 0; i < len(m.Meta["headers"]); i += 2 { - req.Header.Set(m.Meta["headers"][i], m.Meta["headers"][i+1]) - } - - if len(content_type) > 0 { - req.Header.Set("Content-Type", content_type) - m.Log("info", "content-type: %s", content_type) - } - - for _, v := range m.Confv("cookie").(map[string]interface{}) { - req.AddCookie(v.(*http.Cookie)) - } - - res, e := web.client.Do(req) - m.Assert(e) - - for _, v := range res.Cookies() { - m.Confv("cookie", v.Name, v) - m.Log("info", "set-cookie %s: %v", v.Name, v.Value) - } - - if m.Confs("logheaders") { - for k, v := range res.Header { - m.Log("info", "%s: %v", k, v) - } - } - - if m.Confs("output") { - if _, e := os.Stat(m.Conf("output")); e == nil { - name := path.Join(m.Conf("output"), fmt.Sprintf("%d", time.Now().Unix())) - f, e := os.Create(name) - m.Assert(e) - io.Copy(f, res.Body) - if m.Confs("editor") { - cmd := exec.Command(m.Conf("editor"), name) - cmd.Stdin = os.Stdin - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - cmd.Run() - } else { - m.Echo("write to %s\n", name) - } - return - } - } - - buf, e := ioutil.ReadAll(res.Body) - m.Assert(e) - - ct := res.Header.Get("Content-Type") - if len(ct) >= 16 && ct[:16] == "application/json" { - var result interface{} - json.Unmarshal(buf, &result) - m.Option("response_json", result) - if m.Has("json_route") { - routes := strings.Split(m.Option("json_route"), ".") - for _, k := range routes { - if len(k) > 0 && k[0] == '$' { - k = m.Cap(k[1:]) - } - switch r := result.(type) { - case map[string]interface{}: - result = r[k] - } - } - } - - fields := map[string]bool{} - for _, k := range strings.Split(m.Option("fields"), " ") { - if k == "" { - continue - } - if fields[k] = true; len(fields) == 1 { - m.Meta["append"] = append(m.Meta["append"], "index") - } - m.Meta["append"] = append(m.Meta["append"], k) - } - - if len(fields) > 0 { - - switch ret := result.(type) { - case map[string]interface{}: - m.Append("index", "0") - for k, v := range ret { - switch value := v.(type) { - case string: - m.Append(k, strings.Replace(value, "\n", " ", -1)) - case float64: - m.Append(k, fmt.Sprintf("%d", int(value))) - default: - if _, ok := fields[k]; ok { - m.Append(k, fmt.Sprintf("%v", value)) - } - } - } - case []interface{}: - for i, r := range ret { - m.Add("append", "index", i) - if rr, ok := r.(map[string]interface{}); ok { - for k, v := range rr { - switch value := v.(type) { - case string: - if _, ok := fields[k]; len(fields) == 0 || ok { - m.Add("append", k, strings.Replace(value, "\n", " ", -1)) - } - case float64: - if _, ok := fields[k]; len(fields) == 0 || ok { - m.Add("append", k, fmt.Sprintf("%d", int64(value))) - } - case bool: - if _, ok := fields[k]; len(fields) == 0 || ok { - m.Add("append", k, fmt.Sprintf("%v", value)) - } - case map[string]interface{}: - for kk, vv := range value { - key := k + "." + kk - if _, ok := fields[key]; len(fields) == 0 || ok { - m.Add("append", key, strings.Replace(fmt.Sprintf("%v", vv), "\n", " ", -1)) - } - } - default: - if _, ok := fields[k]; ok { - m.Add("append", k, fmt.Sprintf("%v", value)) - } - } - } - } - } - - if m.Has("json_key") { - m.Sort(m.Option("json_key")) - } - m.Meta["index"] = nil - for i, _ := range ret { - m.Add("append", "index", i) - } - } - } - } - - if m.Table(); len(m.Meta["append"]) == 0 { - m.Echo("%s", string(buf)) - } - } - }}, }, } diff --git a/src/examples/code/code.go b/src/examples/code/code.go index a853e772..bbf5adc0 100644 --- a/src/examples/code/code.go +++ b/src/examples/code/code.go @@ -1,21 +1,645 @@ package code import ( + "bytes" "contexts/ctx" "contexts/web" + "encoding/json" + "fmt" + "html/template" + "io" + "net/http" + "os" + "path" + "strings" ) type CODE struct { web.WEB } +// yac := m.Sess("tags", m.Sess("yac").Cmd("scan")) +// yac.Cmd("train", "void", "void", "[\t ]+") +// yac.Cmd("train", "other", "other", "[^\n]+") +// yac.Cmd("train", "key", "key", "[A-Za-z_][A-Za-z_0-9]*") +// yac.Cmd("train", "code", "def", "def", "key", "(", "other") +// yac.Cmd("train", "code", "def", "class", "key", "other") +// yac.Cmd("train", "code", "struct", "struct", "key", "\\{") +// yac.Cmd("train", "code", "struct", "\\}", "key", ";") +// yac.Cmd("train", "code", "struct", "typedef", "struct", "key", "key", ";") +// yac.Cmd("train", "code", "function", "key", "\\*", "key", "(", "other") +// yac.Cmd("train", "code", "function", "key", "key", "(", "other") +// yac.Cmd("train", "code", "variable", "struct", "key", "key", "other") +// yac.Cmd("train", "code", "define", "#define", "key", "other") +// + var Index = &ctx.Context{Name: "code", Help: "代码中心", - Caches: map[string]*ctx.Cache{}, - Configs: map[string]*ctx.Config{}, + Caches: map[string]*ctx.Cache{}, + Configs: map[string]*ctx.Config{ + "library_dir": &ctx.Config{Name: "library_dir", Value: "usr", Help: "通用模板路径"}, + "template_dir": &ctx.Config{Name: "template_dir", Value: "usr/template/", Help: "通用模板路径"}, + "common_tmpl": &ctx.Config{Name: "common_tmpl", Value: "common/*.html", Help: "通用模板路径"}, + "common_main": &ctx.Config{Name: "common_main", Value: "main.html", Help: "通用模板框架"}, + "upload_tmpl": &ctx.Config{Name: "upload_tmpl", Value: "upload.html", Help: "上传文件模板"}, + "upload_main": &ctx.Config{Name: "upload_main", Value: "main.html", Help: "上传文件框架"}, + "travel_tmpl": &ctx.Config{Name: "travel_tmpl", Value: "travel.html", Help: "浏览模块模板"}, + "travel_main": &ctx.Config{Name: "travel_main", Value: "main.html", Help: "浏览模块框架"}, + + "check": &ctx.Config{Name: "check", Value: map[string]interface{}{ + "login": []interface{}{ + map[string]interface{}{ + "session": "aaa", + "module": "aaa", "command": "login", + "variable": []interface{}{"$sessid"}, + "template": "login", "title": "login", + }, + map[string]interface{}{ + "module": "aaa", "command": "login", + "variable": []interface{}{"$username", "$password"}, + "template": "login", "title": "login", + }, + }, + "right": []interface{}{ + map[string]interface{}{ + "module": "web", "command": "right", + "variable": []interface{}{"$username", "check", "command", "/index", "dir", "$dir"}, + "template": "notice", "title": "notice", + }, + map[string]interface{}{ + "module": "aaa", "command": "login", + "variable": []interface{}{"username", "password"}, + "template": "login", "title": "login", + }, + }, + }, Help: "执行条件"}, + "auto_create": &ctx.Config{Name: "auto_create(true/false)", Value: "true", Help: "路由数量"}, + "refresh_time": &ctx.Config{Name: "refresh_time(ms)", Value: "1000", Help: "路由数量"}, + "define": &ctx.Config{Name: "define", Value: map[string]interface{}{ + "ngx_command_t": map[string]interface{}{ + "position": []interface{}{map[string]interface{}{ + "file": "nginx-1.15.2/src/core/ngx_core.h", + "line": "22", + }}, + }, + "ngx_command_s": map[string]interface{}{ + "position": map[string]interface{}{ + "file": "nginx-1.15.2/src/core/ngx_conf_file.h", + "line": "77", + }, + }, + }, Help: "路由数量"}, + "index": &ctx.Config{Name: "index", Value: map[string]interface{}{ + "duyu": []interface{}{ + map[string]interface{}{ + "template": "userinfo", "title": "userinfo", + }, + map[string]interface{}{ + "from": "root", "to": []interface{}{}, + "module": "aaa", "command": "lark", + "argument": []interface{}{}, + "template": "append", "title": "lark_friend", + }, + map[string]interface{}{ + "module": "aaa", "detail": []interface{}{"lark"}, + "template": "detail", "title": "send_lark", + "option": map[string]interface{}{"ninput": 2}, + }, + map[string]interface{}{ + "module": "aaa", "command": "lark", + "argument": []interface{}{"duyu"}, + "template": "append", "title": "lark", + }, + map[string]interface{}{ + "module": "nfs", "command": "dir", + "argument": []interface{}{"dir_type", "all", "dir_deep", "false", "dir_field", "time size line filename", "sort_field", "time", "sort_order", "time_r"}, + "template": "append", "title": "", + }, + }, + "shy": []interface{}{ + map[string]interface{}{ + "from": "root", "to": []interface{}{}, + "template": "userinfo", "title": "userinfo", + }, + //文件服务 + map[string]interface{}{ + "from": "root", "to": []interface{}{}, + "module": "nfs", "command": "dir", + "argument": []interface{}{"dir_type", "all", "dir_deep", "false", "dir_field", "time size line filename", "sort_field", "time", "sort_order", "time_r"}, + "template": "append", "title": "", + }, + map[string]interface{}{ + "from": "root", "to": []interface{}{}, + "template": "upload", "title": "upload", + }, + map[string]interface{}{ + "from": "root", "to": []interface{}{}, + "template": "create", "title": "create", + }, + //会话服务 + map[string]interface{}{ + "from": "root", "to": []interface{}{}, + "module": "cli", "command": "system", + "argument": []interface{}{"tmux", "show-buffer"}, + "template": "result", "title": "buffer", + }, + map[string]interface{}{ + "from": "root", "to": []interface{}{}, + "module": "cli", "command": "system", + "argument": []interface{}{"tmux", "list-clients"}, + "template": "result", "title": "client", + }, + map[string]interface{}{ + "from": "root", "to": []interface{}{}, + "module": "cli", "command": "system", + "argument": []interface{}{"tmux", "list-sessions"}, + "template": "result", "title": "session", + }, + //格式转换 + map[string]interface{}{ + "from": "root", "to": []interface{}{}, + "module": "cli", "detail": []interface{}{"time"}, + "template": "detail", "title": "time", + "option": map[string]interface{}{"refresh": true, "ninput": 1}, + }, + map[string]interface{}{ + "from": "root", "to": []interface{}{}, + "module": "nfs", "detail": []interface{}{"json"}, + "template": "detail", "title": "json", + "option": map[string]interface{}{"ninput": 1}, + }, + map[string]interface{}{ + "from": "root", "to": []interface{}{}, + "module": "nfs", "detail": []interface{}{"pwd"}, + "template": "detail", "title": "pwd", + "option": map[string]interface{}{"refresh": true}, + }, + map[string]interface{}{ + "from": "root", "to": []interface{}{}, + "module": "nfs", "command": "git", + "argument": []interface{}{}, + "template": "result", "title": "git", + }, + map[string]interface{}{ + "from": "root", "to": []interface{}{}, + "module": "web", "command": "/share", + "argument": []interface{}{}, + "template": "share", "title": "share", + }, + }, + "notice": []interface{}{ + map[string]interface{}{ + "template": "userinfo", "title": "userinfo", + }, + map[string]interface{}{ + "template": "notice", "title": "notice", + }, + }, + "login": []interface{}{ + map[string]interface{}{ + "template": "login", "title": "login", + }, + }, + "wiki": []interface{}{ + map[string]interface{}{ + "template": "wiki_head", "title": "wiki_head", + }, + map[string]interface{}{ + "template": "wiki_menu", "title": "wiki_menu", + }, + map[string]interface{}{ + "module": "web", "command": "/wiki_list", + "template": "wiki_list", "title": "wiki_list", + }, + map[string]interface{}{ + "module": "web", "command": "/wiki_body", + "template": "wiki_body", "title": "wiki_body", + }, + }, + }, Help: "资源列表"}, + }, Commands: map[string]*ctx.Command{ "/demo": &ctx.Command{Name: "/demo", Help: "demo", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { m.Echo("demo") }}, + "/render": &ctx.Command{Name: "/render index", Help: "模板响应, main: 模板入口, tmpl: 附加模板", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + w := m.Optionv("response").(http.ResponseWriter) + w.Header().Add("Content-Type", "text/html") + m.Optioni("ninput", 0) + + tpl := template.New("render").Funcs(ctx.CGI) + tpl = template.Must(tpl.ParseGlob(path.Join(m.Conf("template_dir"), m.Conf("common_tmpl")))) + tpl = template.Must(tpl.ParseGlob(path.Join(m.Conf("template_dir"), m.Conf("upload_tmpl")))) + + replace := [][]byte{ + []byte{27, 91, 51, 50, 109}, []byte(""), + []byte{27, 91, 51, 49, 109}, []byte(""), + []byte{27, 91, 109}, []byte(""), + } + + if m.Confv("index", arg[0]) == nil { + arg[0] = "notice" + } + + m.Assert(tpl.ExecuteTemplate(w, "head", m)) + for _, v := range m.Confv("index", arg[0]).([]interface{}) { + if v == nil { + continue + } + val := v.(map[string]interface{}) + //命令模板 + if detail, ok := val["detail"].([]interface{}); ok { + msg := m.Spawn().Add("detail", detail[0].(string), detail[1:]) + msg.Option("module", val["module"]) + msg.Option("title", val["title"]) + if option, ok := val["option"].(map[string]interface{}); ok { + for k, v := range option { + msg.Option(k, v) + } + } + + m.Assert(tpl.ExecuteTemplate(w, val["template"].(string), msg)) + continue + } + + //执行命令 + if _, ok := val["command"]; ok { + msg := m.Find(val["module"].(string)).Cmd(val["command"], val["argument"]) + for i, v := range msg.Meta["result"] { + b := []byte(v) + for i := 0; i < len(replace)-1; i += 2 { + b = bytes.Replace(b, replace[i], replace[i+1], -1) + } + msg.Meta["result"][i] = string(b) + } + if msg.Option("title", val["title"]) == "" { + msg.Option("title", m.Option("dir")) + } + m.Assert(tpl.ExecuteTemplate(w, val["template"].(string), msg)) + continue + } + + //解析模板 + if _, ok := val["template"]; ok { + m.Assert(tpl.ExecuteTemplate(w, val["template"].(string), m)) + } + } + m.Assert(tpl.ExecuteTemplate(w, "tail", m)) + }}, + + "/check": &ctx.Command{Name: "/check arg...", Help: "权限检查, cache|config|command: 接口类型, name: 接口名称, args: 其它参数", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + if login := m.Spawn().Cmd("/login"); login.Has("template") { + m.Echo("no").Copy(login, "append") + return + } + + if msg := m.Spawn().Cmd("right", m.Append("username"), "check", arg); !msg.Results(0) { + m.Echo("no").Append("message", "no right, please contact manager") + return + } + + m.Echo("ok") + + }}, + "/login": &ctx.Command{Name: "/login", Help: "用户登录", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + if m.Options("sessid") { + if aaa := m.Sess("aaa").Cmd("login", m.Option("sessid")); aaa.Results(0) { + m.Append("redirect", m.Option("referer")) + m.Append("username", aaa.Result(0)) + return + } + } + + w := m.Optionv("response").(http.ResponseWriter) + if m.Options("username") && m.Options("password") { + if aaa := m.Sess("aaa").Cmd("login", m.Option("username"), m.Option("password")); aaa.Results(0) { + http.SetCookie(w, &http.Cookie{Name: "sessid", Value: aaa.Result(0)}) + m.Append("redirect", m.Option("referer")) + m.Append("username", m.Option("username")) + return + } + } + + w.WriteHeader(http.StatusUnauthorized) + m.Append("template", "login") + + }}, + "/lookup": &ctx.Command{Name: "user", Help: "应用示例", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + if len(arg) > 0 { + m.Option("service", arg[0]) + } + msg := m.Sess("cli").Cmd("system", "sd", "lookup", m.Option("service")) + + rs := strings.Split(msg.Result(0), "\n") + i := 0 + for ; i < len(rs); i++ { + if len(rs[i]) == 0 { + break + } + fields := strings.SplitN(rs[i], ": ", 2) + m.Append(fields[0], fields[1]) + } + + lists := []interface{}{} + for i += 2; i < len(rs); i++ { + fields := strings.SplitN(rs[i], " ", 3) + if len(fields) < 3 { + break + } + lists = append(lists, map[string]interface{}{ + "ip": fields[0], + "port": fields[1], + "tags": fields[2], + }) + } + + m.Appendv("lists", lists) + m.Log("log", "%v", lists) + }}, + "upload": &ctx.Command{Name: "upload file", Help: "上传文件", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + msg := m.Spawn(m.Target()) + msg.Cmd("get", "/upload", "method", "POST", "file", "file", arg[0]) + m.Copy(msg, "result") + + }}, + "/travel": &ctx.Command{Name: "/travel", Help: "文件上传", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + // r := m.Optionv("request").(*http.Request) + // w := m.Optionv("response").(http.ResponseWriter) + + if !m.Options("dir") { + m.Option("dir", "ctx") + } + + check := m.Spawn().Cmd("/share", "/travel", "dir", m.Option("dir")) + if !check.Results(0) { + m.Copy(check, "append") + return + } + + // 权限检查 + if m.Option("method") == "POST" { + if m.Options("domain") { + msg := m.Find("ssh", true) + msg.Detail(0, "send", "domain", m.Option("domain"), "context", "find", m.Option("dir")) + if m.Option("name") != "" { + msg.Add("detail", m.Option("name")) + } + if m.Options("value") { + value := []string{} + json.Unmarshal([]byte(m.Option("value")), &value) + if len(value) > 0 { + msg.Add("detail", value[0], value[1:]) + } + } + + msg.CallBack(true, func(sub *ctx.Message) *ctx.Message { + m.Copy(sub, "result").Copy(sub, "append") + return nil + }) + return + } + + msg := m.Find(m.Option("dir"), true) + if msg == nil { + return + } + + switch m.Option("ccc") { + case "cache": + m.Echo(msg.Cap(m.Option("name"))) + case "config": + if m.Has("value") { + m.Echo(msg.Conf(m.Option("name"), m.Option("value"))) + } else { + m.Echo(msg.Conf(m.Option("name"))) + } + case "command": + msg = msg.Spawn(msg.Target()) + msg.Detail(0, m.Option("name")) + if m.Options("value") { + value := []string{} + json.Unmarshal([]byte(m.Option("value")), &value) + if len(value) > 0 { + msg.Add("detail", value[0], value[1:]) + } + } + + msg.Cmd() + m.Copy(msg, "result").Copy(msg, "append") + } + return + } + + // 解析模板 + m.Set("append", "tmpl", "userinfo", "share") + msg := m + for _, v := range []string{"cache", "config", "command", "module", "domain"} { + if m.Options("domain") { + msg = m.Find("ssh", true) + msg.Detail(0, "send", "domain", m.Option("domain"), "context", "find", m.Option("dir"), "list", v) + msg.CallBack(true, func(sub *ctx.Message) *ctx.Message { + msg.Copy(sub, "result").Copy(sub, "append") + return nil + }) + } else { + msg = m.Spawn() + msg.Cmd("context", "find", msg.Option("dir"), "list", v) + } + + if len(msg.Meta["append"]) > 0 { + msg.Option("current_module", m.Option("dir")) + msg.Option("current_domain", m.Option("domain")) + m.Add("option", "tmpl", v) + m.Sess(v, msg) + } + } + m.Append("template", m.Conf("travel_main"), m.Conf("travel_tmpl")) + + }}, + "/index/": &ctx.Command{Name: "/index", Help: "网页门户", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + r := m.Optionv("request").(*http.Request) + w := m.Optionv("response").(http.ResponseWriter) + + if login := m.Spawn().Cmd("/login"); login.Has("template") { + m.Echo("no").Copy(login, "append") + return + } + m.Option("username", m.Append("username")) + + //权限检查 + dir := m.Option("dir", path.Join(m.Cap("directory"), "local", m.Option("username"), m.Option("dir", strings.TrimPrefix(m.Option("path"), "/index")))) + // if check := m.Spawn(c).Cmd("/check", "command", "/index/", "dir", dir); !check.Results(0) { + // m.Copy(check, "append") + // return + // } + + //执行命令 + if m.Has("details") { + if m.Confs("check_right") { + if check := m.Spawn().Cmd("/check", "target", m.Option("module"), "command", m.Option("details")); !check.Results(0) { + m.Copy(check, "append") + return + } + } + + msg := m.Find(m.Option("module")).Cmd(m.Optionv("details")) + m.Copy(msg, "result").Copy(msg, "append") + return + } + + //下载文件 + if s, e := os.Stat(dir); e == nil && !s.IsDir() { + http.ServeFile(w, r, dir) + return + } + + if !m.Options("module") { + m.Option("module", "web") + } + //浏览目录 + m.Append("template", m.Append("username")) + m.Option("page_title", "index") + + }}, + "/create": &ctx.Command{Name: "/create", Help: "创建目录或文件", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + // if check := m.Spawn().Cmd("/share", "/upload", "dir", m.Option("dir")); !check.Results(0) { + // m.Copy(check, "append") + // return + // } + + r := m.Optionv("request").(*http.Request) + if m.Option("method") == "POST" { + if m.Options("filename") { //添加文件或目录 + name := path.Join(m.Option("dir"), m.Option("filename")) + if _, e := os.Stat(name); e != nil { + if m.Options("content") { + f, e := os.Create(name) + m.Assert(e) + defer f.Close() + + _, e = f.WriteString(m.Option("content")) + m.Assert(e) + } else { + e = os.Mkdir(name, 0766) + m.Assert(e) + } + m.Append("message", name, " create success!") + } else { + m.Append("message", name, " already exist!") + } + } else { //上传文件 + file, header, e := r.FormFile("file") + m.Assert(e) + + name := path.Join(m.Option("dir"), header.Filename) + + if _, e := os.Stat(name); e != nil { + f, e := os.Create(name) + m.Assert(e) + defer f.Close() + + _, e = io.Copy(f, file) + m.Assert(e) + m.Append("message", name, " upload success!") + } else { + m.Append("message", name, " already exist!") + } + } + } + m.Append("redirect", m.Option("referer")) + + }}, + "/share": &ctx.Command{Name: "/share arg...", Help: "资源共享", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + if check := m.Spawn().Cmd("/check", "target", m.Option("module"), m.Optionv("share")); !check.Results(0) { + m.Copy(check, "append") + return + } + m.Option("username", m.Append("username")) + + // if m.Options("friend") && m.Options("module") { + // m.Copy(m.Appendv("aaa").(*ctx.Message).Find(m.Option("module")).Cmd("right", m.Option("friend"), m.Option("action"), m.Optionv("share")), "result") + // if m.Confv("index", m.Option("friend")) == nil { + // m.Confv("index", m.Option("friend"), m.Confv("index", m.Append("username"))) + // } + // return + // } + // + // msg := m.Spawn().Cmd("right", "target", m.Option("module"), m.Append("username"), "show", "context") + // m.Copy(msg, "append") + if m.Options("friend") && m.Options("template") && m.Options("title") { + for i, v := range m.Confv("index", m.Option("username")).([]interface{}) { + if v == nil { + continue + } + val := v.(map[string]interface{}) + if val["template"].(string) == m.Option("template") && val["title"].(string) == m.Option("title") { + if m.Option("action") == "del" { + friends := m.Confv("index", strings.Join([]string{m.Option("username"), fmt.Sprintf("%d", i), "to"}, ".")).([]interface{}) + for j, x := range friends { + if x.(string) == m.Option("friend") { + m.Confv("index", strings.Join([]string{m.Option("username"), fmt.Sprintf("%d", i), "to", fmt.Sprintf("%d", j)}, "."), nil) + } + } + + temps := m.Confv("index", strings.Join([]string{m.Option("friend")}, ".")).([]interface{}) + for j, x := range temps { + if x == nil { + continue + } + val = x.(map[string]interface{}) + if val["template"].(string) == m.Option("template") && val["title"].(string) == m.Option("title") { + m.Confv("index", strings.Join([]string{m.Option("friend"), fmt.Sprintf("%d", j)}, "."), nil) + } + } + + break + } + + if m.Confv("index", m.Option("friend")) == nil && !m.Confs("auto_create") { + break + } + m.Confv("index", strings.Join([]string{m.Option("username"), fmt.Sprintf("%d", i), "to", "-2"}, "."), m.Option("friend")) + + item := map[string]interface{}{ + "template": val["template"], + "title": val["title"], + "from": m.Option("username"), + } + if val["command"] != nil { + item["module"] = val["module"] + item["command"] = val["command"] + item["argument"] = val["argument"] + } else if val["detail"] != nil { + item["module"] = val["module"] + item["detail"] = val["detail"] + item["option"] = val["option"] + } + + m.Confv("index", strings.Join([]string{m.Option("friend"), fmt.Sprintf("%d", -2)}, "."), item) + m.Appendv("aaa").(*ctx.Message).Spawn(c).Cmd("right", m.Option("friend"), "add", "command", "/index/", "dir", m.Cap("directory")) + os.Mkdir(path.Join(m.Cap("directory"), m.Option("friend")), 0666) + break + } + } + return + } + for _, v := range m.Confv("index", m.Option("username")).([]interface{}) { + val := v.(map[string]interface{}) + m.Add("append", "template", val["template"]) + m.Add("append", "titles", val["title"]) + m.Add("append", "from", val["from"]) + m.Add("append", "to", "") + if val["to"] == nil { + continue + } + for _, u := range val["to"].([]interface{}) { + m.Add("append", "template", val["template"]) + m.Add("append", "titles", val["title"]) + m.Add("append", "from", val["from"]) + m.Add("append", "to", u) + } + } + + }}, }, } diff --git a/src/examples/wiki/wiki.go b/src/examples/wiki/wiki.go index 7cad805d..ed5772bc 100644 --- a/src/examples/wiki/wiki.go +++ b/src/examples/wiki/wiki.go @@ -1,19 +1,24 @@ package wiki import ( + "os/exec" + "time" + "bufio" + "bytes" "contexts/ctx" "contexts/web" + "encoding/json" "encoding/xml" - "github.com/gomarkdown/markdown" - "io/ioutil" - "net/http" - "path" - - "bytes" - "fmt" + "github.com/gomarkdown/markdown" + "io" + "io/ioutil" + "mime/multipart" + "net/http" "os" + "path" + "path/filepath" "strings" ) @@ -342,6 +347,264 @@ var Index = &ctx.Context{Name: "wiki", Help: "文档中心", m.Echo(string(b)) } }}, + "old_get": &ctx.Command{ + Name: "get [method GET|POST] [file name filename] url arg...", + Help: "访问服务, method: 请求方法, file: 发送文件, url: 请求地址, arg: 请求参数", + Form: map[string]int{"method": 1, "content_type": 1, "headers": 2, "file": 2, "body_type": 1, "body": 1, "fields": 1, "value": 1, "json_route": 1, "json_key": 1}, + Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + if web, ok := m.Target().Server.(*web.WEB); m.Assert(ok) { + if web.Client == nil { + web.Client = &http.Client{} + } + + if m.Has("value") { + args := strings.Split(m.Option("value"), " ") + values := []interface{}{} + for _, v := range args { + if len(v) > 1 && v[0] == '$' { + values = append(values, m.Cap(v[1:])) + } else { + values = append(values, v) + } + } + arg[0] = fmt.Sprintf(arg[0], values...) + } + + method := m.Confx("method") + uri := web.Merge(m, arg[0], arg[1:]...) + m.Log("info", "%s %s", method, uri) + m.Echo("%s: %s\n", method, uri) + + var body io.Reader + index := strings.Index(uri, "?") + content_type := "" + + switch method { + case "POST": + if m.Options("file") { + file, e := os.Open(m.Meta["file"][1]) + m.Assert(e) + defer file.Close() + + if m.Option("body_type") == "json" { + content_type = "application/json" + body = file + break + } + buf := &bytes.Buffer{} + writer := multipart.NewWriter(buf) + + part, e := writer.CreateFormFile(m.Option("file"), filepath.Base(m.Meta["file"][1])) + m.Assert(e) + io.Copy(part, file) + + for i := 0; i < len(arg)-1; i += 2 { + value := arg[i+1] + if len(arg[i+1]) > 1 { + switch arg[i+1][0] { + case '$': + value = m.Cap(arg[i+1][1:]) + case '@': + value = m.Conf(arg[i+1][1:]) + } + } + writer.WriteField(arg[i], value) + } + + content_type = writer.FormDataContentType() + body = buf + writer.Close() + } else if m.Option("body_type") == "json" { + if m.Options("body") { + data := []interface{}{} + for _, v := range arg[1:] { + if len(v) > 1 && v[0] == '$' { + v = m.Cap(v[1:]) + } + data = append(data, v) + } + body = strings.NewReader(fmt.Sprintf(m.Option("body"), data...)) + } else { + data := map[string]interface{}{} + for i := 1; i < len(arg)-1; i += 2 { + switch arg[i+1] { + case "false": + data[arg[i]] = false + case "true": + data[arg[i]] = true + default: + if len(arg[i+1]) > 1 && arg[i+1][0] == '$' { + data[arg[i]] = m.Cap(arg[i+1][1:]) + } else { + data[arg[i]] = arg[i+1] + } + } + } + + b, e := json.Marshal(data) + m.Assert(e) + body = bytes.NewReader(b) + } + + content_type = "application/json" + if index > -1 { + uri = uri[:index] + } + + } else if index > 0 { + content_type = "application/x-www-form-urlencoded" + body = strings.NewReader(uri[index+1:]) + uri = uri[:index] + } + } + + req, e := http.NewRequest(method, uri, body) + m.Assert(e) + for i := 0; i < len(m.Meta["headers"]); i += 2 { + req.Header.Set(m.Meta["headers"][i], m.Meta["headers"][i+1]) + } + + if len(content_type) > 0 { + req.Header.Set("Content-Type", content_type) + m.Log("info", "content-type: %s", content_type) + } + + for _, v := range m.Confv("cookie").(map[string]interface{}) { + req.AddCookie(v.(*http.Cookie)) + } + + res, e := web.Client.Do(req) + m.Assert(e) + + for _, v := range res.Cookies() { + m.Confv("cookie", v.Name, v) + m.Log("info", "set-cookie %s: %v", v.Name, v.Value) + } + + if m.Confs("logheaders") { + for k, v := range res.Header { + m.Log("info", "%s: %v", k, v) + } + } + + if m.Confs("output") { + if _, e := os.Stat(m.Conf("output")); e == nil { + name := path.Join(m.Conf("output"), fmt.Sprintf("%d", time.Now().Unix())) + f, e := os.Create(name) + m.Assert(e) + io.Copy(f, res.Body) + if m.Confs("editor") { + cmd := exec.Command(m.Conf("editor"), name) + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Run() + } else { + m.Echo("write to %s\n", name) + } + return + } + } + + buf, e := ioutil.ReadAll(res.Body) + m.Assert(e) + + ct := res.Header.Get("Content-Type") + if len(ct) >= 16 && ct[:16] == "application/json" { + var result interface{} + json.Unmarshal(buf, &result) + m.Option("response_json", result) + if m.Has("json_route") { + routes := strings.Split(m.Option("json_route"), ".") + for _, k := range routes { + if len(k) > 0 && k[0] == '$' { + k = m.Cap(k[1:]) + } + switch r := result.(type) { + case map[string]interface{}: + result = r[k] + } + } + } + + fields := map[string]bool{} + for _, k := range strings.Split(m.Option("fields"), " ") { + if k == "" { + continue + } + if fields[k] = true; len(fields) == 1 { + m.Meta["append"] = append(m.Meta["append"], "index") + } + m.Meta["append"] = append(m.Meta["append"], k) + } + + if len(fields) > 0 { + + switch ret := result.(type) { + case map[string]interface{}: + m.Append("index", "0") + for k, v := range ret { + switch value := v.(type) { + case string: + m.Append(k, strings.Replace(value, "\n", " ", -1)) + case float64: + m.Append(k, fmt.Sprintf("%d", int(value))) + default: + if _, ok := fields[k]; ok { + m.Append(k, fmt.Sprintf("%v", value)) + } + } + } + case []interface{}: + for i, r := range ret { + m.Add("append", "index", i) + if rr, ok := r.(map[string]interface{}); ok { + for k, v := range rr { + switch value := v.(type) { + case string: + if _, ok := fields[k]; len(fields) == 0 || ok { + m.Add("append", k, strings.Replace(value, "\n", " ", -1)) + } + case float64: + if _, ok := fields[k]; len(fields) == 0 || ok { + m.Add("append", k, fmt.Sprintf("%d", int64(value))) + } + case bool: + if _, ok := fields[k]; len(fields) == 0 || ok { + m.Add("append", k, fmt.Sprintf("%v", value)) + } + case map[string]interface{}: + for kk, vv := range value { + key := k + "." + kk + if _, ok := fields[key]; len(fields) == 0 || ok { + m.Add("append", key, strings.Replace(fmt.Sprintf("%v", vv), "\n", " ", -1)) + } + } + default: + if _, ok := fields[k]; ok { + m.Add("append", k, fmt.Sprintf("%v", value)) + } + } + } + } + } + + if m.Has("json_key") { + m.Sort(m.Option("json_key")) + } + m.Meta["index"] = nil + for i, _ := range ret { + m.Add("append", "index", i) + } + } + } + } + + if m.Table(); len(m.Meta["append"]) == 0 { + m.Echo("%s", string(buf)) + } + } + }}, }, } From 9c90712446ae55ecc3c75a8a102188d1ce4178d1 Mon Sep 17 00:00:00 2001 From: shaoying Date: Mon, 22 Oct 2018 09:16:31 +0800 Subject: [PATCH 2/2] mac add aaa.right web.render --- etc/init.shy | 12 - src/contexts/aaa/aaa.go | 99 ++++++- src/contexts/cli/cli.go | 131 +++++----- src/contexts/ctx/ctx.go | 123 +++++++-- src/contexts/nfs/nfs.go | 67 +++-- src/contexts/web/web.go | 453 ++++++++++++++++++++++++++++++--- usr/library/base.js | 239 +++++++++++++---- usr/library/context.js | 235 +++-------------- usr/library/wiki.js | 211 --------------- usr/template/common/base.html | 145 ----------- usr/template/common/base.tmpl | 138 ++++++++++ usr/template/common/login.html | 94 ------- usr/template/common/main.html | 9 - usr/template/common/wiki.html | 222 ---------------- usr/template/travel.html | 431 ------------------------------- usr/template/upload.html | 163 ------------ 16 files changed, 1085 insertions(+), 1687 deletions(-) delete mode 100644 usr/library/wiki.js delete mode 100644 usr/template/common/base.html create mode 100644 usr/template/common/base.tmpl delete mode 100644 usr/template/common/login.html delete mode 100644 usr/template/common/main.html delete mode 100644 usr/template/common/wiki.html delete mode 100644 usr/template/travel.html delete mode 100644 usr/template/upload.html diff --git a/etc/init.shy b/etc/init.shy index 5bfdb1e3..a95b3d83 100644 --- a/etc/init.shy +++ b/etc/init.shy @@ -1,14 +1,2 @@ -~aaa - # login load var/login.txt -~file1 - history load var/history.txt - source etc/local.shy -~shell1 - alias import nfs - alias send send - alias open open - alias dial dial - alias pwd pwd - diff --git a/src/contexts/aaa/aaa.go b/src/contexts/aaa/aaa.go index cce25fb9..224742e0 100644 --- a/src/contexts/aaa/aaa.go +++ b/src/contexts/aaa/aaa.go @@ -69,7 +69,9 @@ func (aaa *AAA) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server return time.Unix(int64(n), 0).Format("15:03:04") }}, } - c.Configs = map[string]*ctx.Config{} + c.Configs = map[string]*ctx.Config{ + "right": &ctx.Config{Name: "right", Value: map[string]interface{}{}, Help: "用户权限"}, + } s := new(AAA) s.Context = c @@ -153,6 +155,7 @@ var Index = &ctx.Context{Name: "aaa", Help: "认证中心", } return true }, c) + if m.Results(0) { return } @@ -173,18 +176,26 @@ var Index = &ctx.Context{Name: "aaa", Help: "认证中心", } return true }, c) + if m.Results(0) { + m.Append("sessid", m.Result(0)) + return + } + if arg[0] == "" { return } m.Start(fmt.Sprintf("user%d", m.Capi("nuser", 1)), "密码登录", "password", arg[0]) m.Cap("password", "password", aaa.Password(arg[1]), "密码登录") + m.Append("sessid", m.Cap("sessid")) m.Echo(m.Cap("sessid")) return case 1: + m.Sess("login", nil) m.Travel(func(m *ctx.Message, n int) bool { if n > 0 && m.Cap("sessid") == arg[0] { if int64(m.Capi("expire_time")) > time.Now().Unix() { + m.Sess("login", m.Target().Message()) m.Echo(m.Cap("stream")) } else { m.Target().Close(m) @@ -205,6 +216,92 @@ var Index = &ctx.Context{Name: "aaa", Help: "认证中心", } } }}, + "right": &ctx.Command{Name: "right [user [check|owner|share group [order] [add|del]]]", Form: map[string]int{"from": 1}, Help: "权限管理", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + m.Travel(func(m *ctx.Message, n int) bool { + if n == 0 { + return true + } + if len(arg) == 0 { + m.Add("append", "user", m.Cap("stream")) + m.Add("append", "right", m.Confv("right")) + return true + } + if m.Cap("stream") == arg[0] { + if len(arg) == 1 { //查看所有权 + for k, v := range m.Confv("right").(map[string]interface{}) { + m.Add("append", "group", k) + m.Add("append", "right", v) + } + return true + } + if arg[1] == "check" { //权限检查 + if from := m.Confv("right", []interface{}{"right", "role"}); from != nil && from.(string) == "root" { + m.Echo("root") + } + if len(arg) == 2 { + return false + } + if from := m.Confv("right", []interface{}{arg[2], "right", "role"}); from != nil && from.(string) == "owner" { + m.Echo("owner") + } + if len(arg) == 3 { + return false + } + if from := m.Confv("right", []interface{}{arg[2], arg[3], "right", "role"}); from != nil && from.(string) == "share" { + m.Echo("share") + } + return false + } + if len(arg) == 2 { //分配人事权 + if m.Option("from") != "root" { + return false + } + switch arg[1] { + case "add": + m.Confv("right", []interface{}{"right", "role"}, "root") + m.Confv("right", []interface{}{"right", "from"}, m.Option("from")) + case "del": + m.Confv("right", []interface{}{"right", "role"}, "") + } + return true + } + if len(arg) == 3 { //查看使用权 + for k, v := range m.Confv("right", arg[2]).(map[string]interface{}) { + m.Add("append", "order", k) + m.Add("append", "right", v) + } + return true + } + switch arg[1] { + case "owner": //分配所有权 + if m.Cmd("right", m.Option("from"), "check").Result(0) == "" { + return false + } + switch arg[3] { + case "add": + m.Confv("right", []interface{}{arg[2], "right", "role"}, "owner") + m.Confv("right", []interface{}{arg[2], "right", "from"}, m.Option("from")) + case "del": + m.Confv("right", []interface{}{arg[2], "right", "role"}, "") + } + case "share": //分配使用权 + if m.Cmd("right", m.Option("from"), "check", arg[2]).Result(0) == "" { + return false + } + switch arg[4] { + case "add": + m.Confv("right", []interface{}{arg[2], arg[3], "right", "role"}, "share") + m.Confv("right", []interface{}{arg[2], arg[3], "right", "from"}, m.Option("from")) + case "del": + m.Confv("right", []interface{}{arg[2], arg[3], "right", "role"}, "") + } + } + return false + } + return true + }, c) + m.Table() + }}, "cert": &ctx.Command{Name: "cert [filename]", Help: "导出证书", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { if aaa, ok := m.Target().Server.(*AAA); m.Assert(ok) && aaa.certificate != nil { certificate := string(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: aaa.certificate.Raw})) diff --git a/src/contexts/cli/cli.go b/src/contexts/cli/cli.go index 09596344..5420c38d 100644 --- a/src/contexts/cli/cli.go +++ b/src/contexts/cli/cli.go @@ -1,20 +1,16 @@ -package cli // {{{ -// }}} -import ( // {{{ - "contexts/ctx" +package cli +import ( + "contexts/ctx" "fmt" + "os" + "os/exec" "regexp" "strconv" "strings" - - "os" - "os/exec" "time" ) -// }}} - type Frame struct { key string run bool @@ -22,7 +18,6 @@ type Frame struct { index int list []string } - type CLI struct { alias map[string][]string label map[string]string @@ -33,7 +28,7 @@ type CLI struct { *ctx.Context } -func (cli *CLI) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server { // {{{ +func (cli *CLI) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server { c.Caches = map[string]*ctx.Cache{ "level": &ctx.Cache{Name: "level", Value: "0", Help: "嵌套层级"}, "parse": &ctx.Cache{Name: "parse(true/false)", Value: "true", Help: "命令解析"}, @@ -43,15 +38,15 @@ func (cli *CLI) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server } c.Configs = map[string]*ctx.Config{ "ps_time": &ctx.Config{Name: "ps_time", Value: "[15:04:05]", Help: "当前时间", Hand: func(m *ctx.Message, x *ctx.Config, arg ...string) string { - if len(arg) > 0 { // {{{ + if len(arg) > 0 { return arg[0] } return time.Now().Format(x.Value.(string)) - // }}} + }}, "ps_end": &ctx.Config{Name: "ps_end", Value: "> ", Help: "命令行提示符结尾"}, "prompt": &ctx.Config{Name: "prompt(ps_count/ps_time/ps_target/ps_end/...)", Value: "ps_count ps_time ps_target ps_end", Help: "命令行提示符, 以空格分隔, 依次显示缓存或配置信息", Hand: func(m *ctx.Message, x *ctx.Config, arg ...string) string { - if len(arg) > 0 { // {{{ + if len(arg) > 0 { return arg[0] } @@ -64,7 +59,7 @@ func (cli *CLI) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server } } return strings.Join(ps, "") - // }}} + }}, } @@ -83,15 +78,11 @@ func (cli *CLI) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server return s } - -// }}} -func (cli *CLI) Begin(m *ctx.Message, arg ...string) ctx.Server { // {{{ +func (cli *CLI) Begin(m *ctx.Message, arg ...string) ctx.Server { cli.Message = m return cli } - -// }}} -func (cli *CLI) Start(m *ctx.Message, arg ...string) bool { // {{{ +func (cli *CLI) Start(m *ctx.Message, arg ...string) bool { cli.Message = m m.Sess("cli", m) yac := m.Sess("yac") @@ -178,9 +169,7 @@ func (cli *CLI) Start(m *ctx.Message, arg ...string) bool { // {{{ } return false } - -// }}} -func (cli *CLI) Close(m *ctx.Message, arg ...string) bool { // {{{ +func (cli *CLI) Close(m *ctx.Message, arg ...string) bool { switch cli.Context { case m.Target(): case m.Source(): @@ -188,8 +177,6 @@ func (cli *CLI) Close(m *ctx.Message, arg ...string) bool { // {{{ return true } -// }}} - var Pulse *ctx.Message var Index = &ctx.Context{Name: "cli", Help: "管理中心", Caches: map[string]*ctx.Cache{ @@ -199,11 +186,11 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", "init.shy": &ctx.Config{Name: "init.shy", Value: "etc/init.shy", Help: "启动脚本"}, "exit.shy": &ctx.Config{Name: "exit.shy", Value: "etc/exit.shy", Help: "启动脚本"}, "cli_name": &ctx.Config{Name: "cli_name", Value: "shell", Help: "模块命名", Hand: func(m *ctx.Message, x *ctx.Config, arg ...string) string { - if len(arg) > 0 { // {{{ + if len(arg) > 0 { return arg[0] } return fmt.Sprintf("%s%d", x.Value, m.Capi("nshell", 1)) - // }}} + }}, "cli_help": &ctx.Config{Name: "cli_help", Value: "shell", Help: "模块文档"}, "cmd_timeout": &ctx.Config{Name: "cmd_timeout", Value: "60s", Help: "系统命令超时"}, @@ -239,28 +226,28 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", } }}, "label": &ctx.Command{Name: "label name", Help: "记录当前脚本的位置, name: 位置名", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{ + if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { if cli.label == nil { cli.label = map[string]string{} } cli.label[arg[1]] = m.Option("file_pos") - } // }}} + } }}, "goto": &ctx.Command{Name: "goto label [exp] condition", Help: "向上跳转到指定位置, label: 跳转位置, condition: 跳转条件", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{ + if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { if pos, ok := cli.label[arg[1]]; ok { if !ctx.Right(arg[len(arg)-1]) { return } m.Append("file_pos0", pos) } - } // }}} + } }}, "return": &ctx.Command{Name: "return result...", Help: "结束脚本, result: 返回值", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { m.Add("append", "return", arg[1:]) }}, "target": &ctx.Command{Name: "target module", Help: "设置当前模块, module: 模块全名", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{ + if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { if len(arg) == 0 { m.Echo("%s", m.Cap("ps_target")) return @@ -269,13 +256,13 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", cli.target = msg.Target() m.Cap("ps_target", cli.target.Name) } - } // }}} + } }}, "alias": &ctx.Command{ Name: "alias [short [long...]]|[delete short]|[import module [command [alias]]]", Help: "查看、定义或删除命令别名, short: 命令别名, long: 命令原名, delete: 删除别名, import导入模块所有命令", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{ + if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { switch len(arg) { case 0: for k, v := range cli.alias { @@ -318,21 +305,21 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", m.Log("info", "%s: %v", arg[0], cli.alias[arg[0]]) } } - } // }}} + } }}, "sleep": &ctx.Command{Name: "sleep time", Help: "睡眠, time(ns/us/ms/s/m/h): 时间值(纳秒/微秒/毫秒/秒/分钟/小时)", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - if d, e := time.ParseDuration(arg[0]); m.Assert(e) { // {{{ + if d, e := time.ParseDuration(arg[0]); m.Assert(e) { m.Log("info", "sleep %v", d) time.Sleep(d) m.Log("info", "sleep %v done", d) - } // }}} + } }}, "time": &ctx.Command{ Name: "time [time_format format] [parse when] when [begin|end|yestoday|tommorow|monday|sunday|first|last|origin|last]", Form: map[string]int{"time_format": 1, "parse": 1, "time_interval": 1}, Help: "查看时间, time_format: 输出或解析的时间格式, parse: 输入的时间字符串, when: 输入的时间戳, 其它是时间偏移", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - t := time.Now() // {{{ + t := time.Now() if m.Options("parse") { n, e := time.ParseInLocation(m.Confx("time_format"), m.Option("parse"), time.Local) m.Assert(e) @@ -341,7 +328,6 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", if len(arg) > 0 { if i, e := strconv.ParseInt(arg[0], 10, 64); e == nil { - m.Option("time_format", m.Conf("time_format")) t = time.Unix(int64(i/int64(m.Confi("time_unit"))), 0) arg = arg[1:] } else if n, e := time.ParseInLocation(m.Confx("time_format"), arg[0], time.Local); e == nil { @@ -405,7 +391,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", } else { m.Echo(t.Format(m.Confx("time_format"))) } - // }}} + }}, "echo": &ctx.Command{Name: "echo arg...", Help: "函数调用, name: 函数名, arg: 参数", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { m.Echo("%s", strings.Join(arg, "")) @@ -415,7 +401,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", m.Echo(arg[0][1 : len(arg[0])-1]) }}, "exe": &ctx.Command{Name: "exe $ ( cmd )", Help: "解析嵌套命令", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{ + if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { switch len(arg) { case 1: m.Echo(arg[0]) @@ -438,7 +424,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", } //}}} }}, "val": &ctx.Command{Name: "val exp", Help: "表达式运算", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - result := "false" // {{{ + result := "false" switch len(arg) { case 0: result = "" @@ -567,7 +553,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", } } m.Echo(result) - // }}} + }}, "exp": &ctx.Command{Name: "exp word", Help: "表达式运算", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { if len(arg) > 0 && arg[0] == "{" { @@ -585,7 +571,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", return } - pre := map[string]int{ // {{{ + pre := map[string]int{ "=": 1, "+": 2, "-": 2, "*": 3, "/": 3, "%": 3, @@ -609,10 +595,10 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", } m.Echo("%s", num[0]) - // }}} + }}, "var": &ctx.Command{Name: "var a [= exp]", Help: "定义变量, a: 变量名, exp: 表达式", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - if m.Cap(arg[1], arg[1], "", "临时变量"); len(arg) > 1 { // {{{ + if m.Cap(arg[1], arg[1], "", "临时变量"); len(arg) > 1 { switch arg[2] { case "=": m.Cap(arg[1], arg[3]) @@ -621,28 +607,28 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", } } m.Echo(m.Cap(arg[1])) - // }}} + }}, "let": &ctx.Command{Name: "let a = exp", Help: "设置变量, a: 变量名, exp: 表达式(a {+|-|*|/|%} b)", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - switch arg[2] { // {{{ + switch arg[2] { case "=": m.Cap(arg[1], arg[3]) case "<-": m.Cap(arg[1], m.Cap("last_msg")) } m.Echo(m.Cap(arg[1])) - // }}} + }}, "if": &ctx.Command{Name: "if exp", Help: "条件语句, exp: 表达式", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{ + if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { run := m.Caps("parse") && ctx.Right(arg[1]) cli.stack = append(cli.stack, &Frame{pos: m.Optioni("file_pos"), key: key, run: run}) m.Capi("level", 1) m.Caps("parse", run) - } // }}} + } }}, "else": &ctx.Command{Name: "else", Help: "条件语句", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{ + if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { if !m.Caps("parse") { m.Caps("parse", true) } else { @@ -653,10 +639,10 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", m.Caps("parse", !frame.run) } } - } // }}} + } }}, "end": &ctx.Command{Name: "end", Help: "结束语句", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{ + if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { if frame := cli.stack[len(cli.stack)-1]; frame.key == "for" && frame.run { m.Append("file_pos0", frame.pos) return @@ -667,13 +653,13 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", } else { m.Caps("parse", true) } - } // }}} + } }}, "for": &ctx.Command{ Name: "for [[express ;] condition]|[index message meta value]", Help: "循环语句, express: 每次循环运行的表达式, condition: 循环条件, index: 索引消息, message: 消息编号, meta: value: ", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{ + if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { run := m.Caps("parse") defer func() { m.Caps("parse", run) }() @@ -726,10 +712,10 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", } m.Cap(arg[3], arg[3], frame.list[0], "临时变量") } - } // }}} + } }}, "cmd": &ctx.Command{Name: "cmd word", Help: "", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{ + if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { detail := []string{} if a, ok := cli.alias[arg[0]]; ok { detail = append(detail, a...) @@ -774,14 +760,14 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", m.Capi("last_msg", 0, msg.Code()) m.Capi("ps_count", 1) } - // }}} + }}, "system": &ctx.Command{ Name: "system [cmd_combine true|false] [cmd_timeout time] word...", Help: "调用系统命令, cmd_combine: 非交互式命令, cmd_timeout: 命令超时, word: 命令", Form: map[string]int{"cmd_combine": 1, "cmd_timeout": 1}, Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - system := map[string]bool{"vi": true} // {{{ + system := map[string]bool{"vi": true} ui, ok := system[arg[0]] if ui = ok && ui; m.Option("cmd_combine") != "" { ui = !m.Options("cmd_combine") @@ -816,7 +802,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", case <-wait: } } - // }}} + }}, "login": &ctx.Command{Name: "login username password", Help: "", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { m.Sess("aaa", false).Cmd("login", arg[0], arg[1]) @@ -827,6 +813,27 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", "tmux": &ctx.Command{Name: "tmux", Help: "", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { m.Copy(m.Spawn().Cmd("system", "tmux", arg), "result") }}, + "buffer": &ctx.Command{Name: "buffer", Help: "", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + bufs := strings.Split(m.Spawn().Cmd("system", "tmux", "list-buffers").Result(0), "\n") + + n := 3 + if m.Option("limit") != "" { + n = m.Optioni("limit") + } + + for i, b := range bufs { + if i >= n { + break + } + bs := strings.SplitN(b, ": ", 3) + if len(bs) > 1 { + m.Add("append", "buffer", bs[0][:len(bs[0])]) + m.Add("append", "length", bs[1][:len(bs[1])-6]) + m.Add("append", "string", bs[2][1:len(bs[2])-1]) + } + } + m.Echo(m.Append("string")) + }}, }, Index: map[string]*ctx.Context{ "void": &ctx.Context{Caches: map[string]*ctx.Cache{"nshell": &ctx.Cache{}}}, diff --git a/src/contexts/ctx/ctx.go b/src/contexts/ctx/ctx.go index 2544921a..b5abe2ca 100644 --- a/src/contexts/ctx/ctx.go +++ b/src/contexts/ctx/ctx.go @@ -709,7 +709,14 @@ func (m *Message) Search(key string, root ...bool) []*Message { } func (m *Message) Sess(key string, arg ...interface{}) *Message { spawn := true - if _, ok := m.Sessions[key]; !ok && len(arg) > 0 { + if len(arg) > 0 { + switch v := arg[0].(type) { + case bool: + spawn, arg = v, arg[1:] + } + } + + if len(arg) > 0 { if m.Sessions == nil { m.Sessions = make(map[string]*Message) } @@ -747,13 +754,9 @@ func (m *Message) Sess(key string, arg ...interface{}) *Message { m.Sessions[key] = m.Search(value, root)[0] } return m.Sessions[key] - } - } - - if len(arg) > 0 { - switch v := arg[0].(type) { - case bool: - spawn = v + case nil: + m.Sessions[key] = nil + return nil } } @@ -1077,6 +1080,14 @@ func (m *Message) Sort(key string, arg ...string) *Message { for j := i + 1; j < len(table); j++ { result := false switch cmp { + case "str": + if table[i][key] > table[j][key] { + result = true + } + case "str_r": + if table[i][key] < table[j][key] { + result = true + } case "int": a, e := strconv.Atoi(table[i][key]) m.Assert(e) @@ -1093,14 +1104,6 @@ func (m *Message) Sort(key string, arg ...string) *Message { if a < b { result = true } - case "string": - if table[i][key] > table[j][key] { - result = true - } - case "string_r": - if table[i][key] < table[j][key] { - result = true - } case "time": ti, e := time.ParseInLocation(m.Confx("time_layout"), table[i][key], time.Local) m.Assert(e) @@ -1964,16 +1967,18 @@ var CGI = template.FuncMap{ m.Assert(e) index = i } + if len(arg) == 2 { return m.Detail(index) } + return m.Detail(index, arg[2]) case map[string][]string: return strings.Join(m["detail"], "") case []string: return strings.Join(m, "") default: - return fmt.Sprintf("%v", arg[0]) + return m } return "" }, @@ -2016,7 +2021,7 @@ var CGI = template.FuncMap{ case []string: return strings.Join(m, "") default: - return fmt.Sprintf("%v", arg[0]) + return m } return "" }, @@ -2040,16 +2045,18 @@ var CGI = template.FuncMap{ m.Assert(e) index = i } + if len(arg) == 2 { return m.Result(index) } + return m.Result(index, arg[2]) case map[string][]string: return strings.Join(m["result"], "") case []string: return strings.Join(m, "") default: - return fmt.Sprintf("%v", arg[0]) + return m } return "" }, @@ -2092,11 +2099,55 @@ var CGI = template.FuncMap{ case []string: return strings.Join(m, "") default: - return fmt.Sprintf("%v", arg[0]) + return m } return "" }, - "unscaped": func(str string) interface{} { + "table": func(arg ...interface{}) []interface{} { + if len(arg) == 0 { + return []interface{}{} + } + + switch m := arg[0].(type) { + case *Message: + if len(m.Meta["append"]) == 0 { + return []interface{}{} + } + if len(arg) == 1 { + data := []interface{}{} + nrow := len(m.Meta[m.Meta["append"][0]]) + for i := 0; i < nrow; i++ { + line := map[string]string{} + for _, k := range m.Meta["append"] { + line[k] = m.Meta[k][i] + if len(m.Meta[k]) != i { + continue + } + } + data = append(data, line) + } + + return data + } + case map[string][]string: + if len(arg) == 1 { + data := []interface{}{} + nrow := len(m[m["append"][0]]) + + for i := 0; i < nrow; i++ { + line := map[string]string{} + for _, k := range m["append"] { + line[k] = m[k][i] + } + data = append(data, line) + } + + return data + } + } + return []interface{}{} + }, + "unescape": func(str string) interface{} { return template.HTML(str) }, @@ -2978,7 +3029,8 @@ var Index = &Context{Name: "ctx", Help: "模块中心", "where_field": 1, "where_value": 1, "sort_field": 1, "sort_order": 1, "page_limit": 1, "page_offset": 1, - "select": 3, + "format_field": 2, + "select": 3, }, Hand: func(m *Message, c *Context, key string, arg ...string) { offset, e := strconv.Atoi(m.Confx("page_offset")) @@ -3022,6 +3074,12 @@ var Index = &Context{Name: "ctx", Help: "模块中心", de.Decode(&save) } + format_field := m.Option("format_field") + format_str := "%s" + if format_field != "" { + format_str = m.Meta["format_field"][1] + } + // sort_field := m.Option("sort_field") // sort_order := m.Option("sort_order") m.BackTrace(func(m *Message) bool { @@ -3113,7 +3171,11 @@ var Index = &Context{Name: "ctx", Help: "模块中心", m.Add("append", "index", "0") for k, v := range val { if len(fields) == 0 || fields[k] { - m.Add("append", k, v) + if k == format_field { + m.Add("append", k, fmt.Sprintf(format_str, v)) + } else { + m.Add("append", k, v) + } } } case []interface{}: @@ -3134,7 +3196,11 @@ var Index = &Context{Name: "ctx", Help: "模块中心", m.Add("append", "index", i) for k, v := range val { if len(fields) == 0 || fields[k] { - m.Add("append", k, v) + if k == format_field { + m.Add("append", k, fmt.Sprintf(format_str, v, v)) + } else { + m.Add("append", k, v) + } } } } @@ -3142,11 +3208,18 @@ var Index = &Context{Name: "ctx", Help: "模块中心", case []string: for i, v := range val { m.Add("append", "index", i) - m.Add("append", "value", v) + if k == format_field { + m.Add("append", k, fmt.Sprintf(format_str, v, v)) + } else { + m.Add("append", k, v) + } } default: m.Echo("%v", Trans(val)[0]) } + case 3: + m.Echo("%v", m.Confv(arg[0], strings.Split(arg[1], "."), arg[2])) + default: m.Echo("%v", m.Confv(arg[0], arg[1:])) return false diff --git a/src/contexts/nfs/nfs.go b/src/contexts/nfs/nfs.go index c864bc6f..7904ec3e 100644 --- a/src/contexts/nfs/nfs.go +++ b/src/contexts/nfs/nfs.go @@ -68,8 +68,8 @@ func dir(m *ctx.Message, name string, level int, deep bool, fields []string) { switch k { case "filename": m.Add("append", "filename", "..") - case "dir": - m.Add("append", "dir", "true") + case "is_dir": + m.Add("append", "is_dir", "true") case "size": m.Add("append", "size", 0) case "line": @@ -130,8 +130,8 @@ func dir(m *ctx.Message, name string, level int, deep bool, fields []string) { switch k { case "filename": m.Add("append", "filename", filename) - case "dir": - m.Add("append", "dir", f.IsDir()) + case "is_dir": + m.Add("append", "is_dir", f.IsDir()) case "size": m.Add("append", "size", f.Size()) case "line": @@ -803,11 +803,12 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心", "buf_size": &ctx.Config{Name: "buf_size", Value: "1024", Help: "读取文件的缓存区的大小"}, "qr_size": &ctx.Config{Name: "qr_size", Value: "256", Help: "生成二维码的图片的大小"}, - "dir_name": &ctx.Config{Name: "dir_name(name/tree/path/full)", Value: "name", Help: "dir命令输出文件名的类型, name: 文件名, tree: 带缩进的文件名, path: 相对路径, full: 绝对路径"}, - "dir_info": &ctx.Config{Name: "dir_info(sizes/lines/files/dirs)", Value: "sizes lines files dirs", Help: "dir命令输出目录的统计信息, info: 输出统计信息, 否则输出"}, + "dir_root": &ctx.Config{Name: "dir_root", Value: "usr", Help: "dir命令输出目录的统计信息, info: 输出统计信息, 否则输出"}, "dir_deep": &ctx.Config{Name: "dir_deep(yes/no)", Value: "yes", Help: "dir命令输出目录的统计信息, info: 输出统计信息, 否则输出"}, "dir_type": &ctx.Config{Name: "dir_type(file/dir)", Value: "file", Help: "dir命令输出的文件类型, file: 只输出普通文件, dir: 只输出目录文件, 否则输出所有文件"}, - "dir_field": &ctx.Config{Name: "dir_field", Value: "filename line size time", Help: "表格排序字段"}, + "dir_name": &ctx.Config{Name: "dir_name(name/tree/path/full)", Value: "name", Help: "dir命令输出文件名的类型, name: 文件名, tree: 带缩进的文件名, path: 相对路径, full: 绝对路径"}, + "dir_info": &ctx.Config{Name: "dir_info(sizes/lines/files/dirs)", Value: "sizes lines files dirs", Help: "dir命令输出目录的统计信息, info: 输出统计信息, 否则输出"}, + "dir_field": &ctx.Config{Name: "dir_field", Value: "filename is_dir line size time", Help: "表格排序字段"}, "sort_field": &ctx.Config{Name: "sort_field", Value: "line", Help: "表格排序字段"}, "sort_order": &ctx.Config{Name: "sort_order(int/int_r/string/string_r/time/time_r)", Value: "int", Help: "表格排序类型"}, @@ -1078,13 +1079,16 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心", if len(arg) == 1 { var data interface{} e := json.Unmarshal([]byte(arg[0]), &data) + if e != nil { + return + } m.Assert(e) buf, e := json.MarshalIndent(data, "", " ") m.Assert(e) - m.Echo("'") + // m.Echo("'") m.Echo(string(buf)) - m.Echo("'") + // m.Echo("'") return } @@ -1122,10 +1126,6 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心", "pwd": &ctx.Command{Name: "pwd", Help: "查看当前路径", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { if m.Options("dir") { m.Echo(m.Option("dir")) - m.Add("append", "hi", "hello") - m.Add("append", "he", "hello") - m.Add("append", "hi", "world") - m.Add("append", "he", "world") return } if len(arg) > 0 { @@ -1134,20 +1134,31 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心", wd, e := os.Getwd() m.Assert(e) m.Echo(wd) - m.Append("hi", "hello") }}, "dir": &ctx.Command{ - Name: "dir dir [dir_deep yes|no] [dir_info info] [dir_name name|tree|path|full] [dir_type file|dir] [sort_field name] [sort_order type]", + Name: "dir dir [dir_deep yes|no] [dir_info info] [dir_name name|tree|path|full] [dir_type both|file|dir] [sort_field name] [sort_order type]", Help: "查看目录, dir: 目录名, dir_info: 显示统计信息, dir_name: 文件名类型, dir_type: 文件类型, sort_field: 排序字段, sort_order: 排序类型", - Form: map[string]int{"dir_field": 1, "dir_deep": 1, "dir_info": 1, "dir_name": 1, "dir_type": 1, "sort_field": 1, "sort_order": 1}, + Form: map[string]int{ + "dir_root": 1, + "dir_deep": 1, + "dir_type": 1, + "dir_name": 1, + "dir_info": 1, + "dir_link": 1, + "dir_field": 1, + "sort_field": 1, + "sort_order": 1, + }, Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - d := "./" + m.Option("dir") if len(arg) > 0 { - d = arg[0] + m.Option("dir", arg[0]) } + m.Option("dir", path.Clean(m.Option("dir"))) + d := path.Join(m.Confx("dir_root"), m.Option("dir")) if s, e := os.Stat(d); m.Assert(e) && !s.IsDir() { d = path.Dir(d) } + fields := strings.Split(m.Confx("dir_field"), " ") trip := 0 @@ -1170,22 +1181,30 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心", key := m.Meta["append"][i] switch key { case "filename": + v = maps[key] if line > -1 && trip > 0 && trip <= len(v) { v = v[trip:] - m.Meta["filename"][line] = v + if m.Options("dir_link") { + m.Meta["filename"][line] = fmt.Sprintf(m.Option("dir_link"), maps["is_dir"], v) + } else { + m.Meta["filename"][line] = v + } + } + if line > -1 { + if m.Options("dir_link") { + m.Meta["filename"][line] = fmt.Sprintf(m.Option("dir_link"), maps["is_dir"], v) + } } - case "dir": - continue } - m.Echo("%s\t", v) } - m.Echo("\n") return true }) + if !m.Options("dir_link") { + m.Table() + } for _, v := range info { m.Echo("%s: %s\n", v, m.Option(v)) } - }}, "git": &ctx.Command{ Name: "git branch|status|diff|log|info arg... [dir path]...", diff --git a/src/contexts/web/web.go b/src/contexts/web/web.go index 4d9c22d7..4536944f 100644 --- a/src/contexts/web/web.go +++ b/src/contexts/web/web.go @@ -27,8 +27,8 @@ type MUX interface { type WEB struct { *http.Client *http.ServeMux - *http.Server - *template.Template + server *http.Server + template *template.Template *ctx.Context } @@ -80,7 +80,9 @@ func (web *WEB) HandleCmd(m *ctx.Message, key string, cmd *ctx.Command) { m.TryCatch(m.Spawn(), true, func(msg *ctx.Message) { msg.Add("option", "method", r.Method).Add("option", "path", r.URL.Path) + msg.Option("remote_addr", r.RemoteAddr) msg.Option("referer", r.Header.Get("Referer")) + msg.Option("accept", r.Header.Get("Accept")) if r.ParseForm(); len(r.PostForm) > 0 { for k, v := range r.PostForm { @@ -101,11 +103,11 @@ func (web *WEB) HandleCmd(m *ctx.Message, key string, cmd *ctx.Command) { switch { case msg.Has("redirect"): - http.Redirect(w, r, msg.Append("redirect"), http.StatusFound) + http.Redirect(w, r, msg.Append("redirect"), http.StatusTemporaryRedirect) case msg.Has("directory"): http.ServeFile(w, r, msg.Append("directory")) - case msg.Has("template"): - msg.Spawn().Cmd("/render", msg.Meta["template"]) + case msg.Has("componet"): + msg.Spawn().Add("option", "componet_group", msg.Meta["componet"]).Cmd("/render") case msg.Has("append"): meta := map[string]interface{}{} if len(msg.Meta["result"]) > 0 { @@ -208,16 +210,16 @@ func (web *WEB) Start(m *ctx.Message, arg ...string) bool { web.Caches["protocol"] = &ctx.Cache{Name: "protocol", Value: m.Confx("protocol", arg, 2), Help: "服务协议"} web.Caches["address"] = &ctx.Cache{Name: "address", Value: m.Confx("address", arg, 1), Help: "服务地址"} m.Log("info", "%d %s://%s", m.Capi("nserve", 1), m.Cap("protocol"), m.Cap("stream", m.Cap("address"))) - web.Server = &http.Server{Addr: m.Cap("address"), Handler: web} + web.server = &http.Server{Addr: m.Cap("address"), Handler: web} if m.Caps("master", true); m.Cap("protocol") == "https" { web.Caches["cert"] = &ctx.Cache{Name: "cert", Value: m.Confx("cert", arg, 3), Help: "服务证书"} web.Caches["key"] = &ctx.Cache{Name: "key", Value: m.Confx("key", arg, 4), Help: "服务密钥"} m.Log("info", "cert [%s]", m.Cap("cert")) m.Log("info", "key [%s]", m.Cap("key")) - web.Server.ListenAndServeTLS(m.Cap("cert"), m.Cap("key")) + web.server.ListenAndServeTLS(m.Cap("cert"), m.Cap("key")) } else { - web.Server.ListenAndServe() + web.server.ListenAndServe() } return true } @@ -244,16 +246,192 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心", "cert": &ctx.Config{Name: "cert", Value: "etc/cert.pem", Help: "路由数量"}, "key": &ctx.Config{Name: "key", Value: "etc/key.pem", Help: "路由数量"}, - "template_dir": &ctx.Config{Name: "template_dir", Value: "usr/template", Help: "路由数量"}, - "template_file": &ctx.Config{Name: "template_file", Value: "usr/template", Help: "路由数量"}, - "template": &ctx.Config{Name: "template", Value: map[string]interface{}{ - "index": []interface{}{ + "web_site": &ctx.Config{Name: "web_site", Value: []interface{}{ + map[string]interface{}{"_name": "MDN", "site": "https://developer.mozilla.org"}, + map[string]interface{}{"_name": "github", "site": "https://github.com"}, + }, Help: "web_site"}, + "template_dir": &ctx.Config{Name: "template_dir", Value: "usr/template", Help: "模板路径"}, + + "componet_context": &ctx.Config{Name: "component_context", Value: "nfs", Help: "默认模块"}, + "componet_command": &ctx.Config{Name: "component_command", Value: "pwd", Help: "默认命令"}, + "componet_group": &ctx.Config{Name: "component_group", Value: "index", Help: "默认组件"}, + "componet": &ctx.Config{Name: "componet", Value: map[string]interface{}{ + "login": []interface{}{ map[string]interface{}{ - "name": "message", "title": "message", - "context": "nfs", "command": "pwd", + "template": "head", "name": "head", "help": "head", + "context": "", "command": "", "arguments": []interface{}{}, + }, + map[string]interface{}{ + "template": "componet", "name": "login", "help": "login", + "context": "aaa", "command": "login", "arguments": []interface{}{"@username", "@password"}, + "inputs": []interface{}{ + map[string]interface{}{ + "type": "text", "name": "username", + "label": "username", "value": "", + }, + map[string]interface{}{ + "type": "password", "name": "password", + "label": "password", "value": "", + }, + map[string]interface{}{ + "type": "button", "name": "string", + "label": "string", "value": "login", + }, + }, + "display_append": "", + "display_result": "", + "result_reload": "10", + }, + map[string]interface{}{ + "template": "tail", "name": "tail", "help": "tail", + "context": "", "command": "", "arguments": []interface{}{}, }, }, - }, Help: "路由数量"}, + "index": []interface{}{ + map[string]interface{}{ + "template": "head", "name": "head", "help": "head", + "context": "", "command": "", "arguments": []interface{}{}, + }, + map[string]interface{}{ + "template": "clipboard", "name": "clipbaord", "help": "clipbaord", + "context": "", "command": "", "arguments": []interface{}{}, + }, + map[string]interface{}{ + "template": "componet", "name": "message", "help": "message", + "context": "cli", "command": "buffer", "arguments": []interface{}{}, + "inputs": []interface{}{ + map[string]interface{}{ + "type": "text", "name": "limit", + "label": "limit", "value": "3", + }, + map[string]interface{}{ + "type": "button", "name": "string", + "label": "string", "value": "refresh", + }, + }, + }, + map[string]interface{}{ + "template": "componet", "name": "time", "help": "time", + "context": "cli", "command": "time", + "arguments": []interface{}{"@string"}, + "inputs": []interface{}{ + map[string]interface{}{ + "type": "text", "name": "time_format", + "label": "format", "value": "2006-01-02 15:04:05", + }, + map[string]interface{}{ + "type": "text", "name": "string", + "label": "string", "value": "", + }, + map[string]interface{}{ + "type": "button", "name": "button", + "label": "string", "value": "refresh", + }, + }, + }, + map[string]interface{}{ + "template": "componet", "name": "json", "help": "json", + "context": "nfs", "command": "json", + "arguments": []interface{}{"@string"}, + "inputs": []interface{}{ + map[string]interface{}{ + "type": "text", "name": "string", + "label": "string", "value": "", + }, + map[string]interface{}{ + "type": "button", "name": "button", + "label": "string", "value": "refresh", + }, + }, + }, + map[string]interface{}{ + "template": "componet", "name": "dir", "help": "dir", + "context": "nfs", "command": "dir", + "arguments": []interface{}{"@dir", + "dir_deep", "no", + "dir_name", "name", + "dir_link", "%s", + "dir_info", "", + }, + "inputs": []interface{}{ + map[string]interface{}{ + "type": "text", "name": "dir", + "label": "dir", "value": "", + }, + map[string]interface{}{ + "type": "choice", "name": "dir_type", + "label": "dir_type", "value": "both", + "choice": []interface{}{ + map[string]interface{}{ + "name": "both", "value": "both", + }, + map[string]interface{}{ + "name": "file", "value": "file", + }, + map[string]interface{}{ + "name": "dir", "value": "dir", + }, + }, + }, + map[string]interface{}{ + "type": "choice", "name": "sort_field", + "label": "sort_field", "value": "time", + "choice": []interface{}{ + map[string]interface{}{ + "name": "filename", "value": "filename", + }, + map[string]interface{}{ + "name": "line", "value": "line", + }, + map[string]interface{}{ + "name": "size", "value": "size", + }, + map[string]interface{}{ + "name": "time", "value": "time", + }, + }, + }, + map[string]interface{}{ + "type": "choice", "name": "sort_order", + "label": "sort_order", "value": "time", + "choice": []interface{}{ + map[string]interface{}{ + "name": "str", "value": "str", + }, + map[string]interface{}{ + "name": "str_r", "value": "str_r", + }, + map[string]interface{}{ + "name": "int", "value": "int", + }, + map[string]interface{}{ + "name": "int_r", "value": "int_r", + }, + map[string]interface{}{ + "name": "time", "value": "time", + }, + map[string]interface{}{ + "name": "time_r", "value": "time_r", + }, + }, + }, + }, + }, + map[string]interface{}{ + "template": "componet", "name": "web_site", "help": "web_site", + "context": "web", "command": "config", + "arguments": []interface{}{ + "web_site", + "format_field", "site", "%s", + }, + "display_result": "", + }, + map[string]interface{}{ + "template": "tail", "name": "tail", "help": "tail", + "context": "", "command": "", "arguments": []interface{}{}, + }, + }, + }, Help: "组件列表"}, }, Commands: map[string]*ctx.Command{ "client": &ctx.Command{Name: "client address [output [editor]]", Help: "添加浏览器配置, address: 默认地址, output: 输出路径, editor: 编辑器", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { @@ -517,55 +695,248 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心", } } }}, - "/demo": &ctx.Command{Name: "/demo template", Help: "渲染模板, template: 模板名称", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - m.Append("template", "index") - }}, - "template": &ctx.Command{Name: "template [file directory]|[name content]", Help: "添加模块, content: 模板内容, directory: 模板目录", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + "template": &ctx.Command{Name: "template [file [directory]]|[name [content]]", Help: "添加模板, content: 模板内容, directory: 模板目录", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { if web, ok := m.Target().Server.(*WEB); m.Assert(ok) { if len(arg) == 0 { - for _, v := range web.Template.Templates() { + for _, v := range web.template.Templates() { m.Add("append", "name", v.Name()) } m.Sort("name").Table() return } - if web.Template == nil { - web.Template = template.New("render").Funcs(ctx.CGI) + if web.template == nil { + web.template = template.New("render").Funcs(ctx.CGI) } dir := path.Join(m.Confx("template_dir", arg, 1), arg[0]) - if t, e := web.Template.ParseGlob(dir); e == nil { - web.Template = t + if t, e := web.template.ParseGlob(dir); e == nil { + web.template = t } else { + m.Log("info", "%s", e) if len(arg) > 1 { - web.Template = template.Must(web.Template.New(arg[0]).Parse(arg[1])) + web.template = template.Must(web.template.New(arg[0]).Parse(arg[1])) } else { - buf := bytes.NewBuffer(make([]byte, 1024)) - tmpl, e := web.Template.Clone() + tmpl, e := web.template.Clone() m.Assert(e) + tmpl.Funcs(ctx.CGI) + + buf := bytes.NewBuffer(make([]byte, 1024)) tmpl.ExecuteTemplate(buf, arg[0], m) m.Echo(string(buf.Bytes())) } } } }}, - "/render": &ctx.Command{Name: "/render template", Help: "渲染模板, template: 模板名称", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - if web, ok := m.Target().Server.(*WEB); m.Assert(ok) { - w := m.Optionv("response").(http.ResponseWriter) - w.Header().Add("Content-Type", "text/html") - tmpl, e := web.Template.Clone() - m.Assert(e) - - for _, v := range m.Confv("template", arg[0]).([]interface{}) { - //执行命令 - val := v.(map[string]interface{}) - if _, ok := val["command"]; ok { - msg := m.Find(val["context"].(string)).Cmd(val["command"], val["argument"]) - msg.Option("title", val["title"]) - m.Assert(tmpl.ExecuteTemplate(w, val["name"].(string), msg)) + "componet": &ctx.Command{Name: "componet [group [order [arg...]]]", Help: "添加组件, group: 组件分组, arg...: 组件参数", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + switch len(arg) { + case 0: + for k, v := range m.Confv("componet").(map[string]interface{}) { + for i, val := range v.([]interface{}) { + value := val.(map[string]interface{}) + m.Add("append", "group", k) + m.Add("append", "order", i) + m.Add("append", "name", value["name"]) + m.Add("append", "help", value["help"]) + m.Add("append", "context", value["context"]) + m.Add("append", "command", value["command"]) } } + m.Sort("group").Table() + case 1: + for i, val := range m.Confv("componet", arg[0]).([]interface{}) { + value := val.(map[string]interface{}) + m.Add("append", "order", i) + m.Add("append", "name", value["name"]) + m.Add("append", "help", value["help"]) + m.Add("append", "context", value["context"]) + m.Add("append", "command", value["command"]) + } + m.Table() + case 2: + value := m.Confv("componet", []interface{}{arg[0], arg[1]}).(map[string]interface{}) + for k, v := range value { + m.Add("append", k, v) + } + m.Table() + default: + if com, ok := m.Confv("componet", []interface{}{arg[0], arg[1]}).(map[string]interface{}); ok { + for i := 2; i < len(arg)-1; i += 2 { + com[arg[i]] = arg[i+1] + } + } else { + m.Confv("componet", []interface{}{arg[0], arg[1]}, map[string]interface{}{ + "name": arg[2], "help": arg[3], + "context": m.Confx("componet_context", arg, 4), + "command": m.Confx("componet_command", arg, 5), + }) + break + } + } + }}, + "session": &ctx.Command{Name: "session", Help: "用户登录", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + sessid := m.Option("sessid") + if sessid == "" && m.Options("username") && m.Options("password") { + sessid = m.Sess("aaa").Cmd("login", m.Option("username"), m.Option("password")).Result(0) + } + if sessid == "" && m.Options("remote_addr") { + sessid = m.Sess("aaa").Cmd("login", "ip", m.Option("remote_addr")).Result(0) + } + + login := m.Sess("aaa").Cmd("login", sessid).Sess("login", false) + m.Appendv("login", login) + m.Echo(sessid) + }}, + "/render": &ctx.Command{Name: "/render template", Help: "渲染模板, template: 模板名称", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + if _, ok := m.Target().Server.(*WEB); m.Assert(ok) { + accept_json := strings.HasPrefix(m.Option("accept"), "application/json") + list := []interface{}{} + + // tmpl, e := web.template.Clone() + // m.Assert(e) + // tmpl.Funcs(ctx.CGI) + // + + tmpl := template.New("render").Funcs(ctx.CGI) + tmpl.ParseGlob("/Users/shaoying/context/usr/template/common/base.tmpl") + + w := m.Optionv("response").(http.ResponseWriter) + if accept_json { + w.Header().Add("Content-Type", "application/json") + } else { + w.Header().Add("Content-Type", "text/html") + } + + if m.Option("componet_group") == "" { + m.Option("componet_group", m.Conf("componet_group")) + } + group := m.Option("componet_group") + + right := false + if group == "login" { + right = true + } + + login := m + login = nil + + for count := 0; count == 0; { + order := -1 + if m.Option("componet_order") != "" { + order = m.Optioni("componet_order") + } + + if !right { + login = m.Spawn().Cmd("session").Appendv("login").(*ctx.Message) + } + if !right && login != nil { + if role := login.Confv("right", []interface{}{"right", "role"}); role != nil && role.(string) == "root" { + right = true + } + } + if !right && login != nil { + if role := login.Confv("right", []interface{}{group, "right", "role"}); role != nil && role.(string) == "owner" { + right = true + } + } + + for i, v := range m.Confv("componet", group).([]interface{}) { + if order != -1 && i != order { + continue + } + + val := v.(map[string]interface{}) + + order_right := right + if !order_right && login != nil { + if role := login.Confv("right", []interface{}{group, val["name"], "right", "role"}); role != nil && role.(string) == "share" { + order_right = true + } + } + if !order_right { + continue + } + + msg := m.Find(val["context"].(string)) + if msg == nil { + if !accept_json { + m.Assert(tmpl.ExecuteTemplate(w, val["template"].(string), m)) + } + continue + } + count++ + + msg.Option("componet_order", i) + + for k, v := range val { + if msg.Option(k) != "" { + continue + } + switch value := v.(type) { + case []string: + msg.Add("option", k, value) + case string: + msg.Add("option", k, value) + default: + msg.Put("option", k, value) + } + } + + args := []string{} + if val["arguments"] != nil { + for _, v := range val["arguments"].([]interface{}) { + switch value := v.(type) { + case string: + if len(value) > 1 && value[0] == '$' { + args = append(args, msg.Cap(value[1:])) + } else if len(value) > 1 && value[0] == '@' { + args = append(args, msg.Confx(value[1:])) + } else { + args = append(args, value) + } + } + } + } + if val["inputs"] != nil { + for _, v := range val["inputs"].([]interface{}) { + value := v.(map[string]interface{}) + if msg.Option(value["name"].(string)) == "" { + msg.Add("option", value["name"].(string), value["value"]) + } + } + } + + if msg.Cmd(val["command"], args); accept_json { + list = append(list, msg.Meta) + } else { + m.Assert(tmpl.ExecuteTemplate(w, val["template"].(string), msg)) + } + + if msg.Appends("sessid") { + http.SetCookie(w, &http.Cookie{Name: "sessid", Value: msg.Append("sessid")}) + m.Append("page_redirect", fmt.Sprintf("/render?componet_group=%s&componet_order=%s", + m.Option("componet_group", m.Option("last_componet_group")), + m.Option("componet_order", m.Option("last_componet_order")))) + return + } + } + + if count == 0 { + m.Option("last_componet_group", m.Option("componet_group")) + m.Option("last_componet_order", m.Option("componet_order")) + m.Option("componet_group", "login") + m.Option("componet_order", "-1") + group = m.Option("componet_group") + order = -1 + right = true + } + } + + if accept_json { + en := json.NewEncoder(w) + en.SetIndent("", " ") + en.Encode(list) + } } }}, }, diff --git a/usr/library/base.js b/usr/library/base.js index 6ab18a33..e4281724 100644 --- a/usr/library/base.js +++ b/usr/library/base.js @@ -1,59 +1,194 @@ - -function update(event, module, details, key) { - if (event) { - window[key+"timer"] = !window[key+"timer"]; - } - if (!window[key+"timer"]) { - return - } - console.log("update "+key) - setTimeout(function() { - action(event, module, details, key); - update(null, module, details, key); - }, refresh_time); +function insert_child(parent, element, html, position) { + var elm = document.createElement(element) + html && (elm.innerHTML = html) + return parent.insertBefore(elm, position || parent.firstElementChild) +} +function append_child(parent, element, html) { + var elm = document.createElement(element) + html && (elm.innerHTML = html) + parent.append(elm) + return elm +} +function insert_before(self, element, html) { + var elm = document.createElement(element) + html && (elm.innerHTML = html) + return self.parentElement.insertBefore(elm, self) } -function input(event, module, details, key) { - if (event.code == "Enter") { - action(event, module, details, key); - } +function copy_to_clipboard(text) { + var clipboard = document.querySelector("#clipboard") + clipboard.value = text + clipboard.select() + document.execCommand("copy") + clipboard.blur() + + var clipstack = document.querySelector("#clipstack") + insert_child(clipstack, "option").value = clipboard.value + clipstack.childElementCount > 3 && clipstack.removeChild(clipstack.lastElementChild) } -function action(event, module, details, key) { - var input = document.getElementsByClassName(key+"_input"); - for (var i = 0; i < input.length; i++ ){ - if (input[i].value != "") { - details.push(input[i].value) - } - } - ctx.POST("", {module:module, details:details}, function(msg) { - if (msg && msg.result) { - var result = document.getElementsByClassName(key+"_result")[0]; - result.innerHTML = msg.result; - } - if (!msg || !msg.append || msg.append.length < 1) { - return - } +function send_command(form, cb) { + var data = {} + for (var key in form.dataset) { + data[key] = form.dataset[key] + } + for (var i = 0; i < form.length; i++) { + data[form[i].name] = form[i].value + } - var append = document.getElementsByClassName(key+"_append")[0]; - if (append.rows.length == msg[msg.append[0]].length+1) { - return - } - append.innerHTML = ''; - var tr = append.insertRow(0); - for (var i in msg.append) { - var th = tr.appendChild(document.createElement("th")); - th.appendChild(document.createTextNode(msg.append[i])); - } + context.GET("", data, function(msg) { + msg = msg[0] - for (var i = 0; i < msg[msg.append[0]].length; i++) { - var tr = append.insertRow(1); - for (var j in msg.append) { - var td = tr.appendChild(document.createElement("td")); - td.appendChild(document.createTextNode(msg[msg.append[j]][i])); - } - } - var div = append.parent; + var result = document.querySelector("code.result."+data["componet_name"]+" pre") + result && (result.innerHTML = (msg.result || []).join("")) - }) - return false; + var append = document.querySelector("table.append."+data["componet_name"]) + append && (append.innerHTML = "") + + if (append && msg.append) { + var tr = append_child(append, "tr") + for (var i in msg.append) { + append_child(tr, "th", msg.append[i]) + } + + var ncol = msg.append.length + var nrow = msg[msg.append[0]].length + for (var i = 0; i < nrow; i ++) { + var tr = append_child(append, "tr") + for (var k in msg.append) { + append_child(tr, "td", msg[msg.append[k]][i]) + } + } + } + + typeof(cb) == "function" && cb(msg) + }) +} +function onaction(event, action) { + switch (action) { + case "command": + send_command(event.target.form) + break + case "input": + switch (event.key) { + case "Enter": + var form = event.target.form + for (var i = 0; i < form.length; i++) { + if (form[i] == event.target) { + continue + } + (i == form.length-1)? send_command(form): form[i+1].focus() + } + break + case "Escape": + event.target.value = "" + event.target.blur() + break + } + break + case "keymap": + switch (event.key) { + case "g": + document.querySelectorAll("form.option label.keymap").forEach(function(item) { + item.className = (item.className == "keymap show")? "keymap hide": "keymap show" + }) + break + default: + if (inputs[event.key]) { + inputs[event.key].focus() + } + break + } + break + case "copy": + copy_to_clipboard(event.target.innerText) + break + } +} +var inputs = {} +var ninput = 0 +var keymap = ['a', 'b', 'c'] +function init_option() { + inputs = {} + ninput = 0 + keymap =[] + for (var i = 97; i < 123; i++) { + if (i == 103) { + continue + } + keymap.push(String.fromCharCode(i)) + } + + document.querySelectorAll("form.option input").forEach(function(input) { + if (ninput < keymap.length && input.style.display != "none") { + input.title = "keymap: "+keymap[ninput] + input.dataset["keymap"] = keymap[ninput] + insert_before(input, "label", "("+keymap[ninput]+")").className = "keymap" + inputs[keymap[ninput++]] = input + } + }) +} +function init_append(event) { + var append = document.querySelectorAll("table.append").forEach(function(item) { + item.onclick = function(event) { + if (event.target.tagName == "TD") { + copy_to_clipboard(event.target.innerText) + } + } + }) +} +function init_result(event) { + var result = document.querySelectorAll("code.result pre").forEach(function(item) { + item.onclick = function(event) { + copy_to_clipboard(event.target.innerText) + } + }) +} +function init_download(event) { + var option = document.querySelector("form.option.dir") + if (!option) { + return + } + option["dir"].value && send_command(option) + + var append = document.querySelector("table.append.dir") + append.onclick = function(event) { + if (event.target.tagName == "A") { + if (event.target.dataset.type != "true") { + location.href = option["dir"].value+"/"+event.target.innerText + return + } + + option["dir"].value = option["dir"].value+"/"+event.target.innerText + send_command(option, function(msg) { + option["dir"].value = msg.dir.join("") + }) + } else if (event.target.tagName == "TD") { + copy_to_clipboard(event.target.innerText) + } else if (event.target.tagName == "TH") { + option["sort_field"].value = event.target.innerText + + var sort_order = option["sort_order"] + switch (event.target.innerText) { + case "filename": + sort_order.value = (sort_order.value == "str")? "str_r": "str" + break + case "line": + case "size": + sort_order.value = (sort_order.value == "int")? "int_r": "int" + break + case "time": + sort_order.value = (sort_order.value == "time")? "time_r": "time" + break + } + + send_command(option) + } + } +} + +window.onload = function() { + init_option() + init_append() + init_result() + init_download() } diff --git a/usr/library/context.js b/usr/library/context.js index d53f55e8..3c2de56c 100644 --- a/usr/library/context.js +++ b/usr/library/context.js @@ -1,202 +1,47 @@ -ctx = { - Cookie: function(key, value) {//{{{ - if (value == undefined) { - var pattern = new RegExp(key+"=([^;]*);?"); - var result = pattern.exec(document.cookie); - if (result && result.length > 0) { - return result[1]; - } - return ""; - } +context = { + GET: function(url, form, cb) { + form = form || {} - document.cookie = key+"="+value; - return this.Cookie(key); - },//}}} - Search: function(key, value) {//{{{ - var args = {}; - var search = location.search.split("?"); - if (search.length > 1) { - var searchs = search[1].split("&"); - for (var i = 0; i < searchs.length; i++) { - var keys = searchs[i].split("="); - args[keys[0]] = decodeURIComponent(keys[1]); - } - } - - if (typeof key == "object") { - for (var k in key) { - if (key[k] != undefined) { - args[k] = key[k]; - } - } - } else if (value == undefined) { - return args[key] || ""; - } else { - args[key] = value; - } - - var arg = []; - for (var k in args) { - arg.push(k+"="+encodeURIComponent(args[k])); - } - location.search = arg.join("&"); - },//}}} - GET: function(url, form, cb) {//{{{ - var xhr = new XMLHttpRequest(); - xhr.onreadystatechange = function() { - switch (xhr.readyState) { - case 4: - switch (xhr.status) { - case 200: - try { - var msg = JSON.parse(xhr.responseText||'{"result":[]}'); - } catch (e) { - msg = {"result": [xhr.responseText]} - } - - msg && console.log(msg) - msg.result && console.log(msg.result.join("")); - typeof cb == "function" && cb(msg) - } - break; - } - } - - form = form || {} - form["dir"] = form["dir"] || this.Search("dir") || undefined - form["module"] = form["module"] || this.Search("module") || undefined - form["domain"] = form["domain"] || this.Search("domain") || undefined - - var args = []; - for (k in form) { - if (form[k] instanceof Array) { - for (i in form[k]) { - args.push(k+"="+encodeURIComponent(form[k][i])); - } - } else if (form[k] != undefined) { - args.push(k+"="+encodeURIComponent(form[k])); - } - } - - var arg = args.join("&"); - if (arg) { - url += "?"+arg + var args = []; + for (var k in form) { + if (form[k] instanceof Array) { + for (i in form[k]) { + args.push(k+"="+encodeURIComponent(form[k][i])); + } + } else if (form[k] != undefined) { + args.push(k+"="+encodeURIComponent(form[k])); + } } - xhr.open("GET", url); - console.log("GET: "+url+"?"+arg); - xhr.send(); - },//}}} - POST: function(url, form, cb) {//{{{ - var xhr = new XMLHttpRequest(); - xhr.onreadystatechange = function() { - switch (xhr.readyState) { - case 4: - switch (xhr.status) { - case 200: - try { - var msg = JSON.parse(xhr.responseText||'{"result":[]}'); - } catch (e) { - msg = {"result": [xhr.responseText]} - } + var arg = args.join("&"); + arg && (url += ((url.indexOf("?")>-1)? "&": "?") + arg) + console.log("GET: "+url); - msg && console.log(msg) - msg.result && console.log(msg.result.join("")); - typeof cb == "function" && cb(msg) - } - break; - } - } + var xhr = new XMLHttpRequest(); + xhr.open("GET", url); + xhr.setRequestHeader("Accept", "application/json") - xhr.open("POST", url); - xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); + xhr.onreadystatechange = function() { + if (xhr.readyState != 4) { + return + } + if (xhr.status != 200) { + return + } + try { + var msg = JSON.parse(xhr.responseText||'{"result":[]}'); + } catch (e) { + var msg = {"result": [xhr.responseText]} + } - form = form || {} - form["dir"] = form["dir"] || this.Search("dir") || undefined - form["module"] = form["module"] || this.Search("module") || undefined - form["domain"] = form["domain"] || this.Search("domain") || undefined - - var args = []; - for (k in form) { - if (form[k] instanceof Array) { - for (i in form[k]) { - args.push(k+"="+encodeURIComponent(form[k][i])); - } - } else if (form[k] != undefined) { - args.push(k+"="+encodeURIComponent(form[k])); - } - } - - var arg = args.join("&"); - console.log("POST: "+url+"?"+arg); - xhr.send(arg); - },//}}} - Refresh: function() {//{{{ - location.assign(location.href); - },//}}} - - Cap: function(cap, cb) {//{{{ - if (typeof cap == "function") { - cb = cap; - cap = undefined; - } - - var args = {ccc:"cache"}; - if (cap != undefined) { - args.name = cap; - } - - this.POST("", args, function(msg) { - var value = msg.result.join(""); - typeof cb == "function" && cb(value); - }); - },//}}} - Conf: function(name, value, cb) {//{{{ - if (typeof name == "function") { - value = name; - name = undefined; - } - if (typeof value == "function") { - cb = value; - value = undefined; - } - - var args = {ccc:"config"}; - if (name != undefined) { - args.name = name - } - if (value != undefined) { - args.value = value - } - - this.POST("", args, function(msg) { - var value = msg.result.join(""); - typeof cb == "function" && cb(value); - }); - },//}}} - Cmd: function(cmd, value, cb) {//{{{ - if (typeof cmd == "function") { - value = cmd; - cmd = undefined; - } - if (typeof value == "function") { - cb = value; - value = undefined; - } - - var args = {ccc:"command"}; - if (cmd != undefined) { - args.name = cmd - } - if (value != undefined) { - args.value = JSON.stringify(value) - } - - this.POST("", args, cb); - },//}}} - Module: function(module, domain) {//{{{ - this.Search({module:module, domain:domain}) - },//}}} -}; - + console.log(msg) + msg.result && console.log(msg.result.join("")); + if (msg.page_redirect) { + location.href = msg.page_redirect.join("") + } + typeof cb == "function" && cb(msg) + } + xhr.send(); + }, +} diff --git a/usr/library/wiki.js b/usr/library/wiki.js deleted file mode 100644 index 8d4eb8a9..00000000 --- a/usr/library/wiki.js +++ /dev/null @@ -1,211 +0,0 @@ -function jumpto(url) { - if (url == "..") { - var ps = locaiton.href.split(); - } - location.href=url; -} - -function keyup(event) { - console.log(event); - if (typeof window.control == "function") { - control(event); - } - if (event.key == "z") { - var input = document.getElementsByClassName("query_input")[0]; - if (!window.query_show) { - window.query_show = true; - var query = document.getElementsByClassName("query_menu")[0]; - var input = query.getElementsByTagName("input")[0]; - input.style.visibility = "visible"; - input.style.width = "80px"; - input.focus(); - } - return true - } - return true -} - -document.onkeyup = keyup; -function toggle(side) { - if (side == "left") { - window.left_list_hide = !window.left_list_hide; - var list = document.getElementsByClassName("list")[0]; - var content = document.getElementsByClassName("content")[0]; - if (left_list_hide) { - list.style.visibility = "hidden"; - list.style.width="0px"; - list.style.height="0px"; - list.style["min-width"]="0px"; - content.style.width="100%"; - } else { - list.style.visibility = "visible"; - list.style.width="15%"; - list.style.height="100%"; - list.style["min-width"]="180px"; - content.style.width="85%"; - } - } -} - -function menu() { - var max = 0; - var min = 1000; - var list = []; - var hs = ["h2", "h3", "h4"]; - for (var i = 0; i < hs.length; i++) { - var head = document.getElementsByTagName(hs[i]); - for (var j = 0; j < head.length; j++) { - head[j].id = "head"+head[j].offsetTop; - head[j].onclick = function(event) {} - list.push({"level": hs[i], "position": head[j].offsetTop, "title": head[j].innerText, "hash": head[j].id}) - if (head[j].offsetTop > max) { - max = head[j].offsetTop; - } - if (head[j].offsetTop < min) { - min = head[j].offsetTop; - } - } - } - max = max - min; - - var link = []; - var a = document.getElementsByTagName("a"); - for (var i = 0; i < a.length; i++) { - link.push({href: a[i].href, title: a[i].innerText}); - } - - for (var i = 0; i < list.length-1; i++) { - for (var j = i+1; j < list.length; j++) { - if (list[j].position < list[i].position) { - var a = list[i]; - list[i] = list[j]; - list[j] = a; - } - } - } - - var index = [-1, 0, 0] - for (var i = 0; i < list.length; i++) { - if (list[i].level == "h2") { - index[0]++; - index[1]=0; - index[2]=0; - } else if (list[i].level == "h3") { - index[1]++; - index[2]=0; - } else { - index[2]++; - } - - list[i].index4 = index[2]; - list[i].index3 = index[1]; - list[i].index2 = index[0]; - } - - var m = document.getElementsByClassName("menu"); - for (var i = 0; i < m.length; i++) { - for (var j = 0; j < list.length; j++) { - var text = list[j].index2+"." - if (list[j].level == "h3") { - text += list[j].index3 - } else if (list[j].level == "h4") { - text += list[j].index3+"."+list[j].index4 - } - - text += " " - text += list[j].title; - - var h = document.getElementById(list[j].hash) - h.innerText = text - - var one = m[i].appendChild(document.createElement("div")); - var a = one.appendChild(document.createElement("a")); - a.href = "#"+list[j].hash; - a.innerText = text+" ("+parseInt((list[j].position-min)/max*100)+"%)"; - - one.className = list[j].level; - } - } - - var m = document.getElementsByClassName("link"); - for (var i = 0; i < m.length; i++) { - var one = m[i].appendChild(document.createElement("div")); - var a = one.appendChild(document.createTextNode("相关链接: ")); - - for (var j = 0; j < link.length; j++) { - var one = m[i].appendChild(document.createElement("div")); - var a = one.appendChild(document.createTextNode(link[j].title+": ")); - var a = one.appendChild(document.createElement("a")); - a.href = link[j].href - a.innerText = a.href - } - } - - var m = document.getElementsByTagName("pre"); - for (var i = 0; i < m.length; i++) { - var line = (m[i].clientHeight-10)/15 - // if (line < 3) { - // continue - // } - console.log(m[i].clientHeight) - var nu = m[i].parentElement.insertBefore(document.createElement("div"), m[i]); - nu.className = "number1" - - for (var j = 1; j <= line; j++) { - console.log(j) - var li = nu.appendChild(document.createElement("div")); - li.appendChild(document.createTextNode(""+j)); - } - } -} - -function query(event) { - if (event) { - if (event.code == "Enter") { - jumpto("/wiki/?query="+encodeURIComponent(event.target.value)); - } - console.log("what") - return true - } - window.query_show = !window.query_show; - var query = document.getElementsByClassName("query_menu")[0]; - var input = query.getElementsByTagName("input")[0]; - if (window.query_show) { - input.style.visibility = "visible"; - input.style.width = "80px"; - - } else { - input.style.visibility = "hidden"; - input.style.width = "0px"; - } -} - -var tags_list = {}; -ctx.GET("/wiki/define.json", undefined, function(msg){ - tags_list = msg["define"]; -}) - -function tags(event) { - console.log(event); - - if (event.srcElement.tagName == "CODE") { - var tag = document.getSelection().toString(); - console.log(tag); - if (tag && tag.length > 0 && tags_list[tag]) { - var position = tags_list[tag].position; - if (position.length == 1) { - jumpto("/wiki/src/"+position[0].file+"#hash_"+position[0].line); - } else { - jumpto("/wiki/?query="+encodeURIComponent(tag)); - } - } - } -} - -document.onmouseup = tags; -window.onload = function() { - toggle(); - if (location.href.endsWith(".md")) { - menu(); - } -} diff --git a/usr/template/common/base.html b/usr/template/common/base.html deleted file mode 100644 index d14b78a9..00000000 --- a/usr/template/common/base.html +++ /dev/null @@ -1,145 +0,0 @@ -{{define "head"}} - - - - -{{option .Meta "page_title"}} - - - - - -{{end}} - -{{define "code"}} -
{{.}}
-{{end}} - -{{define "notice"}} -
[notice] - {{template "code" result .Meta}} -
- -{{end}} - -{{define "detail"}} -{{$msg := .}} -{{$key := append . "title"|meta}} -
{{option . "title"}} - {{range option . "ninput"|meta|list}} - - {{end}} - {{if option . "refresh"}} - - - {{end}} -
-
-
-
-
- -{{end}} - -{{define "result"}} -
{{option . "title"}} - {{template "code" result .Meta|unscaped}} -
-{{end}} - -{{define "append_link"}} -{{.}} - -{{end}} - -{{define "append"}} -
{{option . "title"}} - - {{$msg := .}} - {{$ncol := append . |len}} - {{$nrow := append . 0|append .|len}} - {{range append .}}{{end}} - {{range $row, $val := append . 0|append .}} - - {{range append $msg}} - {{$value := append $msg . $row}} - - {{end}} - - {{end}} -
{{.}}
- {{if eq . "filename"}} - {{template "append_link" $value}} - {{else}} - {{$value}} - {{end}} -
-
- -{{end}} - -{{define "main"}} -welcome to context world! -{{end}} - -{{define "tail"}} - -{{end}} diff --git a/usr/template/common/base.tmpl b/usr/template/common/base.tmpl new file mode 100644 index 00000000..a6771bc7 --- /dev/null +++ b/usr/template/common/base.tmpl @@ -0,0 +1,138 @@ +{{define "head"}} + + + + +{{option .Meta "page_title"}} + + + + + +{{end}} + +{{define "detail"}}{{detail .}}{{end}} +{{define "option"}}{{option .}}{{end}} +{{define "append"}}{{append .}}{{end}} +{{define "result"}}{{result .}}{{end}} + +{{define "clipboard"}} +
clipboard + + +
+{{end}} + +{{define "componet"}} +
{{option .Meta "context"}}.{{option .Meta "command"}} +
+ + {{range $index, $input := option . "inputs"}} +
+ {{$type := index $input "type"}} + {{if eq $type "button"}} + + {{else if eq $type "choice"}} + {{$default_value := index $input "value"}} + + + {{else}} + + + {{end}} +
+ {{end}} +
+
+ + {{if index .Meta "display_append"}} + {{option .Meta "display_append"}} + {{else}} + + {{$msg := .}} + {{range $field := append .}}{{end}} + {{range $line := table .}} + {{range $field := append $msg}}{{end}} + {{end}} +
{{$field}}
{{index $line $field|unescape}}
+ {{end}} + + {{if index .Meta "display_result"}} + {{option .Meta "display_result"}} + {{else}} +
{{result .Meta}}
+ {{end}} +
+{{end}} + +{{define "tail"}} + + + +{{end}} diff --git a/usr/template/common/login.html b/usr/template/common/login.html deleted file mode 100644 index 472887a7..00000000 --- a/usr/template/common/login.html +++ /dev/null @@ -1,94 +0,0 @@ -{{define "login"}} -
login -
- - - -
-
-{{end}} - -{{define "userinfo"}} -
userinfo - welcome {{option . "username"}} to context world - -
- - -{{end}} - -{{define "share"}} -
share - - {{$msg := .}} - {{$ncol := append . |len}} - {{$nrow := append . 0|append .|len}} - {{range append .}}{{end}} - {{range $row, $val := append . 0|append .}} - - {{range append $msg}} - {{$value := append $msg . $row}} - - {{end}} - - {{end}} -
{{.}}
- {{if eq . "to"}} - {{if eq $value ""}} - - {{else}} - {{$value}} - {{end}} - {{else if eq . "value"}} - {{$value}} - {{else}} - {{$value}} - {{end}} -
-
- -{{end}} - -{{$msg := .}} -{{$meta := .Meta}} - -{{template "head" $meta}} -{{if meta $meta.notice}} - {{template "notice" $meta}} -{{end}} -{{template "login" $meta}} -{{template "tail" $meta}} diff --git a/usr/template/common/main.html b/usr/template/common/main.html deleted file mode 100644 index ce3e2dc1..00000000 --- a/usr/template/common/main.html +++ /dev/null @@ -1,9 +0,0 @@ -{{$msg := .}} -{{$meta := .Meta}} - -{{template "head" $meta}} -{{if meta $meta.message}} - {{template "message" $meta}} -{{end}} -{{template "main" $msg}} -{{template "tail" $meta}} diff --git a/usr/template/common/wiki.html b/usr/template/common/wiki.html deleted file mode 100644 index 835fe9ab..00000000 --- a/usr/template/common/wiki.html +++ /dev/null @@ -1,222 +0,0 @@ -{{define "wiki_head"}} -{{end}} - -{{define "wiki_menu"}} -{{end}} - -{{define "wiki_list"}} - -
-
-
-
- -
Q
-
-
shylinux
-
-
- {{$msg := .}} - {{$ncol := append . |len}} - {{$nrow := append . 0|append .|len}} -
    -
  • -
    返回上一层
    -
  • - {{range $row, $val := append . 0|append .}} -
  • -
    - {{append $msg "name" $row}} -
    -
  • - {{end}} -
-
-{{end}} - -{{define "wiki_body"}} - -
-
-
- {{if option . "modify_time"|meta}} -
上次修订时间: {{option . "modify_time"|meta}} 修订次数: {{option . "modify_count"|meta}}
- {{end}} -
上次阅读时间: {{option . "last_record_time"|meta}} 总访问量: {{option . "record_count"|meta}}
-
- - -
- {{range option . "nline"|meta|list}} -
{{.}}
- {{end}} -
- {{$msg := .}} - {{if append . "name"}} - {{$l := append . "name"|len}} - {{if eq $l 1}} - - {{else}} -
    - {{range $i, $v := append . "name"}} - - {{end}} -
      - {{end}} - {{else if append . "code"|meta}} -

      {{append . "code"|meta}}

      - {{else}} -

      {{append . "body"|meta|unscaped}}

      - {{end}} -
-
- -
- -{{end}} diff --git a/usr/template/travel.html b/usr/template/travel.html deleted file mode 100644 index b66bb94d..00000000 --- a/usr/template/travel.html +++ /dev/null @@ -1,431 +0,0 @@ -{{define "head"}} - - - - - - -{{end}} - -{{define "cache"}} -{{$meta := .}} -
cache - - {{range .append}}{{end}} - {{range .append}}{{end}} - {{$l := index .append|len}} - {{if gt $l 0}} - {{$first := index .append 0}} - {{range $i, $k := index . $first}} - - {{range $key := index $meta "append"}} - {{$content := index $meta $key $i}} - - {{end}} - - {{end}} - {{end}} -
{{.}}
- {{$content}} -
-
- -{{end}} - -{{define "config"}} -
config - - {{range .append}}{{end}} - {{range .append}}{{end}} - {{$l := index .append|len}} - {{if gt $l 0}} - {{$meta := .}} {{$first := index .append 0}} - {{range $i, $k := index . $first}} - {{$config := index $meta "key" $i}} - {{range $key := index $meta "append"}} - {{if eq $key "value"}} - - {{else}} - - {{end}} - {{end}} - - {{end}} - {{end}} -
{{.}}
- - - {{index $meta $key $i}} -
-
- -{{end}} - -{{define "command2"}} -{{$meta := .}} -
command -
- {{$l := index .append|len}} - {{if gt $l 0}} - {{$first := index .append 0}} - {{range $i, $k := index . $first}} - {{$command := index $meta "key" $i}} -
-
- - {{$command}}: {{index $meta "help" $i}}
- {{index $meta "name" $i}} -
-
-
- - -
- - -
- {{end}} - {{end}} -
-
-
-
-
- -{{end}} - -{{define "command"}} -
command - - {{range .append}}{{end}} - {{range .append}}{{end}} - {{$l := index .append|len}} - {{if gt $l 0}} - {{$meta := .}} {{$first := index .append 0}} - {{range $i, $k := index . $first}} - {{$command := index $meta "key" $i}} - {{range $key := index $meta "append"}} - - {{end}} - - {{end}} - {{end}} -
{{.}}
- {{if eq $key "input"}} - - {{else if eq $key "key"}} - {{index $meta $key $i}} - {{else}} - {{index $meta $key $i}} - {{end}} -
-
-
-
-
-
- -{{end}} - -{{define "module"}} -
- - {{range .append}}{{end}} - {{range .append}}{{end}} - {{$l := index .append|len}} - {{if gt $l 0}} - {{$meta := .}} {{$first := index .append 0}} - {{range $i, $k := index . $first}} - - {{range $key := index $meta "append"}} - {{if eq $key "name"}} - - {{else}} - - {{end}} - {{end}} - - {{end}} - {{end}} -
{{.}}
- {{index $meta $key $i}} - - {{index $meta $key $i}} -
-
-{{end}} - -{{define "domain"}} -
- - {{range .append}}{{end}} - {{range .append}}{{end}} - {{$l := index .append|len}} - {{if gt $l 0}} - {{$meta := .}} {{$first := index .append 0}} - {{range $i, $k := index . $first}} - - {{range $key := index $meta "append"}} - {{if eq $key "name"}} - - {{else}} - - {{end}} - {{end}} - - {{end}} - {{end}} -
{{.}}
- {{index $meta $key $i}} - - {{index $meta $key $i}} -
-
-{{end}} - -{{define "tail"}} - - - -{{end}} - -{{define "main"}} -{{$msg := .}} -{{$meta := .Meta}} -{{$sess := $msg.Sessions}} -{{range .Meta.tmpl}} - {{if eq . "login"}} - {{template "login" $meta}} - {{else if eq . "userinfo"}} - {{template "userinfo" $msg}} - {{else if eq . "share"}} - {{template "share" $sess.share}} - {{else if eq . "cache"}} - {{template "cache" $sess.cache.Meta}} - {{else if eq . "config"}} - {{template "config" $sess.config.Meta}} - {{else if eq . "command"}} - {{template "command" $sess.command.Meta}} - {{template "command2" $sess.command.Meta}} - {{else if eq . "module"}} - {{template "module" $sess.module.Meta}} - {{else if eq . "domain"}} - {{template "domain" $sess.domain.Meta}} - {{end}} -{{end}} -{{end}} diff --git a/usr/template/upload.html b/usr/template/upload.html deleted file mode 100644 index cc19746e..00000000 --- a/usr/template/upload.html +++ /dev/null @@ -1,163 +0,0 @@ -{{define "list"}} -
- - {{range .append}}{{end}} - - - {{$sort := meta .sort}} - {{$reverse := meta .reverse}} - {{range .append}} - {{if eq $sort .}} - - {{else if eq $reverse .}} - - {{else if eq . "path"}} - {{else}} - - {{end}} - {{end}} - - - {{if .append}} - {{$meta := .}} - {{$first := index .append 0}} - {{range $i, $k := index . $first}} - - {{range $key := index $meta "append"}} - {{if eq $key "name"}} - {{$type := index $meta "type" $i}} - - {{else if eq $key "path"}} - {{else}} - - {{end}} - {{end}} - - {{end}} - {{end}} -
{{.}}{{.}}{{.}}
- {{index $meta $key $i}} - - {{index $meta $key $i}} -
-
- - -{{end}} - -{{define "git"}} -
branch -
{{index . "result"}}
-
-
status -
{{index . "result"}}
-
-{{end}} - -{{define "tmux"}} -{{$meta := .}} -{{range $index, $value := index $meta "append"}} -
{{$value}} - {{if eq $value "buffer"}} - - - - - {{else}} -
{{meta $meta $value}}
- {{end}} -
-{{end}} -{{end}} - -{{define "upload"}} -
upload -
- -
-
-{{end}} - -{{define "create"}} -
create -
- - - -
filename:
content:
-
-
-{{end}} - -{{define "main"}} -{{$msg := .}} -{{$meta := .Meta}} -{{$sess := .Sessions}} -{{range .Meta.tmpl}} - {{$tmpl := index $sess .}} - - {{if eq . "login"}} - {{template "login" $meta}} - {{else if eq . "userinfo"}} - {{template "userinfo" $msg}} - {{else if eq . "share"}} - {{template "share" $sess.share}} - {{else if eq . "list"}} - {{template "list" $msg.Sessions.list.Meta}} - {{else if eq . "tmux"}} - {{template "tmux" $msg.Sessions.tmux.Meta}} - {{else if eq . "git"}} - {{if $msg.Sessions.git}} - {{template "git" $msg.Sessions.git.Meta}} - {{end}} - {{else if eq . "upload"}} - {{template "upload" $msg}} - {{else if eq . "create"}} - {{template "create" $msg}} - {{else}} - {{end}} -{{end}} -{{end}} -