美文网首页PHP开发PHP经验分享
SWOOLE开发实时聊天系统(八)观察者模式的调用

SWOOLE开发实时聊天系统(八)观察者模式的调用

作者: 公式般欢笑 | 来源:发表于2020-03-11 00:07 被阅读0次

首先,新建一个注册类,在这个类中,写用户注册的具体实现。

<?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']);
        //用户对应的fd
        pool::redis()->hSet(self::user_bind_redis_key, $frame->fd, $params['user_id']);
        //fd对应的user
        pool::redis()->hSet(self::fd_bind_user_redis_key, $params['user_id'], $frame->fd);
        return true;
    }
}

在这个类中,并没有写通知的具体内容,只是首先需要继承一下CommonService,在CommonService中继承了PushEventGenerator这个类,所以在LoginService中可以直接调用PushEventGenerator的notify方法。
这样做的好处是,只要有了通知,在调用notify方法之后,就会自动一条条去调用通知,而无需在业务代码中写通知的具体实现。

<?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';//分组下对应的用户
    const  redis_key_user_group = 'ws_user_fd';//用户对应的分组
    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中,判断用户发送信息的类型。

    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’,那么就可以直接调用LoginService中的方法。
在调用之前,注入PushToSelfRegisterInfo和PushToAllMessage的类,这样在登录完成之后,就可以直接完成推送通知的需求了。

我们打开两个测试工具,分别输入10086和10087这两个用户,可以看到,如下的结果

结果如图所示:


10086.png 10087.png

OK,下一步我们就可以进行收发消息的开发了。

相关文章

网友评论

    本文标题:SWOOLE开发实时聊天系统(八)观察者模式的调用

    本文链接:https://www.haomeiwen.com/subject/uutcdhtx.html