mirror of
https://github.com/shlinkio/shlink.git
synced 2025-01-04 21:24:58 -06:00
Merge pull request #1523 from acelaya-forks/feature/roadrunner-support
Feature/roadrunner support
This commit is contained in:
commit
e2eed8a728
@ -1,3 +1,4 @@
|
|||||||
|
bin/rr
|
||||||
config/autoload/*local*
|
config/autoload/*local*
|
||||||
data/infra
|
data/infra
|
||||||
data/cache/*
|
data/cache/*
|
||||||
@ -22,4 +23,4 @@ infection*
|
|||||||
**/test*
|
**/test*
|
||||||
build*
|
build*
|
||||||
**/.*
|
**/.*
|
||||||
bin/helper
|
!config/roadrunner/.rr.yml
|
||||||
|
2
.github/actions/ci-setup/action.yml
vendored
2
.github/actions/ci-setup/action.yml
vendored
@ -11,7 +11,7 @@ inputs:
|
|||||||
required: true
|
required: true
|
||||||
php-extensions:
|
php-extensions:
|
||||||
description: 'The PHP extensions to install'
|
description: 'The PHP extensions to install'
|
||||||
required: true
|
required: false
|
||||||
default: ''
|
default: ''
|
||||||
extensions-cache-key:
|
extensions-cache-key:
|
||||||
description: 'The key used to cache PHP extensions. If empty value is provided, extension caching is disabled'
|
description: 'The key used to cache PHP extensions. If empty value is provided, extension caching is disabled'
|
||||||
|
30
.github/workflows/ci.yml
vendored
30
.github/workflows/ci.yml
vendored
@ -29,16 +29,32 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
test-group: unit
|
test-group: unit
|
||||||
|
|
||||||
api-tests:
|
|
||||||
uses: './.github/workflows/ci-tests.yml'
|
|
||||||
with:
|
|
||||||
test-group: api
|
|
||||||
|
|
||||||
cli-tests:
|
cli-tests:
|
||||||
uses: './.github/workflows/ci-tests.yml'
|
uses: './.github/workflows/ci-tests.yml'
|
||||||
with:
|
with:
|
||||||
test-group: cli
|
test-group: cli
|
||||||
|
|
||||||
|
openswoole-api-tests:
|
||||||
|
uses: './.github/workflows/ci-tests.yml'
|
||||||
|
with:
|
||||||
|
test-group: api
|
||||||
|
|
||||||
|
roadrunner-api-tests:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
php-version: [ '8.1' ]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- run: docker-compose -f docker-compose.yml -f docker-compose.ci.yml up -d shlink_db_postgres
|
||||||
|
- uses: shivammathur/setup-php@v2
|
||||||
|
with:
|
||||||
|
php-version: ${{ matrix.php-version }}
|
||||||
|
tools: composer
|
||||||
|
- run: composer install --no-interaction --prefer-dist
|
||||||
|
- run: ./vendor/bin/rr get --no-interaction --location bin/ && chmod +x bin/rr
|
||||||
|
- run: composer test:api:rr
|
||||||
|
|
||||||
sqlite-db-tests:
|
sqlite-db-tests:
|
||||||
uses: './.github/workflows/ci-db-tests.yml'
|
uses: './.github/workflows/ci-db-tests.yml'
|
||||||
with:
|
with:
|
||||||
@ -80,7 +96,7 @@ jobs:
|
|||||||
|
|
||||||
api-mutation-tests:
|
api-mutation-tests:
|
||||||
needs:
|
needs:
|
||||||
- api-tests
|
- openswoole-api-tests
|
||||||
uses: './.github/workflows/ci-mutation-tests.yml'
|
uses: './.github/workflows/ci-mutation-tests.yml'
|
||||||
with:
|
with:
|
||||||
test-group: api
|
test-group: api
|
||||||
@ -95,7 +111,7 @@ jobs:
|
|||||||
upload-coverage:
|
upload-coverage:
|
||||||
needs:
|
needs:
|
||||||
- unit-tests
|
- unit-tests
|
||||||
- api-tests
|
- openswoole-api-tests
|
||||||
- cli-tests
|
- cli-tests
|
||||||
- sqlite-db-tests
|
- sqlite-db-tests
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
|
12
.github/workflows/docker-image-build.yml
vendored
12
.github/workflows/docker-image-build.yml
vendored
@ -8,9 +8,19 @@ on:
|
|||||||
- 'v*'
|
- 'v*'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build-openswool:
|
||||||
uses: shlinkio/github-actions/.github/workflows/docker-build-and-publish.yml@main
|
uses: shlinkio/github-actions/.github/workflows/docker-build-and-publish.yml@main
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
with:
|
with:
|
||||||
image-name: shlinkio/shlink
|
image-name: shlinkio/shlink
|
||||||
version-arg-name: SHLINK_VERSION
|
version-arg-name: SHLINK_VERSION
|
||||||
|
|
||||||
|
build-roadrunner:
|
||||||
|
uses: shlinkio/github-actions/.github/workflows/docker-build-and-publish.yml@main
|
||||||
|
secrets: inherit
|
||||||
|
with:
|
||||||
|
image-name: shlinkio/shlink
|
||||||
|
version-arg-name: SHLINK_VERSION
|
||||||
|
tags-suffix: roadrunner
|
||||||
|
extra-build-args: |
|
||||||
|
SHLINK_RUNTIME=rr
|
||||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,4 +1,7 @@
|
|||||||
.idea
|
.idea
|
||||||
|
bin/.rr.*
|
||||||
|
bin/rr
|
||||||
|
config/roadrunner/.pid
|
||||||
build
|
build
|
||||||
!docker/build
|
!docker/build
|
||||||
composer.lock
|
composer.lock
|
||||||
|
22
Dockerfile
22
Dockerfile
@ -2,6 +2,8 @@ FROM php:8.1.9-alpine3.16 as base
|
|||||||
|
|
||||||
ARG SHLINK_VERSION=latest
|
ARG SHLINK_VERSION=latest
|
||||||
ENV SHLINK_VERSION ${SHLINK_VERSION}
|
ENV SHLINK_VERSION ${SHLINK_VERSION}
|
||||||
|
ARG SHLINK_RUNTIME=openswoole
|
||||||
|
ENV SHLINK_RUNTIME ${SHLINK_RUNTIME}
|
||||||
ENV OPENSWOOLE_VERSION 4.11.1
|
ENV OPENSWOOLE_VERSION 4.11.1
|
||||||
ENV PDO_SQLSRV_VERSION 5.10.1
|
ENV PDO_SQLSRV_VERSION 5.10.1
|
||||||
ENV MS_ODBC_SQL_VERSION 17.5.2.2
|
ENV MS_ODBC_SQL_VERSION 17.5.2.2
|
||||||
@ -22,8 +24,10 @@ RUN \
|
|||||||
|
|
||||||
# Install openswoole and sqlsrv driver for x86_64 builds
|
# Install openswoole and sqlsrv driver for x86_64 builds
|
||||||
RUN apk add --no-cache --virtual .phpize-deps ${PHPIZE_DEPS} unixodbc-dev && \
|
RUN apk add --no-cache --virtual .phpize-deps ${PHPIZE_DEPS} unixodbc-dev && \
|
||||||
pecl install openswoole-${OPENSWOOLE_VERSION} && \
|
if [ "$SHLINK_RUNTIME" == 'openswoole' ]; then \
|
||||||
docker-php-ext-enable openswoole && \
|
pecl install openswoole-${OPENSWOOLE_VERSION} && \
|
||||||
|
docker-php-ext-enable openswoole ; \
|
||||||
|
fi; \
|
||||||
if [ $(uname -m) == "x86_64" ]; then \
|
if [ $(uname -m) == "x86_64" ]; then \
|
||||||
wget https://download.microsoft.com/download/e/4/e/e4e67866-dffd-428c-aac7-8d28ddafb39b/msodbcsql17_${MS_ODBC_SQL_VERSION}-1_amd64.apk && \
|
wget https://download.microsoft.com/download/e/4/e/e4e67866-dffd-428c-aac7-8d28ddafb39b/msodbcsql17_${MS_ODBC_SQL_VERSION}-1_amd64.apk && \
|
||||||
apk add --no-cache --allow-untrusted msodbcsql17_${MS_ODBC_SQL_VERSION}-1_amd64.apk && \
|
apk add --no-cache --allow-untrusted msodbcsql17_${MS_ODBC_SQL_VERSION}-1_amd64.apk && \
|
||||||
@ -38,7 +42,12 @@ FROM base as builder
|
|||||||
COPY . .
|
COPY . .
|
||||||
COPY --from=composer:2 /usr/bin/composer ./composer.phar
|
COPY --from=composer:2 /usr/bin/composer ./composer.phar
|
||||||
RUN apk add --no-cache git && \
|
RUN apk add --no-cache git && \
|
||||||
php composer.phar install --no-dev --optimize-autoloader --prefer-dist --no-progress --no-interaction && \
|
php composer.phar install --no-dev --prefer-dist --optimize-autoloader --no-progress --no-interaction && \
|
||||||
|
if [ "$SHLINK_RUNTIME" == 'openswoole' ]; then \
|
||||||
|
php composer.phar remove spiral/roadrunner spiral/roadrunner-jobs --with-all-dependencies --update-no-dev --optimize-autoloader --no-progress --no-interactionc ; \
|
||||||
|
elif [ $SHLINK_RUNTIME == 'rr' ]; then \
|
||||||
|
php composer.phar remove mezzio/mezzio-swoole --with-all-dependencies --update-no-dev --optimize-autoloader --no-progress --no-interaction ; \
|
||||||
|
fi; \
|
||||||
php composer.phar clear-cache && \
|
php composer.phar clear-cache && \
|
||||||
rm -r docker composer.* && \
|
rm -r docker composer.* && \
|
||||||
sed -i "s/%SHLINK_VERSION%/${SHLINK_VERSION}/g" config/autoload/app_options.global.php
|
sed -i "s/%SHLINK_VERSION%/${SHLINK_VERSION}/g" config/autoload/app_options.global.php
|
||||||
@ -49,9 +58,12 @@ FROM base
|
|||||||
LABEL maintainer="Alejandro Celaya <alejandro@alejandrocelaya.com>"
|
LABEL maintainer="Alejandro Celaya <alejandro@alejandrocelaya.com>"
|
||||||
|
|
||||||
COPY --from=builder /etc/shlink .
|
COPY --from=builder /etc/shlink .
|
||||||
RUN ln -s /etc/shlink/bin/cli /usr/local/bin/shlink
|
RUN ln -s /etc/shlink/bin/cli /usr/local/bin/shlink && \
|
||||||
|
if [ "$SHLINK_RUNTIME" == 'rr' ]; then \
|
||||||
|
php ./vendor/bin/rr get --no-interaction --location bin/ && chmod +x bin/rr ; \
|
||||||
|
fi;
|
||||||
|
|
||||||
# Expose default openswoole port
|
# Expose default port
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
|
|
||||||
# Copy config specific for the image
|
# Copy config specific for the image
|
||||||
|
@ -15,7 +15,7 @@ A PHP-based self-hosted URL shortener that can be used to serve shortened URLs u
|
|||||||
|
|
||||||
- [Full documentation](#full-documentation)
|
- [Full documentation](#full-documentation)
|
||||||
- [Docker image](#docker-image)
|
- [Docker image](#docker-image)
|
||||||
- [Self hosted](#self-hosted)
|
- [Self-hosted](#self-hosted)
|
||||||
- [Download](#download)
|
- [Download](#download)
|
||||||
- [Configure](#configure)
|
- [Configure](#configure)
|
||||||
- [Using shlink](#using-shlink)
|
- [Using shlink](#using-shlink)
|
||||||
|
32
bin/roadrunner-worker.php
Normal file
32
bin/roadrunner-worker.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Mezzio\Application;
|
||||||
|
use Psr\Container\ContainerInterface;
|
||||||
|
use Shlinkio\Shlink\EventDispatcher\RoadRunner\RoadRunnerTaskConsumerToListener;
|
||||||
|
use Spiral\RoadRunner\Http\PSR7Worker;
|
||||||
|
|
||||||
|
use function Shlinkio\Shlink\Config\env;
|
||||||
|
|
||||||
|
(static function (): void {
|
||||||
|
/** @var ContainerInterface $container */
|
||||||
|
$container = include __DIR__ . '/../config/container.php';
|
||||||
|
$rrMode = env('RR_MODE');
|
||||||
|
|
||||||
|
if ($rrMode === 'http') {
|
||||||
|
// This was spin-up as a web worker
|
||||||
|
$app = $container->get(Application::class);
|
||||||
|
$worker = $container->get(PSR7Worker::class);
|
||||||
|
|
||||||
|
while ($req = $worker->waitRequest()) {
|
||||||
|
try {
|
||||||
|
$worker->respond($app->handle($req));
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
$worker->getWorker()->error((string) $e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$container->get(RoadRunnerTaskConsumerToListener::class)->listenForTasks();
|
||||||
|
}
|
||||||
|
})();
|
@ -1,25 +1,38 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
export APP_ENV=test
|
export APP_ENV=test
|
||||||
export DB_DRIVER=postgres
|
|
||||||
export TEST_ENV=api
|
export TEST_ENV=api
|
||||||
export GENERATE_COVERAGE=${GENERATE_COVERAGE:-"no"}
|
export TEST_RUNTIME="${TEST_RUNTIME:-"openswoole"}"
|
||||||
|
export DB_DRIVER="${DB_DRIVER:-"postgres"}"
|
||||||
|
export GENERATE_COVERAGE="${GENERATE_COVERAGE:-"no"}"
|
||||||
|
|
||||||
# Reset logs
|
# Reset logs
|
||||||
|
OUTPUT_LOGS=data/log/api-tests/output.log
|
||||||
rm -rf data/log/api-tests
|
rm -rf data/log/api-tests
|
||||||
mkdir data/log/api-tests
|
mkdir data/log/api-tests
|
||||||
touch data/log/api-tests/output.log
|
touch $OUTPUT_LOGS
|
||||||
|
|
||||||
# Try to stop server just in case it hanged in last execution
|
# Try to stop server just in case it hanged in last execution
|
||||||
vendor/bin/laminas mezzio:swoole:stop
|
[ "$TEST_RUNTIME" = 'openswoole' ] && vendor/bin/laminas mezzio:swoole:stop
|
||||||
|
[ "$TEST_RUNTIME" = 'rr' ] && bin/rr stop -f
|
||||||
|
|
||||||
echo 'Starting server...'
|
echo 'Starting server...'
|
||||||
vendor/bin/laminas mezzio:swoole:start -d
|
[ "$TEST_RUNTIME" = 'openswoole' ] && vendor/bin/laminas mezzio:swoole:start -d
|
||||||
sleep 2
|
[ "$TEST_RUNTIME" = 'rr' ] && bin/rr serve -p -c=config/roadrunner/.rr.dev.yml \
|
||||||
|
-o=http.address=0.0.0.0:9999 \
|
||||||
|
-o=logs.encoding=json \
|
||||||
|
-o=logs.channels.http.encoding=json \
|
||||||
|
-o=logs.channels.server.encoding=json \
|
||||||
|
-o=logs.output="${PWD}/${OUTPUT_LOGS}" \
|
||||||
|
-o=logs.channels.http.output="${PWD}/${OUTPUT_LOGS}" \
|
||||||
|
-o=logs.channels.server.output="${PWD}/${OUTPUT_LOGS}" &
|
||||||
|
sleep 2 # Let's give the server a couple of seconds to start
|
||||||
|
|
||||||
vendor/bin/phpunit --order-by=random -c phpunit-api.xml --testdox --colors=always --log-junit=build/coverage-api/junit.xml $*
|
vendor/bin/phpunit --order-by=random -c phpunit-api.xml --testdox --colors=always --log-junit=build/coverage-api/junit.xml $*
|
||||||
testsExitCode=$?
|
testsExitCode=$?
|
||||||
|
|
||||||
vendor/bin/laminas mezzio:swoole:stop
|
[ "$TEST_RUNTIME" = 'openswoole' ] && vendor/bin/laminas mezzio:swoole:stop
|
||||||
|
[ "$TEST_RUNTIME" = 'rr' ] && bin/rr stop -c config/roadrunner/.rr.dev.yml -o=http.address=0.0.0.0:9999
|
||||||
|
|
||||||
# Exit this script with the same code as the tests. If tests failed, this script has to fail
|
# Exit this script with the same code as the tests. If tests failed, this script has to fail
|
||||||
exit $testsExitCode
|
exit $testsExitCode
|
||||||
|
4
build.sh
4
build.sh
@ -24,6 +24,7 @@ rsync -av * "${builtContent}" \
|
|||||||
--exclude=*docker* \
|
--exclude=*docker* \
|
||||||
--exclude=Dockerfile \
|
--exclude=Dockerfile \
|
||||||
--include=.htaccess \
|
--include=.htaccess \
|
||||||
|
--include=config/roadrunner/.rr.yml \
|
||||||
--exclude-from=./.dockerignore
|
--exclude-from=./.dockerignore
|
||||||
cd "${builtContent}"
|
cd "${builtContent}"
|
||||||
|
|
||||||
@ -36,6 +37,9 @@ ${composerBin} install --no-dev --prefer-dist $composerFlags
|
|||||||
if [[ $noSwoole ]]; then
|
if [[ $noSwoole ]]; then
|
||||||
# If generating a dist not for openswoole, uninstall mezzio-swoole
|
# If generating a dist not for openswoole, uninstall mezzio-swoole
|
||||||
${composerBin} remove mezzio/mezzio-swoole --with-all-dependencies --update-no-dev $composerFlags
|
${composerBin} remove mezzio/mezzio-swoole --with-all-dependencies --update-no-dev $composerFlags
|
||||||
|
else
|
||||||
|
# If generating a dist for openswoole, uninstall RoadRunner
|
||||||
|
${composerBin} remove spiral/roadrunner spiral/roadrunner-jobs --with-all-dependencies --update-no-dev $composerFlags
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Delete development files
|
# Delete development files
|
||||||
|
@ -44,11 +44,13 @@
|
|||||||
"pugx/shortid-php": "^1.0",
|
"pugx/shortid-php": "^1.0",
|
||||||
"ramsey/uuid": "^4.3",
|
"ramsey/uuid": "^4.3",
|
||||||
"shlinkio/shlink-common": "^5.0",
|
"shlinkio/shlink-common": "^5.0",
|
||||||
"shlinkio/shlink-config": "^2.0",
|
"shlinkio/shlink-config": "dev-main#33004e6 as 2.1",
|
||||||
"shlinkio/shlink-event-dispatcher": "^2.5",
|
"shlinkio/shlink-event-dispatcher": "dev-main#48c0137 as 2.6",
|
||||||
"shlinkio/shlink-importer": "^4.0",
|
"shlinkio/shlink-importer": "^4.0",
|
||||||
"shlinkio/shlink-installer": "^8.1",
|
"shlinkio/shlink-installer": "^8.1",
|
||||||
"shlinkio/shlink-ip-geolocation": "^3.0",
|
"shlinkio/shlink-ip-geolocation": "^3.0",
|
||||||
|
"spiral/roadrunner": "^2.11",
|
||||||
|
"spiral/roadrunner-jobs": "^2.3",
|
||||||
"symfony/console": "^6.1",
|
"symfony/console": "^6.1",
|
||||||
"symfony/filesystem": "^6.1",
|
"symfony/filesystem": "^6.1",
|
||||||
"symfony/lock": "^6.1",
|
"symfony/lock": "^6.1",
|
||||||
@ -120,6 +122,7 @@
|
|||||||
"test:db:postgres": "DB_DRIVER=postgres composer test:db:sqlite",
|
"test:db:postgres": "DB_DRIVER=postgres composer test:db:sqlite",
|
||||||
"test:db:ms": "DB_DRIVER=mssql composer test:db:sqlite",
|
"test:db:ms": "DB_DRIVER=mssql composer test:db:sqlite",
|
||||||
"test:api": "bin/test/run-api-tests.sh",
|
"test:api": "bin/test/run-api-tests.sh",
|
||||||
|
"test:api:rr": "TEST_RUNTIME=rr bin/test/run-api-tests.sh",
|
||||||
"test:api:ci": "GENERATE_COVERAGE=yes composer test:api",
|
"test:api:ci": "GENERATE_COVERAGE=yes composer test:api",
|
||||||
"test:api:pretty": "GENERATE_COVERAGE=pretty composer test:api",
|
"test:api:pretty": "GENERATE_COVERAGE=pretty composer test:api",
|
||||||
"test:cli": "APP_ENV=test DB_DRIVER=maria TEST_ENV=cli php vendor/bin/phpunit --order-by=random --colors=always --testdox -c phpunit-cli.xml --log-junit=build/coverage-cli/junit.xml",
|
"test:cli": "APP_ENV=test DB_DRIVER=maria TEST_ENV=cli php vendor/bin/phpunit --order-by=random --colors=always --testdox -c phpunit-cli.xml --log-junit=build/coverage-cli/junit.xml",
|
||||||
|
@ -3,12 +3,22 @@
|
|||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
use GuzzleHttp\Client;
|
use GuzzleHttp\Client;
|
||||||
|
use Laminas\ServiceManager\AbstractFactory\ConfigAbstractFactory;
|
||||||
use Mezzio\Container;
|
use Mezzio\Container;
|
||||||
use Psr\Http\Client\ClientInterface;
|
use Psr\Http\Client\ClientInterface;
|
||||||
|
use Psr\Http\Message\ServerRequestFactoryInterface;
|
||||||
|
use Psr\Http\Message\StreamFactoryInterface;
|
||||||
|
use Psr\Http\Message\UploadedFileFactoryInterface;
|
||||||
|
use Spiral\RoadRunner\Http\PSR7Worker;
|
||||||
|
use Spiral\RoadRunner\WorkerInterface;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
||||||
'dependencies' => [
|
'dependencies' => [
|
||||||
|
'factories' => [
|
||||||
|
PSR7Worker::class => ConfigAbstractFactory::class,
|
||||||
|
],
|
||||||
|
|
||||||
'delegators' => [
|
'delegators' => [
|
||||||
Mezzio\Application::class => [
|
Mezzio\Application::class => [
|
||||||
Container\ApplicationConfigInjectionDelegator::class,
|
Container\ApplicationConfigInjectionDelegator::class,
|
||||||
@ -26,4 +36,13 @@ return [
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|
||||||
|
ConfigAbstractFactory::class => [
|
||||||
|
PSR7Worker::class => [
|
||||||
|
WorkerInterface::class,
|
||||||
|
ServerRequestFactoryInterface::class,
|
||||||
|
StreamFactoryInterface::class,
|
||||||
|
UploadedFileFactoryInterface::class,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
];
|
];
|
||||||
|
@ -7,7 +7,7 @@ return [
|
|||||||
'mercure' => [
|
'mercure' => [
|
||||||
'public_hub_url' => 'http://localhost:8001',
|
'public_hub_url' => 'http://localhost:8001',
|
||||||
'internal_hub_url' => 'http://shlink_mercure_proxy',
|
'internal_hub_url' => 'http://shlink_mercure_proxy',
|
||||||
'jwt_secret' => 'mercure_jwt_key',
|
'jwt_secret' => 'mercure_jwt_key_long_enough_to_avoid_error',
|
||||||
],
|
],
|
||||||
|
|
||||||
];
|
];
|
||||||
|
@ -2,14 +2,19 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
$isSwoole = extension_loaded('openswoole');
|
use function Shlinkio\Shlink\Config\runningInOpenswoole;
|
||||||
|
use function Shlinkio\Shlink\Config\runningInRoadRunner;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
||||||
'url_shortener' => [
|
'url_shortener' => [
|
||||||
'domain' => [
|
'domain' => [
|
||||||
'schema' => 'http',
|
'schema' => 'http',
|
||||||
'hostname' => sprintf('localhost:%s', $isSwoole ? '8080' : '8000'),
|
'hostname' => sprintf('localhost:%s', match (true) {
|
||||||
|
runningInRoadRunner() => '8800',
|
||||||
|
runningInOpenswoole() => '8080',
|
||||||
|
default => '8000',
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
'auto_resolve_titles' => true,
|
'auto_resolve_titles' => true,
|
||||||
// 'multi_segment_slugs_enabled' => true,
|
// 'multi_segment_slugs_enabled' => true,
|
||||||
|
@ -13,11 +13,13 @@ use Shlinkio\Shlink\Config\ConfigAggregator\EnvVarLoaderProvider;
|
|||||||
|
|
||||||
use function class_exists;
|
use function class_exists;
|
||||||
use function Shlinkio\Shlink\Config\env;
|
use function Shlinkio\Shlink\Config\env;
|
||||||
|
use function Shlinkio\Shlink\Config\openswooleIsInstalled;
|
||||||
|
use function Shlinkio\Shlink\Config\runningInRoadRunner;
|
||||||
|
|
||||||
use const PHP_SAPI;
|
use const PHP_SAPI;
|
||||||
|
|
||||||
$isCli = PHP_SAPI === 'cli';
|
|
||||||
$isTestEnv = env('APP_ENV') === 'test';
|
$isTestEnv = env('APP_ENV') === 'test';
|
||||||
|
$enableSwoole = PHP_SAPI === 'cli' && openswooleIsInstalled() && ! runningInRoadRunner();
|
||||||
|
|
||||||
return (new ConfigAggregator\ConfigAggregator([
|
return (new ConfigAggregator\ConfigAggregator([
|
||||||
! $isTestEnv
|
! $isTestEnv
|
||||||
@ -26,7 +28,7 @@ return (new ConfigAggregator\ConfigAggregator([
|
|||||||
Mezzio\ConfigProvider::class,
|
Mezzio\ConfigProvider::class,
|
||||||
Mezzio\Router\ConfigProvider::class,
|
Mezzio\Router\ConfigProvider::class,
|
||||||
Mezzio\Router\FastRouteRouter\ConfigProvider::class,
|
Mezzio\Router\FastRouteRouter\ConfigProvider::class,
|
||||||
$isCli && class_exists(Swoole\ConfigProvider::class)
|
$enableSwoole && class_exists(Swoole\ConfigProvider::class)
|
||||||
? Swoole\ConfigProvider::class
|
? Swoole\ConfigProvider::class
|
||||||
: new ConfigAggregator\ArrayProvider([]),
|
: new ConfigAggregator\ArrayProvider([]),
|
||||||
ProblemDetails\ConfigProvider::class,
|
ProblemDetails\ConfigProvider::class,
|
||||||
|
49
config/roadrunner/.rr.dev.yml
Normal file
49
config/roadrunner/.rr.dev.yml
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
version: '2.7'
|
||||||
|
|
||||||
|
rpc:
|
||||||
|
listen: tcp://127.0.0.1:6001
|
||||||
|
|
||||||
|
server:
|
||||||
|
command: 'php ../../bin/roadrunner-worker.php'
|
||||||
|
|
||||||
|
http:
|
||||||
|
address: '0.0.0.0:8080'
|
||||||
|
middleware: ['static']
|
||||||
|
static:
|
||||||
|
dir: '../../public'
|
||||||
|
forbid: ['.php', '.htaccess']
|
||||||
|
pool:
|
||||||
|
num_workers: 16
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
pool:
|
||||||
|
num_workers: 16
|
||||||
|
timeout: 300
|
||||||
|
consume: ['shlink']
|
||||||
|
pipelines:
|
||||||
|
shlink:
|
||||||
|
driver: memory
|
||||||
|
config:
|
||||||
|
priority: 10
|
||||||
|
prefetch: 10
|
||||||
|
|
||||||
|
logs:
|
||||||
|
mode: development
|
||||||
|
channels:
|
||||||
|
http:
|
||||||
|
level: debug
|
||||||
|
server:
|
||||||
|
level: debug
|
||||||
|
metrics:
|
||||||
|
level: debug
|
||||||
|
|
||||||
|
reload:
|
||||||
|
interval: 1s
|
||||||
|
patterns: ['.php']
|
||||||
|
services:
|
||||||
|
http:
|
||||||
|
dirs: ['../../bin', '../../config', '../../data/migrations', '../../module', '../../vendor']
|
||||||
|
recursive: true
|
||||||
|
jobs:
|
||||||
|
dirs: ['../../bin', '../../config', '../../data/migrations', '../../module', '../../vendor']
|
||||||
|
recursive: true
|
36
config/roadrunner/.rr.yml
Normal file
36
config/roadrunner/.rr.yml
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
version: '2.7'
|
||||||
|
|
||||||
|
rpc:
|
||||||
|
listen: tcp://127.0.0.1:6001
|
||||||
|
|
||||||
|
server:
|
||||||
|
command: 'php -dopcache.enable_cli=1 -dopcache.validate_timestamps=0 ../../bin/roadrunner-worker.php'
|
||||||
|
|
||||||
|
http:
|
||||||
|
address: '0.0.0.0:${PORT}'
|
||||||
|
middleware: ['static']
|
||||||
|
static:
|
||||||
|
dir: '../../public'
|
||||||
|
forbid: ['.php', '.htaccess']
|
||||||
|
pool:
|
||||||
|
num_workers: ${WEB_WORKER_NUM}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
timeout: 300 # 5 minutes
|
||||||
|
pool:
|
||||||
|
num_workers: ${TASK_WORKER_NUM}
|
||||||
|
consume: ['shlink']
|
||||||
|
pipelines:
|
||||||
|
shlink:
|
||||||
|
driver: memory
|
||||||
|
config:
|
||||||
|
priority: 10
|
||||||
|
prefetch: 10
|
||||||
|
|
||||||
|
logs:
|
||||||
|
mode: production
|
||||||
|
channels:
|
||||||
|
http:
|
||||||
|
level: info # Log all http requests, set to info to disable
|
||||||
|
server:
|
||||||
|
level: debug # Everything written to worker stderr is logged
|
@ -10,8 +10,8 @@ use Psr\Container\ContainerInterface;
|
|||||||
use function register_shutdown_function;
|
use function register_shutdown_function;
|
||||||
use function sprintf;
|
use function sprintf;
|
||||||
|
|
||||||
use const ShlinkioTest\Shlink\SWOOLE_TESTING_HOST;
|
use const ShlinkioTest\Shlink\API_TESTS_HOST;
|
||||||
use const ShlinkioTest\Shlink\SWOOLE_TESTING_PORT;
|
use const ShlinkioTest\Shlink\API_TESTS_PORT;
|
||||||
|
|
||||||
/** @var ContainerInterface $container */
|
/** @var ContainerInterface $container */
|
||||||
$container = require __DIR__ . '/../container.php';
|
$container = require __DIR__ . '/../container.php';
|
||||||
@ -24,7 +24,7 @@ $httpClient = $container->get('shlink_test_api_client');
|
|||||||
register_shutdown_function(function () use ($httpClient): void {
|
register_shutdown_function(function () use ($httpClient): void {
|
||||||
$httpClient->request(
|
$httpClient->request(
|
||||||
'GET',
|
'GET',
|
||||||
sprintf('http://%s:%s/api-tests/stop-coverage', SWOOLE_TESTING_HOST, SWOOLE_TESTING_PORT),
|
sprintf('http://%s:%s/api-tests/stop-coverage', API_TESTS_HOST, API_TESTS_PORT),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -4,5 +4,5 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace ShlinkioTest\Shlink;
|
namespace ShlinkioTest\Shlink;
|
||||||
|
|
||||||
const SWOOLE_TESTING_HOST = '127.0.0.1';
|
const API_TESTS_HOST = '127.0.0.1';
|
||||||
const SWOOLE_TESTING_PORT = 9999;
|
const API_TESTS_PORT = 9999;
|
||||||
|
@ -34,8 +34,8 @@ use function Shlinkio\Shlink\Config\env;
|
|||||||
use function sprintf;
|
use function sprintf;
|
||||||
use function sys_get_temp_dir;
|
use function sys_get_temp_dir;
|
||||||
|
|
||||||
use const ShlinkioTest\Shlink\SWOOLE_TESTING_HOST;
|
use const ShlinkioTest\Shlink\API_TESTS_HOST;
|
||||||
use const ShlinkioTest\Shlink\SWOOLE_TESTING_PORT;
|
use const ShlinkioTest\Shlink\API_TESTS_PORT;
|
||||||
|
|
||||||
$isApiTest = env('TEST_ENV') === 'api';
|
$isApiTest = env('TEST_ENV') === 'api';
|
||||||
$isCliTest = env('TEST_ENV') === 'cli';
|
$isCliTest = env('TEST_ENV') === 'cli';
|
||||||
@ -136,8 +136,8 @@ return [
|
|||||||
'mezzio-swoole' => [
|
'mezzio-swoole' => [
|
||||||
'enable_coroutine' => false,
|
'enable_coroutine' => false,
|
||||||
'swoole-http-server' => [
|
'swoole-http-server' => [
|
||||||
'host' => SWOOLE_TESTING_HOST,
|
'host' => API_TESTS_HOST,
|
||||||
'port' => SWOOLE_TESTING_PORT,
|
'port' => API_TESTS_PORT,
|
||||||
'process-name' => 'shlink_test',
|
'process-name' => 'shlink_test',
|
||||||
'options' => [
|
'options' => [
|
||||||
'pid_file' => sys_get_temp_dir() . '/shlink-test-swoole.pid',
|
'pid_file' => sys_get_temp_dir() . '/shlink-test-swoole.pid',
|
||||||
@ -188,7 +188,7 @@ return [
|
|||||||
'dependencies' => [
|
'dependencies' => [
|
||||||
'services' => [
|
'services' => [
|
||||||
'shlink_test_api_client' => new Client([
|
'shlink_test_api_client' => new Client([
|
||||||
'base_uri' => sprintf('http://%s:%s/', SWOOLE_TESTING_HOST, SWOOLE_TESTING_PORT),
|
'base_uri' => sprintf('http://%s:%s/', API_TESTS_HOST, API_TESTS_PORT),
|
||||||
'http_errors' => false,
|
'http_errors' => false,
|
||||||
]),
|
]),
|
||||||
],
|
],
|
||||||
|
73
data/infra/roadrunner.Dockerfile
Normal file
73
data/infra/roadrunner.Dockerfile
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
FROM php:8.1.9-alpine3.16
|
||||||
|
MAINTAINER Alejandro Celaya <alejandro@alejandrocelaya.com>
|
||||||
|
|
||||||
|
ENV APCU_VERSION 5.1.21
|
||||||
|
ENV PDO_SQLSRV_VERSION 5.10.1
|
||||||
|
ENV MS_ODBC_SQL_VERSION 17.5.2.2
|
||||||
|
|
||||||
|
RUN apk update
|
||||||
|
|
||||||
|
# Install common php extensions
|
||||||
|
RUN docker-php-ext-install pdo_mysql
|
||||||
|
RUN docker-php-ext-install calendar
|
||||||
|
|
||||||
|
RUN apk add --no-cache oniguruma-dev
|
||||||
|
RUN docker-php-ext-install mbstring
|
||||||
|
|
||||||
|
RUN apk add --no-cache sqlite-libs
|
||||||
|
RUN apk add --no-cache sqlite-dev
|
||||||
|
RUN docker-php-ext-install pdo_sqlite
|
||||||
|
|
||||||
|
RUN apk add --no-cache icu-dev
|
||||||
|
RUN docker-php-ext-install intl
|
||||||
|
|
||||||
|
RUN apk add --no-cache libzip-dev zlib-dev
|
||||||
|
RUN docker-php-ext-install zip
|
||||||
|
|
||||||
|
RUN apk add --no-cache libpng-dev
|
||||||
|
RUN docker-php-ext-install gd
|
||||||
|
|
||||||
|
RUN apk add --no-cache postgresql-dev
|
||||||
|
RUN docker-php-ext-install pdo_pgsql
|
||||||
|
|
||||||
|
RUN docker-php-ext-install sockets
|
||||||
|
RUN docker-php-ext-install bcmath
|
||||||
|
|
||||||
|
# Install APCu extension
|
||||||
|
ADD https://pecl.php.net/get/apcu-$APCU_VERSION.tgz /tmp/apcu.tar.gz
|
||||||
|
RUN mkdir -p /usr/src/php/ext/apcu \
|
||||||
|
&& tar xf /tmp/apcu.tar.gz -C /usr/src/php/ext/apcu --strip-components=1 \
|
||||||
|
&& docker-php-ext-configure apcu \
|
||||||
|
&& docker-php-ext-install apcu \
|
||||||
|
&& rm /tmp/apcu.tar.gz \
|
||||||
|
&& rm /usr/local/etc/php/conf.d/docker-php-ext-apcu.ini \
|
||||||
|
&& echo extension=apcu.so > /usr/local/etc/php/conf.d/20-php-ext-apcu.ini
|
||||||
|
|
||||||
|
# Install pcov and sqlsrv driver
|
||||||
|
RUN wget https://download.microsoft.com/download/e/4/e/e4e67866-dffd-428c-aac7-8d28ddafb39b/msodbcsql17_${MS_ODBC_SQL_VERSION}-1_amd64.apk && \
|
||||||
|
apk add --allow-untrusted msodbcsql17_${MS_ODBC_SQL_VERSION}-1_amd64.apk && \
|
||||||
|
apk add --no-cache --virtual .phpize-deps $PHPIZE_DEPS unixodbc-dev && \
|
||||||
|
pecl install pdo_sqlsrv-${PDO_SQLSRV_VERSION} pcov && \
|
||||||
|
docker-php-ext-enable pdo_sqlsrv pcov && \
|
||||||
|
apk del .phpize-deps && \
|
||||||
|
rm msodbcsql17_${MS_ODBC_SQL_VERSION}-1_amd64.apk
|
||||||
|
|
||||||
|
# Install composer
|
||||||
|
COPY --from=composer:2 /usr/bin/composer /usr/local/bin/composer
|
||||||
|
|
||||||
|
# Make home directory writable by anyone
|
||||||
|
RUN chmod 777 /home
|
||||||
|
|
||||||
|
VOLUME /home/shlink
|
||||||
|
WORKDIR /home/shlink
|
||||||
|
|
||||||
|
# Expose roadrunner port
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
CMD \
|
||||||
|
# Install dependencies if the vendor dir does not exist
|
||||||
|
if [[ ! -d "./vendor" ]]; then /usr/local/bin/composer install ; fi && \
|
||||||
|
# Download roadrunner binary
|
||||||
|
if [[ ! -f "./bin/rr" ]]; then ./vendor/bin/rr get --no-interaction --location bin/ && chmod +x bin/rr ; fi && \
|
||||||
|
# This forces the app to be started every second until the exit code is 0
|
||||||
|
until ./bin/rr serve -c config/roadrunner/.rr.dev.yml; do sleep 1 ; done
|
@ -13,6 +13,12 @@ services:
|
|||||||
- /etc/passwd:/etc/passwd:ro
|
- /etc/passwd:/etc/passwd:ro
|
||||||
- /etc/group:/etc/group:ro
|
- /etc/group:/etc/group:ro
|
||||||
|
|
||||||
|
shlink_roadrunner:
|
||||||
|
user: 1000:1000
|
||||||
|
volumes:
|
||||||
|
- /etc/passwd:/etc/passwd:ro
|
||||||
|
- /etc/group:/etc/group:ro
|
||||||
|
|
||||||
shlink_db_mysql:
|
shlink_db_mysql:
|
||||||
user: 1000:1000
|
user: 1000:1000
|
||||||
volumes:
|
volumes:
|
||||||
|
@ -73,6 +73,30 @@ services:
|
|||||||
extra_hosts:
|
extra_hosts:
|
||||||
- 'host.docker.internal:host-gateway'
|
- 'host.docker.internal:host-gateway'
|
||||||
|
|
||||||
|
shlink_roadrunner:
|
||||||
|
container_name: shlink_roadrunner
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: ./data/infra/roadrunner.Dockerfile
|
||||||
|
ports:
|
||||||
|
- "8800:8080"
|
||||||
|
volumes:
|
||||||
|
- ./:/home/shlink
|
||||||
|
- ./data/infra/php.ini:/usr/local/etc/php/php.ini
|
||||||
|
links:
|
||||||
|
- shlink_db_mysql
|
||||||
|
- shlink_db_postgres
|
||||||
|
- shlink_db_maria
|
||||||
|
- shlink_db_ms
|
||||||
|
- shlink_redis
|
||||||
|
- shlink_mercure
|
||||||
|
- shlink_mercure_proxy
|
||||||
|
- shlink_rabbitmq
|
||||||
|
environment:
|
||||||
|
LC_ALL: C
|
||||||
|
extra_hosts:
|
||||||
|
- 'host.docker.internal:host-gateway'
|
||||||
|
|
||||||
shlink_db_mysql:
|
shlink_db_mysql:
|
||||||
container_name: shlink_db_mysql
|
container_name: shlink_db_mysql
|
||||||
image: mysql:5.7
|
image: mysql:5.7
|
||||||
@ -144,8 +168,8 @@ services:
|
|||||||
- "3080:80"
|
- "3080:80"
|
||||||
environment:
|
environment:
|
||||||
SERVER_NAME: ":80"
|
SERVER_NAME: ":80"
|
||||||
MERCURE_PUBLISHER_JWT_KEY: mercure_jwt_key
|
MERCURE_PUBLISHER_JWT_KEY: mercure_jwt_key_long_enough_to_avoid_error
|
||||||
MERCURE_SUBSCRIBER_JWT_KEY: mercure_jwt_key
|
MERCURE_SUBSCRIBER_JWT_KEY: mercure_jwt_key_long_enough_to_avoid_error
|
||||||
MERCURE_EXTRA_DIRECTIVES: "cors_origins https://app.shlink.io http://localhost:3000 http://127.0.0.1:3000"
|
MERCURE_EXTRA_DIRECTIVES: "cors_origins https://app.shlink.io http://localhost:3000 http://127.0.0.1:3000"
|
||||||
|
|
||||||
shlink_rabbitmq:
|
shlink_rabbitmq:
|
||||||
|
@ -6,11 +6,14 @@ namespace Shlinkio\Shlink;
|
|||||||
|
|
||||||
use Shlinkio\Shlink\Common\Logger\LoggerType;
|
use Shlinkio\Shlink\Common\Logger\LoggerType;
|
||||||
|
|
||||||
|
use function Shlinkio\Shlink\Config\runningInRoadRunner;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
||||||
'logger' => [
|
'logger' => [
|
||||||
'Shlink' => [
|
'Shlink' => [
|
||||||
'type' => LoggerType::STREAM->value,
|
'type' => LoggerType::STREAM->value,
|
||||||
|
'destination' => runningInRoadRunner() ? 'php://stderr' : 'php://stdout',
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|
||||||
|
@ -31,6 +31,15 @@ if [ $ENABLE_PERIODIC_VISIT_LOCATE ]; then
|
|||||||
/usr/sbin/crond &
|
/usr/sbin/crond &
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# When restarting the container, openswoole might think it is already in execution
|
# RoadRunner config needs these to have been set, so falling back to default values if not set yet
|
||||||
# This forces the app to be started every second until the exit code is 0
|
export PORT="${PORT:-"8765"}"
|
||||||
until php vendor/bin/laminas mezzio:swoole:start; do sleep 1 ; done
|
export WEB_WORKER_NUM="${WEB_WORKER_NUM:-"16"}"
|
||||||
|
export TASK_WORKER_NUM="${TASK_WORKER_NUM:-"16"}"
|
||||||
|
|
||||||
|
if [ "$SHLINK_RUNTIME" == 'openswoole' ]; then
|
||||||
|
# When restarting the container, openswoole might think it is already in execution
|
||||||
|
# This forces the app to be started every second until the exit code is 0
|
||||||
|
until php vendor/bin/laminas mezzio:swoole:start; do sleep 1 ; done
|
||||||
|
elif [ "$SHLINK_RUNTIME" == 'rr' ]; then
|
||||||
|
./bin/rr serve -c config/roadrunner/.rr.yml
|
||||||
|
fi
|
||||||
|
2
indocker
2
indocker
@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
# Run docker containers if they are not up yet
|
# Run docker containers if they are not up yet
|
||||||
if ! [[ $(docker ps | grep shlink_swoole) ]]; then
|
if ! [[ $(docker ps | grep shlink) ]]; then
|
||||||
docker-compose up -d
|
docker-compose up -d
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -5,10 +5,11 @@ declare(strict_types=1);
|
|||||||
namespace Shlinkio\Shlink\Core\EventDispatcher\Event;
|
namespace Shlinkio\Shlink\Core\EventDispatcher\Event;
|
||||||
|
|
||||||
use JsonSerializable;
|
use JsonSerializable;
|
||||||
|
use Shlinkio\Shlink\EventDispatcher\Util\JsonUnserializable;
|
||||||
|
|
||||||
abstract class AbstractVisitEvent implements JsonSerializable
|
abstract class AbstractVisitEvent implements JsonSerializable, JsonUnserializable
|
||||||
{
|
{
|
||||||
public function __construct(public readonly string $visitId)
|
final public function __construct(public readonly string $visitId)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -16,4 +17,9 @@ abstract class AbstractVisitEvent implements JsonSerializable
|
|||||||
{
|
{
|
||||||
return ['visitId' => $this->visitId];
|
return ['visitId' => $this->visitId];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function fromPayload(array $payload): self
|
||||||
|
{
|
||||||
|
return new static($payload['visitId'] ?? '');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,9 @@ declare(strict_types=1);
|
|||||||
namespace Shlinkio\Shlink\Core\EventDispatcher\Event;
|
namespace Shlinkio\Shlink\Core\EventDispatcher\Event;
|
||||||
|
|
||||||
use JsonSerializable;
|
use JsonSerializable;
|
||||||
|
use Shlinkio\Shlink\EventDispatcher\Util\JsonUnserializable;
|
||||||
|
|
||||||
final class ShortUrlCreated implements JsonSerializable
|
final class ShortUrlCreated implements JsonSerializable, JsonUnserializable
|
||||||
{
|
{
|
||||||
public function __construct(public readonly string $shortUrlId)
|
public function __construct(public readonly string $shortUrlId)
|
||||||
{
|
{
|
||||||
@ -18,4 +19,9 @@ final class ShortUrlCreated implements JsonSerializable
|
|||||||
'shortUrlId' => $this->shortUrlId,
|
'shortUrlId' => $this->shortUrlId,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function fromPayload(array $payload): self
|
||||||
|
{
|
||||||
|
return new self($payload['shortUrlId'] ?? '');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,18 @@ namespace Shlinkio\Shlink\Core\EventDispatcher\Event;
|
|||||||
|
|
||||||
final class UrlVisited extends AbstractVisitEvent
|
final class UrlVisited extends AbstractVisitEvent
|
||||||
{
|
{
|
||||||
public function __construct(string $visitId, public readonly ?string $originalIpAddress = null)
|
private ?string $originalIpAddress = null;
|
||||||
|
|
||||||
|
public static function withOriginalIpAddress(string $visitId, ?string $originalIpAddress): self
|
||||||
{
|
{
|
||||||
parent::__construct($visitId);
|
$instance = new self($visitId);
|
||||||
|
$instance->originalIpAddress = $originalIpAddress;
|
||||||
|
|
||||||
|
return $instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function originalIpAddress(): ?string
|
||||||
|
{
|
||||||
|
return $this->originalIpAddress;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ class LocateVisit
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->locateVisit($visitId, $shortUrlVisited->originalIpAddress, $visit);
|
$this->locateVisit($visitId, $shortUrlVisited->originalIpAddress(), $visit);
|
||||||
$this->eventDispatcher->dispatch(new VisitLocated($visitId));
|
$this->eventDispatcher->dispatch(new VisitLocated($visitId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,6 +72,6 @@ class VisitsTracker implements VisitsTrackerInterface
|
|||||||
$this->em->persist($visit);
|
$this->em->persist($visit);
|
||||||
$this->em->flush();
|
$this->em->flush();
|
||||||
|
|
||||||
$this->eventDispatcher->dispatch(new UrlVisited($visit->getId(), $visitor->remoteAddress));
|
$this->eventDispatcher->dispatch(UrlVisited::withOriginalIpAddress($visit->getId(), $visitor->remoteAddress));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -193,7 +193,7 @@ class LocateVisitTest extends TestCase
|
|||||||
{
|
{
|
||||||
$ipAddr = $originalIpAddress ?? $visit->getRemoteAddr();
|
$ipAddr = $originalIpAddress ?? $visit->getRemoteAddr();
|
||||||
$location = new Location('', '', '', '', 0.0, 0.0, '');
|
$location = new Location('', '', '', '', 0.0, 0.0, '');
|
||||||
$event = new UrlVisited('123', $originalIpAddress);
|
$event = UrlVisited::withOriginalIpAddress('123', $originalIpAddress);
|
||||||
|
|
||||||
$findVisit = $this->em->find(Visit::class, '123')->willReturn($visit);
|
$findVisit = $this->em->find(Visit::class, '123')->willReturn($visit);
|
||||||
$flush = $this->em->flush()->will(function (): void {
|
$flush = $this->em->flush()->will(function (): void {
|
||||||
|
@ -11,14 +11,14 @@ use Psr\Http\Server\RequestHandlerInterface;
|
|||||||
|
|
||||||
class DropDefaultDomainFromRequestMiddleware implements MiddlewareInterface
|
class DropDefaultDomainFromRequestMiddleware implements MiddlewareInterface
|
||||||
{
|
{
|
||||||
public function __construct(private string $defaultDomain)
|
public function __construct(private readonly string $defaultDomain)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
|
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
|
||||||
{
|
{
|
||||||
/** @var array $body */
|
/** @var array $body */
|
||||||
$body = $request->getParsedBody();
|
$body = $request->getParsedBody() ?? [];
|
||||||
$request = $request->withQueryParams($this->sanitizeDomainFromPayload($request->getQueryParams()))
|
$request = $request->withQueryParams($this->sanitizeDomainFromPayload($request->getQueryParams()))
|
||||||
->withParsedBody($this->sanitizeDomainFromPayload($body));
|
->withParsedBody($this->sanitizeDomainFromPayload($body));
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user