1
0
forked from x/ContextOS

vps add web/wiki

This commit is contained in:
shylinux 2018-08-25 12:07:09 +08:00
parent 54904b5c7a
commit 07165a1957
9 changed files with 450 additions and 31 deletions

View File

@ -5,6 +5,7 @@ install:
@go get github.com/go-sql-driver/mysql
@go get github.com/nsf/termbox-go
@go get github.com/skip2/go-qrcode
@go get github.com/gomarkdown/markdown
@cp etc/go.snippets ~/.vim/snippets/
@cp etc/shy.vim ~/.vim/syntax/
@touch etc/local.shy

View File

@ -169,7 +169,7 @@ var Index = &ctx.Context{Name: "aaa", Help: "认证中心",
Help: "用户登录, sessid: 会话ID, username: 用户名, password: 密码, load: 加载用户信息, save: 保存用户信息, filename: 文件名",
Form: map[string]int{"cert": 1, "pub": 1, "key": 1, "ip": 1},
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if aaa, ok := m.Target().Server.(*AAA); m.Assert(ok) { // {{{
if aaa, ok := c.Server.(*AAA); m.Assert(ok) { // {{{
stream := ""
if m.Has("ip") {
stream = m.Option("ip")

View File

@ -168,7 +168,7 @@ func (cli *CLI) Start(m *ctx.Message, arg ...string) bool { // {{{
}
m.Optionv("ps_target", cli.target)
return nil
}, "parse", arg[1]).Target().Name)
}, "scan", arg[1]).Target().Name)
if m.Options("init.shy") {
msg := m.Spawn().Cmd("source", m.Conf("init.shy"))

View File

@ -544,7 +544,7 @@ func (m *Message) Copy(msg *Message, meta string, arg ...string) *Message { // {
func (m *Message) Log(action string, str string, arg ...interface{}) *Message { // {{{
l := m.Sess("log", !m.Confs("compact_log"))
if l == nil || m.Detail(0) == "log" || m.Detail(0) == "write" {
if l == nil || m.Detail(0) == "log" || m.Detail(0) == "write" || m.Options("silent") {
return m
}
@ -973,7 +973,10 @@ func (m *Message) Gets(key string) bool { // {{{
// }}}
func (m *Message) Echo(str string, arg ...interface{}) *Message { // {{{
if len(arg) > 0 {
return m.Add("result", fmt.Sprintf(str, arg...))
}
return m.Add("result", str)
}
// }}}
@ -2232,8 +2235,8 @@ var CGI = template.FuncMap{
}
list := make([]int, n)
for i := 0; i < n; i++ {
list[i] = i
for i := 1; i <= n; i++ {
list[i-1] = i
}
return list
}, // }}}

View File

@ -1209,8 +1209,9 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心",
key := m.Meta["append"][i]
switch key {
case "filename":
if trip > 0 {
if line > -1 && trip > 0 && trip <= len(v) {
v = v[trip:]
m.Meta["filename"][line] = v
}
case "dir":
continue

View File

@ -1,7 +1,10 @@
package web // {{{
// }}}
import ( // {{{
"bufio"
"contexts"
"github.com/gomarkdown/markdown"
"path/filepath"
"runtime"
"encoding/json"
@ -13,7 +16,6 @@ import ( // {{{
"bytes"
"mime/multipart"
"path/filepath"
"fmt"
"io"
@ -101,7 +103,7 @@ func (web *WEB) Trans(m *ctx.Message, key string, hand func(*ctx.Message, *ctx.C
msg.Log("cmd", "%s [] %v", key, msg.Meta["option"])
msg.Put("option", "request", r).Put("option", "response", w)
hand(msg, msg.Target(), key)
hand(msg, msg.Target(), msg.Option("path"))
switch {
case msg.Has("redirect"):
@ -243,6 +245,17 @@ func (web *WEB) Start(m *ctx.Message, arg ...string) bool { // {{{
web.Configs["logheaders"] = &ctx.Config{Name: "日志输出报文头(yes/no)", Value: "no", Help: "日志输出报文头"}
m.Capi("nserve", 1)
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", "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", "define", "#define", "key", "other")
if m.Cap("protocol") == "https" {
web.Caches["cert"] = &ctx.Cache{Name: "服务证书", Value: m.Conf("cert"), Help: "服务证书"}
web.Caches["key"] = &ctx.Cache{Name: "服务密钥", Value: m.Conf("key"), Help: "服务密钥"}
@ -277,9 +290,25 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心",
"cmd": &ctx.Config{Name: "cmd", Value: "tmux", Help: "路由数量"},
"cert": &ctx.Config{Name: "cert", Value: "etc/cert.pem", Help: "路由数量"},
"key": &ctx.Config{Name: "key", Value: "etc/key.pem", Help: "路由数量"},
"wiki_dir": &ctx.Config{Name: "wiki_dir", Value: "usr/wiki", Help: "路由数量"},
"which": &ctx.Config{Name: "which", Value: "redis.note", Help: "路由数量"},
"root_index": &ctx.Config{Name: "root_index(true/false)", Value: "true", 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": 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: "路由数量"},
"check": &ctx.Config{Name: "check", Value: map[string]interface{}{
"login": []interface{}{
map[string]interface{}{
@ -438,9 +467,11 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心",
"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",
},
},
@ -875,11 +906,11 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心",
// }}}
}},
"/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
// }
//
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") { //添加文件或目录
@ -1076,7 +1107,6 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心",
continue
}
val := v.(map[string]interface{})
m.Log("fuck", "why %v", val)
//命令模板
if detail, ok := val["detail"].([]interface{}); ok {
msg := m.Spawn().Add("detail", detail[0].(string), detail[1:])
@ -1148,7 +1178,150 @@ var Index = &ctx.Context{Name: "web", Help: "应用中心",
m.Echo("blog service")
}},
"/wiki": &ctx.Command{Name: "/wiki", Help: "维基", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
"/wiki_tags": &ctx.Command{Name: "/wiki_tags ", Help: "博客", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if len(arg) > 0 {
m.Option("dir", arg[0])
}
yac := m.Find("yac.parse4", true)
msg := m.Sess("nfs").Cmd("dir", path.Join(m.Conf("wiki_dir"), m.Option("dir")), "dir_name", "path")
for i, v := range msg.Meta["filename"] {
name := strings.TrimSpace(v)
es := strings.Split(name, ".")
switch es[len(es)-1] {
case "pyc", "o", "gz", "tar":
continue
case "c":
m.Log("fuck", "parse %s", name)
case "h":
default:
continue
}
f, e := os.Open(name)
m.Assert(e)
defer f.Close()
m.Log("fuck", "parse %d/%d %s", i, len(msg.Meta["filename"]), name)
bio := bufio.NewScanner(f)
for line := 1; bio.Scan(); line++ {
yac.Options("silent", true)
l := yac.Cmd("parse", "code", "void", bio.Text())
key := ""
switch l.Result(1) {
case "struct":
switch l.Result(2) {
case "struct", "}":
key = l.Result(3)
case "typedef":
if l.Result(3) == "struct" {
key = l.Result(5)
}
}
case "function":
switch l.Result(3) {
case "*":
key = l.Result(4)
default:
key = l.Result(3)
}
case "define":
key = l.Result(3)
}
if key != "" {
m.Confv("define", strings.Join([]string{key, "position"}, "."), map[string]interface{}{
"file": strings.TrimPrefix(name, m.Confx("wiki_dir")),
"line": line,
"type": l.Result(1),
})
}
yac.Meta = nil
}
}
m.Log("fuck", "parse %s", time.Now().Format("2006-01-02 15:04:05"))
}},
"/wiki_body": &ctx.Command{Name: "/wiki_body", Help: "维基", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if ls, e := ioutil.ReadFile(path.Join(m.Conf("wiki_dir"), m.Confx("which"))); e == nil {
pre := false
es := strings.Split(m.Confx("which"), ".")
if len(es) > 0 {
switch es[len(es)-1] {
case "md":
ls = markdown.ToHTML(ls, nil, nil)
default:
pre = true
}
}
if pre {
m.Option("nline", bytes.Count(ls, []byte("\n")))
m.Option("nbyte", len(ls))
m.Add("append", "code", string(ls))
m.Add("append", "body", "")
} else {
m.Add("append", "body", string(ls))
m.Add("append", "code", "")
}
return
}
if m.Options("query") {
if v, ok := m.Confv("define", m.Option("query")).(map[string]interface{}); ok {
if val, ok := v["position"].(map[string]interface{}); ok {
m.Add("append", "name", fmt.Sprintf("%v#hash_%v", val["file"], val["line"]))
return
}
}
msg := m.Sess("nfs").Cmd("dir", path.Join(m.Conf("wiki_dir"), m.Option("dir")), "dir_name", "path")
for _, v := range msg.Meta["filename"] {
name := strings.TrimPrefix(strings.TrimSpace(v), m.Conf("wiki_dir"))
es := strings.Split(name, ".")
switch es[len(es)-1] {
case "pyc", "o", "gz", "tar":
continue
}
if strings.Contains(name, m.Option("query")) {
m.Add("append", "name", name)
}
}
return
}
msg := m.Spawn().Cmd("/wiki_list")
m.Copy(msg, "append").Copy(msg, "option")
}},
"/wiki_list": &ctx.Command{Name: "/wiki_list", Help: "维基", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
ls, e := ioutil.ReadDir(path.Join(m.Conf("wiki_dir"), m.Option("which")))
m.Option("dir", m.Option("which"))
if e != nil {
dir, _ := path.Split(m.Option("which"))
m.Option("dir", dir)
ls, e = ioutil.ReadDir(path.Join(m.Conf("wiki_dir"), dir))
}
parent, _ := path.Split(strings.TrimSuffix(m.Option("dir"), "/"))
m.Option("parent", parent)
for _, l := range ls {
if l.Name()[0] == '.' {
continue
}
es := strings.Split(l.Name(), ".")
if len(es) > 0 {
switch es[len(es)-1] {
case "pyc", "o", "gz", "tar":
continue
}
}
m.Add("append", "name", l.Name())
}
}},
"/wiki/": &ctx.Command{Name: "/wiki", Help: "维基", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
m.Option("which", strings.TrimPrefix(key, "/wiki/"))
m.Append("template", "wiki")
}},
"temp": &ctx.Command{Name: "temp", Help: "应用示例", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {

View File

@ -185,7 +185,7 @@ func (yac *YAC) train(m *ctx.Message, page, hash int, word []string) (int, []*Po
}
// }}}
func (yac *YAC) parse(m *ctx.Message, out *ctx.Message, page int, void int, line string, level int) (string, []string) { // {{{
func (yac *YAC) parse(m *ctx.Message, out *ctx.Message, page int, void int, line string, level int) (string, []string, int) { // {{{
if m.Confs("debug") {
m.Log("debug", "%s\\%d %s(%d): %s", m.Conf("label")[0:level], level, yac.name(page), page, line)
}
@ -224,7 +224,7 @@ func (yac *YAC) parse(m *ctx.Message, out *ctx.Message, page int, void int, line
if state == nil { //嵌套语法递归解析
for i := 0; i < m.Capi("ncell"); i++ {
if x := yac.mat[s][byte(i)]; i < m.Capi("nlang") && x != nil {
if l, w := yac.parse(m, out, i, void, line, level+1); l != line {
if l, w, _ := yac.parse(m, out, i, void, line, level+1); l != line {
line, word = l, append(word, w...)
state = x
break
@ -245,7 +245,7 @@ func (yac *YAC) parse(m *ctx.Message, out *ctx.Message, page int, void int, line
if hash == 0 {
word = word[:0]
} else { //执行命令
} else if out != nil { //执行命令
msg := out.Spawn(m.Source()).Add("detail", yac.hand[hash], word)
if m.Back(msg); msg.Hand { //命令替换
m.Assert(!msg.Has("return"))
@ -257,7 +257,7 @@ func (yac *YAC) parse(m *ctx.Message, out *ctx.Message, page int, void int, line
m.Log("debug", "%s/%d %s(%d): %v", m.Conf("label")[0:level], level, yac.name(page), page, word)
}
return line, word
return line, word, hash
}
// }}}
@ -266,7 +266,7 @@ func (yac *YAC) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server
c.Caches = map[string]*ctx.Cache{}
c.Configs = map[string]*ctx.Config{}
if len(arg) > 0 && arg[0] == "parse" {
if len(arg) > 0 && arg[0] == "scan" {
return yac
}
@ -277,7 +277,7 @@ func (yac *YAC) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server
// }}}
func (yac *YAC) Begin(m *ctx.Message, arg ...string) ctx.Server { // {{{
if len(arg) > 0 && arg[0] == "parse" {
if len(arg) > 0 && arg[0] == "scan" {
return yac
}
@ -304,7 +304,7 @@ func (yac *YAC) Begin(m *ctx.Message, arg ...string) ctx.Server { // {{{
// }}}
func (yac *YAC) Start(m *ctx.Message, arg ...string) (close bool) { // {{{
if len(arg) > 0 && arg[0] == "parse" {
if len(arg) > 0 && arg[0] == "scan" {
lex := m.Sess("lex")
if lex.Cap("status") != "start" {
lex.Target().Start(lex)
@ -338,7 +338,7 @@ func (yac *YAC) Start(m *ctx.Message, arg ...string) (close bool) { // {{{
if len(line) == 0 {
continue
}
_, word := yac.parse(m, out, m.Optioni("page"), m.Optioni("void"), line, 1)
_, word, _ := yac.parse(m, out, m.Optioni("page"), m.Optioni("void"), line, 1)
if len(word) > 0 {
word = word[:len(word)-1]
@ -469,14 +469,28 @@ var Index = &ctx.Context{Name: "yac", Help: "语法中心",
}
// }}}
}},
"parse": &ctx.Command{
Name: "parse filename [yac_name [help]] [line line] [void void]",
"parse": &ctx.Command{Name: "parse page hash word...", Help: "添加语法规则, page: 语法集合, hash: 语句类型, word: 语法模板", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if yac, ok := m.Target().Server.(*YAC); m.Assert(ok) { // {{{
m.Optioni("page", yac.page[arg[0]])
m.Optioni("void", yac.page[arg[1]])
str, word, hash := yac.parse(m, nil, m.Optioni("page"), m.Optioni("void"), arg[2], 1)
m.Result(str, yac.hand[hash], word)
}
// }}}
}},
"scan": &ctx.Command{
Name: "scan filename [yac_name [help]] [line line] [void void]",
Help: "解析文件, filename: yac_name:模块名, yac_help:模块帮助, 文件名, line: 默认语法, void: 默认空白",
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if yac, ok := m.Target().Server.(*YAC); m.Assert(ok) { // {{{
m.Optioni("page", yac.page["line"])
m.Optioni("void", yac.page["void"])
if len(arg) > 0 {
m.Start(m.Confx("yac_name", arg, 1), m.Confx("yac_help", arg, 2), key, arg[0])
} else {
m.Start(m.Confx("yac_name", arg, 1), m.Confx("yac_help", arg, 2))
}
}
// }}}
}},

View File

@ -2,6 +2,7 @@
<!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 {
@ -20,6 +21,12 @@
padding-left: 10px;
padding-right: 20px;
}
pre {
border:solid 1px green;
padding:5px;
border-left:solid 5px green;
overflow:scroll;
}
code {
font-size:14px;
}
@ -27,6 +34,11 @@
font-size:14px;
font-family:monospace;
}
html, body {
height:100%;
width:100%;
margin:0px;
}
</style>
<script src="/library/context.js"></script>
<script>

View File

@ -1,12 +1,227 @@
{{define "wiki_head"}}
<div>hello wiki_head world!</div>
{{end}}
{{define "wiki_menu"}}
<div>hello wiki_menu world!</div>
{{end}}
{{define "wiki_list"}}
<div>hello wiki_list world!</div>
<script>
function jumpto(url) {
if (url == "..") {
var ps = locaiton.href.split();
}
location.href=url;
}
function keyup(event) {
console.log(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;
</script>
<style>
.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"}}
<div>hello wiki world!</div>
<script>
function toggle() {
window.list_hide = !window.list_hide;
var list = document.getElementsByClassName("list")[0];
var content = document.getElementsByClassName("content")[0];
if (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 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 = {
{{range $key, $val := conf . "define"}}
"{{$key}}": true,
{{end}}
};
function tags(event) {
var tag = document.getSelection().toString();
console.log(tag);
if (tag && tag.length > 0 && tags_list[tag]) {
jumpto("/wiki/?query="+encodeURIComponent(tag));
}
}
toggle();
</script>
<style>
.content {
width:85%;
height:100%;
float:left;
min-width:400px;
}
.toggle {
background-color:green;
width:2%;
height:100%;
float:left;
}
.text {
width:96%;
float:left;
margin-left:2%;
}
.link {
font-size:18px;
}
.number {
font-size:12px;
float:left;
position:relative;
left:-6px;
top:22px;
text-align:right;
}
</style>
<div class="content">
<div class="toggle" title="点击,显示或隐藏目录" onclick="toggle()"></div>
<div class="text">
<div class="number">
{{range option . "nline"|meta|list}}
<div id="hash_{{.}}"><code>{{.}}</code></div>
{{end}}
</div>
{{$msg := .}}
{{if append . "name"}}
<ul>
{{range append . "name"}}
<li class="link">
<div><a href="/wiki/{{option $msg "dir"|meta}}/{{.}}">{{.}}</a></div>
</li>
{{end}}
<ul>
{{else}}
<p>{{append . "body"|meta|unscaped}}</p>
<p><pre><code onmouseup="return tags(event)">{{append . "code"|meta}}</code></pre><p>
{{end}}
</div>
</div>
</div>
{{end}}