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

mac add 添加了消息处理的事件回调

This commit is contained in:
shaoying 2018-03-24 15:50:18 +08:00
parent a596b23e1b
commit 6303d02c4a
4 changed files with 214 additions and 72 deletions

158
README.md
View File

@ -22,20 +22,26 @@ https://github.com/shylinux/context-bin/raw/master/bench-windows-amd64.exe
https://github.com/shylinux/context-bin/raw/master/bench-darwin-amd64
### 1.1 context源码安装
#### 1.1.0 golang开发环境安装
#### 1.1.0 golang安装
* mac安装 https://github.com/shylinux/context-bin/raw/master/go1.6.2.darwin-amd64.pkg
* windows安装(推荐使用git的shell) https://github.com/shylinux/context-bin/raw/master/Git-2.12.2-32-bit.exe
* windows安装 https://github.com/shylinux/context-bin/raw/master/go1.6.2.windows-386.msi
* Linux安装 集成在了开发环境的安装包中先安装好git即可
#### 1.1.1 golang开发环境安装
* 下载git clone https://github.com/shylinux/context-dev
* 安装cd context-dev && ./install.sh
#### 1.1.1 context源码安装
#### 1.1.2 context源码安装
* 下载git clone https://github.com/shylinux/context
* 编译cd context && go install src/example/bench.go
## 2 context使用
### 2.0 应用示例--启动WEB服务器
```sh
$ bench
> ~web
 > serve ./ ':9090'
$ bench
> ~web
> serve ./ ':9090'
```
在shell中运行命令bench启动应用进入到一个类似于shell的环境中。
@ -44,7 +50,7 @@ https://github.com/shylinux/context-bin/raw/master/bench-darwin-amd64
打开浏览器输入"http://localhost:9090" 即可看一个静态WEB服务器已经启动。
### 2.1 常用命令
#### 2.1.1 cache: 缓存管理
#### 2.1.1 缓存管理cache
```sh
web> cache
address(:9090): 服务地址
@ -54,7 +60,7 @@ protocol(http): 服务协议
输入"cache"命令,即可查看当前模块的缓存数据,通过这些缓存数据,就可以了解模块的当前各种运行状态。
如"address"代表web模块监听的网络地址为"0.0.0.0:9090"。
#### 2.1.2 config: 配置管理
#### 2.1.2 配置管理config
```sh
web> config
logheaders(yes): 日志输出报文头(yes/no)
@ -68,7 +74,7 @@ logheaders(no): 日志输出报文头(yes/no)
```
输入"config logheaders no"命令修改logheaders的值为no即不在日志中输出报文头。
#### 2.1.3 command: 命令管理
#### 2.1.3 命令管理command
```sh
web> command
serve: serve [directory [address [protocol]]]
@ -81,7 +87,7 @@ route: route directory|template|script route content
参数"address",代表服务器监听的网络地址。
参数"protocol",代表服务器使用的网络协议。
#### 2.1.4 context: 模块管理
#### 2.1.4 模块管理context
```sh
web> context
web(ctx:cli:aaa::): start(:9090) 应用中心
@ -108,7 +114,7 @@ file2(nfs::aaa:root:root): start(etc/init.shy) 扫描文件
输入"context ctx"命令切换ctx模块为当前模块。输入"context"命令,即可查看当前模块及子模块的基本信息。
ctx为根模块所以可以查看到所有模块的基本信息。
#### 2.1.5 message: 消息管理
#### 2.1.5 消息管理message
```sh
tcp> message
requests:
@ -124,7 +130,7 @@ historys:
输入"message"命令,查看当前模块收发的所有消息。
其中"requests"是收到的长消息如有一条ctx模块发送给tcp模块的编号为9消息。
其中"sessions"是发送出的长消息这里为空所以tcp模块没有发送长消息。
其中"historys"是模块收到的所有消息,包括长消息和短消息。显示中除了显示当前消息,还会显示消息的子消息。
其中"historys"是模块收到的所有消息,包括长消息和短消息。显示中除了显示当前消息,还会显示消息的子消息。如这里编号为4358的消息就有三条子消息4359、4361、4363。
```sh
tcp> message 9
message: 0
@ -133,7 +139,7 @@ message: 0
输入"message 9"命令查看编号为9的消息的具体信息。
### 2.2 web模块的命令
web模块提供web服务。目前有两条命令serve主机管理route路由管理
web模块提供web服务。目前有两条命令主机管理serve路由管理route
```sh
web> command
serve: serve [directory [address [protocol]]]
@ -141,30 +147,33 @@ route: route directory|template|script route content
/demo: /demo
```
#### 2.2.1 serve主机管理
#### 2.2.1 主机管理serve
```sh
web> command serve
serve [directory [address [protocol]]]
开启应用服务
```
serve命令会监听网络端口并启动web服务器。
* directory服务目录
* address服务地址(ip:port)
* protocol服务协议(http/https)
#### 2.2.2 route路由管理
#### 2.2.2 路由管理route
```sh
web> command route
route directory|template|script route content
添加应用内容
```
route命令会向指定的URI添加响应内容。响应内容可以是文件内容可以是golang的模板可以是脚本执行结果。
参数route代表http请求的uri地址参数content代表响应回复的内容不同类型的服务有不同的意义。
* directory静态服务
```sh
web> route directory /p pkg
```
命令"route diretory /p pkg"当web模块接收到请求uri为"/p/"时把目录"pkg"中的内容作为响应回复。
content代表路径即web服务请求此route路径时回复的内容为content指定的目录或文件。
* template模板服务
```sh
web> route template /t LICENSE
@ -172,7 +181,9 @@ web> route template /t LICENSE
命令"route template /t LICENSE"当web模块接收到请求uri为"/t"时把文件"LICENSE"中的内容作为响应回复。
* script脚本服务
```sh
web> route script /s echo.shy
```
content代表脚本的文件名即web服务请求此route路径时回复的内容为content指定的脚本运行后输出的内容。
## 3 context开发
@ -207,6 +218,7 @@ func init() {
ctx.Index.Register(Index, nil)
}
```
在context目录下打开src/example/bench.go文件添加一行 _ "example/demo",引入新添加的模块 。
```go
package main
@ -235,6 +247,7 @@ func main() {
ctx.Start(os.Args[1:]...)
}
```
在context目录下编译安装bench.go启动bench进入新模块执行新添加的命令。
```sh
$ go install src/example/bench.go
@ -251,6 +264,7 @@ func init() {
}
```
在模块初始化时向ctx模块注册当前模块即当前模块为ctx的子模块。
```go
var Index = &ctx.Context{Name: "demo", Help :example demo",
Caches: map[string]*ctx.Cache{},
@ -260,6 +274,8 @@ var Index = &ctx.Context{Name: "demo", Help :example demo",
```
Index即为模块的数据结构Name为模块的名字Help为模块的简介Caches为模块的缓存项
Configs为模块的配置项Commands为命令项。
每个模块都需要初始化这五个属性,通过这些属性向外提供标准接口。
```go
type Cache struct {
Name string
@ -285,9 +301,15 @@ type Command struct {
Hand func(m *Message, c *Context, key string, arg ...string)
}
```
三种标准接口的定义如上Cache为缓存项模块的内部数据可以定义成Cache外部通过查看这些Cache就可以了解模块当前运行的各种状态。
Config为配置项模块内的一些常量或是可配置的数据就可以定义成Config外部通过对这些配置的设置就可以改变模块的运行环境控制模块的功能。
Command的命令项模块向外提供的各种API接口或是CLI接口都统一定义为command即可以被其它模块在代码中直接调用也可以在命令行实时调用。
通过这种方式直接解除了模块的依赖关系,每个模块都可以独立编译,独立运行。
通过脚本或是配置把各种模块组合在一起,完成复杂的功能。这样大大降低了代码的重复性,提高了代码的通用性。
Cache为缓存项的定义Name为缓存项的名字Value为缓存项的值Help为缓存项的帮助信息Hand为缓存项读写函数可选。
Config为配置项的定义Name为配置项的名字Value为配置项的值Help为配置项的帮助信息Hand为配置项读写函数可选。
Command为命令项的定义Name为命令项的名字Help为命令项的帮助信息Hand为命令项执行函数。
```go
Commands: map[string]*ctx.Command{
"echo": &ctx.Command{Name: "echo word", Help: "echo something", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
@ -295,7 +317,10 @@ Commands: map[string]*ctx.Command{
}},
},
```
命令Hand函数是消息驱动的。
echo命令按照缓存项format的格式输出配置项default的内容。
这样可以从命令行查看缓存项format的值就可以知道echo命令输出的格式。
这样可以从命令行设置配置项default的值就可以改变echo命令输出的内容。
命令Hand函数是消息驱动的。所以各种通过消息m就可以调用到各种函数。
m.Cap()读写当前模块的某个缓存项。
m.Conf()读写当前模块的某个配置项。
m.Echo()输出命令执行结果。
@ -332,8 +357,7 @@ func (m *Message) Log(action string, ctx *Context, str string, arg ...interface{
参数ctx指定模块, 可取nil。
参数str与arg与Printf参数相同。
### 3.1 context模块开发进阶
#### 3.1.0 context模块的生命周期与继承多态
### 3.1 context模块的生命周期与继承多态
context结构体封封装了三种标准接口cache、config、command。
但这些接口只能保存与处理简单的数据。如果需要处理复杂的数据,可以自己定义类型。
自定义的类型必须实现Server接口。
@ -427,9 +451,19 @@ func init() {
ctx.Index.Register(Index, demo)
}
```
模块通过Context结构向外提供各种功能调用的接口通过Server接口向ctx模块提供生命周期的控制函数。
所以模块可以被复制,被删除,就有了生命周期。
并且每个模块都会有父模块与子模块,所以就会形成一个动态的树状态结构,不断的有新加的模块,也会有消失的模块。
每个模块在被加载与注册时生成一个静态模块Index即是静态模块的Context在init()函数中会给创建模块的Server并将Context与Server绑定到一起同时向父模块注册当前模块。
当需要创新新模块时会调用Spawn()从当前模块复制出来一个新的模块作为当前模块的子模块。并调用Begin()对新模块进行初始化操作。
当需要模块启动一个服务时会调用Start() 当需要模块关闭一个服务时会调用Close()。服务的实现方式可以是一次性操作的,也可以是一直运行的。
新定义了一个结构体Demo可以向其添加各种自定义的数据。ctx.Context指向绑定的模块。
并实现了四个生命周期函数。Spawn()在创建新模块时会添加一个新缓存项。创建新的自定义结构体,并与新模块绑定。
init()创建新的自定义结构体,并与静态模块绑定。
```sh
$ go install src/example/bench.go
$ bench
@ -455,6 +489,7 @@ one: hello go world
新模块中有format缓存项则不会调用父模块的format。
新模块中没有default配置项则会调用父模块的配置项。
从而实现了模块间的继承与多态。
```sh
one> del
one> context demo
@ -464,9 +499,10 @@ two(demo:cli:aaa:root:root): start() new module
```
在one模块下调用del则会删除当前模块。调用context demo切换到父模块则看到one模块已经被删除。
#### 3.1.1 message消息驱动的开发模型
为了降低模块间的信赖关系,除了定义三种标准接口外,还有模块间的通信使用消息机制。
所以大多函数中都会有参数m代表当前的消息arg消息的请求行参数。
### 3.2 message消息驱动的开发模型
无论是Context中的三种标准接口还是Server中的四个生命周期接口都是基于消息调用的。
即模块的所有操作都是消息驱动的。 所以大多函数中都会有参数m代表当前的消息arg消息的请求行参数。
```go
Commands: map[string]*ctx.Command{
"send": &ctx.Command{
@ -480,11 +516,15 @@ Commands: map[string]*ctx.Command{
},
...
```
如上再给demo模块添加一条send命令。
m.Find()会查找当前模块的子模块,并创建一个由当前模块发送给子模块的消息。
msg.Cmd()设置请求行,并执行命令。
msg.Result()取出响应行的数据。
m.Echo()设置当前命令的执行结果,即当前命令的响应行。
如上,消息的使用示例。 再给demo模块添加一条send命令。
消息是有发起模块与接收模块,所以首先要指定接收模块创建一个新的消息。
然后设置请求行与请求头的数据,并发送消息。
最后从响应行与响应头中取出执行的结果。
这里从参数arg中取出接收模块的名字调用Find()查找此模块,并创建新消息。
然后调用Cmd()发送消息通过参数设置了请求行。消息会发送给对应模块并调用模块的echo命令。
最后调用Result()取了响应行的数据并调用Echo()设置了send命令的执行结果。
```sh
$ go install src/example/bench.go
$ bench
@ -495,7 +535,7 @@ one: hello go world
```
重新编译并运行bench在demo模块下创建一个新的模块one并切换回demo模块向one模块发送一条消息。
* 消息创建
#### 3.2.1 消息创建
```go
func (m *Message) Search(key string, root ...bool) []*Message
func (m *Message) Find(name string, root ...bool) *Message
@ -511,13 +551,13 @@ Sess()是对Search()与Find()进行了封装,会把搜索的结果保存下来
参数key为保存名第二个参数为模块名第三个参数为搜索方法search或find第四个参数为搜索起点是否为根模块。
后面三个参数都有默认值使用方法类似于C++的变参。如果只有一个参数则会直接取出之前的查找结果并创建一个新的消息。
* 消息发送
#### 3.2.2 消息发送
```go
func (m *Message) Cmd(arg ...interface{}) *Message
```
消息发送给目标模块调用对应的Command接口。参数为命令行包括命令名与命令参数。
* 消息读写
#### 3.2.3 消息读写
```go
func (m *Message) Detail(index int, arg ...interface{}) string
func (m *Message) Detaili(index int, arg ...int) int
@ -581,6 +621,7 @@ Commands: map[string]*ctx.Command{
然后调用Cmd()执行命令。命令执行完成后调用Result()取出响应行调用Append()取出响应头。
在echo命令中调用Option取出请求头调用Result设置响应行调用Append设置响应头。
```sh
$ go install src/example/bench.go
$ bench
@ -590,6 +631,63 @@ demo> send one
hello world nice
```
### 3.3 message消息驱动的事件回调
每个模块都可以运行自己的协程有自己的消息队列从而实现并发。为了更简单的使用并发对Cmd()封装了一个异步接口Call()。
```go
func (m *Message) Call(cb func() bool)
func (m *Message) Back()
```
Call()发送消息,命令执行完成后会调用参数的中的回调函数。
在回调函数中如果返回值为true则代表消息执行完成会删除回调函数。
如果返回值为false则代表消息还未处理完成。在其它事件中调用Back()可以再调用回调函数。
```go
"send": &ctx.Command{
Name: "send module",
Help: "send something",
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
m.Sess("sub", arg[0], "find", "false")
msg := m.Sess("sub")
msg.Detail(0, "echo")
msg.Option("key", "hello")
msg.Call(func() bool {
if msg.Append("get") == "" {
return false
}
m.Echo(msg.Result(0))
m.Echo(" ")
m.Echo(msg.Result(1))
m.Echo(" ")
m.Echo(msg.Append("hi"))
return true
})
time.Sleep(2 * time.Second)
},
},
"echo": &ctx.Command{
Name: "echo word",
Help: "echo something",
Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
m.Result(0, m.Option("key"), "world")
m.Append("hi", "nice")
go func() {
time.Sleep(time.Second)
m.Append("get", "good")
m.Back()
}()
},
},
```
把send与echo修改为异步方式在send命令中调用Call()发送消息当echo命令执行完成后会调用回调函数但msg.Append("get")参数还不存在所以返回false保留消息。
1s后echo命令中的协程会向消息中添加了响应头get调用Back(),回调函数会被再次调用,此时条件满足,则会向后执行。
为了看到执行结果在send命令最后加了两秒的睡眼。
如果去掉send命令中的睡眠send命令直接就结束。当回调函数再次被调用时就看不到执行行结果了。
## 4 context核心模块详解
### 4.0 ctx模块中心
### 4.1 cli命令中心

View File

@ -38,7 +38,7 @@ func (cli *CLI) check(arg string) bool { // {{{
// }}}
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{}
c.Configs = map[string]*ctx.Config{}
@ -51,7 +51,8 @@ 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.Caches["level"] = &ctx.Cache{Name: "嵌套层级", Value: "0", Help: "嵌套层级"}
cli.Caches["skip"] = &ctx.Cache{Name: "跳过执行", Value: "0", Help: "命令只解析不执行"}
cli.Caches["else"] = &ctx.Cache{Name: "解析选择语句", Value: "false", Help: "解析选择语句"}
@ -190,7 +191,8 @@ func (cli *CLI) Begin(m *ctx.Message, arg ...string) ctx.Server {
return cli
}
func (cli *CLI) Start(m *ctx.Message, arg ...string) bool {
// }}}
func (cli *CLI) Start(m *ctx.Message, arg ...string) bool { // {{{
cli.Caches["#"] = &ctx.Cache{Name: "参数个数", Value: fmt.Sprintf("%d", len(arg)), Help: "参数个数"}
for i, v := range arg {
cli.Caches[fmt.Sprintf("%d", i)] = &ctx.Cache{Name: "执行参数", Value: v, Help: "执行参数"}
@ -252,7 +254,8 @@ func (cli *CLI) Start(m *ctx.Message, arg ...string) bool {
return !cli.Pulse.Has("save")
}
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():
m.Echo(cli.nfs.Cap("return"))
@ -267,6 +270,8 @@ 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{},
@ -576,26 +581,26 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
} // }}}
}},
"source": &ctx.Command{Name: "source file", Help: "运行脚本, file: 脚本文件名", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if _, ok := m.Target().Server.(*CLI); m.Assert(ok) && !m.Caps("skip") {
if _, ok := m.Target().Server.(*CLI); m.Assert(ok) && !m.Caps("skip") { // {{{
m.Start(fmt.Sprintf("%s%d", key, m.Optioni("level", m.Capi("level")+1)), "脚本文件", arg[0])
}
} // }}}
}},
"return": &ctx.Command{Name: "return result...", Help: "结束脚本, rusult: 返回值", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if _, ok := m.Target().Server.(*CLI); m.Assert(ok) && !m.Caps("skip") {
if _, ok := m.Target().Server.(*CLI); m.Assert(ok) && !m.Caps("skip") { // {{{
m.Add("append", "return", 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) { // {{{
if m.Optioni("skip", 0); m.Caps("skip") || !cli.check(arg[1]) {
m.Optioni("skip", m.Capi("skip")+1)
}
m.Start(fmt.Sprintf("%s%d", key, m.Optioni("level", m.Capi("level")+1)), "条件语句")
}
} // }}}
}},
"elif": &ctx.Command{Name: "elif 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) { // {{{
if !m.Caps("else") {
m.Caps("skip", true)
return
@ -608,15 +613,15 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
}
m.Caps("else", m.Caps("skip", !cli.check(arg[1])))
}
} // }}}
}},
"else": &ctx.Command{Name: "else", Help: "条件语句", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if _, ok := m.Target().Server.(*CLI); m.Assert(ok) {
if _, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{
m.Caps("skip", !m.Caps("else"))
}
} // }}}
}},
"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 m.Capi("fork") != -2 {
m.Spawn(cli.nfs.Target()).Cmd("copy", cli.Name, m.Cap("fork"), m.Option("pos"))
}
@ -627,10 +632,10 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
} else {
m.Put("append", "cli", cli.Context.Context())
}
}
} // }}}
}},
"for": &ctx.Command{Name: "for 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) { // {{{
if m.Capi("loop") != -2 && m.Capi("loop") == m.Optioni("pos")-1 {
m.Caps("skip", !cli.check(arg[1]))
return
@ -641,18 +646,18 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心",
}
m.Optioni("loop", m.Optioni("pos")-1)
m.Start(fmt.Sprintf("%s%d", key, m.Optioni("level", m.Capi("level")+1)), "循环语句")
}
} // }}}
}},
"function": &ctx.Command{Name: "function name", Help: "函数定义, name: 函数名", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if _, ok := m.Target().Server.(*CLI); m.Assert(ok) {
if _, ok := m.Target().Server.(*CLI); m.Assert(ok) { // {{{
m.Optioni("fork", m.Optioni("pos")+1)
m.Optioni("skip", m.Capi("skip")+1)
m.Start(arg[1], "循环语句")
}
} // }}}
}},
"call": &ctx.Command{Name: "call name arg...", Help: "函数调用, name: 函数名, arg: 参数", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
fun := m.Find("nfs.file1." + arg[0])
fun.Target().Start(fun)
fun := m.Find("nfs.file1." + arg[0]) // {{{
fun.Target().Start(fun) // }}}
}},
},
}

View File

@ -470,6 +470,9 @@ type Message struct {
target *Context
Index int
ncallback int
callback func() bool
Template *Message
}
@ -820,12 +823,6 @@ func (m *Message) Find(name string, root ...bool) *Message { // {{{
}
// }}}
func (m *Message) Start(name string, help string, arg ...string) bool { // {{{
return m.Set("detail", arg...).target.Spawn(m, name, help).Begin(m).Start(m)
}
// }}}
func (m *Message) Sess(key string, arg ...string) *Message { // {{{
if len(arg) > 0 {
root := true
@ -856,6 +853,12 @@ func (m *Message) Sess(key string, arg ...string) *Message { // {{{
// }}}
func (m *Message) Start(name string, help string, arg ...string) bool { // {{{
return m.Set("detail", arg...).target.Spawn(m, name, help).Begin(m).Start(m)
}
// }}}
func (m *Message) Add(meta string, key string, value ...string) *Message { // {{{
if m.Meta == nil {
m.Meta = make(map[string][]string)
@ -1211,6 +1214,8 @@ func (m *Message) Exec(key string, arg ...string) string { // {{{
m.target.Historys = make([]*Message, 0, 10)
}
m.target.Historys = append(m.target.Historys, m)
m.Back()
})
return m.Get("result")
@ -1292,6 +1297,31 @@ func (m *Message) Cmd(arg ...interface{}) *Message { // {{{
return m
}
// }}}
func (m *Message) Call(cb func() bool) { // {{{
m.callback = cb
m.message.ncallback++
m.Wait = nil
m.Cmd()
}
// }}}
func (m *Message) Back() { // {{{
if m.callback == nil {
return
}
if m.callback() {
m.callback = nil
m.message.ncallback--
}
if m.message.ncallback == 0 {
m.message.Back()
}
}
// }}}
func (m *Message) Confs(key string, arg ...bool) bool { // {{{

View File

@ -1,6 +1,6 @@
package nfs
import (
package nfs // {{{
// }}}
import ( // {{{
"context"
"bufio"
@ -13,6 +13,8 @@ import (
"strings"
)
// }}}
type NFS struct {
io io.ReadWriteCloser
*bufio.Reader
@ -26,7 +28,7 @@ type NFS struct {
*ctx.Context
}
func (nfs *NFS) print(str string, arg ...interface{}) bool {
func (nfs *NFS) print(str string, arg ...interface{}) bool { // {{{
switch {
case nfs.io != nil:
fmt.Fprintf(nfs.io, str, arg...)
@ -38,7 +40,9 @@ func (nfs *NFS) print(str string, arg ...interface{}) bool {
return true
}
func (nfs *NFS) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server {
// }}}
func (nfs *NFS) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server { // {{{
c.Caches = map[string]*ctx.Cache{
"pos": &ctx.Cache{Name: "读写位置", Value: "0", Help: "读写位置"},
"nline": &ctx.Cache{Name: "缓存命令行数", Value: "0", Help: "缓存命令行数"},
@ -67,7 +71,8 @@ func (nfs *NFS) Spawn(m *ctx.Message, c *ctx.Context, arg ...string) ctx.Server
}
func (nfs *NFS) Begin(m *ctx.Message, arg ...string) ctx.Server {
// }}}
func (nfs *NFS) Begin(m *ctx.Message, arg ...string) ctx.Server { // {{{
nfs.Context.Master(nil)
if nfs.Context == Index {
Pulse = m
@ -75,7 +80,8 @@ func (nfs *NFS) Begin(m *ctx.Message, arg ...string) ctx.Server {
return nfs
}
func (nfs *NFS) Start(m *ctx.Message, arg ...string) bool {
// }}}
func (nfs *NFS) Start(m *ctx.Message, arg ...string) bool { // {{{
if socket, ok := m.Data["io"]; ok {
nfs.io = socket.(io.ReadWriteCloser)
nfs.Reader = bufio.NewReader(nfs.io)
@ -224,7 +230,8 @@ out:
return false
}
func (nfs *NFS) Close(m *ctx.Message, arg ...string) bool {
// }}}
func (nfs *NFS) Close(m *ctx.Message, arg ...string) bool { // {{{
switch nfs.Context {
case m.Target():
if nfs.in != nil {
@ -237,6 +244,8 @@ func (nfs *NFS) Close(m *ctx.Message, arg ...string) bool {
return true
}
// }}}
var Pulse *ctx.Message
var Index = &ctx.Context{Name: "nfs", Help: "存储中心",
Caches: map[string]*ctx.Cache{
@ -304,7 +313,7 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心",
// }}}
}},
"send": &ctx.Command{Name: "send [file] args...", Help: "连接文件服务, args: 参考tcp模块, dial命令的参数", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if nfs, ok := m.Target().Server.(*NFS); m.Assert(ok) {
if nfs, ok := m.Target().Server.(*NFS); m.Assert(ok) { // {{{
if m.Has("nrecv") {
if len(arg) > 1 && arg[0] == "file" {
info, e := os.Stat(arg[1])
@ -361,10 +370,10 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心",
m.Recv = make(chan bool)
<-m.Recv
}
}
} // }}}
}},
"recv": &ctx.Command{Name: "recv [file] args...", Help: "连接文件服务, args: 参考tcp模块, dial命令的参数", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if nfs, ok := m.Target().Server.(*NFS); m.Assert(ok) {
if nfs, ok := m.Target().Server.(*NFS); m.Assert(ok) { // {{{
if m.Has("nrecv") {
if len(arg) > 1 && arg[0] == "file" {
f, e := os.Create(arg[1])
@ -404,7 +413,7 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心",
m.Recv = make(chan bool)
<-m.Recv
}
} // }}}
}},
"open": &ctx.Command{Name: "open file", Help: "打开文件, file: 文件名", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
if m.Has("io") { // {{{
@ -500,9 +509,9 @@ var Index = &ctx.Context{Name: "nfs", Help: "存储中心",
}},
"pwd": &ctx.Command{Name: "pwd", Help: "写入文件, string: 写入内容, pos: 写入位置", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) {
wd, e := os.Getwd()
wd, e := os.Getwd() // {{{
m.Assert(e)
m.Echo(wd)
m.Echo(wd) // }}}
}},
},
Index: map[string]*ctx.Context{