version 1.1.2 release
Showing
21 changed files
with
595 additions
and
131 deletions
| ... | @@ -2,6 +2,7 @@ package beego | ... | @@ -2,6 +2,7 @@ package beego |
| 2 | 2 | ||
| 3 | import ( | 3 | import ( |
| 4 | "net/http" | 4 | "net/http" |
| 5 | "os" | ||
| 5 | "path" | 6 | "path" |
| 6 | "path/filepath" | 7 | "path/filepath" |
| 7 | "strconv" | 8 | "strconv" |
| ... | @@ -12,7 +13,7 @@ import ( | ... | @@ -12,7 +13,7 @@ import ( |
| 12 | ) | 13 | ) |
| 13 | 14 | ||
| 14 | // beego web framework version. | 15 | // beego web framework version. |
| 15 | const VERSION = "1.1.1" | 16 | const VERSION = "1.1.2" |
| 16 | 17 | ||
| 17 | type hookfunc func() error //hook function to run | 18 | type hookfunc func() error //hook function to run |
| 18 | var hooks []hookfunc //hook function slice to store the hookfunc | 19 | var hooks []hookfunc //hook function slice to store the hookfunc |
| ... | @@ -174,6 +175,16 @@ func AddAPPStartHook(hf hookfunc) { | ... | @@ -174,6 +175,16 @@ func AddAPPStartHook(hf hookfunc) { |
| 174 | // Run beego application. | 175 | // Run beego application. |
| 175 | // it's alias of App.Run. | 176 | // it's alias of App.Run. |
| 176 | func Run() { | 177 | func Run() { |
| 178 | initBeforeHttpRun() | ||
| 179 | |||
| 180 | if EnableAdmin { | ||
| 181 | go BeeAdminApp.Run() | ||
| 182 | } | ||
| 183 | |||
| 184 | BeeApp.Run() | ||
| 185 | } | ||
| 186 | |||
| 187 | func initBeforeHttpRun() { | ||
| 177 | // if AppConfigPath not In the conf/app.conf reParse config | 188 | // if AppConfigPath not In the conf/app.conf reParse config |
| 178 | if AppConfigPath != filepath.Join(AppPath, "conf", "app.conf") { | 189 | if AppConfigPath != filepath.Join(AppPath, "conf", "app.conf") { |
| 179 | err := ParseConfig() | 190 | err := ParseConfig() |
| ... | @@ -222,12 +233,13 @@ func Run() { | ... | @@ -222,12 +233,13 @@ func Run() { |
| 222 | middleware.VERSION = VERSION | 233 | middleware.VERSION = VERSION |
| 223 | middleware.AppName = AppName | 234 | middleware.AppName = AppName |
| 224 | middleware.RegisterErrorHandler() | 235 | middleware.RegisterErrorHandler() |
| 236 | } | ||
| 225 | 237 | ||
| 226 | if EnableAdmin { | 238 | func TestBeegoInit(apppath string) { |
| 227 | go BeeAdminApp.Run() | 239 | AppPath = apppath |
| 228 | } | 240 | AppConfigPath = filepath.Join(AppPath, "conf", "app.conf") |
| 229 | 241 | os.Chdir(AppPath) | |
| 230 | BeeApp.Run() | 242 | initBeforeHttpRun() |
| 231 | } | 243 | } |
| 232 | 244 | ||
| 233 | func init() { | 245 | func init() { | ... | ... |
| ... | @@ -11,12 +11,14 @@ import ( | ... | @@ -11,12 +11,14 @@ import ( |
| 11 | "github.com/astaxie/beego/config" | 11 | "github.com/astaxie/beego/config" |
| 12 | "github.com/astaxie/beego/logs" | 12 | "github.com/astaxie/beego/logs" |
| 13 | "github.com/astaxie/beego/session" | 13 | "github.com/astaxie/beego/session" |
| 14 | "github.com/astaxie/beego/utils" | ||
| 14 | ) | 15 | ) |
| 15 | 16 | ||
| 16 | var ( | 17 | var ( |
| 17 | BeeApp *App // beego application | 18 | BeeApp *App // beego application |
| 18 | AppName string | 19 | AppName string |
| 19 | AppPath string | 20 | AppPath string |
| 21 | workPath string | ||
| 20 | AppConfigPath string | 22 | AppConfigPath string |
| 21 | StaticDir map[string]string | 23 | StaticDir map[string]string |
| 22 | TemplateCache map[string]*template.Template // template caching map | 24 | TemplateCache map[string]*template.Template // template caching map |
| ... | @@ -58,15 +60,28 @@ var ( | ... | @@ -58,15 +60,28 @@ var ( |
| 58 | EnableAdmin bool // flag of enable admin module to log every request info. | 60 | EnableAdmin bool // flag of enable admin module to log every request info. |
| 59 | AdminHttpAddr string // http server configurations for admin module. | 61 | AdminHttpAddr string // http server configurations for admin module. |
| 60 | AdminHttpPort int | 62 | AdminHttpPort int |
| 63 | FlashName string // name of the flash variable found in response header and cookie | ||
| 64 | FlashSeperator string // used to seperate flash key:value | ||
| 61 | ) | 65 | ) |
| 62 | 66 | ||
| 63 | func init() { | 67 | func init() { |
| 64 | // create beego application | 68 | // create beego application |
| 65 | BeeApp = NewApp() | 69 | BeeApp = NewApp() |
| 66 | 70 | ||
| 71 | workPath, _ = os.Getwd() | ||
| 72 | workPath, _ = filepath.Abs(workPath) | ||
| 67 | // initialize default configurations | 73 | // initialize default configurations |
| 68 | AppPath, _ = filepath.Abs(filepath.Dir(os.Args[0])) | 74 | AppPath, _ = filepath.Abs(filepath.Dir(os.Args[0])) |
| 69 | os.Chdir(AppPath) | 75 | |
| 76 | AppConfigPath = filepath.Join(AppPath, "conf", "app.conf") | ||
| 77 | |||
| 78 | if workPath != AppPath { | ||
| 79 | if utils.FileExists(AppConfigPath) { | ||
| 80 | os.Chdir(AppPath) | ||
| 81 | } else { | ||
| 82 | AppConfigPath = filepath.Join(workPath, "conf", "app.conf") | ||
| 83 | } | ||
| 84 | } | ||
| 70 | 85 | ||
| 71 | StaticDir = make(map[string]string) | 86 | StaticDir = make(map[string]string) |
| 72 | StaticDir["/static"] = "static" | 87 | StaticDir["/static"] = "static" |
| ... | @@ -105,8 +120,6 @@ func init() { | ... | @@ -105,8 +120,6 @@ func init() { |
| 105 | 120 | ||
| 106 | EnableGzip = false | 121 | EnableGzip = false |
| 107 | 122 | ||
| 108 | AppConfigPath = filepath.Join(AppPath, "conf", "app.conf") | ||
| 109 | |||
| 110 | HttpServerTimeOut = 0 | 123 | HttpServerTimeOut = 0 |
| 111 | 124 | ||
| 112 | ErrorsShow = true | 125 | ErrorsShow = true |
| ... | @@ -123,6 +136,9 @@ func init() { | ... | @@ -123,6 +136,9 @@ func init() { |
| 123 | AdminHttpAddr = "127.0.0.1" | 136 | AdminHttpAddr = "127.0.0.1" |
| 124 | AdminHttpPort = 8088 | 137 | AdminHttpPort = 8088 |
| 125 | 138 | ||
| 139 | FlashName = "BEEGO_FLASH" | ||
| 140 | FlashSeperator = "BEEGOFLASH" | ||
| 141 | |||
| 126 | runtime.GOMAXPROCS(runtime.NumCPU()) | 142 | runtime.GOMAXPROCS(runtime.NumCPU()) |
| 127 | 143 | ||
| 128 | // init BeeLogger | 144 | // init BeeLogger |
| ... | @@ -271,6 +287,14 @@ func ParseConfig() (err error) { | ... | @@ -271,6 +287,14 @@ func ParseConfig() (err error) { |
| 271 | BeegoServerName = serverName | 287 | BeegoServerName = serverName |
| 272 | } | 288 | } |
| 273 | 289 | ||
| 290 | if flashname := AppConfig.String("FlashName"); flashname != "" { | ||
| 291 | FlashName = flashname | ||
| 292 | } | ||
| 293 | |||
| 294 | if flashseperator := AppConfig.String("FlashSeperator"); flashseperator != "" { | ||
| 295 | FlashSeperator = flashseperator | ||
| 296 | } | ||
| 297 | |||
| 274 | if sd := AppConfig.String("StaticDir"); sd != "" { | 298 | if sd := AppConfig.String("StaticDir"); sd != "" { |
| 275 | for k := range StaticDir { | 299 | for k := range StaticDir { |
| 276 | delete(StaticDir, k) | 300 | delete(StaticDir, k) | ... | ... |
config_test.go
0 → 100644
| ... | @@ -4,6 +4,7 @@ import ( | ... | @@ -4,6 +4,7 @@ import ( |
| 4 | "bytes" | 4 | "bytes" |
| 5 | "io/ioutil" | 5 | "io/ioutil" |
| 6 | "net/http" | 6 | "net/http" |
| 7 | "reflect" | ||
| 7 | "strconv" | 8 | "strconv" |
| 8 | "strings" | 9 | "strings" |
| 9 | 10 | ||
| ... | @@ -13,11 +14,13 @@ import ( | ... | @@ -13,11 +14,13 @@ import ( |
| 13 | // BeegoInput operates the http request header ,data ,cookie and body. | 14 | // BeegoInput operates the http request header ,data ,cookie and body. |
| 14 | // it also contains router params and current session. | 15 | // it also contains router params and current session. |
| 15 | type BeegoInput struct { | 16 | type BeegoInput struct { |
| 16 | CruSession session.SessionStore | 17 | CruSession session.SessionStore |
| 17 | Params map[string]string | 18 | Params map[string]string |
| 18 | Data map[interface{}]interface{} // store some values in this context when calling context in filter or controller. | 19 | Data map[interface{}]interface{} // store some values in this context when calling context in filter or controller. |
| 19 | Request *http.Request | 20 | Request *http.Request |
| 20 | RequestBody []byte | 21 | RequestBody []byte |
| 22 | RunController reflect.Type | ||
| 23 | RunMethod string | ||
| 21 | } | 24 | } |
| 22 | 25 | ||
| 23 | // NewInput return BeegoInput generated by http.Request. | 26 | // NewInput return BeegoInput generated by http.Request. | ... | ... |
| ... | @@ -62,7 +62,6 @@ type ControllerInterface interface { | ... | @@ -62,7 +62,6 @@ type ControllerInterface interface { |
| 62 | 62 | ||
| 63 | // Init generates default values of controller operations. | 63 | // Init generates default values of controller operations. |
| 64 | func (c *Controller) Init(ctx *context.Context, controllerName, actionName string, app interface{}) { | 64 | func (c *Controller) Init(ctx *context.Context, controllerName, actionName string, app interface{}) { |
| 65 | c.Data = make(map[interface{}]interface{}) | ||
| 66 | c.Layout = "" | 65 | c.Layout = "" |
| 67 | c.TplNames = "" | 66 | c.TplNames = "" |
| 68 | c.controllerName = controllerName | 67 | c.controllerName = controllerName | ... | ... |
| ... | @@ -6,9 +6,6 @@ import ( | ... | @@ -6,9 +6,6 @@ import ( |
| 6 | "strings" | 6 | "strings" |
| 7 | ) | 7 | ) |
| 8 | 8 | ||
| 9 | // the separation string when encoding flash data. | ||
| 10 | const BEEGO_FLASH_SEP = "#BEEGOFLASH#" | ||
| 11 | |||
| 12 | // FlashData is a tools to maintain data when using across request. | 9 | // FlashData is a tools to maintain data when using across request. |
| 13 | type FlashData struct { | 10 | type FlashData struct { |
| 14 | Data map[string]string | 11 | Data map[string]string |
| ... | @@ -54,29 +51,27 @@ func (fd *FlashData) Store(c *Controller) { | ... | @@ -54,29 +51,27 @@ func (fd *FlashData) Store(c *Controller) { |
| 54 | c.Data["flash"] = fd.Data | 51 | c.Data["flash"] = fd.Data |
| 55 | var flashValue string | 52 | var flashValue string |
| 56 | for key, value := range fd.Data { | 53 | for key, value := range fd.Data { |
| 57 | flashValue += "\x00" + key + BEEGO_FLASH_SEP + value + "\x00" | 54 | flashValue += "\x00" + key + "\x23" + FlashSeperator + "\x23" + value + "\x00" |
| 58 | } | 55 | } |
| 59 | c.Ctx.SetCookie("BEEGO_FLASH", url.QueryEscape(flashValue), 0, "/") | 56 | c.Ctx.SetCookie(FlashName, url.QueryEscape(flashValue), 0, "/") |
| 60 | } | 57 | } |
| 61 | 58 | ||
| 62 | // ReadFromRequest parsed flash data from encoded values in cookie. | 59 | // ReadFromRequest parsed flash data from encoded values in cookie. |
| 63 | func ReadFromRequest(c *Controller) *FlashData { | 60 | func ReadFromRequest(c *Controller) *FlashData { |
| 64 | flash := &FlashData{ | 61 | flash := NewFlash() |
| 65 | Data: make(map[string]string), | 62 | if cookie, err := c.Ctx.Request.Cookie(FlashName); err == nil { |
| 66 | } | ||
| 67 | if cookie, err := c.Ctx.Request.Cookie("BEEGO_FLASH"); err == nil { | ||
| 68 | v, _ := url.QueryUnescape(cookie.Value) | 63 | v, _ := url.QueryUnescape(cookie.Value) |
| 69 | vals := strings.Split(v, "\x00") | 64 | vals := strings.Split(v, "\x00") |
| 70 | for _, v := range vals { | 65 | for _, v := range vals { |
| 71 | if len(v) > 0 { | 66 | if len(v) > 0 { |
| 72 | kv := strings.Split(v, BEEGO_FLASH_SEP) | 67 | kv := strings.Split(v, FlashSeperator) |
| 73 | if len(kv) == 2 { | 68 | if len(kv) == 2 { |
| 74 | flash.Data[kv[0]] = kv[1] | 69 | flash.Data[kv[0]] = kv[1] |
| 75 | } | 70 | } |
| 76 | } | 71 | } |
| 77 | } | 72 | } |
| 78 | //read one time then delete it | 73 | //read one time then delete it |
| 79 | c.Ctx.SetCookie("BEEGO_FLASH", "", -1, "/") | 74 | c.Ctx.SetCookie(FlashName, "", -1, "/") |
| 80 | } | 75 | } |
| 81 | c.Data["flash"] = flash.Data | 76 | c.Data["flash"] = flash.Data |
| 82 | return flash | 77 | return flash | ... | ... |
flash_test.go
0 → 100644
| 1 | package beego | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "net/http" | ||
| 5 | "net/http/httptest" | ||
| 6 | "strings" | ||
| 7 | "testing" | ||
| 8 | ) | ||
| 9 | |||
| 10 | type TestFlashController struct { | ||
| 11 | Controller | ||
| 12 | } | ||
| 13 | |||
| 14 | func (this *TestFlashController) TestWriteFlash() { | ||
| 15 | flash := NewFlash() | ||
| 16 | flash.Notice("TestFlashString") | ||
| 17 | flash.Store(&this.Controller) | ||
| 18 | // we choose to serve json because we don't want to load a template html file | ||
| 19 | this.ServeJson(true) | ||
| 20 | } | ||
| 21 | |||
| 22 | func TestFlashHeader(t *testing.T) { | ||
| 23 | // create fake GET request | ||
| 24 | r, _ := http.NewRequest("GET", "/", nil) | ||
| 25 | w := httptest.NewRecorder() | ||
| 26 | |||
| 27 | // setup the handler | ||
| 28 | handler := NewControllerRegistor() | ||
| 29 | handler.Add("/", &TestFlashController{}, "get:TestWriteFlash") | ||
| 30 | handler.ServeHTTP(w, r) | ||
| 31 | |||
| 32 | // get the Set-Cookie value | ||
| 33 | sc := w.Header().Get("Set-Cookie") | ||
| 34 | // match for the expected header | ||
| 35 | res := strings.Contains(sc, "BEEGO_FLASH=%00notice%23BEEGOFLASH%23TestFlashString%00") | ||
| 36 | // validate the assertion | ||
| 37 | if res != true { | ||
| 38 | t.Errorf("TestFlashHeader() unable to validate flash message") | ||
| 39 | } | ||
| 40 | } |
| ... | @@ -22,12 +22,21 @@ func SetLevel(l int) { | ... | @@ -22,12 +22,21 @@ func SetLevel(l int) { |
| 22 | BeeLogger.SetLevel(l) | 22 | BeeLogger.SetLevel(l) |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | func SetLogFuncCall(b bool) { | ||
| 26 | BeeLogger.EnableFuncCallDepth(b) | ||
| 27 | BeeLogger.SetLogFuncCallDepth(3) | ||
| 28 | } | ||
| 29 | |||
| 25 | // logger references the used application logger. | 30 | // logger references the used application logger. |
| 26 | var BeeLogger *logs.BeeLogger | 31 | var BeeLogger *logs.BeeLogger |
| 27 | 32 | ||
| 28 | // SetLogger sets a new logger. | 33 | // SetLogger sets a new logger. |
| 29 | func SetLogger(adaptername string, config string) { | 34 | func SetLogger(adaptername string, config string) error { |
| 30 | BeeLogger.SetLogger(adaptername, config) | 35 | err := BeeLogger.SetLogger(adaptername, config) |
| 36 | if err != nil { | ||
| 37 | return err | ||
| 38 | } | ||
| 39 | return nil | ||
| 31 | } | 40 | } |
| 32 | 41 | ||
| 33 | // Trace logs a message at trace level. | 42 | // Trace logs a message at trace level. | ... | ... |
| ... | @@ -6,6 +6,7 @@ import ( | ... | @@ -6,6 +6,7 @@ import ( |
| 6 | 6 | ||
| 7 | func TestConsole(t *testing.T) { | 7 | func TestConsole(t *testing.T) { |
| 8 | log := NewLogger(10000) | 8 | log := NewLogger(10000) |
| 9 | log.EnableFuncCallDepth(true) | ||
| 9 | log.SetLogger("console", "") | 10 | log.SetLogger("console", "") |
| 10 | log.Trace("trace") | 11 | log.Trace("trace") |
| 11 | log.Info("info") | 12 | log.Info("info") |
| ... | @@ -23,6 +24,7 @@ func TestConsole(t *testing.T) { | ... | @@ -23,6 +24,7 @@ func TestConsole(t *testing.T) { |
| 23 | 24 | ||
| 24 | func BenchmarkConsole(b *testing.B) { | 25 | func BenchmarkConsole(b *testing.B) { |
| 25 | log := NewLogger(10000) | 26 | log := NewLogger(10000) |
| 27 | log.EnableFuncCallDepth(true) | ||
| 26 | log.SetLogger("console", "") | 28 | log.SetLogger("console", "") |
| 27 | for i := 0; i < b.N; i++ { | 29 | for i := 0; i < b.N; i++ { |
| 28 | log.Trace("trace") | 30 | log.Trace("trace") | ... | ... |
| ... | @@ -97,12 +97,12 @@ func (w *FileLogWriter) Init(jsonconfig string) error { | ... | @@ -97,12 +97,12 @@ func (w *FileLogWriter) Init(jsonconfig string) error { |
| 97 | if len(w.Filename) == 0 { | 97 | if len(w.Filename) == 0 { |
| 98 | return errors.New("jsonconfig must have filename") | 98 | return errors.New("jsonconfig must have filename") |
| 99 | } | 99 | } |
| 100 | err = w.StartLogger() | 100 | err = w.startLogger() |
| 101 | return err | 101 | return err |
| 102 | } | 102 | } |
| 103 | 103 | ||
| 104 | // start file logger. create log file and set to locker-inside file writer. | 104 | // start file logger. create log file and set to locker-inside file writer. |
| 105 | func (w *FileLogWriter) StartLogger() error { | 105 | func (w *FileLogWriter) startLogger() error { |
| 106 | fd, err := w.createLogFile() | 106 | fd, err := w.createLogFile() |
| 107 | if err != nil { | 107 | if err != nil { |
| 108 | return err | 108 | return err |
| ... | @@ -199,7 +199,7 @@ func (w *FileLogWriter) DoRotate() error { | ... | @@ -199,7 +199,7 @@ func (w *FileLogWriter) DoRotate() error { |
| 199 | } | 199 | } |
| 200 | 200 | ||
| 201 | // re-start logger | 201 | // re-start logger |
| 202 | err = w.StartLogger() | 202 | err = w.startLogger() |
| 203 | if err != nil { | 203 | if err != nil { |
| 204 | return fmt.Errorf("Rotate StartLogger: %s\n", err) | 204 | return fmt.Errorf("Rotate StartLogger: %s\n", err) |
| 205 | } | 205 | } | ... | ... |
| ... | @@ -2,6 +2,8 @@ package logs | ... | @@ -2,6 +2,8 @@ package logs |
| 2 | 2 | ||
| 3 | import ( | 3 | import ( |
| 4 | "fmt" | 4 | "fmt" |
| 5 | "path" | ||
| 6 | "runtime" | ||
| 5 | "sync" | 7 | "sync" |
| 6 | ) | 8 | ) |
| 7 | 9 | ||
| ... | @@ -43,10 +45,12 @@ func Register(name string, log loggerType) { | ... | @@ -43,10 +45,12 @@ func Register(name string, log loggerType) { |
| 43 | // BeeLogger is default logger in beego application. | 45 | // BeeLogger is default logger in beego application. |
| 44 | // it can contain several providers and log message into all providers. | 46 | // it can contain several providers and log message into all providers. |
| 45 | type BeeLogger struct { | 47 | type BeeLogger struct { |
| 46 | lock sync.Mutex | 48 | lock sync.Mutex |
| 47 | level int | 49 | level int |
| 48 | msg chan *logMsg | 50 | enableFuncCallDepth bool |
| 49 | outputs map[string]LoggerInterface | 51 | loggerFuncCallDepth int |
| 52 | msg chan *logMsg | ||
| 53 | outputs map[string]LoggerInterface | ||
| 50 | } | 54 | } |
| 51 | 55 | ||
| 52 | type logMsg struct { | 56 | type logMsg struct { |
| ... | @@ -59,10 +63,11 @@ type logMsg struct { | ... | @@ -59,10 +63,11 @@ type logMsg struct { |
| 59 | // if the buffering chan is full, logger adapters write to file or other way. | 63 | // if the buffering chan is full, logger adapters write to file or other way. |
| 60 | func NewLogger(channellen int64) *BeeLogger { | 64 | func NewLogger(channellen int64) *BeeLogger { |
| 61 | bl := new(BeeLogger) | 65 | bl := new(BeeLogger) |
| 66 | bl.loggerFuncCallDepth = 2 | ||
| 62 | bl.msg = make(chan *logMsg, channellen) | 67 | bl.msg = make(chan *logMsg, channellen) |
| 63 | bl.outputs = make(map[string]LoggerInterface) | 68 | bl.outputs = make(map[string]LoggerInterface) |
| 64 | //bl.SetLogger("console", "") // default output to console | 69 | //bl.SetLogger("console", "") // default output to console |
| 65 | go bl.StartLogger() | 70 | go bl.startLogger() |
| 66 | return bl | 71 | return bl |
| 67 | } | 72 | } |
| 68 | 73 | ||
| ... | @@ -73,7 +78,10 @@ func (bl *BeeLogger) SetLogger(adaptername string, config string) error { | ... | @@ -73,7 +78,10 @@ func (bl *BeeLogger) SetLogger(adaptername string, config string) error { |
| 73 | defer bl.lock.Unlock() | 78 | defer bl.lock.Unlock() |
| 74 | if log, ok := adapters[adaptername]; ok { | 79 | if log, ok := adapters[adaptername]; ok { |
| 75 | lg := log() | 80 | lg := log() |
| 76 | lg.Init(config) | 81 | err := lg.Init(config) |
| 82 | if err != nil { | ||
| 83 | return err | ||
| 84 | } | ||
| 77 | bl.outputs[adaptername] = lg | 85 | bl.outputs[adaptername] = lg |
| 78 | return nil | 86 | return nil |
| 79 | } else { | 87 | } else { |
| ... | @@ -100,7 +108,17 @@ func (bl *BeeLogger) writerMsg(loglevel int, msg string) error { | ... | @@ -100,7 +108,17 @@ func (bl *BeeLogger) writerMsg(loglevel int, msg string) error { |
| 100 | } | 108 | } |
| 101 | lm := new(logMsg) | 109 | lm := new(logMsg) |
| 102 | lm.level = loglevel | 110 | lm.level = loglevel |
| 103 | lm.msg = msg | 111 | if bl.enableFuncCallDepth { |
| 112 | _, file, line, ok := runtime.Caller(bl.loggerFuncCallDepth) | ||
| 113 | if ok { | ||
| 114 | _, filename := path.Split(file) | ||
| 115 | lm.msg = fmt.Sprintf("[%s:%d] %s", filename, line, msg) | ||
| 116 | } else { | ||
| 117 | lm.msg = msg | ||
| 118 | } | ||
| 119 | } else { | ||
| 120 | lm.msg = msg | ||
| 121 | } | ||
| 104 | bl.msg <- lm | 122 | bl.msg <- lm |
| 105 | return nil | 123 | return nil |
| 106 | } | 124 | } |
| ... | @@ -111,9 +129,19 @@ func (bl *BeeLogger) SetLevel(l int) { | ... | @@ -111,9 +129,19 @@ func (bl *BeeLogger) SetLevel(l int) { |
| 111 | bl.level = l | 129 | bl.level = l |
| 112 | } | 130 | } |
| 113 | 131 | ||
| 132 | // set log funcCallDepth | ||
| 133 | func (bl *BeeLogger) SetLogFuncCallDepth(d int) { | ||
| 134 | bl.loggerFuncCallDepth = d | ||
| 135 | } | ||
| 136 | |||
| 137 | // enable log funcCallDepth | ||
| 138 | func (bl *BeeLogger) EnableFuncCallDepth(b bool) { | ||
| 139 | bl.enableFuncCallDepth = b | ||
| 140 | } | ||
| 141 | |||
| 114 | // start logger chan reading. | 142 | // start logger chan reading. |
| 115 | // when chan is full, write logs. | 143 | // when chan is full, write logs. |
| 116 | func (bl *BeeLogger) StartLogger() { | 144 | func (bl *BeeLogger) startLogger() { |
| 117 | for { | 145 | for { |
| 118 | select { | 146 | select { |
| 119 | case bm := <-bl.msg: | 147 | case bm := <-bl.msg: | ... | ... |
| ... | @@ -51,9 +51,16 @@ outFor: | ... | @@ -51,9 +51,16 @@ outFor: |
| 51 | continue | 51 | continue |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | switch v := arg.(type) { | 54 | kind := val.Kind() |
| 55 | case []byte: | 55 | if kind == reflect.Ptr { |
| 56 | case string: | 56 | val = val.Elem() |
| 57 | kind = val.Kind() | ||
| 58 | arg = val.Interface() | ||
| 59 | } | ||
| 60 | |||
| 61 | switch kind { | ||
| 62 | case reflect.String: | ||
| 63 | v := val.String() | ||
| 57 | if fi != nil { | 64 | if fi != nil { |
| 58 | if fi.fieldType == TypeDateField || fi.fieldType == TypeDateTimeField { | 65 | if fi.fieldType == TypeDateField || fi.fieldType == TypeDateTimeField { |
| 59 | var t time.Time | 66 | var t time.Time |
| ... | @@ -78,61 +85,66 @@ outFor: | ... | @@ -78,61 +85,66 @@ outFor: |
| 78 | } | 85 | } |
| 79 | } | 86 | } |
| 80 | arg = v | 87 | arg = v |
| 81 | case time.Time: | 88 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: |
| 82 | if fi != nil && fi.fieldType == TypeDateField { | 89 | arg = val.Int() |
| 83 | arg = v.In(tz).Format(format_Date) | 90 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: |
| 84 | } else { | 91 | arg = val.Uint() |
| 85 | arg = v.In(tz).Format(format_DateTime) | 92 | case reflect.Float32: |
| 93 | arg, _ = StrTo(ToStr(arg)).Float64() | ||
| 94 | case reflect.Float64: | ||
| 95 | arg = val.Float() | ||
| 96 | case reflect.Bool: | ||
| 97 | arg = val.Bool() | ||
| 98 | case reflect.Slice, reflect.Array: | ||
| 99 | if _, ok := arg.([]byte); ok { | ||
| 100 | continue outFor | ||
| 86 | } | 101 | } |
| 87 | default: | ||
| 88 | kind := val.Kind() | ||
| 89 | switch kind { | ||
| 90 | case reflect.Slice, reflect.Array: | ||
| 91 | |||
| 92 | var args []interface{} | ||
| 93 | for i := 0; i < val.Len(); i++ { | ||
| 94 | v := val.Index(i) | ||
| 95 | |||
| 96 | var vu interface{} | ||
| 97 | if v.CanInterface() { | ||
| 98 | vu = v.Interface() | ||
| 99 | } | ||
| 100 | 102 | ||
| 101 | if vu == nil { | 103 | var args []interface{} |
| 102 | continue | 104 | for i := 0; i < val.Len(); i++ { |
| 103 | } | 105 | v := val.Index(i) |
| 104 | 106 | ||
| 105 | args = append(args, vu) | 107 | var vu interface{} |
| 108 | if v.CanInterface() { | ||
| 109 | vu = v.Interface() | ||
| 106 | } | 110 | } |
| 107 | 111 | ||
| 108 | if len(args) > 0 { | 112 | if vu == nil { |
| 109 | p := getFlatParams(fi, args, tz) | 113 | continue |
| 110 | params = append(params, p...) | ||
| 111 | } | 114 | } |
| 112 | continue outFor | ||
| 113 | 115 | ||
| 114 | case reflect.Ptr, reflect.Struct: | 116 | args = append(args, vu) |
| 115 | ind := reflect.Indirect(val) | 117 | } |
| 116 | 118 | ||
| 117 | if ind.Kind() == reflect.Struct { | 119 | if len(args) > 0 { |
| 118 | typ := ind.Type() | 120 | p := getFlatParams(fi, args, tz) |
| 119 | name := getFullName(typ) | 121 | params = append(params, p...) |
| 120 | var value interface{} | 122 | } |
| 121 | if mmi, ok := modelCache.getByFN(name); ok { | 123 | continue outFor |
| 122 | if _, vu, exist := getExistPk(mmi, ind); exist { | 124 | case reflect.Struct: |
| 123 | value = vu | 125 | if v, ok := arg.(time.Time); ok { |
| 124 | } | 126 | if fi != nil && fi.fieldType == TypeDateField { |
| 127 | arg = v.In(tz).Format(format_Date) | ||
| 128 | } else { | ||
| 129 | arg = v.In(tz).Format(format_DateTime) | ||
| 130 | } | ||
| 131 | } else { | ||
| 132 | typ := val.Type() | ||
| 133 | name := getFullName(typ) | ||
| 134 | var value interface{} | ||
| 135 | if mmi, ok := modelCache.getByFN(name); ok { | ||
| 136 | if _, vu, exist := getExistPk(mmi, val); exist { | ||
| 137 | value = vu | ||
| 125 | } | 138 | } |
| 126 | arg = value | 139 | } |
| 140 | arg = value | ||
| 127 | 141 | ||
| 128 | if arg == nil { | 142 | if arg == nil { |
| 129 | panic(fmt.Errorf("need a valid args value, unknown table or value `%s`", name)) | 143 | panic(fmt.Errorf("need a valid args value, unknown table or value `%s`", name)) |
| 130 | } | ||
| 131 | } else { | ||
| 132 | arg = ind.Interface() | ||
| 133 | } | 144 | } |
| 134 | } | 145 | } |
| 135 | } | 146 | } |
| 147 | |||
| 136 | params = append(params, arg) | 148 | params = append(params, arg) |
| 137 | } | 149 | } |
| 138 | return | 150 | return | ... | ... |
| ... | @@ -144,6 +144,45 @@ type DataNull struct { | ... | @@ -144,6 +144,45 @@ type DataNull struct { |
| 144 | NullInt64 sql.NullInt64 `orm:"null"` | 144 | NullInt64 sql.NullInt64 `orm:"null"` |
| 145 | } | 145 | } |
| 146 | 146 | ||
| 147 | type String string | ||
| 148 | type Boolean bool | ||
| 149 | type Byte byte | ||
| 150 | type Rune rune | ||
| 151 | type Int int | ||
| 152 | type Int8 int8 | ||
| 153 | type Int16 int16 | ||
| 154 | type Int32 int32 | ||
| 155 | type Int64 int64 | ||
| 156 | type Uint uint | ||
| 157 | type Uint8 uint8 | ||
| 158 | type Uint16 uint16 | ||
| 159 | type Uint32 uint32 | ||
| 160 | type Uint64 uint64 | ||
| 161 | type Float32 float64 | ||
| 162 | type Float64 float64 | ||
| 163 | |||
| 164 | type DataCustom struct { | ||
| 165 | Id int | ||
| 166 | Boolean Boolean | ||
| 167 | Char string `orm:"size(50)"` | ||
| 168 | Text string `orm:"type(text)"` | ||
| 169 | Byte Byte | ||
| 170 | Rune Rune | ||
| 171 | Int Int | ||
| 172 | Int8 Int8 | ||
| 173 | Int16 Int16 | ||
| 174 | Int32 Int32 | ||
| 175 | Int64 Int64 | ||
| 176 | Uint Uint | ||
| 177 | Uint8 Uint8 | ||
| 178 | Uint16 Uint16 | ||
| 179 | Uint32 Uint32 | ||
| 180 | Uint64 Uint64 | ||
| 181 | Float32 Float32 | ||
| 182 | Float64 Float64 | ||
| 183 | Decimal Float64 `orm:"digits(8);decimals(4)"` | ||
| 184 | } | ||
| 185 | |||
| 147 | // only for mysql | 186 | // only for mysql |
| 148 | type UserBig struct { | 187 | type UserBig struct { |
| 149 | Id uint64 | 188 | Id uint64 |
| ... | @@ -155,7 +194,7 @@ type User struct { | ... | @@ -155,7 +194,7 @@ type User struct { |
| 155 | UserName string `orm:"size(30);unique"` | 194 | UserName string `orm:"size(30);unique"` |
| 156 | Email string `orm:"size(100)"` | 195 | Email string `orm:"size(100)"` |
| 157 | Password string `orm:"size(100)"` | 196 | Password string `orm:"size(100)"` |
| 158 | Status int16 | 197 | Status int16 `orm:"column(Status)"` |
| 159 | IsStaff bool | 198 | IsStaff bool |
| 160 | IsActive bool `orm:"default(1)"` | 199 | IsActive bool `orm:"default(1)"` |
| 161 | Created time.Time `orm:"auto_now_add;type(date)"` | 200 | Created time.Time `orm:"auto_now_add;type(date)"` | ... | ... |
| ... | @@ -80,7 +80,6 @@ func getTableUnique(val reflect.Value) [][]string { | ... | @@ -80,7 +80,6 @@ func getTableUnique(val reflect.Value) [][]string { |
| 80 | 80 | ||
| 81 | // get snaked column name | 81 | // get snaked column name |
| 82 | func getColumnName(ft int, addrField reflect.Value, sf reflect.StructField, col string) string { | 82 | func getColumnName(ft int, addrField reflect.Value, sf reflect.StructField, col string) string { |
| 83 | col = strings.ToLower(col) | ||
| 84 | column := col | 83 | column := col |
| 85 | if col == "" { | 84 | if col == "" { |
| 86 | column = snakeString(sf.Name) | 85 | column = snakeString(sf.Name) |
| ... | @@ -99,34 +98,41 @@ func getColumnName(ft int, addrField reflect.Value, sf reflect.StructField, col | ... | @@ -99,34 +98,41 @@ func getColumnName(ft int, addrField reflect.Value, sf reflect.StructField, col |
| 99 | // return field type as type constant from reflect.Value | 98 | // return field type as type constant from reflect.Value |
| 100 | func getFieldType(val reflect.Value) (ft int, err error) { | 99 | func getFieldType(val reflect.Value) (ft int, err error) { |
| 101 | elm := reflect.Indirect(val) | 100 | elm := reflect.Indirect(val) |
| 102 | switch elm.Interface().(type) { | 101 | switch elm.Kind() { |
| 103 | case int8: | 102 | case reflect.Int8: |
| 104 | ft = TypeBitField | 103 | ft = TypeBitField |
| 105 | case int16: | 104 | case reflect.Int16: |
| 106 | ft = TypeSmallIntegerField | 105 | ft = TypeSmallIntegerField |
| 107 | case int32, int: | 106 | case reflect.Int32, reflect.Int: |
| 108 | ft = TypeIntegerField | 107 | ft = TypeIntegerField |
| 109 | case int64, sql.NullInt64: | 108 | case reflect.Int64: |
| 110 | ft = TypeBigIntegerField | 109 | ft = TypeBigIntegerField |
| 111 | case uint8: | 110 | case reflect.Uint8: |
| 112 | ft = TypePositiveBitField | 111 | ft = TypePositiveBitField |
| 113 | case uint16: | 112 | case reflect.Uint16: |
| 114 | ft = TypePositiveSmallIntegerField | 113 | ft = TypePositiveSmallIntegerField |
| 115 | case uint32, uint: | 114 | case reflect.Uint32, reflect.Uint: |
| 116 | ft = TypePositiveIntegerField | 115 | ft = TypePositiveIntegerField |
| 117 | case uint64: | 116 | case reflect.Uint64: |
| 118 | ft = TypePositiveBigIntegerField | 117 | ft = TypePositiveBigIntegerField |
| 119 | case float32, float64, sql.NullFloat64: | 118 | case reflect.Float32, reflect.Float64: |
| 120 | ft = TypeFloatField | 119 | ft = TypeFloatField |
| 121 | case bool, sql.NullBool: | 120 | case reflect.Bool: |
| 122 | ft = TypeBooleanField | 121 | ft = TypeBooleanField |
| 123 | case string, sql.NullString: | 122 | case reflect.String: |
| 124 | ft = TypeCharField | 123 | ft = TypeCharField |
| 125 | default: | 124 | default: |
| 126 | if elm.CanInterface() { | 125 | switch elm.Interface().(type) { |
| 127 | if _, ok := elm.Interface().(time.Time); ok { | 126 | case sql.NullInt64: |
| 128 | ft = TypeDateTimeField | 127 | ft = TypeBigIntegerField |
| 129 | } | 128 | case sql.NullFloat64: |
| 129 | ft = TypeFloatField | ||
| 130 | case sql.NullBool: | ||
| 131 | ft = TypeBooleanField | ||
| 132 | case sql.NullString: | ||
| 133 | ft = TypeCharField | ||
| 134 | case time.Time: | ||
| 135 | ft = TypeDateTimeField | ||
| 130 | } | 136 | } |
| 131 | } | 137 | } |
| 132 | if ft&IsFieldType == 0 { | 138 | if ft&IsFieldType == 0 { | ... | ... |
| ... | @@ -149,7 +149,7 @@ func TestGetDB(t *testing.T) { | ... | @@ -149,7 +149,7 @@ func TestGetDB(t *testing.T) { |
| 149 | } | 149 | } |
| 150 | 150 | ||
| 151 | func TestSyncDb(t *testing.T) { | 151 | func TestSyncDb(t *testing.T) { |
| 152 | RegisterModel(new(Data), new(DataNull)) | 152 | RegisterModel(new(Data), new(DataNull), new(DataCustom)) |
| 153 | RegisterModel(new(User)) | 153 | RegisterModel(new(User)) |
| 154 | RegisterModel(new(Profile)) | 154 | RegisterModel(new(Profile)) |
| 155 | RegisterModel(new(Post)) | 155 | RegisterModel(new(Post)) |
| ... | @@ -165,7 +165,7 @@ func TestSyncDb(t *testing.T) { | ... | @@ -165,7 +165,7 @@ func TestSyncDb(t *testing.T) { |
| 165 | } | 165 | } |
| 166 | 166 | ||
| 167 | func TestRegisterModels(t *testing.T) { | 167 | func TestRegisterModels(t *testing.T) { |
| 168 | RegisterModel(new(Data), new(DataNull)) | 168 | RegisterModel(new(Data), new(DataNull), new(DataCustom)) |
| 169 | RegisterModel(new(User)) | 169 | RegisterModel(new(User)) |
| 170 | RegisterModel(new(Profile)) | 170 | RegisterModel(new(Profile)) |
| 171 | RegisterModel(new(Post)) | 171 | RegisterModel(new(Post)) |
| ... | @@ -309,6 +309,39 @@ func TestNullDataTypes(t *testing.T) { | ... | @@ -309,6 +309,39 @@ func TestNullDataTypes(t *testing.T) { |
| 309 | throwFail(t, AssertIs(d.NullFloat64.Float64, 42.42)) | 309 | throwFail(t, AssertIs(d.NullFloat64.Float64, 42.42)) |
| 310 | } | 310 | } |
| 311 | 311 | ||
| 312 | func TestDataCustomTypes(t *testing.T) { | ||
| 313 | d := DataCustom{} | ||
| 314 | ind := reflect.Indirect(reflect.ValueOf(&d)) | ||
| 315 | |||
| 316 | for name, value := range Data_Values { | ||
| 317 | e := ind.FieldByName(name) | ||
| 318 | if !e.IsValid() { | ||
| 319 | continue | ||
| 320 | } | ||
| 321 | e.Set(reflect.ValueOf(value).Convert(e.Type())) | ||
| 322 | } | ||
| 323 | |||
| 324 | id, err := dORM.Insert(&d) | ||
| 325 | throwFail(t, err) | ||
| 326 | throwFail(t, AssertIs(id, 1)) | ||
| 327 | |||
| 328 | d = DataCustom{Id: 1} | ||
| 329 | err = dORM.Read(&d) | ||
| 330 | throwFail(t, err) | ||
| 331 | |||
| 332 | ind = reflect.Indirect(reflect.ValueOf(&d)) | ||
| 333 | |||
| 334 | for name, value := range Data_Values { | ||
| 335 | e := ind.FieldByName(name) | ||
| 336 | if !e.IsValid() { | ||
| 337 | continue | ||
| 338 | } | ||
| 339 | vu := e.Interface() | ||
| 340 | value = reflect.ValueOf(value).Convert(e.Type()).Interface() | ||
| 341 | throwFail(t, AssertIs(vu == value, true), value, vu) | ||
| 342 | } | ||
| 343 | } | ||
| 344 | |||
| 312 | func TestCRUD(t *testing.T) { | 345 | func TestCRUD(t *testing.T) { |
| 313 | profile := NewProfile() | 346 | profile := NewProfile() |
| 314 | profile.Age = 30 | 347 | profile.Age = 30 |
| ... | @@ -562,6 +595,10 @@ func TestOperators(t *testing.T) { | ... | @@ -562,6 +595,10 @@ func TestOperators(t *testing.T) { |
| 562 | throwFail(t, err) | 595 | throwFail(t, err) |
| 563 | throwFail(t, AssertIs(num, 1)) | 596 | throwFail(t, AssertIs(num, 1)) |
| 564 | 597 | ||
| 598 | num, err = qs.Filter("user_name__exact", String("slene")).Count() | ||
| 599 | throwFail(t, err) | ||
| 600 | throwFail(t, AssertIs(num, 1)) | ||
| 601 | |||
| 565 | num, err = qs.Filter("user_name__exact", "slene").Count() | 602 | num, err = qs.Filter("user_name__exact", "slene").Count() |
| 566 | throwFail(t, err) | 603 | throwFail(t, err) |
| 567 | throwFail(t, AssertIs(num, 1)) | 604 | throwFail(t, AssertIs(num, 1)) |
| ... | @@ -602,11 +639,11 @@ func TestOperators(t *testing.T) { | ... | @@ -602,11 +639,11 @@ func TestOperators(t *testing.T) { |
| 602 | throwFail(t, err) | 639 | throwFail(t, err) |
| 603 | throwFail(t, AssertIs(num, 3)) | 640 | throwFail(t, AssertIs(num, 3)) |
| 604 | 641 | ||
| 605 | num, err = qs.Filter("status__lt", 3).Count() | 642 | num, err = qs.Filter("status__lt", Uint(3)).Count() |
| 606 | throwFail(t, err) | 643 | throwFail(t, err) |
| 607 | throwFail(t, AssertIs(num, 2)) | 644 | throwFail(t, AssertIs(num, 2)) |
| 608 | 645 | ||
| 609 | num, err = qs.Filter("status__lte", 3).Count() | 646 | num, err = qs.Filter("status__lte", Int(3)).Count() |
| 610 | throwFail(t, err) | 647 | throwFail(t, err) |
| 611 | throwFail(t, AssertIs(num, 3)) | 648 | throwFail(t, AssertIs(num, 3)) |
| 612 | 649 | ||
| ... | @@ -1380,7 +1417,7 @@ func TestRawQueryRow(t *testing.T) { | ... | @@ -1380,7 +1417,7 @@ func TestRawQueryRow(t *testing.T) { |
| 1380 | ) | 1417 | ) |
| 1381 | 1418 | ||
| 1382 | cols = []string{ | 1419 | cols = []string{ |
| 1383 | "id", "status", "profile_id", | 1420 | "id", "Status", "profile_id", |
| 1384 | } | 1421 | } |
| 1385 | query = fmt.Sprintf("SELECT %s%s%s FROM %suser%s WHERE id = ?", Q, strings.Join(cols, sep), Q, Q, Q) | 1422 | query = fmt.Sprintf("SELECT %s%s%s FROM %suser%s WHERE id = ?", Q, strings.Join(cols, sep), Q, Q, Q) |
| 1386 | err = dORM.Raw(query, 4).QueryRow(&uid, &status, &pid) | 1423 | err = dORM.Raw(query, 4).QueryRow(&uid, &status, &pid) |
| ... | @@ -1460,7 +1497,7 @@ func TestRawValues(t *testing.T) { | ... | @@ -1460,7 +1497,7 @@ func TestRawValues(t *testing.T) { |
| 1460 | Q := dDbBaser.TableQuote() | 1497 | Q := dDbBaser.TableQuote() |
| 1461 | 1498 | ||
| 1462 | var maps []Params | 1499 | var maps []Params |
| 1463 | query := fmt.Sprintf("SELECT %suser_name%s FROM %suser%s WHERE %sstatus%s = ?", Q, Q, Q, Q, Q, Q) | 1500 | query := fmt.Sprintf("SELECT %suser_name%s FROM %suser%s WHERE %sStatus%s = ?", Q, Q, Q, Q, Q, Q) |
| 1464 | num, err := dORM.Raw(query, 1).Values(&maps) | 1501 | num, err := dORM.Raw(query, 1).Values(&maps) |
| 1465 | throwFail(t, err) | 1502 | throwFail(t, err) |
| 1466 | throwFail(t, AssertIs(num, 1)) | 1503 | throwFail(t, AssertIs(num, 1)) | ... | ... |
| ... | @@ -44,6 +44,11 @@ var ( | ... | @@ -44,6 +44,11 @@ var ( |
| 44 | "GetControllerAndAction"} | 44 | "GetControllerAndAction"} |
| 45 | ) | 45 | ) |
| 46 | 46 | ||
| 47 | // To append a slice's value into "exceptMethod", for controller's methods shouldn't reflect to AutoRouter | ||
| 48 | func ExceptMethodAppend(action string) { | ||
| 49 | exceptMethod = append(exceptMethod, action) | ||
| 50 | } | ||
| 51 | |||
| 47 | type controllerInfo struct { | 52 | type controllerInfo struct { |
| 48 | pattern string | 53 | pattern string |
| 49 | regex *regexp.Regexp | 54 | regex *regexp.Regexp |
| ... | @@ -621,29 +626,37 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) | ... | @@ -621,29 +626,37 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) |
| 621 | context.Input.Body() | 626 | context.Input.Body() |
| 622 | } | 627 | } |
| 623 | 628 | ||
| 629 | if context.Input.RunController != nil && context.Input.RunMethod != "" { | ||
| 630 | findrouter = true | ||
| 631 | runMethod = context.Input.RunMethod | ||
| 632 | runrouter = context.Input.RunController | ||
| 633 | } | ||
| 634 | |||
| 624 | //first find path from the fixrouters to Improve Performance | 635 | //first find path from the fixrouters to Improve Performance |
| 625 | for _, route := range p.fixrouters { | 636 | if !findrouter { |
| 626 | n := len(requestPath) | 637 | for _, route := range p.fixrouters { |
| 627 | if requestPath == route.pattern { | 638 | n := len(requestPath) |
| 628 | runMethod = p.getRunMethod(r.Method, context, route) | 639 | if requestPath == route.pattern { |
| 629 | if runMethod != "" { | 640 | runMethod = p.getRunMethod(r.Method, context, route) |
| 630 | runrouter = route.controllerType | 641 | if runMethod != "" { |
| 631 | findrouter = true | 642 | runrouter = route.controllerType |
| 632 | break | 643 | findrouter = true |
| 644 | break | ||
| 645 | } | ||
| 633 | } | 646 | } |
| 634 | } | 647 | // pattern /admin url /admin 200 /admin/ 200 |
| 635 | // pattern /admin url /admin 200 /admin/ 200 | 648 | // pattern /admin/ url /admin 301 /admin/ 200 |
| 636 | // pattern /admin/ url /admin 301 /admin/ 200 | 649 | if requestPath[n-1] != '/' && requestPath+"/" == route.pattern { |
| 637 | if requestPath[n-1] != '/' && requestPath+"/" == route.pattern { | 650 | http.Redirect(w, r, requestPath+"/", 301) |
| 638 | http.Redirect(w, r, requestPath+"/", 301) | 651 | goto Admin |
| 639 | goto Admin | 652 | } |
| 640 | } | 653 | if requestPath[n-1] == '/' && route.pattern+"/" == requestPath { |
| 641 | if requestPath[n-1] == '/' && route.pattern+"/" == requestPath { | 654 | runMethod = p.getRunMethod(r.Method, context, route) |
| 642 | runMethod = p.getRunMethod(r.Method, context, route) | 655 | if runMethod != "" { |
| 643 | if runMethod != "" { | 656 | runrouter = route.controllerType |
| 644 | runrouter = route.controllerType | 657 | findrouter = true |
| 645 | findrouter = true | 658 | break |
| 646 | break | 659 | } |
| 647 | } | 660 | } |
| 648 | } | 661 | } |
| 649 | } | 662 | } | ... | ... |
| ... | @@ -118,6 +118,7 @@ func (pder *CookieProvider) SessionInit(maxlifetime int64, config string) error | ... | @@ -118,6 +118,7 @@ func (pder *CookieProvider) SessionInit(maxlifetime int64, config string) error |
| 118 | if err != nil { | 118 | if err != nil { |
| 119 | return err | 119 | return err |
| 120 | } | 120 | } |
| 121 | pder.maxlifetime = maxlifetime | ||
| 121 | return nil | 122 | return nil |
| 122 | } | 123 | } |
| 123 | 124 | ... | ... |
session/sess_postgresql.go
0 → 100644
| 1 | package session | ||
| 2 | |||
| 3 | /* | ||
| 4 | |||
| 5 | beego session provider for postgresql | ||
| 6 | ------------------------------------- | ||
| 7 | |||
| 8 | depends on github.com/lib/pq: | ||
| 9 | |||
| 10 | go install github.com/lib/pq | ||
| 11 | |||
| 12 | |||
| 13 | needs this table in your database: | ||
| 14 | |||
| 15 | CREATE TABLE session ( | ||
| 16 | session_key char(64) NOT NULL, | ||
| 17 | session_data bytea, | ||
| 18 | session_expiry timestamp NOT NULL, | ||
| 19 | CONSTRAINT session_key PRIMARY KEY(session_key) | ||
| 20 | ); | ||
| 21 | |||
| 22 | |||
| 23 | will be activated with these settings in app.conf: | ||
| 24 | |||
| 25 | SessionOn = true | ||
| 26 | SessionProvider = postgresql | ||
| 27 | SessionSavePath = "user=a password=b dbname=c sslmode=disable" | ||
| 28 | SessionName = session | ||
| 29 | |||
| 30 | */ | ||
| 31 | |||
| 32 | import ( | ||
| 33 | "database/sql" | ||
| 34 | "net/http" | ||
| 35 | "sync" | ||
| 36 | "time" | ||
| 37 | _ "github.com/lib/pq" | ||
| 38 | ) | ||
| 39 | |||
| 40 | var postgresqlpder = &PostgresqlProvider{} | ||
| 41 | |||
| 42 | // postgresql session store | ||
| 43 | type PostgresqlSessionStore struct { | ||
| 44 | c *sql.DB | ||
| 45 | sid string | ||
| 46 | lock sync.RWMutex | ||
| 47 | values map[interface{}]interface{} | ||
| 48 | } | ||
| 49 | |||
| 50 | // set value in postgresql session. | ||
| 51 | // it is temp value in map. | ||
| 52 | func (st *PostgresqlSessionStore) Set(key, value interface{}) error { | ||
| 53 | st.lock.Lock() | ||
| 54 | defer st.lock.Unlock() | ||
| 55 | st.values[key] = value | ||
| 56 | return nil | ||
| 57 | } | ||
| 58 | |||
| 59 | // get value from postgresql session | ||
| 60 | func (st *PostgresqlSessionStore) Get(key interface{}) interface{} { | ||
| 61 | st.lock.RLock() | ||
| 62 | defer st.lock.RUnlock() | ||
| 63 | if v, ok := st.values[key]; ok { | ||
| 64 | return v | ||
| 65 | } else { | ||
| 66 | return nil | ||
| 67 | } | ||
| 68 | return nil | ||
| 69 | } | ||
| 70 | |||
| 71 | // delete value in postgresql session | ||
| 72 | func (st *PostgresqlSessionStore) Delete(key interface{}) error { | ||
| 73 | st.lock.Lock() | ||
| 74 | defer st.lock.Unlock() | ||
| 75 | delete(st.values, key) | ||
| 76 | return nil | ||
| 77 | } | ||
| 78 | |||
| 79 | // clear all values in postgresql session | ||
| 80 | func (st *PostgresqlSessionStore) Flush() error { | ||
| 81 | st.lock.Lock() | ||
| 82 | defer st.lock.Unlock() | ||
| 83 | st.values = make(map[interface{}]interface{}) | ||
| 84 | return nil | ||
| 85 | } | ||
| 86 | |||
| 87 | // get session id of this postgresql session store | ||
| 88 | func (st *PostgresqlSessionStore) SessionID() string { | ||
| 89 | return st.sid | ||
| 90 | } | ||
| 91 | |||
| 92 | // save postgresql session values to database. | ||
| 93 | // must call this method to save values to database. | ||
| 94 | func (st *PostgresqlSessionStore) SessionRelease(w http.ResponseWriter) { | ||
| 95 | defer st.c.Close() | ||
| 96 | b, err := encodeGob(st.values) | ||
| 97 | if err != nil { | ||
| 98 | return | ||
| 99 | } | ||
| 100 | st.c.Exec("UPDATE session set session_data=$1, session_expiry=$2 where session_key=$3", | ||
| 101 | b, time.Now().Format(time.RFC3339), st.sid) | ||
| 102 | |||
| 103 | } | ||
| 104 | |||
| 105 | // postgresql session provider | ||
| 106 | type PostgresqlProvider struct { | ||
| 107 | maxlifetime int64 | ||
| 108 | savePath string | ||
| 109 | } | ||
| 110 | |||
| 111 | // connect to postgresql | ||
| 112 | func (mp *PostgresqlProvider) connectInit() *sql.DB { | ||
| 113 | db, e := sql.Open("postgres", mp.savePath) | ||
| 114 | if e != nil { | ||
| 115 | return nil | ||
| 116 | } | ||
| 117 | return db | ||
| 118 | } | ||
| 119 | |||
| 120 | // init postgresql session. | ||
| 121 | // savepath is the connection string of postgresql. | ||
| 122 | func (mp *PostgresqlProvider) SessionInit(maxlifetime int64, savePath string) error { | ||
| 123 | mp.maxlifetime = maxlifetime | ||
| 124 | mp.savePath = savePath | ||
| 125 | return nil | ||
| 126 | } | ||
| 127 | |||
| 128 | // get postgresql session by sid | ||
| 129 | func (mp *PostgresqlProvider) SessionRead(sid string) (SessionStore, error) { | ||
| 130 | c := mp.connectInit() | ||
| 131 | row := c.QueryRow("select session_data from session where session_key=$1", sid) | ||
| 132 | var sessiondata []byte | ||
| 133 | err := row.Scan(&sessiondata) | ||
| 134 | if err == sql.ErrNoRows { | ||
| 135 | _, err = c.Exec("insert into session(session_key,session_data,session_expiry) values($1,$2,$3)", | ||
| 136 | sid, "", time.Now().Format(time.RFC3339)) | ||
| 137 | |||
| 138 | if err != nil { | ||
| 139 | return nil, err | ||
| 140 | } | ||
| 141 | } else if err != nil { | ||
| 142 | return nil, err | ||
| 143 | } | ||
| 144 | |||
| 145 | var kv map[interface{}]interface{} | ||
| 146 | if len(sessiondata) == 0 { | ||
| 147 | kv = make(map[interface{}]interface{}) | ||
| 148 | } else { | ||
| 149 | kv, err = decodeGob(sessiondata) | ||
| 150 | if err != nil { | ||
| 151 | return nil, err | ||
| 152 | } | ||
| 153 | } | ||
| 154 | rs := &PostgresqlSessionStore{c: c, sid: sid, values: kv} | ||
| 155 | return rs, nil | ||
| 156 | } | ||
| 157 | |||
| 158 | // check postgresql session exist | ||
| 159 | func (mp *PostgresqlProvider) SessionExist(sid string) bool { | ||
| 160 | c := mp.connectInit() | ||
| 161 | defer c.Close() | ||
| 162 | row := c.QueryRow("select session_data from session where session_key=$1", sid) | ||
| 163 | var sessiondata []byte | ||
| 164 | err := row.Scan(&sessiondata) | ||
| 165 | |||
| 166 | if err == sql.ErrNoRows { | ||
| 167 | return false | ||
| 168 | } else { | ||
| 169 | return true | ||
| 170 | } | ||
| 171 | } | ||
| 172 | |||
| 173 | // generate new sid for postgresql session | ||
| 174 | func (mp *PostgresqlProvider) SessionRegenerate(oldsid, sid string) (SessionStore, error) { | ||
| 175 | c := mp.connectInit() | ||
| 176 | row := c.QueryRow("select session_data from session where session_key=$1", oldsid) | ||
| 177 | var sessiondata []byte | ||
| 178 | err := row.Scan(&sessiondata) | ||
| 179 | if err == sql.ErrNoRows { | ||
| 180 | c.Exec("insert into session(session_key,session_data,session_expiry) values($1,$2,$3)", | ||
| 181 | oldsid, "", time.Now().Format(time.RFC3339)) | ||
| 182 | } | ||
| 183 | c.Exec("update session set session_key=$1 where session_key=$2", sid, oldsid) | ||
| 184 | var kv map[interface{}]interface{} | ||
| 185 | if len(sessiondata) == 0 { | ||
| 186 | kv = make(map[interface{}]interface{}) | ||
| 187 | } else { | ||
| 188 | kv, err = decodeGob(sessiondata) | ||
| 189 | if err != nil { | ||
| 190 | return nil, err | ||
| 191 | } | ||
| 192 | } | ||
| 193 | rs := &PostgresqlSessionStore{c: c, sid: sid, values: kv} | ||
| 194 | return rs, nil | ||
| 195 | } | ||
| 196 | |||
| 197 | // delete postgresql session by sid | ||
| 198 | func (mp *PostgresqlProvider) SessionDestroy(sid string) error { | ||
| 199 | c := mp.connectInit() | ||
| 200 | c.Exec("DELETE FROM session where session_key=$1", sid) | ||
| 201 | c.Close() | ||
| 202 | return nil | ||
| 203 | } | ||
| 204 | |||
| 205 | // delete expired values in postgresql session | ||
| 206 | func (mp *PostgresqlProvider) SessionGC() { | ||
| 207 | c := mp.connectInit() | ||
| 208 | c.Exec("DELETE from session where EXTRACT(EPOCH FROM (current_timestamp - session_expiry)) > $1", mp.maxlifetime) | ||
| 209 | c.Close() | ||
| 210 | return | ||
| 211 | } | ||
| 212 | |||
| 213 | // count values in postgresql session | ||
| 214 | func (mp *PostgresqlProvider) SessionAll() int { | ||
| 215 | c := mp.connectInit() | ||
| 216 | defer c.Close() | ||
| 217 | var total int | ||
| 218 | err := c.QueryRow("SELECT count(*) as num from session").Scan(&total) | ||
| 219 | if err != nil { | ||
| 220 | return 0 | ||
| 221 | } | ||
| 222 | return total | ||
| 223 | } | ||
| 224 | |||
| 225 | func init() { | ||
| 226 | Register("postgresql", postgresqlpder) | ||
| 227 | } |
| ... | @@ -151,7 +151,7 @@ func getTplDeep(root, file, parent string, t *template.Template) (*template.Temp | ... | @@ -151,7 +151,7 @@ func getTplDeep(root, file, parent string, t *template.Template) (*template.Temp |
| 151 | fileabspath = filepath.Join(root, file) | 151 | fileabspath = filepath.Join(root, file) |
| 152 | } | 152 | } |
| 153 | if e := utils.FileExists(fileabspath); !e { | 153 | if e := utils.FileExists(fileabspath); !e { |
| 154 | panic("can't find template file" + file) | 154 | panic("can't find template file:" + file) |
| 155 | } | 155 | } |
| 156 | data, err := ioutil.ReadFile(fileabspath) | 156 | data, err := ioutil.ReadFile(fileabspath) |
| 157 | if err != nil { | 157 | if err != nil { | ... | ... |
| ... | @@ -67,7 +67,7 @@ func (r Required) IsSatisfied(obj interface{}) bool { | ... | @@ -67,7 +67,7 @@ func (r Required) IsSatisfied(obj interface{}) bool { |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | func (r Required) DefaultMessage() string { | 69 | func (r Required) DefaultMessage() string { |
| 70 | return "Required" | 70 | return fmt.Sprint(MessageTmpls["Required"]) |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | func (r Required) GetKey() string { | 73 | func (r Required) GetKey() string { | ... | ... |
-
Please register or sign in to post a comment