diff --git a/compose.yml b/compose.yml index ff202d78..dad288cb 100644 --- a/compose.yml +++ b/compose.yml @@ -84,7 +84,6 @@ services: - "host.docker.internal:host-gateway" # for xdebug healthcheck: test: php artisan octane:status || exit 1 - start_period: 5s interval: 10s timeout: 5s retries: 5 @@ -148,6 +147,18 @@ services: networks: - local + reverb: + depends_on: + app: + condition: service_healthy + build: *app + container_name: anilibrary-reverb + volumes: + - ./src:/anilibrary + - ./docker/php/supervisor/conf.d/reverb.conf:/etc/supervisor/conf.d/reverb.conf + networks: + - local + networks: anilibrary: name: anilibrary @@ -158,4 +169,4 @@ volumes: db-data: name: anilibrary-db-data redis-data: - name: anilibrary-redis-data \ No newline at end of file + name: anilibrary-redis-data diff --git a/docker/nginx/conf.d/default.conf b/docker/nginx/conf.d/default.conf index b940bf2b..bada1c22 100644 --- a/docker/nginx/conf.d/default.conf +++ b/docker/nginx/conf.d/default.conf @@ -23,6 +23,14 @@ server { try_files $uri $uri/ @octane; } + location /app { + try_files $uri $uri/ @reverb; + } + + location /apps { + try_files $uri $uri/ @reverb; + } + location = /favicon.ico { access_log off; log_not_found off; } location = /robots.txt { access_log off; log_not_found off; } @@ -54,4 +62,20 @@ server { proxy_pass http://anilibrary:8000$suffix; } + + location @reverb { + proxy_http_version 1.1; + proxy_set_header Host $http_host; + proxy_set_header Scheme $scheme; + proxy_set_header SERVER_PORT $server_port; + proxy_set_header REMOTE_ADDR $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + proxy_cache_bypass $http_upgrade; + + proxy_read_timeout 60s; + proxy_connect_timeout 60s; + proxy_pass http://anilibrary-reverb:8080; + } } diff --git a/docker/php/Dockerfile b/docker/php/Dockerfile index 67e90522..5e0c1e50 100644 --- a/docker/php/Dockerfile +++ b/docker/php/Dockerfile @@ -20,7 +20,7 @@ ARG USER_ID=1000 RUN apk update \ && apk add --no-cache libstdc++ libpq libzip-dev gmp-dev oniguruma-dev curl git zip unzip supervisor \ && apk add --no-cache --virtual .build-deps $PHPIZE_DEPS linux-headers brotli-dev pcre-dev pcre2-dev zlib-dev \ - && pecl install xdebug swoole \ + && pecl install xdebug swoole uv \ && docker-php-ext-install -j$(nproc) \ pcntl \ mbstring \ @@ -53,7 +53,8 @@ COPY --from=node /usr/local/bin /usr/local/bin WORKDIR /anilibrary -EXPOSE 8000 EXPOSE 5173 +EXPOSE 8000 +EXPOSE 8080 ENTRYPOINT ["supervisord", "-c", "/etc/supervisor/supervisord.conf"] diff --git a/docker/php/supervisor/conf.d/reverb.conf b/docker/php/supervisor/conf.d/reverb.conf new file mode 100644 index 00000000..788d43bc --- /dev/null +++ b/docker/php/supervisor/conf.d/reverb.conf @@ -0,0 +1,9 @@ +[program:reverb] +process_name=%(program_name)s_%(process_num)02d +command=php artisan reverb:start --debug +user=anilibrary +autorestart=true +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 diff --git a/docker/php/supervisor/supervisord.conf b/docker/php/supervisor/supervisord.conf index d4ad7a76..39258313 100644 --- a/docker/php/supervisor/supervisord.conf +++ b/docker/php/supervisor/supervisord.conf @@ -4,6 +4,7 @@ file=/tmp/supervisor.sock [supervisord] nodaemon=true user=anilibrary +minfds=10000 logfile=/tmp/supervisord.log pidfile=/tmp/supervisord.pid diff --git a/src/.env.example b/src/.env.example index b6c90c98..e55d37cd 100644 --- a/src/.env.example +++ b/src/.env.example @@ -37,9 +37,9 @@ SESSION_ENCRYPT=false SESSION_PATH=/ SESSION_DOMAIN=null -BROADCAST_CONNECTION=log +BROADCAST_CONNECTION=reverb FILESYSTEM_DISK=local -QUEUE_CONNECTION=sync +QUEUE_CONNECTION=redis CACHE_STORE=file CACHE_PREFIX= @@ -66,20 +66,18 @@ AWS_DEFAULT_REGION=us-east-1 AWS_BUCKET= AWS_USE_PATH_STYLE_ENDPOINT=false -PUSHER_APP_ID= -PUSHER_APP_KEY= -PUSHER_APP_SECRET= -PUSHER_HOST= -PUSHER_PORT=443 -PUSHER_SCHEME=https -PUSHER_APP_CLUSTER=mt1 +REVERB_APP_ID= +REVERB_APP_KEY= +REVERB_APP_SECRET= +REVERB_HOST=localhost +REVERB_PORT=80 +REVERB_SCHEME=http VITE_APP_NAME="${APP_NAME}" -VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}" -VITE_PUSHER_HOST="${PUSHER_HOST}" -VITE_PUSHER_PORT="${PUSHER_PORT}" -VITE_PUSHER_SCHEME="${PUSHER_SCHEME}" -VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" +VITE_REVERB_APP_KEY="${REVERB_APP_KEY}" +VITE_REVERB_HOST="${REVERB_HOST}" +VITE_REVERB_PORT="${REVERB_PORT}" +VITE_REVERB_SCHEME="${REVERB_SCHEME}" TELEGRAM_BOT_TOKEN= TELEGRAM_BOT_NAME= diff --git a/src/.env.testing b/src/.env.testing index f7f80c4a..2abdb63f 100644 --- a/src/.env.testing +++ b/src/.env.testing @@ -66,20 +66,18 @@ AWS_DEFAULT_REGION=us-east-1 AWS_BUCKET= AWS_USE_PATH_STYLE_ENDPOINT=false -PUSHER_APP_ID= -PUSHER_APP_KEY= -PUSHER_APP_SECRET= -PUSHER_HOST= -PUSHER_PORT=443 -PUSHER_SCHEME=https -PUSHER_APP_CLUSTER=mt1 +REVERB_APP_ID=1 +REVERB_APP_KEY=test +REVERB_APP_SECRET=test +REVERB_HOST=testing.com +REVERB_PORT=80 +REVERB_SCHEME=http VITE_APP_NAME="${APP_NAME}" -VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}" -VITE_PUSHER_HOST="${PUSHER_HOST}" -VITE_PUSHER_PORT="${PUSHER_PORT}" -VITE_PUSHER_SCHEME="${PUSHER_SCHEME}" -VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" +VITE_REVERB_APP_KEY="${REVERB_APP_KEY}" +VITE_REVERB_HOST="${REVERB_HOST}" +VITE_REVERB_PORT="${REVERB_PORT}" +VITE_REVERB_SCHEME="${REVERB_SCHEME}" TELEGRAM_TOKEN=test TELEGRAM_BOT_NAME=anilibrary_test_bot diff --git a/src/app/Broadcasting/Scraper/ScrapeAnimeChannel.php b/src/app/Broadcasting/Scraper/ScrapeAnimeChannel.php new file mode 100644 index 00000000..62c650d1 --- /dev/null +++ b/src/app/Broadcasting/Scraper/ScrapeAnimeChannel.php @@ -0,0 +1,26 @@ +id === $requestedId; + } +} diff --git a/src/app/DTO/Events/Pusher/ScrapeResultDTO.php b/src/app/DTO/Events/Scraper/ScrapeAnimeResultDTO.php similarity index 63% rename from src/app/DTO/Events/Pusher/ScrapeResultDTO.php rename to src/app/DTO/Events/Scraper/ScrapeAnimeResultDTO.php index bb4d0cce..72591e96 100644 --- a/src/app/DTO/Events/Pusher/ScrapeResultDTO.php +++ b/src/app/DTO/Events/Scraper/ScrapeAnimeResultDTO.php @@ -2,11 +2,11 @@ declare(strict_types=1); -namespace App\DTO\Events\Pusher; +namespace App\DTO\Events\Scraper; -use App\Enums\Events\Pusher\ScrapeResultTypeEnum; +use App\Enums\Events\Scraper\ScrapeResultTypeEnum; -final readonly class ScrapeResultDTO +final readonly class ScrapeAnimeResultDTO { public function __construct( public string $userId, diff --git a/src/app/Enums/Events/Pusher/ScrapeResultTypeEnum.php b/src/app/Enums/Events/Scraper/ScrapeResultTypeEnum.php similarity index 78% rename from src/app/Enums/Events/Pusher/ScrapeResultTypeEnum.php rename to src/app/Enums/Events/Scraper/ScrapeResultTypeEnum.php index 3be3516b..37388a63 100644 --- a/src/app/Enums/Events/Pusher/ScrapeResultTypeEnum.php +++ b/src/app/Enums/Events/Scraper/ScrapeResultTypeEnum.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Enums\Events\Pusher; +namespace App\Enums\Events\Scraper; enum ScrapeResultTypeEnum: string { diff --git a/src/app/Enums/QueueEnum.php b/src/app/Enums/QueueEnum.php index acbd6199..f36d505d 100644 --- a/src/app/Enums/QueueEnum.php +++ b/src/app/Enums/QueueEnum.php @@ -11,7 +11,7 @@ enum QueueEnum: string use ProvideValues; case MAIL_QUEUE = 'mail'; - case PUSHER_QUEUE = 'pusher'; + case SOCKET_QUEUE = 'socket'; case SCRAPER_QUEUE = 'scraper'; case TELEGRAM_QUEUE = 'telegram'; case ELASTICSEARCH_QUEUE = 'elasticsearch'; diff --git a/src/app/Events/Pusher/ScrapeResultEvent.php b/src/app/Events/Scraper/ScrapeAnimeResultEvent.php similarity index 76% rename from src/app/Events/Pusher/ScrapeResultEvent.php rename to src/app/Events/Scraper/ScrapeAnimeResultEvent.php index 0f8412c6..20dea572 100644 --- a/src/app/Events/Pusher/ScrapeResultEvent.php +++ b/src/app/Events/Scraper/ScrapeAnimeResultEvent.php @@ -2,9 +2,9 @@ declare(strict_types=1); -namespace App\Events\Pusher; +namespace App\Events\Scraper; -use App\DTO\Events\Pusher\ScrapeResultDTO; +use App\DTO\Events\Scraper\ScrapeAnimeResultDTO; use App\Enums\QueueEnum; use Illuminate\Broadcasting\Channel; use Illuminate\Broadcasting\InteractsWithSockets; @@ -13,7 +13,7 @@ use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Queue\SerializesModels; -final class ScrapeResultEvent implements ShouldBroadcast +final class ScrapeAnimeResultEvent implements ShouldBroadcast { use Dispatchable; use InteractsWithSockets; @@ -24,7 +24,7 @@ final class ScrapeResultEvent implements ShouldBroadcast /** * Create a new event instance. */ - public function __construct(public readonly ScrapeResultDTO $dto) + public function __construct(public readonly ScrapeAnimeResultDTO $dto) { // } @@ -34,7 +34,7 @@ public function __construct(public readonly ScrapeResultDTO $dto) */ public function broadcastQueue(): string { - return QueueEnum::PUSHER_QUEUE->value; + return QueueEnum::SOCKET_QUEUE->value; } /** @@ -42,7 +42,7 @@ public function broadcastQueue(): string */ public function broadcastAs(): string { - return 'scrape.result'; + return 'scrape.anime.result'; } /** @@ -63,6 +63,6 @@ public function broadcastWith(): array */ public function broadcastOn(): Channel { - return new PrivateChannel('scraper.' . $this->dto->userId); + return new PrivateChannel('scrape.anime.' . $this->dto->userId); } } diff --git a/src/app/Jobs/Scraper/ScrapeAnimeJob.php b/src/app/Jobs/Scraper/ScrapeAnimeJob.php index da28cdb9..17c0c1e8 100644 --- a/src/app/Jobs/Scraper/ScrapeAnimeJob.php +++ b/src/app/Jobs/Scraper/ScrapeAnimeJob.php @@ -4,10 +4,10 @@ namespace App\Jobs\Scraper; -use App\DTO\Events\Pusher\ScrapeResultDTO; -use App\Enums\Events\Pusher\ScrapeResultTypeEnum; +use App\DTO\Events\Scraper\ScrapeAnimeResultDTO; +use App\Enums\Events\Scraper\ScrapeResultTypeEnum; use App\Enums\QueueEnum; -use App\Events\Pusher\ScrapeResultEvent; +use App\Events\Scraper\ScrapeAnimeResultEvent; use App\UseCase\Scraper\ScraperUseCase; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; @@ -40,16 +40,16 @@ public function handle(ScraperUseCase $scraperUseCase): void { try { $anime = $scraperUseCase->scrapeByUrl($this->url); - ScrapeResultEvent::broadcast( - new ScrapeResultDTO( + ScrapeAnimeResultEvent::broadcast( + new ScrapeAnimeResultDTO( $this->userId, ScrapeResultTypeEnum::SUCCESS, $anime->id ) ); } catch (RequestException | ValidationException | Throwable $e) { - ScrapeResultEvent::broadcast( - new ScrapeResultDTO( + ScrapeAnimeResultEvent::broadcast( + new ScrapeAnimeResultDTO( $this->userId, ScrapeResultTypeEnum::ERROR, $e->getMessage() diff --git a/src/bootstrap/app.php b/src/bootstrap/app.php index 4627e563..c4cfa4e0 100644 --- a/src/bootstrap/app.php +++ b/src/bootstrap/app.php @@ -22,6 +22,7 @@ ->withRouting( web : __DIR__ . '/../routes/web.php', commands: __DIR__ . '/../routes/console.php', + channels: __DIR__ . '/../routes/channels.php', health : '/up', ) ->withMiddleware(function (Middleware $middleware) { diff --git a/src/composer.json b/src/composer.json index 5bc8bca7..b30cecfa 100644 --- a/src/composer.json +++ b/src/composer.json @@ -20,6 +20,7 @@ "laravel/framework": "v11.16.0", "laravel/horizon": "^5.25.0", "laravel/octane": "^2.5.2", + "laravel/reverb": "^1.0", "laravel/sanctum": "^4.0.2", "laravel/tinker": "^2.9.0", "nutgram/laravel": "^1.4.1", diff --git a/src/composer.lock b/src/composer.lock index f310456c..c026a2f2 100644 --- a/src/composer.lock +++ b/src/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "4de66c8f579de5bf5c63031cd5941f91", + "content-hash": "d1f90285a6d5d470811476a91088c161", "packages": [ { "name": "aws/aws-crt-php", @@ -482,6 +482,122 @@ }, "time": "2024-05-27T12:26:00+00:00" }, + { + "name": "clue/redis-protocol", + "version": "v0.3.1", + "source": { + "type": "git", + "url": "https://github.com/clue/php-redis-protocol.git", + "reference": "271b8009887209d930f613ad3b9518f94bd6b51c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/clue/php-redis-protocol/zipball/271b8009887209d930f613ad3b9518f94bd6b51c", + "reference": "271b8009887209d930f613ad3b9518f94bd6b51c", + "shasum": "" + }, + "require": { + "php": ">=5.3" + }, + "type": "library", + "autoload": { + "psr-0": { + "Clue\\Redis\\Protocol": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@lueck.tv" + } + ], + "description": "A streaming redis wire protocol parser and serializer implementation in PHP", + "homepage": "https://github.com/clue/php-redis-protocol", + "keywords": [ + "parser", + "protocol", + "redis", + "serializer", + "streaming" + ], + "support": { + "issues": "https://github.com/clue/php-redis-protocol/issues", + "source": "https://github.com/clue/php-redis-protocol/tree/v0.3.1" + }, + "time": "2017-06-06T16:07:10+00:00" + }, + { + "name": "clue/redis-react", + "version": "v2.7.0", + "source": { + "type": "git", + "url": "https://github.com/clue/reactphp-redis.git", + "reference": "2283690f249e8d93342dd63b5285732d2654e077" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/clue/reactphp-redis/zipball/2283690f249e8d93342dd63b5285732d2654e077", + "reference": "2283690f249e8d93342dd63b5285732d2654e077", + "shasum": "" + }, + "require": { + "clue/redis-protocol": "0.3.*", + "evenement/evenement": "^3.0 || ^2.0 || ^1.0", + "php": ">=5.3", + "react/event-loop": "^1.2", + "react/promise": "^3 || ^2.0 || ^1.1", + "react/promise-timer": "^1.9", + "react/socket": "^1.12" + }, + "require-dev": { + "clue/block-react": "^1.5", + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" + }, + "type": "library", + "autoload": { + "psr-4": { + "Clue\\React\\Redis\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering" + } + ], + "description": "Async Redis client implementation, built on top of ReactPHP.", + "homepage": "https://github.com/clue/reactphp-redis", + "keywords": [ + "async", + "client", + "database", + "reactphp", + "redis" + ], + "support": { + "issues": "https://github.com/clue/reactphp-redis/issues", + "source": "https://github.com/clue/reactphp-redis/tree/v2.7.0" + }, + "funding": [ + { + "url": "https://clue.engineering/support", + "type": "custom" + }, + { + "url": "https://github.com/clue", + "type": "github" + } + ], + "time": "2024-01-05T15:54:20+00:00" + }, { "name": "dflydev/dot-access-data", "version": "v3.0.3", @@ -966,6 +1082,53 @@ }, "time": "2024-06-12T19:58:31+00:00" }, + { + "name": "evenement/evenement", + "version": "v3.0.2", + "source": { + "type": "git", + "url": "https://github.com/igorw/evenement.git", + "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/igorw/evenement/zipball/0a16b0d71ab13284339abb99d9d2bd813640efbc", + "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc", + "shasum": "" + }, + "require": { + "php": ">=7.0" + }, + "require-dev": { + "phpunit/phpunit": "^9 || ^6" + }, + "type": "library", + "autoload": { + "psr-4": { + "Evenement\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + } + ], + "description": "Événement is a very simple event dispatching library for PHP", + "keywords": [ + "event-dispatcher", + "event-emitter" + ], + "support": { + "issues": "https://github.com/igorw/evenement/issues", + "source": "https://github.com/igorw/evenement/tree/v3.0.2" + }, + "time": "2023-08-08T05:53:35+00:00" + }, { "name": "firebase/php-jwt", "version": "v6.10.1", @@ -2167,6 +2330,88 @@ }, "time": "2024-06-17T13:58:22+00:00" }, + { + "name": "laravel/reverb", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/laravel/reverb.git", + "reference": "15e192405d39ce66a845e56ccefc207cd73c3429" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/reverb/zipball/15e192405d39ce66a845e56ccefc207cd73c3429", + "reference": "15e192405d39ce66a845e56ccefc207cd73c3429", + "shasum": "" + }, + "require": { + "clue/redis-react": "^2.6", + "guzzlehttp/psr7": "^2.6", + "illuminate/console": "^10.47|^11.0", + "illuminate/contracts": "^10.47|^11.0", + "illuminate/http": "^10.47|^11.0", + "illuminate/support": "^10.47|^11.0", + "laravel/prompts": "^0.1.15", + "php": "^8.2", + "pusher/pusher-php-server": "^7.2", + "ratchet/rfc6455": "^0.3.1", + "react/promise-timer": "^1.10", + "react/socket": "^1.14", + "symfony/console": "^6.0|^7.0", + "symfony/http-foundation": "^6.3|^7.0" + }, + "require-dev": { + "orchestra/testbench": "^8.0|^9.0", + "pestphp/pest": "^2.0", + "phpstan/phpstan": "^1.10", + "ratchet/pawl": "^0.4.1", + "react/async": "^4.2", + "react/http": "^1.9" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Laravel\\Reverb\\ApplicationManagerServiceProvider", + "Laravel\\Reverb\\ReverbServiceProvider" + ], + "aliases": { + "Output": "Laravel\\Reverb\\Output" + } + } + }, + "autoload": { + "psr-4": { + "Laravel\\Reverb\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + }, + { + "name": "Joe Dixon", + "email": "joe@laravel.com" + } + ], + "description": "Laravel Reverb provides a real-time WebSocket communication backend for Laravel applications.", + "keywords": [ + "WebSockets", + "laravel", + "real-time", + "websocket" + ], + "support": { + "issues": "https://github.com/laravel/reverb/issues", + "source": "https://github.com/laravel/reverb/tree/v1.0.0" + }, + "time": "2024-07-02T19:11:48+00:00" + }, { "name": "laravel/sanctum", "version": "v4.0.2", @@ -4905,6 +5150,593 @@ ], "time": "2024-04-27T21:32:50+00:00" }, + { + "name": "ratchet/rfc6455", + "version": "v0.3.1", + "source": { + "type": "git", + "url": "https://github.com/ratchetphp/RFC6455.git", + "reference": "7c964514e93456a52a99a20fcfa0de242a43ccdb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ratchetphp/RFC6455/zipball/7c964514e93456a52a99a20fcfa0de242a43ccdb", + "reference": "7c964514e93456a52a99a20fcfa0de242a43ccdb", + "shasum": "" + }, + "require": { + "guzzlehttp/psr7": "^2 || ^1.7", + "php": ">=5.4.2" + }, + "require-dev": { + "phpunit/phpunit": "^5.7", + "react/socket": "^1.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Ratchet\\RFC6455\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "role": "Developer" + }, + { + "name": "Matt Bonneau", + "role": "Developer" + } + ], + "description": "RFC6455 WebSocket protocol handler", + "homepage": "http://socketo.me", + "keywords": [ + "WebSockets", + "rfc6455", + "websocket" + ], + "support": { + "chat": "https://gitter.im/reactphp/reactphp", + "issues": "https://github.com/ratchetphp/RFC6455/issues", + "source": "https://github.com/ratchetphp/RFC6455/tree/v0.3.1" + }, + "time": "2021-12-09T23:20:49+00:00" + }, + { + "name": "react/cache", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/cache.git", + "reference": "d47c472b64aa5608225f47965a484b75c7817d5b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/cache/zipball/d47c472b64aa5608225f47965a484b75c7817d5b", + "reference": "d47c472b64aa5608225f47965a484b75c7817d5b", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "react/promise": "^3.0 || ^2.0 || ^1.1" + }, + "require-dev": { + "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Async, Promise-based cache interface for ReactPHP", + "keywords": [ + "cache", + "caching", + "promise", + "reactphp" + ], + "support": { + "issues": "https://github.com/reactphp/cache/issues", + "source": "https://github.com/reactphp/cache/tree/v1.2.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2022-11-30T15:59:55+00:00" + }, + { + "name": "react/dns", + "version": "v1.13.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/dns.git", + "reference": "eb8ae001b5a455665c89c1df97f6fb682f8fb0f5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/dns/zipball/eb8ae001b5a455665c89c1df97f6fb682f8fb0f5", + "reference": "eb8ae001b5a455665c89c1df97f6fb682f8fb0f5", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "react/cache": "^1.0 || ^0.6 || ^0.5", + "react/event-loop": "^1.2", + "react/promise": "^3.2 || ^2.7 || ^1.2.1" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", + "react/async": "^4.3 || ^3 || ^2", + "react/promise-timer": "^1.11" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Dns\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Async DNS resolver for ReactPHP", + "keywords": [ + "async", + "dns", + "dns-resolver", + "reactphp" + ], + "support": { + "issues": "https://github.com/reactphp/dns/issues", + "source": "https://github.com/reactphp/dns/tree/v1.13.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2024-06-13T14:18:03+00:00" + }, + { + "name": "react/event-loop", + "version": "v1.5.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/event-loop.git", + "reference": "bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/event-loop/zipball/bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354", + "reference": "bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" + }, + "suggest": { + "ext-pcntl": "For signal handling support when using the StreamSelectLoop" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\EventLoop\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "ReactPHP's core reactor event loop that libraries can use for evented I/O.", + "keywords": [ + "asynchronous", + "event-loop" + ], + "support": { + "issues": "https://github.com/reactphp/event-loop/issues", + "source": "https://github.com/reactphp/event-loop/tree/v1.5.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2023-11-13T13:48:05+00:00" + }, + { + "name": "react/promise", + "version": "v3.2.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/promise.git", + "reference": "8a164643313c71354582dc850b42b33fa12a4b63" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/promise/zipball/8a164643313c71354582dc850b42b33fa12a4b63", + "reference": "8a164643313c71354582dc850b42b33fa12a4b63", + "shasum": "" + }, + "require": { + "php": ">=7.1.0" + }, + "require-dev": { + "phpstan/phpstan": "1.10.39 || 1.4.10", + "phpunit/phpunit": "^9.6 || ^7.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "React\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "A lightweight implementation of CommonJS Promises/A for PHP", + "keywords": [ + "promise", + "promises" + ], + "support": { + "issues": "https://github.com/reactphp/promise/issues", + "source": "https://github.com/reactphp/promise/tree/v3.2.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2024-05-24T10:39:05+00:00" + }, + { + "name": "react/promise-timer", + "version": "v1.11.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/promise-timer.git", + "reference": "4f70306ed66b8b44768941ca7f142092600fafc1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/promise-timer/zipball/4f70306ed66b8b44768941ca7f142092600fafc1", + "reference": "4f70306ed66b8b44768941ca7f142092600fafc1", + "shasum": "" + }, + "require": { + "php": ">=5.3", + "react/event-loop": "^1.2", + "react/promise": "^3.2 || ^2.7.0 || ^1.2.1" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "React\\Promise\\Timer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "A trivial implementation of timeouts for Promises, built on top of ReactPHP.", + "homepage": "https://github.com/reactphp/promise-timer", + "keywords": [ + "async", + "event-loop", + "promise", + "reactphp", + "timeout", + "timer" + ], + "support": { + "issues": "https://github.com/reactphp/promise-timer/issues", + "source": "https://github.com/reactphp/promise-timer/tree/v1.11.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2024-06-04T14:27:45+00:00" + }, + { + "name": "react/socket", + "version": "v1.16.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/socket.git", + "reference": "23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/socket/zipball/23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1", + "reference": "23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1", + "shasum": "" + }, + "require": { + "evenement/evenement": "^3.0 || ^2.0 || ^1.0", + "php": ">=5.3.0", + "react/dns": "^1.13", + "react/event-loop": "^1.2", + "react/promise": "^3.2 || ^2.6 || ^1.2.1", + "react/stream": "^1.4" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", + "react/async": "^4.3 || ^3.3 || ^2", + "react/promise-stream": "^1.4", + "react/promise-timer": "^1.11" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Socket\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Async, streaming plaintext TCP/IP and secure TLS socket server and client connections for ReactPHP", + "keywords": [ + "Connection", + "Socket", + "async", + "reactphp", + "stream" + ], + "support": { + "issues": "https://github.com/reactphp/socket/issues", + "source": "https://github.com/reactphp/socket/tree/v1.16.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2024-07-26T10:38:09+00:00" + }, + { + "name": "react/stream", + "version": "v1.4.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/stream.git", + "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/stream/zipball/1e5b0acb8fe55143b5b426817155190eb6f5b18d", + "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d", + "shasum": "" + }, + "require": { + "evenement/evenement": "^3.0 || ^2.0 || ^1.0", + "php": ">=5.3.8", + "react/event-loop": "^1.2" + }, + "require-dev": { + "clue/stream-filter": "~1.2", + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Stream\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Event-driven readable and writable streams for non-blocking I/O in ReactPHP", + "keywords": [ + "event-driven", + "io", + "non-blocking", + "pipe", + "reactphp", + "readable", + "stream", + "writable" + ], + "support": { + "issues": "https://github.com/reactphp/stream/issues", + "source": "https://github.com/reactphp/stream/tree/v1.4.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2024-06-11T12:45:25+00:00" + }, { "name": "sergix44/container", "version": "3.1.0", diff --git a/src/config/reverb.php b/src/config/reverb.php new file mode 100644 index 00000000..bb92ec74 --- /dev/null +++ b/src/config/reverb.php @@ -0,0 +1,92 @@ + env('REVERB_SERVER', 'reverb'), + + /* + |-------------------------------------------------------------------------- + | Reverb Servers + |-------------------------------------------------------------------------- + | + | Here you may define details for each of the supported Reverb servers. + | Each server has its own configuration options that are defined in + | the array below. You should ensure all the options are present. + | + */ + + 'servers' => [ + + 'reverb' => [ + 'host' => env('REVERB_SERVER_HOST', '0.0.0.0'), + 'port' => env('REVERB_SERVER_PORT', 8080), + 'hostname' => env('REVERB_HOST'), + 'options' => [ + 'tls' => [], + ], + 'max_request_size' => env('REVERB_MAX_REQUEST_SIZE', 10_000), + 'scaling' => [ + 'enabled' => env('REVERB_SCALING_ENABLED', false), + 'channel' => env('REVERB_SCALING_CHANNEL', 'reverb'), + 'server' => [ + 'url' => env('REDIS_URL'), + 'host' => env('REDIS_HOST', '127.0.0.1'), + 'port' => env('REDIS_PORT', '6379'), + 'username' => env('REDIS_USERNAME'), + 'password' => env('REDIS_PASSWORD'), + 'database' => env('REDIS_DB', '0'), + ], + ], + 'pulse_ingest_interval' => env('REVERB_PULSE_INGEST_INTERVAL', 15), + 'telescope_ingest_interval' => env('REVERB_TELESCOPE_INGEST_INTERVAL', 15), + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Reverb Applications + |-------------------------------------------------------------------------- + | + | Here you may define how Reverb applications are managed. If you choose + | to use the "config" provider, you may define an array of apps which + | your server will support, including their connection credentials. + | + */ + + 'apps' => [ + + 'provider' => 'config', + + 'apps' => [ + [ + 'key' => env('REVERB_APP_KEY'), + 'secret' => env('REVERB_APP_SECRET'), + 'app_id' => env('REVERB_APP_ID'), + 'options' => [ + 'host' => env('REVERB_HOST'), + 'port' => env('REVERB_PORT', 443), + 'scheme' => env('REVERB_SCHEME', 'https'), + 'useTLS' => env('REVERB_SCHEME', 'https') === 'https', + ], + 'allowed_origins' => ['*'], + 'ping_interval' => env('REVERB_APP_PING_INTERVAL', 60), + 'max_message_size' => env('REVERB_APP_MAX_MESSAGE_SIZE', 10_000), + ], + ], + + ], + +]; diff --git a/src/resources/js/bootstrap.ts b/src/resources/js/bootstrap.ts index 669e4aae..9bcacebd 100644 --- a/src/resources/js/bootstrap.ts +++ b/src/resources/js/bootstrap.ts @@ -21,14 +21,11 @@ window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; // @ts-expect-error Need to resolve problem with Pusher instance window.pusher = Pusher; window.echo = new Echo({ - broadcaster: 'pusher', - key: import.meta.env.VITE_PUSHER_APP_KEY, - cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER ?? 'mt1', - wsHost: import.meta.env.VITE_PUSHER_HOST - ? import.meta.env.VITE_PUSHER_HOST - : `ws-${import.meta.env.VITE_PUSHER_APP_CLUSTER}.pusher.com`, - wsPort: import.meta.env.VITE_PUSHER_PORT ?? 80, - wssPort: import.meta.env.VITE_PUSHER_PORT ?? 443, - forceTLS: (import.meta.env.VITE_PUSHER_SCHEME ?? 'https') === 'https', + broadcaster: 'reverb', + key: import.meta.env.VITE_REVERB_APP_KEY, + wsHost: import.meta.env.VITE_REVERB_HOST, + wsPort: import.meta.env.VITE_REVERB_PORT ?? 80, + wssPort: import.meta.env.VITE_REVERB_PORT ?? 443, + forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https', enabledTransports: ['ws', 'wss'], }); diff --git a/src/resources/js/entities/pusher/index.ts b/src/resources/js/entities/scraper/index.ts similarity index 100% rename from src/resources/js/entities/pusher/index.ts rename to src/resources/js/entities/scraper/index.ts diff --git a/src/resources/js/entities/pusher/model/index.ts b/src/resources/js/entities/scraper/model/index.ts similarity index 100% rename from src/resources/js/entities/pusher/model/index.ts rename to src/resources/js/entities/scraper/model/index.ts diff --git a/src/resources/js/entities/pusher/model/types.ts b/src/resources/js/entities/scraper/model/types.ts similarity index 100% rename from src/resources/js/entities/pusher/model/types.ts rename to src/resources/js/entities/scraper/model/types.ts diff --git a/src/resources/js/features/anime/scrape-anime-modal/ScrapeAnimeModal.vue b/src/resources/js/features/anime/scrape-anime-modal/ScrapeAnimeModal.vue index 4aaf2a25..604e4007 100644 --- a/src/resources/js/features/anime/scrape-anime-modal/ScrapeAnimeModal.vue +++ b/src/resources/js/features/anime/scrape-anime-modal/ScrapeAnimeModal.vue @@ -3,7 +3,7 @@ import { TextInput } from '@/shared/ui/input'; import { Label } from '@/shared/ui/label'; import { ErrorMessage } from '@/shared/ui/error-message'; import { useForm, usePage } from '@inertiajs/vue3'; -import { ScrapeResult } from '@/entities/pusher'; +import { ScrapeResult } from '@/entities/scraper'; import { useToast } from 'primevue/usetoast'; import { Modal } from '@/shared/ui/modal'; import { Button } from '@/shared/ui/button'; @@ -27,7 +27,7 @@ const form = useForm({ const addAnime = () => { form.post(route('anime.store'), { onSuccess: () => { - const channelName = `scraper.${page.props.auth?.user?.id}`; + const channelName = `scrape.anime.${page.props.auth?.user?.id}`; toast.add({ summary: page.props.flash.message, @@ -37,7 +37,7 @@ const addAnime = () => { window.echo .private(channelName) - .listen('.scrape.result', (result: ScrapeResult) => { + .listen('.scrape.anime.result', (result: ScrapeResult) => { toast.add({ summary: result.message, severity: result.type, @@ -48,7 +48,7 @@ const addAnime = () => { }) .error(() => { toast.add({ - summary: 'Error while establishing Pusher connection', + summary: 'Error while establishing websocket connection', severity: 'error', closable: true, }); diff --git a/src/routes/channels.php b/src/routes/channels.php index 0ae1503a..bbe0342b 100644 --- a/src/routes/channels.php +++ b/src/routes/channels.php @@ -2,7 +2,7 @@ declare(strict_types=1); -use App\Models\User; +use App\Broadcasting\Scraper\ScrapeAnimeChannel; use Illuminate\Support\Facades\Broadcast; /* @@ -16,6 +16,4 @@ | */ -Broadcast::channel('scraper.{id}', function (User $user, string $requestedId) { - return $user->id === $requestedId; -}); +Broadcast::channel('scrape.anime.{id}', ScrapeAnimeChannel::class);