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

add context.md 模块

This commit is contained in:
shaoying 2019-05-12 02:09:08 +08:00
parent 9683683c7d
commit 02e51bdec2
8 changed files with 232 additions and 231 deletions

View File

@ -130,11 +130,7 @@ var Index = &ctx.Context{Name: "aaa", Help: "认证中心",
"secrete": map[string]interface{}{"password": true, "token": true, "uuid": true, "ppid": true},
}, Help: "散列"},
"secrete_key": &ctx.Config{Name: "secrete_key", Value: map[string]interface{}{"password": 1, "uuid": 1}, Help: "私钥文件"},
"expire": &ctx.Config{Name: "expire(s)", Value: "72000", Help: "会话超时"},
"cert": &ctx.Config{Name: "cert", Value: "etc/pem/cert.pem", Help: "证书文件"},
"pub": &ctx.Config{Name: "pub", Value: "etc/pem/pub.pem", Help: "公钥文件"},
"key": &ctx.Config{Name: "key", Value: "etc/pem/key.pem", Help: "私钥文件"},
"expire": &ctx.Config{Name: "expire(s)", Value: "72000", Help: "会话超时"},
},
Commands: map[string]*ctx.Command{
"init": &ctx.Command{Name: "init", Help: "数字摘要", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {

View File

@ -36,6 +36,37 @@ func Marshal(m *ctx.Message, meta string) string {
var Index = &ctx.Context{Name: "chat", Help: "会议中心",
Caches: map[string]*ctx.Cache{},
Configs: map[string]*ctx.Config{
"login": &ctx.Config{Name: "login", Value: map[string]interface{}{"check": "false"}, Help: "默认组件"},
"componet": &ctx.Config{Name: "componet", Value: map[string]interface{}{
"index": []interface{}{
map[string]interface{}{"componet_name": "chat", "componet_tmpl": "head", "metas": []interface{}{
map[string]interface{}{"name": "viewport", "content": "width=device-width, initial-scale=0.7, user-scalable=no"},
}, "favicon": "favicon.ico", "styles": []interface{}{"example.css", "chat.css"}},
map[string]interface{}{"componet_name": "header", "componet_tmpl": "fieldset",
"componet_view": "Header", "componet_init": "initHeader",
"title": "shylinux 天行健,君子以自强不息",
},
map[string]interface{}{"componet_name": "ocean", "componet_tmpl": "fieldset",
"componet_view": "Ocean", "componet_init": "initOcean",
"componet_ctx": "web.chat", "componet_cmd": "flow", "arguments": []interface{}{"ocean"},
},
map[string]interface{}{"componet_name": "river", "componet_tmpl": "fieldset",
"componet_view": "River", "componet_init": "initRiver",
"componet_ctx": "web.chat", "componet_cmd": "flow", "arguments": []interface{}{"river"},
},
map[string]interface{}{"componet_name": "footer", "componet_tmpl": "fieldset",
"componet_view": "Footer", "componet_init": "initFooter",
"title": "shycontext 地势坤,君子以厚德载物",
},
map[string]interface{}{"componet_name": "tail", "componet_tmpl": "tail",
"scripts": []interface{}{"toolkit.js", "context.js", "example.js", "chat.js"},
},
},
}, Help: "组件列表"},
"componet_group": &ctx.Config{Name: "component_group", Value: "index", Help: "默认组件"},
"chat_msg": &ctx.Config{Name: "chat_msg", Value: []interface{}{}, Help: "聊天记录"},
"default": &ctx.Config{Name: "default", Value: "", Help: "聊天记录"},
"weather_site": &ctx.Config{Name: "weather_site", Value: "http://weather.sina.com.cn", Help: "聊天记录"},
@ -60,6 +91,17 @@ var Index = &ctx.Context{Name: "chat", Help: "会议中心",
}, Help: "聊天记录"},
},
Commands: map[string]*ctx.Command{
"flow": &ctx.Command{Name: "flow", Help: "信息流", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
switch arg[0] {
case "ocean":
m.Confm("")
m.Echo("ocean")
case "river":
m.Echo("river")
}
return
}},
"/chat": &ctx.Command{Name: "user", Help: "应用示例", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
// 信息验证
nonce := []string{m.Option("timestamp"), m.Option("nonce"), m.Conf("chat", "token")}
@ -224,12 +266,6 @@ var Index = &ctx.Context{Name: "chat", Help: "会议中心",
return
}},
"talk": &ctx.Command{Name: "talk", Help: "talk", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
if m.Confs("default") {
m.Echo(m.Conf("default"))
}
return
}},
"weather": &ctx.Command{Name: "weather where field", Help: "weather", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
where := "beijing"
if len(arg) > 0 {

View File

@ -7,7 +7,7 @@ ctx = context = {
}
this.GET("", option, function(msg) {
msg = msg && msg[0]
msg && (msg.__proto__ = page || {})
// msg && (msg.__proto__ = (page || {}))
typeof cb == "function" && cb(msg || {})
})
},

View File

@ -12,6 +12,10 @@ exp = example = {
initHeader: function(page, field, option, output) {
return [{"text": ["shycontext", "div", "title"]}]
},
initField: function(page, field, option, output) {
ctx.Runs(page, option)
return
},
initBanner: function(page, field, option, output) {
field.querySelectorAll("li").forEach(function(item) {
item.onclick = function(event) {

View File

@ -33,3 +33,9 @@ fieldset.Text>div.output>div.text {
overflow:auto;
padding:10px;
}
fieldset.Text>div.output>div.text strong {
background-color:yellow;
border-left:solid 2px green;
border-top:solid 2px green;
color:red;
}

View File

@ -130,9 +130,11 @@ var page = Page({
ui.text.style.height = height+"px"
ui.text.style.width = field.offsetWidth-30-width+"px"
// ui.text.style.width = field.offsetWidth-ui.menu.offsetWidth+"px"
}
if (location.hash) {
location.href = location.hash
}
})
return
},

View File

@ -1,218 +0,0 @@
{{define "head"}}
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=0.7">
<title>code</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>
textarea.clipboard {
color:white;
background-color:#272822;
width:600px;
}
form.option div {
float:left;
}
form.option hr {
clear:both;
}
form.option label.keymap {
color:red;
display:none;
}
form.option label.keymap.show {
display:inline;
}
form.option input {
margin-right:10px;
}
form.option input.cmd {
color:white;
background-color:#272822;
padding-left:10px;
width:600px;
}
form.option input.file_cmd {
color:white;
background-color:#272822;
padding-left:10px;
width:400px;
}
form.option input.file_name {
width:200px;
}
form.option.exec input {
color:white;
background-color:#272822;
padding-left:10px;
width:600px;
}
form.option select {
margin-right:10px;
}
table.append {
font-size:14px;
overflow: auto;
}
table.append th {
font-family:monospace;
background-color:lightgreen;
cursor:pointer;
}
table.append th.order {
background-color:red;
cursor:pointer;
}
table.append td {
font-family:monospace;
padding-left: 10px;
padding-right: 20px;
}
code.result pre {
color:white;
font-size:14px;
background-color:#272822;
overflow:scroll;
padding:5px;
border:solid 2px green;
border-left:solid 4px green;
margin:0;
}
code.result pre.clipboard {
height:2em;
}
</style>
</head>
<body onkeyup="return onaction(event, 'keymap')" onkeydown="return onaction(event, 'scroll')">
{{end}}
{{define "void"}}{{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>
<datalist id="clistack"></datalist>
<textarea class="clipboard"></textarea>
</fieldset>
{{end}}
{{define "componet"}}
<fieldset><legend title="{{option .Meta "componet_help"}}">{{option .Meta "componet_help"}}({{option .Meta "componet_ctx"}}.{{option .Meta "componet_cmd"}})</legend>
{{$form_type := option . "form_type"|meta}}
{{$msg := .}}
{{if eq $form_type "upload"}}
{{end}}
<form class="option {{option .Meta "componet_name"}}"
data-componet_group="{{option . "componet_group"|meta}}"
data-componet_name="{{option . "componet_name"|meta}}"
{{if eq $form_type "upload"}}
method="POST" action="/upload" enctype="multipart/form-data"
onsubmit="onaction(event,'upload')"
{{end}}
>
<input style="display:none"></input>
{{range $index, $input := option . "inputs"}}
<div>
{{$type := index $input "type"}}
{{if index $input "label"}}
<label>{{index $input "label"}} : </label>
{{end}}
{{if eq $type "button"}}
<input type="button" onclick="return onaction(event, 'command')" value="{{index $input "value"}}">
{{else if eq $type "submit"}}
<input type="submit" value="{{index $input "value"}}">
{{else if eq $type "file"}}
<input type="file" name="{{index $input "name"}}">
{{else if eq $type "choice"}}
{{$default_value := index $input "value"}}
<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 if eq $type "password"}}
<input
type="password"
name="{{index $input "name"}}"
value="{{index $input "value"}}"
class="{{index $input "class"}}"
onclick="return onaction(event, 'click')"
onkeyup="return onaction(event, 'input')">
{{else}}
{{$name := index $input "name"}}
{{$value := option $msg $name|option}}
<input
name="{{index $input "name"}}"
{{if $value}}
value="{{$value}}"
{{else}}
value="{{index $input "value"}}"
{{end}}
class="{{index $input "class"}}"
{{if index $input "clipstack"}}
list="{{index $input "clipstack"}}"
{{else}}
list="clipstack"
{{end}}
onclick="return onaction(event, 'click')"
onkeyup="return onaction(event, 'input')">
{{end}}
</div>
{{end}}
<hr/>
</form>
{{if eq $form_type "upload"}}
{{end}}
{{if index .Meta "display_append"}}
{{option .Meta "display_append"}}
{{else}}
<table class="append {{option .Meta "componet_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 "componet_name"}}"><pre>{{result .Meta}}</pre></code>
{{end}}
</fieldset>
{{end}}
{{define "tail"}}
<script src="/librarys/context.js"></script>
<script src="/librarys/code.js"></script>
</body>
{{end}}

View File

@ -363,8 +363,183 @@ chat模块提供了信息管理。
### 应用框架
#### 模块
context内部使用模块组织功能每个模块都可以独立编译独立运行。
解除了代码之间的包依赖、库依赖、引用依赖、调用依赖。
通过map查找模块通过map查找命令通过map查找配置从而实现完全自由的模块。
**模块定义:**
```
type Context struct { // src/contexts/ctx/ctx.go
Name string
Help string
Caches map[string]*Cache
Configs map[string]*Config
Commands map[string]*Command
...
contexts map[string]*Context
context *Context
root *Context
...
Server
}
```
Name模块名称Help模块帮助。
模糊搜索搜索时会根据Name与Help进行匹配。
每个模块会有命令集合Commands配置集合Configs缓存集合Caches。通过这种形式提供功能集合。
contexts所有子模块context指向父模块root指向根模块。
从而组成一个模块树,所以可以通过路由查找模块,
如ctx.web.codecode的父模块是webweb的父模块是ctxctx是根模块。
所以可以通过命令,查看到当前程序所有模块的信息。
**缓存定义:**
```
type Cache struct {
Value string
Name string
Help string
Hand func(m *Message, x *Cache, arg ...string) string
}
```
Value存放的数据Name变量名称Help变量帮助Hand读写函数。
缓存数量是一种数据接口,用来存放一些状态量,向外部显示程序进行状态,对外部来说一般是只读的。对内部来说可读可写。
所以可以通过命令,查看到当前程序任意模块的状态数据。
如下ncontext当前有多少个模块。nserver有多少个模块运行了守护协程。
```
"nserver": &Cache{Name: "nserver", Value: "0", Help: "服务数量"},
"ncontext": &Cache{Name: "ncontext", Value: "0", Help: "模块数量"},
```
**缓存读写:**
```
func (m *Message) Cap(key string, arg ...interface{}) string {}
func (m *Message) Capi(key string, arg ...interface{}) int {}
func (m *Message) Caps(key string, arg ...interface{}) bool {}
```
定义了缓存数据的三种读写接口。
m.Cap()只有一个参数时会从当前模块查询缓存变量如果查到则返回Value如果没有则依次查询父模块。
如果查找到根模块还没有查到找,变返回空字符串。
m.Cap()有两个参数时,同样会从当前模块依次查询父模块,直到查到变量,然后设置其值。
m.Capi()是对m.Cap()封装了一下在int与str相互转换从而实现用str存储int。
所有转换失败的数据都会返回0。
m.Caps()实现了str存储bool。返回false的值有"", "0", "false", "off", "no", "error: "其它都返回true。
**配置定义:**
```
type Config struct {
Value interface{}
Name string
Help string
Hand func(m *Message, x *Cache, arg ...string) string
}
```
Value存放的数据Name变量名称Help变量帮助Hand读写函数。
与Cache相似只是Value的类型不再是String而是interface{},所以可以用来存放更复杂的数据。
一般用来存放配置数据,是外部控制内部数据接口。
所以可以通过命令,实时修改当前程序任意模块的配置数据。
避免只是修改某个配置变量,就要重启整个进程,从而实现高效灵活的配置。
把每个进程当成一个生命来对待,不要轻易杀死任何一个进程。有问题可以用微创手术解决。
**配置读写:**
```
func (m *Message) Conf(key string, args ...interface{}) string {}
func (m *Message) Confi(key string, arg ...interface{}) int {}
func (m *Message) Confs(key string, arg ...interface{}) bool {}
func (m *Message) Confx(key string, args ...interface{}) string {}
func (m *Message) Confv(key string, args ...interface{}) interface{} {}
func (m *Message) Confm(key string, args ...interface{}) map[string]interface{} {}
```
与Cache相似也定义了各种读写的接口。
因为interface{}可以是任意复合类型,所以数据嵌套很深时,查询会涉及各种类型转换,非常麻烦。
Conf()定义了键值链。内部去处理类型转换与嵌套的深入。
如m.Conf("runtime", "user.node")、m.Conf("runtime", []string{"user", "node"})、m.Conf("runtime", []interface{}{"user", "node"})
都会查询配置runtime下的user下的node的值。
m.Confx()内部进行选择如果m.Option(key)中取到了值则直接返回m.Option(key)否则返回m.Conf(key)。
把配置当成一个备用的默认值,如果命令参数设置了此参数,则用命令中的参数。
m.Confv()直接读写原始数据。
m.Confm()则定义了更丰富的接口m就是map意思直接返回map[string]interface{}
m另外一个意思就是magic可以传入各种回调函数。
如下配置node类型是map[string]interface{}m.Confm()会遍历此map查到value也是map[string]interface{}的键值,调用回调函数。
```
...
m.Confm("node", func(name string, node map[string]interface{}) {
if kit.Format(node["type"]) != "master" {
ps = append(ps, kit.Format(node["module"]))
}
})
...
```
**命令定义:**
```
type Command struct {
Form map[string]int
Name string
Help interface{}
Auto func(m *Message, c *Context, key string, arg ...string) (ok bool)
Hand func(m *Message, c *Context, key string, arg ...string) (e error)
}
```
Name命令语法Help命令帮助。
Hand命令处理函数m是调用消息c是当前模块key是命令名arg是命令参数。
在命令解析时会根据Form将[key value...]形式的参数取出存放到m.Option中方便用key直接查找参数。
所以arg中只剩下序列参数通过index序号查找参数。
Auto终端自动补全函数。在使用终端每输入一个单词时就调用此函数输出提示信息。所以在命令执行前这个函数会被调用多次。
如下定义了trans命令
```
...
"trans": &Command{Name: "trans option [type|data|json] limit 10 [index...]", Help: "数据转换",
Form: map[string]int{"format": 1, "fields": -1},
Hand: func(m *Message, c *Context, key string, arg ...string) (e error) {
...
}}
...
```
**命令调用:**
```
func (m *Message) Cmd(args ...interface{}) *Message {}
func (m *Message) Cmdx(args ...interface{}) string {}
func (m *Message) Cmds(args ...interface{}) bool {}
func (m *Message) Cmdy(args ...interface{}) *Message {}
func (m *Message) Cmdm(args ...interface{}) *Message {}
```
m.Cmd()根据第一个参数去当前查找命令,如果没有查找到,则去父模块查找。如果没有查找,则不会执行。
剩下的参数会根据Form定义来解析存放到m.Option中。
m.Cmds()当返回值转换成bool规则同m.Caps()与m.Confs()。
m.Cmdx()当返回值转换成str。 m.Cmdy()将结果复制到当前Message。
m.Cmdm()m同样是magic会根据当前会话自动定向到远程某主机某模块远程调用其命令当然也可能定向到本机。
#### 协程
#### 消息
context内部调用都是
### 解析引擎
#### 文件扫描
#### 词法解析