diff --git a/entry/http/context.go b/entry/http/context.go index 18cb232..3b5ae7a 100644 --- a/entry/http/context.go +++ b/entry/http/context.go @@ -14,6 +14,15 @@ var ( defaultBinder = &DefaultBinder{} ) +var ( + realIPHeaders = []string{ + "Cf-Connecting-Ip", + "True-Client-IP", + "X-Forwarded-For", + "X-Real-Ip", + } +) + type Context struct { ctx context.Context req *http.Request @@ -28,18 +37,21 @@ func (ctx *Context) reset(req *http.Request, res http.ResponseWriter, ps map[str } func (ctx *Context) RealIp() string { - if ip := ctx.Request().Header.Get("X-Forwarded-For"); ip != "" { - i := strings.IndexAny(ip, ",") - if i > 0 { - return strings.TrimSpace(ip[:i]) + var ( + pos int + ipaddr string + ) + for _, h := range realIPHeaders { + if ipaddr = ctx.Request().Header.Get(h); ipaddr != "" { + goto __end } - return ip } - if ip := ctx.Request().Header.Get("X-Real-IP"); ip != "" { - return ip + ipaddr, _, _ = net.SplitHostPort(ctx.Request().RemoteAddr) +__end: + if pos = strings.LastIndexByte(ipaddr, ','); pos > -1 { + ipaddr = ipaddr[:pos] } - ra, _, _ := net.SplitHostPort(ctx.Request().RemoteAddr) - return ra + return ipaddr } func (ctx *Context) Request() *http.Request { @@ -76,7 +88,7 @@ func (ctx *Context) Param(k string) string { return ctx.Request().FormValue(k) } -func (ctx *Context) send(res responsePayload) (err error) { +func (ctx *Context) json(res responsePayload) (err error) { ctx.Response().Header().Set("Content-Type", "application/json") encoder := json.NewEncoder(ctx.Response()) if strings.HasPrefix(ctx.Request().Header.Get("User-Agent"), "curl") { @@ -86,7 +98,7 @@ func (ctx *Context) send(res responsePayload) (err error) { } func (ctx *Context) Success(v any) (err error) { - return ctx.send(responsePayload{Data: v}) + return ctx.json(responsePayload{Data: v}) } func (ctx *Context) Status(code int) { @@ -94,7 +106,7 @@ func (ctx *Context) Status(code int) { } func (ctx *Context) Error(code int, reason string) (err error) { - return ctx.send(responsePayload{Code: code, Reason: reason}) + return ctx.json(responsePayload{Code: code, Reason: reason}) } func (ctx *Context) Redirect(url string, code int) { diff --git a/instance.go b/instance.go index 5feedea..509ef45 100644 --- a/instance.go +++ b/instance.go @@ -3,6 +3,8 @@ package kos import ( "git.nspix.com/golang/kos/entry/cli" "git.nspix.com/golang/kos/entry/http" + _ "git.nspix.com/golang/kos/pkg/request" + _ "git.nspix.com/golang/kos/util/bs" _ "git.nspix.com/golang/kos/util/fetch" _ "git.nspix.com/golang/kos/util/random" _ "git.nspix.com/golang/kos/util/reflection" diff --git a/options.go b/options.go index 8fe679f..c218500 100644 --- a/options.go +++ b/options.go @@ -92,6 +92,6 @@ func NewOptions() *Options { Signals: []os.Signal{syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGKILL}, } opts.Port = int(env.Integer(18080, EnvAppPort, "HTTP_PORT", "KOS_PORT")) - opts.Address = env.Get(EnvAppAddress, ip.Internal()) + opts.Address = env.Getter(ip.Internal(), EnvAppAddress, "KOS_ADDRESS") return opts } diff --git a/pkg/log/console.go b/pkg/log/console.go index b53d77c..9711a40 100644 --- a/pkg/log/console.go +++ b/pkg/log/console.go @@ -2,6 +2,8 @@ package log import ( "fmt" + "git.nspix.com/golang/kos/util/env" + "strconv" "time" ) @@ -16,10 +18,23 @@ const ( FG_GREY = 37 ) +var ( + levelColor = map[int]int{ + TraceLevel: FG_GREY, + DebugLevel: FG_BLUE, + InfoLevel: FG_GREEN, + WarnLevel: FG_PURPLE, + ErrorLevel: FG_RED, + FatalLevel: FG_RED, + PanicLevel: FG_RED, + } +) + type Console struct { - Level int - EnableColor int - prefix string + Level int + DisableColor bool + DisableTime bool + prefix string } func (log *Console) SetLevel(lv int) { @@ -87,32 +102,29 @@ func (log *Console) Panicf(format string, args ...interface{}) { } func (log *Console) write(level int, s string) { + var ls string if log.Level > level { return } - lvColor := map[int]int{ - TraceLevel: FG_GREY, - DebugLevel: FG_BLUE, - InfoLevel: FG_GREEN, - WarnLevel: FG_PURPLE, - ErrorLevel: FG_RED, - FatalLevel: FG_RED, - PanicLevel: FG_RED, - } - var ls string - if log.EnableColor > 0 { - ls = fmt.Sprintf("\033[0m\033[%dm[%s]\033[0m", lvColor[level], getLevelText(level)) - } else { + if log.DisableColor { ls = getLevelText(level) + } else { + ls = fmt.Sprintf("\033[0m\033[%dm[%s]\033[0m", levelColor[level], getLevelText(level)) } if log.prefix != "" { ls += " [" + log.prefix + "]" } - fmt.Println(time.Now().Format("2006-01-02 15:04:05") + " " + ls + " " + s) + if log.DisableTime { + fmt.Println(ls + " " + s) + } else { + fmt.Println(time.Now().Format("2006-01-02 15:04:05") + " " + ls + " " + s) + } + } func NewConsoleLogger() *Console { - return &Console{ - EnableColor: 1, - } + lg := &Console{} + lg.DisableColor, _ = strconv.ParseBool(env.Get("VOX_DISABLE_LOG_COLOR", "false")) + lg.DisableTime, _ = strconv.ParseBool(env.Get("VOX_DISABLE_LOG_DATETIME", "false")) + return lg } diff --git a/util/bs/safe.go b/util/bs/safe.go new file mode 100644 index 0000000..1d8415a --- /dev/null +++ b/util/bs/safe.go @@ -0,0 +1,12 @@ +//go:build appengine +// +build appengine + +package bs + +func BytesToString(b []byte) string { + return string(b) +} + +func StringToBytes(s string) []byte { + return []byte(s) +} diff --git a/util/bs/unsafe.go b/util/bs/unsafe.go new file mode 100644 index 0000000..5a724aa --- /dev/null +++ b/util/bs/unsafe.go @@ -0,0 +1,23 @@ +//go:build !appengine +// +build !appengine + +package bs + +import ( + "unsafe" +) + +// BytesToString converts byte slice to string. +func BytesToString(b []byte) string { + return *(*string)(unsafe.Pointer(&b)) +} + +// StringToBytes converts string to byte slice. +func StringToBytes(s string) []byte { + return *(*[]byte)(unsafe.Pointer( + &struct { + string + Cap int + }{s, len(s)}, + )) +} diff --git a/util/reflect/reflect.go b/util/reflect/reflect.go index 4efca96..43289eb 100644 --- a/util/reflect/reflect.go +++ b/util/reflect/reflect.go @@ -7,35 +7,34 @@ import ( "strings" ) +var ( + allowTags = []string{"json", "yaml", "xml", "name"} +) + func findField(v reflect.Value, field string) reflect.Value { var ( pos int tagValue string - refValue reflect.Value refType reflect.Type fieldType reflect.StructField - allowTags = []string{"json", "yaml", "xml"} ) - refValue = v.FieldByName(field) - if !refValue.IsValid() { - refType = v.Type() - for i := 0; i < refType.NumField(); i++ { - fieldType = refType.Field(i) - for _, tagName := range allowTags { - tagValue = fieldType.Tag.Get(tagName) - if tagValue == "" { - continue - } - if pos = strings.Index(tagValue, ","); pos != -1 { - tagValue = tagValue[:pos] - } - if tagValue == field { - return v.Field(i) - } + refType = v.Type() + for i := 0; i < refType.NumField(); i++ { + fieldType = refType.Field(i) + for _, tagName := range allowTags { + tagValue = fieldType.Tag.Get(tagName) + if tagValue == "" { + continue + } + if pos = strings.IndexByte(tagValue, ','); pos != -1 { + tagValue = tagValue[:pos] + } + if tagValue == field { + return v.Field(i) } } } - return refValue + return v.FieldByName(field) } func safeAssignment(variable reflect.Value, value interface{}) (err error) {