0

I have the following scenario for a chatroon with Symfony 5.4 and MercureBundle. Chat conversation function like a charm, but I don't understand how to include additional info (username) into a payload config of mercure to get connected users (subscribed users to a chatroom topic) from the subscriptions list with the condition that I use mercure() twig extension.

Environment vars:

return array(  
    'MERCURE_URL' => 'https://pami54.local/.well-known/mercure',
    'MERCURE_PUBLIC_URL' => 'https://pami54.local/.well-known/mercure',
    'MERCURE_JWT_SECRET' => 'm3rcu353cr37pa55pra53DEV',
);

mercure.yaml:

mercure:
    hubs:
        default:
            url: '%env(MERCURE_URL)%'
            public_url: '%env(MERCURE_PUBLIC_URL)%'
            jwt:
                secret: '%env(MERCURE_JWT_SECRET)%'
                publish: ['notif/unreaded/{user}', 'notif/mailbox/unreaded/{buzon}', 'app/chatroom', '/.well-known/mercure/subscriptions/{topic}/{subscriber}']
                subscribe: ['/.well-known/mercure/subscriptions/{topic}/{subscriber}']

The following controller renders in the base template the variables needed to generate the EventSource object (declared topics):

/**
     * 
     * @param Request $request
     * @param UuidEncoder $uuidEncoder
     * @param UserInterface $user
     * @param LoggerInterface $logger
     * @return Response
     */
    public function mercureTopicsAction(Request $request, UuidEncoder $uuidEncoder, UserInterface $user, LoggerInterface $logger): Response
    {
        try {
            $incluirMessageChatTopic = $request->get('includeMessageChatTopic', false);

            $userIdPublico = $uuidEncoder->encode($user->getIdPublico());
            $buzonInternoId = $uuidEncoder->encode($user->getBuzonInterno()->getIdPublico());
            /**
             * Se establecen desde el controller los 3 topic de notificaciones existenes.
             * * */
            $notifUnreadedTopic = sprintf("notif/unreaded/%s", $userIdPublico);
            $notifMailboxTopic = sprintf("notif/mailbox/unreaded/%s", $buzonInternoId);
            $messagesChatroomTopic = "app/chatroom";
            $subscriptionsTopic = sprintf("/.well-known/mercure/subscriptions%s/%s", "?topic=" . $messagesChatroomTopic, $user->getIdPublico());
        } catch (\Exception $exc) {
            $logger->error(sprintf("[%s:%s]: %s", self::class, __FUNCTION__, $exc->getMessage()));
            return $this->render('App\_topics.html.twig', ['topics' => [], 'subscriptionsTopic' => "", 'username' => "nobody", 'hubServer' => ""]);
        }

        $topics = [];
        $topics[] = $notifUnreadedTopic;
        $topics[] = $notifMailboxTopic;
        $topics[] = $messagesChatroomTopic;
        $topics[] = $subscriptionsTopic;

        return $this->render('App\_topics.html.twig', ['topics' => $topics, 'subscriptionsTopic' => $subscriptionsTopic, 'username' => $user->getUserIdentifier(), 'hubServer' => $this->getParameter('app.MERCURE_URL')]);
    }

The view fragment (_topics.html.twig) generated by the controller above:

{% set config = {'mercureHub':mercure(topics, { subscribe:topics}), 'subscriptionsTopic':subscriptionsTopic, 'username':username, 'hubServer':hubServer} %}
<script type="application/json" id="mercure">
    {{ config|json_encode(constant('JSON_UNESCAPED_SLASHES') b-or constant('JSON_HEX_TAG'))|raw }}
</script>

The javascript code:

const {mercureHub, subscriptionsTopic, username, hubServer} = $.parseJSON($('#mercure').text());
    let mercureHubURL = mercureHub;

    let eventSource;
    (async () => {
        const resp = await fetch(new URL(subscriptionsTopic, hubServer), {
            credentials: "include",
        });
        const subscriptionCollection = await resp.json();
        console.log(subscriptionCollection);

        mercureHubURL = mercureHubURL + '&lastEventID=' + subscriptionCollection.lastEventID;

        eventSource = new ReconnectingEventSource(mercureHubURL, {withCredentials: true, max_retry_time: 60000});

        eventSource.onopen = function () {
            console.log('Conexion establecida con el socket!');
        };

//        eventSource.onmessage = function () {
//            console.log('Unknow message!!!!');
//        };

        eventSource.onerror = function () {
            console.log('Error de conexion al socket!');
        };

        eventSource.addEventListener("notif", function (e) {
            if (e.type === 'notif') {
                let parsedData = null;
                try {
                    parsedData = $.parseJSON(e.data);
                } catch (error) {
                    console.log(error);
                }

                if (parsedData) {
                    $('#totalNotificacionesNoAtendidas').html(parsedData.total);
                    let list = $('#lista-notificaciones');
                    list.html('');
                    $.each(parsedData.notificaciones, function (i, e) {
                        list.append('<li><div class="row"><div class="col-md-12 text-sm text-left ' + e.iconoColor + '">&nbsp;<i class="' + e.icono + '"></i>&nbsp;' + e.asunto + '</div></div><div class="row"><div class="col-md-12 text-right text-sm">&nbsp;<a class="link-muted lnkCursorPuntero lnkModalDetallesNotificacion" data-src="' + Routing.generate('panel_notificaciones_detalle', {'id': e.id}) + '"><i class="fa fa-eye"></i>&nbsp;detalles</a>&nbsp;</div></div></li><li role="separator" class="divider"></li>');
                    });
                }
            } else {
                console.log('Incoming unknown message');
            }
        }, false);

        eventSource.addEventListener("mailbox", function (e) {
            if (e.type === 'mailbox') {
                let parsedData = null;
                try {
                    parsedData = $.parseJSON(e.data);
                } catch (error) {
                    console.log(error);
                }
                if (parsedData) {
                    $('.totalMensajesNoLeidosBuzonInternoRecibidos').html(parsedData.total);
                    let list = $('#lista-notificaciones-buzon');
                    list.html('');
                    $.each(parsedData.mensajes, function (i, e) {
                        list.append('<li><a href="' + Routing.generate('buzonInterno_detalleMensaje', {'id': e.id}) + '"><div class="pull-left"><img class="img-circle" src="' + e.foto + '" alt="User image"/></div><h4>' + e.remitente + '</h4><p class="text-truncate">' + e.asunto + '</p></a></li>');
                    });

                    if (parsedData.mostrarMensajeRecibido === true) {
                        toastr.info("Tiene un nuevo mensaje privado", 'Mensaje recibido', {
                            timeOut: 8000,
                            preventDuplicates: false,
                            positionClass: 'toast-top-right',
                            progressBar: true,
                            showDuration: 800,
                            hideDuration: 400,
                            extendedTimeOut: 1000,
                            showEasing: "swing",
                            hideEasing: "linear",
                            showMethod: "fadeIn",
                            hideMethod: "fadeOut",
                        });
                    }
                }
            } else {
                console.log('Incoming unknown message');
            }
        }, false);

        eventSource.addEventListener("chatroom", function (e) {
            if (e.type === 'chatroom') {
                let msg = null;
                try {
                    msg = $.parseJSON(e.data);
                } catch (error) {
                    console.log(error);
                }
                if (msg !== null) {
                    let chatConversationElement = $('#chat-conversations');
                    let sender = chatConversationElement.data('sender');
                    let classOnline = sender === msg.sender ? 'online' : '';
                    chatConversationElement.append('<div class="item" id="' + msg.idMensaje + '" data-sender="' + msg.sender + '"><img src="' + msg.foto + '" alt="user image" class="' + classOnline + '"><p class="message"><a class="name lnkCursorPuntero"><small class="text-muted pull-right"><i class="fa fa-clock-o"></i> ' + msg.time + '</small>' + msg.sender + '</a>' + msg.texto + '</p></div>');
                    chatConversationElement.slimScroll({scrollBy: '400px'});
                }
            } else {
                console.log('Incoming unknown message');
            }
        }, false);

        eventSource.addEventListener("Subscription", function (e) {
            if (e.type === 'Subscription') {
                let msg = null;
                try {
                    msg = JSON.parse(e.data);
                } catch (error) {
                    console.log(error);
                }
                console.log("Nueva suscripcion !!!");
            } else {
                console.log('Incoming unknown message');
            }
        }, false);
    })();

The chat messaging works ok, but the subscription event is not fired. The other important thing, how include a username into a payload array of a JWS if I use Cookie Authorization mechanism?

I don't understand that part of the Mercure configuration.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Francisco
  • 194
  • 2
  • 9

0 Answers0