diff --git a/encoding/gbase64/gbase64.go b/encoding/gbase64/gbase64.go index 0a01680ff..77db9cdb4 100644 --- a/encoding/gbase64/gbase64.go +++ b/encoding/gbase64/gbase64.go @@ -25,8 +25,13 @@ func Decode(dst []byte) ([]byte, error) { return src[:n], err } -// EncodeString encodes bytes with BASE64 algorithm. -func EncodeString(src []byte) string { +// EncodeString encodes string with BASE64 algorithm. +func EncodeString(src string) string { + return EncodeToString([]byte(src)) +} + +// EncodeToString encodes bytes to string with BASE64 algorithm. +func EncodeToString(src []byte) string { return string(Encode(src)) } @@ -34,3 +39,9 @@ func EncodeString(src []byte) string { func DecodeString(str string) ([]byte, error) { return Decode([]byte(str)) } + +// DecodeString decodes string with BASE64 algorithm. +func DecodeToString(str string) (string, error) { + b, err := DecodeString(str) + return string(b), err +} diff --git a/encoding/gyaml/gyaml.go b/encoding/gyaml/gyaml.go index 577b6690d..e1fbf8864 100644 --- a/encoding/gyaml/gyaml.go +++ b/encoding/gyaml/gyaml.go @@ -10,25 +10,24 @@ package gyaml import ( "encoding/json" + "github.com/gf-third/yaml" "github.com/gogf/gf/util/gconv" - - yaml3 "github.com/gf-third/yaml/v3" ) func Encode(v interface{}) ([]byte, error) { - return yaml3.Marshal(v) + return yaml.Marshal(v) } func Decode(v []byte) (interface{}, error) { var result map[string]interface{} - if err := yaml3.Unmarshal(v, &result); err != nil { + if err := yaml.Unmarshal(v, &result); err != nil { return nil, err } return gconv.MapDeep(result), nil } func DecodeTo(v []byte, result interface{}) error { - return yaml3.Unmarshal(v, result) + return yaml.Unmarshal(v, result) } func ToJson(v []byte) ([]byte, error) { diff --git a/go.mod b/go.mod index 5c5d25b54..bbd2da087 100644 --- a/go.mod +++ b/go.mod @@ -6,16 +6,13 @@ require ( github.com/fatih/structs v1.1.0 github.com/fsnotify/fsnotify v1.4.7 github.com/gf-third/mysql v1.4.2 - github.com/gf-third/yaml/v3 v3.0.0 - github.com/gofrs/flock v0.7.1 // indirect + github.com/gf-third/yaml v1.0.1 github.com/gomodule/redigo v2.0.0+incompatible github.com/gorilla/websocket v1.4.1 - github.com/grokify/html-strip-tags-go v0.0.0-20190916062342-6f856a90d556 + github.com/grokify/html-strip-tags-go v0.0.0-20190921062105-daaa06bf1aaf github.com/mattn/go-runewidth v0.0.4 // indirect github.com/olekukonko/tablewriter v0.0.1 - github.com/theckman/go-flock v0.7.1 - golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3 // indirect + golang.org/x/sys v0.0.0-20190924092210-98129a5cf4a0 // indirect golang.org/x/text v0.3.2 - google.golang.org/appengine v1.6.2 // indirect - gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect + google.golang.org/appengine v1.6.3 // indirect ) diff --git a/net/ghttp/ghttp_request.go b/net/ghttp/ghttp_request.go index 509593c09..89afaa1c8 100644 --- a/net/ghttp/ghttp_request.go +++ b/net/ghttp/ghttp_request.go @@ -65,7 +65,7 @@ func newRequest(s *Server, r *http.Request, w http.ResponseWriter) *Request { // 会话处理 request.Cookie = GetCookie(request) request.Session = s.sessionManager.New(request.GetSessionId()) - request.Response.request = request + request.Response.Request = request request.Middleware = &Middleware{ request: request, } @@ -108,8 +108,8 @@ func (r *Request) GetRawString() string { } // 获取原始json请求输入字符串,并解析为json对象 -func (r *Request) GetJson() *gjson.Json { - return gjson.New(r.GetRaw()) +func (r *Request) GetJson() (*gjson.Json, error) { + return gjson.LoadJson(r.GetRaw()) } func (r *Request) GetString(key string, def ...interface{}) string { diff --git a/net/ghttp/ghttp_response.go b/net/ghttp/ghttp_response.go index fbc13a4f4..0e324f438 100644 --- a/net/ghttp/ghttp_response.go +++ b/net/ghttp/ghttp_response.go @@ -23,22 +23,22 @@ import ( // 服务端请求返回对象。 // 注意该对象并没有实现http.ResponseWriter接口,而是依靠ghttp.ResponseWriter实现。 type Response struct { - ResponseWriter - Server *Server // 所属Web Server - Writer *ResponseWriter // ResponseWriter的别名 - request *Request // 关联的Request请求对象 + *ResponseWriter // Underlying ResponseWriter. + Server *Server // Parent server. + Writer *ResponseWriter // Alias of ResponseWriter. + Request *Request // According request. } // 创建一个ghttp.Response对象指针 func newResponse(s *Server, w http.ResponseWriter) *Response { r := &Response{ Server: s, - ResponseWriter: ResponseWriter{ - ResponseWriter: w, - buffer: bytes.NewBuffer(nil), + ResponseWriter: &ResponseWriter{ + writer: w, + buffer: bytes.NewBuffer(nil), }, } - r.Writer = &r.ResponseWriter + r.Writer = r.ResponseWriter return r } @@ -47,7 +47,7 @@ func (r *Response) Write(content ...interface{}) { if len(content) == 0 { return } - if r.Status == 0 && r.request.hasServeHandler { + if r.Status == 0 && r.Request.hasServeHandler { r.Status = http.StatusOK } for _, v := range content { @@ -99,7 +99,7 @@ func (r *Response) WriteJsonP(content interface{}) error { return err } else { //r.Header().Set("Content-Type", "application/json") - if callback := r.request.GetString("callback"); callback != "" { + if callback := r.Request.GetString("callback"); callback != "" { buffer := []byte(callback) buffer = append(buffer, byte('(')) buffer = append(buffer, b...) @@ -128,9 +128,9 @@ func (r *Response) WriteStatus(status int, content ...interface{}) { if r.buffer.Len() == 0 { // 状态码注册回调函数处理 if status != http.StatusOK { - if f := r.request.Server.getStatusHandler(status, r.request); f != nil { + if f := r.Request.Server.getStatusHandler(status, r.Request); f != nil { niceCallFunc(func() { - f(r.request) + f(r.Request) }) // 防止多次设置(http: multiple response.WriteHeader calls) if r.Status == 0 { @@ -168,7 +168,7 @@ func (r *Response) ServeFile(path string, allowIndex ...bool) { } serveFile = &staticServeFile{path: path} } - r.Server.serveFile(r.request, serveFile, allowIndex...) + r.Server.serveFile(r.Request, serveFile, allowIndex...) } // 静态文件下载处理 @@ -200,7 +200,7 @@ func (r *Response) ServeFileDownload(path string, name ...string) { r.Header().Set("Content-Type", "application/force-download") r.Header().Set("Accept-Ranges", "bytes") r.Header().Set("Content-Disposition", fmt.Sprintf(`attachment;filename="%s"`, downloadName)) - r.Server.serveFile(r.request, serveFile) + r.Server.serveFile(r.Request, serveFile) } // 返回location标识,引导客户端跳转。 @@ -208,12 +208,12 @@ func (r *Response) ServeFileDownload(path string, name ...string) { func (r *Response) RedirectTo(location string) { r.Header().Set("Location", location) r.WriteHeader(http.StatusFound) - r.request.Exit() + r.Request.Exit() } // 返回location标识,引导客户端跳转到来源页面 func (r *Response) RedirectBack() { - r.RedirectTo(r.request.GetReferer()) + r.RedirectTo(r.Request.GetReferer()) } // 获取当前缓冲区中的数据 diff --git a/net/ghttp/ghttp_response_cors.go b/net/ghttp/ghttp_response_cors.go index c21cb6a98..796c06c95 100644 --- a/net/ghttp/ghttp_response_cors.go +++ b/net/ghttp/ghttp_response_cors.go @@ -37,7 +37,7 @@ func (r *Response) DefaultCORSOptions() CORSOptions { } if origin := r.Header().Get("Origin"); origin != "" { options.AllowOrigin = origin - } else if referer := r.request.Referer(); referer != "" { + } else if referer := r.Request.Referer(); referer != "" { if p := gstr.PosR(referer, "/", 6); p != -1 { options.AllowOrigin = referer[:p] } else { @@ -75,9 +75,9 @@ func (r *Response) CORSAllowedOrigin(options CORSOptions) bool { if options.AllowDomain == nil { return true } - origin := r.request.Header.Get("Origin") + origin := r.Request.Header.Get("Origin") if origin == "" { - return false + return true } parsed, err := url.Parse(origin) if err != nil { diff --git a/net/ghttp/ghttp_response_view.go b/net/ghttp/ghttp_response_view.go index 9adc0af9e..2be14cc02 100644 --- a/net/ghttp/ghttp_response_view.go +++ b/net/ghttp/ghttp_response_view.go @@ -67,9 +67,9 @@ func (r *Response) buildInVars(params ...map[string]interface{}) map[string]inte if c := gins.Config(); c.FilePath() != "" { vars["Config"] = c.GetMap(".") } - vars["Cookie"] = r.request.Cookie.Map() - vars["Session"] = r.request.Session.Map() - vars["Get"] = r.request.GetQueryMap() - vars["Post"] = r.request.GetPostMap() + vars["Get"] = r.Request.GetQueryMap() + vars["Post"] = r.Request.GetPostMap() + vars["Cookie"] = r.Request.Cookie.Map() + vars["Session"] = r.Request.Session.Map() return vars } diff --git a/net/ghttp/ghttp_response_writer.go b/net/ghttp/ghttp_response_writer.go index 6464ff44a..3300e9fd8 100644 --- a/net/ghttp/ghttp_response_writer.go +++ b/net/ghttp/ghttp_response_writer.go @@ -8,35 +8,47 @@ package ghttp import ( + "bufio" "bytes" + "net" "net/http" ) -// 自定义的ResponseWriter,用于写入流的控制 +// Custom ResponseWriter, which is used for controlling the output buffer. type ResponseWriter struct { - http.ResponseWriter - Status int // http status - buffer *bytes.Buffer // 缓冲区内容 + Status int // HTTP status. + writer http.ResponseWriter // The underlying ResponseWriter. + buffer *bytes.Buffer // The output buffer. } -// 覆盖父级的WriteHeader方法 +// Header implements the interface function of http.ResponseWriter.Header. +func (w *ResponseWriter) Header() http.Header { + return w.writer.Header() +} + +// Write implements the interface function of http.ResponseWriter.Write. func (w *ResponseWriter) Write(data []byte) (int, error) { w.buffer.Write(data) return len(data), nil } -// 覆盖父级的WriteHeader方法, 这里只会记录Status做缓冲处理, 并不会立即输出到HEADER。 +// WriteHeader implements the interface of http.ResponseWriter.WriteHeader. func (w *ResponseWriter) WriteHeader(status int) { w.Status = status } -// 输出buffer数据到客户端. +// Hijack implements the interface function of http.Hijacker.Hijack. +func (w *ResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { + return w.writer.(http.Hijacker).Hijack() +} + +// OutputBuffer outputs the buffer to client. func (w *ResponseWriter) OutputBuffer() { if w.Status != 0 { - w.ResponseWriter.WriteHeader(w.Status) + w.writer.WriteHeader(w.Status) } if w.buffer.Len() > 0 { - w.ResponseWriter.Write(w.buffer.Bytes()) + w.writer.Write(w.buffer.Bytes()) w.buffer.Reset() } } diff --git a/net/ghttp/ghttp_server_config.go b/net/ghttp/ghttp_server_config.go index b0b6024e4..7c7142d29 100644 --- a/net/ghttp/ghttp_server_config.go +++ b/net/ghttp/ghttp_server_config.go @@ -151,12 +151,12 @@ func (s *Server) SetConfigWithMap(m map[string]interface{}) { } // 设置http server参数 - Addr -func (s *Server) SetAddr(itemFunc string) { +func (s *Server) SetAddr(address string) { if s.Status() == SERVER_STATUS_RUNNING { glog.Error(gCHANGE_CONFIG_WHILE_RUNNING_ERROR) return } - s.config.Addr = itemFunc + s.config.Addr = address } // 设置http server参数 - Port @@ -176,12 +176,12 @@ func (s *Server) SetPort(port ...int) { } // 设置http server参数 - HTTPS Addr -func (s *Server) SetHTTPSAddr(itemFunc string) { +func (s *Server) SetHTTPSAddr(address string) { if s.Status() == SERVER_STATUS_RUNNING { glog.Error(gCHANGE_CONFIG_WHILE_RUNNING_ERROR) return } - s.config.HTTPSAddr = itemFunc + s.config.HTTPSAddr = address } // 设置http server参数 - HTTPS Port diff --git a/os/gflock/gflock.go b/os/gflock/gflock.go deleted file mode 100644 index 6e9b1b61e..000000000 --- a/os/gflock/gflock.go +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved. -// -// This Source Code Form is subject to the terms of the MIT License. -// If a copy of the MIT was not distributed with this file, -// You can obtain one at https://github.com/gogf/gf. - -// Package gflock implements a concurrent-safe sync.Locker interface for file locking. -package gflock - -import ( - "github.com/gogf/gf/os/gfile" - flock "github.com/theckman/go-flock" -) - -// File locker. -type Locker struct { - flock *flock.Flock // Underlying file locker. -} - -// New creates and returns a new file locker with given . -// The parameter usually is a absolute file path. -func New(file string) *Locker { - dir := gfile.TempDir() + gfile.Separator + "gflock" - if !gfile.Exists(dir) { - _ = gfile.Mkdir(dir) - } - path := dir + gfile.Separator + file - lock := flock.NewFlock(path) - return &Locker{ - flock: lock, - } -} - -// Path returns the file path of the locker. -func (l *Locker) Path() string { - return l.flock.Path() -} - -// IsLocked returns whether the locker is locked. -func (l *Locker) IsLocked() bool { - return l.flock.Locked() -} - -// IsRLocked returns whether the locker is rlocked. -func (l *Locker) IsRLocked() bool { - return l.flock.RLocked() -} - -// TryLock tries get the writing lock of the locker. -// It returns true if success, or else returns false immediately. -func (l *Locker) TryLock() bool { - ok, _ := l.flock.TryLock() - return ok -} - -// TryRLock tries get the reading lock of the locker. -// It returns true if success, or else returns false immediately. -func (l *Locker) TryRLock() bool { - ok, _ := l.flock.TryRLock() - return ok -} - -// Lock is a blocking call to try and take an exclusive file lock. It will wait -// until it is able to obtain the exclusive file lock. It's recommended that -// TryLock() be used over this function. This function may block the ability to -// query the current Locked() or RLocked() status due to a RW-mutex lock. -// -// If we are already exclusive-locked, this function short-circuits and returns -// immediately assuming it can take the mutex lock. -// -// If the *Flock has a shared lock (RLock), this may transparently replace the -// shared lock with an exclusive lock on some UNIX-like operating systems. Be -// careful when using exclusive locks in conjunction with shared locks -// (RLock()), because calling Unlock() may accidentally release the exclusive -// lock that was once a shared lock. -func (l *Locker) Lock() (err error) { - return l.flock.Lock() -} - -// Unlock is a function to unlock the file. This file takes a RW-mutex lock, so -// while it is running the Locked() and RLocked() functions will be blocked. -// -// This function short-circuits if we are unlocked already. If not, it calls -// syscall.LOCK_UN on the file and closes the file descriptor. It does not -// remove the file from disk. It's up to your application to do. -// -// Please note, if your shared lock became an exclusive lock this may -// unintentionally drop the exclusive lock if called by the consumer that -// believes they have a shared lock. Please see Lock() for more details. -func (l *Locker) Unlock() (err error) { - return l.flock.Unlock() -} - -// RLock is a blocking call to try and take a ahred file lock. It will wait -// until it is able to obtain the shared file lock. It's recommended that -// TryRLock() be used over this function. This function may block the ability to -// query the current Locked() or RLocked() status due to a RW-mutex lock. -// -// If we are already shared-locked, this function short-circuits and returns -// immediately assuming it can take the mutex lock. -func (l *Locker) RLock() (err error) { - return l.flock.RLock() -} - -// Unlock is a function to unlock the file. This file takes a RW-mutex lock, so -// while it is running the Locked() and RLocked() functions will be blocked. -// -// This function short-circuits if we are unlocked already. If not, it calls -// syscall.LOCK_UN on the file and closes the file descriptor. It does not -// remove the file from disk. It's up to your application to do. -// -// Please note, if your shared lock became an exclusive lock this may -// unintentionally drop the exclusive lock if called by the consumer that -// believes they have a shared lock. Please see Lock() for more details. -func (l *Locker) RUnlock() (err error) { - return l.flock.Unlock() -} diff --git a/os/gflock/gflock_unit_test.go b/os/gflock/gflock_unit_test.go deleted file mode 100644 index c4ed45dd0..000000000 --- a/os/gflock/gflock_unit_test.go +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved. -// -// This Source Code Form is subject to the terms of the MIT License. -// If a copy of the MIT was not distributed with this file, -// You can obtain one at https://github.com/gogf/gf. - -package gflock_test - -import ( - "testing" - "time" - - "github.com/gogf/gf/container/garray" - "github.com/gogf/gf/os/gfile" - "github.com/gogf/gf/os/gflock" - "github.com/gogf/gf/test/gtest" -) - -func Test_GFlock_Base(t *testing.T) { - gtest.Case(t, func() { - fileName := "test" - lock := gflock.New(fileName) - gtest.Assert(lock.Path(), gfile.TempDir()+gfile.Separator+"gflock"+gfile.Separator+fileName) - gtest.Assert(lock.IsLocked(), false) - lock.Lock() - gtest.Assert(lock.IsLocked(), true) - lock.Unlock() - gtest.Assert(lock.IsLocked(), false) - }) - - gtest.Case(t, func() { - fileName := "test" - lock := gflock.New(fileName) - gtest.Assert(lock.Path(), gfile.TempDir()+gfile.Separator+"gflock"+gfile.Separator+fileName) - gtest.Assert(lock.IsRLocked(), false) - lock.RLock() - gtest.Assert(lock.IsRLocked(), true) - lock.RUnlock() - gtest.Assert(lock.IsRLocked(), false) - }) -} - -func Test_GFlock_Lock(t *testing.T) { - gtest.Case(t, func() { - fileName := "testLock" - array := garray.New(true) - lock := gflock.New(fileName) - lock2 := gflock.New(fileName) - - go func() { - lock.Lock() - array.Append(1) - time.Sleep(300 * time.Millisecond) - lock.Unlock() - }() - - go func() { - time.Sleep(100 * time.Millisecond) - lock2.Lock() - array.Append(1) - lock2.Unlock() - }() - - time.Sleep(100 * time.Millisecond) - gtest.Assert(array.Len(), 1) - time.Sleep(100 * time.Millisecond) - gtest.Assert(array.Len(), 1) - time.Sleep(200 * time.Millisecond) - gtest.Assert(array.Len(), 2) - }) -} - -func Test_GFlock_RLock(t *testing.T) { - gtest.Case(t, func() { - fileName := "testRLock" - array := garray.New(true) - lock := gflock.New(fileName) - lock2 := gflock.New(fileName) - - go func() { - lock.RLock() - array.Append(1) - time.Sleep(400 * time.Millisecond) - lock.RUnlock() - }() - - go func() { - time.Sleep(200 * time.Millisecond) - lock2.RLock() - array.Append(1) - lock2.RUnlock() - }() - - time.Sleep(100 * time.Millisecond) - gtest.Assert(array.Len(), 1) - time.Sleep(200 * time.Millisecond) - gtest.Assert(array.Len(), 2) - }) -} - -func Test_GFlock_TryLock(t *testing.T) { - gtest.Case(t, func() { - fileName := "testTryLock" - array := garray.New(true) - lock := gflock.New(fileName) - lock2 := gflock.New(fileName) - - go func() { - lock.TryLock() - array.Append(1) - time.Sleep(200 * time.Millisecond) - lock.Unlock() - }() - - go func() { - time.Sleep(100 * time.Millisecond) - if lock2.TryLock() { - array.Append(1) - lock2.Unlock() - } - }() - - go func() { - time.Sleep(300 * time.Millisecond) - if lock2.TryLock() { - array.Append(1) - lock2.Unlock() - } - }() - time.Sleep(100 * time.Millisecond) - gtest.Assert(array.Len(), 1) - time.Sleep(100 * time.Millisecond) - gtest.Assert(array.Len(), 1) - time.Sleep(200 * time.Millisecond) - gtest.Assert(array.Len(), 2) - }) -} - -func Test_GFlock_TryRLock(t *testing.T) { - gtest.Case(t, func() { - fileName := "testTryRLock" - array := garray.New(true) - lock := gflock.New(fileName) - lock2 := gflock.New(fileName) - go func() { - lock.TryRLock() - array.Append(1) - time.Sleep(300 * time.Millisecond) - lock.Unlock() - }() - - go func() { - time.Sleep(200 * time.Millisecond) - if lock2.TryRLock() { - array.Append(1) - lock2.Unlock() - } - }() - - go func() { - time.Sleep(200 * time.Millisecond) - if lock2.TryRLock() { - array.Append(1) - lock2.Unlock() - } - }() - - go func() { - time.Sleep(200 * time.Millisecond) - if lock2.TryRLock() { - array.Append(1) - lock2.Unlock() - } - }() - time.Sleep(100 * time.Millisecond) - gtest.Assert(array.Len(), 1) - time.Sleep(300 * time.Millisecond) - gtest.Assert(array.Len(), 4) - }) -}