1
0
mirror of https://shylinux.com/x/ContextOS synced 2025-04-25 16:58:06 +08:00

Merge branch '1.0' of github.com:shylinux/context into 1.0

This commit is contained in:
shaoying 2018-10-22 09:20:28 +08:00
commit 32601e2634
18 changed files with 2034 additions and 2617 deletions

View File

@ -1,14 +1,2 @@
~aaa
# login load var/login.txt
~file1
history load var/history.txt
source etc/local.shy
~shell1
alias import nfs
alias send send
alias open open
alias dial dial
alias pwd pwd

View File

@ -69,7 +69,9 @@ func (aaa *AAA) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server
return time.Unix(int64(n), 0).Format("15:03:04")
}},
}
c.Configs = map[string]*ctx.Config{}
c.Configs = map[string]*ctx.Config{
"right": &ctx.Config{Name: "right", Value: map[string]interface{}{}, Help: "用户权限"},
}
s := new(AAA)
s.Context = c
@ -153,6 +155,7 @@ var Index = &ctx.Context{Name: "aaa", Help: "认证中心",
}
return true
}, c)
if m.Results(0) {
return
}
@ -173,18 +176,26 @@ var Index = &ctx.Context{Name: "aaa", Help: "认证中心",
}
return true
}, c)
if m.Results(0) {
m.Append("sessid", m.Result(0))
return
}
if arg[0] == "" {
return
}
m.Start(fmt.Sprintf("user%d", m.Capi("nuser", 1)), "密码登录", "password", arg[0])
m.Cap("password", "password", aaa.Password(arg[1]), "密码登录")
m.Append("sessid", m.Cap("sessid"))
m.Echo(m.Cap("sessid"))
return
case 1:
m.Sess("login", nil)
m.Travel(func(m *ctx.Message, n int) bool {
if n > 0 && m.Cap("sessid") == arg[0] {
if int64(m.Capi("expire_time")) > time.Now().Unix() {
m.Sess("login", m.Target().Message())
m.Echo(m.Cap("stream"))
} else {
m.Target().Close(m)
@ -205,6 +216,92 @@ var Index = &ctx.Context{Name: "aaa", Help: "认证中心",
}
}
}},
"right": &ctx.Command{Name: "right [user [check|owner|share group [order] [add|del]]]", Form: map[string]int{"from": 1}, Help: "权限管理", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
m.Travel(func(m *ctx.Message, n int) bool {
if n == 0 {
return true
}
if len(arg) == 0 {
m.Add("append", "user", m.Cap("stream"))
m.Add("append", "right", m.Confv("right"))
return true
}
if m.Cap("stream") == arg[0] {
if len(arg) == 1 { //查看所有权
for k, v := range m.Confv("right").(map[string]interface{}) {
m.Add("append", "group", k)
m.Add("append", "right", v)
}
return true
}
if arg[1] == "check" { //权限检查
if from := m.Confv("right", []interface{}{"right", "role"}); from != nil && from.(string) == "root" {
m.Echo("root")
}
if len(arg) == 2 {
return false
}
if from := m.Confv("right", []interface{}{arg[2], "right", "role"}); from != nil && from.(string) == "owner" {
m.Echo("owner")
}
if len(arg) == 3 {
return false
}
if from := m.Confv("right", []interface{}{arg[2], arg[3], "right", "role"}); from != nil && from.(string) == "share" {
m.Echo("share")
}
return false
}
if len(arg) == 2 { //分配人事权
if m.Option("from") != "root" {
return false
}
switch arg[1] {
case "add":
m.Confv("right", []interface{}{"right", "role"}, "root")
m.Confv("right", []interface{}{"right", "from"}, m.Option("from"))
case "del":
m.Confv("right", []interface{}{"right", "role"}, "")
}
return true
}
if len(arg) == 3 { //查看使用权
for k, v := range m.Confv("right", arg[2]).(map[string]interface{}) {
m.Add("append", "order", k)
m.Add("append", "right", v)
}
return true
}
switch arg[1] {
case "owner": //分配所有权
if m.Cmd("right", m.Option("from"), "check").Result(0) == "" {
return false
}
switch arg[3] {
case "add":
m.Confv("right", []interface{}{arg[2], "right", "role"}, "owner")
m.Confv("right", []interface{}{arg[2], "right", "from"}, m.Option("from"))
case "del":
m.Confv("right", []interface{}{arg[2], "right", "role"}, "")
}
case "share": //分配使用权
if m.Cmd("right", m.Option("from"), "check", arg[2]).Result(0) == "" {
return false
}
switch arg[4] {
case "add":
m.Confv("right", []interface{}{arg[2], arg[3], "right", "role"}, "share")
m.Confv("right", []interface{}{arg[2], arg[3], "right", "from"}, m.Option("from"))
case "del":
m.Confv("right", []interface{}{arg[2], arg[3], "right", "role"}, "")
}
}
return false
}
return true
}, c)
m.Table()
}},
"cert": &ctx.Command{Name: "cert [filename]", Help: "导出证书", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if aaa, ok := m.Target().Server.(*AAA); m.Assert(ok) && aaa.certificate != nil {
certificate := string(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: aaa.certificate.Raw}))

View File

@ -1,20 +1,16 @@
package cli // {{{
// }}}
import ( // {{{
"contexts/ctx"
package cli
import (
"contexts/ctx"
"fmt"
"os"
"os/exec"
"regexp"
"strconv"
"strings"
"os"
"os/exec"
"time"
)
// }}}
type Frame struct {
key string
run bool
@ -22,7 +18,6 @@ type Frame struct {
index int
list []string
}
type CLI struct {
alias map[string][]string
label map[string]string
@ -33,7 +28,7 @@ type CLI struct {
*ctx.Context
}
func (cli *CLI) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server { // {{{
func (cli *CLI) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server {
c.Caches = map[string]*ctx.Cache{
"level": &ctx.Cache{Name: "level", Value: "0", Help: "嵌套层级"},
"parse": &ctx.Cache{Name: "parse(true/false)", Value: "true", Help: "命令解析"},
@ -43,15 +38,15 @@ func (cli *CLI) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server
}
c.Configs = map[string]*ctx.Config{
"ps_time": &ctx.Config{Name: "ps_time", Value: "[15:04:05]", Help: "当前时间", Hand: func(m *ctx.Message, x *ctx.Config, arg ...string) string {
if len(arg) > 0 { // {{{
if len(arg) > 0 {
return arg[0]
}
return time.Now().Format(x.Value.(string))
// }}}
}},
"ps_end": &ctx.Config{Name: "ps_end", Value: "> ", Help: "命令行提示符结尾"},
"prompt": &ctx.Config{Name: "prompt(ps_count/ps_time/ps_target/ps_end/...)", Value: "ps_count ps_time ps_target ps_end", Help: "命令行提示符, 以空格分隔, 依次显示缓存或配置信息", Hand: func(m *ctx.Message, x *ctx.Config, arg ...string) string {
if len(arg) > 0 { // {{{
if len(arg) > 0 {
return arg[0]
}
@ -64,7 +59,7 @@ func (cli *CLI) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server
}
}
return strings.Join(ps, "")
// }}}
}},
}
@ -83,15 +78,11 @@ func (cli *CLI) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server
return s
}
// }}}
func (cli *CLI) Begin(m *ctx.Message, arg ...string) ctx.Server { // {{{
func (cli *CLI) Begin(m *ctx.Message, arg ...string) ctx.Server {
cli.Message = m
return cli
}
// }}}
func (cli *CLI) Start(m *ctx.Message, arg ...string) bool { // {{{
func (cli *CLI) Start(m *ctx.Message, arg ...string) bool {
cli.Message = m
m.Sess("cli", m)
yac := m.Sess("yac")
@ -178,9 +169,7 @@ func (cli *CLI) Start(m *ctx.Message, arg ...string) bool { // {{{
}
return false
}
// }}}
func (cli *CLI) Close(m *ctx.Message, arg ...string) bool { // {{{
func (cli *CLI) Close(m *ctx.Message, arg ...string) bool {
switch cli.Context {
case m.Target():
case m.Source():
@ -188,8 +177,6 @@ func (cli *CLI) Close(m *ctx.Message, arg ...string) bool { // {{{
return true
}
// }}}
var Pulse *ctx.Message
var Index = &ctx.Context{Name: "cli", Help: "管理中心",
Caches: map[string]*ctx.Cache{
@ -199,11 +186,11 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
"init.shy": &ctx.Config{Name: "init.shy", Value: "etc/init.shy", Help: "启动脚本"},
"exit.shy": &ctx.Config{Name: "exit.shy", Value: "etc/exit.shy", Help: "启动脚本"},
"cli_name": &ctx.Config{Name: "cli_name", Value: "shell", Help: "模块命名", Hand: func(m *ctx.Message, x *ctx.Config, arg ...string) string {
if len(arg) > 0 { // {{{
if len(arg) > 0 {
return arg[0]
}
return fmt.Sprintf("%s%d", x.Value, m.Capi("nshell", 1))
// }}}
}},
"cli_help": &ctx.Config{Name: "cli_help", Value: "shell", Help: "模块文档"},
"cmd_timeout": &ctx.Config{Name: "cmd_timeout", Value: "60s", Help: "系统命令超时"},
@ -239,28 +226,28 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
}
}},
"label": &ctx.Command{Name: "label name", Help: "记录当前脚本的位置, name: 位置名", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{
if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) {
if cli.label == nil {
cli.label = map[string]string{}
}
cli.label[arg[1]] = m.Option("file_pos")
} // }}}
}
}},
"goto": &ctx.Command{Name: "goto label [exp] condition", Help: "向上跳转到指定位置, label: 跳转位置, condition: 跳转条件", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{
if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) {
if pos, ok := cli.label[arg[1]]; ok {
if !ctx.Right(arg[len(arg)-1]) {
return
}
m.Append("file_pos0", pos)
}
} // }}}
}
}},
"return": &ctx.Command{Name: "return result...", Help: "结束脚本, result: 返回值", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
m.Add("append", "return", arg[1:])
}},
"target": &ctx.Command{Name: "target module", Help: "设置当前模块, module: 模块全名", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{
if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) {
if len(arg) == 0 {
m.Echo("%s", m.Cap("ps_target"))
return
@ -269,13 +256,13 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
cli.target = msg.Target()
m.Cap("ps_target", cli.target.Name)
}
} // }}}
}
}},
"alias": &ctx.Command{
Name: "alias [short [long...]]|[delete short]|[import module [command [alias]]]",
Help: "查看、定义或删除命令别名, short: 命令别名, long: 命令原名, delete: 删除别名, import导入模块所有命令",
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{
if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) {
switch len(arg) {
case 0:
for k, v := range cli.alias {
@ -318,21 +305,21 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
m.Log("info", "%s: %v", arg[0], cli.alias[arg[0]])
}
}
} // }}}
}
}},
"sleep": &ctx.Command{Name: "sleep time", Help: "睡眠, time(ns/us/ms/s/m/h): 时间值(纳秒/微秒/毫秒/秒/分钟/小时)", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if d, e := time.ParseDuration(arg[0]); m.Assert(e) { // {{{
if d, e := time.ParseDuration(arg[0]); m.Assert(e) {
m.Log("info", "sleep %v", d)
time.Sleep(d)
m.Log("info", "sleep %v done", d)
} // }}}
}
}},
"time": &ctx.Command{
Name: "time [time_format format] [parse when] when [begin|end|yestoday|tommorow|monday|sunday|first|last|origin|last]",
Form: map[string]int{"time_format": 1, "parse": 1, "time_interval": 1},
Help: "查看时间, time_format: 输出或解析的时间格式, parse: 输入的时间字符串, when: 输入的时间戳, 其它是时间偏移",
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
t := time.Now() // {{{
t := time.Now()
if m.Options("parse") {
n, e := time.ParseInLocation(m.Confx("time_format"), m.Option("parse"), time.Local)
m.Assert(e)
@ -341,7 +328,6 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
if len(arg) > 0 {
if i, e := strconv.ParseInt(arg[0], 10, 64); e == nil {
m.Option("time_format", m.Conf("time_format"))
t = time.Unix(int64(i/int64(m.Confi("time_unit"))), 0)
arg = arg[1:]
} else if n, e := time.ParseInLocation(m.Confx("time_format"), arg[0], time.Local); e == nil {
@ -405,7 +391,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
} else {
m.Echo(t.Format(m.Confx("time_format")))
}
// }}}
}},
"echo": &ctx.Command{Name: "echo arg...", Help: "函数调用, name: 函数名, arg: 参数", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
m.Echo("%s", strings.Join(arg, ""))
@ -415,7 +401,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
m.Echo(arg[0][1 : len(arg[0])-1])
}},
"exe": &ctx.Command{Name: "exe $ ( cmd )", Help: "解析嵌套命令", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{
if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) {
switch len(arg) {
case 1:
m.Echo(arg[0])
@ -438,7 +424,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
} //}}}
}},
"val": &ctx.Command{Name: "val exp", Help: "表达式运算", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
result := "false" // {{{
result := "false"
switch len(arg) {
case 0:
result = ""
@ -567,7 +553,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
}
}
m.Echo(result)
// }}}
}},
"exp": &ctx.Command{Name: "exp word", Help: "表达式运算", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if len(arg) > 0 && arg[0] == "{" {
@ -585,7 +571,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
return
}
pre := map[string]int{ // {{{
pre := map[string]int{
"=": 1,
"+": 2, "-": 2,
"*": 3, "/": 3, "%": 3,
@ -609,10 +595,10 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
}
m.Echo("%s", num[0])
// }}}
}},
"var": &ctx.Command{Name: "var a [= exp]", Help: "定义变量, a: 变量名, exp: 表达式", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if m.Cap(arg[1], arg[1], "", "临时变量"); len(arg) > 1 { // {{{
if m.Cap(arg[1], arg[1], "", "临时变量"); len(arg) > 1 {
switch arg[2] {
case "=":
m.Cap(arg[1], arg[3])
@ -621,28 +607,28 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
}
}
m.Echo(m.Cap(arg[1]))
// }}}
}},
"let": &ctx.Command{Name: "let a = exp", Help: "设置变量, a: 变量名, exp: 表达式(a {+|-|*|/|%} b)", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
switch arg[2] { // {{{
switch arg[2] {
case "=":
m.Cap(arg[1], arg[3])
case "<-":
m.Cap(arg[1], m.Cap("last_msg"))
}
m.Echo(m.Cap(arg[1]))
// }}}
}},
"if": &ctx.Command{Name: "if exp", Help: "条件语句, exp: 表达式", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{
if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) {
run := m.Caps("parse") && ctx.Right(arg[1])
cli.stack = append(cli.stack, &Frame{pos: m.Optioni("file_pos"), key: key, run: run})
m.Capi("level", 1)
m.Caps("parse", run)
} // }}}
}
}},
"else": &ctx.Command{Name: "else", Help: "条件语句", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{
if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) {
if !m.Caps("parse") {
m.Caps("parse", true)
} else {
@ -653,10 +639,10 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
m.Caps("parse", !frame.run)
}
}
} // }}}
}
}},
"end": &ctx.Command{Name: "end", Help: "结束语句", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{
if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) {
if frame := cli.stack[len(cli.stack)-1]; frame.key == "for" && frame.run {
m.Append("file_pos0", frame.pos)
return
@ -667,13 +653,13 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
} else {
m.Caps("parse", true)
}
} // }}}
}
}},
"for": &ctx.Command{
Name: "for [[express ;] condition]|[index message meta value]",
Help: "循环语句, express: 每次循环运行的表达式, condition: 循环条件, index: 索引消息, message: 消息编号, meta: value: ",
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{
if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) {
run := m.Caps("parse")
defer func() { m.Caps("parse", run) }()
@ -726,10 +712,10 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
}
m.Cap(arg[3], arg[3], frame.list[0], "临时变量")
}
} // }}}
}
}},
"cmd": &ctx.Command{Name: "cmd word", Help: "", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{
if cli, ok := m.Target().Server.(*CLI); m.Assert(ok) {
detail := []string{}
if a, ok := cli.alias[arg[0]]; ok {
detail = append(detail, a...)
@ -769,18 +755,19 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
msg.Copy(m, "target").Detail(-1, "system")
msg.Cmd()
}
m.Target().Message().Set("result").Set("append").Copy(msg, "result").Copy(msg, "append")
m.Copy(msg, "result").Copy(msg, "append")
m.Capi("last_msg", 0, msg.Code())
m.Capi("ps_count", 1)
}
// }}}
}},
"system": &ctx.Command{
Name: "system [cmd_combine true|false] [cmd_timeout time] word...",
Help: "调用系统命令, cmd_combine: 非交互式命令, cmd_timeout: 命令超时, word: 命令",
Form: map[string]int{"cmd_combine": 1, "cmd_timeout": 1},
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
system := map[string]bool{"vi": true} // {{{
system := map[string]bool{"vi": true}
ui, ok := system[arg[0]]
if ui = ok && ui; m.Option("cmd_combine") != "" {
ui = !m.Options("cmd_combine")
@ -815,7 +802,7 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
case <-wait:
}
}
// }}}
}},
"login": &ctx.Command{Name: "login username password", Help: "", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
m.Sess("aaa", false).Cmd("login", arg[0], arg[1])
@ -826,6 +813,27 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
"tmux": &ctx.Command{Name: "tmux", Help: "", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
m.Copy(m.Spawn().Cmd("system", "tmux", arg), "result")
}},
"buffer": &ctx.Command{Name: "buffer", Help: "", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
bufs := strings.Split(m.Spawn().Cmd("system", "tmux", "list-buffers").Result(0), "\n")
n := 3
if m.Option("limit") != "" {
n = m.Optioni("limit")
}
for i, b := range bufs {
if i >= n {
break
}
bs := strings.SplitN(b, ": ", 3)
if len(bs) > 1 {
m.Add("append", "buffer", bs[0][:len(bs[0])])
m.Add("append", "length", bs[1][:len(bs[1])-6])
m.Add("append", "string", bs[2][1:len(bs[2])-1])
}
}
m.Echo(m.Append("string"))
}},
},
Index: map[string]*ctx.Context{
"void": &ctx.Context{Caches: map[string]*ctx.Cache{"nshell": &ctx.Cache{}}},

View File

@ -709,7 +709,14 @@ func (m *Message) Search(key string, root ...bool) []*Message {
}
func (m *Message) Sess(key string, arg ...interface{}) *Message {
spawn := true
if _, ok := m.Sessions[key]; !ok && len(arg) > 0 {
if len(arg) > 0 {
switch v := arg[0].(type) {
case bool:
spawn, arg = v, arg[1:]
}
}
if len(arg) > 0 {
if m.Sessions == nil {
m.Sessions = make(map[string]*Message)
}
@ -747,13 +754,9 @@ func (m *Message) Sess(key string, arg ...interface{}) *Message {
m.Sessions[key] = m.Search(value, root)[0]
}
return m.Sessions[key]
}
}
if len(arg) > 0 {
switch v := arg[0].(type) {
case bool:
spawn = v
case nil:
m.Sessions[key] = nil
return nil
}
}
@ -1077,6 +1080,14 @@ func (m *Message) Sort(key string, arg ...string) *Message {
for j := i + 1; j < len(table); j++ {
result := false
switch cmp {
case "str":
if table[i][key] > table[j][key] {
result = true
}
case "str_r":
if table[i][key] < table[j][key] {
result = true
}
case "int":
a, e := strconv.Atoi(table[i][key])
m.Assert(e)
@ -1093,14 +1104,6 @@ func (m *Message) Sort(key string, arg ...string) *Message {
if a < b {
result = true
}
case "string":
if table[i][key] > table[j][key] {
result = true
}
case "string_r":
if table[i][key] < table[j][key] {
result = true
}
case "time":
ti, e := time.ParseInLocation(m.Confx("time_layout"), table[i][key], time.Local)
m.Assert(e)
@ -1964,16 +1967,18 @@ var CGI = template.FuncMap{
m.Assert(e)
index = i
}
if len(arg) == 2 {
return m.Detail(index)
}
return m.Detail(index, arg[2])
case map[string][]string:
return strings.Join(m["detail"], "")
case []string:
return strings.Join(m, "")
default:
return fmt.Sprintf("%v", arg[0])
return m
}
return ""
},
@ -2016,7 +2021,7 @@ var CGI = template.FuncMap{
case []string:
return strings.Join(m, "")
default:
return fmt.Sprintf("%v", arg[0])
return m
}
return ""
},
@ -2040,16 +2045,18 @@ var CGI = template.FuncMap{
m.Assert(e)
index = i
}
if len(arg) == 2 {
return m.Result(index)
}
return m.Result(index, arg[2])
case map[string][]string:
return strings.Join(m["result"], "")
case []string:
return strings.Join(m, "")
default:
return fmt.Sprintf("%v", arg[0])
return m
}
return ""
},
@ -2092,11 +2099,55 @@ var CGI = template.FuncMap{
case []string:
return strings.Join(m, "")
default:
return fmt.Sprintf("%v", arg[0])
return m
}
return ""
},
"unscaped": func(str string) interface{} {
"table": func(arg ...interface{}) []interface{} {
if len(arg) == 0 {
return []interface{}{}
}
switch m := arg[0].(type) {
case *Message:
if len(m.Meta["append"]) == 0 {
return []interface{}{}
}
if len(arg) == 1 {
data := []interface{}{}
nrow := len(m.Meta[m.Meta["append"][0]])
for i := 0; i < nrow; i++ {
line := map[string]string{}
for _, k := range m.Meta["append"] {
line[k] = m.Meta[k][i]
if len(m.Meta[k]) != i {
continue
}
}
data = append(data, line)
}
return data
}
case map[string][]string:
if len(arg) == 1 {
data := []interface{}{}
nrow := len(m[m["append"][0]])
for i := 0; i < nrow; i++ {
line := map[string]string{}
for _, k := range m["append"] {
line[k] = m[k][i]
}
data = append(data, line)
}
return data
}
}
return []interface{}{}
},
"unescape": func(str string) interface{} {
return template.HTML(str)
},
@ -2327,7 +2378,7 @@ var Index = &Context{Name: "ctx", Help: "模块中心",
m.Color(31, "option(%d): %v\n", len(msg.Meta["option"]), msg.Meta["option"])
for _, k := range msg.Meta["option"] {
if v, ok := msg.Data[k]; ok {
m.Echo(" %s: %v\n", k, v)
m.Echo(" %s: %#v\n", k, v)
} else {
m.Echo(" %s(%d): %v\n", k, len(msg.Meta[k]), msg.Meta[k])
}
@ -2978,6 +3029,7 @@ var Index = &Context{Name: "ctx", Help: "模块中心",
"where_field": 1, "where_value": 1,
"sort_field": 1, "sort_order": 1,
"page_limit": 1, "page_offset": 1,
"format_field": 2,
"select": 3,
},
Hand: func(m *Message, c *Context, key string, arg ...string) {
@ -3022,6 +3074,12 @@ var Index = &Context{Name: "ctx", Help: "模块中心",
de.Decode(&save)
}
format_field := m.Option("format_field")
format_str := "%s"
if format_field != "" {
format_str = m.Meta["format_field"][1]
}
// sort_field := m.Option("sort_field")
// sort_order := m.Option("sort_order")
m.BackTrace(func(m *Message) bool {
@ -3113,9 +3171,13 @@ var Index = &Context{Name: "ctx", Help: "模块中心",
m.Add("append", "index", "0")
for k, v := range val {
if len(fields) == 0 || fields[k] {
if k == format_field {
m.Add("append", k, fmt.Sprintf(format_str, v))
} else {
m.Add("append", k, v)
}
}
}
case []interface{}:
n := 0
for i, value := range val {
@ -3134,19 +3196,30 @@ var Index = &Context{Name: "ctx", Help: "模块中心",
m.Add("append", "index", i)
for k, v := range val {
if len(fields) == 0 || fields[k] {
if k == format_field {
m.Add("append", k, fmt.Sprintf(format_str, v, v))
} else {
m.Add("append", k, v)
}
}
}
}
}
case []string:
for i, v := range val {
m.Add("append", "index", i)
m.Add("append", "value", v)
if k == format_field {
m.Add("append", k, fmt.Sprintf(format_str, v, v))
} else {
m.Add("append", k, v)
}
}
default:
m.Echo("%v", Trans(val)[0])
}
case 3:
m.Echo("%v", m.Confv(arg[0], strings.Split(arg[1], "."), arg[2]))
default:
m.Echo("%v", m.Confv(arg[0], arg[1:]))
return false

View File

@ -68,8 +68,8 @@ func dir(m *ctx.Message, name string, level int, deep bool, fields []string) {
switch k {
case "filename":
m.Add("append", "filename", "..")
case "dir":
m.Add("append", "dir", "true")
case "is_dir":
m.Add("append", "is_dir", "true")
case "size":
m.Add("append", "size", 0)
case "line":
@ -130,8 +130,8 @@ func dir(m *ctx.Message, name string, level int, deep bool, fields []string) {
switch k {
case "filename":
m.Add("append", "filename", filename)
case "dir":
m.Add("append", "dir", f.IsDir())
case "is_dir":
m.Add("append", "is_dir", f.IsDir())
case "size":
m.Add("append", "size", f.Size())
case "line":
@ -803,11 +803,12 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心",
"buf_size": &ctx.Config{Name: "buf_size", Value: "1024", Help: "读取文件的缓存区的大小"},
"qr_size": &ctx.Config{Name: "qr_size", Value: "256", Help: "生成二维码的图片的大小"},
"dir_name": &ctx.Config{Name: "dir_name(name/tree/path/full)", Value: "name", Help: "dir命令输出文件名的类型, name: 文件名, tree: 带缩进的文件名, path: 相对路径, full: 绝对路径"},
"dir_info": &ctx.Config{Name: "dir_info(sizes/lines/files/dirs)", Value: "sizes lines files dirs", Help: "dir命令输出目录的统计信息, info: 输出统计信息, 否则输出"},
"dir_root": &ctx.Config{Name: "dir_root", Value: "usr", Help: "dir命令输出目录的统计信息, info: 输出统计信息, 否则输出"},
"dir_deep": &ctx.Config{Name: "dir_deep(yes/no)", Value: "yes", Help: "dir命令输出目录的统计信息, info: 输出统计信息, 否则输出"},
"dir_type": &ctx.Config{Name: "dir_type(file/dir)", Value: "file", Help: "dir命令输出的文件类型, file: 只输出普通文件, dir: 只输出目录文件, 否则输出所有文件"},
"dir_field": &ctx.Config{Name: "dir_field", Value: "filename line size time", Help: "表格排序字段"},
"dir_name": &ctx.Config{Name: "dir_name(name/tree/path/full)", Value: "name", Help: "dir命令输出文件名的类型, name: 文件名, tree: 带缩进的文件名, path: 相对路径, full: 绝对路径"},
"dir_info": &ctx.Config{Name: "dir_info(sizes/lines/files/dirs)", Value: "sizes lines files dirs", Help: "dir命令输出目录的统计信息, info: 输出统计信息, 否则输出"},
"dir_field": &ctx.Config{Name: "dir_field", Value: "filename is_dir line size time", Help: "表格排序字段"},
"sort_field": &ctx.Config{Name: "sort_field", Value: "line", Help: "表格排序字段"},
"sort_order": &ctx.Config{Name: "sort_order(int/int_r/string/string_r/time/time_r)", Value: "int", Help: "表格排序类型"},
@ -1078,13 +1079,16 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心",
if len(arg) == 1 {
var data interface{}
e := json.Unmarshal([]byte(arg[0]), &data)
if e != nil {
return
}
m.Assert(e)
buf, e := json.MarshalIndent(data, "", " ")
m.Assert(e)
m.Echo("'")
// m.Echo("'")
m.Echo(string(buf))
m.Echo("'")
// m.Echo("'")
return
}
@ -1122,10 +1126,6 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心",
"pwd": &ctx.Command{Name: "pwd", Help: "查看当前路径", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if m.Options("dir") {
m.Echo(m.Option("dir"))
m.Add("append", "hi", "hello")
m.Add("append", "he", "hello")
m.Add("append", "hi", "world")
m.Add("append", "he", "world")
return
}
if len(arg) > 0 {
@ -1134,20 +1134,31 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心",
wd, e := os.Getwd()
m.Assert(e)
m.Echo(wd)
m.Append("hi", "hello")
}},
"dir": &ctx.Command{
Name: "dir dir [dir_deep yes|no] [dir_info info] [dir_name name|tree|path|full] [dir_type file|dir] [sort_field name] [sort_order type]",
Name: "dir dir [dir_deep yes|no] [dir_info info] [dir_name name|tree|path|full] [dir_type both|file|dir] [sort_field name] [sort_order type]",
Help: "查看目录, dir: 目录名, dir_info: 显示统计信息, dir_name: 文件名类型, dir_type: 文件类型, sort_field: 排序字段, sort_order: 排序类型",
Form: map[string]int{"dir_field": 1, "dir_deep": 1, "dir_info": 1, "dir_name": 1, "dir_type": 1, "sort_field": 1, "sort_order": 1},
Form: map[string]int{
"dir_root": 1,
"dir_deep": 1,
"dir_type": 1,
"dir_name": 1,
"dir_info": 1,
"dir_link": 1,
"dir_field": 1,
"sort_field": 1,
"sort_order": 1,
},
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
d := "./" + m.Option("dir")
if len(arg) > 0 {
d = arg[0]
m.Option("dir", arg[0])
}
m.Option("dir", path.Clean(m.Option("dir")))
d := path.Join(m.Confx("dir_root"), m.Option("dir"))
if s, e := os.Stat(d); m.Assert(e) && !s.IsDir() {
d = path.Dir(d)
}
fields := strings.Split(m.Confx("dir_field"), " ")
trip := 0
@ -1170,22 +1181,30 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心",
key := m.Meta["append"][i]
switch key {
case "filename":
v = maps[key]
if line > -1 && trip > 0 && trip <= len(v) {
v = v[trip:]
if m.Options("dir_link") {
m.Meta["filename"][line] = fmt.Sprintf(m.Option("dir_link"), maps["is_dir"], v)
} else {
m.Meta["filename"][line] = v
}
case "dir":
continue
}
m.Echo("%s\t", v)
if line > -1 {
if m.Options("dir_link") {
m.Meta["filename"][line] = fmt.Sprintf(m.Option("dir_link"), maps["is_dir"], v)
}
}
}
}
m.Echo("\n")
return true
})
if !m.Options("dir_link") {
m.Table()
}
for _, v := range info {
m.Echo("%s: %s\n", v, m.Option(v))
}
}},
"git": &ctx.Command{
Name: "git branch|status|diff|log|info arg... [dir path]...",

File diff suppressed because it is too large Load Diff

View File

@ -1,21 +1,645 @@
package code
import (
"bytes"
"contexts/ctx"
"contexts/web"
"encoding/json"
"fmt"
"html/template"
"io"
"net/http"
"os"
"path"
"strings"
)
type CODE struct {
web.WEB
}
// yac := m.Sess("tags", m.Sess("yac").Cmd("scan"))
// yac.Cmd("train", "void", "void", "[\t ]+")
// yac.Cmd("train", "other", "other", "[^\n]+")
// yac.Cmd("train", "key", "key", "[A-Za-z_][A-Za-z_0-9]*")
// yac.Cmd("train", "code", "def", "def", "key", "(", "other")
// yac.Cmd("train", "code", "def", "class", "key", "other")
// yac.Cmd("train", "code", "struct", "struct", "key", "\\{")
// yac.Cmd("train", "code", "struct", "\\}", "key", ";")
// yac.Cmd("train", "code", "struct", "typedef", "struct", "key", "key", ";")
// yac.Cmd("train", "code", "function", "key", "\\*", "key", "(", "other")
// yac.Cmd("train", "code", "function", "key", "key", "(", "other")
// yac.Cmd("train", "code", "variable", "struct", "key", "key", "other")
// yac.Cmd("train", "code", "define", "#define", "key", "other")
//
var Index = &ctx.Context{Name: "code", Help: "代码中心",
Caches: map[string]*ctx.Cache{},
Configs: map[string]*ctx.Config{},
Configs: map[string]*ctx.Config{
"library_dir": &ctx.Config{Name: "library_dir", Value: "usr", Help: "通用模板路径"},
"template_dir": &ctx.Config{Name: "template_dir", Value: "usr/template/", Help: "通用模板路径"},
"common_tmpl": &ctx.Config{Name: "common_tmpl", Value: "common/*.html", Help: "通用模板路径"},
"common_main": &ctx.Config{Name: "common_main", Value: "main.html", Help: "通用模板框架"},
"upload_tmpl": &ctx.Config{Name: "upload_tmpl", Value: "upload.html", Help: "上传文件模板"},
"upload_main": &ctx.Config{Name: "upload_main", Value: "main.html", Help: "上传文件框架"},
"travel_tmpl": &ctx.Config{Name: "travel_tmpl", Value: "travel.html", Help: "浏览模块模板"},
"travel_main": &ctx.Config{Name: "travel_main", Value: "main.html", Help: "浏览模块框架"},
"check": &ctx.Config{Name: "check", Value: map[string]interface{}{
"login": []interface{}{
map[string]interface{}{
"session": "aaa",
"module": "aaa", "command": "login",
"variable": []interface{}{"$sessid"},
"template": "login", "title": "login",
},
map[string]interface{}{
"module": "aaa", "command": "login",
"variable": []interface{}{"$username", "$password"},
"template": "login", "title": "login",
},
},
"right": []interface{}{
map[string]interface{}{
"module": "web", "command": "right",
"variable": []interface{}{"$username", "check", "command", "/index", "dir", "$dir"},
"template": "notice", "title": "notice",
},
map[string]interface{}{
"module": "aaa", "command": "login",
"variable": []interface{}{"username", "password"},
"template": "login", "title": "login",
},
},
}, Help: "执行条件"},
"auto_create": &ctx.Config{Name: "auto_create(true/false)", Value: "true", Help: "路由数量"},
"refresh_time": &ctx.Config{Name: "refresh_time(ms)", Value: "1000", Help: "路由数量"},
"define": &ctx.Config{Name: "define", Value: map[string]interface{}{
"ngx_command_t": map[string]interface{}{
"position": []interface{}{map[string]interface{}{
"file": "nginx-1.15.2/src/core/ngx_core.h",
"line": "22",
}},
},
"ngx_command_s": map[string]interface{}{
"position": map[string]interface{}{
"file": "nginx-1.15.2/src/core/ngx_conf_file.h",
"line": "77",
},
},
}, Help: "路由数量"},
"index": &ctx.Config{Name: "index", Value: map[string]interface{}{
"duyu": []interface{}{
map[string]interface{}{
"template": "userinfo", "title": "userinfo",
},
map[string]interface{}{
"from": "root", "to": []interface{}{},
"module": "aaa", "command": "lark",
"argument": []interface{}{},
"template": "append", "title": "lark_friend",
},
map[string]interface{}{
"module": "aaa", "detail": []interface{}{"lark"},
"template": "detail", "title": "send_lark",
"option": map[string]interface{}{"ninput": 2},
},
map[string]interface{}{
"module": "aaa", "command": "lark",
"argument": []interface{}{"duyu"},
"template": "append", "title": "lark",
},
map[string]interface{}{
"module": "nfs", "command": "dir",
"argument": []interface{}{"dir_type", "all", "dir_deep", "false", "dir_field", "time size line filename", "sort_field", "time", "sort_order", "time_r"},
"template": "append", "title": "",
},
},
"shy": []interface{}{
map[string]interface{}{
"from": "root", "to": []interface{}{},
"template": "userinfo", "title": "userinfo",
},
//文件服务
map[string]interface{}{
"from": "root", "to": []interface{}{},
"module": "nfs", "command": "dir",
"argument": []interface{}{"dir_type", "all", "dir_deep", "false", "dir_field", "time size line filename", "sort_field", "time", "sort_order", "time_r"},
"template": "append", "title": "",
},
map[string]interface{}{
"from": "root", "to": []interface{}{},
"template": "upload", "title": "upload",
},
map[string]interface{}{
"from": "root", "to": []interface{}{},
"template": "create", "title": "create",
},
//会话服务
map[string]interface{}{
"from": "root", "to": []interface{}{},
"module": "cli", "command": "system",
"argument": []interface{}{"tmux", "show-buffer"},
"template": "result", "title": "buffer",
},
map[string]interface{}{
"from": "root", "to": []interface{}{},
"module": "cli", "command": "system",
"argument": []interface{}{"tmux", "list-clients"},
"template": "result", "title": "client",
},
map[string]interface{}{
"from": "root", "to": []interface{}{},
"module": "cli", "command": "system",
"argument": []interface{}{"tmux", "list-sessions"},
"template": "result", "title": "session",
},
//格式转换
map[string]interface{}{
"from": "root", "to": []interface{}{},
"module": "cli", "detail": []interface{}{"time"},
"template": "detail", "title": "time",
"option": map[string]interface{}{"refresh": true, "ninput": 1},
},
map[string]interface{}{
"from": "root", "to": []interface{}{},
"module": "nfs", "detail": []interface{}{"json"},
"template": "detail", "title": "json",
"option": map[string]interface{}{"ninput": 1},
},
map[string]interface{}{
"from": "root", "to": []interface{}{},
"module": "nfs", "detail": []interface{}{"pwd"},
"template": "detail", "title": "pwd",
"option": map[string]interface{}{"refresh": true},
},
map[string]interface{}{
"from": "root", "to": []interface{}{},
"module": "nfs", "command": "git",
"argument": []interface{}{},
"template": "result", "title": "git",
},
map[string]interface{}{
"from": "root", "to": []interface{}{},
"module": "web", "command": "/share",
"argument": []interface{}{},
"template": "share", "title": "share",
},
},
"notice": []interface{}{
map[string]interface{}{
"template": "userinfo", "title": "userinfo",
},
map[string]interface{}{
"template": "notice", "title": "notice",
},
},
"login": []interface{}{
map[string]interface{}{
"template": "login", "title": "login",
},
},
"wiki": []interface{}{
map[string]interface{}{
"template": "wiki_head", "title": "wiki_head",
},
map[string]interface{}{
"template": "wiki_menu", "title": "wiki_menu",
},
map[string]interface{}{
"module": "web", "command": "/wiki_list",
"template": "wiki_list", "title": "wiki_list",
},
map[string]interface{}{
"module": "web", "command": "/wiki_body",
"template": "wiki_body", "title": "wiki_body",
},
},
}, Help: "资源列表"},
},
Commands: map[string]*ctx.Command{
"/demo": &ctx.Command{Name: "/demo", Help: "demo", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
m.Echo("demo")
}},
"/render": &ctx.Command{Name: "/render index", Help: "模板响应, main: 模板入口, tmpl: 附加模板", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
w := m.Optionv("response").(http.ResponseWriter)
w.Header().Add("Content-Type", "text/html")
m.Optioni("ninput", 0)
tpl := template.New("render").Funcs(ctx.CGI)
tpl = template.Must(tpl.ParseGlob(path.Join(m.Conf("template_dir"), m.Conf("common_tmpl"))))
tpl = template.Must(tpl.ParseGlob(path.Join(m.Conf("template_dir"), m.Conf("upload_tmpl"))))
replace := [][]byte{
[]byte{27, 91, 51, 50, 109}, []byte("<span style='color:red'>"),
[]byte{27, 91, 51, 49, 109}, []byte("<span style='color:green'>"),
[]byte{27, 91, 109}, []byte("</span>"),
}
if m.Confv("index", arg[0]) == nil {
arg[0] = "notice"
}
m.Assert(tpl.ExecuteTemplate(w, "head", m))
for _, v := range m.Confv("index", arg[0]).([]interface{}) {
if v == nil {
continue
}
val := v.(map[string]interface{})
//命令模板
if detail, ok := val["detail"].([]interface{}); ok {
msg := m.Spawn().Add("detail", detail[0].(string), detail[1:])
msg.Option("module", val["module"])
msg.Option("title", val["title"])
if option, ok := val["option"].(map[string]interface{}); ok {
for k, v := range option {
msg.Option(k, v)
}
}
m.Assert(tpl.ExecuteTemplate(w, val["template"].(string), msg))
continue
}
//执行命令
if _, ok := val["command"]; ok {
msg := m.Find(val["module"].(string)).Cmd(val["command"], val["argument"])
for i, v := range msg.Meta["result"] {
b := []byte(v)
for i := 0; i < len(replace)-1; i += 2 {
b = bytes.Replace(b, replace[i], replace[i+1], -1)
}
msg.Meta["result"][i] = string(b)
}
if msg.Option("title", val["title"]) == "" {
msg.Option("title", m.Option("dir"))
}
m.Assert(tpl.ExecuteTemplate(w, val["template"].(string), msg))
continue
}
//解析模板
if _, ok := val["template"]; ok {
m.Assert(tpl.ExecuteTemplate(w, val["template"].(string), m))
}
}
m.Assert(tpl.ExecuteTemplate(w, "tail", m))
}},
"/check": &ctx.Command{Name: "/check arg...", Help: "权限检查, cache|config|command: 接口类型, name: 接口名称, args: 其它参数", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if login := m.Spawn().Cmd("/login"); login.Has("template") {
m.Echo("no").Copy(login, "append")
return
}
if msg := m.Spawn().Cmd("right", m.Append("username"), "check", arg); !msg.Results(0) {
m.Echo("no").Append("message", "no right, please contact manager")
return
}
m.Echo("ok")
}},
"/login": &ctx.Command{Name: "/login", Help: "用户登录", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if m.Options("sessid") {
if aaa := m.Sess("aaa").Cmd("login", m.Option("sessid")); aaa.Results(0) {
m.Append("redirect", m.Option("referer"))
m.Append("username", aaa.Result(0))
return
}
}
w := m.Optionv("response").(http.ResponseWriter)
if m.Options("username") && m.Options("password") {
if aaa := m.Sess("aaa").Cmd("login", m.Option("username"), m.Option("password")); aaa.Results(0) {
http.SetCookie(w, &http.Cookie{Name: "sessid", Value: aaa.Result(0)})
m.Append("redirect", m.Option("referer"))
m.Append("username", m.Option("username"))
return
}
}
w.WriteHeader(http.StatusUnauthorized)
m.Append("template", "login")
}},
"/lookup": &ctx.Command{Name: "user", Help: "应用示例", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if len(arg) > 0 {
m.Option("service", arg[0])
}
msg := m.Sess("cli").Cmd("system", "sd", "lookup", m.Option("service"))
rs := strings.Split(msg.Result(0), "\n")
i := 0
for ; i < len(rs); i++ {
if len(rs[i]) == 0 {
break
}
fields := strings.SplitN(rs[i], ": ", 2)
m.Append(fields[0], fields[1])
}
lists := []interface{}{}
for i += 2; i < len(rs); i++ {
fields := strings.SplitN(rs[i], " ", 3)
if len(fields) < 3 {
break
}
lists = append(lists, map[string]interface{}{
"ip": fields[0],
"port": fields[1],
"tags": fields[2],
})
}
m.Appendv("lists", lists)
m.Log("log", "%v", lists)
}},
"upload": &ctx.Command{Name: "upload file", Help: "上传文件", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
msg := m.Spawn(m.Target())
msg.Cmd("get", "/upload", "method", "POST", "file", "file", arg[0])
m.Copy(msg, "result")
}},
"/travel": &ctx.Command{Name: "/travel", Help: "文件上传", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
// r := m.Optionv("request").(*http.Request)
// w := m.Optionv("response").(http.ResponseWriter)
if !m.Options("dir") {
m.Option("dir", "ctx")
}
check := m.Spawn().Cmd("/share", "/travel", "dir", m.Option("dir"))
if !check.Results(0) {
m.Copy(check, "append")
return
}
// 权限检查
if m.Option("method") == "POST" {
if m.Options("domain") {
msg := m.Find("ssh", true)
msg.Detail(0, "send", "domain", m.Option("domain"), "context", "find", m.Option("dir"))
if m.Option("name") != "" {
msg.Add("detail", m.Option("name"))
}
if m.Options("value") {
value := []string{}
json.Unmarshal([]byte(m.Option("value")), &value)
if len(value) > 0 {
msg.Add("detail", value[0], value[1:])
}
}
msg.CallBack(true, func(sub *ctx.Message) *ctx.Message {
m.Copy(sub, "result").Copy(sub, "append")
return nil
})
return
}
msg := m.Find(m.Option("dir"), true)
if msg == nil {
return
}
switch m.Option("ccc") {
case "cache":
m.Echo(msg.Cap(m.Option("name")))
case "config":
if m.Has("value") {
m.Echo(msg.Conf(m.Option("name"), m.Option("value")))
} else {
m.Echo(msg.Conf(m.Option("name")))
}
case "command":
msg = msg.Spawn(msg.Target())
msg.Detail(0, m.Option("name"))
if m.Options("value") {
value := []string{}
json.Unmarshal([]byte(m.Option("value")), &value)
if len(value) > 0 {
msg.Add("detail", value[0], value[1:])
}
}
msg.Cmd()
m.Copy(msg, "result").Copy(msg, "append")
}
return
}
// 解析模板
m.Set("append", "tmpl", "userinfo", "share")
msg := m
for _, v := range []string{"cache", "config", "command", "module", "domain"} {
if m.Options("domain") {
msg = m.Find("ssh", true)
msg.Detail(0, "send", "domain", m.Option("domain"), "context", "find", m.Option("dir"), "list", v)
msg.CallBack(true, func(sub *ctx.Message) *ctx.Message {
msg.Copy(sub, "result").Copy(sub, "append")
return nil
})
} else {
msg = m.Spawn()
msg.Cmd("context", "find", msg.Option("dir"), "list", v)
}
if len(msg.Meta["append"]) > 0 {
msg.Option("current_module", m.Option("dir"))
msg.Option("current_domain", m.Option("domain"))
m.Add("option", "tmpl", v)
m.Sess(v, msg)
}
}
m.Append("template", m.Conf("travel_main"), m.Conf("travel_tmpl"))
}},
"/index/": &ctx.Command{Name: "/index", Help: "网页门户", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
r := m.Optionv("request").(*http.Request)
w := m.Optionv("response").(http.ResponseWriter)
if login := m.Spawn().Cmd("/login"); login.Has("template") {
m.Echo("no").Copy(login, "append")
return
}
m.Option("username", m.Append("username"))
//权限检查
dir := m.Option("dir", path.Join(m.Cap("directory"), "local", m.Option("username"), m.Option("dir", strings.TrimPrefix(m.Option("path"), "/index"))))
// if check := m.Spawn(c).Cmd("/check", "command", "/index/", "dir", dir); !check.Results(0) {
// m.Copy(check, "append")
// return
// }
//执行命令
if m.Has("details") {
if m.Confs("check_right") {
if check := m.Spawn().Cmd("/check", "target", m.Option("module"), "command", m.Option("details")); !check.Results(0) {
m.Copy(check, "append")
return
}
}
msg := m.Find(m.Option("module")).Cmd(m.Optionv("details"))
m.Copy(msg, "result").Copy(msg, "append")
return
}
//下载文件
if s, e := os.Stat(dir); e == nil && !s.IsDir() {
http.ServeFile(w, r, dir)
return
}
if !m.Options("module") {
m.Option("module", "web")
}
//浏览目录
m.Append("template", m.Append("username"))
m.Option("page_title", "index")
}},
"/create": &ctx.Command{Name: "/create", Help: "创建目录或文件", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
// if check := m.Spawn().Cmd("/share", "/upload", "dir", m.Option("dir")); !check.Results(0) {
// m.Copy(check, "append")
// return
// }
r := m.Optionv("request").(*http.Request)
if m.Option("method") == "POST" {
if m.Options("filename") { //添加文件或目录
name := path.Join(m.Option("dir"), m.Option("filename"))
if _, e := os.Stat(name); e != nil {
if m.Options("content") {
f, e := os.Create(name)
m.Assert(e)
defer f.Close()
_, e = f.WriteString(m.Option("content"))
m.Assert(e)
} else {
e = os.Mkdir(name, 0766)
m.Assert(e)
}
m.Append("message", name, " create success!")
} else {
m.Append("message", name, " already exist!")
}
} else { //上传文件
file, header, e := r.FormFile("file")
m.Assert(e)
name := path.Join(m.Option("dir"), header.Filename)
if _, e := os.Stat(name); e != nil {
f, e := os.Create(name)
m.Assert(e)
defer f.Close()
_, e = io.Copy(f, file)
m.Assert(e)
m.Append("message", name, " upload success!")
} else {
m.Append("message", name, " already exist!")
}
}
}
m.Append("redirect", m.Option("referer"))
}},
"/share": &ctx.Command{Name: "/share arg...", Help: "资源共享", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if check := m.Spawn().Cmd("/check", "target", m.Option("module"), m.Optionv("share")); !check.Results(0) {
m.Copy(check, "append")
return
}
m.Option("username", m.Append("username"))
// if m.Options("friend") && m.Options("module") {
// m.Copy(m.Appendv("aaa").(*ctx.Message).Find(m.Option("module")).Cmd("right", m.Option("friend"), m.Option("action"), m.Optionv("share")), "result")
// if m.Confv("index", m.Option("friend")) == nil {
// m.Confv("index", m.Option("friend"), m.Confv("index", m.Append("username")))
// }
// return
// }
//
// msg := m.Spawn().Cmd("right", "target", m.Option("module"), m.Append("username"), "show", "context")
// m.Copy(msg, "append")
if m.Options("friend") && m.Options("template") && m.Options("title") {
for i, v := range m.Confv("index", m.Option("username")).([]interface{}) {
if v == nil {
continue
}
val := v.(map[string]interface{})
if val["template"].(string) == m.Option("template") && val["title"].(string) == m.Option("title") {
if m.Option("action") == "del" {
friends := m.Confv("index", strings.Join([]string{m.Option("username"), fmt.Sprintf("%d", i), "to"}, ".")).([]interface{})
for j, x := range friends {
if x.(string) == m.Option("friend") {
m.Confv("index", strings.Join([]string{m.Option("username"), fmt.Sprintf("%d", i), "to", fmt.Sprintf("%d", j)}, "."), nil)
}
}
temps := m.Confv("index", strings.Join([]string{m.Option("friend")}, ".")).([]interface{})
for j, x := range temps {
if x == nil {
continue
}
val = x.(map[string]interface{})
if val["template"].(string) == m.Option("template") && val["title"].(string) == m.Option("title") {
m.Confv("index", strings.Join([]string{m.Option("friend"), fmt.Sprintf("%d", j)}, "."), nil)
}
}
break
}
if m.Confv("index", m.Option("friend")) == nil && !m.Confs("auto_create") {
break
}
m.Confv("index", strings.Join([]string{m.Option("username"), fmt.Sprintf("%d", i), "to", "-2"}, "."), m.Option("friend"))
item := map[string]interface{}{
"template": val["template"],
"title": val["title"],
"from": m.Option("username"),
}
if val["command"] != nil {
item["module"] = val["module"]
item["command"] = val["command"]
item["argument"] = val["argument"]
} else if val["detail"] != nil {
item["module"] = val["module"]
item["detail"] = val["detail"]
item["option"] = val["option"]
}
m.Confv("index", strings.Join([]string{m.Option("friend"), fmt.Sprintf("%d", -2)}, "."), item)
m.Appendv("aaa").(*ctx.Message).Spawn(c).Cmd("right", m.Option("friend"), "add", "command", "/index/", "dir", m.Cap("directory"))
os.Mkdir(path.Join(m.Cap("directory"), m.Option("friend")), 0666)
break
}
}
return
}
for _, v := range m.Confv("index", m.Option("username")).([]interface{}) {
val := v.(map[string]interface{})
m.Add("append", "template", val["template"])
m.Add("append", "titles", val["title"])
m.Add("append", "from", val["from"])
m.Add("append", "to", "")
if val["to"] == nil {
continue
}
for _, u := range val["to"].([]interface{}) {
m.Add("append", "template", val["template"])
m.Add("append", "titles", val["title"])
m.Add("append", "from", val["from"])
m.Add("append", "to", u)
}
}
}},
},
}

View File

@ -1,19 +1,24 @@
package wiki
import (
"os/exec"
"time"
"bufio"
"bytes"
"contexts/ctx"
"contexts/web"
"encoding/json"
"encoding/xml"
"github.com/gomarkdown/markdown"
"io/ioutil"
"net/http"
"path"
"bytes"
"fmt"
"github.com/gomarkdown/markdown"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"os"
"path"
"path/filepath"
"strings"
)
@ -342,6 +347,264 @@ var Index = &ctx.Context{Name: "wiki", Help: "文档中心",
m.Echo(string(b))
}
}},
"old_get": &ctx.Command{
Name: "get [method GET|POST] [file name filename] url arg...",
Help: "访问服务, method: 请求方法, file: 发送文件, url: 请求地址, arg: 请求参数",
Form: map[string]int{"method": 1, "content_type": 1, "headers": 2, "file": 2, "body_type": 1, "body": 1, "fields": 1, "value": 1, "json_route": 1, "json_key": 1},
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if web, ok := m.Target().Server.(*web.WEB); m.Assert(ok) {
if web.Client == nil {
web.Client = &http.Client{}
}
if m.Has("value") {
args := strings.Split(m.Option("value"), " ")
values := []interface{}{}
for _, v := range args {
if len(v) > 1 && v[0] == '$' {
values = append(values, m.Cap(v[1:]))
} else {
values = append(values, v)
}
}
arg[0] = fmt.Sprintf(arg[0], values...)
}
method := m.Confx("method")
uri := web.Merge(m, arg[0], arg[1:]...)
m.Log("info", "%s %s", method, uri)
m.Echo("%s: %s\n", method, uri)
var body io.Reader
index := strings.Index(uri, "?")
content_type := ""
switch method {
case "POST":
if m.Options("file") {
file, e := os.Open(m.Meta["file"][1])
m.Assert(e)
defer file.Close()
if m.Option("body_type") == "json" {
content_type = "application/json"
body = file
break
}
buf := &bytes.Buffer{}
writer := multipart.NewWriter(buf)
part, e := writer.CreateFormFile(m.Option("file"), filepath.Base(m.Meta["file"][1]))
m.Assert(e)
io.Copy(part, file)
for i := 0; i < len(arg)-1; i += 2 {
value := arg[i+1]
if len(arg[i+1]) > 1 {
switch arg[i+1][0] {
case '$':
value = m.Cap(arg[i+1][1:])
case '@':
value = m.Conf(arg[i+1][1:])
}
}
writer.WriteField(arg[i], value)
}
content_type = writer.FormDataContentType()
body = buf
writer.Close()
} else if m.Option("body_type") == "json" {
if m.Options("body") {
data := []interface{}{}
for _, v := range arg[1:] {
if len(v) > 1 && v[0] == '$' {
v = m.Cap(v[1:])
}
data = append(data, v)
}
body = strings.NewReader(fmt.Sprintf(m.Option("body"), data...))
} else {
data := map[string]interface{}{}
for i := 1; i < len(arg)-1; i += 2 {
switch arg[i+1] {
case "false":
data[arg[i]] = false
case "true":
data[arg[i]] = true
default:
if len(arg[i+1]) > 1 && arg[i+1][0] == '$' {
data[arg[i]] = m.Cap(arg[i+1][1:])
} else {
data[arg[i]] = arg[i+1]
}
}
}
b, e := json.Marshal(data)
m.Assert(e)
body = bytes.NewReader(b)
}
content_type = "application/json"
if index > -1 {
uri = uri[:index]
}
} else if index > 0 {
content_type = "application/x-www-form-urlencoded"
body = strings.NewReader(uri[index+1:])
uri = uri[:index]
}
}
req, e := http.NewRequest(method, uri, body)
m.Assert(e)
for i := 0; i < len(m.Meta["headers"]); i += 2 {
req.Header.Set(m.Meta["headers"][i], m.Meta["headers"][i+1])
}
if len(content_type) > 0 {
req.Header.Set("Content-Type", content_type)
m.Log("info", "content-type: %s", content_type)
}
for _, v := range m.Confv("cookie").(map[string]interface{}) {
req.AddCookie(v.(*http.Cookie))
}
res, e := web.Client.Do(req)
m.Assert(e)
for _, v := range res.Cookies() {
m.Confv("cookie", v.Name, v)
m.Log("info", "set-cookie %s: %v", v.Name, v.Value)
}
if m.Confs("logheaders") {
for k, v := range res.Header {
m.Log("info", "%s: %v", k, v)
}
}
if m.Confs("output") {
if _, e := os.Stat(m.Conf("output")); e == nil {
name := path.Join(m.Conf("output"), fmt.Sprintf("%d", time.Now().Unix()))
f, e := os.Create(name)
m.Assert(e)
io.Copy(f, res.Body)
if m.Confs("editor") {
cmd := exec.Command(m.Conf("editor"), name)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Run()
} else {
m.Echo("write to %s\n", name)
}
return
}
}
buf, e := ioutil.ReadAll(res.Body)
m.Assert(e)
ct := res.Header.Get("Content-Type")
if len(ct) >= 16 && ct[:16] == "application/json" {
var result interface{}
json.Unmarshal(buf, &result)
m.Option("response_json", result)
if m.Has("json_route") {
routes := strings.Split(m.Option("json_route"), ".")
for _, k := range routes {
if len(k) > 0 && k[0] == '$' {
k = m.Cap(k[1:])
}
switch r := result.(type) {
case map[string]interface{}:
result = r[k]
}
}
}
fields := map[string]bool{}
for _, k := range strings.Split(m.Option("fields"), " ") {
if k == "" {
continue
}
if fields[k] = true; len(fields) == 1 {
m.Meta["append"] = append(m.Meta["append"], "index")
}
m.Meta["append"] = append(m.Meta["append"], k)
}
if len(fields) > 0 {
switch ret := result.(type) {
case map[string]interface{}:
m.Append("index", "0")
for k, v := range ret {
switch value := v.(type) {
case string:
m.Append(k, strings.Replace(value, "\n", " ", -1))
case float64:
m.Append(k, fmt.Sprintf("%d", int(value)))
default:
if _, ok := fields[k]; ok {
m.Append(k, fmt.Sprintf("%v", value))
}
}
}
case []interface{}:
for i, r := range ret {
m.Add("append", "index", i)
if rr, ok := r.(map[string]interface{}); ok {
for k, v := range rr {
switch value := v.(type) {
case string:
if _, ok := fields[k]; len(fields) == 0 || ok {
m.Add("append", k, strings.Replace(value, "\n", " ", -1))
}
case float64:
if _, ok := fields[k]; len(fields) == 0 || ok {
m.Add("append", k, fmt.Sprintf("%d", int64(value)))
}
case bool:
if _, ok := fields[k]; len(fields) == 0 || ok {
m.Add("append", k, fmt.Sprintf("%v", value))
}
case map[string]interface{}:
for kk, vv := range value {
key := k + "." + kk
if _, ok := fields[key]; len(fields) == 0 || ok {
m.Add("append", key, strings.Replace(fmt.Sprintf("%v", vv), "\n", " ", -1))
}
}
default:
if _, ok := fields[k]; ok {
m.Add("append", k, fmt.Sprintf("%v", value))
}
}
}
}
}
if m.Has("json_key") {
m.Sort(m.Option("json_key"))
}
m.Meta["index"] = nil
for i, _ := range ret {
m.Add("append", "index", i)
}
}
}
}
if m.Table(); len(m.Meta["append"]) == 0 {
m.Echo("%s", string(buf))
}
}
}},
},
}

View File

@ -1,59 +1,194 @@
function update(event, module, details, key) {
if (event) {
window[key+"timer"] = !window[key+"timer"];
}
if (!window[key+"timer"]) {
return
}
console.log("update "+key)
setTimeout(function() {
action(event, module, details, key);
update(null, module, details, key);
}, refresh_time);
function insert_child(parent, element, html, position) {
var elm = document.createElement(element)
html && (elm.innerHTML = html)
return parent.insertBefore(elm, position || parent.firstElementChild)
}
function append_child(parent, element, html) {
var elm = document.createElement(element)
html && (elm.innerHTML = html)
parent.append(elm)
return elm
}
function insert_before(self, element, html) {
var elm = document.createElement(element)
html && (elm.innerHTML = html)
return self.parentElement.insertBefore(elm, self)
}
function input(event, module, details, key) {
if (event.code == "Enter") {
action(event, module, details, key);
}
function copy_to_clipboard(text) {
var clipboard = document.querySelector("#clipboard")
clipboard.value = text
clipboard.select()
document.execCommand("copy")
clipboard.blur()
var clipstack = document.querySelector("#clipstack")
insert_child(clipstack, "option").value = clipboard.value
clipstack.childElementCount > 3 && clipstack.removeChild(clipstack.lastElementChild)
}
function action(event, module, details, key) {
var input = document.getElementsByClassName(key+"_input");
for (var i = 0; i < input.length; i++ ){
if (input[i].value != "") {
details.push(input[i].value)
function send_command(form, cb) {
var data = {}
for (var key in form.dataset) {
data[key] = form.dataset[key]
}
}
ctx.POST("", {module:module, details:details}, function(msg) {
if (msg && msg.result) {
var result = document.getElementsByClassName(key+"_result")[0];
result.innerHTML = msg.result;
}
if (!msg || !msg.append || msg.append.length < 1) {
return
for (var i = 0; i < form.length; i++) {
data[form[i].name] = form[i].value
}
var append = document.getElementsByClassName(key+"_append")[0];
if (append.rows.length == msg[msg.append[0]].length+1) {
return
}
append.innerHTML = '';
var tr = append.insertRow(0);
context.GET("", data, function(msg) {
msg = msg[0]
var result = document.querySelector("code.result."+data["componet_name"]+" pre")
result && (result.innerHTML = (msg.result || []).join(""))
var append = document.querySelector("table.append."+data["componet_name"])
append && (append.innerHTML = "")
if (append && msg.append) {
var tr = append_child(append, "tr")
for (var i in msg.append) {
var th = tr.appendChild(document.createElement("th"));
th.appendChild(document.createTextNode(msg.append[i]));
append_child(tr, "th", msg.append[i])
}
for (var i = 0; i < msg[msg.append[0]].length; i++) {
var tr = append.insertRow(1);
for (var j in msg.append) {
var td = tr.appendChild(document.createElement("td"));
td.appendChild(document.createTextNode(msg[msg.append[j]][i]));
var ncol = msg.append.length
var nrow = msg[msg.append[0]].length
for (var i = 0; i < nrow; i ++) {
var tr = append_child(append, "tr")
for (var k in msg.append) {
append_child(tr, "td", msg[msg.append[k]][i])
}
}
}
var div = append.parent;
typeof(cb) == "function" && cb(msg)
})
return false;
}
function onaction(event, action) {
switch (action) {
case "command":
send_command(event.target.form)
break
case "input":
switch (event.key) {
case "Enter":
var form = event.target.form
for (var i = 0; i < form.length; i++) {
if (form[i] == event.target) {
continue
}
(i == form.length-1)? send_command(form): form[i+1].focus()
}
break
case "Escape":
event.target.value = ""
event.target.blur()
break
}
break
case "keymap":
switch (event.key) {
case "g":
document.querySelectorAll("form.option label.keymap").forEach(function(item) {
item.className = (item.className == "keymap show")? "keymap hide": "keymap show"
})
break
default:
if (inputs[event.key]) {
inputs[event.key].focus()
}
break
}
break
case "copy":
copy_to_clipboard(event.target.innerText)
break
}
}
var inputs = {}
var ninput = 0
var keymap = ['a', 'b', 'c']
function init_option() {
inputs = {}
ninput = 0
keymap =[]
for (var i = 97; i < 123; i++) {
if (i == 103) {
continue
}
keymap.push(String.fromCharCode(i))
}
document.querySelectorAll("form.option input").forEach(function(input) {
if (ninput < keymap.length && input.style.display != "none") {
input.title = "keymap: "+keymap[ninput]
input.dataset["keymap"] = keymap[ninput]
insert_before(input, "label", "("+keymap[ninput]+")").className = "keymap"
inputs[keymap[ninput++]] = input
}
})
}
function init_append(event) {
var append = document.querySelectorAll("table.append").forEach(function(item) {
item.onclick = function(event) {
if (event.target.tagName == "TD") {
copy_to_clipboard(event.target.innerText)
}
}
})
}
function init_result(event) {
var result = document.querySelectorAll("code.result pre").forEach(function(item) {
item.onclick = function(event) {
copy_to_clipboard(event.target.innerText)
}
})
}
function init_download(event) {
var option = document.querySelector("form.option.dir")
if (!option) {
return
}
option["dir"].value && send_command(option)
var append = document.querySelector("table.append.dir")
append.onclick = function(event) {
if (event.target.tagName == "A") {
if (event.target.dataset.type != "true") {
location.href = option["dir"].value+"/"+event.target.innerText
return
}
option["dir"].value = option["dir"].value+"/"+event.target.innerText
send_command(option, function(msg) {
option["dir"].value = msg.dir.join("")
})
} else if (event.target.tagName == "TD") {
copy_to_clipboard(event.target.innerText)
} else if (event.target.tagName == "TH") {
option["sort_field"].value = event.target.innerText
var sort_order = option["sort_order"]
switch (event.target.innerText) {
case "filename":
sort_order.value = (sort_order.value == "str")? "str_r": "str"
break
case "line":
case "size":
sort_order.value = (sort_order.value == "int")? "int_r": "int"
break
case "time":
sort_order.value = (sort_order.value == "time")? "time_r": "time"
break
}
send_command(option)
}
}
}
window.onload = function() {
init_option()
init_append()
init_result()
init_download()
}

View File

@ -1,74 +1,9 @@
ctx = {
Cookie: function(key, value) {//{{{
if (value == undefined) {
var pattern = new RegExp(key+"=([^;]*);?");
var result = pattern.exec(document.cookie);
if (result && result.length > 0) {
return result[1];
}
return "";
}
document.cookie = key+"="+value;
return this.Cookie(key);
},//}}}
Search: function(key, value) {//{{{
var args = {};
var search = location.search.split("?");
if (search.length > 1) {
var searchs = search[1].split("&");
for (var i = 0; i < searchs.length; i++) {
var keys = searchs[i].split("=");
args[keys[0]] = decodeURIComponent(keys[1]);
}
}
if (typeof key == "object") {
for (var k in key) {
if (key[k] != undefined) {
args[k] = key[k];
}
}
} else if (value == undefined) {
return args[key] || "";
} else {
args[key] = value;
}
var arg = [];
for (var k in args) {
arg.push(k+"="+encodeURIComponent(args[k]));
}
location.search = arg.join("&");
},//}}}
GET: function(url, form, cb) {//{{{
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
switch (xhr.readyState) {
case 4:
switch (xhr.status) {
case 200:
try {
var msg = JSON.parse(xhr.responseText||'{"result":[]}');
} catch (e) {
msg = {"result": [xhr.responseText]}
}
msg && console.log(msg)
msg.result && console.log(msg.result.join(""));
typeof cb == "function" && cb(msg)
}
break;
}
}
context = {
GET: function(url, form, cb) {
form = form || {}
form["dir"] = form["dir"] || this.Search("dir") || undefined
form["module"] = form["module"] || this.Search("module") || undefined
form["domain"] = form["domain"] || this.Search("domain") || undefined
var args = [];
for (k in form) {
for (var k in form) {
if (form[k] instanceof Array) {
for (i in form[k]) {
args.push(k+"="+encodeURIComponent(form[k][i]));
@ -79,124 +14,34 @@ ctx = {
}
var arg = args.join("&");
if (arg) {
url += "?"+arg
}
arg && (url += ((url.indexOf("?")>-1)? "&": "?") + arg)
console.log("GET: "+url);
var xhr = new XMLHttpRequest();
xhr.open("GET", url);
console.log("GET: "+url+"?"+arg);
xhr.send();
},//}}}
POST: function(url, form, cb) {//{{{
var xhr = new XMLHttpRequest();
xhr.setRequestHeader("Accept", "application/json")
xhr.onreadystatechange = function() {
switch (xhr.readyState) {
case 4:
switch (xhr.status) {
case 200:
if (xhr.readyState != 4) {
return
}
if (xhr.status != 200) {
return
}
try {
var msg = JSON.parse(xhr.responseText||'{"result":[]}');
} catch (e) {
msg = {"result": [xhr.responseText]}
var msg = {"result": [xhr.responseText]}
}
msg && console.log(msg)
console.log(msg)
msg.result && console.log(msg.result.join(""));
if (msg.page_redirect) {
location.href = msg.page_redirect.join("")
}
typeof cb == "function" && cb(msg)
}
break;
}
}
xhr.open("POST", url);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
form = form || {}
form["dir"] = form["dir"] || this.Search("dir") || undefined
form["module"] = form["module"] || this.Search("module") || undefined
form["domain"] = form["domain"] || this.Search("domain") || undefined
var args = [];
for (k in form) {
if (form[k] instanceof Array) {
for (i in form[k]) {
args.push(k+"="+encodeURIComponent(form[k][i]));
}
} else if (form[k] != undefined) {
args.push(k+"="+encodeURIComponent(form[k]));
}
}
var arg = args.join("&");
console.log("POST: "+url+"?"+arg);
xhr.send(arg);
},//}}}
Refresh: function() {//{{{
location.assign(location.href);
},//}}}
Cap: function(cap, cb) {//{{{
if (typeof cap == "function") {
cb = cap;
cap = undefined;
}
var args = {ccc:"cache"};
if (cap != undefined) {
args.name = cap;
}
this.POST("", args, function(msg) {
var value = msg.result.join("");
typeof cb == "function" && cb(value);
});
},//}}}
Conf: function(name, value, cb) {//{{{
if (typeof name == "function") {
value = name;
name = undefined;
}
if (typeof value == "function") {
cb = value;
value = undefined;
}
var args = {ccc:"config"};
if (name != undefined) {
args.name = name
}
if (value != undefined) {
args.value = value
}
this.POST("", args, function(msg) {
var value = msg.result.join("");
typeof cb == "function" && cb(value);
});
},//}}}
Cmd: function(cmd, value, cb) {//{{{
if (typeof cmd == "function") {
value = cmd;
cmd = undefined;
}
if (typeof value == "function") {
cb = value;
value = undefined;
}
var args = {ccc:"command"};
if (cmd != undefined) {
args.name = cmd
}
if (value != undefined) {
args.value = JSON.stringify(value)
}
this.POST("", args, cb);
},//}}}
Module: function(module, domain) {//{{{
this.Search({module:module, domain:domain})
},//}}}
};
xhr.send();
},
}

View File

@ -1,211 +0,0 @@
function jumpto(url) {
if (url == "..") {
var ps = locaiton.href.split();
}
location.href=url;
}
function keyup(event) {
console.log(event);
if (typeof window.control == "function") {
control(event);
}
if (event.key == "z") {
var input = document.getElementsByClassName("query_input")[0];
if (!window.query_show) {
window.query_show = true;
var query = document.getElementsByClassName("query_menu")[0];
var input = query.getElementsByTagName("input")[0];
input.style.visibility = "visible";
input.style.width = "80px";
input.focus();
}
return true
}
return true
}
document.onkeyup = keyup;
function toggle(side) {
if (side == "left") {
window.left_list_hide = !window.left_list_hide;
var list = document.getElementsByClassName("list")[0];
var content = document.getElementsByClassName("content")[0];
if (left_list_hide) {
list.style.visibility = "hidden";
list.style.width="0px";
list.style.height="0px";
list.style["min-width"]="0px";
content.style.width="100%";
} else {
list.style.visibility = "visible";
list.style.width="15%";
list.style.height="100%";
list.style["min-width"]="180px";
content.style.width="85%";
}
}
}
function menu() {
var max = 0;
var min = 1000;
var list = [];
var hs = ["h2", "h3", "h4"];
for (var i = 0; i < hs.length; i++) {
var head = document.getElementsByTagName(hs[i]);
for (var j = 0; j < head.length; j++) {
head[j].id = "head"+head[j].offsetTop;
head[j].onclick = function(event) {}
list.push({"level": hs[i], "position": head[j].offsetTop, "title": head[j].innerText, "hash": head[j].id})
if (head[j].offsetTop > max) {
max = head[j].offsetTop;
}
if (head[j].offsetTop < min) {
min = head[j].offsetTop;
}
}
}
max = max - min;
var link = [];
var a = document.getElementsByTagName("a");
for (var i = 0; i < a.length; i++) {
link.push({href: a[i].href, title: a[i].innerText});
}
for (var i = 0; i < list.length-1; i++) {
for (var j = i+1; j < list.length; j++) {
if (list[j].position < list[i].position) {
var a = list[i];
list[i] = list[j];
list[j] = a;
}
}
}
var index = [-1, 0, 0]
for (var i = 0; i < list.length; i++) {
if (list[i].level == "h2") {
index[0]++;
index[1]=0;
index[2]=0;
} else if (list[i].level == "h3") {
index[1]++;
index[2]=0;
} else {
index[2]++;
}
list[i].index4 = index[2];
list[i].index3 = index[1];
list[i].index2 = index[0];
}
var m = document.getElementsByClassName("menu");
for (var i = 0; i < m.length; i++) {
for (var j = 0; j < list.length; j++) {
var text = list[j].index2+"."
if (list[j].level == "h3") {
text += list[j].index3
} else if (list[j].level == "h4") {
text += list[j].index3+"."+list[j].index4
}
text += " "
text += list[j].title;
var h = document.getElementById(list[j].hash)
h.innerText = text
var one = m[i].appendChild(document.createElement("div"));
var a = one.appendChild(document.createElement("a"));
a.href = "#"+list[j].hash;
a.innerText = text+" ("+parseInt((list[j].position-min)/max*100)+"%)";
one.className = list[j].level;
}
}
var m = document.getElementsByClassName("link");
for (var i = 0; i < m.length; i++) {
var one = m[i].appendChild(document.createElement("div"));
var a = one.appendChild(document.createTextNode("相关链接: "));
for (var j = 0; j < link.length; j++) {
var one = m[i].appendChild(document.createElement("div"));
var a = one.appendChild(document.createTextNode(link[j].title+": "));
var a = one.appendChild(document.createElement("a"));
a.href = link[j].href
a.innerText = a.href
}
}
var m = document.getElementsByTagName("pre");
for (var i = 0; i < m.length; i++) {
var line = (m[i].clientHeight-10)/15
// if (line < 3) {
// continue
// }
console.log(m[i].clientHeight)
var nu = m[i].parentElement.insertBefore(document.createElement("div"), m[i]);
nu.className = "number1"
for (var j = 1; j <= line; j++) {
console.log(j)
var li = nu.appendChild(document.createElement("div"));
li.appendChild(document.createTextNode(""+j));
}
}
}
function query(event) {
if (event) {
if (event.code == "Enter") {
jumpto("/wiki/?query="+encodeURIComponent(event.target.value));
}
console.log("what")
return true
}
window.query_show = !window.query_show;
var query = document.getElementsByClassName("query_menu")[0];
var input = query.getElementsByTagName("input")[0];
if (window.query_show) {
input.style.visibility = "visible";
input.style.width = "80px";
} else {
input.style.visibility = "hidden";
input.style.width = "0px";
}
}
var tags_list = {};
ctx.GET("/wiki/define.json", undefined, function(msg){
tags_list = msg["define"];
})
function tags(event) {
console.log(event);
if (event.srcElement.tagName == "CODE") {
var tag = document.getSelection().toString();
console.log(tag);
if (tag && tag.length > 0 && tags_list[tag]) {
var position = tags_list[tag].position;
if (position.length == 1) {
jumpto("/wiki/src/"+position[0].file+"#hash_"+position[0].line);
} else {
jumpto("/wiki/?query="+encodeURIComponent(tag));
}
}
}
}
document.onmouseup = tags;
window.onload = function() {
toggle();
if (location.href.endsWith(".md")) {
menu();
}
}

View File

@ -1,145 +0,0 @@
{{define "head"}}
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{option .Meta "page_title"}}</title>
<style>
fieldset {
margin-top:8px;
}
legend {
font-size:16px;
font-weight:bold;
font-family:monospace;
}
th {
cursor:pointer;
background-color:lightgreen;
}
td {
padding-left: 10px;
padding-right: 20px;
}
pre {
color:white;
font-size:14px;
background-color:#272822;
padding:5px;
border:solid 2px green;
border-left:solid 4px green;
overflow:scroll;
}
.command {
font-size:14px;
font-family:monospace;
}
html, body {
height:100%;
width:100%;
margin:0px;
background-color:#d8d8d8;
}
h4 {
margin:0px;
padding:0px;
}
</style>
<script src="/library/context.js"></script>
<script src="/library/base.js"></script>
</head>
<body>
{{end}}
{{define "code"}}
<pre><code>{{.}}</code></pre>
{{end}}
{{define "notice"}}
<fieldset class="notice"><legend>[notice]</legend>
{{template "code" result .Meta}}
</fieldset>
<style>
.notice {color:red}
</style>
{{end}}
{{define "detail"}}
{{$msg := .}}
{{$key := append . "title"|meta}}
<fieldset><legend><a onclick="return action(event, '{{option .Meta "module"}}', ['{{detail .Meta}}'], '{{$key}}')" href="/">{{option . "title"}}</a></legend>
{{range option . "ninput"|meta|list}}
<input type="text" class="{{$key}}_input" value="" onkeyup="return input(event, '{{option $msg.Meta "module"}}', ['{{detail $msg.Meta}}'], '{{$key}}')"></input>
{{end}}
{{if option . "refresh"}}
<input type="button" class="{{$key}}_button" value="update" onclick="return update(event, '{{option $msg.Meta "module"}}', ['{{detail $msg.Meta}}'], '{{$key}}')"></input>
<input type="button" class="{{$key}}_button" value="cancel" onclick="return update(event, '{{option $msg.Meta "module"}}', ['{{detail $msg.Meta}}'], '{{$key}}')"></input>
{{end}}
<pre><code class="{{$key}}_result"></code></pre>
<div style="max-height:150px;overflow:auto">
<table class="{{$key}}_append"></table>
</div>
</fieldset>
<script>
var refresh_time = parseInt({{conf . "refresh_time"}});
{{if option . "auto_refresh"}}
update(true, '{{option $msg.Meta "module"}}', ['{{detail $msg.Meta}}'], '{{$key}}');
{{end}}
</script>
{{end}}
{{define "result"}}
<fieldset><legend>{{option . "title"}}</legend>
{{template "code" result .Meta|unscaped}}
</fieldset>
{{end}}
{{define "append_link"}}
<a onclick="return jump('{{.}}')" href="{{.}}">{{.}}</a>
<script>
function jump(to) {
location.href = location.href + "/" +to;
return false
}
</script>
{{end}}
{{define "append"}}
<fieldset><legend>{{option . "title"}}</legend>
<table class="append">
{{$msg := .}}
{{$ncol := append . |len}}
{{$nrow := append . 0|append .|len}}
<tr>{{range append .}}<th><code onclick="sort_table('{{.}}')">{{.}}</code></th>{{end}}</tr>
{{range $row, $val := append . 0|append .}}
<tr>
{{range append $msg}}
{{$value := append $msg . $row}}
<td><code>
{{if eq . "filename"}}
{{template "append_link" $value}}
{{else}}
{{$value}}
{{end}}
</code></td>
{{end}}
</tr>
{{end}}
</table>
</fieldset>
<script>
var sort_field="";
function sort_table(field) {
sort_field = field;
console.log(sort_field);
}
</script>
{{end}}
{{define "main"}}
welcome to context world!
{{end}}
{{define "tail"}}
</body>
{{end}}

View File

@ -0,0 +1,138 @@
{{define "head"}}
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{option .Meta "page_title"}}</title>
<style>
html, body {
height:100%;
width:100%;
margin:0px;
background-color:#d8d8d8;
}
fieldset {
margin-top:8px;
}
legend {
font-size:16px;
font-weight:bold;
font-family:monospace;
}
</style>
<style>
form.option div {
float:left;
}
form.option hr {
clear:both;
}
form.option label.keymap {
display:none;
color:red;
}
form.option label.keymap.show {
display:inline;
}
table.append th {
cursor:pointer;
background-color:lightgreen;
}
table.append th.order {
cursor:pointer;
background-color:red;
}
table.append td {
padding-left: 10px;
padding-right: 20px;
}
code.result pre {
color:white;
font-size:14px;
background-color:#272822;
padding:5px;
border:solid 2px green;
border-left:solid 4px green;
overflow:scroll;
}
</style>
</head>
<body onkeyup="return onaction(event, 'keymap')">
{{end}}
{{define "detail"}}{{detail .}}{{end}}
{{define "option"}}{{option .}}{{end}}
{{define "append"}}{{append .}}{{end}}
{{define "result"}}{{result .}}{{end}}
{{define "clipboard"}}
<fieldset><legend>clipboard</legend>
<datalist id="clipstack"></datalist>
<input id="clipboard">
</fieldset>
{{end}}
{{define "componet"}}
<fieldset><legend title="{{option .Meta "help"}}">{{option .Meta "context"}}.{{option .Meta "command"}}</legend>
<form class="option {{option .Meta "name"}}"
data-last_componet_group="{{option . "last_componet_group"|meta}}"
data-last_componet_order="{{option . "last_componet_order"|meta}}"
data-componet_group="{{option . "componet_group"|meta}}"
data-componet_order="{{option . "componet_order"|meta}}"
data-componet_name="{{option . "name"|meta}}"
data-componet_help="{{option . "help"|meta}}"
>
<input style="display:none"></input>
{{range $index, $input := option . "inputs"}}
<div>
{{$type := index $input "type"}}
{{if eq $type "button"}}
<input type="button" name="{{index $input "name"}}" value="{{index $input "value"}}" onclick="return onaction(event, 'command')">
{{else if eq $type "choice"}}
{{$default_value := index $input "value"}}
<label>{{index $input "label"}} : </label>
<select name="{{index $input "name"}}" onchange="return onaction(event, 'command')">
{{range $index, $value := index $input "choice"}}
{{$val := index $value "value"}}
{{if eq $default_value $val}}
<option value="{{index $value "value"}}" selected>{{index $value "name"}}</option>
{{else}}
<option value="{{index $value "value"}}">{{index $value "name"}}</option>
{{end}}
{{end}}
</select>
{{else}}
<label>{{index $input "label"}} : </label>
<input name="{{index $input "name"}}" value="{{index $input "value"}}" onkeyup="return onaction(event, 'input')" list="clipstack">
{{end}}
</div>
{{end}}
<hr/>
</form>
{{if index .Meta "display_append"}}
{{option .Meta "display_append"}}
{{else}}
<table class="append {{option .Meta "name"}}">
{{$msg := .}}
<tr>{{range $field := append .}}<th>{{$field}}</th>{{end}}</tr>
{{range $line := table .}}
<tr>{{range $field := append $msg}}<td>{{index $line $field|unescape}}</td>{{end}}</tr>
{{end}}
</table>
{{end}}
{{if index .Meta "display_result"}}
{{option .Meta "display_result"}}
{{else}}
<code class="result {{option .Meta "name"}}"><pre>{{result .Meta}}</pre></code>
{{end}}
</fieldset>
{{end}}
{{define "tail"}}
<script src="/library/context.js"></script>
<script src="/library/base.js"></script>
</body>
{{end}}

View File

@ -1,94 +0,0 @@
{{define "login"}}
<fieldset><legend>login</legend>
<form method="POST" action="/login">
<label>username:</label><input type="text" name="username" required autofocus>
<label>password:</label><input type="password" name="password" required>
<input type="submit">
</form>
</fieldset>
{{end}}
{{define "userinfo"}}
<fieldset><legend>userinfo</legend>
welcome <span class="username">{{option . "username"}}</span> to context world
<button onclick="return logout(event)">logout</button>
</fieldset>
<style>
.username {
color:red;
font-weight:bold;
}
</style>
<script>
function logout(event) {
ctx.Cookie("sessid", ";path=/");
ctx.Refresh();
return false;
}
</script>
{{end}}
{{define "share"}}
<fieldset><legend>share</legend>
<table>
{{$msg := .}}
{{$ncol := append . |len}}
{{$nrow := append . 0|append .|len}}
<tr>{{range append .}}<th><code onclick="sort_table('{{.}}')">{{.}}</code></th>{{end}}</tr>
{{range $row, $val := append . 0|append .}}
<tr>
{{range append $msg}}
{{$value := append $msg . $row}}
<td><code>
{{if eq . "to"}}
{{if eq $value ""}}
<input type="text" onkeyup="return share_input(event, '{{append $msg "template" $row}}', '{{append $msg "titles" $row}}', 'add')">
{{else}}
<code><a href="/" title="点击取消共享" onclick="return shareto('{{append $msg "template" $row}}', '{{append $msg "titles" $row}}', '{{$value}}','del')">{{$value}}</a></code>
{{end}}
{{else if eq . "value"}}
<code><a title="点击删除" href="/" onclick="deleteshare(event, '{{append $msg "friend" $row}}', '{{$value}}')">{{$value}}</a></code>
{{else}}
{{$value}}
{{end}}
</code></td>
{{end}}
</tr>
{{end}}
</table>
</fieldset>
<script>
function share_input(event, template, title, action) {
if (event.code == "Enter") {
shareto(template, title, event.target.value, action);
}
console.log(event.code)
console.log(event.key)
console.log(event)
}
function shareto(template, title, friend, action) {
ctx.POST("/share", {
module: "web",
template: template,
title: title,
friend: friend,
action: action,
share: ["command", "/index/"],
}, function(msg) {
ctx.Refresh();
})
return false
}
</script>
{{end}}
{{$msg := .}}
{{$meta := .Meta}}
{{template "head" $meta}}
{{if meta $meta.notice}}
{{template "notice" $meta}}
{{end}}
{{template "login" $meta}}
{{template "tail" $meta}}

View File

@ -1,9 +0,0 @@
{{$msg := .}}
{{$meta := .Meta}}
{{template "head" $meta}}
{{if meta $meta.message}}
{{template "message" $meta}}
{{end}}
{{template "main" $msg}}
{{template "tail" $meta}}

View File

@ -1,222 +0,0 @@
{{define "wiki_head"}}
{{end}}
{{define "wiki_menu"}}
{{end}}
{{define "wiki_list"}}
<style>
p {
text-indent:2em;
}
.container {
height:100%;
min-width:300px;
}
.head {
color:white;
font-size:20px;
font-weight:bold;
background-color:#222;
text-align:center;
vertical-align:middle;
padding:10px;
width:100%;
height:27px;
}
.title {
font-style:italic;
}
.toggle_menu {
cursor:pointer;
float:left;
}
.query_menu {
cursor:pointer;
margin-right:20px;
float:right;
}
.query_button {
cursor:pointer;
float:right;
margin-left:10px;
}
.query_input {
visibility:hidden;
width:0px;
position:absolute;
right:40px;
top:12px;
}
.list {
width:15%;
min-width:140px;
float:left;
max-height:1000px;
overflow:scroll;
}
.list_item {
padding-top:10px;
padding-left:30px;
min-height:30px;
margin-left:-30px;
}
.list_item:hover, .list_item:active {
background-color:green;
}
</style>
<div class="container">
<div class="head">
<div class="toggle_menu" onclick="toggle()"></div>
<div class="query_menu">
<input class="query_input" type="text" onkeyup="return query(event)">
<div class="query_button" onclick="return query()"> Q</div>
</div>
<div class="title" onclick="return jumpto('/wiki/')">shylinux</div>
</div>
<div class="list">
{{$msg := .}}
{{$ncol := append . |len}}
{{$nrow := append . 0|append .|len}}
<ul>
<li>
<div class="list_item" onclick="return jumpto('/wiki/{{option $msg "parent"|meta}}')">返回上一层</div>
</li>
{{range $row, $val := append . 0|append .}}
<li>
<div class="list_item" onclick="return jumpto('/wiki/{{option $msg "dir"|meta}}/{{append $msg "name" $row}}')">
{{append $msg "name" $row}}
</div>
</li>
{{end}}
</ul>
</div>
{{end}}
{{define "wiki_body"}}
<style>
.content {
width:85%;
height:100%;
float:left;
min-width:400px;
}
.toggle {
background-color:green;
width:2%;
height:100%;
float:left;
}
.toggle1 {
background-color:green;
width:2%;
height:100%;
float:right;
}
.texts {
max-width:800px;
width:94%;
float:left;
margin-left:2%;
}
.li_link {
font-size:18px;
}
.number {
float:left;
position:relative;
left:-6px;
top:18px;
text-align:right;
}
.number div {
margin:0px;
padding:0px;
height:16px;
}
.record {
margin: 10px 10px;
float:left;
}
.menu {
}
.menu a {
text-decoration:none;
}
.menu .h3 {
padding-left: 20px;
}
.menu .h4 {
padding-left: 40px;
}
.link {
margin-top:10px;
font-size: 14px;
}
.link div:first-child {
margin-left:-10px;
}
.link div {
padding-left:10px;
}
.number1 {
color:#271ace;
font-size:14px;
font-family:monospace;
background-color:#77b724;
padding:5px;
border:solid 2px green;
margin-left:0px;
float:left;
}
.number1 div {
text-align:right;
margin:0;
padding:0;
}
</style>
<div class="content">
<div class="toggle" title="点击,显示或隐藏目录" onclick="toggle('left')"></div>
<div class="toggle1" title="点击,显示或隐藏目录" onclick="toggle('right')"></div>
{{if option . "modify_time"|meta}}
<div class="record">上次修订时间: {{option . "modify_time"|meta}} 修订次数: {{option . "modify_count"|meta}}</div>
{{end}}
<div class="record">上次阅读时间: {{option . "last_record_time"|meta}} 总访问量: {{option . "record_count"|meta}}</div>
<div class="texts">
<div class="menu"></div>
<div class="link"></div>
<div class="number">
{{range option . "nline"|meta|list}}
<div id="hash_{{.}}" style="margin-top:-1px"><code>{{.}}</code></div>
{{end}}
</div>
{{$msg := .}}
{{if append . "name"}}
{{$l := append . "name"|len}}
{{if eq $l 1}}
<script>
location.replace("/wiki/{{option $msg "dir"|meta|unscaped}}/{{append . "name"|meta|unscaped}}");
</script>
{{else}}
<ul>
{{range $i, $v := append . "name"}}
<li class="li_link">
<div>
<code>{{option $msg "time" $i}}&nbsp;&nbsp;&nbsp;</code>
<a href="/wiki/{{option $msg "dir"|meta}}/{{$v}}{{option $msg "pend" $i}}">{{$v}}{{option $msg "pend" $i}}</a>
</div>
</li>
{{end}}
<ul>
{{end}}
{{else if append . "code"|meta}}
<p><pre><code>{{append . "code"|meta}}</code></pre><p>
{{else}}
<p>{{append . "body"|meta|unscaped}}</p>
{{end}}
</div>
</div>
</div>
<script src="/library/wiki.js"></script>
{{end}}

View File

@ -1,431 +0,0 @@
{{define "head"}}
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<style>
legend {
font-size:16px;
font-weight:bold;
}
th {
cursor:pointer;
background-color:lightgray;
}
.name {
padding-left:10px;
text-align:left;
}
.help {
padding-left:10px;
text-align:left;
}
.status {
padding-left:10px;
text-align:left;
}
.stream {
padding-left:10px;
text-align:left;
}
.result {
background-color:black;
color:white;
padding:10px;
margin:0px;
}
code {
font-size:14px;
}
</style>
</head>
<body>
{{end}}
{{define "cache"}}
{{$meta := .}}
<fieldset><legend>cache</legend>
<table>
<colgroup>{{range .append}}<col class="{{.}}">{{end}}</colgroup>
<tr>{{range .append}}<th class="{{.}}" onclick="list('{{.}}')">{{.}}</th>{{end}}</tr>
{{$l := index .append|len}}
{{if gt $l 0}}
{{$first := index .append 0}}
{{range $i, $k := index . $first}}
<tr>
{{range $key := index $meta "append"}}
{{$content := index $meta $key $i}}
<td class="{{$key}}">
<code>{{$content}}</code>
</td>
{{end}}
</tr>
{{end}}
{{end}}
</table>
</fieldset>
<script>
function cache(event, key, value) {
console.log(event);
switch (event.type) {
case "keydown":
if (event.key != "Enter") {
return true;
}
value = event.target.value;
ctx.Cap(key, value);
}
}
</script>
{{end}}
{{define "config"}}
<fieldset><legend>config</legend>
<table>
<colgroup>{{range .append}}<col class="{{.}}">{{end}}</colgroup>
<tr>{{range .append}}<th class="{{.}}" onclick="list('{{.}}')">{{.}}</th>{{end}}</tr>
{{$l := index .append|len}}
{{if gt $l 0}}
{{$meta := .}} {{$first := index .append 0}}
{{range $i, $k := index . $first}}
<tr>{{$config := index $meta "key" $i}}
{{range $key := index $meta "append"}}
{{if eq $key "value"}}
<td class="{{$key}}">
<input type="text" value="{{index $meta $key $i}}" onkeydown="return Config(event, '{{$config}}')">
</td>
{{else}}
<td class="{{$key}}">
<code>{{index $meta $key $i}}</code>
</td>
{{end}}
{{end}}
</tr>
{{end}}
{{end}}
</table>
</fieldset>
<script>
function Config(event, name) {
if (event.type=="keydown" && event.key == "Enter") {
ctx.Conf(name, event.target.value, function(msg) {alert("ok")});
}
}
</script>
{{end}}
{{define "command2"}}
{{$meta := .}}
<fieldset><legend>command</legend>
<div>
{{$l := index .append|len}}
{{if gt $l 0}}
{{$first := index .append 0}}
{{range $i, $k := index . $first}}
{{$command := index $meta "key" $i}}
<div>
<div>
<code>
{{$command}}: {{index $meta "help" $i}}<br/>
<a href="" onclick="return shell(event, '{{$command}}')">{{index $meta "name" $i}}</a>
</code>
</div>
<div id="argument_{{$command}}">
<button onclick="return Argument(event, 'add', '{{$command}}')">add</button>
<button onclick="return Argument(event, 'del', '{{$command}}')">del</button>
</div>
<pre class="result" hidden><code id="result_{{$command}}"></code></pre>
<table id="append_{{$command}}" hidden></table>
</div>
{{end}}
{{end}}
</div>
</fieldset>
<fieldset><legend><input id="direct" type="text" onkeydown="return shell(event)"></legend>
<pre class="result"><code id="result2"></code></pre>
</fieldset>
<script>
function show(msg, command) {
console.log(msg);
if (msg.result) {
var result = document.getElementById("result_"+command);
if (!result) {
var result = document.getElementById("result2");
}
result.innerHTML = msg.result.join("");
}
var append = document.getElementById("append_"+command);
append.innerHTML = "";
if (msg.append) {
append.hidden = false;
var tr = document.createElement("tr");
append.appendChild(tr)
for (var k in msg.append) {
var th = document.createElement("th");
th.innerHTML = msg.append[k];
tr.appendChild(th)
}
for (var i in msg[msg.append[0]]) {
var tr = document.createElement("tr");
append.appendChild(tr)
for (var k in msg.append) {
var td = document.createElement("td");
var pre = document.createElement("pre");
var code = document.createElement("code");
code.innerHTML = msg[msg.append[k]][i];
pre.appendChild(code)
td.appendChild(pre)
tr.appendChild(td);
}
}
}
}
function Argument(event, action, command) {
var argument = document.getElementById("argument_"+command);
switch (action) {
case "add":
var arg = document.createElement("input");
arg.type = "text";
argument.appendChild(arg);
break;
case "del":
var arg = argument.lastElementChild;
if (arg.type == "text") {
argument.removeChild(arg);
}
break;
}
}
function shell(event, command) {
console.log(event);
switch (event.type) {
case "keydown":
if (event.key != "Enter") {
return true;
}
command = event.target.value
// no break
case "click":
var detail = [];
var result = document.getElementById("result_"+command);
var append = document.getElementById("append_"+command);
if (!result) {
var result = document.getElementById("result2");
} else {
var div = document.getElementById("argument_"+command);
var input = div.getElementsByTagName("input");
for (var i in input) {
if (input[i].value) {
detail.push(input[i].value);
}
}
result = result.parentElement;
result.hidden = !result.hidden;
append.hidden = result.hidden;
}
if (!result.hidden) {
ctx.Cmd(command, detail, function(msg) {
show(msg, command);
if (!msg.result) {
}
});
}
return false;
}
return true;
}
function Direct(event, name, value) {
debugger;
console.log(event)
if (!name) {
name = event.currentTarget.value;
}
var direct = document.getElementById("direct");
direct.value = name;
ctx.Cmd(name, value, function(msg){
Result(msg, name);
});
return false;
}
</script>
{{end}}
{{define "command"}}
<fieldset><legend>command</legend>
<table>
<colgroup>{{range .append}}<col class="{{.}}">{{end}}</colgroup>
<tr>{{range .append}}<th class="{{.}}" onclick="list('{{.}}')">{{.}}</th>{{end}}</tr>
{{$l := index .append|len}}
{{if gt $l 0}}
{{$meta := .}} {{$first := index .append 0}}
{{range $i, $k := index . $first}}
<tr>{{$command := index $meta "key" $i}}
{{range $key := index $meta "append"}}
<td class="{{$key}}">
{{if eq $key "input"}}
<input type="text" name="{{$command}}" onkeydown="return Command(event, '{{$command}}')">
{{else if eq $key "key"}}
<code><a href="" onclick="return Direct(event, '{{$command}}')">{{index $meta $key $i}}</a></code>
{{else}}
<code>{{index $meta $key $i}}</code>
{{end}}
</td>
{{end}}
</tr>
{{end}}
{{end}}
</table>
</fieldset>
<fieldset><legend><input id="direct" type="text" onkeydown="return Command(event)"></legend>
<table id="append"></table>
<pre class="result"><code id="result"></code></pre>
</fieldset>
<script>
function Result(msg) {
var result = document.getElementById("result");
result.innerHTML = msg.result.join("");
var append = document.getElementById("append");
var tr = document.createElement("tr");
append.appendChild(tr)
for (var k in msg.append) {
var th = document.createElement("th");
th.innerHTML = k;
}
}
function Command(event, name) {
if (event.keyCode == 13) {
var direct = document.getElementById("direct");
if (name) {
direct.value = name;
ctx.Cmd(name, event.currentTarget.value, Result);
} else {
ctx.Cmd(event.currentTarget.value, "", Result);
}
}
}
function Direct(event, name, value) {
console.log(event)
if (!name) {
name = event.currentTarget.value;
}
var direct = document.getElementById("direct");
direct.value = name;
ctx.Cmd(name, value, Result);
return false;
}
</script>
{{end}}
{{define "module"}}
<fieldset><legend><input type="text" id="module" value="{{index .current_module 0}}" onkeydown="return Change(event, 'dir')"></legend>
<table>
<colgroup>{{range .append}}<col class="{{.}}">{{end}}</colgroup>
<tr>{{range .append}}<th class="{{.}}" onclick="list('{{.}}')">{{.}}</th>{{end}}</tr>
{{$l := index .append|len}}
{{if gt $l 0}}
{{$meta := .}} {{$first := index .append 0}}
{{range $i, $k := index . $first}}
<tr>
{{range $key := index $meta "append"}}
{{if eq $key "name"}}
<td class="{{$key}}">
<code><a href="" onclick="ctx.Search('dir', '{{index $meta "module" $i}}'); return false">{{index $meta $key $i}}</a></code>
</td>
{{else}}
<td class="{{$key}}">
<code>{{index $meta $key $i}}</code>
</td>
{{end}}
{{end}}
</tr>
{{end}}
{{end}}
</table>
</fieldset>
{{end}}
{{define "domain"}}
<fieldset><legend><input type="text" id="domain" value="{{index . "current_domain" 0}}" onkeydown="return Change(event, 'dir')"></legend>
<table>
<colgroup>{{range .append}}<col class="{{.}}">{{end}}</colgroup>
<tr>{{range .append}}<th class="{{.}}" onclick="list('{{.}}')">{{.}}</th>{{end}}</tr>
{{$l := index .append|len}}
{{if gt $l 0}}
{{$meta := .}} {{$first := index .append 0}}
{{range $i, $k := index . $first}}
<tr>
{{range $key := index $meta "append"}}
{{if eq $key "name"}}
<td class="{{$key}}">
<code><a href="" onclick="ctx.Search('domain', '{{index $meta "domain" $i}}'); return false">{{index $meta $key $i}}</a></code>
</td>
{{else}}
<td class="{{$key}}">
<code>{{index $meta $key $i}}</code>
</td>
{{end}}
{{end}}
</tr>
{{end}}
{{end}}
</table>
</fieldset>
{{end}}
{{define "tail"}}
<script src="library/context.js"></script>
<script>
function Change(event, key) {
if (event.keyCode == 13) {
ctx.Search(key, event.target.value);
}
}
function list(what) {
ctx.Cookie("list", what);
ctx.Cookie("sort_order", ctx.Cookie("sort_order")*1 + 1);
location.assign(location.href);
}
</script>
</body>
{{end}}
{{define "main"}}
{{$msg := .}}
{{$meta := .Meta}}
{{$sess := $msg.Sessions}}
{{range .Meta.tmpl}}
{{if eq . "login"}}
{{template "login" $meta}}
{{else if eq . "userinfo"}}
{{template "userinfo" $msg}}
{{else if eq . "share"}}
{{template "share" $sess.share}}
{{else if eq . "cache"}}
{{template "cache" $sess.cache.Meta}}
{{else if eq . "config"}}
{{template "config" $sess.config.Meta}}
{{else if eq . "command"}}
{{template "command" $sess.command.Meta}}
{{template "command2" $sess.command.Meta}}
{{else if eq . "module"}}
{{template "module" $sess.module.Meta}}
{{else if eq . "domain"}}
{{template "domain" $sess.domain.Meta}}
{{end}}
{{end}}
{{end}}

View File

@ -1,163 +0,0 @@
{{define "list"}}
<fieldset><legend><input type="text" id="dir" value="{{meta .dir}}" onkeydown="return Change(event)"></legend>
<table>
<colgroup>{{range .append}}<col class="{{.}}">{{end}}</colgroup>
<tr>
{{$sort := meta .sort}}
{{$reverse := meta .reverse}}
{{range .append}}
{{if eq $sort .}}
<th class="{{.}} sort" onclick="list('{{.}}')">{{.}}</th>
{{else if eq $reverse .}}
<th class="{{.}} reverse" onclick="list('{{.}}')">{{.}}</th>
{{else if eq . "path"}}
{{else}}
<th class="{{.}}" onclick="list('{{.}}')">{{.}}</th>
{{end}}
{{end}}
</tr>
{{if .append}}
{{$meta := .}}
{{$first := index .append 0}}
{{range $i, $k := index . $first}}
<tr>
{{range $key := index $meta "append"}}
{{if eq $key "name"}}
{{$type := index $meta "type" $i}}
<td class="{{$key}}">
<a {{if eq $type "file"}} download="{{index $meta $key $i}}" {{end}}
href="/upload?dir={{index $meta "path" $i}}"><code>{{index $meta $key $i}}</code></a>
</td>
{{else if eq $key "path"}}
{{else}}
<td class="{{$key}}">
<code>{{index $meta $key $i}}</code>
</td>
{{end}}
{{end}}
</tr>
{{end}}
{{end}}
</table>
</fieldset>
<style>
.time {
padding-right:20px;
}
.size {
text-align:right;
padding-right:20px;
}
.name {
padding-left:10px;
text-align:left;
}
.sort {
color:red;
}
.reverse {
color:green;
}
</style>
<script>
function Change(event) {
if (event.keyCode == 13) {
ctx.Search("dir", event.target.value);
}
}
function list(what) {
ctx.Cookie("list_order", ctx.Cookie("list_order")*1 + 1);
ctx.Cookie("list", what);
ctx.Refresh();
}
</script>
{{end}}
{{define "git"}}
<fieldset><legend>branch</legend>
<pre>{{index . "result"}}</pre>
</fieldset>
<fieldset><legend>status</legend>
<pre>{{index . "result"}}</pre>
</fieldset>
{{end}}
{{define "tmux"}}
{{$meta := .}}
{{range $index, $value := index $meta "append"}}
<fieldset><legend>{{$value}}</legend>
{{if eq $value "buffer"}}
<button onclick="copy_tmux_buffer('copy')">copy</button>
<button onclick="send_tmux_buffer('paste')">send</button>
<textarea rows="5" cols="60" name="tmux_buffer">{{meta . "buffer" 0}}</textarea>
<script>
var buffer = document.getElementsByName("tmux_buffer")[0];
function copy_tmux_buffer(action) {
buffer.select();
document.execCommand(action);
}
function send_tmux_buffer(action) {
var xhr = new XMLHttpRequest();
xhr.open("POST", "/paste?content="+encodeURIComponent(buffer.value));
xhr.send()
}
</script>
{{else}}
<pre>{{meta $meta $value}}</pre>
{{end}}
</fieldset>
{{end}}
{{end}}
{{define "upload"}}
<fieldset><legend>upload</legend>
<form method="POST" action="/create?dir={{option . "dir"|meta|unscaped}}" enctype="multipart/form-data">
<input type="file" name="file"><input type="submit">
</form>
</fieldset>
{{end}}
{{define "create"}}
<fieldset><legend>create</legend>
<form method="POST" action="/create?dir={{option . "dir"|meta|unscaped}}">
<table>
<tr><td>filename:</td><td><input type="text" name="filename" required><input type="submit"></td></tr>
<tr><td>content:</td><td><textarea rows="5" cols="60" name="content"></textarea></td></tr>
</table>
</form>
</fieldset>
{{end}}
{{define "main"}}
{{$msg := .}}
{{$meta := .Meta}}
{{$sess := .Sessions}}
{{range .Meta.tmpl}}
{{$tmpl := index $sess .}}
{{if eq . "login"}}
{{template "login" $meta}}
{{else if eq . "userinfo"}}
{{template "userinfo" $msg}}
{{else if eq . "share"}}
{{template "share" $sess.share}}
{{else if eq . "list"}}
{{template "list" $msg.Sessions.list.Meta}}
{{else if eq . "tmux"}}
{{template "tmux" $msg.Sessions.tmux.Meta}}
{{else if eq . "git"}}
{{if $msg.Sessions.git}}
{{template "git" $msg.Sessions.git.Meta}}
{{end}}
{{else if eq . "upload"}}
{{template "upload" $msg}}
{{else if eq . "create"}}
{{template "create" $msg}}
{{else}}
{{end}}
{{end}}
{{end}}