remove temprary function map parameter for gview when parsing template file and content

This commit is contained in:
John
2019-04-25 22:14:20 +08:00
parent d39ef156de
commit 34cb222b33
19 changed files with 152 additions and 184 deletions

View File

@ -289,6 +289,10 @@ func (l *List) RemoveAll() {
l.mu.Unlock()
}
func (l *List) Clear() {
l.RemoveAll()
}
// 读锁操作
func (l *List) RLockFunc(f func(list *list.List)) {
l.mu.RLock()

View File

@ -4,14 +4,18 @@
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
// Package gqueue provides a dynamic/static concurrent-safe(alternative) queue.
// Package gqueue provides a dynamic/static concurrent-safe queue.
//
// 并发安全动态队列.
// Features:
//
// 1. FIFO queue(data -> list -> chan);
//
// 2. Fast creation and initialization;
//
// 3. Support dynamic queue size(unlimited queue size);
//
// 4. Blocking when reading data from queue;
//
// 特点:
// 1. 动态队列初始化速度快;
// 2. 动态的队列大小(不限大小)
// 3. 取数据时如果队列为空那么会阻塞等待;
package gqueue
import (
@ -19,27 +23,21 @@ import (
"math"
)
// 1、这是一个先进先出的队列(chan <-- list)
//
// 2、当创建Queue对象时限定大小那么等同于一个同步的chan并发安全队列
//
// 3、不限制大小时list链表用以存储数据临时chan负责为客户端读取数据当从chan获取数据时list往chan中不停补充数据
//
// 4、由于功能主体是chan那么操作仍然像chan那样具有阻塞效果
type Queue struct {
limit int // 队列限制大小
list *glist.List // 底层数据链表
events chan struct{} // 写入事件通知
closed chan struct{} // 队列关闭通知
C chan interface{} // 队列数据读取
limit int // Limit for queue size.
list *glist.List // Underlying list structure for data maintaining.
events chan struct{} // Events for data writing.
closed chan struct{} // Events for queue closing.
C chan interface{} // Underlying channel for data reading.
}
const (
// 动态队列缓冲区大小
// Size for queue buffer.
gDEFAULT_QUEUE_SIZE = 10000
)
// 队列大小为非必须参数,默认不限制
// New returns a queue object.
// Param <limit> is optional and it is not limited by default.
func New(limit...int) *Queue {
q := &Queue {
closed : make(chan struct{}, 0),
@ -56,7 +54,8 @@ func New(limit...int) *Queue {
return q
}
// 异步list->chan同步队列
// startAsyncLoop starts an asynchronous goroutine,
// which handles the data synchronization from list <q.list> to channel <q.C>.
func (q *Queue) startAsyncLoop() {
for {
select {
@ -84,7 +83,8 @@ func (q *Queue) startAsyncLoop() {
}
}
// 将数据压入队列, 队尾
// Push pushes the data <v> into the queue.
// Note that it would panics if the Push method is called after the queue is closed.
func (q *Queue) Push(v interface{}) {
if q.limit > 0 {
q.C <- v
@ -94,19 +94,22 @@ func (q *Queue) Push(v interface{}) {
}
}
// 从队头先进先出地从队列取出一项数据
// Pop pops an item from the queue in FIFO way.
// Note that it would return nil immediately if the Pop method is called after the queue is closed.
func (q *Queue) Pop() interface{} {
return <- q.C
}
// 关闭队列(通知所有通过Pop*阻塞的协程退出)
// Close closes the queue.
// Notice: It would notify all goroutines exit immediately,
// which are blocked reading by Pop method).
func (q *Queue) Close() {
close(q.C)
close(q.events)
close(q.closed)
}
// 获取当前队列大小
// Size returns the length of the queue.
func (q *Queue) Size() int {
return len(q.C) + q.list.Len()
}

View File

@ -295,4 +295,10 @@ func (set *Set) Sum() (sum int) {
sum += gconv.Int(k)
}
return
}
// Join joins items with a string <glue>.
func (set *Set) Pops(size int) []interface{} {
array := make([]interface{}, 0, size)
return array
}

View File

@ -18,7 +18,6 @@ type View struct {
mu sync.RWMutex // 并发互斥锁
view *gview.View // 底层视图对象
data gview.Params // 视图数据/模板变量
fmap gview.FuncMap // 绑定的模板函数
response *ghttp.Response // 数据返回对象
}
@ -27,7 +26,6 @@ func NewView(w *ghttp.Response) *View {
return &View {
view : gins.View(),
data : make(gview.Params),
fmap : make(gview.FuncMap),
response : w,
}
}
@ -48,18 +46,11 @@ func (view *View) Assign(key string, value interface{}) {
view.mu.Unlock()
}
// 绑定自定义模板函数
func (view *View) BindFunc(name string, function interface{}){
view.mu.Lock()
view.fmap[name] = function
view.mu.Unlock()
}
// 解析模板,并返回解析后的内容
func (view *View) Parse(file string) (string, error) {
view.mu.RLock()
defer view.mu.RUnlock()
buffer, err := view.response.ParseTpl(file, view.data, view.fmap)
buffer, err := view.response.ParseTpl(file, view.data)
return buffer, err
}
@ -67,7 +58,7 @@ func (view *View) Parse(file string) (string, error) {
func (view *View) ParseContent(content string) (string, error) {
view.mu.RLock()
defer view.mu.RUnlock()
buffer, err := view.response.ParseTplContent(content, view.data, view.fmap)
buffer, err := view.response.ParseTplContent(content, view.data)
return buffer, err
}

View File

@ -13,13 +13,9 @@ import (
)
// 展示模板,可以给定模板参数,及临时的自定义模板函数
func (r *Response) WriteTpl(tpl string, params map[string]interface{}, funcMap...map[string]interface{}) error {
fmap := make(gview.FuncMap)
if len(funcMap) > 0 {
fmap = funcMap[0]
}
if b, err := r.ParseTpl(tpl, params, fmap); err != nil {
r.Write("Tpl Parsing Error: " + err.Error())
func (r *Response) WriteTpl(tpl string, params...gview.Params) error {
if b, err := r.ParseTpl(tpl, params...); err != nil {
r.Write("Template Parsing Error: " + err.Error())
return err
} else {
r.Write(b)
@ -28,13 +24,9 @@ func (r *Response) WriteTpl(tpl string, params map[string]interface{}, funcMap..
}
// 展示模板内容,可以给定模板参数,及临时的自定义模板函数
func (r *Response) WriteTplContent(content string, params map[string]interface{}, funcMap...map[string]interface{}) error {
fmap := make(gview.FuncMap)
if len(funcMap) > 0 {
fmap = funcMap[0]
}
if b, err := r.ParseTplContent(content, params, fmap); err != nil {
r.Write("Tpl Parsing Error: " + err.Error())
func (r *Response) WriteTplContent(content string, params...gview.Params) error {
if b, err := r.ParseTplContent(content, params...); err != nil {
r.Write("Template Parsing Error: " + err.Error())
return err
} else {
r.Write(b)
@ -43,61 +35,27 @@ func (r *Response) WriteTplContent(content string, params map[string]interface{}
}
// 解析模板文件,并返回模板内容
func (r *Response) ParseTpl(tpl string, params gview.Params, funcMap...map[string]interface{}) (string, error) {
m := make(gview.FuncMap)
if len(funcMap) > 0 {
m = funcMap[0]
}
return gins.View().Parse(tpl, r.buildInVars(params), r.buildInFuncs(m))
func (r *Response) ParseTpl(tpl string, params...gview.Params) (string, error) {
return gins.View().Parse(tpl, r.buildInVars(params...))
}
// 解析并返回模板内容
func (r *Response) ParseTplContent(content string, params gview.Params, funcMap...map[string]interface{}) (string, error) {
m := make(gview.FuncMap)
if len(funcMap) > 0 {
m = funcMap[0]
}
return gins.View().ParseContent(content, r.buildInVars(params), r.buildInFuncs(m))
func (r *Response) ParseTplContent(content string, params...gview.Params) (string, error) {
return gins.View().ParseContent(content, r.buildInVars(params...))
}
// 内置变量
func (r *Response) buildInVars(params map[string]interface{}) map[string]interface{} {
if params == nil {
params = make(map[string]interface{})
}
c := gins.Config()
if c.GetFilePath() != "" {
params["Config"] = c.GetMap("")
// 内置变量/对象
func (r *Response) buildInVars(params...map[string]interface{}) map[string]interface{} {
vars := map[string]interface{}(nil)
if len(params) > 0 {
vars = params[0]
} else {
params["Config"] = nil
vars = make(map[string]interface{})
}
params["Cookie"] = r.request.Cookie.Map()
params["Session"] = r.request.Session.Data()
return params
}
// 内置函数
func (r *Response) buildInFuncs(funcMap map[string]interface{}) map[string]interface{} {
if funcMap == nil {
funcMap = make(map[string]interface{})
}
funcMap["get"] = r.funcGet
funcMap["post"] = r.funcPost
funcMap["request"] = r.funcRequest
return funcMap
}
// 模板内置函数: get
func (r *Response) funcGet(key string, def...string) string {
return r.request.GetQueryString(key, def...)
}
// 模板内置函数: post
func (r *Response) funcPost(key string, def...string) string {
return r.request.GetPostString(key, def...)
}
// 模板内置函数: request
func (r *Response) funcRequest(key string, def...string) string {
return r.request.Get(key, def...)
vars["Config"] = gins.Config().GetMap("")
vars["Cookie"] = r.request.Cookie.Map()
vars["Session"] = r.request.Session.Map()
vars["Get"] = r.request.GetQueryMap()
vars["Post"] = r.request.GetPostMap()
return vars
}

View File

@ -15,7 +15,8 @@ import (
"github.com/gogf/gf/g/container/gtype"
"github.com/gogf/gf/g/os/gcache"
"github.com/gogf/gf/g/os/genv"
"github.com/gogf/gf/g/os/glog"
"github.com/gogf/gf/g/os/gfile"
"github.com/gogf/gf/g/os/glog"
"github.com/gogf/gf/g/os/gproc"
"github.com/gogf/gf/g/os/gtimer"
"github.com/gogf/gf/g/text/gregex"
@ -108,9 +109,9 @@ const (
HOOK_BEFORE_OUTPUT = "BeforeOutput"
HOOK_AFTER_OUTPUT = "AfterOutput"
// deprecated.
// Deprecated.
HOOK_BEFORE_CLOSE = "BeforeClose"
// deprecated.
// Deprecated.
HOOK_AFTER_CLOSE = "AfterClose"
HTTP_METHODS = "GET,PUT,POST,DELETE,PATCH,HEAD,CONNECT,OPTIONS,TRACE"
@ -188,10 +189,10 @@ func serverProcessInit() {
go handleProcessMessage()
}
// 是否处于开发环境
//if gfile.MainPkgPath() != "" {
// glog.Debug("GF notices that you're in develop environment, so error logs are auto enabled to stdout.")
//}
// 是否处于开发环境这里调用该方法初始化main包路径值
// 防止异步服务goroutine获取main包路径失败
// 该方法只有在main协程中才会执行。
gfile.MainPkgPath()
}
// 获取/创建一个默认配置的HTTP Server(默认监听端口是80)

View File

@ -69,7 +69,7 @@ func (s *Session) Id() string {
}
// 获取当前session所有数据
func (s *Session) Data() map[string]interface{} {
func (s *Session) Map() map[string]interface{} {
if len(s.id) > 0 || s.request.Cookie.GetSessionId() != "" {
s.init()
return s.data.Map()

View File

@ -440,10 +440,14 @@ func homeWindows() (string, error) {
// Available in develop environment.
//
// 获取入口函数文件所在目录(main包文件目录),
// **仅对源码开发环境有效(即仅对生成该可执行文件的系统下有效)**
// **仅对源码开发环境有效(即仅对生成该可执行文件的系统下有效)**
// 注意该方法被第一次调用时如果是在异步的goroutine中该方法可能无法获取到main包路径。
func MainPkgPath() string {
path := mainPkgPath.Val()
if path != "" {
if path == "-" {
return ""
}
return path
}
for i := 1; i < 10000; i++ {
@ -457,6 +461,8 @@ func MainPkgPath() string {
break
}
}
// 找不到,下次不用再检索了
mainPkgPath.Set("-")
return ""
}

View File

@ -31,7 +31,8 @@ var (
// if the template files under <path> changes (recursively).
func (view *View) getTemplate(path string, pattern string) (tpl *template.Template, err error) {
r := templates.GetOrSetFuncLock(path, func() interface {} {
files, err := gfile.ScanDir(path, pattern, true)
files := ([]string)(nil)
files, err = gfile.ScanDir(path, pattern, true)
if err != nil {
return nil
}
@ -90,7 +91,7 @@ func (view *View) searchFile(file string) (path string, folder string, err error
// ParseContent parses given template file <file>
// with given template parameters <params> and function map <funcMap>
// and returns the parsed string content.
func (view *View) Parse(file string, params map[string]interface{}, funcMap...map[string]interface{}) (parsed string, err error) {
func (view *View) Parse(file string, params...Params) (parsed string, err error) {
view.mu.RLock()
defer view.mu.RUnlock()
path, folder, err := view.searchFile(file)
@ -101,9 +102,6 @@ func (view *View) Parse(file string, params map[string]interface{}, funcMap...ma
if err != nil {
return "", err
}
if len(funcMap) > 0 {
tpl = tpl.Funcs(funcMap[0])
}
tpl, err = tpl.Parse(gfcache.GetContents(path))
if err != nil {
return "", err
@ -112,10 +110,16 @@ func (view *View) Parse(file string, params map[string]interface{}, funcMap...ma
// of the existing <params> or view.data because both variables are pointers.
// It's need to merge the values of the two maps into a new map.
vars := (map[string]interface{})(nil)
length := len(view.data)
if len(params) > 0 {
length += len(params[0])
}
if length > 0 {
vars = make(map[string]interface{}, length)
}
if len(view.data) > 0 {
if len(params) > 0 {
vars = make(map[string]interface{}, len(view.data) + len(params))
for k, v := range params {
for k, v := range params[0] {
vars[k] = v
}
for k, v := range view.data {
@ -125,7 +129,9 @@ func (view *View) Parse(file string, params map[string]interface{}, funcMap...ma
vars = view.data
}
} else {
vars = params
if len(params) > 0 {
vars = params[0]
}
}
buffer := bytes.NewBuffer(nil)
if err := tpl.Execute(buffer, vars); err != nil {
@ -137,13 +143,10 @@ func (view *View) Parse(file string, params map[string]interface{}, funcMap...ma
// ParseContent parses given template content <content>
// with given template parameters <params> and function map <funcMap>
// and returns the parsed content in []byte.
func (view *View) ParseContent(content string, params Params, funcMap...map[string]interface{}) (string, error) {
func (view *View) ParseContent(content string, params...Params) (string, error) {
view.mu.RLock()
defer view.mu.RUnlock()
tpl := template.New("").Delims(view.delimiters[0], view.delimiters[1]).Funcs(view.funcMap)
if len(funcMap) > 0 {
tpl = tpl.Funcs(funcMap[0])
}
tpl := template.New("template content").Delims(view.delimiters[0], view.delimiters[1]).Funcs(view.funcMap)
tpl, err := tpl.Parse(content)
if err != nil {
return "", err
@ -152,10 +155,16 @@ func (view *View) ParseContent(content string, params Params, funcMap...map[stri
// of the existing <params> or view.data because both variables are pointers.
// It's need to merge the values of the two maps into a new map.
vars := (map[string]interface{})(nil)
length := len(view.data)
if len(params) > 0 {
length += len(params[0])
}
if length > 0 {
vars = make(map[string]interface{}, length)
}
if len(view.data) > 0 {
if len(params) > 0 {
vars = make(map[string]interface{}, len(view.data) + len(params))
for k, v := range params {
for k, v := range params[0] {
vars[k] = v
}
for k, v := range view.data {
@ -165,7 +174,9 @@ func (view *View) ParseContent(content string, params Params, funcMap...map[stri
vars = view.data
}
} else {
vars = params
if len(params) > 0 {
vars = params[0]
}
}
buffer := bytes.NewBuffer(nil)
if err := tpl.Execute(buffer, vars); err != nil {

View File

@ -62,7 +62,7 @@ func Export(i...interface{}) string {
func PrintBacktrace() {
index := 1
buffer := bytes.NewBuffer(nil)
for i := 0; i < 10000; i++ {
for i := 1; i < 10000; i++ {
if _, path, line, ok := runtime.Caller(i); ok {
buffer.WriteString(fmt.Sprintf(`%d. %s:%d%s`, index, path, line, "\n"))
index++

View File

@ -6,13 +6,12 @@ import (
func main() {
s := ghttp.GetServer()
s.EnableAdmin()
s.BindHandler("/", func(r *ghttp.Request) {
r.Response.Writeln("您可以同时通过HTTP和HTTPS方式看到该内容")
})
s.EnableHTTPS("./server.crt", "./server.key")
s.SetHTTPSPort(8198, 8199)
s.SetPort(8200, 8300)
s.SetHTTPSPort(8100, 8200)
s.SetPort(8300, 8400)
s.EnableAdmin()
s.Run()
}

View File

@ -0,0 +1,16 @@
package main
import (
"github.com/gogf/gf/g"
"github.com/gogf/gf/g/net/ghttp"
)
func main() {
s := g.Server()
s.BindHandler("/", func(r *ghttp.Request) {
content := `{{.Request.Get "name"}}`
r.Response.WriteTplContent(content)
})
s.SetPort(8199)
s.Run()
}

View File

@ -10,8 +10,13 @@ func main() {
s.BindHandler("/", func(r *ghttp.Request) {
r.Cookie.Set("theme", "default")
r.Session.Set("name", "john")
content := `Config:{{.Config.redis.cache}}, Cookie:{{.Cookie.theme}}, Session:{{.Session.name}}`
r.Response.WriteTplContent(content, nil)
content := `
Get: {{.Get.name}}
Post: {{.Post.name}}
Config: {{.Config.redis}}
Cookie: {{.Cookie.theme}},
Session: {{.Session.name}}`
r.Response.WriteTplContent(content)
})
s.SetPort(8199)
s.Run()

View File

@ -1,6 +1,7 @@
package main
import (
"github.com/gogf/gf/g"
"github.com/gogf/gf/g/frame/gmvc"
"github.com/gogf/gf/g/net/ghttp"
)
@ -11,7 +12,7 @@ type ControllerIndex struct {
func (c *ControllerIndex) Info() {
c.View.Assign("title", "Go Frame 第一个网站")
c.View.Assigns(map[string]interface{}{
c.View.Assigns(g.Map{
"name": "很开心1",
"score": 100,
})

View File

@ -14,9 +14,6 @@ func main() {
s.SetAccessLogEnabled(true)
s.SetPort(2333)
v := g.View()
v.AddPath("template")
s.BindHandler("/", func(r *ghttp.Request) {
content, _ := gins.View().Parse("test.html", nil)
r.Response.Write(content)

View File

@ -2,14 +2,20 @@ package main
import (
"github.com/gogf/gf/g"
"github.com/gogf/gf/g/net/ghttp"
"github.com/gogf/gf/g/frame/gmvc"
)
type Controller struct {
gmvc.Controller
}
func (c *Controller) Test() {
c.View.Display("layout.html")
}
func main() {
s := g.Server()
s.BindHandler("/", func(r *ghttp.Request) {
r.Response.WriteTpl("layout.html", nil)
})
s.BindControllerMethod("/", new(Controller), "Test")
s.SetPort(8199)
s.Run()
}

View File

@ -1,52 +1,16 @@
package main
import (
"github.com/gogf/gf/g/container/gset"
"fmt"
"github.com/gogf/gf/g/os/gfile"
"time"
)
func main() {
// 创建一个非并发安全的集合对象
s := gset.New(true)
// 添加数据项
s.Add(1)
// 批量添加数据项
s.Add([]interface{}{1, 2, 3}...)
// 集合数据项大小
fmt.Println(s.Size())
// 集合中是否存在指定数据项
fmt.Println(s.Contains(2))
// 返回数据项slice
fmt.Println(s.Slice())
// 删除数据项
s.Remove(3)
// 遍历数据项
s.Iterator(func(v interface{}) bool {
fmt.Println("Iterator:", v)
return true
})
// 将集合转换为字符串
fmt.Println(s.String())
// 并发安全写锁操作
s.LockFunc(func(m map[interface{}]struct{}) {
m[4] = struct{}{}
})
// 并发安全读锁操作
s.RLockFunc(func(m map[interface{}]struct{}) {
fmt.Println(m)
})
// 清空集合
s.Clear()
fmt.Println(s.Size())
go func() {
go func() {
fmt.Println("main:", gfile.MainPkgPath())
}()
}()
time.Sleep(time.Second)
}

View File

@ -1,4 +1,4 @@
package gf
const VERSION = "v1.6.4"
const VERSION = "v1.6.5"
const AUTHORS = "john<john@goframe.org>"