1
0
forked from x/icebergs

add story.upload

This commit is contained in:
shaoying 2019-12-23 22:29:14 +08:00
parent b7a09f2733
commit 1e7aed134c
11 changed files with 434 additions and 259 deletions

View File

@ -18,7 +18,7 @@ var Index = &ice.Context{Name: "aaa", Help: "认证模块",
ice.AAA_ROLE: {Name: "role", Help: "角色", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { ice.AAA_ROLE: {Name: "role", Help: "角色", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
switch arg[0] { switch arg[0] {
case "check": case "check":
m.Echo(kit.Select("void", "root", arg[1] == m.Conf("cli.runtime", "boot.username"))) m.Echo(kit.Select("void", "root", arg[1] == m.Conf(ice.CLI_RUNTIME, "boot.username")))
} }
}}, }},
ice.AAA_USER: {Name: "user", Help: "用户", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { ice.AAA_USER: {Name: "user", Help: "用户", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
@ -27,10 +27,10 @@ var Index = &ice.Context{Name: "aaa", Help: "认证模块",
// 用户认证 // 用户认证
user := m.Richs(ice.AAA_USER, nil, arg[1], nil) user := m.Richs(ice.AAA_USER, nil, arg[1], nil)
if user == nil { if user == nil {
m.Rich(ice.AAA_USER, nil, map[string]interface{}{ m.Rich(ice.AAA_USER, nil, kit.Dict(
"username": arg[1], "password": arg[2], "username", arg[1], "password", arg[2],
"usernode": m.Conf("cli.runtime", "boot.hostname"), "usernode", m.Conf(ice.CLI_RUNTIME, "boot.hostname"),
}) ))
user = m.Richs(ice.AAA_USER, nil, arg[1], nil) user = m.Richs(ice.AAA_USER, nil, arg[1], nil)
m.Info("create user: %s %s", arg[1], kit.Format(user)) m.Info("create user: %s %s", arg[1], kit.Format(user))
} else if kit.Format(user["password"]) != arg[2] { } else if kit.Format(user["password"]) != arg[2] {
@ -42,9 +42,9 @@ var Index = &ice.Context{Name: "aaa", Help: "认证模块",
sessid := kit.Format(user[ice.WEB_SESS]) sessid := kit.Format(user[ice.WEB_SESS])
if sessid == "" { if sessid == "" {
role := m.Cmdx(ice.AAA_ROLE, "check", arg[1]) role := m.Cmdx(ice.AAA_ROLE, "check", arg[1])
sessid = m.Rich(ice.AAA_SESS, nil, map[string]interface{}{ sessid = m.Rich(ice.AAA_SESS, nil, kit.Dict(
"username": arg[1], "userrole": role, "username", arg[1], "userrole", role,
}) ))
m.Info("user: %s role: %s sess: %s", arg[1], role, sessid) m.Info("user: %s role: %s sess: %s", arg[1], role, sessid)
} }
m.Echo(sessid) m.Echo(sessid)

View File

@ -5,6 +5,7 @@ import (
"github.com/shylinux/toolkits" "github.com/shylinux/toolkits"
"bytes" "bytes"
"fmt"
"os" "os"
"os/exec" "os/exec"
"os/user" "os/user"
@ -15,55 +16,58 @@ import (
var Index = &ice.Context{Name: "cli", Help: "命令模块", var Index = &ice.Context{Name: "cli", Help: "命令模块",
Caches: map[string]*ice.Cache{}, Caches: map[string]*ice.Cache{},
Configs: map[string]*ice.Config{ Configs: map[string]*ice.Config{
"runtime": {Name: "runtime", Value: map[string]interface{}{ ice.CLI_RUNTIME: {Name: "runtime", Help: "运行环境", Value: kit.Dict()},
"host": map[string]interface{}{},
"boot": map[string]interface{}{},
"node": map[string]interface{}{},
"user": map[string]interface{}{},
"work": map[string]interface{}{},
}},
}, },
Commands: map[string]*ice.Command{ Commands: map[string]*ice.Command{
ice.ICE_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { ice.ICE_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
m.Cmd(ice.CTX_CONFIG, "load", "var/conf/cli.json") m.Cmd(ice.CTX_CONFIG, "load", "cli.json")
m.Conf("runtime", "host.GOARCH", runtime.GOARCH) m.Conf(ice.CLI_RUNTIME, "host.GOARCH", runtime.GOARCH)
m.Conf("runtime", "host.GOOS", runtime.GOOS) m.Conf(ice.CLI_RUNTIME, "host.GOOS", runtime.GOOS)
m.Conf("runtime", "host.pid", os.Getpid()) m.Conf(ice.CLI_RUNTIME, "host.pid", os.Getpid())
if name, e := os.Hostname(); e == nil { if name, e := os.Hostname(); e == nil {
m.Conf("runtime", "boot.hostname", kit.Select(name, os.Getenv("HOSTNAME"))) m.Conf(ice.CLI_RUNTIME, "boot.hostname", kit.Select(name, os.Getenv("HOSTNAME")))
} }
if user, e := user.Current(); e == nil { if user, e := user.Current(); e == nil {
m.Conf("runtime", "boot.username", path.Base(kit.Select(user.Name, os.Getenv("USER")))) m.Conf(ice.CLI_RUNTIME, "boot.username", path.Base(kit.Select(user.Name, os.Getenv("USER"))))
} }
if name, e := os.Getwd(); e == nil { if name, e := os.Getwd(); e == nil {
m.Conf("runtime", "boot.pathname", path.Base(kit.Select(name, os.Getenv("PWD")))) m.Conf(ice.CLI_RUNTIME, "boot.pathname", path.Base(kit.Select(name, os.Getenv("PWD"))))
} }
m.Conf("runtime", "node.type", "worker") m.Conf(ice.CLI_RUNTIME, "node.type", kit.MIME_WORKER)
m.Conf("runtime", "node.name", m.Conf("runtime", "boot.pathname")) m.Conf(ice.CLI_RUNTIME, "node.name", m.Conf(ice.CLI_RUNTIME, "boot.pathname"))
m.Log("info", "runtime %v", kit.Formats(m.Confv("runtime"))) m.Log("info", "runtime %v", kit.Formats(m.Confv(ice.CLI_RUNTIME)))
}}, }},
ice.ICE_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { ice.ICE_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
m.Cmd(ice.CTX_CONFIG, "save", "var/conf/cli.json", "cli.runtime") m.Cmd(ice.CTX_CONFIG, "save", "cli.json", ice.CLI_RUNTIME)
}}, }},
"runtime": {Name: "runtime", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { ice.CLI_RUNTIME: {Name: "runtime", Help: "运行环境", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
}}, }},
"system": {Name: "system", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) { ice.CLI_SYSTEM: {Name: "system", Help: "系统命令", Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
cmd := exec.Command(arg[0], arg[1:]...) cmd := exec.Command(arg[0], arg[1:]...)
// 运行目录
cmd.Dir = m.Option("cmd_dir") cmd.Dir = m.Option("cmd_dir")
m.Log("info", "dir: %s", cmd.Dir) m.Info("dir: %s", cmd.Dir)
// 环境变量
env := kit.Simple(m.Optionv("cmd_env"))
for i := 0; i < len(env)-1; i += 2 {
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", env[i], env[i+1]))
}
m.Info("env: %s", cmd.Env)
if m.Option("cmd_type") == "daemon" { if m.Option("cmd_type") == "daemon" {
// 守护进程 // 守护进程
m.Gos(m, func(m *ice.Message) { m.Gos(m, func(m *ice.Message) {
if e := cmd.Start(); e != nil { if e := cmd.Start(); e != nil {
m.Log("warn", "%v start %s", arg, e) m.Warn(e != nil, "%v start: %s", arg, e)
} else if e := cmd.Wait(); e != nil { } else if e := cmd.Wait(); e != nil {
m.Log("warn", "%v wait %s", arg, e) m.Warn(e != nil, "%v wait: %s", arg, e)
} else { } else {
m.Log("info", "%v exit", arg) m.Info("%v exit", arg)
} }
}) })
} else { } else {
@ -73,15 +77,13 @@ var Index = &ice.Context{Name: "cli", Help: "命令模块",
cmd.Stdout = out cmd.Stdout = out
cmd.Stderr = err cmd.Stderr = err
if e := cmd.Run(); e != nil { if e := cmd.Run(); e != nil {
m.Warn(e != nil, kit.Select(e.Error(), err.String())) m.Warn(e != nil, "%v run: %s", arg, kit.Select(e.Error(), err.String()))
} else { } else {
m.Echo(out.String()) m.Echo(out.String())
} }
m.Push("code", int(cmd.ProcessState.ExitCode())) m.Push("code", int(cmd.ProcessState.ExitCode()))
} }
}}, }},
"timer": {Name: "timer", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
}},
}, },
} }

View File

@ -63,8 +63,8 @@ var Index = &ice.Context{Name: "ctx", Help: "元始模块",
m.Push("meta", kit.Format(cmd.Meta)) m.Push("meta", kit.Format(cmd.Meta))
m.Push("list", kit.Format(cmd.List)) m.Push("list", kit.Format(cmd.List))
} else { } else {
if cmd.Meta != nil && kit.Format(cmd.Meta["remote"]) == "true" && m.Option("you") != "" { if you := m.Option(kit.Format(kit.Value(cmd.Meta, "remote"))); you != "" {
m.Copy(m.Spawns(s).Cmd("web.space", m.Option("you"), "ctx.command", arg[0], arg[1], "run", arg[3:])) m.Copy(m.Spawns(s).Cmd("web.space", you, "ctx.command", arg[0], arg[1], "run", arg[3:]))
} else { } else {
m.Copy(s.Run(m.Spawns(s), cmd, key, arg[3:]...)) m.Copy(s.Run(m.Spawns(s), cmd, key, arg[3:]...))
} }

17
base/web/template.go Normal file
View File

@ -0,0 +1,17 @@
package web
var share_template = map[string]interface{}{
"shy/story": `{{}}`,
"shy/chain": `<!DOCTYPE html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" text="text/css" href="/style.css">
</head>
<body>
<fieldset>
{{.Append "type"}}
{{.Append "text"}}
</fieldset>
</body>
`,
}

View File

@ -8,10 +8,12 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io"
"math/rand" "math/rand"
"net" "net"
"net/http" "net/http"
"net/url" "net/url"
"os"
"path" "path"
"strings" "strings"
"text/template" "text/template"
@ -39,69 +41,66 @@ func Cookie(msg *ice.Message, sessid string) string {
} }
func (web *Frame) Login(msg *ice.Message, w http.ResponseWriter, r *http.Request) bool { func (web *Frame) Login(msg *ice.Message, w http.ResponseWriter, r *http.Request) bool {
if msg.Options(ice.WEB_SESS) { if msg.Options(ice.WEB_SESS) {
sub := msg.Cmd("aaa.sess", "check", msg.Option(ice.WEB_SESS)) sub := msg.Cmd(ice.AAA_SESS, "check", msg.Option(ice.WEB_SESS))
msg.Log("info", "role: %s user: %s", msg.Option(ice.MSG_USERROLE, sub.Append("userrole")), msg.Info("role: %s user: %s", msg.Option(ice.MSG_USERROLE, sub.Append("userrole")),
msg.Option(ice.MSG_USERNAME, sub.Append("username"))) msg.Option(ice.MSG_USERNAME, sub.Append("username")))
} }
msg.Target().Runs(msg, msg.Option("url"), ice.WEB_LOGIN, kit.Simple(msg.Optionv("cmds"))...) if s, ok := msg.Target().Commands[ice.WEB_LOGIN]; ok {
return true msg.Target().Run(msg, s, ice.WEB_LOGIN, kit.Simple(msg.Optionv("cmds"))...)
}
return msg.Option("url") != ""
} }
func (web *Frame) HandleWSS(m *ice.Message, safe bool, c *websocket.Conn) bool { func (web *Frame) HandleWSS(m *ice.Message, safe bool, c *websocket.Conn) bool {
for { for {
if t, b, e := c.ReadMessage(); e != nil { if t, b, e := c.ReadMessage(); m.Warn(e != nil, "space recv %d msg %v", t, e) {
m.Log("warn", "space recv %d msg %v", t, e)
break break
} else { } else {
switch t { switch t {
case MSG_MAPS: case MSG_MAPS:
// 接收报文
socket, msg := c, m.Spawn(b) socket, msg := c, m.Spawn(b)
source := kit.Simple(msg.Optionv("_source")) source := kit.Simple(msg.Optionv(ice.MSG_SOURCE))
target := kit.Simple(msg.Optionv("_target")) target := kit.Simple(msg.Optionv(ice.MSG_TARGET))
msg.Log("space", "recv %v %v->%v %v", t, source, target, msg.Formats("meta")) msg.Info("recv %v %v->%v %v", t, source, target, msg.Format("meta"))
if len(target) > 0 { if len(target) == 0 {
if s, ok := msg.Confv("web.space", "hash."+target[0]+".socket").(*websocket.Conn); ok {
msg.Log("space", "route")
// 转发报文
socket, source, target = s, append(source, target[0]), target[1:]
} else if call, ok := web.send[msg.Option("_target")]; len(target) == 1 && ok {
msg.Log("space", "done")
// 接收响应
delete(web.send, msg.Option("_target"))
call.Back(msg)
break
} else if msg.Option("_handle") == "true" {
msg.Log("space", "miss")
// 丢弃报文
break
} else {
// 失败报文
msg.Log("space", "error")
msg.Echo("error")
source, target = []string{source[len(source)-1]}, kit.Revert(source)[1:]
}
} else {
msg.Log("space", "run")
// 本地执行 // 本地执行
if safe { if msg.Optionv(ice.MSG_HANDLE, "true"); !msg.Warn(!safe, "no right") {
msg = msg.Cmd() if msg = msg.Cmd(); msg.Detail() == "exit" {
if msg.Detail() == "exit" {
return true return true
} }
} else {
msg.Echo("no right")
} }
msg.Optionv("_handle", "true")
kit.Revert(source) kit.Revert(source)
source, target = []string{source[0]}, source[1:] source, target = []string{source[0]}, source[1:]
} else if s, ok := msg.Confv(ice.WEB_SPACE, kit.Keys("hash", target[0], "socket")).(*websocket.Conn); ok {
// 转发报文
msg.Info("space route")
socket, source, target = s, append(source, target[0]), target[1:]
} else if call, ok := web.send[msg.Option(ice.MSG_TARGET)]; len(target) == 1 && ok {
// 接收响应
msg.Info("space done")
delete(web.send, msg.Option(ice.MSG_TARGET))
call.Back(msg)
break
} else if msg.Warn(msg.Option("_handle") == "true", "space miss") {
// 丢弃报文
break
} else {
// 失败报文
msg.Warn(true, "space error")
source, target = []string{source[len(source)-1]}, kit.Revert(source)[1:]
} }
// 发送报文 // 发送报文
msg.Optionv("_source", source) msg.Optionv(ice.MSG_SOURCE, source)
msg.Optionv("_target", target) msg.Optionv(ice.MSG_TARGET, target)
msg.Log("space", "send %v %v->%v %v", t, source, target, msg.Formats("meta"))
socket.WriteMessage(t, []byte(msg.Format("meta"))) socket.WriteMessage(t, []byte(msg.Format("meta")))
msg.Info("send %v %v->%v %v", t, source, target, msg.Format("meta"))
} }
} }
} }
@ -151,10 +150,9 @@ func (web *Frame) HandleCGI(m *ice.Message, alias map[string]interface{}, which
func (web *Frame) HandleCmd(m *ice.Message, key string, cmd *ice.Command) { func (web *Frame) HandleCmd(m *ice.Message, key string, cmd *ice.Command) {
web.HandleFunc(key, func(w http.ResponseWriter, r *http.Request) { web.HandleFunc(key, func(w http.ResponseWriter, r *http.Request) {
m.TryCatch(m.Spawns(), true, func(msg *ice.Message) { m.TryCatch(m.Spawns(), true, func(msg *ice.Message) {
defer func() { defer func() { msg.Log("cost", msg.Format("cost")) }()
msg.Log("cost", msg.Format("cost"))
}()
// 解析请求
msg.Optionv("request", r) msg.Optionv("request", r)
msg.Optionv("response", w) msg.Optionv("response", w)
msg.Option("user.agent", r.Header.Get("User-Agent")) msg.Option("user.agent", r.Header.Get("User-Agent"))
@ -176,40 +174,44 @@ func (web *Frame) HandleCmd(m *ice.Message, key string, cmd *ice.Command) {
r.ParseMultipartForm(4096) r.ParseMultipartForm(4096)
if r.ParseForm(); len(r.PostForm) > 0 { if r.ParseForm(); len(r.PostForm) > 0 {
for k, v := range r.PostForm { for k, v := range r.PostForm {
msg.Log("info", "%s: %v", k, v) msg.Info("%s: %v", k, v)
} }
msg.Log("info", "") msg.Info("")
} }
for k, v := range r.Form { for k, v := range r.Form {
for _, v := range v { msg.Optionv(k, v)
msg.Add(ice.MSG_OPTION, k, v)
}
} }
// 请求数据 // 请求数据
switch r.Header.Get("Content-Type") { switch r.Header.Get("Content-Type") {
case "application/json": case "application/json":
var data interface{} var data interface{}
if e := json.NewDecoder(r.Body).Decode(&data); e != nil { if e := json.NewDecoder(r.Body).Decode(&data); !msg.Warn(e != nil, "%s", e) {
msg.Log("warn", "%v", e) msg.Optionv("content_data", data)
msg.Info("%s", kit.Formats(data))
} }
msg.Optionv("content_data", data)
msg.Log("info", "%v", kit.Formats(data))
switch d := data.(type) { switch d := data.(type) {
case map[string]interface{}: case map[string]interface{}:
for k, v := range d { for k, v := range d {
for _, v := range kit.Simple(v) { msg.Optionv(k, v)
msg.Add(ice.MSG_OPTION, k, v)
}
} }
} }
} }
// 执行命令
if web.Login(msg, w, r) && msg.Target().Run(msg, cmd, msg.Option("url"), kit.Simple(msg.Optionv("cmds"))...) != nil { if web.Login(msg, w, r) && msg.Target().Run(msg, cmd, msg.Option("url"), kit.Simple(msg.Optionv("cmds"))...) != nil {
switch msg.Append("content-type") { // 输出响应
case "text/html": switch msg.Append("_output") {
w.Header().Set("Content-Type", "text/html") case "void":
case "file":
msg.Info("_output: %s %s", msg.Append("_output"), msg.Append("file"))
w.Header().Set("Content-Disposition", fmt.Sprintf("filename=%s", kit.Select("hi.txt", msg.Append("name"))))
w.Header().Set("Content-Type", kit.Select("text/html", msg.Append("type")))
http.ServeFile(w, r, msg.Append("file"))
case "result":
w.Header().Set("Content-Type", kit.Select("text/html", msg.Append("type")))
fmt.Fprint(w, msg.Result()) fmt.Fprint(w, msg.Result())
default: default:
fmt.Fprint(w, msg.Formats("meta")) fmt.Fprint(w, msg.Formats("meta"))
@ -223,6 +225,7 @@ func (web *Frame) ServeHTTP(w http.ResponseWriter, r *http.Request) {
index := r.Header.Get("index.module") == "" index := r.Header.Get("index.module") == ""
if index { if index {
// 解析地址
if ip := r.Header.Get("X-Forwarded-For"); ip != "" { if ip := r.Header.Get("X-Forwarded-For"); ip != "" {
r.Header.Set("user.ip", ip) r.Header.Set("user.ip", ip)
} else if ip := r.Header.Get("X-Real-Ip"); ip != "" { } else if ip := r.Header.Get("X-Real-Ip"); ip != "" {
@ -232,13 +235,29 @@ func (web *Frame) ServeHTTP(w http.ResponseWriter, r *http.Request) {
} else { } else {
r.Header.Set("user.ip", strings.Split(r.RemoteAddr, ":")[0]) r.Header.Set("user.ip", strings.Split(r.RemoteAddr, ":")[0])
} }
m.Log("info", "").Log("info", "%v %s %s", r.Header.Get("user.ip"), r.Method, r.URL) m.Info("").Info("%s %s %s", r.Header.Get("user.ip"), r.Method, r.URL)
// 解析地址
r.Header.Set("index.module", "some") r.Header.Set("index.module", "some")
r.Header.Set("index.url", r.URL.String())
r.Header.Set("index.path", r.URL.Path) 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(" ")
} }
web.ServeMux.ServeHTTP(w, r) 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 { func (web *Frame) Spawn(m *ice.Message, c *ice.Context, arg ...string) ice.Server {
@ -255,8 +274,9 @@ func (web *Frame) Start(m *ice.Message, arg ...string) bool {
return return
} }
w.ServeMux = http.NewServeMux() w.ServeMux = http.NewServeMux()
msg := m.Spawns(s)
// 静态路由 // 静态路由
msg := m.Spawns(s)
m.Confm(ice.WEB_SERVE, ice.Meta("static"), func(key string, value string) { m.Confm(ice.WEB_SERVE, ice.Meta("static"), func(key string, value string) {
m.Log("route", "%s <- %s <- %s", s.Name, key, value) m.Log("route", "%s <- %s <- %s", s.Name, key, value)
w.Handle(key, http.StripPrefix(key, http.FileServer(http.Dir(value)))) w.Handle(key, http.StripPrefix(key, http.FileServer(http.Dir(value))))
@ -279,8 +299,11 @@ func (web *Frame) Start(m *ice.Message, arg ...string) bool {
} }
}) })
// 服务地址
port := m.Cap(ice.CTX_STREAM, kit.Select(m.Conf(ice.WEB_SPIDE, ice.Meta("self", "port")), arg, 0)) port := m.Cap(ice.CTX_STREAM, kit.Select(m.Conf(ice.WEB_SPIDE, ice.Meta("self", "port")), arg, 0))
m.Log("serve", "listen %s %v", port, m.Conf("cli.runtime", "node")) m.Log("serve", "listen %s %v", port, m.Conf(ice.CLI_RUNTIME, "node"))
// 启动服务
web.m, web.Server = m, &http.Server{Addr: port, Handler: web} web.m, web.Server = m, &http.Server{Addr: port, Handler: web}
m.Log("serve", "listen %s", web.Server.ListenAndServe()) m.Log("serve", "listen %s", web.Server.ListenAndServe())
return true return true
@ -300,9 +323,18 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
"template", map[string]interface{}{"path": "usr/template", "list": []interface{}{ "template", map[string]interface{}{"path": "usr/template", "list": []interface{}{
`{{define "raw"}}{{.Result}}{{end}}`, `{{define "raw"}}{{.Result}}{{end}}`,
}}, }},
"logheaders", "false",
)},
ice.WEB_SPACE: {Name: "space", Help: "空间站", Value: kit.Data(
"redial.a", 3000, "redial.b", 1000, "redial.c", 10,
"buffer.r", 4096, "buffer.w", 4096,
kit.MDB_SHORT, "name",
)},
ice.WEB_STORY: {Name: "story", Help: "故事会", Value: kit.Dict(
kit.MDB_META, kit.Dict(kit.MDB_SHORT, "data",
"download", `<a href="/code/zsh?cmd=download&arg=%s" target="_blank">%s</a>`),
"head", kit.Data(kit.MDB_SHORT, "story"),
)}, )},
ice.WEB_SPACE: {Name: "space", Help: "空间站", Value: kit.Data("buffer", 4096, "redial", 3000)},
ice.WEB_STORY: {Name: "story", Help: "故事会", Value: kit.Data(kit.MDB_SHORT, "data")},
ice.WEB_CACHE: {Name: "cache", Help: "缓存", Value: kit.Data( ice.WEB_CACHE: {Name: "cache", Help: "缓存", Value: kit.Data(
kit.MDB_SHORT, "text", "path", "var/file", kit.MDB_SHORT, "text", "path", "var/file",
"store", "var/data", "limit", "30", "least", "10", "store", "var/data", "limit", "30", "least", "10",
@ -310,7 +342,10 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
ice.WEB_ROUTE: {Name: "route", Help: "路由", Value: kit.Data()}, ice.WEB_ROUTE: {Name: "route", Help: "路由", Value: kit.Data()},
ice.WEB_PROXY: {Name: "proxy", Help: "代理", Value: kit.Data()}, ice.WEB_PROXY: {Name: "proxy", Help: "代理", Value: kit.Data()},
ice.WEB_FAVOR: {Name: "favor", Help: "收藏", Value: kit.Data(kit.MDB_SHORT, kit.MDB_NAME)}, ice.WEB_FAVOR: {Name: "favor", Help: "收藏", Value: kit.Data(kit.MDB_SHORT, kit.MDB_NAME)},
ice.WEB_SHARE: {Name: "share", Help: "共享", Value: kit.Data()}, ice.WEB_SHARE: {Name: "share", Help: "共享", Value: kit.Data(
"href", `<a href="/share/%s" target="_blank">%s</a>`,
"template", share_template,
)},
}, },
Commands: map[string]*ice.Command{ Commands: map[string]*ice.Command{
ice.ICE_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {}}, ice.ICE_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {}},
@ -318,24 +353,25 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
ice.WEB_SPIDE: {Name: "spide", Help: "客户端", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { ice.WEB_SPIDE: {Name: "spide", Help: "客户端", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
}}, }},
ice.WEB_SERVE: {Name: "serve", Help: "服务器", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { ice.WEB_SERVE: {Name: "serve", Help: "服务器", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
m.Conf("cli.runtime", "node.name", m.Conf("cli.runtime", "boot.hostname")) m.Conf(ice.CLI_RUNTIME, "node.name", m.Conf(ice.CLI_RUNTIME, "boot.hostname"))
m.Conf("cli.runtime", "node.type", "server") m.Conf(ice.CLI_RUNTIME, "node.type", kit.MIME_SERVER)
m.Rich(ice.WEB_SPACE, nil, kit.Dict( m.Rich(ice.WEB_SPACE, nil, kit.Dict(
"type", "myself", "type", kit.MIME_MYSELF,
"node", m.Conf("cli.runtime", "boot.hostname"), "name", m.Conf(ice.CLI_RUNTIME, "boot.hostname"),
"user", m.Conf("cli.runtime", "boot.username"), "user", m.Conf(ice.CLI_RUNTIME, "boot.username"),
)) ))
m.Target().Start(m, arg...) m.Target().Start(m, arg...)
}}, }},
ice.WEB_SPACE: {Name: "space", Help: "空间站", Meta: kit.Dict("exports", []string{"pod", "node"}), List: kit.List( ice.WEB_SPACE: {Name: "space", Help: "空间站", Meta: kit.Dict("exports", []string{"pod", "name"}), List: kit.List(
kit.MDB_INPUT, "text", "name", "pod", "action", "auto", kit.MDB_INPUT, "text", "name", "node",
kit.MDB_INPUT, "button", "value", "查看", "action", "auto", kit.MDB_INPUT, "button", "value", "查看", "action", "auto",
kit.MDB_INPUT, "button", "value", "返回", "cb", "Last", kit.MDB_INPUT, "button", "value", "返回", "cb", "Last",
), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { ), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(arg) == 0 { if len(arg) == 0 {
// 节点列表
m.Richs(ice.WEB_SPACE, nil, "", func(key string, value map[string]interface{}) { m.Richs(ice.WEB_SPACE, nil, "", func(key string, value map[string]interface{}) {
m.Push(key, value) m.Push(key, value, []string{"time", "type", "name", "user"})
}) })
return return
} }
@ -343,98 +379,110 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
web := m.Target().Server().(*Frame) web := m.Target().Server().(*Frame)
switch arg[0] { switch arg[0] {
case "connect": case "connect":
node, name := m.Conf("cli.runtime", "node.type"), m.Conf("cli.runtime", "boot.hostname") // 基本信息
if node == "worker" { node := m.Conf(ice.CLI_RUNTIME, "node.type")
name = m.Conf("cli.runtime", "boot.pathname") name := kit.Select(m.Conf(ice.CLI_RUNTIME, "boot.pathname"), m.Conf(ice.CLI_RUNTIME, "boot.hostname"), node == kit.MIME_SERVER)
} user := m.Conf(ice.CLI_RUNTIME, "boot.username")
host := kit.Select(m.Conf("web.spide", "self.port"), arg, 1) host := kit.Select(m.Conf(ice.WEB_SPIDE, "meta.self.port"), arg, 1)
p := "ws://" + host + kit.Select("/space", arg, 2) + "?node=" + node + "&name=" + name
if u, e := url.Parse(p); m.Assert(e) { if u, e := url.Parse(kit.MergeURL("ws://"+host+kit.Select("/space", arg, 2), "node", node, "name", name, "user", user)); m.Assert(e) {
m.TryCatch(m, true, func(m *ice.Message) { for i := 0; i < m.Confi(ice.WEB_SPACE, "meta.redial.c"); i++ {
for { if s, e := net.Dial("tcp", host); !m.Warn(e != nil, "%s", e) {
if s, e := net.Dial("tcp", host); e == nil { if s, _, e := websocket.NewClient(s, u, nil, m.Confi(ice.WEB_SPACE, "meta.buffer.r"), m.Confi(ice.WEB_SPACE, "meta.buffer.w")); !m.Warn(e != nil, "%s", e) {
if s, _, e := websocket.NewClient(s, u, nil, m.Confi("web.space", "meta.buffer"), m.Confi("web.space", "meta.buffer")); e == nil { // 连接成功
id := m.Option("_source", []string{kit.Format(c.ID()), "some"}) m.Info("conn %d success %s", i, u)
web.send[id] = m if i = 0; web.HandleWSS(m, true, s) {
s.WriteMessage(MSG_MAPS, []byte(m.Format("meta"))) break
if web.HandleWSS(m, true, s) {
break
}
} else {
m.Log("warn", "wss %s", e)
} }
} else {
m.Log("warn", "dial %s", e)
} }
time.Sleep(time.Duration(rand.Intn(m.Confi("web.space", "meta.redial"))) * time.Millisecond)
m.Log("info", "reconnect %v", u)
} }
})
// 断线重连
sleep := time.Duration(rand.Intn(m.Confi(ice.WEB_SPACE, "meta.redial.a"))*i+i*m.Confi(ice.WEB_SPACE, "meta.redial.b")) * time.Millisecond
m.Info("%d sleep: %s reconnect: %s", i, sleep, u)
time.Sleep(sleep)
}
} }
default: default:
// 本地命令 // 本地命令
if arg[0] == "" || arg[0] == m.Conf("cli.runtime", "node.name") { if arg[0] == "" || arg[0] == m.Conf(ice.CLI_RUNTIME, "node.name") {
m.Cmdy(arg[1:]) m.Cmdy(arg[1:])
break break
} }
target := strings.Split(arg[0], ".") target := strings.Split(arg[0], ".")
if socket, ok := m.Confv(ice.WEB_SPACE, "hash."+target[0]+".socket").(*websocket.Conn); !ok { m.Warn(m.Richs(ice.WEB_SPACE, nil, target[0], func(key string, value map[string]interface{}) {
m.Echo("error").Echo("not found") if socket, ok := value["socket"].(*websocket.Conn); ok {
} else { // 构造路由
id := kit.Format(c.ID()) id := kit.Format(c.ID())
m.Optionv("_source", []string{id, target[0]}) m.Optionv(ice.MSG_SOURCE, []string{id, target[0]})
m.Optionv("_target", target[1:]) m.Optionv(ice.MSG_TARGET, target[1:])
m.Set(ice.MSG_DETAIL, arg[1:]...) m.Set(ice.MSG_DETAIL, arg[1:]...)
m.Info("send %s %s", id, m.Format("meta"))
web := m.Target().Server().(*Frame) // 下发命令
web.send[id] = m now := time.Now()
m.Target().Server().(*Frame).send[id] = m
now := time.Now() socket.WriteMessage(MSG_MAPS, []byte(m.Format("meta")))
socket.WriteMessage(MSG_MAPS, []byte(m.Format("meta"))) m.Call(true, func(msg *ice.Message) *ice.Message {
m.Call(true, func(msg *ice.Message) *ice.Message { // 返回结果
m.Copy(msg) m.Copy(msg).Log("cost", "cost: %s", kit.FmtTime(kit.Int64(time.Now().Sub(now))))
m.Log("info", "cost %s", time.Now().Sub(now)) return nil
return nil })
}) }
} }) == nil, "not found %s", arg[0])
} }
}}, }},
ice.WEB_STORY: {Name: "story", Help: "故事会", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { ice.WEB_STORY: {Name: "story", Help: "故事会", Meta: kit.Dict("exports", []string{"top", "story"}), List: kit.List(
kit.MDB_INPUT, "text", "name", "top", "action", "auto",
kit.MDB_INPUT, "button", "value", "查看", "action", "auto",
kit.MDB_INPUT, "button", "value", "返回", "cb", "Last",
), Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(arg) == 0 { if len(arg) == 0 {
m.Confm("story", ice.Meta("head"), func(key string, value map[string]interface{}) { // 故事列表
m.Push(key, value, []string{"key", "type", "time", "story"}) m.Richs(ice.WEB_STORY, "head", "", func(key string, value map[string]interface{}) {
m.Push(key, value, []string{"time", "story", "scene"})
}) })
return return
} }
// head list data time text file // head list data time text file
switch arg[0] { switch arg[0] {
case "add": case "add", "upload":
// 保存数据
m.Cmdy(ice.WEB_CACHE, arg)
arg = []string{arg[0], m.Append("type"), m.Append("name"), m.Append("data")}
// 查询索引 // 查询索引
head := kit.Hashs(arg[1], arg[2]) head, prev := "", ""
prev := m.Conf("story", ice.Meta("head", head, "list")) m.Richs(ice.WEB_STORY, "head", arg[2], func(key string, value map[string]interface{}) {
m.Log("info", "head: %v prev: %v", head, prev) head, prev = key, kit.Format(value["list"])
m.Log("info", "head: %v prev: %v", head, prev)
})
// 添加节点 // 添加节点
meta := map[string]interface{}{ list := m.Rich(ice.WEB_STORY, nil, kit.Dict(
"time": m.Time(), "scene", arg[1], "story", arg[2], "data", arg[3], "prev", prev,
"scene": arg[1], ))
"story": arg[2], m.Info("%s: %s story: %s", arg[1], arg[2], list)
"data": m.Cmdx(ice.WEB_CACHE, "add", "text", arg[3]), m.Push("list", list)
"prev": prev,
}
list := m.Rich("story", nil, meta)
m.Log("info", "list: %v meta: %v", list, kit.Format(meta))
// 添加索引 // 添加索引
m.Conf("story", ice.Meta("head", head), map[string]interface{}{ m.Rich(ice.WEB_STORY, "head", kit.Dict(
"time": m.Time(), "scene": arg[1], "story": arg[2], "list": list, "scene", arg[1], "story", arg[2], "list", list,
}) ))
m.Echo(list) m.Echo(list)
case "download":
// 下载文件
if m.Cmdy(ice.WEB_STORY, "index", arg[1]); m.Append("file") != "" {
m.Push("_output", "file")
} else {
m.Push("_output", "result")
m.Echo(m.Append("text"))
}
case "commit": case "commit":
// 查询索引 // 查询索引
head := kit.Hashs(arg[1]) head := kit.Hashs(arg[1])
@ -472,55 +520,121 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
}) })
m.Echo(list) m.Echo(list)
case "share":
m.Cmdy(ice.WEB_SHARE, arg[1:])
case "history": case "history":
list := kit.Select(arg[1], kit.Select(m.Conf(ice.WEB_STORY, ice.Meta("head", arg[1], "list")), // 历史记录
m.Conf(ice.WEB_STORY, ice.Meta("head", kit.Hashs(arg[1]), "list")))) list := m.Cmd(ice.WEB_STORY, "index", arg[1]).Append("list")
for i := 0; i < 10 && list != ""; i++ { for i := 0; i < 10 && list != ""; i++ {
m.Confm(ice.WEB_STORY, kit.Keys("hash", list), func(value map[string]interface{}) { m.Confm(ice.WEB_STORY, kit.Keys("hash", list), func(value map[string]interface{}) {
m.Push(list, value, []string{"key", "time", "story", "scene"}) // 直连节点
m.Push("text", m.Conf(ice.WEB_CACHE, kit.Keys("hash", value["data"], "text"))) m.Confm(ice.WEB_CACHE, kit.Keys("hash", value["data"]), func(val map[string]interface{}) {
m.Push(list, value, []string{"data"}) m.Push(list, value, []string{"key", "time", "scene", "story"})
m.Push("text", val["text"])
m.Push("data", value["data"])
})
// 复合节点
kit.Fetch(value["list"], func(key string, val string) { kit.Fetch(value["list"], func(key string, val string) {
m.Push(list, value, []string{"key", "time"}) m.Push(list, value, []string{"key", "time"})
node := m.Confm(ice.WEB_STORY, kit.Keys("hash", val))
m.Push("scene", node["scene"])
m.Push("story", kit.Keys(kit.Format(value["story"]), key)) m.Push("story", kit.Keys(kit.Format(value["story"]), key))
m.Push("scene", value["scene"])
data := m.Conf(ice.WEB_STORY, kit.Keys("hash", val, "data")) m.Push("text", m.Conf(ice.WEB_CACHE, kit.Keys("hash", node["data"], "text")))
m.Push("text", m.Conf(ice.WEB_CACHE, kit.Keys("hash", data, "text"))) m.Push("data", node["data"])
m.Push("data", data)
}) })
list = kit.Format(value["prev"]) list = kit.Format(value["prev"])
}) })
} }
case "share":
m.Cmdy(ice.WEB_SHARE, arg[1:])
case "index": case "index":
list := kit.Select(arg[1], kit.Select(m.Conf(ice.WEB_STORY, ice.Meta("head", arg[1], "list")), // 查询索引
m.Conf(ice.WEB_STORY, ice.Meta("head", kit.Hashs(arg[1]), "list")))) if m.Richs(ice.WEB_STORY, "head", arg[1], func(key string, value map[string]interface{}) {
data := kit.Select(list, m.Conf(ice.WEB_STORY, []string{"hash", list, "data"})) arg[1] = kit.Format(value["list"])
text := m.Conf(ice.WEB_CACHE, []string{"hash", data, "text"}) }) == nil {
m.Echo(text) arg[1] = kit.Select(arg[1], m.Conf(ice.WEB_STORY, kit.Keys("head.hash", arg[1], "list")))
}
// 查询节点
if node := m.Confm(ice.WEB_STORY, kit.Keys("hash", arg[1])); node != nil {
m.Push("list", arg[1])
m.Push(arg[1], node, []string{"scene", "story"})
arg[1] = kit.Format(node["data"])
}
// 查询数据
if node := m.Confm(ice.WEB_CACHE, kit.Keys("hash", arg[1])); node != nil {
m.Push("data", arg[1])
m.Push(arg[1], node, []string{"text", "time", "size", "type", "name", "file"})
m.Echo("%s", node["text"])
}
default:
m.Cmd(ice.WEB_STORY, "history", arg).Table(func(index int, value map[string]string, head []string) {
m.Push("time", value["time"])
m.Push("story", value["story"])
m.Push("text", value["text"])
m.Push("list", kit.Format(m.Conf(ice.WEB_STORY, kit.Keys(kit.MDB_META, "download")), value["key"], value["key"]))
})
} }
}}, }},
ice.WEB_CACHE: {Name: "cache", Help: "缓存", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { ice.WEB_CACHE: {Name: "cache", Help: "缓存", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(arg) == 0 { if len(arg) == 0 {
m.Confm("cache", "hash", func(key string, value map[string]interface{}) { // 缓存列表
m.Push(key, value, []string{"time", "text"}) m.Richs(ice.WEB_CACHE, nil, "", func(key string, value map[string]interface{}) {
m.Push(key, value, []string{kit.MDB_TIME, kit.MDB_NAME, kit.MDB_SIZE, kit.MDB_TYPE, kit.MDB_TEXT})
}) })
return return
} }
switch arg[0] { switch arg[0] {
case "upload":
// 打开文件
r := m.Optionv("request").(*http.Request)
if f, h, e := r.FormFile(kit.Select("upload", arg, 1)); m.Assert(e) {
defer f.Close()
// 创建文件
file := kit.Hashs(f)
if o, p, e := kit.Create(path.Join(m.Conf(ice.WEB_CACHE, ice.Meta("path")), file[:2], file)); m.Assert(e) {
defer o.Close()
// 保存文件
f.Seek(0, os.SEEK_SET)
if n, e := io.Copy(o, f); m.Assert(e) {
m.Info("upload: %s file: %s", kit.FmtSize(n), p)
arg = kit.Simple(arg[0], h.Header.Get("Content-Type"), h.Filename, p, p, n)
}
}
}
fallthrough
case "add": case "add":
// 添加数据 // 添加数据
data := m.Rich("cache", nil, map[string]interface{}{ size := kit.Select(kit.Format(len(arg[3])), arg, 5)
"time": m.Time(), "type": arg[1], arg[1]: arg[2], h := m.Rich(ice.WEB_CACHE, nil, kit.Dict(
}) kit.MDB_TYPE, arg[1], kit.MDB_NAME, arg[2], kit.MDB_TEXT, arg[3],
m.Info("data: %v type: %v text: %v", data, arg[1], arg[2]) kit.MDB_FILE, kit.Select("", arg, 4),
m.Echo(data) kit.MDB_SIZE, size, arg[1], arg[3],
m.Cmd("nfs.save", path.Join(m.Conf("cache", ice.Meta("path")), data[:2], data), arg[2]) ))
m.Info("cache: %s type: %s name: %s", h, arg[1], arg[2])
// 返回结果
m.Push("time", m.Time())
m.Push("type", arg[1])
m.Push("name", arg[2])
m.Push("text", arg[3])
m.Push("size", size)
m.Push("data", h)
// 保存数据
if arg[0] == "add" {
m.Cmd("nfs.save", path.Join(m.Conf(ice.WEB_CACHE, ice.Meta("path")), h[:2], h), arg[3])
}
default:
} }
}}, }},
ice.WEB_ROUTE: {Name: "route", Help: "路由", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { ice.WEB_ROUTE: {Name: "route", Help: "路由", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
@ -536,9 +650,9 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
if len(arg) == 0 { if len(arg) == 0 {
// 收藏门类 // 收藏门类
m.Richs(ice.WEB_FAVOR, nil, "", func(key string, value map[string]interface{}) { m.Richs(ice.WEB_FAVOR, nil, "", func(key string, value map[string]interface{}) {
m.Push("time", kit.Value(value, "meta.time"))
m.Push("favor", kit.Value(value, "meta.name")) m.Push("favor", kit.Value(value, "meta.name"))
m.Push("count", kit.Value(value, "meta.count")) m.Push("count", kit.Value(value, "meta.count"))
m.Push("time", kit.Value(value, "meta.create_time"))
}) })
return return
} }
@ -569,7 +683,14 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
if len(arg) == 1 { if len(arg) == 1 {
// 收藏列表 // 收藏列表
m.Grows(ice.WEB_FAVOR, kit.Keys(kit.MDB_HASH, favor), "", "", func(index int, value map[string]interface{}) { m.Grows(ice.WEB_FAVOR, kit.Keys(kit.MDB_HASH, favor), "", "", func(index int, value map[string]interface{}) {
m.Push(kit.Format(index), value, []string{"create_time", "id", "type", "name", "text"}) m.Push(kit.Format(index), value, []string{kit.MDB_TIME, kit.MDB_ID, kit.MDB_TYPE, kit.MDB_NAME})
switch kit.Format(value[kit.MDB_TYPE]) {
case kit.MIME_STORY:
m.Push(kit.MDB_TEXT, kit.Format(m.Conf(ice.WEB_STORY, kit.Keys(kit.MDB_META, "download")),
value[kit.MDB_TEXT], value[kit.MDB_TEXT]))
default:
m.Push(kit.MDB_TEXT, value[kit.MDB_TEXT])
}
}) })
return return
} }
@ -584,6 +705,9 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
}) })
return return
} }
if arg[1] == "file" {
arg[1] = kit.MIME_FILE
}
// 添加收藏 // 添加收藏
index := m.Grow(ice.WEB_FAVOR, kit.Keys(kit.MDB_HASH, favor), kit.Dict( index := m.Grow(ice.WEB_FAVOR, kit.Keys(kit.MDB_HASH, favor), kit.Dict(
@ -594,57 +718,58 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
}}, }},
ice.WEB_SHARE: {Name: "share", Help: "共享", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { ice.WEB_SHARE: {Name: "share", Help: "共享", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
if len(arg) == 0 { if len(arg) == 0 {
m.Confm(ice.WEB_SHARE, "hash", func(key string, value map[string]interface{}) { // 共享列表
m.Push(key, value) m.Richs(ice.WEB_SHARE, nil, "", func(key string, value map[string]interface{}) {
m.Push(key, value, []string{kit.MDB_TIME, kit.MDB_TYPE, kit.MDB_NAME})
m.Push("link", fmt.Sprintf(m.Conf(ice.WEB_SHARE, kit.Keys(kit.MDB_META, "href")), key, key))
}) })
return return
} }
m.Echo(m.Rich(ice.WEB_SHARE, nil, map[string]interface{}{
"create_time": m.Time(), "type": arg[0], "name": arg[1], "text": kit.Select("", arg, 2), // 创建共享
})) h := m.Rich(ice.WEB_SHARE, nil, kit.Dict(
kit.MDB_TYPE, arg[0], kit.MDB_NAME, arg[1], kit.MDB_TEXT, kit.Select("", arg, 2),
))
m.Info("share: %s", h)
m.Echo(h)
}}, }},
"/share/": &ice.Command{Name: "/share", Help: "共享", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
"/share/": {Name: "/share", Help: "共享", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
key := kit.Select("", strings.Split(cmd, "/"), 2) key := kit.Select("", strings.Split(cmd, "/"), 2)
m.Confm(ice.WEB_SHARE, kit.Keys("hash", key), func(value map[string]interface{}) { m.Confm(ice.WEB_SHARE, kit.Keys("hash", key), func(value map[string]interface{}) {
m.Push("content-type", "text/html") m.Info("share %s %v", key, kit.Format(value))
m.Echo(`<!DOCTYPE html>`) switch value["type"] {
m.Echo(`<head>`) case kit.MIME_STORY:
m.Echo(`<meta charset="utf-8">`) m.Cmdy(ice.WEB_STORY, "index", value["text"]).Push("_output", "file")
m.Echo(`<link rel="stylesheet" text="text/css" href="/style.css">`) return
m.Echo(`</head>`) default:
m.Echo(`<body>`) m.Push("_output", "result").Push(key, value)
m.Echo(`<fieldset>`) m.Render(m.Conf(ice.WEB_SHARE, kit.Keys(kit.MDB_META, "template", value["type"])))
key := kit.Keys("web.wiki", value["type"]) m.Append("type", "text/html")
if key == "web.wiki.chain" {
m.Cmdy("web.wiki.chart", "chain", value["name"], value["text"])
} else {
m.Cmdy(key, value["name"], "", value["text"])
} }
m.Echo(`</fieldset>`)
m.Echo(`</body>`)
}) })
}}, }},
"/space": {Name: "/space", Help: "空间站", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
"/space": &ice.Command{Name: "/space", Help: "空间站", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
r := m.Optionv("request").(*http.Request) r := m.Optionv("request").(*http.Request)
w := m.Optionv("response").(http.ResponseWriter) w := m.Optionv("response").(http.ResponseWriter)
if s, e := websocket.Upgrade(w, r, nil, m.Confi("web.space", "meta.buffer"), m.Confi("web.space", "meta.buffer")); m.Assert(e) {
h := m.Option("name")
meta := map[string]interface{}{ if s, e := websocket.Upgrade(w, r, nil, m.Confi(ice.WEB_SPACE, "meta.buffer"), m.Confi(ice.WEB_SPACE, "meta.buffer")); m.Assert(e) {
"create_time": m.Time(), // 添加节点
"socket": s, m.Rich(ice.WEB_SPACE, nil, kit.Dict(
"type": m.Option("node"), kit.MDB_TYPE, m.Option("node"),
"name": m.Option("name"), kit.MDB_NAME, m.Option("name"),
} kit.MDB_USER, m.Option("user"),
m.Confv(ice.WEB_SPACE, []string{kit.MDB_HASH, h}, meta) "socket", s,
m.Log("space", "conn %v %v", h, kit.Formats(m.Confv(ice.WEB_SPACE))) ))
m.Info("conn %s", m.Option(kit.MDB_NAME))
web := m.Target().Server().(*Frame)
m.Gos(m, func(m *ice.Message) { m.Gos(m, func(m *ice.Message) {
// 监听消息
web := m.Target().Server().(*Frame)
web.HandleWSS(m, false, s) web.HandleWSS(m, false, s)
m.Log("space", "close %v %v", h, kit.Formats(m.Confv(ice.WEB_SPACE))) m.Info("close %s %s", m.Option(kit.MDB_NAME), kit.Format(m.Confv(ice.WEB_SPACE, kit.Keys(kit.MDB_HASH, m.Option(kit.MDB_NAME)))))
m.Confv(ice.WEB_SPACE, []string{kit.MDB_HASH, h}, "") m.Confv(ice.WEB_SPACE, kit.Keys(kit.MDB_HASH, m.Option(kit.MDB_NAME)), "")
}) })
} }
}}, }},

11
conf.go
View File

@ -14,12 +14,20 @@ const (
CTX_COMMAND = "command" CTX_COMMAND = "command"
CTX_CONTEXT = "context" CTX_CONTEXT = "context"
) )
const (
CLI_RUNTIME = "runtime"
CLI_SYSTEM = "system"
)
const ( const (
MSG_DETAIL = "detail" MSG_DETAIL = "detail"
MSG_OPTION = "option" MSG_OPTION = "option"
MSG_APPEND = "append" MSG_APPEND = "append"
MSG_RESULT = "result" MSG_RESULT = "result"
MSG_SOURCE = "_source"
MSG_TARGET = "_target"
MSG_HANDLE = "_handle"
MSG_SESSID = "sessid" MSG_SESSID = "sessid"
MSG_USERNAME = "user.name" MSG_USERNAME = "user.name"
MSG_USERROLE = "user.role" MSG_USERROLE = "user.role"
@ -75,6 +83,9 @@ var Alias = map[string]string{
CTX_COMMAND: "ctx.command", CTX_COMMAND: "ctx.command",
CTX_CONTEXT: "ctx.context", CTX_CONTEXT: "ctx.context",
CLI_RUNTIME: "cli.runtime",
CLI_SYSTEM: "cli.system",
AAA_ROLE: "aaa.role", AAA_ROLE: "aaa.role",
AAA_USER: "aaa.user", AAA_USER: "aaa.user",
AAA_SESS: "aaa.sess", AAA_SESS: "aaa.sess",

View File

@ -49,7 +49,7 @@ var Index = &ice.Context{Name: "chat", Help: "聊天模块",
// 登录检查 // 登录检查
if m.Warn(!m.Options(ice.MSG_SESSID) || !m.Options(ice.MSG_USERNAME), "not login") { if m.Warn(!m.Options(ice.MSG_SESSID) || !m.Options(ice.MSG_USERNAME), "not login") {
m.Option("path", "") m.Option("url", "")
} }
}}, }},
@ -145,7 +145,7 @@ var Index = &ice.Context{Name: "chat", Help: "聊天模块",
if len(arg) < 2 { if len(arg) < 2 {
// 设备列表 // 设备列表
m.Richs(ice.WEB_SPACE, nil, "", func(key string, value map[string]interface{}) { m.Richs(ice.WEB_SPACE, nil, "", func(key string, value map[string]interface{}) {
m.Push(key, value, []string{"user", "node"}) m.Push(key, value, []string{"type", "name", "user"})
}) })
return return
} }

View File

@ -56,7 +56,26 @@ var Index = &ice.Context{Name: "code", Help: "编程模块",
}, },
Commands: map[string]*ice.Command{ Commands: map[string]*ice.Command{
ice.ICE_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { ice.ICE_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
m.Cmd(ice.GDB_EVENT, "listen", "miss.start", "web.code.docker", "image") }},
"/zsh": {Name: "/zsh", Help: "终端", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
m.Info("%s cmd: %s arg: %v sub: %v", cmd, m.Option("cmd"), m.Optionv("arg"), m.Optionv("sub"))
switch m.Option("cmd") {
case "upload":
// 上传文件
msg := m.Cmd(ice.WEB_STORY, "upload")
m.Push("_output", "result")
m.Echo("list: %s\n", msg.Append("list"))
m.Echo("data: %s\n", msg.Append("data"))
m.Echo("time: %s\n", msg.Append("time"))
m.Echo("type: %s\n", msg.Append("type"))
m.Echo("name: %s\n", msg.Append("name"))
m.Echo("size: %s\n", msg.Append("size"))
case "download":
// 下载文件
m.Cmdy(ice.WEB_STORY, "download", m.Optionv("arg"))
}
}}, }},
"tmux": {Name: "tmux [session [window [pane cmd]]]", Help: "窗口", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { "tmux": {Name: "tmux [session [window [pane cmd]]]", Help: "窗口", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
prefix := kit.Simple(m.Confv("prefix", "tmux")) prefix := kit.Simple(m.Confv("prefix", "tmux"))

View File

@ -162,7 +162,7 @@ var Index = &ice.Context{Name: "wiki", Help: "文档模块",
kit.Select("", arg, 0), m.Conf("note", ice.Meta("head"))) kit.Select("", arg, 0), m.Conf("note", ice.Meta("head")))
}}, }},
"note": {Name: "note file", Help: "笔记", Meta: map[string]interface{}{ "note": {Name: "note file", Help: "笔记", Meta: map[string]interface{}{
"remote": "true", "display": "inner", "remote": "you", "display": "inner",
"detail": []string{"add", "commit", "history", "share"}, "detail": []string{"add", "commit", "history", "share"},
}, List: kit.List( }, List: kit.List(
kit.MDB_INPUT, "text", "value", "miss.md", "name", "path", kit.MDB_INPUT, "text", "value", "miss.md", "name", "path",

View File

@ -155,6 +155,7 @@ var Index = &ice.Context{Name: "tmux", Help: "终端模块",
target := arg[0] target := arg[0]
if m.Cmd(prefix, "has-session", "-t", target).Append("code") != "0" { if m.Cmd(prefix, "has-session", "-t", target).Append("code") != "0" {
// 创建会话 // 创建会话
m.Option("cmd_env", "TMUX", "")
m.Cmd(prefix, "new-session", "-ds", arg[0]) m.Cmd(prefix, "new-session", "-ds", arg[0])
} }

36
type.go
View File

@ -549,13 +549,13 @@ func (m *Message) Optionv(key string, arg ...interface{}) interface{} {
m.meta[MSG_OPTION] = append(m.meta[MSG_OPTION], key) m.meta[MSG_OPTION] = append(m.meta[MSG_OPTION], key)
} }
switch arg := arg[0].(type) { switch str := arg[0].(type) {
case string: case string:
m.meta[key] = []string{arg} m.meta[key] = kit.Simple(arg)
case []string: case []string:
m.meta[key] = arg m.meta[key] = str
default: default:
m.data[key] = arg m.data[key] = str
} }
} }
@ -576,9 +576,12 @@ func (m *Message) Option(key string, arg ...interface{}) string {
return kit.Select("", kit.Simple(m.Optionv(key, arg...)), 0) return kit.Select("", kit.Simple(m.Optionv(key, arg...)), 0)
} }
func (m *Message) Append(key string, arg ...interface{}) string { func (m *Message) Append(key string, arg ...interface{}) string {
return kit.Select("", m.meta[key], 0) return kit.Select("", m.Appendv(key, arg...), 0)
} }
func (m *Message) Appendv(key string, arg ...interface{}) []string { func (m *Message) Appendv(key string, arg ...interface{}) []string {
if len(arg) > 0 {
m.meta[key] = kit.Simple(arg...)
}
return m.meta[key] return m.meta[key]
} }
func (m *Message) Resultv(arg ...interface{}) []string { func (m *Message) Resultv(arg ...interface{}) []string {
@ -824,9 +827,11 @@ func (m *Message) Richs(key string, chain interface{}, raw interface{}, cb inter
switch cb := cb.(type) { switch cb := cb.(type) {
case func(string, map[string]interface{}): case func(string, map[string]interface{}):
for k, v := range hash { for k, v := range hash {
cb(k, v.(map[string]interface{})) res = v.(map[string]interface{})
cb(k, res)
} }
} }
return res
case "%": case "%":
// 随机选取 // 随机选取
list := []string{} list := []string{}
@ -875,11 +880,8 @@ func (m *Message) Rich(key string, chain interface{}, data interface{}) string {
} }
// 通用数据 // 通用数据
if kit.Value(data, "meta") != nil { prefix := kit.Select("", "meta.", kit.Value(data, "meta") != nil)
kit.Value(data, "meta.create_time", m.Time()) kit.Value(data, prefix+kit.MDB_TIME, m.Time())
} else {
kit.Value(data, "create_time", m.Time())
}
// 生成键值 // 生成键值
h := "" h := ""
@ -918,13 +920,9 @@ func (m *Message) Grow(key string, chain interface{}, data interface{}) int {
// 通用数据 // 通用数据
id := kit.Int(meta["count"]) + 1 id := kit.Int(meta["count"]) + 1
if kit.Value(data, "meta") != nil { prefix := kit.Select("", "meta.", kit.Value(data, "meta") != nil)
kit.Value(data, "meta.id", id) kit.Value(data, prefix+kit.MDB_TIME, m.Time())
kit.Value(data, "meta.create_time", m.Time()) kit.Value(data, prefix+kit.MDB_ID, id)
} else {
kit.Value(data, "id", id)
kit.Value(data, "create_time", m.Time())
}
// 添加数据 // 添加数据
list = append(list, data) list = append(list, data)
@ -1120,6 +1118,8 @@ func (m *Message) Cmd(arg ...interface{}) *Message {
c.Run(msg, cmd, key, list[1:]...) c.Run(msg, cmd, key, list[1:]...)
}) })
}) })
m.Warn(m.Hand == false, "not found %v", list)
return m return m
} }
func (m *Message) Confv(arg ...interface{}) (val interface{}) { func (m *Message) Confv(arg ...interface{}) (val interface{}) {