You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ngs/session/session.go

399 lines
7.3 KiB
Go

package session
import (
"errors"
"git.noahlan.cn/northlan/ngs/service"
"net"
"sync"
"sync/atomic"
"time"
)
// NetworkEntity represent low-level network instance
type NetworkEntity interface {
Push(route string, v interface{}) error
RPC(route string, v interface{}) error
LastMid() uint64
Response(v interface{}) error
ResponseMid(mid uint64, v interface{}) error
Close() error
RemoteAddr() net.Addr
}
var (
// ErrIllegalUID represents a invalid uid
ErrIllegalUID = errors.New("illegal uid")
)
// Session represents a client session which could storage temp data during low-level
// keep connected, all data will be released when the low-level connection was broken.
// Session instance related to the client will be passed to Handler method as the first
// parameter.
type Session struct {
sync.RWMutex // protect data
id int64 // session global unique id
uid int64 // binding user id
lastTime int64 // last heartbeat time
entity NetworkEntity // low-level network entity
data map[string]interface{} // session data store
router *Router
}
// New returns a new session instance
// a NetworkEntity is a low-level network instance
func New(entity NetworkEntity) *Session {
return &Session{
id: service.Connections.SessionID(),
entity: entity,
data: make(map[string]interface{}),
lastTime: time.Now().Unix(),
router: newRouter(),
}
}
// NetworkEntity returns the low-level network agent object
func (s *Session) NetworkEntity() NetworkEntity {
return s.entity
}
// Router returns the service router
func (s *Session) Router() *Router {
return s.router
}
// RPC sends message to remote server
func (s *Session) RPC(route string, v interface{}) error {
return s.entity.RPC(route, v)
}
// Push message to client
func (s *Session) Push(route string, v interface{}) error {
return s.entity.Push(route, v)
}
// Response message to client
func (s *Session) Response(v interface{}) error {
return s.entity.Response(v)
}
// ResponseMID responses message to client, mid is
// request message ID
func (s *Session) ResponseMID(mid uint64, v interface{}) error {
return s.entity.ResponseMid(mid, v)
}
// ID returns the session id
func (s *Session) ID() int64 {
return s.id
}
// UID returns uid that bind to current session
func (s *Session) UID() int64 {
return atomic.LoadInt64(&s.uid)
}
// LastMid returns the last message id
func (s *Session) LastMid() uint64 {
return s.entity.LastMid()
}
// Bind UID to current session
func (s *Session) Bind(uid int64) error {
if uid < 1 {
return ErrIllegalUID
}
atomic.StoreInt64(&s.uid, uid)
return nil
}
// Close terminate current session, session related data will not be released,
// all related data should be Clear explicitly in Session closed callback
func (s *Session) Close() {
_ = s.entity.Close()
}
// RemoteAddr returns the remote network address.
func (s *Session) RemoteAddr() net.Addr {
return s.entity.RemoteAddr()
}
// Remove delete data associated with the key from session storage
func (s *Session) Remove(key string) {
s.Lock()
defer s.Unlock()
delete(s.data, key)
}
// Set associates value with the key in session storage
func (s *Session) Set(key string, value interface{}) {
s.Lock()
defer s.Unlock()
s.data[key] = value
}
// HasKey decides whether a key has associated value
func (s *Session) HasKey(key string) bool {
s.RLock()
defer s.RUnlock()
_, has := s.data[key]
return has
}
// Int returns the value associated with the key as a int.
func (s *Session) Int(key string) int {
s.RLock()
defer s.RUnlock()
v, ok := s.data[key]
if !ok {
return 0
}
value, ok := v.(int)
if !ok {
return 0
}
return value
}
// Int8 returns the value associated with the key as a int8.
func (s *Session) Int8(key string) int8 {
s.RLock()
defer s.RUnlock()
v, ok := s.data[key]
if !ok {
return 0
}
value, ok := v.(int8)
if !ok {
return 0
}
return value
}
// Int16 returns the value associated with the key as a int16.
func (s *Session) Int16(key string) int16 {
s.RLock()
defer s.RUnlock()
v, ok := s.data[key]
if !ok {
return 0
}
value, ok := v.(int16)
if !ok {
return 0
}
return value
}
// Int32 returns the value associated with the key as a int32.
func (s *Session) Int32(key string) int32 {
s.RLock()
defer s.RUnlock()
v, ok := s.data[key]
if !ok {
return 0
}
value, ok := v.(int32)
if !ok {
return 0
}
return value
}
// Int64 returns the value associated with the key as a int64.
func (s *Session) Int64(key string) int64 {
s.RLock()
defer s.RUnlock()
v, ok := s.data[key]
if !ok {
return 0
}
value, ok := v.(int64)
if !ok {
return 0
}
return value
}
// Uint returns the value associated with the key as a uint.
func (s *Session) Uint(key string) uint {
s.RLock()
defer s.RUnlock()
v, ok := s.data[key]
if !ok {
return 0
}
value, ok := v.(uint)
if !ok {
return 0
}
return value
}
// Uint8 returns the value associated with the key as a uint8.
func (s *Session) Uint8(key string) uint8 {
s.RLock()
defer s.RUnlock()
v, ok := s.data[key]
if !ok {
return 0
}
value, ok := v.(uint8)
if !ok {
return 0
}
return value
}
// Uint16 returns the value associated with the key as a uint16.
func (s *Session) Uint16(key string) uint16 {
s.RLock()
defer s.RUnlock()
v, ok := s.data[key]
if !ok {
return 0
}
value, ok := v.(uint16)
if !ok {
return 0
}
return value
}
// Uint32 returns the value associated with the key as a uint32.
func (s *Session) Uint32(key string) uint32 {
s.RLock()
defer s.RUnlock()
v, ok := s.data[key]
if !ok {
return 0
}
value, ok := v.(uint32)
if !ok {
return 0
}
return value
}
// Uint64 returns the value associated with the key as a uint64.
func (s *Session) Uint64(key string) uint64 {
s.RLock()
defer s.RUnlock()
v, ok := s.data[key]
if !ok {
return 0
}
value, ok := v.(uint64)
if !ok {
return 0
}
return value
}
// Float32 returns the value associated with the key as a float32.
func (s *Session) Float32(key string) float32 {
s.RLock()
defer s.RUnlock()
v, ok := s.data[key]
if !ok {
return 0
}
value, ok := v.(float32)
if !ok {
return 0
}
return value
}
// Float64 returns the value associated with the key as a float64.
func (s *Session) Float64(key string) float64 {
s.RLock()
defer s.RUnlock()
v, ok := s.data[key]
if !ok {
return 0
}
value, ok := v.(float64)
if !ok {
return 0
}
return value
}
// String returns the value associated with the key as a string.
func (s *Session) String(key string) string {
s.RLock()
defer s.RUnlock()
v, ok := s.data[key]
if !ok {
return ""
}
value, ok := v.(string)
if !ok {
return ""
}
return value
}
// Value returns the value associated with the key as a interface{}.
func (s *Session) Value(key string) interface{} {
s.RLock()
defer s.RUnlock()
return s.data[key]
}
// State returns all session state
func (s *Session) State() map[string]interface{} {
s.RLock()
defer s.RUnlock()
return s.data
}
// Restore session state after reconnect
func (s *Session) Restore(data map[string]interface{}) {
s.Lock()
defer s.Unlock()
s.data = data
}
// Clear releases all data related to current session
func (s *Session) Clear() {
s.Lock()
defer s.Unlock()
s.uid = 0
s.data = map[string]interface{}{}
}