From ea99c5ef2194ca5c0e0ffce1808465a81fc7e59f Mon Sep 17 00:00:00 2001 From: shaoying Date: Wed, 1 Apr 2020 17:59:28 +0800 Subject: [PATCH] add code.pprof --- base/cli/cli.go | 5 ++-- base/tcp/tcp.go | 33 ++++++++++++++++++++++-- base/web/web.go | 66 ++++++++++++++++++++++++++++++++++------------- conf.go | 4 +++ core/chat/chat.go | 8 ++++++ core/code/code.go | 59 ++++++++++++++++++++++++++++++++++++++++++ core/wiki/wiki.go | 10 +------ type.go | 7 ++--- 8 files changed, 157 insertions(+), 35 deletions(-) diff --git a/base/cli/cli.go b/base/cli/cli.go index fb3a545b..7b4c47bc 100644 --- a/base/cli/cli.go +++ b/base/cli/cli.go @@ -130,9 +130,8 @@ var Index = &ice.Context{Name: "cli", Help: "命令模块", } }}, "daemon": {Name: "daemon", Help: "守护进程", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - switch arg[0] { - case "exit": - } + m.Option("cmd_type", "daemon") + m.Cmdy(ice.CLI_SYSTEM, arg) }}, "python": {Name: "python", Help: "运行环境", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { prefix := []string{ice.CLI_SYSTEM, m.Conf("python", "meta.python")} diff --git a/base/tcp/tcp.go b/base/tcp/tcp.go index 74aa95fd..5b996bb2 100644 --- a/base/tcp/tcp.go +++ b/base/tcp/tcp.go @@ -2,15 +2,27 @@ package tcp import ( "github.com/shylinux/icebergs" + "github.com/shylinux/toolkits" "net" "strings" ) var Index = &ice.Context{Name: "tcp", Help: "通信模块", - Caches: map[string]*ice.Cache{}, - Configs: map[string]*ice.Config{}, + Caches: map[string]*ice.Cache{}, + Configs: map[string]*ice.Config{ + "getport": &ice.Config{Name: "getport", Help: "getport", Value: kit.Data( + "begin", 10000, "end", 20000, + )}, + }, Commands: map[string]*ice.Command{ + ice.ICE_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + m.Load() + }}, + ice.ICE_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + m.Save("getport") + }}, + "ip": {Name: "ifconfig [name]", Help: "网络配置", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { if addr, e := net.InterfaceAddrs(); m.Assert(e) { for _, v := range addr { @@ -18,6 +30,23 @@ var Index = &ice.Context{Name: "tcp", Help: "通信模块", } } }}, + "getport": {Name: "getport", Help: "分配端口", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + begin := kit.Int(m.Conf("getport", "meta.begin")) + end := kit.Int(m.Conf("getport", "meta.end")) + if begin >= end { + begin = 10000 + } + for i := begin; i < end; i++ { + if m.Cmd(ice.CLI_SYSTEM, "lsof", "-i", kit.Format(":%d", i)).Append("code") != "0" { + m.Conf("getport", "meta.begin", i+1) + m.Echo("%d", i) + break + } + } + }}, + "netstat": {Name: "netstat [name]", Help: "网络配置", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + m.Cmdy(ice.CLI_SYSTEM, "netstat", "-lanp") + }}, "ifconfig": {Name: "ifconfig [name]", Help: "网络配置", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { if ifs, e := net.Interfaces(); m.Assert(e) { for _, v := range ifs { diff --git a/base/web/web.go b/base/web/web.go index 8623f706..da89e59a 100644 --- a/base/web/web.go +++ b/base/web/web.go @@ -309,15 +309,12 @@ func (web *Frame) HandleCmd(m *ice.Message, key string, cmd *ice.Command) { } cmds := kit.Simple(msg.Optionv("cmds")) - // 登录检查 - if !web.Login(msg, w, r) { - // msg.Render("status", 401, "not login") - return + if web.Login(msg, w, r) { + // 登录成功 + msg.Option("_option", msg.Optionv(ice.MSG_OPTION)) + // 执行命令 + msg.Target().Run(msg, cmd, msg.Option(ice.MSG_USERURL), cmds...) } - msg.Option("_option", msg.Optionv(ice.MSG_OPTION)) - - // 执行命令 - msg.Target().Run(msg, cmd, msg.Option(ice.MSG_USERURL), cmds...) // 渲染引擎 _args, _ := msg.Optionv(ice.MSG_ARGS).([]interface{}) @@ -356,6 +353,10 @@ func (web *Frame) ServeHTTP(w http.ResponseWriter, r *http.Request) { m.Info(" ") } + if strings.HasPrefix(r.URL.Path, "/debug") { + r.URL.Path = strings.Replace(r.URL.Path, "/debug", "/code", -1) + } + if r.URL.Path == "/" && m.Conf(ice.WEB_SERVE, "meta.init") != "true" { if _, e := os.Stat(m.Conf(ice.WEB_SERVE, "meta.volcanos.path")); e == nil { // 初始化成功 @@ -428,7 +429,7 @@ func (web *Frame) Start(m *ice.Message, arg ...string) bool { // 启动服务 web.m, web.Server = m, &http.Server{Addr: port, Handler: web} m.Event(ice.SERVE_START, arg[0]) - m.Log("serve", "listen %s", web.Server.ListenAndServe()) + m.Warn(true, "listen %s", web.Server.ListenAndServe()) m.Event(ice.SERVE_CLOSE, arg[0]) }) return true @@ -489,9 +490,7 @@ var Index = &ice.Context{Name: "web", Help: "网络模块", ice.ICE_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { m.Load() - if m.Richs(ice.WEB_SPIDE, nil, "self", nil) == nil { - m.Cmd(ice.WEB_SPIDE, "add", "self", kit.Select("http://:9020", m.Conf(ice.CLI_RUNTIME, "conf.ctx_self"))) - } + m.Cmd(ice.WEB_SPIDE, "add", "self", kit.Select("http://:9020", m.Conf(ice.CLI_RUNTIME, "conf.ctx_self"))) if m.Richs(ice.WEB_SPIDE, nil, "dev", nil) == nil { m.Cmd(ice.WEB_SPIDE, "add", "dev", kit.Select("http://:9020", m.Conf(ice.CLI_RUNTIME, "conf.ctx_dev"))) } @@ -550,16 +549,21 @@ var Index = &ice.Context{Name: "web", Help: "网络模块", case "add": // 添加爬虫 if uri, e := url.Parse(arg[2]); e == nil && arg[2] != "" { + if uri.Host == "random" { + uri.Host = ":" + m.Cmdx("tcp.getport") + arg[2] = strings.Replace(arg[2], "random", uri.Host, -1) + } dir, file := path.Split(uri.EscapedPath()) if m.Richs(ice.WEB_SPIDE, nil, arg[1], func(key string, value map[string]interface{}) { - value["name"] = arg[1] - value["text"] = arg[2] - value["url"] = arg[2] + // kit.Value(value, "client.name", arg[1]) + // kit.Value(value, "client.text", arg[2]) + kit.Value(value, "client.hostname", uri.Host) + kit.Value(value, "client.url", arg[2]) }) == nil { m.Rich(ice.WEB_SPIDE, nil, kit.Dict( "cookie", kit.Dict(), "header", kit.Dict(), "client", kit.Dict( "share", m.Cmdx(ice.WEB_SHARE, "add", ice.TYPE_SPIDE, arg[1], arg[2]), - "type", "POST", "name", arg[1], "text", arg[2], + // "type", "POST", "name", arg[1], "text", arg[2], "name", arg[1], "url", arg[2], "method", "POST", "protocol", uri.Scheme, "hostname", uri.Host, "path", dir, "file", file, "query", uri.RawQuery, @@ -725,7 +729,8 @@ var Index = &ice.Context{Name: "web", Help: "网络模块", switch cache { case "cache": m.Optionv("response", res) - m.Echo(m.Cmd(ice.WEB_CACHE, "download", res.Header.Get("Content-Type"), uri).Append("data")) + m.Cmdy(ice.WEB_CACHE, "download", res.Header.Get("Content-Type"), uri) + m.Echo(m.Append("data")) case "raw": if b, e := ioutil.ReadAll(res.Body); m.Assert(e) { m.Echo(string(b)) @@ -919,6 +924,7 @@ var Index = &ice.Context{Name: "web", Help: "网络模块", } }) m.Sort("name") + m.Sort("status") return } @@ -1265,6 +1271,25 @@ var Index = &ice.Context{Name: "web", Help: "网络模块", m.Push("text", arg[3]) m.Push("size", size) m.Push("data", h) + case "watch": + if m.Richs(ice.WEB_CACHE, nil, arg[1], func(key string, value map[string]interface{}) { + if value["file"] == "" { + if f, _, e := kit.Create(arg[2]); m.Assert(e) { + defer f.Close() + f.WriteString(kit.Format(value["text"])) + } + } else { + os.MkdirAll(path.Dir(arg[2]), 0777) + os.Remove(arg[2]) + os.Link(kit.Format(value["file"]), arg[2]) + } + }) == nil { + m.Cmdy(ice.WEB_SPIDE, "dev", "cache", "/cache/"+arg[1]) + os.MkdirAll(path.Dir(arg[2]), 0777) + os.Remove(arg[2]) + os.Link(m.Append("file"), arg[2]) + } + m.Echo(arg[2]) } }}, ice.WEB_STORY: {Name: "story", Help: "故事会", Meta: kit.Dict("exports", []string{"top", "story"}, @@ -1754,7 +1779,7 @@ var Index = &ice.Context{Name: "web", Help: "网络模块", }) }}, ice.WEB_PROXY: {Name: "proxy", Help: "代理", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - m.Richs(ice.WEB_SPACE, nil, arg[0], func(key string, value map[string]interface{}) { + m.Richs(ice.WEB_SPACE, nil, kit.Select(m.Conf(ice.WEB_FAVOR, "meta.proxy"), arg[0]), func(key string, value map[string]interface{}) { if value[kit.MDB_TYPE] == ice.WEB_BETTER { switch value[kit.MDB_NAME] { case "tmux": @@ -2107,6 +2132,11 @@ var Index = &ice.Context{Name: "web", Help: "网络模块", } }) }}, + "/cache/": {Name: "/cache/", Help: "缓存池", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + m.Richs(ice.WEB_CACHE, nil, arg[0], func(key string, value map[string]interface{}) { + m.Render(ice.RENDER_DOWNLOAD, value["file"]) + }) + }}, "/story/": {Name: "/story/", Help: "故事会", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { switch arg[0] { diff --git a/conf.go b/conf.go index 8c0a44d9..9ebf0123 100644 --- a/conf.go +++ b/conf.go @@ -53,6 +53,7 @@ const ( // CTX const ( // CLI CLI_RUNTIME = "runtime" CLI_SYSTEM = "system" + CLI_DAEMON = "daemon" ) const ( // AAA AAA_ROLE = "role" @@ -211,6 +212,7 @@ const ( // STORY STORY_DOWNLOAD = "download" ) const ( // RENDER + RENDER_VOID = "_output" RENDER_OUTPUT = "_output" RENDER_TEMPLATE = "_template" RENDER_DOWNLOAD = "_download" @@ -225,6 +227,7 @@ var Alias = map[string]string{ CLI_RUNTIME: "cli.runtime", CLI_SYSTEM: "cli.system", + CLI_DAEMON: "cli.daemon", SSH_SOURCE: "ssh.source", AAA_ROLE: "aaa.role", @@ -270,4 +273,5 @@ var Alias = map[string]string{ "compile": "web.code.compile", "publish": "web.code.publish", "upgrade": "web.code.upgrade", + "pprof": "web.code.pprof", } diff --git a/core/chat/chat.go b/core/chat/chat.go index 272c4db4..4c595022 100644 --- a/core/chat/chat.go +++ b/core/chat/chat.go @@ -455,6 +455,14 @@ var Index = &ice.Context{Name: "chat", Help: "聊天中心", return } + if m.Option("_action") == "上传" { + msg := m.Cmd(ice.WEB_CACHE, "upload") + m.Option("_data", msg.Append("data")) + m.Option("_name", msg.Append("name")) + m.Cmd(ice.WEB_FAVOR, "upload", msg.Append("type"), msg.Append("name"), msg.Append("data")) + m.Option("_option", m.Optionv("option")) + } + // 查询命令 cmds := []string{} m.Grows(ice.CHAT_RIVER, prefix, kit.MDB_ID, kit.Format(kit.Int(arg[2])+1), func(index int, value map[string]interface{}) { diff --git a/core/code/code.go b/core/code/code.go index af58a44d..347873a6 100644 --- a/core/code/code.go +++ b/core/code/code.go @@ -8,6 +8,9 @@ import ( "os" "path" "strings" + + "net/http" + _ "net/http/pprof" ) var Index = &ice.Context{Name: "code", Help: "编程中心", @@ -23,6 +26,11 @@ var Index = &ice.Context{Name: "code", Help: "编程中心", ))}, "login": {Name: "login", Help: "登录", Value: kit.Data()}, + + "pprof": {Name: "pprof", Help: "性能分析", Value: kit.Data( + kit.MDB_SHORT, kit.MDB_NAME, + "stop", "ps aux|grep pprof|grep -v grep|cut -d' ' -f2|xargs -n1 kill", + )}, }, Commands: map[string]*ice.Command{ ice.ICE_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { @@ -189,6 +197,57 @@ var Index = &ice.Context{Name: "code", Help: "编程中心", m.Cmd("exit") } }}, + + "pprof": {Name: "pprof run name time", Help: "性能分析", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + if m.Show(cmd, arg...) { + return + } + + switch arg[0] { + case "run": + m.Richs(cmd, nil, arg[1], func(key string, value map[string]interface{}) { + m.Gos(m.Spawn(), func(msg *ice.Message) { + m.Sleep("1s").Grows(cmd, kit.Keys(kit.MDB_HASH, key), "", "", func(index int, value map[string]interface{}) { + m.Cmd(ice.WEB_FAVOR, "pprof", "shell", value["text"], m.Cmdx(kit.Split(kit.Format(value["text"])))) + }) + }) + + name := arg[1] + ".pd.gz" + value = value["meta"].(map[string]interface{}) + msg := m.Cmd(ice.WEB_SPIDE, "self", "cache", "GET", kit.Select("/code/pprof/profile", value["remote"]), "seconds", kit.Select("5", arg, 2)) + m.Cmd(ice.WEB_FAVOR, "pprof", "shell", "text", m.Cmdx(ice.CLI_SYSTEM, "go", "tool", "pprof", "-text", msg.Append("text"))) + m.Cmd(ice.WEB_FAVOR, "pprof", "pprof", name, msg.Append("data")) + + arg = kit.Simple("web", value["bin"], value[kit.MDB_TEXT], name) + }) + + fallthrough + case "web": + p := kit.Format("%s:%s", m.Conf(ice.WEB_SHARE, "meta.host"), m.Cmdx("tcp.getport")) + m.Cmd(ice.CLI_DAEMON, "go", "tool", "pprof", "-http="+p, arg[1:]) + m.Cmd(ice.WEB_FAVOR, "pprof", "bin", arg[1], m.Cmd(ice.WEB_CACHE, "catch", "bin", arg[1]).Append("data")) + m.Cmd(ice.WEB_FAVOR, "pprof", "spide", arg[2], "http://"+p) + m.Echo(p) + + case "stop": + m.Cmd(ice.CLI_SYSTEM, "sh", "-c", m.Conf(cmd, "meta.stop")) + + case "add": + key := m.Rich(cmd, nil, kit.Data( + kit.MDB_NAME, arg[1], kit.MDB_TEXT, arg[2], "remote", arg[3], + )) + for i := 4; i < len(arg)-1; i += 2 { + m.Grow(cmd, kit.Keys(kit.MDB_HASH, key), kit.Dict( + kit.MDB_NAME, arg[i], kit.MDB_TEXT, arg[i+1], + )) + } + } + }}, + "/pprof/": {Name: "/pprof/", Help: "性能分析", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + m.R.URL.Path = strings.Replace("/code"+m.R.URL.Path, "code", "debug", 1) + http.DefaultServeMux.ServeHTTP(m.W, m.R) + m.Render(ice.RENDER_VOID) + }}, }, } diff --git a/core/wiki/wiki.go b/core/wiki/wiki.go index 08b7bb89..ea9a0c05 100644 --- a/core/wiki/wiki.go +++ b/core/wiki/wiki.go @@ -8,7 +8,6 @@ import ( "github.com/shylinux/toolkits" "fmt" - "io" "io/ioutil" "math/rand" "os" @@ -481,14 +480,7 @@ var Index = &ice.Context{Name: "wiki", Help: "文档中心", kit.MDB_INPUT, "button", "name", "上传", "figure", "upload", ), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { if m.Option("_action") == "上传" { - if f, h, e := m.R.FormFile("upload"); m.Assert(e) { - defer f.Close() - if o, p, e := kit.Create(path.Join(m.Option("name"), h.Filename)); m.Assert(e) { - if n, e := io.Copy(o, f); m.Assert(e) { - m.Log(ice.LOG_IMPORT, "%s: %s", kit.FmtSize(n), p) - } - } - } + m.Cmd(ice.WEB_CACHE, "watch", m.Option("_data"), path.Join(m.Option("name"), m.Option("_name"))) return } diff --git a/type.go b/type.go index e8c52e14..8d21140d 100644 --- a/type.go +++ b/type.go @@ -1532,7 +1532,7 @@ func (m *Message) Show(cmd string, arg ...string) bool { return true } if len(arg) < 3 { - m.Richs(cmd, nil, arg[0], func(key string, val map[string]interface{}) { + if m.Richs(cmd, nil, arg[0], func(key string, val map[string]interface{}) { if len(arg) == 1 { // 日志列表 m.Grows(cmd, kit.Keys(kit.MDB_HASH, key), "", "", func(index int, value map[string]interface{}) { @@ -1544,8 +1544,9 @@ func (m *Message) Show(cmd string, arg ...string) bool { m.Grows(cmd, kit.Keys(kit.MDB_HASH, key), "id", arg[1], func(index int, value map[string]interface{}) { m.Push("detail", value) }) - }) - return true + }) != nil { + return true + } } return false }