Giter Club home page Giter Club logo

livewire-mercure-demo's Introduction

livewire-mercure-demo.mp4

Livewire Mercure Demo

This demo showcases the use of Mercure (a modern substitute for WebSockets) to send real-time public and private messages in a Laravel Livewire application—no page refresh or polling required.

Quickstart

  1. Clone the repository:git clone https://github.com/benbjurstrom/livewire-mercure-demo.git
  2. Enter the directory: cd livewire-mercure-demo
  3. Install php dependencies: composer install
  4. Install node dependencies: npm install && npm run build
  5. Start the docker environment: ./vendor/bin/sail up
  6. Run migrations and seeders: ./vendor/bin/sail artisan migrate:fresh --seed
  7. Access the app at http://localhost/login. Login with [email protected] and password.
  8. Use the Artisan command sail artisan message:send to send a message.

Technical Details

This repo was created from a fresh Laravel 10 install with the Laravel Breeze package added. From there everything needed to get Mercure up and running can be found in this diff: https://github.com/benbjurstrom/livewire-mercure-demo/commit/220ec5118c107f3c1cef7ddbf73d058e4744d0de

livewire-mercure-demo's People

Contributors

benbjurstrom avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

Forkers

panicoding camkem

livewire-mercure-demo's Issues

  RuntimeException PHP 8.2.13 LARAVEL 10.38.1 Failed to send an update.

Route::get('/test', function () {

    $type = request()->input('type', 'Public'); // Default to 'Public'



        if ($type === 'Private') {

            $userId = request()->input('user_id', '1'); // Default user ID

            $message = request()->input('private_message', 'I have a secret to tell you!');



            broadcast(new NewPrivateMessage($message, $userId));



            return response()->json(['message' => 'Private message was sent!']);

        }



        $message = request()->input('public_message', 'Hello everyone!');

            broadcast(new NewMessage($message));



        return response()->json(['message' => 'Public message was sent!']);



});

my docker-compose.yml (running without sail)

services:
    laravel.test:
        build:
            context: ./vendor/laravel/sail/runtimes/8.2
            dockerfile: Dockerfile
            args:
                WWWGROUP: '1000'
        image: sail-8.2/app
        extra_hosts:
            - 'host.docker.internal:host-gateway'
        ports:
            - '${APP_PORT:-80}:80'
            - '${VITE_PORT:-5173}:${VITE_PORT:-5173}'
        environment:
            WWWUSER: '1000'
            LARAVEL_SAIL: 1
            XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}'
            XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}'
            IGNITION_LOCAL_SITES_PATH: '${PWD}'
        volumes:
            - '.:/var/www/html'
        networks:
            - sail
        depends_on:
            - mysql
    mysql:
        image: 'mysql/mysql-server:8.0'
        ports:
            - '${FORWARD_DB_PORT:-3306}:3306'
        environment:
            MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
            MYSQL_ROOT_HOST: '%'
            MYSQL_DATABASE: '${DB_DATABASE}'
            MYSQL_USER: '${DB_USERNAME}'
            MYSQL_PASSWORD: '${DB_PASSWORD}'
            MYSQL_ALLOW_EMPTY_PASSWORD: 1
        volumes:
            - 'sail-mysql:/var/lib/mysql'
            - './vendor/laravel/sail/database/mysql/create-testing-database.sh:/docker-entrypoint-initdb.d/10-create-testing-database.sh'
        networks:
            - sail
        healthcheck:
            test:
                - CMD
                - mysqladmin
                - ping
                - '-p${DB_PASSWORD}'
            retries: 3
            timeout: 5s
    mercure:
        image: dunglas/mercure
        restart: unless-stopped
        environment:
            # Uncomment the following line to disable HTTPS
            SERVER_NAME: ':80'
            MERCURE_PUBLISHER_JWT_KEY: '!ChangeThisMercureHubJWTSecretKey!'
            MERCURE_SUBSCRIBER_JWT_KEY: '!ChangeThisMercureHubJWTSecretKey!'
            MERCURE_EXTRA_DIRECTIVES: |
                cors_origins http://localhost
                ui
                subscriptions
        # Uncomment the following line to enable the development mode
        command: /usr/bin/caddy run --config /etc/caddy/Caddyfile.dev
        ports:
            - '8888:80'
            - '4433:443'
        volumes:
            - mercure_data:/data
            - mercure_config:/config
networks:
    sail:
        driver: bridge
volumes:
    mercure_data:
    mercure_config:
    sail-mysql:
        driver: local


console:

PS \livewire-mercure-demo> docker compose up
time="2023-12-21T16:54:40+01:00" level=warning msg="The \"PWD\" variable is not set. Defaulting to a blank string."
[+] Running 3/3
 ✔ Container livewire-mercure-demo-mysql-1         Created                                                                                    0.0s
 ✔ Container livewire-mercure-demo-mercure-1       Recreated                                                                                  0.1s
 ✔ Container livewire-mercure-demo-laravel.test-1  Created                                                                                    0.0s
Attaching to laravel.test-1, mercure-1, mysql-1
mysql-1         | [Entrypoint] MySQL Docker Image 8.0.32-1.2.11-server
mercure-1       | {"level":"info","ts":1703174081.6410258,"msg":"using provided configuration","config_file":"/etc/caddy/Caddyfile.dev","config_adapter":""}
mercure-1       | {"level":"warn","ts":1703174081.6424212,"msg":"Caddyfile input is not formatted; run 'caddy fmt --overwrite' to fix inconsistencies","adapter":"caddyfile","file":"/etc/caddy/Caddyfile.dev","line":3}
mercure-1       | {"level":"info","ts":1703174081.6441708,"logger":"admin","msg":"admin endpoint started","address":"localhost:2019","enforce_origin":false,"origins":["//localhost:2019","//[::1]:2019","//127.0.0.1:2019"]}
mercure-1       | {"level":"warn","ts":1703174081.6443107,"logger":"http.auto_https","msg":"server is listening only on the HTTP port, so no automatic HTTPS will be applied to this server","server_name":"srv0","http_port":80}
mercure-1       | {"level":"info","ts":1703174081.6448932,"logger":"tls.cache.maintenance","msg":"started background certificate maintenance","cache":"0xc00029bb00"}
mercure-1       | {"level":"info","ts":1703174081.6449819,"logger":"http.log","msg":"server running","name":"srv0","protocols":["h1","h2","h3"]}
mercure-1       | {"level":"info","ts":1703174081.64524,"msg":"autosaved config (load with --resume flag)","file":"/config/caddy/autosave.json"}
mercure-1       | {"level":"info","ts":1703174081.6452782,"msg":"serving initial configuration"}
mercure-1       | {"level":"warn","ts":1703174081.6490808,"logger":"tls","msg":"storage cleaning happened too recently; skipping for now","storage":"FileStorage:/data/caddy","instance":"3997bdb3-1b33-493d-bf54-fb4c408489cd","try_again":1703260481.6490772,"try_again_in":86399.999999591}
mercure-1       | {"level":"info","ts":1703174081.6491592,"logger":"tls","msg":"finished cleaning storage units"}
mysql-1         | [Entrypoint] Starting MySQL 8.0.32-1.2.11-server
mysql-1         | 2023-12-21T15:54:41.860104Z 0 [Warning] [MY-011068] [Server] The syntax '--skip-host-cache' is deprecated and will be removed in a future release. Please use SET GLOBAL host_cache_size=0 instead.
mysql-1         | 2023-12-21T15:54:41.861775Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.0.32) starting as process 1
mysql-1         | 2023-12-21T15:54:41.867903Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
laravel.test-1  | usermod: no changes
mysql-1         | 2023-12-21T15:54:41.998079Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.
laravel.test-1  | 2023-12-21 15:54:42,081 INFO Set uid to user 0 succeeded
laravel.test-1  | 2023-12-21 15:54:42,082 INFO supervisord started with pid 1
mysql-1         | 2023-12-21T15:54:42.148201Z 0 [Warning] [MY-010068] [Server] CA certificate ca.pem is self signed.
mysql-1         | 2023-12-21T15:54:42.148261Z 0 [System] [MY-013602] [Server] Channel mysql_main configured to support TLS. Encrypted connections are now supported for this channel.
mysql-1         | 2023-12-21T15:54:42.168250Z 0 [System] [MY-011323] [Server] X Plugin ready for connections. Bind-address: '::' port: 33060, socket: /var/run/mysqld/mysqlx.sock
mysql-1         | 2023-12-21T15:54:42.168307Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.32'  socket: '/var/lib/mysql/mysql.sock'  port: 3306  MySQL Community Server - GPL.
laravel.test-1  | 2023-12-21 15:54:43,084 INFO spawned: 'php' with pid 8
laravel.test-1  | 2023-12-21 15:54:44,086 INFO success: php entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
laravel.test-1  |
laravel.test-1  |    INFO  Server running on [http://0.0.0.0:80].
laravel.test-1  |
laravel.test-1  |   Press Ctrl+C to stop the server
laravel.test-1  |
mercure-1       | {"level":"info","ts":1703174486.7544103,"logger":"http.handlers.mercure","msg":"New subscriber","subscriber":{"id":"urn:uuid:30722d6b-ab87-4fdc-ab4d-09f1c2995103","last_event_id":"","remote_addr":"172.19.0.1:58780","topic_selectors":["public.{event}","private.2.{event}"],"topics":["public.newMessage"]}}
mercure-1       | {"level":"info","ts":1703174486.7587354,"logger":"http.handlers.mercure","msg":"New subscriber","subscriber":{"id":"urn:uuid:6bbb438a-b257-4b92-9bb5-1844665322b8","last_event_id":"","remote_addr":"172.19.0.1:58790","topic_selectors":["public.{event}","private.2.{event}"],"topics":["private.2.newMessage"]}}
laravel.test-1  |   2023-12-21 16:01:21 ................................................... ~ 5s
laravel.test-1  |   2023-12-21 16:01:26 /build/assets/app-c2b61067.css .................... ~ 0s
laravel.test-1  |   2023-12-21 16:01:26 /build/assets/app-c7657dfc.js ..................... ~ 0s
laravel.test-1  |   2023-12-21 16:01:26 /favicon.ico ...................................... ~ 0s
mercure-1       | {"level":"info","ts":1703174510.3827791,"logger":"http.handlers.mercure","msg":"New subscriber","subscriber":{"id":"urn:uuid:6517742c-4d95-46d0-a58e-777bff6f94c7","last_event_id":"","remote_addr":"172.19.0.1:49214","topic_selectors":["public.{event}","private.2.{event}"],"topics":["public.newMessage"]}}
mercure-1       | {"level":"info","ts":1703174510.3919957,"logger":"http.handlers.mercure","msg":"Subscriber disconnected","subscriber":{"id":"urn:uuid:6bbb438a-b257-4b92-9bb5-1844665322b8","last_event_id":"","remote_addr":"172.19.0.1:58790","topic_selectors":["public.{event}","private.2.{event}"],"topics":["private.2.newMessage"]}}
mercure-1       | 2023/12/21 16:01:50.392       INFO    http.log.access.log0    handled request {"request": {"remote_ip": "172.19.0.1", "remote_port": "58790", "client_ip": "172.19.0.1", "proto": "HTTP/1.1", "method": "GET", "host": "localhost:8888", "uri": "/.well-known/mercure?topic=private.2.newMessage", "headers": {"Cookie": [], "Sec-Ch-Ua-Platform": ["\"Android\""], "Origin": ["http://localhost"], "Sec-Fetch-Site": ["same-site"], "Sec-Fetch-Mode": ["cors"], "Sec-Fetch-Dest": ["empty"], "Sec-Ch-Ua": ["\"Not_A Brand\";v=\"8\", \"Chromium\";v=\"120\", \"Google Chrome\";v=\"120\""], "Cache-Control": ["no-cache"], "Accept": ["text/event-stream"], "Accept-Encoding": ["gzip, deflate, br"], "Accept-Language": ["en-US,en;q=0.9"], "Connection": ["keep-alive"], "Sec-Ch-Ua-Mobile": ["?1"], "User-Agent": ["Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36"], "Referer": ["http://localhost/"]}}, "bytes_read": 0, "user_id": "", "duration": 23.653105757, "size": 2, "status": 200, "resp_headers": {"Connection": ["keep-alive"], "Expire": ["0"], "Content-Type": ["text/event-stream"], "Cache-Control": ["private, no-cache, no-store, must-revalidate, max-age=0"], "Server": ["Caddy"], "X-Content-Type-Options": ["nosniff"], "X-Xss-Protection": ["1; mode=block"], "Access-Control-Allow-Credentials": ["true"], "Access-Control-Allow-Origin": ["http://localhost"], "Content-Security-Policy": ["default-src 'self' mercure.rocks cdn.jsdelivr.net"], "X-Frame-Options": ["DENY"], "Pragma": ["no-cache"], "X-Accel-Buffering": ["no"]}}
mercure-1       | {"level":"info","ts":1703174510.397029,"logger":"http.handlers.mercure","msg":"Subscriber disconnected","subscriber":{"id":"urn:uuid:30722d6b-ab87-4fdc-ab4d-09f1c2995103","last_event_id":"","remote_addr":"172.19.0.1:58780","topic_selectors":["public.{event}","private.2.{event}"],"topics":["public.newMessage"]}}
mercure-1       | 2023/12/21 16:01:50.397       INFO    http.log.access.log0    handled request {"request": {"remote_ip": "172.19.0.1", "remote_port": "58780", "client_ip": "172.19.0.1", "proto": "HTTP/1.1", "method": "GET", "host": "localhost:8888", "uri": "/.well-known/mercure?topic=public.newMessage", "headers": {"Sec-Ch-Ua-Mobile": ["?1"], "Sec-Ch-Ua-Platform": ["\"Android\""], "Sec-Fetch-Mode": ["cors"], "Accept-Language": ["en-US,en;q=0.9"], "Connection": ["keep-alive"], "Accept": ["text/event-stream"], "Origin": ["http://localhost"], "Referer": ["http://localhost/"], "Cookie": [], "Sec-Ch-Ua": ["\"Not_A Brand\";v=\"8\", \"Chromium\";v=\"120\", \"Google Chrome\";v=\"120\""], "Cache-Control": ["no-cache"], "Sec-Fetch-Site": ["same-site"], "User-Agent": ["Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36"], "Sec-Fetch-Dest": ["empty"], "Accept-Encoding": ["gzip, deflate, br"]}}, "bytes_read": 0, "user_id": "", "duration": 23.659357655, "size": 2, "status": 200, "resp_headers": {"Server": ["Caddy"], "Access-Control-Allow-Origin": ["http://localhost"], "X-Frame-Options": ["DENY"], "Connection": ["keep-alive"], "Pragma": ["no-cache"], "Expire": ["0"], "X-Content-Type-Options": ["nosniff"], "Content-Security-Policy": ["default-src 'self' mercure.rocks cdn.jsdelivr.net"], "Access-Control-Allow-Credentials": ["true"], "Content-Type": ["text/event-stream"], "X-Xss-Protection": ["1; mode=block"], "Cache-Control": ["private, no-cache, no-store, must-revalidate, max-age=0"], "X-Accel-Buffering": ["no"]}}
mercure-1       | {"level":"info","ts":1703174518.3048244,"logger":"http.handlers.mercure","msg":"Subscriber disconnected","subscriber":{"id":"urn:uuid:6517742c-4d95-46d0-a58e-777bff6f94c7","last_event_id":"","remote_addr":"172.19.0.1:49214","topic_selectors":["public.{event}","private.2.{event}"],"topics":["public.newMessage"]}}
mercure-1       | 2023/12/21 16:01:58.304       INFO    http.log.access.log0    handled request {"request": {"remote_ip": "172.19.0.1", "remote_port": "49214", "client_ip": "172.19.0.1", "proto": "HTTP/1.1", "method": "GET", "host": "localhost:8888", "uri": "/.well-known/mercure?topic=public.newMessage", "headers": {"Upgrade-Insecure-Requests": ["1"], "Sec-Ch-Ua-Platform": ["\"Android\""], "User-Agent": ["Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36"], "Sec-Fetch-Mode": ["navigate"], "Accept-Encoding": ["gzip, deflate, br"], "Sec-Ch-Ua-Mobile": ["?1"], "Sec-Ch-Ua": ["\"Not_A Brand\";v=\"8\", \"Chromium\";v=\"120\", \"Google Chrome\";v=\"120\""], "Accept": ["text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"], "Cookie": [], "Sec-Fetch-Site": ["none"], "Sec-Fetch-User": ["?1"], "Sec-Fetch-Dest": ["document"], "Accept-Language": ["en-US,en;q=0.9"], "Connection": ["keep-alive"]}}, "bytes_read": 0, "user_id": "", "duration": 7.935280053, "size": 2, "status": 200, "resp_headers": {"Server": ["Caddy"], "X-Content-Type-Options": ["nosniff"], "Content-Security-Policy": ["default-src 'self' mercure.rocks cdn.jsdelivr.net"], "Content-Type": ["text/event-stream"], "Cache-Control": ["private, no-cache, no-store, must-revalidate, max-age=0"], "X-Xss-Protection": ["1; mode=block"], "X-Frame-Options": ["DENY"], "Connection": ["keep-alive"], "Pragma": ["no-cache"], "Expire": ["0"], "X-Accel-Buffering": ["no"]}}
mercure-1       | {"level":"info","ts":1703174518.3669512,"logger":"http.handlers.mercure","msg":"New subscriber","subscriber":{"id":"urn:uuid:8ff69f06-a8eb-4d39-9dc0-f9e66a0b609f","last_event_id":"","remote_addr":"172.19.0.1:40502","topic_selectors":["public.{event}","private.2.{event}"],"topics":["public.newMessage"]}}
mercure-1       | {"level":"info","ts":1703174518.3701656,"logger":"http.handlers.mercure","msg":"New subscriber","subscriber":{"id":"urn:uuid:b3aa572e-5eab-4146-b8ec-bb6756aa0a16","last_event_id":"","remote_addr":"172.19.0.1:40514","topic_selectors":["public.{event}","private.2.{event}"],"topics":["private.2.newMessage"]}}
laravel.test-1  |   2023-12-21 16:01:56 ................................................... ~ 2s
laravel.test-1  |   2023-12-21 16:01:58 /favicon.ico ...................................... ~ 0s

image

Installation problems

Hello,

When running the installation steps from the readme Sail returns an error that its missing Octane;
ERROR There are no commands defined in the "octane" namespace.

This can be fixed by installing Octane with FrankenPHP.

After following the steps form the installation everything seems to work fine, including sending messages. However the messages are never shown in the frontend.

The following errors returns inside the console:
[Error] Failed to load resource: A server with the specified hostname could not be found. (mercure, line 0) http://mercure/.well-known/mercure?topic=public.newMessage

I did not change anything else beside the base installation and installing octane.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.