mirror of
https://github.com/astaxie/beego.git
synced 2025-07-11 19:51:01 +00:00
Compare commits
52 Commits
v2.0.0-bet
...
develop
Author | SHA1 | Date | |
---|---|---|---|
093f976365 | |||
198b9cce5f | |||
1452a75de4 | |||
728296a7ae | |||
e2fc8b93f2 | |||
86620210f8 | |||
64d7d36794 | |||
88bd9f594a | |||
2e1c50253c | |||
a5842e9de2 | |||
40f7a56bf5 | |||
aec5f4b3a5 | |||
9eda707297 | |||
b92edb6587 | |||
53688ce32f | |||
debd68cbe4 | |||
b6d6571e99 | |||
db785479ab | |||
54ab211f00 | |||
c034d3767a | |||
99a47e7644 | |||
59ca0d063f | |||
aa05b66ca1 | |||
8d7f48ea75 | |||
fd48c62873 | |||
7ee5c8e553 | |||
4afa9d2d25 | |||
fad897346f | |||
650fde66aa | |||
359ad7a889 | |||
00ed1c3733 | |||
0958174bc8 | |||
c6282e7b27 | |||
6225f0c1e9 | |||
05d8e293f7 | |||
663e5d728c | |||
26bc9e7264 | |||
0a852912b4 | |||
647e21b0c4 | |||
a00b54d8f6 | |||
8f16098508 | |||
aad80ba4fa | |||
8f3fd317da | |||
c5c03815f3 | |||
0b3bcbd3ec | |||
49d763dc6c | |||
aa2c0ca108 | |||
b3474b20b9 | |||
2a6fadb9ae | |||
e284b0ddae | |||
8ef8fd2606 | |||
0cd80525e7 |
260
README.md
260
README.md
@ -1,19 +1,32 @@
|
||||
# Beego [](https://travis-ci.org/astaxie/beego) [](http://godoc.org/github.com/astaxie/beego) [](http://golangfoundation.org) [](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).
|
||||

|
||||
|
||||
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
|
||||
|
||||

|
||||
|
||||
#### Create `hello` directory, cd `hello` directory
|
||||
|
||||
mkdir hello
|
||||
@ -25,18 +38,20 @@ It is inspired by Tornado, Sinatra and Flask. beego has some Go-specific feature
|
||||
|
||||
#### 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
|
||||
|
||||
|
@ -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"
|
||||
)
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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/ ")
|
||||
}
|
||||
}
|
@ -28,5 +28,5 @@ var (
|
||||
|
||||
const (
|
||||
// VERSION represent beego web framework version.
|
||||
VERSION = "2.0.0-alpha"
|
||||
VERSION = "2.0.0"
|
||||
)
|
||||
|
98
client/cache/cache_test.go
vendored
98
client/cache/cache_test.go
vendored
@ -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")
|
||||
}
|
||||
}
|
||||
|
99
client/cache/file.go
vendored
99
client/cache/file.go
vendored
@ -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.
|
||||
|
25
client/cache/memcache/memcache.go
vendored
25
client/cache/memcache/memcache.go
vendored
@ -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.
|
||||
|
15
client/cache/memcache/memcache_test.go
vendored
15
client/cache/memcache/memcache_test.go
vendored
@ -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")
|
||||
|
24
client/cache/memory.go
vendored
24
client/cache/memory.go
vendored
@ -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.
|
||||
|
8
client/cache/redis/redis_test.go
vendored
8
client/cache/redis/redis_test.go
vendored
@ -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")
|
||||
|
33
client/cache/ssdb/ssdb.go
vendored
33
client/cache/ssdb/ssdb.go
vendored
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@ -28,36 +29,50 @@ func NewSsdbCache() cache.Cache {
|
||||
func (rc *Cache) Get(ctx context.Context, key string) (interface{}, error) {
|
||||
if rc.conn == nil {
|
||||
if err := rc.connectInit(); err != nil {
|
||||
return nil, nil
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
value, err := rc.conn.Get(key)
|
||||
if err == nil {
|
||||
return value, nil
|
||||
}
|
||||
return nil, nil
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
|
14
client/cache/ssdb/ssdb_test.go
vendored
14
client/cache/ssdb/ssdb_test.go
vendored
@ -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")
|
||||
|
@ -76,10 +76,13 @@ func (c Condition) AndNot(expr string, args ...interface{}) *Condition {
|
||||
|
||||
// AndCond combine a condition to current condition
|
||||
func (c *Condition) AndCond(cond *Condition) *Condition {
|
||||
c = c.clone()
|
||||
|
||||
if c == cond {
|
||||
panic(fmt.Errorf("<Condition.AndCond> cannot use self as sub cond"))
|
||||
}
|
||||
|
||||
c = c.clone()
|
||||
|
||||
if cond != nil {
|
||||
c.params = append(c.params, condValue{cond: cond, isCond: true})
|
||||
}
|
||||
@ -149,5 +152,8 @@ func (c *Condition) IsEmpty() bool {
|
||||
|
||||
// clone clone a condition
|
||||
func (c Condition) clone() *Condition {
|
||||
params := make([]condValue, len(c.params))
|
||||
copy(params, c.params)
|
||||
c.params = params
|
||||
return &c
|
||||
}
|
||||
|
@ -2668,3 +2668,48 @@ func TestPSQueryBuilder(t *testing.T) {
|
||||
throwFailNow(t, AssertIs(l[0].UserName, "astaxie"))
|
||||
throwFailNow(t, AssertIs(l[0].Age, 30))
|
||||
}
|
||||
|
||||
func TestCondition(t *testing.T) {
|
||||
// test Condition whether to include yourself
|
||||
cond := NewCondition()
|
||||
cond = cond.AndCond(cond.Or("ID", 1))
|
||||
cond = cond.AndCond(cond.Or("ID", 2))
|
||||
cond = cond.AndCond(cond.Or("ID", 3))
|
||||
cond = cond.AndCond(cond.Or("ID", 4))
|
||||
|
||||
cycleFlag := false
|
||||
var hasCycle func(*Condition)
|
||||
hasCycle = func(c *Condition) {
|
||||
if nil == c || cycleFlag {
|
||||
return
|
||||
}
|
||||
condPointMap := make(map[string]bool)
|
||||
condPointMap[fmt.Sprintf("%p", c)] = true
|
||||
for _, p := range c.params {
|
||||
if p.isCond {
|
||||
adr := fmt.Sprintf("%p", p.cond)
|
||||
if condPointMap[adr] {
|
||||
// self as sub cond was cycle
|
||||
cycleFlag = true
|
||||
break
|
||||
}
|
||||
condPointMap[adr] = true
|
||||
|
||||
}
|
||||
}
|
||||
if cycleFlag {
|
||||
return
|
||||
}
|
||||
for _, p := range c.params {
|
||||
if p.isCond {
|
||||
// check next cond
|
||||
hasCycle(p.cond)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
hasCycle(cond)
|
||||
// cycleFlag was true,meaning use self as sub cond
|
||||
throwFail(t, AssertIs(!cycleFlag, true))
|
||||
return
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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"
|
@ -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
|
@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package governor
|
||||
package admin
|
||||
|
||||
import (
|
||||
"fmt"
|
@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package governor
|
||||
package admin
|
||||
|
||||
import (
|
||||
"os"
|
@ -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"
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -764,9 +764,7 @@ func formatLog(f interface{}, v ...interface{}) string {
|
||||
if len(v) == 0 {
|
||||
return msg
|
||||
}
|
||||
if strings.Contains(msg, "%") && !strings.Contains(msg, "%%") {
|
||||
// format string
|
||||
} else {
|
||||
if !strings.Contains(msg, "%") {
|
||||
// do not contain format char
|
||||
msg += strings.Repeat(" %v", len(v))
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
package logs
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
@ -25,8 +25,8 @@ func newSLACKWriter() Logger {
|
||||
}
|
||||
|
||||
func (s *SLACKWriter) Format(lm *LogMsg) string {
|
||||
text := fmt.Sprintf("{\"text\": \"%s %s\"}", lm.When.Format("2006-01-02 15:04:05"), lm.OldStyleFormat())
|
||||
return text
|
||||
// text := fmt.Sprintf("{\"text\": \"%s\"}", msg)
|
||||
return lm.When.Format("2006-01-02 15:04:05") + " " + lm.OldStyleFormat()
|
||||
}
|
||||
|
||||
func (s *SLACKWriter) SetFormatter(f LogFormatter) {
|
||||
@ -55,10 +55,12 @@ func (s *SLACKWriter) WriteMsg(lm *LogMsg) error {
|
||||
return nil
|
||||
}
|
||||
msg := s.Format(lm)
|
||||
form := url.Values{}
|
||||
form.Add("payload", msg)
|
||||
m := make(map[string]string, 1)
|
||||
m["text"] = msg
|
||||
|
||||
resp, err := http.PostForm(s.WebhookURL, form)
|
||||
body, _ := json.Marshal(m)
|
||||
// resp, err := http.PostForm(s.WebhookURL, form)
|
||||
resp, err := http.Post(s.WebhookURL, "application/json", bytes.NewReader(body))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
44
core/logs/slack_test.go
Normal file
44
core/logs/slack_test.go
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright 2020
|
||||
//
|
||||
// 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
|
||||
|
||||
// func TestSLACKWriter_WriteMsg(t *testing.T) {
|
||||
// sc := `
|
||||
// {
|
||||
// "webhookurl":"",
|
||||
// "level":7
|
||||
// }
|
||||
// `
|
||||
// l := newSLACKWriter()
|
||||
// err := l.Init(sc)
|
||||
// if err != nil {
|
||||
// Debug(err)
|
||||
// }
|
||||
//
|
||||
// err = l.WriteMsg(&LogMsg{
|
||||
// Level: 7,
|
||||
// Msg: `{ "abs"`,
|
||||
// When: time.Now(),
|
||||
// FilePath: "main.go",
|
||||
// LineNumber: 100,
|
||||
// enableFullFilePath: true,
|
||||
// enableFuncCallDepth: true,
|
||||
// })
|
||||
//
|
||||
// if err != nil {
|
||||
// Debug(err)
|
||||
// }
|
||||
//
|
||||
// }
|
@ -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",
|
||||
|
@ -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 {
|
||||
|
@ -21,7 +21,7 @@ var indexTpl = `
|
||||
For detail usage please check our document:
|
||||
</p>
|
||||
<p>
|
||||
<a target="_blank" href="http://beego.me/docs/module/governor.md">Toolbox</a>
|
||||
<a target="_blank" href="http://beego.me/docs/module/admin.md">Toolbox</a>
|
||||
</p>
|
||||
<p>
|
||||
<a target="_blank" href="http://beego.me/docs/advantage/monitor.md">Live Monitor</a>
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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])
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -273,7 +273,6 @@ func (p *ControllerRegister) Include(cList ...ControllerInterface) {
|
||||
for _, f := range a.Filters {
|
||||
p.InsertFilter(f.Pattern, f.Pos, f.Filter, WithReturnOnOutput(f.ReturnOnOutput), WithResetParams(f.ResetParams))
|
||||
}
|
||||
|
||||
p.addWithMethodParams(a.Router, c, a.MethodParams, strings.Join(a.AllowHTTPMethods, ",")+":"+a.Method)
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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)\)`},
|
||||
|
@ -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{})
|
||||
}
|
||||
|
@ -452,9 +452,11 @@ func (m *taskManager) StartTask() {
|
||||
|
||||
func (m *taskManager) run() {
|
||||
now := time.Now().Local()
|
||||
m.taskLock.Lock()
|
||||
for _, t := range m.adminTaskList {
|
||||
t.SetNext(nil, now)
|
||||
}
|
||||
m.taskLock.Unlock()
|
||||
|
||||
for {
|
||||
// we only use RLock here because NewMapSorter copy the reference, do not change any thing
|
||||
|
Reference in New Issue
Block a user