1
0
forked from x/icebergs

add web.wiki

This commit is contained in:
shaoying 2019-12-16 01:38:35 +08:00
parent 47bb65632d
commit ab6bfe93d4
32 changed files with 1390 additions and 205 deletions

View File

@ -1,2 +0,0 @@
all:
cd demo && go build main.go

View File

@ -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
View 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) }

View File

@ -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
View 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
View 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
View 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
View 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"
)

View File

@ -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] == "" {

View File

@ -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
View 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{}) }

View File

@ -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) }

View File

@ -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) }

View File

@ -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
View 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
View 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{}) }

View File

@ -1,2 +1,2 @@
all:
go build main.go
sh build.sh build && sh build.sh restart

53
demo/build.sh Executable file
View 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 $*

View File

@ -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=

View File

@ -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
View 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
View File

@ -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
View File

@ -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=

View File

@ -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{}) }

View File

@ -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
View File

@ -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