web

package
v2.1.0+incompatible Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 29, 2019 License: MIT Imports: 19 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var Index = &ctx.Context{Name: "web", Help: "应用中心",
	Caches: map[string]*ctx.Cache{
		"nserve": &ctx.Cache{Name: "nserve", Value: "0", Help: "主机数量"},
		"nroute": &ctx.Cache{Name: "nroute", Value: "0", Help: "路由数量"},
	},
	Configs: map[string]*ctx.Config{
		"spide": &ctx.Config{Name: "spide", Value: map[string]interface{}{
			"": map[string]interface{}{
				"client": map[string]interface{}{},
				"header": map[string]interface{}{},
				"cookie": map[string]interface{}{},
			},
		}, Help: "爬虫配置"},
		"serve": &ctx.Config{Name: "serve", Value: map[string]interface{}{
			"autofree":   false,
			"logheaders": false,
			"form_size":  "102400",
			"directory":  "usr",
			"protocol":   "http",
			"cert":       "etc/cert.pem",
			"key":        "etc/key.pem",
			"site":       "",
			"index":      "/chat/",
			"open":       []interface{}{},
		}, Help: "服务配置"},
		"route": &ctx.Config{Name: "route", Value: map[string]interface{}{
			"index":          "/render",
			"template_dir":   "usr/template",
			"template_debug": false,
			"componet_index": "index",
			"toolkit_view": map[string]interface{}{
				"top": 96, "left": 472, "width": 600, "height": 300,
			},
		}, Help: "功能配置"},
		"login": &ctx.Config{Name: "login", Value: map[string]interface{}{
			"expire":    "240h",
			"local":     true,
			"check":     true,
			"sess_void": false,
			"cas_uuid":  "email",
		}, Help: "认证配置"},
		"componet": &ctx.Config{Name: "componet", Value: map[string]interface{}{
			"login": []interface{}{},
			"index": []interface{}{
				map[string]interface{}{"name": "head", "template": "head"},
				map[string]interface{}{"name": "clipbaord", "template": "clipboard"},
				map[string]interface{}{"name": "tail", "template": "tail"},
			},
		}, Help: "组件列表"},
		"upload": &ctx.Config{Name: "upload", Value: map[string]interface{}{
			"path": "var/file",
		}, Help: "上件文件"},
		"toolkit": &ctx.Config{Name: "toolkit", Value: map[string]interface{}{
			"time": map[string]interface{}{"cmd": "time"},
		}, Help: "工具列表"},
		"wss": &ctx.Config{Name: "wss", Value: map[string]interface{}{}, Help: ""},
	},
	Commands: map[string]*ctx.Command{
		"_init": &ctx.Command{Name: "_init", Help: "post请求", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
			m.Cmd("web.spide", "cas", "client", "new", m.Conf("runtime", "boot.ctx_cas"))
			m.Cmd("web.spide", "dev", "client", "new", kit.Select(m.Conf("runtime", "boot.ctx_dev"), m.Conf("runtime", "boot.ctx_box")))
			return
		}},
		"spide": &ctx.Command{Name: "spide [which [client|header|cookie [name|new [value]]]]", Help: "爬虫配置", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
			switch len(arg) {
			case 0:
				m.Confm("spide", func(key string, value map[string]interface{}) {
					m.Push("key", key)
					m.Push("protocol", kit.Chains(value, "client.protocol"))
					m.Push("hostname", kit.Chains(value, "client.hostname"))
					m.Push("path", kit.Chains(value, "client.path"))
				})
				m.Sort("key").Table()
			case 1:
				m.Cmdy("ctx.config", "spide", arg[0])
			case 2:
				m.Cmdy("ctx.config", "spide", strings.Join(arg[:2], "."))
			default:
				switch arg[1] {
				case "client":
					if len(arg) == 3 {
						m.Cmdy("ctx.config", "spide", strings.Join(arg[:3], "."))
						break
					}

					if arg[2] == "new" {
						if uri, e := url.Parse(arg[3]); e == nil && arg[3] != "" {
							dir, file := path.Split(uri.EscapedPath())
							m.Confv("spide", arg[0], map[string]interface{}{
								"cookie": map[string]interface{}{},
								"header": map[string]interface{}{},
								"client": map[string]interface{}{
									"logheaders": false,
									"timeout":    "100s",
									"method":     "GET",
									"protocol":   uri.Scheme,
									"hostname":   uri.Host,
									"path":       dir,
									"file":       file,
									"query":      uri.RawQuery,
									"url":        arg[3],
								},
							})
						}
						break
					}

					m.Cmd("ctx.config", "spide", strings.Join(arg[:3], "."), arg[3])
				case "merge":
					m.Echo(Merge(m, m.Confm("spide", []string{arg[0], "client"}), arg[2], arg[3:]...))

				case "cookie", "header":
					if len(arg) > 3 {
						m.Cmd("ctx.config", "spide", strings.Join(arg[:3], "."), arg[3])
					}
					m.Cmdy("ctx.config", "spide", strings.Join(arg[:3], "."))

				default:
					m.Cmd("ctx.config", "spide", strings.Join(arg[:2], "."), arg[2])
				}
			}
			return
		}},
		"post": &ctx.Command{Name: "post args...", Help: "post请求", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
			m.Cmdy("web.get", "method", "POST", arg)
			return
		}},
		"get": &ctx.Command{Name: "get [which] name [method GET|POST] url arg...", Help: "访问服务, method: 请求方法, url: 请求地址, arg: 请求参数",
			Form: map[string]int{
				"which": 1, "method": 1, "args": 1, "headers": 2,
				"content_type": 1, "content_data": 1, "body": 1, "file": 2,
				"parse": 1, "temp": -1, "temp_expire": 1, "save": 1,
			}, Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {

				if len(arg) == 0 {
					m.Cmdy("web.spide")
					return
				}
				if len(arg) == 1 {
					m.Cmdy("web.spide", arg[0])
					return
				}

				web, ok := m.Target().Server.(*WEB)
				m.Assert(ok)

				which, client := m.Option("which"), m.Confm("spide", []string{m.Option("which"), "client"})
				if c := m.Confm("spide", []string{arg[0], "client"}); c != nil {
					which, client, arg = arg[0], c, arg[1:]
				}

				method := kit.Select(kit.Format(client["method"]), m.Option("method"))
				uri := Merge(m, client, arg[0], arg[1:]...)
				uri_arg := ""

				body, ok := m.Optionv("body").(io.Reader)
				if method == "POST" && !ok {
					uuu, e := url.Parse(uri)
					m.Assert(e)

					if m.Has("content_data") {
						body = bytes.NewReader([]byte(m.Option("content_data")))

					} else if m.Has("file") {
						writer := multipart.NewWriter(&bytes.Buffer{})
						defer writer.Close()

						for k, v := range uuu.Query() {
							for _, v := range v {
								writer.WriteField(k, v)
							}
						}

						if file, e := os.Open(m.Cmdx("nfs.path", m.Meta["file"][1])); m.Assert(e) {
							defer file.Close()

							if part, e := writer.CreateFormFile(m.Option("file"), filepath.Base(m.Meta["file"][1])); m.Assert(e) {
								io.Copy(part, file)
								m.Option("content_type", writer.FormDataContentType())
							}
						}

					} else if index := strings.Index(uri, "?"); index > 0 {
						switch m.Option("content_type") {
						case "application/json":
							var data interface{}
							for k, v := range uuu.Query() {
								if len(v) == 1 {
									if i, e := strconv.Atoi(v[0]); e == nil {
										data = kit.Chain(data, k, i)
									} else {
										data = kit.Chain(data, k, v[0])
									}
								} else {
									for i, val := range v {
										if i, e := strconv.Atoi(v[i]); e == nil {
											data = kit.Chain(data, []string{k, "-2"}, i)
										} else {
											data = kit.Chain(data, []string{k, "-2"}, val)
										}
									}
								}
							}

							if b, e := json.Marshal(data); m.Assert(e) {
								m.Log("info", "json %v", string(b))

								if body = bytes.NewReader(b); m.Has("args") {
									uri = uri[:index] + "?" + m.Option("args")
									index = len(uri)
								}
							}

						default:
							m.Log("info", "body %v", string(uri[index+1:]))
							body = strings.NewReader(uri[index+1:])
							m.Option("content_type", "application/x-www-form-urlencoded")
							m.Option("content_length", len(uri[index+1:]))
						}
						uri, uri_arg = uri[:index], "?"+uuu.RawQuery
					}
				}

				if m.Options("temp_expire") {
					if h := m.Cmdx("mdb.temp", "check", "url", uri+uri_arg); h != "" {
						m.Cmdy("mdb.temp", h, "data", "data", m.Meta["temp"])
						return
					}
				}

				req, e := http.NewRequest(method, uri, body)
				m.Assert(e)
				m.Log("info", "%s %s", req.Method, req.URL)

				m.Confm("spide", []string{which, "header"}, func(key string, value string) {
					if key != "" {
						req.Header.Set(key, value)
						m.Log("info", "header %v %v", key, value)
					}
				})
				for i := 0; i < len(m.Meta["headers"]); i += 2 {
					req.Header.Set(m.Meta["headers"][i], m.Meta["headers"][i+1])
				}
				if m.Options("content_type") {
					req.Header.Set("Content-Type", m.Option("content_type"))
				}
				if m.Options("content_length") {
					req.Header.Set("Content-Length", m.Option("content_length"))
				}

				if kit.Right(client["logheaders"]) {
					for k, v := range req.Header {
						m.Log("info", "%s: %s", k, v)
					}
					m.Log("info", "")
				}

				kit.Structm(m.Magic("user", []string{"cookie", which}), func(key string, value string) {
					req.AddCookie(&http.Cookie{Name: key, Value: value})
					m.Log("info", "set-cookie %s: %v", key, value)
				})

				if web.Client == nil {
					web.Client = &http.Client{Timeout: kit.Duration(kit.Format(client["timeout"]))}
				}
				res, e := web.Client.Do(req)
				if e != nil {
					m.Log("warn", "%v", e)
					m.Echo("%v", e)
					return e
				}

				if res.StatusCode != http.StatusOK {
					m.Log("warn", "%d: %s\n", res.StatusCode, res.Status)
					m.Echo("%d: %s\n", res.StatusCode, res.Status)
				}

				for _, v := range res.Cookies() {
					if m.Log("info", "get-cookie %s: %v", v.Name, v.Value); v.Value != "" {
						m.Magic("user", []string{"cookie", which, v.Name}, v.Value)
					}
				}

				if kit.Right(client["logheaders"]) {
					for k, v := range res.Header {
						m.Log("info", "%s: %v", k, v)
					}
				}

				if res.StatusCode == http.StatusOK && m.Options("save") {
					if f, p, e := kit.Create(m.Option("save")); m.Assert(e) {
						defer f.Close()

						if n, e := io.Copy(f, res.Body); m.Assert(e) {
							m.Log("info", "save %d %s", n, p)
							m.Echo(p)
						}
					}
					return
				}

				// 解析响应
				var result interface{}
				ct := res.Header.Get("Content-Type")
				parse := kit.Select(kit.Format(client["parse"]), m.Option("parse"))
				m.Log("info", "parse: %s content: %s", parse, ct)

				switch {
				case parse == "json" || strings.HasPrefix(ct, "application/json") || strings.HasPrefix(ct, "application/javascript"):

					if json.NewDecoder(res.Body).Decode(&result); m.Options("temp_expire") {
						if m.Log("info", "res: %v", kit.Format(result)); !m.Has("temp") {
							m.Option("temp", "")
						}

						m.Put("option", "data", result).Cmdy("mdb.temp", "url", uri+uri_arg, "data", "data", m.Meta["temp"])
						break
					} else if result != nil {
						if b, e := json.MarshalIndent(result, "", "  "); m.Assert(e) {
							m.Echo(string(b))
						}
						break
					}
					fallthrough
				default:

					if buf, e := ioutil.ReadAll(res.Body); m.Assert(e) {
						m.Echo(string(buf))
					}
				}
				return
			}},

		"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) (e error) {
			m.Set("detail", arg).Target().Start(m)
			return
		}},
		"route": &ctx.Command{Name: "route index content [help]", Help: "添加路由响应, index: 路由, context: 响应, help: 说明", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
			if mux, ok := m.Target().Server.(MUX); m.Assert(ok) {
				switch len(arg) {
				case 0:
					for k, v := range m.Target().Commands {
						if k[0] == '/' {
							m.Add("append", "route", k)
							m.Add("append", "name", v.Name)
						}
					}
					m.Sort("route").Table()
				case 1:
					for k, v := range m.Target().Commands {
						if k == arg[0] {
							m.Echo("%s: %s\n%s", k, v.Name, v.Help)
						}
					}
				default:
					help := kit.Select("dynamic route", arg, 2)
					hand := func(m *ctx.Message, c *ctx.Context, key string, a ...string) (e error) {
						w := m.Optionv("response").(http.ResponseWriter)
						template.Must(template.New("temp").Parse(arg[1])).Execute(w, m)
						return
					}

					if s, e := os.Stat(arg[1]); e == nil {
						if s.IsDir() {
							mux.Handle(arg[0]+"/", http.StripPrefix(arg[0], http.FileServer(http.Dir(arg[1]))))
						} else if strings.HasSuffix(arg[1], ".shy") {
							hand = func(m *ctx.Message, c *ctx.Context, key string, a ...string) (e error) {
								m.Cmdy("cli.source", arg[1])
								return
							}
						} else {
							hand = func(m *ctx.Message, c *ctx.Context, key string, a ...string) (e error) {
								w := m.Optionv("response").(http.ResponseWriter)
								template.Must(template.ParseGlob(arg[1])).Execute(w, m)
								return
							}
						}
					}

					if _, ok := m.Target().Commands[arg[0]]; ok {
						m.Target().Commands[arg[0]].Help = help
						m.Target().Commands[arg[0]].Name = arg[1]
						m.Target().Commands[arg[0]].Hand = hand
					} else {
						cmd := &ctx.Command{Name: arg[1], Help: help, Hand: hand}
						m.Target().Commands[arg[0]] = cmd
						mux.HandleCmd(m, arg[0], cmd)
					}
				}
			}
			return
		}},
		"template": &ctx.Command{Name: "template [name [file...]]", Help: "模板管理, name: 模板名, file: 模板文件", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
			if web, ok := m.Target().Server.(*WEB); m.Assert(ok) {
				if len(arg) == 0 {
					for _, v := range web.Template.Templates() {
						m.Add("append", "name", v.Name())
					}
					m.Sort("name").Table()
					return
				}

				tmpl := web.Template
				if len(arg) > 1 {
					tmpl = template.Must(web.Template.Clone())
					tmpl = template.Must(tmpl.ParseFiles(arg[1:]...))
				}

				buf := bytes.NewBuffer(make([]byte, 1024))
				tmpl.ExecuteTemplate(buf, arg[0], m)
				m.Echo(string(buf.Bytes()))
			}
			return
		}},
		"componet": &ctx.Command{Name: "componet [group [order [arg...]]]", Help: "添加组件, group: 组件分组, arg...: 组件参数", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
			if len(arg) > 0 && arg[0] == "share" {
				m.Cmd("aaa.role", arg[1], "componet", arg[2], "command", arg[3:])
				m.Echo("%s%s?componet_group=%s&relay=%s", m.Conf("serve", "site"), m.Option("index_path"), arg[2], m.Cmdx("aaa.relay", "share", arg[1], "temp"))
				return
			}

			switch len(arg) {
			case 0:
				m.Cmdy("ctx.config", "componet")
			case 1:
				m.Confm("componet", arg[0], func(index int, val map[string]interface{}) {
					m.Add("append", "ctx", val["componet_ctx"])
					m.Add("append", "cmd", val["componet_cmd"])
					m.Add("append", "name", val["componet_name"])
					m.Add("append", "help", val["componet_help"])
					m.Add("append", "tmpl", val["componet_tmpl"])
					m.Add("append", "view", val["componet_view"])
					m.Add("append", "init", val["componet_init"])
				})
				m.Table()
			case 2:
				m.Cmdy("ctx.config", "componet", strings.Join(arg, "."))
			default:
				switch arg[0] {
				case "create":
					m.Confm("componet", arg[1:3], map[string]interface{}{
						"name": arg[3], "help": arg[4],
						"componet_ctx": arg[5], "componet_cmd": arg[6],
					})
				default:
					componet := m.Confm("componet", arg[:2])
					for i := 2; i < len(arg)-1; i += 2 {
						kit.Chain(componet, arg[i], arg[i+1])
					}
				}
			}
			return
		}},

		"/render": &ctx.Command{Name: "/render template", Help: "渲染模板, template: 模板名称", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {

			if m.Confs("login", "check") {
				if !m.Options("sessid") || !m.Options("username") || !m.Cmds("aaa.role", m.Option("userrole"), "check", m.Confx("group")) {
					m.Set("option", "group", "login").Set("option", "name", "")
				}
			}

			accept_json := strings.HasPrefix(m.Option("accept"), "application/json")
			w := m.Optionv("response").(http.ResponseWriter)
			if !accept_json {
				w.Header().Set("Content-Type", "text/html")
			} else {
				w.Header().Set("Content-Type", "application/json")
			}

			web, ok := m.Target().Server.(*WEB)
			m.Assert(ok)

			tmpl := web.Template
			if m.Confs("route", "template_debug") {
				tmpl = template.New("render").Funcs(ctx.CGI)
				tmpl.ParseGlob(path.Join(m.Conf("route", "template_dir"), "/*.tmpl"))
				tmpl.ParseGlob(path.Join(m.Conf("route", "template_dir"), m.Cap("route"), "/*.tmpl"))
			}

			m.Option("title", m.Conf("runtime", "boot.hostname"))

			group, order := m.Option("group", kit.Select(m.Conf("route", "componet_index"), m.Option("group"))), m.Option("names")
			list := []interface{}{}

			for _, v := range m.Confv("componet", group).([]interface{}) {
				val := v.(map[string]interface{})
				if order != "" && val["name"].(string) != order {
					continue
				}

				msg := m.Find(kit.Select(m.Cap("module"), val["ctx"]))

				for k, v := range val {
					switch value := v.(type) {
					case []string:
						msg.Set("option", k, value)
					case string:
						msg.Set("option", k, value)
					default:
						msg.Put("option", k, value)
					}
				}

				if kit.Right(val["cmd"]) {
					arg = append(arg, kit.Format(val["cmd"]))
				}

				if m.Has("cmds") {
					arg = append(arg, kit.Trans(m.Optionv("cmds"))...)
				} else {
					kit.Map(val["args"], "", func(index int, value map[string]interface{}) {
						if value["name"] != nil {
							arg = append(arg, kit.Select(msg.Option(value["name"].(string)), msg.Parse(value["value"])))
						}
					})
				}

				if len(arg) > 0 {
					if order != "" || kit.Right(val["pre_run"]) {

						if m.Confs("login", "check") && m.Cmds("aaa.role", m.Option("userrole"), "check", m.Option("componet_group"), arg[0]) {
							continue
						}

						msg.Cmd(arg)
					}
				}

				if msg.Appends("qrcode") {
					m.Append("qrcode", msg.Append("qrcode"))
				} else if msg.Appends("directory") {
					m.Append("download_file", fmt.Sprintf("/download/%s", msg.Append("directory")))
					return
				} else if accept_json {
					list = append(list, msg.Meta)
				} else if val["tmpl"] != nil {
					m.Assert(tmpl.ExecuteTemplate(w, val["tmpl"].(string), msg))
				}
			}

			if accept_json {
				en := json.NewEncoder(w)
				en.SetIndent("", "  ")
				en.Encode(list)
			}
			return
		}},
		"/upload": &ctx.Command{Name: "/upload", Help: "上传文件", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
			r := m.Optionv("request").(*http.Request)
			if f, h, e := r.FormFile("upload"); m.Assert(e) {
				defer f.Close()

				name := kit.Hashx(f)
				if o, p, e := kit.Create(path.Join(m.Conf("web.upload", "path"), "list", name)); m.Assert(e) {
					defer o.Close()

					f.Seek(0, os.SEEK_SET)
					if n, e := io.Copy(o, f); m.Assert(e) {
						m.Log("upload", "file: %s %d", p, n)

						code := kit.Hashs("uniq")
						if o, p, e := kit.Create(path.Join(m.Conf("web.upload", "path"), "meta", code)); m.Assert(e) {
							defer o.Close()

							kind := h.Header.Get("Content-Type")
							m.Log("upload", "file: %s %d", p, n)
							fmt.Fprintf(o, "create_time: %s\n", m.Time())
							fmt.Fprintf(o, "create_user: %s\n", m.Option("username"))
							fmt.Fprintf(o, "name: %s\n", h.Filename)
							fmt.Fprintf(o, "type: %s\n", kind)
							fmt.Fprintf(o, "hash: %s\n", name)
							fmt.Fprintf(o, "size: %d\n", n)

							m.Append("size", kit.FmtSize(n))
							m.Append("code", code)
							m.Append("link", fmt.Sprintf(`<a href="/download/%s" target="_blank">%s</a>`, code, h.Filename))
							m.Append("type", kind)
							m.Append("hash", name)

							kind = strings.Split(kind, "/")[0]
							m.Cmd("nfs.copy", path.Join(m.Conf("web.upload", "path"), kind, code), p)
							m.Cmd("ssh.data", "insert", kit.Select(kind, m.Option("table")),
								"name", h.Filename, "kind", kind, "hash", name, "size", n)
						}
						m.Table()
					}
				}
			}
			return
		}},
		"/download/": &ctx.Command{Name: "/download/", Help: "下载文件", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
			r := m.Optionv("request").(*http.Request)
			w := m.Optionv("response").(http.ResponseWriter)

			kind := kit.Select("meta", kit.Select(m.Option("meta"), arg, 0))
			file := strings.TrimPrefix(key, "/download/")
			if file == "" {

				if fs, e := ioutil.ReadDir(path.Join(m.Conf("web.upload", "path"), kind)); e == nil {
					for _, f := range fs {
						meta := kit.Linex(path.Join(m.Conf("web.upload", "path"), kind, f.Name()))
						m.Push("time", meta["create_time"])
						m.Push("user", meta["create_user"])
						m.Push("size", kit.FmtSize(int64(kit.Int(meta["size"]))))
						if kind == "image" {
							m.Push("name", f.Name())
						} else {
							m.Push("name", fmt.Sprintf(`<a href="/download/%s" target="_blank">%s</a>`, f.Name(), meta["name"]))
						}
						m.Push("hash", meta["hash"][:8])
					}
					m.Sort("time", "time_r").Table()
				}
				return
			}

			if p := m.Cmdx("nfs.path", path.Join(m.Conf("web.upload", "path"), "list", file)); p != "" {
				m.Log("info", "download %s direct", p)
				http.ServeFile(w, r, p)
				return
			}

			if p := m.Cmdx("nfs.path", path.Join(m.Conf("web.upload", "path"), kind, file)); p != "" {
				meta := kit.Linex(p)
				if p := m.Cmdx("nfs.path", path.Join(m.Conf("web.upload", "path"), "list", meta["hash"])); p != "" {
					m.Log("info", "download %s %s", p, m.Cmdx("nfs.hash", meta["hash"]))
					w.Header().Set("Content-Disposition", fmt.Sprintf("filename=%s", meta["name"]))
					http.ServeFile(w, r, p)
				} else {
					http.NotFound(w, r)
				}
				return
			}

			if m.Option("userrole") != "root" {
				return
			}

			if p := m.Cmdx("nfs.path", file); p != "" {
				m.Log("info", "download %s %s", p, m.Cmdx("nfs.hash", p))
				http.ServeFile(w, r, p)
			}
			return
		}},
		"/require/": &ctx.Command{Name: "/require/", Help: "加载脚本", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
			r := m.Optionv("request").(*http.Request)
			w := m.Optionv("response").(http.ResponseWriter)
			file := strings.TrimPrefix(key, "/require/")

			if p := m.Cmdx("nfs.path", m.Conf("cli.project", "plugin.path"), file); p != "" {
				m.Log("info", "download %s direct", p)
				http.ServeFile(w, r, p)
				return
			}
			return
		}},
		"/proxy/": &ctx.Command{Name: "/proxy/which/method/url", Help: "服务代理", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
			fields := strings.Split(key, "/")
			m.Cmdy("web.get", "which", fields[2], "method", fields[3], strings.Join(fields, "/"))
			return
		}},
		"/login": &ctx.Command{Name: "/login", Help: "认证", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
			switch {
			case m.Options("cert"):
				msg := m.Cmd("aaa.rsa", "info", m.Option("cert"))
				m.Cmd("aaa.auth", "nodes", msg.Append("route"), "cert", m.Option("cert"))
				m.Append("sess", m.Cmdx("aaa.sess", "nodes", "nodes", msg.Append("route")))

			case m.Options("pull"):
				sess := m.Cmd("aaa.auth", "nodes", m.Option("pull"), "session").Append("key")
				m.Add("append", "username", m.Cmd("aaa.auth", sess, "username").Append("meta"))
				m.Add("append", "cert", (m.Cmd("aaa.auth", "nodes", m.Option("pull"), "cert").Append("meta")))

			case m.Options("bind"):
				sess := m.Cmd("aaa.auth", "nodes", m.Option("bind"), "session").Append("key")
				if m.Cmd("aaa.auth", sess, "username").Appends("meta") {
					return
				}

				if m.Cmds("aaa.rsa", "verify", m.Cmd("aaa.auth", "username", m.Option("username"), "cert").Append("meta"), m.Option("code"), m.Option("bind")) {
					m.Cmd("aaa.login", sess, "username", m.Option("username"))
					m.Append("userrole", "root")
				}
			case m.Options("user.cert"):
				if !m.Cmds("aaa.auth", "username", m.Option("username"), "cert") {
					m.Cmd("aaa.auth", "username", m.Option("username"), "cert", m.Option("user.cert"))
				}
				m.Append("username", m.Option("username"))
			}
			return
		}},

		"/publish/": &ctx.Command{Name: "/publish/filename [upgrade script|plugin]", Help: "下载项目", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {

			key = strings.TrimPrefix(key, "/publish/")
			if strings.HasSuffix(key, "bench") {
				key = key + "." + kit.Select(m.Conf("runtime", "host.GOOS"), m.Option("GOOS")) +
					"." + kit.Select(m.Conf("runtime", "host.GOARCH"), m.Option("GOARCH"))
			}

			p := ""
			if m.Option("upgrade") == "script" {

				if m.Options("missyou") {
					p = m.Cmdx("nfs.path", path.Join(m.Conf("missyou", "path"), m.Option("missyou"), "usr/script", key))
				} else {
					p = m.Cmdx("nfs.path", path.Join("usr/script", key))
				}
			} else if m.Option("upgrade") == "plugin" {

				p = m.Cmdx("nfs.path", path.Join(m.Conf("publish", "path"), key, kit.Select("index.shy", m.Option("index"))))

			} else {

				if p = m.Cmdx("nfs.path", path.Join(m.Conf("publish", "path"), key)); p == "" {
					p = m.Cmdx("nfs.path", m.Conf("publish", []string{"list", kit.Key(key)}))
				}
			}

			if s, e := os.Stat(p); e == nil && !s.IsDir() {
				m.Log("info", "publish %s %s", kit.Hashs(p), p)
				http.ServeFile(m.Optionv("response").(http.ResponseWriter), m.Optionv("request").(*http.Request), p)
			}
			return
		}},
		"/shadow": &ctx.Command{Name: "/shadow", Help: "暗网", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
			m.Confm("runtime", "node.port", func(index int, value string) {
				m.Add("append", "ports", value)
			})
			return
		}},

		"/wss": &ctx.Command{Name: "/wss", Help: "", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
			r := m.Optionv("request").(*http.Request)
			w := m.Optionv("response").(http.ResponseWriter)
			agent := r.Header.Get("User-Agent")

			if s, e := websocket.Upgrade(w, r, nil, 4096, 4096); m.Assert(e) {
				h := m.Option("wssid")
				if h == "" || m.Confs("wss", h) {
					h = kit.Hashs("uniq")
				}
				p := make(chan *ctx.Message, 10)
				meta := map[string]interface{}{
					"create_time": m.Time(),
					"create_user": m.Option("username"),
					"agent":       agent,
					"sessid":      m.Option("sessid"),
					"socket":      s,
					"channel":     p,
				}
				m.Conf("wss", []string{m.Option("username"), h}, meta)
				m.Conf("wss", h, meta)
				p <- m.Spawn().Add("detail", "wssid", h)

				what := m
				m.Log("wss", "conn %v %s", h, agent)
				m.Gos(m.Spawn(), func(msg *ctx.Message) {
					for {
						if t, b, e := s.ReadMessage(); e == nil {
							var data interface{}
							if e := json.Unmarshal(b, &data); e == nil {
								m.Log("wss", "recv %s %d msg %v", h, t, data)
							} else {
								m.Log("wss", "recv %s %d msg %v", h, t, b)
								data = b
							}

							what.Optionv("data", data)
							what.Back(what)
						} else {
							m.Log("warn", "wss recv %s %d msg %v", h, t, e)
							close(p)
							break
						}
					}
				})

				for what = range p {
					s.WriteJSON(what.Meta)
				}

				m.Log("wss", "close %s %s", h, agent)
				m.Conf("wss", []string{m.Option("username"), h}, "")
				m.Conf("wss", h, "")
				s.Close()
			}
			return
		}},
		"wss": &ctx.Command{Name: "wss", Help: "", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
			if len(arg) == 0 || arg[0] == "" {
				m.Confm("wss", func(key string, value map[string]interface{}) {
					if value["agent"] == nil {
						return
					}
					m.Push("key", m.Cmdx("aaa.short", key))
					m.Push("create_time", value["create_time"])
					m.Push("create_user", value["create_user"])
					m.Push("sessid", kit.Format(value["sessid"])[:6])
					m.Push("agent", value["agent"])
				})
				m.Table()
				return
			}

			list := []string{}
			if strings.Contains(arg[0], ".") {
				vs := strings.SplitN(arg[0], ".", 2)
				m.Confm("wss", vs[0], func(key string, value map[string]interface{}) {
					if len(vs) == 1 || vs[1] == "*" || strings.Contains(kit.Format(value["agent"]), vs[1]) {
						list = append(list, key)
					}
				})
			} else {
				if len(arg[0]) != 32 {
					arg[0] = m.Cmdx("aaa.short", arg[0])
				}
				list = append(list, arg[0])
			}

			if len(arg) == 1 {
				m.Cmdy(".config", "wss", arg[0])
				return
			}

			for _, v := range list {
				if p, ok := m.Confv("wss", []string{v, "channel"}).(chan *ctx.Message); ok {
					if msg := m.Spawn(); arg[1] == "sync" {
						p <- msg.Add("detail", arg[2], arg[3:])
						msg.CallBack(true, func(msg *ctx.Message) *ctx.Message {
							if data, ok := msg.Optionv("data").(map[string]interface{}); ok {
								if len(list) == 1 && data["append"] != nil {
									for _, k := range kit.Trans(data["append"]) {
										m.Push(k, kit.Trans(data[k]))
									}
								} else {
									m.Push("time", m.Time())
									m.Push("key", m.Cmdx("aaa.short", v))
									m.Push("action", kit.Format(arg[2:]))

									res := kit.Trans(data["result"])
									m.Push("return", kit.Format(res))
									m.Log("wss", "result: %v", res)
								}

							} else {
								m.Push("time", m.Time())
								m.Push("key", m.Cmdx("aaa.short", v))
								m.Push("action", kit.Format(arg[2:]))
							}
							return m
						}, "skip")
						m.Table()
					} else {
						p <- msg.Add("detail", arg[1], arg[2:])
					}
				}
			}
			return
		}},
	},
}

Functions

func Cookie(msg *ctx.Message, w http.ResponseWriter, r *http.Request)

func Merge added in v1.1.1

func Merge(m *ctx.Message, client map[string]interface{}, uri string, arg ...string) string

Types

type MUX

type MUX interface {
	Handle(string, http.Handler)
	HandleFunc(string, func(http.ResponseWriter, *http.Request))
	HandleCmd(*ctx.Message, string, *ctx.Command)
	ServeHTTP(http.ResponseWriter, *http.Request)
}

type WEB

func (*WEB) Begin

func (web *WEB) Begin(m *ctx.Message, arg ...string) ctx.Server

func (*WEB) Close

func (web *WEB) Close(m *ctx.Message, arg ...string) bool

func (*WEB) HandleCmd added in v1.1.0

func (web *WEB) HandleCmd(m *ctx.Message, key string, cmd *ctx.Command)

func (*WEB) Login added in v1.1.1

func (web *WEB) Login(msg *ctx.Message, w http.ResponseWriter, r *http.Request) bool

func (*WEB) ServeHTTP

func (web *WEB) ServeHTTP(w http.ResponseWriter, r *http.Request)

func (*WEB) Spawn

func (web *WEB) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server

func (*WEB) Start

func (web *WEB) Start(m *ctx.Message, arg ...string) bool

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL