ChatHub.php 6.67 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
<?php
/**
 * Created by PhpStorm.
 * User: mat
 * Date: 2/07/18
 * Time: 11:18
 */

namespace SocketBundle\Services;

11
use Lexik\Bundle\JWTAuthenticationBundle\Security\Authentication\Token\JWTUserToken;
12 13
use Ratchet\ConnectionInterface;
use Ratchet\MessageComponentInterface;
14
use SocketBundle\Entity\Message;
15
use SocketBundle\Entity\User;
16
use Symfony\Component\DependencyInjection\ContainerInterface;
17 18 19 20 21 22 23 24

class ChatHub implements MessageComponentInterface
{
    /*
     * le curseur sur MessageComponentInterface -> Alt-Enter -> Add method stubs
     * et hop, il ajoute tout ce qui doit être implémenté
     */
    
25 26 27
    /**
     * @var ContainerInterface
     */
28
    private $container;
29 30 31 32
    
    /**
     * @var ConnectionInterface
     */
33 34
    private $clients;
    
Mat's avatar
hop  
Mat committed
35
    
36 37 38 39 40
    /**
     * ChatHub constructor.
     *
     * @param ContainerInterface $_container
     */
41 42 43 44 45 46
    public function __construct(ContainerInterface $_container)
    {
        $this->container = $_container;
        $this->clients = array();
    }
    
47 48 49 50 51 52 53 54 55
    
    /**
     * When a new connection is opened it will be passed to this method
     *
     * @param  ConnectionInterface $conn The socket/connection that just connected to your application
     * @throws \Exception
     */
    function onOpen(ConnectionInterface $conn)
    {
56
        echo "Un utilisateur s'est connecté\n";
Mat's avatar
hop  
Mat committed
57

Mat's avatar
Mat committed
58 59 60 61 62 63
        $response = json_encode([
            'type' => 'msg_server',
            'author' => 'server',
            'content' => "Bienvenue sur notre Web Socket Server",
            'timestamp' => (new \DateTime())->getTimestamp()
        ]);
64
        
Mat's avatar
Mat committed
65
        $conn->send($response);
66 67
    }
    
Mat's avatar
hop  
Mat committed
68
    
69 70 71 72 73 74 75 76
    /**
     * This is called before or after a socket is closed (depends on how it's closed).  SendMessage to $conn will not result in an error if it has already been closed.
     *
     * @param  ConnectionInterface $conn The socket/connection that is closing/closed
     * @throws \Exception
     */
    function onClose(ConnectionInterface $conn)
    {
77
        echo "Un utilisateur s'est déconnecté\n";
Mat's avatar
hop  
Mat committed
78
        
Mat's avatar
hop  
Mat committed
79 80
        foreach ($this->clients as $key => $client) {
            if ($client === $conn) {
Mat's avatar
hop  
Mat committed
81 82 83
                unset($this->clients[$key]);
            }
        }
84
        $this->refreshUsers();
85 86
    }
    
Mat's avatar
hop  
Mat committed
87
    
88 89 90 91 92 93 94 95 96 97
    /**
     * If there is an error with one of the sockets, or somewhere in the application where an Exception is thrown,
     * the Exception is sent back down the stack, handled by the Server and bubbled back up the application through this method
     *
     * @param  ConnectionInterface $conn
     * @param  \Exception $e
     * @throws \Exception
     */
    function onError(ConnectionInterface $conn, \Exception $e)
    {
98
        echo "Une erreur s'est produite\n";
99
        echo $e->getMessage() . "\n";
100 101
    }
    
Mat's avatar
hop  
Mat committed
102
    
103 104 105 106 107
    /**
     * Triggered when a client sends data through the socket
     *
     * @param  \Ratchet\ConnectionInterface $from The socket/connection that sent the message to your application
     * @param  string $msg The message received
Mat's avatar
Mat committed
108 109
     * @return string
     * @throws \Twig\Error\Error
110 111 112
     */
    function onMessage(ConnectionInterface $from, $msg)
    {
113 114 115 116 117 118
        // retransforme le string $msg en objet
        $data = json_decode($msg);
        
        $dataPath = $data->path;       // la route qui nous mène qqpart
        $dataToken = $data->token; // token d'identification
        
Mat's avatar
hop  
Mat committed
119
        // le token brut, façon JWT
120 121 122 123 124 125
        $token = new JWTUserToken();
        $token->setRawToken($dataToken);
        
        switch ($dataPath) {
            case '/register':
                
126 127 128 129 130 131 132 133
                // on a créé une fonction private pour partager
                $username = $this->getUser($token);
                
                // from c'est le client qui vient d'envoyer un message
                // sauvegarde sa 'connection Interface'
                $this->clients[$username] = $from;
                
                $this->refreshUsers();
134

135
            break;
136 137
            case '/history':
                
Mat's avatar
Mat committed
138
                // récupère le destinataire
139
                $dest = $data->dest;
Mat's avatar
Mat committed
140 141
                
                // appelle getUser
142 143
                $username = $this->getUser($token);
                
Mat's avatar
Mat committed
144
                // récupère l'historique des messages entre les 2 utilisateurs
145
                $messageRepo = $this->getDoctrine()->getManager()->getRepository(Message::class);
Mat's avatar
Mat committed
146 147 148 149 150 151 152 153 154 155 156 157 158
                $messages = $messageRepo->getHistory($username, $dest);
    
                // passe l'historique dans le fragment twig
                $twig = $this->container->get('templating');
                $fragment = $twig->render('@Socket/Chat/usersHistory.html.twig', array(
                   'messages' => $messages
                ));
                
                // retourne le fragment en json
                return json_encode(array(
                    'action' => 'refreseh_messages',
                    'view' => $fragment
                ));
159 160
            
            break;
161 162 163 164 165 166 167 168
        }
    }
    
    /**
     * @throws \Twig\Error\Error
     */
    private function refreshUsers()
    {
169
        $em = $this->getDoctrine()->getManager();
170 171
        $repo = $this->getDoctrine()->getRepository(User::class);
        
Mat's avatar
hop  
Mat committed
172
        // twig va génèrer le fragment à retourner
173
        $twig = $this->container->get('templating');
Mat's avatar
Mat committed
174
        
175
        // array_map récupère chaque user et le map avec nos clients
Mat's avatar
hop  
Mat committed
176
        $fragment = $twig->render('@Socket/Chat/listUsers.html.twig', array(
177 178 179 180
            'users' => array_map(function ($username) use($repo, $em) {
                $user = $repo->findOneBy(array('username' => $username));
                $em->refresh($user);
                return $user;
181
            }, array_keys($this->clients))
182 183 184 185 186
        ));
    
        // formate la response
        $response = json_encode(array(
            'action' => 'refresh_users',
Mat's avatar
hop  
Mat committed
187
            'view' => $fragment
188 189 190 191 192 193
        ));
    
        // renvoie la réponse à tous les clients
        foreach ($this->clients as $client)
        {
            $client->send($response);
194
        }
195
    }
Mat's avatar
hop  
Mat committed
196
    
197 198 199 200 201 202 203
    /**
     * @return \Doctrine\Bundle\DoctrineBundle\Registry|mixed|object
     */
    private function getDoctrine()
    {
        return $this->container->get('doctrine');
    }
204
    
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
    /**
     * @param $token
     * @return mixed
     */
    private function getUser($token)
    {
        // importe le service qui permet de traiter le token
        $tokenManager = $this->container->get('lexik_jwt_authentication.jwt_manager');
    
        // payload, ce sont les données chiffrées à l'intérieur du token
        $payload = $tokenManager->decode($token);
    
        // retourne le username qui est dans le payload du token
        return $username = $payload['username'];
    }
    
    
222
}