1
0
forked from x/icebergs

add qrcode

This commit is contained in:
shaoying 2020-01-02 19:10:03 +08:00
parent deb76d84cb
commit 55d19488d3
12 changed files with 193 additions and 64 deletions

View File

@ -5,6 +5,13 @@ import (
)
var share_template = kit.Dict(
"story.prefix", `<!DOCTYPE html>
<head>
<meta charset="utf-8">
</head>
<body>
`, "story.suffix", `</body>`,
"download", `<a href="/code/zsh?cmd=download&arg=%s" target="_blank">%s</a>`,
"share", `<a href="/share/%s" target="_blank">%s</a>`,
"shy/story", `{{.}}`,

View File

@ -4,6 +4,7 @@ import (
"github.com/gorilla/websocket"
"github.com/shylinux/icebergs"
"github.com/shylinux/toolkits"
"github.com/skip2/go-qrcode"
"bytes"
"encoding/json"
@ -227,6 +228,11 @@ func (web *Frame) HandleCmd(m *ice.Message, key string, cmd *ice.Command) {
w.Header().Set("Content-Disposition", fmt.Sprintf("filename=%s", kit.Select(msg.Append("name"), msg.Append("story"))))
w.Header().Set("Content-Type", kit.Select("text/html", msg.Append("type")))
http.ServeFile(w, r, msg.Append("file"))
case "qrcode":
if qr, e := qrcode.New(msg.Append("qrcode"), qrcode.Medium); m.Assert(e) {
w.Header().Set("Content-Type", "image/png")
m.Assert(qr.Write(256, w))
}
case "result":
w.Header().Set("Content-Type", kit.Select("text/html", msg.Append("type")))
fmt.Fprint(w, msg.Result())
@ -363,7 +369,11 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
)},
ice.WEB_FAVOR: {Name: "favor", Help: "收藏夹", Value: kit.Data(kit.MDB_SHORT, kit.MDB_NAME)},
ice.WEB_CACHE: {Name: "cache", Help: "缓存池", Value: kit.Data(kit.MDB_SHORT, "text", "path", "var/file", "store", "var/data", "limit", "30", "least", "10")},
ice.WEB_STORY: {Name: "story", Help: "故事会", Value: kit.Dict(kit.MDB_META, kit.Dict(kit.MDB_SHORT, "data"), "head", kit.Data(kit.MDB_SHORT, "story"))},
ice.WEB_STORY: {Name: "story", Help: "故事会", Value: kit.Dict(
kit.MDB_META, kit.Dict(kit.MDB_SHORT, "data"),
"head", kit.Data(kit.MDB_SHORT, "story"),
"mime", kit.Dict("md", "txt"),
)},
ice.WEB_SHARE: {Name: "share", Help: "共享链", Value: kit.Data("template", share_template)},
ice.WEB_ROUTE: {Name: "route", Help: "路由", Value: kit.Data()},
ice.WEB_PROXY: {Name: "proxy", Help: "代理", Value: kit.Data()},
@ -785,6 +795,7 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
m.Sort("name")
m.Sort("status")
}},
ice.WEB_FAVOR: {Name: "favor", Help: "收藏夹", Meta: kit.Dict("remote", "you", "exports", []string{"hot", "favor"}, "detail", []string{"执行", "编辑", "收录", "下载"}), List: kit.List(
kit.MDB_INPUT, "text", "name", "hot", "action", "auto",
kit.MDB_INPUT, "text", "name", "id", "action", "auto",
@ -803,6 +814,7 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
})
})
arg = []string{m.Option("hot")}
case "收录":
m.Richs(ice.WEB_FAVOR, nil, m.Option("hot"), func(key string, value map[string]interface{}) {
m.Grows(ice.WEB_FAVOR, kit.Keys(kit.MDB_HASH, key), "id", id, func(index int, value map[string]interface{}) {
@ -810,8 +822,13 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
})
})
arg = []string{m.Option("hot")}
case "执行":
m.Event(ice.FAVOR_START, m.Option("you"), kit.Select(m.Option("hot"), arg[3], arg[2] == "favor"))
arg = arg[:0]
}
}
if len(arg) > 0 {
switch arg[0] {
case "import":
@ -917,7 +934,7 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
case "upload", "download":
// 打开文件
if m.R != nil {
if f, h, e := m.R.FormFile(kit.Select("upload", arg, 1)); m.Assert(e) {
if f, h, e := m.R.FormFile(kit.Select("upload", arg, 1)); e == nil {
defer f.Close()
// 创建文件
@ -1302,6 +1319,12 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
m.Echo("%s", node["text"])
default:
if len(arg) == 1 {
if _, e := os.Stat(arg[0]); e == nil {
if scene := m.Conf(ice.WEB_STORY, kit.Keys("mime", strings.TrimPrefix(path.Ext(arg[0]), "."))); scene != "" {
m.Cmd(ice.WEB_STORY, ice.STORY_CATCH, scene, arg[0])
}
}
m.Cmd(ice.WEB_STORY, "history", arg).Table(func(index int, value map[string]string, head []string) {
m.Push("time", value["time"])
m.Push("list", value["key"])
@ -1340,18 +1363,21 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
switch arg[0] {
case "add":
arg = arg[1:]
fallthrough
default:
// 创建共享
extra := kit.Dict()
for i := 4; i < len(arg)-1; i += 2 {
for i := 3; i < len(arg)-1; i += 2 {
kit.Value(extra, arg[i], arg[i+1])
}
h := m.Rich(ice.WEB_SHARE, nil, kit.Dict(
kit.MDB_TYPE, arg[1], kit.MDB_NAME, arg[2], kit.MDB_TEXT, arg[3],
kit.MDB_TYPE, arg[0], kit.MDB_NAME, arg[1], kit.MDB_TEXT, arg[2],
"extra", extra,
))
m.Grow(ice.WEB_SHARE, nil, kit.Dict(
kit.MDB_TYPE, arg[1], kit.MDB_NAME, arg[2], kit.MDB_TEXT, arg[3],
kit.MDB_TYPE, arg[0], kit.MDB_NAME, arg[1], kit.MDB_TEXT, arg[2],
"share", h,
))
m.Log(ice.LOG_CREATE, "share: %s extra: %s", h, kit.Format(extra))
@ -1374,15 +1400,37 @@ var Index = &ice.Context{Name: "web", Help: "网页模块",
Cookie(m, m.Cmdx(ice.AAA_USER, "login", m.Option("username"), m.Option("password")))
default:
key := kit.Select("", strings.Split(cmd, "/"), 2)
m.Confm(ice.WEB_SHARE, kit.Keys("hash", key), func(value map[string]interface{}) {
m.Info("share %s %v", key, kit.Format(value))
m.Richs(ice.WEB_SHARE, nil, arg[0], func(key string, value map[string]interface{}) {
m.Info("share %s %v", arg, kit.Format(value))
switch value["type"] {
case ice.TYPE_STORY:
if m.Cmdy(ice.WEB_STORY, "index", kit.Value(value, "extra.data")).Append("text") == "" {
m.Cmdy(ice.WEB_SPACE, kit.Value(value, "extra.pod"), ice.WEB_STORY, "index", kit.Value(value, "extra.data"))
if m.Cmdy(ice.WEB_STORY, "index", kit.Value(value, "text")).Append("text") == "" {
m.Cmdy(ice.WEB_SPACE, kit.Value(value, "extra.pod"), ice.WEB_STORY, "index", kit.Value(value, "text"))
}
m.Push("_output", kit.Select("file", "result", m.Append("file") == ""))
p := path.Join("tmp/file", m.Append("data"))
if _, e := os.Stat(p); e == nil {
m.Append("_output", "file")
m.Append("file", p)
break
}
m.Set("result")
m.Render(m.Conf(ice.WEB_SHARE, "meta.template.story.prefix"))
m.Cmdy("web.wiki._text", m.Append("file"))
m.Render(m.Conf(ice.WEB_SHARE, "meta.template.story.suffix"))
m.Push("_output", "result")
if f, p, e := kit.Create(p); e == nil {
defer f.Close()
if n, e := f.WriteString(m.Result()); e == nil {
m.Log(ice.LOG_EXPORT, "%d: %s", n, p)
}
}
case "qrcode":
m.Push("_output", "qrcode")
m.Push("qrcode", value["text"])
default:
if m.Cmdy(ice.WEB_STORY, "index", value["data"]); m.Append("file") != "" {

View File

@ -20,6 +20,8 @@ END
[ -f Makefile ] || cat >> Makefile <<END
all:
@echo
@date
go build -o ice.bin main.go && chmod u+x ice.bin && ./ice.sh restart
END
@ -27,7 +29,8 @@ END
#! /bin/sh
export PATH=\${PWD}:\$PATH
export ctx_pid=var/run/ice.pid
export ctx_pid=\${ctx_pid:=var/run/ice.pid}
export ctx_log=\${ctx_log:=boot.log}
prepare() {
[ -e ice.sh ] || curl \$ctx_dev/publish/ice.sh -o ice.sh && chmod u+x ice.sh
@ -48,7 +51,7 @@ prepare() {
}
start() {
trap HUP hup && while true; do
date && ice.bin \$@ 2>boot.log && echo -e "\n\nrestarting..." || break
date && ice.bin \$@ 2>\$ctx_log && echo -e "\n\nrestarting..." || break
done
}
serve() {

View File

@ -71,6 +71,7 @@ const ( // WEB
const ( // LOG
LOG_ENABLE = "enable"
LOG_IMPORT = "import"
LOG_MODIFY = "modify"
LOG_CREATE = "create"
LOG_INSERT = "insert"
LOG_EXPORT = "export"
@ -107,6 +108,7 @@ const ( // GDB
DREAM_CLOSE = "dream.close"
USER_CREATE = "user.create"
MISS_CREATE = "miss.create"
)
const ( // MDB
MDB_REDIS = "redis"
@ -139,6 +141,7 @@ const ( // TYPE
TYPE_RIVER = "river"
TYPE_STORM = "storm"
TYPE_DRIVE = "drive"
TYPE_STORY = "story"
TYPE_SHELL = "shell"
TYPE_VIMRC = "vimrc"
@ -150,8 +153,9 @@ const ( // FAVOR
FAVOR_CHAT = "chat.init"
FAVOR_TMUX = "tmux.init"
FAVOR_RIVER = "river.init"
FAVOR_START = "favor.start"
)
const ( // FAVOR
const ( // STORY
STORY_CATCH = "catch"
STORY_WATCH = "watch"
STORY_STATUS = "status"

View File

@ -174,6 +174,9 @@ var Index = &ice.Context{Name: "chat", Help: "聊天中心",
))
m.Log("insert", "storm: %s %d: %v", arg[1], id, arg[i:i+4])
}
case "share":
m.Cmdy(ice.WEB_SHARE, "add", arg[3:])
case "rename":
// 重命名应用
old := m.Conf(ice.CHAT_RIVER, kit.Keys(prefix, kit.MDB_HASH, arg[1], kit.MDB_META, kit.MDB_NAME))

View File

@ -109,7 +109,7 @@ var Index = &ice.Context{Name: "code", Help: "编程模块",
value["file"] = kit.Keys("ice", m.Conf(ice.CLI_RUNTIME, "host.GOOS"), m.Conf(ice.CLI_RUNTIME, "host.GOARCH"))
}
h := m.Cmdx(ice.WEB_SPIDE, "dev", "cache", "/publish/"+kit.Format(value["file"]))
h := m.Cmdx(ice.WEB_SPIDE, "dev", "cache", "GET", "/publish/"+kit.Format(value["file"]))
if h == "" {
exit = false
return

View File

@ -12,10 +12,20 @@ import (
var Index = &ice.Context{Name: "team", Help: "团队模块",
Caches: map[string]*ice.Cache{},
Configs: map[string]*ice.Config{
ice.APP_MISS: {Name: "miss", Help: "任务", Value: kit.Data()},
ice.APP_MISS: {Name: "miss", Help: "任务", Value: kit.Data(
"mis", []interface{}{"已取消", "准备中", "开发中", "测试中", "发布中", "已完成"}, "fsm", kit.Dict(
"准备中", kit.Dict("next", "开发中"),
"开发中", kit.Dict("next", "测试中", "prev", "准备中"),
"测试中", kit.Dict("next", "发布中", "prev", "开发中"),
"发布中", kit.Dict("next", "已完成", "prev", "测试中"),
"已完成", kit.Dict(),
"已取消", kit.Dict(),
),
)},
},
Commands: map[string]*ice.Command{
ice.ICE_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
m.Watch(ice.MISS_CREATE, ice.APP_MISS)
m.Cmd(ice.CTX_CONFIG, "load", "team.json")
}},
ice.ICE_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
@ -27,8 +37,11 @@ var Index = &ice.Context{Name: "team", Help: "团队模块",
switch arg[1] {
case "modify":
// 修改任务
m.Grows(ice.APP_MISS, nil, "id", arg[0], func(index int, value map[string]interface{}) {
value[arg[2]] = arg[3]
m.Richs(ice.WEB_FAVOR, nil, m.Option("hot"), func(key string, value map[string]interface{}) {
m.Grows(ice.WEB_FAVOR, kit.Keys("hash", key), "id", arg[0], func(index int, value map[string]interface{}) {
m.Log(ice.LOG_MODIFY, "%s: %s->%s", arg[2], arg[4], arg[3])
kit.Value(value, arg[2], arg[3])
})
})
arg = arg[:0]
}
@ -36,22 +49,19 @@ var Index = &ice.Context{Name: "team", Help: "团队模块",
if len(arg) == 0 {
// 任务列表
m.Grows(ice.APP_MISS, nil, "", "", func(index int, value map[string]interface{}) {
m.Push(kit.Format(index), value, []string{"begin_time", "close_time", "status", "id", "type", "name", "text"})
m.Richs(ice.WEB_FAVOR, nil, m.Option("hot"), func(key string, value map[string]interface{}) {
m.Grows(ice.WEB_FAVOR, kit.Keys("hash", key), "", "", func(index int, value map[string]interface{}) {
m.Push(kit.Format(index), value, []string{"extra.begin_time", "extra.close_time", "extra.status", "id", "type", "name", "text"})
})
})
return
}
// 添加任务
h := m.Grow(ice.APP_MISS, nil, kit.Dict(
kit.MDB_NAME, arg[0],
kit.MDB_TYPE, kit.Select("开发", arg, 1),
kit.MDB_TEXT, kit.Select("功能开发", arg, 2),
"status", kit.Select("准备中", arg, 3),
m.Cmdy(ice.WEB_FAVOR, kit.Select("miss", m.Option("hot")), ice.TYPE_DRIVE, arg[0], arg[1],
"begin_time", m.Time(), "close_time", m.Time(),
))
m.Info("miss: %d", h)
m.Echo("%d", h)
"status", kit.Select("准备中", arg, 3),
)
}},
"date": {Name: "date", Help: "日历", Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
show := map[int]string{0: "周日", 1: "周一", 2: "周二", 3: "周三", 4: "周四", 5: "周五", 6: "周六"}
@ -107,49 +117,45 @@ var Index = &ice.Context{Name: "team", Help: "团队模块",
"detail", []string{"回退", "前进", "取消", "完成"},
), Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
if len(arg) > 0 {
m.Grows(ice.APP_MISS, nil, "id", arg[0], func(index int, value map[string]interface{}) {
switch value["status"] {
case "准备中":
switch arg[1] {
case "开始":
value["status"] = "进行中"
value["begin_time"] = m.Time()
value["close_time"] = m.Time("30m")
m.Richs(ice.WEB_FAVOR, nil, m.Option("hot"), func(key string, value map[string]interface{}) {
m.Grows(ice.WEB_FAVOR, kit.Keys("hash", key), "id", arg[0], func(index int, value map[string]interface{}) {
switch value = value["extra"].(map[string]interface{}); arg[1] {
case "前进":
if value["status"] == "准备中" {
value["begin_time"] = m.Time()
value["close_time"] = m.Time("30m")
}
if next := m.Conf(ice.APP_MISS, kit.Keys("meta.fsm", value["status"], "next")); next != "" {
value["status"] = next
}
case "回退":
if prev := m.Conf(ice.APP_MISS, kit.Keys("meta.fsm", value["status"], "prev")); prev != "" {
value["status"] = prev
}
case "取消":
value["status"] = "已取消"
value["close_time"] = m.Time()
case "完成":
value["status"] = "已完成"
value["close_time"] = m.Time()
}
case "进行中":
switch arg[1] {
case "准备":
value["status"] = "准备中"
value["begin_time"] = m.Time()
value["close_time"] = m.Time()
case "取消":
value["status"] = "已取消"
value["close_time"] = m.Time()
case "完成":
value["status"] = "已完成"
value["close_time"] = m.Time()
}
}
})
})
}
m.Push("准备中", "")
m.Push("开发中", "")
m.Push("测试中", "")
m.Push("发布中", "")
m.Push("已取消", "")
m.Push("已完成", "")
m.Grows(ice.APP_MISS, nil, "", "", func(index int, value map[string]interface{}) {
m.Push(kit.Format(value["status"]),
kit.Format(`<span title="%v" data-id="%v">%v</span>`,
kit.Format("%s-%s\n%s", value["begin_time"], value["close_time"], value["text"]),
value["id"], value["name"]))
m.Confm(ice.APP_MISS, "meta.mis", func(index int, value string) {
m.Push(value, "")
})
m.Richs(ice.WEB_FAVOR, nil, m.Option("hot"), func(key string, value map[string]interface{}) {
m.Grows(ice.WEB_FAVOR, kit.Keys("hash", key), "", "", func(index int, value map[string]interface{}) {
m.Push(kit.Format(kit.Value(value, "extra.status")),
kit.Format(`<span title="%v" data-id="%v">%v</span>`,
kit.Format("%s-%s\n%s", kit.Value(value, "extra.begin_time"), kit.Value(value, "extra.close_time"), value["text"]),
value["id"], value["name"]))
})
})
}},
},

View File

@ -143,7 +143,7 @@ var Index = &ice.Context{Name: "wiki", Help: "文档模块",
// 生成文章
buffer := bytes.NewBuffer([]byte{})
f := m.Target().Server().(*web.Frame)
tmpl := f.HandleCGI(m, m.Confm("note", ice.Meta("alias")), path.Join(m.Conf("note", ice.Meta("path")), arg[0]))
tmpl := f.HandleCGI(m, m.Confm("note", ice.Meta("alias")), arg[0])
m.Assert(tmpl.ExecuteTemplate(buffer, m.Option("filename", path.Base(arg[0])), m))
// 缓存文章
@ -158,8 +158,8 @@ var Index = &ice.Context{Name: "wiki", Help: "文档模块",
m.Echo(string(markdown.ToHTML(buffer.Bytes(), nil, nil)))
}},
"_tree": {Name: "_tree path", Help: "文库", Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {
m.Cmdy("nfs.dir", m.Conf("note", ice.Meta("path")),
kit.Select("", arg, 0), m.Conf("note", ice.Meta("head")))
m.Cmdy("nfs.dir", m.Conf("note", "meta.path"),
kit.Select("", arg, 0), m.Conf("note", "meta.head"))
}},
"note": {Name: "note file", Help: "笔记", Meta: map[string]interface{}{
"remote": "you", "display": "inner",
@ -180,6 +180,9 @@ var Index = &ice.Context{Name: "wiki", Help: "文档模块",
}
return
}
if len(arg) > 0 && strings.HasSuffix(arg[0], ".md") {
arg[0] = path.Join(m.Conf("note", "meta.path"), arg[0])
}
m.Cmdy(kit.Select("_tree", "_text", len(arg) > 0 && strings.HasSuffix(arg[0], ".md")), arg)
}},
"index": {Name: "index hash", Help: "索引", Hand: func(m *ice.Message, c *ice.Context, key string, arg ...string) {

1
go.mod
View File

@ -6,4 +6,5 @@ require (
github.com/gomarkdown/markdown v0.0.0-20191207194928-fbea82c4bb03
github.com/gorilla/websocket v1.4.1
github.com/shylinux/toolkits v0.1.0
github.com/skip2/go-qrcode v0.0.0-20191027152451-9434209cb086
)

2
go.sum
View File

@ -6,4 +6,6 @@ github.com/shylinux/toolkits v0.0.0-20191225132906-3c11db083b5b h1:BXDEMcpHmwuwo
github.com/shylinux/toolkits v0.0.0-20191225132906-3c11db083b5b/go.mod h1:Y68Ot6xOmo1bun67YvqC3chDGeU2gDxtsUnvVDGJm4g=
github.com/shylinux/toolkits v0.1.0 h1:7ghnVEjuwLf7zBsyeR37ahm2gaOKIyjSw9F9Pp9oTBU=
github.com/shylinux/toolkits v0.1.0/go.mod h1:Y68Ot6xOmo1bun67YvqC3chDGeU2gDxtsUnvVDGJm4g=
github.com/skip2/go-qrcode v0.0.0-20191027152451-9434209cb086 h1:RYiqpb2ii2Z6J4x0wxK46kvPBbFuZcdhS+CIztmYgZs=
github.com/skip2/go-qrcode v0.0.0-20191027152451-9434209cb086/go.mod h1:PLPIyL7ikehBD1OAjmKKiOEhbvWyHGaNDjquXMcYABo=
golang.org/dl v0.0.0-20190829154251-82a15e2f2ead/go.mod h1:IUMfjQLJQd4UTqG1Z90tenwKoCX93Gn3MAQJMOSBsDQ=

View File

@ -55,6 +55,7 @@ var Index = &ice.Context{Name: "tmux", Help: "终端模块",
ice.ICE_INIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
m.Watch(ice.SYSTEM_INIT, "cli.tmux.init")
m.Watch(ice.DREAM_START, "cli.tmux.auto")
m.Watch(ice.FAVOR_START, "cli.tmux.auto")
}},
ice.ICE_EXIT: {Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
}},
@ -234,6 +235,13 @@ var Index = &ice.Context{Name: "tmux", Help: "终端模块",
}},
"auto": {Name: "auto", Help: "终端", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) {
prefix := []string{"cli.system", "tmux"}
if arg[0] == "" {
m.Cmd("cli.tmux.session").Table(func(index int, value map[string]string, head []string) {
if value["tag"] == "1" {
arg[0] = value["session"]
}
})
}
m.Option("cmd_env", "TMUX", "")
m.Option("cmd_dir", path.Join(m.Conf(ice.WEB_DREAM, "meta.path"), arg[0]))

View File

@ -2,6 +2,46 @@
icebergs是一个后端框架通过模块化、集群化实现资源的无限的扩展与自由的组合。
{{chain "icebergs" `
icebergs
type.go
msg.Detail
msg.Option
msg.Append
msg.Result
msg.Travel
msg.Search
msg.Conf
msg.Cmd
msg.Cap
base.go bg blue
Begin
_init
Start bg red
code
wiki
chat
ocean
river
action
storm
steam
team
mall
_exit
Close
conf.go
init
host
boot
node
user
work
auth
data
file
` "" "" 16}}
一键创建项目
```
mkdir miss; cd miss && curl -s https://shylinux.com/publish/build.sh | sh
@ -18,6 +58,10 @@ cli模块用于与系统进行交互。
- 系统信息 ice.CLI_RUNTIME
- 系统命令 ice.CLI_SYSTEM
## 网络模块 base/tcp
tcp模块用于管理网络的读写
## 文件模块 base/nfs
nfs模块用于管理文件的读写。