mirror of
https://gitee.com/johng/gf
synced 2026-06-08 18:47:45 +08:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c07c4d7217 | |||
| b867b2a0bc | |||
| 872d674182 | |||
| 4682abafdf | |||
| b7d194cf52 | |||
| edf2366296 | |||
| 22af5be71f | |||
| f662ff8051 |
@ -5,4 +5,8 @@
|
||||
|
||||
[redis]
|
||||
default = "127.0.0.1:6379,0"
|
||||
cache = "127.0.0.1:6379,1"
|
||||
cache = "127.0.0.1:6379,1"
|
||||
|
||||
[viewer]
|
||||
delimiters = ["${", "}"]
|
||||
autoencode = true
|
||||
@ -1,14 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/os/gfile"
|
||||
)
|
||||
|
||||
func main() {
|
||||
g.Dump(gfile.ScanDirFile("/Users/john/Temp/test", "Dockerfile", true))
|
||||
//if err := gfile.ReplaceDir("gf-empty", "app", "/Users/john/Temp/test", "*.*", true); err != nil {
|
||||
// glog.Fatal("content replacing failed,", err.Error())
|
||||
//}
|
||||
|
||||
fmt.Println(g.Cfg().FilePath())
|
||||
g.Cfg().Dump()
|
||||
}
|
||||
|
||||
21
README.MD
21
README.MD
@ -41,27 +41,6 @@ golang version >= 1.10
|
||||
<img src="https://goframe.org/images/arch.png?v=10"/>
|
||||
</div>
|
||||
|
||||
# Quick Start
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
r.Response.Write("Hello World")
|
||||
})
|
||||
s.Run()
|
||||
}
|
||||
```
|
||||
|
||||
[More Features...](https://goframe.org/start/index)
|
||||
|
||||
|
||||
# License
|
||||
|
||||
|
||||
21
README_ZH.MD
21
README_ZH.MD
@ -51,27 +51,6 @@ golang版本 >= 1.11
|
||||
|
||||
接口文档:[https://godoc.org/github.com/gogf/gf](https://godoc.org/github.com/gogf/gf)
|
||||
|
||||
# 使用
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
r.Response.Write("Hello World")
|
||||
})
|
||||
s.Run()
|
||||
}
|
||||
```
|
||||
|
||||
[更多..](https://goframe.org/start/index)
|
||||
|
||||
|
||||
# 协议
|
||||
|
||||
`GF` 使用非常友好的 [MIT](LICENSE) 开源协议进行发布,永久`100%`开源免费。
|
||||
|
||||
@ -57,7 +57,7 @@ func (v *Bool) Val() bool {
|
||||
}
|
||||
|
||||
// Cas executes the compare-and-swap operation for value.
|
||||
func (v *Bool) Cas(old, new bool) bool {
|
||||
func (v *Bool) Cas(old, new bool) (swapped bool) {
|
||||
var oldInt32, newInt32 int32
|
||||
if old {
|
||||
oldInt32 = 1
|
||||
|
||||
@ -49,7 +49,7 @@ func (v *Byte) Add(delta byte) (new byte) {
|
||||
}
|
||||
|
||||
// Cas executes the compare-and-swap operation for value.
|
||||
func (v *Byte) Cas(old, new byte) bool {
|
||||
func (v *Byte) Cas(old, new byte) (swapped bool) {
|
||||
return atomic.CompareAndSwapInt32(&v.value, int32(old), int32(new))
|
||||
}
|
||||
|
||||
|
||||
@ -62,7 +62,7 @@ func (v *Float32) Add(delta float32) (new float32) {
|
||||
}
|
||||
|
||||
// Cas executes the compare-and-swap operation for value.
|
||||
func (v *Float32) Cas(old, new float32) bool {
|
||||
func (v *Float32) Cas(old, new float32) (swapped bool) {
|
||||
return atomic.CompareAndSwapUint32(&v.value, math.Float32bits(old), math.Float32bits(new))
|
||||
}
|
||||
|
||||
|
||||
@ -62,7 +62,7 @@ func (v *Float64) Add(delta float64) (new float64) {
|
||||
}
|
||||
|
||||
// Cas executes the compare-and-swap operation for value.
|
||||
func (v *Float64) Cas(old, new float64) bool {
|
||||
func (v *Float64) Cas(old, new float64) (swapped bool) {
|
||||
return atomic.CompareAndSwapUint64(&v.value, math.Float64bits(old), math.Float64bits(new))
|
||||
}
|
||||
|
||||
|
||||
@ -49,7 +49,7 @@ func (v *Int) Add(delta int) (new int) {
|
||||
}
|
||||
|
||||
// Cas executes the compare-and-swap operation for value.
|
||||
func (v *Int) Cas(old, new int) bool {
|
||||
func (v *Int) Cas(old, new int) (swapped bool) {
|
||||
return atomic.CompareAndSwapInt64(&v.value, int64(old), int64(new))
|
||||
}
|
||||
|
||||
|
||||
@ -49,7 +49,7 @@ func (v *Int32) Add(delta int32) (new int32) {
|
||||
}
|
||||
|
||||
// Cas executes the compare-and-swap operation for value.
|
||||
func (v *Int32) Cas(old, new int32) bool {
|
||||
func (v *Int32) Cas(old, new int32) (swapped bool) {
|
||||
return atomic.CompareAndSwapInt32(&v.value, old, new)
|
||||
}
|
||||
|
||||
|
||||
@ -49,7 +49,7 @@ func (v *Int64) Add(delta int64) (new int64) {
|
||||
}
|
||||
|
||||
// Cas executes the compare-and-swap operation for value.
|
||||
func (v *Int64) Cas(old, new int64) bool {
|
||||
func (v *Int64) Cas(old, new int64) (swapped bool) {
|
||||
return atomic.CompareAndSwapInt64(&v.value, old, new)
|
||||
}
|
||||
|
||||
|
||||
@ -49,7 +49,7 @@ func (v *Uint) Add(delta uint) (new uint) {
|
||||
}
|
||||
|
||||
// Cas executes the compare-and-swap operation for value.
|
||||
func (v *Uint) Cas(old, new uint) bool {
|
||||
func (v *Uint) Cas(old, new uint) (swapped bool) {
|
||||
return atomic.CompareAndSwapUint64(&v.value, uint64(old), uint64(new))
|
||||
}
|
||||
|
||||
|
||||
@ -49,7 +49,7 @@ func (v *Uint32) Add(delta uint32) (new uint32) {
|
||||
}
|
||||
|
||||
// Cas executes the compare-and-swap operation for value.
|
||||
func (v *Uint32) Cas(old, new uint32) bool {
|
||||
func (v *Uint32) Cas(old, new uint32) (swapped bool) {
|
||||
return atomic.CompareAndSwapUint32(&v.value, old, new)
|
||||
}
|
||||
|
||||
|
||||
@ -49,7 +49,7 @@ func (v *Uint64) Add(delta uint64) (new uint64) {
|
||||
}
|
||||
|
||||
// Cas executes the compare-and-swap operation for value.
|
||||
func (v *Uint64) Cas(old, new uint64) bool {
|
||||
func (v *Uint64) Cas(old, new uint64) (swapped bool) {
|
||||
return atomic.CompareAndSwapUint64(&v.value, old, new)
|
||||
}
|
||||
|
||||
|
||||
@ -49,6 +49,12 @@ func BenchmarkInt_Add(b *testing.B) {
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkInt_Cas(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
it.Cas(i, i)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkInt32_Set(b *testing.B) {
|
||||
for i := int32(0); i < int32(b.N); i++ {
|
||||
it32.Set(i)
|
||||
|
||||
@ -844,16 +844,12 @@ func (m *Model) Count(where ...interface{}) (int, error) {
|
||||
if len(where) > 0 {
|
||||
return m.Where(where[0], where[1:]...).Count()
|
||||
}
|
||||
defer func(fields string) {
|
||||
m.fields = fields
|
||||
}(m.fields)
|
||||
if m.fields == "" || m.fields == "*" {
|
||||
m.fields = "COUNT(1)"
|
||||
} else {
|
||||
m.fields = fmt.Sprintf(`COUNT(%s)`, m.fields)
|
||||
countFields := "COUNT(1)"
|
||||
if m.fields != "" && m.fields != "*" {
|
||||
countFields = fmt.Sprintf(`COUNT(%s)`, m.fields)
|
||||
}
|
||||
condition, conditionArgs := m.formatCondition(false)
|
||||
s := fmt.Sprintf("SELECT %s FROM %s %s", m.fields, m.tables, condition)
|
||||
s := fmt.Sprintf("SELECT %s FROM %s %s", countFields, m.tables, condition)
|
||||
if len(m.groupBy) > 0 {
|
||||
s = fmt.Sprintf("SELECT COUNT(1) FROM (%s) count_alias", s)
|
||||
}
|
||||
|
||||
@ -86,11 +86,19 @@ func (bs *dbBase) convertValue(fieldValue []byte, fieldType string) interface{}
|
||||
return gconv.Int(string(fieldValue))
|
||||
|
||||
case strings.Contains(t, "time"):
|
||||
t, _ := gtime.StrToTime(string(fieldValue))
|
||||
s := string(fieldValue)
|
||||
t, err := gtime.StrToTime(s)
|
||||
if err != nil {
|
||||
return s
|
||||
}
|
||||
return t.String()
|
||||
|
||||
case strings.Contains(t, "date"):
|
||||
t, _ := gtime.StrToTime(string(fieldValue))
|
||||
s := string(fieldValue)
|
||||
t, err := gtime.StrToTime(s)
|
||||
if err != nil {
|
||||
return s
|
||||
}
|
||||
return t.Format("Y-m-d")
|
||||
|
||||
default:
|
||||
|
||||
@ -24,6 +24,7 @@ func Test_Types(t *testing.T) {
|
||||
%s blob NOT NULL,
|
||||
%s binary(8) NOT NULL,
|
||||
%s date NOT NULL,
|
||||
%s time NOT NULL,
|
||||
%s decimal(5,2) NOT NULL,
|
||||
%s double NOT NULL,
|
||||
%s bit(2) NOT NULL,
|
||||
@ -31,7 +32,8 @@ func Test_Types(t *testing.T) {
|
||||
%s bool NOT NULL,
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
`, "`blob`", "`binary`", "`date`", "`decimal`", "`double`", "`bit`", "`tinyint`", "`bool`")); err != nil {
|
||||
`, "`blob`", "`binary`", "`date`", "`time`",
|
||||
"`decimal`", "`double`", "`bit`", "`tinyint`", "`bool`")); err != nil {
|
||||
gtest.Error(err)
|
||||
}
|
||||
defer dropTable("types")
|
||||
@ -40,6 +42,7 @@ func Test_Types(t *testing.T) {
|
||||
"blob": "i love gf",
|
||||
"binary": []byte("abcdefgh"),
|
||||
"date": "2018-10-24",
|
||||
"time": "10:00:01",
|
||||
"decimal": 123.456,
|
||||
"double": 123.456,
|
||||
"bit": 2,
|
||||
@ -57,6 +60,7 @@ func Test_Types(t *testing.T) {
|
||||
gtest.Assert(one["blob"].String(), data["blob"])
|
||||
gtest.Assert(one["binary"].String(), data["binary"])
|
||||
gtest.Assert(one["date"].String(), data["date"])
|
||||
gtest.Assert(one["time"].String(), data["time"])
|
||||
gtest.Assert(one["decimal"].String(), 123.46)
|
||||
gtest.Assert(one["double"].String(), data["double"])
|
||||
gtest.Assert(one["bit"].Int(), data["bit"])
|
||||
|
||||
@ -6,78 +6,3 @@
|
||||
|
||||
// Package gcompress provides kinds of compression algorithms for binary/bytes data.
|
||||
package gcompress
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"compress/zlib"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Zlib compresses <data> with zlib algorithm.
|
||||
func Zlib(data []byte) ([]byte, error) {
|
||||
if data == nil || len(data) < 13 {
|
||||
return data, nil
|
||||
}
|
||||
var in bytes.Buffer
|
||||
var err error
|
||||
w := zlib.NewWriter(&in)
|
||||
if _, err = w.Write(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = w.Close(); err != nil {
|
||||
return in.Bytes(), err
|
||||
}
|
||||
return in.Bytes(), nil
|
||||
}
|
||||
|
||||
// UnZlib decompresses <data> with zlib algorithm.
|
||||
func UnZlib(data []byte) ([]byte, error) {
|
||||
if data == nil || len(data) < 13 {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
b := bytes.NewReader(data)
|
||||
var out bytes.Buffer
|
||||
var err error
|
||||
r, err := zlib.NewReader(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err = io.Copy(&out, r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out.Bytes(), nil
|
||||
}
|
||||
|
||||
// Gzip compresses <data> with gzip algorithm.
|
||||
func Gzip(data []byte) ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
var err error
|
||||
zip := gzip.NewWriter(&buf)
|
||||
_, err = zip.Write(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = zip.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// UnGzip decompresses <data> with gzip algorithm.
|
||||
func UnGzip(data []byte) ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
content := bytes.NewReader(data)
|
||||
zipData, err := gzip.NewReader(content)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err = io.Copy(&buf, zipData); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = zipData.Close(); err != nil {
|
||||
return buf.Bytes(), err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
55
encoding/gcompress/gcompress_gzip.go
Normal file
55
encoding/gcompress/gcompress_gzip.go
Normal file
@ -0,0 +1,55 @@
|
||||
// Copyright 2017 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 gcompress
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Gzip compresses <data> with gzip algorithm.
|
||||
// The optional parameter <level> specifies the compression level from
|
||||
// 1 to 9 which means from none to the best compression.
|
||||
//
|
||||
// Note that it returns error if given <level> is invalid.
|
||||
func Gzip(data []byte, level ...int) ([]byte, error) {
|
||||
var writer *gzip.Writer
|
||||
var buf bytes.Buffer
|
||||
var err error
|
||||
if len(level) > 0 {
|
||||
writer, err = gzip.NewWriterLevel(&buf, level[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
writer = gzip.NewWriter(&buf)
|
||||
}
|
||||
if _, err = writer.Write(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = writer.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// UnGzip decompresses <data> with gzip algorithm.
|
||||
func UnGzip(data []byte) ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
reader, err := gzip.NewReader(bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err = io.Copy(&buf, reader); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = reader.Close(); err != nil {
|
||||
return buf.Bytes(), err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
@ -24,7 +24,8 @@ import (
|
||||
// ZipPath compresses <paths> to <dest> using zip compressing algorithm.
|
||||
// The unnecessary parameter <prefix> indicates the path prefix for zip file.
|
||||
//
|
||||
// Note that parameter <paths> supports multiple paths join with ','.
|
||||
// Note that the parameter <paths> can be either a directory or a file, which
|
||||
// supports multiple paths join with ','.
|
||||
func ZipPath(paths, dest string, prefix ...string) error {
|
||||
writer, err := os.Create(dest)
|
||||
if err != nil {
|
||||
@ -37,7 +38,8 @@ func ZipPath(paths, dest string, prefix ...string) error {
|
||||
// ZipPathWriter compresses <paths> to <writer> using zip compressing algorithm.
|
||||
// The unnecessary parameter <prefix> indicates the path prefix for zip file.
|
||||
//
|
||||
// Note that parameter <paths> supports multiple paths join with ','.
|
||||
// Note that the parameter <paths> can be either a directory or a file, which
|
||||
// supports multiple paths join with ','.
|
||||
func ZipPathWriter(paths string, writer io.Writer, prefix ...string) error {
|
||||
zipWriter := zip.NewWriter(writer)
|
||||
defer zipWriter.Close()
|
||||
@ -51,24 +53,30 @@ func ZipPathWriter(paths string, writer io.Writer, prefix ...string) error {
|
||||
}
|
||||
|
||||
func doZipPathWriter(path string, zipWriter *zip.Writer, prefix ...string) error {
|
||||
var err error
|
||||
var files []string
|
||||
realPath, err := gfile.Search(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
files, err := gfile.ScanDir(path, "*", true)
|
||||
if err != nil {
|
||||
return err
|
||||
if gfile.IsDir(path) {
|
||||
files, err = gfile.ScanDir(path, "*", true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
files = []string{path}
|
||||
}
|
||||
headerPrefix := ""
|
||||
if len(prefix) > 0 && prefix[0] != "" {
|
||||
headerPrefix = prefix[0]
|
||||
}
|
||||
headerPrefix = strings.TrimRight(headerPrefix, "\\/")
|
||||
if gfile.IsDir(path) {
|
||||
if len(headerPrefix) > 0 {
|
||||
headerPrefix += "/"
|
||||
}
|
||||
headerPrefix = headerPrefix + gfile.Basename(path)
|
||||
if len(headerPrefix) > 0 && gfile.IsDir(path) {
|
||||
headerPrefix += "/"
|
||||
}
|
||||
if headerPrefix == "" {
|
||||
headerPrefix = gfile.Basename(path)
|
||||
}
|
||||
headerPrefix = strings.Replace(headerPrefix, "//", "/", -1)
|
||||
for _, file := range files {
|
||||
50
encoding/gcompress/gcompress_zlib.go
Normal file
50
encoding/gcompress/gcompress_zlib.go
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright 2017 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 gcompress provides kinds of compression algorithms for binary/bytes data.
|
||||
package gcompress
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/zlib"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Zlib compresses <data> with zlib algorithm.
|
||||
func Zlib(data []byte) ([]byte, error) {
|
||||
if data == nil || len(data) < 13 {
|
||||
return data, nil
|
||||
}
|
||||
var in bytes.Buffer
|
||||
var err error
|
||||
w := zlib.NewWriter(&in)
|
||||
if _, err = w.Write(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = w.Close(); err != nil {
|
||||
return in.Bytes(), err
|
||||
}
|
||||
return in.Bytes(), nil
|
||||
}
|
||||
|
||||
// UnZlib decompresses <data> with zlib algorithm.
|
||||
func UnZlib(data []byte) ([]byte, error) {
|
||||
if data == nil || len(data) < 13 {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
b := bytes.NewReader(data)
|
||||
var out bytes.Buffer
|
||||
var err error
|
||||
r, err := zlib.NewReader(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err = io.Copy(&out, r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out.Bytes(), nil
|
||||
}
|
||||
@ -1,23 +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 utibytes provides some bytes functions for internal usage.
|
||||
package utilbytes
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func Export(b []byte) string {
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
buffer.WriteString(`[]byte("`)
|
||||
for _, v := range b {
|
||||
fmt.Fprintf(buffer, `\x%02x`, v)
|
||||
}
|
||||
buffer.WriteString(`")`)
|
||||
return buffer.String()
|
||||
}
|
||||
@ -90,16 +90,24 @@ func (r *Response) ServeFileDownload(path string, name ...string) {
|
||||
r.Server.serveFile(r.Request, serveFile)
|
||||
}
|
||||
|
||||
// RedirectTo redirects client to another location using http status 302.
|
||||
func (r *Response) RedirectTo(location string) {
|
||||
// RedirectTo redirects client to another location.
|
||||
// The optional parameter <code> specifies the http status code for redirecting,
|
||||
// which commonly can be 301 or 302. It's 302 in default.
|
||||
func (r *Response) RedirectTo(location string, code ...int) {
|
||||
r.Header().Set("Location", location)
|
||||
r.WriteHeader(http.StatusFound)
|
||||
if len(code) > 0 {
|
||||
r.WriteHeader(code[0])
|
||||
} else {
|
||||
r.WriteHeader(http.StatusFound)
|
||||
}
|
||||
r.Request.Exit()
|
||||
}
|
||||
|
||||
// RedirectBack redirects client back to referer using http status 302.
|
||||
func (r *Response) RedirectBack() {
|
||||
r.RedirectTo(r.Request.GetReferer())
|
||||
// RedirectBack redirects client back to referer.
|
||||
// The optional parameter <code> specifies the http status code for redirecting,
|
||||
// which commonly can be 301 or 302. It's 302 in default.
|
||||
func (r *Response) RedirectBack(code ...int) {
|
||||
r.RedirectTo(r.Request.GetReferer(), code...)
|
||||
}
|
||||
|
||||
// BufferString returns the buffered content as []byte.
|
||||
|
||||
@ -20,28 +20,36 @@ import (
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
)
|
||||
|
||||
// 静态文件目录映射关系对象
|
||||
// staticPathItem is the item struct for static path configuration.
|
||||
type staticPathItem struct {
|
||||
prefix string // 映射的URI前缀
|
||||
path string // 静态文件目录绝对路径
|
||||
prefix string // The router URI.
|
||||
path string // The static path.
|
||||
}
|
||||
|
||||
// 设置http server参数 - IndexFiles,默认展示文件,如:index.html, index.htm
|
||||
func (s *Server) SetIndexFiles(index []string) {
|
||||
s.config.IndexFiles = index
|
||||
// SetIndexFiles sets the index files for server.
|
||||
func (s *Server) SetIndexFiles(indexFiles []string) {
|
||||
s.config.IndexFiles = indexFiles
|
||||
}
|
||||
|
||||
// 允许展示访问目录的文件列表
|
||||
// GetIndexFiles retrieves and returns the index files from server.
|
||||
func (s *Server) GetIndexFiles() []string {
|
||||
return s.config.IndexFiles
|
||||
}
|
||||
|
||||
// SetIndexFolder enables/disables listing the sub-files if requesting a directory.
|
||||
func (s *Server) SetIndexFolder(enabled bool) {
|
||||
s.config.IndexFolder = enabled
|
||||
}
|
||||
|
||||
// 是否开启/关闭静态文件服务,当关闭时仅提供动态接口服务,路由性能会得到一定提升
|
||||
// SetFileServerEnabled enables/disables the static file service.
|
||||
// It's the main switch for the static file service. When static file service configuration
|
||||
// functions like SetServerRoot, AddSearchPath and AddStaticPath are called, this configuration
|
||||
// is automatically enabled.
|
||||
func (s *Server) SetFileServerEnabled(enabled bool) {
|
||||
s.config.FileServerEnabled = enabled
|
||||
}
|
||||
|
||||
// 设置http server参数 - ServerRoot
|
||||
// SetServerRoot sets the document root for static service.
|
||||
func (s *Server) SetServerRoot(root string) {
|
||||
realPath := root
|
||||
if !gres.Contains(realPath) {
|
||||
@ -56,7 +64,7 @@ func (s *Server) SetServerRoot(root string) {
|
||||
s.config.FileServerEnabled = true
|
||||
}
|
||||
|
||||
// 添加静态文件搜索**目录**,必须给定目录的绝对路径
|
||||
// AddSearchPath add searching directory path for static file service.
|
||||
func (s *Server) AddSearchPath(path string) {
|
||||
realPath := path
|
||||
if !gres.Contains(realPath) {
|
||||
@ -70,7 +78,7 @@ func (s *Server) AddSearchPath(path string) {
|
||||
s.config.FileServerEnabled = true
|
||||
}
|
||||
|
||||
// 添加URI与静态**目录**的映射
|
||||
// AddStaticPath sets the uri to static directory path mapping for static file service.
|
||||
func (s *Server) AddStaticPath(prefix string, path string) {
|
||||
realPath := path
|
||||
if !gres.Contains(realPath) {
|
||||
|
||||
@ -24,11 +24,11 @@ import (
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
)
|
||||
|
||||
// 服务静态文件信息
|
||||
// staticServeFile is the file struct for static service.
|
||||
type staticServeFile struct {
|
||||
file *gres.File // 资源文件
|
||||
path string // 文件路径
|
||||
dir bool // 是否目录
|
||||
file *gres.File // Resource file object.
|
||||
path string // File path.
|
||||
dir bool // Is directory.
|
||||
}
|
||||
|
||||
// 默认HTTP Server处理入口,http包底层默认使用了gorutine异步处理请求,所以这里不再异步执行
|
||||
@ -172,7 +172,8 @@ func (s *Server) handleRequest(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// 查找静态文件的绝对路径
|
||||
// searchStaticFile searches the file with given URI.
|
||||
// It returns a file struct specifying the file information.
|
||||
func (s *Server) searchStaticFile(uri string) *staticServeFile {
|
||||
var file *gres.File
|
||||
var path string
|
||||
@ -185,7 +186,6 @@ func (s *Server) searchStaticFile(uri string) *staticServeFile {
|
||||
if len(uri) > len(item.prefix) && uri[len(item.prefix)] != '/' {
|
||||
continue
|
||||
}
|
||||
// Firstly searching resource manager.
|
||||
file = gres.GetWithIndex(item.path+uri[len(item.prefix):], s.config.IndexFiles)
|
||||
if file != nil {
|
||||
return &staticServeFile{
|
||||
@ -193,7 +193,6 @@ func (s *Server) searchStaticFile(uri string) *staticServeFile {
|
||||
dir: file.FileInfo().IsDir(),
|
||||
}
|
||||
}
|
||||
// Secondly searching the file system.
|
||||
path, dir = gspath.Search(item.path, uri[len(item.prefix):], s.config.IndexFiles...)
|
||||
if path != "" {
|
||||
return &staticServeFile{
|
||||
@ -205,10 +204,9 @@ func (s *Server) searchStaticFile(uri string) *staticServeFile {
|
||||
}
|
||||
}
|
||||
}
|
||||
// 其次查找root和search path
|
||||
// Secondly search the root and searching paths.
|
||||
if len(s.config.SearchPaths) > 0 {
|
||||
for _, p := range s.config.SearchPaths {
|
||||
// 优先检索资源管理器
|
||||
file = gres.GetWithIndex(p+uri, s.config.IndexFiles)
|
||||
if file != nil {
|
||||
return &staticServeFile{
|
||||
@ -216,7 +214,6 @@ func (s *Server) searchStaticFile(uri string) *staticServeFile {
|
||||
dir: file.FileInfo().IsDir(),
|
||||
}
|
||||
}
|
||||
// 其次检索文件系统
|
||||
if path, dir = gspath.Search(p, uri, s.config.IndexFiles...); path != "" {
|
||||
return &staticServeFile{
|
||||
path: path,
|
||||
@ -225,7 +222,7 @@ func (s *Server) searchStaticFile(uri string) *staticServeFile {
|
||||
}
|
||||
}
|
||||
}
|
||||
// 最后通过资源对象+URI进行文件检索
|
||||
// Lastly search the resource manager.
|
||||
if len(s.config.StaticPaths) == 0 && len(s.config.SearchPaths) == 0 {
|
||||
if file = gres.GetWithIndex(uri, s.config.IndexFiles); file != nil {
|
||||
return &staticServeFile{
|
||||
|
||||
60
net/ghttp/ghttp_unit_pprof_test.go
Normal file
60
net/ghttp/ghttp_unit_pprof_test.go
Normal file
@ -0,0 +1,60 @@
|
||||
// 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.
|
||||
|
||||
// static service testing.
|
||||
|
||||
package ghttp_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
. "github.com/gogf/gf/test/gtest"
|
||||
)
|
||||
|
||||
func TestServer_EnablePProf(t *testing.T) {
|
||||
Case(t, func() {
|
||||
p := ports.PopRand()
|
||||
s := g.Server(p)
|
||||
s.EnablePProf("/pprof")
|
||||
s.SetDumpRouterMap(false)
|
||||
s.SetPort(p)
|
||||
s.Start()
|
||||
defer s.Shutdown()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
client := ghttp.NewClient()
|
||||
client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", p))
|
||||
|
||||
r, err := client.Get("/pprof/index")
|
||||
Assert(err, nil)
|
||||
Assert(r.StatusCode, 200)
|
||||
r.Close()
|
||||
|
||||
r, err = client.Get("/pprof/cmdline")
|
||||
Assert(err, nil)
|
||||
Assert(r.StatusCode, 200)
|
||||
r.Close()
|
||||
|
||||
//r, err = client.Get("/pprof/profile")
|
||||
//Assert(err, nil)
|
||||
//Assert(r.StatusCode, 200)
|
||||
//r.Close()
|
||||
|
||||
r, err = client.Get("/pprof/symbol")
|
||||
Assert(err, nil)
|
||||
Assert(r.StatusCode, 200)
|
||||
r.Close()
|
||||
|
||||
r, err = client.Get("/pprof/trace")
|
||||
Assert(err, nil)
|
||||
Assert(r.StatusCode, 200)
|
||||
r.Close()
|
||||
})
|
||||
|
||||
}
|
||||
@ -63,18 +63,18 @@ func GetNameByAddr(ipAddress string) (string, error) {
|
||||
}
|
||||
|
||||
// Ip2long converts ip address to an uint32 integer.
|
||||
func Ip2long(ipAddress string) uint32 {
|
||||
ip := net.ParseIP(ipAddress)
|
||||
if ip == nil {
|
||||
func Ip2long(ip string) uint32 {
|
||||
netIp := net.ParseIP(ip)
|
||||
if netIp == nil {
|
||||
return 0
|
||||
}
|
||||
return binary.BigEndian.Uint32(ip.To4())
|
||||
return binary.BigEndian.Uint32(netIp.To4())
|
||||
}
|
||||
|
||||
// Long2ip converts an uint32 integer ip address to its string type address.
|
||||
func Long2ip(properAddress uint32) string {
|
||||
func Long2ip(long uint32) string {
|
||||
ipByte := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(ipByte, properAddress)
|
||||
binary.BigEndian.PutUint32(ipByte, long)
|
||||
return net.IP(ipByte).String()
|
||||
}
|
||||
|
||||
|
||||
@ -77,7 +77,7 @@ func ParseWithArgs(args []string, supportedOptions map[string]bool, strict ...bo
|
||||
} else {
|
||||
if parser.isOptionValid(option) {
|
||||
if parser.isOptionNeedArgument(option) {
|
||||
if i+1 < len(args) {
|
||||
if i < len(args)-1 {
|
||||
parser.setOptionValue(option, args[i+1])
|
||||
i += 2
|
||||
continue
|
||||
@ -171,8 +171,14 @@ func (p *Parser) GetOpt(name string, def ...string) string {
|
||||
}
|
||||
|
||||
// GetOptVar returns the option value named <name> as *gvar.Var.
|
||||
func (p *Parser) GetOptVar(name string, def ...string) *gvar.Var {
|
||||
return gvar.New(p.GetOpt(name, def...))
|
||||
func (p *Parser) GetOptVar(name string, def ...interface{}) *gvar.Var {
|
||||
if p.ContainsOpt(name) {
|
||||
return gvar.New(p.GetOpt(name))
|
||||
}
|
||||
if len(def) > 0 {
|
||||
return gvar.New(def[0])
|
||||
}
|
||||
return gvar.New(nil)
|
||||
}
|
||||
|
||||
// GetOptAll returns all parsed options.
|
||||
@ -181,7 +187,7 @@ func (p *Parser) GetOptAll() map[string]string {
|
||||
}
|
||||
|
||||
// ContainsOpt checks whether option named <name> exist in the arguments.
|
||||
func (p *Parser) ContainsOpt(name string, def ...string) bool {
|
||||
func (p *Parser) ContainsOpt(name string) bool {
|
||||
_, ok := p.parsedOptions[name]
|
||||
return ok
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -20,7 +20,7 @@ var (
|
||||
// Add unpacks and adds the <content> into the default resource object.
|
||||
// The unnecessary parameter <prefix> indicates the prefix
|
||||
// for each file storing into current resource object.
|
||||
func Add(content []byte, prefix ...string) error {
|
||||
func Add(content string, prefix ...string) error {
|
||||
return defaultResource.Add(content, prefix...)
|
||||
}
|
||||
|
||||
|
||||
@ -9,10 +9,11 @@ package gres
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
|
||||
"github.com/gogf/gf/encoding/gcompress"
|
||||
"github.com/gogf/gf/internal/utilbytes"
|
||||
"github.com/gogf/gf/os/gfile"
|
||||
)
|
||||
|
||||
@ -22,7 +23,7 @@ const (
|
||||
import "github.com/gogf/gf/os/gres"
|
||||
|
||||
func init() {
|
||||
if err := gres.Add(%s); err != nil {
|
||||
if err := gres.Add("%s"); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
@ -44,7 +45,8 @@ func Pack(srcPaths string, keyPrefix ...string) ([]byte, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buffer.Bytes(), nil
|
||||
// Gzip the data bytes to reduce the size.
|
||||
return gcompress.Gzip(buffer.Bytes(), 9)
|
||||
}
|
||||
|
||||
// PackToFile packs the path specified by <srcPaths> to target file <dstPath>.
|
||||
@ -73,7 +75,8 @@ func PackToGoFile(srcPath, goFilePath, pkgName string, keyPrefix ...string) erro
|
||||
return err
|
||||
}
|
||||
return gfile.PutContents(
|
||||
goFilePath, fmt.Sprintf(gPACKAGE_TEMPLATE, pkgName, utilbytes.Export(data)),
|
||||
goFilePath,
|
||||
fmt.Sprintf(gPACKAGE_TEMPLATE, pkgName, bytesToHexStr(data)),
|
||||
)
|
||||
}
|
||||
|
||||
@ -83,12 +86,16 @@ func Unpack(path string) ([]*File, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return UnpackContent(gfile.GetBytes(realPath))
|
||||
return UnpackContent(gfile.GetContents(realPath))
|
||||
}
|
||||
|
||||
// UnpackContent unpacks the content to []*File.
|
||||
func UnpackContent(content []byte) ([]*File, error) {
|
||||
reader, err := zip.NewReader(bytes.NewReader(content), int64(len(content)))
|
||||
func UnpackContent(content string) ([]*File, error) {
|
||||
data, err := gcompress.UnGzip(hexStrToBytes(content))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reader, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -98,3 +105,18 @@ func UnpackContent(content []byte) ([]*File, error) {
|
||||
}
|
||||
return array, nil
|
||||
}
|
||||
|
||||
// bytesToHexString converts binary content to hex string content.
|
||||
func bytesToHexStr(b []byte) string {
|
||||
dst := make([]byte, hex.EncodedLen(len(b)))
|
||||
hex.Encode(dst, b)
|
||||
return gconv.UnsafeBytesToStr(dst)
|
||||
}
|
||||
|
||||
// hexStrToBytes converts hex string content to []byte.
|
||||
func hexStrToBytes(s string) []byte {
|
||||
src := gconv.UnsafeStrToBytes(s)
|
||||
dst := make([]byte, hex.DecodedLen(len(src)))
|
||||
hex.Decode(dst, src)
|
||||
return dst
|
||||
}
|
||||
|
||||
@ -38,7 +38,7 @@ func New() *Resource {
|
||||
// Add unpacks and adds the <content> into current resource object.
|
||||
// The unnecessary parameter <prefix> indicates the prefix
|
||||
// for each file storing into current resource object.
|
||||
func (r *Resource) Add(content []byte, prefix ...string) error {
|
||||
func (r *Resource) Add(content string, prefix ...string) error {
|
||||
files, err := UnpackContent(content)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -62,7 +62,7 @@ func (r *Resource) Load(path string, prefix ...string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return r.Add(gfile.GetBytes(realPath), prefix...)
|
||||
return r.Add(gfile.GetContents(realPath), prefix...)
|
||||
}
|
||||
|
||||
// Get returns the file with given path.
|
||||
|
||||
2
os/gres/testdata/data/data.go
vendored
2
os/gres/testdata/data/data.go
vendored
File diff suppressed because one or more lines are too long
2
os/gres/testdata/testdata.go
vendored
2
os/gres/testdata/testdata.go
vendored
File diff suppressed because one or more lines are too long
@ -47,6 +47,14 @@ func Test_NewFromStrFormat(t *testing.T) {
|
||||
t.Error("test fail")
|
||||
}
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
t1 := gtime.NewFromStrFormat("2019/2/1", "Y/n/j")
|
||||
gtest.Assert(t1.Format("Y-m-d"), "2019-02-01")
|
||||
|
||||
t2 := gtime.NewFromStrFormat("2019/10/12", "Y/n/j")
|
||||
gtest.Assert(t2.Format("Y-m-d"), "2019-10-12")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_NewFromStrLayout(t *testing.T) {
|
||||
|
||||
@ -16,6 +16,8 @@ import (
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
|
||||
htmltpl "html/template"
|
||||
)
|
||||
|
||||
// funcDump implements build-in template function: dump
|
||||
@ -85,7 +87,8 @@ func (view *View) funcGe(value, other interface{}) bool {
|
||||
}
|
||||
|
||||
// funcInclude implements build-in template function: include
|
||||
func (view *View) funcInclude(file interface{}, data ...map[string]interface{}) string {
|
||||
// Note that configuration AutoEncode does not affect the output of this function.
|
||||
func (view *View) funcInclude(file interface{}, data ...map[string]interface{}) htmltpl.HTML {
|
||||
var m map[string]interface{} = nil
|
||||
if len(data) > 0 {
|
||||
m = data[0]
|
||||
@ -97,9 +100,9 @@ func (view *View) funcInclude(file interface{}, data ...map[string]interface{})
|
||||
// It will search the file internally.
|
||||
content, err := view.Parse(path, m)
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
return htmltpl.HTML(err.Error())
|
||||
}
|
||||
return content
|
||||
return htmltpl.HTML(content)
|
||||
}
|
||||
|
||||
// funcText implements build-in template function: text
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package gf
|
||||
|
||||
const VERSION = "v1.11.2"
|
||||
const VERSION = "v1.11.3"
|
||||
const AUTHORS = "john<john@goframe.org>"
|
||||
|
||||
Reference in New Issue
Block a user