#ifndef __SESSION_HPP__ #define __SESSION_HPP__ #include "online.hpp" #include "logger.hpp" #include typedef enum { UNLOGIN, LOGIN } ss_statu; /*用户session信息管理模块 -- 用于http短连接通信情况下用户状态的管理(登录/未登录)*/ /*session 类*/ class session { public: session(uint64_t ssid) : _ssid(ssid), _statu(LOGIN) { LOG(DEBUG, "session %d:%p 被创建", _ssid, this); } ~session() { LOG(DEBUG, "session %d:%p 被删除", _ssid, this); } /*添加用户*/ void add_user(uint64_t uid) { _uid = uid; } /*获取用户id*/ uint64_t get_user() { return _uid; } /*获取用户状态(检查用户是否已登录)*/ bool is_login() { return _statu == LOGIN; } /*获取session id*/ uint64_t get_ssid() { return _ssid; } /*设置session定时删除任务*/ void set_timer(const wsserver_t::timer_ptr &tp) { _tp = tp; } /*获取session关联的定时器*/ wsserver_t::timer_ptr& get_timer() { return _tp; } private: uint64_t _ssid; // session id uint64_t _uid; // session对应的用户id ss_statu _statu; // 用户状态(登录/未登录) wsserver_t::timer_ptr _tp; // session关联的定时器 }; #define SESSION_TIMEOUT 30000 //30s #define SESSION_FOREVER -1 /*使用智能指针来管理session信息*/ using session_ptr = std::shared_ptr; /*session 管理类*/ class session_manager { public: session_manager(wsserver_t *server) : _server(server), _next_ssid(1) { LOG(DEBUG, "用户session管理模块初始化成功"); } ~session_manager() { LOG(DEBUG, "用户session管理模块已被销毁"); } /*为指定用户创建session信息并返回*/ session_ptr create_session(uint64_t uid) { std::unique_lock lock(_mutex); // 创建session信息 session_ptr ssp(new session(_next_ssid)); ssp->add_user(uid); // 建立sessionID与session信息的关联关系 _sessions[_next_ssid] = ssp; // 更新下一个session的id计数 ++_next_ssid; return ssp; } /*通过sessionID获取session信息*/ session_ptr get_session_by_ssid(uint64_t ssid) { std::unique_lock lock(_mutex); auto it = _sessions.find(ssid); if(it == _sessions.end()) return session_ptr(); return _sessions[ssid]; } /*删除session信息*/ void remove_session(uint64_t ssid) { std::unique_lock lock(_mutex); _sessions.erase(ssid); } /*重新添加因cancel函数被删除的_sessions成员*/ void append_session(session_ptr ssp) { std::unique_lock lock(_mutex); _sessions.insert(make_pair(ssp->get_ssid(), ssp)); // _sessions[ssp->get_ssid()] = ssp; } /*设置session过期时间(毫秒)*/ /*基于websocketpp定时器(timer_ptr)来完成对session生命周期的管理*/ void set_session_expire_time(uint64_t ssid, int ms) { //当客户端与服务器建立http短连接通信(登录/注册)时,session应该是临时的,需要设置定时删除任务 //当客户端与服务器建立websocket长连接通信(游戏大厅/游戏房间)时,session应该是永久的,直到websocket长连接断开 session_ptr ssp = get_session_by_ssid(ssid); if(ssp.get() == nullptr) return; // 获取session状态 -- session对象创建时默认没有关联time_ptr,此时session是永久存在的(timer_ptr==nullptr) wsserver_t::timer_ptr tp = ssp->get_timer(); // 1. 在session永久的情况下设置永久 if(tp.get() == nullptr && ms == SESSION_FOREVER) return; // 2. 在session永久的情况下设置定时删除任务 else if(tp.get() == nullptr && ms != SESSION_FOREVER) { wsserver_t::timer_ptr tp_task = _server->set_timer(ms, std::bind(&session_manager::remove_session, this, ssid)); ssp->set_timer(tp_task); // 重新设置session关联的定时器 } // 3. 在session定时删除的情况下设置永久(删除定时任务) else if(tp.get() != nullptr && ms == SESSION_FOREVER) { // 注意:websocketpp使用cancel函数删除定时任务会导致定时任务直接被执行,所以我们需要重新向_sessions中添加ssid与session_ptr // 同时,由于这个定时任务不是立即被执行的(服务器处理时才处理这个任务),所以我们不能在cancel函数后面直接重新添加session_ptr(这样可能出现先添加、再删除的情况) // 而是需要专门设置一个定时器来添加ssid与session_ptr tp->cancel(); // 通过定时器来添加被删除的_sessions成员 _server->set_timer(0, std::bind(&session_manager::append_session, this, ssp)); ssp->set_timer(wsserver_t::timer_ptr()); // 将session关联的定时器设置为空(session永久有效) } // 4. 在session定时删除的情况下重置删除时间 else { // 先删除定时任务 tp->cancel(); _server->set_timer(0, std::bind(&session_manager::append_session, this, ssp)); ssp->set_timer(wsserver_t::timer_ptr()); // 将session关联的定时器设置为空(session永久有效) // 再重新添加定时任务 wsserver_t::timer_ptr tp_task = _server->set_timer(ms, std::bind(&session_manager::remove_session, this, ssid)); ssp->set_timer(tp_task); // 重新设置session关联的定时器 } } private: uint64_t _next_ssid; // sessionID计数器 std::mutex _mutex; std::unordered_map _sessions; // 建立ssid与session信息之间的关联关系 wsserver_t *_server; // 服务器指针对象,用于设置定时任务 }; #endif