fix issue in rebinding feature for grou router of ghttp.Server

This commit is contained in:
John
2020-03-24 19:48:10 +08:00
parent 8447b1a42b
commit 75054ee109
8 changed files with 165 additions and 37 deletions

View File

@ -8,7 +8,7 @@ package utils
import "strings"
// IsLetterUpper tests whether the given byte b is in upper case.
// IsLetterUpper checks whether the given byte b is in upper case.
func IsLetterUpper(b byte) bool {
if b >= byte('A') && b <= byte('Z') {
return true
@ -16,7 +16,7 @@ func IsLetterUpper(b byte) bool {
return false
}
// IsLetterLower tests whether the given byte b is in lower case.
// IsLetterLower checks whether the given byte b is in lower case.
func IsLetterLower(b byte) bool {
if b >= byte('a') && b <= byte('z') {
return true
@ -24,7 +24,12 @@ func IsLetterLower(b byte) bool {
return false
}
// IsNumeric tests whether the given string s is numeric.
// IsLetter checks whether the given byte b is a letter.
func IsLetter(b byte) bool {
return IsLetterUpper(b) || IsLetterLower(b)
}
// IsNumeric checks whether the given string s is numeric.
// Note that float string like "123.456" is also numeric.
func IsNumeric(s string) bool {
length := len(s)

View File

@ -38,12 +38,13 @@ type (
pattern string
object interface{} // Can be handler, controller or object.
params []interface{} // Extra parameters for route registering depending on the type.
source string // // Handler is register at certain source file path:line.
source string // Handler is register at certain source file path:line.
bound bool // Is this item bound to server.
}
)
var (
preBindItems = make([]preBindItem, 0, 64)
preBindItems = make([]*preBindItem, 0, 64)
)
// handlePreBindItems is called when server starts, which does really route registering to the server.
@ -52,6 +53,9 @@ func (s *Server) handlePreBindItems() {
return
}
for _, item := range preBindItems {
if item.bound {
continue
}
// Handle the items of current server.
if item.group.server != nil && item.group.server != s {
continue
@ -60,8 +64,8 @@ func (s *Server) handlePreBindItems() {
continue
}
item.group.doBindRoutersToServer(item)
item.bound = true
}
preBindItems = preBindItems[:0]
}
// Group creates and returns a RouterGroup object.
@ -238,7 +242,7 @@ func (g *RouterGroup) Middleware(handlers ...HandlerFunc) *RouterGroup {
// preBindToLocalArray adds the route registering parameters to internal variable array for lazily registering feature.
func (g *RouterGroup) preBindToLocalArray(bindType string, pattern string, object interface{}, params ...interface{}) *RouterGroup {
_, file, line := gdebug.CallerWithFilter(gFILTER_KEY)
preBindItems = append(preBindItems, preBindItem{
preBindItems = append(preBindItems, &preBindItem{
group: g,
bindType: bindType,
pattern: pattern,
@ -261,7 +265,7 @@ func (g *RouterGroup) getPrefix() string {
}
// doBindRoutersToServer does really registering for the group.
func (g *RouterGroup) doBindRoutersToServer(item preBindItem) *RouterGroup {
func (g *RouterGroup) doBindRoutersToServer(item *preBindItem) *RouterGroup {
var (
bindType = item.bindType
pattern = item.pattern

View File

@ -214,3 +214,38 @@ func Test_Router_Group_Mthods(t *testing.T) {
t.Assert(client.GetContent("/obj/delete"), "1Object Delete2")
})
}
func Test_Router_Group_MultiServer(t *testing.T) {
p1 := ports.PopRand()
p2 := ports.PopRand()
s1 := g.Server(p1)
s2 := g.Server(p2)
s1.Group("/", func(group *ghttp.RouterGroup) {
group.POST("/post", func(r *ghttp.Request) {
r.Response.Write("post1")
})
})
s2.Group("/", func(group *ghttp.RouterGroup) {
group.POST("/post", func(r *ghttp.Request) {
r.Response.Write("post2")
})
})
s1.SetPort(p1)
s2.SetPort(p2)
s1.SetDumpRouterMap(false)
s2.SetDumpRouterMap(false)
gtest.Assert(s1.Start(), nil)
gtest.Assert(s2.Start(), nil)
defer s1.Shutdown()
defer s2.Shutdown()
time.Sleep(100 * time.Millisecond)
gtest.C(t, func(t *gtest.T) {
c1 := ghttp.NewClient()
c1.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", p1))
c2 := ghttp.NewClient()
c2.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", p2))
t.Assert(c1.PostContent("/post"), "post1")
t.Assert(c2.PostContent("/post"), "post2")
})
}

View File

@ -9,6 +9,8 @@ package gfile
import (
"fmt"
"os"
"strconv"
"strings"
)
// Size returns the size of file specified by <path> in byte.
@ -25,50 +27,100 @@ func ReadableSize(path string) string {
return FormatSize(Size(path))
}
// StrToSize converts formatted size string to its size in bytes from Bytes to BrontoByte.
func StrToSize(sizeStr string) int64 {
i := 0
for ; i < len(sizeStr); i++ {
if sizeStr[i] == '.' || (sizeStr[i] >= '0' && sizeStr[i] <= '9') {
continue
} else {
break
}
}
var (
unit = sizeStr[i:]
number, _ = strconv.ParseFloat(sizeStr[:i], 64)
)
if unit == "" {
return int64(number)
}
switch strings.ToLower(unit) {
case "b", "bytes":
return int64(number)
case "k", "kb", "kib", "kilobyte":
return int64(number * 1024)
case "m", "mb", "mib", "mebibyte":
return int64(number * 1024 * 1024)
case "g", "gb", "gib", "gigabyte":
return int64(number * 1024 * 1024 * 1024)
case "t", "tb", "tib", "terabyte":
return int64(number * 1024 * 1024 * 1024 * 1024)
case "p", "pb", "pib", "petabyte":
return int64(number * 1024 * 1024 * 1024 * 1024 * 1024)
case "e", "eb", "eib", "exabyte":
return int64(number * 1024 * 1024 * 1024 * 1024 * 1024 * 1024)
case "z", "zb", "zib", "zettabyte":
return int64(number * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024)
case "y", "yb", "yib", "yottabyte":
return int64(number * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024)
case "bb", "brontobyte":
return int64(number * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024)
}
return -1
}
// FormatSize formats size <raw> for more human readable.
func FormatSize(raw int64) string {
var r float64 = float64(raw)
var t float64 = 1024
var d float64 = 1
if r < t {
return fmt.Sprintf("%.2fB", r/d)
}
d *= 1024
t *= 1024
if r < t {
return fmt.Sprintf("%.2fK", r/d)
}
d *= 1024
t *= 1024
if r < t {
return fmt.Sprintf("%.2fM", r/d)
}
d *= 1024
t *= 1024
if r < t {
return fmt.Sprintf("%.2fG", r/d)
}
d *= 1024
t *= 1024
if r < t {
return fmt.Sprintf("%.2fT", r/d)
}
d *= 1024
t *= 1024
if r < t {
return fmt.Sprintf("%.2fP", r/d)
}
d *= 1024
t *= 1024
if r < t {
return fmt.Sprintf("%.2fE", r/d)
}
d *= 1024
t *= 1024
if r < t {
return fmt.Sprintf("%.2fZ", r/d)
}
d *= 1024
t *= 1024
if r < t {
return fmt.Sprintf("%.2fY", r/d)
}
d *= 1024
t *= 1024
if r < t {
return fmt.Sprintf("%.2fBB", r/d)
}
return "TooLarge"
}

View File

@ -7,6 +7,7 @@
package gfile_test
import (
"github.com/gogf/gf/util/gconv"
"testing"
"github.com/gogf/gf/os/gfile"
@ -32,6 +33,25 @@ func Test_Size(t *testing.T) {
})
}
func Test_StrToSize(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
t.Assert(gfile.StrToSize("0.00B"), 0)
t.Assert(gfile.StrToSize("16.00B"), 16)
t.Assert(gfile.StrToSize("1.00K"), 1024)
t.Assert(gfile.StrToSize("1.00KB"), 1024)
t.Assert(gfile.StrToSize("1.00KiloByte"), 1024)
t.Assert(gfile.StrToSize("15.26M"), gconv.Int64(15.26*1024*1024))
t.Assert(gfile.StrToSize("15.26MB"), gconv.Int64(15.26*1024*1024))
t.Assert(gfile.StrToSize("1.49G"), gconv.Int64(1.49*1024*1024*1024))
t.Assert(gfile.StrToSize("1.49GB"), gconv.Int64(1.49*1024*1024*1024))
t.Assert(gfile.StrToSize("8.73T"), gconv.Int64(8.73*1024*1024*1024*1024))
t.Assert(gfile.StrToSize("8.73TB"), gconv.Int64(8.73*1024*1024*1024*1024))
t.Assert(gfile.StrToSize("8.53P"), gconv.Int64(8.53*1024*1024*1024*1024*1024))
t.Assert(gfile.StrToSize("8.53PB"), gconv.Int64(8.53*1024*1024*1024*1024*1024))
t.Assert(gfile.StrToSize("8.01EB"), gconv.Int64(8.01*1024*1024*1024*1024*1024*1024))
})
}
func Test_FormatSize(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
t.Assert(gfile.FormatSize(0), "0.00B")

View File

@ -78,7 +78,7 @@ func (l *Logger) Clone() *Logger {
// getFilePointer returns the file pinter for file logging.
// It returns nil if file logging is disabled, or file opening fails.
func (l *Logger) getFilePointer() *gfpool.File {
func (l *Logger) getFilePointer(now time.Time) *gfpool.File {
if path := l.config.Path; path != "" {
// Create path if it does not exist.
if !gfile.Exists(path) {
@ -88,7 +88,7 @@ func (l *Logger) getFilePointer() *gfpool.File {
}
}
if fp, err := gfpool.Open(
l.getFilePath(),
l.getFilePath(now),
gDEFAULT_FILE_POOL_FLAGS,
gDEFAULT_FPOOL_PERM,
gDEFAULT_FPOOL_EXPIRE); err == nil {
@ -101,17 +101,20 @@ func (l *Logger) getFilePointer() *gfpool.File {
}
// getFilePath returns the logging file path.
func (l *Logger) getFilePath() string {
func (l *Logger) getFilePath(now time.Time) string {
// Content containing "{}" in the file name is formatted using gtime.
file, _ := gregex.ReplaceStringFunc(`{.+?}`, l.config.File, func(s string) string {
return gtime.Now().Format(strings.Trim(s, "{}"))
return gtime.New(now).Format(strings.Trim(s, "{}"))
})
return gfile.Join(l.config.Path, file)
}
// print prints <s> to defined writer, logging file or passed <std>.
func (l *Logger) print(std io.Writer, lead string, value ...interface{}) {
buffer := bytes.NewBuffer(nil)
var (
now = time.Now()
buffer = bytes.NewBuffer(nil)
)
if l.config.HeaderPrint {
// Time.
timeFormat := ""
@ -125,7 +128,7 @@ func (l *Logger) print(std io.Writer, lead string, value ...interface{}) {
timeFormat += "15:04:05.000 "
}
if len(timeFormat) > 0 {
buffer.WriteString(time.Now().Format(timeFormat))
buffer.WriteString(now.Format(timeFormat))
}
// Lead string.
if len(lead) > 0 {
@ -179,20 +182,20 @@ func (l *Logger) print(std io.Writer, lead string, value ...interface{}) {
buffer.WriteString(valueStr + "\n")
if l.config.Flags&F_ASYNC > 0 {
err := asyncPool.Add(func() {
l.printToWriter(std, buffer)
l.printToWriter(now, std, buffer)
})
if err != nil {
intlog.Error(err)
}
} else {
l.printToWriter(std, buffer)
l.printToWriter(now, std, buffer)
}
}
// printToWriter writes buffer to writer.
func (l *Logger) printToWriter(std io.Writer, buffer *bytes.Buffer) {
func (l *Logger) printToWriter(now time.Time, std io.Writer, buffer *bytes.Buffer) {
if l.config.Writer == nil {
if f := l.getFilePointer(); f != nil {
if f := l.getFilePointer(now); f != nil {
defer f.Close()
// Rotation file size checks.
if l.config.RotateSize > 0 {
@ -201,8 +204,8 @@ func (l *Logger) printToWriter(std io.Writer, buffer *bytes.Buffer) {
panic(err)
}
if state.Size() > l.config.RotateSize {
l.rotateFile()
l.printToWriter(std, buffer)
l.rotateFile(now)
l.printToWriter(now, std, buffer)
return
}
}

View File

@ -80,7 +80,7 @@ func (l *Logger) SetConfigWithMap(m map[string]interface{}) error {
return errors.New("configuration cannot be empty")
}
// Change string configuration to int value for level.
levelKey, levelValue := gutil.MapPossibleItemByKey(m, "level")
levelKey, levelValue := gutil.MapPossibleItemByKey(m, "Level")
if levelValue != nil {
if level, ok := levelStringMap[strings.ToUpper(gconv.String(levelValue))]; ok {
m[levelKey] = level
@ -88,6 +88,14 @@ func (l *Logger) SetConfigWithMap(m map[string]interface{}) error {
return errors.New(fmt.Sprintf(`invalid level string: %v`, levelValue))
}
}
// Change string configuration to int value for file rotation size.
rotateSizeKey, rotateSizeValue := gutil.MapPossibleItemByKey(m, "RotateSize")
if rotateSizeValue != nil {
m[rotateSizeKey] = gfile.StrToSize(gconv.String(rotateSizeValue))
if m[rotateSizeKey] == -1 {
return errors.New(fmt.Sprintf(`invalid rotate size: %v`, rotateSizeValue))
}
}
config := DefaultConfig()
err := gconv.Struct(m, &config)
if err != nil {

View File

@ -15,17 +15,18 @@ import (
"github.com/gogf/gf/os/gtime"
"github.com/gogf/gf/os/gtimer"
"github.com/gogf/gf/text/gregex"
"time"
)
// rotateFile rotates the current logging file.
func (l *Logger) rotateFile() {
func (l *Logger) rotateFile(now time.Time) {
// Rotation feature is not enabled as rotation file size is zero.
if l.config.RotateSize == 0 {
if l.config.RotateSize <= 0 {
return
}
l.mu.Lock()
defer l.mu.Unlock()
filePath := l.getFilePath()
filePath := l.getFilePath(now)
// No backups, it then just removes the current logging file.
if l.config.RotateBackups == 0 {
if err := gfile.Remove(filePath); err != nil {
@ -66,7 +67,7 @@ func (l *Logger) rotateChecks() {
}()
// Checks whether file rotation not enabled.
if l.config.RotateSize == 0 || l.config.RotateBackups == 0 {
if l.config.RotateSize <= 0 || l.config.RotateBackups == 0 {
return
}
files, _ := gfile.ScanDirFile(l.config.Path, "*.*", true)