Files
2016-12-28 19:40:55 -05:00

140 lines
4.2 KiB
Markdown

# 6.3 Almacenamiento de sesiones
Introducimos los principios de un manejador de sesiones simple en la sección anterior, y entre otras cosas, definimos una interfaz de almacenamiento de sesión. En esta sección, voy a mostrarte un ejemplo de un motor de sesiones basado en memoria que implementa esa interfaz. Puedes mejorar este a otros mecanísmos de almacenamiento también.
```
package memory
import (
"container/list"
"github.com/astaxie/session"
"sync"
"time"
)
var pder = &Provider{list: list.New()}
type SessionStore struct {
sid string // identificador único de sesión
timeAccessed time.Time // último tiempo de acceso
value map[interface{}]interface{} // valor de la sesión accedida
}
func (st *SessionStore) Set(key, value interface{}) error {
st.value[key] = value
pder.SessionUpdate(st.sid)
return nil
}
func (st *SessionStore) Get(key interface{}) interface{} {
pder.SessionUpdate(st.sid)
if v, ok := st.value[key]; ok {
return v
} else {
return nil
}
return nil
}
func (st *SessionStore) Delete(key interface{}) error {
delete(st.value, key)
pder.SessionUpdate(st.sid)
return nil
}
func (st *SessionStore) SessionID() string {
return st.sid
}
type Provider struct {
lock sync.Mutex // bloqueo
sessions map[string]*list.Element // guardar en memoria
list *list.List // recikector de basura
}
func (pder *Provider) SessionInit(sid string) (session.Session, error) {
pder.lock.Lock()
defer pder.lock.Unlock()
v := make(map[interface{}]interface{}, 0)
newsess := &SessionStore{sid: sid, timeAccessed: time.Now(), value: v}
element := pder.list.PushBack(newsess)
pder.sessions[sid] = element
return newsess, nil
}
func (pder *Provider) SessionRead(sid string) (session.Session, error) {
if element, ok := pder.sessions[sid]; ok {
return element.Value.(*SessionStore), nil
} else {
sess, err := pder.SessionInit(sid)
return sess, err
}
return nil, nil
}
func (pder *Provider) SessionDestroy(sid string) error {
if element, ok := pder.sessions[sid]; ok {
delete(pder.sessions, sid)
pder.list.Remove(element)
return nil
}
return nil
}
func (pder *Provider) SessionGC(maxlifetime int64) {
pder.lock.Lock()
defer pder.lock.Unlock()
for {
element := pder.list.Back()
if element == nil {
break
}
if (element.Value.(*SessionStore).timeAccessed.Unix() + maxlifetime) < time.Now().Unix() {
pder.list.Remove(element)
delete(pder.sessions, element.Value.(*SessionStore).sid)
} else {
break
}
}
}
func (pder *Provider) SessionUpdate(sid string) error {
pder.lock.Lock()
defer pder.lock.Unlock()
if element, ok := pder.sessions[sid]; ok {
element.Value.(*SessionStore).timeAccessed = time.Now()
pder.list.MoveToFront(element)
return nil
}
return nil
}
func init() {
pder.sessions = make(map[string]*list.Element, 0)
session.Register("memory", pder)
}
```
El ejmplo superior implementa un mecanismo de almacenamiento de sesiones en memoria. Usa la función `init()` para registrar este motor de almacenamiento al manejador de sesiones. ¿Cómo registramos este motor en nuestro programa principal?
```
import (
"github.com/astaxie/session"
_ "github.com/astaxie/session/providers/memory"
)
```
Usamos el mecanismo de importación del guión bajo (que invoca a la funcuón `init` del paquete automáticamente) para registrar este motor al manejador de sesiones. Luego usamos el siguiente código para inicializar el manejador de sesión.
```
var globalSessions *session.Manager
// initialize in init() function
func init() {
globalSessions, _ = session.NewManager("memory", "gosessionid", 3600)
go globalSessions.GC()
}
```
## Enlaces
- [Índice](preface.md)
- Sección previa: [Cómo usar sesiones en Go](06.2.md)
- Siguiente sección: [Prevenir el hijacking de sesión](06.4.md)