这篇我们来研究自定义服务是如何创建和注册的,谁来调用和初始化这些需要后面解析到网络服务后再说了
IService.cpp
头文件在上一篇做过简单介绍,这里就不赘述,直接上CPP
1、可以看到在构造函数初始化时需要传入了三个参数:①TYPE类型 ②服务名 ③是否需要鉴权
- 类型:开发者自定义的类型,要求是int,不过我自定义了一个enum枚举
- 服务名:该服务名需唯一,用于服务之前通过名称相互获取
- 是否需要鉴权:一般用于登录后该连接会绑定到玩家缓存,没有登录的连接没有缓存,如此参数传入false,则没有缓存的请求将被ServiceManager默认回复
2、regist成员函数
该成员函数需要两个参数,第一个为自定义action,该action在同一服务或同一type中不可重复,参数二为callback原型:std::function<void(Request& request)> 用于相应触发回调
#include "iservice.h"
#include "servicemanager.h"
#include "utils/utils.h"
IService::IService(int type, const std::string& name,bool haveLogined):m_type(type),m_name(name), m_haveLogined(haveLogined)
{
Utils::assert(ServiceManager::getInstance()->registService(this), ServiceManager::getInstance()->last_error());
}
IService::~IService()
{
}
void IService::regist(int action, REQUEST_CALLBACK callback)
{
ServiceManager::getInstance()->registAction(action,callback,this);
}
# 大家应该有一个疑问,就是这个callback原型有一个Request,这是什么?这其实是一个类,每个请求包到最终回调的生命周期中会创建一个,用来存储请求数据、返回结果等。其头文件如下
request.h:请求
该类由HandleCenter控制器创建和释放
<pre class="prism-highlight prism-language-cpp">#pragma once
#include "ybase/define.h"
#include "ybase/error.h"
#include "core/define.h"
#include "common.h"
#include "entity/Player.h"
class Request{
public:
/// <summary>
/// 构造
/// </summary>
/// <param name="player_id">玩家ID</param>
/// <param name="fd">连接ID</param>
/// <param name="index">包索引</param>
/// <param name="data">请求数据</param>
Request(uint64 player_id,uint64 fd,uint32 index,const ylib::json& data);
~Request();
ylib::json& data() { return m_data; }
/// <summary>
/// 回复(仅允许调用1次)
/// </summary>
/// <param name="data"></param>
void repSuccess(const ylib::json& data = ylib::json());
void repFailed(const std::string& error_msg);
void response(bool result,const std::string& msg,const ylib::json& data);
/// <summary>
/// 取Player指针
/// </summary>
/// <returns></returns>
std::shared_ptr<Player> player();
uint64 fd() { return m_fd; }
private:
// 玩家ID
uint64 m_player_id = 0;
// 连接ID
uint64 m_fd = 0;
// 回复索引
uint32 m_index = 0;
// 接收数据
ylib::json m_data;
// 是否已回复
bool m_responsed = false;
};
以 user_ns.h 和 user_ns.cpp 做为示例来演示吧
user_ns.h
头文件很简单继承了IService,声明了两个函数:login和regist用来注册,并且都有一个参数Request
基本就是这些没什么重要的了
#pragma once
#include "core/iservice.h"
/// <summary>
/// User Not Session
/// </summary>
class UserNS :IService
{
public:
UserNS();
~UserNS();
private:
void login(Request& request);
void regist(Request& request);
};
user_ns.cpp
构造函数可以有两个 IService::regist 函数的调用,其用于注册当前成员函数与ACTION的对应关系
#include "user_ns.h"
#include "utils/utils.h"
#include "game/playermanager.h"
#include "network/server.h"
#include "ymysql/mysql_plus.h"
#include "HPSocket/HPSocket.h"
UserNS::UserNS():IService(c2s::USER,"user_ns",false)
{
::IService::regist(c2s::UserAction::LOGIN, std::bind(&UserNS::login, this, std::placeholders::_1));
::IService::regist(c2s::UserAction::REGIST, std::bind(&UserNS::regist, this, std::placeholders::_1));
}
UserNS::~UserNS()
{
}
void UserNS::login(Request& request)
{
std::string username = request.data()["username"].to<std::string>();
std::string password = request.data()["password"].to<std::string>();
// 校验账号
{
auto [result, msg] = Utils::checkUsername(username);
if (result == false)
{
request.repFailed(msg);
return;
}
}
// 校验密码
{
auto [result, msg] = Utils::checkPassword(password);
if (result == false)
{
request.repFailed(msg);
return;
}
}
conn_autofree conn(SQLPOOL->get());
auto pptp = conn->setsql("SELECT id,money,sex FROM users WHERE username = ? AND password = ? LIMIT 1");
pptp->set_string(1, username);
pptp->set_string(2, password);
auto result = pptp->query();
if (result->row_count() != 1)
{
request.repFailed("账号或密码错误");
return;
}
result->next();
uint64 player_id = result->get_uint64("id");
auto sex = (Sex)result->get_int32("sex");
// 删除之前用户缓存并断线
PlayerManager::getInstance()->remove(player_id,true);
// 增加新的绑定
auto player = PlayerManager::getInstance()->create(player_id);
Server::getInstance()->hp()->SetConnectionExtra(request.fd(),(PVOID)player_id);
player->setMoney(result->get_uint64("money"));
player->setSex(sex);
player->setFD(request.fd());
request.repSuccess();
}
void UserNS::regist(Request& request)
{
std::string username = request.data()["username"].to<std::string>();
std::string password = request.data()["password"].to<std::string>();
// 校验账号
{
auto [result, msg] = Utils::checkUsername(username);
if (result == false)
{
request.repFailed(msg);
return;
}
}
// 校验密码
{
auto [result, msg] = Utils::checkPassword(password);
if (result == false)
{
request.repFailed(msg);
return;
}
}
conn_autofree conn(SQLPOOL->get());
// 校验重名
{
auto pptp = conn->setsql("SELECT id FROM users WHERE username = ? LIMIT 1");
pptp->set_string(1, username);
auto result = pptp->query();
if (result->row_count() > 0)
{
request.repFailed("账号已被注册");
return;
}
}
// 注册账号
auto pptp = conn->setsql("INSERT INTO users (username, password) VALUES (?, ?)");
if (pptp->update() == 1)
{
request.repSuccess();
}
else
{
request.repFailed(pptp->last_error());
}
}