mirror of
https://gitee.com/johng/gf
synced 2026-06-06 02:25:47 +08:00
fix issue in rebinding feature for grou router of ghttp.Server
This commit is contained in:
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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")
|
||||
})
|
||||
}
|
||||
|
||||
@ -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"
|
||||
}
|
||||
|
||||
@ -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")
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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)
|
||||
|
||||
Reference in New Issue
Block a user