diff --git a/.gitignore b/.gitignore index 482e34b1..39ae5706 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.idea .DS_Store *.swp *.swo diff --git a/.go_style b/.go_style new file mode 100644 index 00000000..26682eed --- /dev/null +++ b/.go_style @@ -0,0 +1,16 @@ +{ + "file_line": 500, + "func_line": 80, + "params_num":4, + "results_num":3, + "formated": true, + "pkg_name": true, + "camel_name":true, + "ignore":[ + "a/*", + "b/*/c/*.go" + ], + "fatal":[ + "formated" + ] +} diff --git a/README.md b/README.md index 776e5c2d..3357beef 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,7 @@ [![Build Status](https://drone.io/github.com/astaxie/beego/status.png)](https://drone.io/github.com/astaxie/beego/latest) -beego is a Go Framework inspired by tornado and sinatra. - -It is a simple & powerful web framework. +beego is an open-source, high-performance, modularity, full-stack web framework. More info [beego.me](http://beego.me) @@ -12,20 +10,18 @@ More info [beego.me](http://beego.me) * RESTful support * MVC architecture -* Session support (store in memory, file, Redis or MySQL) -* Cache support (store in memory, Redis or Memcache) -* Global Config -* Intelligent routing -* Thread-safe map -* Friendly displaying of errors -* Useful template functions - +* modularity +* auto API documents +* annotation router +* namespace +* powerful develop tools +* full stack for web & API ## Documentation [English](http://beego.me/docs/intro/) -[API](http://gowalker.org/github.com/astaxie/beego) +[API](http://godoc.org/github.com/astaxie/beego) [中文文档](http://beego.me/docs/intro/) @@ -33,7 +29,4 @@ More info [beego.me](http://beego.me) ## LICENSE beego is licensed under the Apache Licence, Version 2.0 -(http://www.apache.org/licenses/LICENSE-2.0.html). - -[![Clone in Koding](http://learn.koding.com/btn/clone_d.png)][koding] -[koding]: https://koding.com/Teamwork?import=https://github.com/astaxie/beego/archive/master.zip&c=git1 \ No newline at end of file +(http://www.apache.org/licenses/LICENSE-2.0.html). \ No newline at end of file diff --git a/admin.go b/admin.go index cfaaef72..e464a0e3 100644 --- a/admin.go +++ b/admin.go @@ -1,15 +1,25 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package beego import ( + "bytes" + "encoding/json" "fmt" "net/http" - "strconv" + "text/template" "time" "github.com/astaxie/beego/toolbox" @@ -46,7 +56,6 @@ func init() { beeAdminApp.Route("/prof", profIndex) beeAdminApp.Route("/healthcheck", healthcheck) beeAdminApp.Route("/task", taskStatus) - beeAdminApp.Route("/runtask", runTask) beeAdminApp.Route("/listconf", listConf) FilterMonitorFunc = func(string, string, time.Duration) bool { return true } } @@ -54,22 +63,24 @@ func init() { // AdminIndex is the default http.Handler for admin module. // it matches url pattern "/". func adminIndex(rw http.ResponseWriter, r *http.Request) { - rw.Write([]byte("beego admin dashboard")) - rw.Write([]byte("Welcome to Admin Dashboard
\n")) - rw.Write([]byte("There are servral functions:
\n")) - rw.Write([]byte("1. Record all request and request time, http://localhost:" + strconv.Itoa(AdminHttpPort) + "/qps
\n")) - rw.Write([]byte("2. Get runtime profiling data by the pprof, http://localhost:" + strconv.Itoa(AdminHttpPort) + "/prof
\n")) - rw.Write([]byte("3. Get healthcheck result from http://localhost:" + strconv.Itoa(AdminHttpPort) + "/healthcheck
\n")) - rw.Write([]byte("4. Get current task infomation from task http://localhost:" + strconv.Itoa(AdminHttpPort) + "/task
\n")) - rw.Write([]byte("5. To run a task passed a param http://localhost:" + strconv.Itoa(AdminHttpPort) + "/runtask
\n")) - rw.Write([]byte("6. Get all confige & router infomation http://localhost:" + strconv.Itoa(AdminHttpPort) + "/listconf
\n")) - rw.Write([]byte("")) + tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl)) + tmpl = template.Must(tmpl.Parse(indexTpl)) + tmpl = template.Must(tmpl.Parse(defaultScriptsTpl)) + data := make(map[interface{}]interface{}) + tmpl.Execute(rw, data) } // QpsIndex is the http.Handler for writing qbs statistics map result info in http.ResponseWriter. // it's registered with url pattern "/qbs" in admin module. func qpsIndex(rw http.ResponseWriter, r *http.Request) { - toolbox.StatisticsMap.GetMap(rw) + tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl)) + tmpl = template.Must(tmpl.Parse(qpsTpl)) + tmpl = template.Must(tmpl.Parse(defaultScriptsTpl)) + data := make(map[interface{}]interface{}) + data["Content"] = toolbox.StatisticsMap.GetMap() + + tmpl.Execute(rw, data) + } // ListConf is the http.Handler of displaying all beego configuration values as key/value pair. @@ -78,112 +89,220 @@ func listConf(rw http.ResponseWriter, r *http.Request) { r.ParseForm() command := r.Form.Get("command") if command != "" { + data := make(map[interface{}]interface{}) switch command { case "conf": - fmt.Fprintln(rw, "list all beego's conf:") - fmt.Fprintln(rw, "AppName:", AppName) - fmt.Fprintln(rw, "AppPath:", AppPath) - fmt.Fprintln(rw, "AppConfigPath:", AppConfigPath) - fmt.Fprintln(rw, "StaticDir:", StaticDir) - fmt.Fprintln(rw, "StaticExtensionsToGzip:", StaticExtensionsToGzip) - fmt.Fprintln(rw, "HttpAddr:", HttpAddr) - fmt.Fprintln(rw, "HttpPort:", HttpPort) - fmt.Fprintln(rw, "HttpTLS:", EnableHttpTLS) - fmt.Fprintln(rw, "HttpCertFile:", HttpCertFile) - fmt.Fprintln(rw, "HttpKeyFile:", HttpKeyFile) - fmt.Fprintln(rw, "RecoverPanic:", RecoverPanic) - fmt.Fprintln(rw, "AutoRender:", AutoRender) - fmt.Fprintln(rw, "ViewsPath:", ViewsPath) - fmt.Fprintln(rw, "RunMode:", RunMode) - fmt.Fprintln(rw, "SessionOn:", SessionOn) - fmt.Fprintln(rw, "SessionProvider:", SessionProvider) - fmt.Fprintln(rw, "SessionName:", SessionName) - fmt.Fprintln(rw, "SessionGCMaxLifetime:", SessionGCMaxLifetime) - fmt.Fprintln(rw, "SessionSavePath:", SessionSavePath) - fmt.Fprintln(rw, "SessionHashFunc:", SessionHashFunc) - fmt.Fprintln(rw, "SessionHashKey:", SessionHashKey) - fmt.Fprintln(rw, "SessionCookieLifeTime:", SessionCookieLifeTime) - fmt.Fprintln(rw, "UseFcgi:", UseFcgi) - fmt.Fprintln(rw, "MaxMemory:", MaxMemory) - fmt.Fprintln(rw, "EnableGzip:", EnableGzip) - fmt.Fprintln(rw, "DirectoryIndex:", DirectoryIndex) - fmt.Fprintln(rw, "HttpServerTimeOut:", HttpServerTimeOut) - fmt.Fprintln(rw, "ErrorsShow:", ErrorsShow) - fmt.Fprintln(rw, "XSRFKEY:", XSRFKEY) - fmt.Fprintln(rw, "EnableXSRF:", EnableXSRF) - fmt.Fprintln(rw, "XSRFExpire:", XSRFExpire) - fmt.Fprintln(rw, "CopyRequestBody:", CopyRequestBody) - fmt.Fprintln(rw, "TemplateLeft:", TemplateLeft) - fmt.Fprintln(rw, "TemplateRight:", TemplateRight) - fmt.Fprintln(rw, "BeegoServerName:", BeegoServerName) - fmt.Fprintln(rw, "EnableAdmin:", EnableAdmin) - fmt.Fprintln(rw, "AdminHttpAddr:", AdminHttpAddr) - fmt.Fprintln(rw, "AdminHttpPort:", AdminHttpPort) + m := make(map[string]interface{}) + + m["AppName"] = AppName + m["AppPath"] = AppPath + m["AppConfigPath"] = AppConfigPath + m["StaticDir"] = StaticDir + m["StaticExtensionsToGzip"] = StaticExtensionsToGzip + m["HttpAddr"] = HttpAddr + m["HttpPort"] = HttpPort + m["HttpTLS"] = EnableHttpTLS + m["HttpCertFile"] = HttpCertFile + m["HttpKeyFile"] = HttpKeyFile + m["RecoverPanic"] = RecoverPanic + m["AutoRender"] = AutoRender + m["ViewsPath"] = ViewsPath + m["RunMode"] = RunMode + m["SessionOn"] = SessionOn + m["SessionProvider"] = SessionProvider + m["SessionName"] = SessionName + m["SessionGCMaxLifetime"] = SessionGCMaxLifetime + m["SessionSavePath"] = SessionSavePath + m["SessionHashFunc"] = SessionHashFunc + m["SessionHashKey"] = SessionHashKey + m["SessionCookieLifeTime"] = SessionCookieLifeTime + m["UseFcgi"] = UseFcgi + m["MaxMemory"] = MaxMemory + m["EnableGzip"] = EnableGzip + m["DirectoryIndex"] = DirectoryIndex + m["HttpServerTimeOut"] = HttpServerTimeOut + m["ErrorsShow"] = ErrorsShow + m["XSRFKEY"] = XSRFKEY + m["EnableXSRF"] = EnableXSRF + m["XSRFExpire"] = XSRFExpire + m["CopyRequestBody"] = CopyRequestBody + m["TemplateLeft"] = TemplateLeft + m["TemplateRight"] = TemplateRight + m["BeegoServerName"] = BeegoServerName + m["EnableAdmin"] = EnableAdmin + m["AdminHttpAddr"] = AdminHttpAddr + m["AdminHttpPort"] = AdminHttpPort + + tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl)) + tmpl = template.Must(tmpl.Parse(configTpl)) + tmpl = template.Must(tmpl.Parse(defaultScriptsTpl)) + + data["Content"] = m + + tmpl.Execute(rw, data) + case "router": - fmt.Fprintln(rw, "Print all router infomation:") - for method, t := range BeeApp.Handlers.routers { - fmt.Fprintln(rw) - fmt.Fprintln(rw) - fmt.Fprintln(rw, " Method:", method) - printTree(rw, t) + resultList := new([][]string) + + var result = []string{ + fmt.Sprintf("header"), + fmt.Sprintf("Router Pattern"), + fmt.Sprintf("Methods"), + fmt.Sprintf("Controller"), } - // @todo print routers + *resultList = append(*resultList, result) + + for method, t := range BeeApp.Handlers.routers { + var result = []string{ + fmt.Sprintf("success"), + fmt.Sprintf("Method: %s", method), + fmt.Sprintf(""), + fmt.Sprintf(""), + } + *resultList = append(*resultList, result) + + printTree(resultList, t) + } + data["Content"] = resultList + data["Title"] = "Routers" + tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl)) + tmpl = template.Must(tmpl.Parse(routerAndFilterTpl)) + tmpl = template.Must(tmpl.Parse(defaultScriptsTpl)) + tmpl.Execute(rw, data) case "filter": - fmt.Fprintln(rw, "Print all filter infomation:") + resultList := new([][]string) + + var result = []string{ + fmt.Sprintf("header"), + fmt.Sprintf("Router Pattern"), + fmt.Sprintf("Filter Function"), + } + *resultList = append(*resultList, result) + if BeeApp.Handlers.enableFilter { - fmt.Fprintln(rw, "BeforeRouter:") + var result = []string{ + fmt.Sprintf("success"), + fmt.Sprintf("Before Router"), + fmt.Sprintf(""), + } + *resultList = append(*resultList, result) + if bf, ok := BeeApp.Handlers.filters[BeforeRouter]; ok { for _, f := range bf { - fmt.Fprintln(rw, f.pattern, utils.GetFuncName(f.filterFunc)) + + var result = []string{ + fmt.Sprintf(""), + fmt.Sprintf("%s", f.pattern), + fmt.Sprintf("%s", utils.GetFuncName(f.filterFunc)), + } + *resultList = append(*resultList, result) + } } - fmt.Fprintln(rw, "BeforeExec:") + result = []string{ + fmt.Sprintf("success"), + fmt.Sprintf("Before Exec"), + fmt.Sprintf(""), + } + *resultList = append(*resultList, result) if bf, ok := BeeApp.Handlers.filters[BeforeExec]; ok { for _, f := range bf { - fmt.Fprintln(rw, f.pattern, utils.GetFuncName(f.filterFunc)) + + var result = []string{ + fmt.Sprintf(""), + fmt.Sprintf("%s", f.pattern), + fmt.Sprintf("%s", utils.GetFuncName(f.filterFunc)), + } + *resultList = append(*resultList, result) + } } - fmt.Fprintln(rw, "AfterExec:") + result = []string{ + fmt.Sprintf("success"), + fmt.Sprintf("AfterExec Exec"), + fmt.Sprintf(""), + } + *resultList = append(*resultList, result) + if bf, ok := BeeApp.Handlers.filters[AfterExec]; ok { for _, f := range bf { - fmt.Fprintln(rw, f.pattern, utils.GetFuncName(f.filterFunc)) + + var result = []string{ + fmt.Sprintf(""), + fmt.Sprintf("%s", f.pattern), + fmt.Sprintf("%s", utils.GetFuncName(f.filterFunc)), + } + *resultList = append(*resultList, result) + } } - fmt.Fprintln(rw, "FinishRouter:") + result = []string{ + fmt.Sprintf("success"), + fmt.Sprintf("Finish Router"), + fmt.Sprintf(""), + } + *resultList = append(*resultList, result) + if bf, ok := BeeApp.Handlers.filters[FinishRouter]; ok { for _, f := range bf { - fmt.Fprintln(rw, f.pattern, utils.GetFuncName(f.filterFunc)) + + var result = []string{ + fmt.Sprintf(""), + fmt.Sprintf("%s", f.pattern), + fmt.Sprintf("%s", utils.GetFuncName(f.filterFunc)), + } + *resultList = append(*resultList, result) + } } } + data["Content"] = resultList + data["Title"] = "Filters" + tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl)) + tmpl = template.Must(tmpl.Parse(routerAndFilterTpl)) + tmpl = template.Must(tmpl.Parse(defaultScriptsTpl)) + tmpl.Execute(rw, data) + default: rw.Write([]byte("command not support")) } } else { - rw.Write([]byte("beego admin dashboard")) - rw.Write([]byte("ListConf support this command:
\n")) - rw.Write([]byte("1. command=conf
\n")) - rw.Write([]byte("2. command=router
\n")) - rw.Write([]byte("3. command=filter
\n")) - rw.Write([]byte("")) } } -func printTree(rw http.ResponseWriter, t *Tree) { +func printTree(resultList *[][]string, t *Tree) { for _, tr := range t.fixrouters { - printTree(rw, tr) + printTree(resultList, tr) } if t.wildcard != nil { - printTree(rw, t.wildcard) + printTree(resultList, t.wildcard) } for _, l := range t.leaves { if v, ok := l.runObject.(*controllerInfo); ok { if v.routerType == routerTypeBeego { - fmt.Fprintln(rw, v.pattern, v.methods, v.controllerType.Name()) + var result = []string{ + fmt.Sprintf(""), + fmt.Sprintf("%s", v.pattern), + fmt.Sprintf("%s", v.methods), + fmt.Sprintf("%s", v.controllerType), + } + *resultList = append(*resultList, result) } else if v.routerType == routerTypeRESTFul { - fmt.Fprintln(rw, v.pattern, v.methods) + var result = []string{ + fmt.Sprintf(""), + fmt.Sprintf("%s", v.pattern), + fmt.Sprintf("%s", v.methods), + fmt.Sprintf(""), + } + *resultList = append(*resultList, result) } else if v.routerType == routerTypeHandler { - fmt.Fprintln(rw, v.pattern, "handler") + var result = []string{ + fmt.Sprintf(""), + fmt.Sprintf("%s", v.pattern), + fmt.Sprintf(""), + fmt.Sprintf(""), + } + *resultList = append(*resultList, result) } } } @@ -194,58 +313,127 @@ func printTree(rw http.ResponseWriter, t *Tree) { func profIndex(rw http.ResponseWriter, r *http.Request) { r.ParseForm() command := r.Form.Get("command") + format := r.Form.Get("format") + data := make(map[string]interface{}) + + var result bytes.Buffer if command != "" { - toolbox.ProcessInput(command, rw) + toolbox.ProcessInput(command, &result) + data["Content"] = result.String() + + if format == "json" && command == "gc summary" { + dataJson, err := json.Marshal(data) + if err != nil { + http.Error(rw, err.Error(), http.StatusInternalServerError) + return + } + + rw.Header().Set("Content-Type", "application/json") + rw.Write(dataJson) + return + } + + data["Title"] = command + tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl)) + tmpl = template.Must(tmpl.Parse(profillingTpl)) + if command == "gc summary" { + tmpl = template.Must(tmpl.Parse(gcAjaxTpl)) + } else { + + tmpl = template.Must(tmpl.Parse(defaultScriptsTpl)) + } + tmpl.Execute(rw, data) } else { - rw.Write([]byte("beego admin dashboard")) - rw.Write([]byte("request url like '/prof?command=lookup goroutine'
\n")) - rw.Write([]byte("the command have below types:
\n")) - rw.Write([]byte("1. lookup goroutine
\n")) - rw.Write([]byte("2. lookup heap
\n")) - rw.Write([]byte("3. lookup threadcreate
\n")) - rw.Write([]byte("4. lookup block
\n")) - rw.Write([]byte("5. start cpuprof
\n")) - rw.Write([]byte("6. stop cpuprof
\n")) - rw.Write([]byte("7. get memprof
\n")) - rw.Write([]byte("8. gc summary
\n")) - rw.Write([]byte("")) } } // Healthcheck is a http.Handler calling health checking and showing the result. // it's in "/healthcheck" pattern in admin module. func healthcheck(rw http.ResponseWriter, req *http.Request) { + data := make(map[interface{}]interface{}) + + resultList := new([][]string) + var result = []string{ + fmt.Sprintf("header"), + fmt.Sprintf("Name"), + fmt.Sprintf("Status"), + } + *resultList = append(*resultList, result) + for name, h := range toolbox.AdminCheckList { if err := h.Check(); err != nil { - fmt.Fprintf(rw, "%s : %s\n", name, err.Error()) + result = []string{ + fmt.Sprintf("error"), + fmt.Sprintf("%s", name), + fmt.Sprintf("%s", err.Error()), + } + } else { - fmt.Fprintf(rw, "%s : ok\n", name) + result = []string{ + fmt.Sprintf("success"), + fmt.Sprintf("%s", name), + fmt.Sprintf("OK"), + } + } + *resultList = append(*resultList, result) } + + data["Content"] = resultList + data["Title"] = "Health Check" + tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl)) + tmpl = template.Must(tmpl.Parse(healthCheckTpl)) + tmpl = template.Must(tmpl.Parse(defaultScriptsTpl)) + tmpl.Execute(rw, data) + } // TaskStatus is a http.Handler with running task status (task name, status and the last execution). // it's in "/task" pattern in admin module. func taskStatus(rw http.ResponseWriter, req *http.Request) { - for tname, tk := range toolbox.AdminTaskList { - fmt.Fprintf(rw, "%s:%s:%s", tname, tk.GetStatus(), tk.GetPrev().String()) - } -} + data := make(map[interface{}]interface{}) -// RunTask is a http.Handler to run a Task from the "query string. -// the request url likes /runtask?taskname=sendmail. -func runTask(rw http.ResponseWriter, req *http.Request) { + // Run Task req.ParseForm() taskname := req.Form.Get("taskname") - if t, ok := toolbox.AdminTaskList[taskname]; ok { - err := t.Run() - if err != nil { - fmt.Fprintf(rw, "%v", err) + if taskname != "" { + + if t, ok := toolbox.AdminTaskList[taskname]; ok { + err := t.Run() + if err != nil { + data["Message"] = []string{"error", fmt.Sprintf("%s", err)} + } + data["Message"] = []string{"success", fmt.Sprintf("%s run success,Now the Status is %s", taskname, t.GetStatus())} + } else { + data["Message"] = []string{"warning", fmt.Sprintf("there's no task which named: %s", taskname)} } - fmt.Fprintf(rw, "%s run success,Now the Status is %s", taskname, t.GetStatus()) - } else { - fmt.Fprintf(rw, "there's no task which named:%s", taskname) } + + // List Tasks + resultList := new([][]string) + var result = []string{ + fmt.Sprintf("header"), + fmt.Sprintf("Task Name"), + fmt.Sprintf("Task Spec"), + fmt.Sprintf("Task Function"), + } + *resultList = append(*resultList, result) + for tname, tk := range toolbox.AdminTaskList { + result = []string{ + fmt.Sprintf(""), + fmt.Sprintf("%s", tname), + fmt.Sprintf("%s", tk.GetStatus()), + fmt.Sprintf("%s", tk.GetPrev().String()), + } + *resultList = append(*resultList, result) + } + + data["Content"] = resultList + data["Title"] = "Tasks" + tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl)) + tmpl = template.Must(tmpl.Parse(tasksTpl)) + tmpl = template.Must(tmpl.Parse(defaultScriptsTpl)) + tmpl.Execute(rw, data) } // adminApp is an http.HandlerFunc map used as beeAdminApp. diff --git a/adminui.go b/adminui.go new file mode 100644 index 00000000..0c82775e --- /dev/null +++ b/adminui.go @@ -0,0 +1,345 @@ +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package beego + +var indexTpl = ` +{{define "content"}} +

Beego Admin Dashboard

+

+For detail usage please check our document: +

+

+Toolbox +

+

+Live Monitor +

+{{.Content}} +{{end}}` + +var profillingTpl = ` +{{define "content"}} +

{{.Title}}

+
+
{{.Content}}
+
+{{end}}` + +var defaultScriptsTpl = `` + +var gcAjaxTpl = ` +{{define "scripts"}} + +{{end}} +` + +var qpsTpl = ` +{{define "content"}} +

Requests statistics

+ +{{range $i, $slice := .Content}} + +{{range $j, $elem := $slice}} +{{if eq $i 0}} + +{{end}} +{{end}} + + +{{end}} +
+{{else}} + +{{end}} +{{$elem}} +{{if eq $i 0}} + +{{else}} +
+{{end}} +` + +var configTpl = ` +{{define "content"}} +

Configurations

+
+{{range $index, $elem := .Content}}
+{{$index}}={{$elem}}
+{{end}}
+
+{{end}} +` + +var routerAndFilterTpl = ` +{{define "content"}} + +

{{.Title}}

+ +{{range $i, $slice := .Content}} + + +{{ $header := index $slice 0}} +{{if eq "header" $header }} + {{range $j, $elem := $slice}} + {{if ne $j 0}} + + {{end}} + {{end}} +{{else if eq "success" $header}} + {{range $j, $elem := $slice}} + {{if ne $j 0}} + + {{end}} + {{end}} +{{else}} + {{range $j, $elem := $slice}} + {{if ne $j 0}} + + {{end}} + {{end}} +{{end}} + + +{{end}} +
+ {{$elem}} + + {{$elem}} + + {{$elem}} +
+{{end}} +` + +var tasksTpl = ` +{{define "content"}} + +

{{.Title}}

+ +{{if .Message }} +{{ $messageType := index .Message 0}} +

+{{index .Message 1}} +

+{{end}} + + + +{{range $i, $slice := .Content}} + + +{{ $header := index $slice 0}} +{{if eq "header" $header }} + {{range $j, $elem := $slice}} + {{if ne $j 0}} + + {{end}} + {{end}} + +{{else}} + {{range $j, $elem := $slice}} + {{if ne $j 0}} + + {{end}} + {{end}} + +{{end}} + + +{{end}} +
+ {{$elem}} + + Run Task + + {{$elem}} + + Run +
+{{end}} +` + +var healthCheckTpl = ` +{{define "content"}} + +

{{.Title}}

+ +{{range $i, $slice := .Content}} + +{{ $header := index $slice 0}} +{{if eq "header" $header }} + + {{range $j, $elem := $slice}} + {{if ne $j 0}} + + {{end}} + {{end}} + +{{else}} + {{ if eq "success" $header}} + + {{else if eq "error" $header}} + + {{else}} + + {{end}} + {{range $j, $elem := $slice}} + {{if ne $j 0}} + + {{end}} + {{end}} + +{{end}} + +{{end}} +
+ {{$elem}} +
+ {{$elem}} +
+{{end}}` + +// The base dashboardTpl +var dashboardTpl = ` + + + + + + + + + + +Welcome to Beego Admin Dashboard + + + + + + + + + + + + +
+{{template "content" .}} +
+ + + + +{{template "scripts" .}} + + +` diff --git a/app.go b/app.go index 26e565c5..f1706616 100644 --- a/app.go +++ b/app.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package beego @@ -66,6 +74,7 @@ func (app *App) Run() { if EnableHttpTLS { go func() { + time.Sleep(20 * time.Microsecond) if HttpsPort != 0 { app.Server.Addr = fmt.Sprintf("%s:%d", HttpAddr, HttpsPort) } @@ -80,6 +89,7 @@ func (app *App) Run() { if EnableHttpListen { go func() { + app.Server.Addr = addr err := app.Server.ListenAndServe() if err != nil { BeeLogger.Critical("ListenAndServe: ", err) diff --git a/beego.go b/beego.go index d230d998..46499743 100644 --- a/beego.go +++ b/beego.go @@ -1,9 +1,28 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// beego is an open-source, high-performance, modularity, full-stack web framework +// +// package main +// +// import "github.com/astaxie/beego" +// +// func main() { +// beego.Run() +// } +// +// more infomation: http://beego.me package beego import ( @@ -19,7 +38,7 @@ import ( ) // beego web framework version. -const VERSION = "1.3.1" +const VERSION = "1.4.0" type hookfunc func() error //hook function to run var hooks []hookfunc //hook function slice to store the hookfunc @@ -359,6 +378,7 @@ func initBeforeHttpRun() { `"sessionIDHashFunc":"` + SessionHashFunc + `",` + `"sessionIDHashKey":"` + SessionHashKey + `",` + `"enableSetCookie":` + strconv.FormatBool(SessionAutoSetCookie) + `,` + + `"domain":"` + SessionDomain + `",` + `"cookieLifeTime":` + strconv.Itoa(SessionCookieLifeTime) + `}` } GlobalSessions, err = session.NewManager(SessionProvider, @@ -380,14 +400,13 @@ func initBeforeHttpRun() { middleware.AppName = AppName middleware.RegisterErrorHandler() - for u, _ := range StaticDir { - Get(u, serverStaticRouter) - Get(u+"/*", serverStaticRouter) - } if EnableDocs { Get("/docs", serverDocs) Get("/docs/*", serverDocs) } + + //init mime + AddAPPStartHook(initMime) } // this function is for test package init @@ -406,6 +425,4 @@ func TestBeegoInit(apppath string) { func init() { hooks = make([]hookfunc, 0) - //init mime - AddAPPStartHook(initMime) } diff --git a/cache/README.md b/cache/README.md index c0bfcc59..72d0d1c5 100644 --- a/cache/README.md +++ b/cache/README.md @@ -22,7 +22,7 @@ First you must import it Then init a Cache (example with memory adapter) - bm, err := NewCache("memory", `{"interval":60}`) + bm, err := cache.NewCache("memory", `{"interval":60}`) Use it like this: diff --git a/cache/cache.go b/cache/cache.go index 3273e2f9..d4ad5d59 100644 --- a/cache/cache.go +++ b/cache/cache.go @@ -1,9 +1,33 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// Usage: +// +// import( +// "github.com/astaxie/beego/cache" +// ) +// +// bm, err := cache.NewCache("memory", `{"interval":60}`) +// +// Use it like this: +// +// bm.Put("astaxie", 1, 10) +// bm.Get("astaxie") +// bm.IsExist("astaxie") +// bm.Delete("astaxie") +// +// more docs http://beego.me/docs/module/cache.md package cache import ( @@ -13,7 +37,7 @@ import ( // Cache interface contains all behaviors for cache adapter. // usage: // cache.Register("file",cache.NewFileCache()) // this operation is run in init method of file.go. -// c := cache.NewCache("file","{....}") +// c,err := cache.NewCache("file","{....}") // c.Put("key",value,3600) // v := c.Get("key") // @@ -31,11 +55,11 @@ type Cache interface { Incr(key string) error // decrease cached int value by key, as a counter. Decr(key string) error - // check cached value is existed or not. + // check if cached value exists or not. IsExist(key string) bool // clear all cache. ClearAll() error - // start gc routine via config string setting. + // start gc routine based on config string settings. StartAndGC(config string) error } @@ -48,23 +72,24 @@ func Register(name string, adapter Cache) { if adapter == nil { panic("cache: Register adapter is nil") } - if _, dup := adapters[name]; dup { + if _, ok := adapters[name]; ok { panic("cache: Register called twice for adapter " + name) } adapters[name] = adapter } -// Create a new cache driver by adapter and config string. +// Create a new cache driver by adapter name and config string. // config need to be correct JSON as string: {"interval":360}. // it will start gc automatically. -func NewCache(adapterName, config string) (Cache, error) { +func NewCache(adapterName, config string) (adapter Cache, e error) { adapter, ok := adapters[adapterName] if !ok { - return nil, fmt.Errorf("cache: unknown adaptername %q (forgotten import?)", adapterName) + e = fmt.Errorf("cache: unknown adapter name %q (forgot to import?)", adapterName) + return } err := adapter.StartAndGC(config) if err != nil { - return nil, err + adapter = nil } - return adapter, nil + return } diff --git a/cache/cache_test.go b/cache/cache_test.go index 263ad257..bf9e79c2 100644 --- a/cache/cache_test.go +++ b/cache/cache_test.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package cache diff --git a/cache/conv.go b/cache/conv.go index 00cbdd24..724abfd2 100644 --- a/cache/conv.go +++ b/cache/conv.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package cache @@ -19,12 +27,11 @@ func GetString(v interface{}) string { case []byte: return string(result) default: - if v == nil { - return "" - } else { + if v != nil { return fmt.Sprintf("%v", result) } } + return "" } // convert interface to int. @@ -37,12 +44,9 @@ func GetInt(v interface{}) int { case int64: return int(result) default: - d := GetString(v) - if d != "" { - value, err := strconv.Atoi(d) - if err == nil { - return value - } + if d := GetString(v); d != "" { + value, _ := strconv.Atoi(d) + return value } } return 0 @@ -58,12 +62,10 @@ func GetInt64(v interface{}) int64 { case int64: return result default: - d := GetString(v) - if d != "" { - result, err := strconv.ParseInt(d, 10, 64) - if err == nil { - return result - } + + if d := GetString(v); d != "" { + value, _ := strconv.ParseInt(d, 10, 64) + return value } } return 0 @@ -75,12 +77,9 @@ func GetFloat64(v interface{}) float64 { case float64: return result default: - d := GetString(v) - if d != "" { - value, err := strconv.ParseFloat(d, 64) - if err == nil { - return value - } + if d := GetString(v); d != "" { + value, _ := strconv.ParseFloat(d, 64) + return value } } return 0 @@ -92,12 +91,9 @@ func GetBool(v interface{}) bool { case bool: return result default: - d := GetString(v) - if d != "" { - result, err := strconv.ParseBool(d) - if err == nil { - return result - } + if d := GetString(v); d != "" { + value, _ := strconv.ParseBool(d) + return value } } return false diff --git a/cache/conv_test.go b/cache/conv_test.go index 82d73af7..267bb0c9 100644 --- a/cache/conv_test.go +++ b/cache/conv_test.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package cache diff --git a/cache/file.go b/cache/file.go index 7178aa20..6ecf6568 100644 --- a/cache/file.go +++ b/cache/file.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package cache @@ -57,12 +65,10 @@ func NewFileCache() *FileCache { // Start and begin gc for file cache. // the config need to be like {CachePath:"/cache","FileSuffix":".bin","DirectoryLevel":2,"EmbedExpiry":0} -func (this *FileCache) StartAndGC(config string) error { +func (fc *FileCache) StartAndGC(config string) error { var cfg map[string]string json.Unmarshal([]byte(config), &cfg) - //fmt.Println(cfg) - //fmt.Println(config) if _, ok := cfg["CachePath"]; !ok { cfg["CachePath"] = FileCachePath } @@ -75,69 +81,53 @@ func (this *FileCache) StartAndGC(config string) error { if _, ok := cfg["EmbedExpiry"]; !ok { cfg["EmbedExpiry"] = strconv.FormatInt(FileCacheEmbedExpiry, 10) } - this.CachePath = cfg["CachePath"] - this.FileSuffix = cfg["FileSuffix"] - this.DirectoryLevel, _ = strconv.Atoi(cfg["DirectoryLevel"]) - this.EmbedExpiry, _ = strconv.Atoi(cfg["EmbedExpiry"]) + fc.CachePath = cfg["CachePath"] + fc.FileSuffix = cfg["FileSuffix"] + fc.DirectoryLevel, _ = strconv.Atoi(cfg["DirectoryLevel"]) + fc.EmbedExpiry, _ = strconv.Atoi(cfg["EmbedExpiry"]) - this.Init() + fc.Init() return nil } // Init will make new dir for file cache if not exist. -func (this *FileCache) Init() { +func (fc *FileCache) Init() { app := filepath.Dir(os.Args[0]) - this.CachePath = filepath.Join(app, this.CachePath) - ok, err := exists(this.CachePath) - if err != nil { // print error - //fmt.Println(err) + fc.CachePath = filepath.Join(app, fc.CachePath) + if ok, _ := exists(fc.CachePath); !ok { // todo : error handle + _ = os.MkdirAll(fc.CachePath, os.ModePerm) // todo : error handle } - if !ok { - if err = os.Mkdir(this.CachePath, os.ModePerm); err != nil { - //fmt.Println(err); - } - } - //fmt.Println(this.getCacheFileName("123456")); } // get cached file name. it's md5 encoded. -func (this *FileCache) getCacheFileName(key string) string { +func (fc *FileCache) getCacheFileName(key string) string { m := md5.New() io.WriteString(m, key) keyMd5 := hex.EncodeToString(m.Sum(nil)) - cachePath := this.CachePath - //fmt.Println("cachepath : " , cachePath) - //fmt.Println("md5" , keyMd5); - switch this.DirectoryLevel { + cachePath := fc.CachePath + switch fc.DirectoryLevel { case 2: cachePath = filepath.Join(cachePath, keyMd5[0:2], keyMd5[2:4]) case 1: cachePath = filepath.Join(cachePath, keyMd5[0:2]) } - ok, err := exists(cachePath) - if err != nil { - //fmt.Println(err) + if ok, _ := exists(cachePath); !ok { // todo : error handle + _ = os.MkdirAll(cachePath, os.ModePerm) // todo : error handle } - if !ok { - if err = os.MkdirAll(cachePath, os.ModePerm); err != nil { - //fmt.Println(err); - } - } - return filepath.Join(cachePath, fmt.Sprintf("%s%s", keyMd5, this.FileSuffix)) + + return filepath.Join(cachePath, fmt.Sprintf("%s%s", keyMd5, fc.FileSuffix)) } // Get value from file cache. // if non-exist or expired, return empty string. -func (this *FileCache) Get(key string) interface{} { - filename := this.getCacheFileName(key) - filedata, err := File_get_contents(filename) - //fmt.Println("get length:" , len(filedata)); +func (fc *FileCache) Get(key string) interface{} { + fileData, err := File_get_contents(fc.getCacheFileName(key)) if err != nil { return "" } var to FileCacheItem - Gob_decode(filedata, &to) + Gob_decode(fileData, &to) if to.Expired < time.Now().Unix() { return "" } @@ -147,12 +137,10 @@ func (this *FileCache) Get(key string) interface{} { // Put value into file cache. // timeout means how long to keep this file, unit of ms. // if timeout equals FileCacheEmbedExpiry(default is 0), cache this item forever. -func (this *FileCache) Put(key string, val interface{}, timeout int64) error { +func (fc *FileCache) Put(key string, val interface{}, timeout int64) error { gob.Register(val) - filename := this.getCacheFileName(key) - var item FileCacheItem - item.Data = val + item := FileCacheItem{Data: val} if timeout == FileCacheEmbedExpiry { item.Expired = time.Now().Unix() + (86400 * 365 * 10) // ten years } else { @@ -163,13 +151,12 @@ func (this *FileCache) Put(key string, val interface{}, timeout int64) error { if err != nil { return err } - err = File_put_contents(filename, data) - return err + return File_put_contents(fc.getCacheFileName(key), data) } // Delete file cache value. -func (this *FileCache) Delete(key string) error { - filename := this.getCacheFileName(key) +func (fc *FileCache) Delete(key string) error { + filename := fc.getCacheFileName(key) if ok, _ := exists(filename); ok { return os.Remove(filename) } @@ -177,44 +164,41 @@ func (this *FileCache) Delete(key string) error { } // Increase cached int value. -// this value is saving forever unless Delete. -func (this *FileCache) Incr(key string) error { - data := this.Get(key) +// fc value is saving forever unless Delete. +func (fc *FileCache) Incr(key string) error { + data := fc.Get(key) var incr int - //fmt.Println(reflect.TypeOf(data).Name()) if reflect.TypeOf(data).Name() != "int" { incr = 0 } else { incr = data.(int) + 1 } - this.Put(key, incr, FileCacheEmbedExpiry) + fc.Put(key, incr, FileCacheEmbedExpiry) return nil } // Decrease cached int value. -func (this *FileCache) Decr(key string) error { - data := this.Get(key) +func (fc *FileCache) Decr(key string) error { + data := fc.Get(key) var decr int if reflect.TypeOf(data).Name() != "int" || data.(int)-1 <= 0 { decr = 0 } else { decr = data.(int) - 1 } - this.Put(key, decr, FileCacheEmbedExpiry) + fc.Put(key, decr, FileCacheEmbedExpiry) return nil } // Check value is exist. -func (this *FileCache) IsExist(key string) bool { - filename := this.getCacheFileName(key) - ret, _ := exists(filename) +func (fc *FileCache) IsExist(key string) bool { + ret, _ := exists(fc.getCacheFileName(key)) return ret } // Clean cached files. // not implemented. -func (this *FileCache) ClearAll() error { - //this.CachePath +func (fc *FileCache) ClearAll() error { return nil } @@ -232,22 +216,22 @@ func exists(path string) (bool, error) { // Get bytes to file. // if non-exist, create this file. -func File_get_contents(filename string) ([]byte, error) { - f, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, os.ModePerm) - if err != nil { - return []byte(""), err +func File_get_contents(filename string) (data []byte, e error) { + f, e := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, os.ModePerm) + if e != nil { + return } defer f.Close() - stat, err := f.Stat() - if err != nil { - return []byte(""), err + stat, e := f.Stat() + if e != nil { + return } - data := make([]byte, stat.Size()) - result, err := f.Read(data) - if int64(result) == stat.Size() { - return data, err + data = make([]byte, stat.Size()) + result, e := f.Read(data) + if e != nil || int64(result) != stat.Size() { + return nil, e } - return []byte(""), err + return } // Put bytes to file. diff --git a/cache/memcache/memcache.go b/cache/memcache/memcache.go index 37658ffe..f5a5c6ef 100644 --- a/cache/memcache/memcache.go +++ b/cache/memcache/memcache.go @@ -1,24 +1,48 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -package cache +// package memcahe for cache provider +// +// depend on github.com/bradfitz/gomemcache/memcache +// +// go install github.com/bradfitz/gomemcache/memcache +// +// Usage: +// import( +// _ "github.com/astaxie/beego/cache/memcache" +// "github.com/astaxie/beego/cache" +// ) +// +// bm, err := cache.NewCache("memcache", `{"conn":"127.0.0.1:11211"}`) +// +// more docs http://beego.me/docs/module/cache.md +package memcache import ( "encoding/json" "errors" + "strings" - "github.com/beego/memcache" + "github.com/bradfitz/gomemcache/memcache" "github.com/astaxie/beego/cache" ) // Memcache adapter. type MemcacheCache struct { - c *memcache.Connection - conninfo string + conn *memcache.Client + conninfo []string } // create new memcache adapter. @@ -28,32 +52,21 @@ func NewMemCache() *MemcacheCache { // get value from memcache. func (rc *MemcacheCache) Get(key string) interface{} { - if rc.c == nil { - var err error - rc.c, err = rc.connectInit() - if err != nil { + if rc.conn == nil { + if err := rc.connectInit(); err != nil { return err } } - v, err := rc.c.Get(key) - if err != nil { - return nil + if item, err := rc.conn.Get(key); err == nil { + return string(item.Value) } - var contain interface{} - if len(v) > 0 { - contain = string(v[0].Value) - } else { - contain = nil - } - return contain + return nil } // put value to memcache. only support string. func (rc *MemcacheCache) Put(key string, val interface{}, timeout int64) error { - if rc.c == nil { - var err error - rc.c, err = rc.connectInit() - if err != nil { + if rc.conn == nil { + if err := rc.connectInit(); err != nil { return err } } @@ -61,69 +74,64 @@ func (rc *MemcacheCache) Put(key string, val interface{}, timeout int64) error { if !ok { return errors.New("val must string") } - stored, err := rc.c.Set(key, 0, uint64(timeout), []byte(v)) - if err == nil && stored == false { - return errors.New("stored fail") - } - return err + item := memcache.Item{Key: key, Value: []byte(v), Expiration: int32(timeout)} + return rc.conn.Set(&item) } // delete value in memcache. func (rc *MemcacheCache) Delete(key string) error { - if rc.c == nil { - var err error - rc.c, err = rc.connectInit() - if err != nil { + if rc.conn == nil { + if err := rc.connectInit(); err != nil { return err } } - _, err := rc.c.Delete(key) + return rc.conn.Delete(key) +} + +// increase counter. +func (rc *MemcacheCache) Incr(key string) error { + if rc.conn == nil { + if err := rc.connectInit(); err != nil { + return err + } + } + _, err := rc.conn.Increment(key, 1) return err } -// [Not Support] -// increase counter. -func (rc *MemcacheCache) Incr(key string) error { - return errors.New("not support in memcache") -} - -// [Not Support] // decrease counter. func (rc *MemcacheCache) Decr(key string) error { - return errors.New("not support in memcache") + if rc.conn == nil { + if err := rc.connectInit(); err != nil { + return err + } + } + _, err := rc.conn.Decrement(key, 1) + return err } // check value exists in memcache. func (rc *MemcacheCache) IsExist(key string) bool { - if rc.c == nil { - var err error - rc.c, err = rc.connectInit() - if err != nil { + if rc.conn == nil { + if err := rc.connectInit(); err != nil { return false } } - v, err := rc.c.Get(key) + _, err := rc.conn.Get(key) if err != nil { return false } - if len(v) == 0 { - return false - } else { - return true - } + return true } // clear all cached in memcache. func (rc *MemcacheCache) ClearAll() error { - if rc.c == nil { - var err error - rc.c, err = rc.connectInit() - if err != nil { + if rc.conn == nil { + if err := rc.connectInit(); err != nil { return err } } - err := rc.c.FlushAll() - return err + return rc.conn.FlushAll() } // start memcache adapter. @@ -135,24 +143,19 @@ func (rc *MemcacheCache) StartAndGC(config string) error { if _, ok := cf["conn"]; !ok { return errors.New("config has no conn key") } - rc.conninfo = cf["conn"] - var err error - if rc.c != nil { - rc.c, err = rc.connectInit() - if err != nil { - return errors.New("dial tcp conn error") + rc.conninfo = strings.Split(cf["conn"], ";") + if rc.conn == nil { + if err := rc.connectInit(); err != nil { + return err } } return nil } // connect to memcache and keep the connection. -func (rc *MemcacheCache) connectInit() (*memcache.Connection, error) { - c, err := memcache.Connect(rc.conninfo) - if err != nil { - return nil, err - } - return c, nil +func (rc *MemcacheCache) connectInit() error { + rc.conn = memcache.New(rc.conninfo...) + return nil } func init() { diff --git a/cache/memory.go b/cache/memory.go index 2d2f3803..b90d227c 100644 --- a/cache/memory.go +++ b/cache/memory.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package cache @@ -46,15 +54,14 @@ func NewMemoryCache() *MemoryCache { func (bc *MemoryCache) Get(name string) interface{} { bc.lock.RLock() defer bc.lock.RUnlock() - itm, ok := bc.items[name] - if !ok { - return nil + if itm, ok := bc.items[name]; ok { + if (time.Now().Unix() - itm.Lastaccess.Unix()) > itm.expired { + go bc.Delete(name) + return nil + } + return itm.val } - if (time.Now().Unix() - itm.Lastaccess.Unix()) > itm.expired { - go bc.Delete(name) - return nil - } - return itm.val + return nil } // Put cache to memory. @@ -62,12 +69,11 @@ func (bc *MemoryCache) Get(name string) interface{} { func (bc *MemoryCache) Put(name string, value interface{}, expired int64) error { bc.lock.Lock() defer bc.lock.Unlock() - t := MemoryItem{ + bc.items[name] = &MemoryItem{ val: value, Lastaccess: time.Now(), expired: expired, } - bc.items[name] = &t return nil } @@ -79,8 +85,7 @@ func (bc *MemoryCache) Delete(name string) error { return errors.New("key not exist") } delete(bc.items, name) - _, valid := bc.items[name] - if valid { + if _, ok := bc.items[name]; ok { return errors.New("delete key error") } return nil @@ -211,8 +216,7 @@ func (bc *MemoryCache) item_expired(name string) bool { if !ok { return true } - sec := time.Now().Unix() - itm.Lastaccess.Unix() - if sec >= itm.expired { + if time.Now().Unix()-itm.Lastaccess.Unix() >= itm.expired { delete(bc.items, name) return true } diff --git a/cache/redis/redis.go b/cache/redis/redis.go index 451166a3..35cf88cd 100644 --- a/cache/redis/redis.go +++ b/cache/redis/redis.go @@ -1,17 +1,40 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -package cache +// package redis for cache provider +// +// depend on github.com/garyburd/redigo/redis +// +// go install github.com/garyburd/redigo/redis +// +// Usage: +// import( +// _ "github.com/astaxie/beego/cache/redis" +// "github.com/astaxie/beego/cache" +// ) +// +// bm, err := cache.NewCache("redis", `{"conn":"127.0.0.1:11211"}`) +// +// more docs http://beego.me/docs/module/cache.md +package redis import ( "encoding/json" "errors" "time" - "github.com/beego/redigo/redis" + "github.com/garyburd/redigo/redis" "github.com/astaxie/beego/cache" ) @@ -43,52 +66,74 @@ func (rc *RedisCache) do(commandName string, args ...interface{}) (reply interfa // Get cache from redis. func (rc *RedisCache) Get(key string) interface{} { - v, err := rc.do("HGET", rc.key, key) - if err != nil { - return nil + if v, err := rc.do("GET", key); err == nil { + return v } - - return v + return nil } // put cache to redis. -// timeout is ignored. func (rc *RedisCache) Put(key string, val interface{}, timeout int64) error { - _, err := rc.do("HSET", rc.key, key, val) + var err error + if _, err = rc.do("SET", key, val); err != nil { + return err + } + + if _, err = rc.do("HSET", rc.key, key, true); err != nil { + return err + } + _, err = rc.do("EXPIRE", key, timeout) return err } // delete cache in redis. func (rc *RedisCache) Delete(key string) error { - _, err := rc.do("HDEL", rc.key, key) + var err error + if _, err = rc.do("DEL", key); err != nil { + return err + } + _, err = rc.do("HDEL", rc.key, key) return err } -// check cache exist in redis. +// check cache's existence in redis. func (rc *RedisCache) IsExist(key string) bool { - v, err := redis.Bool(rc.do("HEXISTS", rc.key, key)) + v, err := redis.Bool(rc.do("EXISTS", key)) if err != nil { return false } - + if v == false { + if _, err = rc.do("HDEL", rc.key, key); err != nil { + return false + } + } return v } // increase counter in redis. func (rc *RedisCache) Incr(key string) error { - _, err := redis.Bool(rc.do("HINCRBY", rc.key, key, 1)) + _, err := redis.Bool(rc.do("INCRBY", key, 1)) return err } // decrease counter in redis. func (rc *RedisCache) Decr(key string) error { - _, err := redis.Bool(rc.do("HINCRBY", rc.key, key, -1)) + _, err := redis.Bool(rc.do("INCRBY", key, -1)) return err } // clean all cache in redis. delete this redis collection. func (rc *RedisCache) ClearAll() error { - _, err := rc.do("DEL", rc.key) + cachedKeys, err := redis.Strings(rc.do("HKEYS", rc.key)) + if err != nil { + return err + } + for _, str := range cachedKeys { + if _, err = rc.do("DEL", str); err != nil { + return err + } + } + _, err = rc.do("DEL", rc.key) return err } @@ -114,26 +159,21 @@ func (rc *RedisCache) StartAndGC(config string) error { c := rc.p.Get() defer c.Close() - if err := c.Err(); err != nil { - return err - } - return nil + return c.Err() } // connect to redis. func (rc *RedisCache) connectInit() { + dialFunc := func() (c redis.Conn, err error) { + c, err = redis.Dial("tcp", rc.conninfo) + return + } // initialize a new pool rc.p = &redis.Pool{ MaxIdle: 3, IdleTimeout: 180 * time.Second, - Dial: func() (redis.Conn, error) { - c, err := redis.Dial("tcp", rc.conninfo) - if err != nil { - return nil, err - } - return c, nil - }, + Dial: dialFunc, } } diff --git a/cache/redis/redis_test.go b/cache/redis/redis_test.go new file mode 100644 index 00000000..fbe82ac5 --- /dev/null +++ b/cache/redis/redis_test.go @@ -0,0 +1,85 @@ +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package redis + +import ( + "testing" + "time" + + "github.com/garyburd/redigo/redis" + + "github.com/astaxie/beego/cache" +) + +func TestRedisCache(t *testing.T) { + bm, err := cache.NewCache("redis", `{"conn": "127.0.0.1:6379"}`) + if err != nil { + t.Error("init err") + } + if err = bm.Put("astaxie", 1, 10); err != nil { + t.Error("set Error", err) + } + if !bm.IsExist("astaxie") { + t.Error("check err") + } + + time.Sleep(10 * time.Second) + + if bm.IsExist("astaxie") { + t.Error("check err") + } + if err = bm.Put("astaxie", 1, 10); err != nil { + t.Error("set Error", err) + } + + if v, _ := redis.Int(bm.Get("astaxie"), err); v != 1 { + t.Error("get err") + } + + if err = bm.Incr("astaxie"); err != nil { + t.Error("Incr Error", err) + } + + if v, _ := redis.Int(bm.Get("astaxie"), err); v != 2 { + t.Error("get err") + } + + if err = bm.Decr("astaxie"); err != nil { + t.Error("Decr Error", err) + } + + if v, _ := redis.Int(bm.Get("astaxie"), err); v != 1 { + t.Error("get err") + } + bm.Delete("astaxie") + if bm.IsExist("astaxie") { + t.Error("delete err") + } + //test string + if err = bm.Put("astaxie", "author", 10); err != nil { + t.Error("set Error", err) + } + if !bm.IsExist("astaxie") { + t.Error("check err") + } + + if v, _ := redis.String(bm.Get("astaxie"), err); v != "author" { + t.Error("get err") + } + // test clear all + if err = bm.ClearAll(); err != nil { + t.Error("clear all err") + } +} diff --git a/config.go b/config.go index 280edc6b..db234e16 100644 --- a/config.go +++ b/config.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package beego @@ -52,6 +60,7 @@ var ( SessionHashKey string // session hash salt string. SessionCookieLifeTime int // the life time of session id in cookie. SessionAutoSetCookie bool // auto setcookie + SessionDomain string // the cookie domain default is empty UseFcgi bool MaxMemory int64 EnableGzip bool // flag of enable gzip @@ -180,147 +189,147 @@ func ParseConfig() (err error) { return err } else { - if v, err := getConfig("string", "HttpAddr"); err == nil { + if v, err := GetConfig("string", "HttpAddr"); err == nil { HttpAddr = v.(string) } - if v, err := getConfig("int", "HttpPort"); err == nil { + if v, err := GetConfig("int", "HttpPort"); err == nil { HttpPort = v.(int) } - if v, err := getConfig("bool", "EnableHttpListen"); err == nil { + if v, err := GetConfig("bool", "EnableHttpListen"); err == nil { EnableHttpListen = v.(bool) } - if maxmemory, err := getConfig("int64", "MaxMemory"); err == nil { + if maxmemory, err := GetConfig("int64", "MaxMemory"); err == nil { MaxMemory = maxmemory.(int64) } - if appname, _ := getConfig("string", "AppName"); appname != "" { + if appname, _ := GetConfig("string", "AppName"); appname != "" { AppName = appname.(string) } - if runmode, _ := getConfig("string", "RunMode"); runmode != "" { + if runmode, _ := GetConfig("string", "RunMode"); runmode != "" { RunMode = runmode.(string) } - if autorender, err := getConfig("bool", "AutoRender"); err == nil { + if autorender, err := GetConfig("bool", "AutoRender"); err == nil { AutoRender = autorender.(bool) } - if autorecover, err := getConfig("bool", "RecoverPanic"); err == nil { + if autorecover, err := GetConfig("bool", "RecoverPanic"); err == nil { RecoverPanic = autorecover.(bool) } - if views, _ := getConfig("string", "ViewsPath"); views != "" { + if views, _ := GetConfig("string", "ViewsPath"); views != "" { ViewsPath = views.(string) } - if sessionon, err := getConfig("bool", "SessionOn"); err == nil { + if sessionon, err := GetConfig("bool", "SessionOn"); err == nil { SessionOn = sessionon.(bool) } - if sessProvider, _ := getConfig("string", "SessionProvider"); sessProvider != "" { + if sessProvider, _ := GetConfig("string", "SessionProvider"); sessProvider != "" { SessionProvider = sessProvider.(string) } - if sessName, _ := getConfig("string", "SessionName"); sessName != "" { + if sessName, _ := GetConfig("string", "SessionName"); sessName != "" { SessionName = sessName.(string) } - if sesssavepath, _ := getConfig("string", "SessionSavePath"); sesssavepath != "" { + if sesssavepath, _ := GetConfig("string", "SessionSavePath"); sesssavepath != "" { SessionSavePath = sesssavepath.(string) } - if sesshashfunc, _ := getConfig("string", "SessionHashFunc"); sesshashfunc != "" { + if sesshashfunc, _ := GetConfig("string", "SessionHashFunc"); sesshashfunc != "" { SessionHashFunc = sesshashfunc.(string) } - if sesshashkey, _ := getConfig("string", "SessionHashKey"); sesshashkey != "" { + if sesshashkey, _ := GetConfig("string", "SessionHashKey"); sesshashkey != "" { SessionHashKey = sesshashkey.(string) } - if sessMaxLifeTime, err := getConfig("int64", "SessionGCMaxLifetime"); err == nil && sessMaxLifeTime != 0 { + if sessMaxLifeTime, err := GetConfig("int64", "SessionGCMaxLifetime"); err == nil && sessMaxLifeTime != 0 { SessionGCMaxLifetime = sessMaxLifeTime.(int64) } - if sesscookielifetime, err := getConfig("int", "SessionCookieLifeTime"); err == nil && sesscookielifetime != 0 { + if sesscookielifetime, err := GetConfig("int", "SessionCookieLifeTime"); err == nil && sesscookielifetime != 0 { SessionCookieLifeTime = sesscookielifetime.(int) } - if usefcgi, err := getConfig("bool", "UseFcgi"); err == nil { + if usefcgi, err := GetConfig("bool", "UseFcgi"); err == nil { UseFcgi = usefcgi.(bool) } - if enablegzip, err := getConfig("bool", "EnableGzip"); err == nil { + if enablegzip, err := GetConfig("bool", "EnableGzip"); err == nil { EnableGzip = enablegzip.(bool) } - if directoryindex, err := getConfig("bool", "DirectoryIndex"); err == nil { + if directoryindex, err := GetConfig("bool", "DirectoryIndex"); err == nil { DirectoryIndex = directoryindex.(bool) } - if timeout, err := getConfig("int64", "HttpServerTimeOut"); err == nil { + if timeout, err := GetConfig("int64", "HttpServerTimeOut"); err == nil { HttpServerTimeOut = timeout.(int64) } - if errorsshow, err := getConfig("bool", "ErrorsShow"); err == nil { + if errorsshow, err := GetConfig("bool", "ErrorsShow"); err == nil { ErrorsShow = errorsshow.(bool) } - if copyrequestbody, err := getConfig("bool", "CopyRequestBody"); err == nil { + if copyrequestbody, err := GetConfig("bool", "CopyRequestBody"); err == nil { CopyRequestBody = copyrequestbody.(bool) } - if xsrfkey, _ := getConfig("string", "XSRFKEY"); xsrfkey != "" { + if xsrfkey, _ := GetConfig("string", "XSRFKEY"); xsrfkey != "" { XSRFKEY = xsrfkey.(string) } - if enablexsrf, err := getConfig("bool", "EnableXSRF"); err == nil { + if enablexsrf, err := GetConfig("bool", "EnableXSRF"); err == nil { EnableXSRF = enablexsrf.(bool) } - if expire, err := getConfig("int", "XSRFExpire"); err == nil { + if expire, err := GetConfig("int", "XSRFExpire"); err == nil { XSRFExpire = expire.(int) } - if tplleft, _ := getConfig("string", "TemplateLeft"); tplleft != "" { + if tplleft, _ := GetConfig("string", "TemplateLeft"); tplleft != "" { TemplateLeft = tplleft.(string) } - if tplright, _ := getConfig("string", "TemplateRight"); tplright != "" { + if tplright, _ := GetConfig("string", "TemplateRight"); tplright != "" { TemplateRight = tplright.(string) } - if httptls, err := getConfig("bool", "EnableHttpTLS"); err == nil { + if httptls, err := GetConfig("bool", "EnableHttpTLS"); err == nil { EnableHttpTLS = httptls.(bool) } - if httpsport, err := getConfig("int", "HttpsPort"); err == nil { + if httpsport, err := GetConfig("int", "HttpsPort"); err == nil { HttpsPort = httpsport.(int) } - if certfile, _ := getConfig("string", "HttpCertFile"); certfile != "" { + if certfile, _ := GetConfig("string", "HttpCertFile"); certfile != "" { HttpCertFile = certfile.(string) } - if keyfile, _ := getConfig("string", "HttpKeyFile"); keyfile != "" { + if keyfile, _ := GetConfig("string", "HttpKeyFile"); keyfile != "" { HttpKeyFile = keyfile.(string) } - if serverName, _ := getConfig("string", "BeegoServerName"); serverName != "" { + if serverName, _ := GetConfig("string", "BeegoServerName"); serverName != "" { BeegoServerName = serverName.(string) } - if flashname, _ := getConfig("string", "FlashName"); flashname != "" { + if flashname, _ := GetConfig("string", "FlashName"); flashname != "" { FlashName = flashname.(string) } - if flashseperator, _ := getConfig("string", "FlashSeperator"); flashseperator != "" { + if flashseperator, _ := GetConfig("string", "FlashSeperator"); flashseperator != "" { FlashSeperator = flashseperator.(string) } - if sd, _ := getConfig("string", "StaticDir"); sd != "" { + if sd, _ := GetConfig("string", "StaticDir"); sd != "" { for k := range StaticDir { delete(StaticDir, k) } @@ -334,7 +343,7 @@ func ParseConfig() (err error) { } } - if sgz, _ := getConfig("string", "StaticExtensionsToGzip"); sgz != "" { + if sgz, _ := GetConfig("string", "StaticExtensionsToGzip"); sgz != "" { extensions := strings.Split(sgz.(string), ",") if len(extensions) > 0 { StaticExtensionsToGzip = []string{} @@ -351,26 +360,37 @@ func ParseConfig() (err error) { } } - if enableadmin, err := getConfig("bool", "EnableAdmin"); err == nil { + if enableadmin, err := GetConfig("bool", "EnableAdmin"); err == nil { EnableAdmin = enableadmin.(bool) } - if adminhttpaddr, _ := getConfig("string", "AdminHttpAddr"); adminhttpaddr != "" { + if adminhttpaddr, _ := GetConfig("string", "AdminHttpAddr"); adminhttpaddr != "" { AdminHttpAddr = adminhttpaddr.(string) } - if adminhttpport, err := getConfig("int", "AdminHttpPort"); err == nil { + if adminhttpport, err := GetConfig("int", "AdminHttpPort"); err == nil { AdminHttpPort = adminhttpport.(int) } - if enabledocs, err := getConfig("bool", "EnableDocs"); err == nil { + if enabledocs, err := GetConfig("bool", "EnableDocs"); err == nil { EnableDocs = enabledocs.(bool) } } return nil } -func getConfig(typ, key string) (interface{}, error) { +// Getconfig throw the Runmode +// [dev] +// name = astaixe +// IsEnable = false +// [prod] +// name = slene +// IsEnable = true +// +// usage: +// GetConfig("string", "name") +// GetConfig("bool", "IsEnable") +func GetConfig(typ, key string) (interface{}, error) { switch typ { case "string": v := AppConfig.String(RunMode + "::" + key) diff --git a/config/config.go b/config/config.go index 7446abb4..8d9261b8 100644 --- a/config/config.go +++ b/config/config.go @@ -1,9 +1,44 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// Usage: +// import( +// "github.com/astaxie/beego/config" +// ) +// +// cnf, err := config.NewConfig("ini", "config.conf") +// +// cnf APIS: +// +// cnf.Set(key, val string) error +// cnf.String(key string) string +// cnf.Strings(key string) []string +// cnf.Int(key string) (int, error) +// cnf.Int64(key string) (int64, error) +// cnf.Bool(key string) (bool, error) +// cnf.Float(key string) (float64, error) +// cnf.DefaultString(key string, defaultval string) string +// cnf.DefaultStrings(key string, defaultval []string) []string +// cnf.DefaultInt(key string, defaultval int) int +// cnf.DefaultInt64(key string, defaultval int64) int64 +// cnf.DefaultBool(key string, defaultval bool) bool +// cnf.DefaultFloat(key string, defaultval float64) float64 +// cnf.DIY(key string) (interface{}, error) +// cnf.GetSection(section string) (map[string]string, error) +// cnf.SaveConfigFile(filename string) error +// +// more docs http://beego.me/docs/module/config.md package config import ( @@ -19,12 +54,21 @@ type ConfigContainer interface { Int64(key string) (int64, error) Bool(key string) (bool, error) Float(key string) (float64, error) + DefaultString(key string, defaultval string) string // support section::key type in key string when using ini and json type; Int,Int64,Bool,Float,DIY are same. + DefaultStrings(key string, defaultval []string) []string //get string slice + DefaultInt(key string, defaultval int) int + DefaultInt64(key string, defaultval int64) int64 + DefaultBool(key string, defaultval bool) bool + DefaultFloat(key string, defaultval float64) float64 DIY(key string) (interface{}, error) + GetSection(section string) (map[string]string, error) + SaveConfigFile(filename string) error } // Config is the adapter interface for parsing config file to get raw data to ConfigContainer. type Config interface { Parse(key string) (ConfigContainer, error) + ParseData(data []byte) (ConfigContainer, error) } var adapters = make(map[string]Config) @@ -36,7 +80,7 @@ func Register(name string, adapter Config) { if adapter == nil { panic("config: Register adapter is nil") } - if _, dup := adapters[name]; dup { + if _, ok := adapters[name]; ok { panic("config: Register called twice for adapter " + name) } adapters[name] = adapter @@ -51,3 +95,13 @@ func NewConfig(adapterName, fileaname string) (ConfigContainer, error) { } return adapter.Parse(fileaname) } + +// adapterName is ini/json/xml/yaml. +// data is the config data. +func NewConfigData(adapterName string, data []byte) (ConfigContainer, error) { + adapter, ok := adapters[adapterName] + if !ok { + return nil, fmt.Errorf("config: unknown adaptername %q (forgotten import?)", adapterName) + } + return adapter.ParseData(data) +} diff --git a/config/fake.go b/config/fake.go index ece4f696..54588e5e 100644 --- a/config/fake.go +++ b/config/fake.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package config @@ -17,13 +25,11 @@ type fakeConfigContainer struct { } func (c *fakeConfigContainer) getData(key string) string { - key = strings.ToLower(key) - return c.data[key] + return c.data[strings.ToLower(key)] } func (c *fakeConfigContainer) Set(key, val string) error { - key = strings.ToLower(key) - c.data[key] = val + c.data[strings.ToLower(key)] = val return nil } @@ -31,34 +37,89 @@ func (c *fakeConfigContainer) String(key string) string { return c.getData(key) } +func (c *fakeConfigContainer) DefaultString(key string, defaultval string) string { + if v := c.getData(key); v == "" { + return defaultval + } else { + return v + } +} + func (c *fakeConfigContainer) Strings(key string) []string { return strings.Split(c.getData(key), ";") } +func (c *fakeConfigContainer) DefaultStrings(key string, defaultval []string) []string { + if v := c.Strings(key); len(v) == 0 { + return defaultval + } else { + return v + } +} + func (c *fakeConfigContainer) Int(key string) (int, error) { return strconv.Atoi(c.getData(key)) } +func (c *fakeConfigContainer) DefaultInt(key string, defaultval int) int { + if v, err := c.Int(key); err != nil { + return defaultval + } else { + return v + } +} + func (c *fakeConfigContainer) Int64(key string) (int64, error) { return strconv.ParseInt(c.getData(key), 10, 64) } +func (c *fakeConfigContainer) DefaultInt64(key string, defaultval int64) int64 { + if v, err := c.Int64(key); err != nil { + return defaultval + } else { + return v + } +} + func (c *fakeConfigContainer) Bool(key string) (bool, error) { return strconv.ParseBool(c.getData(key)) } +func (c *fakeConfigContainer) DefaultBool(key string, defaultval bool) bool { + if v, err := c.Bool(key); err != nil { + return defaultval + } else { + return v + } +} + func (c *fakeConfigContainer) Float(key string) (float64, error) { return strconv.ParseFloat(c.getData(key), 64) } +func (c *fakeConfigContainer) DefaultFloat(key string, defaultval float64) float64 { + if v, err := c.Float(key); err != nil { + return defaultval + } else { + return v + } +} + func (c *fakeConfigContainer) DIY(key string) (interface{}, error) { - key = strings.ToLower(key) - if v, ok := c.data[key]; ok { + if v, ok := c.data[strings.ToLower(key)]; ok { return v, nil } return nil, errors.New("key not find") } +func (c *fakeConfigContainer) GetSection(section string) (map[string]string, error) { + return nil, errors.New("not implement in the fakeConfigContainer") +} + +func (c *fakeConfigContainer) SaveConfigFile(filename string) error { + return errors.New("not implement in the fakeConfigContainer") +} + var _ ConfigContainer = new(fakeConfigContainer) func NewFakeConfig() ConfigContainer { diff --git a/config/ini.go b/config/ini.go index 0593864a..ec72a718 100644 --- a/config/ini.go +++ b/config/ini.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package config @@ -10,11 +18,15 @@ import ( "bufio" "bytes" "errors" + "fmt" "io" + "io/ioutil" "os" + "path" "strconv" "strings" "sync" + "time" "unicode" ) @@ -27,6 +39,7 @@ var ( bDQuote = []byte{'"'} // quote signal sectionStart = []byte{'['} // section start signal sectionEnd = []byte{']'} // section end signal + lineBreak = "\n" ) // IniConfig implements Config to parse ini file. @@ -80,8 +93,7 @@ func (ini *IniConfig) Parse(name string) (ConfigContainer, error) { } if bytes.HasPrefix(line, sectionStart) && bytes.HasSuffix(line, sectionEnd) { - section = string(line[1 : len(line)-1]) - section = strings.ToLower(section) // section name case insensitive + section = strings.ToLower(string(line[1 : len(line)-1])) // section name case insensitive if comment.Len() > 0 { cfg.sectionComment[section] = comment.String() comment.Reset() @@ -89,67 +101,124 @@ func (ini *IniConfig) Parse(name string) (ConfigContainer, error) { if _, ok := cfg.data[section]; !ok { cfg.data[section] = make(map[string]string) } - } else { - if _, ok := cfg.data[section]; !ok { - cfg.data[section] = make(map[string]string) - } - keyval := bytes.SplitN(line, bEqual, 2) - val := bytes.TrimSpace(keyval[1]) - if bytes.HasPrefix(val, bDQuote) { - val = bytes.Trim(val, `"`) - } + continue + } - key := string(bytes.TrimSpace(keyval[0])) // key name case insensitive - key = strings.ToLower(key) - cfg.data[section][key] = string(val) - if comment.Len() > 0 { - cfg.keycomment[section+"."+key] = comment.String() - comment.Reset() - } + if _, ok := cfg.data[section]; !ok { + cfg.data[section] = make(map[string]string) + } + keyValue := bytes.SplitN(line, bEqual, 2) + val := bytes.TrimSpace(keyValue[1]) + if bytes.HasPrefix(val, bDQuote) { + val = bytes.Trim(val, `"`) + } + + key := string(bytes.TrimSpace(keyValue[0])) // key name case insensitive + key = strings.ToLower(key) + cfg.data[section][key] = string(val) + if comment.Len() > 0 { + cfg.keyComment[section+"."+key] = comment.String() + comment.Reset() } } return cfg, nil } +func (ini *IniConfig) ParseData(data []byte) (ConfigContainer, error) { + // Save memory data to temporary file + tmpName := path.Join(os.TempDir(), "beego", fmt.Sprintf("%d", time.Now().Nanosecond())) + os.MkdirAll(path.Dir(tmpName), os.ModePerm) + if err := ioutil.WriteFile(tmpName, data, 0655); err != nil { + return nil, err + } + return ini.Parse(tmpName) +} + // A Config represents the ini configuration. // When set and get value, support key as section:name type. type IniConfigContainer struct { filename string data map[string]map[string]string // section=> key:val sectionComment map[string]string // section : comment - keycomment map[string]string // id: []{comment, key...}; id 1 is for main comment. + keyComment map[string]string // id: []{comment, key...}; id 1 is for main comment. sync.RWMutex } // Bool returns the boolean value for a given key. func (c *IniConfigContainer) Bool(key string) (bool, error) { - key = strings.ToLower(key) - return strconv.ParseBool(c.getdata(key)) + return strconv.ParseBool(c.getdata(strings.ToLower(key))) +} + +// DefaultBool returns the boolean value for a given key. +// if err != nil return defaltval +func (c *IniConfigContainer) DefaultBool(key string, defaultval bool) bool { + if v, err := c.Bool(key); err != nil { + return defaultval + } else { + return v + } } // Int returns the integer value for a given key. func (c *IniConfigContainer) Int(key string) (int, error) { - key = strings.ToLower(key) - return strconv.Atoi(c.getdata(key)) + return strconv.Atoi(c.getdata(strings.ToLower(key))) +} + +// DefaultInt returns the integer value for a given key. +// if err != nil return defaltval +func (c *IniConfigContainer) DefaultInt(key string, defaultval int) int { + if v, err := c.Int(key); err != nil { + return defaultval + } else { + return v + } } // Int64 returns the int64 value for a given key. func (c *IniConfigContainer) Int64(key string) (int64, error) { - key = strings.ToLower(key) - return strconv.ParseInt(c.getdata(key), 10, 64) + return strconv.ParseInt(c.getdata(strings.ToLower(key)), 10, 64) +} + +// DefaultInt64 returns the int64 value for a given key. +// if err != nil return defaltval +func (c *IniConfigContainer) DefaultInt64(key string, defaultval int64) int64 { + if v, err := c.Int64(key); err != nil { + return defaultval + } else { + return v + } } // Float returns the float value for a given key. func (c *IniConfigContainer) Float(key string) (float64, error) { - key = strings.ToLower(key) - return strconv.ParseFloat(c.getdata(key), 64) + return strconv.ParseFloat(c.getdata(strings.ToLower(key)), 64) +} + +// DefaultFloat returns the float64 value for a given key. +// if err != nil return defaltval +func (c *IniConfigContainer) DefaultFloat(key string, defaultval float64) float64 { + if v, err := c.Float(key); err != nil { + return defaultval + } else { + return v + } } // String returns the string value for a given key. func (c *IniConfigContainer) String(key string) string { key = strings.ToLower(key) - return c.getdata(key) + return c.getdata(strings.ToLower(key)) +} + +// DefaultString returns the string value for a given key. +// if err != nil return defaltval +func (c *IniConfigContainer) DefaultString(key string, defaultval string) string { + if v := c.String(key); v == "" { + return defaultval + } else { + return v + } } // Strings returns the []string value for a given key. @@ -157,6 +226,78 @@ func (c *IniConfigContainer) Strings(key string) []string { return strings.Split(c.String(key), ";") } +// DefaultStrings returns the []string value for a given key. +// if err != nil return defaltval +func (c *IniConfigContainer) DefaultStrings(key string, defaultval []string) []string { + if v := c.Strings(key); len(v) == 0 { + return defaultval + } else { + return v + } +} + +// GetSection returns map for the given section +func (c *IniConfigContainer) GetSection(section string) (map[string]string, error) { + if v, ok := c.data[section]; ok { + return v, nil + } else { + return nil, errors.New("not exist setction") + } +} + +// SaveConfigFile save the config into file +func (c *IniConfigContainer) SaveConfigFile(filename string) (err error) { + // Write configuration file by filename. + f, err := os.Create(filename) + if err != nil { + return err + } + defer f.Close() + + buf := bytes.NewBuffer(nil) + for section, dt := range c.data { + // Write section comments. + if v, ok := c.sectionComment[section]; ok { + if _, err = buf.WriteString(string(bNumComment) + v + lineBreak); err != nil { + return err + } + } + + if section != DEFAULT_SECTION { + // Write section name. + if _, err = buf.WriteString(string(sectionStart) + section + string(sectionEnd) + lineBreak); err != nil { + return err + } + } + + for key, val := range dt { + if key != " " { + // Write key comments. + if v, ok := c.keyComment[key]; ok { + if _, err = buf.WriteString(string(bNumComment) + v + lineBreak); err != nil { + return err + } + } + + // Write key and value. + if _, err = buf.WriteString(key + string(bEqual) + val + lineBreak); err != nil { + return err + } + } + } + + // Put a line between sections. + if _, err = buf.WriteString(lineBreak); err != nil { + return err + } + } + + if _, err = buf.WriteTo(f); err != nil { + return err + } + return nil +} + // WriteValue writes a new value for key. // if write to one section, the key need be "section::key". // if the section is not existed, it panics. @@ -167,16 +308,19 @@ func (c *IniConfigContainer) Set(key, value string) error { return errors.New("key is empty") } - var section, k string - key = strings.ToLower(key) - sectionkey := strings.Split(key, "::") - if len(sectionkey) >= 2 { - section = sectionkey[0] - k = sectionkey[1] + var ( + section, k string + sectionKey []string = strings.Split(key, "::") + ) + + if len(sectionKey) >= 2 { + section = sectionKey[0] + k = sectionKey[1] } else { section = DEFAULT_SECTION - k = sectionkey[0] + k = sectionKey[0] } + if _, ok := c.data[section]; !ok { c.data[section] = make(map[string]string) } @@ -186,8 +330,7 @@ func (c *IniConfigContainer) Set(key, value string) error { // DIY returns the raw value by a given key. func (c *IniConfigContainer) DIY(key string) (v interface{}, err error) { - key = strings.ToLower(key) - if v, ok := c.data[key]; ok { + if v, ok := c.data[strings.ToLower(key)]; ok { return v, nil } return v, errors.New("key not find") @@ -201,18 +344,19 @@ func (c *IniConfigContainer) getdata(key string) string { return "" } - var section, k string - key = strings.ToLower(key) - sectionkey := strings.Split(key, "::") - if len(sectionkey) >= 2 { - section = sectionkey[0] - k = sectionkey[1] + var ( + section, k string + sectionKey []string = strings.Split(key, "::") + ) + if len(sectionKey) >= 2 { + section = sectionKey[0] + k = sectionKey[1] } else { section = DEFAULT_SECTION - k = sectionkey[0] + k = sectionKey[0] } if v, ok := c.data[section]; ok { - if vv, o := v[k]; o { + if vv, ok := v[k]; ok { return vv } } diff --git a/config/ini_test.go b/config/ini_test.go index 3e792ded..7599ab8b 100644 --- a/config/ini_test.go +++ b/config/ini_test.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package config diff --git a/config/json.go b/config/json.go index 440d98bf..ae86ea53 100644 --- a/config/json.go +++ b/config/json.go @@ -1,18 +1,29 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package config import ( "encoding/json" "errors" + "fmt" "io/ioutil" "os" + "path" "strings" "sync" + "time" ) // JsonConfig is a json config parser and implements Config interface. @@ -26,13 +37,13 @@ func (js *JsonConfig) Parse(filename string) (ConfigContainer, error) { return nil, err } defer file.Close() - x := &JsonConfigContainer{ - data: make(map[string]interface{}), - } content, err := ioutil.ReadAll(file) if err != nil { return nil, err } + x := &JsonConfigContainer{ + data: make(map[string]interface{}), + } err = json.Unmarshal(content, &x.data) if err != nil { var wrappingArray []interface{} @@ -45,6 +56,16 @@ func (js *JsonConfig) Parse(filename string) (ConfigContainer, error) { return x, nil } +func (js *JsonConfig) ParseData(data []byte) (ConfigContainer, error) { + // Save memory data to temporary file + tmpName := path.Join(os.TempDir(), "beego", fmt.Sprintf("%d", time.Now().Nanosecond())) + os.MkdirAll(path.Dir(tmpName), os.ModePerm) + if err := ioutil.WriteFile(tmpName, data, 0655); err != nil { + return nil, err + } + return js.Parse(tmpName) +} + // A Config represents the json configuration. // Only when get value, support key as section:name type. type JsonConfigContainer struct { @@ -54,71 +75,110 @@ type JsonConfigContainer struct { // Bool returns the boolean value for a given key. func (c *JsonConfigContainer) Bool(key string) (bool, error) { - val := c.getdata(key) + val := c.getData(key) if val != nil { if v, ok := val.(bool); ok { return v, nil - } else { - return false, errors.New("not bool value") } + return false, errors.New("not bool value") + } + return false, errors.New("not exist key:" + key) +} + +// DefaultBool return the bool value if has no error +// otherwise return the defaultval +func (c *JsonConfigContainer) DefaultBool(key string, defaultval bool) bool { + if v, err := c.Bool(key); err != nil { + return defaultval } else { - return false, errors.New("not exist key:" + key) + return v } } // Int returns the integer value for a given key. func (c *JsonConfigContainer) Int(key string) (int, error) { - val := c.getdata(key) + val := c.getData(key) if val != nil { if v, ok := val.(float64); ok { return int(v), nil - } else { - return 0, errors.New("not int value") } + return 0, errors.New("not int value") + } + return 0, errors.New("not exist key:" + key) +} + +// DefaultInt returns the integer value for a given key. +// if err != nil return defaltval +func (c *JsonConfigContainer) DefaultInt(key string, defaultval int) int { + if v, err := c.Int(key); err != nil { + return defaultval } else { - return 0, errors.New("not exist key:" + key) + return v } } // Int64 returns the int64 value for a given key. func (c *JsonConfigContainer) Int64(key string) (int64, error) { - val := c.getdata(key) + val := c.getData(key) if val != nil { if v, ok := val.(float64); ok { return int64(v), nil - } else { - return 0, errors.New("not int64 value") } + return 0, errors.New("not int64 value") + } + return 0, errors.New("not exist key:" + key) +} + +// DefaultInt64 returns the int64 value for a given key. +// if err != nil return defaltval +func (c *JsonConfigContainer) DefaultInt64(key string, defaultval int64) int64 { + if v, err := c.Int64(key); err != nil { + return defaultval } else { - return 0, errors.New("not exist key:" + key) + return v } } // Float returns the float value for a given key. func (c *JsonConfigContainer) Float(key string) (float64, error) { - val := c.getdata(key) + val := c.getData(key) if val != nil { if v, ok := val.(float64); ok { return v, nil - } else { - return 0.0, errors.New("not float64 value") } + return 0.0, errors.New("not float64 value") + } + return 0.0, errors.New("not exist key:" + key) +} + +// DefaultFloat returns the float64 value for a given key. +// if err != nil return defaltval +func (c *JsonConfigContainer) DefaultFloat(key string, defaultval float64) float64 { + if v, err := c.Float(key); err != nil { + return defaultval } else { - return 0.0, errors.New("not exist key:" + key) + return v } } // String returns the string value for a given key. func (c *JsonConfigContainer) String(key string) string { - val := c.getdata(key) + val := c.getData(key) if val != nil { if v, ok := val.(string); ok { return v - } else { - return "" } + } + return "" +} + +// DefaultString returns the string value for a given key. +// if err != nil return defaltval +func (c *JsonConfigContainer) DefaultString(key string, defaultval string) string { + if v := c.String(key); v == "" { + return defaultval } else { - return "" + return v } } @@ -127,6 +187,41 @@ func (c *JsonConfigContainer) Strings(key string) []string { return strings.Split(c.String(key), ";") } +// DefaultStrings returns the []string value for a given key. +// if err != nil return defaltval +func (c *JsonConfigContainer) DefaultStrings(key string, defaultval []string) []string { + if v := c.Strings(key); len(v) == 0 { + return defaultval + } else { + return v + } +} + +// GetSection returns map for the given section +func (c *JsonConfigContainer) GetSection(section string) (map[string]string, error) { + if v, ok := c.data[section]; ok { + return v.(map[string]string), nil + } else { + return nil, errors.New("not exist setction") + } +} + +// SaveConfigFile save the config into file +func (c *JsonConfigContainer) SaveConfigFile(filename string) (err error) { + // Write configuration file by filename. + f, err := os.Create(filename) + if err != nil { + return err + } + defer f.Close() + b, err := json.MarshalIndent(c.data, "", " ") + if err != nil { + return err + } + _, err = f.Write(b) + return err +} + // WriteValue writes a new value for key. func (c *JsonConfigContainer) Set(key, val string) error { c.Lock() @@ -137,39 +232,37 @@ func (c *JsonConfigContainer) Set(key, val string) error { // DIY returns the raw value by a given key. func (c *JsonConfigContainer) DIY(key string) (v interface{}, err error) { - val := c.getdata(key) + val := c.getData(key) if val != nil { return val, nil - } else { - return nil, errors.New("not exist key") } + return nil, errors.New("not exist key") } // section.key or key -func (c *JsonConfigContainer) getdata(key string) interface{} { +func (c *JsonConfigContainer) getData(key string) interface{} { c.RLock() defer c.RUnlock() if len(key) == 0 { return nil } - sectionkey := strings.Split(key, "::") - if len(sectionkey) >= 2 { - cruval, ok := c.data[sectionkey[0]] + sectionKey := strings.Split(key, "::") + if len(sectionKey) >= 2 { + curValue, ok := c.data[sectionKey[0]] if !ok { return nil } - for _, key := range sectionkey[1:] { - if v, ok := cruval.(map[string]interface{}); !ok { - return nil - } else if cruval, ok = v[key]; !ok { - return nil + for _, key := range sectionKey[1:] { + if v, ok := curValue.(map[string]interface{}); ok { + if curValue, ok = v[key]; !ok { + return nil + } } } - return cruval - } else { - if v, ok := c.data[key]; ok { - return v - } + return curValue + } + if v, ok := c.data[key]; ok { + return v } return nil } diff --git a/config/json_test.go b/config/json_test.go index a2741941..409e2c12 100644 --- a/config/json_test.go +++ b/config/json_test.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package config @@ -61,13 +69,13 @@ func TestJsonStartsWithArray(t *testing.T) { t.Fatal(err) } rootArray, err := jsonconf.DIY("rootArray") - if (err != nil) { + if err != nil { t.Error("array does not exist as element") } rootArrayCasted := rootArray.([]interface{}) - if (rootArrayCasted == nil) { + if rootArrayCasted == nil { t.Error("array from root is nil") - }else { + } else { elem := rootArrayCasted[0].(map[string]interface{}) if elem["url"] != "user" || elem["serviceAPI"] != "http://www.test.com/user" { t.Error("array[0] values are not valid") diff --git a/config/xml/xml.go b/config/xml/xml.go index f763d4f0..a1d9fcdb 100644 --- a/config/xml/xml.go +++ b/config/xml/xml.go @@ -1,18 +1,45 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -package config +// package xml for config provider +// +// depend on github.com/beego/x2j +// +// go install github.com/beego/x2j +// +// Usage: +// import( +// _ "github.com/astaxie/beego/config/xml" +// "github.com/astaxie/beego/config" +// ) +// +// cnf, err := config.NewConfig("xml", "config.xml") +// +// more docs http://beego.me/docs/module/config.md +package xml import ( + "encoding/xml" "errors" + "fmt" "io/ioutil" "os" + "path" "strconv" "strings" "sync" + "time" "github.com/astaxie/beego/config" "github.com/beego/x2j" @@ -21,31 +48,41 @@ import ( // XmlConfig is a xml config parser and implements Config interface. // xml configurations should be included in tag. // only support key/value pair as value as each item. -type XMLConfig struct { -} +type XMLConfig struct{} // Parse returns a ConfigContainer with parsed xml config map. -func (xmls *XMLConfig) Parse(filename string) (config.ConfigContainer, error) { +func (xc *XMLConfig) Parse(filename string) (config.ConfigContainer, error) { file, err := os.Open(filename) if err != nil { return nil, err } defer file.Close() - x := &XMLConfigContainer{ - data: make(map[string]interface{}), - } + + x := &XMLConfigContainer{data: make(map[string]interface{})} content, err := ioutil.ReadAll(file) if err != nil { return nil, err } + d, err := x2j.DocToMap(string(content)) if err != nil { return nil, err } + x.data = d["config"].(map[string]interface{}) return x, nil } +func (x *XMLConfig) ParseData(data []byte) (config.ConfigContainer, error) { + // Save memory data to temporary file + tmpName := path.Join(os.TempDir(), "beego", fmt.Sprintf("%d", time.Now().Nanosecond())) + os.MkdirAll(path.Dir(tmpName), os.ModePerm) + if err := ioutil.WriteFile(tmpName, data, 0655); err != nil { + return nil, err + } + return x.Parse(tmpName) +} + // A Config represents the xml configuration. type XMLConfigContainer struct { data map[string]interface{} @@ -57,21 +94,61 @@ func (c *XMLConfigContainer) Bool(key string) (bool, error) { return strconv.ParseBool(c.data[key].(string)) } +// DefaultBool return the bool value if has no error +// otherwise return the defaultval +func (c *XMLConfigContainer) DefaultBool(key string, defaultval bool) bool { + if v, err := c.Bool(key); err != nil { + return defaultval + } else { + return v + } +} + // Int returns the integer value for a given key. func (c *XMLConfigContainer) Int(key string) (int, error) { return strconv.Atoi(c.data[key].(string)) } +// DefaultInt returns the integer value for a given key. +// if err != nil return defaltval +func (c *XMLConfigContainer) DefaultInt(key string, defaultval int) int { + if v, err := c.Int(key); err != nil { + return defaultval + } else { + return v + } +} + // Int64 returns the int64 value for a given key. func (c *XMLConfigContainer) Int64(key string) (int64, error) { return strconv.ParseInt(c.data[key].(string), 10, 64) } +// DefaultInt64 returns the int64 value for a given key. +// if err != nil return defaltval +func (c *XMLConfigContainer) DefaultInt64(key string, defaultval int64) int64 { + if v, err := c.Int64(key); err != nil { + return defaultval + } else { + return v + } +} + // Float returns the float value for a given key. func (c *XMLConfigContainer) Float(key string) (float64, error) { return strconv.ParseFloat(c.data[key].(string), 64) } +// DefaultFloat returns the float64 value for a given key. +// if err != nil return defaltval +func (c *XMLConfigContainer) DefaultFloat(key string, defaultval float64) float64 { + if v, err := c.Float(key); err != nil { + return defaultval + } else { + return v + } +} + // String returns the string value for a given key. func (c *XMLConfigContainer) String(key string) string { if v, ok := c.data[key].(string); ok { @@ -80,11 +157,56 @@ func (c *XMLConfigContainer) String(key string) string { return "" } +// DefaultString returns the string value for a given key. +// if err != nil return defaltval +func (c *XMLConfigContainer) DefaultString(key string, defaultval string) string { + if v := c.String(key); v == "" { + return defaultval + } else { + return v + } +} + // Strings returns the []string value for a given key. func (c *XMLConfigContainer) Strings(key string) []string { return strings.Split(c.String(key), ";") } +// DefaultStrings returns the []string value for a given key. +// if err != nil return defaltval +func (c *XMLConfigContainer) DefaultStrings(key string, defaultval []string) []string { + if v := c.Strings(key); len(v) == 0 { + return defaultval + } else { + return v + } +} + +// GetSection returns map for the given section +func (c *XMLConfigContainer) GetSection(section string) (map[string]string, error) { + if v, ok := c.data[section]; ok { + return v.(map[string]string), nil + } else { + return nil, errors.New("not exist setction") + } +} + +// SaveConfigFile save the config into file +func (c *XMLConfigContainer) SaveConfigFile(filename string) (err error) { + // Write configuration file by filename. + f, err := os.Create(filename) + if err != nil { + return err + } + defer f.Close() + b, err := xml.MarshalIndent(c.data, " ", " ") + if err != nil { + return err + } + _, err = f.Write(b) + return err +} + // WriteValue writes a new value for key. func (c *XMLConfigContainer) Set(key, val string) error { c.Lock() diff --git a/config/xml/xml_test.go b/config/xml/xml_test.go index 767b02ed..fa3c17f1 100644 --- a/config/xml/xml_test.go +++ b/config/xml/xml_test.go @@ -1,10 +1,18 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -package config +package xml import ( "os" diff --git a/config/yaml/yaml.go b/config/yaml/yaml.go index 04a6def3..c5be44a9 100644 --- a/config/yaml/yaml.go +++ b/config/yaml/yaml.go @@ -1,59 +1,92 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -package config +// package yaml for config provider +// +// depend on github.com/beego/goyaml2 +// +// go install github.com/beego/goyaml2 +// +// Usage: +// import( +// _ "github.com/astaxie/beego/config/yaml" +// "github.com/astaxie/beego/config" +// ) +// +// cnf, err := config.NewConfig("yaml", "config.yaml") +// +// more docs http://beego.me/docs/module/config.md +package yaml import ( "bytes" "encoding/json" "errors" + "fmt" "io/ioutil" "log" "os" + "path" "strings" "sync" + "time" "github.com/astaxie/beego/config" "github.com/beego/goyaml2" ) // YAMLConfig is a yaml config parser and implements Config interface. -type YAMLConfig struct { -} +type YAMLConfig struct{} // Parse returns a ConfigContainer with parsed yaml config map. -func (yaml *YAMLConfig) Parse(filename string) (config.ConfigContainer, error) { - y := &YAMLConfigContainer{ - data: make(map[string]interface{}), - } +func (yaml *YAMLConfig) Parse(filename string) (y config.ConfigContainer, err error) { cnf, err := ReadYmlReader(filename) if err != nil { + return + } + y = &YAMLConfigContainer{ + data: cnf, + } + return +} + +func (yaml *YAMLConfig) ParseData(data []byte) (config.ConfigContainer, error) { + // Save memory data to temporary file + tmpName := path.Join(os.TempDir(), "beego", fmt.Sprintf("%d", time.Now().Nanosecond())) + os.MkdirAll(path.Dir(tmpName), os.ModePerm) + if err := ioutil.WriteFile(tmpName, data, 0655); err != nil { return nil, err } - y.data = cnf - return y, nil + return yaml.Parse(tmpName) } // Read yaml file to map. // if json like, use json package, unless goyaml2 package. func ReadYmlReader(path string) (cnf map[string]interface{}, err error) { - err = nil f, err := os.Open(path) if err != nil { return } defer f.Close() - err = nil + buf, err := ioutil.ReadAll(f) if err != nil || len(buf) < 3 { return } if string(buf[0:1]) == "{" { - log.Println("Look lile a Json, try it") + log.Println("Look like a Json, try json umarshal") err = json.Unmarshal(buf, &cnf) if err == nil { log.Println("It is Json Map") @@ -61,19 +94,19 @@ func ReadYmlReader(path string) (cnf map[string]interface{}, err error) { } } - _map, _err := goyaml2.Read(bytes.NewBuffer(buf)) - if _err != nil { - log.Println("Goyaml2 ERR>", string(buf), _err) - //err = goyaml.Unmarshal(buf, &cnf) - err = _err + data, err := goyaml2.Read(bytes.NewBuffer(buf)) + if err != nil { + log.Println("Goyaml2 ERR>", string(buf), err) return } - if _map == nil { + + if data == nil { log.Println("Goyaml2 output nil? Pls report bug\n" + string(buf)) + return } - cnf, ok := _map.(map[string]interface{}) + cnf, ok := data.(map[string]interface{}) if !ok { - log.Println("Not a Map? >> ", string(buf), _map) + log.Println("Not a Map? >> ", string(buf), data) cnf = nil } return @@ -93,6 +126,16 @@ func (c *YAMLConfigContainer) Bool(key string) (bool, error) { return false, errors.New("not bool value") } +// DefaultBool return the bool value if has no error +// otherwise return the defaultval +func (c *YAMLConfigContainer) DefaultBool(key string, defaultval bool) bool { + if v, err := c.Bool(key); err != nil { + return defaultval + } else { + return v + } +} + // Int returns the integer value for a given key. func (c *YAMLConfigContainer) Int(key string) (int, error) { if v, ok := c.data[key].(int64); ok { @@ -101,6 +144,16 @@ func (c *YAMLConfigContainer) Int(key string) (int, error) { return 0, errors.New("not int value") } +// DefaultInt returns the integer value for a given key. +// if err != nil return defaltval +func (c *YAMLConfigContainer) DefaultInt(key string, defaultval int) int { + if v, err := c.Int(key); err != nil { + return defaultval + } else { + return v + } +} + // Int64 returns the int64 value for a given key. func (c *YAMLConfigContainer) Int64(key string) (int64, error) { if v, ok := c.data[key].(int64); ok { @@ -109,6 +162,16 @@ func (c *YAMLConfigContainer) Int64(key string) (int64, error) { return 0, errors.New("not bool value") } +// DefaultInt64 returns the int64 value for a given key. +// if err != nil return defaltval +func (c *YAMLConfigContainer) DefaultInt64(key string, defaultval int64) int64 { + if v, err := c.Int64(key); err != nil { + return defaultval + } else { + return v + } +} + // Float returns the float value for a given key. func (c *YAMLConfigContainer) Float(key string) (float64, error) { if v, ok := c.data[key].(float64); ok { @@ -117,6 +180,16 @@ func (c *YAMLConfigContainer) Float(key string) (float64, error) { return 0.0, errors.New("not float64 value") } +// DefaultFloat returns the float64 value for a given key. +// if err != nil return defaltval +func (c *YAMLConfigContainer) DefaultFloat(key string, defaultval float64) float64 { + if v, err := c.Float(key); err != nil { + return defaultval + } else { + return v + } +} + // String returns the string value for a given key. func (c *YAMLConfigContainer) String(key string) string { if v, ok := c.data[key].(string); ok { @@ -125,11 +198,52 @@ func (c *YAMLConfigContainer) String(key string) string { return "" } +// DefaultString returns the string value for a given key. +// if err != nil return defaltval +func (c *YAMLConfigContainer) DefaultString(key string, defaultval string) string { + if v := c.String(key); v == "" { + return defaultval + } else { + return v + } +} + // Strings returns the []string value for a given key. func (c *YAMLConfigContainer) Strings(key string) []string { return strings.Split(c.String(key), ";") } +// DefaultStrings returns the []string value for a given key. +// if err != nil return defaltval +func (c *YAMLConfigContainer) DefaultStrings(key string, defaultval []string) []string { + if v := c.Strings(key); len(v) == 0 { + return defaultval + } else { + return v + } +} + +// GetSection returns map for the given section +func (c *YAMLConfigContainer) GetSection(section string) (map[string]string, error) { + if v, ok := c.data[section]; ok { + return v.(map[string]string), nil + } else { + return nil, errors.New("not exist setction") + } +} + +// SaveConfigFile save the config into file +func (c *YAMLConfigContainer) SaveConfigFile(filename string) (err error) { + // Write configuration file by filename. + f, err := os.Create(filename) + if err != nil { + return err + } + defer f.Close() + err = goyaml2.Write(f, c.data) + return err +} + // WriteValue writes a new value for key. func (c *YAMLConfigContainer) Set(key, val string) error { c.Lock() diff --git a/config/yaml/yaml_test.go b/config/yaml/yaml_test.go index fbeaf654..19ecdca1 100644 --- a/config/yaml/yaml_test.go +++ b/config/yaml/yaml_test.go @@ -1,10 +1,18 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -package config +package yaml import ( "os" diff --git a/config_test.go b/config_test.go index 19eaeacf..17645f80 100644 --- a/config_test.go +++ b/config_test.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package beego diff --git a/context/context.go b/context/context.go index 87986bec..d31076d4 100644 --- a/context/context.go +++ b/context/context.go @@ -1,9 +1,24 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// Usage: +// +// import "github.com/astaxie/beego/context" +// +// ctx := context.Context{Request:req,ResponseWriter:rw} +// +// more docs http://beego.me/docs/module/context.md package context import ( @@ -17,6 +32,7 @@ import ( "time" "github.com/astaxie/beego/middleware" + "github.com/astaxie/beego/utils" ) // Http request context struct including BeegoInput, BeegoOutput, http.Request and http.ResponseWriter. @@ -26,20 +42,21 @@ type Context struct { Output *BeegoOutput Request *http.Request ResponseWriter http.ResponseWriter + _xsrf_token string } // Redirect does redirection to localurl with http header status code. // It sends http response header directly. func (ctx *Context) Redirect(status int, localurl string) { ctx.Output.Header("Location", localurl) - ctx.Output.SetStatus(status) + ctx.ResponseWriter.WriteHeader(status) } // Abort stops this request. // if middleware.ErrorMaps exists, panic body. // if middleware.HTTPExceptionMaps exists, panic HTTPException struct with status and body string. func (ctx *Context) Abort(status int, body string) { - ctx.Output.SetStatus(status) + ctx.ResponseWriter.WriteHeader(status) // first panic from ErrorMaps, is is user defined error functions. if _, ok := middleware.ErrorMaps[body]; ok { panic(body) @@ -58,7 +75,7 @@ func (ctx *Context) Abort(status int, body string) { // Write string to response body. // it sends response body. func (ctx *Context) WriteString(content string) { - ctx.Output.Body([]byte(content)) + ctx.ResponseWriter.Write([]byte(content)) } // Get cookie from request by a given key. @@ -110,3 +127,35 @@ func (ctx *Context) SetSecureCookie(Secret, name, value string, others ...interf cookie := strings.Join([]string{vs, timestamp, sig}, "|") ctx.Output.Cookie(name, cookie, others...) } + +// XsrfToken creates a xsrf token string and returns. +func (ctx *Context) XsrfToken(key string, expire int64) string { + if ctx._xsrf_token == "" { + token, ok := ctx.GetSecureCookie(key, "_xsrf") + if !ok { + token = string(utils.RandomCreateBytes(32)) + ctx.SetSecureCookie(key, "_xsrf", token, expire) + } + ctx._xsrf_token = token + } + return ctx._xsrf_token +} + +// CheckXsrfCookie checks xsrf token in this request is valid or not. +// the token can provided in request header "X-Xsrftoken" and "X-CsrfToken" +// or in form field value named as "_xsrf". +func (ctx *Context) CheckXsrfCookie() bool { + token := ctx.Input.Query("_xsrf") + if token == "" { + token = ctx.Request.Header.Get("X-Xsrftoken") + } + if token == "" { + token = ctx.Request.Header.Get("X-Csrftoken") + } + if token == "" { + ctx.Abort(403, "'_xsrf' argument missing from POST") + } else if ctx._xsrf_token != token { + ctx.Abort(403, "XSRF cookie does not match POST argument") + } + return true +} diff --git a/context/input.go b/context/input.go index 400f8a57..c6038693 100644 --- a/context/input.go +++ b/context/input.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package context diff --git a/context/input_test.go b/context/input_test.go index f53d013d..ddd1a056 100644 --- a/context/input_test.go +++ b/context/input_test.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package context diff --git a/context/output.go b/context/output.go index 8011392f..6298ee77 100644 --- a/context/output.go +++ b/context/output.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package context @@ -68,6 +76,14 @@ func (output *BeegoOutput) Body(content []byte) { } else { output.Header("Content-Length", strconv.Itoa(len(content))) } + + // Write status code if it has been set manually + // Set it to 0 afterwards to prevent "multiple response.WriteHeader calls" + if output.Status != 0 { + output.Context.ResponseWriter.WriteHeader(output.Status) + output.Status = 0 + } + output_writer.Write(content) switch output_writer.(type) { case *gzip.Writer: @@ -267,7 +283,6 @@ func (output *BeegoOutput) ContentType(ext string) { // SetStatus sets response status code. // It writes response header directly. func (output *BeegoOutput) SetStatus(status int) { - output.Context.ResponseWriter.WriteHeader(status) output.Status = status } diff --git a/controller.go b/controller.go index d1f19e43..eee79513 100644 --- a/controller.go +++ b/controller.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package beego @@ -22,7 +30,6 @@ import ( "github.com/astaxie/beego/context" "github.com/astaxie/beego/session" - "github.com/astaxie/beego/utils" ) //commonly used mime-types @@ -270,6 +277,11 @@ func (c *Controller) Abort(code string) { } } +// CustomAbort stops controller handler and show the error data, it's similar Aborts, but support status code and body. +func (c *Controller) CustomAbort(status int, body string) { + c.Ctx.Abort(status, body) +} + // StopRun makes panic of USERSTOPRUN error and go to recover function if defined. func (c *Controller) StopRun() { panic(USERSTOPRUN) @@ -474,18 +486,13 @@ func (c *Controller) SetSecureCookie(Secret, name, value string, others ...inter // XsrfToken creates a xsrf token string and returns. func (c *Controller) XsrfToken() string { if c._xsrf_token == "" { - token, ok := c.GetSecureCookie(XSRFKEY, "_xsrf") - if !ok { - var expire int64 - if c.XSRFExpire > 0 { - expire = int64(c.XSRFExpire) - } else { - expire = int64(XSRFExpire) - } - token = string(utils.RandomCreateBytes(32)) - c.SetSecureCookie(XSRFKEY, "_xsrf", token, expire) + var expire int64 + if c.XSRFExpire > 0 { + expire = int64(c.XSRFExpire) + } else { + expire = int64(XSRFExpire) } - c._xsrf_token = token + c._xsrf_token = c.Ctx.XsrfToken(XSRFKEY, expire) } return c._xsrf_token } @@ -497,19 +504,7 @@ func (c *Controller) CheckXsrfCookie() bool { if !c.EnableXSRF { return true } - token := c.GetString("_xsrf") - if token == "" { - token = c.Ctx.Request.Header.Get("X-Xsrftoken") - } - if token == "" { - token = c.Ctx.Request.Header.Get("X-Csrftoken") - } - if token == "" { - c.Ctx.Abort(403, "'_xsrf' argument missing from POST") - } else if c._xsrf_token != token { - c.Ctx.Abort(403, "XSRF cookie does not match POST argument") - } - return true + return c.Ctx.CheckXsrfCookie() } // XsrfFormHtml writes an input field contains xsrf token value. diff --git a/docs.go b/docs.go index b8e7d193..aaad205e 100644 --- a/docs.go +++ b/docs.go @@ -1,3 +1,17 @@ +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package beego import ( diff --git a/example/beeapi/main.go b/example/beeapi/main.go index bed06196..c1250e03 100644 --- a/example/beeapi/main.go +++ b/example/beeapi/main.go @@ -1,7 +1,11 @@ // Beego (http://beego.me/) + // @description beego is an open-source, high-performance web framework for the Go programming language. + // @link http://github.com/astaxie/beego for the canonical source repository + // @license http://github.com/astaxie/beego/blob/master/LICENSE + // @authors astaxie package main diff --git a/filter.go b/filter.go index a7db36a4..294966d4 100644 --- a/filter.go +++ b/filter.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package beego diff --git a/filter_test.go b/filter_test.go index e5428b96..ff6f750b 100644 --- a/filter_test.go +++ b/filter_test.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package beego diff --git a/flash.go b/flash.go index a67ee5c8..6e85141f 100644 --- a/flash.go +++ b/flash.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package beego diff --git a/flash_test.go b/flash_test.go index f0a17480..7c581e6a 100644 --- a/flash_test.go +++ b/flash_test.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package beego diff --git a/httplib/httplib.go b/httplib/httplib.go index f7d083f2..1c0d5544 100644 --- a/httplib/httplib.go +++ b/httplib/httplib.go @@ -1,9 +1,33 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// Usage: +// +// import "github.com/astaxie/beego/context" +// +// b := httplib.Post("http://beego.me/") +// b.Param("username","astaxie") +// b.Param("password","123456") +// b.PostFile("uploadfile1", "httplib.pdf") +// b.PostFile("uploadfile2", "httplib.txt") +// str, err := b.String() +// if err != nil { +// t.Fatal(err) +// } +// fmt.Println(str) +// +// more docs http://beego.me/docs/module/httplib.md package httplib import ( @@ -52,41 +76,46 @@ func SetDefaultSetting(setting BeegoHttpSettings) { // Get returns *BeegoHttpRequest with GET method. func Get(url string) *BeegoHttpRequest { var req http.Request + var resp http.Response req.Method = "GET" req.Header = http.Header{} - return &BeegoHttpRequest{url, &req, map[string]string{}, map[string]string{}, defaultSetting} + return &BeegoHttpRequest{url, &req, map[string]string{}, map[string]string{}, defaultSetting, &resp, nil} } // Post returns *BeegoHttpRequest with POST method. func Post(url string) *BeegoHttpRequest { var req http.Request + var resp http.Response req.Method = "POST" req.Header = http.Header{} - return &BeegoHttpRequest{url, &req, map[string]string{}, map[string]string{}, defaultSetting} + return &BeegoHttpRequest{url, &req, map[string]string{}, map[string]string{}, defaultSetting, &resp, nil} } // Put returns *BeegoHttpRequest with PUT method. func Put(url string) *BeegoHttpRequest { var req http.Request + var resp http.Response req.Method = "PUT" req.Header = http.Header{} - return &BeegoHttpRequest{url, &req, map[string]string{}, map[string]string{}, defaultSetting} + return &BeegoHttpRequest{url, &req, map[string]string{}, map[string]string{}, defaultSetting, &resp, nil} } // Delete returns *BeegoHttpRequest DELETE GET method. func Delete(url string) *BeegoHttpRequest { var req http.Request + var resp http.Response req.Method = "DELETE" req.Header = http.Header{} - return &BeegoHttpRequest{url, &req, map[string]string{}, map[string]string{}, defaultSetting} + return &BeegoHttpRequest{url, &req, map[string]string{}, map[string]string{}, defaultSetting, &resp, nil} } // Head returns *BeegoHttpRequest with HEAD method. func Head(url string) *BeegoHttpRequest { var req http.Request + var resp http.Response req.Method = "HEAD" req.Header = http.Header{} - return &BeegoHttpRequest{url, &req, map[string]string{}, map[string]string{}, defaultSetting} + return &BeegoHttpRequest{url, &req, map[string]string{}, map[string]string{}, defaultSetting, &resp, nil} } // BeegoHttpSettings @@ -108,6 +137,8 @@ type BeegoHttpRequest struct { params map[string]string files map[string]string setting BeegoHttpSettings + resp *http.Response + body []byte } // Change request settings @@ -123,7 +154,7 @@ func (b *BeegoHttpRequest) SetEnableCookie(enable bool) *BeegoHttpRequest { } // SetUserAgent sets User-Agent header field -func (b *BeegoHttpRequest) SetAgent(useragent string) *BeegoHttpRequest { +func (b *BeegoHttpRequest) SetUserAgent(useragent string) *BeegoHttpRequest { b.setting.UserAgent = useragent return b } @@ -223,6 +254,9 @@ func (b *BeegoHttpRequest) Body(data interface{}) *BeegoHttpRequest { } func (b *BeegoHttpRequest) getResponse() (*http.Response, error) { + if b.resp.StatusCode != 0 { + return b.resp, nil + } var paramBody string if len(b.params) > 0 { var buf bytes.Buffer @@ -341,6 +375,7 @@ func (b *BeegoHttpRequest) getResponse() (*http.Response, error) { if err != nil { return nil, err } + b.resp = resp return resp, nil } @@ -358,6 +393,9 @@ func (b *BeegoHttpRequest) String() (string, error) { // Bytes returns the body []byte in response. // it calls Response inner. func (b *BeegoHttpRequest) Bytes() ([]byte, error) { + if b.body != nil { + return b.body, nil + } resp, err := b.getResponse() if err != nil { return nil, err @@ -370,6 +408,7 @@ func (b *BeegoHttpRequest) Bytes() ([]byte, error) { if err != nil { return nil, err } + b.body = data return data, nil } @@ -391,10 +430,7 @@ func (b *BeegoHttpRequest) ToFile(filename string) error { } defer resp.Body.Close() _, err = io.Copy(f, resp.Body) - if err != nil { - return err - } - return nil + return err } // ToJson returns the map that marshals from the body bytes as json in response . @@ -405,24 +441,18 @@ func (b *BeegoHttpRequest) ToJson(v interface{}) error { return err } err = json.Unmarshal(data, v) - if err != nil { - return err - } - return nil + return err } // ToXml returns the map that marshals from the body bytes as xml in response . // it calls Response inner. -func (b *BeegoHttpRequest) ToXML(v interface{}) error { +func (b *BeegoHttpRequest) ToXml(v interface{}) error { data, err := b.Bytes() if err != nil { return err } err = xml.Unmarshal(data, v) - if err != nil { - return err - } - return nil + return err } // Response executes request client gets response mannually. diff --git a/httplib/httplib_test.go b/httplib/httplib_test.go index 7325862c..2d49d875 100644 --- a/httplib/httplib_test.go +++ b/httplib/httplib_test.go @@ -1,100 +1,193 @@ -// Beego (http://beego.me) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package httplib import ( - "fmt" "io/ioutil" + "os" + "strings" "testing" ) -func TestGetUrl(t *testing.T) { - resp, err := Get("http://beego.me").Debug(true).Response() +func TestResponse(t *testing.T) { + req := Get("http://httpbin.org/get") + resp, err := req.Response() if err != nil { t.Fatal(err) } - if resp.Body == nil { - t.Fatal("body is nil") - } - data, err := ioutil.ReadAll(resp.Body) - defer resp.Body.Close() - if err != nil { - t.Fatal(err) - } - if len(data) == 0 { - t.Fatal("data is no") - } + t.Log(resp) +} - str, err := Get("http://beego.me").String() +func TestGet(t *testing.T) { + req := Get("http://httpbin.org/get") + b, err := req.Bytes() if err != nil { t.Fatal(err) } - if len(str) == 0 { - t.Fatal("has no info") + t.Log(b) + + s, err := req.String() + if err != nil { + t.Fatal(err) + } + t.Log(s) + + if string(b) != s { + t.Fatal("request data not match") } } -func ExamplePost(t *testing.T) { - b := Post("http://beego.me/").Debug(true) - b.Param("username", "astaxie") - b.Param("password", "hello") - b.PostFile("uploadfile", "httplib_test.go") - str, err := b.String() +func TestSimplePost(t *testing.T) { + v := "smallfish" + req := Post("http://httpbin.org/post") + req.Param("username", v) + + str, err := req.String() if err != nil { t.Fatal(err) } - fmt.Println(str) + t.Log(str) + + n := strings.Index(str, v) + if n == -1 { + t.Fatal(v + " not found in post") + } } -func TestSimpleGetString(t *testing.T) { - fmt.Println("TestSimpleGetString==========================================") - html, err := Get("http://httpbin.org/headers").SetAgent("beegoooooo").String() +func TestPostFile(t *testing.T) { + v := "smallfish" + req := Post("http://httpbin.org/post") + req.Param("username", v) + req.PostFile("uploadfile", "httplib_test.go") + + str, err := req.String() if err != nil { t.Fatal(err) } - fmt.Println(html) - fmt.Println("TestSimpleGetString==========================================") + t.Log(str) + + n := strings.Index(str, v) + if n == -1 { + t.Fatal(v + " not found in post") + } } -func TestSimpleGetStringWithDefaultCookie(t *testing.T) { - fmt.Println("TestSimpleGetStringWithDefaultCookie==========================================") - html, err := Get("http://httpbin.org/cookies/set?k1=v1").SetEnableCookie(true).String() +func TestSimplePut(t *testing.T) { + str, err := Put("http://httpbin.org/put").String() if err != nil { t.Fatal(err) } - fmt.Println(html) - html, err = Get("http://httpbin.org/cookies").SetEnableCookie(true).String() - if err != nil { - t.Fatal(err) - } - fmt.Println(html) - fmt.Println("TestSimpleGetStringWithDefaultCookie==========================================") + t.Log(str) } -func TestDefaultSetting(t *testing.T) { - fmt.Println("TestDefaultSetting==========================================") - var def BeegoHttpSettings - def.EnableCookie = true - //def.ShowDebug = true - def.UserAgent = "UserAgent" - //def.ConnectTimeout = 60*time.Second - //def.ReadWriteTimeout = 60*time.Second - def.Transport = nil //http.DefaultTransport - SetDefaultSetting(def) - - html, err := Get("http://httpbin.org/headers").String() +func TestSimpleDelete(t *testing.T) { + str, err := Delete("http://httpbin.org/delete").String() if err != nil { t.Fatal(err) } - fmt.Println(html) - html, err = Get("http://httpbin.org/headers").String() - if err != nil { - t.Fatal(err) - } - fmt.Println(html) - fmt.Println("TestDefaultSetting==========================================") + t.Log(str) +} + +func TestWithCookie(t *testing.T) { + v := "smallfish" + str, err := Get("http://httpbin.org/cookies/set?k1=" + v).SetEnableCookie(true).String() + if err != nil { + t.Fatal(err) + } + t.Log(str) + + str, err = Get("http://httpbin.org/cookies").SetEnableCookie(true).String() + if err != nil { + t.Fatal(err) + } + t.Log(str) + + n := strings.Index(str, v) + if n == -1 { + t.Fatal(v + " not found in cookie") + } +} + +func TestWithUserAgent(t *testing.T) { + v := "beego" + str, err := Get("http://httpbin.org/headers").SetUserAgent(v).String() + if err != nil { + t.Fatal(err) + } + t.Log(str) + + n := strings.Index(str, v) + if n == -1 { + t.Fatal(v + " not found in user-agent") + } +} + +func TestWithSetting(t *testing.T) { + v := "beego" + var setting BeegoHttpSettings + setting.EnableCookie = true + setting.UserAgent = v + setting.Transport = nil + SetDefaultSetting(setting) + + str, err := Get("http://httpbin.org/get").String() + if err != nil { + t.Fatal(err) + } + t.Log(str) + + n := strings.Index(str, v) + if n == -1 { + t.Fatal(v + " not found in user-agent") + } +} + +func TestToJson(t *testing.T) { + req := Get("http://httpbin.org/ip") + resp, err := req.Response() + if err != nil { + t.Fatal(err) + } + t.Log(resp) + + // httpbin will return http remote addr + type Ip struct { + Origin string `json:"origin"` + } + var ip Ip + err = req.ToJson(&ip) + if err != nil { + t.Fatal(err) + } + t.Log(ip.Origin) + + if n := strings.Count(ip.Origin, "."); n != 3 { + t.Fatal("response is not valid ip") + } +} + +func TestToFile(t *testing.T) { + f := "beego_testfile" + req := Get("http://httpbin.org/ip") + err := req.ToFile(f) + if err != nil { + t.Fatal(err) + } + defer os.Remove(f) + b, err := ioutil.ReadFile(f) + if n := strings.Index(string(b), "origin"); n == -1 { + t.Fatal(err) + } } diff --git a/log.go b/log.go index ac72ec34..5afba8ed 100644 --- a/log.go +++ b/log.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package beego @@ -14,12 +22,14 @@ import ( // Log levels to control the logging output. const ( - LevelTrace = iota - LevelDebug - LevelInfo - LevelWarning - LevelError + LevelEmergency = iota + LevelAlert LevelCritical + LevelError + LevelWarning + LevelNotice + LevelInformational + LevelDebug ) // SetLogLevel sets the global log level used by the simple @@ -45,29 +55,12 @@ func SetLogger(adaptername string, config string) error { return nil } -// Trace logs a message at trace level. -func Trace(v ...interface{}) { - BeeLogger.Trace(generateFmtStr(len(v)), v...) +func Emergency(v ...interface{}) { + BeeLogger.Emergency(generateFmtStr(len(v)), v...) } -// Debug logs a message at debug level. -func Debug(v ...interface{}) { - BeeLogger.Debug(generateFmtStr(len(v)), v...) -} - -// Info logs a message at info level. -func Info(v ...interface{}) { - BeeLogger.Info(generateFmtStr(len(v)), v...) -} - -// Warning logs a message at warning level. -func Warn(v ...interface{}) { - BeeLogger.Warn(generateFmtStr(len(v)), v...) -} - -// Error logs a message at error level. -func Error(v ...interface{}) { - BeeLogger.Error(generateFmtStr(len(v)), v...) +func Alert(v ...interface{}) { + BeeLogger.Alert(generateFmtStr(len(v)), v...) } // Critical logs a message at critical level. @@ -75,6 +68,46 @@ func Critical(v ...interface{}) { BeeLogger.Critical(generateFmtStr(len(v)), v...) } +// Error logs a message at error level. +func Error(v ...interface{}) { + BeeLogger.Error(generateFmtStr(len(v)), v...) +} + +// Warning logs a message at warning level. +func Warning(v ...interface{}) { + BeeLogger.Warning(generateFmtStr(len(v)), v...) +} + +// Deprecated: compatibility alias for Warning(), Will be removed in 1.5.0. +func Warn(v ...interface{}) { + Warning(v...) +} + +func Notice(v ...interface{}) { + BeeLogger.Notice(generateFmtStr(len(v)), v...) +} + +// Info logs a message at info level. +func Informational(v ...interface{}) { + BeeLogger.Informational(generateFmtStr(len(v)), v...) +} + +// Deprecated: compatibility alias for Warning(), Will be removed in 1.5.0. +func Info(v ...interface{}) { + Informational(v...) +} + +// Debug logs a message at debug level. +func Debug(v ...interface{}) { + BeeLogger.Debug(generateFmtStr(len(v)), v...) +} + +// Trace logs a message at trace level. +// Deprecated: compatibility alias for Warning(), Will be removed in 1.5.0. +func Trace(v ...interface{}) { + BeeLogger.Trace(generateFmtStr(len(v)), v...) +} + func generateFmtStr(n int) string { return strings.Repeat("%v ", n) } diff --git a/logs/conn.go b/logs/conn.go index 588e73f4..612634fa 100644 --- a/logs/conn.go +++ b/logs/conn.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package logs @@ -45,7 +53,7 @@ func (c *ConnWriter) Init(jsonconfig string) error { // write message in connection. // if connection is down, try to re-connect. func (c *ConnWriter) WriteMsg(msg string, level int) error { - if level < c.Level { + if level > c.Level { return nil } if c.neddedConnectOnMsg() { diff --git a/logs/conn_test.go b/logs/conn_test.go index e05cbe05..747fb890 100644 --- a/logs/conn_test.go +++ b/logs/conn_test.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package logs @@ -13,5 +21,5 @@ import ( func TestConn(t *testing.T) { log := NewLogger(1000) log.SetLogger("conn", `{"net":"tcp","addr":":7020"}`) - log.Info("info") + log.Informational("informational") } diff --git a/logs/console.go b/logs/console.go index 9316a55e..461291c2 100644 --- a/logs/console.go +++ b/logs/console.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package logs @@ -24,12 +32,14 @@ func NewBrush(color string) Brush { } var colors = []Brush{ - NewBrush("1;36"), // Trace cyan - NewBrush("1;34"), // Debug blue - NewBrush("1;32"), // Info green - NewBrush("1;33"), // Warn yellow + NewBrush("1;37"), // Emergency white + NewBrush("1;36"), // Alert cyan + NewBrush("1;35"), // Critical magenta NewBrush("1;31"), // Error red - NewBrush("1;35"), // Critical purple + NewBrush("1;33"), // Warning yellow + NewBrush("1;32"), // Notice green + NewBrush("1;34"), // Informational blue + NewBrush("1;34"), // Debug blue } // ConsoleWriter implements LoggerInterface and writes messages to terminal. @@ -42,7 +52,7 @@ type ConsoleWriter struct { func NewConsole() LoggerInterface { cw := new(ConsoleWriter) cw.lg = log.New(os.Stdout, "", log.Ldate|log.Ltime) - cw.Level = LevelTrace + cw.Level = LevelDebug return cw } @@ -61,7 +71,7 @@ func (c *ConsoleWriter) Init(jsonconfig string) error { // write message in console. func (c *ConsoleWriter) WriteMsg(msg string, level int) error { - if level < c.Level { + if level > c.Level { return nil } if goos := runtime.GOOS; goos == "windows" { diff --git a/logs/console_test.go b/logs/console_test.go index a8c942c1..2fad7241 100644 --- a/logs/console_test.go +++ b/logs/console_test.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package logs @@ -10,22 +18,29 @@ import ( "testing" ) +// Try each log level in decreasing order of priority. +func testConsoleCalls(bl *BeeLogger) { + bl.Emergency("emergency") + bl.Alert("alert") + bl.Critical("critical") + bl.Error("error") + bl.Warning("warning") + bl.Notice("notice") + bl.Informational("informational") + bl.Debug("debug") +} + +// Test console logging by visually comparing the lines being output with and +// without a log level specification. func TestConsole(t *testing.T) { - log := NewLogger(10000) - log.EnableFuncCallDepth(true) - log.SetLogger("console", "") - log.Trace("trace") - log.Info("info") - log.Warn("warning") - log.Debug("debug") - log.Critical("critical") + log1 := NewLogger(10000) + log1.EnableFuncCallDepth(true) + log1.SetLogger("console", "") + testConsoleCalls(log1) + log2 := NewLogger(100) - log2.SetLogger("console", `{"level":1}`) - log.Trace("trace") - log.Info("info") - log.Warn("warning") - log.Debug("debug") - log.Critical("critical") + log2.SetLogger("console", `{"level":3}`) + testConsoleCalls(log2) } func BenchmarkConsole(b *testing.B) { @@ -33,6 +48,6 @@ func BenchmarkConsole(b *testing.B) { log.EnableFuncCallDepth(true) log.SetLogger("console", "") for i := 0; i < b.N; i++ { - log.Trace("trace") + log.Debug("debug") } } diff --git a/logs/file.go b/logs/file.go index f5cbb9ff..e80b955c 100644 --- a/logs/file.go +++ b/logs/file.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package logs @@ -138,7 +146,7 @@ func (w *FileLogWriter) docheck(size int) { // write logger message into file. func (w *FileLogWriter) WriteMsg(msg string, level int) error { - if level < w.Level { + if level > w.Level { return nil } n := 24 + len(msg) // 24 stand for the length "2013/06/23 21:00:22 [T] " diff --git a/logs/file_test.go b/logs/file_test.go index 90349ec6..c71e9bb4 100644 --- a/logs/file_test.go +++ b/logs/file_test.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package logs @@ -10,6 +18,7 @@ import ( "bufio" "fmt" "os" + "strconv" "testing" "time" ) @@ -17,12 +26,14 @@ import ( func TestFile(t *testing.T) { log := NewLogger(10000) log.SetLogger("file", `{"filename":"test.log"}`) - log.Trace("test") - log.Info("info") log.Debug("debug") - log.Warn("warning") + log.Informational("info") + log.Notice("notice") + log.Warning("warning") log.Error("error") + log.Alert("alert") log.Critical("critical") + log.Emergency("emergency") time.Sleep(time.Second * 4) f, err := os.Open("test.log") if err != nil { @@ -39,21 +50,24 @@ func TestFile(t *testing.T) { linenum++ } } - if linenum != 6 { - t.Fatal(linenum, "not line 6") + var expected = LevelDebug + 1 + if linenum != expected { + t.Fatal(linenum, "not "+strconv.Itoa(expected)+" lines") } os.Remove("test.log") } func TestFile2(t *testing.T) { log := NewLogger(10000) - log.SetLogger("file", `{"filename":"test2.log","level":2}`) - log.Trace("test") - log.Info("info") + log.SetLogger("file", fmt.Sprintf(`{"filename":"test2.log","level":%d}`, LevelError)) log.Debug("debug") - log.Warn("warning") + log.Info("info") + log.Notice("notice") + log.Warning("warning") log.Error("error") + log.Alert("alert") log.Critical("critical") + log.Emergency("emergency") time.Sleep(time.Second * 4) f, err := os.Open("test2.log") if err != nil { @@ -70,8 +84,9 @@ func TestFile2(t *testing.T) { linenum++ } } - if linenum != 4 { - t.Fatal(linenum, "not line 4") + var expected = LevelError + 1 + if linenum != expected { + t.Fatal(linenum, "not "+strconv.Itoa(expected)+" lines") } os.Remove("test2.log") } @@ -79,17 +94,19 @@ func TestFile2(t *testing.T) { func TestFileRotate(t *testing.T) { log := NewLogger(10000) log.SetLogger("file", `{"filename":"test3.log","maxlines":4}`) - log.Trace("test") - log.Info("info") log.Debug("debug") - log.Warn("warning") + log.Info("info") + log.Notice("notice") + log.Warning("warning") log.Error("error") + log.Alert("alert") log.Critical("critical") + log.Emergency("emergency") time.Sleep(time.Second * 4) rotatename := "test3.log" + fmt.Sprintf(".%s.%03d", time.Now().Format("2006-01-02"), 1) b, err := exists(rotatename) if !b || err != nil { - t.Fatal("rotate not gen") + t.Fatal("rotate not generated") } os.Remove(rotatename) os.Remove("test3.log") @@ -110,7 +127,7 @@ func BenchmarkFile(b *testing.B) { log := NewLogger(100000) log.SetLogger("file", `{"filename":"test4.log"}`) for i := 0; i < b.N; i++ { - log.Trace("trace") + log.Debug("debug") } os.Remove("test4.log") } diff --git a/logs/log.go b/logs/log.go index 423f9ec3..4349e8a5 100644 --- a/logs/log.go +++ b/logs/log.go @@ -1,9 +1,35 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// Usage: +// +// import "github.com/astaxie/beego/logs" +// +// log := NewLogger(10000) +// log.SetLogger("console", "") +// +// > the first params stand for how many channel +// +// Use it like this: +// +// log.Trace("trace") +// log.Info("info") +// log.Warn("warning") +// log.Debug("debug") +// log.Critical("critical") +// +// more docs http://beego.me/docs/module/logs.md package logs import ( @@ -13,14 +39,25 @@ import ( "sync" ) +// RFC5424 log message levels. const ( - // log message levels - LevelTrace = iota - LevelDebug - LevelInfo - LevelWarn - LevelError + LevelEmergency = iota + LevelAlert LevelCritical + LevelError + LevelWarning + LevelNotice + LevelInformational + LevelDebug +) + +// Legacy loglevel constants to ensure backwards compatibility. +// +// Deprecated: will be removed in 1.5.0. +const ( + LevelInfo = LevelInformational + LevelTrace = LevelDebug + LevelWarn = LevelWarning ) type loggerType func() LoggerInterface @@ -69,6 +106,7 @@ type logMsg struct { // if the buffering chan is full, logger adapters write to file or other way. func NewLogger(channellen int64) *BeeLogger { bl := new(BeeLogger) + bl.level = LevelDebug bl.loggerFuncCallDepth = 2 bl.msg = make(chan *logMsg, channellen) bl.outputs = make(map[string]LoggerInterface) @@ -110,7 +148,7 @@ func (bl *BeeLogger) DelLogger(adaptername string) error { } func (bl *BeeLogger) writerMsg(loglevel int, msg string) error { - if bl.level > loglevel { + if loglevel > bl.level { return nil } lm := new(logMsg) @@ -130,8 +168,10 @@ func (bl *BeeLogger) writerMsg(loglevel int, msg string) error { return nil } -// set log message level. -// if message level (such as LevelTrace) is less than logger level (such as LevelWarn), ignore message. +// Set log message level. +// +// If message level (such as LevelDebug) is higher than logger level (such as LevelWarning), +// log providers will not even be sent the message. func (bl *BeeLogger) SetLevel(l int) { bl.level = l } @@ -147,7 +187,7 @@ func (bl *BeeLogger) EnableFuncCallDepth(b bool) { } // start logger chan reading. -// when chan is full, write logs. +// when chan is not empty, write logs. func (bl *BeeLogger) startLogger() { for { select { @@ -159,40 +199,73 @@ func (bl *BeeLogger) startLogger() { } } -// log trace level message. -func (bl *BeeLogger) Trace(format string, v ...interface{}) { - msg := fmt.Sprintf("[T] "+format, v...) - bl.writerMsg(LevelTrace, msg) -} - -// log debug level message. -func (bl *BeeLogger) Debug(format string, v ...interface{}) { +// Log EMERGENCY level message. +func (bl *BeeLogger) Emergency(format string, v ...interface{}) { msg := fmt.Sprintf("[D] "+format, v...) - bl.writerMsg(LevelDebug, msg) + bl.writerMsg(LevelEmergency, msg) } -// log info level message. -func (bl *BeeLogger) Info(format string, v ...interface{}) { - msg := fmt.Sprintf("[I] "+format, v...) - bl.writerMsg(LevelInfo, msg) +// Log ALERT level message. +func (bl *BeeLogger) Alert(format string, v ...interface{}) { + msg := fmt.Sprintf("[D] "+format, v...) + bl.writerMsg(LevelAlert, msg) } -// log warn level message. -func (bl *BeeLogger) Warn(format string, v ...interface{}) { - msg := fmt.Sprintf("[W] "+format, v...) - bl.writerMsg(LevelWarn, msg) +// Log CRITICAL level message. +func (bl *BeeLogger) Critical(format string, v ...interface{}) { + msg := fmt.Sprintf("[C] "+format, v...) + bl.writerMsg(LevelCritical, msg) } -// log error level message. +// Log ERROR level message. func (bl *BeeLogger) Error(format string, v ...interface{}) { msg := fmt.Sprintf("[E] "+format, v...) bl.writerMsg(LevelError, msg) } -// log critical level message. -func (bl *BeeLogger) Critical(format string, v ...interface{}) { - msg := fmt.Sprintf("[C] "+format, v...) - bl.writerMsg(LevelCritical, msg) +// Log WARNING level message. +func (bl *BeeLogger) Warning(format string, v ...interface{}) { + msg := fmt.Sprintf("[W] "+format, v...) + bl.writerMsg(LevelWarning, msg) +} + +// Log NOTICE level message. +func (bl *BeeLogger) Notice(format string, v ...interface{}) { + msg := fmt.Sprintf("[W] "+format, v...) + bl.writerMsg(LevelNotice, msg) +} + +// Log INFORMATIONAL level message. +func (bl *BeeLogger) Informational(format string, v ...interface{}) { + msg := fmt.Sprintf("[I] "+format, v...) + bl.writerMsg(LevelInformational, msg) +} + +// Log DEBUG level message. +func (bl *BeeLogger) Debug(format string, v ...interface{}) { + msg := fmt.Sprintf("[D] "+format, v...) + bl.writerMsg(LevelDebug, msg) +} + +// Log WARN level message. +// +// Deprecated: compatibility alias for Warning(), Will be removed in 1.5.0. +func (bl *BeeLogger) Warn(format string, v ...interface{}) { + bl.Warning(format, v...) +} + +// Log INFO level message. +// +// Deprecated: compatibility alias for Informational(), Will be removed in 1.5.0. +func (bl *BeeLogger) Info(format string, v ...interface{}) { + bl.Informational(format, v...) +} + +// Log TRACE level message. +// +// Deprecated: compatibility alias for Debug(), Will be removed in 1.5.0. +func (bl *BeeLogger) Trace(format string, v ...interface{}) { + bl.Debug(format, v...) } // flush all chan data. diff --git a/logs/smtp.go b/logs/smtp.go index 2b9e50a0..3373d7f4 100644 --- a/logs/smtp.go +++ b/logs/smtp.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package logs @@ -51,22 +59,30 @@ func (s *SmtpWriter) Init(jsonconfig string) error { return nil } +func (s *SmtpWriter) GetSmtpAuth(host string) smtp.Auth { + if len(strings.Trim(s.Username, " ")) == 0 && len(strings.Trim(s.Password, " ")) == 0 { + return nil + } + return smtp.PlainAuth( + "", + s.Username, + s.Password, + host, + ) +} + // write message in smtp writer. // it will send an email with subject and only this message. func (s *SmtpWriter) WriteMsg(msg string, level int) error { - if level < s.Level { + if level > s.Level { return nil } hp := strings.Split(s.Host, ":") // Set up authentication information. - auth := smtp.PlainAuth( - "", - s.Username, - s.Password, - hp[0], - ) + auth := s.GetSmtpAuth(hp[0]) + // Connect to the server, authenticate, set the sender and recipient, // and send the email all in one step. content_type := "Content-Type: text/plain" + "; charset=UTF-8" diff --git a/logs/smtp_test.go b/logs/smtp_test.go index cb8d3009..28e762d2 100644 --- a/logs/smtp_test.go +++ b/logs/smtp_test.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package logs diff --git a/memzipfile.go b/memzipfile.go index 92d6003a..cc5e3851 100644 --- a/memzipfile.go +++ b/memzipfile.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package beego diff --git a/middleware/error.go b/middleware/error.go index 3aff9a80..3b7191e9 100644 --- a/middleware/error.go +++ b/middleware/error.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package middleware @@ -311,6 +319,7 @@ func Exception(errcode string, w http.ResponseWriter, r *http.Request, msg strin if err != nil { isint = 500 } + w.Header().Set("Content-Type", "text/html; charset=utf-8") w.WriteHeader(isint) h(w, r) return diff --git a/middleware/exceptions.go b/middleware/exceptions.go index 09cb46cb..a08a7358 100644 --- a/middleware/exceptions.go +++ b/middleware/exceptions.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package middleware diff --git a/middleware/i18n.go b/middleware/i18n.go index 10ec12bb..e4dab693 100644 --- a/middleware/i18n.go +++ b/middleware/i18n.go @@ -1,90 +1,71 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// Usage: +// +// import "github.com/astaxie/beego/middleware" +// +// I18N = middleware.NewLocale("conf/i18n.conf", beego.AppConfig.String("language")) +// +// more docs: http://beego.me/docs/module/i18n.md package middleware -//import ( -// "github.com/astaxie/beego/config" -// "os" -// "path" -//) +import ( + "encoding/json" + "io/ioutil" + "os" +) -//type Translation struct { -// filetype string -// CurrentLocal string -// Locales map[string]map[string]string -//} +type Translation struct { + filepath string + CurrentLocal string + Locales map[string]map[string]string +} -//func NewLocale(filetype string) *Translation { -// return &Translation{ -// filetype: filetype, -// CurrentLocal: "zh", -// Locales: make(map[string]map[string]string), -// } -//} +func NewLocale(filepath string, defaultlocal string) *Translation { + i18n := make(map[string]map[string]string) + file, err := os.Open(filepath) + if err != nil { + panic("open " + filepath + " err :" + err.Error()) + } + data, err := ioutil.ReadAll(file) + if err != nil { + panic("read " + filepath + " err :" + err.Error()) + } + err = json.Unmarshal(data, &i18n) + if err != nil { + panic("json.Unmarshal " + filepath + " err :" + err.Error()) + } + return &Translation{ + filepath: filepath, + CurrentLocal: defaultlocal, + Locales: i18n, + } +} -//func (t *Translation) loadTranslations(dirPath string) error { -// dir, err := os.Open(dirPath) -// if err != nil { -// return err -// } -// defer dir.Close() +func (t *Translation) SetLocale(local string) { + t.CurrentLocal = local +} -// names, err := dir.Readdirnames(-1) -// if err != nil { -// return err -// } - -// for _, name := range names { -// fullPath := path.Join(dirPath, name) - -// fi, err := os.Stat(fullPath) -// if err != nil { -// return err -// } - -// if fi.IsDir() { -// continue -// } else { -// if err := t.loadTranslation(fullPath, name); err != nil { -// return err -// } -// } -// } - -// return nil -//} - -//func (t *Translation) loadTranslation(fullPath, locale string) error { - -// sourceKey2Trans, ok := t.Locales[locale] -// if !ok { -// sourceKey2Trans = make(map[string]string) - -// t.Locales[locale] = sourceKey2Trans -// } - -// for _, m := range trf.Messages { -// if m.Translation != "" { -// sourceKey2Trans[sourceKey(m.Source, m.Context)] = m.Translation -// } -// } - -// return nil -//} - -//func (t *Translation) SetLocale(local string) { -// t.CurrentLocal = local -//} - -//func (t *Translation) Translate(key string) string { -// if ct, ok := t.Locales[t.CurrentLocal]; ok { -// if v, o := ct[key]; o { -// return v -// } -// } -// return key -//} +func (t *Translation) Translate(key string, local string) string { + if local == "" { + local = t.CurrentLocal + } + if ct, ok := t.Locales[key]; ok { + if v, o := ct[local]; o { + return v + } + } + return key +} diff --git a/migration/migration.go b/migration/migration.go new file mode 100644 index 00000000..d64d60d3 --- /dev/null +++ b/migration/migration.go @@ -0,0 +1,280 @@ +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// migration package for migration +// +// The table structure is as follow: +// +// CREATE TABLE `migrations` ( +// `id_migration` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'surrogate key', +// `name` varchar(255) DEFAULT NULL COMMENT 'migration name, unique', +// `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'date migrated or rolled back', +// `statements` longtext COMMENT 'SQL statements for this migration', +// `rollback_statements` longtext, +// `status` enum('update','rollback') DEFAULT NULL COMMENT 'update indicates it is a normal migration while rollback means this migration is rolled back', +// PRIMARY KEY (`id_migration`) +// ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +package migration + +import ( + "errors" + "sort" + "strings" + "time" + + "github.com/astaxie/beego" + "github.com/astaxie/beego/orm" +) + +// const the data format for the bee generate migration datatype +const ( + M_DATE_FORMAT = "20060102_150405" + M_DB_DATE_FORMAT = "2006-01-02 15:04:05" +) + +// Migrationer is an interface for all Migration struct +type Migrationer interface { + Up() + Down() + Reset() + Exec(name, status string) error + GetCreated() int64 +} + +var ( + migrationMap map[string]Migrationer +) + +func init() { + migrationMap = make(map[string]Migrationer) +} + +// the basic type which will implement the basic type +type Migration struct { + sqls []string + Created string +} + +// implement in the Inheritance struct for upgrade +func (m *Migration) Up() { + +} + +// implement in the Inheritance struct for down +func (m *Migration) Down() { + +} + +// add sql want to execute +func (m *Migration) Sql(sql string) { + m.sqls = append(m.sqls, sql) +} + +// Reset the sqls +func (m *Migration) Reset() { + m.sqls = make([]string, 0) +} + +// execute the sql already add in the sql +func (m *Migration) Exec(name, status string) error { + o := orm.NewOrm() + for _, s := range m.sqls { + beego.Info("exec sql:", s) + r := o.Raw(s) + _, err := r.Exec() + if err != nil { + return err + } + } + return m.addOrUpdateRecord(name, status) +} + +func (m *Migration) addOrUpdateRecord(name, status string) error { + o := orm.NewOrm() + if status == "down" { + status = "rollback" + p, err := o.Raw("update migrations set `status` = ?, `rollback_statements` = ?, `created_at` = ? where name = ?").Prepare() + if err != nil { + return nil + } + _, err = p.Exec(status, strings.Join(m.sqls, "; "), time.Now().Format(M_DB_DATE_FORMAT), name) + return err + } else { + status = "update" + p, err := o.Raw("insert into migrations(`name`, `created_at`, `statements`, `status`) values(?,?,?,?)").Prepare() + if err != nil { + return err + } + _, err = p.Exec(name, time.Now().Format(M_DB_DATE_FORMAT), strings.Join(m.sqls, "; "), status) + return err + } +} + +// get the unixtime from the Created +func (m *Migration) GetCreated() int64 { + t, err := time.Parse(M_DATE_FORMAT, m.Created) + if err != nil { + return 0 + } + return t.Unix() +} + +// register the Migration in the map +func Register(name string, m Migrationer) error { + if _, ok := migrationMap[name]; ok { + return errors.New("already exist name:" + name) + } + migrationMap[name] = m + return nil +} + +// upgrate the migration from lasttime +func Upgrade(lasttime int64) error { + sm := sortMap(migrationMap) + i := 0 + for _, v := range sm { + if v.created > lasttime { + beego.Info("start upgrade", v.name) + v.m.Reset() + v.m.Up() + err := v.m.Exec(v.name, "up") + if err != nil { + beego.Error("execute error:", err) + time.Sleep(2 * time.Second) + return err + } + beego.Info("end upgrade:", v.name) + i++ + } + } + beego.Info("total success upgrade:", i, " migration") + time.Sleep(2 * time.Second) + return nil +} + +//rollback the migration by the name +func Rollback(name string) error { + if v, ok := migrationMap[name]; ok { + beego.Info("start rollback") + v.Reset() + v.Down() + err := v.Exec(name, "down") + if err != nil { + beego.Error("execute error:", err) + time.Sleep(2 * time.Second) + return err + } + beego.Info("end rollback") + time.Sleep(2 * time.Second) + return nil + } else { + beego.Error("not exist the migrationMap name:" + name) + time.Sleep(2 * time.Second) + return errors.New("not exist the migrationMap name:" + name) + } +} + +// reset all migration +// run all migration's down function +func Reset() error { + sm := sortMap(migrationMap) + i := 0 + for j := len(sm) - 1; j >= 0; j-- { + v := sm[j] + if isRollBack(v.name) { + beego.Info("skip the", v.name) + time.Sleep(1 * time.Second) + continue + } + beego.Info("start reset:", v.name) + v.m.Reset() + v.m.Down() + err := v.m.Exec(v.name, "down") + if err != nil { + beego.Error("execute error:", err) + time.Sleep(2 * time.Second) + return err + } + i++ + beego.Info("end reset:", v.name) + } + beego.Info("total success reset:", i, " migration") + time.Sleep(2 * time.Second) + return nil +} + +// first Reset, then Upgrade +func Refresh() error { + err := Reset() + if err != nil { + beego.Error("execute error:", err) + time.Sleep(2 * time.Second) + return err + } + err = Upgrade(0) + return err +} + +type dataSlice []data + +type data struct { + created int64 + name string + m Migrationer +} + +// Len is part of sort.Interface. +func (d dataSlice) Len() int { + return len(d) +} + +// Swap is part of sort.Interface. +func (d dataSlice) Swap(i, j int) { + d[i], d[j] = d[j], d[i] +} + +// Less is part of sort.Interface. We use count as the value to sort by +func (d dataSlice) Less(i, j int) bool { + return d[i].created < d[j].created +} + +func sortMap(m map[string]Migrationer) dataSlice { + s := make(dataSlice, 0, len(m)) + for k, v := range m { + d := data{} + d.created = v.GetCreated() + d.name = k + d.m = v + s = append(s, d) + } + sort.Sort(s) + return s +} + +func isRollBack(name string) bool { + o := orm.NewOrm() + var maps []orm.Params + num, err := o.Raw("select * from migrations where `name` = ? order by id_migration desc", name).Values(&maps) + if err != nil { + beego.Info("get name has error", err) + return false + } + if num <= 0 { + return false + } + if maps[0]["status"] == "rollback" { + return true + } + return false +} diff --git a/mime.go b/mime.go index f611a16e..155e5e12 100644 --- a/mime.go +++ b/mime.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package beego diff --git a/namespace.go b/namespace.go index 512afd69..d0109291 100644 --- a/namespace.go +++ b/namespace.go @@ -1,8 +1,17 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package beego import ( diff --git a/namespace_test.go b/namespace_test.go index 9142d62c..a92ae3ef 100644 --- a/namespace_test.go +++ b/namespace_test.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package beego diff --git a/orm/README.md b/orm/README.md index d4721307..74f1b47b 100644 --- a/orm/README.md +++ b/orm/README.md @@ -154,10 +154,5 @@ note: not recommend use this in product env. more details and examples in docs and test -* [中文](http://beego.me/docs/Models_Overview?lang=zh) -* [English](http://beego.me/docs/Models_Overview?lang=en) +[documents](http://beego.me/docs/mvc/model/overview.md) -## TODO -- some unrealized api -- examples -- docs diff --git a/orm/cmd.go b/orm/cmd.go index ecfc3bd5..2358ef3c 100644 --- a/orm/cmd.go +++ b/orm/cmd.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors slene +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package orm diff --git a/orm/cmd_utils.go b/orm/cmd_utils.go index 63cc5a64..8304da6b 100644 --- a/orm/cmd_utils.go +++ b/orm/cmd_utils.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors slene +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package orm @@ -144,6 +152,10 @@ func getDbCreateSql(al *alias) (sqls []string, tableIndexes map[string][]dbIndex column += " " + "NOT NULL" } + //if fi.initial.String() != "" { + // column += " DEFAULT " + fi.initial.String() + //} + if fi.unique { column += " " + "UNIQUE" } diff --git a/orm/db.go b/orm/db.go index d8301b75..2addff22 100644 --- a/orm/db.go +++ b/orm/db.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors slene +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package orm diff --git a/orm/db_alias.go b/orm/db_alias.go index f9d0ab5a..0a862241 100644 --- a/orm/db_alias.go +++ b/orm/db_alias.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors slene +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package orm @@ -136,7 +144,7 @@ func detectTZ(al *alias) { if engine != "" { al.Engine = engine } else { - engine = "INNODB" + al.Engine = "INNODB" } case DR_Sqlite: diff --git a/orm/db_mysql.go b/orm/db_mysql.go index 33a01ba4..3c2ad3a4 100644 --- a/orm/db_mysql.go +++ b/orm/db_mysql.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors slene +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package orm diff --git a/orm/db_oracle.go b/orm/db_oracle.go index d2253758..1e385c9a 100644 --- a/orm/db_oracle.go +++ b/orm/db_oracle.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors slene +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package orm diff --git a/orm/db_postgres.go b/orm/db_postgres.go index 463150dc..296ee6a0 100644 --- a/orm/db_postgres.go +++ b/orm/db_postgres.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors slene +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package orm diff --git a/orm/db_sqlite.go b/orm/db_sqlite.go index 94c74a69..0a2f32c8 100644 --- a/orm/db_sqlite.go +++ b/orm/db_sqlite.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors slene +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package orm diff --git a/orm/db_tables.go b/orm/db_tables.go index 690b4eaa..a9aa10ab 100644 --- a/orm/db_tables.go +++ b/orm/db_tables.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors slene +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package orm diff --git a/orm/db_utils.go b/orm/db_utils.go index 8f963f5e..4a3ba464 100644 --- a/orm/db_utils.go +++ b/orm/db_utils.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors slene +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package orm diff --git a/orm/docs/zh/Cmd.md b/orm/docs/zh/Cmd.md deleted file mode 100644 index 932cb1c6..00000000 --- a/orm/docs/zh/Cmd.md +++ /dev/null @@ -1,43 +0,0 @@ -## 命令模式 - -注册模型与数据库以后,调用 RunCommand 执行 orm 命令 - -```go -func main() { - // orm.RegisterModel... - // orm.RegisterDataBase... - ... - orm.RunCommand() -} -``` - -```bash -go build main.go -./main orm -# 直接执行可以显示帮助 -# 如果你的程序可以支持的话,直接运行 go run main.go orm 也是一样的效果 -``` - -## 自动建表 - -```bash -./main orm syncdb -h -Usage of orm command: syncdb: - -db="default": DataBase alias name - -force=false: drop tables before create - -v=false: verbose info -``` - -使用 `-force=1` 可以 drop table 后再建表 - -使用 `-v` 可以查看执行的 sql 语句 - -## 打印建表SQL - -```bash -./main orm sqlall -h -Usage of orm command: syncdb: - -db="default": DataBase alias name -``` - -默认使用别名为 default 的数据库 diff --git a/orm/docs/zh/CustomFields.md b/orm/docs/zh/CustomFields.md deleted file mode 100644 index 3a3c835c..00000000 --- a/orm/docs/zh/CustomFields.md +++ /dev/null @@ -1,38 +0,0 @@ -## Custom Fields - - TypeBooleanField = 1 << iota - - // string - TypeCharField - - // string - TypeTextField - - // time.Time - TypeDateField - // time.Time - TypeDateTimeField - - // int16 - TypeSmallIntegerField - // int32 - TypeIntegerField - // int64 - TypeBigIntegerField - // uint16 - TypePositiveSmallIntegerField - // uint32 - TypePositiveIntegerField - // uint64 - TypePositiveBigIntegerField - - // float64 - TypeFloatField - // float64 - TypeDecimalField - - RelForeignKey - RelOneToOne - RelManyToMany - RelReverseOne - RelReverseMany \ No newline at end of file diff --git a/orm/docs/zh/Models.md b/orm/docs/zh/Models.md deleted file mode 100644 index c8263822..00000000 --- a/orm/docs/zh/Models.md +++ /dev/null @@ -1,288 +0,0 @@ -## 模型定义 - -复杂的模型定义不是必须的,此功能用作数据库数据转换和[自动建表](Cmd.md#自动建表) - -默认的表名使用驼峰转蛇形,比如 AuthUser -> auth_user - -**自定义表名** - -```go -type User struct { - Id int - Name string -} - -func (u *User) TableName() string { - return "auth_user" -} -``` - -如果[前缀设置](Orm.md#registermodelwithprefix)为`prefix_`那么表名为:prefix_auth_user - -## Struct Tag 设置参数 -```go -orm:"null;rel(fk)" -``` - -多个设置间使用 `;` 分隔,设置的值如果是多个,使用 `,` 分隔。 - -#### 忽略字段 - -设置 `-` 即可忽略 struct 中的字段 - -```go -type User struct { -... - AnyField string `orm:"-"` -... -``` - -#### auto - -当 Field 类型为 int, int32, int64 时,可以设置字段为自增健 - -当模型定义里没有主键时,符合上述类型且名称为 `Id` 的 Field 将被视为自增健。 - -#### pk - -设置为主键,适用于自定义其他类型为主键 - -#### null - -数据库表默认为 `NOT NULL`,设置 null 代表 `ALLOW NULL` - -#### blank - -设置 string 类型的字段允许为空,否则 clean 会返回错误 - -#### index - -为字段增加索引 - -#### unique - -为字段增加 unique 键 - -#### column - -为字段设置 db 字段的名称 -```go -Name `orm:"column(user_name)"` -``` -#### default - -为字段设置默认值,类型必须符合 -```go -type User struct { - ... - Status int `orm:"default(1)"` -``` -#### size - -string 类型字段默认为 varchar(255) - -设置 size 以后,db type 将使用 varchar(size) - -```go -Title string `orm:"size(60)"` -``` -#### digits / decimals - -设置 float32, float64 类型的浮点精度 -```go -Money float64 `orm:"digits(12);decimals(4)"` -``` -总长度 12 小数点后 4 位 eg: `99999999.9999` - -#### auto_now / auto_now_add -```go -Created time.Time `auto_now_add` -Updated time.Time `auto_now` -``` -* auto_now 每次 model 保存时都会对时间自动更新 -* auto_now_add 第一次保存时才设置时间 - -对于批量的 update 此设置是不生效的 - -#### type - -设置为 date 时,time.Time 字段的对应 db 类型使用 date - -```go -Created time.Time `orm:"auto_now_add;type(date)"` -``` - -设置为 text 时,string 字段对应的 db 类型使用 text - -```go -Content string `orm:"type(text)"` -``` - -## 表关系设置 - -#### rel / reverse - -**RelOneToOne**: -```go -type User struct { - ... - Profile *Profile `orm:"null;rel(one);on_delete(set_null)"` -``` -对应的反向关系 **RelReverseOne**: -```go -type Profile struct { - ... - User *User `orm:"reverse(one)" json:"-"` -``` -**RelForeignKey**: -```go -type Post struct { - ... - User*User `orm:"rel(fk)"` // RelForeignKey relation -``` -对应的反向关系 **RelReverseMany**: -```go -type User struct { - ... - Posts []*Post `orm:"reverse(many)" json:"-"` // fk 的反向关系 -``` -**RelManyToMany**: -```go -type Post struct { - ... - Tags []*Tag `orm:"rel(m2m)"` // ManyToMany relation -``` -对应的反向关系 **RelReverseMany**: -```go -type Tag struct { - ... - Posts []*Post `orm:"reverse(many)" json:"-"` -``` -#### rel_table / rel_through - -此设置针对 `orm:"rel(m2m)"` 的关系字段 - - rel_table 设置自动生成的 m2m 关系表的名称 - rel_through 如果要在 m2m 关系中使用自定义的 m2m 关系表 - 通过这个设置其名称,格式为 pkg.path.ModelName - eg: app.models.PostTagRel - PostTagRel 表需要有到 Post 和 Tag 的关系 - -当设置 rel_table 时会忽略 rel_through - -#### on_delete - -设置对应的 rel 关系删除时,如何处理关系字段。 - - cascade 级联删除(默认值) - set_null 设置为 NULL,需要设置 null = true - set_default 设置为默认值,需要设置 default 值 - do_nothing 什么也不做,忽略 - -```go -type User struct { - ... - Profile *Profile `orm:"null;rel(one);on_delete(set_null)"` -... -type Profile struct { - ... - User *User `orm:"reverse(one)" json:"-"` - -// 删除 Profile 时将设置 User.Profile 的数据库字段为 NULL -``` - - -## 模型字段与数据库类型的对应 - -在此列出 orm 推荐的对应数据库类型,自动建表功能也会以此为标准。 - -默认所有的字段都是 **NOT NULL** - -#### MySQL - -| go |mysql -| :--- | :--- -| int, int32, int64 - 设置 auto 或者名称为 `Id` 时 | integer AUTO_INCREMENT -| bool | bool -| string - 默认为 size 255 | varchar(size) -| string - 设置 type(text) 时 | longtext -| time.Time - 设置 type 为 date 时 | date -| time.TIme | datetime -| byte | tinyint unsigned -| rune | integer -| int | integer -| int8 | tinyint -| int16 | smallint -| int32 | integer -| int64 | bigint -| uint | integer unsigned -| uint8 | tinyint unsigned -| uint16 | smallint unsigned -| uint32 | integer unsigned -| uint64 | bigint unsigned -| float32 | double precision -| float64 | double precision -| float64 - 设置 digits, decimals 时 | numeric(digits, decimals) - -#### Sqlite3 - -| go | sqlite3 -| :--- | :--- -| int, int32, int64 - 设置 auto 或者名称为 `Id` 时 | integer AUTOINCREMENT -| bool | bool -| string - 默认为 size 255 | varchar(size) -| string - 设置 type(text) 时 | text -| time.Time - 设置 type 为 date 时 | date -| time.TIme | datetime -| byte | tinyint unsigned -| rune | integer -| int | integer -| int8 | tinyint -| int16 | smallint -| int32 | integer -| int64 | bigint -| uint | integer unsigned -| uint8 | tinyint unsigned -| uint16 | smallint unsigned -| uint32 | integer unsigned -| uint64 | bigint unsigned -| float32 | real -| float64 | real -| float64 - 设置 digits, decimals 时 | decimal - -#### PostgreSQL - -| go | postgres -| :--- | :--- -| int, int32, int64 - 设置 auto 或者名称为 `Id` 时 | serial -| bool | bool -| string - 默认为 size 255 | varchar(size) -| string - 设置 type(text) 时 | text -| time.Time - 设置 type 为 date 时 | date -| time.TIme | timestamp with time zone -| byte | smallint CHECK("column" >= 0 AND "column" <= 255) -| rune | integer -| int | integer -| int8 | smallint CHECK("column" >= -127 AND "column" <= 128) -| int16 | smallint -| int32 | integer -| int64 | bigint -| uint | bigint CHECK("column" >= 0) -| uint8 | smallint CHECK("column" >= 0 AND "column" <= 255) -| uint16 | integer CHECK("column" >= 0) -| uint32 | bigint CHECK("column" >= 0) -| uint64 | bigint CHECK("column" >= 0) -| float32 | double precision -| float64 | double precision -| float64 - 设置 digits, decimals 时 | numeric(digits, decimals) - - -## 关系型字段 - -其字段类型取决于对应的主键。 - -* RelForeignKey -* RelOneToOne -* RelManyToMany -* RelReverseOne -* RelReverseMany \ No newline at end of file diff --git a/orm/docs/zh/Models.sql b/orm/docs/zh/Models.sql deleted file mode 100644 index 2d9d5ce0..00000000 --- a/orm/docs/zh/Models.sql +++ /dev/null @@ -1,83 +0,0 @@ -SET NAMES utf8; -SET FOREIGN_KEY_CHECKS = 0; - --- ---------------------------- --- Table structure for `comment` --- ---------------------------- -DROP TABLE IF EXISTS `comment`; -CREATE TABLE `comment` ( - `id` int(11) NOT NULL, - `post_id` bigint(200) NOT NULL, - `content` longtext NOT NULL, - `parent_id` int(11) DEFAULT NULL, - `status` smallint(4) NOT NULL, - `created` datetime NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - --- ---------------------------- --- Table structure for `post` --- ---------------------------- -DROP TABLE IF EXISTS `post`; -CREATE TABLE `post` ( - `id` int(11) NOT NULL, - `user_id` int(11) NOT NULL, - `title` varchar(60) NOT NULL, - `content` longtext NOT NULL, - `created` datetime NOT NULL, - `updated` datetime NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - --- ---------------------------- --- Table structure for `post_tag_rel` --- ---------------------------- -DROP TABLE IF EXISTS `post_tag_rel`; -CREATE TABLE `post_tag_rel` ( - `id` int(11) NOT NULL, - `post_id` int(11) NOT NULL, - `tag_id` int(11) NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - --- ---------------------------- --- Table structure for `tag` --- ---------------------------- -DROP TABLE IF EXISTS `tag`; -CREATE TABLE `tag` ( - `id` int(11) NOT NULL, - `name` varchar(30) NOT NULL, - `status` smallint(4) NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - --- ---------------------------- --- Table structure for `user` --- ---------------------------- -DROP TABLE IF EXISTS `user`; -CREATE TABLE `user` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `user_name` varchar(30) NOT NULL, - `email` varchar(100) NOT NULL, - `password` varchar(30) NOT NULL, - `status` smallint(4) NOT NULL, - `is_staff` tinyint(1) NOT NULL, - `is_active` tinyint(1) NOT NULL, - `created` date NOT NULL, - `updated` datetime NOT NULL, - `profile_id` int(11) DEFAULT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - --- ---------------------------- --- Table structure for `profile` --- ---------------------------- -DROP TABLE IF EXISTS `profile`; -CREATE TABLE `profile` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `age` smallint(4) NOT NULL, - `money` double NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -SET FOREIGN_KEY_CHECKS = 1; diff --git a/orm/docs/zh/Object.md b/orm/docs/zh/Object.md deleted file mode 100644 index f1a2e0e1..00000000 --- a/orm/docs/zh/Object.md +++ /dev/null @@ -1,59 +0,0 @@ -## 对象的CRUD操作 - -对 object 操作简单的三个方法 Read / Insert / Update / Delete -```go -o := orm.NewOrm() -user := new(User) -user.Name = "slene" - -fmt.Println(o.Insert(user)) - -user.Name = "Your" -fmt.Println(o.Update(user)) -fmt.Println(o.Read(user)) -fmt.Println(o.Delete(user)) -``` -### Read -```go -o := orm.NewOrm() -user := User{Id: 1} - -err = o.Read(&user) - -if err == sql.ErrNoRows { - fmt.Println("查询不到") -} else if err == orm.ErrMissPK { - fmt.Println("找不到主键") -} else { - fmt.Println(user.Id, user.Name) -} -``` -### Insert -```go -o := orm.NewOrm() -var user User -user.Name = "slene" -user.IsActive = true - -fmt.Println(o.Insert(&user)) -fmt.Println(user.Id) -``` -创建后会自动对 auto 的 field 赋值 - -### Update -```go -o := orm.NewOrm() -user := User{Id: 1} -if o.Read(&user) == nil { - user.Name = "MyName" - o.Update(&user) -} -``` -### Delete -```go -o := orm.NewOrm() -o.Delete(&User{Id: 1}) -``` -Delete 操作会对反向关系进行操作,此例中 Post 拥有一个到 User 的外键。删除 User 的时候。如果 on_delete 设置为默认的级联操作,将删除对应的 Post - -删除以后会清除 auto field 的值 diff --git a/orm/docs/zh/Orm.md b/orm/docs/zh/Orm.md deleted file mode 100644 index 6d3b6b06..00000000 --- a/orm/docs/zh/Orm.md +++ /dev/null @@ -1,316 +0,0 @@ -## Orm 使用方法 - -beego/orm 的使用例子 - -后文例子如无特殊说明都以这个为基础。 - -##### models.go: - -```go -package main - -import ( - "github.com/astaxie/beego/orm" -) - -type User struct { - Id int - Name string - Profile *Profile `orm:"rel(one)"` // OneToOne relation -} - -type Profile struct { - Id int - Age int16 - User *User `orm:"reverse(one)"` // 设置反向关系(可选) -} - -func init() { - // 需要在init中注册定义的model - orm.RegisterModel(new(User), new(Profile)) -} -``` - -##### main.go - -```go -package main - -import ( - "fmt" - "github.com/astaxie/beego/orm" - _ "github.com/go-sql-driver/mysql" -) - -func init() { - orm.RegisterDriver("mysql", orm.DR_MySQL) - - orm.RegisterDataBase("default", "mysql", "root:root@/orm_test?charset=utf8", 30) -} - -func main() { - o := orm.NewOrm() - o.Using("default") // 默认使用 default,你可以指定为其他数据库 - - profile := new(Profile) - profile.Age = 30 - - user := new(User) - user.Profile = profile - user.Name = "slene" - - fmt.Println(o.Insert(profile)) - fmt.Println(o.Insert(user)) -} -``` - -## 数据库的设置 - -目前 orm 支持三种数据库,以下为测试过的 driver - -将你需要使用的 driver 加入 import 中 - -```go -import ( - _ "github.com/go-sql-driver/mysql" - _ "github.com/lib/pq" - _ "github.com/mattn/go-sqlite3" -) -``` - -#### RegisterDriver - -三种默认数据库类型 - -```go -orm.DR_MySQL -orm.DR_Sqlite -orm.DR_Postgres -``` - -```go -// 参数1 driverName -// 参数2 数据库类型 -// 这个用来设置 driverName 对应的数据库类型 -// mysql / sqlite3 / postgres 这三种是默认已经注册过的,所以可以无需设置 -orm.RegisterDriver("mymysql", orm.DR_MySQL) -``` - -#### RegisterDataBase - -orm 必须注册一个别名为 `default` 的数据库,作为默认使用。 - -```go -// 参数1 数据库的别名,用来在orm中切换数据库使用 -// 参数2 driverName -// 参数3 对应的链接字符串 -// 参数4 设置最大的空闲连接数,使用 golang 自己的连接池 -orm.RegisterDataBase("default", "mysql", "root:root@/orm_test?charset=utf8", 30) -``` - -#### 时区设置 - -orm 默认使用 time.Local 本地时区 - -* 作用于 orm 自动创建的时间 -* 从数据库中取回的时间转换成 orm 本地时间 - -如果需要的话,你也可以进行更改 - -```go -// 设置为 UTC 时间 -orm.DefaultTimeLoc = time.UTC -``` - -orm 在进行 RegisterDataBase 的同时,会获取数据库使用的时区,然后在 time.Time 类型存取的时做相应转换,以匹配时间系统,从而保证时间不会出错。 - -**注意:** 鉴于 Sqlite3 的设计,存取默认都为 UTC 时间 - -## 注册模型 - -如果使用 orm.QuerySeter 进行高级查询的话,这个是必须的。 - -反之,如果只使用 Raw 查询和 map struct,是无需这一步的。您可以去查看 [Raw SQL 查询](Raw.md) - -#### RegisterModel - -将你定义的 Model 进行注册,最佳设计是有单独的 models.go 文件,在他的 init 函数中进行注册。 - - -迷你版 models.go -```go -package main - -import "github.com/astaxie/beego/orm" - -type User struct { - Id int - Name string -} - -func init(){ - orm.RegisterModel(new(User)) -} -``` - -RegisterModel 也可以同时注册多个 model - -```go -orm.RegisterModel(new(User), new(Profile), new(Post)) -``` - -详细的 struct 定义请查看文档 [模型定义](Models.md) - -#### RegisterModelWithPrefix - -使用表名前缀 - -```go -orm.RegisterModelWithPrefix("prefix_", new(User)) -``` - -创建后的表名为 prefix_user - -## ORM 接口使用 - -使用 orm 必然接触的 Ormer 接口,我们来熟悉一下 - -```go -var o Ormer -o = orm.NewOrm() // 创建一个 Ormer -// NewOrm 的同时会执行 orm.BootStrap (整个 app 只执行一次),用以验证模型之间的定义并缓存。 -``` - -* type Ormer interface { - * [Read(Modeler) error](Object.md#read) - * [Insert(Modeler) (int64, error)](Object.md#insert) - * [Update(Modeler) (int64, error)](Object.md#update) - * [Delete(Modeler) (int64, error)](Object.md#delete) - * [M2mAdd(Modeler, string, ...interface{}) (int64, error)](Object.md#m2madd) - * [M2mDel(Modeler, string, ...interface{}) (int64, error)](Object.md#m2mdel) - * [LoadRel(Modeler, string) (int64, error)](Object.md#loadRel) - * [QueryTable(interface{}) QuerySeter](#querytable) - * [Using(string) error](#using) - * [Begin() error](Transaction.md) - * [Commit() error](Transaction.md) - * [Rollback() error](Transaction.md) - * [Raw(string, ...interface{}) RawSeter](#raw) - * [Driver() Driver](#driver) -* } - - -#### QueryTable - -传入表名,或者 Modeler 对象,返回一个 [QuerySeter](Query.md#queryseter) - -```go -o := orm.NewOrm() -var qs QuerySeter -qs = o.QueryTable("user") -// 如果表没有定义过,会立刻 panic -``` - -#### Using - -切换为其他数据库 - -```go -orm.RegisterDataBase("db1", "mysql", "root:root@/orm_db2?charset=utf8", 30) -orm.RegisterDataBase("db2", "sqlite3", "data.db", 30) - -o1 := orm.NewOrm() -o1.Using("db1") - -o2 := orm.NewOrm() -o2.Using("db2") - -// 切换为其他数据库以后 -// 这个 Ormer 对象的其下的 api 调用都将使用这个数据库 - -``` - -默认使用 `default` 数据库,无需调用 Using - -#### Raw - -使用 sql 语句直接进行操作 - -Raw 函数,返回一个 [RawSeter](Raw.md) 用以对设置的 sql 语句和参数进行操作 - -```go -o := NewOrm() -var r RawSeter -r = o.Raw("UPDATE user SET name = ? WHERE name = ?", "testing", "slene") -``` - -#### Driver - -返回当前 orm 使用的 db 信息 - -```go -type Driver interface { - Name() string - Type() DriverType -} -``` - -```go -orm.RegisterDataBase("db1", "mysql", "root:root@/orm_db2?charset=utf8", 30) -orm.RegisterDataBase("db2", "sqlite3", "data.db", 30) - -o1 := orm.NewOrm() -o1.Using("db1") -dr := o1.Driver() -fmt.Println(dr.Name() == "db1") // true -fmt.Println(dr.Type() == orm.DR_MySQL) // true - -o2 := orm.NewOrm() -o2.Using("db2") -dr = o2.Driver() -fmt.Println(dr.Name() == "db2") // true -fmt.Println(dr.Type() == orm.DR_Sqlite) // true - -``` - -## 调试模式打印查询语句 - -简单的设置 Debug 为 true 打印查询的语句 - -可能存在性能问题,不建议使用在产品模式 - -```go -func main() { - orm.Debug = true -... -``` - -默认使用 os.Stderr 输出日志信息 - -改变输出到你自己的 io.Writer - -```go -var w io.Writer -... -// 设置为你的 io.Writer -... -orm.DebugLog = orm.NewLog(w) -``` - -日志格式 - -```go -[ORM] - 时间 - [Queries/数据库名] - [执行操作/执行时间] - [SQL语句] - 使用标点 `,` 分隔的参数列表 - 打印遇到的错误 -``` - -```go -[ORM] - 2013-08-09 13:18:16 - [Queries/default] - [ db.Exec / 0.4ms] - [INSERT INTO `user` (`name`) VALUES (?)] - `slene` -[ORM] - 2013-08-09 13:18:16 - [Queries/default] - [ db.Exec / 0.5ms] - [UPDATE `user` SET `name` = ? WHERE `id` = ?] - `astaxie`, `14` -[ORM] - 2013-08-09 13:18:16 - [Queries/default] - [db.QueryRow / 0.4ms] - [SELECT `id`, `name` FROM `user` WHERE `id` = ?] - `14` -[ORM] - 2013-08-09 13:18:16 - [Queries/default] - [ db.Exec / 0.4ms] - [INSERT INTO `post` (`user_id`,`title`,`content`) VALUES (?, ?, ?)] - `14`, `beego orm`, `powerful amazing` -[ORM] - 2013-08-09 13:18:16 - [Queries/default] - [ db.Query / 0.4ms] - [SELECT T1.`name` `User__Name`, T0.`user_id` `User`, T1.`id` `User__Id` FROM `post` T0 INNER JOIN `user` T1 ON T1.`id` = T0.`user_id` WHERE T0.`id` = ? LIMIT 1000] - `68` -[ORM] - 2013-08-09 13:18:16 - [Queries/default] - [ db.Exec / 0.4ms] - [DELETE FROM `user` WHERE `id` = ?] - `14` -[ORM] - 2013-08-09 13:18:16 - [Queries/default] - [ db.Query / 0.3ms] - [SELECT T0.`id` FROM `post` T0 WHERE T0.`user_id` IN (?) ] - `14` -[ORM] - 2013-08-09 13:18:16 - [Queries/default] - [ db.Exec / 0.4ms] - [DELETE FROM `post` WHERE `id` IN (?)] - `68` -``` - -日志内容包括 **所有的数据库操作**,事务,Prepare,等 diff --git a/orm/docs/zh/Query.md b/orm/docs/zh/Query.md deleted file mode 100644 index cfc4073c..00000000 --- a/orm/docs/zh/Query.md +++ /dev/null @@ -1,411 +0,0 @@ -## 高级查询 - -orm 以 **QuerySeter** 来组织查询,每个返回 **QuerySeter** 的方法都会获得一个新的 **QuerySeter** 对象。 - -基本使用方法: -```go -o := orm.NewOrm() - -// 获取 QuerySeter 对象,user 为表名 -qs := o.QueryTable("user") - -// 也可以直接使用对象作为表名 -user := new(User) -qs = o.QueryTable(user) // 返回 QuerySeter -``` -## expr - -QuerySeter 中用于描述字段和 sql 操作符,使用简单的 expr 查询方法 - -字段组合的前后顺序依照表的关系,比如 User 表拥有 Profile 的外键,那么对 User 表查询对应的 Profile.Age 为条件,则使用 `Profile__Age` 注意,字段的分隔符号使用双下划线 `__`,除了描述字段, expr 的尾部可以增加操作符以执行对应的 sql 操作。比如 `Profile__Age__gt` 代表 Profile.Age > 18 的条件查询。 - -注释后面将描述对应的 sql 语句,仅仅是描述 expr 的类似结果,并不代表实际生成的语句。 -```go -qs.Filter("id", 1) // WHERE id = 1 -qs.Filter("profile__age", 18) // WHERE profile.age = 18 -qs.Filter("Profile__Age", 18) // 使用字段名和Field名都是允许的 -qs.Filter("profile__age", 18) // WHERE profile.age = 18 -qs.Filter("profile__age__gt", 18) // WHERE profile.age > 18 -qs.Filter("profile__age__gte", 18) // WHERE profile.age >= 18 -qs.Filter("profile__age__in", 18, 20) // WHERE profile.age IN (18, 20) - -qs.Filter("profile__age__in", 18, 20).Exclude("profile__lt", 1000) -// WHERE profile.age IN (18, 20) AND NOT profile_id < 1000 -``` -## Operators - -当前支持的操作符号: - -* [exact](#exact) / [iexact](#iexact) 等于 -* [contains](#contains) / [icontains](#icontains) 包含 -* [gt / gte](#gt / gte) 大于 / 大于等于 -* [lt / lte](#lt / lte) 小于 / 小于等于 -* [startswith](#startswith) / [istartswith](#istartswith) 以...起始 -* [endswith](#endswith) / [iendswith](#iendswith) 以...结束 -* [in](#in) -* [isnull](#isnull) - -后面以 `i` 开头的表示:大小写不敏感 - -#### exact - -Filter / Exclude / Condition expr 的默认值 -```go -qs.Filter("name", "slene") // WHERE name = 'slene' -qs.Filter("name__exact", "slene") // WHERE name = 'slene' -// 使用 = 匹配,大小写是否敏感取决于数据表使用的 collation -qs.Filter("profile", nil) // WHERE profile_id IS NULL -``` -#### iexact -```go -qs.Filter("name__iexact", "slene") -// WHERE name LIKE 'slene' -// 大小写不敏感,匹配任意 'Slene' 'sLENE' -``` -#### contains -```go -qs.Filter("name__contains", "slene") -// WHERE name LIKE BINARY '%slene%' -// 大小写敏感, 匹配包含 slene 的字符 -``` -#### icontains -```go -qs.Filter("name__icontains", "slene") -// WHERE name LIKE '%slene%' -// 大小写不敏感, 匹配任意 'im Slene', 'im sLENE' -``` -#### in -```go -qs.Filter("profile__age__in", 17, 18, 19, 20) -// WHERE profile.age IN (17, 18, 19, 20) -``` -#### gt / gte -```go -qs.Filter("profile__age__gt", 17) -// WHERE profile.age > 17 - -qs.Filter("profile__age__gte", 18) -// WHERE profile.age >= 18 -``` -#### lt / lte -```go -qs.Filter("profile__age__lt", 17) -// WHERE profile.age < 17 - -qs.Filter("profile__age__lte", 18) -// WHERE profile.age <= 18 -``` -#### startswith -```go -qs.Filter("name__startswith", "slene") -// WHERE name LIKE BINARY 'slene%' -// 大小写敏感, 匹配以 'slene' 起始的字符串 -``` -#### istartswith -```go -qs.Filter("name__istartswith", "slene") -// WHERE name LIKE 'slene%' -// 大小写不敏感, 匹配任意以 'slene', 'Slene' 起始的字符串 -``` -#### endswith -```go -qs.Filter("name__endswith", "slene") -// WHERE name LIKE BINARY '%slene' -// 大小写敏感, 匹配以 'slene' 结束的字符串 -``` -#### iendswith -```go -qs.Filter("name__startswith", "slene") -// WHERE name LIKE '%slene' -// 大小写不敏感, 匹配任意以 'slene', 'Slene' 结束的字符串 -``` -#### isnull -```go -qs.Filter("profile__isnull", true) -qs.Filter("profile_id__isnull", true) -// WHERE profile_id IS NULL - -qs.Filter("profile__isnull", false) -// WHERE profile_id IS NOT NULL -``` -## 高级查询接口使用 - -QuerySeter 是高级查询使用的接口,我们来熟悉下他的接口方法 - -* type QuerySeter interface { - * [Filter(string, ...interface{}) QuerySeter](#filter) - * [Exclude(string, ...interface{}) QuerySeter](#exclude) - * [SetCond(*Condition) QuerySeter](#setcond) - * [Limit(int, ...int64) QuerySeter](#limit) - * [Offset(int64) QuerySeter](#offset) - * [OrderBy(...string) QuerySeter](#orderby) - * [RelatedSel(...interface{}) QuerySeter](#relatedsel) - * [Count() (int64, error)](#count) - * [Update(Params) (int64, error)](#update) - * [Delete() (int64, error)](#delete) - * [PrepareInsert() (Inserter, error)](#prepareinsert) - * [All(interface{}) (int64, error)](#all) - * [One(Modeler) error](#one) - * [Values(*[]Params, ...string) (int64, error)](#values) - * [ValuesList(*[]ParamsList, ...string) (int64, error)](#valueslist) - * [ValuesFlat(*ParamsList, string) (int64, error)](#valuesflat) -* } - -* 每个返回 QuerySeter 的 api 调用时都会新建一个 QuerySeter,不影响之前创建的。 - -* 高级查询使用 Filter 和 Exclude 来做常用的条件查询。囊括两种清晰的过滤规则:包含, 排除 - -#### Filter - -用来过滤查询结果,起到 **包含条件** 的作用 - -多个 Filter 之间使用 `AND` 连接 -```go -qs.Filter("profile__isnull", true).Filter("name", "slene") -// WHERE profile_id IS NULL AND name = 'slene' -``` - -#### Exclude - -用来过滤查询结果,起到 **排除条件** 的作用 - -使用 `NOT` 排除条件 - -多个 Exclude 之间使用 `AND` 连接 -```go -qs.Exclude("profile__isnull", true).Filter("name", "slene") -// WHERE NOT profile_id IS NULL AND name = 'slene' -``` - -#### SetCond - -自定义条件表达式 - -```go -cond := NewCondition() -cond1 := cond.And("profile__isnull", false).AndNot("status__in", 1).Or("profile__age__gt", 2000) - -qs := orm.QueryTable("user") -qs = qs.SetCond(cond1) -// WHERE ... AND ... AND NOT ... OR ... - -cond2 := cond.AndCond(cond1).OrCond(cond.And("name", "slene")) -qs = qs.SetCond(cond2).Count() -// WHERE (... AND ... AND NOT ... OR ...) OR ( ... ) -``` - -#### Limit - -限制最大返回数据行数,第二个参数可以设置 `Offset` -```go -var DefaultRowsLimit = 1000 // orm 默认的 limit 值为 1000 - -// 默认情况下 select 查询的最大行数为 1000 -// LIMIT 1000 - -qs.Limit(10) -// LIMIT 10 - -qs.Limit(10, 20) -// LIMIT 10 OFFSET 20 - -qs.Limit(-1) -// no limit - -qs.Limit(-1, 100) -// LIMIT 18446744073709551615 OFFSET 100 -// 18446744073709551615 是 1<<64 - 1 用来指定无 limit 限制 但有 offset 偏移的情况 -``` - -#### Offset - -设置 偏移行数 -```go -qs.Offset(20) -// LIMIT 1000 OFFSET 20 -``` - -#### OrderBy - -参数使用 **expr** - -在 expr 前使用减号 `-` 表示 `DESC` 的排列 -```go -qs.OrderBy("id", "-profile__age") -// ORDER BY id ASC, profile.age DESC - -qs.OrderBy("-profile__age", "profile") -// ORDER BY profile.age DESC, profile_id ASC -``` - -#### RelatedSel - -关系查询,参数使用 **expr** -```go -var DefaultRelsDepth = 5 // 默认情况下直接调用 RelatedSel 将进行最大 5 层的关系查询 - -qs := o.QueryTable("post") - -qs.RelateSel() -// INNER JOIN user ... LEFT OUTER JOIN profile ... - -qs.RelateSel("user") -// INNER JOIN user ... -// 设置 expr 只对设置的字段进行关系查询 - -// 对设置 null 属性的 Field 将使用 LEFT OUTER JOIN -``` - -#### Count -依据当前的查询条件,返回结果行数 -```go -cnt, err := o.QueryTable("user").Count() // SELECT COUNT(*) FROM USER -fmt.Printf("Count Num: %s, %s", cnt, err) -``` - -#### Update -依据当前查询条件,进行批量更新操作 -```go -num, err := o.QueryTable("user").Filter("name", "slene").Update(orm.Params{ - "name": "astaxie", -}) -fmt.Printf("Affected Num: %s, %s", num, err) -// SET name = "astaixe" WHERE name = "slene" -``` - -#### Delete -依据当前查询条件,进行批量删除操作 -```go -num, err := o.QueryTable("user").Filter("name", "slene").Delete() -fmt.Printf("Affected Num: %s, %s", num, err) -// DELETE FROM user WHERE name = "slene" -``` - -#### PrepareInsert - -用于一次 prepare 多次 insert 插入,以提高批量插入的速度。 - -```go -var users []*User -... -qs := o.QueryTable("user") -i, _ := qs.PrepareInsert() -for _, user := range users { - id, err := i.Insert(user) - if err != nil { - ... - } -} -// PREPARE INSERT INTO user (`name`, ...) VALUES (?, ...) -// EXECUTE INSERT INTO user (`name`, ...) VALUES ("slene", ...) -// EXECUTE ... -// ... -i.Close() // 别忘记关闭 statement -``` - -#### All -返回对应的结果集对象 -```go -var users []*User -num, err := o.QueryTable("user").Filter("name", "slene").All(&users) -fmt.Printf("Returned Rows Num: %s, %s", num, err) -``` - -#### One - -尝试返回单条记录 - -```go -var user *User -err := o.QueryTable("user").Filter("name", "slene").One(&user) -if err == orm.ErrMultiRows { - // 多条的时候报错 - fmt.Printf("Returned Multi Rows Not One") -} -if err == orm.ErrNoRows { - // 没有找到记录 - fmt.Printf("Not row found") -} -``` - -#### Values -返回结果集的 key => value 值 - -key 为 Model 里的 Field name,value 的值 以 string 保存 - -```go -var maps []orm.Params -num, err := o.QueryTable("user").Values(&maps) -if err != nil { - fmt.Printf("Result Nums: %d\n", num) - for _, m := range maps { - fmt.Println(m["Id"], m["Name"]) - } -} -``` - -返回指定的 Field 数据 - -**TODO**: 暂不支持级联查询 **RelatedSel** 直接返回 Values - -但可以直接指定 expr 级联返回需要的数据 - -```go -var maps []orm.Params -num, err := o.QueryTable("user").Values(&maps, "id", "name", "profile", "profile__age") -if err != nil { - fmt.Printf("Result Nums: %d\n", num) - for _, m := range maps { - fmt.Println(m["Id"], m["Name"], m["Profile"], m["Profile__Age"]) - // map 中的数据都是展开的,没有复杂的嵌套 - } -} -``` - -#### ValuesList - -顾名思义,返回的结果集以slice存储 - -结果的排列与 Model 中定义的 Field 顺序一致 - -返回的每个元素值以 string 保存 - -```go -var lists []orm.ParamsList -num, err := o.QueryTable("user").ValuesList(&lists) -if err != nil { - fmt.Printf("Result Nums: %d\n", num) - for _, row := range lists { - fmt.Println(row) - } -} -``` - -当然也可以指定 expr 返回指定的 Field - -```go -var lists []orm.ParamsList -num, err := o.QueryTable("user").ValuesList(&lists, "name", "profile__age") -if err != nil { - fmt.Printf("Result Nums: %d\n", num) - for _, row := range lists { - fmt.Printf("Name: %s, Age: %s\m", row[0], row[1]) - } -} -``` - -#### ValuesFlat - -只返回特定的 Field 值,讲结果集展开到单个 slice 里 - -```go -var list orm.ParamsList -num, err := o.QueryTable("user").ValuesFlat(&list, "name") -if err != nil { - fmt.Printf("Result Nums: %d\n", num) - fmt.Printf("All User Names: %s", strings.Join(list, ", ") -} -``` - - - diff --git a/orm/docs/zh/README.md b/orm/docs/zh/README.md deleted file mode 100644 index e01c8cad..00000000 --- a/orm/docs/zh/README.md +++ /dev/null @@ -1,40 +0,0 @@ -最新文档请查看 beedoc - -* [中文](http://beego.me/docs/Models_Overview?lang=zh) -* [English](http://beego.me/docs/Models_Overview?lang=en) - -## 文档目录 - -1. [Orm 使用方法](Orm.md) - - [数据库的设置](Orm.md#数据库的设置) - * [驱动类型设置](Orm.md#registerdriver) - * [参数设置](Orm.md#registerdatabase) - * [时区设置](Orm.md#时区设置) - - [注册模型](Orm.md#注册模型) - - [ORM 接口使用](Orm.md#orm-接口使用) - - [调试模式打印查询语句](Orm.md#调试模式打印查询语句) -2. [对象的CRUD操作](Object.md) -3. [高级查询](Query.md) - - [使用的表达式语法](Query.md#expr) - - [支持的操作符号](Query.md#operators) - - [高级查询接口使用](Query.md#高级查询接口使用) -4. [使用SQL语句进行查询](Raw.md) -5. [事务处理](Transaction.md) -6. [模型定义](Models.md) - - [Struct Tag 设置参数](Models.md#struct-tag-设置参数) - - [表关系设置](Models.md#表关系设置) - - [模型字段与数据库类型的对应](Models.md#模型字段与数据库类型的对应) -7. [命令模式](Cmd.md) - - [自动建表](Cmd.md#自动建表) - - [打印建表SQL](Cmd.md#打印建表sql) -8. [Test ORM](Test.md) -9. Custom Fields -10. Faq - - -### 文档更新记录 - -* 2013-08-20: 这里不再更新,最新文档在 beedoc, [中文](http://beego.me/docs/Models_Overview?lang=zh) / [English](http://beego.me/docs/Models_Overview?lang=en) -* 2013-08-19: 增加[自动建表](Cmd.md#自动建表)功能 -* 2013-08-13: ORM 的 [时区设置](Orm.md#时区设置) -* 2013-08-13: [模型字段与数据库类型的对应](Models.md#模型字段与数据库类型的对应) 推荐的数据库对应使用的类型 diff --git a/orm/docs/zh/Raw.md b/orm/docs/zh/Raw.md deleted file mode 100644 index 0d571edf..00000000 --- a/orm/docs/zh/Raw.md +++ /dev/null @@ -1,116 +0,0 @@ -## 使用SQL语句进行查询 - -* 使用 Raw SQL 查询,无需使用 ORM 表定义 -* 多数据库,都可直接使用占位符号 `?`,自动转换 -* 查询时的参数,支持使用 Model Struct 和 Slice, Array - -```go -ids := []int{1, 2, 3} -p.Raw("SELECT name FROM user WHERE id IN (?, ?, ?)", ids) -``` - -创建一个 **RawSeter** - -```go -o := NewOrm() -var r RawSeter -r = o.Raw("UPDATE user SET name = ? WHERE name = ?", "testing", "slene") -``` - -* type RawSeter interface { - * [Exec() (int64, error)](#exec) - * [QueryRow(...interface{}) error](#queryrow) - * [QueryRows(...interface{}) (int64, error)](#queryrows) - * [SetArgs(...interface{}) RawSeter](#setargs) - * [Values(*[]Params) (int64, error)](#values) - * [ValuesList(*[]ParamsList) (int64, error)](#valueslist) - * [ValuesFlat(*ParamsList) (int64, error)](#valuesflat) - * [Prepare() (RawPreparer, error)](#prepare) -* } - -#### Exec - -执行sql语句 - -```go -num, err := r.Exec() -``` - -#### QueryRow - -TODO - -#### QueryRows - -TODO - -#### SetArgs - -改变 Raw(sql, args...) 中的 args 参数,返回一个新的 RawSeter - -用于单条 sql 语句,重复利用,替换参数然后执行。 - -```go -num, err := r.SetArgs("arg1", "arg2").Exec() -num, err := r.SetArgs("arg1", "arg2").Exec() -... -``` -#### Values / ValuesList / ValuesFlat - -Raw SQL 查询获得的结果集 Value 为 `string` 类型,NULL 字段的值为空 `` - -#### Values - - -返回结果集的 key => value 值 - -```go -var maps []orm.Params -num, err = o.Raw("SELECT user_name FROM user WHERE status = ?", 1).Values(&maps) -if err == nil && num > 0 { - fmt.Println(maps[0]["user_name"]) // slene -} -``` - -#### ValuesList - -返回结果集 slice - -```go -var lists []orm.ParamsList -num, err = o.Raw("SELECT user_name FROM user WHERE status = ?", 1).ValuesList(&lists) -if err == nil && num > 0 { - fmt.Println(lists[0][0]) // slene -} -``` - -#### ValuesFlat - -返回单一字段的平铺 slice 数据 - -```go -var list orm.ParamsList -num, err = o.Raw("SELECT id FROM user WHERE id < ?", 10).ValuesList(&list) -if err == nil && num > 0 { - fmt.Println(list) // []{"1","2","3",...} -} -``` - -#### Prepare - -用于一次 prepare 多次 exec,以提高批量执行的速度。 - -```go -p, err := o.Raw("UPDATE user SET name = ? WHERE name = ?").Prepare() -num, err := p.Exec("testing", "slene") -num, err = p.Exec("testing", "astaxie") -... -... -p.Close() // 别忘记关闭 statement -``` - -## FAQ - -1. 我的 app 需要支持多类型数据库,如何在使用 Raw SQL 的时候判断当前使用的数据库类型。 - -使用 Ormer 的 [Driver方法](Orm.md#driver) 可以进行判断 diff --git a/orm/docs/zh/Test.md b/orm/docs/zh/Test.md deleted file mode 100644 index c2146336..00000000 --- a/orm/docs/zh/Test.md +++ /dev/null @@ -1,34 +0,0 @@ -## Test ORM - -测试代码参见 - -```bash -models_test.go // 表定义 -orm_test.go // 测试用例 -``` - -#### MySQL -```bash -mysql -u root -e 'create database orm_test;' -export ORM_DRIVER=mysql -export ORM_SOURCE="root:@/orm_test?charset=utf8" -go test -v github.com/astaxie/beego/orm -``` - - -#### Sqlite3 -```bash -touch /path/to/orm_test.db -export ORM_DRIVER=sqlite3 -export ORM_SOURCE=/path/to/orm_test.db -go test -v github.com/astaxie/beego/orm -``` - - -#### PostgreSQL -```bash -psql -c 'create database orm_test;' -U postgres -export ORM_DRIVER=postgres -export ORM_SOURCE="user=postgres dbname=orm_test sslmode=disable" -go test -v github.com/astaxie/beego/orm -``` \ No newline at end of file diff --git a/orm/docs/zh/Transaction.md b/orm/docs/zh/Transaction.md deleted file mode 100644 index 51172c09..00000000 --- a/orm/docs/zh/Transaction.md +++ /dev/null @@ -1,17 +0,0 @@ -## 事务处理 - -orm 可以简单的进行事务操作 - -```go -o := NewOrm() -err := o.Begin() -// 事务处理过程 -... -... -// 此过程中的所有使用 o Ormer 对象的查询都在事务处理范围内 -if SomeError { - err = o.Rollback() -} else { - err = o.Commit() -} -``` diff --git a/orm/models.go b/orm/models.go index ff71ee62..dcb32b55 100644 --- a/orm/models.go +++ b/orm/models.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors slene +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package orm diff --git a/orm/models_boot.go b/orm/models_boot.go index 0abaf98f..cb44bc05 100644 --- a/orm/models_boot.go +++ b/orm/models_boot.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors slene +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package orm diff --git a/orm/models_fields.go b/orm/models_fields.go index c1c9b7e2..f038dd0f 100644 --- a/orm/models_fields.go +++ b/orm/models_fields.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors slene +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package orm diff --git a/orm/models_info_f.go b/orm/models_info_f.go index 8ec2bbeb..a79ffab2 100644 --- a/orm/models_info_f.go +++ b/orm/models_info_f.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors slene +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package orm diff --git a/orm/models_info_m.go b/orm/models_info_m.go index 265c6379..3600ee7c 100644 --- a/orm/models_info_m.go +++ b/orm/models_info_m.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors slene +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package orm diff --git a/orm/models_test.go b/orm/models_test.go index 775c2856..fe78c45f 100644 --- a/orm/models_test.go +++ b/orm/models_test.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors slene +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package orm diff --git a/orm/models_utils.go b/orm/models_utils.go index c448c55e..ffde40ea 100644 --- a/orm/models_utils.go +++ b/orm/models_utils.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors slene +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package orm @@ -128,6 +136,9 @@ func getFieldType(val reflect.Value) (ft int, err error) { case reflect.String: ft = TypeCharField default: + if elm.Interface() == nil { + panic(fmt.Errorf("%s is nil pointer, may be miss setting tag", val)) + } switch elm.Interface().(type) { case sql.NullInt64: ft = TypeBigIntegerField diff --git a/orm/orm.go b/orm/orm.go index 5503256e..cdb7f27c 100644 --- a/orm/orm.go +++ b/orm/orm.go @@ -1,9 +1,53 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors slene +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// Simple Usage +// +// package main +// +// import ( +// "fmt" +// "github.com/astaxie/beego/orm" +// _ "github.com/go-sql-driver/mysql" // import your used driver +// ) +// +// // Model Struct +// type User struct { +// Id int `orm:"auto"` +// Name string `orm:"size(100)"` +// } +// +// func init() { +// orm.RegisterDataBase("default", "mysql", "root:root@/my_db?charset=utf8", 30) +// } +// +// func main() { +// o := orm.NewOrm() +// user := User{Name: "slene"} +// // insert +// id, err := o.Insert(&user) +// // update +// user.Name = "astaxie" +// num, err := o.Update(&user) +// // read one +// u := User{Id: user.Id} +// err = o.Read(&u) +// // delete +// num, err = o.Delete(&u) +// } +// +// more docs: http://beego.me/docs/mvc/model/overview.md package orm import ( diff --git a/orm/orm_conds.go b/orm/orm_conds.go index 4b0cfa65..6344653a 100644 --- a/orm/orm_conds.go +++ b/orm/orm_conds.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors slene +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package orm diff --git a/orm/orm_log.go b/orm/orm_log.go index e132992d..419d8e11 100644 --- a/orm/orm_log.go +++ b/orm/orm_log.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors slene +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package orm diff --git a/orm/orm_object.go b/orm/orm_object.go index 44d4aebc..df5a6600 100644 --- a/orm/orm_object.go +++ b/orm/orm_object.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors slene +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package orm diff --git a/orm/orm_querym2m.go b/orm/orm_querym2m.go index 370de60d..1eaccf72 100644 --- a/orm/orm_querym2m.go +++ b/orm/orm_querym2m.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors slene +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package orm diff --git a/orm/orm_queryset.go b/orm/orm_queryset.go index 6d2dd418..4f5d5485 100644 --- a/orm/orm_queryset.go +++ b/orm/orm_queryset.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors slene +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package orm diff --git a/orm/orm_raw.go b/orm/orm_raw.go index ea701cce..1393d414 100644 --- a/orm/orm_raw.go +++ b/orm/orm_raw.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors slene +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package orm diff --git a/orm/orm_test.go b/orm/orm_test.go index 5859f426..e7420bcb 100644 --- a/orm/orm_test.go +++ b/orm/orm_test.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors slene +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package orm diff --git a/orm/types.go b/orm/types.go index 0f1b37ba..c342e1c2 100644 --- a/orm/types.go +++ b/orm/types.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors slene +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package orm diff --git a/orm/utils.go b/orm/utils.go index e53042d9..df6147c1 100644 --- a/orm/utils.go +++ b/orm/utils.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors slene +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package orm diff --git a/parser.go b/parser.go index 5b2cd616..65144f5d 100644 --- a/parser.go +++ b/parser.go @@ -1,8 +1,17 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package beego import ( @@ -61,7 +70,9 @@ func parserPkg(pkgRealpath, pkgpath string) error { for _, d := range fl.Decls { switch specDecl := d.(type) { case *ast.FuncDecl: - parserComments(specDecl.Doc, specDecl.Name.String(), fmt.Sprint(specDecl.Recv.List[0].Type.(*ast.StarExpr).X), pkgpath) + if specDecl.Recv != nil { + parserComments(specDecl.Doc, specDecl.Name.String(), fmt.Sprint(specDecl.Recv.List[0].Type.(*ast.StarExpr).X), pkgpath) + } } } } @@ -110,7 +121,7 @@ func parserComments(comments *ast.CommentGroup, funcName, controllerName, pkgpat } func genRouterCode() { - os.Mkdir(path.Join(AppPath, "routers"), 0755) + os.Mkdir(path.Join(workPath, "routers"), 0755) Info("generate router from comments") var globalinfo string for k, cList := range genInfoList { @@ -144,7 +155,7 @@ func genRouterCode() { } } if globalinfo != "" { - f, err := os.Create(path.Join(AppPath, "routers", "commentsRouter.go")) + f, err := os.Create(path.Join(workPath, "routers", "commentsRouter.go")) if err != nil { panic(err) } @@ -154,18 +165,21 @@ func genRouterCode() { } func compareFile(pkgRealpath string) bool { - if utils.FileExists(path.Join(AppPath, lastupdateFilename)) { - content, err := ioutil.ReadFile(path.Join(AppPath, lastupdateFilename)) + if !utils.FileExists(path.Join(workPath, "routers", "commentsRouter.go")) { + return true + } + if utils.FileExists(path.Join(workPath, lastupdateFilename)) { + content, err := ioutil.ReadFile(path.Join(workPath, lastupdateFilename)) if err != nil { return true } json.Unmarshal(content, &pkgLastupdate) - ft, err := os.Lstat(pkgRealpath) + lastupdate, err := getpathTime(pkgRealpath) if err != nil { return true } if v, ok := pkgLastupdate[pkgRealpath]; ok { - if ft.ModTime().UnixNano() <= v { + if lastupdate <= v { return false } } @@ -174,14 +188,27 @@ func compareFile(pkgRealpath string) bool { } func savetoFile(pkgRealpath string) { - ft, err := os.Lstat(pkgRealpath) + lastupdate, err := getpathTime(pkgRealpath) if err != nil { return } - pkgLastupdate[pkgRealpath] = ft.ModTime().UnixNano() + pkgLastupdate[pkgRealpath] = lastupdate d, err := json.Marshal(pkgLastupdate) if err != nil { return } - ioutil.WriteFile(path.Join(AppPath, lastupdateFilename), d, os.ModePerm) + ioutil.WriteFile(path.Join(workPath, lastupdateFilename), d, os.ModePerm) +} + +func getpathTime(pkgRealpath string) (lastupdate int64, err error) { + fl, err := ioutil.ReadDir(pkgRealpath) + if err != nil { + return lastupdate, err + } + for _, f := range fl { + if lastupdate < f.ModTime().UnixNano() { + lastupdate = f.ModTime().UnixNano() + } + } + return lastupdate, nil } diff --git a/plugins/auth/basic.go b/plugins/auth/basic.go index a74bcf22..ed8bc4bd 100644 --- a/plugins/auth/basic.go +++ b/plugins/auth/basic.go @@ -1,21 +1,39 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// Package auth provides handlers to enable basic auth support. +// Simple Usage: +// import( +// "github.com/astaxie/beego" +// "github.com/astaxie/beego/plugins/auth" +// ) +// +// func main(){ +// // authenticate every request +// beego.InsertFilter("*", beego.BeforeRouter,auth.Basic("username","secretpassword")) +// beego.Run() +// } +// +// +// Advanced Usage: +// func SecretAuth(username, password string) bool { +// return username == "astaxie" && password == "helloBeego" +// } +// authPlugin := auth.NewBasicAuthenticator(SecretAuth, "Authorization Required") +// beego.InsertFilter("*", beego.BeforeRouter,authPlugin) package auth -// Example: -// func SecretAuth(username, password string) bool { -// if username == "astaxie" && password == "helloBeego" { -// return true -// } -// return false -// } -// authPlugin := auth.NewBasicAuthenticator(SecretAuth, "My Realm") -// beego.AddFilter("*","AfterStatic",authPlugin) - import ( "encoding/base64" "net/http" @@ -25,6 +43,15 @@ import ( "github.com/astaxie/beego/context" ) +var defaultRealm = "Authorization Required" + +func Basic(username string, password string) beego.FilterFunc { + secrets := func(user, pass string) bool { + return user == username && pass == password + } + return NewBasicAuthenticator(secrets, defaultRealm) +} + func NewBasicAuthenticator(secrets SecretProvider, Realm string) beego.FilterFunc { return func(ctx *context.Context) { a := &BasicAuth{Secrets: secrets, Realm: Realm} @@ -41,13 +68,10 @@ type BasicAuth struct { Realm string } -/* - Checks the username/password combination from the request. Returns - either an empty string (authentication failed) or the name of the - authenticated user. - - Supports MD5 and SHA1 password entries -*/ +//Checks the username/password combination from the request. Returns +//either an empty string (authentication failed) or the name of the +//authenticated user. +//Supports MD5 and SHA1 password entries func (a *BasicAuth) CheckAuth(r *http.Request) string { s := strings.SplitN(r.Header.Get("Authorization"), " ", 2) if len(s) != 2 || s[0] != "Basic" { @@ -69,10 +93,8 @@ func (a *BasicAuth) CheckAuth(r *http.Request) string { return "" } -/* - http.Handler for BasicAuth which initiates the authentication process - (or requires reauthentication). -*/ +//http.Handler for BasicAuth which initiates the authentication process +//(or requires reauthentication). func (a *BasicAuth) RequireAuth(w http.ResponseWriter, r *http.Request) { w.Header().Set("WWW-Authenticate", `Basic realm="`+a.Realm+`"`) w.WriteHeader(401) diff --git a/plugins/cors/cors.go b/plugins/cors/cors.go new file mode 100644 index 00000000..dce750eb --- /dev/null +++ b/plugins/cors/cors.go @@ -0,0 +1,228 @@ +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package cors provides handlers to enable CORS support. +// Usage +// import ( +// "github.com/astaxie/beego" +// "github.com/astaxie/beego/plugins/cors" +// ) +// +// func main() { +// // CORS for https://foo.* origins, allowing: +// // - PUT and PATCH methods +// // - Origin header +// // - Credentials share +// beego.InsertFilter("*", beego.BeforeRouter,cors.Allow(&cors.Options{ +// AllowOrigins: []string{"https://*.foo.com"}, +// AllowMethods: []string{"PUT", "PATCH"}, +// AllowHeaders: []string{"Origin"}, +// ExposeHeaders: []string{"Content-Length"}, +// AllowCredentials: true, +// })) +// beego.Run() +// } +package cors + +import ( + "net/http" + "regexp" + "strconv" + "strings" + "time" + + "github.com/astaxie/beego" + "github.com/astaxie/beego/context" +) + +const ( + headerAllowOrigin = "Access-Control-Allow-Origin" + headerAllowCredentials = "Access-Control-Allow-Credentials" + headerAllowHeaders = "Access-Control-Allow-Headers" + headerAllowMethods = "Access-Control-Allow-Methods" + headerExposeHeaders = "Access-Control-Expose-Headers" + headerMaxAge = "Access-Control-Max-Age" + + headerOrigin = "Origin" + headerRequestMethod = "Access-Control-Request-Method" + headerRequestHeaders = "Access-Control-Request-Headers" +) + +var ( + defaultAllowHeaders = []string{"Origin", "Accept", "Content-Type", "Authorization"} + // Regex patterns are generated from AllowOrigins. These are used and generated internally. + allowOriginPatterns = []string{} +) + +// Options represents Access Control options. +type Options struct { + // If set, all origins are allowed. + AllowAllOrigins bool + // A list of allowed origins. Wild cards and FQDNs are supported. + AllowOrigins []string + // If set, allows to share auth credentials such as cookies. + AllowCredentials bool + // A list of allowed HTTP methods. + AllowMethods []string + // A list of allowed HTTP headers. + AllowHeaders []string + // A list of exposed HTTP headers. + ExposeHeaders []string + // Max age of the CORS headers. + MaxAge time.Duration +} + +// Header converts options into CORS headers. +func (o *Options) Header(origin string) (headers map[string]string) { + headers = make(map[string]string) + // if origin is not allowed, don't extend the headers + // with CORS headers. + if !o.AllowAllOrigins && !o.IsOriginAllowed(origin) { + return + } + + // add allow origin + if o.AllowAllOrigins { + headers[headerAllowOrigin] = "*" + } else { + headers[headerAllowOrigin] = origin + } + + // add allow credentials + headers[headerAllowCredentials] = strconv.FormatBool(o.AllowCredentials) + + // add allow methods + if len(o.AllowMethods) > 0 { + headers[headerAllowMethods] = strings.Join(o.AllowMethods, ",") + } + + // add allow headers + if len(o.AllowHeaders) > 0 { + headers[headerAllowHeaders] = strings.Join(o.AllowHeaders, ",") + } + + // add exposed header + if len(o.ExposeHeaders) > 0 { + headers[headerExposeHeaders] = strings.Join(o.ExposeHeaders, ",") + } + // add a max age header + if o.MaxAge > time.Duration(0) { + headers[headerMaxAge] = strconv.FormatInt(int64(o.MaxAge/time.Second), 10) + } + return +} + +// PreflightHeader converts options into CORS headers for a preflight response. +func (o *Options) PreflightHeader(origin, rMethod, rHeaders string) (headers map[string]string) { + headers = make(map[string]string) + if !o.AllowAllOrigins && !o.IsOriginAllowed(origin) { + return + } + // verify if requested method is allowed + for _, method := range o.AllowMethods { + if method == rMethod { + headers[headerAllowMethods] = strings.Join(o.AllowMethods, ",") + break + } + } + + // verify if requested headers are allowed + var allowed []string + for _, rHeader := range strings.Split(rHeaders, ",") { + rHeader = strings.TrimSpace(rHeader) + lookupLoop: + for _, allowedHeader := range o.AllowHeaders { + if strings.ToLower(rHeader) == strings.ToLower(allowedHeader) { + allowed = append(allowed, rHeader) + break lookupLoop + } + } + } + + headers[headerAllowCredentials] = strconv.FormatBool(o.AllowCredentials) + // add allow origin + if o.AllowAllOrigins { + headers[headerAllowOrigin] = "*" + } else { + headers[headerAllowOrigin] = origin + } + + // add allowed headers + if len(allowed) > 0 { + headers[headerAllowHeaders] = strings.Join(allowed, ",") + } + + // add exposed headers + if len(o.ExposeHeaders) > 0 { + headers[headerExposeHeaders] = strings.Join(o.ExposeHeaders, ",") + } + // add a max age header + if o.MaxAge > time.Duration(0) { + headers[headerMaxAge] = strconv.FormatInt(int64(o.MaxAge/time.Second), 10) + } + return +} + +// IsOriginAllowed looks up if the origin matches one of the patterns +// generated from Options.AllowOrigins patterns. +func (o *Options) IsOriginAllowed(origin string) (allowed bool) { + for _, pattern := range allowOriginPatterns { + allowed, _ = regexp.MatchString(pattern, origin) + if allowed { + return + } + } + return +} + +// Allow enables CORS for requests those match the provided options. +func Allow(opts *Options) beego.FilterFunc { + // Allow default headers if nothing is specified. + if len(opts.AllowHeaders) == 0 { + opts.AllowHeaders = defaultAllowHeaders + } + + for _, origin := range opts.AllowOrigins { + pattern := regexp.QuoteMeta(origin) + pattern = strings.Replace(pattern, "\\*", ".*", -1) + pattern = strings.Replace(pattern, "\\?", ".", -1) + allowOriginPatterns = append(allowOriginPatterns, "^"+pattern+"$") + } + + return func(ctx *context.Context) { + var ( + origin = ctx.Input.Header(headerOrigin) + requestedMethod = ctx.Input.Header(headerRequestMethod) + requestedHeaders = ctx.Input.Header(headerRequestHeaders) + // additional headers to be added + // to the response. + headers map[string]string + ) + + if ctx.Input.Method() == "OPTIONS" && + (requestedMethod != "" || requestedHeaders != "") { + headers = opts.PreflightHeader(origin, requestedMethod, requestedHeaders) + for key, value := range headers { + ctx.Output.Header(key, value) + } + ctx.Output.SetStatus(http.StatusOK) + return + } + headers = opts.Header(origin) + + for key, value := range headers { + ctx.Output.Header(key, value) + } + } +} diff --git a/plugins/cors/cors_test.go b/plugins/cors/cors_test.go new file mode 100644 index 00000000..5c02ab98 --- /dev/null +++ b/plugins/cors/cors_test.go @@ -0,0 +1,252 @@ +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cors + +import ( + "net/http" + "net/http/httptest" + "strings" + "testing" + "time" + + "github.com/astaxie/beego" + "github.com/astaxie/beego/context" +) + +type HttpHeaderGuardRecorder struct { + *httptest.ResponseRecorder + savedHeaderMap http.Header +} + +func NewRecorder() *HttpHeaderGuardRecorder { + return &HttpHeaderGuardRecorder{httptest.NewRecorder(), nil} +} + +func (gr *HttpHeaderGuardRecorder) WriteHeader(code int) { + gr.ResponseRecorder.WriteHeader(code) + gr.savedHeaderMap = gr.ResponseRecorder.Header() +} + +func (gr *HttpHeaderGuardRecorder) Header() http.Header { + if gr.savedHeaderMap != nil { + // headers were written. clone so we don't get updates + clone := make(http.Header) + for k, v := range gr.savedHeaderMap { + clone[k] = v + } + return clone + } else { + return gr.ResponseRecorder.Header() + } +} + +func Test_AllowAll(t *testing.T) { + recorder := httptest.NewRecorder() + handler := beego.NewControllerRegister() + handler.InsertFilter("*", beego.BeforeRouter, Allow(&Options{ + AllowAllOrigins: true, + })) + handler.Any("/foo", func(ctx *context.Context) { + ctx.Output.SetStatus(500) + }) + r, _ := http.NewRequest("PUT", "/foo", nil) + handler.ServeHTTP(recorder, r) + + if recorder.HeaderMap.Get(headerAllowOrigin) != "*" { + t.Errorf("Allow-Origin header should be *") + } +} + +func Test_AllowRegexMatch(t *testing.T) { + recorder := httptest.NewRecorder() + handler := beego.NewControllerRegister() + handler.InsertFilter("*", beego.BeforeRouter, Allow(&Options{ + AllowOrigins: []string{"https://aaa.com", "https://*.foo.com"}, + })) + handler.Any("/foo", func(ctx *context.Context) { + ctx.Output.SetStatus(500) + }) + origin := "https://bar.foo.com" + r, _ := http.NewRequest("PUT", "/foo", nil) + r.Header.Add("Origin", origin) + handler.ServeHTTP(recorder, r) + + headerValue := recorder.HeaderMap.Get(headerAllowOrigin) + if headerValue != origin { + t.Errorf("Allow-Origin header should be %v, found %v", origin, headerValue) + } +} + +func Test_AllowRegexNoMatch(t *testing.T) { + recorder := httptest.NewRecorder() + handler := beego.NewControllerRegister() + handler.InsertFilter("*", beego.BeforeRouter, Allow(&Options{ + AllowOrigins: []string{"https://*.foo.com"}, + })) + handler.Any("/foo", func(ctx *context.Context) { + ctx.Output.SetStatus(500) + }) + origin := "https://ww.foo.com.evil.com" + r, _ := http.NewRequest("PUT", "/foo", nil) + r.Header.Add("Origin", origin) + handler.ServeHTTP(recorder, r) + + headerValue := recorder.HeaderMap.Get(headerAllowOrigin) + if headerValue != "" { + t.Errorf("Allow-Origin header should not exist, found %v", headerValue) + } +} + +func Test_OtherHeaders(t *testing.T) { + recorder := httptest.NewRecorder() + handler := beego.NewControllerRegister() + handler.InsertFilter("*", beego.BeforeRouter, Allow(&Options{ + AllowAllOrigins: true, + AllowCredentials: true, + AllowMethods: []string{"PATCH", "GET"}, + AllowHeaders: []string{"Origin", "X-whatever"}, + ExposeHeaders: []string{"Content-Length", "Hello"}, + MaxAge: 5 * time.Minute, + })) + handler.Any("/foo", func(ctx *context.Context) { + ctx.Output.SetStatus(500) + }) + r, _ := http.NewRequest("PUT", "/foo", nil) + handler.ServeHTTP(recorder, r) + + credentialsVal := recorder.HeaderMap.Get(headerAllowCredentials) + methodsVal := recorder.HeaderMap.Get(headerAllowMethods) + headersVal := recorder.HeaderMap.Get(headerAllowHeaders) + exposedHeadersVal := recorder.HeaderMap.Get(headerExposeHeaders) + maxAgeVal := recorder.HeaderMap.Get(headerMaxAge) + + if credentialsVal != "true" { + t.Errorf("Allow-Credentials is expected to be true, found %v", credentialsVal) + } + + if methodsVal != "PATCH,GET" { + t.Errorf("Allow-Methods is expected to be PATCH,GET; found %v", methodsVal) + } + + if headersVal != "Origin,X-whatever" { + t.Errorf("Allow-Headers is expected to be Origin,X-whatever; found %v", headersVal) + } + + if exposedHeadersVal != "Content-Length,Hello" { + t.Errorf("Expose-Headers are expected to be Content-Length,Hello. Found %v", exposedHeadersVal) + } + + if maxAgeVal != "300" { + t.Errorf("Max-Age is expected to be 300, found %v", maxAgeVal) + } +} + +func Test_DefaultAllowHeaders(t *testing.T) { + recorder := httptest.NewRecorder() + handler := beego.NewControllerRegister() + handler.InsertFilter("*", beego.BeforeRouter, Allow(&Options{ + AllowAllOrigins: true, + })) + handler.Any("/foo", func(ctx *context.Context) { + ctx.Output.SetStatus(500) + }) + + r, _ := http.NewRequest("PUT", "/foo", nil) + handler.ServeHTTP(recorder, r) + + headersVal := recorder.HeaderMap.Get(headerAllowHeaders) + if headersVal != "Origin,Accept,Content-Type,Authorization" { + t.Errorf("Allow-Headers is expected to be Origin,Accept,Content-Type,Authorization; found %v", headersVal) + } +} + +func Test_Preflight(t *testing.T) { + recorder := NewRecorder() + handler := beego.NewControllerRegister() + handler.InsertFilter("*", beego.BeforeRouter, Allow(&Options{ + AllowAllOrigins: true, + AllowMethods: []string{"PUT", "PATCH"}, + AllowHeaders: []string{"Origin", "X-whatever", "X-CaseSensitive"}, + })) + + handler.Any("/foo", func(ctx *context.Context) { + ctx.Output.SetStatus(200) + }) + + r, _ := http.NewRequest("OPTIONS", "/foo", nil) + r.Header.Add(headerRequestMethod, "PUT") + r.Header.Add(headerRequestHeaders, "X-whatever, x-casesensitive") + handler.ServeHTTP(recorder, r) + + headers := recorder.Header() + methodsVal := headers.Get(headerAllowMethods) + headersVal := headers.Get(headerAllowHeaders) + originVal := headers.Get(headerAllowOrigin) + + if methodsVal != "PUT,PATCH" { + t.Errorf("Allow-Methods is expected to be PUT,PATCH, found %v", methodsVal) + } + + if !strings.Contains(headersVal, "X-whatever") { + t.Errorf("Allow-Headers is expected to contain X-whatever, found %v", headersVal) + } + + if !strings.Contains(headersVal, "x-casesensitive") { + t.Errorf("Allow-Headers is expected to contain x-casesensitive, found %v", headersVal) + } + + if originVal != "*" { + t.Errorf("Allow-Origin is expected to be *, found %v", originVal) + } + + if recorder.Code != http.StatusOK { + t.Errorf("Status code is expected to be 200, found %d", recorder.Code) + } +} + +func Benchmark_WithoutCORS(b *testing.B) { + recorder := httptest.NewRecorder() + handler := beego.NewControllerRegister() + beego.RunMode = "prod" + handler.Any("/foo", func(ctx *context.Context) { + ctx.Output.SetStatus(500) + }) + b.ResetTimer() + for i := 0; i < 100; i++ { + r, _ := http.NewRequest("PUT", "/foo", nil) + handler.ServeHTTP(recorder, r) + } +} + +func Benchmark_WithCORS(b *testing.B) { + recorder := httptest.NewRecorder() + handler := beego.NewControllerRegister() + beego.RunMode = "prod" + handler.InsertFilter("*", beego.BeforeRouter, Allow(&Options{ + AllowAllOrigins: true, + AllowCredentials: true, + AllowMethods: []string{"PATCH", "GET"}, + AllowHeaders: []string{"Origin", "X-whatever"}, + MaxAge: 5 * time.Minute, + })) + handler.Any("/foo", func(ctx *context.Context) { + ctx.Output.SetStatus(500) + }) + b.ResetTimer() + for i := 0; i < 100; i++ { + r, _ := http.NewRequest("PUT", "/foo", nil) + handler.ServeHTTP(recorder, r) + } +} diff --git a/router.go b/router.go index 0041c273..6f8bd769 100644 --- a/router.go +++ b/router.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package beego @@ -29,7 +37,8 @@ import ( const ( // default filter execution points - BeforeRouter = iota + BeforeStatic = iota + BeforeRouter BeforeExec AfterExec FinishRouter @@ -62,6 +71,8 @@ var ( "DelSession", "SessionRegenerateID", "DestroySession", "IsAjax", "GetSecureCookie", "SetSecureCookie", "XsrfToken", "CheckXsrfCookie", "XsrfFormHtml", "GetControllerAndAction"} + + url_placeholder = "{{placeholder}}" ) // To append a slice's value into "exceptMethod", for controller's methods shouldn't reflect to AutoRouter @@ -342,19 +353,23 @@ func (p *ControllerRegistor) AddAutoPrefix(prefix string, c ControllerInterface) reflectVal := reflect.ValueOf(c) rt := reflectVal.Type() ct := reflect.Indirect(reflectVal).Type() - controllerName := strings.ToLower(strings.TrimSuffix(ct.Name(), "Controller")) + controllerName := strings.TrimSuffix(ct.Name(), "Controller") for i := 0; i < rt.NumMethod(); i++ { if !utils.InSlice(rt.Method(i).Name, exceptMethod) { route := &controllerInfo{} route.routerType = routerTypeBeego route.methods = map[string]string{"*": rt.Method(i).Name} route.controllerType = ct - pattern := path.Join(prefix, controllerName, strings.ToLower(rt.Method(i).Name), "*") - patternfix := path.Join(prefix, controllerName, strings.ToLower(rt.Method(i).Name)) + pattern := path.Join(prefix, strings.ToLower(controllerName), strings.ToLower(rt.Method(i).Name), "*") + patternInit := path.Join(prefix, controllerName, rt.Method(i).Name, "*") + patternfix := path.Join(prefix, strings.ToLower(controllerName), strings.ToLower(rt.Method(i).Name)) + patternfixInit := path.Join(prefix, controllerName, rt.Method(i).Name) route.pattern = pattern for _, m := range HTTPMETHOD { p.addToRouter(m, pattern, route) + p.addToRouter(m, patternInit, route) p.addToRouter(m, patternfix, route) + p.addToRouter(m, patternfixInit, route) } } } @@ -420,6 +435,7 @@ func (p *ControllerRegistor) geturl(t *Tree, url, controllName, methodName strin } } if t.wildcard != nil { + url = path.Join(url, url_placeholder) ok, u := p.geturl(t.wildcard, url, controllName, methodName, params) if ok { return ok, u @@ -448,15 +464,14 @@ func (p *ControllerRegistor) geturl(t *Tree, url, controllName, methodName strin if find { if l.regexps == nil { if len(l.wildcards) == 0 { - return true, url + return true, strings.Replace(url, "/"+url_placeholder, "", 1) + tourl(params) } if len(l.wildcards) == 1 { if v, ok := params[l.wildcards[0]]; ok { delete(params, l.wildcards[0]) - return true, url + "/" + v + tourl(params) - } - if l.wildcards[0] == ":splat" { - return true, url + tourl(params) + return true, strings.Replace(url, url_placeholder, v, 1) + tourl(params) + } else { + return false, "" } } if len(l.wildcards) == 3 && l.wildcards[0] == "." { @@ -464,7 +479,7 @@ func (p *ControllerRegistor) geturl(t *Tree, url, controllName, methodName strin if e, isok := params[":ext"]; isok { delete(params, ":path") delete(params, ":ext") - return true, url + "/" + p + "." + e + tourl(params) + return true, strings.Replace(url, url_placeholder, p+"."+e, -1) + tourl(params) } } } @@ -475,7 +490,8 @@ func (p *ControllerRegistor) geturl(t *Tree, url, controllName, methodName strin continue } if u, ok := params[v]; ok { - url += "/" + u + delete(params, v) + url = strings.Replace(url, url_placeholder, u, 1) } else { if canskip { canskip = false @@ -485,7 +501,7 @@ func (p *ControllerRegistor) geturl(t *Tree, url, controllName, methodName strin } } } - return true, url + return true, url + tourl(params) } else { var i int var startreg bool @@ -508,11 +524,11 @@ func (p *ControllerRegistor) geturl(t *Tree, url, controllName, methodName strin } } if l.regexps.MatchString(regurl) { - if url == "/" { - return true, url + regurl + tourl(params) - } else { - return true, url + "/" + regurl + tourl(params) + ps := strings.Split(regurl, "/") + for _, p := range ps { + url = strings.Replace(url, url_placeholder, p, 1) } + return true, url + tourl(params) } } } @@ -567,6 +583,23 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) return false } + // filter wrong httpmethod + if _, ok := HTTPMETHOD[r.Method]; !ok { + http.Error(w, "Method Not Allowed", 405) + goto Admin + } + + // filter for static file + if do_filter(BeforeStatic) { + goto Admin + } + + serverStaticRouter(context) + if w.started { + findrouter = true + goto Admin + } + // session init if SessionOn { context.Input.CruSession = GlobalSessions.SessionStart(w, r) @@ -575,11 +608,6 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) }() } - if _, ok := HTTPMETHOD[r.Method]; !ok { - http.Error(w, "Method Not Allowed", 405) - goto Admin - } - if r.Method != "GET" && r.Method != "HEAD" { if CopyRequestBody && !context.Input.IsUpload() { context.Input.CopyBody() @@ -710,12 +738,11 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) } //render template - if !w.started { + if !w.started && context.Output.Status == 0 { if AutoRender { if err := execController.Render(); err != nil { panic(err) } - } } } @@ -746,11 +773,22 @@ Admin: } if RunMode == "dev" { + var devinfo string if findrouter { - Info("beego: router defined " + routerInfo.pattern + " " + r.URL.Path + " +" + timeend.String()) + if routerInfo != nil { + devinfo = fmt.Sprintf("| % -10s | % -40s | % -16s | % -10s | % -40s |", r.Method, r.URL.Path, timeend.String(), "match", routerInfo.pattern) + } else { + devinfo = fmt.Sprintf("| % -10s | % -40s | % -16s | % -10s |", r.Method, r.URL.Path, timeend.String(), "match") + } } else { - Info("beego:" + r.URL.Path + " 404" + " +" + timeend.String()) + devinfo = fmt.Sprintf("| % -10s | % -40s | % -16s | % -10s |", r.Method, r.URL.Path, timeend.String(), "notmatch") } + Debug(devinfo) + } + + // Call WriteHeader if status code has been set changed + if context.Output.Status != 0 { + w.writer.WriteHeader(context.Output.Status) } } diff --git a/router_test.go b/router_test.go index b80000f4..d378589b 100644 --- a/router_test.go +++ b/router_test.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package beego @@ -91,10 +99,10 @@ func TestUrlFor(t *testing.T) { func TestUrlFor3(t *testing.T) { handler := NewControllerRegister() handler.AddAuto(&TestController{}) - if a := handler.UrlFor("TestController.Myext"); a != "/test/myext" { + if a := handler.UrlFor("TestController.Myext"); a != "/test/myext" && a != "/Test/Myext" { t.Errorf("TestController.Myext must equal to /test/myext, but get " + a) } - if a := handler.UrlFor("TestController.GetUrl"); a != "/test/geturl" { + if a := handler.UrlFor("TestController.GetUrl"); a != "/test/geturl" && a != "/Test/GetUrl" { t.Errorf("TestController.GetUrl must equal to /test/geturl, but get " + a) } } @@ -102,8 +110,14 @@ func TestUrlFor3(t *testing.T) { func TestUrlFor2(t *testing.T) { handler := NewControllerRegister() handler.Add("/v1/:v/cms_:id(.+)_:page(.+).html", &TestController{}, "*:List") + handler.Add("/v1/:username/edit", &TestController{}, "get:GetUrl") handler.Add("/v1/:v(.+)_cms/ttt_:id(.+)_:page(.+).html", &TestController{}, "*:Param") handler.Add("/:year:int/:month:int/:title/:entid", &TestController{}) + if handler.UrlFor("TestController.GetUrl", ":username", "astaxie") != "/v1/astaxie/edit" { + Info(handler.UrlFor("TestController.GetUrl")) + t.Errorf("TestController.List must equal to /v1/astaxie/edit") + } + if handler.UrlFor("TestController.List", ":v", "za", ":id", "12", ":page", "123") != "/v1/za/cms_12_123.html" { Info(handler.UrlFor("TestController.List")) @@ -158,6 +172,18 @@ func TestAutoFunc(t *testing.T) { } } +func TestAutoFunc2(t *testing.T) { + r, _ := http.NewRequest("GET", "/Test/List", nil) + w := httptest.NewRecorder() + + handler := NewControllerRegister() + handler.AddAuto(&TestController{}) + handler.ServeHTTP(w, r) + if w.Body.String() != "i am list" { + t.Errorf("user define func can't run") + } +} + func TestAutoFuncParams(t *testing.T) { r, _ := http.NewRequest("GET", "/test/params/2009/11/12", nil) w := httptest.NewRecorder() diff --git a/session/couchbase/sess_couchbase.go b/session/couchbase/sess_couchbase.go index 9f68b946..827d55d9 100644 --- a/session/couchbase/sess_couchbase.go +++ b/session/couchbase/sess_couchbase.go @@ -1,9 +1,35 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// package couchbase for session provider +// +// depend on github.com/couchbaselabs/go-couchbasee +// +// go install github.com/couchbaselabs/go-couchbase +// +// Usage: +// import( +// _ "github.com/astaxie/beego/session/couchbase" +// "github.com/astaxie/beego/session" +// ) +// +// func init() { +// globalSessions, _ = session.NewManager("couchbase", ``{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"http://host:port/, Pool, Bucket"}``) +// go globalSessions.GC() +// } +// +// more docs: http://beego.me/docs/module/session.md package session import ( @@ -72,12 +98,6 @@ func (cs *CouchbaseSessionStore) SessionID() string { func (cs *CouchbaseSessionStore) SessionRelease(w http.ResponseWriter) { defer cs.b.Close() - // if rs.values is empty, return directly - if len(cs.values) < 1 { - cs.b.Delete(cs.sid) - return - } - bo, err := session.EncodeGob(cs.values) if err != nil { return diff --git a/session/memcache/sess_memcache.go b/session/memcache/sess_memcache.go index fa8fa165..5827a0a9 100644 --- a/session/memcache/sess_memcache.go +++ b/session/memcache/sess_memcache.go @@ -1,25 +1,52 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// package memcache for session provider +// +// depend on github.com/bradfitz/gomemcache/memcache +// +// go install github.com/bradfitz/gomemcache/memcache +// +// Usage: +// import( +// _ "github.com/astaxie/beego/session/memcache" +// "github.com/astaxie/beego/session" +// ) +// +// func init() { +// globalSessions, _ = session.NewManager("memcache", ``{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"127.0.0.1:11211"}``) +// go globalSessions.GC() +// } +// +// more docs: http://beego.me/docs/module/session.md package session import ( "net/http" + "strings" "sync" "github.com/astaxie/beego/session" - "github.com/beego/memcache" + "github.com/bradfitz/gomemcache/memcache" ) var mempder = &MemProvider{} +var client *memcache.Client // memcache session store type MemcacheSessionStore struct { - c *memcache.Connection sid string lock sync.RWMutex values map[interface{}]interface{} @@ -61,133 +88,138 @@ func (rs *MemcacheSessionStore) Flush() error { return nil } -// get redis session id +// get memcache session id func (rs *MemcacheSessionStore) SessionID() string { return rs.sid } -// save session values to redis +// save session values to memcache func (rs *MemcacheSessionStore) SessionRelease(w http.ResponseWriter) { - defer rs.c.Close() - // if rs.values is empty, return directly - if len(rs.values) < 1 { - rs.c.Delete(rs.sid) - return - } - b, err := session.EncodeGob(rs.values) if err != nil { return } - rs.c.Set(rs.sid, 0, uint64(rs.maxlifetime), b) + item := memcache.Item{Key: rs.sid, Value: b, Expiration: int32(rs.maxlifetime)} + client.Set(&item) } -// redis session provider +// memcahe session provider type MemProvider struct { maxlifetime int64 - savePath string + conninfo []string poolsize int password string } -// init redis session +// init memcache session // savepath like // e.g. 127.0.0.1:9090 func (rp *MemProvider) SessionInit(maxlifetime int64, savePath string) error { rp.maxlifetime = maxlifetime - rp.savePath = savePath + rp.conninfo = strings.Split(savePath, ";") + client = memcache.New(rp.conninfo...) return nil } -// read redis session by sid +// read memcache session by sid func (rp *MemProvider) SessionRead(sid string) (session.SessionStore, error) { - conn, err := rp.connectInit() + if client == nil { + if err := rp.connectInit(); err != nil { + return nil, err + } + } + item, err := client.Get(sid) if err != nil { return nil, err } - kvs, err := conn.Get(sid) - if err != nil { - return nil, err - } - var contain []byte - if len(kvs) > 0 { - contain = kvs[0].Value - } var kv map[interface{}]interface{} - if len(contain) == 0 { + if len(item.Value) == 0 { kv = make(map[interface{}]interface{}) } else { - kv, err = session.DecodeGob(contain) + kv, err = session.DecodeGob(item.Value) if err != nil { return nil, err } } - rs := &MemcacheSessionStore{c: conn, sid: sid, values: kv, maxlifetime: rp.maxlifetime} + rs := &MemcacheSessionStore{sid: sid, values: kv, maxlifetime: rp.maxlifetime} return rs, nil } -// check redis session exist by sid +// check memcache session exist by sid func (rp *MemProvider) SessionExist(sid string) bool { - conn, err := rp.connectInit() - if err != nil { - return false + if client == nil { + if err := rp.connectInit(); err != nil { + return false + } } - defer conn.Close() - if kvs, err := conn.Get(sid); err != nil || len(kvs) == 0 { + if item, err := client.Get(sid); err != nil || len(item.Value) == 0 { return false } else { return true } } -// generate new sid for redis session +// generate new sid for memcache session func (rp *MemProvider) SessionRegenerate(oldsid, sid string) (session.SessionStore, error) { - conn, err := rp.connectInit() - if err != nil { - return nil, err + if client == nil { + if err := rp.connectInit(); err != nil { + return nil, err + } } var contain []byte - if kvs, err := conn.Get(sid); err != nil || len(kvs) == 0 { + if item, err := client.Get(sid); err != nil || len(item.Value) == 0 { // oldsid doesn't exists, set the new sid directly // ignore error here, since if it return error // the existed value will be 0 - conn.Set(sid, 0, uint64(rp.maxlifetime), []byte("")) + item.Key = sid + item.Value = []byte("") + item.Expiration = int32(rp.maxlifetime) + client.Set(item) } else { - conn.Delete(oldsid) - conn.Set(sid, 0, uint64(rp.maxlifetime), kvs[0].Value) - contain = kvs[0].Value + client.Delete(oldsid) + item.Key = sid + item.Value = item.Value + item.Expiration = int32(rp.maxlifetime) + client.Set(item) + contain = item.Value } var kv map[interface{}]interface{} if len(contain) == 0 { kv = make(map[interface{}]interface{}) } else { + var err error kv, err = session.DecodeGob(contain) if err != nil { return nil, err } } - rs := &MemcacheSessionStore{c: conn, sid: sid, values: kv, maxlifetime: rp.maxlifetime} + rs := &MemcacheSessionStore{sid: sid, values: kv, maxlifetime: rp.maxlifetime} return rs, nil } -// delete redis session by id +// delete memcache session by id func (rp *MemProvider) SessionDestroy(sid string) error { - conn, err := rp.connectInit() - if err != nil { - return err + if client == nil { + if err := rp.connectInit(); err != nil { + return err + } } - defer conn.Close() - _, err = conn.Delete(sid) + err := client.Delete(sid) if err != nil { return err } return nil } +func (rp *MemProvider) connectInit() error { + client = memcache.New(rp.conninfo...) + return nil +} + // Impelment method, no used. func (rp *MemProvider) SessionGC() { return @@ -198,15 +230,6 @@ func (rp *MemProvider) SessionAll() int { return 0 } -// connect to memcache and keep the connection. -func (rp *MemProvider) connectInit() (*memcache.Connection, error) { - c, err := memcache.Connect(rp.savePath) - if err != nil { - return nil, err - } - return c, nil -} - func init() { session.Register("memcache", mempder) } diff --git a/session/mysql/sess_mysql.go b/session/mysql/sess_mysql.go index 530ca158..0f6d3e4f 100644 --- a/session/mysql/sess_mysql.go +++ b/session/mysql/sess_mysql.go @@ -1,11 +1,23 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie - -package session +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// package mysql for session provider +// +// depends on github.com/go-sql-driver/mysql: +// +// go install github.com/go-sql-driver/mysql +// // mysql session support need create table as sql: // CREATE TABLE `session` ( // `session_key` char(64) NOT NULL, @@ -13,6 +25,20 @@ package session // `session_expiry` int(11) unsigned NOT NULL, // PRIMARY KEY (`session_key`) // ) ENGINE=MyISAM DEFAULT CHARSET=utf8; +// +// Usage: +// import( +// _ "github.com/astaxie/beego/session/mysql" +// "github.com/astaxie/beego/session" +// ) +// +// func init() { +// globalSessions, _ = session.NewManager("mysql", ``{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"[username[:password]@][protocol[(address)]]/dbname[?param1=value1&...¶mN=valueN]"}``) +// go globalSessions.GC() +// } +// +// more docs: http://beego.me/docs/module/session.md +package session import ( "database/sql" diff --git a/session/postgres/sess_postgresql.go b/session/postgres/sess_postgresql.go index 7f905997..ac9a1612 100644 --- a/session/postgres/sess_postgresql.go +++ b/session/postgres/sess_postgresql.go @@ -1,40 +1,55 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// package postgresql for session provider +// +// depends on github.com/lib/pq: +// +// go install github.com/lib/pq +// +// +// needs this table in your database: +// +// CREATE TABLE session ( +// session_key char(64) NOT NULL, +// session_data bytea, +// session_expiry timestamp NOT NULL, +// CONSTRAINT session_key PRIMARY KEY(session_key) +// ); + +// will be activated with these settings in app.conf: + +// SessionOn = true +// SessionProvider = postgresql +// SessionSavePath = "user=a password=b dbname=c sslmode=disable" +// SessionName = session +// +// +// Usage: +// import( +// _ "github.com/astaxie/beego/session/postgresql" +// "github.com/astaxie/beego/session" +// ) +// +// func init() { +// globalSessions, _ = session.NewManager("postgresql", ``{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"user=pqgotest dbname=pqgotest sslmode=verify-full"}``) +// go globalSessions.GC() +// } +// +// more docs: http://beego.me/docs/module/session.md package session -/* - -beego session provider for postgresql -------------------------------------- - -depends on github.com/lib/pq: - -go install github.com/lib/pq - - -needs this table in your database: - -CREATE TABLE session ( -session_key char(64) NOT NULL, -session_data bytea, -session_expiry timestamp NOT NULL, -CONSTRAINT session_key PRIMARY KEY(session_key) -); - - -will be activated with these settings in app.conf: - -SessionOn = true -SessionProvider = postgresql -SessionSavePath = "user=a password=b dbname=c sslmode=disable" -SessionName = session - -*/ - import ( "database/sql" "net/http" diff --git a/session/redis/sess_redis.go b/session/redis/sess_redis.go index 3ad19792..f2b0b29b 100644 --- a/session/redis/sess_redis.go +++ b/session/redis/sess_redis.go @@ -1,9 +1,35 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// package redis for session provider +// +// depend on github.com/garyburd/redigo/redis +// +// go install github.com/garyburd/redigo/redis +// +// Usage: +// import( +// _ "github.com/astaxie/beego/session/redis" +// "github.com/astaxie/beego/session" +// ) +// +// func init() { +// globalSessions, _ = session.NewManager("redis", ``{"cookieName":"gosessionid","gclifetime":3600,"ProviderConfig":"127.0.0.1:7070"}``) +// go globalSessions.GC() +// } +// +// more docs: http://beego.me/docs/module/session.md package session import ( @@ -14,7 +40,7 @@ import ( "github.com/astaxie/beego/session" - "github.com/beego/redigo/redis" + "github.com/garyburd/redigo/redis" ) var redispder = &RedisProvider{} @@ -78,12 +104,6 @@ func (rs *RedisSessionStore) SessionRelease(w http.ResponseWriter) { c := rs.p.Get() defer c.Close() - // if rs.values is empty, return directly - if len(rs.values) < 1 { - c.Do("DEL", rs.sid) - return - } - b, err := session.EncodeGob(rs.values) if err != nil { return diff --git a/session/sess_cookie.go b/session/sess_cookie.go index 1a06add6..01dc505c 100644 --- a/session/sess_cookie.go +++ b/session/sess_cookie.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package session diff --git a/session/sess_cookie_test.go b/session/sess_cookie_test.go index 9ab321f5..4f40a7ba 100644 --- a/session/sess_cookie_test.go +++ b/session/sess_cookie_test.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package session diff --git a/session/sess_file.go b/session/sess_file.go index 74b71223..b1084acf 100644 --- a/session/sess_file.go +++ b/session/sess_file.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package session @@ -26,7 +34,6 @@ var ( // File session store type FileSessionStore struct { - f *os.File sid string lock sync.RWMutex values map[interface{}]interface{} @@ -74,14 +81,23 @@ func (fs *FileSessionStore) SessionID() string { // Write file session to local file with Gob string func (fs *FileSessionStore) SessionRelease(w http.ResponseWriter) { - defer fs.f.Close() b, err := EncodeGob(fs.values) if err != nil { return } - fs.f.Truncate(0) - fs.f.Seek(0, 0) - fs.f.Write(b) + _, err = os.Stat(path.Join(filepder.savePath, string(fs.sid[0]), string(fs.sid[1]), fs.sid)) + var f *os.File + if err == nil { + f, err = os.OpenFile(path.Join(filepder.savePath, string(fs.sid[0]), string(fs.sid[1]), fs.sid), os.O_RDWR, 0777) + } else if os.IsNotExist(err) { + f, err = os.Create(path.Join(filepder.savePath, string(fs.sid[0]), string(fs.sid[1]), fs.sid)) + } else { + return + } + f.Truncate(0) + f.Seek(0, 0) + f.Write(b) + f.Close() } // File session provider @@ -134,8 +150,7 @@ func (fp *FileProvider) SessionRead(sid string) (SessionStore, error) { } } f.Close() - f, err = os.OpenFile(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid), os.O_WRONLY|os.O_CREATE, 0777) - ss := &FileSessionStore{f: f, sid: sid, values: kv} + ss := &FileSessionStore{sid: sid, values: kv} return ss, nil } @@ -232,9 +247,7 @@ func (fp *FileProvider) SessionRegenerate(oldsid, sid string) (SessionStore, err return nil, err } } - - newf, err = os.OpenFile(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid), os.O_WRONLY|os.O_CREATE, 0777) - ss := &FileSessionStore{f: newf, sid: sid, values: kv} + ss := &FileSessionStore{sid: sid, values: kv} return ss, nil } diff --git a/session/sess_mem.go b/session/sess_mem.go index e440b2f5..627a3246 100644 --- a/session/sess_mem.go +++ b/session/sess_mem.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package session diff --git a/session/sess_mem_test.go b/session/sess_mem_test.go index 5e54c634..03927c76 100644 --- a/session/sess_mem_test.go +++ b/session/sess_mem_test.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package session diff --git a/session/sess_test.go b/session/sess_test.go index 1db55a64..5ba910f2 100644 --- a/session/sess_test.go +++ b/session/sess_test.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package session diff --git a/session/sess_utils.go b/session/sess_utils.go index b9a965c3..9ae74528 100644 --- a/session/sess_utils.go +++ b/session/sess_utils.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package session diff --git a/session/session.go b/session/session.go index eb9162b8..88e94d59 100644 --- a/session/session.go +++ b/session/session.go @@ -1,9 +1,30 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// package session provider +// +// Usage: +// import( +// "github.com/astaxie/beego/session" +// ) +// +// func init() { +// globalSessions, _ = session.NewManager("memory", `{"cookieName":"gosessionid", "enableSetCookie,omitempty": true, "gclifetime":3600, "maxLifetime": 3600, "secure": false, "sessionIDHashFunc": "sha1", "sessionIDHashKey": "", "cookieLifeTime": 3600, "providerConfig": ""}`) +// go globalSessions.GC() +// } +// +// more docs: http://beego.me/docs/module/session.md package session import ( @@ -69,6 +90,7 @@ type managerConfig struct { SessionIDHashKey string `json:"sessionIDHashKey"` CookieLifeTime int `json:"cookieLifeTime"` ProviderConfig string `json:"providerConfig"` + Domain string `json:"domain"` } // Manager contains Provider and its configuration. @@ -131,7 +153,8 @@ func (manager *Manager) SessionStart(w http.ResponseWriter, r *http.Request) (se Value: url.QueryEscape(sid), Path: "/", HttpOnly: true, - Secure: manager.config.Secure} + Secure: manager.config.Secure, + Domain: manager.config.Domain} if manager.config.CookieLifeTime >= 0 { cookie.MaxAge = manager.config.CookieLifeTime } @@ -150,7 +173,8 @@ func (manager *Manager) SessionStart(w http.ResponseWriter, r *http.Request) (se Value: url.QueryEscape(sid), Path: "/", HttpOnly: true, - Secure: manager.config.Secure} + Secure: manager.config.Secure, + Domain: manager.config.Domain} if manager.config.CookieLifeTime >= 0 { cookie.MaxAge = manager.config.CookieLifeTime } @@ -205,6 +229,7 @@ func (manager *Manager) SessionRegenerateId(w http.ResponseWriter, r *http.Reque Path: "/", HttpOnly: true, Secure: manager.config.Secure, + Domain: manager.config.Domain, } } else { oldsid, _ := url.QueryUnescape(cookie.Value) diff --git a/staticfile.go b/staticfile.go index 09f3018f..a9deabe9 100644 --- a/staticfile.go +++ b/staticfile.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package beego @@ -19,16 +27,22 @@ import ( ) func serverStaticRouter(ctx *context.Context) { + if ctx.Input.Method() != "GET" && ctx.Input.Method() != "HEAD" { + return + } requestPath := path.Clean(ctx.Input.Request.URL.Path) for prefix, staticDir := range StaticDir { if len(prefix) == 0 { continue } - if requestPath == "/favicon.ico" { + if requestPath == "/favicon.ico" || requestPath == "/robots.txt" { file := path.Join(staticDir, requestPath) if utils.FileExists(file) { http.ServeFile(ctx.ResponseWriter, ctx.Request, file) return + } else { + http.NotFound(ctx.ResponseWriter, ctx.Request) + return } } if strings.HasPrefix(requestPath, prefix) { diff --git a/swagger/docsSpec.go b/swagger/docsSpec.go index 94ff75ef..6f8fe1db 100644 --- a/swagger/docsSpec.go +++ b/swagger/docsSpec.go @@ -1,3 +1,18 @@ +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// swagger struct definition package swagger const SwaggerVersion = "1.2" diff --git a/template.go b/template.go index 9411930c..2ca84f22 100644 --- a/template.go +++ b/template.go @@ -1,13 +1,19 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package beego -//@todo add template funcs - import ( "errors" "fmt" diff --git a/template_test.go b/template_test.go index 15014980..b35da5ce 100644 --- a/template_test.go +++ b/template_test.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package beego diff --git a/templatefunc.go b/templatefunc.go index ef7658d6..a365718d 100644 --- a/templatefunc.go +++ b/templatefunc.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package beego @@ -24,6 +32,9 @@ func Substr(s string, start, length int) string { if start < 0 { start = 0 } + if start > len(bt) { + start = start % len(bt) + } var end int if (start + length) > (len(bt) - 1) { end = len(bt) @@ -37,23 +48,20 @@ func Substr(s string, start, length int) string { func Html2str(html string) string { src := string(html) - //将HTML标签全转换成小写 re, _ := regexp.Compile("\\<[\\S\\s]+?\\>") src = re.ReplaceAllStringFunc(src, strings.ToLower) - //去除STYLE + //remove STYLE re, _ = regexp.Compile("\\") src = re.ReplaceAllString(src, "") - //去除SCRIPT + //remove SCRIPT re, _ = regexp.Compile("\\") src = re.ReplaceAllString(src, "") - //去除所有尖括号内的HTML代码,并换成换行符 re, _ = regexp.Compile("\\<[\\S\\s]+?\\>") src = re.ReplaceAllString(src, "\n") - //去除连续的换行符 re, _ = regexp.Compile("\\s{2,}") src = re.ReplaceAllString(src, "\n") @@ -326,14 +334,6 @@ func ParseForm(form url.Values, obj interface{}) error { return nil } -// form types for RenderForm function -var FormType = map[string]bool{ - "text": true, - "textarea": true, - "hidden": true, - "password": true, -} - var unKind = map[reflect.Kind]bool{ reflect.Uintptr: true, reflect.Complex64: true, @@ -367,44 +367,75 @@ func RenderForm(obj interface{}) template.HTML { } fieldT := objT.Field(i) - tags := strings.Split(fieldT.Tag.Get("form"), ",") - label := fieldT.Name + ": " - name := fieldT.Name - fType := "text" - switch len(tags) { - case 1: - if tags[0] == "-" { - continue - } - if len(tags[0]) > 0 { - name = tags[0] - } - case 2: - if len(tags[0]) > 0 { - name = tags[0] - } - if len(tags[1]) > 0 { - fType = tags[1] - } - case 3: - if len(tags[0]) > 0 { - name = tags[0] - } - if len(tags[1]) > 0 { - fType = tags[1] - } - if len(tags[2]) > 0 { - label = tags[2] - } + label, name, fType, ignored := parseFormTag(fieldT) + if ignored { + continue } - raw = append(raw, fmt.Sprintf(`%v`, - label, name, fType, fieldV.Interface())) + raw = append(raw, renderFormField(label, name, fType, fieldV.Interface())) } return template.HTML(strings.Join(raw, "
")) } +// renderFormField returns a string containing HTML of a single form field. +func renderFormField(label, name, fType string, value interface{}) string { + if isValidForInput(fType) { + return fmt.Sprintf(`%v`, label, name, fType, value) + } + + return fmt.Sprintf(`%v<%v name="%v">%v`, label, fType, name, value, fType) +} + +// isValidForInput checks if fType is a valid value for the `type` property of an HTML input element. +func isValidForInput(fType string) bool { + validInputTypes := strings.Fields("text password checkbox radio submit reset hidden image file button search email url tel number range date month week time datetime datetime-local color") + for _, validType := range validInputTypes { + if fType == validType { + return true + } + } + return false +} + +// parseFormTag takes the stuct-tag of a StructField and parses the `form` value. +// returned are the form label, name-property, type and wether the field should be ignored. +func parseFormTag(fieldT reflect.StructField) (label, name, fType string, ignored bool) { + tags := strings.Split(fieldT.Tag.Get("form"), ",") + label = fieldT.Name + ": " + name = fieldT.Name + fType = "text" + ignored = false + + switch len(tags) { + case 1: + if tags[0] == "-" { + ignored = true + } + if len(tags[0]) > 0 { + name = tags[0] + } + case 2: + if len(tags[0]) > 0 { + name = tags[0] + } + if len(tags[1]) > 0 { + fType = tags[1] + } + case 3: + if len(tags[0]) > 0 { + name = tags[0] + } + if len(tags[1]) > 0 { + fType = tags[1] + } + if len(tags[2]) > 0 { + label = tags[2] + } + } + return +} + func isStructPtr(t reflect.Type) bool { return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct } diff --git a/templatefunc_test.go b/templatefunc_test.go index 8a450408..44a06dec 100644 --- a/templatefunc_test.go +++ b/templatefunc_test.go @@ -1,14 +1,23 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package beego import ( "html/template" "net/url" + "reflect" "testing" "time" ) @@ -21,6 +30,9 @@ func TestSubstr(t *testing.T) { if Substr(s, 0, 100) != "012345" { t.Error("should be equal") } + if Substr(s, 12, 100) != "012345" { + t.Error("should be equal") + } } func TestHtml2str(t *testing.T) { @@ -136,16 +148,17 @@ func TestParseForm(t *testing.T) { func TestRenderForm(t *testing.T) { type user struct { - Id int `form:"-"` - tag string `form:"tag"` - Name interface{} `form:"username"` - Age int `form:"age,text,年龄:"` - Sex string - Email []string - Intro string `form:",textarea"` + Id int `form:"-"` + tag string `form:"tag"` + Name interface{} `form:"username"` + Age int `form:"age,text,年龄:"` + Sex string + Email []string + Intro string `form:",textarea"` + Ignored string `form:"-"` } - u := user{Name: "test"} + u := user{Name: "test", Intro: "Some Text"} output := RenderForm(u) if output != template.HTML("") { t.Errorf("output should be empty but got %v", output) @@ -155,8 +168,58 @@ func TestRenderForm(t *testing.T) { `Name:
` + `年龄:
` + `Sex:
` + - `Intro: `) + `Intro: `) if output != result { t.Errorf("output should equal `%v` but got `%v`", result, output) } } + +func TestRenderFormField(t *testing.T) { + html := renderFormField("Label: ", "Name", "text", "Value") + if html != `Label: ` { + t.Errorf("Wrong html output for input[type=text]: %v ", html) + } + + html = renderFormField("Label: ", "Name", "textarea", "Value") + if html != `Label: ` { + t.Errorf("Wrong html output for textarea: %v ", html) + } +} + +func TestParseFormTag(t *testing.T) { + // create struct to contain field with different types of struct-tag `form` + type user struct { + All int `form:"name,text,年龄:"` + NoName int `form:",hidden,年龄:"` + OnlyLabel int `form:",,年龄:"` + OnlyName int `form:"name"` + Ignored int `form:"-"` + } + + objT := reflect.TypeOf(&user{}).Elem() + + label, name, fType, ignored := parseFormTag(objT.Field(0)) + if !(name == "name" && label == "年龄:" && fType == "text" && ignored == false) { + t.Errorf("Form Tag with name, label and type was not correctly parsed.") + } + + label, name, fType, ignored = parseFormTag(objT.Field(1)) + if !(name == "NoName" && label == "年龄:" && fType == "hidden" && ignored == false) { + t.Errorf("Form Tag with label and type but without name was not correctly parsed.") + } + + label, name, fType, ignored = parseFormTag(objT.Field(2)) + if !(name == "OnlyLabel" && label == "年龄:" && fType == "text" && ignored == false) { + t.Errorf("Form Tag containing only label was not correctly parsed.") + } + + label, name, fType, ignored = parseFormTag(objT.Field(3)) + if !(name == "name" && label == "OnlyName: " && fType == "text" && ignored == false) { + t.Errorf("Form Tag containing only name was not correctly parsed.") + } + + label, name, fType, ignored = parseFormTag(objT.Field(4)) + if ignored == false { + t.Errorf("Form Tag that should be ignored was not correctly parsed.") + } +} diff --git a/testing/assertions.go b/testing/assertions.go new file mode 100644 index 00000000..96c5d4dd --- /dev/null +++ b/testing/assertions.go @@ -0,0 +1,15 @@ +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package testing diff --git a/testing/client.go b/testing/client.go index a4408681..366bda96 100644 --- a/testing/client.go +++ b/testing/client.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package testing diff --git a/toolbox/debug_test.go b/toolbox/debug_test.go deleted file mode 100644 index 4ef89983..00000000 --- a/toolbox/debug_test.go +++ /dev/null @@ -1,38 +0,0 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie - -package toolbox - -import ( - "testing" -) - -type mytype struct { - next *mytype - prev *mytype -} - -func TestPrint(t *testing.T) { - Display("v1", 1, "v2", 2, "v3", 3) -} - -func TestPrintPoint(t *testing.T) { - var v1 = new(mytype) - var v2 = new(mytype) - - v1.prev = nil - v1.next = v2 - - v2.prev = v1 - v2.next = nil - - Display("v1", v1, "v2", v2) -} - -func TestPrintString(t *testing.T) { - str := GetDisplayString("v1", 1, "v2", 2) - println(str) -} diff --git a/toolbox/healthcheck.go b/toolbox/healthcheck.go index 0f4c0e29..4ccff785 100644 --- a/toolbox/healthcheck.go +++ b/toolbox/healthcheck.go @@ -1,23 +1,34 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -package toolbox - -//type DatabaseCheck struct { -//} - -//func (dc *DatabaseCheck) Check() error { +// toolbox healthcheck +// +// type DatabaseCheck struct { +// } +// +// func (dc *DatabaseCheck) Check() error { // if dc.isConnected() { // return nil // } else { // return errors.New("can't connect database") -// } -//} - -//AddHealthCheck("database",&DatabaseCheck{}) +// } +// } +// +// AddHealthCheck("database",&DatabaseCheck{}) +// +// more docs: http://beego.me/docs/module/toolbox.md +package toolbox // health checker map var AdminCheckList map[string]HealthChecker diff --git a/toolbox/profile.go b/toolbox/profile.go index 3200d547..b428e2ff 100644 --- a/toolbox/profile.go +++ b/toolbox/profile.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package toolbox @@ -11,6 +19,7 @@ import ( "io" "log" "os" + "path" "runtime" "runtime/debug" "runtime/pprof" @@ -40,40 +49,47 @@ func ProcessInput(input string, w io.Writer) { case "lookup block": p := pprof.Lookup("block") p.WriteTo(w, 2) - case "start cpuprof": - StartCPUProfile() - case "stop cpuprof": - StopCPUProfile() + case "get cpuprof": + GetCPUProfile(w) case "get memprof": - MemProf() + MemProf(w) case "gc summary": PrintGCSummary(w) } } // record memory profile in pprof -func MemProf() { - if f, err := os.Create("mem-" + strconv.Itoa(pid) + ".memprof"); err != nil { - log.Fatal("record memory profile failed: ", err) +func MemProf(w io.Writer) { + filename := "mem-" + strconv.Itoa(pid) + ".memprof" + if f, err := os.Create(filename); err != nil { + fmt.Fprintf(w, "create file %s error %s\n", filename, err.Error()) + log.Fatal("record heap profile failed: ", err) } else { runtime.GC() pprof.WriteHeapProfile(f) f.Close() + fmt.Fprintf(w, "create heap profile %s \n", filename) + _, fl := path.Split(os.Args[0]) + fmt.Fprintf(w, "Now you can use this to check it: go tool pprof %s %s\n", fl, filename) } } // start cpu profile monitor -func StartCPUProfile() { - f, err := os.Create("cpu-" + strconv.Itoa(pid) + ".pprof") +func GetCPUProfile(w io.Writer) { + sec := 30 + filename := "cpu-" + strconv.Itoa(pid) + ".pprof" + f, err := os.Create(filename) if err != nil { - log.Fatal(err) + fmt.Fprintf(w, "Could not enable CPU profiling: %s\n", err) + log.Fatal("record cpu profile failed: ", err) } pprof.StartCPUProfile(f) -} - -// stop cpu profile monitor -func StopCPUProfile() { + time.Sleep(time.Duration(sec) * time.Second) pprof.StopCPUProfile() + + fmt.Fprintf(w, "create cpu profile %s \n", filename) + _, fl := path.Split(os.Args[0]) + fmt.Fprintf(w, "Now you can use this to check it: go tool pprof %s %s\n", fl, filename) } // print gc information to io.Writer diff --git a/toolbox/profile_test.go b/toolbox/profile_test.go index 661d6ea1..07a20c4e 100644 --- a/toolbox/profile_test.go +++ b/toolbox/profile_test.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package toolbox diff --git a/toolbox/statistics.go b/toolbox/statistics.go index 8904dc60..0a5170b0 100644 --- a/toolbox/statistics.go +++ b/toolbox/statistics.go @@ -1,14 +1,21 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package toolbox import ( "fmt" - "io" "sync" "time" ) @@ -76,17 +83,28 @@ func (m *UrlMap) AddStatistics(requestMethod, requestUrl, requestController stri } // put url statistics result in io.Writer -func (m *UrlMap) GetMap(rw io.Writer) { +func (m *UrlMap) GetMap() [][]string { m.lock.RLock() defer m.lock.RUnlock() - fmt.Fprintf(rw, "| % -50s| % -10s | % -16s | % -16s | % -16s | % -16s | % -16s |\n", "requestUrl", "method", "times", "used", "max used", "min used", "avg used") + resultLists := make([][]string, 0) + + var result = []string{"requestUrl", "method", "times", "used", "max used", "min used", "avg used"} + resultLists = append(resultLists, result) for k, v := range m.urlmap { for kk, vv := range v { - fmt.Fprintf(rw, "| % -50s| % -10s | % -16d | % -16s | % -16s | % -16s | % -16s |\n", k, - kk, vv.RequestNum, toS(vv.TotalTime), toS(vv.MaxTime), toS(vv.MinTime), toS(time.Duration(int64(vv.TotalTime)/vv.RequestNum)), - ) + result := []string{ + fmt.Sprintf("% -50s", k), + fmt.Sprintf("% -10s", kk), + fmt.Sprintf("% -16d", vv.RequestNum), + fmt.Sprintf("% -16s", toS(vv.TotalTime)), + fmt.Sprintf("% -16s", toS(vv.MaxTime)), + fmt.Sprintf("% -16s", toS(vv.MinTime)), + fmt.Sprintf("% -16s", toS(time.Duration(int64(vv.TotalTime)/vv.RequestNum))), + } + resultLists = append(resultLists, result) } } + return resultLists } // global statistics data map diff --git a/toolbox/statistics_test.go b/toolbox/statistics_test.go index ec7ceab5..448b2af5 100644 --- a/toolbox/statistics_test.go +++ b/toolbox/statistics_test.go @@ -1,13 +1,20 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package toolbox import ( - "os" "testing" "time" ) @@ -20,5 +27,5 @@ func TestStatics(t *testing.T) { StatisticsMap.AddStatistics("POST", "/api/user/astaxie", "&admin.user", time.Duration(12000)) StatisticsMap.AddStatistics("POST", "/api/user/xiemengjun", "&admin.user", time.Duration(13000)) StatisticsMap.AddStatistics("DELETE", "/api/user", "&admin.user", time.Duration(1400)) - StatisticsMap.GetMap(os.Stdout) + t.Log(StatisticsMap.GetMap()) } diff --git a/toolbox/task.go b/toolbox/task.go index dadc8913..6931e189 100644 --- a/toolbox/task.go +++ b/toolbox/task.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package toolbox diff --git a/toolbox/task_test.go b/toolbox/task_test.go index 2bbd4ac7..596bc9c5 100644 --- a/toolbox/task_test.go +++ b/toolbox/task_test.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package toolbox diff --git a/tree.go b/tree.go index 93d4ab02..eebc7f85 100644 --- a/tree.go +++ b/tree.go @@ -1,3 +1,17 @@ +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package beego import ( @@ -37,22 +51,38 @@ func (t *Tree) addtree(segments []string, tree *Tree, wildcards []string, reg st } seg := segments[0] iswild, params, regexpStr := splitSegment(seg) - if len(segments) == 1 && seg != "" { + if len(segments) == 1 { if iswild { - wildcards = append(wildcards, params...) if regexpStr != "" { - for _, w := range params { + if reg == "" { + rr := "" + for _, w := range wildcards { + if w == "." || w == ":" { + continue + } + if w == ":splat" { + rr = rr + "(.+)/" + } else { + rr = rr + "([^/]+)/" + } + } + regexpStr = rr + regexpStr + } else { + regexpStr = "/" + regexpStr + } + } else { + for _, w := range wildcards { if w == "." || w == ":" { continue } regexpStr = "([^/]+)/" + regexpStr } } - reg = reg + regexpStr - filterTreeWithPrefix(tree, wildcards, reg) + reg = strings.Trim(reg+regexpStr, "/") + filterTreeWithPrefix(tree, append(wildcards, params...), reg) t.wildcard = tree } else { - filterTreeWithPrefix(tree, wildcards, reg) + filterTreeWithPrefix(tree, append(wildcards, params...), reg) t.fixrouters[seg] = tree } return @@ -61,21 +91,41 @@ func (t *Tree) addtree(segments []string, tree *Tree, wildcards []string, reg st if t.wildcard == nil { t.wildcard = NewTree() } - wildcards = append(wildcards) if regexpStr != "" { - for _, w := range params { + if reg == "" { + rr := "" + for _, w := range wildcards { + if w == "." || w == ":" { + continue + } + if w == ":splat" { + rr = rr + "(.+)/" + } else { + rr = rr + "([^/]+)/" + } + } + regexpStr = rr + regexpStr + "/" + } else { + regexpStr = "/" + regexpStr + "/" + } + } else { + for _, w := range wildcards { if w == "." || w == ":" { continue } - regexpStr = "([^/]+)/" + regexpStr + if w == ":splat" { + regexpStr = "(.+)/" + regexpStr + } else { + regexpStr = "([^/]+)/" + regexpStr + } } } reg = reg + regexpStr - t.wildcard.addtree(segments[1:], tree, wildcards, reg) + t.wildcard.addtree(segments[1:], tree, append(wildcards, params...), reg) } else { subTree := NewTree() t.fixrouters[seg] = subTree - subTree.addtree(segments[1:], tree, wildcards, reg) + subTree.addtree(segments[1:], tree, append(wildcards, params...), reg) } } @@ -87,8 +137,24 @@ func filterTreeWithPrefix(t *Tree, wildcards []string, reg string) { filterTreeWithPrefix(t.wildcard, wildcards, reg) } for _, l := range t.leaves { - l.wildcards = append(wildcards, l.wildcards...) if reg != "" { + if l.regexps != nil { + l.wildcards = append(wildcards, l.wildcards...) + l.regexps = regexp.MustCompile("^" + reg + strings.Trim(l.regexps.String(), "^$") + "$") + } else { + for _, v := range l.wildcards { + if v == ":" || v == "." { + continue + } + if v == ":splat" { + reg = reg + "/(.+)" + } else { + reg = reg + "/([^/]+)" + } + } + l.regexps = regexp.MustCompile("^" + reg + "$") + l.wildcards = append(wildcards, l.wildcards...) + } filterCards := []string{} for _, v := range l.wildcards { if v == ":" || v == "." { @@ -97,22 +163,18 @@ func filterTreeWithPrefix(t *Tree, wildcards []string, reg string) { filterCards = append(filterCards, v) } l.wildcards = filterCards - l.regexps = regexp.MustCompile("^" + reg + strings.Trim(l.regexps.String(), "^$") + "$") } else { + l.wildcards = append(wildcards, l.wildcards...) if l.regexps != nil { - filterCards := []string{} - for _, v := range l.wildcards { - if v == ":" || v == "." { - continue - } - filterCards = append(filterCards, v) - } - l.wildcards = filterCards for _, w := range wildcards { if w == "." || w == ":" { continue } - reg = "([^/]+)/" + reg + if w == ":splat" { + reg = "(.+)/" + reg + } else { + reg = "([^/]+)/" + reg + } } l.regexps = regexp.MustCompile("^" + reg + strings.Trim(l.regexps.String(), "^$") + "$") } @@ -149,6 +211,10 @@ func (t *Tree) addseg(segments []string, route interface{}, wildcards []string, iswild = true regexpStr = seg } + if seg == "*" && len(wildcards) > 0 && reg == "" { + iswild = true + regexpStr = "(.+)" + } if iswild { if t.wildcard == nil { t.wildcard = NewTree() diff --git a/tree_test.go b/tree_test.go index 57f0a9fd..30856d29 100644 --- a/tree_test.go +++ b/tree_test.go @@ -1,3 +1,17 @@ +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package beego import "testing" @@ -22,6 +36,9 @@ func init() { routers = append(routers, testinfo{"/aa/*/bb", "/aa/2009/bb", map[string]string{":splat": "2009"}}) routers = append(routers, testinfo{"/cc/*/dd", "/cc/2009/11/dd", map[string]string{":splat": "2009/11"}}) routers = append(routers, testinfo{"/ee/:year/*/ff", "/ee/2009/11/ff", map[string]string{":year": "2009", ":splat": "11"}}) + routers = append(routers, testinfo{"/thumbnail/:size/uploads/*", + "/thumbnail/100x100/uploads/items/2014/04/20/dPRCdChkUd651t1Hvs18.jpg", + map[string]string{":size": "100x100", ":splat": "items/2014/04/20/dPRCdChkUd651t1Hvs18.jpg"}}) routers = append(routers, testinfo{"/*.*", "/nice/api.json", map[string]string{":path": "nice/api", ":ext": "json"}}) routers = append(routers, testinfo{"/:name/*.*", "/nice/api.json", map[string]string{":name": "nice", ":path": "api", ":ext": "json"}}) routers = append(routers, testinfo{"/:name/test/*.*", "/nice/test/api.json", map[string]string{":name": "nice", ":path": "api", ":ext": "json"}}) @@ -110,6 +127,24 @@ func TestAddTree(t *testing.T) { } } +func TestAddTree2(t *testing.T) { + tr := NewTree() + tr.AddRouter("/shop/:id/account", "astaxie") + tr.AddRouter("/shop/:sd/ttt_:id(.+)_:page(.+).html", "astaxie") + t3 := NewTree() + t3.AddTree("/:version(v1|v2)/:prefix", tr) + obj, param := t3.Match("/v1/zl/shop/123/account") + if obj == nil || obj.(string) != "astaxie" { + t.Fatal("/:version(v1|v2)/:prefix/shop/:id/account can't get obj ") + } + if param == nil { + t.Fatal("get param error") + } + if param[":id"] != "123" || param[":prefix"] != "zl" || param[":version"] != "v1" { + t.Fatal("get :id :prefix :version param error") + } +} + func TestSplitPath(t *testing.T) { a := splitPath("/") if len(a) != 0 { diff --git a/utils/caller.go b/utils/caller.go index 52cd5fe4..de04d96e 100644 --- a/utils/caller.go +++ b/utils/caller.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package utils diff --git a/utils/caller_test.go b/utils/caller_test.go index c7068f3c..0675f0aa 100644 --- a/utils/caller_test.go +++ b/utils/caller_test.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package utils diff --git a/utils/captcha/captcha.go b/utils/captcha/captcha.go index 133a2fe2..62adc81d 100644 --- a/utils/captcha/captcha.go +++ b/utils/captcha/captcha.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. // an example for use captcha // @@ -196,7 +204,7 @@ func (c *Captcha) Verify(id string, challenge string) (success bool) { key := c.key(id) - if v, ok := c.store.Get(key).([]byte); ok && len(v) == len(challenge) { + if v, ok := c.store.Get(key).([]byte); ok { chars = v } else { return @@ -207,6 +215,9 @@ func (c *Captcha) Verify(id string, challenge string) (success bool) { c.store.Delete(key) }() + if len(chars) != len(challenge) { + return + } // verify challenge for i, c := range chars { if c != challenge[i]-48 { diff --git a/utils/captcha/image.go b/utils/captcha/image.go index 93eb3383..8e9039d0 100644 --- a/utils/captcha/image.go +++ b/utils/captcha/image.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package captcha diff --git a/utils/captcha/image_test.go b/utils/captcha/image_test.go index 14a18fbc..5e35b7f7 100644 --- a/utils/captcha/image_test.go +++ b/utils/captcha/image_test.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package captcha diff --git a/utils/captcha/siprng.go b/utils/captcha/siprng.go index 26651b9b..5e256cf9 100644 --- a/utils/captcha/siprng.go +++ b/utils/captcha/siprng.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package captcha diff --git a/utils/captcha/siprng_test.go b/utils/captcha/siprng_test.go index 8f3444b4..189d3d3c 100644 --- a/utils/captcha/siprng_test.go +++ b/utils/captcha/siprng_test.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package captcha diff --git a/toolbox/debug.go b/utils/debug.go similarity index 93% rename from toolbox/debug.go rename to utils/debug.go index dd775e69..f9a682d3 100644 --- a/toolbox/debug.go +++ b/utils/debug.go @@ -1,10 +1,18 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -package toolbox +package utils import ( "bytes" diff --git a/utils/debug_test.go b/utils/debug_test.go new file mode 100644 index 00000000..efb8924e --- /dev/null +++ b/utils/debug_test.go @@ -0,0 +1,46 @@ +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package utils + +import ( + "testing" +) + +type mytype struct { + next *mytype + prev *mytype +} + +func TestPrint(t *testing.T) { + Display("v1", 1, "v2", 2, "v3", 3) +} + +func TestPrintPoint(t *testing.T) { + var v1 = new(mytype) + var v2 = new(mytype) + + v1.prev = nil + v1.next = v2 + + v2.prev = v1 + v2.next = nil + + Display("v1", v1, "v2", v2) +} + +func TestPrintString(t *testing.T) { + str := GetDisplayString("v1", 1, "v2", 2) + println(str) +} diff --git a/utils/file.go b/utils/file.go index 5246d88c..c9c3e903 100644 --- a/utils/file.go +++ b/utils/file.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package utils diff --git a/utils/file_test.go b/utils/file_test.go index 8dfd1ff6..020d7e4c 100644 --- a/utils/file_test.go +++ b/utils/file_test.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package utils diff --git a/utils/mail.go b/utils/mail.go index 8eb97b1a..c7ab73d8 100644 --- a/utils/mail.go +++ b/utils/mail.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package utils diff --git a/utils/mail_test.go b/utils/mail_test.go index 109bf7ba..c38356a2 100644 --- a/utils/mail_test.go +++ b/utils/mail_test.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package utils diff --git a/utils/rand.go b/utils/rand.go index 363f41b7..74bb4121 100644 --- a/utils/rand.go +++ b/utils/rand.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package utils diff --git a/utils/safemap.go b/utils/safemap.go index 35bf695b..37e76eb3 100644 --- a/utils/safemap.go +++ b/utils/safemap.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package utils @@ -69,5 +77,9 @@ func (m *BeeMap) Delete(k interface{}) { func (m *BeeMap) Items() map[interface{}]interface{} { m.lock.RLock() defer m.lock.RUnlock() - return m.bm + r := make(map[interface{}]interface{}) + for k, v := range m.bm { + r[k] = v + } + return r } diff --git a/utils/safemap_test.go b/utils/safemap_test.go index e1148a1c..fb271d18 100644 --- a/utils/safemap_test.go +++ b/utils/safemap_test.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package utils diff --git a/utils/slice.go b/utils/slice.go index fee1b741..729f6594 100644 --- a/utils/slice.go +++ b/utils/slice.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package utils @@ -98,7 +106,7 @@ func SliceDiff(slice1, slice2 []interface{}) (diffslice []interface{}) { return } -// SliceIntersect returns diff slice of slice2 - slice1. +// SliceIntersect returns diff slice of slice1 - slice2. func SliceIntersect(slice1, slice2 []interface{}) (diffslice []interface{}) { for _, v := range slice1 { if !InSliceIface(v, slice2) { diff --git a/utils/slice_test.go b/utils/slice_test.go index fb2266a0..142dec96 100644 --- a/utils/slice_test.go +++ b/utils/slice_test.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package utils diff --git a/validation/README.md b/validation/README.md index 4bb5b416..e0c30df7 100644 --- a/validation/README.md +++ b/validation/README.md @@ -33,7 +33,7 @@ Direct Use: valid.Required(u.Name, "name") valid.MaxSize(u.Name, 15, "nameMax") valid.Range(u.Age, 0, 140, "age") - if valid.HasErrors { + if valid.HasErrors() { // validation does not pass // print invalid message for _, err := range valid.Errors { diff --git a/validation/util.go b/validation/util.go index 3ac56f81..249462d4 100644 --- a/validation/util.go +++ b/validation/util.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package validation diff --git a/validation/util_test.go b/validation/util_test.go index 8345daa6..c4283c4e 100644 --- a/validation/util_test.go +++ b/validation/util_test.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package validation diff --git a/validation/validation.go b/validation/validation.go index 7087ccff..addf6b7e 100644 --- a/validation/validation.go +++ b/validation/validation.go @@ -1,9 +1,49 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// package for validations +// +// import ( +// "github.com/astaxie/beego/validation" +// "log" +// ) +// +// type User struct { +// Name string +// Age int +// } +// +// func main() { +// u := User{"man", 40} +// valid := validation.Validation{} +// valid.Required(u.Name, "name") +// valid.MaxSize(u.Name, 15, "nameMax") +// valid.Range(u.Age, 0, 140, "age") +// if valid.HasErrors() { +// // validation does not pass +// // print invalid message +// for _, err := range valid.Errors { +// log.Println(err.Key, err.Message) +// } +// } +// // or use like this +// if v := valid.Max(u.Age, 140); !v.Ok { +// log.Println(v.Error.Key, v.Error.Message) +// } +// } +// +// more info: http://beego.me/docs/mvc/controller/validation.md package validation import ( diff --git a/validation/validation_test.go b/validation/validation_test.go index 47de304a..be63ac93 100644 --- a/validation/validation_test.go +++ b/validation/validation_test.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package validation diff --git a/validation/validators.go b/validation/validators.go index d59b42b0..25415bdd 100644 --- a/validation/validators.go +++ b/validation/validators.go @@ -1,8 +1,16 @@ -// Beego (http://beego.me/) -// @description beego is an open-source, high-performance web framework for the Go programming language. -// @link http://github.com/astaxie/beego for the canonical source repository -// @license http://github.com/astaxie/beego/blob/master/LICENSE -// @authors astaxie +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package validation