forked from x/icebergs
add web.wiki
This commit is contained in:
parent
47bb65632d
commit
ab6bfe93d4
@ -1,6 +1,7 @@
|
||||
package ice
|
||||
|
||||
import (
|
||||
"github.com/shylinux/toolkits"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
@ -34,7 +35,10 @@ func (f *Frame) Start(m *Message, arg ...string) bool {
|
||||
|
||||
// 启动服务
|
||||
Index.begin.Cmd(arg)
|
||||
|
||||
return true
|
||||
}
|
||||
func (f *Frame) Close(m *Message, arg ...string) bool {
|
||||
// 保存配置
|
||||
m.Travel(func(p *Context, s *Context) {
|
||||
if cmd, ok := s.Commands["_exit"]; ok {
|
||||
msg := m.Spawns(s)
|
||||
@ -42,10 +46,7 @@ func (f *Frame) Start(m *Message, arg ...string) bool {
|
||||
cmd.Hand(msg, s, "_exit", arg...)
|
||||
}
|
||||
})
|
||||
// 保存配置
|
||||
return true
|
||||
}
|
||||
func (f *Frame) Close(m *Message, arg ...string) bool {
|
||||
|
||||
list := map[*Context]*Message{m.target: m}
|
||||
m.Travel(func(p *Context, s *Context) {
|
||||
if msg, ok := list[p]; ok && msg != nil {
|
||||
@ -59,13 +60,21 @@ func (f *Frame) Close(m *Message, arg ...string) bool {
|
||||
|
||||
var Index = &Context{Name: "ice", Help: "冰山模块",
|
||||
Caches: map[string]*Cache{},
|
||||
Configs: map[string]*Config{},
|
||||
Configs: map[string]*Config{
|
||||
"cache": {Name: "数据缓存", Value: map[string]interface{}{
|
||||
"store": "var/data",
|
||||
"limit": "30",
|
||||
"least": "10",
|
||||
}},
|
||||
},
|
||||
Commands: map[string]*Command{
|
||||
"_init": {Name: "_init", Help: "hello", Hand: func(m *Message, c *Context, cmd string, arg ...string) {
|
||||
m.Echo("hello %s world", c.Name)
|
||||
}},
|
||||
"hi": {Name: "hi", Help: "hello", Hand: func(m *Message, c *Context, cmd string, arg ...string) {
|
||||
m.Echo("hello %s world", c.Name)
|
||||
"exit": {Name: "exit", Help: "hello", Hand: func(m *Message, c *Context, cmd string, arg ...string) {
|
||||
c.Close(m.Spawn(c), arg...)
|
||||
os.Exit(kit.Int(kit.Select("0", arg, 0)))
|
||||
}},
|
||||
"_exit": {Name: "_init", Help: "hello", Hand: func(m *Message, c *Context, cmd string, arg ...string) {
|
||||
}},
|
||||
},
|
||||
}
|
||||
@ -89,6 +98,9 @@ func Run(arg ...string) string {
|
||||
if len(arg) == 0 {
|
||||
arg = os.Args[1:]
|
||||
}
|
||||
if len(arg) == 0 {
|
||||
arg = append(arg, os.Getenv("ice_serve"))
|
||||
}
|
||||
|
||||
if Index.Begin(Pulse.Spawns(), arg...).Start(Index.begin.Spawns(), arg...) {
|
||||
Index.Close(Index.start.Spawns(), arg...)
|
96
base/aaa/aaa.go
Normal file
96
base/aaa/aaa.go
Normal file
@ -0,0 +1,96 @@
|
||||
package aaa
|
||||
|
||||
import (
|
||||
"github.com/shylinux/icebergs"
|
||||
"github.com/shylinux/toolkits"
|
||||
)
|
||||
|
||||
var Index = &ice.Context{Name: "aaa", Help: "认证模块",
|
||||
Caches: map[string]*ice.Cache{},
|
||||
Configs: map[string]*ice.Config{
|
||||
"role": {Name: "role", Help: "角色", Value: map[string]interface{}{
|
||||
"meta": map[string]interface{}{},
|
||||
"hash": map[string]interface{}{
|
||||
"root": map[string]interface{}{},
|
||||
"tech": map[string]interface{}{},
|
||||
"void": map[string]interface{}{},
|
||||
},
|
||||
"list": map[string]interface{}{},
|
||||
}},
|
||||
"user": {Name: "user", Help: "用户", Value: map[string]interface{}{
|
||||
"meta": map[string]interface{}{},
|
||||
"hash": map[string]interface{}{},
|
||||
"list": map[string]interface{}{},
|
||||
}},
|
||||
"sess": {Name: "sess", Help: "会话", Value: map[string]interface{}{
|
||||
"meta": map[string]interface{}{"expire": "720h"},
|
||||
"hash": map[string]interface{}{},
|
||||
"list": map[string]interface{}{},
|
||||
}},
|
||||
},
|
||||
Commands: map[string]*ice.Command{
|
||||
"_init": {Name: "_init", Help: "加载", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
}},
|
||||
"_exit": {Name: "_exit", Help: "加载", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
}},
|
||||
"role": {Name: "role", Help: "角色", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
}},
|
||||
"user": {Name: "user", Help: "用户", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
switch arg[0] {
|
||||
case "login":
|
||||
user := m.Confm("user", "hash."+arg[1])
|
||||
if user == nil {
|
||||
m.Confv("user", "hash."+arg[1], map[string]interface{}{
|
||||
"create_time": m.Time(),
|
||||
"password": arg[2],
|
||||
"userrole": kit.Select("void", "root", arg[1] == m.Conf("cli.runtime", "boot.username")),
|
||||
})
|
||||
m.Log("info", "create user %s %s", arg[1], m.Conf("user", "hash."+arg[1]))
|
||||
} else if kit.Format(user["password"]) != arg[2] {
|
||||
m.Log("warn", "login fail %s", arg[1])
|
||||
// 登录失败
|
||||
break
|
||||
}
|
||||
|
||||
sessid := kit.Format(user["sessid"])
|
||||
if sessid == "" {
|
||||
sessid = m.Cmdx("aaa.sess", "login", arg[1])
|
||||
}
|
||||
|
||||
m.Grow("user", nil, map[string]interface{}{
|
||||
"create_time": m.Time(),
|
||||
"remote_ip": m.Option("remote_ip"),
|
||||
"username": arg[1],
|
||||
"sessid": sessid,
|
||||
})
|
||||
// 登录成功
|
||||
m.Echo(sessid)
|
||||
}
|
||||
}},
|
||||
"sess": {Name: "sess check|login", Help: "会话", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
switch arg[0] {
|
||||
case "check":
|
||||
|
||||
user := m.Conf("sess", "hash."+arg[1]+".username")
|
||||
if user != "" {
|
||||
m.Confm("user", "hash."+user, func(value map[string]interface{}) {
|
||||
m.Push("username", user)
|
||||
m.Push("userrole", value["userrole"])
|
||||
})
|
||||
}
|
||||
|
||||
m.Echo(user)
|
||||
case "login":
|
||||
sessid := kit.Hashs("uniq")
|
||||
m.Conf("sess", "hash."+sessid, map[string]interface{}{
|
||||
"create_time": m.Time(),
|
||||
"username": arg[1],
|
||||
})
|
||||
m.Log("info", "create sess %s %s", arg[1], sessid)
|
||||
m.Echo(sessid)
|
||||
}
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
func init() { ice.Index.Register(Index, nil) }
|
@ -39,6 +39,7 @@ var Index = &ice.Context{Name: "cli", Help: "命令模块",
|
||||
}
|
||||
|
||||
m.Conf("runtime", "node.type", "worker")
|
||||
m.Conf("runtime", "node.name", m.Conf("runtime", "boot.pathname"))
|
||||
m.Log("info", "runtime %v", kit.Formats(m.Confv("runtime")))
|
||||
}},
|
||||
"runtime": {Name: "runtime", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
85
base/ctx/ctx.go
Normal file
85
base/ctx/ctx.go
Normal file
@ -0,0 +1,85 @@
|
||||
package ctx
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/shylinux/icebergs"
|
||||
"github.com/shylinux/toolkits"
|
||||
"os"
|
||||
)
|
||||
|
||||
var Index = &ice.Context{Name: "ctx", Help: "元始模块",
|
||||
Caches: map[string]*ice.Cache{},
|
||||
Configs: map[string]*ice.Config{},
|
||||
Commands: map[string]*ice.Command{
|
||||
"command": {Name: "command", Help: "命令", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
if len(arg) == 0 {
|
||||
ice.Pulse.Travel(func(p *ice.Context, s *ice.Context) {
|
||||
for k, v := range s.Commands {
|
||||
if k[0] == '/' || k[0] == '_' {
|
||||
continue
|
||||
}
|
||||
if p != nil && p != ice.Index {
|
||||
m.Push("key", p.Name+"."+s.Name)
|
||||
} else {
|
||||
m.Push("key", s.Name)
|
||||
}
|
||||
m.Push("index", k)
|
||||
m.Push("name", v.Name)
|
||||
m.Push("help", v.Help)
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
m.Search(arg[0]+"."+arg[1], func(p *ice.Context, s *ice.Context, key string) {
|
||||
if i, ok := s.Commands[key]; ok {
|
||||
if len(arg) == 2 {
|
||||
m.Push("name", i.Name)
|
||||
m.Push("help", i.Help)
|
||||
m.Push("meta", kit.Format(i.Meta))
|
||||
m.Push("list", kit.Format(i.List))
|
||||
} else {
|
||||
switch arg[2] {
|
||||
case "run":
|
||||
m.Log("info", "run %s %s %v", s.Name, key, arg[3:])
|
||||
msg := m.Spawn(s)
|
||||
i.Hand(msg, s, key, arg[3:]...)
|
||||
m.Copy(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}},
|
||||
"config": {Name: "config", Help: "配置", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
switch arg[0] {
|
||||
case "save":
|
||||
if f, p, e := kit.Create(arg[1]); m.Assert(e) {
|
||||
data := map[string]interface{}{}
|
||||
for _, k := range arg[2:] {
|
||||
data[k] = m.Confv(k)
|
||||
}
|
||||
if s, e := json.MarshalIndent(data, "", " "); m.Assert(e) {
|
||||
if n, e := f.Write(s); m.Assert(e) {
|
||||
m.Log("info", "save %d %s", n, p)
|
||||
}
|
||||
}
|
||||
m.Echo(p)
|
||||
}
|
||||
case "load":
|
||||
if f, e := os.Open(arg[1]); e == nil {
|
||||
data := map[string]interface{}{}
|
||||
json.NewDecoder(f).Decode(&data)
|
||||
|
||||
for k, v := range data {
|
||||
m.Search(k, func(p *ice.Context, s *ice.Context, key string) {
|
||||
m.Log("info", "load %s.%s %v", s.Name, key, kit.Format(v))
|
||||
s.Configs[key].Value = v
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
func init() { ice.Index.Register(Index, nil) }
|
97
base/gdb/gdb.go
Normal file
97
base/gdb/gdb.go
Normal file
@ -0,0 +1,97 @@
|
||||
package gdb
|
||||
|
||||
import (
|
||||
"github.com/shylinux/icebergs"
|
||||
"github.com/shylinux/toolkits"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Frame struct {
|
||||
signal chan os.Signal
|
||||
}
|
||||
|
||||
func (f *Frame) Spawn(m *ice.Message, c *ice.Context, arg ...string) ice.Server {
|
||||
return &Frame{}
|
||||
}
|
||||
func (f *Frame) Begin(m *ice.Message, arg ...string) ice.Server {
|
||||
if f, p, e := kit.Create(m.Conf("logpid")); m.Assert(e) {
|
||||
defer f.Close()
|
||||
f.WriteString(kit.Format(os.Getpid()))
|
||||
m.Log("info", "pid %d %s", os.Getpid(), p)
|
||||
}
|
||||
|
||||
f.signal = make(chan os.Signal, 10)
|
||||
m.Confm("signal", nil, func(sig string, action string) {
|
||||
m.Log("signal", "add %s: %s", sig, action)
|
||||
signal.Notify(f.signal, syscall.Signal(kit.Int(sig)))
|
||||
})
|
||||
|
||||
m.Gos(m, func(m *ice.Message) {
|
||||
if s, ok := <-f.signal; ok {
|
||||
m.Log("info", "signal %v", s)
|
||||
m.Cmd(m.Confv("signal", kit.Format(s)))
|
||||
}
|
||||
})
|
||||
m.Gos(m, func(m *ice.Message) {
|
||||
for {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
now := int(time.Now().Unix())
|
||||
m.Confm("timer", "hash", func(key string, value map[string]interface{}) {
|
||||
if kit.Int(value["next"]) <= now {
|
||||
m.Log("info", "timer %v %v", key, value["next"])
|
||||
m.Cmd(value["cmd"])
|
||||
value["next"] = now + int(kit.Duration(value["interval"]))/int(time.Second)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
return f
|
||||
}
|
||||
func (f *Frame) Start(m *ice.Message, arg ...string) bool {
|
||||
return true
|
||||
}
|
||||
func (f *Frame) Close(m *ice.Message, arg ...string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
var Index = &ice.Context{Name: "gdb", Help: "调试模块",
|
||||
Caches: map[string]*ice.Cache{},
|
||||
Configs: map[string]*ice.Config{
|
||||
"logpid": &ice.Config{Name: "logpid", Value: "var/run/shy.pid", Help: ""},
|
||||
"signal": &ice.Config{Name: "signal", Value: map[string]interface{}{
|
||||
"2": []interface{}{"exit"}, "3": "QUIT", "15": "TERM",
|
||||
"28": "WINCH",
|
||||
"30": "restart",
|
||||
"31": "upgrade",
|
||||
}, Help: "信号"},
|
||||
"timer": {Name: "定时器", Value: map[string]interface{}{
|
||||
"meta": map[string]interface{}{},
|
||||
"hash": map[string]interface{}{},
|
||||
"list": map[string]interface{}{},
|
||||
}},
|
||||
},
|
||||
Commands: map[string]*ice.Command{
|
||||
"timer": {Name: "timer", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
switch arg[0] {
|
||||
case "start":
|
||||
h := kit.ShortKey(m.Confm("timer", "hash"), 6)
|
||||
|
||||
next := time.Now().Add(kit.Duration(arg[1])).Unix()
|
||||
m.Conf("timer", "hash."+h, map[string]interface{}{
|
||||
"interval": arg[1],
|
||||
"next": next,
|
||||
"cmd": arg[2:],
|
||||
})
|
||||
m.Echo(h)
|
||||
|
||||
case "stop":
|
||||
m.Conf("timer", "hash."+arg[1], "")
|
||||
}
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
func init() { ice.Index.Register(Index, &Frame{}) }
|
140
base/nfs/nfs.go
Normal file
140
base/nfs/nfs.go
Normal file
@ -0,0 +1,140 @@
|
||||
package nfs
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/sha1"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/shylinux/icebergs"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func dir(m *ice.Message, root string, name string, level int, deep bool, dir_type string, dir_reg *regexp.Regexp, fields []string, format string) {
|
||||
|
||||
if fs, e := ioutil.ReadDir(name); m.Assert(e) {
|
||||
for _, f := range fs {
|
||||
if f.Name() == "." || f.Name() == ".." {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(f.Name(), ".") && dir_type != "all" {
|
||||
continue
|
||||
}
|
||||
|
||||
p := path.Join(name, f.Name())
|
||||
if f, e = os.Lstat(p); e != nil {
|
||||
m.Log("info", "%s", e)
|
||||
continue
|
||||
} else if (f.Mode()&os.ModeSymlink) != 0 && f.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
if !(dir_type == "file" && f.IsDir() || dir_type == "dir" && !f.IsDir()) && (dir_reg == nil || dir_reg.MatchString(f.Name())) {
|
||||
for _, field := range fields {
|
||||
switch field {
|
||||
case "time":
|
||||
m.Push("time", f.ModTime().Format(format))
|
||||
case "type":
|
||||
if m.Assert(e) && f.IsDir() {
|
||||
m.Push("type", "dir")
|
||||
} else {
|
||||
m.Push("type", "file")
|
||||
}
|
||||
case "full":
|
||||
if f.IsDir() {
|
||||
m.Push("full", path.Join(root, name, f.Name())+"/")
|
||||
} else {
|
||||
m.Push("full", path.Join(root, name, f.Name()))
|
||||
}
|
||||
case "path":
|
||||
if f.IsDir() {
|
||||
m.Push("path", path.Join(name, f.Name())+"/")
|
||||
} else {
|
||||
m.Push("path", path.Join(name, f.Name()))
|
||||
}
|
||||
case "file":
|
||||
if f.IsDir() {
|
||||
m.Push("file", f.Name()+"/")
|
||||
} else {
|
||||
m.Push("file", f.Name())
|
||||
}
|
||||
case "name":
|
||||
m.Push("name", f.Name())
|
||||
case "tree":
|
||||
if level == 0 {
|
||||
m.Push("tree", f.Name())
|
||||
} else {
|
||||
m.Push("tree", strings.Repeat("| ", level-1)+"|-"+f.Name())
|
||||
}
|
||||
case "size":
|
||||
m.Push("size", f.Size())
|
||||
case "line":
|
||||
if f.IsDir() {
|
||||
if d, e := ioutil.ReadDir(p); m.Assert(e) {
|
||||
count := 0
|
||||
for _, f := range d {
|
||||
if strings.HasPrefix(f.Name(), ".") {
|
||||
continue
|
||||
}
|
||||
count++
|
||||
}
|
||||
m.Push("line", count)
|
||||
}
|
||||
} else {
|
||||
nline := 0
|
||||
if f, e := os.Open(p); m.Assert(e) {
|
||||
defer f.Close()
|
||||
for bio := bufio.NewScanner(f); bio.Scan(); nline++ {
|
||||
bio.Text()
|
||||
}
|
||||
}
|
||||
m.Push("line", nline)
|
||||
}
|
||||
case "hash", "hashs":
|
||||
var h [20]byte
|
||||
if f.IsDir() {
|
||||
if d, e := ioutil.ReadDir(p); m.Assert(e) {
|
||||
meta := []string{}
|
||||
for _, v := range d {
|
||||
meta = append(meta, fmt.Sprintf("%s%d%s", v.Name(), v.Size(), v.ModTime()))
|
||||
}
|
||||
sort.Strings(meta)
|
||||
h = sha1.Sum([]byte(strings.Join(meta, "")))
|
||||
}
|
||||
} else {
|
||||
if f, e := ioutil.ReadFile(path.Join(name, f.Name())); m.Assert(e) {
|
||||
h = sha1.Sum(f)
|
||||
}
|
||||
}
|
||||
if field == "hash" {
|
||||
m.Push("hash", hex.EncodeToString(h[:]))
|
||||
} else {
|
||||
m.Push("hash", hex.EncodeToString(h[:4]))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if f.IsDir() && deep {
|
||||
dir(m, root, p, level+1, deep, dir_type, dir_reg, fields, format)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var Index = &ice.Context{Name: "nfs", Help: "文件模块",
|
||||
Caches: map[string]*ice.Cache{},
|
||||
Configs: map[string]*ice.Config{},
|
||||
Commands: map[string]*ice.Command{
|
||||
"dir": {Name: "dir", Help: "目录", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
rg, _ := regexp.Compile(m.Option("dir_reg"))
|
||||
dir(m, arg[0], arg[1], 0, false, "both", rg,
|
||||
strings.Split("time size line path", " "), "2006-01-02 15:04:05")
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
func init() { ice.Index.Register(Index, nil) }
|
11
base/shy.go
Normal file
11
base/shy.go
Normal file
@ -0,0 +1,11 @@
|
||||
package shy
|
||||
|
||||
import (
|
||||
_ "github.com/shylinux/icebergs/base/aaa"
|
||||
_ "github.com/shylinux/icebergs/base/cli"
|
||||
_ "github.com/shylinux/icebergs/base/ctx"
|
||||
_ "github.com/shylinux/icebergs/base/gdb"
|
||||
_ "github.com/shylinux/icebergs/base/log"
|
||||
_ "github.com/shylinux/icebergs/base/nfs"
|
||||
_ "github.com/shylinux/icebergs/base/web"
|
||||
)
|
@ -1,15 +1,20 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/shylinux/icebergs"
|
||||
"github.com/shylinux/toolkits"
|
||||
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -24,6 +29,22 @@ type WEB struct {
|
||||
send map[string]*ice.Message
|
||||
}
|
||||
|
||||
func Cookie(msg *ice.Message, sessid string) string {
|
||||
w := msg.Optionv("response").(http.ResponseWriter)
|
||||
expire := time.Now().Add(kit.Duration(msg.Conf("aaa.sess", "meta.expire")))
|
||||
msg.Log("cookie", "expire %v sessid %s", kit.Format(expire), sessid)
|
||||
http.SetCookie(w, &http.Cookie{Name: "sessid", Value: sessid, Path: "/", Expires: expire})
|
||||
return sessid
|
||||
}
|
||||
|
||||
func (web *WEB) Login(msg *ice.Message, w http.ResponseWriter, r *http.Request) bool {
|
||||
if msg.Options("sessid") {
|
||||
sub := msg.Cmd("aaa.sess", "check", msg.Option("sessid"))
|
||||
msg.Log("info", "user %s %s", msg.Option("userrole", sub.Append("userrole")),
|
||||
msg.Option("username", sub.Append("username")))
|
||||
}
|
||||
return true
|
||||
}
|
||||
func (web *WEB) HandleWSS(m *ice.Message, safe bool, c *websocket.Conn) {
|
||||
for {
|
||||
if t, b, e := c.ReadMessage(); e != nil {
|
||||
@ -61,7 +82,11 @@ func (web *WEB) HandleWSS(m *ice.Message, safe bool, c *websocket.Conn) {
|
||||
} else {
|
||||
msg.Log("space", "run")
|
||||
// 本地执行
|
||||
if safe {
|
||||
msg = msg.Cmd()
|
||||
} else {
|
||||
msg.Echo("no right")
|
||||
}
|
||||
msg.Optionv("_handle", "true")
|
||||
kit.Revert(source)
|
||||
source, target = []string{source[0]}, source[1:]
|
||||
@ -76,11 +101,53 @@ func (web *WEB) HandleWSS(m *ice.Message, safe bool, c *websocket.Conn) {
|
||||
}
|
||||
}
|
||||
}
|
||||
func (web *WEB) HandleCGI(m *ice.Message, which string) *template.Template {
|
||||
cgi := template.FuncMap{
|
||||
"result": func(msg *ice.Message) string {
|
||||
return msg.Result()
|
||||
},
|
||||
}
|
||||
tmpl := template.New("render")
|
||||
for k, v := range m.Target().Commands {
|
||||
m.Log("info", "%v, %v", k, v.Name)
|
||||
if strings.HasPrefix(k, "/") || strings.HasPrefix(k, "_") {
|
||||
continue
|
||||
}
|
||||
|
||||
func(k string, v *ice.Command) {
|
||||
cgi[k] = func(arg ...interface{}) (res interface{}) {
|
||||
m.TryCatch(m.Spawn(), true, func(msg *ice.Message) {
|
||||
msg.Option("render", "table")
|
||||
v.Hand(msg, m.Target(), k, kit.Simple(arg)...)
|
||||
|
||||
buffer := bytes.NewBuffer([]byte{})
|
||||
m.Assert(tmpl.ExecuteTemplate(buffer, msg.Option("render"), msg))
|
||||
res = string(buffer.Bytes())
|
||||
})
|
||||
return
|
||||
}
|
||||
}(k, v)
|
||||
}
|
||||
tmpl = tmpl.Funcs(cgi)
|
||||
tmpl = template.Must(tmpl.ParseGlob(path.Join(m.Conf("serve", "template.path"), "/*.tmpl")))
|
||||
tmpl = template.Must(tmpl.ParseGlob(path.Join(m.Conf("serve", "template.path"), m.Target().Name, "/*.tmpl")))
|
||||
tmpl = template.Must(tmpl.ParseFiles(which))
|
||||
m.Confm("serve", "template.list", func(index int, value string) { tmpl = template.Must(tmpl.Parse(value)) })
|
||||
for i, v := range tmpl.Templates() {
|
||||
m.Log("info", "%v, %v", i, v.Name())
|
||||
}
|
||||
return tmpl
|
||||
}
|
||||
func (web *WEB) 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.Log("cost", msg.Format("cost"))
|
||||
}()
|
||||
|
||||
msg.Optionv("request", r)
|
||||
msg.Optionv("response", w)
|
||||
msg.Option("remote_ip", r.Header.Get("remote_ip"))
|
||||
msg.Option("agent", r.Header.Get("User-Agent"))
|
||||
msg.Option("referer", r.Header.Get("Referer"))
|
||||
msg.Option("accept", r.Header.Get("Accept"))
|
||||
@ -129,14 +196,12 @@ func (web *WEB) HandleCmd(m *ice.Message, key string, cmd *ice.Command) {
|
||||
}
|
||||
}
|
||||
|
||||
if web.Login(msg, w, r) {
|
||||
msg.Log("cmd", "%s %s", msg.Target().Name, key)
|
||||
cmd.Hand(msg, msg.Target(), msg.Option("path"))
|
||||
cmd.Hand(msg, msg.Target(), msg.Option("path"), kit.Simple(msg.Optionv("cmds"))...)
|
||||
msg.Set("option")
|
||||
if msg.Optionv("append") == nil {
|
||||
msg.Result()
|
||||
}
|
||||
w.Write([]byte(msg.Formats("meta")))
|
||||
msg.Log("cost", msg.Format("cost"))
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -176,16 +241,23 @@ func (web *WEB) Start(m *ice.Message, arg ...string) bool {
|
||||
if w.ServeMux != nil {
|
||||
return
|
||||
}
|
||||
|
||||
msg := m.Spawns(s)
|
||||
w.ServeMux = http.NewServeMux()
|
||||
msg := m.Spawns(s)
|
||||
|
||||
// 级联路由
|
||||
route := "/" + s.Name + "/"
|
||||
if n, ok := p.Server().(*WEB); ok && n.ServeMux != nil {
|
||||
msg.Log("route", "%s <- %s", p.Name, route)
|
||||
n.Handle(route, http.StripPrefix(path.Dir(route), w))
|
||||
}
|
||||
|
||||
// 静态路由
|
||||
m.Confm("web.serve", "static", func(key string, value string) {
|
||||
msg.Log("route", "%s <- %s <- %s", s.Name, key, value)
|
||||
w.Handle(key, http.StripPrefix(key, http.FileServer(http.Dir(value))))
|
||||
})
|
||||
|
||||
// 命令路由
|
||||
for k, x := range s.Commands {
|
||||
if k[0] == '/' {
|
||||
msg.Log("route", "%s <- %s", s.Name, k)
|
||||
@ -212,9 +284,23 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
|
||||
"spide": {Name: "客户端", Value: map[string]interface{}{
|
||||
"self": map[string]interface{}{"port": ":9020"},
|
||||
}},
|
||||
"serve": {Name: "服务端", Value: map[string]interface{}{}},
|
||||
"serve": {Name: "服务端", Value: map[string]interface{}{
|
||||
"static": map[string]interface{}{"/": "usr/volcanos/",
|
||||
"/static/volcanos/": "usr/volcanos/",
|
||||
},
|
||||
"template": map[string]interface{}{
|
||||
"path": "usr/template",
|
||||
"list": []interface{}{
|
||||
`{{define "raw"}}{{.|result}}{{end}}`,
|
||||
`{{define "title"}}{{.|result}}{{end}}`,
|
||||
`{{define "chapter"}}{{.|result}}{{end}}`,
|
||||
`{{define "section"}}{{.|result}}{{end}}`,
|
||||
`{{define "block"}}<div>{{.|result}}<div>{{end}}`,
|
||||
},
|
||||
},
|
||||
}},
|
||||
"space": {Name: "空间端", Value: map[string]interface{}{
|
||||
"meta": map[string]interface{}{"buffer": 4096},
|
||||
"meta": map[string]interface{}{"buffer": 4096, "redial": 3000},
|
||||
"hash": map[string]interface{}{},
|
||||
"list": map[string]interface{}{},
|
||||
}},
|
||||
@ -259,16 +345,22 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
|
||||
host := kit.Select(m.Conf("web.spide", "self.port"), arg, 1)
|
||||
p := "ws://" + host + kit.Select("/space", arg, 2) + "?node=" + node + "&name=" + name
|
||||
|
||||
if s, e := net.Dial("tcp", host); m.Assert(e) {
|
||||
if u, e := url.Parse(p); m.Assert(e) {
|
||||
if s, _, e := websocket.NewClient(s, u, nil, m.Confi("web.space", "meta.buffer"), m.Confi("web.space", "meta.buffer")); m.Assert(e) {
|
||||
|
||||
m.TryCatch(m, true, func(m *ice.Message) {
|
||||
for {
|
||||
if s, e := net.Dial("tcp", host); e == nil {
|
||||
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"})
|
||||
web.send[id] = m
|
||||
s.WriteMessage(MSG_MAPS, []byte(m.Format("meta")))
|
||||
|
||||
web.HandleWSS(m, true, s)
|
||||
}
|
||||
}
|
||||
time.Sleep(time.Duration(rand.Intn(m.Confi("web.space", "meta.redial"))) * time.Millisecond)
|
||||
m.Log("info", "reconnect %v", host)
|
||||
}
|
||||
})
|
||||
}
|
||||
default:
|
||||
if arg[0] == "" {
|
@ -1,17 +0,0 @@
|
||||
package aaa
|
||||
|
||||
import (
|
||||
"github.com/shylinux/icebergs"
|
||||
)
|
||||
|
||||
var Index = &ice.Context{Name: "aaa", Help: "认证模块",
|
||||
Caches: map[string]*ice.Cache{},
|
||||
Configs: map[string]*ice.Config{},
|
||||
Commands: map[string]*ice.Command{
|
||||
"hi": {Name: "hi", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
m.Echo("hello %s world", c.Name)
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
func init() { ice.Index.Register(Index, nil) }
|
166
core/chat/chat.go
Normal file
166
core/chat/chat.go
Normal file
@ -0,0 +1,166 @@
|
||||
package chat
|
||||
|
||||
import (
|
||||
"github.com/shylinux/icebergs"
|
||||
_ "github.com/shylinux/icebergs/base"
|
||||
"github.com/shylinux/icebergs/base/web"
|
||||
"github.com/shylinux/toolkits"
|
||||
)
|
||||
|
||||
var Index = &ice.Context{Name: "chat", Help: "聊天模块",
|
||||
Caches: map[string]*ice.Cache{},
|
||||
Configs: map[string]*ice.Config{
|
||||
"group": {Name: "group", Value: map[string]interface{}{
|
||||
"meta": map[string]interface{}{},
|
||||
"list": map[string]interface{}{},
|
||||
"hash": map[string]interface{}{},
|
||||
}},
|
||||
},
|
||||
Commands: map[string]*ice.Command{
|
||||
"_init": {Name: "_init", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
m.Cmd("ctx.config", "load", "var/conf/cli.json")
|
||||
m.Cmd("ctx.config", "load", "var/conf/aaa.json")
|
||||
m.Cmd("ctx.config", "load", "var/conf/chat.json")
|
||||
}},
|
||||
"_exit": {Name: "_init", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
m.Cmd("ctx.config", "save", "var/conf/chat.json", "web.chat.group")
|
||||
m.Cmd("ctx.config", "save", "var/conf/aaa.json", "aaa.role", "aaa.user", "aaa.sess")
|
||||
m.Cmd("ctx.config", "save", "var/conf/cli.json", "cli.runtime")
|
||||
}},
|
||||
"/login": {Name: "/login", Help: "登录", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
switch arg[0] {
|
||||
case "check":
|
||||
m.Push("username", m.Option("username"))
|
||||
m.Push("userrole", m.Option("userrole"))
|
||||
m.Echo(m.Option("username"))
|
||||
case "login":
|
||||
m.Echo(web.Cookie(m, m.Cmdx("aaa.user", "login", arg[1], arg[2])))
|
||||
}
|
||||
}},
|
||||
"/favor": {Name: "/favor", Help: "登录", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
m.Cmdy("cli.system", arg)
|
||||
}},
|
||||
"/ocean": {Name: "/ocean", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
if len(arg) == 0 {
|
||||
m.Confm("aaa.user", "hash", func(key string, value map[string]interface{}) {
|
||||
m.Push("key", key)
|
||||
m.Push("user.route", m.Conf("cli.runtime", "node.name"))
|
||||
})
|
||||
return
|
||||
}
|
||||
switch arg[0] {
|
||||
case "spawn":
|
||||
if arg[1] == "" {
|
||||
arg[1] = kit.ShortKey(m.Confm("group", "hash"), 6)
|
||||
}
|
||||
user := map[string]interface{}{
|
||||
"meta": map[string]interface{}{},
|
||||
"hash": map[string]interface{}{},
|
||||
"list": []interface{}{},
|
||||
}
|
||||
tool := map[string]interface{}{
|
||||
"meta": map[string]interface{}{},
|
||||
"hash": map[string]interface{}{},
|
||||
"list": []interface{}{},
|
||||
}
|
||||
for _, v := range arg[3:] {
|
||||
kit.Value(user, "hash."+v, map[string]interface{}{
|
||||
"create_time": m.Time(),
|
||||
})
|
||||
kit.Value(user, "list."+v+".-2", map[string]interface{}{
|
||||
"create_time": m.Time(),
|
||||
"operation": "add",
|
||||
"username": v,
|
||||
})
|
||||
}
|
||||
|
||||
m.Conf("group", "hash."+arg[1], map[string]interface{}{
|
||||
"meta": map[string]interface{}{
|
||||
"create_time": m.Time(),
|
||||
"name": arg[2],
|
||||
},
|
||||
"user": user,
|
||||
"tool": tool,
|
||||
})
|
||||
|
||||
m.Log("info", "river create %v %v", arg[1], kit.Formats(m.Confv("group", "hash."+arg[1])))
|
||||
m.Echo(arg[1])
|
||||
}
|
||||
}},
|
||||
"/river": {Name: "/river", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
if len(arg) == 0 {
|
||||
m.Confm("group", "hash", func(key string, value map[string]interface{}) {
|
||||
m.Push("key", key)
|
||||
m.Push("name", kit.Value(value["meta"], "name"))
|
||||
})
|
||||
return
|
||||
}
|
||||
}},
|
||||
"/action": {Name: "/action", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
if len(arg) == 2 {
|
||||
m.Confm("group", "hash."+arg[0]+".tool.hash."+arg[1]+".list", func(index int, value map[string]interface{}) {
|
||||
m.Push("river", arg[0])
|
||||
m.Push("storm", arg[1])
|
||||
m.Push("action", index)
|
||||
|
||||
m.Push("node", value["pod"])
|
||||
m.Push("group", value["ctx"])
|
||||
m.Push("index", value["cmd"])
|
||||
|
||||
msg := m.Cmd("web.space", value["pod"], "ctx.command", value["ctx"], value["cmd"])
|
||||
m.Push("name", value["cmd"])
|
||||
m.Push("help", msg.Append("help"))
|
||||
m.Push("inputs", msg.Append("list"))
|
||||
m.Push("feature", msg.Append("meta"))
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
m.Confm("group", "hash."+arg[0]+".tool.hash."+arg[1]+".list."+arg[2], func(value map[string]interface{}) {
|
||||
m.Cmdy("web.space", value["pod"], "ctx.command", value["ctx"], value["cmd"], "run", arg[3:])
|
||||
})
|
||||
}},
|
||||
"/storm": {Name: "/storm", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
if len(arg) < 2 {
|
||||
m.Confm("group", "hash."+arg[0]+".tool.hash", func(key string, value map[string]interface{}) {
|
||||
m.Push("key", key).Push("count", len(value["list"].([]interface{})))
|
||||
})
|
||||
return
|
||||
}
|
||||
}},
|
||||
"/steam": {Name: "/steam", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
if len(arg) < 2 {
|
||||
m.Confm("web.space", "hash", func(key string, value map[string]interface{}) {
|
||||
m.Push("user", m.Conf("cli.runtime", "boot.username"))
|
||||
m.Push("node", value["name"])
|
||||
})
|
||||
return
|
||||
}
|
||||
switch arg[1] {
|
||||
case "spawn":
|
||||
list := []interface{}{}
|
||||
for i := 3; i < len(arg)-3; i += 4 {
|
||||
list = append(list, map[string]interface{}{
|
||||
"pod": arg[i],
|
||||
"ctx": arg[i+1],
|
||||
"cmd": arg[i+2],
|
||||
"key": arg[i+3],
|
||||
})
|
||||
}
|
||||
m.Conf("group", "hash."+arg[0]+".tool.hash."+arg[2], map[string]interface{}{
|
||||
"meta": map[string]interface{}{
|
||||
"create_time": m.Time(),
|
||||
},
|
||||
"hash": map[string]interface{}{},
|
||||
"list": list,
|
||||
})
|
||||
|
||||
m.Log("info", "steam spawn %v %v %v", arg[0], arg[2], list)
|
||||
default:
|
||||
m.Cmdy("web.space", arg[2], "ctx.command")
|
||||
}
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
func init() { web.Index.Register(Index, &web.WEB{}) }
|
@ -1,17 +0,0 @@
|
||||
package ctx
|
||||
|
||||
import (
|
||||
"github.com/shylinux/icebergs"
|
||||
)
|
||||
|
||||
var Index = &ice.Context{Name: "ctx", Help: "元始模块",
|
||||
Caches: map[string]*ice.Cache{},
|
||||
Configs: map[string]*ice.Config{},
|
||||
Commands: map[string]*ice.Command{
|
||||
"hi": {Name: "hi", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
m.Echo("hello %s world", c.Name)
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
func init() { ice.Index.Register(Index, nil) }
|
@ -1,17 +0,0 @@
|
||||
package gdb
|
||||
|
||||
import (
|
||||
"github.com/shylinux/icebergs"
|
||||
)
|
||||
|
||||
var Index = &ice.Context{Name: "gdb", Help: "调试模块",
|
||||
Caches: map[string]*ice.Cache{},
|
||||
Configs: map[string]*ice.Config{},
|
||||
Commands: map[string]*ice.Command{
|
||||
"hi": {Name: "hi", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
m.Echo("hello %s world", c.Name)
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
func init() { ice.Index.Register(Index, nil) }
|
@ -1,17 +0,0 @@
|
||||
package nfs
|
||||
|
||||
import (
|
||||
"github.com/shylinux/icebergs"
|
||||
)
|
||||
|
||||
var Index = &ice.Context{Name: "nfs", Help: "文件模块",
|
||||
Caches: map[string]*ice.Cache{},
|
||||
Configs: map[string]*ice.Config{},
|
||||
Commands: map[string]*ice.Command{
|
||||
"hi": {Name: "hi", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
m.Echo("hello %s world", c.Name)
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
func init() { ice.Index.Register(Index, nil) }
|
276
core/wiki/chart.go
Normal file
276
core/wiki/chart.go
Normal file
@ -0,0 +1,276 @@
|
||||
package wiki
|
||||
|
||||
import (
|
||||
"github.com/shylinux/icebergs"
|
||||
"github.com/shylinux/toolkits"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 图形接口
|
||||
type Chart interface {
|
||||
Init(*ice.Message, ...string) Chart
|
||||
Draw(*ice.Message, int, int) Chart
|
||||
|
||||
GetWidth(...string) int
|
||||
GetHeight(...string) int
|
||||
}
|
||||
|
||||
// 图形基类
|
||||
type Block struct {
|
||||
Text string
|
||||
FontColor string
|
||||
FontFamily string
|
||||
BackGround string
|
||||
|
||||
FontSize int
|
||||
LineSize int
|
||||
Padding int
|
||||
Margin int
|
||||
|
||||
Width, Height int
|
||||
|
||||
TextData string
|
||||
RectData string
|
||||
}
|
||||
|
||||
func (b *Block) Init(m *ice.Message, arg ...string) Chart {
|
||||
b.Text = kit.Select(b.Text, arg, 0)
|
||||
b.FontColor = kit.Select("white", kit.Select(b.FontColor, arg, 1))
|
||||
b.BackGround = kit.Select("red", kit.Select(b.BackGround, arg, 2))
|
||||
b.FontSize = kit.Int(kit.Select("24", kit.Select(kit.Format(b.FontSize), arg, 3)))
|
||||
b.LineSize = kit.Int(kit.Select("12", kit.Select(kit.Format(b.LineSize), arg, 4)))
|
||||
return b
|
||||
}
|
||||
func (b *Block) Draw(m *ice.Message, x, y int) Chart {
|
||||
m.Echo(`<rect x="%d" y="%d" width="%d" height="%d" fill="%s" %v/>`,
|
||||
x+b.Margin/2, y+b.Margin/2, b.GetWidth(), b.GetHeight(), b.BackGround, b.RectData)
|
||||
m.Echo("\n")
|
||||
m.Echo(`<text x="%d" y="%d" font-size="%d" style="dominant-baseline:middle;text-anchor:middle;" fill="%s" %v>%v</text>`,
|
||||
x+b.GetWidths()/2, y+b.GetHeights()/2, b.FontSize, b.FontColor, b.TextData, b.Text)
|
||||
m.Echo("\n")
|
||||
return b
|
||||
}
|
||||
func (b *Block) Data(root interface{}) {
|
||||
kit.Table(kit.Value(root, "data"), 0, 100, func(key string, value string) {
|
||||
b.TextData += key + "='" + value + "' "
|
||||
})
|
||||
kit.Table(kit.Value(root, "rect"), 0, 100, func(key string, value string) {
|
||||
b.RectData += key + "='" + value + "' "
|
||||
})
|
||||
b.FontColor = kit.Select(b.FontColor, kit.Value(root, "fg"))
|
||||
b.BackGround = kit.Select(b.BackGround, kit.Value(root, "bg"))
|
||||
}
|
||||
func (b *Block) GetWidth(str ...string) int {
|
||||
if b.Width != 0 {
|
||||
return b.Width
|
||||
}
|
||||
return len(kit.Select(b.Text, str, 0))*b.FontSize*6/10 + b.Padding
|
||||
}
|
||||
func (b *Block) GetHeight(str ...string) int {
|
||||
if b.Height != 0 {
|
||||
return b.Height
|
||||
}
|
||||
return b.FontSize*b.LineSize/10 + b.Padding
|
||||
}
|
||||
func (b *Block) GetWidths(str ...string) int {
|
||||
return b.GetWidth(str...) + b.Margin
|
||||
}
|
||||
func (b *Block) GetHeights(str ...string) int {
|
||||
return b.GetHeight() + b.Margin
|
||||
}
|
||||
|
||||
// 树
|
||||
type Chain struct {
|
||||
data map[string]interface{}
|
||||
max map[int]int
|
||||
Block
|
||||
}
|
||||
|
||||
func (b *Chain) Init(m *ice.Message, arg ...string) Chart {
|
||||
// 解数据
|
||||
b.data = kit.Parse(nil, "", b.show(m, arg[0])...).(map[string]interface{})
|
||||
b.FontColor = kit.Select("white", arg, 1)
|
||||
b.BackGround = kit.Select("red", arg, 2)
|
||||
b.FontSize = kit.Int(kit.Select("24", arg, 3))
|
||||
b.LineSize = kit.Int(kit.Select("12", arg, 4))
|
||||
b.Padding = kit.Int(kit.Select("8", arg, 5))
|
||||
b.Margin = kit.Int(kit.Select("8", arg, 6))
|
||||
m.Log("info", "data %v", kit.Formats(b.data))
|
||||
|
||||
// 计算尺寸
|
||||
b.max = map[int]int{}
|
||||
b.Height = b.size(m, b.data, 0, b.max) * b.GetHeights()
|
||||
width := 0
|
||||
for _, v := range b.max {
|
||||
width += b.GetWidths(strings.Repeat(" ", v))
|
||||
}
|
||||
b.Width = width
|
||||
m.Log("info", "data %v", kit.Formats(b.data))
|
||||
return b
|
||||
}
|
||||
func (b *Chain) Draw(m *ice.Message, x, y int) Chart {
|
||||
return b.draw(m, b.data, 0, b.max, x, y, &Block{})
|
||||
}
|
||||
func (b *Chain) show(m *ice.Message, str string) (res []string) {
|
||||
miss := []int{}
|
||||
list := kit.Split(str, "\n")
|
||||
for _, line := range list {
|
||||
// 计算缩进
|
||||
dep := 0
|
||||
loop:
|
||||
for _, v := range []rune(line) {
|
||||
switch v {
|
||||
case ' ':
|
||||
dep++
|
||||
case '\t':
|
||||
dep += 4
|
||||
default:
|
||||
break loop
|
||||
}
|
||||
}
|
||||
|
||||
// 计算层次
|
||||
if len(miss) > 0 {
|
||||
if miss[len(miss)-1] > dep {
|
||||
for i := len(miss) - 1; i >= 0; i-- {
|
||||
if miss[i] < dep {
|
||||
break
|
||||
}
|
||||
res = append(res, "]", "}")
|
||||
miss = miss[:i]
|
||||
}
|
||||
miss = append(miss, dep)
|
||||
} else if miss[len(miss)-1] < dep {
|
||||
miss = append(miss, dep)
|
||||
} else {
|
||||
res = append(res, "]", "}")
|
||||
}
|
||||
} else {
|
||||
miss = append(miss, dep)
|
||||
}
|
||||
|
||||
// 输出节点
|
||||
word := kit.Split(line)
|
||||
res = append(res, "{", "meta", "{", "text")
|
||||
res = append(res, word...)
|
||||
res = append(res, "}", "list", "[")
|
||||
}
|
||||
return
|
||||
}
|
||||
func (b *Chain) size(m *ice.Message, root map[string]interface{}, depth int, width map[int]int) int {
|
||||
meta := root["meta"].(map[string]interface{})
|
||||
|
||||
// 最大宽度
|
||||
text := kit.Format(meta["text"])
|
||||
if len(text) > width[depth] {
|
||||
width[depth] = len(text)
|
||||
}
|
||||
|
||||
// 计算高度
|
||||
height := 0
|
||||
if list, ok := root["list"].([]interface{}); ok && len(list) > 0 {
|
||||
kit.Fetch(root["list"], func(index int, value map[string]interface{}) {
|
||||
height += b.size(m, value, depth+1, width)
|
||||
})
|
||||
} else {
|
||||
height = 1
|
||||
}
|
||||
|
||||
meta["height"] = height
|
||||
return height
|
||||
}
|
||||
func (b *Chain) draw(m *ice.Message, root map[string]interface{}, depth int, width map[int]int, x, y int, p *Block) Chart {
|
||||
meta := root["meta"].(map[string]interface{})
|
||||
b.Width, b.Height = 0, 0
|
||||
|
||||
// 当前节点
|
||||
block := &Block{
|
||||
BackGround: kit.Select(b.BackGround, kit.Select(p.BackGround, meta["bg"])),
|
||||
FontColor: kit.Select(b.FontColor, kit.Select(p.FontColor, meta["fg"])),
|
||||
FontSize: b.FontSize,
|
||||
LineSize: b.LineSize,
|
||||
Padding: b.Padding,
|
||||
Margin: b.Margin,
|
||||
Width: b.GetWidth(strings.Repeat(" ", width[depth])),
|
||||
}
|
||||
|
||||
block.Data(root["meta"])
|
||||
block.Init(m, kit.Format(meta["text"])).Draw(m, x, y+(kit.Int(meta["height"])-1)*b.GetHeights()/2)
|
||||
|
||||
// 递归节点
|
||||
kit.Fetch(root["list"], func(index int, value map[string]interface{}) {
|
||||
b.draw(m, value, depth+1, width, x+b.GetWidths(strings.Repeat(" ", width[depth])), y, block)
|
||||
y += kit.Int(kit.Value(value, "meta.height")) * b.GetHeights()
|
||||
})
|
||||
return b
|
||||
}
|
||||
|
||||
// 表
|
||||
type Table struct {
|
||||
data [][]string
|
||||
max map[int]int
|
||||
Block
|
||||
}
|
||||
|
||||
func (b *Table) Init(m *ice.Message, arg ...string) Chart {
|
||||
// 解析数据
|
||||
b.max = map[int]int{}
|
||||
for _, v := range kit.Split(arg[0], "\n") {
|
||||
l := kit.Split(v)
|
||||
for i, v := range l {
|
||||
switch data := kit.Parse(nil, "", kit.Split(v)...).(type) {
|
||||
case map[string]interface{}:
|
||||
v = kit.Select("", data["text"])
|
||||
}
|
||||
if len(v) > b.max[i] {
|
||||
b.max[i] = len(v)
|
||||
}
|
||||
}
|
||||
b.data = append(b.data, l)
|
||||
}
|
||||
b.FontColor = kit.Select("white", arg, 1)
|
||||
b.BackGround = kit.Select("red", arg, 2)
|
||||
b.FontSize = kit.Int(kit.Select("24", arg, 3))
|
||||
b.LineSize = kit.Int(kit.Select("12", arg, 4))
|
||||
b.Padding = kit.Int(kit.Select("8", arg, 5))
|
||||
b.Margin = kit.Int(kit.Select("8", arg, 6))
|
||||
|
||||
// 计算尺寸
|
||||
width := 0
|
||||
for _, v := range b.max {
|
||||
width += b.GetWidths(strings.Repeat(" ", v))
|
||||
}
|
||||
b.Width = width
|
||||
b.Height = len(b.data) * b.GetHeights()
|
||||
|
||||
m.Log("info", "data %v", kit.Formats(b.data))
|
||||
return b
|
||||
}
|
||||
func (b *Table) Draw(m *ice.Message, x, y int) Chart {
|
||||
b.Width, b.Height = 0, 0
|
||||
for n, line := range b.data {
|
||||
for i, text := range line {
|
||||
l := 0
|
||||
for j := 0; j < i; j++ {
|
||||
l += b.GetWidths(strings.Repeat(" ", b.max[i]))
|
||||
}
|
||||
block := &Block{
|
||||
BackGround: kit.Select(b.BackGround),
|
||||
FontColor: kit.Select(b.FontColor),
|
||||
FontSize: b.FontSize,
|
||||
LineSize: b.LineSize,
|
||||
Padding: b.Padding,
|
||||
Margin: b.Margin,
|
||||
Width: b.GetWidth(strings.Repeat(" ", b.max[i])),
|
||||
}
|
||||
|
||||
switch data := kit.Parse(nil, "", kit.Split(text)...).(type) {
|
||||
case map[string]interface{}:
|
||||
text = kit.Select(text, data["text"])
|
||||
block.Data(data)
|
||||
}
|
||||
block.Init(m, text).Draw(m, x+l, y+n*b.GetHeights())
|
||||
}
|
||||
}
|
||||
return b
|
||||
}
|
92
core/wiki/wiki.go
Normal file
92
core/wiki/wiki.go
Normal file
@ -0,0 +1,92 @@
|
||||
package wiki
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/gomarkdown/markdown"
|
||||
"github.com/shylinux/icebergs"
|
||||
_ "github.com/shylinux/icebergs/base"
|
||||
"github.com/shylinux/icebergs/base/web"
|
||||
"github.com/shylinux/toolkits"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var Index = &ice.Context{Name: "wiki", Help: "文档模块",
|
||||
Caches: map[string]*ice.Cache{},
|
||||
Configs: map[string]*ice.Config{},
|
||||
Commands: map[string]*ice.Command{
|
||||
"chart": {Name: "chart", Help: "绘图", List: []interface{}{
|
||||
map[string]interface{}{"type": "select", "value": "chain", "values": "chain table"},
|
||||
map[string]interface{}{"type": "text", "value": ""},
|
||||
map[string]interface{}{"type": "button", "value": "执行"},
|
||||
}, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
m.Option("render", "raw")
|
||||
var chart Chart
|
||||
switch arg[0] {
|
||||
case "block":
|
||||
chart = &Block{}
|
||||
case "chain":
|
||||
chart = &Chain{}
|
||||
case "table":
|
||||
chart = &Table{}
|
||||
}
|
||||
arg[1] = strings.TrimSpace(arg[1])
|
||||
|
||||
chart.Init(m, arg[1:]...)
|
||||
m.Echo(`<svg vertion="1.1" xmlns="http://www.w3.org/2000/svg" width="%d", height="%d" style="%s">`,
|
||||
chart.GetWidth(), chart.GetHeight(), m.Option("style"))
|
||||
m.Echo("\n")
|
||||
chart.Draw(m, 0, 0)
|
||||
m.Echo(`</svg>`)
|
||||
m.Echo("\n")
|
||||
return
|
||||
}},
|
||||
|
||||
"_tree": {Name: "_tree", Help: "目录", Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
|
||||
m.Cmdy("nfs.dir", "", arg[0])
|
||||
}},
|
||||
"_text": {Name: "_text", Help: "文章", Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
|
||||
tmpl := m.Target().Server().(*web.WEB).HandleCGI(m, arg[0])
|
||||
m.Optionv("title", map[string]int{})
|
||||
|
||||
buffer := bytes.NewBuffer([]byte{})
|
||||
m.Assert(tmpl.ExecuteTemplate(buffer, m.Option("filename", path.Base(arg[0])), m))
|
||||
|
||||
if f, p, e := kit.Create(path.Join("var/tmp/file", arg[0])); e == nil {
|
||||
defer f.Close()
|
||||
if n, e := f.Write(buffer.Bytes()); e == nil {
|
||||
m.Log("info", "save %d %v", n, p)
|
||||
}
|
||||
}
|
||||
|
||||
data := markdown.ToHTML(buffer.Bytes(), nil, nil)
|
||||
m.Echo(string(data))
|
||||
}},
|
||||
"note": {Name: "note file|favor|commit", Help: "笔记", Meta: map[string]interface{}{
|
||||
"display": "inner",
|
||||
}, List: []interface{}{
|
||||
map[string]interface{}{"type": "text", "value": "miss.md"},
|
||||
map[string]interface{}{"type": "button", "value": "执行"},
|
||||
}, Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
|
||||
if len(arg) == 0 {
|
||||
m.Cmdy("_tree")
|
||||
return
|
||||
}
|
||||
|
||||
switch arg[0] {
|
||||
case "favor", "commit":
|
||||
m.Cmdy("story", arg[0], arg[1:])
|
||||
default:
|
||||
m.Cmdy(kit.Select("_tree", "_text", strings.HasSuffix(arg[0], ".md")), arg[0])
|
||||
}
|
||||
}},
|
||||
|
||||
"title": {Name: "title text", Help: "一级标题", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
ns := strings.Split(m.Conf("runtime", "node.name"), "-")
|
||||
m.Option("render", cmd)
|
||||
m.Echo(kit.Select(ns[len(ns)-1], arg, 0))
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
func init() { web.Index.Register(Index, &web.WEB{}) }
|
@ -1,2 +1,2 @@
|
||||
all:
|
||||
go build main.go
|
||||
sh build.sh build && sh build.sh restart
|
||||
|
53
demo/build.sh
Executable file
53
demo/build.sh
Executable file
@ -0,0 +1,53 @@
|
||||
#! /bin/sh
|
||||
|
||||
export ice_err=${ice_err:="boot.log"}
|
||||
export ice_serve=${ice_serve:="web.serve"}
|
||||
|
||||
prepare() {
|
||||
[ -f main.go ] || cat >> main.go <<END
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/shylinux/icebergs"
|
||||
_ "github.com/shylinux/icebergs/core/chat"
|
||||
)
|
||||
|
||||
func main() {
|
||||
println(ice.Run())
|
||||
}
|
||||
END
|
||||
|
||||
[ -f go.mod ] || go mod init
|
||||
|
||||
[ -f Makefile ] || cat >> Makefile <<END
|
||||
all:
|
||||
sh build.sh build && sh build.sh restart
|
||||
END
|
||||
mkdir -p usr/template/wiki
|
||||
[ -f usr/template/common.tmpl ] || cat >> usr/template/common.tmpl <<END
|
||||
|
||||
END
|
||||
[ -f usr/template/wiki/common.tmpl ] || cat >> usr/template/wiki/common.tmpl <<END
|
||||
|
||||
END
|
||||
}
|
||||
build() {
|
||||
prepare && go build -o bin/shy main.go
|
||||
}
|
||||
start() {
|
||||
[ -d usr/volcanos ] || git clone https://github.com/shylinux/volcanos usr/volcanos
|
||||
while true; do
|
||||
date && bin/shy 2>$ice_err && log "\n\nrestarting..." && sleep 1 || break
|
||||
done
|
||||
}
|
||||
log() { echo -e $*; }
|
||||
restart() {
|
||||
kill -2 `cat var/run/shy.pid`
|
||||
}
|
||||
help() {
|
||||
echo "usage: $0 cmd arg"
|
||||
}
|
||||
|
||||
cmd=$1 && shift
|
||||
[ -z "$cmd" ] && cmd=start
|
||||
$cmd $*
|
11
demo/go.sum
11
demo/go.sum
@ -1,10 +1,9 @@
|
||||
github.com/gomarkdown/markdown v0.0.0-20191207194928-fbea82c4bb03 h1:m13UZm540+0yrpGOIXd7q4AvPGQPSTo+2jxrBK26o64=
|
||||
github.com/gomarkdown/markdown v0.0.0-20191207194928-fbea82c4bb03/go.mod h1:aii0r/K0ZnHv7G0KF7xy1v0A7s2Ljrb5byB7MO5p6TU=
|
||||
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
|
||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/shylinux/icebergs v0.0.0-20191209060320-9f0b85bae35a h1:0RgyhBEPMnRwECFoDPYsz/FgB9yVA9/nJ+tJacwSAig=
|
||||
github.com/shylinux/icebergs v0.0.0-20191209060320-9f0b85bae35a/go.mod h1:FowoSa6syu4hP1QWT9UNoQICuIwfP2PGQ/ao1fSeoOc=
|
||||
github.com/shylinux/icebergs v0.0.0-20191212145348-fe6226481eaa h1:DcLg8BUz5a0ON2UICK7b61LPFJ2+HVC7E8vV5ItYABo=
|
||||
github.com/shylinux/icebergs v0.0.0-20191212145348-fe6226481eaa/go.mod h1:FowoSa6syu4hP1QWT9UNoQICuIwfP2PGQ/ao1fSeoOc=
|
||||
github.com/shylinux/icebergs v0.0.0-20191214121808-47bb65632d9d h1:154JIv2bSmesyjggRhH1lQKZ6WmvnvDQfWvQiWqvAbk=
|
||||
github.com/shylinux/icebergs v0.0.0-20191214121808-47bb65632d9d/go.mod h1:lDuCMlmptkcvDfdAfRGo/Dt0xLS/cOaIXnliLYwpFWA=
|
||||
github.com/shylinux/toolkits v0.0.0-20191205193931-8b65f7e78477 h1:xwu6cGDBy/ZCrVklmCqSgx9O7Hr1v+hkzsIh1yc0hxg=
|
||||
github.com/shylinux/toolkits v0.0.0-20191205193931-8b65f7e78477/go.mod h1:e1dV0lMyoKz4Luib6XyMNpfpn5Sn7POnq7XTT4wfN7k=
|
||||
github.com/shylinux/toolkits v0.0.0-20191212145555-d32eaba90a9e h1:eFZMsw0LuDeeVgwYwNJISebbMUZCVHEdQRaYBNWvC9s=
|
||||
github.com/shylinux/toolkits v0.0.0-20191212145555-d32eaba90a9e/go.mod h1:e1dV0lMyoKz4Luib6XyMNpfpn5Sn7POnq7XTT4wfN7k=
|
||||
golang.org/dl v0.0.0-20190829154251-82a15e2f2ead/go.mod h1:IUMfjQLJQd4UTqG1Z90tenwKoCX93Gn3MAQJMOSBsDQ=
|
||||
|
@ -2,7 +2,8 @@ package main
|
||||
|
||||
import (
|
||||
"github.com/shylinux/icebergs"
|
||||
_ "github.com/shylinux/icebergs/misc/chat"
|
||||
_ "github.com/shylinux/icebergs/core/chat"
|
||||
_ "github.com/shylinux/icebergs/core/wiki"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
17
demo/miss.md
Normal file
17
demo/miss.md
Normal file
@ -0,0 +1,17 @@
|
||||
# {{title "hello world"}}
|
||||
|
||||
{{chart "chain" `
|
||||
context
|
||||
volcanos
|
||||
proto.js
|
||||
frame.js
|
||||
order.js
|
||||
style.css
|
||||
index.html
|
||||
icebergs bg blue
|
||||
web.go
|
||||
aaa.go
|
||||
cli.go
|
||||
ctx.go
|
||||
toolkits
|
||||
`}}
|
1
go.mod
1
go.mod
@ -3,6 +3,7 @@ module github.com/shylinux/icebergs
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/gomarkdown/markdown v0.0.0-20191207194928-fbea82c4bb03
|
||||
github.com/gorilla/websocket v1.4.1
|
||||
github.com/shylinux/toolkits v0.0.0-20191205193931-8b65f7e78477
|
||||
)
|
||||
|
3
go.sum
3
go.sum
@ -1,4 +1,7 @@
|
||||
github.com/gomarkdown/markdown v0.0.0-20191207194928-fbea82c4bb03 h1:m13UZm540+0yrpGOIXd7q4AvPGQPSTo+2jxrBK26o64=
|
||||
github.com/gomarkdown/markdown v0.0.0-20191207194928-fbea82c4bb03/go.mod h1:aii0r/K0ZnHv7G0KF7xy1v0A7s2Ljrb5byB7MO5p6TU=
|
||||
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
|
||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/shylinux/toolkits v0.0.0-20191205193931-8b65f7e78477 h1:xwu6cGDBy/ZCrVklmCqSgx9O7Hr1v+hkzsIh1yc0hxg=
|
||||
github.com/shylinux/toolkits v0.0.0-20191205193931-8b65f7e78477/go.mod h1:e1dV0lMyoKz4Luib6XyMNpfpn5Sn7POnq7XTT4wfN7k=
|
||||
golang.org/dl v0.0.0-20190829154251-82a15e2f2ead/go.mod h1:IUMfjQLJQd4UTqG1Z90tenwKoCX93Gn3MAQJMOSBsDQ=
|
||||
|
@ -1,65 +0,0 @@
|
||||
package chat
|
||||
|
||||
import (
|
||||
"github.com/shylinux/icebergs"
|
||||
"github.com/shylinux/icebergs/core/web"
|
||||
_ "github.com/shylinux/icebergs/misc"
|
||||
"github.com/shylinux/toolkits"
|
||||
)
|
||||
|
||||
var Index = &ice.Context{Name: "chat", Help: "聊天模块",
|
||||
Caches: map[string]*ice.Cache{},
|
||||
Configs: map[string]*ice.Config{
|
||||
"group": {Name: "group", Value: map[string]interface{}{
|
||||
"meta": map[string]interface{}{},
|
||||
"list": map[string]interface{}{},
|
||||
"hash": map[string]interface{}{},
|
||||
}},
|
||||
},
|
||||
Commands: map[string]*ice.Command{
|
||||
"_init": {Name: "_init", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
}},
|
||||
"/ocean": {Name: "/ocean", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
}},
|
||||
"/river": {Name: "/river", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
if len(arg) == 0 {
|
||||
arg = kit.Simple(m.Optionv("cmds"))
|
||||
}
|
||||
|
||||
if len(arg) == 0 {
|
||||
m.Confm("group", "hash", func(key string, value map[string]interface{}) {
|
||||
m.Push("key", key)
|
||||
m.Push("create_time", value["create_time"])
|
||||
m.Push("name", value["name"])
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
switch arg[0] {
|
||||
case "create":
|
||||
// h := kit.Hashs("uniq")
|
||||
h := kit.ShortKey(m.Confm("group", "hash"), 6)
|
||||
m.Conf("group", "hash."+h, map[string]interface{}{
|
||||
"create_time": m.Time(),
|
||||
"create_name": arg[1],
|
||||
})
|
||||
m.Log("info", "river create %v %v", h, kit.Formats(m.Confv("group", "hash."+h)))
|
||||
m.Echo(h)
|
||||
}
|
||||
}},
|
||||
"/action": {Name: "/action", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
if cmds, ok := m.Optionv("cmds").([]string); ok {
|
||||
m.Cmdy("web.space", cmds)
|
||||
return
|
||||
}
|
||||
}},
|
||||
"/storm": {Name: "/storm", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
}},
|
||||
"/steam": {Name: "/steam", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
}},
|
||||
"_exit": {Name: "_init", Help: "hello", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
func init() { web.Index.Register(Index, &web.WEB{}) }
|
16
misc/shy.go
16
misc/shy.go
@ -1,16 +0,0 @@
|
||||
package shy
|
||||
|
||||
import (
|
||||
_ "github.com/shylinux/icebergs/core/aaa"
|
||||
_ "github.com/shylinux/icebergs/core/cli"
|
||||
_ "github.com/shylinux/icebergs/core/ctx"
|
||||
_ "github.com/shylinux/icebergs/core/gdb"
|
||||
_ "github.com/shylinux/icebergs/core/lex"
|
||||
_ "github.com/shylinux/icebergs/core/log"
|
||||
_ "github.com/shylinux/icebergs/core/mdb"
|
||||
_ "github.com/shylinux/icebergs/core/nfs"
|
||||
_ "github.com/shylinux/icebergs/core/ssh"
|
||||
_ "github.com/shylinux/icebergs/core/tcp"
|
||||
_ "github.com/shylinux/icebergs/core/web"
|
||||
_ "github.com/shylinux/icebergs/core/yac"
|
||||
)
|
224
type.go
224
type.go
@ -3,12 +3,15 @@ package ice
|
||||
import (
|
||||
"github.com/shylinux/toolkits"
|
||||
|
||||
"encoding/csv"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
@ -26,7 +29,8 @@ type Config struct {
|
||||
type Command struct {
|
||||
Name string
|
||||
Help interface{}
|
||||
Form map[string]int
|
||||
Meta map[string]interface{}
|
||||
List []interface{}
|
||||
Hand func(m *Message, c *Context, key string, arg ...string)
|
||||
}
|
||||
type Context struct {
|
||||
@ -183,7 +187,7 @@ func (m *Message) Spawn(arg ...interface{}) *Message {
|
||||
}
|
||||
func (m *Message) Spawns(arg ...interface{}) *Message {
|
||||
msg := m.Spawn(arg...)
|
||||
msg.code = Index.ID()
|
||||
msg.code = m.target.root.ID()
|
||||
m.messages = append(m.messages, msg)
|
||||
return msg
|
||||
}
|
||||
@ -244,6 +248,9 @@ func (m *Message) Echo(str string, arg ...interface{}) *Message {
|
||||
func (m *Message) Option(key string, arg ...interface{}) string {
|
||||
return kit.Select("", kit.Simple(m.Optionv(key, arg...)), 0)
|
||||
}
|
||||
func (m *Message) Options(key string, arg ...interface{}) bool {
|
||||
return kit.Select("", kit.Simple(m.Optionv(key, arg...)), 0) != ""
|
||||
}
|
||||
func (m *Message) Optionv(key string, arg ...interface{}) interface{} {
|
||||
if len(arg) > 0 {
|
||||
if kit.IndexOf(m.meta["option"], key) == -1 {
|
||||
@ -270,6 +277,9 @@ func (m *Message) Optionv(key string, arg ...interface{}) interface{} {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *Message) Append(key string, arg ...interface{}) string {
|
||||
return kit.Select("", m.meta[key], 0)
|
||||
}
|
||||
func (m *Message) Resultv(arg ...interface{}) []string {
|
||||
return m.meta["result"]
|
||||
}
|
||||
@ -343,9 +353,11 @@ func (m *Message) Search(key interface{}, cb func(p *Context, s *Context, key st
|
||||
break
|
||||
}
|
||||
}
|
||||
if p != nil {
|
||||
cb(p.context, p, list[len(list)-1])
|
||||
if p == nil {
|
||||
m.Log("warn", "not found %s", key)
|
||||
break
|
||||
}
|
||||
cb(p.context, p, list[len(list)-1])
|
||||
} else {
|
||||
cb(m.target.context, m.target, key)
|
||||
}
|
||||
@ -378,11 +390,198 @@ func (m *Message) Back(sub *Message) *Message {
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *Message) Grow(key string, args interface{}, data interface{}) interface{} {
|
||||
cache := m.Confm(key, args)
|
||||
if cache == nil {
|
||||
cache = map[string]interface{}{}
|
||||
}
|
||||
meta, ok := cache["meta"].(map[string]interface{})
|
||||
if !ok {
|
||||
meta = map[string]interface{}{}
|
||||
}
|
||||
list, _ := cache["list"].([]interface{})
|
||||
|
||||
list = append(list, data)
|
||||
if len(list) > kit.Int(kit.Select(m.Conf("cache", "limit"), meta["limit"])) {
|
||||
least := kit.Int(kit.Select(m.Conf("cache", "least"), meta["least"]))
|
||||
|
||||
// 创建文件
|
||||
name := kit.Select(path.Join(m.Conf("cache", "store"), key+".csv"), meta["store"])
|
||||
f, e := os.OpenFile(name, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666)
|
||||
if e != nil {
|
||||
f, _, e = kit.Create(name)
|
||||
}
|
||||
defer f.Close()
|
||||
s, e := f.Stat()
|
||||
m.Assert(e)
|
||||
|
||||
// 保存数据
|
||||
keys := []string{}
|
||||
w := csv.NewWriter(f)
|
||||
if s.Size() == 0 {
|
||||
for k := range list[0].(map[string]interface{}) {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
w.Write(keys)
|
||||
w.Flush()
|
||||
s, e = f.Stat()
|
||||
} else {
|
||||
r := csv.NewReader(f)
|
||||
keys, e = r.Read()
|
||||
}
|
||||
|
||||
// 保存状态
|
||||
count := len(list) - least
|
||||
offset := kit.Int(meta["offset"])
|
||||
record, _ := meta["record"].([]interface{})
|
||||
meta["record"] = append(record, map[string]interface{}{
|
||||
"time": m.Time(),
|
||||
"offset": offset,
|
||||
"position": s.Size(),
|
||||
"count": count,
|
||||
"file": name,
|
||||
})
|
||||
|
||||
// 保存数据
|
||||
for i, v := range list {
|
||||
if i >= count {
|
||||
break
|
||||
}
|
||||
|
||||
val := v.(map[string]interface{})
|
||||
|
||||
values := []string{}
|
||||
for _, k := range keys {
|
||||
values = append(values, kit.Format(val[k]))
|
||||
}
|
||||
w.Write(values)
|
||||
|
||||
if i < least {
|
||||
list[i] = list[count+i]
|
||||
}
|
||||
}
|
||||
|
||||
m.Log("info", "save %s offset %v+%v", name, offset, count)
|
||||
meta["offset"] = offset + count
|
||||
list = list[:least]
|
||||
w.Flush()
|
||||
}
|
||||
cache["meta"] = meta
|
||||
cache["list"] = list
|
||||
if args == nil {
|
||||
m.Conf(key, cache)
|
||||
} else {
|
||||
m.Conf(key, args, cache)
|
||||
}
|
||||
return list
|
||||
}
|
||||
func (m *Message) Grows(key string, args interface{}, cb interface{}) map[string]interface{} {
|
||||
cache := m.Confm(key, args)
|
||||
if cache == nil {
|
||||
return nil
|
||||
}
|
||||
meta, ok := cache["meta"].(map[string]interface{})
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
list, ok := cache["list"].([]interface{})
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
offend := kit.Int(kit.Select("0", m.Option("cache.offend")))
|
||||
limit := kit.Int(kit.Select("10", m.Option("cache.limit")))
|
||||
match := kit.Select("", m.Option("cache.match"))
|
||||
value := kit.Select("", m.Option("cache.value"))
|
||||
current := kit.Int(meta["offset"])
|
||||
end := current + len(list) - offend
|
||||
begin := end - limit
|
||||
|
||||
data := make([]interface{}, 0, limit)
|
||||
m.Log("info", "read %v-%v from %v-%v", begin, end, current, current+len(list))
|
||||
if begin < current {
|
||||
store, _ := meta["record"].([]interface{})
|
||||
for s := len(store) - 1; s > -1; s-- {
|
||||
item, _ := store[s].(map[string]interface{})
|
||||
line := kit.Int(item["offset"])
|
||||
m.Log("info", "check history %v %v %v", s, line, item)
|
||||
if begin < line && s > 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
for ; s < len(store); s++ {
|
||||
if begin >= end {
|
||||
break
|
||||
}
|
||||
item, _ := store[s].(map[string]interface{})
|
||||
if line+kit.Int(item["count"]) < begin {
|
||||
continue
|
||||
}
|
||||
|
||||
name := kit.Format(item["file"])
|
||||
pos := kit.Int(item["position"])
|
||||
line := kit.Int(item["offset"])
|
||||
m.Log("info", "load history %v %v %v", s, line, item)
|
||||
if f, e := os.Open(name); m.Assert(e) {
|
||||
defer f.Close()
|
||||
r := csv.NewReader(f)
|
||||
heads, _ := r.Read()
|
||||
m.Log("info", "load head %v", heads)
|
||||
|
||||
f.Seek(int64(pos), os.SEEK_SET)
|
||||
r = csv.NewReader(f)
|
||||
for i := line; i < end; i++ {
|
||||
lines, e := r.Read()
|
||||
if e != nil {
|
||||
break
|
||||
}
|
||||
|
||||
if i >= begin {
|
||||
item := map[string]interface{}{}
|
||||
for i := range heads {
|
||||
item[heads[i]] = lines[i]
|
||||
}
|
||||
m.Log("info", "load line %v %v %v", i, len(data), item)
|
||||
if match == "" || strings.Contains(kit.Format(item[match]), value) {
|
||||
data = append(data, item)
|
||||
}
|
||||
begin = i + 1
|
||||
} else {
|
||||
m.Log("info", "skip line %v", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if begin < current {
|
||||
begin = current
|
||||
}
|
||||
m.Log("info", "cache %v-%v", begin-current, end-current)
|
||||
for i := begin - current; i < end-current; i++ {
|
||||
if match == "" || strings.Contains(kit.Format(kit.Value(list[i], match)), value) {
|
||||
data = append(data, list[i])
|
||||
}
|
||||
}
|
||||
val := map[string]interface{}{"meta": meta, "list": data}
|
||||
kit.Fetch(val, cb)
|
||||
return val
|
||||
}
|
||||
|
||||
func (m *Message) Cmdy(arg ...interface{}) *Message {
|
||||
msg := m.Cmd(arg...)
|
||||
m.Copy(msg)
|
||||
return m
|
||||
}
|
||||
func (m *Message) Cmdx(arg ...interface{}) string {
|
||||
return kit.Select("", m.Cmd(arg...).meta["result"], 0)
|
||||
}
|
||||
func (m *Message) Cmds(arg ...interface{}) bool {
|
||||
return kit.Select("", m.Cmd(arg...).meta["result"], 0) != ""
|
||||
}
|
||||
func (m *Message) Cmd(arg ...interface{}) *Message {
|
||||
list := kit.Simple(arg...)
|
||||
if len(list) == 0 {
|
||||
@ -410,8 +609,11 @@ func (m *Message) Confv(arg ...interface{}) (val interface{}) {
|
||||
m.Search(arg[0], func(p *Context, s *Context, key string) {
|
||||
for c := s; c != nil; c = c.context {
|
||||
if conf, ok := c.Configs[key]; ok {
|
||||
if len(arg) > 0 {
|
||||
val = kit.Value(conf.Value, arg[1:]...)
|
||||
if len(arg) > 1 {
|
||||
if len(arg) > 2 {
|
||||
kit.Value(conf.Value, arg[1:]...)
|
||||
}
|
||||
val = kit.Value(conf.Value, arg[1])
|
||||
} else {
|
||||
val = conf.Value
|
||||
}
|
||||
@ -423,15 +625,7 @@ func (m *Message) Confv(arg ...interface{}) (val interface{}) {
|
||||
func (m *Message) Confm(key string, chain interface{}, cbs ...interface{}) map[string]interface{} {
|
||||
val := m.Confv(key, chain)
|
||||
if len(cbs) > 0 {
|
||||
switch val := val.(type) {
|
||||
case map[string]interface{}:
|
||||
switch cb := cbs[0].(type) {
|
||||
case func(string, map[string]interface{}):
|
||||
for k, v := range val {
|
||||
cb(k, v.(map[string]interface{}))
|
||||
}
|
||||
}
|
||||
}
|
||||
kit.Fetch(val, cbs[0])
|
||||
}
|
||||
value, _ := val.(map[string]interface{})
|
||||
return value
|
||||
|
Loading…
x
Reference in New Issue
Block a user