mirror of
https://shylinux.com/x/icebergs
synced 2025-04-26 01:24:05 +08:00
opt web
This commit is contained in:
parent
84d5e3800e
commit
6aff305ded
@ -2,7 +2,7 @@ package aaa
|
||||
|
||||
import (
|
||||
"github.com/shylinux/icebergs"
|
||||
"github.com/shylinux/icebergs/base/cli"
|
||||
// "github.com/shylinux/icebergs/base/cli"
|
||||
"github.com/shylinux/toolkits"
|
||||
)
|
||||
|
||||
@ -26,8 +26,6 @@ var Index = &ice.Context{Name: "aaa", Help: "认证模块", Commands: map[string
|
||||
m.Rich(ROLE, nil, kit.Dict(kit.MDB_NAME, TECH, Black, kit.Dict(), White, kit.Dict()))
|
||||
m.Rich(ROLE, nil, kit.Dict(kit.MDB_NAME, VOID, White, kit.Dict(), Black, kit.Dict()))
|
||||
m.Load()
|
||||
cli.PassWord = kit.Hashs("uniq")
|
||||
_user_create(m, cli.UserName, cli.PassWord)
|
||||
}},
|
||||
ice.ICE_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
m.Save(ROLE, USER, SESS)
|
||||
|
@ -21,17 +21,19 @@ func _sess_auth(m *ice.Message, sessid string, username string, userrole string)
|
||||
}
|
||||
value["username"] = username
|
||||
m.Log_AUTH(SESSID, sessid, USERNAME, username, USERROLE, userrole)
|
||||
m.Echo("%v", value[USERROLE])
|
||||
})
|
||||
}
|
||||
func _sess_check(m *ice.Message, sessid string) {
|
||||
m.Richs(SESS, nil, sessid, func(value map[string]interface{}) {
|
||||
m.Push(sessid, value, []string{USERNAME, USERROLE})
|
||||
m.Echo("%s", value[USERROLE])
|
||||
m.Log_AUTH(
|
||||
USERROLE, m.Option(ice.MSG_USERROLE, value[USERROLE]),
|
||||
USERNAME, m.Option(ice.MSG_USERNAME, value[USERNAME]),
|
||||
)
|
||||
})
|
||||
}
|
||||
func _sess_create(m *ice.Message, username string) string {
|
||||
h := m.Rich(SESS, nil, kit.Dict(
|
||||
kit.MDB_TIME, m.Time(m.Conf(SESS, "meta.expire")),
|
||||
USERNAME, username, "from", m.Option(ice.MSG_SESSID),
|
||||
))
|
||||
m.Log_CREATE(SESSID, h, USERNAME, username)
|
||||
|
@ -25,12 +25,17 @@ func _user_create(m *ice.Message, name, word string) {
|
||||
// 创建用户
|
||||
m.Rich(USER, nil, kit.Dict(
|
||||
USERNAME, name, PASSWORD, word,
|
||||
USERNICK, name, USERNODE, m.Conf(ice.CLI_RUNTIME, "boot.hostname"),
|
||||
USERNICK, name, USERNODE, cli.NodeName,
|
||||
))
|
||||
m.Log_CREATE(USERNAME, name)
|
||||
m.Event(ice.USER_CREATE, name)
|
||||
}
|
||||
|
||||
func UserRoot(m *ice.Message) {
|
||||
cli.PassWord = kit.Hashs("uniq")
|
||||
cli.PassWord = cli.UserName
|
||||
_user_create(m, cli.UserName, cli.PassWord)
|
||||
}
|
||||
func UserRole(m *ice.Message, username string) string {
|
||||
if username == cli.UserName {
|
||||
return ROOT
|
||||
@ -42,12 +47,6 @@ func UserLogin(m *ice.Message, username, password string) bool {
|
||||
m.Option(ice.MSG_USERNAME, username)
|
||||
m.Option(ice.MSG_USERROLE, UserRole(m, username))
|
||||
m.Option(ice.MSG_SESSID, SessCreate(m, m.Option(ice.MSG_USERNAME), m.Option(ice.MSG_USERROLE)))
|
||||
|
||||
m.Log_AUTH(
|
||||
USERROLE, m.Option(ice.MSG_USERROLE),
|
||||
USERNAME, m.Option(ice.MSG_USERNAME),
|
||||
SESSID, m.Option(ice.MSG_SESSID),
|
||||
)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@ -66,43 +65,7 @@ func init() {
|
||||
_user_login(m, arg[0], arg[1])
|
||||
}},
|
||||
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
if len(arg) == 0 {
|
||||
_user_list(m)
|
||||
return
|
||||
}
|
||||
|
||||
switch arg[0] {
|
||||
case "first":
|
||||
// 超级用户
|
||||
if m.Richs(ice.AAA_USER, nil, "%", nil) == nil {
|
||||
}
|
||||
|
||||
case "login":
|
||||
// 用户认证
|
||||
user := m.Richs(USER, nil, arg[1], nil)
|
||||
if word := kit.Select("", arg, 2); user == nil {
|
||||
nick := arg[1]
|
||||
if len(nick) > 8 {
|
||||
nick = nick[:8]
|
||||
}
|
||||
_user_create(m, arg[1], word)
|
||||
|
||||
} else if word != "" {
|
||||
if !_user_login(m, arg[1], word) {
|
||||
m.Info("login fail user: %s", arg[1])
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if m.Options(ice.MSG_SESSID) && m.Cmdx(ice.AAA_SESS, "check", m.Option(ice.MSG_SESSID)) == arg[1] {
|
||||
// 复用会话
|
||||
m.Echo(m.Option(ice.MSG_SESSID))
|
||||
break
|
||||
}
|
||||
|
||||
// 创建会话
|
||||
m.Echo(m.Cmdx(ice.AAA_SESS, "create", arg[1]))
|
||||
}
|
||||
_user_list(m)
|
||||
}},
|
||||
},
|
||||
}, nil)
|
||||
|
@ -24,6 +24,12 @@ var HostName = ""
|
||||
var PathName = ""
|
||||
var NodeName = ""
|
||||
|
||||
func NodeType(m *ice.Message, kind, name string) {
|
||||
m.Conf(ice.CLI_RUNTIME, "node.type", kind)
|
||||
m.Conf(ice.CLI_RUNTIME, "node.name", name)
|
||||
NodeName = name
|
||||
}
|
||||
|
||||
var Index = &ice.Context{Name: "cli", Help: "命令模块",
|
||||
Configs: map[string]*ice.Config{
|
||||
RUNTIME: {Name: "runtime", Help: "运行环境", Value: kit.Dict()},
|
||||
|
@ -30,7 +30,8 @@ func _system_show(m *ice.Message, cmd *exec.Cmd) {
|
||||
cmd.Stderr = err
|
||||
|
||||
defer m.Cost("%v exit: %v out: %v err: %v ", cmd.Args, 0, out.Len(), err.Len())
|
||||
if e := cmd.Run(); !m.Warn(e != nil, "%v run: %s", cmd.Args, kit.Select(e.Error(), err.String())) {
|
||||
if e := cmd.Run(); e != nil {
|
||||
m.Warn(e != nil, "%v run: %s", cmd.Args, kit.Select(e.Error(), err.String()))
|
||||
}
|
||||
|
||||
m.Push(CMD_CODE, int(cmd.ProcessState.ExitCode()))
|
||||
|
@ -40,9 +40,6 @@ func _config_list(m *ice.Message, all bool) {
|
||||
func _config_save(m *ice.Message, name string, arg ...string) {
|
||||
msg := m.Spawn(m.Source())
|
||||
// 保存配置
|
||||
if m.Cap(ice.CTX_STATUS) != ice.ICE_START {
|
||||
return
|
||||
}
|
||||
name = path.Join(msg.Conf(ice.CTX_CONFIG, "meta.path"), name)
|
||||
if f, p, e := kit.Create(name); m.Assert(e) {
|
||||
data := map[string]interface{}{}
|
||||
|
@ -2,6 +2,7 @@ package ssh
|
||||
|
||||
import (
|
||||
"github.com/shylinux/icebergs"
|
||||
"github.com/shylinux/icebergs/base/aaa"
|
||||
"github.com/shylinux/toolkits"
|
||||
|
||||
"bufio"
|
||||
@ -178,6 +179,7 @@ func (f *Frame) Begin(m *ice.Message, arg ...string) ice.Server {
|
||||
func (f *Frame) Start(m *ice.Message, arg ...string) bool {
|
||||
m.Option(ice.MSG_PROMPT, m.Confv("prompt", "meta.PS1"))
|
||||
f.target = m.Source()
|
||||
aaa.UserRoot(m)
|
||||
|
||||
switch kit.Select("stdio", arg, 0) {
|
||||
case "stdio":
|
||||
|
@ -57,7 +57,7 @@ func _ip_islocal(m *ice.Message, ip string) (ok bool) {
|
||||
})
|
||||
return ok
|
||||
}
|
||||
func _tcp_port(m *ice.Message) {
|
||||
func _tcp_port(m *ice.Message) string {
|
||||
current := kit.Int(m.Conf(GETPORT, "meta.current"))
|
||||
end := kit.Int(m.Conf(GETPORT, "meta.end"))
|
||||
if current >= end {
|
||||
@ -67,15 +67,19 @@ func _tcp_port(m *ice.Message) {
|
||||
if m.Cmd(cli.SYSTEM, "lsof", "-i", kit.Format(":%d", i)).Append(cli.CMD_CODE) != "0" {
|
||||
m.Conf(GETPORT, "meta.current", i)
|
||||
m.Log_CREATE(GETPORT, i)
|
||||
m.Echo("%d", i)
|
||||
return kit.Format("%d", i)
|
||||
break
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func IPIsLocal(m *ice.Message, ip string) bool {
|
||||
return _ip_islocal(m, ip)
|
||||
}
|
||||
func TCPPort(m *ice.Message) string {
|
||||
return _tcp_port(m)
|
||||
}
|
||||
|
||||
var Index = &ice.Context{Name: "tcp", Help: "通信模块",
|
||||
Caches: map[string]*ice.Cache{},
|
||||
@ -92,7 +96,7 @@ var Index = &ice.Context{Name: "tcp", Help: "通信模块",
|
||||
_ip_list(m, "")
|
||||
}},
|
||||
GETPORT: {Name: "getport", Help: "分配端口", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
_tcp_port(m)
|
||||
m.Echo(_tcp_port(m))
|
||||
}},
|
||||
|
||||
"ip": {Name: "ifconfig [name]", Help: "网络配置", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
|
@ -101,6 +101,12 @@ func _cache_watch(m *ice.Message, key, file string) {
|
||||
}
|
||||
|
||||
func _cache_catch(m *ice.Message, arg ...string) []string {
|
||||
if r, ok := m.Optionv("response").(*http.Response); ok {
|
||||
return _cache_download(m, r, arg...)
|
||||
} else if m.R != nil {
|
||||
return _cache_upload(m, arg...)
|
||||
}
|
||||
|
||||
if f, e := os.Open(arg[2]); m.Assert(e) {
|
||||
defer f.Close()
|
||||
|
||||
@ -188,16 +194,9 @@ func init() {
|
||||
}
|
||||
|
||||
switch arg[0] {
|
||||
case "catch":
|
||||
case "download", "upload", "catch":
|
||||
arg = _cache_catch(m, arg...)
|
||||
fallthrough
|
||||
case "download", "upload":
|
||||
if r, ok := m.Optionv("response").(*http.Response); ok {
|
||||
arg = _cache_download(m, r, arg...)
|
||||
} else if m.R != nil {
|
||||
arg = _cache_upload(m, arg...)
|
||||
}
|
||||
fallthrough
|
||||
case "add":
|
||||
_cache_save(m, arg[0], arg[1], arg[2], arg[3], arg[4:]...)
|
||||
case "watch":
|
||||
|
87
base/web/dream.go
Normal file
87
base/web/dream.go
Normal file
@ -0,0 +1,87 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
ice "github.com/shylinux/icebergs"
|
||||
kit "github.com/shylinux/toolkits"
|
||||
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Index.Merge(&ice.Context{
|
||||
Configs: map[string]*ice.Config{
|
||||
ice.WEB_DREAM: {Name: "dream", Help: "梦想家", Value: kit.Data("path", "usr/local/work",
|
||||
// "cmd", []interface{}{ice.CLI_SYSTEM, "ice.sh", "start", ice.WEB_SPACE, "connect"},
|
||||
"cmd", []interface{}{ice.CLI_SYSTEM, "ice.bin", ice.WEB_SPACE, "connect"},
|
||||
)},
|
||||
},
|
||||
Commands: map[string]*ice.Command{
|
||||
ice.WEB_DREAM: {Name: "dream name auto", Help: "梦想家", Meta: kit.Dict(
|
||||
"exports", []string{"you", "name"}, "detail", []interface{}{"启动", "停止"},
|
||||
), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
if len(arg) > 1 && arg[0] == "action" {
|
||||
switch arg[1] {
|
||||
case "启动", "start":
|
||||
arg = []string{arg[4]}
|
||||
case "停止", "stop":
|
||||
m.Cmd(ice.WEB_SPACE, kit.Select(m.Option("name"), arg, 4), "exit", "1")
|
||||
m.Event(ice.DREAM_CLOSE, arg[4])
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if len(arg) == 0 {
|
||||
// 任务列表
|
||||
m.Cmdy("nfs.dir", m.Conf(ice.WEB_DREAM, "meta.path"), "time name")
|
||||
m.Table(func(index int, value map[string]string, head []string) {
|
||||
if m.Richs(ice.WEB_SPACE, nil, value["name"], func(key string, value map[string]interface{}) {
|
||||
m.Push("type", value["type"])
|
||||
m.Push("status", "start")
|
||||
}) == nil {
|
||||
m.Push("type", "none")
|
||||
m.Push("status", "stop")
|
||||
}
|
||||
})
|
||||
m.Sort("name")
|
||||
m.Sort("status")
|
||||
return
|
||||
}
|
||||
|
||||
// 规范命名
|
||||
if !strings.Contains(arg[0], "-") || !strings.HasPrefix(arg[0], "20") {
|
||||
arg[0] = m.Time("20060102-") + arg[0]
|
||||
}
|
||||
|
||||
// 创建目录
|
||||
p := path.Join(m.Conf(ice.WEB_DREAM, "meta.path"), arg[0])
|
||||
os.MkdirAll(p, 0777)
|
||||
|
||||
if b, e := ioutil.ReadFile(path.Join(p, m.Conf(ice.GDB_SIGNAL, "meta.pid"))); e == nil {
|
||||
if s, e := os.Stat("/proc/" + string(b)); e == nil && s.IsDir() {
|
||||
m.Info("already exists %v", string(b))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if m.Richs(ice.WEB_SPACE, nil, arg[0], nil) == nil {
|
||||
// 启动任务
|
||||
m.Option("cmd_dir", p)
|
||||
m.Option("cmd_type", "daemon")
|
||||
m.Optionv("cmd_env",
|
||||
"ctx_dev", m.Conf(ice.CLI_RUNTIME, "conf.ctx_dev"),
|
||||
"ctx_log", "boot.log", "ctx_mod", "ctx,log,gdb,ssh",
|
||||
"PATH", kit.Path(path.Join(p, "bin"))+":"+os.Getenv("PATH"),
|
||||
)
|
||||
m.Cmd(m.Confv(ice.WEB_DREAM, "meta.cmd"), "self", arg[0])
|
||||
time.Sleep(time.Second * 1)
|
||||
m.Event(ice.DREAM_START, arg...)
|
||||
}
|
||||
m.Cmdy("nfs.dir", p)
|
||||
}},
|
||||
},
|
||||
}, nil)
|
||||
}
|
245
base/web/serve.go
Normal file
245
base/web/serve.go
Normal file
@ -0,0 +1,245 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
ice "github.com/shylinux/icebergs"
|
||||
"github.com/shylinux/icebergs/base/aaa"
|
||||
"github.com/shylinux/icebergs/base/cli"
|
||||
"github.com/shylinux/icebergs/base/tcp"
|
||||
kit "github.com/shylinux/toolkits"
|
||||
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func Login(msg *ice.Message, w http.ResponseWriter, r *http.Request) bool {
|
||||
msg.Option(ice.MSG_USERNAME, "")
|
||||
msg.Option(ice.MSG_USERROLE, "")
|
||||
|
||||
if msg.Options(ice.MSG_SESSID) {
|
||||
// 会话认证
|
||||
aaa.SessCheck(msg, msg.Option(ice.MSG_SESSID))
|
||||
}
|
||||
|
||||
if !msg.Options(ice.MSG_USERNAME) && tcp.IPIsLocal(msg, msg.Option(ice.MSG_USERIP)) {
|
||||
// 自动认证
|
||||
if aaa.UserLogin(msg, cli.UserName, cli.PassWord) {
|
||||
Render(msg, "cookie", msg.Option(ice.MSG_SESSID))
|
||||
}
|
||||
}
|
||||
|
||||
if s, ok := msg.Target().Commands[ice.WEB_LOGIN]; ok {
|
||||
// 权限检查
|
||||
msg.Target().Run(msg, s, ice.WEB_LOGIN, kit.Simple(msg.Optionv("cmds"))...)
|
||||
|
||||
} else if ls := strings.Split(msg.Option(ice.MSG_USERURL), "/"); msg.Conf(SERVE, kit.Keys("meta.black", ls[1])) == "true" {
|
||||
return false // black
|
||||
|
||||
} else if msg.Conf(SERVE, kit.Keys("meta.white", ls[1])) == "true" {
|
||||
return true // white
|
||||
|
||||
} else {
|
||||
if msg.Warn(!msg.Options(ice.MSG_USERNAME), "not login %s", msg.Option(ice.MSG_USERURL)) {
|
||||
msg.Render("status", 401, "not login")
|
||||
return false
|
||||
}
|
||||
if !msg.Right(msg.Option(ice.MSG_USERURL)) {
|
||||
msg.Render("status", 403, "not auth")
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return msg.Option(ice.MSG_USERURL) != ""
|
||||
}
|
||||
func Trans(web *Frame, m *ice.Message, key string, cmd *ice.Command) {
|
||||
web.HandleFunc(key, func(w http.ResponseWriter, r *http.Request) {
|
||||
m.TryCatch(m.Spawns(), true, func(msg *ice.Message) {
|
||||
defer func() { msg.Cost("%s %v %v", r.URL.Path, msg.Optionv("cmds"), msg.Format("append")) }()
|
||||
if u, e := url.Parse(r.Header.Get("Referer")); e == nil {
|
||||
for k, v := range u.Query() {
|
||||
msg.Logs("refer", k, v)
|
||||
msg.Option(k, v)
|
||||
}
|
||||
}
|
||||
|
||||
// 用户请求
|
||||
msg.Option(ice.MSG_USERWEB, m.Conf(SHARE, "meta.domain"))
|
||||
msg.Option(ice.MSG_USERIP, r.Header.Get(ice.MSG_USERIP))
|
||||
msg.Option(ice.MSG_USERUA, r.Header.Get("User-Agent"))
|
||||
msg.Option(ice.MSG_USERURL, r.URL.Path)
|
||||
if msg.R, msg.W = r, w; r.Header.Get("X-Real-Port") != "" {
|
||||
msg.Option(ice.MSG_USERADDR, msg.Option(ice.MSG_USERIP)+":"+r.Header.Get("X-Real-Port"))
|
||||
} else {
|
||||
msg.Option(ice.MSG_USERADDR, r.RemoteAddr)
|
||||
}
|
||||
|
||||
// 请求变量
|
||||
msg.Option(ice.MSG_SESSID, "")
|
||||
msg.Option(ice.MSG_OUTPUT, "")
|
||||
for _, v := range r.Cookies() {
|
||||
msg.Option(v.Name, v.Value)
|
||||
}
|
||||
|
||||
// 解析引擎
|
||||
switch r.Header.Get("Content-Type") {
|
||||
case "application/json":
|
||||
var data interface{}
|
||||
if e := json.NewDecoder(r.Body).Decode(&data); !msg.Warn(e != nil, "%s", e) {
|
||||
msg.Optionv(ice.MSG_USERDATA, data)
|
||||
msg.Logs("json", "value", kit.Formats(data))
|
||||
}
|
||||
|
||||
switch d := data.(type) {
|
||||
case map[string]interface{}:
|
||||
for k, v := range d {
|
||||
msg.Optionv(k, v)
|
||||
}
|
||||
}
|
||||
default:
|
||||
r.ParseMultipartForm(kit.Int64(kit.Select(r.Header.Get("Content-Length"), "4096")))
|
||||
if r.ParseForm(); len(r.PostForm) > 0 {
|
||||
for k, v := range r.PostForm {
|
||||
msg.Logs("form", k, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 请求参数
|
||||
for k, v := range r.Form {
|
||||
if msg.Optionv(k, v); k == ice.MSG_SESSID {
|
||||
msg.Render("cookie", v[0])
|
||||
}
|
||||
}
|
||||
|
||||
// 请求命令
|
||||
if msg.Option(ice.MSG_USERPOD, msg.Option("pod")); msg.Optionv("cmds") == nil {
|
||||
if p := strings.TrimPrefix(msg.Option(ice.MSG_USERURL), key); p != "" {
|
||||
msg.Optionv("cmds", strings.Split(p, "/"))
|
||||
}
|
||||
}
|
||||
|
||||
// 执行命令
|
||||
if cmds := kit.Simple(msg.Optionv("cmds")); Login(msg, w, r) {
|
||||
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{})
|
||||
Render(msg, msg.Option(ice.MSG_OUTPUT), _args...)
|
||||
})
|
||||
})
|
||||
}
|
||||
func (web *Frame) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
m := web.m
|
||||
|
||||
if r.Header.Get("index.module") == "" {
|
||||
// 解析地址
|
||||
if ip := r.Header.Get("X-Forwarded-For"); ip != "" {
|
||||
r.Header.Set(ice.MSG_USERIP, ip)
|
||||
} else if ip := r.Header.Get("X-Real-Ip"); ip != "" {
|
||||
r.Header.Set(ice.MSG_USERIP, ip)
|
||||
} else if strings.HasPrefix(r.RemoteAddr, "[") {
|
||||
r.Header.Set(ice.MSG_USERIP, strings.Split(r.RemoteAddr, "]")[0][1:])
|
||||
} else {
|
||||
r.Header.Set(ice.MSG_USERIP, strings.Split(r.RemoteAddr, ":")[0])
|
||||
}
|
||||
m.Info("").Info("%s %s %s", r.Header.Get(ice.MSG_USERIP), r.Method, r.URL)
|
||||
|
||||
r.Header.Set("index.module", m.Target().Name)
|
||||
r.Header.Set("index.path", r.URL.Path)
|
||||
r.Header.Set("index.url", r.URL.String())
|
||||
|
||||
if m.Conf(SERVE, "meta.logheaders") == "true" {
|
||||
// 请求参数
|
||||
for k, v := range r.Header {
|
||||
m.Info("%s: %v", k, kit.Format(v))
|
||||
}
|
||||
m.Info(" ")
|
||||
|
||||
defer func() {
|
||||
// 响应参数
|
||||
for k, v := range w.Header() {
|
||||
m.Info("%s: %v", k, kit.Format(v))
|
||||
}
|
||||
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(SERVE, "meta.init") != "true" {
|
||||
if _, e := os.Stat(m.Conf(SERVE, "meta.volcanos.path")); e == nil {
|
||||
// 初始化成功
|
||||
m.Conf(SERVE, "meta.init", "true")
|
||||
}
|
||||
m.W = w
|
||||
Render(m, "refresh", m.Conf(SERVE, "meta.volcanos.refresh"))
|
||||
m.Event(ice.SYSTEM_INIT)
|
||||
m.W = nil
|
||||
} else if r.URL.Path == "/share" && r.Method == "GET" {
|
||||
http.ServeFile(w, r, m.Conf(SERVE, "meta.page.share"))
|
||||
} else {
|
||||
web.ServeMux.ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
func init() {
|
||||
Index.Merge(&ice.Context{
|
||||
Configs: map[string]*ice.Config{
|
||||
ice.WEB_SERVE: {Name: "serve", Help: "服务器", Value: kit.Data(
|
||||
"init", "false", "logheaders", "false",
|
||||
"black", kit.Dict(),
|
||||
"white", kit.Dict(
|
||||
"login", true,
|
||||
"share", true,
|
||||
"space", true,
|
||||
"route", true,
|
||||
"static", true,
|
||||
"plugin", true,
|
||||
"publish", true,
|
||||
),
|
||||
|
||||
"title", "github.com/shylinux/contexts",
|
||||
"legal", []interface{}{`<a href="mailto:shylinuxc@gmail.com">shylinuxc@gmail.com</a>`},
|
||||
|
||||
"static", kit.Dict("/", "usr/volcanos/"),
|
||||
"volcanos", kit.Dict("path", "usr/volcanos", "branch", "master",
|
||||
"repos", "https://github.com/shylinux/volcanos",
|
||||
"require", ".ish/pluged",
|
||||
"refresh", "5",
|
||||
), "page", kit.Dict(
|
||||
"index", "usr/volcanos/page/index.html",
|
||||
"share", "usr/volcanos/page/share.html",
|
||||
), "publish", "usr/publish/",
|
||||
|
||||
"template", kit.Dict("path", "usr/template", "list", []interface{}{
|
||||
`{{define "raw"}}{{.Result}}{{end}}`,
|
||||
}),
|
||||
)},
|
||||
},
|
||||
Commands: map[string]*ice.Command{
|
||||
ice.WEB_SERVE: {Name: "serve [random] [ups...]", Help: "服务器", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
if cli.NodeType(m, ice.WEB_SERVER, cli.HostName); len(arg) > 0 && arg[0] == "random" {
|
||||
cli.NodeType(m, ice.WEB_SERVER, cli.PathName)
|
||||
// 随机端口
|
||||
SpideCreate(m, "self", "http://random")
|
||||
arg = arg[1:]
|
||||
}
|
||||
|
||||
// 启动服务
|
||||
m.Target().Start(m, "self")
|
||||
defer m.Cmd(ice.WEB_SPACE, "connect", "self")
|
||||
m.Sleep("1s")
|
||||
|
||||
// 连接服务
|
||||
for _, k := range arg {
|
||||
m.Cmd(ice.WEB_SPACE, "connect", k)
|
||||
}
|
||||
}},
|
||||
}}, nil)
|
||||
}
|
@ -10,8 +10,6 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
var SHARE = ice.Name(kit.MDB_SHARE, Index)
|
||||
|
||||
func _share_list(m *ice.Message, key string, fields ...string) {
|
||||
if key == "" {
|
||||
m.Grows(SHARE, nil, "", "", func(index int, value map[string]interface{}) {
|
||||
@ -85,7 +83,7 @@ func _share_remote(m *ice.Message, pod string, arg ...string) {
|
||||
m.Cmdy(ice.WEB_SPACE, pod, "web./publish/", arg)
|
||||
m.Render(ice.RENDER_RESULT)
|
||||
}
|
||||
func _share_create(m *ice.Message, kind, name, text string, arg ...string) {
|
||||
func _share_create(m *ice.Message, kind, name, text string, arg ...string) string {
|
||||
for _, k := range []string{"river", "storm"} {
|
||||
arg = append(arg, k, m.Option(k))
|
||||
}
|
||||
@ -103,6 +101,7 @@ func _share_create(m *ice.Message, kind, name, text string, arg ...string) {
|
||||
))
|
||||
m.Log_CREATE(kit.MDB_SHARE, h, kit.MDB_TYPE, kind, kit.MDB_NAME, name)
|
||||
m.Echo(h)
|
||||
return h
|
||||
}
|
||||
|
||||
func _share_story(m *ice.Message, value map[string]interface{}, arg ...string) map[string]interface{} {
|
||||
@ -221,6 +220,11 @@ func _trash(m *ice.Message, arg ...string) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ShareCreate(m *ice.Message, kind, name, text string, arg ...string) string {
|
||||
return _share_create(m, kind, name, text, arg...)
|
||||
}
|
||||
|
||||
func init() {
|
||||
Index.Merge(&ice.Context{
|
||||
Configs: map[string]*ice.Config{
|
||||
|
@ -58,7 +58,7 @@ func _space_dial(m *ice.Message, dev, name string, arg ...string) {
|
||||
"socket", s,
|
||||
))
|
||||
msg.Log(ice.LOG_CMDS, "%d conn %s success %s", i, dev, u)
|
||||
if i = 0; web.HandleWSS(msg, true, s, dev) {
|
||||
if i = 0; HandleWSS(msg, true, web.send, s, dev) {
|
||||
break
|
||||
}
|
||||
}
|
||||
@ -112,6 +112,70 @@ func _space_send(m *ice.Message, space string, arg ...string) {
|
||||
}) == nil, "not found %s", space)
|
||||
}
|
||||
|
||||
func HandleWSS(m *ice.Message, safe bool, send map[string]*ice.Message, c *websocket.Conn, name string) bool {
|
||||
for running := true; running; {
|
||||
if t, b, e := c.ReadMessage(); m.Warn(e != nil, "space recv %d msg %v", t, e) {
|
||||
// 解析失败
|
||||
break
|
||||
} else {
|
||||
socket, msg := c, m.Spawns(b)
|
||||
target := kit.Simple(msg.Optionv(ice.MSG_TARGET))
|
||||
source := kit.Simple(msg.Optionv(ice.MSG_SOURCE), name)
|
||||
msg.Info("recv %v<-%v %s %v", target, source, msg.Detailv(), msg.Format("meta"))
|
||||
|
||||
if len(target) == 0 {
|
||||
msg.Option(ice.MSG_USERROLE, msg.Cmdx(ice.AAA_ROLE, "check", msg.Option(ice.MSG_USERNAME)))
|
||||
msg.Logs(ice.LOG_AUTH, "role", msg.Option(ice.MSG_USERROLE), "user", msg.Option(ice.MSG_USERNAME))
|
||||
if msg.Optionv(ice.MSG_HANDLE, "true"); !msg.Warn(!safe, "no right") {
|
||||
// 本地执行
|
||||
m.Option("_dev", name)
|
||||
msg = msg.Cmd()
|
||||
msg.Set("_option")
|
||||
msg.Set("_option")
|
||||
}
|
||||
if source, target = []string{}, kit.Revert(source)[1:]; msg.Detail() == "exit" {
|
||||
// 重启进程
|
||||
return true
|
||||
}
|
||||
} else if msg.Richs(ice.WEB_SPACE, nil, target[0], func(key string, value map[string]interface{}) {
|
||||
// 查询节点
|
||||
if s, ok := value["socket"].(*websocket.Conn); ok {
|
||||
socket, source, target = s, source, target[1:]
|
||||
} else {
|
||||
socket, source, target = s, source, target[1:]
|
||||
}
|
||||
}) != nil {
|
||||
// 转发报文
|
||||
|
||||
} else if res, ok := send[msg.Option(ice.MSG_TARGET)]; len(target) == 1 && ok {
|
||||
// 接收响应
|
||||
delete(send, msg.Option(ice.MSG_TARGET))
|
||||
res.Cost("%v->%v %v %v", target, source, res.Detailv(), msg.Format("append"))
|
||||
res.Back(msg)
|
||||
continue
|
||||
|
||||
} else if msg.Warn(msg.Option("_handle") == "true", "space miss") {
|
||||
// 回复失败
|
||||
continue
|
||||
|
||||
} else {
|
||||
// 下发失败
|
||||
msg.Warn(true, "space error")
|
||||
source, target = []string{}, kit.Revert(source)[1:]
|
||||
}
|
||||
|
||||
// 发送报文
|
||||
msg.Optionv(ice.MSG_SOURCE, source)
|
||||
msg.Optionv(ice.MSG_TARGET, target)
|
||||
socket.WriteMessage(t, []byte(msg.Format("meta")))
|
||||
target = append([]string{name}, target...)
|
||||
msg.Info("send %v %v->%v %v %v", t, source, target, msg.Detailv(), msg.Format("meta"))
|
||||
msg.Cost("%v->%v %v %v", source, target, msg.Detailv(), msg.Format("append"))
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func init() {
|
||||
Index.Merge(&ice.Context{
|
||||
Configs: map[string]*ice.Config{
|
||||
@ -180,7 +244,7 @@ func init() {
|
||||
m.Gos(m, func(m *ice.Message) {
|
||||
// 监听消息
|
||||
m.Event(ice.SPACE_START, m.Option("node"), m.Option("name"))
|
||||
m.Target().Server().(*Frame).HandleWSS(m, false, s, m.Option("name"))
|
||||
HandleWSS(m, false, m.Target().Server().(*Frame).send, s, m.Option("name"))
|
||||
m.Log(ice.LOG_CLOSE, "%s: %s", m.Option(kit.MDB_NAME), kit.Format(m.Confv(ice.WEB_SPACE, kit.Keys(kit.MDB_HASH, h))))
|
||||
m.Event(ice.SPACE_CLOSE, m.Option("node"), m.Option("name"))
|
||||
m.Confv(ice.WEB_SPACE, kit.Keys(kit.MDB_HASH, h), "")
|
||||
|
273
base/web/spide.go
Normal file
273
base/web/spide.go
Normal file
@ -0,0 +1,273 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
ice "github.com/shylinux/icebergs"
|
||||
"github.com/shylinux/icebergs/base/tcp"
|
||||
kit "github.com/shylinux/toolkits"
|
||||
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func _spide_list(m *ice.Message, name string) {
|
||||
if name == "" {
|
||||
m.Richs(SPIDE, nil, kit.MDB_FOREACH, func(key string, value map[string]interface{}) {
|
||||
m.Push(key, value["client"], []string{"name", "share", "login", "method", "url"})
|
||||
})
|
||||
m.Sort("name")
|
||||
return
|
||||
}
|
||||
|
||||
m.Richs(SPIDE, nil, name, func(key string, value map[string]interface{}) {
|
||||
m.Push("detail", value)
|
||||
if kit.Value(value, "client.share") != nil {
|
||||
m.Push("key", "share")
|
||||
m.Push("value", fmt.Sprintf(m.Conf(SHARE, "meta.template.text"), m.Conf(SHARE, "meta.domain"), kit.Value(value, "client.share")))
|
||||
}
|
||||
})
|
||||
}
|
||||
func _spide_show(m *ice.Message, name string) {
|
||||
}
|
||||
func _spide_login(m *ice.Message, name string) {
|
||||
m.Richs(SPIDE, nil, name, func(key string, value map[string]interface{}) {
|
||||
msg := m.Cmd(SPIDE, name, "msg", "/route/login", "login")
|
||||
if msg.Append(ice.MSG_USERNAME) != "" {
|
||||
m.Echo(msg.Append(ice.MSG_USERNAME))
|
||||
return
|
||||
}
|
||||
if msg.Result() != "" {
|
||||
kit.Value(value, "client.login", msg.Result())
|
||||
kit.Value(value, "client.share", m.Cmdx(SHARE, ice.TYPE_SPIDE, name,
|
||||
kit.Format("%s?sessid=%s", kit.Value(value, "client.url"), kit.Value(value, "cookie.sessid"))))
|
||||
}
|
||||
m.Render(ice.RENDER_QRCODE, kit.Dict(
|
||||
kit.MDB_TYPE, "login", kit.MDB_NAME, name,
|
||||
kit.MDB_TEXT, kit.Value(value, "cookie.sessid"),
|
||||
))
|
||||
})
|
||||
}
|
||||
func _spide_create(m *ice.Message, name, address string, arg ...string) {
|
||||
if uri, e := url.Parse(address); e == nil && address != "" {
|
||||
if uri.Host == "random" {
|
||||
uri.Host = ":" + tcp.TCPPort(m)
|
||||
address = strings.Replace(address, "random", uri.Host, -1)
|
||||
}
|
||||
|
||||
if m.Richs(SPIDE, nil, name, func(key string, value map[string]interface{}) {
|
||||
kit.Value(value, "client.hostname", uri.Host)
|
||||
kit.Value(value, "client.url", address)
|
||||
}) == nil {
|
||||
dir, file := path.Split(uri.EscapedPath())
|
||||
m.Rich(SPIDE, nil, kit.Dict(
|
||||
"cookie", kit.Dict(), "header", kit.Dict(), "client", kit.Dict(
|
||||
"share", ShareCreate(m.Spawn(), ice.TYPE_SPIDE, name, address),
|
||||
"name", name, "url", address, "method", "POST",
|
||||
"protocol", uri.Scheme, "hostname", uri.Host,
|
||||
"path", dir, "file", file, "query", uri.RawQuery,
|
||||
"timeout", "100s", "logheaders", false,
|
||||
),
|
||||
))
|
||||
}
|
||||
m.Log_CREATE(SPIDE, name, "address", address)
|
||||
}
|
||||
}
|
||||
|
||||
func SpideCreate(m *ice.Message, name, address string, arg ...string) {
|
||||
_spide_create(m, name, address, arg...)
|
||||
}
|
||||
func init() {
|
||||
Index.Merge(&ice.Context{
|
||||
Configs: map[string]*ice.Config{
|
||||
SPIDE: {Name: "spide", Help: "蜘蛛侠", Value: kit.Data(kit.MDB_SHORT, "client.name")},
|
||||
},
|
||||
Commands: map[string]*ice.Command{
|
||||
SPIDE: {Name: "spide name=auto [action:select=msg|raw|cache] [method:select=POST|GET] url [format:select=json|form|part|data|file] arg... auto", Help: "蜘蛛侠", Action: map[string]*ice.Action{
|
||||
kit.MDB_CREATE: {Name: "create name address", Help: "", Hand: func(m *ice.Message, arg ...string) {
|
||||
_spide_create(m, arg[0], arg[1])
|
||||
}},
|
||||
"login": {Name: "login name", Help: "", Hand: func(m *ice.Message, arg ...string) {
|
||||
_spide_login(m, arg[0])
|
||||
}},
|
||||
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
if len(arg) < 2 || len(arg) > 3 && arg[3] == "" {
|
||||
_spide_list(m, kit.Select("", arg, 1))
|
||||
return
|
||||
}
|
||||
|
||||
m.Richs(SPIDE, nil, arg[0], func(key string, value map[string]interface{}) {
|
||||
client := value["client"].(map[string]interface{})
|
||||
// 缓存数据
|
||||
cache := ""
|
||||
switch arg[1] {
|
||||
case "raw":
|
||||
cache, arg = arg[1], arg[1:]
|
||||
case "msg":
|
||||
cache, arg = arg[1], arg[1:]
|
||||
case "cache":
|
||||
cache, arg = arg[1], arg[1:]
|
||||
}
|
||||
|
||||
// 请求方法
|
||||
method := kit.Select("POST", client["method"])
|
||||
switch arg = arg[1:]; arg[0] {
|
||||
case "POST":
|
||||
method, arg = "POST", arg[1:]
|
||||
case "GET":
|
||||
method, arg = "GET", arg[1:]
|
||||
}
|
||||
|
||||
// 请求地址
|
||||
uri, arg := arg[0], arg[1:]
|
||||
|
||||
// 渲染引擎
|
||||
head := map[string]string{}
|
||||
body, ok := m.Optionv("body").(io.Reader)
|
||||
if !ok && len(arg) > 0 && method != "GET" {
|
||||
switch arg[0] {
|
||||
case "file":
|
||||
if f, e := os.Open(arg[1]); m.Warn(e != nil, "%s", e) {
|
||||
return
|
||||
} else {
|
||||
defer f.Close()
|
||||
body, arg = f, arg[2:]
|
||||
}
|
||||
case "data":
|
||||
body, arg = bytes.NewBufferString(arg[1]), arg[2:]
|
||||
case "part":
|
||||
buf := &bytes.Buffer{}
|
||||
mp := multipart.NewWriter(buf)
|
||||
for i := 1; i < len(arg)-1; i += 2 {
|
||||
if strings.HasPrefix(arg[i+1], "@") {
|
||||
if f, e := os.Open(arg[i+1][1:]); m.Assert(e) {
|
||||
defer f.Close()
|
||||
if p, e := mp.CreateFormFile(arg[i], path.Base(arg[i+1][1:])); m.Assert(e) {
|
||||
io.Copy(p, f)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mp.WriteField(arg[i], arg[i+1])
|
||||
}
|
||||
}
|
||||
mp.Close()
|
||||
head["Content-Type"] = mp.FormDataContentType()
|
||||
body = buf
|
||||
case "form":
|
||||
data := []string{}
|
||||
for i := 1; i < len(arg)-1; i += 2 {
|
||||
data = append(data, url.QueryEscape(arg[i])+"="+url.QueryEscape(arg[i+1]))
|
||||
}
|
||||
body = bytes.NewBufferString(strings.Join(data, "&"))
|
||||
head["Content-Type"] = "application/x-www-form-urlencoded"
|
||||
case "json":
|
||||
arg = arg[1:]
|
||||
fallthrough
|
||||
default:
|
||||
data := map[string]interface{}{}
|
||||
for i := 0; i < len(arg)-1; i += 2 {
|
||||
kit.Value(data, arg[i], arg[i+1])
|
||||
}
|
||||
if b, e := json.Marshal(data); m.Assert(e) {
|
||||
head["Content-Type"] = "application/json"
|
||||
body = bytes.NewBuffer(b)
|
||||
}
|
||||
m.Log(ice.LOG_EXPORT, "json: %s", kit.Format(data))
|
||||
}
|
||||
arg = arg[:0]
|
||||
} else {
|
||||
body = bytes.NewBuffer([]byte{})
|
||||
}
|
||||
|
||||
// 请求地址
|
||||
uri = kit.MergeURL2(kit.Format(client["url"]), uri, arg)
|
||||
req, e := http.NewRequest(method, uri, body)
|
||||
m.Info("%s %s", req.Method, req.URL)
|
||||
m.Assert(e)
|
||||
|
||||
// 请求变量
|
||||
kit.Fetch(value["cookie"], func(key string, value string) {
|
||||
req.AddCookie(&http.Cookie{Name: key, Value: value})
|
||||
m.Info("%s: %s", key, value)
|
||||
})
|
||||
kit.Fetch(value["header"], func(key string, value string) {
|
||||
req.Header.Set(key, value)
|
||||
})
|
||||
list := kit.Simple(m.Optionv("header"))
|
||||
for i := 0; i < len(list)-1; i += 2 {
|
||||
req.Header.Set(list[i], list[i+1])
|
||||
}
|
||||
for k, v := range head {
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
|
||||
// 请求代理
|
||||
web := m.Target().Server().(*Frame)
|
||||
if web.Client == nil {
|
||||
web.Client = &http.Client{Timeout: kit.Duration(kit.Format(client["timeout"]))}
|
||||
}
|
||||
if method == "POST" {
|
||||
m.Info("%s: %s", req.Header.Get("Content-Length"), req.Header.Get("Content-Type"))
|
||||
}
|
||||
|
||||
// 发送请求
|
||||
res, e := web.Client.Do(req)
|
||||
if m.Warn(e != nil, "%s", e) {
|
||||
return
|
||||
}
|
||||
|
||||
// 检查结果
|
||||
if m.Cost("%s %s: %s", res.Status, res.Header.Get("Content-Length"), res.Header.Get("Content-Type")); m.Warn(res.StatusCode != http.StatusOK, "%s", res.Status) {
|
||||
return
|
||||
}
|
||||
|
||||
// 缓存变量
|
||||
for _, v := range res.Cookies() {
|
||||
kit.Value(value, "cookie."+v.Name, v.Value)
|
||||
m.Log(ice.LOG_IMPORT, "%s: %s", v.Name, v.Value)
|
||||
}
|
||||
|
||||
// 解析引擎
|
||||
switch cache {
|
||||
case "cache":
|
||||
m.Optionv("response", res)
|
||||
CacheCatch(m, 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))
|
||||
}
|
||||
case "msg":
|
||||
var data map[string][]string
|
||||
m.Assert(json.NewDecoder(res.Body).Decode(&data))
|
||||
m.Info("res: %s", kit.Formats(data))
|
||||
for _, k := range data[ice.MSG_APPEND] {
|
||||
for i := range data[k] {
|
||||
m.Push(k, data[k][i])
|
||||
}
|
||||
}
|
||||
m.Resultv(data[ice.MSG_RESULT])
|
||||
default:
|
||||
if strings.HasPrefix(res.Header.Get("Content-Type"), "text/html") {
|
||||
b, _ := ioutil.ReadAll(res.Body)
|
||||
m.Echo(string(b))
|
||||
break
|
||||
}
|
||||
|
||||
var data interface{}
|
||||
m.Assert(json.NewDecoder(res.Body).Decode(&data))
|
||||
data = kit.KeyValue(map[string]interface{}{}, "", data)
|
||||
m.Info("res: %s", kit.Formats(data))
|
||||
m.Push("", data)
|
||||
}
|
||||
})
|
||||
}},
|
||||
}}, nil)
|
||||
}
|
685
base/web/web.go
685
base/web/web.go
@ -1,31 +1,23 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"github.com/gorilla/websocket"
|
||||
ice "github.com/shylinux/icebergs"
|
||||
"github.com/shylinux/icebergs/base/aaa"
|
||||
"github.com/shylinux/icebergs/base/cli"
|
||||
"github.com/shylinux/icebergs/base/tcp"
|
||||
kit "github.com/shylinux/toolkits"
|
||||
"github.com/skip2/go-qrcode"
|
||||
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"sync"
|
||||
"text/template"
|
||||
"time"
|
||||
)
|
||||
|
||||
var SERVE = ice.Name("serve", Index)
|
||||
const (
|
||||
SPIDE = "spide"
|
||||
SERVE = "serve"
|
||||
SHARE = "share"
|
||||
)
|
||||
|
||||
type Frame struct {
|
||||
*http.Client
|
||||
@ -99,306 +91,6 @@ func Render(msg *ice.Message, cmd string, args ...interface{}) {
|
||||
}
|
||||
msg.Append(ice.MSG_OUTPUT, ice.RENDER_OUTPUT)
|
||||
}
|
||||
func IsLocalIP(msg *ice.Message, ip string) (ok bool) {
|
||||
if ip == "::1" || strings.HasPrefix(ip, "127.") {
|
||||
return true
|
||||
}
|
||||
|
||||
msg.Log_AUTH("ip", ip)
|
||||
if msg.Richs(SERVE, kit.Keys("meta.white"), ip, nil) != nil {
|
||||
msg.Log_AUTH("ip", ip)
|
||||
return true
|
||||
}
|
||||
|
||||
msg.Cmd("tcp.ifconfig").Table(func(index int, value map[string]string, head []string) {
|
||||
if value["ip"] == ip {
|
||||
ok = true
|
||||
}
|
||||
})
|
||||
return ok
|
||||
}
|
||||
|
||||
func (web *Frame) Login(msg *ice.Message, w http.ResponseWriter, r *http.Request) bool {
|
||||
msg.Option(ice.MSG_USERNAME, "")
|
||||
msg.Option(ice.MSG_USERROLE, "")
|
||||
|
||||
if msg.Options(ice.MSG_SESSID) {
|
||||
// 会话认证
|
||||
sub := aaa.SessCheck(msg.Spawn(), msg.Option(ice.MSG_SESSID))
|
||||
msg.Log_AUTH(
|
||||
aaa.USERROLE, msg.Option(ice.MSG_USERROLE, sub.Append(aaa.USERROLE)),
|
||||
aaa.USERNAME, msg.Option(ice.MSG_USERNAME, sub.Append(aaa.USERNAME)),
|
||||
)
|
||||
}
|
||||
|
||||
if !msg.Options(ice.MSG_USERNAME) && tcp.IPIsLocal(msg, msg.Option(ice.MSG_USERIP)) {
|
||||
// 自动认证
|
||||
if aaa.UserLogin(msg, cli.UserName, cli.PassWord) {
|
||||
Render(msg, "cookie", msg.Option(ice.MSG_SESSID))
|
||||
}
|
||||
}
|
||||
|
||||
if s, ok := msg.Target().Commands[ice.WEB_LOGIN]; ok {
|
||||
// 权限检查
|
||||
msg.Target().Run(msg, s, ice.WEB_LOGIN, kit.Simple(msg.Optionv("cmds"))...)
|
||||
} else if ls := strings.Split(msg.Option(ice.MSG_USERURL), "/"); kit.IndexOf([]string{
|
||||
"static", "plugin", "login", "space", "route", "share",
|
||||
"publish",
|
||||
}, ls[1]) > -1 {
|
||||
|
||||
} else {
|
||||
if msg.Warn(!msg.Options(ice.MSG_USERNAME), "not login %s", msg.Option(ice.MSG_USERURL)) {
|
||||
msg.Render("status", 401, "not login")
|
||||
return false
|
||||
}
|
||||
if !msg.Right(msg.Option(ice.MSG_USERURL)) {
|
||||
msg.Render("status", 403, "not auth")
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return msg.Option(ice.MSG_USERURL) != ""
|
||||
}
|
||||
func (web *Frame) HandleWSS(m *ice.Message, safe bool, c *websocket.Conn, name string) bool {
|
||||
for running := true; running; {
|
||||
if t, b, e := c.ReadMessage(); m.Warn(e != nil, "space recv %d msg %v", t, e) {
|
||||
// 解析失败
|
||||
break
|
||||
} else {
|
||||
socket, msg := c, m.Spawns(b)
|
||||
target := kit.Simple(msg.Optionv(ice.MSG_TARGET))
|
||||
source := kit.Simple(msg.Optionv(ice.MSG_SOURCE), name)
|
||||
msg.Info("recv %v<-%v %s %v", target, source, msg.Detailv(), msg.Format("meta"))
|
||||
|
||||
if len(target) == 0 {
|
||||
msg.Option(ice.MSG_USERROLE, msg.Cmdx(ice.AAA_ROLE, "check", msg.Option(ice.MSG_USERNAME)))
|
||||
msg.Logs(ice.LOG_AUTH, "role", msg.Option(ice.MSG_USERROLE), "user", msg.Option(ice.MSG_USERNAME))
|
||||
if msg.Optionv(ice.MSG_HANDLE, "true"); !msg.Warn(!safe, "no right") {
|
||||
// 本地执行
|
||||
m.Option("_dev", name)
|
||||
msg = msg.Cmd()
|
||||
msg.Set("_option")
|
||||
msg.Set("_option")
|
||||
}
|
||||
if source, target = []string{}, kit.Revert(source)[1:]; msg.Detail() == "exit" {
|
||||
// 重启进程
|
||||
return true
|
||||
}
|
||||
} else if msg.Richs(ice.WEB_SPACE, nil, target[0], func(key string, value map[string]interface{}) {
|
||||
// 查询节点
|
||||
if s, ok := value["socket"].(*websocket.Conn); ok {
|
||||
socket, source, target = s, source, target[1:]
|
||||
} else {
|
||||
socket, source, target = s, source, target[1:]
|
||||
}
|
||||
}) != nil {
|
||||
// 转发报文
|
||||
|
||||
} else if res, ok := web.send[msg.Option(ice.MSG_TARGET)]; len(target) == 1 && ok {
|
||||
// 接收响应
|
||||
delete(web.send, msg.Option(ice.MSG_TARGET))
|
||||
res.Cost("%v->%v %v %v", target, source, res.Detailv(), msg.Format("append"))
|
||||
res.Back(msg)
|
||||
continue
|
||||
|
||||
} else if msg.Warn(msg.Option("_handle") == "true", "space miss") {
|
||||
// 回复失败
|
||||
continue
|
||||
|
||||
} else {
|
||||
// 下发失败
|
||||
msg.Warn(true, "space error")
|
||||
source, target = []string{}, kit.Revert(source)[1:]
|
||||
}
|
||||
|
||||
// 发送报文
|
||||
msg.Optionv(ice.MSG_SOURCE, source)
|
||||
msg.Optionv(ice.MSG_TARGET, target)
|
||||
socket.WriteMessage(t, []byte(msg.Format("meta")))
|
||||
target = append([]string{name}, target...)
|
||||
msg.Info("send %v %v->%v %v %v", t, source, target, msg.Detailv(), msg.Format("meta"))
|
||||
msg.Cost("%v->%v %v %v", source, target, msg.Detailv(), msg.Format("append"))
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
func (web *Frame) HandleCGI(m *ice.Message, alias map[string]interface{}, which string) *template.Template {
|
||||
cgi := template.FuncMap{}
|
||||
|
||||
tmpl := template.New(ice.WEB_TMPL)
|
||||
cb := func(k string, p []string, v *ice.Command) {
|
||||
cgi[k] = func(arg ...interface{}) (res interface{}) {
|
||||
m.TryCatch(m.Spawn(), true, func(msg *ice.Message) {
|
||||
msg.Target().Run(msg, v, k, kit.Simple(p, arg)...)
|
||||
|
||||
buffer := bytes.NewBuffer([]byte{})
|
||||
m.Assert(tmpl.ExecuteTemplate(buffer, msg.Option(ice.WEB_TMPL), msg))
|
||||
res = string(buffer.Bytes())
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
for k, v := range alias {
|
||||
list := kit.Simple(v)
|
||||
if v, ok := m.Target().Commands[list[0]]; ok {
|
||||
cb(k, list[1:], v)
|
||||
}
|
||||
}
|
||||
for k, v := range m.Target().Commands {
|
||||
if strings.HasPrefix(k, "/") || strings.HasPrefix(k, "_") {
|
||||
continue
|
||||
}
|
||||
cb(k, nil, v)
|
||||
}
|
||||
|
||||
tmpl = tmpl.Funcs(cgi)
|
||||
// tmpl = template.Must(tmpl.ParseGlob(path.Join(m.Conf(ice.WEB_SERVE, ice.Meta("template", "path")), "/*.tmpl")))
|
||||
// tmpl = template.Must(tmpl.ParseGlob(path.Join(m.Conf(ice.WEB_SERVE, ice.Meta("template", "path")), m.Target().Name, "/*.tmpl")))
|
||||
tmpl, e := tmpl.ParseFiles(which)
|
||||
if e != nil {
|
||||
}
|
||||
// m.Confm(ice.WEB_SERVE, ice.Meta("template", "list"), func(index int, value string) { tmpl = template.Must(tmpl.Parse(value)) })
|
||||
return tmpl
|
||||
}
|
||||
func (web *Frame) HandleCmd(m *ice.Message, key string, cmd *ice.Command) {
|
||||
web.HandleFunc(key, func(w http.ResponseWriter, r *http.Request) {
|
||||
m.TryCatch(m.Spawns(), true, func(msg *ice.Message) {
|
||||
defer func() { msg.Cost("%s %v %v", r.URL.Path, msg.Optionv("cmds"), msg.Format("append")) }()
|
||||
if u, e := url.Parse(r.Header.Get("Referer")); e == nil {
|
||||
for k, v := range u.Query() {
|
||||
msg.Logs("refer", k, v)
|
||||
msg.Option(k, v)
|
||||
}
|
||||
}
|
||||
|
||||
// 用户请求
|
||||
msg.Option(ice.MSG_USERWEB, m.Conf(ice.WEB_SHARE, "meta.domain"))
|
||||
msg.Option(ice.MSG_USERIP, r.Header.Get(ice.MSG_USERIP))
|
||||
msg.Option(ice.MSG_USERUA, r.Header.Get("User-Agent"))
|
||||
msg.Option(ice.MSG_USERURL, r.URL.Path)
|
||||
if msg.R, msg.W = r, w; r.Header.Get("X-Real-Port") != "" {
|
||||
msg.Option(ice.MSG_USERADDR, msg.Option(ice.MSG_USERIP)+":"+r.Header.Get("X-Real-Port"))
|
||||
} else {
|
||||
msg.Option(ice.MSG_USERADDR, r.RemoteAddr)
|
||||
}
|
||||
|
||||
// 请求变量
|
||||
msg.Option(ice.MSG_SESSID, "")
|
||||
msg.Option(ice.MSG_OUTPUT, "")
|
||||
for _, v := range r.Cookies() {
|
||||
msg.Option(v.Name, v.Value)
|
||||
}
|
||||
|
||||
// 解析引擎
|
||||
switch r.Header.Get("Content-Type") {
|
||||
case "application/json":
|
||||
var data interface{}
|
||||
if e := json.NewDecoder(r.Body).Decode(&data); !msg.Warn(e != nil, "%s", e) {
|
||||
msg.Optionv(ice.MSG_USERDATA, data)
|
||||
msg.Info("%s", kit.Formats(data))
|
||||
}
|
||||
|
||||
switch d := data.(type) {
|
||||
case map[string]interface{}:
|
||||
for k, v := range d {
|
||||
msg.Optionv(k, v)
|
||||
}
|
||||
}
|
||||
default:
|
||||
r.ParseMultipartForm(kit.Int64(kit.Select(r.Header.Get("Content-Length"), "4096")))
|
||||
if r.ParseForm(); len(r.PostForm) > 0 {
|
||||
for k, v := range r.PostForm {
|
||||
msg.Logs("form", k, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 请求参数
|
||||
for k, v := range r.Form {
|
||||
if msg.Optionv(k, v); k == ice.MSG_SESSID {
|
||||
msg.Render("cookie", v[0])
|
||||
}
|
||||
}
|
||||
|
||||
// 请求命令
|
||||
if msg.Option(ice.MSG_USERPOD, msg.Option("pod")); msg.Optionv("cmds") == nil {
|
||||
if p := strings.TrimPrefix(msg.Option(ice.MSG_USERURL), key); p != "" {
|
||||
msg.Optionv("cmds", strings.Split(p, "/"))
|
||||
}
|
||||
}
|
||||
|
||||
// 执行命令
|
||||
if cmds := kit.Simple(msg.Optionv("cmds")); web.Login(msg, w, r) {
|
||||
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{})
|
||||
Render(msg, msg.Option(ice.MSG_OUTPUT), _args...)
|
||||
})
|
||||
})
|
||||
}
|
||||
func (web *Frame) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
m, index := web.m, r.Header.Get("index.module") == ""
|
||||
if index {
|
||||
// 解析地址
|
||||
if ip := r.Header.Get("X-Forwarded-For"); ip != "" {
|
||||
r.Header.Set(ice.MSG_USERIP, ip)
|
||||
} else if ip := r.Header.Get("X-Real-Ip"); ip != "" {
|
||||
r.Header.Set(ice.MSG_USERIP, ip)
|
||||
} else if strings.HasPrefix(r.RemoteAddr, "[") {
|
||||
r.Header.Set(ice.MSG_USERIP, strings.Split(r.RemoteAddr, "]")[0][1:])
|
||||
} else {
|
||||
r.Header.Set(ice.MSG_USERIP, strings.Split(r.RemoteAddr, ":")[0])
|
||||
}
|
||||
m.Info("").Info("%s %s %s", r.Header.Get(ice.MSG_USERIP), r.Method, r.URL)
|
||||
|
||||
// 解析地址
|
||||
r.Header.Set("index.module", "some")
|
||||
r.Header.Set("index.path", r.URL.Path)
|
||||
r.Header.Set("index.url", r.URL.String())
|
||||
}
|
||||
|
||||
if index && kit.Right(m.Conf(ice.WEB_SERVE, "meta.logheaders")) {
|
||||
// 请求参数
|
||||
for k, v := range r.Header {
|
||||
m.Info("%s: %v", k, kit.Format(v))
|
||||
}
|
||||
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 {
|
||||
// 初始化成功
|
||||
m.Conf(ice.WEB_SERVE, "meta.init", "true")
|
||||
}
|
||||
m.W = w
|
||||
Render(m, "refresh", m.Conf(ice.WEB_SERVE, "meta.volcanos.refresh"))
|
||||
m.Event(ice.SYSTEM_INIT)
|
||||
m.W = nil
|
||||
} else if r.URL.Path == "/share" && r.Method == "GET" {
|
||||
http.ServeFile(w, r, m.Conf(ice.WEB_SERVE, "meta.page.share"))
|
||||
|
||||
// } else if r.URL.Path == "/" && r.Method == "GET" {
|
||||
// http.ServeFile(w, r, m.Conf(ice.WEB_SERVE, "meta.page.index"))
|
||||
//
|
||||
} else {
|
||||
web.ServeMux.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
if index && kit.Right(m.Conf(ice.WEB_SERVE, "meta.logheaders")) {
|
||||
// 响应参数
|
||||
for k, v := range w.Header() {
|
||||
m.Info("%s: %v", k, kit.Format(v))
|
||||
}
|
||||
m.Info(" ")
|
||||
}
|
||||
}
|
||||
|
||||
func (web *Frame) Spawn(m *ice.Message, c *ice.Context, arg ...string) ice.Server {
|
||||
return &Frame{}
|
||||
@ -417,7 +109,7 @@ func (web *Frame) Start(m *ice.Message, arg ...string) bool {
|
||||
|
||||
// 静态路由
|
||||
msg := m.Spawns(s)
|
||||
m.Confm(ice.WEB_SERVE, "meta.static", func(key string, value string) {
|
||||
m.Confm(SERVE, "meta.static", func(key string, value string) {
|
||||
m.Log("route", "%s <- %s <- %s", s.Name, key, value)
|
||||
w.Handle(key, http.StripPrefix(key, http.FileServer(http.Dir(value))))
|
||||
})
|
||||
@ -433,7 +125,7 @@ func (web *Frame) Start(m *ice.Message, arg ...string) bool {
|
||||
m.Travel(func(p *ice.Context, sub *ice.Context, k string, x *ice.Command) {
|
||||
if s == sub && k[0] == '/' {
|
||||
msg.Log("route", "%s <- %s", s.Name, k)
|
||||
w.HandleCmd(msg, k, x)
|
||||
Trans(w, msg, k, x)
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -460,41 +152,15 @@ func (web *Frame) Close(m *ice.Message, arg ...string) bool {
|
||||
}
|
||||
|
||||
var Index = &ice.Context{Name: "web", Help: "网络模块",
|
||||
Caches: map[string]*ice.Cache{},
|
||||
Configs: map[string]*ice.Config{
|
||||
ice.WEB_SPIDE: {Name: "spide", Help: "蜘蛛侠", Value: kit.Data(kit.MDB_SHORT, "client.name")},
|
||||
ice.WEB_SERVE: {Name: "serve", Help: "服务器", Value: kit.Data(
|
||||
"title", "github.com/shylinux/contexts",
|
||||
"legal", []interface{}{`<a href="mailto:shylinuxc@gmail.com">shylinuxc@gmail.com</a>`},
|
||||
"page", kit.Dict(
|
||||
"index", "usr/volcanos/page/index.html",
|
||||
"share", "usr/volcanos/page/share.html",
|
||||
),
|
||||
"static", kit.Dict("/", "usr/volcanos/"),
|
||||
"publish", "usr/publish/",
|
||||
"volcanos", kit.Dict("path", "usr/volcanos", "branch", "master",
|
||||
"repos", "https://github.com/shylinux/volcanos",
|
||||
"require", ".ish/pluged",
|
||||
"refresh", "5",
|
||||
),
|
||||
"template", kit.Dict("path", "usr/template", "list", []interface{}{
|
||||
`{{define "raw"}}{{.Result}}{{end}}`,
|
||||
}),
|
||||
"logheaders", "false", "init", "false",
|
||||
"black", kit.Dict(),
|
||||
)},
|
||||
ice.WEB_DREAM: {Name: "dream", Help: "梦想家", Value: kit.Data("path", "usr/local/work",
|
||||
// "cmd", []interface{}{ice.CLI_SYSTEM, "ice.sh", "start", ice.WEB_SPACE, "connect"},
|
||||
"cmd", []interface{}{ice.CLI_SYSTEM, "ice.bin", ice.WEB_SPACE, "connect"},
|
||||
)},
|
||||
},
|
||||
Caches: map[string]*ice.Cache{},
|
||||
Configs: map[string]*ice.Config{},
|
||||
Commands: map[string]*ice.Command{
|
||||
ice.ICE_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
m.Load()
|
||||
|
||||
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", "dev", kit.Select("http://:9020", m.Conf(ice.CLI_RUNTIME, "conf.ctx_dev")))
|
||||
m.Cmd(ice.WEB_SPIDE, "add", "shy", kit.Select("https://shylinux.com:443", m.Conf(ice.CLI_RUNTIME, "conf.ctx_shy")))
|
||||
SpideCreate(m, "self", kit.Select("http://:9020", m.Conf(ice.CLI_RUNTIME, "conf.ctx_self")))
|
||||
SpideCreate(m, "dev", kit.Select("http://:9020", m.Conf(ice.CLI_RUNTIME, "conf.ctx_dev")))
|
||||
SpideCreate(m, "shy", kit.Select("https://shylinux.com:443", m.Conf(ice.CLI_RUNTIME, "conf.ctx_shy")))
|
||||
|
||||
m.Cmd(ice.APP_SEARCH, "add", "favor", "base", m.AddCmd(&ice.Command{Name: "search word", Help: "搜索引擎", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
switch arg[0] {
|
||||
@ -594,332 +260,7 @@ var Index = &ice.Context{Name: "web", Help: "网络模块",
|
||||
}
|
||||
})
|
||||
}},
|
||||
|
||||
ice.WEB_SPIDE: {Name: "spide name=auto [action:select=msg|raw|cache] [method:select=POST|GET] url [format:select=json|form|part|data|file] arg... auto", Help: "蜘蛛侠", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
if len(arg) == 0 || arg[0] == "" {
|
||||
// 爬虫列表
|
||||
m.Richs(ice.WEB_SPIDE, nil, "*", func(key string, value map[string]interface{}) {
|
||||
m.Push(key, value["client"], []string{"name", "share", "login", "method", "url"})
|
||||
})
|
||||
m.Sort("name")
|
||||
return
|
||||
}
|
||||
if len(arg) == 1 || len(arg) > 3 && arg[3] == "" {
|
||||
// 爬虫详情
|
||||
m.Richs(ice.WEB_SPIDE, nil, arg[0], func(key string, value map[string]interface{}) {
|
||||
m.Push("detail", value)
|
||||
if kit.Value(value, "client.share") != nil {
|
||||
m.Push("key", "share")
|
||||
m.Push("value", fmt.Sprintf(m.Conf(ice.WEB_SHARE, "meta.template.text"), m.Conf(ice.WEB_SHARE, "meta.domain"), kit.Value(value, "client.share")))
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
switch arg[0] {
|
||||
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{}) {
|
||||
// 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, ice.TYPE_SPIDE, arg[1], 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,
|
||||
"timeout", "100s", "logheaders", false,
|
||||
),
|
||||
))
|
||||
}
|
||||
m.Log(ice.LOG_CREATE, "%s: %v", arg[1], arg[2:])
|
||||
}
|
||||
return
|
||||
case "login":
|
||||
m.Richs(ice.WEB_SPIDE, nil, arg[1], func(key string, value map[string]interface{}) {
|
||||
msg := m.Cmd(ice.WEB_SPIDE, arg[1], "msg", "/route/login", "login")
|
||||
if msg.Append(ice.MSG_USERNAME) != "" {
|
||||
m.Echo(msg.Append(ice.MSG_USERNAME))
|
||||
return
|
||||
}
|
||||
if msg.Result() != "" {
|
||||
kit.Value(value, "client.login", msg.Result())
|
||||
kit.Value(value, "client.share", m.Cmdx(ice.WEB_SHARE, ice.TYPE_SPIDE, arg[1],
|
||||
kit.Format("%s?sessid=%s", kit.Value(value, "client.url"), kit.Value(value, "cookie.sessid"))))
|
||||
}
|
||||
m.Render(ice.RENDER_QRCODE, kit.Dict(
|
||||
kit.MDB_TYPE, "login", kit.MDB_NAME, arg[1],
|
||||
kit.MDB_TEXT, kit.Value(value, "cookie.sessid"),
|
||||
))
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
m.Richs(ice.WEB_SPIDE, nil, arg[0], func(key string, value map[string]interface{}) {
|
||||
client := value["client"].(map[string]interface{})
|
||||
// 缓存数据
|
||||
cache := ""
|
||||
switch arg[1] {
|
||||
case "raw":
|
||||
cache, arg = arg[1], arg[1:]
|
||||
case "msg":
|
||||
cache, arg = arg[1], arg[1:]
|
||||
case "cache":
|
||||
cache, arg = arg[1], arg[1:]
|
||||
}
|
||||
|
||||
// 请求方法
|
||||
method := kit.Select("POST", client["method"])
|
||||
switch arg = arg[1:]; arg[0] {
|
||||
case "POST":
|
||||
method, arg = "POST", arg[1:]
|
||||
case "GET":
|
||||
method, arg = "GET", arg[1:]
|
||||
}
|
||||
|
||||
// 请求地址
|
||||
uri, arg := arg[0], arg[1:]
|
||||
|
||||
// 渲染引擎
|
||||
head := map[string]string{}
|
||||
body, ok := m.Optionv("body").(io.Reader)
|
||||
if !ok && len(arg) > 0 && method != "GET" {
|
||||
switch arg[0] {
|
||||
case "file":
|
||||
if f, e := os.Open(arg[1]); m.Warn(e != nil, "%s", e) {
|
||||
return
|
||||
} else {
|
||||
defer f.Close()
|
||||
body, arg = f, arg[2:]
|
||||
}
|
||||
case "data":
|
||||
body, arg = bytes.NewBufferString(arg[1]), arg[2:]
|
||||
case "part":
|
||||
buf := &bytes.Buffer{}
|
||||
mp := multipart.NewWriter(buf)
|
||||
for i := 1; i < len(arg)-1; i += 2 {
|
||||
if strings.HasPrefix(arg[i+1], "@") {
|
||||
if f, e := os.Open(arg[i+1][1:]); m.Assert(e) {
|
||||
defer f.Close()
|
||||
if p, e := mp.CreateFormFile(arg[i], path.Base(arg[i+1][1:])); m.Assert(e) {
|
||||
io.Copy(p, f)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mp.WriteField(arg[i], arg[i+1])
|
||||
}
|
||||
}
|
||||
mp.Close()
|
||||
head["Content-Type"] = mp.FormDataContentType()
|
||||
body = buf
|
||||
case "form":
|
||||
data := []string{}
|
||||
for i := 1; i < len(arg)-1; i += 2 {
|
||||
data = append(data, url.QueryEscape(arg[i])+"="+url.QueryEscape(arg[i+1]))
|
||||
}
|
||||
body = bytes.NewBufferString(strings.Join(data, "&"))
|
||||
head["Content-Type"] = "application/x-www-form-urlencoded"
|
||||
case "json":
|
||||
arg = arg[1:]
|
||||
fallthrough
|
||||
default:
|
||||
data := map[string]interface{}{}
|
||||
for i := 0; i < len(arg)-1; i += 2 {
|
||||
kit.Value(data, arg[i], arg[i+1])
|
||||
}
|
||||
if b, e := json.Marshal(data); m.Assert(e) {
|
||||
head["Content-Type"] = "application/json"
|
||||
body = bytes.NewBuffer(b)
|
||||
}
|
||||
m.Log(ice.LOG_EXPORT, "json: %s", kit.Format(data))
|
||||
}
|
||||
arg = arg[:0]
|
||||
} else {
|
||||
body = bytes.NewBuffer([]byte{})
|
||||
}
|
||||
|
||||
// 请求地址
|
||||
uri = kit.MergeURL2(kit.Format(client["url"]), uri, arg)
|
||||
req, e := http.NewRequest(method, uri, body)
|
||||
m.Info("%s %s", req.Method, req.URL)
|
||||
m.Assert(e)
|
||||
|
||||
// 请求变量
|
||||
kit.Fetch(value["cookie"], func(key string, value string) {
|
||||
req.AddCookie(&http.Cookie{Name: key, Value: value})
|
||||
m.Info("%s: %s", key, value)
|
||||
})
|
||||
kit.Fetch(value["header"], func(key string, value string) {
|
||||
req.Header.Set(key, value)
|
||||
})
|
||||
list := kit.Simple(m.Optionv("header"))
|
||||
for i := 0; i < len(list)-1; i += 2 {
|
||||
req.Header.Set(list[i], list[i+1])
|
||||
}
|
||||
for k, v := range head {
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
|
||||
// 请求代理
|
||||
web := m.Target().Server().(*Frame)
|
||||
if web.Client == nil {
|
||||
web.Client = &http.Client{Timeout: kit.Duration(kit.Format(client["timeout"]))}
|
||||
}
|
||||
if method == "POST" {
|
||||
m.Info("%s: %s", req.Header.Get("Content-Length"), req.Header.Get("Content-Type"))
|
||||
}
|
||||
|
||||
// 发送请求
|
||||
res, e := web.Client.Do(req)
|
||||
if m.Warn(e != nil, "%s", e) {
|
||||
return
|
||||
}
|
||||
|
||||
// 检查结果
|
||||
if m.Cost("%s %s: %s", res.Status, res.Header.Get("Content-Length"), res.Header.Get("Content-Type")); m.Warn(res.StatusCode != http.StatusOK, "%s", res.Status) {
|
||||
return
|
||||
}
|
||||
|
||||
// 缓存变量
|
||||
for _, v := range res.Cookies() {
|
||||
kit.Value(value, "cookie."+v.Name, v.Value)
|
||||
m.Log(ice.LOG_IMPORT, "%s: %s", v.Name, v.Value)
|
||||
}
|
||||
|
||||
// 解析引擎
|
||||
switch cache {
|
||||
case "cache":
|
||||
m.Optionv("response", res)
|
||||
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))
|
||||
}
|
||||
case "msg":
|
||||
var data map[string][]string
|
||||
m.Assert(json.NewDecoder(res.Body).Decode(&data))
|
||||
m.Info("res: %s", kit.Formats(data))
|
||||
for _, k := range data[ice.MSG_APPEND] {
|
||||
for i := range data[k] {
|
||||
m.Push(k, data[k][i])
|
||||
}
|
||||
}
|
||||
m.Resultv(data[ice.MSG_RESULT])
|
||||
default:
|
||||
if strings.HasPrefix(res.Header.Get("Content-Type"), "text/html") {
|
||||
b, _ := ioutil.ReadAll(res.Body)
|
||||
m.Echo(string(b))
|
||||
break
|
||||
}
|
||||
|
||||
var data interface{}
|
||||
m.Assert(json.NewDecoder(res.Body).Decode(&data))
|
||||
data = kit.KeyValue(map[string]interface{}{}, "", data)
|
||||
m.Info("res: %s", kit.Formats(data))
|
||||
m.Push("", data)
|
||||
}
|
||||
})
|
||||
}},
|
||||
ice.WEB_SERVE: {Name: "serve [random] [ups...]", Help: "服务器", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
m.Conf(ice.CLI_RUNTIME, "node.name", m.Conf(ice.CLI_RUNTIME, "boot.hostname"))
|
||||
m.Conf(ice.CLI_RUNTIME, "node.type", ice.WEB_SERVER)
|
||||
|
||||
if len(arg) > 0 && arg[0] == "random" {
|
||||
// 随机端口
|
||||
m.Conf(ice.CLI_RUNTIME, "node.name", m.Conf(ice.CLI_RUNTIME, "boot.pathname"))
|
||||
m.Cmd(ice.WEB_SPIDE, "add", "self", "http://random")
|
||||
arg = arg[1:]
|
||||
}
|
||||
|
||||
// 启动服务
|
||||
m.Target().Start(m, "self")
|
||||
m.Sleep("1s")
|
||||
|
||||
// 连接服务
|
||||
m.Cmd(ice.WEB_SPACE, "connect", "self")
|
||||
for _, k := range arg {
|
||||
m.Cmd(ice.WEB_SPACE, "connect", k)
|
||||
}
|
||||
|
||||
m.Watch(ice.SYSTEM_INIT, "web.code.git.repos", "volcanos", m.Conf(ice.WEB_SERVE, "meta.volcanos.path"),
|
||||
m.Conf(ice.WEB_SERVE, "meta.volcanos.repos"), m.Conf(ice.WEB_SERVE, "meta.volcanos.branch"))
|
||||
m.Conf(ice.WEB_FAVOR, "meta.template", favor_template)
|
||||
m.Conf(ice.WEB_SHARE, "meta.template", share_template)
|
||||
}},
|
||||
ice.WEB_DREAM: {Name: "dream name auto", Help: "梦想家", Meta: kit.Dict(
|
||||
"exports", []string{"you", "name"}, "detail", []interface{}{"启动", "停止"},
|
||||
), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
if len(arg) > 1 && arg[0] == "action" {
|
||||
switch arg[1] {
|
||||
case "启动", "start":
|
||||
arg = []string{arg[4]}
|
||||
case "停止", "stop":
|
||||
m.Cmd(ice.WEB_SPACE, kit.Select(m.Option("name"), arg, 4), "exit", "1")
|
||||
m.Event(ice.DREAM_CLOSE, arg[4])
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if len(arg) == 0 {
|
||||
// 任务列表
|
||||
m.Cmdy("nfs.dir", m.Conf(ice.WEB_DREAM, "meta.path"), "time name")
|
||||
m.Table(func(index int, value map[string]string, head []string) {
|
||||
if m.Richs(ice.WEB_SPACE, nil, value["name"], func(key string, value map[string]interface{}) {
|
||||
m.Push("type", value["type"])
|
||||
m.Push("status", "start")
|
||||
}) == nil {
|
||||
m.Push("type", "none")
|
||||
m.Push("status", "stop")
|
||||
}
|
||||
})
|
||||
m.Sort("name")
|
||||
m.Sort("status")
|
||||
return
|
||||
}
|
||||
|
||||
// 规范命名
|
||||
if !strings.Contains(arg[0], "-") || !strings.HasPrefix(arg[0], "20") {
|
||||
arg[0] = m.Time("20060102-") + arg[0]
|
||||
}
|
||||
|
||||
// 创建目录
|
||||
p := path.Join(m.Conf(ice.WEB_DREAM, "meta.path"), arg[0])
|
||||
os.MkdirAll(p, 0777)
|
||||
|
||||
if b, e := ioutil.ReadFile(path.Join(p, m.Conf(ice.GDB_SIGNAL, "meta.pid"))); e == nil {
|
||||
if s, e := os.Stat("/proc/" + string(b)); e == nil && s.IsDir() {
|
||||
m.Info("already exists %v", string(b))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if m.Richs(ice.WEB_SPACE, nil, arg[0], nil) == nil {
|
||||
// 启动任务
|
||||
m.Option("cmd_dir", p)
|
||||
m.Option("cmd_type", "daemon")
|
||||
m.Optionv("cmd_env",
|
||||
"ctx_dev", m.Conf(ice.CLI_RUNTIME, "conf.ctx_dev"),
|
||||
"ctx_log", "boot.log", "ctx_mod", "ctx,log,gdb,ssh",
|
||||
"PATH", kit.Path(path.Join(p, "bin"))+":"+os.Getenv("PATH"),
|
||||
)
|
||||
m.Cmd(m.Confv(ice.WEB_DREAM, "meta.cmd"), "self", arg[0])
|
||||
time.Sleep(time.Second * 1)
|
||||
m.Event(ice.DREAM_START, arg...)
|
||||
}
|
||||
m.Cmdy("nfs.dir", p)
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
func init() { ice.Index.Register(Index, &Frame{}) }
|
||||
func init() { ice.Index.Register(Index, &Frame{}, SERVE) }
|
||||
|
@ -66,7 +66,7 @@ var Index = &ice.Context{Name: "lark", Help: "机器人",
|
||||
Commands: map[string]*ice.Command{
|
||||
ice.ICE_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
m.Load()
|
||||
m.Cmd(ice.WEB_SPIDE, "add", LARK, m.Conf(APP, "meta.lark"))
|
||||
web.SpideCreate(m, LARK, m.Conf(APP, "meta.lark"))
|
||||
m.Cmd(DUTY, "boot", m.Conf(ice.CLI_RUNTIME, "boot.hostname"), m.Time())
|
||||
}},
|
||||
ice.ICE_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
|
@ -22,7 +22,7 @@ var Index = &ice.Context{Name: "mp", Help: "小程序",
|
||||
Commands: map[string]*ice.Command{
|
||||
ice.ICE_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
m.Load()
|
||||
m.Cmd(ice.WEB_SPIDE, "add", "weixin", m.Conf("login", "meta.weixin"))
|
||||
web.SpideCreate(m, "weixin", m.Conf("login", "meta.weixin"))
|
||||
m.Confm("login", "meta.userrole", func(key string, value string) {
|
||||
m.Cmd(ice.AAA_ROLE, value, key)
|
||||
})
|
||||
|
@ -14,7 +14,7 @@ var Index = &ice.Context{Name: "railway", Help: "railway",
|
||||
Commands: map[string]*ice.Command{
|
||||
ice.ICE_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
m.Load()
|
||||
m.Cmd(ice.WEB_SPIDE, "add", "12306", m.Conf("railway", "meta.site"))
|
||||
web.SpideCreate(m, "12306", m.Conf("railway", "meta.site"))
|
||||
}},
|
||||
ice.ICE_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
m.Save("railway")
|
||||
|
Loading…
x
Reference in New Issue
Block a user