diff --git a/etc/dotsfile/.vimrc b/etc/dotsfile/.vimrc index 6bbd28ef..902a1b3b 100644 --- a/etc/dotsfile/.vimrc +++ b/etc/dotsfile/.vimrc @@ -8,14 +8,14 @@ "加载插件"{{{ call plug#begin() Plug 'vim-scripts/tComment' +Plug 'gcmt/taboo.vim' +Plug 'vim-scripts/tComment' Plug 'tpope/vim-fugitive' Plug 'airblade/vim-gitgutter' Plug 'vim-airline/vim-airline' Plug 'vim-airline/vim-airline-themes' Plug 'ntpeters/vim-better-whitespace' Plug 'easymotion/vim-easymotion' -nmap t ;;t -nmap T ;;T Plug 'vim-scripts/taglist.vim' let g:Tlist_WinWidth=45 @@ -55,12 +55,14 @@ let g:syntastic_quiet_messages = { "regex": [ \ "Invalid variable name", \ "Too many instance attributes", \ "defined outside __init__", + \ "Catching too general exception Exception", \ ] } Plug 'Valloric/YouCompleteMe' let g:syntastic_enable_signs = 1 let g:ycm_confirm_extra_conf=0 nnoremap gd :YcmCompleter GoToDeclaration +nnoremap gD :YcmCompleter GoToReferences Plug 'benmills/vimux' let mapleader=";" @@ -126,13 +128,14 @@ cnoremap jk "}}} " 编程配置{{{ set keywordprg=man\ -a +set splitbelow +set splitright +autocmd BufReadPost * normal `" autocmd BufNewFile,BufReadPost *.shy set filetype=shy autocmd BufNewFile,BufReadPost *.shy set commentstring=#%s autocmd BufNewFile,BufReadPost *.conf set filetype=nginx -autocmd BufNewFile,BufReadPost *.go set foldmethod=syntax command! RR wa | source ~/.vimrc |e - source ~/.vim_local "}}} diff --git a/etc/dotsfile/.zshrc b/etc/dotsfile/.zshrc index 50aba0e7..61dc9fd5 100644 --- a/etc/dotsfile/.zshrc +++ b/etc/dotsfile/.zshrc @@ -51,7 +51,7 @@ ZSH_THEME="robbyrussell" # Custom plugins may be added to ~/.oh-my-zsh/custom/plugins/ # Example format: plugins=(rails git textmate ruby lighthouse) # Add wisely, as too many plugins slow down shell startup. -plugins=(tmux docker git) +plugins=(tmux git) source $ZSH/oh-my-zsh.sh source ~/.oh-my-zsh/plugins/z/z.sh diff --git a/etc/dotsfile/shy.vim b/etc/dotsfile/shy.vim index 905d6924..ef96204c 100644 --- a/etc/dotsfile/shy.vim +++ b/etc/dotsfile/shy.vim @@ -17,33 +17,31 @@ syn keyword shStatement if else elif end for syn keyword shStatement let var " ctx command -syn match shStatement "\(^\|\t\|$(\|\ \ \)cache" -syn match shStatement "\(^\|\t\|$(\|\ \ \)config" - -syn match shStatement "\(^\|\t\|$(\|\ \ \)detail" -syn match shStatement "\(^\|\t\|$(\|\ \ \)option" -syn match shStatement "\(^\|\t\|$(\|\ \ \)append" -syn match shStatement "\(^\|\t\|$(\|\ \ \)result" +syn match shStatement "\(^\|\t\|$(\)cache" +syn match shStatement "\(^\|\t\|$(\)config" +syn match shStatement "\(^\|\t\|$(\)detail" +syn match shStatement "\(^\|\t\|$(\)option" +syn match shStatement "\(^\|\t\|$(\)append" +syn match shStatement "\(^\|\t\|$(\)result" " ctx command -syn match shCommand "\(^\|\t\|$(\|\ \ \)command" -syn match shCommand "\(^\|\t\|$(\|\ \ \)context" -syn match shCommand "\(^\|\t\|$(\|\ \ \)message" -syn match shCommand "\(^\|\t\|$(\|\ \ \)session" -syn match shCommand "\(^\|\t\|$(\|\ \ \)server" -syn match shCommand "\(^\|\t\|$(\|\ \ \)right" +syn match shCommand "\(^\|\t\|$(\)message" +syn match shCommand "\(^\|\t\|$(\)session" +syn match shCommand "\(^\|\t\|$(\)context" +syn match shCommand "\(^\|\t\|$(\)server" +syn match shCommand "\(^\|\t\|$(\)command" +syn match shCommand "\(^\|\t\|$(\)right" " tcp command -syn match shCommand "\(^\|\t\|$(\|\ \ \)listen" +syn match shCommand "\(^\|\t\|$(\)listen" " web command -syn match shCommand "\(^\|\t\|$(\|\ \ \)client" -syn match shCommand "\(^\|\t\|$(\|\ \ \)serve\$" -syn match shCommand "\(^\|\t\|$(\|\ \ \)route" +syn match shCommand "\(^\|\t\|$(\)serve" +syn match shCommand "\(^\|\t\|$(\)route" -syn match shCommand "\(^\|\t\|$(\|\ \ \)open" -syn match shCommand "\(^\|\t\|$(\|\ \ \)cookie" -syn match shCommand "\(^\|\t\|$(\|\ \ \)login" +syn match shCommand "\(^\|\t\|$(\)open" +syn match shCommand "\(^\|\t\|$(\)cookie" +syn match shCommand "\(^\|\t\|$(\)login" hi def link shComment Comment hi def link shString String diff --git a/src/contexts/cli/cli.go b/src/contexts/cli/cli.go index 1f653f1d..2a545818 100644 --- a/src/contexts/cli/cli.go +++ b/src/contexts/cli/cli.go @@ -73,10 +73,12 @@ func (cli *CLI) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server s.Message = m s.target = c s.alias = map[string][]string{ - "~": []string{"context"}, - "!": []string{"message"}, - "@": []string{"config"}, - "$": []string{"cache"}, + "~": []string{"context"}, + "!": []string{"message"}, + ":": []string{"command"}, + "::": []string{"command", "list"}, + "@": []string{"config"}, + "$": []string{"cache"}, } return s diff --git a/src/contexts/ctx/ctx.go b/src/contexts/ctx/ctx.go index 568b3893..fd3d17d2 100644 --- a/src/contexts/ctx/ctx.go +++ b/src/contexts/ctx/ctx.go @@ -39,6 +39,8 @@ func Trans(arg ...interface{}) []string { ls = append(ls, fmt.Sprintf("%t", val)) case int, int8, int16, int32, int64: ls = append(ls, fmt.Sprintf("%d", val)) + case float64: + ls = append(ls, fmt.Sprintf("%d", int(val))) case []interface{}: for _, v := range val { switch val := v.(type) { @@ -68,15 +70,15 @@ func Trans(arg ...interface{}) []string { return ls } func Chain(m *Message, data interface{}, args ...interface{}) interface{} { - if len(args) == 1 { - if arg, ok := args[0].([]string); ok { - args = args[:0] - for _, v := range arg { - args = append(args, v) - } - } - } - + // if len(args) == 1 { + // if arg, ok := args[0].([]string); ok { + // args = args[:0] + // for _, v := range arg { + // args = append(args, v) + // } + // } + // } + // root := data for i := 0; i < len(args); i += 2 { var parent interface{} @@ -2132,6 +2134,9 @@ var Index = &Context{Name: "ctx", Help: "模块中心", "table_compact": &Config{Name: "table_compact", Value: "false", Help: "命令列表帮助"}, "table_col_sep": &Config{Name: "table_col_sep", Value: "\t", Help: "命令列表帮助"}, "table_row_sep": &Config{Name: "table_row_sep", Value: "\n", Help: "命令列表帮助"}, + + "page_offset": &Config{Name: "page_offset", Value: "0", Help: "列表偏移"}, + "page_limit": &Config{Name: "page_limit", Value: "10", Help: "列表大小"}, }, Commands: map[string]*Command{ "help": &Command{Name: "help topic", Help: "帮助", Hand: func(m *Message, c *Context, key string, arg ...string) { @@ -2846,7 +2851,8 @@ var Index = &Context{Name: "ctx", Help: "模块中心", } } if cache_name != "" && li > -1 { - m.Echo(m.Cap(cache_name, msg.Meta[cache_index][li])) + // m.Echo(m.Cap(cache_name, msg.Meta[cache_index][li])) + m.Echo(m.Cap(cache_name, fmt.Sprint(msg.Confv(m.Confx("body_response"), cache_index)))) } else { m.Copy(msg, "result").Copy(msg, "append") } @@ -2942,7 +2948,19 @@ var Index = &Context{Name: "ctx", Help: "模块中心", "config": &Command{ Name: "config [all] [save|load file key...] [delete] [pop index] key [value...]|key name value help", Help: "查看、读写、添加配置变量", + Form: map[string]int{ + "chains": 1, "fields": 1, + "where_field": 1, "where_value": 1, + "sort_field": 1, "sort_order": 1, + "page_limit": 1, "page_offset": 1, + "select": 3, + }, Hand: func(m *Message, c *Context, key string, arg ...string) { + offset, e := strconv.Atoi(m.Confx("page_offset")) + m.Assert(e) + limit, e := strconv.Atoi(m.Confx("page_limit")) + m.Assert(e) + all := false if len(arg) > 0 && arg[0] == "all" { arg, all = arg[1:], true @@ -2977,7 +2995,8 @@ var Index = &Context{Name: "ctx", Help: "模块中心", de.Decode(&save) } - sort := "string" + sort_field := m.Option("sort_field") + sort_order := m.Option("sort_order") m.BackTrace(func(m *Message) bool { for k, v := range m.target.Configs { switch action { @@ -3033,31 +3052,70 @@ var Index = &Context{Name: "ctx", Help: "模块中心", if k != arg[0] { continue } - switch val := v.Value.(type) { - case map[string]string: - for k, _ := range val { - m.Add("append", "key", k) - m.Add("append", "val", m.Conf(arg[0], k)) + + value := m.Confv(arg[0]) + if m.Options("chains") { + value = m.Confv(arg[0], strings.Split(m.Option("chains"), ".")) + } + + 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) + } + m.Log("fuck", "what %v", fields) + + switch val := value.(type) { case map[string]interface{}: - for k, _ := range val { - m.Add("append", "key", k) - m.Add("append", "val", m.Conf(arg[0], k)) + m.Add("append", "index", "0") + for k, v := range val { + if len(fields) == 0 || fields[k] { + m.Add("append", k, v) + } } - case []string: - sort = "int" - for i, _ := range val { - m.Add("append", "key", i) - m.Add("append", "val", m.Conf(arg[0], k)) + m.Log("fuck", "what %v", m.Meta) + case map[string]string: + m.Add("append", "index", "0") + for k, v := range val { + if len(fields) == 0 || fields[k] { + m.Add("append", k, v) + } } case []interface{}: - sort = "int" - for i, _ := range val { - m.Add("append", "key", i) - m.Add("append", "val", m.Conf(arg[0], k)) + n := 0 + for i, value := range val { + switch val := value.(type) { + case map[string]interface{}: + if m.Options("where_field") && m.Options("where_value") { + if !strings.Contains(fmt.Sprintf("%v", val[m.Option("where_field")]), m.Option("where_value")) { + continue + } + } + n++ + if n <= offset || n > offset+limit { + continue + } + + m.Add("append", "index", i) + for k, v := range val { + if len(fields) == 0 || fields[k] { + m.Add("append", k, v) + } + } + } } - case string: - m.Echo(m.Conf(arg[0])) + case []string: + for i, v := range val { + m.Add("append", "index", i) + m.Add("append", "value", v) + } + default: + m.Echo("%v", Trans(val)[0]) } default: m.Echo("%v", m.Confv(arg[0], arg[1:])) @@ -3066,7 +3124,18 @@ var Index = &Context{Name: "ctx", Help: "模块中心", } } return all - }).Sort("key", sort).Table() + }) + + if m.Sort(sort_field, sort_order); m.Has("index") { + for i := 0; i < len(m.Meta["index"]); i++ { + m.Meta["index"][i] = fmt.Sprintf("%d", i+offset) + } + } + if m.Has("select") { + m.Echo(m.Cap(m.Meta["select"][2], m.Meta[m.Meta["select"][1]][m.Optioni("select")])) + } else { + m.Table() + } switch action { case "save": @@ -3082,13 +3151,12 @@ var Index = &Context{Name: "ctx", Help: "模块中心", m.Assert(e) m.Echo("%s", string(buf)) } - }}, "cache": &Command{ Name: "cache [all|key [value]|key = value|key name value help|delete key]", Help: "查看、读写、赋值、新建、删除缓存变量", Hand: func(m *Message, c *Context, key string, arg ...string) { - switch len(arg) { //{{{ + switch len(arg) { case 0: for k, v := range m.target.Caches { m.Add("append", "key", k) diff --git a/src/contexts/web/web.go b/src/contexts/web/web.go index b5be53cd..85bf1cf8 100644 --- a/src/contexts/web/web.go +++ b/src/contexts/web/web.go @@ -28,7 +28,6 @@ type MUX interface { } type WEB struct { client *http.Client - *http.ServeMux *http.Server @@ -274,12 +273,14 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心", "nroute": &ctx.Cache{Name: "nroute", Value: "0", Help: "路由数量"}, }, Configs: map[string]*ctx.Config{ - "brow_home": &ctx.Config{Name: "brow_home", Value: "http://localhost:9094", Help: "服务"}, - "directory": &ctx.Config{Name: "directory", Value: "usr", Help: "服务目录"}, - "address": &ctx.Config{Name: "address", Value: ":9094", Help: "服务地址"}, - "protocol": &ctx.Config{Name: "protocol", Value: "http", Help: "服务协议"}, - "cert": &ctx.Config{Name: "cert", Value: "etc/cert.pem", Help: "路由数量"}, - "key": &ctx.Config{Name: "key", Value: "etc/key.pem", Help: "路由数量"}, + "body_response": &ctx.Config{Name: "body_response", Value: "response", Help: "响应缓存"}, + "method": &ctx.Config{Name: "method", Value: "GET", Help: "请求方法"}, + "brow_home": &ctx.Config{Name: "brow_home", Value: "http://localhost:9094", Help: "服务"}, + "directory": &ctx.Config{Name: "directory", Value: "usr", Help: "服务目录"}, + "address": &ctx.Config{Name: "address", Value: ":9094", Help: "服务地址"}, + "protocol": &ctx.Config{Name: "protocol", Value: "http", 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: "路由数量"}, @@ -456,64 +457,57 @@ var Index = &ctx.Context{Name: "web", 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) { - if _, e := m.Target().Server.(*WEB); m.Assert(e) && len(arg) > 0 { - uri, e := url.Parse(arg[0]) - m.Assert(e) - m.Conf("method", "method", "GET", "请求方法") - m.Conf("protocol", "protocol", uri.Scheme, "服务协议") - m.Conf("hostname", "hostname", uri.Host, "服务主机") + uri, e := url.Parse(arg[0]) + m.Assert(e) + m.Conf("method", "method", "GET", "请求方法") + m.Conf("protocol", "protocol", uri.Scheme, "服务协议") + m.Conf("hostname", "hostname", uri.Host, "服务主机") - dir, file := path.Split(uri.EscapedPath()) - m.Conf("path", "path", dir, "服务路由") - m.Conf("file", "file", file, "服务文件") - m.Conf("query", "query", uri.RawQuery, "服务参数") + dir, file := path.Split(uri.EscapedPath()) + m.Conf("path", "path", dir, "服务路由") + m.Conf("file", "file", file, "服务文件") + m.Conf("query", "query", uri.RawQuery, "服务参数") - if m.Conf("output", "output", "stdout", "文件缓存"); len(arg) > 1 { - m.Conf("output", arg[1]) - } - if m.Conf("editor", "editor", "vim", "文件编辑器"); len(arg) > 2 { - m.Conf("editor", arg[2]) - } + if m.Conf("output", "output", "stdout", "文件缓存"); len(arg) > 1 { + m.Conf("output", arg[1]) + } + if m.Conf("editor", "editor", "vim", "文件编辑器"); len(arg) > 2 { + m.Conf("editor", arg[2]) } }}, "cookie": &ctx.Command{Name: "cookie [create]|[name [value]]", Help: "读写浏览器的Cookie, create: 创建cookiejar, name: 变量名, value: 变量值", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - if _, ok := m.Target().Server.(*WEB); m.Assert(ok) { - switch len(arg) { - case 0: - for k, v := range m.Confv("cookie").(map[string]interface{}) { - m.Echo("%s: %v\n", k, v.(*http.Cookie).Value) - } - case 1: - if arg[0] == "create" { - m.Target().Configs["cookie"] = &ctx.Config{Name: "cookie", Value: map[string]interface{}{}, Help: "cookie"} - break - } - if v, ok := m.Confv("cookie", arg[0]).(*http.Cookie); ok { - m.Echo("%s", v.Value) - } - default: - if v, ok := m.Confv("cookie", arg[0]).(*http.Cookie); ok { - v.Value = arg[1] - } else { - m.Confv("cookie", arg[0], &http.Cookie{Name: arg[0], Value: arg[1]}) - } + switch len(arg) { + case 0: + for k, v := range m.Confv("cookie").(map[string]interface{}) { + m.Echo("%s: %v\n", k, v.(*http.Cookie).Value) + } + case 1: + if arg[0] == "create" { + m.Target().Configs["cookie"] = &ctx.Config{Name: "cookie", Value: map[string]interface{}{}, Help: "cookie"} + break + } + if v, ok := m.Confv("cookie", arg[0]).(*http.Cookie); ok { + m.Echo("%s", v.Value) + } + default: + if m.Confv("cookie") == nil { + m.Target().Configs["cookie"] = &ctx.Config{Name: "cookie", Value: map[string]interface{}{}, Help: "cookie"} + } + if v, ok := m.Confv("cookie", arg[0]).(*http.Cookie); ok { + v.Value = arg[1] + } else { + m.Confv("cookie", arg[0], &http.Cookie{Name: arg[0], Value: arg[1]}) } } }}, - "get": &ctx.Command{ - Name: "get [method GET|POST] [file name filename] url arg...", - Help: "访问服务, method: 请求方法, file: 发送文件, url: 请求地址, arg: 请求参数", - Form: map[string]int{"method": 1, "headers": 2, "file": 2, "body_type": 1, "body": 1, "fields": 1, "value": 1, "json_route": 1, "json_key": 1}, + "get": &ctx.Command{Name: "get [method GET|POST] url arg...", + Help: "访问服务, method: 请求方法, url: 请求地址, arg: 请求参数", + Form: map[string]int{"method": 1, "headers": 2, "content_type": 1, "body": 1, "path_value": 1, "body_response": 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"), " ") + if m.Has("path_value") { values := []interface{}{} - for _, v := range args { + for _, v := range strings.Split(m.Option("path_value"), " ") { if len(v) > 1 && v[0] == '$' { values = append(values, m.Cap(v[1:])) } else { @@ -525,107 +519,39 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心", 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) + body, _ := m.Optionv("body").(io.Reader) - var body io.Reader - index := strings.Index(uri, "?") - contenttype := "" - - 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" { - contenttype = "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) - } - - contenttype = 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) - } - - contenttype = "application/json" - if index > -1 { - uri = uri[:index] - } - - } else if index > 0 { - contenttype = "application/x-www-form-urlencoded" - body = strings.NewReader(uri[index+1:]) - uri = uri[:index] + if method == "POST" && body == nil { + if index := strings.Index(uri, "?"); index > 0 { + uri, body = uri[:index], strings.NewReader(uri[index+1:]) } } 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(contenttype) > 0 { - req.Header.Set("Content-Type", contenttype) - m.Log("info", "content-type: %s", contenttype) + if m.Options("content_type") { + req.Header.Set("Content-Type", m.Option("content_type")) + } + switch cs := m.Confv("cookie").(type) { + case map[string]interface{}: + for _, v := range cs { + req.AddCookie(v.(*http.Cookie)) + } } - for _, v := range m.Confv("cookie").(map[string]interface{}) { - req.AddCookie(v.(*http.Cookie)) + m.Log("info", "%s %s", req.Method, req.URL) + m.Echo("%s: %s\n", req.Method, req.URL) + for k, v := range req.Header { + m.Log("fuck", "%s: %s", k, v) } + if web.client == nil { + web.client = &http.Client{} + } res, e := web.client.Do(req) m.Assert(e) @@ -634,134 +560,94 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心", 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) + var result interface{} ct := res.Header.Get("Content-Type") - if len(ct) >= 16 && ct[:16] == "application/json" { - var result interface{} + switch { + case strings.HasPrefix(ct, "application/json"): 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)) + default: + result = string(buf) } + m.Target().Configs[m.Confx("body_response")] = &ctx.Config{Value: result} + m.Echo(string(buf)) } }}, - "post": &ctx.Command{Name: "post", Help: "post请求", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - msg := m.Spawn().Cmd("get", "method", "POST", arg) - m.Copy(msg, "result").Copy(msg, "append") - }}, + "post": &ctx.Command{Name: "post [file fieldname filename]", Help: "post请求", + Form: map[string]int{"file": 2, "content_type": 1}, + Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + msg := m.Spawn() + if m.Has("file") { + file, e := os.Open(m.Meta["file"][1]) + m.Assert(e) + defer file.Close() + + buf := &bytes.Buffer{} + writer := multipart.NewWriter(buf) + writer.SetBoundary(fmt.Sprintf("\r\n--%s--\r\n", writer.Boundary())) + 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) + // } + + writer.Close() + msg.Optionv("body", buf) + msg.Option("content_type", writer.FormDataContentType()) + msg.Option("headers", "Content-Length", buf.Len()) + } else if m.Option("content_type") == "json" { + 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) + msg.Optionv("body", bytes.NewReader(b)) + msg.Option("content_type", "application/json") + arg = arg[:1] + } else if m.Option("content_type") == "json_fmt" { + data := []interface{}{} + for _, v := range arg[2:] { + if len(v) > 1 && v[0] == '$' { + v = m.Cap(v[1:]) + } else if len(v) > 1 && v[0] == '@' { + v = m.Cap(v[1:]) + } + data = append(data, v) + } + msg.Optionv("body", strings.NewReader(fmt.Sprintf(arg[1], data...))) + msg.Option("content_type", "application/json") + arg = arg[:1] + } else { + msg.Option("content_type", "application/x-www-form-urlencoded") + } + msg.Cmd("get", "method", "POST", arg) + m.Copy(msg, "result").Copy(msg, "append") + }}, "brow": &ctx.Command{Name: "brow url", Help: "浏览网页", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { url := m.Confx("brow_home", arg, 0) switch runtime.GOOS { @@ -1220,25 +1106,18 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心", if len(m.Meta["append"]) > 0 { meta["append"] = m.Meta["append"] for _, v := range m.Meta["append"] { - m.Log("json", "won %v %v", v, m.Meta[v]) if _, ok := m.Data[v]; ok { meta[v] = m.Data[v] - m.Log("json", "1won %v %v", v, meta[v]) - m.Log("json", "1won %v %v", v, meta[v], m.Meta[v]) } else if _, ok := m.Meta[v]; ok { - m.Log("json", "2won %v %v", v, meta[v]) meta[v] = m.Meta[v] } - m.Log("json", "won %v %v", v, meta[v]) } } if b, e := json.Marshal(meta); m.Assert(e) { w.Header().Set("Content-Type", "application/javascript") - m.Log("json", "won %v", string(b)) 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") { @@ -1246,6 +1125,13 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心", } }}, + "/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")) @@ -1293,6 +1179,264 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心", 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/jira/jira.go b/src/examples/jira/jira.go index 2159a493..292641b6 100644 --- a/src/examples/jira/jira.go +++ b/src/examples/jira/jira.go @@ -5,10 +5,6 @@ import ( "contexts/web" ) -type JIRA struct { - web.WEB -} - var Index = &ctx.Context{Name: "jira", Help: "任务中心", Caches: map[string]*ctx.Cache{}, Configs: map[string]*ctx.Config{}, @@ -20,7 +16,7 @@ var Index = &ctx.Context{Name: "jira", Help: "任务中心", } func init() { - jira := &JIRA{} + jira := &web.WEB{} jira.Context = Index web.Index.Register(Index, jira) } diff --git a/src/examples/lark/lark.go b/src/examples/lark/lark.go index 53ffece4..f50360b0 100644 --- a/src/examples/lark/lark.go +++ b/src/examples/lark/lark.go @@ -9,10 +9,6 @@ import ( "net/http" ) -type LARK struct { - web.WEB -} - var Index = &ctx.Context{Name: "lark", Help: "会议中心", Caches: map[string]*ctx.Cache{}, Configs: map[string]*ctx.Config{ @@ -42,7 +38,7 @@ var Index = &ctx.Context{Name: "lark", Help: "会议中心", } func init() { - lark := &LARK{} + lark := &web.WEB{} lark.Context = Index web.Index.Register(Index, lark) }