首先,新建一個注冊類,在這個類中,寫用戶注冊的具體實現(xiàn)。
<?php
namespace app\services;
use pool\pool;
class LoginService extends CommonService
{
public function __construct($server) {
$this->server = $server;
parent::__construct();
}
public function register($frame, $params) {
try {
//注冊 一級和二級topic不能為空。
if (!$params['first_topic'] || !$params['second_topic']) {
throw new \Exception("當前用戶的分組不存在,請重試!");
}
if (!$params['user_id']) {
throw new \Exception("用戶ID不存在,請重試!");
}
$result=$this->saveToRedis($frame,$params);
//TODO 插入redis出錯處理
if(!$result){
throw new \Exception('插入redis出錯,請重試!');
}
$this->notify();
} catch (\Exception $e) {
$this->result['status'] = 1;
$this->result['msg'] = $e->getMessage();
echo json_encode($this->result,JSON_UNESCAPED_UNICODE);
}
return $this->result;
}
/**
* 用戶斷開后的操作
* @param $fd int ws的fd標識
*/
public static function close($fd) {
}
private function saveToRedis($frame,$params){
//存入組-用戶中
$rk = str_replace(['first_topic', 'second_topic'], [$params['first_topic'], $params['second_topic']], self::redis_key_group_user);
$user_list = [];
if (pool::redis()->exists($rk)) {
$user_list = explode(",", pool::redis()->get($rk));
}
$user_list[] = $params['user_id'];
pool::redis()->set($rk, implode(",", array_unique(array_filter($user_list))));
//存入 用戶-組
$rk = str_replace('fd', $frame->fd, self::redis_key_user_group);
pool::redis()->set($rk, $params['first_topic'] . "_" . $params['second_topic']);
//用戶對應(yīng)的fd
pool::redis()->hSet(self::user_bind_redis_key, $frame->fd, $params['user_id']);
//fd對應(yīng)的user
pool::redis()->hSet(self::fd_bind_user_redis_key, $params['user_id'], $frame->fd);
return true;
}
}
在這個類中,并沒有寫通知的具體內(nèi)容,只是首先需要繼承一下CommonService,在CommonService中繼承了PushEventGenerator這個類,所以在LoginService中可以直接調(diào)用PushEventGenerator的notify方法。
這樣做的好處是,只要有了通知,在調(diào)用notify方法之后,就會自動一條條去調(diào)用通知,而無需在業(yè)務(wù)代碼中寫通知的具體實現(xiàn)。
<?php
namespace app\services;
use app\services\push\PushEventGenerator;
use pool\pool;
use services\LogService;
/**
* Class CommonService
* @package app\services
*/
class CommonService extends PushEventGenerator
{
const redis_key_group_user = 'ws_topic_first_topic_second_topic';//分組下對應(yīng)的用戶
const redis_key_user_group = 'ws_user_fd';//用戶對應(yīng)的分組
const user_bind_redis_key = "ws_user_bind_fd_redis_key";//fd綁定用戶的redis_key fd=》user
const fd_bind_user_redis_key = "ws_fd_bind_user_redis_key";//用戶綁定fd的redis_key user=>fd
const redis_expire_time=86400;
public $result = ['status' => 0, 'msg' => 'success', 'data' => []];
public $server;
public function __construct() {
}
}
最后,我們回到MessageController中,在getMessage中,判斷用戶發(fā)送信息的類型。
public function getMessage(\swoole_websocket_frame $frame)
{
$data=json_decode($frame->data,true);
switch($data['type']){
case 'login':
$loginService = new LoginService($this->server);
//注入推送給自己注冊成功的方法;
$pushtoselfstatus = new PushToSelfRegisterInfo($this->server, '注冊成功', [$frame->fd]);
$loginService->addPushObServer($pushtoselfstatus);
//注入推送給所有人 “xxx進入房間”的消息。
//拼裝消息體
$msgService=new MessageService();
$data=$msgService->getMessageContent($data,0);
$userService = new UserService();
$fds = $userService->getFdByGroup($data['first_topic'], $data['second_topic']);
$pushToAll = new PushToAllMessage($this->server,$data,$fds);
$loginService->addPushObServer($pushToAll);
$result = $loginService->register($frame, $data);
if($result['status']!=0){
echo json_encode($result,JSON_UNESCAPED_UNICODE) ."\n";
}
break;
}
}
如果type是‘login’,那么就可以直接調(diào)用LoginService中的方法。
在調(diào)用之前,注入PushToSelfRegisterInfo和PushToAllMessage的類,這樣在登錄完成之后,就可以直接完成推送通知的需求了。
我們打開兩個測試工具,分別輸入10086和10087這兩個用戶,可以看到,如下的結(jié)果
結(jié)果如圖所示:

10086.png

10087.png
OK,下一步我們就可以進行收發(fā)消息的開發(fā)了。