前面准备了那么多,这里就直接是水到渠成了。
该讲的前面都讲的差不多了,剩下还没讲的都在代码里面。
不过由于文档Telnet一直是发送不了数据的状态,就一直没法进一步的测试,等后面写了客户端再说。
#ifndef CHATSERVICE_H_
#define CHATSERVICE_H_
#include<muduo/net/TcpConnection.h>
#include<unordered_map>
#include<functional>
#include<mutex>
#include "json.hpp"
#include "usermodel.hpp"
using json = nlohmann::json;
using namespace std;
using namespace muduo;
using namespace muduo::net;
//处理消息的事件回调方法类型
using MsgHandler = std::function<void(const TcpConnectionPtr &conn,json &js,Timestamp time)>;
//聊天服务器业务
class ChatService{
public:
//单例模式
static ChatService* instance();
void login(const TcpConnectionPtr &conn,json &js,Timestamp time);
void reg(const TcpConnectionPtr &conn,json &js,Timestamp time);
//获取消息对应的处理器
MsgHandler getHandle(int msgid);
private:
ChatService();
//存储消息id和对应的处理方法
unordered_map<int,MsgHandler> _msgHanderMap;
//存储在线用户连接
unordered_map<int,TcpConnectionPtr> _userConnMap;
//数据操作类的对象
UserModel _usermodel;
//定义互斥锁
mutex _connMutex;
};
#endif
#include"chatservice.hpp"
#include"public.hpp"
#include<string>
#include<muduo/base/Logging.h>
using namespace std;
using namespace muduo;
ChatService* ChatService::instance(){
static ChatService service;
return &service;
}
//注册消息以及对应的回调操作
ChatService::ChatService(){
_msgHanderMap.insert({LOGIN_TYPE,std::bind(&ChatService::login,this,_1,_2,_3)});
_msgHanderMap.insert({REG_TYPE,std::bind(&ChatService::reg,this,_1,_2,_3)});
}
//获取存储消息id和对应的处理方法
MsgHandler ChatService::getHandle(int msgid){
//日志记录
auto it = _msgHanderMap.find(msgid);
if(it == _msgHanderMap.end()){
//返回一个lambda表达式,返回一个默认的空处理器,防止业务挂掉,后可做平滑升级处理
return [=](const TcpConnectionPtr &conn,json &js,Timestamp time){
LOG_ERROR<<"msgid:"<<msgid<<"can not find handle!";
};
}
else{
return _msgHanderMap[msgid];
}
}
void ChatService::login(const TcpConnectionPtr &conn,json &js,Timestamp time){
int id = js["id"].get<int>();
string pwd = js["password"];
User user = _usermodel.query(id);
if (user.getID() == id && user.getpassword() == pwd)
{
if (user.getstate() == "online")
{
// 该用户已经登录,不允许重复登录
json response;
response["msgid"] = LOGIN_MSG_ACK;
response["errno"] = 2;
response["errmsg"] = "this account is using, input another!";
conn->send(response.dump());
}
else
{
//添加作用域,限制锁的粒度
{
lock_guard<mutex> lock(_connMutex);
//记录用户连接
_userConnMap.insert({id,conn});
}
// 登录成功,更新用户状态信息 state offline=>online
user.setstate("online");
_usermodel.updateState(user);
json response;
response["msgid"] = LOGIN_MSG_ACK;
response["errno"] = 0;
response["id"] = user.getID();
response["name"] = user.getname();
conn->send(response.dump());
}
}
else
{
// 该用户不存在,用户存在但是密码错误,登录失败
json response;
response["msgid"] = LOGIN_MSG_ACK;
response["errno"] = 1;
response["errmsg"] = "id or password is invalid!";
conn->send(response.dump());
}
}
void ChatService::reg(const TcpConnectionPtr &conn,json &js,Timestamp time){
string name = js["name"];
string pwd = js["password"];
User _user;
_user.setname(name);
_user.setpassword(pwd);
bool state = _usermodel.insert(_user);
if(state){
//注册成功
json response;
response["msgid"] = REG_MSG_ACK;
response["errno"] = 0;
response["id"] = _user.getID();
conn->send(response.dump());
}
else{
//注册失败
json response;
response["msgid"] = REG_MSG_ACK;
response["errno"] = 1;
conn->send(response.dump());
}
}