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.
399 lines
7.3 KiB
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{}{}
|
|
}
|