Fix session middleware (#1235)

encoding/gob for session middleware
pull/1243/head
RW 2021-03-26 11:24:55 +01:00 committed by GitHub
parent 861e5d21fb
commit b1b490645e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 38 additions and 1300 deletions

4
go.sum
View File

@ -8,19 +8,15 @@ github.com/valyala/fasthttp v1.18.0 h1:IV0DdMlatq9QO1Cr6wGJPVW1sV1Q8HvZXAIcjoryl
github.com/valyala/fasthttp v1.18.0/go.mod h1:jjraHZVbKOXftJfsOYoAjaeygpj5hr8ermTRJNroD7A=
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a h1:0R4NLDRDZX6JcmhJgXi5E4b8Wg84ihbmUKp/GvSPEzc=
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20201016165138-7b1cca2348c0 h1:5kGOVHlq0euqwzgTC9Vu15p6fV1Wi0ArVi8da2urnVg=
golang.org/x/net v0.0.0-20201016165138-7b1cca2348c0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201210223839-7e3030f88018 h1:XKi8B/gRBuTZN1vU9gFsLMm6zVz5FSCDzm8JYACnjy8=
golang.org/x/sys v0.0.0-20201210223839-7e3030f88018/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e h1:FDhOuMEY4JVRztM/gsbk+IKUQ8kj74bxZrgw87eMMVc=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@ -1,20 +0,0 @@
The MIT License (MIT)
Copyright (c) 2016 zheng-ji.info
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,205 +0,0 @@
package gotiny
import (
"fmt"
"reflect"
"sync"
"time"
"unsafe"
)
type decEng func(*Decoder, unsafe.Pointer) // 解码器
var (
rt2decEng = map[reflect.Type]decEng{
reflect.TypeOf((*bool)(nil)).Elem(): decBool,
reflect.TypeOf((*int)(nil)).Elem(): decInt,
reflect.TypeOf((*int8)(nil)).Elem(): decInt8,
reflect.TypeOf((*int16)(nil)).Elem(): decInt16,
reflect.TypeOf((*int32)(nil)).Elem(): decInt32,
reflect.TypeOf((*int64)(nil)).Elem(): decInt64,
reflect.TypeOf((*uint)(nil)).Elem(): decUint,
reflect.TypeOf((*uint8)(nil)).Elem(): decUint8,
reflect.TypeOf((*uint16)(nil)).Elem(): decUint16,
reflect.TypeOf((*uint32)(nil)).Elem(): decUint32,
reflect.TypeOf((*uint64)(nil)).Elem(): decUint64,
reflect.TypeOf((*uintptr)(nil)).Elem(): decUintptr,
reflect.TypeOf((*unsafe.Pointer)(nil)).Elem(): decPointer,
reflect.TypeOf((*float32)(nil)).Elem(): decFloat32,
reflect.TypeOf((*float64)(nil)).Elem(): decFloat64,
reflect.TypeOf((*complex64)(nil)).Elem(): decComplex64,
reflect.TypeOf((*complex128)(nil)).Elem(): decComplex128,
reflect.TypeOf((*[]byte)(nil)).Elem(): decBytes,
reflect.TypeOf((*string)(nil)).Elem(): decString,
reflect.TypeOf((*time.Time)(nil)).Elem(): decTime,
reflect.TypeOf((*struct{})(nil)).Elem(): decIgnore,
reflect.TypeOf(nil): decIgnore,
}
baseDecEngines = []decEng{
reflect.Invalid: decIgnore,
reflect.Bool: decBool,
reflect.Int: decInt,
reflect.Int8: decInt8,
reflect.Int16: decInt16,
reflect.Int32: decInt32,
reflect.Int64: decInt64,
reflect.Uint: decUint,
reflect.Uint8: decUint8,
reflect.Uint16: decUint16,
reflect.Uint32: decUint32,
reflect.Uint64: decUint64,
reflect.Uintptr: decUintptr,
reflect.UnsafePointer: decPointer,
reflect.Float32: decFloat32,
reflect.Float64: decFloat64,
reflect.Complex64: decComplex64,
reflect.Complex128: decComplex128,
reflect.String: decString,
}
decLock sync.RWMutex
)
func getDecEngine(rt reflect.Type) decEng {
decLock.RLock()
engine := rt2decEng[rt]
decLock.RUnlock()
if engine != nil {
return engine
}
decLock.Lock()
buildDecEngine(rt, &engine)
decLock.Unlock()
return engine
}
func buildDecEngine(rt reflect.Type, engPtr *decEng) {
engine, has := rt2decEng[rt]
if has {
*engPtr = engine
return
}
if _, engine = implementOtherSerializer(rt); engine != nil {
rt2decEng[rt] = engine
*engPtr = engine
return
}
kind := rt.Kind()
var eEng decEng
switch kind {
case reflect.Ptr:
et := rt.Elem()
defer buildDecEngine(et, &eEng)
engine = func(d *Decoder, p unsafe.Pointer) {
if d.decIsNotNil() {
if isNil(p) {
*(*unsafe.Pointer)(p) = unsafe.Pointer(reflect.New(et).Elem().UnsafeAddr())
}
eEng(d, *(*unsafe.Pointer)(p))
} else if !isNil(p) {
*(*unsafe.Pointer)(p) = nil
}
}
case reflect.Array:
l, et := rt.Len(), rt.Elem()
size := et.Size()
defer buildDecEngine(et, &eEng)
engine = func(d *Decoder, p unsafe.Pointer) {
for i := 0; i < l; i++ {
eEng(d, unsafe.Pointer(uintptr(p)+uintptr(i)*size))
}
}
case reflect.Slice:
et := rt.Elem()
size := et.Size()
defer buildDecEngine(et, &eEng)
engine = func(d *Decoder, p unsafe.Pointer) {
header := (*reflect.SliceHeader)(p)
if d.decIsNotNil() {
l := d.decLength()
if isNil(p) || header.Cap < l {
*header = reflect.SliceHeader{Data: reflect.MakeSlice(rt, l, l).Pointer(), Len: l, Cap: l}
} else {
header.Len = l
}
for i := 0; i < l; i++ {
eEng(d, unsafe.Pointer(header.Data+uintptr(i)*size))
}
} else if !isNil(p) {
*header = reflect.SliceHeader{}
}
}
case reflect.Map:
kt, vt := rt.Key(), rt.Elem()
skt, svt := reflect.SliceOf(kt), reflect.SliceOf(vt)
var kEng, vEng decEng
defer buildDecEngine(kt, &kEng)
defer buildDecEngine(vt, &vEng)
engine = func(d *Decoder, p unsafe.Pointer) {
if d.decIsNotNil() {
l := d.decLength()
var v reflect.Value
if isNil(p) {
v = reflect.MakeMapWithSize(rt, l)
*(*unsafe.Pointer)(p) = unsafe.Pointer(v.Pointer())
} else {
v = reflect.NewAt(rt, p).Elem()
}
keys, vals := reflect.MakeSlice(skt, l, l), reflect.MakeSlice(svt, l, l)
for i := 0; i < l; i++ {
key, val := keys.Index(i), vals.Index(i)
kEng(d, unsafe.Pointer(key.UnsafeAddr()))
vEng(d, unsafe.Pointer(val.UnsafeAddr()))
v.SetMapIndex(key, val)
}
} else if !isNil(p) {
*(*unsafe.Pointer)(p) = nil
}
}
case reflect.Struct:
fields, offs := getFieldType(rt, 0)
nf := len(fields)
fEngines := make([]decEng, nf)
defer func() {
for i := 0; i < nf; i++ {
buildDecEngine(fields[i], &fEngines[i])
}
}()
engine = func(d *Decoder, p unsafe.Pointer) {
for i := 0; i < len(fEngines) && i < len(offs); i++ {
fEngines[i](d, unsafe.Pointer(uintptr(p)+offs[i]))
}
}
case reflect.Interface:
engine = func(d *Decoder, p unsafe.Pointer) {
if d.decIsNotNil() {
name := ""
decString(d, unsafe.Pointer(&name))
et, has := name2type[name]
if !has {
//panic("unknown typ:" + name)
fmt.Println("[session] Register this type first with the `RegisterType` method.")
}
v := reflect.NewAt(rt, p).Elem()
var ev reflect.Value
if v.IsNil() || v.Elem().Type() != et {
ev = reflect.New(et).Elem()
} else {
ev = v.Elem()
}
getDecEngine(et)(d, getUnsafePointer(&ev))
v.Set(ev)
} else if !isNil(p) {
*(*unsafe.Pointer)(p) = nil
}
}
case reflect.Chan, reflect.Func:
//panic("not support " + rt.String() + " type")
default:
engine = baseDecEngines[kind]
}
rt2decEng[rt] = engine
*engPtr = engine
}

View File

@ -1,161 +0,0 @@
package gotiny
import (
"time"
"unsafe"
)
func (d *Decoder) decBool() (b bool) {
if d.boolBit == 0 {
d.boolBit = 1
d.boolPos = d.buf[d.index]
d.index++
}
b = d.boolPos&d.boolBit != 0
d.boolBit <<= 1
return
}
func (d *Decoder) decUint64() uint64 {
buf, i := d.buf, d.index
x := uint64(buf[i])
if x < 0x80 {
d.index++
return x
}
x1 := buf[i+1]
x += uint64(x1) << 7
if x1 < 0x80 {
d.index += 2
return x - 1<<7
}
x2 := buf[i+2]
x += uint64(x2) << 14
if x2 < 0x80 {
d.index += 3
return x - (1<<7 + 1<<14)
}
x3 := buf[i+3]
x += uint64(x3) << 21
if x3 < 0x80 {
d.index += 4
return x - (1<<7 + 1<<14 + 1<<21)
}
x4 := buf[i+4]
x += uint64(x4) << 28
if x4 < 0x80 {
d.index += 5
return x - (1<<7 + 1<<14 + 1<<21 + 1<<28)
}
x5 := buf[i+5]
x += uint64(x5) << 35
if x5 < 0x80 {
d.index += 6
return x - (1<<7 + 1<<14 + 1<<21 + 1<<28 + 1<<35)
}
x6 := buf[i+6]
x += uint64(x6) << 42
if x6 < 0x80 {
d.index += 7
return x - (1<<7 + 1<<14 + 1<<21 + 1<<28 + 1<<35 + 1<<42)
}
x7 := buf[i+7]
x += uint64(x7) << 49
if x7 < 0x80 {
d.index += 8
return x - (1<<7 + 1<<14 + 1<<21 + 1<<28 + 1<<35 + 1<<42 + 1<<49)
}
d.index += 9
return x + uint64(buf[i+8])<<56 - (1<<7 + 1<<14 + 1<<21 + 1<<28 + 1<<35 + 1<<42 + 1<<49 + 1<<56)
}
func (d *Decoder) decUint16() uint16 {
buf, i := d.buf, d.index
x := uint16(buf[i])
if x < 0x80 {
d.index++
return x
}
x1 := buf[i+1]
x += uint16(x1) << 7
if x1 < 0x80 {
d.index += 2
return x - 1<<7
}
d.index += 3
return x + uint16(buf[i+2])<<14 - (1<<7 + 1<<14)
}
func (d *Decoder) decUint32() uint32 {
buf, i := d.buf, d.index
x := uint32(buf[i])
if x < 0x80 {
d.index++
return x
}
x1 := buf[i+1]
x += uint32(x1) << 7
if x1 < 0x80 {
d.index += 2
return x - 1<<7
}
x2 := buf[i+2]
x += uint32(x2) << 14
if x2 < 0x80 {
d.index += 3
return x - (1<<7 + 1<<14)
}
x3 := buf[i+3]
x += uint32(x3) << 21
if x3 < 0x80 {
d.index += 4
return x - (1<<7 + 1<<14 + 1<<21)
}
x4 := buf[i+4]
x += uint32(x4) << 28
d.index += 5
return x - (1<<7 + 1<<14 + 1<<21 + 1<<28)
}
func (d *Decoder) decLength() int { return int(d.decUint32()) }
func (d *Decoder) decIsNotNil() bool { return d.decBool() }
func decIgnore(*Decoder, unsafe.Pointer) {}
func decBool(d *Decoder, p unsafe.Pointer) { *(*bool)(p) = d.decBool() }
func decInt(d *Decoder, p unsafe.Pointer) { *(*int)(p) = int(uint64ToInt64(d.decUint64())) }
func decInt8(d *Decoder, p unsafe.Pointer) { *(*int8)(p) = int8(d.buf[d.index]); d.index++ }
func decInt16(d *Decoder, p unsafe.Pointer) { *(*int16)(p) = uint16ToInt16(d.decUint16()) }
func decInt32(d *Decoder, p unsafe.Pointer) { *(*int32)(p) = uint32ToInt32(d.decUint32()) }
func decInt64(d *Decoder, p unsafe.Pointer) { *(*int64)(p) = uint64ToInt64(d.decUint64()) }
func decUint(d *Decoder, p unsafe.Pointer) { *(*uint)(p) = uint(d.decUint64()) }
func decUint8(d *Decoder, p unsafe.Pointer) { *(*uint8)(p) = d.buf[d.index]; d.index++ }
func decUint16(d *Decoder, p unsafe.Pointer) { *(*uint16)(p) = d.decUint16() }
func decUint32(d *Decoder, p unsafe.Pointer) { *(*uint32)(p) = d.decUint32() }
func decUint64(d *Decoder, p unsafe.Pointer) { *(*uint64)(p) = d.decUint64() }
func decUintptr(d *Decoder, p unsafe.Pointer) { *(*uintptr)(p) = uintptr(d.decUint64()) }
func decPointer(d *Decoder, p unsafe.Pointer) { *(*uintptr)(p) = uintptr(d.decUint64()) }
func decFloat32(d *Decoder, p unsafe.Pointer) { *(*float32)(p) = uint32ToFloat32(d.decUint32()) }
func decFloat64(d *Decoder, p unsafe.Pointer) { *(*float64)(p) = uint64ToFloat64(d.decUint64()) }
func decTime(d *Decoder, p unsafe.Pointer) { *(*time.Time)(p) = time.Unix(0, int64(d.decUint64())) }
func decComplex64(d *Decoder, p unsafe.Pointer) { *(*uint64)(p) = d.decUint64() }
func decComplex128(d *Decoder, p unsafe.Pointer) {
*(*uint64)(p) = d.decUint64()
*(*uint64)(unsafe.Pointer(uintptr(p) + ptr1Size)) = d.decUint64()
}
func decString(d *Decoder, p unsafe.Pointer) {
l, val := int(d.decUint32()), (*string)(p)
*val = string(d.buf[d.index : d.index+l])
d.index += l
}
func decBytes(d *Decoder, p unsafe.Pointer) {
bytes := (*[]byte)(p)
if d.decIsNotNil() {
l := int(d.decUint32())
*bytes = d.buf[d.index : d.index+l]
d.index += l
} else if !isNil(p) {
*bytes = nil
}
}

View File

@ -1,97 +0,0 @@
package gotiny
import (
"reflect"
"unsafe"
)
type Decoder struct {
buf []byte //buf
index int //下一个要使用的字节在buf中的下标
boolPos byte //下一次要读取的bool在buf中的下标,即buf[boolPos]
boolBit byte //下一次要读取的bool的buf[boolPos]中的bit位
engines []decEng //解码器集合
length int //解码器数量
}
func Unmarshal(buf []byte, is ...interface{}) int {
return NewDecoderWithPtr(is...).Decode(buf, is...)
}
func NewDecoderWithPtr(is ...interface{}) *Decoder {
l := len(is)
engines := make([]decEng, l)
for i := 0; i < l; i++ {
rt := reflect.TypeOf(is[i])
if rt.Kind() != reflect.Ptr {
panic("must a pointer type!")
}
engines[i] = getDecEngine(rt.Elem())
}
return &Decoder{
length: l,
engines: engines,
}
}
func NewDecoder(is ...interface{}) *Decoder {
l := len(is)
engines := make([]decEng, l)
for i := 0; i < l; i++ {
engines[i] = getDecEngine(reflect.TypeOf(is[i]))
}
return &Decoder{
length: l,
engines: engines,
}
}
func NewDecoderWithType(ts ...reflect.Type) *Decoder {
l := len(ts)
des := make([]decEng, l)
for i := 0; i < l; i++ {
des[i] = getDecEngine(ts[i])
}
return &Decoder{
length: l,
engines: des,
}
}
func (d *Decoder) reset() int {
index := d.index
d.index = 0
d.boolPos = 0
d.boolBit = 0
return index
}
// is is pointer of variable
func (d *Decoder) Decode(buf []byte, is ...interface{}) int {
d.buf = buf
engines := d.engines
for i := 0; i < len(engines) && i < len(is); i++ {
engines[i](d, (*[2]unsafe.Pointer)(unsafe.Pointer(&is[i]))[1])
}
return d.reset()
}
// ps is a unsafe.Pointer of the variable
func (d *Decoder) DecodePtr(buf []byte, ps ...unsafe.Pointer) int {
d.buf = buf
engines := d.engines
for i := 0; i < len(engines) && i < len(ps); i++ {
engines[i](d, ps[i])
}
return d.reset()
}
func (d *Decoder) DecodeValue(buf []byte, vs ...reflect.Value) int {
d.buf = buf
engines := d.engines
for i := 0; i < len(engines) && i < len(vs); i++ {
engines[i](d, unsafe.Pointer(vs[i].UnsafeAddr()))
}
return d.reset()
}

View File

@ -1,196 +0,0 @@
package gotiny
import (
"reflect"
"sync"
"time"
"unsafe"
)
type encEng func(*Encoder, unsafe.Pointer) //编码器
var (
rt2encEng = map[reflect.Type]encEng{
reflect.TypeOf((*bool)(nil)).Elem(): encBool,
reflect.TypeOf((*int)(nil)).Elem(): encInt,
reflect.TypeOf((*int8)(nil)).Elem(): encInt8,
reflect.TypeOf((*int16)(nil)).Elem(): encInt16,
reflect.TypeOf((*int32)(nil)).Elem(): encInt32,
reflect.TypeOf((*int64)(nil)).Elem(): encInt64,
reflect.TypeOf((*uint)(nil)).Elem(): encUint,
reflect.TypeOf((*uint8)(nil)).Elem(): encUint8,
reflect.TypeOf((*uint16)(nil)).Elem(): encUint16,
reflect.TypeOf((*uint32)(nil)).Elem(): encUint32,
reflect.TypeOf((*uint64)(nil)).Elem(): encUint64,
reflect.TypeOf((*uintptr)(nil)).Elem(): encUintptr,
reflect.TypeOf((*unsafe.Pointer)(nil)).Elem(): encPointer,
reflect.TypeOf((*float32)(nil)).Elem(): encFloat32,
reflect.TypeOf((*float64)(nil)).Elem(): encFloat64,
reflect.TypeOf((*complex64)(nil)).Elem(): encComplex64,
reflect.TypeOf((*complex128)(nil)).Elem(): encComplex128,
reflect.TypeOf((*[]byte)(nil)).Elem(): encBytes,
reflect.TypeOf((*string)(nil)).Elem(): encString,
reflect.TypeOf((*time.Time)(nil)).Elem(): encTime,
reflect.TypeOf((*struct{})(nil)).Elem(): encIgnore,
reflect.TypeOf(nil): encIgnore,
}
encEngines = [...]encEng{
reflect.Invalid: encIgnore,
reflect.Bool: encBool,
reflect.Int: encInt,
reflect.Int8: encInt8,
reflect.Int16: encInt16,
reflect.Int32: encInt32,
reflect.Int64: encInt64,
reflect.Uint: encUint,
reflect.Uint8: encUint8,
reflect.Uint16: encUint16,
reflect.Uint32: encUint32,
reflect.Uint64: encUint64,
reflect.Uintptr: encUintptr,
reflect.UnsafePointer: encPointer,
reflect.Float32: encFloat32,
reflect.Float64: encFloat64,
reflect.Complex64: encComplex64,
reflect.Complex128: encComplex128,
reflect.String: encString,
}
encLock sync.RWMutex
)
func UnusedUnixNanoEncodeTimeType() {
delete(rt2encEng, reflect.TypeOf((*time.Time)(nil)).Elem())
delete(rt2decEng, reflect.TypeOf((*time.Time)(nil)).Elem())
}
func getEncEngine(rt reflect.Type) encEng {
encLock.RLock()
engine := rt2encEng[rt]
encLock.RUnlock()
if engine != nil {
return engine
}
encLock.Lock()
buildEncEngine(rt, &engine)
encLock.Unlock()
return engine
}
func buildEncEngine(rt reflect.Type, engPtr *encEng) {
engine := rt2encEng[rt]
if engine != nil {
*engPtr = engine
return
}
if engine, _ = implementOtherSerializer(rt); engine != nil {
rt2encEng[rt] = engine
*engPtr = engine
return
}
kind := rt.Kind()
var eEng encEng
switch kind {
case reflect.Ptr:
defer buildEncEngine(rt.Elem(), &eEng)
engine = func(e *Encoder, p unsafe.Pointer) {
isNotNil := !isNil(p)
e.encIsNotNil(isNotNil)
if isNotNil {
eEng(e, *(*unsafe.Pointer)(p))
}
}
case reflect.Array:
et, l := rt.Elem(), rt.Len()
defer buildEncEngine(et, &eEng)
size := et.Size()
engine = func(e *Encoder, p unsafe.Pointer) {
for i := 0; i < l; i++ {
eEng(e, unsafe.Pointer(uintptr(p)+uintptr(i)*size))
}
}
case reflect.Slice:
et := rt.Elem()
size := et.Size()
defer buildEncEngine(et, &eEng)
engine = func(e *Encoder, p unsafe.Pointer) {
isNotNil := !isNil(p)
e.encIsNotNil(isNotNil)
if isNotNil {
header := (*reflect.SliceHeader)(p)
l := header.Len
e.encLength(l)
for i := 0; i < l; i++ {
eEng(e, unsafe.Pointer(header.Data+uintptr(i)*size))
}
}
}
case reflect.Map:
var kEng encEng
defer buildEncEngine(rt.Key(), &kEng)
defer buildEncEngine(rt.Elem(), &eEng)
engine = func(e *Encoder, p unsafe.Pointer) {
isNotNil := !isNil(p)
e.encIsNotNil(isNotNil)
if isNotNil {
v := reflect.NewAt(rt, p).Elem()
e.encLength(v.Len())
keys := v.MapKeys()
for i := 0; i < len(keys); i++ {
val := v.MapIndex(keys[i])
kEng(e, getUnsafePointer(&keys[i]))
eEng(e, getUnsafePointer(&val))
}
}
}
case reflect.Struct:
fields, offs := getFieldType(rt, 0)
nf := len(fields)
fEngines := make([]encEng, nf)
defer func() {
for i := 0; i < nf; i++ {
buildEncEngine(fields[i], &fEngines[i])
}
}()
engine = func(e *Encoder, p unsafe.Pointer) {
for i := 0; i < len(fEngines) && i < len(offs); i++ {
fEngines[i](e, unsafe.Pointer(uintptr(p)+offs[i]))
}
}
case reflect.Interface:
if rt.NumMethod() > 0 {
engine = func(e *Encoder, p unsafe.Pointer) {
isNotNil := !isNil(p)
e.encIsNotNil(isNotNil)
if isNotNil {
v := reflect.ValueOf(*(*interface {
M()
})(p))
et := v.Type()
e.encString(getNameOfType(et))
getEncEngine(et)(e, getUnsafePointer(&v))
}
}
} else {
engine = func(e *Encoder, p unsafe.Pointer) {
isNotNil := !isNil(p)
e.encIsNotNil(isNotNil)
if isNotNil {
v := reflect.ValueOf(*(*interface{})(p))
et := v.Type()
e.encString(getNameOfType(et))
getEncEngine(et)(e, getUnsafePointer(&v))
}
}
}
case reflect.Chan, reflect.Func:
//panic("not support " + rt.String() + " type")
default:
engine = encEngines[kind]
}
rt2encEng[rt] = engine
*engPtr = engine
}

View File

@ -1,108 +0,0 @@
package gotiny
import (
"time"
"unsafe"
)
func (e *Encoder) encBool(v bool) {
if e.boolBit == 0 {
e.boolPos = len(e.buf)
e.buf = append(e.buf, 0)
e.boolBit = 1
}
if v {
e.buf[e.boolPos] |= e.boolBit
}
e.boolBit <<= 1
}
func (e *Encoder) encUint64(v uint64) {
switch {
case v < 1<<7-1:
e.buf = append(e.buf, byte(v))
case v < 1<<14-1:
e.buf = append(e.buf, byte(v)|0x80, byte(v>>7))
case v < 1<<21-1:
e.buf = append(e.buf, byte(v)|0x80, byte(v>>7)|0x80, byte(v>>14))
case v < 1<<28-1:
e.buf = append(e.buf, byte(v)|0x80, byte(v>>7)|0x80, byte(v>>14)|0x80, byte(v>>21))
case v < 1<<35-1:
e.buf = append(e.buf, byte(v)|0x80, byte(v>>7)|0x80, byte(v>>14)|0x80, byte(v>>21)|0x80, byte(v>>28))
case v < 1<<42-1:
e.buf = append(e.buf, byte(v)|0x80, byte(v>>7)|0x80, byte(v>>14)|0x80, byte(v>>21)|0x80, byte(v>>28)|0x80, byte(v>>35))
case v < 1<<49-1:
e.buf = append(e.buf, byte(v)|0x80, byte(v>>7)|0x80, byte(v>>14)|0x80, byte(v>>21)|0x80, byte(v>>28)|0x80, byte(v>>35)|0x80, byte(v>>42))
case v < 1<<56-1:
e.buf = append(e.buf, byte(v)|0x80, byte(v>>7)|0x80, byte(v>>14)|0x80, byte(v>>21)|0x80, byte(v>>28)|0x80, byte(v>>35)|0x80, byte(v>>42)|0x80, byte(v>>49))
default:
e.buf = append(e.buf, byte(v)|0x80, byte(v>>7)|0x80, byte(v>>14)|0x80, byte(v>>21)|0x80, byte(v>>28)|0x80, byte(v>>35)|0x80, byte(v>>42)|0x80, byte(v>>49)|0x80, byte(v>>56))
}
}
func (e *Encoder) encUint16(v uint16) {
if v < 1<<7-1 {
e.buf = append(e.buf, byte(v))
} else if v < 1<<14-1 {
e.buf = append(e.buf, byte(v)|0x80, byte(v>>7))
} else {
e.buf = append(e.buf, byte(v)|0x80, byte(v>>7)|0x80, byte(v>>14))
}
}
func (e *Encoder) encUint32(v uint32) {
switch {
case v < 1<<7-1:
e.buf = append(e.buf, byte(v))
case v < 1<<14-1:
e.buf = append(e.buf, byte(v)|0x80, byte(v>>7))
case v < 1<<21-1:
e.buf = append(e.buf, byte(v)|0x80, byte(v>>7)|0x80, byte(v>>14))
case v < 1<<28-1:
e.buf = append(e.buf, byte(v)|0x80, byte(v>>7)|0x80, byte(v>>14)|0x80, byte(v>>21))
default:
e.buf = append(e.buf, byte(v)|0x80, byte(v>>7)|0x80, byte(v>>14)|0x80, byte(v>>21)|0x80, byte(v>>28))
}
}
func (e *Encoder) encLength(v int) { e.encUint32(uint32(v)) }
func (e *Encoder) encString(s string) { e.encUint32(uint32(len(s))); e.buf = append(e.buf, s...) }
func (e *Encoder) encIsNotNil(v bool) { e.encBool(v) }
func encIgnore(*Encoder, unsafe.Pointer) {}
func encBool(e *Encoder, p unsafe.Pointer) { e.encBool(*(*bool)(p)) }
func encInt(e *Encoder, p unsafe.Pointer) { e.encUint64(int64ToUint64(int64(*(*int)(p)))) }
func encInt8(e *Encoder, p unsafe.Pointer) { e.buf = append(e.buf, *(*uint8)(p)) }
func encInt16(e *Encoder, p unsafe.Pointer) { e.encUint16(int16ToUint16(*(*int16)(p))) }
func encInt32(e *Encoder, p unsafe.Pointer) { e.encUint32(int32ToUint32(*(*int32)(p))) }
func encInt64(e *Encoder, p unsafe.Pointer) { e.encUint64(int64ToUint64(*(*int64)(p))) }
func encUint8(e *Encoder, p unsafe.Pointer) { e.buf = append(e.buf, *(*uint8)(p)) }
func encUint16(e *Encoder, p unsafe.Pointer) { e.encUint16(*(*uint16)(p)) }
func encUint32(e *Encoder, p unsafe.Pointer) { e.encUint32(*(*uint32)(p)) }
func encUint64(e *Encoder, p unsafe.Pointer) { e.encUint64(uint64(*(*uint64)(p))) }
func encUint(e *Encoder, p unsafe.Pointer) { e.encUint64(uint64(*(*uint)(p))) }
func encUintptr(e *Encoder, p unsafe.Pointer) { e.encUint64(uint64(*(*uintptr)(p))) }
func encPointer(e *Encoder, p unsafe.Pointer) { e.encUint64(uint64(*(*uintptr)(p))) }
func encFloat32(e *Encoder, p unsafe.Pointer) { e.encUint32(float32ToUint32(p)) }
func encFloat64(e *Encoder, p unsafe.Pointer) { e.encUint64(float64ToUint64(p)) }
func encString(e *Encoder, p unsafe.Pointer) {
s := *(*string)(p)
e.encUint32(uint32(len(s)))
e.buf = append(e.buf, s...)
}
func encTime(e *Encoder, p unsafe.Pointer) { e.encUint64(uint64((*time.Time)(p).UnixNano())) }
func encComplex64(e *Encoder, p unsafe.Pointer) { e.encUint64(*(*uint64)(p)) }
func encComplex128(e *Encoder, p unsafe.Pointer) {
e.encUint64(*(*uint64)(p))
e.encUint64(*(*uint64)(unsafe.Pointer(uintptr(p) + ptr1Size)))
}
func encBytes(e *Encoder, p unsafe.Pointer) {
isNotNil := !isNil(p)
e.encIsNotNil(isNotNil)
if isNotNil {
buf := *(*[]byte)(p)
e.encLength(len(buf))
e.buf = append(e.buf, buf...)
}
}

View File

@ -1,103 +0,0 @@
package gotiny
import (
"reflect"
"unsafe"
)
type Encoder struct {
buf []byte //编码目的数组
off int
boolPos int //下一次要设置的bool在buf中的下标,即buf[boolPos]
boolBit byte //下一次要设置的bool的buf[boolPos]中的bit位
engines []encEng
length int
}
func Marshal(is ...interface{}) []byte {
return NewEncoderWithPtr(is...).Encode(is...)
}
// 创建一个编码ps 指向类型的编码器
func NewEncoderWithPtr(ps ...interface{}) *Encoder {
l := len(ps)
engines := make([]encEng, l)
for i := 0; i < l; i++ {
rt := reflect.TypeOf(ps[i])
if rt.Kind() != reflect.Ptr {
panic("must a pointer type!")
}
engines[i] = getEncEngine(rt.Elem())
}
return &Encoder{
length: l,
engines: engines,
}
}
// 创建一个编码is 类型的编码器
func NewEncoder(is ...interface{}) *Encoder {
l := len(is)
engines := make([]encEng, l)
for i := 0; i < l; i++ {
engines[i] = getEncEngine(reflect.TypeOf(is[i]))
}
return &Encoder{
length: l,
engines: engines,
}
}
func NewEncoderWithType(ts ...reflect.Type) *Encoder {
l := len(ts)
engines := make([]encEng, l)
for i := 0; i < l; i++ {
engines[i] = getEncEngine(ts[i])
}
return &Encoder{
length: l,
engines: engines,
}
}
// 入参是要编码值的指针
func (e *Encoder) Encode(is ...interface{}) []byte {
engines := e.engines
for i := 0; i < len(engines) && i < len(is); i++ {
engines[i](e, (*[2]unsafe.Pointer)(unsafe.Pointer(&is[i]))[1])
}
return e.reset()
}
// 入参是要编码的值得unsafe.Pointer 指针
func (e *Encoder) EncodePtr(ps ...unsafe.Pointer) []byte {
engines := e.engines
for i := 0; i < len(engines) && i < len(ps); i++ {
engines[i](e, ps[i])
}
return e.reset()
}
// vs 是持有要编码的值
func (e *Encoder) EncodeValue(vs ...reflect.Value) []byte {
engines := e.engines
for i := 0; i < len(engines) && i < len(vs); i++ {
engines[i](e, getUnsafePointer(&vs[i]))
}
return e.reset()
}
// 编码产生的数据将append到buf上
func (e *Encoder) AppendTo(buf []byte) {
e.off = len(buf)
e.buf = buf
}
func (e *Encoder) reset() []byte {
buf := e.buf
e.buf = buf[:e.off]
e.boolBit = 0
e.boolPos = 0
return buf
}

View File

@ -1,144 +0,0 @@
package gotiny
import (
"reflect"
"strconv"
)
var (
type2name = map[reflect.Type]string{}
name2type = map[string]reflect.Type{}
)
func GetName(obj interface{}) string {
return GetNameByType(reflect.TypeOf(obj))
}
func GetNameByType(rt reflect.Type) string {
return string(getName([]byte(nil), rt))
}
func getName(prefix []byte, rt reflect.Type) []byte {
if rt == nil || rt.Kind() == reflect.Invalid {
return append(prefix, []byte("<nil>")...)
}
if rt.Name() == "" { //未命名的,组合类型
switch rt.Kind() {
case reflect.Ptr:
return getName(append(prefix, '*'), rt.Elem())
case reflect.Array:
return getName(append(prefix, "["+strconv.Itoa(rt.Len())+"]"...), rt.Elem())
case reflect.Slice:
return getName(append(prefix, '[', ']'), rt.Elem())
case reflect.Struct:
prefix = append(prefix, "struct {"...)
nf := rt.NumField()
if nf > 0 {
prefix = append(prefix, ' ')
}
for i := 0; i < nf; i++ {
field := rt.Field(i)
if field.Anonymous {
prefix = getName(prefix, field.Type)
} else {
prefix = getName(append(prefix, field.Name+" "...), field.Type)
}
if i != nf-1 {
prefix = append(prefix, ';', ' ')
} else {
prefix = append(prefix, ' ')
}
}
return append(prefix, '}')
case reflect.Map:
return getName(append(getName(append(prefix, "map["...), rt.Key()), ']'), rt.Elem())
case reflect.Interface:
prefix = append(prefix, "interface {"...)
nm := rt.NumMethod()
if nm > 0 {
prefix = append(prefix, ' ')
}
for i := 0; i < nm; i++ {
method := rt.Method(i)
fn := getName([]byte(nil), method.Type)
prefix = append(prefix, method.Name+string(fn[4:])...)
if i != nm-1 {
prefix = append(prefix, ';', ' ')
} else {
prefix = append(prefix, ' ')
}
}
return append(prefix, '}')
case reflect.Func:
prefix = append(prefix, "func("...)
for i := 0; i < rt.NumIn(); i++ {
prefix = getName(prefix, rt.In(i))
if i != rt.NumIn()-1 {
prefix = append(prefix, ',', ' ')
}
}
prefix = append(prefix, ')')
no := rt.NumOut()
if no > 0 {
prefix = append(prefix, ' ')
}
if no > 1 {
prefix = append(prefix, '(')
}
for i := 0; i < no; i++ {
prefix = getName(prefix, rt.Out(i))
if i != no-1 {
prefix = append(prefix, ',', ' ')
}
}
if no > 1 {
prefix = append(prefix, ')')
}
return prefix
}
}
if rt.PkgPath() == "" {
prefix = append(prefix, rt.Name()...)
} else {
prefix = append(prefix, rt.PkgPath()+"."+rt.Name()...)
}
return prefix
}
func getNameOfType(rt reflect.Type) string {
if name, has := type2name[rt]; has {
return name
} else {
return registerType(rt)
}
}
func Register(i interface{}) string {
return registerType(reflect.TypeOf(i))
}
func registerType(rt reflect.Type) string {
name := GetNameByType(rt)
RegisterName(name, rt)
return name
}
func RegisterName(name string, rt reflect.Type) {
if name == "" {
panic("attempt to register empty name")
}
if rt == nil || rt.Kind() == reflect.Invalid {
panic("attempt to register nil type or invalid type")
}
if _, has := type2name[rt]; has {
panic("gotiny: registering duplicate types for " + GetNameByType(rt))
}
if _, has := name2type[name]; has {
panic("gotiny: registering name" + name + " is exist")
}
name2type[name] = rt
type2name[rt] = name
}

View File

@ -1,57 +0,0 @@
package gotiny
import (
"reflect"
"unsafe"
)
const (
kindDirectIface = 1 << 5
)
// rtype is the common implementation of most values.
// It is embedded in other struct types.
//
// rtype must be kept in sync with reflect/type.go:/^type._type.
type rtype struct {
_ uintptr
_ uintptr // number of bytes in the type that can contain pointers
_ uint32 // hash of type; avoids computation in hash tables
_ uint8 // extra type information flags
_ uint8 // alignment of variable with this type
_ uint8 // alignment of struct field with this type
kind uint8 // enumeration for C
_ uintptr // algorithm table
_ uintptr // garbage collection data
_ int32 // string form
_ int32 // type for pointer to this type, may be zero
}
// ifaceIndir reports whether t is stored indirectly in an interface value.
func ifaceDirect(t *rtype) bool {
return t.kind&kindDirectIface != 0
}
func directType(rt *reflect.Type) bool {
return ifaceDirect((*rtype)((*[2]unsafe.Pointer)(unsafe.Pointer(rt))[1]))
}
type refVal struct {
_ unsafe.Pointer
ptr unsafe.Pointer
flag flag
}
type flag uintptr
//go:linkname flagIndir reflect.flagIndir
const flagIndir flag = 1 << 7
func getUnsafePointer(rv *reflect.Value) unsafe.Pointer {
vv := (*refVal)(unsafe.Pointer(rv))
if vv.flag&flagIndir == 0 {
return unsafe.Pointer(&vv.ptr)
} else {
return vv.ptr
}
}

View File

@ -1,185 +0,0 @@
package gotiny
import (
"encoding"
"encoding/gob"
"reflect"
"strings"
"unsafe"
)
const (
ptr1Size = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const
)
func float64ToUint64(v unsafe.Pointer) uint64 {
return reverse64Byte(*(*uint64)(v))
}
func uint64ToFloat64(u uint64) float64 {
u = reverse64Byte(u)
return *((*float64)(unsafe.Pointer(&u)))
}
func reverse64Byte(u uint64) uint64 {
u = (u << 32) | (u >> 32)
u = ((u << 16) & 0xFFFF0000FFFF0000) | ((u >> 16) & 0xFFFF0000FFFF)
u = ((u << 8) & 0xFF00FF00FF00FF00) | ((u >> 8) & 0xFF00FF00FF00FF)
return u
}
func float32ToUint32(v unsafe.Pointer) uint32 {
return reverse32Byte(*(*uint32)(v))
}
func uint32ToFloat32(u uint32) float32 {
u = reverse32Byte(u)
return *((*float32)(unsafe.Pointer(&u)))
}
func reverse32Byte(u uint32) uint32 {
u = (u << 16) | (u >> 16)
return ((u << 8) & 0xFF00FF00) | ((u >> 8) & 0xFF00FF)
}
// int -5 -4 -3 -2 -1 0 1 2 3 4 5 6
// uint 9 7 5 3 1 0 2 4 6 8 10 12
func int64ToUint64(v int64) uint64 {
return uint64((v << 1) ^ (v >> 63))
}
// uint 9 7 5 3 1 0 2 4 6 8 10 12
// int -5 -4 -3 -2 -1 0 1 2 3 4 5 6
func uint64ToInt64(u uint64) int64 {
v := int64(u)
return (-(v & 1)) ^ (v>>1)&0x7FFFFFFFFFFFFFFF
}
// int -5 -4 -3 -2 -1 0 1 2 3 4 5 6
// uint 9 7 5 3 1 0 2 4 6 8 10 12
func int32ToUint32(v int32) uint32 {
return uint32((v << 1) ^ (v >> 31))
}
// uint 9 7 5 3 1 0 2 4 6 8 10 12
// int -5 -4 -3 -2 -1 0 1 2 3 4 5 6
func uint32ToInt32(u uint32) int32 {
v := int32(u)
return (-(v & 1)) ^ (v>>1)&0x7FFFFFFF
}
// int -5 -4 -3 -2 -1 0 1 2 3 4 5 6
// uint 9 7 5 3 1 0 2 4 6 8 10 12
func int16ToUint16(v int16) uint16 {
return uint16((v << 1) ^ (v >> 15))
}
// uint 9 7 5 3 1 0 2 4 6 8 10 12
// int -5 -4 -3 -2 -1 0 1 2 3 4 5 6
func uint16ToInt16(u uint16) int16 {
v := int16(u)
return (-(v & 1)) ^ (v>>1)&0x7FFF
}
func isNil(p unsafe.Pointer) bool {
return *(*unsafe.Pointer)(p) == nil
}
type gobInter interface {
gob.GobEncoder
gob.GobDecoder
}
type binInter interface {
encoding.BinaryMarshaler
encoding.BinaryUnmarshaler
}
// 只应该由指针来实现该接口
type GoTinySerializer interface {
// 编码方法将对象的序列化结果append到入参数并返回方法不应该修改入参数值原有的值
GotinyEncode([]byte) []byte
// 解码方法将入参解码到对象里并返回使用的长度。方法从入参的第0个字节开始使用并且不应该修改入参中的任何数据
GotinyDecode([]byte) int
}
func implementOtherSerializer(rt reflect.Type) (encEng encEng, decEng decEng) {
rtNil := reflect.Zero(reflect.PtrTo(rt)).Interface()
if _, ok := rtNil.(GoTinySerializer); ok {
encEng = func(e *Encoder, p unsafe.Pointer) {
e.buf = reflect.NewAt(rt, p).Interface().(GoTinySerializer).GotinyEncode(e.buf)
}
decEng = func(d *Decoder, p unsafe.Pointer) {
d.index += reflect.NewAt(rt, p).Interface().(GoTinySerializer).GotinyDecode(d.buf[d.index:])
}
return
}
if _, ok := rtNil.(binInter); ok {
encEng = func(e *Encoder, p unsafe.Pointer) {
buf, err := reflect.NewAt(rt, p).Interface().(encoding.BinaryMarshaler).MarshalBinary()
if err != nil {
panic(err)
}
e.encLength(len(buf))
e.buf = append(e.buf, buf...)
}
decEng = func(d *Decoder, p unsafe.Pointer) {
length := d.decLength()
start := d.index
d.index += length
if err := reflect.NewAt(rt, p).Interface().(encoding.BinaryUnmarshaler).UnmarshalBinary(d.buf[start:d.index]); err != nil {
panic(err)
}
}
return
}
if _, ok := rtNil.(gobInter); ok {
encEng = func(e *Encoder, p unsafe.Pointer) {
buf, err := reflect.NewAt(rt, p).Interface().(gob.GobEncoder).GobEncode()
if err != nil {
panic(err)
}
e.encLength(len(buf))
e.buf = append(e.buf, buf...)
}
decEng = func(d *Decoder, p unsafe.Pointer) {
length := d.decLength()
start := d.index
d.index += length
if err := reflect.NewAt(rt, p).Interface().(gob.GobDecoder).GobDecode(d.buf[start:d.index]); err != nil {
panic(err)
}
}
}
return
}
// rt.kind is reflect.struct
func getFieldType(rt reflect.Type, baseOff uintptr) (fields []reflect.Type, offs []uintptr) {
for i := 0; i < rt.NumField(); i++ {
field := rt.Field(i)
if ignoreField(field) {
continue
}
ft := field.Type
if ft.Kind() == reflect.Struct {
if _, engine := implementOtherSerializer(ft); engine == nil {
fFields, fOffs := getFieldType(ft, field.Offset+baseOff)
fields = append(fields, fFields...)
offs = append(offs, fOffs...)
continue
}
}
fields = append(fields, ft)
offs = append(offs, field.Offset+baseOff)
}
return
}
func ignoreField(field reflect.StructField) bool {
tinyTag, ok := field.Tag.Lookup("gotiny")
return ok && strings.TrimSpace(tinyTag) == "-"
}

View File

@ -9,14 +9,14 @@ import (
// don't forget to replace the msgp import path to:
// "github.com/gofiber/fiber/v2/internal/msgp"
type data struct {
sync.RWMutex `gotiny:"-"`
d map[string]interface{} `gotiny:"d"`
sync.RWMutex
Data map[string]interface{}
}
var dataPool = sync.Pool{
New: func() interface{} {
d := new(data)
d.d = make(map[string]interface{})
d.Data = make(map[string]interface{})
return d
},
}
@ -32,31 +32,31 @@ func releaseData(d *data) {
func (d *data) Reset() {
d.Lock()
for key := range d.d {
delete(d.d, key)
for key := range d.Data {
delete(d.Data, key)
}
d.Unlock()
}
func (d *data) Get(key string) interface{} {
d.RLock()
v := d.d[key]
v := d.Data[key]
d.RUnlock()
return v
}
func (d *data) Set(key string, value interface{}) {
d.Lock()
d.d[key] = value
d.Data[key] = value
d.Unlock()
}
func (d *data) Delete(key string) {
d.Lock()
delete(d.d, key)
delete(d.Data, key)
d.Unlock()
}
func (d *data) Len() int {
return len(d.d)
return len(d.Data)
}

View File

@ -1,21 +1,23 @@
package session
import (
"bytes"
"encoding/gob"
"sync"
"time"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/internal/gotiny"
"github.com/gofiber/fiber/v2/utils"
"github.com/valyala/fasthttp"
)
type Session struct {
id string // session id
fresh bool // if new session
ctx *fiber.Ctx // fiber context
config *Store // store configuration
data *data // key value data
id string // session id
fresh bool // if new session
ctx *fiber.Ctx // fiber context
config *Store // store configuration
data *data // key value data
byteBuffer *bytes.Buffer // byte buffer for the en- and decode
}
var sessionPool = sync.Pool{
@ -29,6 +31,9 @@ func acquireSession() *Session {
if s.data == nil {
s.data = acquireData()
}
if s.byteBuffer == nil {
s.byteBuffer = new(bytes.Buffer)
}
s.fresh = true
return s
}
@ -40,6 +45,9 @@ func releaseSession(s *Session) {
if s.data != nil {
s.data.Reset()
}
if s.byteBuffer != nil {
s.byteBuffer.Reset()
}
sessionPool.Put(s)
}
@ -134,11 +142,15 @@ func (s *Session) Save() error {
// Convert data to bytes
mux.Lock()
data := gotiny.Marshal(&s.data)
encCache := gob.NewEncoder(s.byteBuffer)
err := encCache.Encode(&s.data.Data)
if err != nil {
return err
}
mux.Unlock()
// pass raw bytes with session id to provider
if err := s.config.Storage.Set(s.id, data, s.config.Expiration); err != nil {
if err := s.config.Storage.Set(s.id, s.byteBuffer.Bytes(), s.config.Expiration); err != nil {
return err
}

View File

@ -92,6 +92,7 @@ func Test_Session_Types(t *testing.T) {
type User struct {
Name string
}
store.RegisterType(User{})
var vuser = User{
Name: "John",
}

View File

@ -1,10 +1,10 @@
package session
import (
"encoding/gob"
"sync"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/internal/gotiny"
"github.com/gofiber/fiber/v2/internal/storage/memory"
"github.com/gofiber/fiber/v2/utils"
"github.com/valyala/fasthttp"
@ -32,7 +32,7 @@ func New(config ...Config) *Store {
// RegisterType will allow you to encode/decode custom types
// into any Storage provider
func (s *Store) RegisterType(i interface{}) {
gotiny.Register(i)
gob.Register(i)
}
// Get will get/create a session
@ -70,7 +70,12 @@ func (s *Store) Get(c *fiber.Ctx) (*Session, error) {
// Unmashal if we found data
if raw != nil && err == nil {
mux.Lock()
gotiny.Unmarshal(raw, &sess.data)
_, _ = sess.byteBuffer.Write(raw)
encCache := gob.NewDecoder(sess.byteBuffer)
err := encCache.Decode(&sess.data.Data)
if err != nil {
return nil, err
}
mux.Unlock()
} else if err != nil {
return nil, err