From 723d1824d62c3d59001104c519ee8b3f35c3f5bf Mon Sep 17 00:00:00 2001 From: shaoying Date: Sun, 1 Jul 2018 01:52:28 +0800 Subject: [PATCH] mac pro web --- src/contexts/ctx.go | 153 +++++++------ src/contexts/mdb/mdb.go | 83 ++++--- src/contexts/web/web.go | 472 +++++++++++++++++++--------------------- 3 files changed, 357 insertions(+), 351 deletions(-) diff --git a/src/contexts/ctx.go b/src/contexts/ctx.go index 3dca5426..469f25af 100644 --- a/src/contexts/ctx.go +++ b/src/contexts/ctx.go @@ -680,10 +680,9 @@ func (m *Message) Assert(e interface{}, msg ...string) bool { // {{{ func (m *Message) TryCatch(msg *Message, safe bool, hand ...func(msg *Message)) *Message { // {{{ defer func() { if e := recover(); e != nil { - - switch e.(type) { + switch v := e.(type) { case *Message: - panic(e) + e = strings.Join(v.Meta["result"][1:], "") } msg.Log("error", nil, "error: %v", e) @@ -1203,6 +1202,39 @@ func (m *Message) Table(cb func(map[string]string, []string, int) bool) *Message return m } +// }}} +func (m *Message) Matrix(index int, arg ...interface{}) string { // {{{ + if len(m.Meta["append"]) == 0 || index < 0 { + return "" + } + + key := m.Meta["append"][0] + if len(arg) > 0 { + switch v := arg[0].(type) { + case string: + for _, k := range m.Meta["append"] { + if k == v { + key = v + } + } + if key != v { + return "" + } + case int: + if v < len(m.Meta["append"]) { + key = m.Meta["append"][v] + } else { + return "" + } + } + } + if index < len(m.Meta[key]) { + return m.Meta[key][index] + + } + return "" +} + // }}} func (m *Message) Sort(key string, arg ...string) { // {{{ table := []map[string]string{} @@ -1633,57 +1665,54 @@ func (m *Message) Confx(key string, arg ...interface{}) string { // {{{ return value } - skip := false + value := "" + switch v := arg[0].(type) { + case string: + value = v + case []string: + which := 0 + if len(arg) > 1 { + if x, ok := arg[1].(int); ok { + which = x + arg = arg[1:] + } + } + if which < len(v) { + value = v[which] + } + default: + x := fmt.Sprintf("%v", v) + if v != nil && x != "" { + value = x + } + } + + force := false + if len(arg) > 1 { + if v, ok := arg[1].(bool); ok { + arg = arg[1:] + force = v + } + } + if !force && value == "" { + value = m.Conf(key) + } + format := "%s" if len(arg) > 1 { - switch v := arg[1].(type) { - case bool: - skip = !v - case string: + if v, ok := arg[1].(string); ok { + arg = arg[1:] format = v } } - - if len(arg) > 0 { - switch v := arg[0].(type) { - case string: - if skip || v == "" { - v = m.Conf(key) - } - if v == "" { - return v - } - return fmt.Sprintf(format, v) - case []string: - which := 0 - if len(arg) > 1 { - if x, ok := arg[1].(int); ok { - which = x - } - } - value := "" - if which < len(v) { - value = v[which] - } else { - value = m.Conf(key) - } - if len(arg) > 2 { - format = arg[2].(string) - } - if value == "" { - return value - } - return fmt.Sprintf(format, value) - default: - x := fmt.Sprintf("%v", v) - if skip || v == nil || x == "" { - return m.Conf(key) - } - return x + if value != "" { + args := []interface{}{value} + for _, v := range arg[1:] { + args = append(args, v) } + value = fmt.Sprintf(format, args...) } - - return "" + return value } // }}} @@ -2641,9 +2670,9 @@ var Index = &Context{Name: "ctx", Help: "模块中心", Hand: func(m *Message, c *Context, key string, arg ...string) { switch len(arg) { // {{{ case 0: - m.Travel(m.target.root, func(msg *Message) bool { - if msg.Cap("status") == "start" { - msg.Echo("%s(%s): %s\n", msg.target.Name, msg.Cap("stream"), msg.target.Help) + m.Travel(m.target.root, func(m *Message) bool { + if m.Cap("status") == "start" { + m.Echo("%s(%s): %s\n", m.target.Name, m.Cap("stream"), m.target.Help) } return true }) @@ -2651,24 +2680,20 @@ var Index = &Context{Name: "ctx", Help: "模块中心", default: switch arg[0] { case "spawn": - if len(arg) > 1 { - msg := m.Spawn(m.Target()) - msg.Detail(0, arg[2:]) - msg.Target().Spawn(msg, arg[0], arg[1]) + if len(arg) > 2 { + msg := m.Spawn().Set("detail", arg[3:]...) + msg.target.Spawn(msg, arg[1], arg[2]) + m.target = msg.target } - case "begin": - msg := m.Spawn(m.Target()) - msg.Detail(0, arg) - msg.Target().Begin(msg) + msg := m.Spawn().Set("detail", arg...) + msg.target.Begin(msg) case "start": - msg := m.Spawn(m.Target()) - msg.Detail(0, arg) - msg.Target().Start(msg) + msg := m.Spawn().Set("detail", arg...) + msg.target.Start(msg) case "close": - msg := m.Spawn(m.Target()) - msg.Detail(0, arg) - msg.Target().Close(msg) + msg := m.Spawn().Set("detail", arg...) + msg.target.Close(msg) } } // }}} diff --git a/src/contexts/mdb/mdb.go b/src/contexts/mdb/mdb.go index 0d898250..b51455d4 100644 --- a/src/contexts/mdb/mdb.go +++ b/src/contexts/mdb/mdb.go @@ -25,11 +25,11 @@ type MDB struct { func (mdb *MDB) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server { c.Caches = map[string]*ctx.Cache{ - "database": &ctx.Cache{Name: "数据库", Value: m.Confx("database", arg, 0), Help: "数据库驱动"}, - "username": &ctx.Cache{Name: "用户名", Value: m.Confx("username", arg, 1), Help: "数据库驱动"}, - "password": &ctx.Cache{Name: "密码", Value: m.Confx("password", arg, 2), Help: "数据库驱动"}, - "protocol": &ctx.Cache{Name: "协议", Value: m.Confx("protocol", arg, 4), Help: "数据库驱动"}, - "address": &ctx.Cache{Name: "地址", Value: m.Confx("address", arg, 3), Help: "数据库驱动"}, + "database": &ctx.Cache{Name: "数据库", Value: m.Confx("database", arg, 0), Help: "数据库"}, + "username": &ctx.Cache{Name: "账户", Value: m.Confx("username", arg, 1), Help: "账户"}, + "password": &ctx.Cache{Name: "密码", Value: m.Confx("password", arg, 2), Help: "密码"}, + "address": &ctx.Cache{Name: "服务地址", Value: m.Confx("address", arg, 3), Help: "服务地址"}, + "protocol": &ctx.Cache{Name: "服务协议(tcp)", Value: m.Confx("protocol", arg, 4), Help: "服务协议"}, "driver": &ctx.Cache{Name: "数据库驱动(mysql)", Value: m.Confx("driver", arg, 5), Help: "数据库驱动"}, } c.Configs = map[string]*ctx.Config{ @@ -62,8 +62,7 @@ func (mdb *MDB) Start(m *ctx.Message, arg ...string) bool { // {{{ m.Cap("username"), m.Cap("password"), m.Cap("protocol"), m.Cap("address"), m.Cap("database"))) m.Assert(e) mdb.DB = db - - m.Log("info", nil, "%d open %s %s", m.Capi("nsource"), m.Cap("driver"), m.Cap("stream", m.Cap("database"))) + m.Log("info", nil, "mdb open %s", m.Cap("database")) return false } @@ -72,7 +71,7 @@ func (mdb *MDB) Close(m *ctx.Message, arg ...string) bool { // {{{ switch mdb.Context { case m.Target(): if mdb.DB != nil { - m.Log("info", nil, "close") + m.Log("info", nil, "mdb close %s", m.Cap("database")) mdb.DB.Close() mdb.DB = nil } @@ -89,11 +88,11 @@ var Index = &ctx.Context{Name: "mdb", Help: "数据中心", "nsource": &ctx.Cache{Name: "数据源数量", Value: "0", Help: "已打开数据库的数量"}, }, Configs: map[string]*ctx.Config{ - "database": &ctx.Config{Name: "默认数据库", Value: "demo", Help: "数据库驱动"}, - "username": &ctx.Config{Name: "默认用户名", Value: "demo", Help: "数据库驱动"}, - "password": &ctx.Config{Name: "默认密码", Value: "demo", Help: "数据库驱动"}, - "protocol": &ctx.Config{Name: "默认协议", Value: "tcp", Help: "数据库驱动"}, - "address": &ctx.Config{Name: "默认地址", Value: "", Help: "数据库驱动"}, + "database": &ctx.Config{Name: "默认数据库", Value: "demo", Help: "默认数据库"}, + "username": &ctx.Config{Name: "默认用户名", Value: "demo", Help: "默认用户名"}, + "password": &ctx.Config{Name: "默认密码", Value: "demo", Help: "默认密码"}, + "protocol": &ctx.Config{Name: "默认协议", Value: "tcp", Help: "默认协议"}, + "address": &ctx.Config{Name: "默认地址", Value: "", Help: "默认地址"}, "driver": &ctx.Config{Name: "数据库驱动(mysql)", Value: "mysql", Help: "数据库驱动"}, "dbhelp": &ctx.Config{Name: "默认帮助", Value: "数据存储", Help: "默认帮助"}, @@ -105,17 +104,18 @@ var Index = &ctx.Context{Name: "mdb", Help: "数据中心", // }}} }}, - "csv_sep": &ctx.Config{Name: "字段分隔符", Value: "\t", Help: "字段分隔符"}, + "csv_col_sep": &ctx.Config{Name: "字段分隔符", Value: "\t", Help: "字段分隔符"}, + "csv_row_sep": &ctx.Config{Name: "记录分隔符", Value: "\n", Help: "记录分隔符"}, }, Commands: map[string]*ctx.Command{ "open": &ctx.Command{ Name: "open [database [username [password [address [protocol [driver]]]]]] [dbname name] [dbhelp help]", - Help: "open打开数据库, database: 数据库名, username: 用户名, password: 密码, address: 主机地址, protocol: 主机协议, driver: 数据库类型, dbname: 模块名称, dbhelp: 帮助信息", + Help: "open打开数据库, database: 数据库名, username: 用户名, password: 密码, address: 服务地址, protocol: 服务协议, driver: 数据库类型, dbname: 模块名称, dbhelp: 帮助信息", Form: map[string]int{"dbname": 1, "dbhelp": 1}, Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { m.Start(m.Confx("dbname"), m.Confx("dbhelp"), arg...) }}, - "exec": &ctx.Command{Name: "exec sql [arg]", Help: "操作数据库, sql: SQL语句, arg: 查询参数", + "exec": &ctx.Command{Name: "exec sql [arg]", Help: "操作数据库, sql: SQL语句, arg: 操作参数", Appends: map[string]string{"last": "最后插入元组的标识", "nrow": "修改元组的数量"}, Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { if mdb, ok := m.Target().Server.(*MDB); m.Assert(ok) { // {{{ @@ -179,11 +179,10 @@ var Index = &ctx.Context{Name: "mdb", Help: "数据中心", } // }}} }}, - "db": &ctx.Command{Name: "db", Help: "查看关系表信息,which: 表名, field: 字段名", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + "db": &ctx.Command{Name: "db [which]", Help: "查看或选择数据库信息", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { if mdb, ok := m.Target().Server.(*MDB); m.Assert(ok) { // {{{ - msg := m.Spawn() if len(arg) == 0 { - msg.Cmd("query", "show databases") + msg := m.Spawn().Cmd("query", "show databases") mdb.db = []string{} for i, v := range msg.Meta[msg.Meta["append"][0]] { mdb.db = append(mdb.db, v) @@ -193,20 +192,18 @@ var Index = &ctx.Context{Name: "mdb", Help: "数据中心", } db := arg[0] - index, e := strconv.Atoi(arg[0]) - if e == nil && index < len(mdb.db) { - db = mdb.db[index] + if i, e := strconv.Atoi(arg[0]); e == nil && i < len(mdb.db) { + db = mdb.db[i] } + m.Assert(m.Spawn().Cmd("exec", fmt.Sprintf("use %s", db))) m.Cap("database", db) - mdb.Exec(fmt.Sprintf("use %s", db)) } // }}} }}, "table": &ctx.Command{Name: "table [which [field]]", Help: "查看关系表信息,which: 表名, field: 字段名", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { if mdb, ok := m.Target().Server.(*MDB); m.Assert(ok) { // {{{ - msg := m.Spawn() if len(arg) == 0 { - msg.Cmd("query", "show tables") + msg := m.Spawn().Cmd("query", "show tables") mdb.table = []string{} for i, v := range msg.Meta[msg.Meta["append"][0]] { mdb.table = append(mdb.table, v) @@ -216,12 +213,11 @@ var Index = &ctx.Context{Name: "mdb", Help: "数据中心", } table := arg[0] - index, e := strconv.Atoi(arg[0]) - if e == nil && index < len(mdb.table) { - table = mdb.table[index] + if i, e := strconv.Atoi(arg[0]); e == nil && i < len(mdb.table) { + table = mdb.table[i] } - msg.Cmd("query", fmt.Sprintf("desc %s", table)) + msg := m.Spawn().Cmd("query", fmt.Sprintf("desc %s", table)) if len(arg) == 1 { for _, v := range msg.Meta[msg.Meta["append"][0]] { m.Echo("%s\n", v) @@ -267,11 +263,10 @@ var Index = &ctx.Context{Name: "mdb", Help: "数据中心", offset := m.Confx("offset", m.Option("offset"), "offset %s") msg := m.Spawn().Cmd("query", fmt.Sprintf("select %s from %s %s %s %s %s %s", field, table, where, group, order, limit, offset), m.Meta["other"]) - if !m.Options("save") { + if m.Optioni("query", msg.Code()); !m.Options("save") { m.Color(31, table).Echo(" %s %s %s %s %s %v\n", where, group, order, limit, offset, m.Meta["other"]) } - m.Optioni("query", msg.Code()) msg.Table(func(maps map[string]string, lists []string, line int) bool { for i, v := range lists { if m.Options("save") { @@ -282,10 +277,10 @@ var Index = &ctx.Context{Name: "mdb", Help: "数据中心", m.Echo(v) } if i < len(lists)-1 { - m.Echo(m.Conf("csv_sep")) + m.Echo(m.Conf("csv_col_sep")) } } - m.Echo("\n") + m.Echo(m.Conf("csv_row_sep")) return true }) @@ -300,20 +295,25 @@ var Index = &ctx.Context{Name: "mdb", Help: "数据中心", } } // }}} }}, - "get": &ctx.Command{Name: "get field table where offset [parse func field]", Help: "执行查询语句", + "get": &ctx.Command{Name: "get field offset table where [parse func field]", Help: "执行查询语句", Form: map[string]int{"parse": 2}, Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - field := m.Confx("field", arg, 0) // {{{ - table := m.Confx("table", arg, 1, "from %s") - where := m.Confx("where", arg, 2, "where %s") + index := 0 // {{{ + if len(arg) > 1 { + if i, e := strconv.Atoi(arg[1]); e == nil { + index = i + } + } + field := m.Confx("field", arg, 0) + offset := m.Confx("offset", arg, 1, "offset %s") + table := m.Confx("table", arg, 2, "from %s") + where := m.Confx("where", arg, 3, "where %s") limit := "limit 1" - offset := m.Confx("offset", arg, 3, "offset %s") msg := m.Spawn().Cmd("query", fmt.Sprintf("select %s %s %s %s %s", field, table, where, limit, offset)) - value := m.Append(msg.Meta["append"][0]) + value := msg.Matrix(index, field) - parse := m.Confx("parse", m.Option("parse")) - switch parse { + switch m.Confx("parse", m.Option("parse")) { case "json": extra := "" if len(m.Meta["parse"]) > 1 { @@ -330,7 +330,6 @@ var Index = &ctx.Context{Name: "mdb", Help: "数据中心", default: m.Echo("%v", value) } - return // }}} }}, }, diff --git a/src/contexts/web/web.go b/src/contexts/web/web.go index 56511868..dde25b4a 100644 --- a/src/contexts/web/web.go +++ b/src/contexts/web/web.go @@ -41,9 +41,6 @@ type WEB struct { client *http.Client cookie map[string]*http.Cookie - list map[string][]string - list_key []string - *ctx.Message *ctx.Context } @@ -220,9 +217,6 @@ func (web *WEB) Begin(m *ctx.Message, arg ...string) ctx.Server { // {{{ } } } - - web.list = map[string][]string{} - return web } @@ -235,6 +229,7 @@ func (web *WEB) Start(m *ctx.Message, arg ...string) bool { // {{{ m.Travel(m.Target(), func(m *ctx.Message) bool { if h, ok := m.Target().Server.(http.Handler); ok && m.Cap("register") == "no" { m.Cap("register", "yes") + m.Capi("nroute", 1) p, i := m.Target(), 0 m.BackTrace(func(m *ctx.Message) bool { @@ -258,6 +253,14 @@ func (web *WEB) Start(m *ctx.Message, arg ...string) bool { // {{{ return true }) + web.Configs["template_dir"] = &ctx.Config{Name: "template_dir", Value: "usr/template/", Help: "通用模板路径"} + web.Configs["common_tmpl"] = &ctx.Config{Name: "common_tmpl", Value: "common/*.html", Help: "通用模板路径"} + web.Configs["common_main"] = &ctx.Config{Name: "common_main", Value: "main.html", Help: "通用模板框架"} + web.Configs["upload_tmpl"] = &ctx.Config{Name: "upload_tmpl", Value: "upload.html", Help: "上传文件模板"} + web.Configs["upload_main"] = &ctx.Config{Name: "upload_main", Value: "main.html", Help: "上传文件框架"} + web.Configs["travel_tmpl"] = &ctx.Config{Name: "travel_tmpl", Value: "travel.html", Help: "浏览模块模板"} + web.Configs["travel_main"] = &ctx.Config{Name: "travel_main", Value: "main.html", Help: "浏览模块框架"} + web.Caches["address"] = &ctx.Cache{Name: "服务地址", Value: ":9191", Help: "服务地址"} web.Caches["protocol"] = &ctx.Cache{Name: "服务协议", Value: "http", Help: "服务协议"} if len(arg) > 1 { @@ -274,6 +277,7 @@ func (web *WEB) Start(m *ctx.Message, arg ...string) bool { // {{{ web.Server = &http.Server{Addr: m.Cap("address"), Handler: web} web.Configs["logheaders"] = &ctx.Config{Name: "日志输出报文头(yes/no)", Value: "yes", Help: "日志输出报文头"} + m.Capi("nserve", 1) if web.Message = m; m.Cap("protocol") == "https" { web.Caches["cert"] = &ctx.Cache{Name: "服务证书", Value: m.Conf("cert"), Help: "服务证书"} @@ -302,270 +306,248 @@ func (web *WEB) Close(m *ctx.Message, arg ...string) bool { // {{{ var Index = &ctx.Context{Name: "web", Help: "应用中心", Caches: map[string]*ctx.Cache{ - "count": &ctx.Cache{Name: "count", Value: "0", Help: "主机协议"}, - }, - Configs: map[string]*ctx.Config{ - "protocol": &ctx.Config{Name: "protocol", Value: "", Help: "主机协议"}, - "hostname": &ctx.Config{Name: "hostname", Value: "", Help: "主机地址"}, - "port": &ctx.Config{Name: "port", Value: "", Help: "主机端口"}, - "dir": &ctx.Config{Name: "dir", Value: "/", Help: "主机路由"}, - "file": &ctx.Config{Name: "file", Value: "", Help: "主机文件"}, - "query": &ctx.Config{Name: "query", Value: "", Help: "主机参数"}, - "output": &ctx.Config{Name: "output", Value: "stdout", Help: "响应输出"}, - "editor": &ctx.Config{Name: "editor", Value: "vim", 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: "浏览模块框架"}, + "nserve": &ctx.Cache{Name: "nserve", Value: "0", Help: "主机数量"}, + "nroute": &ctx.Cache{Name: "nroute", Value: "0", Help: "路由数量"}, }, + Configs: map[string]*ctx.Config{}, Commands: map[string]*ctx.Command{ - "serve": &ctx.Command{Name: "serve [directory [address [protocol]]]", Help: "开启应用服务", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - m.Set("detail", arg...).Target().Start(m) - }}, - "route": &ctx.Command{Name: "route directory|template|script route content", Help: "添加应用内容", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - mux, ok := m.Target().Server.(MUX) // {{{ - m.Assert(ok, "模块类型错误") - m.Assert(len(arg) == 3, "缺少参数") - - switch arg[0] { - case "directory": - mux.Handle(arg[1]+"/", http.StripPrefix(arg[1], http.FileServer(http.Dir(arg[2])))) - case "template": - mux.Trans(m, arg[1], func(m *ctx.Message, c *ctx.Context, key string, a ...string) { - w := m.Data["response"].(http.ResponseWriter) - - if _, e := os.Stat(arg[2]); e == nil { - template.Must(template.ParseGlob(arg[2])).Execute(w, m) - } else { - template.Must(template.New("temp").Parse(arg[2])).Execute(w, m) + "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 web, e := m.Target().Server.(*WEB); m.Assert(e) { // {{{ + if len(arg) == 0 { + return } - }) - case "script": - cli := m.Find("cli") - lex := m.Find("lex") - mux.Trans(m, arg[1], func(m *ctx.Message, c *ctx.Context, key string, a ...string) { - f, e := os.Open(arg[2]) - line, bio := "", bufio.NewReader(f) - if e != nil { - line = arg[2] - } + uri, e := url.Parse(arg[0]) + m.Assert(e) + web.Configs["method"] = &ctx.Config{Name: "method", Value: "GET", Help: "请求方法"} + web.Configs["protocol"] = &ctx.Config{Name: "protocol", Value: uri.Scheme, Help: "服务协议"} + web.Configs["hostname"] = &ctx.Config{Name: "hostname", Value: uri.Hostname(), Help: "服务主机"} + web.Configs["port"] = &ctx.Config{Name: "port", Value: uri.Port(), Help: "服务端口"} - for { - if line = strings.TrimSpace(line); line != "" { - lex.Cmd("split", line, "void") - cli.Wait = make(chan bool) - cli.Cmd(lex.Meta["result"]) - m.Meta["result"] = cli.Meta["result"] + dir, file := path.Split(uri.EscapedPath()) + web.Configs["path"] = &ctx.Config{Name: "path", Value: dir, Help: "服务路由"} + web.Configs["file"] = &ctx.Config{Name: "file", Value: file, Help: "服务文件"} + web.Configs["query"] = &ctx.Config{Name: "query", Value: uri.RawQuery, Help: "服务参数"} + + web.Configs["output"] = &ctx.Config{Name: "output", Value: "stdout", Help: "文件缓存"} + if len(arg) > 1 { + m.Conf("output", arg[1]) + } + web.Configs["editor"] = &ctx.Config{Name: "editor", Value: "vim", Help: "文件编辑器"} + if len(arg) > 2 { + m.Conf("editor", arg[2]) + } + } // }}} + }}, + "cookie": &ctx.Command{ + Name: "cookie [name [value]]", + Help: "读写请求的Cookie, name: 变量名, value: 变量值", + Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + if web, ok := m.Target().Server.(*WEB); m.Assert(ok) { // {{{ + switch len(arg) { + case 0: + for k, v := range web.cookie { + m.Echo("%s: %v\n", k, v.Value) } - - if line, e = bio.ReadString('\n'); e != nil { - break + case 1: + if v, ok := web.cookie[arg[0]]; ok { + m.Echo("%s", v.Value) + } + default: + if web.cookie == nil { + web.cookie = make(map[string]*http.Cookie) + } + if v, ok := web.cookie[arg[0]]; ok { + v.Value = arg[1] + } else { + web.cookie[arg[0]] = &http.Cookie{Name: arg[0], Value: arg[1]} } } - }) - } // }}} - }}, - "cookie": &ctx.Command{Name: "cookie add|del arg...", Help: "访问URL", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - web, ok := m.Target().Server.(*WEB) // {{{ - m.Assert(ok) - - switch len(arg) { - case 0: - for k, v := range web.cookie { - m.Echo("%s: %v\n", k, v.Value) - } - case 1: - if v, ok := web.cookie[arg[0]]; ok { - m.Echo("%s", v.Value) - } - default: - if web.cookie == nil { - web.cookie = make(map[string]*http.Cookie) - } - if v, ok := web.cookie[arg[0]]; ok { - v.Value = arg[1] - } else { - web.cookie[arg[0]] = &http.Cookie{Name: arg[0], Value: arg[1]} - } - } - // }}} - }}, - "get": &ctx.Command{Name: "get [method GET|POST] [file filename] url arg...", Help: "访问URL", + } // }}} + }}, + "get": &ctx.Command{ + Name: "get [method GET|POST] [file name filename] url arg...", + Help: "访问服务, method: 请求方法, file: 发送文件, url: 请求地址, arg: 请求参数", Form: map[string]int{"method": 1, "file": 2}, Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - web, ok := m.Target().Server.(*WEB) // {{{ - m.Assert(ok) - - if web.client == nil { - web.client = &http.Client{} - } - - method := "GET" - if m.Options("method") { - method = m.Option("method") - } - - uri := web.generate(m, arg[0], arg[1:]...) - m.Log("info", nil, "GET %s", uri) - m.Echo("%s: %s\n", method, uri) - - 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() - - 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 index > 0 { - contenttype = "application/x-www-form-urlencoded" - body = strings.NewReader(uri[index+1:]) - uri = uri[:index] + if web, ok := m.Target().Server.(*WEB); m.Assert(ok) { // {{{ + if web.client == nil { + web.client = &http.Client{} } - } - req, e := http.NewRequest(method, uri, body) - m.Assert(e) + method := m.Confx("method") + uri := web.generate(m, arg[0], arg[1:]...) + m.Log("info", nil, "GET %s", uri) + m.Echo("%s: %s\n", method, uri) - if len(contenttype) > 0 { - req.Header.Set("Content-Type", contenttype) - } + var body io.Reader + index := strings.Index(uri, "?") + contenttype := "" - for _, v := range web.cookie { - req.AddCookie(v) - } + switch method { + case "POST": + if m.Options("file") { + file, e := os.Open(m.Meta["file"][1]) + m.Assert(e) + defer file.Close() - res, e := web.client.Do(req) - m.Assert(e) + buf := &bytes.Buffer{} + writer := multipart.NewWriter(buf) - if web.cookie == nil { - web.cookie = make(map[string]*http.Cookie) - } - for _, v := range res.Cookies() { - web.cookie[v.Name] = v - } + part, e := writer.CreateFormFile(m.Option("file"), filepath.Base(m.Meta["file"][1])) + m.Assert(e) + io.Copy(part, file) - for k, v := range res.Header { - m.Log("info", nil, "%s: %v", k, v) - } + 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) + } - 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) + contenttype = writer.FormDataContentType() + body = buf + writer.Close() + } else if index > 0 { + contenttype = "application/x-www-form-urlencoded" + body = strings.NewReader(uri[index+1:]) + uri = uri[:index] + } + } + + req, e := http.NewRequest(method, uri, body) + m.Assert(e) + + if len(contenttype) > 0 { + req.Header.Set("Content-Type", contenttype) + } + + for _, v := range web.cookie { + req.AddCookie(v) + } + + res, e := web.client.Do(req) + m.Assert(e) + + if web.cookie == nil { + web.cookie = make(map[string]*http.Cookie) + } + for _, v := range res.Cookies() { + web.cookie[v.Name] = v + } + + for k, v := range res.Header { + m.Log("info", nil, "%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) + + if res.Header.Get("Content-Type") == "application/json" { + result := map[string]interface{}{} + json.Unmarshal(buf, &result) + for k, v := range result { + switch value := v.(type) { + case string: + m.Append(k, value) + case float64: + m.Append(k, fmt.Sprintf("%d", int(value))) + default: + m.Put("append", k, value) + } + } + } + + result := string(buf) + m.Echo(result) + m.Append("response", result) + } // }}} + }}, + "serve": &ctx.Command{ + Name: "serve [directory [address [protocol]]]", + Help: "启动服务, directory: 服务路径, address: 服务地址, protocol: 服务协议(https/http)", + Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + m.Set("detail", arg...).Target().Start(m) + }}, + "route": &ctx.Command{ + Name: "route directory|template|script route content", + Help: "添加响应, directory: 目录响应, template: 模板响应, script: 脚本响应, route: 请求路由, content: 响应内容", + Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { + if mux, ok := m.Target().Server.(MUX); m.Assert(ok) { // {{{ + if len(arg) < 3 { + for k, v := range m.Target().Commands { + if k[0] == '/' { + m.Echo("%s: %s\n", k, v.Name) + } } return } - } + switch arg[0] { + case "directory": + mux.Handle(arg[1]+"/", http.StripPrefix(arg[1], http.FileServer(http.Dir(arg[2])))) + case "template": + mux.Trans(m, arg[1], func(m *ctx.Message, c *ctx.Context, key string, a ...string) { + w := m.Optionv("response").(http.ResponseWriter) + if _, e := os.Stat(arg[2]); e == nil { + template.Must(template.ParseGlob(arg[2])).Execute(w, m) + } else { + template.Must(template.New("temp").Parse(arg[2])).Execute(w, m) + } + }) + case "script": + cli := m.Find("cli") + lex := m.Find("lex") + mux.Trans(m, arg[1], func(m *ctx.Message, c *ctx.Context, key string, a ...string) { + f, e := os.Open(arg[2]) + line, bio := "", bufio.NewReader(f) + if e != nil { + line = arg[2] + } - buf, e := ioutil.ReadAll(res.Body) - m.Assert(e) + for { + if line = strings.TrimSpace(line); line != "" { + lex.Cmd("split", line, "void") + cli.Wait = make(chan bool) + cli.Cmd(lex.Meta["result"]) + m.Meta["result"] = cli.Meta["result"] + } - if res.Header.Get("Content-Type") == "application/json" { - result := map[string]interface{}{} - json.Unmarshal(buf, &result) - for k, v := range result { - switch value := v.(type) { - case string: - m.Append(k, value) - case float64: - m.Append(k, fmt.Sprintf("%d", int(value))) - default: - m.Put("append", k, value) - } + if line, e = bio.ReadString('\n'); e != nil { + break + } + } + }) } - } - - result := string(buf) - m.Echo(result) - m.Append("response", result) - // }}} + } // }}} }}, - "list": &ctx.Command{Name: "list [set|add|del [url]]", Help: "查看、访问、添加url", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) { - web, ok := m.Target().Server.(*WEB) // {{{ - m.Assert(ok) - - switch len(arg) { - case 0: - for _, k := range web.list_key { - if v, ok := web.list[k]; ok { - m.Echo("%s: %s\n", k, v) - } - } - case 1: - msg := m.Spawn(m.Target()).Cmd("get", web.list[arg[0]]) - m.Copy(msg, "result") - default: - switch arg[0] { - case "add": - web.list[m.Cap("count")] = arg[1:] - web.list_key = append(web.list_key, m.Cap("count")) - m.Capi("count", 1) - case "del": - delete(web.list, arg[1]) - case "set": - web.list[arg[1]] = arg[2:] - default: - list := []string{} - j := 1 - for _, v := range web.list[arg[0]] { - if v == "_" && j < len(arg) { - list = append(list, arg[j]) - j++ - } else { - list = append(list, v) - } - } - for ; j < len(arg); j++ { - list = append(list, arg[j]) - } - - msg := m.Spawn(m.Target()).Cmd("get", list) - m.Copy(msg, "result") - } - } // }}} - }}, "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])