diff --git a/README.md b/README.md index 934fc429..dc048bba 100644 --- a/README.md +++ b/README.md @@ -1,42 +1,57 @@ # Beego [![Build Status](https://travis-ci.org/astaxie/beego.svg?branch=master)](https://travis-ci.org/astaxie/beego) [![GoDoc](http://godoc.org/github.com/astaxie/beego?status.svg)](http://godoc.org/github.com/astaxie/beego) [![Foundation](https://img.shields.io/badge/Golang-Foundation-green.svg)](http://golangfoundation.org) [![Go Report Card](https://goreportcard.com/badge/github.com/astaxie/beego)](https://goreportcard.com/report/github.com/astaxie/beego) +Beego is used for rapid development of enterprise application in Go, including RESTful APIs, web apps and backend +services. -beego is used for rapid development of RESTful APIs, web apps and backend services in Go. -It is inspired by Tornado, Sinatra and Flask. beego has some Go-specific features such as interfaces and struct embedding. +It is inspired by Tornado, Sinatra and Flask. beego has some Go-specific features such as interfaces and struct +embedding. -###### More info at [beego.me](http://beego.me). +![architecture](https://cdn.nlark.com/yuque/0/2020/png/755700/1607857489109-1e267fce-d65f-4c5e-b915-5c475df33c58.png) + +Beego is compos of four parts: +1. Base modules: including log module, config module, governor module; +2. Task: is used for running timed tasks or periodic tasks; +3. Client: including ORM module, httplib module, cache module; +4. Server: including web module. We will support gRPC in the future; ## Quick Start -###### Please see [Documentation](http://beego.me/docs) for more. +[Officail website](http://beego.me) + +[Example](https://github.com/beego-dev/beego-example) + +> If you could not open official website, go to [beedoc](https://github.com/beego/beedoc) -###### [beego-example](https://github.com/beego-dev/beego-example) ### Web Application +![Http Request](https://cdn.nlark.com/yuque/0/2020/png/755700/1607857462507-855ec543-7ce3-402d-a0cb-b2524d5a4b60.png) + #### Create `hello` directory, cd `hello` directory mkdir hello cd hello - + #### Init module go mod init #### Download and install - go get github.com/astaxie/beego + go get github.com/astaxie/beego@v2.0.0 #### Create file `hello.go` + ```go package main import "github.com/astaxie/beego/server/web" -func main(){ - web.Run() +func main() { + web.Run() } ``` + #### Build and run go build hello.go @@ -46,227 +61,36 @@ func main(){ Congratulations! You've just built your first **beego** app. -### Using ORM module - -```go - -package main - -import ( - "github.com/astaxie/beego/client/orm" - "github.com/astaxie/beego/core/logs" - _ "github.com/go-sql-driver/mysql" -) - -// User - -type User struct { - ID int `orm:"column(id)"` - Name string `orm:"column(name)"` -} - -func init() { - // need to register models in init - orm.RegisterModel(new(User)) - - // need to register db driver - orm.RegisterDriver("mysql", orm.DRMySQL) - - // need to register default database - orm.RegisterDataBase("default", "mysql", "beego:test@tcp(192.168.0.105:13306)/orm_test?charset=utf8") -} - -func main() { - // automatically build table - orm.RunSyncdb("default", false, true) - - // create orm object, and it will use `default` database - o := orm.NewOrm() - - // data - user := new(User) - user.Name = "mike" - - // insert data - id, err := o.Insert(user) - if err != nil { - logs.Info(err) - } - - // ... -} -``` - -### Using httplib as http client -```go -package main - -import ( - "github.com/astaxie/beego/client/httplib" - "github.com/astaxie/beego/core/logs" -) - -func main() { - // Get, more methods please read docs - req := httplib.Get("http://beego.me/") - str, err := req.String() - if err != nil { - logs.Error(err) - } - logs.Info(str) -} - -``` - -### Using config module - -```go -package main - -import ( - "context" - - "github.com/astaxie/beego/core/config" - "github.com/astaxie/beego/core/logs" -) - -var ( - ConfigFile = "./app.conf" -) - -func main() { - cfg, err := config.NewConfig("ini", ConfigFile) - if err != nil { - logs.Critical("An error occurred:", err) - panic(err) - } - res, _ := cfg.String(context.Background(), "name") - logs.Info("load config name is", res) -} -``` -### Using logs module -```go -package main - -import ( - "github.com/astaxie/beego/core/logs" -) - -func main() { - err := logs.SetLogger(logs.AdapterFile, `{"filename":"project.log","level":7,"maxlines":0,"maxsize":0,"daily":true,"maxdays":10,"color":true}`) - if err != nil { - panic(err) - } - logs.Info("hello beego") -} -``` -### Using timed task - -```go -package main - -import ( - "context" - "time" - - "github.com/astaxie/beego/core/logs" - "github.com/astaxie/beego/task" -) - -func main() { - // create a task - tk1 := task.NewTask("tk1", "0/3 * * * * *", func(ctx context.Context) error { logs.Info("tk1"); return nil }) - - // check task - err := tk1.Run(context.Background()) - if err != nil { - logs.Error(err) - } - - // add task to global todolist - task.AddTask("tk1", tk1) - - // start tasks - task.StartTask() - - // wait 12 second - time.Sleep(12 * time.Second) - defer task.StopTask() -} -``` - -### Using cache module - -```go -package main - -import ( - "context" - "time" - - "github.com/astaxie/beego/client/cache" - - // don't forget this - _ "github.com/astaxie/beego/client/cache/redis" - - "github.com/astaxie/beego/core/logs" -) - -func main() { - // create cache - bm, err := cache.NewCache("redis", `{"key":"default", "conn":":6379", "password":"123456", "dbNum":"0"}`) - if err != nil { - logs.Error(err) - } - - // put - isPut := bm.Put(context.Background(), "astaxie", 1, time.Second*10) - logs.Info(isPut) - - isPut = bm.Put(context.Background(), "hello", "world", time.Second*10) - logs.Info(isPut) - - // get - result, _ := bm.Get(context.Background(),"astaxie") - logs.Info(string(result.([]byte))) - - multiResult, _ := bm.GetMulti(context.Background(), []string{"astaxie", "hello"}) - for i := range multiResult { - logs.Info(string(multiResult[i].([]byte))) - } - - // isExist - isExist, _ := bm.IsExist(context.Background(), "astaxie") - logs.Info(isExist) - - // delete - isDelete := bm.Delete(context.Background(), "astaxie") - logs.Info(isDelete) -} -``` - - ## Features * RESTful support -* MVC architecture +* [MVC architecture](https://github.com/beego/beedoc/tree/master/en-US/mvc) * Modularity -* Auto API documents -* Annotation router -* Namespace -* Powerful development tools +* [Auto API documents](https://github.com/beego/beedoc/blob/master/en-US/advantage/docs.md) +* [Annotation router](https://github.com/beego/beedoc/blob/master/en-US/mvc/controller/router.md) +* [Namespace](https://github.com/beego/beedoc/blob/master/en-US/mvc/controller/router.md#namespace) +* [Powerful development tools](https://github.com/beego/bee) * Full stack for Web & API -## Documentation - -* [English](http://beego.me/docs/intro/) -* [中文文档](http://beego.me/docs/intro/) -* [Русский](http://beego.me/docs/intro/) +## Modules +* [orm](https://github.com/beego/beedoc/tree/master/en-US/mvc/model) +* [session](https://github.com/beego/beedoc/blob/master/en-US/module/session.md) +* [logs](https://github.com/beego/beedoc/blob/master/en-US/module/logs.md) +* [config](https://github.com/beego/beedoc/blob/master/en-US/module/config.md) +* [cache](https://github.com/beego/beedoc/blob/master/en-US/module/cache.md) +* [context](https://github.com/beego/beedoc/blob/master/en-US/module/context.md) +* [governor](https://github.com/beego/beedoc/blob/master/en-US/module/governor.md) +* [httplib](https://github.com/beego/beedoc/blob/master/en-US/module/httplib.md) +* [task](https://github.com/beego/beedoc/blob/master/en-US/module/task.md) +* [i18n](https://github.com/beego/beedoc/blob/master/en-US/module/i18n.md) ## Community * [http://beego.me/community](http://beego.me/community) -* Welcome to join us in Slack: [https://beego.slack.com](https://beego.slack.com), you can get invited from [here](https://github.com/beego/beedoc/issues/232) +* Welcome to join us in Slack: [https://beego.slack.com](https://beego.slack.com), you can get invited + from [here](https://github.com/beego/beedoc/issues/232) * QQ Group Group ID:523992905 +* [Contribution Guide](https://github.com/beego/beedoc/blob/master/en-US/intro/contributing.md). ## License diff --git a/adapter/admin.go b/adapter/admin.go index e555f59e..828ee399 100644 --- a/adapter/admin.go +++ b/adapter/admin.go @@ -17,7 +17,7 @@ package adapter import ( "time" - _ "github.com/astaxie/beego/core/governor" + _ "github.com/astaxie/beego/core/admin" "github.com/astaxie/beego/server/web" ) diff --git a/adapter/controller.go b/adapter/controller.go index 14dc9b97..a56d1743 100644 --- a/adapter/controller.go +++ b/adapter/controller.go @@ -212,7 +212,8 @@ func (c *Controller) ServeFormatted(encoding ...bool) { // Input returns the input data map from POST or PUT request body and query string. func (c *Controller) Input() url.Values { - return (*web.Controller)(c).Input() + val, _ := (*web.Controller)(c).Input() + return val } // ParseForm maps input data map to obj struct. diff --git a/adapter/session/session.go b/adapter/session/session.go index d8b151b7..72eeb080 100644 --- a/adapter/session/session.go +++ b/adapter/session/session.go @@ -141,7 +141,7 @@ func (manager *Manager) GC() { // SessionRegenerateID Regenerate a session id for this SessionStore who's id is saving in http request. func (manager *Manager) SessionRegenerateID(w http.ResponseWriter, r *http.Request) Store { - s := (*session.Manager)(manager).SessionRegenerateID(w, r) + s, _ := (*session.Manager)(manager).SessionRegenerateID(w, r) return &NewToOldStoreAdapter{ delegate: s, } diff --git a/adapter/toolbox/healthcheck.go b/adapter/toolbox/healthcheck.go index 7d89c2fb..cb07e6aa 100644 --- a/adapter/toolbox/healthcheck.go +++ b/adapter/toolbox/healthcheck.go @@ -31,19 +31,19 @@ package toolbox import ( - "github.com/astaxie/beego/core/governor" + "github.com/astaxie/beego/core/admin" ) // AdminCheckList holds health checker map -// Deprecated using governor.AdminCheckList +// Deprecated using admin.AdminCheckList var AdminCheckList map[string]HealthChecker // HealthChecker health checker interface -type HealthChecker governor.HealthChecker +type HealthChecker admin.HealthChecker // AddHealthCheck add health checker with name string func AddHealthCheck(name string, hc HealthChecker) { - governor.AddHealthCheck(name, hc) + admin.AddHealthCheck(name, hc) AdminCheckList[name] = hc } diff --git a/adapter/toolbox/profile.go b/adapter/toolbox/profile.go index a5434360..09a97542 100644 --- a/adapter/toolbox/profile.go +++ b/adapter/toolbox/profile.go @@ -19,7 +19,7 @@ import ( "os" "time" - "github.com/astaxie/beego/core/governor" + "github.com/astaxie/beego/core/admin" ) var startTime = time.Now() @@ -31,20 +31,20 @@ func init() { // ProcessInput parse input command string func ProcessInput(input string, w io.Writer) { - governor.ProcessInput(input, w) + admin.ProcessInput(input, w) } // MemProf record memory profile in pprof func MemProf(w io.Writer) { - governor.MemProf(w) + admin.MemProf(w) } // GetCPUProfile start cpu profile monitor func GetCPUProfile(w io.Writer) { - governor.GetCPUProfile(w) + admin.GetCPUProfile(w) } // PrintGCSummary print gc information to io.Writer func PrintGCSummary(w io.Writer) { - governor.PrintGCSummary(w) + admin.PrintGCSummary(w) } diff --git a/adapter/tree_test.go b/adapter/tree_test.go deleted file mode 100644 index 2315d829..00000000 --- a/adapter/tree_test.go +++ /dev/null @@ -1,249 +0,0 @@ -// 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 adapter - -import ( - "testing" - - "github.com/astaxie/beego/adapter/context" - beecontext "github.com/astaxie/beego/server/web/context" -) - -type testinfo struct { - url string - requesturl string - params map[string]string -} - -var routers []testinfo - -func init() { - routers = make([]testinfo, 0) - routers = append(routers, testinfo{"/topic/?:auth:int", "/topic", nil}) - routers = append(routers, testinfo{"/topic/?:auth:int", "/topic/123", map[string]string{":auth": "123"}}) - routers = append(routers, testinfo{"/topic/:id/?:auth", "/topic/1", map[string]string{":id": "1"}}) - routers = append(routers, testinfo{"/topic/:id/?:auth", "/topic/1/2", map[string]string{":id": "1", ":auth": "2"}}) - routers = append(routers, testinfo{"/topic/:id/?:auth:int", "/topic/1", map[string]string{":id": "1"}}) - routers = append(routers, testinfo{"/topic/:id/?:auth:int", "/topic/1/123", map[string]string{":id": "1", ":auth": "123"}}) - routers = append(routers, testinfo{"/:id", "/123", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/hello/?:id", "/hello", map[string]string{":id": ""}}) - routers = append(routers, testinfo{"/", "/", nil}) - routers = append(routers, testinfo{"/customer/login", "/customer/login", nil}) - routers = append(routers, testinfo{"/customer/login", "/customer/login.json", map[string]string{":ext": "json"}}) - routers = append(routers, testinfo{"/*", "/http://customer/123/", map[string]string{":splat": "http://customer/123/"}}) - routers = append(routers, testinfo{"/*", "/customer/2009/12/11", map[string]string{":splat": "customer/2009/12/11"}}) - 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{"/cc/:id/*", "/cc/2009/11/dd", map[string]string{":id": "2009", ":splat": "11/dd"}}) - 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"}}) - routers = append(routers, testinfo{"/dl/:width:int/:height:int/*.*", - "/dl/48/48/05ac66d9bda00a3acf948c43e306fc9a.jpg", - map[string]string{":width": "48", ":height": "48", ":ext": "jpg", ":path": "05ac66d9bda00a3acf948c43e306fc9a"}}) - routers = append(routers, testinfo{"/v1/shop/:id:int", "/v1/shop/123", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/v1/shop/:id\\((a|b|c)\\)", "/v1/shop/123(a)", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/v1/shop/:id\\((a|b|c)\\)", "/v1/shop/123(b)", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/v1/shop/:id\\((a|b|c)\\)", "/v1/shop/123(c)", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/:year:int/:month:int/:id/:endid", "/1111/111/aaa/aaa", map[string]string{":year": "1111", ":month": "111", ":id": "aaa", ":endid": "aaa"}}) - routers = append(routers, testinfo{"/v1/shop/:id/:name", "/v1/shop/123/nike", map[string]string{":id": "123", ":name": "nike"}}) - routers = append(routers, testinfo{"/v1/shop/:id/account", "/v1/shop/123/account", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/v1/shop/:name:string", "/v1/shop/nike", map[string]string{":name": "nike"}}) - routers = append(routers, testinfo{"/v1/shop/:id([0-9]+)", "/v1/shop//123", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/v1/shop/:id([0-9]+)_:name", "/v1/shop/123_nike", map[string]string{":id": "123", ":name": "nike"}}) - routers = append(routers, testinfo{"/v1/shop/:id(.+)_cms.html", "/v1/shop/123_cms.html", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/v1/shop/cms_:id(.+)_:page(.+).html", "/v1/shop/cms_123_1.html", map[string]string{":id": "123", ":page": "1"}}) - routers = append(routers, testinfo{"/v1/:v/cms/aaa_:id(.+)_:page(.+).html", "/v1/2/cms/aaa_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"}}) - routers = append(routers, testinfo{"/v1/:v/cms_:id(.+)_:page(.+).html", "/v1/2/cms_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"}}) - routers = append(routers, testinfo{"/v1/:v(.+)_cms/ttt_:id(.+)_:page(.+).html", "/v1/2_cms/ttt_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"}}) - routers = append(routers, testinfo{"/api/projects/:pid/members/?:mid", "/api/projects/1/members", map[string]string{":pid": "1"}}) - routers = append(routers, testinfo{"/api/projects/:pid/members/?:mid", "/api/projects/1/members/2", map[string]string{":pid": "1", ":mid": "2"}}) -} - -func TestTreeRouters(t *testing.T) { - for _, r := range routers { - tr := NewTree() - tr.AddRouter(r.url, "astaxie") - ctx := context.NewContext() - obj := tr.Match(r.requesturl, ctx) - if obj == nil || obj.(string) != "astaxie" { - t.Fatal(r.url+" can't get obj, Expect ", r.requesturl) - } - if r.params != nil { - for k, v := range r.params { - if vv := ctx.Input.Param(k); vv != v { - t.Fatal("The Rule: " + r.url + "\nThe RequestURL:" + r.requesturl + "\nThe Key is " + k + ", The Value should be: " + v + ", but get: " + vv) - } else if vv == "" && v != "" { - t.Fatal(r.url + " " + r.requesturl + " get param empty:" + k) - } - } - } - } -} - -func TestStaticPath(t *testing.T) { - tr := NewTree() - tr.AddRouter("/topic/:id", "wildcard") - tr.AddRouter("/topic", "static") - ctx := context.NewContext() - obj := tr.Match("/topic", ctx) - if obj == nil || obj.(string) != "static" { - t.Fatal("/topic is a static route") - } - obj = tr.Match("/topic/1", ctx) - if obj == nil || obj.(string) != "wildcard" { - t.Fatal("/topic/1 is a wildcard route") - } -} - -func TestAddTree(t *testing.T) { - tr := NewTree() - tr.AddRouter("/shop/:id/account", "astaxie") - tr.AddRouter("/shop/:sd/ttt_:id(.+)_:page(.+).html", "astaxie") - t1 := NewTree() - t1.AddTree("/v1/zl", tr) - ctx := context.NewContext() - obj := t1.Match("/v1/zl/shop/123/account", ctx) - if obj == nil || obj.(string) != "astaxie" { - t.Fatal("/v1/zl/shop/:id/account can't get obj ") - } - if ctx.Input.ParamsLen() == 0 { - t.Fatal("get param error") - } - if ctx.Input.Param(":id") != "123" { - t.Fatal("get :id param error") - } - ctx.Input.Reset((*beecontext.Context)(ctx)) - obj = t1.Match("/v1/zl/shop/123/ttt_1_12.html", ctx) - if obj == nil || obj.(string) != "astaxie" { - t.Fatal("/v1/zl//shop/:sd/ttt_:id(.+)_:page(.+).html can't get obj ") - } - if ctx.Input.ParamsLen() == 0 { - t.Fatal("get param error") - } - if ctx.Input.Param(":sd") != "123" || ctx.Input.Param(":id") != "1" || ctx.Input.Param(":page") != "12" { - t.Fatal("get :sd :id :page param error") - } - - t2 := NewTree() - t2.AddTree("/v1/:shopid", tr) - ctx.Input.Reset((*beecontext.Context)(ctx)) - obj = t2.Match("/v1/zl/shop/123/account", ctx) - if obj == nil || obj.(string) != "astaxie" { - t.Fatal("/v1/:shopid/shop/:id/account can't get obj ") - } - if ctx.Input.ParamsLen() == 0 { - t.Fatal("get param error") - } - if ctx.Input.Param(":id") != "123" || ctx.Input.Param(":shopid") != "zl" { - t.Fatal("get :id :shopid param error") - } - ctx.Input.Reset((*beecontext.Context)(ctx)) - obj = t2.Match("/v1/zl/shop/123/ttt_1_12.html", ctx) - if obj == nil || obj.(string) != "astaxie" { - t.Fatal("/v1/:shopid/shop/:sd/ttt_:id(.+)_:page(.+).html can't get obj ") - } - if ctx.Input.ParamsLen() == 0 { - t.Fatal("get :shopid param error") - } - if ctx.Input.Param(":sd") != "123" || ctx.Input.Param(":id") != "1" || ctx.Input.Param(":page") != "12" || ctx.Input.Param(":shopid") != "zl" { - t.Fatal("get :sd :id :page :shopid param error") - } -} - -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) - ctx := context.NewContext() - obj := t3.Match("/v1/zl/shop/123/account", ctx) - if obj == nil || obj.(string) != "astaxie" { - t.Fatal("/:version(v1|v2)/:prefix/shop/:id/account can't get obj ") - } - if ctx.Input.ParamsLen() == 0 { - t.Fatal("get param error") - } - if ctx.Input.Param(":id") != "123" || ctx.Input.Param(":prefix") != "zl" || ctx.Input.Param(":version") != "v1" { - t.Fatal("get :id :prefix :version param error") - } -} - -func TestAddTree3(t *testing.T) { - tr := NewTree() - tr.AddRouter("/create", "astaxie") - tr.AddRouter("/shop/:sd/account", "astaxie") - t3 := NewTree() - t3.AddTree("/table/:num", tr) - ctx := context.NewContext() - obj := t3.Match("/table/123/shop/123/account", ctx) - if obj == nil || obj.(string) != "astaxie" { - t.Fatal("/table/:num/shop/:sd/account can't get obj ") - } - if ctx.Input.ParamsLen() == 0 { - t.Fatal("get param error") - } - if ctx.Input.Param(":num") != "123" || ctx.Input.Param(":sd") != "123" { - t.Fatal("get :num :sd param error") - } - ctx.Input.Reset((*beecontext.Context)(ctx)) - obj = t3.Match("/table/123/create", ctx) - if obj == nil || obj.(string) != "astaxie" { - t.Fatal("/table/:num/create can't get obj ") - } -} - -func TestAddTree4(t *testing.T) { - tr := NewTree() - tr.AddRouter("/create", "astaxie") - tr.AddRouter("/shop/:sd/:account", "astaxie") - t4 := NewTree() - t4.AddTree("/:info:int/:num/:id", tr) - ctx := context.NewContext() - obj := t4.Match("/12/123/456/shop/123/account", ctx) - if obj == nil || obj.(string) != "astaxie" { - t.Fatal("/:info:int/:num/:id/shop/:sd/:account can't get obj ") - } - if ctx.Input.ParamsLen() == 0 { - t.Fatal("get param error") - } - if ctx.Input.Param(":info") != "12" || ctx.Input.Param(":num") != "123" || - ctx.Input.Param(":id") != "456" || ctx.Input.Param(":sd") != "123" || - ctx.Input.Param(":account") != "account" { - t.Fatal("get :info :num :id :sd :account param error") - } - ctx.Input.Reset((*beecontext.Context)(ctx)) - obj = t4.Match("/12/123/456/create", ctx) - if obj == nil || obj.(string) != "astaxie" { - t.Fatal("/:info:int/:num/:id/create can't get obj ") - } -} - -// Test for issue #1595 -func TestAddTree5(t *testing.T) { - tr := NewTree() - tr.AddRouter("/v1/shop/:id", "shopdetail") - tr.AddRouter("/v1/shop/", "shophome") - ctx := context.NewContext() - obj := tr.Match("/v1/shop/", ctx) - if obj == nil || obj.(string) != "shophome" { - t.Fatal("url /v1/shop/ need match router /v1/shop/ ") - } -} diff --git a/build_info.go b/build_info.go index 42f42c28..23f74b53 100644 --- a/build_info.go +++ b/build_info.go @@ -28,5 +28,5 @@ var ( const ( // VERSION represent beego web framework version. - VERSION = "2.0.0-alpha" + VERSION = "2.0.0" ) diff --git a/client/cache/cache_test.go b/client/cache/cache_test.go index 6066b72d..85f83fc4 100644 --- a/client/cache/cache_test.go +++ b/client/cache/cache_test.go @@ -72,21 +72,9 @@ func TestCache(t *testing.T) { t.Error("set Error", err) } - if err = bm.Incr(context.Background(), "astaxie"); err != nil { - t.Error("Incr Error", err) - } + // test different integer type for incr & decr + testMultiIncrDecr(t, bm, timeoutDuration) - if v, _ := bm.Get(context.Background(), "astaxie"); v.(int) != 2 { - t.Error("get err") - } - - if err = bm.Decr(context.Background(), "astaxie"); err != nil { - t.Error("Decr Error", err) - } - - if v, _ := bm.Get(context.Background(), "astaxie"); v.(int) != 1 { - t.Error("get err") - } bm.Delete(context.Background(), "astaxie") if res, _ := bm.IsExist(context.Background(), "astaxie"); res { t.Error("delete err") @@ -120,6 +108,20 @@ func TestCache(t *testing.T) { if vv[1].(string) != "author1" { t.Error("GetMulti ERROR") } + + vv, err = bm.GetMulti(context.Background(), []string{"astaxie0", "astaxie1"}) + if len(vv) != 2 { + t.Error("GetMulti ERROR") + } + if vv[0] != nil { + t.Error("GetMulti ERROR") + } + if vv[1].(string) != "author1" { + t.Error("GetMulti ERROR") + } + if err != nil && err.Error() != "key [astaxie0] error: the key isn't exist" { + t.Error("GetMulti ERROR") + } } func TestFileCache(t *testing.T) { @@ -139,21 +141,9 @@ func TestFileCache(t *testing.T) { t.Error("get err") } - if err = bm.Incr(context.Background(), "astaxie"); err != nil { - t.Error("Incr Error", err) - } + // test different integer type for incr & decr + testMultiIncrDecr(t, bm, timeoutDuration) - if v, _ := bm.Get(context.Background(), "astaxie"); v.(int) != 2 { - t.Error("get err") - } - - if err = bm.Decr(context.Background(), "astaxie"); err != nil { - t.Error("Decr Error", err) - } - - if v, _ := bm.Get(context.Background(), "astaxie"); v.(int) != 1 { - t.Error("get err") - } bm.Delete(context.Background(), "astaxie") if res, _ := bm.IsExist(context.Background(), "astaxie"); res { t.Error("delete err") @@ -189,5 +179,57 @@ func TestFileCache(t *testing.T) { t.Error("GetMulti ERROR") } + vv, err = bm.GetMulti(context.Background(), []string{"astaxie0", "astaxie1"}) + if len(vv) != 2 { + t.Error("GetMulti ERROR") + } + if vv[0] != nil { + t.Error("GetMulti ERROR") + } + if vv[1].(string) != "author1" { + t.Error("GetMulti ERROR") + } + if err == nil { + t.Error("GetMulti ERROR") + } + os.RemoveAll("cache") } + +func testMultiIncrDecr(t *testing.T, c Cache, timeout time.Duration) { + testIncrDecr(t, c, 1, 2, timeout) + testIncrDecr(t, c, int32(1), int32(2), timeout) + testIncrDecr(t, c, int64(1), int64(2), timeout) + testIncrDecr(t, c, uint(1), uint(2), timeout) + testIncrDecr(t, c, uint32(1), uint32(2), timeout) + testIncrDecr(t, c, uint64(1), uint64(2), timeout) +} + +func testIncrDecr(t *testing.T, c Cache, beforeIncr interface{}, afterIncr interface{}, timeout time.Duration) { + var err error + ctx := context.Background() + key := "incDecKey" + if err = c.Put(ctx, key, beforeIncr, timeout); err != nil { + t.Error("Get Error", err) + } + + if err = c.Incr(ctx, key); err != nil { + t.Error("Incr Error", err) + } + + if v, _ := c.Get(ctx, key); v != afterIncr { + t.Error("Get Error") + } + + if err = c.Decr(ctx, key); err != nil { + t.Error("Decr Error", err) + } + + if v, _ := c.Get(ctx, key); v != beforeIncr { + t.Error("Get Error") + } + + if err := c.Delete(ctx, key); err != nil { + t.Error("Delete Error") + } +} diff --git a/client/cache/file.go b/client/cache/file.go index dc818258..043c4650 100644 --- a/client/cache/file.go +++ b/client/cache/file.go @@ -26,8 +26,8 @@ import ( "io/ioutil" "os" "path/filepath" - "reflect" "strconv" + "strings" "time" "github.com/pkg/errors" @@ -144,17 +144,22 @@ func (fc *FileCache) Get(ctx context.Context, key string) (interface{}, error) { // GetMulti gets values from file cache. // if nonexistent or expired return an empty string. func (fc *FileCache) GetMulti(ctx context.Context, keys []string) ([]interface{}, error) { - var rc []interface{} - for _, key := range keys { - val, err := fc.Get(context.Background(), key) - if err != nil { - rc = append(rc, err) - } else { - rc = append(rc, val) - } + rc := make([]interface{}, len(keys)) + keysErr := make([]string, 0) + for i, ki := range keys { + val, err := fc.Get(context.Background(), ki) + if err != nil { + keysErr = append(keysErr, fmt.Sprintf("key [%s] error: %s", ki, err.Error())) + continue + } + rc[i] = val } - return rc, nil + + if len(keysErr) == 0 { + return rc, nil + } + return rc, errors.New(strings.Join(keysErr, "; ")) } // Put value into file cache. @@ -189,28 +194,70 @@ func (fc *FileCache) Delete(ctx context.Context, key string) error { // Incr increases cached int value. // fc value is saved forever unless deleted. func (fc *FileCache) Incr(ctx context.Context, key string) error { - data, _ := fc.Get(context.Background(), key) - var incr int - if reflect.TypeOf(data).Name() != "int" { - incr = 0 - } else { - incr = data.(int) + 1 + data, err := fc.Get(context.Background(), key) + if err != nil { + return err } - fc.Put(context.Background(), key, incr, time.Duration(fc.EmbedExpiry)) - return nil + + var res interface{} + switch val := data.(type) { + case int: + res = val + 1 + case int32: + res = val + 1 + case int64: + res = val + 1 + case uint: + res = val + 1 + case uint32: + res = val + 1 + case uint64: + res = val + 1 + default: + return errors.Errorf("data is not (u)int (u)int32 (u)int64") + } + + return fc.Put(context.Background(), key, res, time.Duration(fc.EmbedExpiry)) } // Decr decreases cached int value. func (fc *FileCache) Decr(ctx context.Context, key string) error { - data, _ := fc.Get(context.Background(), key) - var decr int - if reflect.TypeOf(data).Name() != "int" || data.(int)-1 <= 0 { - decr = 0 - } else { - decr = data.(int) - 1 + data, err := fc.Get(context.Background(), key) + if err != nil { + return err } - fc.Put(context.Background(), key, decr, time.Duration(fc.EmbedExpiry)) - return nil + + var res interface{} + switch val := data.(type) { + case int: + res = val - 1 + case int32: + res = val - 1 + case int64: + res = val - 1 + case uint: + if val > 0 { + res = val - 1 + } else { + return errors.New("data val is less than 0") + } + case uint32: + if val > 0 { + res = val - 1 + } else { + return errors.New("data val is less than 0") + } + case uint64: + if val > 0 { + res = val - 1 + } else { + return errors.New("data val is less than 0") + } + default: + return errors.Errorf("data is not (u)int (u)int32 (u)int64") + } + + return fc.Put(context.Background(), key, res, time.Duration(fc.EmbedExpiry)) } // IsExist checks if value exists. diff --git a/client/cache/memcache/memcache.go b/client/cache/memcache/memcache.go index f3774571..67aedc73 100644 --- a/client/cache/memcache/memcache.go +++ b/client/cache/memcache/memcache.go @@ -33,6 +33,7 @@ import ( "context" "encoding/json" "errors" + "fmt" "strings" "time" @@ -68,19 +69,31 @@ func (rc *Cache) Get(ctx context.Context, key string) (interface{}, error) { // GetMulti gets a value from a key in memcache. func (rc *Cache) GetMulti(ctx context.Context, keys []string) ([]interface{}, error) { - var rv []interface{} + rv := make([]interface{}, len(keys)) if rc.conn == nil { if err := rc.connectInit(); err != nil { return rv, err } } + mv, err := rc.conn.GetMulti(keys) - if err == nil { - for _, v := range mv { - rv = append(rv, v.Value) - } + if err != nil { + return rv, err } - return rv, err + + keysErr := make([]string, 0) + for i, ki := range keys { + if _, ok := mv[ki]; !ok { + keysErr = append(keysErr, fmt.Sprintf("key [%s] error: %s", ki, "the key isn't exist")) + continue + } + rv[i] = mv[ki].Value + } + + if len(keysErr) == 0 { + return rv, nil + } + return rv, fmt.Errorf(strings.Join(keysErr, "; ")) } // Put puts a value into memcache. diff --git a/client/cache/memcache/memcache_test.go b/client/cache/memcache/memcache_test.go index bc8936a7..ca86276e 100644 --- a/client/cache/memcache/memcache_test.go +++ b/client/cache/memcache/memcache_test.go @@ -28,7 +28,6 @@ import ( ) func TestMemcacheCache(t *testing.T) { - addr := os.Getenv("MEMCACHE_ADDR") if addr == "" { addr = "127.0.0.1:11211" @@ -114,6 +113,20 @@ func TestMemcacheCache(t *testing.T) { t.Error("GetMulti ERROR") } + vv, err = bm.GetMulti(context.Background(), []string{"astaxie0", "astaxie1"}) + if len(vv) != 2 { + t.Error("GetMulti ERROR") + } + if vv[0] != nil { + t.Error("GetMulti ERROR") + } + if string(vv[1].([]byte)) != "author1" { + t.Error("GetMulti ERROR") + } + if err != nil && err.Error() == "key [astaxie0] error: key isn't exist" { + t.Error("GetMulti ERROR") + } + // test clear all if err = bm.ClearAll(context.Background()); err != nil { t.Error("clear all err") diff --git a/client/cache/memory.go b/client/cache/memory.go index 6f87ec08..28c7d980 100644 --- a/client/cache/memory.go +++ b/client/cache/memory.go @@ -18,6 +18,8 @@ import ( "context" "encoding/json" "errors" + "fmt" + "strings" "sync" "time" ) @@ -68,22 +70,28 @@ func (bc *MemoryCache) Get(ctx context.Context, key string) (interface{}, error) } return itm.val, nil } - return nil, nil + return nil, errors.New("the key isn't exist") } // GetMulti gets caches from memory. // If non-existent or expired, return nil. func (bc *MemoryCache) GetMulti(ctx context.Context, keys []string) ([]interface{}, error) { - var rc []interface{} - for _, name := range keys { - val, err := bc.Get(context.Background(), name) + rc := make([]interface{}, len(keys)) + keysErr := make([]string, 0) + + for i, ki := range keys { + val, err := bc.Get(context.Background(), ki) if err != nil { - rc = append(rc, err) - } else { - rc = append(rc, val) + keysErr = append(keysErr, fmt.Sprintf("key [%s] error: %s", ki, err.Error())) + continue } + rc[i] = val } - return rc, nil + + if len(keysErr) == 0 { + return rc, nil + } + return rc, errors.New(strings.Join(keysErr, "; ")) } // Put puts cache into memory. diff --git a/client/cache/redis/redis_test.go b/client/cache/redis/redis_test.go index f82b2c40..c8cf0024 100644 --- a/client/cache/redis/redis_test.go +++ b/client/cache/redis/redis_test.go @@ -113,6 +113,14 @@ func TestRedisCache(t *testing.T) { t.Error("GetMulti ERROR") } + vv, _ = bm.GetMulti(context.Background(), []string{"astaxie0", "astaxie1"}) + if vv[0] != nil { + t.Error("GetMulti ERROR") + } + if v, _ := redis.String(vv[1], nil); v != "author1" { + t.Error("GetMulti ERROR") + } + // test clear all if err = bm.ClearAll(context.Background()); err != nil { t.Error("clear all err") diff --git a/client/cache/ssdb/ssdb.go b/client/cache/ssdb/ssdb.go index def9273d..8d9d2b35 100644 --- a/client/cache/ssdb/ssdb.go +++ b/client/cache/ssdb/ssdb.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "errors" + "fmt" "strconv" "strings" "time" @@ -41,23 +42,37 @@ func (rc *Cache) Get(ctx context.Context, key string) (interface{}, error) { // GetMulti gets one or keys values from ssdb. func (rc *Cache) GetMulti(ctx context.Context, keys []string) ([]interface{}, error) { size := len(keys) - var values []interface{} + values := make([]interface{}, size) if rc.conn == nil { if err := rc.connectInit(); err != nil { return values, err } } + res, err := rc.conn.Do("multi_get", keys) + if err != nil { + return values, err + } + resSize := len(res) - if err == nil { - for i := 1; i < resSize; i += 2 { - values = append(values, res[i+1]) + keyIdx := make(map[string]int) + for i := 1; i < resSize; i += 2 { + keyIdx[res[i]] = i + } + + keysErr := make([]string, 0) + for i, ki := range keys { + if _, ok := keyIdx[ki]; !ok { + keysErr = append(keysErr, fmt.Sprintf("key [%s] error: %s", ki, "the key isn't exist")) + continue } - return values, nil + values[i] = res[keyIdx[ki]+1] } - for i := 0; i < size; i++ { - values = append(values, err) + + if len(keysErr) != 0 { + return values, fmt.Errorf(strings.Join(keysErr, "; ")) } + return values, nil } diff --git a/client/cache/ssdb/ssdb_test.go b/client/cache/ssdb/ssdb_test.go index cebaa975..b23871ca 100644 --- a/client/cache/ssdb/ssdb_test.go +++ b/client/cache/ssdb/ssdb_test.go @@ -106,6 +106,20 @@ func TestSsdbcacheCache(t *testing.T) { t.Error("getmulti error") } + vv, err = ssdb.GetMulti(context.Background(), []string{"ssdb", "ssdb11"}) + if len(vv) != 2 { + t.Error("getmulti error") + } + if vv[0].(string) != "ssdb" { + t.Error("getmulti error") + } + if vv[1] != nil { + t.Error("getmulti error") + } + if err != nil && err.Error() != "key [ssdb11] error: the key isn't exist" { + t.Error("getmulti error") + } + // test clear all done if err = ssdb.ClearAll(context.Background()); err != nil { t.Error("clear all err") diff --git a/client/orm/utils.go b/client/orm/utils.go index 3ff76772..d6c0a8e8 100644 --- a/client/orm/utils.go +++ b/client/orm/utils.go @@ -49,12 +49,12 @@ func (f *StrTo) Set(v string) { // Clear string func (f *StrTo) Clear() { - *f = StrTo(0x1E) + *f = StrTo(rune(0x1E)) } // Exist check string exist func (f StrTo) Exist() bool { - return string(f) != string(0x1E) + return string(f) != string(rune(0x1E)) } // Bool string to bool diff --git a/client/orm/utils_test.go b/client/orm/utils_test.go index 7d94cada..fa75258a 100644 --- a/client/orm/utils_test.go +++ b/client/orm/utils_test.go @@ -67,4 +67,4 @@ func TestSnakeStringWithAcronym(t *testing.T) { t.Error("Unit Test Fail:", v, res, answer[v]) } } -} +} \ No newline at end of file diff --git a/core/governor/command.go b/core/admin/command.go similarity index 99% rename from core/governor/command.go rename to core/admin/command.go index 75df5815..f65d2750 100644 --- a/core/governor/command.go +++ b/core/admin/command.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package governor +package admin import ( "github.com/pkg/errors" diff --git a/core/governor/healthcheck.go b/core/admin/healthcheck.go similarity index 96% rename from core/governor/healthcheck.go rename to core/admin/healthcheck.go index a91f09fa..79738d1d 100644 --- a/core/governor/healthcheck.go +++ b/core/admin/healthcheck.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package governor healthcheck +// Package admin healthcheck // // type DatabaseCheck struct { // } @@ -28,7 +28,7 @@ // AddHealthCheck("database",&DatabaseCheck{}) // // more docs: http://beego.me/docs/module/toolbox.md -package governor +package admin // AdminCheckList holds health checker map var AdminCheckList map[string]HealthChecker diff --git a/core/governor/profile.go b/core/admin/profile.go similarity index 99% rename from core/governor/profile.go rename to core/admin/profile.go index 17f1f375..1e4e4953 100644 --- a/core/governor/profile.go +++ b/core/admin/profile.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package governor +package admin import ( "fmt" diff --git a/core/governor/profile_test.go b/core/admin/profile_test.go similarity index 98% rename from core/governor/profile_test.go rename to core/admin/profile_test.go index 530b0637..139c4b99 100644 --- a/core/governor/profile_test.go +++ b/core/admin/profile_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package governor +package admin import ( "os" diff --git a/core/config/global.go b/core/config/global.go index 5491fe2c..a7fb795f 100644 --- a/core/config/global.go +++ b/core/config/global.go @@ -18,7 +18,6 @@ package config // for most users, they only need to use those methods var globalInstance Configer - // InitGlobalInstance will ini the global instance // If you want to use specific implementation, don't forget to import it. // e.g. _ import "github.com/astaxie/beego/core/config/etcd" diff --git a/core/config/ini.go b/core/config/ini.go index 4d17fb7a..70d00980 100644 --- a/core/config/ini.go +++ b/core/config/ini.go @@ -519,7 +519,7 @@ func (c *IniConfigContainer) Unmarshaler(prefix string, obj interface{}, opt ... func init() { Register("ini", &IniConfig{}) - err := InitGlobalInstance("ini", "config/app.conf") + err := InitGlobalInstance("ini", "conf/app.conf") if err != nil { logs.Warn("init global config instance failed. If you donot use this, just ignore it. ", err) } diff --git a/server/web/admin_controller.go b/server/web/admin_controller.go index 2998c8d4..60296976 100644 --- a/server/web/admin_controller.go +++ b/server/web/admin_controller.go @@ -24,7 +24,7 @@ import ( "github.com/prometheus/client_golang/prometheus/promhttp" - "github.com/astaxie/beego/core/governor" + "github.com/astaxie/beego/core/admin" ) type adminController struct { @@ -51,7 +51,7 @@ func (a *adminController) ProfIndex() { data = make(map[interface{}]interface{}) result bytes.Buffer ) - governor.ProcessInput(command, &result) + admin.ProcessInput(command, &result) data["Content"] = template.HTMLEscapeString(result.String()) if format == "json" && command == "gc summary" { @@ -88,7 +88,7 @@ func (a *adminController) TaskStatus() { req.ParseForm() taskname := req.Form.Get("taskname") if taskname != "" { - cmd := governor.GetCommand("task", "run") + cmd := admin.GetCommand("task", "run") res := cmd.Execute(taskname) if res.IsSuccess() { @@ -103,7 +103,7 @@ func (a *adminController) TaskStatus() { // List Tasks content := make(M) - resultList := governor.GetCommand("task", "list").Execute().Content.([][]string) + resultList := admin.GetCommand("task", "list").Execute().Content.([][]string) var fields = []string{ "Task Name", "Task Spec", @@ -141,7 +141,7 @@ func heathCheck(rw http.ResponseWriter, r *http.Request) { } ) - for name, h := range governor.AdminCheckList { + for name, h := range admin.AdminCheckList { if err := h.Check(); err != nil { result = []string{ "error", diff --git a/server/web/admin_test.go b/server/web/admin_test.go index 5ef57323..9ab11ee3 100644 --- a/server/web/admin_test.go +++ b/server/web/admin_test.go @@ -11,7 +11,7 @@ import ( "github.com/stretchr/testify/assert" - "github.com/astaxie/beego/core/governor" + "github.com/astaxie/beego/core/admin" ) type SampleDatabaseCheck struct { @@ -126,8 +126,8 @@ func TestWriteJSON(t *testing.T) { func TestHealthCheckHandlerDefault(t *testing.T) { endpointPath := "/healthcheck" - governor.AddHealthCheck("database", &SampleDatabaseCheck{}) - governor.AddHealthCheck("cache", &SampleCacheCheck{}) + admin.AddHealthCheck("database", &SampleDatabaseCheck{}) + admin.AddHealthCheck("cache", &SampleCacheCheck{}) req, err := http.NewRequest("GET", endpointPath, nil) if err != nil { @@ -187,8 +187,8 @@ func TestBuildHealthCheckResponseList(t *testing.T) { func TestHealthCheckHandlerReturnsJSON(t *testing.T) { - governor.AddHealthCheck("database", &SampleDatabaseCheck{}) - governor.AddHealthCheck("cache", &SampleCacheCheck{}) + admin.AddHealthCheck("database", &SampleDatabaseCheck{}) + admin.AddHealthCheck("cache", &SampleCacheCheck{}) req, err := http.NewRequest("GET", "/healthcheck?json=true", nil) if err != nil { diff --git a/server/web/adminui.go b/server/web/adminui.go index de8c9455..54d67354 100644 --- a/server/web/adminui.go +++ b/server/web/adminui.go @@ -21,7 +21,7 @@ var indexTpl = ` For detail usage please check our document:

-Toolbox +Toolbox

Live Monitor diff --git a/server/web/context/context.go b/server/web/context/context.go index 53ed3d01..930c14a4 100644 --- a/server/web/context/context.go +++ b/server/web/context/context.go @@ -149,7 +149,8 @@ func (ctx *Context) XSRFToken(key string, expire int64) string { token, ok := ctx.GetSecureCookie(key, "_xsrf") if !ok { token = string(utils.RandomCreateBytes(32)) - ctx.SetSecureCookie(key, "_xsrf", token, expire, "", "", true, true) + // TODO make it configurable + ctx.SetSecureCookie(key, "_xsrf", token, expire, "", "") } ctx._xsrfToken = token } diff --git a/server/web/context/output.go b/server/web/context/output.go index a6e83681..28ff2819 100644 --- a/server/web/context/output.go +++ b/server/web/context/output.go @@ -261,15 +261,15 @@ func (output *BeegoOutput) XML(data interface{}, hasIndent bool) error { } // ServeFormatted serves YAML, XML or JSON, depending on the value of the Accept header -func (output *BeegoOutput) ServeFormatted(data interface{}, hasIndent bool, hasEncode ...bool) { +func (output *BeegoOutput) ServeFormatted(data interface{}, hasIndent bool, hasEncode ...bool) error { accept := output.Context.Input.Header("Accept") switch accept { case ApplicationYAML: - output.YAML(data) + return output.YAML(data) case ApplicationXML, TextXML: - output.XML(data, hasIndent) + return output.XML(data, hasIndent) default: - output.JSON(data, hasIndent, len(hasEncode) > 0 && hasEncode[0]) + return output.JSON(data, hasIndent, len(hasEncode) > 0 && hasEncode[0]) } } diff --git a/server/web/controller.go b/server/web/controller.go index 3a1b9837..f363c655 100644 --- a/server/web/controller.go +++ b/server/web/controller.go @@ -16,6 +16,7 @@ package web import ( "bytes" + context2 "context" "errors" "fmt" "html/template" @@ -250,13 +251,16 @@ func (c *Controller) Render() error { // RenderString returns the rendered template string. Do not send out response. func (c *Controller) RenderString() (string, error) { b, e := c.RenderBytes() + if e != nil { + return "", e + } return string(b), e } // RenderBytes returns the bytes of rendered template string. Do not send out response. func (c *Controller) RenderBytes() ([]byte, error) { buf, err := c.renderTemplate() - //if the controller has set layout, then first get the tplName's content set the content to the layout + // if the controller has set layout, then first get the tplName's content set the content to the layout if err == nil && c.Layout != "" { c.Data["LayoutContent"] = template.HTML(buf.String()) @@ -276,7 +280,7 @@ func (c *Controller) RenderBytes() ([]byte, error) { } buf.Reset() - ExecuteViewPathTemplate(&buf, c.Layout, c.viewPath(), c.Data) + err = ExecuteViewPathTemplate(&buf, c.Layout, c.viewPath(), c.Data) } return buf.Bytes(), err } @@ -373,50 +377,57 @@ func (c *Controller) URLFor(endpoint string, values ...interface{}) string { } // ServeJSON sends a json response with encoding charset. -func (c *Controller) ServeJSON(encoding ...bool) { +func (c *Controller) ServeJSON(encoding ...bool) error { var ( hasIndent = BConfig.RunMode != PROD hasEncoding = len(encoding) > 0 && encoding[0] ) - c.Ctx.Output.JSON(c.Data["json"], hasIndent, hasEncoding) + return c.Ctx.Output.JSON(c.Data["json"], hasIndent, hasEncoding) } // ServeJSONP sends a jsonp response. -func (c *Controller) ServeJSONP() { +func (c *Controller) ServeJSONP() error { hasIndent := BConfig.RunMode != PROD - c.Ctx.Output.JSONP(c.Data["jsonp"], hasIndent) + return c.Ctx.Output.JSONP(c.Data["jsonp"], hasIndent) } // ServeXML sends xml response. -func (c *Controller) ServeXML() { +func (c *Controller) ServeXML() error { hasIndent := BConfig.RunMode != PROD - c.Ctx.Output.XML(c.Data["xml"], hasIndent) + return c.Ctx.Output.XML(c.Data["xml"], hasIndent) } // ServeYAML sends yaml response. -func (c *Controller) ServeYAML() { - c.Ctx.Output.YAML(c.Data["yaml"]) +func (c *Controller) ServeYAML() error { + return c.Ctx.Output.YAML(c.Data["yaml"]) } // ServeFormatted serve YAML, XML OR JSON, depending on the value of the Accept header -func (c *Controller) ServeFormatted(encoding ...bool) { +func (c *Controller) ServeFormatted(encoding ...bool) error { hasIndent := BConfig.RunMode != PROD hasEncoding := len(encoding) > 0 && encoding[0] - c.Ctx.Output.ServeFormatted(c.Data, hasIndent, hasEncoding) + return c.Ctx.Output.ServeFormatted(c.Data, hasIndent, hasEncoding) } // Input returns the input data map from POST or PUT request body and query string. -func (c *Controller) Input() url.Values { +func (c *Controller) Input() (url.Values, error) { if c.Ctx.Request.Form == nil { - c.Ctx.Request.ParseForm() + err := c.Ctx.Request.ParseForm() + if err != nil { + return nil, err + } } - return c.Ctx.Request.Form + return c.Ctx.Request.Form, nil } // ParseForm maps input data map to obj struct. func (c *Controller) ParseForm(obj interface{}) error { - return ParseForm(c.Input(), obj) + form, err := c.Input() + if err != nil { + return err + } + return ParseForm(form, obj) } // GetString returns the input value by key string or the default value while it's present and input is blank @@ -438,7 +449,7 @@ func (c *Controller) GetStrings(key string, def ...[]string) []string { defv = def[0] } - if f := c.Input(); f == nil { + if f, err := c.Input(); f == nil || err != nil { return defv } else if vs := f[key]; len(vs) > 0 { return vs @@ -618,11 +629,11 @@ func (c *Controller) StartSession() session.Store { } // SetSession puts value into session. -func (c *Controller) SetSession(name interface{}, value interface{}) { +func (c *Controller) SetSession(name interface{}, value interface{}) error { if c.CruSession == nil { c.StartSession() } - c.CruSession.Set(nil, name, value) + return c.CruSession.Set(context2.Background(), name, value) } // GetSession gets value from session. @@ -630,32 +641,38 @@ func (c *Controller) GetSession(name interface{}) interface{} { if c.CruSession == nil { c.StartSession() } - return c.CruSession.Get(nil, name) + return c.CruSession.Get(context2.Background(), name) } // DelSession removes value from session. -func (c *Controller) DelSession(name interface{}) { +func (c *Controller) DelSession(name interface{}) error { if c.CruSession == nil { c.StartSession() } - c.CruSession.Delete(nil, name) + return c.CruSession.Delete(context2.Background(), name) } // SessionRegenerateID regenerates session id for this session. // the session data have no changes. -func (c *Controller) SessionRegenerateID() { +func (c *Controller) SessionRegenerateID() error { if c.CruSession != nil { - c.CruSession.SessionRelease(nil, c.Ctx.ResponseWriter) + c.CruSession.SessionRelease(context2.Background(), c.Ctx.ResponseWriter) } - c.CruSession = GlobalSessions.SessionRegenerateID(c.Ctx.ResponseWriter, c.Ctx.Request) + var err error + c.CruSession, err = GlobalSessions.SessionRegenerateID(c.Ctx.ResponseWriter, c.Ctx.Request) c.Ctx.Input.CruSession = c.CruSession + return err } // DestroySession cleans session data and session cookie. -func (c *Controller) DestroySession() { - c.Ctx.Input.CruSession.Flush(nil) +func (c *Controller) DestroySession() error { + err := c.Ctx.Input.CruSession.Flush(nil) + if err != nil { + return err + } c.Ctx.Input.CruSession = nil GlobalSessions.SessionDestroy(c.Ctx.ResponseWriter, c.Ctx.Request) + return nil } // IsAjax returns this request is ajax or not. diff --git a/server/web/session/session.go b/server/web/session/session.go index bb7e5bd6..60fc0e00 100644 --- a/server/web/session/session.go +++ b/server/web/session/session.go @@ -298,15 +298,21 @@ func (manager *Manager) GC() { } // SessionRegenerateID Regenerate a session id for this SessionStore who's id is saving in http request. -func (manager *Manager) SessionRegenerateID(w http.ResponseWriter, r *http.Request) (session Store) { +func (manager *Manager) SessionRegenerateID(w http.ResponseWriter, r *http.Request) (Store, error) { sid, err := manager.sessionID() if err != nil { - return + return nil, err } + + var session Store + cookie, err := r.Cookie(manager.config.CookieName) if err != nil || cookie.Value == "" { //delete old cookie - session, _ = manager.provider.SessionRead(nil, sid) + session, err = manager.provider.SessionRead(nil, sid) + if err != nil { + return nil, err + } cookie = &http.Cookie{Name: manager.config.CookieName, Value: url.QueryEscape(sid), Path: "/", @@ -315,8 +321,16 @@ func (manager *Manager) SessionRegenerateID(w http.ResponseWriter, r *http.Reque Domain: manager.config.Domain, } } else { - oldsid, _ := url.QueryUnescape(cookie.Value) - session, _ = manager.provider.SessionRegenerate(nil, oldsid, sid) + oldsid, err := url.QueryUnescape(cookie.Value) + if err != nil { + return nil, err + } + + session, err = manager.provider.SessionRegenerate(nil, oldsid, sid) + if err != nil { + return nil, err + } + cookie.Value = url.QueryEscape(sid) cookie.HttpOnly = true cookie.Path = "/" @@ -335,7 +349,7 @@ func (manager *Manager) SessionRegenerateID(w http.ResponseWriter, r *http.Reque w.Header().Set(manager.config.SessionNameInHTTPHeader, sid) } - return + return session, nil } // GetActiveSession Get all active sessions count number. diff --git a/server/web/tree_test.go b/server/web/tree_test.go index e72bc1f9..2c41a227 100644 --- a/server/web/tree_test.go +++ b/server/web/tree_test.go @@ -21,76 +21,109 @@ import ( "github.com/astaxie/beego/server/web/context" ) -type testinfo struct { - url string - requesturl string - params map[string]string +type testInfo struct { + pattern string + requestUrl string + params map[string]string + shouldMatchOrNot bool } -var routers []testinfo +var routers []testInfo + +func matchTestInfo(pattern, url string, params map[string]string) testInfo { + return testInfo{ + pattern: pattern, + requestUrl: url, + params: params, + shouldMatchOrNot: true, + } +} + +func notMatchTestInfo(pattern, url string) testInfo { + return testInfo{ + pattern: pattern, + requestUrl: url, + params: nil, + shouldMatchOrNot: false, + } +} func init() { - routers = make([]testinfo, 0) - routers = append(routers, testinfo{"/topic/?:auth:int", "/topic", nil}) - routers = append(routers, testinfo{"/topic/?:auth:int", "/topic/123", map[string]string{":auth": "123"}}) - routers = append(routers, testinfo{"/topic/:id/?:auth", "/topic/1", map[string]string{":id": "1"}}) - routers = append(routers, testinfo{"/topic/:id/?:auth", "/topic/1/2", map[string]string{":id": "1", ":auth": "2"}}) - routers = append(routers, testinfo{"/topic/:id/?:auth:int", "/topic/1", map[string]string{":id": "1"}}) - routers = append(routers, testinfo{"/topic/:id/?:auth:int", "/topic/1/123", map[string]string{":id": "1", ":auth": "123"}}) - routers = append(routers, testinfo{"/:id", "/123", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/hello/?:id", "/hello", map[string]string{":id": ""}}) - routers = append(routers, testinfo{"/", "/", nil}) - routers = append(routers, testinfo{"/customer/login", "/customer/login", nil}) - routers = append(routers, testinfo{"/customer/login", "/customer/login.json", map[string]string{":ext": "json"}}) - routers = append(routers, testinfo{"/*", "/http://customer/123/", map[string]string{":splat": "http://customer/123/"}}) - routers = append(routers, testinfo{"/*", "/customer/2009/12/11", map[string]string{":splat": "customer/2009/12/11"}}) - 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{"/cc/:id/*", "/cc/2009/11/dd", map[string]string{":id": "2009", ":splat": "11/dd"}}) - 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"}}) - routers = append(routers, testinfo{"/dl/:width:int/:height:int/*.*", - "/dl/48/48/05ac66d9bda00a3acf948c43e306fc9a.jpg", - map[string]string{":width": "48", ":height": "48", ":ext": "jpg", ":path": "05ac66d9bda00a3acf948c43e306fc9a"}}) - routers = append(routers, testinfo{"/v1/shop/:id:int", "/v1/shop/123", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/v1/shop/:id\\((a|b|c)\\)", "/v1/shop/123(a)", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/v1/shop/:id\\((a|b|c)\\)", "/v1/shop/123(b)", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/v1/shop/:id\\((a|b|c)\\)", "/v1/shop/123(c)", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/:year:int/:month:int/:id/:endid", "/1111/111/aaa/aaa", map[string]string{":year": "1111", ":month": "111", ":id": "aaa", ":endid": "aaa"}}) - routers = append(routers, testinfo{"/v1/shop/:id/:name", "/v1/shop/123/nike", map[string]string{":id": "123", ":name": "nike"}}) - routers = append(routers, testinfo{"/v1/shop/:id/account", "/v1/shop/123/account", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/v1/shop/:name:string", "/v1/shop/nike", map[string]string{":name": "nike"}}) - routers = append(routers, testinfo{"/v1/shop/:id([0-9]+)", "/v1/shop//123", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/v1/shop/:id([0-9]+)_:name", "/v1/shop/123_nike", map[string]string{":id": "123", ":name": "nike"}}) - routers = append(routers, testinfo{"/v1/shop/:id(.+)_cms.html", "/v1/shop/123_cms.html", map[string]string{":id": "123"}}) - routers = append(routers, testinfo{"/v1/shop/cms_:id(.+)_:page(.+).html", "/v1/shop/cms_123_1.html", map[string]string{":id": "123", ":page": "1"}}) - routers = append(routers, testinfo{"/v1/:v/cms/aaa_:id(.+)_:page(.+).html", "/v1/2/cms/aaa_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"}}) - routers = append(routers, testinfo{"/v1/:v/cms_:id(.+)_:page(.+).html", "/v1/2/cms_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"}}) - routers = append(routers, testinfo{"/v1/:v(.+)_cms/ttt_:id(.+)_:page(.+).html", "/v1/2_cms/ttt_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"}}) - routers = append(routers, testinfo{"/api/projects/:pid/members/?:mid", "/api/projects/1/members", map[string]string{":pid": "1"}}) - routers = append(routers, testinfo{"/api/projects/:pid/members/?:mid", "/api/projects/1/members/2", map[string]string{":pid": "1", ":mid": "2"}}) + routers = make([]testInfo, 0) + //match example + routers = append(routers, matchTestInfo("/topic/?:auth:int", "/topic", nil)) + routers = append(routers, matchTestInfo("/topic/?:auth:int", "/topic/123", map[string]string{":auth": "123"})) + routers = append(routers, matchTestInfo("/topic/:id/?:auth", "/topic/1", map[string]string{":id": "1"})) + routers = append(routers, matchTestInfo("/topic/:id/?:auth", "/topic/1/2", map[string]string{":id": "1", ":auth": "2"})) + routers = append(routers, matchTestInfo("/topic/:id/?:auth:int", "/topic/1", map[string]string{":id": "1"})) + routers = append(routers, matchTestInfo("/topic/:id/?:auth:int", "/topic/1/123", map[string]string{":id": "1", ":auth": "123"})) + routers = append(routers, matchTestInfo("/:id", "/123", map[string]string{":id": "123"})) + routers = append(routers, matchTestInfo("/hello/?:id", "/hello", map[string]string{":id": ""})) + routers = append(routers, matchTestInfo("/", "/", nil)) + routers = append(routers, matchTestInfo("/customer/login", "/customer/login", nil)) + routers = append(routers, matchTestInfo("/customer/login", "/customer/login.json", map[string]string{":ext": "json"})) + routers = append(routers, matchTestInfo("/*", "/http://customer/123/", map[string]string{":splat": "http://customer/123/"})) + routers = append(routers, matchTestInfo("/*", "/customer/2009/12/11", map[string]string{":splat": "customer/2009/12/11"})) + routers = append(routers, matchTestInfo("/aa/*/bb", "/aa/2009/bb", map[string]string{":splat": "2009"})) + routers = append(routers, matchTestInfo("/cc/*/dd", "/cc/2009/11/dd", map[string]string{":splat": "2009/11"})) + routers = append(routers, matchTestInfo("/cc/:id/*", "/cc/2009/11/dd", map[string]string{":id": "2009", ":splat": "11/dd"})) + routers = append(routers, matchTestInfo("/ee/:year/*/ff", "/ee/2009/11/ff", map[string]string{":year": "2009", ":splat": "11"})) + routers = append(routers, matchTestInfo("/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, matchTestInfo("/*.*", "/nice/api.json", map[string]string{":path": "nice/api", ":ext": "json"})) + routers = append(routers, matchTestInfo("/:name/*.*", "/nice/api.json", map[string]string{":name": "nice", ":path": "api", ":ext": "json"})) + routers = append(routers, matchTestInfo("/:name/test/*.*", "/nice/test/api.json", map[string]string{":name": "nice", ":path": "api", ":ext": "json"})) + routers = append(routers, matchTestInfo("/dl/:width:int/:height:int/*.*", "/dl/48/48/05ac66d9bda00a3acf948c43e306fc9a.jpg", map[string]string{":width": "48", ":height": "48", ":ext": "jpg", ":path": "05ac66d9bda00a3acf948c43e306fc9a"})) + routers = append(routers, matchTestInfo("/v1/shop/:id:int", "/v1/shop/123", map[string]string{":id": "123"})) + routers = append(routers, matchTestInfo("/v1/shop/:id\\((a|b|c)\\)", "/v1/shop/123(a)", map[string]string{":id": "123"})) + routers = append(routers, matchTestInfo("/v1/shop/:id\\((a|b|c)\\)", "/v1/shop/123(b)", map[string]string{":id": "123"})) + routers = append(routers, matchTestInfo("/v1/shop/:id\\((a|b|c)\\)", "/v1/shop/123(c)", map[string]string{":id": "123"})) + routers = append(routers, matchTestInfo("/:year:int/:month:int/:id/:endid", "/1111/111/aaa/aaa", map[string]string{":year": "1111", ":month": "111", ":id": "aaa", ":endid": "aaa"})) + routers = append(routers, matchTestInfo("/v1/shop/:id/:name", "/v1/shop/123/nike", map[string]string{":id": "123", ":name": "nike"})) + routers = append(routers, matchTestInfo("/v1/shop/:id/account", "/v1/shop/123/account", map[string]string{":id": "123"})) + routers = append(routers, matchTestInfo("/v1/shop/:name:string", "/v1/shop/nike", map[string]string{":name": "nike"})) + routers = append(routers, matchTestInfo("/v1/shop/:id([0-9]+)", "/v1/shop//123", map[string]string{":id": "123"})) + routers = append(routers, matchTestInfo("/v1/shop/:id([0-9]+)_:name", "/v1/shop/123_nike", map[string]string{":id": "123", ":name": "nike"})) + routers = append(routers, matchTestInfo("/v1/shop/:id(.+)_cms.html", "/v1/shop/123_cms.html", map[string]string{":id": "123"})) + routers = append(routers, matchTestInfo("/v1/shop/cms_:id(.+)_:page(.+).html", "/v1/shop/cms_123_1.html", map[string]string{":id": "123", ":page": "1"})) + routers = append(routers, matchTestInfo("/v1/:v/cms/aaa_:id(.+)_:page(.+).html", "/v1/2/cms/aaa_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"})) + routers = append(routers, matchTestInfo("/v1/:v/cms_:id(.+)_:page(.+).html", "/v1/2/cms_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"})) + routers = append(routers, matchTestInfo("/v1/:v(.+)_cms/ttt_:id(.+)_:page(.+).html", "/v1/2_cms/ttt_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"})) + routers = append(routers, matchTestInfo("/api/projects/:pid/members/?:mid", "/api/projects/1/members", map[string]string{":pid": "1"})) + routers = append(routers, matchTestInfo("/api/projects/:pid/members/?:mid", "/api/projects/1/members/2", map[string]string{":pid": "1", ":mid": "2"})) + + //not match example + + // https://github.com/astaxie/beego/issues/3865 + routers = append(routers, notMatchTestInfo("/read_:id:int\\.htm", "/read_222htm")) + routers = append(routers, notMatchTestInfo("/read_:id:int\\.htm", "/read_222_htm")) + routers = append(routers, notMatchTestInfo("/read_:id:int\\.htm", " /read_262shtm")) + } func TestTreeRouters(t *testing.T) { for _, r := range routers { + shouldMatch := r.shouldMatchOrNot + tr := NewTree() - tr.AddRouter(r.url, "astaxie") + tr.AddRouter(r.pattern, "astaxie") ctx := context.NewContext() - obj := tr.Match(r.requesturl, ctx) + obj := tr.Match(r.requestUrl, ctx) + if !shouldMatch { + if obj != nil { + t.Fatal("pattern:", r.pattern, ", should not match", r.requestUrl) + } else { + return + } + } if obj == nil || obj.(string) != "astaxie" { - t.Fatal(r.url+" can't get obj, Expect ", r.requesturl) + t.Fatal("pattern:", r.pattern+", can't match obj, Expect ", r.requestUrl) } if r.params != nil { for k, v := range r.params { if vv := ctx.Input.Param(k); vv != v { - t.Fatal("The Rule: " + r.url + "\nThe RequestURL:" + r.requesturl + "\nThe Key is " + k + ", The Value should be: " + v + ", but get: " + vv) + t.Fatal("The Rule: " + r.pattern + "\nThe RequestURL:" + r.requestUrl + "\nThe Key is " + k + ", The Value should be: " + v + ", but get: " + vv) } else if vv == "" && v != "" { - t.Fatal(r.url + " " + r.requesturl + " get param empty:" + k) + t.Fatal(r.pattern + " " + r.requestUrl + " get param empty:" + k) } } } @@ -247,7 +280,6 @@ func TestAddTree5(t *testing.T) { t.Fatal("url /v1/shop/ need match router /v1/shop/ ") } } - func TestSplitPath(t *testing.T) { a := splitPath("") if len(a) != 0 { @@ -292,6 +324,7 @@ func TestSplitSegment(t *testing.T) { ":id([0-9]+)": {true, []string{":id"}, `([0-9]+)`}, ":id([0-9]+)_:name": {true, []string{":id", ":name"}, `([0-9]+)_(.+)`}, ":id(.+)_cms.html": {true, []string{":id"}, `(.+)_cms.html`}, + ":id(.+)_cms\\.html": {true, []string{":id"}, `(.+)_cms\.html`}, "cms_:id(.+)_:page(.+).html": {true, []string{":id", ":page"}, `cms_(.+)_(.+).html`}, `:app(a|b|c)`: {true, []string{":app"}, `(a|b|c)`}, `:app\((a|b|c)\)`: {true, []string{":app"}, `(.+)\((a|b|c)\)`}, @@ -303,4 +336,4 @@ func TestSplitSegment(t *testing.T) { t.Fatalf("%s should return %t,%s,%q, got %t,%s,%q", pattern, v.isReg, v.params, v.regStr, b, w, r) } } -} +} \ No newline at end of file diff --git a/task/govenor_command.go b/task/govenor_command.go index 15e25e43..8dd92b67 100644 --- a/task/govenor_command.go +++ b/task/govenor_command.go @@ -21,13 +21,13 @@ import ( "github.com/pkg/errors" - "github.com/astaxie/beego/core/governor" + "github.com/astaxie/beego/core/admin" ) type listTaskCommand struct { } -func (l *listTaskCommand) Execute(params ...interface{}) *governor.Result { +func (l *listTaskCommand) Execute(params ...interface{}) *admin.Result { resultList := make([][]string, 0, len(globalTaskManager.adminTaskList)) for tname, tk := range globalTaskManager.adminTaskList { result := []string{ @@ -39,7 +39,7 @@ func (l *listTaskCommand) Execute(params ...interface{}) *governor.Result { resultList = append(resultList, result) } - return &governor.Result{ + return &admin.Result{ Status: 200, Content: resultList, } @@ -48,9 +48,9 @@ func (l *listTaskCommand) Execute(params ...interface{}) *governor.Result { type runTaskCommand struct { } -func (r *runTaskCommand) Execute(params ...interface{}) *governor.Result { +func (r *runTaskCommand) Execute(params ...interface{}) *admin.Result { if len(params) == 0 { - return &governor.Result{ + return &admin.Result{ Status: 400, Error: errors.New("task name not passed"), } @@ -59,7 +59,7 @@ func (r *runTaskCommand) Execute(params ...interface{}) *governor.Result { tn, ok := params[0].(string) if !ok { - return &governor.Result{ + return &admin.Result{ Status: 400, Error: errors.New("parameter is invalid"), } @@ -68,17 +68,17 @@ func (r *runTaskCommand) Execute(params ...interface{}) *governor.Result { if t, ok := globalTaskManager.adminTaskList[tn]; ok { err := t.Run(context.Background()) if err != nil { - return &governor.Result{ + return &admin.Result{ Status: 500, Error: err, } } - return &governor.Result{ + return &admin.Result{ Status: 200, Content: t.GetStatus(context.Background()), } } else { - return &governor.Result{ + return &admin.Result{ Status: 400, Error: errors.New(fmt.Sprintf("task with name %s not found", tn)), } @@ -87,6 +87,6 @@ func (r *runTaskCommand) Execute(params ...interface{}) *governor.Result { } func registerCommands() { - governor.RegisterCommand("task", "list", &listTaskCommand{}) - governor.RegisterCommand("task", "run", &runTaskCommand{}) + admin.RegisterCommand("task", "list", &listTaskCommand{}) + admin.RegisterCommand("task", "run", &runTaskCommand{}) }