1
0
mirror of https://shylinux.com/x/ContextOS synced 2025-04-26 09:14:06 +08:00

mac add code & wiki

This commit is contained in:
shaoying 2018-11-05 09:17:50 +08:00
parent 880551e252
commit 32d272ee42
11 changed files with 1361 additions and 1674 deletions

View File

@ -244,9 +244,20 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
args := []string{}
rest := []string{}
exec := true
execexec := false
exports := []map[string]string{}
for i := 0; i < len(detail); i++ {
switch detail[i] {
case "?":
if !ctx.Right(detail[i+1]) {
return
}
i++
case "??":
exec = false
execexec = execexec || ctx.Right(detail[i+1])
i++
case "<":
pipe := m.Spawn().Cmd("import", detail[i+1])
msg.Copy(pipe, "append")
@ -254,12 +265,36 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
case ">":
exports = append(exports, map[string]string{"file": detail[i+1]})
i++
case ">$":
if i == len(detail)-2 {
exports = append(exports, map[string]string{"cache": detail[i+1], "index": "result"})
i += 1
break
}
exports = append(exports, map[string]string{"cache": detail[i+1], "index": detail[i+2]})
i += 2
case ">@":
if i == len(detail)-2 {
exports = append(exports, map[string]string{"config": detail[i+1], "index": "result"})
i += 1
break
}
exports = append(exports, map[string]string{"config": detail[i+1], "index": detail[i+2]})
i += 2
case "|":
detail, rest = detail[:i], detail[i+1:]
case "%":
rest = append(rest, "select")
detail, rest = detail[:i], append(rest, detail[i+1:]...)
default:
args = append(args, detail[i])
}
}
if !exec && !execexec {
return
}
detail = args
if msg.Cmd(detail); msg.Hand {
@ -270,7 +305,24 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
}
for _, v := range exports {
m.Spawn().Copy(msg, "option").Copy(msg, "append").Copy(msg, "result").Cmd("export", v["file"])
m.Log("info", "export %v", v)
if v["file"] != "" {
m.Spawn().Copy(msg, "option").Copy(msg, "append").Copy(msg, "result").Cmd("export", v["file"])
}
if v["cache"] != "" {
if v["index"] == "result" {
m.Cap(v["cache"], strings.Join(msg.Meta["result"], ""))
} else {
m.Cap(v["cache"], msg.Append(v["index"]))
}
}
if v["config"] != "" {
if v["index"] == "result" {
m.Conf(v["config"], strings.Join(msg.Meta["result"], ""))
} else {
m.Conf(v["config"], msg.Append(v["index"]))
}
}
}
if len(rest) > 0 {
@ -298,7 +350,12 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
case "$":
m.Echo(msg.Cap(arg[1]))
case "@":
m.Echo(msg.Conf(arg[1]))
value := msg.Option(arg[1])
if value == "" {
value = msg.Conf(arg[1])
}
m.Echo(value)
default:
m.Echo(arg[0]).Echo(arg[1])
}
@ -551,7 +608,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
yac.Cmd("train", "stm", "echo", "echo", "rep{", "exp", "}")
yac.Cmd("train", "stm", "return", "return", "rep{", "exp", "}")
yac.Cmd("train", "word", "word", "mul{", "~", "!", "=", "\\|", "\\<", "\\>", "exe", "str", "[a-zA-Z0-9_/\\-.:]+", "}")
yac.Cmd("train", "word", "word", "mul{", "~", "!", "=", "\\?\\?", "\\?", "<", ">$", ">@", ">", "\\|", "%", "exe", "str", "[a-zA-Z0-9_/\\-.:]+", "}")
yac.Cmd("train", "cmd", "cmd", "rep{", "word", "}")
yac.Cmd("train", "exe", "exe", "$", "(", "cmd", ")")

File diff suppressed because it is too large Load Diff

View File

@ -27,9 +27,10 @@ type MUX interface {
}
type WEB struct {
*http.Client
*http.Server
*http.ServeMux
server *http.Server
template *template.Template
*template.Template
*ctx.Context
}
@ -173,16 +174,24 @@ func (web *WEB) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server
func (web *WEB) Begin(m *ctx.Message, arg ...string) ctx.Server {
web.Configs["root_index"] = &ctx.Config{Name: "root_index", Value: "/render", Help: "默认路由"}
web.Configs["logheaders"] = &ctx.Config{Name: "logheaders(yes/no)", Value: "no", Help: "日志输出报文头"}
web.Configs["template_sub"] = &ctx.Config{Name: "template_sub", Value: web.Context.Name, 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: "是否已初始化"}
web.Caches["master"] = &ctx.Cache{Name: "master(yes/no)", Value: "no", Help: "服务入口"}
web.ServeMux = http.NewServeMux()
web.Template = template.New("render").Funcs(ctx.CGI)
web.Template.ParseGlob(path.Join(m.Conf("template_dir"), "/*.tmpl"))
web.Template.ParseGlob(path.Join(m.Conf("template_dir"), m.Conf("template_sub"), "/*.tmpl"))
return web
}
func (web *WEB) Start(m *ctx.Message, arg ...string) bool {
m.Cap("directory", m.Confx("directory", arg, 0))
render := m.Target().Commands["/render"]
m.Travel(func(m *ctx.Message, i int) bool {
if h, ok := m.Target().Server.(MUX); ok && m.Cap("register") == "no" {
m.Cap("register", "yes")
@ -193,10 +202,15 @@ func (web *WEB) Start(m *ctx.Message, arg ...string) bool {
s.Handle(m.Cap("route"), http.StripPrefix(path.Dir(m.Cap("route")), h))
}
if m.Target().Commands["/render"] == nil {
m.Target().Commands["/render"] = render
}
msg := m.Target().Message()
for k, x := range m.Target().Commands {
if k[0] == '/' {
m.Log("info", "route: %s", k)
h.HandleCmd(m, k, x)
h.HandleCmd(msg, k, x)
m.Capi("nroute", 1)
}
}
@ -209,19 +223,23 @@ func (web *WEB) Start(m *ctx.Message, arg ...string) bool {
return true
})
if len(arg) == 0 {
return false
}
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
}
@ -250,51 +268,15 @@ 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: "路由数量"},
"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: "模板路径"},
"template_dir": &ctx.Config{Name: "template_dir", Value: "usr/template", Help: "模板路径"},
"template_debug": &ctx.Config{Name: "template_debug", Value: "true", 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": "head", "template": "head"},
map[string]interface{}{"name": "userinfo", "help": "userinfo",
"context": "aaa", "command": "userinfo", "arguments": []interface{}{"@sessid"},
},
map[string]interface{}{"name": "login", "help": "login", "template": "componet",
"context": "aaa", "command": "login", "arguments": []interface{}{"@username", "@password"},
"inputs": []interface{}{
map[string]interface{}{"type": "text", "name": "username", "label": "username"},
map[string]interface{}{"type": "password", "name": "password", "label": "password"},
map[string]interface{}{"type": "button", "label": "login"},
},
"display_append": "", "display_result": "", "result_reload": "10",
},
map[string]interface{}{"name": "tail", "template": "tail"},
},
"index": []interface{}{
map[string]interface{}{"name": "head", "template": "head"},
map[string]interface{}{"name": "clipbaord", "help": "clipbaord", "template": "clipboard"},
map[string]interface{}{"name": "buffer", "help": "buffer", "template": "componet",
"context": "cli", "command": "tmux", "arguments": []interface{}{"buffer"}, "inputs": []interface{}{
map[string]interface{}{"type": "text", "name": "limit", "label": "limit", "value": "3"},
map[string]interface{}{"type": "text", "name": "index", "label": "index"},
map[string]interface{}{"type": "button", "label": "refresh"},
},
"pre_run": true,
},
map[string]interface{}{"name": "command", "help": "command", "template": "componet",
"context": "cli.shell1", "command": "source", "arguments": []interface{}{"@cmd"},
"inputs": []interface{}{
map[string]interface{}{"type": "text", "name": "cmd", "value": "",
"class": "cmd", "clipstack": "clistack",
},
},
},
map[string]interface{}{"name": "time", "help": "time", "template": "componet",
"context": "cli", "command": "time", "arguments": []interface{}{"@string"},
"inputs": []interface{}{
@ -305,83 +287,6 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心",
map[string]interface{}{"type": "button", "label": "refresh"},
},
},
map[string]interface{}{"name": "json", "help": "json", "template": "componet",
"context": "nfs", "command": "json", "arguments": []interface{}{"@string"},
"inputs": []interface{}{
map[string]interface{}{"type": "text", "name": "string", "label": "string"},
map[string]interface{}{"type": "button", "label": "refresh"},
},
},
map[string]interface{}{"name": "upload", "help": "upload", "template": "componet",
"form_type": "upload",
"inputs": []interface{}{
map[string]interface{}{"type": "file", "name": "upload"},
map[string]interface{}{"type": "submit", "value": "submit"},
},
"display_result": "",
},
map[string]interface{}{"name": "dir", "help": "dir", "template": "componet",
"context": "nfs", "command": "dir", "arguments": []interface{}{"@dir",
"dir_deep", "no", "dir_name", "name", "dir_info", "",
"dir_link", "<a class='download' data-type='%s'>%s<a>",
},
"pre_run": true,
"inputs": []interface{}{
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": "is_dir", "value": "is_dir"},
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_r", "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{}{"type": "text", "name": "dir", "label": "dir"},
},
},
map[string]interface{}{"name": "web_site", "help": "web_site", "template": "componet",
"context": "web", "command": "config", "arguments": []interface{}{
"web_site", "format_field", "site", "<a href='%s'>%s<a>",
},
"display_result": "",
},
map[string]interface{}{"name": "prompt", "help": "prompt", "template": "componet",
"context": "nfs.stdio", "command": "prompt", "arguments": []interface{}{"@string"},
"inputs": []interface{}{
map[string]interface{}{"type": "text", "name": "string", "label": "string"},
map[string]interface{}{"type": "button", "label": "refresh"},
},
},
map[string]interface{}{"name": "exec", "help": "exec", "template": "componet",
"context": "nfs.stdio", "command": "exec", "arguments": []interface{}{"@string"},
"inputs": []interface{}{
map[string]interface{}{"type": "text", "name": "string"},
},
},
map[string]interface{}{"name": "show", "help": "show", "template": "componet",
"context": "nfs.stdio", "command": "show", "arguments": []interface{}{"\n", "@string", "\n"},
"inputs": []interface{}{
map[string]interface{}{"type": "text", "name": "string", "label": "string"},
map[string]interface{}{"type": "button", "label": "refresh"},
},
},
map[string]interface{}{"name": "tail", "template": "tail"},
},
}, Help: "组件列表"},
@ -599,6 +504,7 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心",
m.Spawn().Cmd("open", url)
}
}},
"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)
}},
@ -660,26 +566,26 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心",
"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 {
tmpl, e := web.template.Clone()
tmpl, e := web.Template.Clone()
m.Assert(e)
tmpl.Funcs(ctx.CGI)
@ -765,16 +671,21 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心",
m.Append("redirect", m.Option("referer"))
}},
"/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) {
if web, ok := m.Target().Server.(*WEB); m.Assert(ok) {
accept_json := strings.HasPrefix(m.Option("accept"), "application/json")
list := []interface{}{}
// tmpl, e := web.template.Clone()
// tmpl, e := web.Template.Clone()
// m.Assert(e)
// tmpl.Funcs(ctx.CGI)
//
tmpl := template.New("render").Funcs(ctx.CGI)
tmpl.ParseGlob(fmt.Sprintf("%s/context/usr/template/common/base.tmpl", os.Getenv("HOME")))
tmpl := web.Template
if m.Confs("template_debug") {
tmpl = template.New("render").Funcs(ctx.CGI)
tmpl.ParseGlob(path.Join(m.Conf("template_dir"), "/*.tmpl"))
tmpl.ParseGlob(path.Join(m.Conf("template_dir"), m.Conf("template_sub"), "/*.tmpl"))
}
w := m.Optionv("response").(http.ResponseWriter)
if accept_json {

View File

@ -1,650 +1,151 @@
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{
"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{}{
"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"},
"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{}{
"session": "aaa",
"module": "aaa", "command": "login",
"variable": []interface{}{"$sessid"},
"template": "login", "title": "login",
map[string]interface{}{"name": "head", "template": "head"},
map[string]interface{}{"name": "userinfo", "help": "userinfo",
"context": "aaa", "command": "userinfo", "arguments": []interface{}{"@sessid"},
},
map[string]interface{}{
"module": "aaa", "command": "login",
"variable": []interface{}{"$username", "$password"},
"template": "login", "title": "login",
map[string]interface{}{"name": "login", "help": "login", "template": "componet",
"context": "aaa", "command": "login", "arguments": []interface{}{"@username", "@password"},
"inputs": []interface{}{
map[string]interface{}{"type": "text", "name": "username", "label": "username"},
map[string]interface{}{"type": "password", "name": "password", "label": "password"},
map[string]interface{}{"type": "button", "label": "login"},
},
"display_append": "", "display_result": "", "result_reload": "10",
},
map[string]interface{}{"name": "tail", "template": "tail"},
},
"right": []interface{}{
map[string]interface{}{
"module": "web", "command": "right",
"variable": []interface{}{"$username", "check", "command", "/index", "dir", "$dir"},
"template": "notice", "title": "notice",
"index": []interface{}{
map[string]interface{}{"name": "head", "template": "head"},
map[string]interface{}{"name": "clipbaord", "help": "clipbaord", "template": "clipboard"},
map[string]interface{}{"name": "buffer", "help": "buffer", "template": "componet",
"context": "cli", "command": "tmux", "arguments": []interface{}{"buffer"}, "inputs": []interface{}{
map[string]interface{}{"type": "text", "name": "limit", "label": "limit", "value": "3"},
map[string]interface{}{"type": "text", "name": "index", "label": "index"},
map[string]interface{}{"type": "button", "label": "refresh"},
},
"pre_run": true,
},
map[string]interface{}{
"module": "aaa", "command": "login",
"variable": []interface{}{"username", "password"},
"template": "login", "title": "login",
map[string]interface{}{"name": "command", "help": "command", "template": "componet",
"context": "cli.shell1", "command": "source", "arguments": []interface{}{"@cmd"},
"inputs": []interface{}{
map[string]interface{}{"type": "text", "name": "cmd", "value": "",
"class": "cmd", "clipstack": "clistack",
},
},
},
map[string]interface{}{"name": "time", "help": "time", "template": "componet",
"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"},
map[string]interface{}{"type": "button", "label": "refresh"},
},
},
map[string]interface{}{"name": "json", "help": "json", "template": "componet",
"context": "nfs", "command": "json", "arguments": []interface{}{"@string"},
"inputs": []interface{}{
map[string]interface{}{"type": "text", "name": "string", "label": "string"},
map[string]interface{}{"type": "button", "label": "refresh"},
},
},
map[string]interface{}{"name": "upload", "help": "upload", "template": "componet",
"form_type": "upload",
"inputs": []interface{}{
map[string]interface{}{"type": "file", "name": "upload"},
map[string]interface{}{"type": "submit", "value": "submit"},
},
"display_result": "",
},
map[string]interface{}{"name": "dir", "help": "dir", "template": "componet",
"context": "nfs", "command": "dir", "arguments": []interface{}{"@dir",
"dir_deep", "no", "dir_name", "name", "dir_info", "",
"dir_link", "<a class='download' data-type='%s'>%s<a>",
},
"pre_run": true,
"inputs": []interface{}{
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": "is_dir", "value": "is_dir"},
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_r", "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{}{"type": "text", "name": "dir", "label": "dir"},
},
},
map[string]interface{}{"name": "web_site", "help": "web_site", "template": "componet",
"context": "web", "command": "config", "arguments": []interface{}{
"web_site", "format_field", "site", "<a href='%s'>%s<a>",
},
"display_result": "",
},
map[string]interface{}{"name": "prompt", "help": "prompt", "template": "componet",
"context": "nfs.stdio", "command": "prompt", "arguments": []interface{}{"@string"},
"inputs": []interface{}{
map[string]interface{}{"type": "text", "name": "string", "label": "string"},
map[string]interface{}{"type": "button", "label": "refresh"},
},
},
map[string]interface{}{"name": "exec", "help": "exec", "template": "componet",
"context": "nfs.stdio", "command": "exec", "arguments": []interface{}{"@string"},
"inputs": []interface{}{
map[string]interface{}{"type": "text", "name": "string"},
},
},
map[string]interface{}{"name": "show", "help": "show", "template": "componet",
"context": "nfs.stdio", "command": "show", "arguments": []interface{}{"\n", "@string", "\n"},
"inputs": []interface{}{
map[string]interface{}{"type": "text", "name": "string", "label": "string"},
map[string]interface{}{"type": "button", "label": "refresh"},
},
},
map[string]interface{}{"name": "tail", "template": "tail"},
},
}, 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("<span style='color:red'>"),
[]byte{27, 91, 51, 49, 109}, []byte("<span style='color:green'>"),
[]byte{27, 91, 109}, []byte("</span>"),
}
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)
}
}
}},
}, Help: "组件列表"},
},
Commands: map[string]*ctx.Command{},
}
func init() {
code := &CODE{}
code := &web.WEB{}
code.Context = Index
web.Index.Register(Index, code)
}

View File

@ -1,48 +1,119 @@
package wiki
import (
"os/exec"
"time"
"bufio"
"bytes"
"contexts/ctx"
"contexts/web"
"encoding/json"
"encoding/xml"
"fmt"
"github.com/gomarkdown/markdown"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"os"
"path"
"path/filepath"
"strings"
)
type WIKI struct {
web.WEB
}
var Index = &ctx.Context{Name: "wiki", Help: "文档中心",
Caches: map[string]*ctx.Cache{},
Configs: map[string]*ctx.Config{
"which": &ctx.Config{Name: "which", Value: "redis.note", Help: "路由数量"},
"wiki_dir": &ctx.Config{Name: "wiki_dir", Value: "usr/wiki", Help: "路由数量"},
"wiki_dir": &ctx.Config{Name: "wiki_dir", Value: "usr/wiki", Help: "路由数量"},
"wiki_favor": &ctx.Config{Name: "wiki_favor", Value: "lamp.md", Help: "路由数量"},
"wiki_list": &ctx.Config{Name: "wiki_list", Value: []interface{}{}, Help: "路由数量"},
"wiki_list_show": &ctx.Config{Name: "wiki_list_show", Value: map[string]interface{}{
"md": true,
}, Help: "路由数量"},
"componet_group": &ctx.Config{Name: "component_group", Value: "index", Help: "默认组件"},
"componet": &ctx.Config{Name: "componet", Value: map[string]interface{}{
"index": []interface{}{
map[string]interface{}{"name": "head", "template": "head"},
map[string]interface{}{"name": "header", "template": "header"},
map[string]interface{}{"name": "list", "template": "list",
"context": "web.wiki", "command": "wiki_list", "arguments": []interface{}{"h2", "int_r"},
"pre_run": true,
},
map[string]interface{}{"name": "text", "template": "text",
"context": "web.wiki", "command": "wiki_body", "arguments": []interface{}{"@wiki_favor"},
"pre_run": true,
},
map[string]interface{}{"name": "footer", "template": "footer"},
map[string]interface{}{"name": "tail", "template": "tail"},
},
}, Help: "组件列表"},
},
Commands: map[string]*ctx.Command{
"/blog": &ctx.Command{Name: "/blog", Help: "博客", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if m.Has("title") && m.Has("content") {
"wiki_list": &ctx.Command{Name: "wiki_list sort_field sort_order", Help: "wiki_list", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
sort_field, sort_order := "h2", "int_r"
if len(arg) > 0 {
sort_field, arg = arg[0], arg[1:]
}
if len(arg) > 0 {
sort_order, arg = arg[0], arg[1:]
}
m.Echo("blog service")
md, e := ioutil.ReadDir(m.Conf("wiki_dir"))
m.Assert(e)
for _, v := range md {
if strings.HasSuffix(v.Name(), ".md") {
f, e := os.Open(path.Join(m.Conf("wiki_dir"), v.Name()))
m.Assert(e)
defer f.Close()
title := ""
nline, ncode := 0, 0
h2, h3, h4 := 0, 0, 0
for bio := bufio.NewScanner(f); bio.Scan(); {
line := bio.Text()
nline++
if strings.HasPrefix(line, "## ") {
h2++
if title == "" {
title = line[3:]
}
} else if strings.HasPrefix(line, "### ") {
h3++
} else if strings.HasPrefix(line, "#### ") {
h4++
} else if strings.HasPrefix(line, "```") {
ncode++
}
}
m.Add("append", "time", v.ModTime().Format("2006/01/02"))
m.Add("append", "file", v.Name())
m.Add("append", "size", v.Size())
m.Add("append", "line", nline)
m.Add("append", "code", ncode/2)
m.Add("append", "h4", h4)
m.Add("append", "h3", h3)
m.Add("append", "h2", h2)
m.Add("append", "title", title)
}
}
m.Sort(sort_field, sort_order).Table()
m.Target().Configs["wiki_list"].Value = []interface{}{}
m.Table(func(maps map[string]string, list []string, line int) bool {
if line > 0 {
m.Confv("wiki_list", -2, maps)
}
return true
})
}},
"wiki_body": &ctx.Command{Name: "wiki_body", Help: "wiki_body", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
which := path.Join(m.Conf("wiki_dir"), m.Confx("wiki_favor", arg, 0))
if ls, e := ioutil.ReadFile(which); e == nil {
ls = markdown.ToHTML(ls, nil, nil)
m.Echo(string(ls))
}
}},
"/wiki_tags": &ctx.Command{Name: "/wiki_tags ", Help: "博客", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if len(arg) > 0 {
m.Option("dir", arg[0])
@ -347,269 +418,11 @@ 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))
}
}
}},
},
}
func init() {
wiki := &WIKI{}
wiki := &web.WEB{}
wiki.Context = Index
web.Index.Register(Index, wiki)
}

View File

@ -1,20 +1,3 @@
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 copy_to_clipboard(text) {
var clipboard = document.querySelector(".clipboard")
clipboard.value = text

View File

@ -126,3 +126,23 @@ context = {
xhr.send();
},
}
context.isMobile = navigator.userAgent.indexOf("Mobile") > -1
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)
}

154
usr/librarys/wiki.js Normal file
View File

@ -0,0 +1,154 @@
function action(event, cmd) {
switch (cmd) {
case "toggle_nav":
var nav = document.querySelector("nav")
nav.hidden = !nav.hidden
var article = document.querySelector("article")
if (!context.isMobile) {
article.style.width = nav.hidden? "80%": "calc(100% - 250px)"
}
break
case "toggle_list":
var list = document.querySelector(".list")
list.hidden = !list.hidden
break
case "toggle_menu":
var menu = document.querySelector(".menu")
menu.hidden = !menu.hidden
break
case "toggle_link":
var link = document.querySelector(".link")
link.hidden = !link.hidden
break
}
}
function init_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;
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 = append_child(m[i], "li")
var a = append_child(one, "a")
a.href = "#"+list[j].hash;
a.innerText = text+" ("+parseInt((list[j].position-min)/max*100)+"%)";
one.className = list[j].level;
}
}
}
function init_link() {
var link = [];
var a = document.querySelectorAll(".text a");
for (var i = 0; i < a.length; i++) {
link.push({href: a[i].href, title: a[i].innerText});
}
var m = document.getElementsByClassName("link");
for (var i = 0; i < m.length; i++) {
var one = append_child(m[i], "li")
var a = one.appendChild(document.createTextNode("相关链接: "));
for (var j = 0; j < link.length; j++) {
var one = append_child(m[i], "li")
var a = one.appendChild(document.createTextNode(link[j].title+": "));
var a = append_child(one, "a");
a.href = link[j].href
a.innerText = a.href
}
}
}
function init_code() {
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));
}
}
}
window.onload = function() {
init_menu()
init_link()
init_code()
var article = document.querySelector("article")
var mav = document.querySelector("nav")
alert(context.isMobile)
if (context.isMobile) {
article.style.width = "100%"
} else {
article.style.maxHeight = "calc(100% - 80px)"
mav.style.maxHeight = "calc(100% - 80px)"
}
}

198
usr/template/code/code.tmpl Normal file
View File

@ -0,0 +1,198 @@
{{define "head"}}
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=0.7">
<title>{{option .Meta "page_title"}}</title>
<style>
html, body {
height:100%;
width:100%;
margin:0px;
background-color:#d8d8d8;
}
fieldset {
margin-top:8px;
}
legend {
font-size:16px;
font-weight:bold;
font-family:monospace;
}
</style>
<style>
textarea.clipboard {
color:white;
background-color:#272822;
width:600px;
}
form.option div {
float:left;
}
form.option hr {
clear:both;
}
form.option label.keymap {
color:red;
display:none;
}
form.option label.keymap.show {
display:inline;
}
form.option input {
margin-right:10px;
}
form.option input.cmd {
color:white;
background-color:#272822;
padding-left:10px;
width:600px;
}
form.option.exec input {
color:white;
background-color:#272822;
padding-left:10px;
width:600px;
}
form.option select {
margin-right:10px;
}
table.append {
font-size:14px;
}
table.append th {
font-family:monospace;
background-color:lightgreen;
cursor:pointer;
}
table.append th.order {
background-color:red;
cursor:pointer;
}
table.append td {
font-family:monospace;
padding-left: 10px;
padding-right: 20px;
}
code.result pre {
color:white;
font-size:14px;
background-color:#272822;
overflow:scroll;
padding:5px;
border:solid 2px green;
border-left:solid 4px green;
margin:0;
}
code.result pre.clipboard {
height:2em;
}
</style>
</head>
<body onkeyup="return onaction(event, 'keymap')">
{{end}}
{{define "void"}}{{end}}
{{define "detail"}}{{detail .}}{{end}}
{{define "option"}}{{option .}}{{end}}
{{define "append"}}{{append .}}{{end}}
{{define "result"}}{{result .}}{{end}}
{{define "clipboard"}}
<fieldset><legend>clipboard</legend>
<datalist id="clipstack"></datalist>
<datalist id="clistack"></datalist>
<textarea class="clipboard"></textarea>
</fieldset>
{{end}}
{{define "componet"}}
<fieldset><legend title="{{option .Meta "help"}}">{{option .Meta "help"}}({{option .Meta "context"}}.{{option .Meta "command"}})</legend>
{{$form_type := option . "form_type"|meta}}
{{if eq $form_type "upload"}}
{{end}}
<form class="option {{option .Meta "name"}}"
data-last_componet_group="{{option . "last_componet_group"|meta}}"
data-last_componet_order="{{option . "last_componet_order"|meta}}"
data-componet_group="{{option . "componet_group"|meta}}"
data-componet_order="{{option . "componet_order"|meta}}"
data-componet_name="{{option . "name"|meta}}"
data-componet_help="{{option . "help"|meta}}"
{{if eq $form_type "upload"}}
method="POST" action="/upload" enctype="multipart/form-data"
onsubmit="onaction(event,'upload')"
{{end}}
>
<input style="display:none"></input>
{{range $index, $input := option . "inputs"}}
<div>
{{$type := index $input "type"}}
{{if index $input "label"}}
<label>{{index $input "label"}} : </label>
{{end}}
{{if eq $type "button"}}
<input type="button" onclick="return onaction(event, 'command')" value="{{index $input "label"}}">
{{else if eq $type "submit"}}
<input type="submit" value="{{index $input "value"}}">
{{else if eq $type "file"}}
<input type="file" name="{{index $input "name"}}">
{{else if eq $type "choice"}}
{{$default_value := index $input "value"}}
<select name="{{index $input "name"}}" onchange="return onaction(event, 'command')">
{{range $index, $value := index $input "choice"}}
{{$val := index $value "value"}}
{{if eq $default_value $val}}
<option value="{{index $value "value"}}" selected>{{index $value "name"}}</option>
{{else}}
<option value="{{index $value "value"}}">{{index $value "name"}}</option>
{{end}}
{{end}}
</select>
{{else}}
<input
name="{{index $input "name"}}"
value="{{index $input "value"}}"
class="{{index $input "class"}}"
{{if index $input "clipstack"}}
list="{{index $input "clipstack"}}"
{{else}}
list="clipstack"
{{end}}
onclick="return onaction(event, 'click')"
onkeyup="return onaction(event, 'input')">
{{end}}
</div>
{{end}}
<hr/>
</form>
{{if eq $form_type "upload"}}
{{end}}
{{if index .Meta "display_append"}}
{{option .Meta "display_append"}}
{{else}}
<table class="append {{option .Meta "name"}}">
{{$msg := .}}
<tr>{{range $field := append .}}<th>{{$field}}</th>{{end}}</tr>
{{range $line := table .}}
<tr>{{range $field := append $msg}}<td>{{index $line $field|unescape}}</td>{{end}}</tr>
{{end}}
</table>
{{end}}
{{if index .Meta "display_result"}}
{{option .Meta "display_result"}}
{{else}}
<code class="result {{option .Meta "name"}}"><pre>{{result .Meta}}</pre></code>
{{end}}
</fieldset>
{{end}}
{{define "tail"}}
<script src="/librarys/context.js"></script>
<script src="/librarys/code.js"></script>
</body>
{{end}}

148
usr/template/wiki/wiki.tmpl Normal file
View File

@ -0,0 +1,148 @@
{{define "head"}}
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=0.7">
<title>{{option .Meta "page_title"}}</title>
<style>
html, body {
height:100%;
width:100%;
margin:0px;
background-color:#d8d8d8;
}
header {
color:white;
font-size:20px;
font-family:monospace;
text-align:center;
background-color:#0747a6;
width:100%;
height:40px;
}
header .title {
padding:6px;
}
header .toggle {
cursor:pointer;
width:40px;
position:absolute;
left:20px;
top:5px;
}
header .toggle:hover {
background-color:blue;
}
header .search {
position:absolute;
right:20px;
top:5px;
}
header .search input {
font-size:14px;
background-color:#91d7f5;
padding:4px;
width:60px;
}
header .search input:focus {
width:120px;
}
nav {
float:left;
min-width:250px;
overflow:auto;
}
article {
float:left;
width:calc(100% - 250px);
min-width:600px;
overflow:auto;
}
.list li {
padding-top:10px;
}
.list li:hover {
background-color:green;
}
.list a {
text-decoration-line:none;
}
.toggle_menu {
width:100%;
cursor:pointer;
background-color:green;
}
.menu li {
padding-top:10px;
}
.menu a {
text-decoration-line:none;
}
.menu li:hover {
background-color:green;
}
.toggle_list {
width:100%;
cursor:pointer;
background-color:green;
}
.link a {
text-decoration-line:none;
}
.text {
margin:20px;
}
.mono {
font-family:monospace;
}
footer {
clear:both;
}
</style>
</head>
<body>
{{end}}
{{define "header"}}
<header>
<div class="toggle" onclick="action(event, 'toggle_nav')">三</div>
<div class="search"><input type="text" placeholder="搜索"></div>
<div class="title">shylinux</div>
</header>
<nav>
{{end}}
{{define "list"}}
<div class="toggle_menu" onclick="action(event, 'toggle_list')">文章</div>
<ul class="list" hidden>
{{range $i, $l := table .}}
<li>
<a href="?wiki_favor={{index $l "file"}}">{{index $l "file"}}</a><br/>
<span class="mono"> {{index $l "time"}} </span>
</li>
{{end}}
</ul>
{{end}}
{{define "text"}}
<div class="toggle_menu" onclick="action(event, 'toggle_menu')">目录</div>
<ul class="menu"></ul>
</nav>
<article>
<div class="toggle_link" onclick="action(event, 'toggle_link')">参考链接</div>
<ul class="link" hidden></ul>
<div class="text">{{result .|meta|unescape}}</div>
</article>
{{end}}
{{define "footer"}}
<footer>shylinux</footer>
{{end}}
{{define "tail"}}
<script src="/librarys/context.js"></script>
<script src="/librarys/wiki.js"></script>
</body>
{{end}}