This commit is contained in:
t0is 2025-04-25 08:42:43 +02:00
parent 74c479bc61
commit 93be8e2c76
283 changed files with 1156 additions and 10 deletions

2
.dockerignore Normal file
View File

@ -0,0 +1,2 @@
src/storage/logs/*
src/vendor

5
.gitignore vendored
View File

@ -1,6 +1,7 @@
/vendor/
node_modules/
/src/vendor/
/src/node_modules/
package-lock.json
composer.lock
.idea
/src/storage/debugbar
.vite

131
docker-compose.yml Normal file
View File

@ -0,0 +1,131 @@
networks:
laravel:
mariadb:
external: true
name: mariadb
volumes:
vendor_data:
services:
nginx:
image: nginx:alpine-slim
restart: always
ports:
- '8877:80'
container_name: shipping-nginx
volumes:
# Please update below path as per your environment.
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
depends_on:
- php
- laravel-redis
# - laravel-queue
# - laravel-cron
# - phpmyadmin
networks:
- laravel
- mariadb
php:
container_name: shipping-php
# user: "www-data"
# restart: always
platform: linux/amd64
user: www-data:1002
build:
# Please update below path as per your environment.
context: .
dockerfile: ./docker/php/Dockerfile
ports:
- '9001:9001'
volumes:
- ./src:/var/www/html
- vendor_data:/var/www/html/vendor
- ./src/.env:/var/www/html/.env
- ./docker/roadrunner.yaml:/var/www/html/.rr.yaml
networks:
- laravel
- mariadb
depends_on:
- laravel-redis
laravel-redis:
image: redis:alpine
container_name: laravel-redis
restart: unless-stopped
ports:
- 6380:6379
networks:
- laravel
- mariadb
npm:
image: node:alpine
# container_name: npm
volumes:
- ./src:/var/www/html
- ./src/.env:/var/www/html/.env
ports:
- 3000:3000
- 3001:3001
working_dir: /var/www/html
profiles: [ "npm" ]
entrypoint: [ 'npm' ]
networks:
- laravel
- mariadb
horizon:
# user: "www-data"
user: www-data:1002
container_name: shipping-horizon
platform: linux/arm64/v8
build:
context: .
dockerfile: ./docker/horizon.dockerfile
restart: unless-stopped
volumes:
- ./src:/var/www/html
- ./src/.env:/var/www/html/.env
- vendor_data:/var/www/html/vendor
- ./docker/supervisor/horizon.conf:/etc/supervisor/conf.d/horizon.conf
depends_on:
- laravel-redis
networks:
- laravel
- mariadb
#
#
# pdf_manager:
# container_name: shipping-pdf_manager
# build:
# context: .
# dockerfile: ./docker/python/Dockerfile
# ports:
# - "5001:5000"
# volumes:
# - ./src/scripts/pdf_manage.py:/app/pdf_manage.py
# - ./src/scripts/pdf_data:/app/pdfs
# networks:
# - laravel
# - mariadb
laravel-cron:
build:
context: .
dockerfile: ./docker/php.dockerfile
container_name: laravel-cron
volumes:
- ./src:/var/www/html
- ./src/.env:/var/www/html/.env
- vendor_data:/var/www/html/vendor
networks:
- laravel
- mariadb

View File

@ -0,0 +1,19 @@
FROM composer:latest as composer
# environment arguments
ARG UID
ARG GID
ARG USER
ENV UID=${UID}
ENV GID=${GID}
ENV USER=${USER}
# Dialout group in alpine linux conflicts with MacOS staff group's gid, whis is 20. So we remove it.
RUN delgroup dialout
# Creating user and group
RUN addgroup -g ${GID} --system ${USER}
RUN adduser -G ${USER} --system -D -s /bin/sh -u ${UID} ${USER}
WORKDIR /var/www/html

25
docker/horizon.dockerfile Normal file
View File

@ -0,0 +1,25 @@
FROM t0is/laravel-roadrunner-base:latest
RUN apt update -y && apt upgrade -y
RUN apt-get install -y supervisor
RUN docker-php-ext-enable redis
WORKDIR /var/www/html
COPY --chown=www-data src/. /var/www/html
COPY --chown=www-data src/.env /var/www/html/.env
COPY --chown=www-data docker/roadrunner.yaml /var/www/html/.rr.yaml
COPY --chown=www-data docker/supervisor/horizon.conf /etc/supervisor/conf.d/horizon.conf
USER www-data:1002
ENV COMPOSER_HOME=/tmp/composer
RUN composer install --optimize-autoloader --no-dev
RUN #chown -R www-data:www-data /var/www/html/vendor
RUN #php artisan optimize:clear && php artisan optimize
RUN php artisan octane:install --server=roadrunner
CMD ["supervisord", "-c", "/etc/supervisor/conf.d/horizon.conf"]

7
docker/init_db.sql Normal file
View File

@ -0,0 +1,7 @@
CREATE USER IF NOT EXISTS 'shipping'@'%' IDENTIFIED BY 'shipping';
CREATE DATABASE IF NOT EXISTS shipping CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
GRANT ALL ON shipping.* TO shipping@'%';
GRANT ALL ON pps.* TO shipping@'%';
GRANT ALL ON vat_warehouse.* TO shipping@'%';
GRANT SELECT,DELETE,DROP ON mysql.general_log TO shipping@'%';
flush privileges;

26
docker/nginx.dockerfile Normal file
View File

@ -0,0 +1,26 @@
FROM nginx:stable-alpine
# environment arguments
ARG UID
ARG GID
ARG USER
ENV UID=${UID}
ENV GID=${GID}
ENV USER=${USER}
# Dialout group in alpine linux conflicts with MacOS staff group's gid, whis is 20. So we remove it.
RUN delgroup dialout
# Creating user and group
RUN addgroup -g ${GID} --system ${USER}
RUN adduser -G ${USER} --system -D -s /bin/sh -u ${UID} ${USER}
# Modify nginx configuration to use the new user's priviledges for starting it.
RUN sed -i "s/user nginx/user '${USER}'/g" /etc/nginx/nginx.conf
# Copies nginx configurations to override the default.
ADD ./nginx/*.conf /etc/nginx/conf.d/
# Make html directory
RUN mkdir -p /var/www/html

129
docker/nginx/default.conf Normal file
View File

@ -0,0 +1,129 @@
# Nginx default.conf
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_min_length 256;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/vnd.ms-fontobject application/x-font-ttf font/opentype image/svg+xml image/x-icon;
server_tokens off;
client_body_buffer_size 200;
client_max_body_size 200m;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
upstream upstream_backend_php {
server shipping-php:9001;
}
server {
listen 80;
listen [::]:80;
server_name my_backend;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
index index.php index.html index.htm;
charset utf-8;
server_tokens off;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
# SEO trailing slash problem fix
# rewrite ^/(.*)/$ /$1 permanent; # remove trailing slash
# rewrite ^(.*[^/])$ $1/ permanent; # add a trailing slash
############################
# Reference: https://gist.github.com/Ellrion/4eb5df00173f0fb13a76
############################
location ~* \.(jpg|jpeg|png|gif|svg|webp|html|txt|json|ico|css|js)$ {
expires 1d;
add_header Cache-Control public;
access_log off;
try_files $uri $uri/ @octane;
}
location ~ /\.(?!well-known).* {
deny all;
}
# /etc/nginx/global/php-restrictions.conf
# Don't throw any errors for missing favicons and don't display them in the logs
location = /favicon.ico { log_not_found off; access_log off; try_files $uri $uri/ @octane;}
# Don't log missing robots or show them in the nginx logs
location = /robots.txt { allow all; log_not_found off; access_log off; try_files $uri $uri/ @octane;}
# Deny all attempts to access hidden files such as .htaccess, .htpasswd, .DS_Store (Mac).
# Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
location ~ /\. {
deny all;
}
# Deny access to any files with a .php extension in the uploads directory
# Works in sub-directory installs and also in multisite network
# Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
location ~* /(?:uploads|files)/.*\.php$ {
deny all;
}
############################
# Customize
############################
location /index.php {
try_files /not_exists @octane;
}
location / {
if ($request_method !~ ^(GET|POST|HEAD|OPTIONS|PUT|DELETE)$) {
return 405;
}
try_files $uri $uri/ @octane;
}
location @octane {
set $suffix "";
if ($uri = /index.php) {
set $suffix ?$query_string;
}
proxy_http_version 1.1;
proxy_set_header Http_Host $http_host;
proxy_set_header Host $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_set_header X-CSRF-TOKEN $http_x_csrf_token;
proxy_set_header X-Real-IP $remote_addr;
# Add timeout settings
proxy_read_timeout 300s; # Increase read timeout
proxy_send_timeout 300s; # Increase send timeout
proxy_connect_timeout 300s; # Increase connect timeout
send_timeout 300s; # Increase overall send timeout
proxy_pass http://upstream_backend_php$suffix;
}
}

19
docker/php.dockerfile Normal file
View File

@ -0,0 +1,19 @@
FROM t0is/laravel-roadrunner-base:latest-amd64
RUN apt update -y && apt upgrade -y
WORKDIR /var/www/html
RUN docker-php-ext-enable redis
COPY --chown=www-data src/. /var/www/html
COPY --chown=www-data src/.env /var/www/html/.env
USER www-data:1002
ENV COMPOSER_HOME=/tmp/composer
RUN composer install --optimize-autoloader --no-dev
RUN #chown -R www-data:www-data /var/www/html/vendor
CMD ["php", "artisan", "schedule:work"]

28
docker/php/Dockerfile Normal file
View File

@ -0,0 +1,28 @@
FROM t0is/laravel-roadrunner-base:latest
RUN apt update -y && apt upgrade -y
WORKDIR /var/www/html
RUN docker-php-ext-enable redis
RUN python3 -m venv /var/www/html/shipping_env
# Activate the virtual environment and install pymupdf
RUN /var/www/html/shipping_env/bin/pip install --upgrade pip && \
/var/www/html/shipping_env/bin/pip install pymupdf
COPY --chown=www-data src/. /var/www/html
COPY --chown=www-data src/.env /var/www/html/.env
COPY --chown=www-data docker/roadrunner.yaml /var/www/html/.rr.yaml
USER www-data:1002
ENV COMPOSER_HOME=/tmp/composer
RUN composer install --optimize-autoloader --no-dev
RUN #chown -R www-data:www-data /var/www/html/vendor
RUN php artisan octane:install --server=roadrunner
EXPOSE 9001
CMD ["php", "artisan", "octane:start", "--server=roadrunner", "--host=0.0.0.0", "--port=9001", "--log-level=debug", "--rr-config=/var/www/html/.rr.yaml"]

View File

@ -0,0 +1,62 @@
FROM php:8.3-cli
RUN apt update -y && apt upgrade -y
RUN apt install -y --no-install-recommends \
libfreetype-dev \
libjpeg62-turbo-dev \
libpng-dev \
imagemagick \
libmagickwand-dev \
git \
zip unzip \
openssl libssl-dev libcurl4-openssl-dev \
autoconf zlib1g-dev \
python3 python3-venv python3-pip ghostscript\
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install -j$(nproc) gd
RUN pecl install redis
RUN docker-php-ext-install opcache
RUN docker-php-ext-install pdo pdo_mysql
RUN docker-php-ext-install mysqli
RUN docker-php-ext-install sockets
RUN docker-php-ext-install soap
RUN docker-php-ext-install intl
# https://github.com/viest/php-ext-xlswriter
RUN pecl install xlswriter
# https://dev.to/kakisoft/php-docker-how-to-enable-pcntlprocess-control-extensions-1afk
RUN docker-php-ext-configure pcntl --enable-pcntl && docker-php-ext-install pcntl
RUN pecl install apcu
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
RUN rm -rf /var/cache/apt/lists
# Please refer to the README.md for updating these 2 files.
#COPY src/composer.json /tmp
#RUN cd /tmp && composer install && composer update --optimize-autoloader
#RUN mv /tmp/vendor /var/www/html
#RUN cp /tmp/composer.* /var/www/html
#RUN composer clear-cache
RUN curl -L https://github.com/roadrunner-server/roadrunner/releases/download/v2024.3.0/roadrunner-2024.3.0-linux-amd64.tar.gz -o /tmp/roadrunner.tar.gz \
&& tar -xvzf /tmp/roadrunner.tar.gz -C /tmp \
&& mv /tmp/roadrunner-2024.3.0-linux-amd64/rr /var/www/html/rr \
&& chmod +x /var/www/html/rr \
&& rm -rf /tmp/roadrunner.tar.gz /tmp/roadrunner-2024.3.0-linux-amd64
# Set PHP configurations for memory, execution time, and file upload sizes
RUN echo "memory_limit = 1024M" > /usr/local/etc/php/conf.d/custom-php-memlimit.ini; \
echo "max_execution_time = 500" > /usr/local/etc/php/conf.d/custom-php-time.ini; \
echo "post_max_size = 100M" > /usr/local/etc/php/conf.d/custom-php-size.ini;
# Modify user and group ID for www-data
RUN groupmod -g 1001 www-data && usermod -u 1001 -g 1001 www-data

90
docker/policy.xml Normal file
View File

@ -0,0 +1,90 @@
<!--
Configure ImageMagick policies.
Domains include system, delegate, coder, filter, path, or resource.
Rights include none, read, write, execute and all. Use | to combine them,
for example: "read | write" to permit read from, or write to, a path.
Use a glob expression as a pattern.
Suppose we do not want users to process MPEG video images:
<policy domain="delegate" rights="none" pattern="mpeg:decode" />
Here we do not want users reading images from HTTP:
<policy domain="coder" rights="none" pattern="HTTP" />
The /repository file system is restricted to read only. We use a glob
expression to match all paths that start with /repository:
<policy domain="path" rights="read" pattern="/repository/*" />
Lets prevent users from executing any image filters:
<policy domain="filter" rights="none" pattern="*" />
Any large image is cached to disk rather than memory:
<policy domain="resource" name="area" value="1GP"/>
Use the default system font unless overwridden by the application:
<policy domain="system" name="font" value="/usr/share/fonts/favorite.ttf"/>
Define arguments for the memory, map, area, width, height and disk resources
with SI prefixes (.e.g 100MB). In addition, resource policies are maximums
for each instance of ImageMagick (e.g. policy memory limit 1GB, -limit 2GB
exceeds policy maximum so memory limit is 1GB).
Rules are processed in order. Here we want to restrict ImageMagick to only
read or write a small subset of proven web-safe image types:
<policy domain="delegate" rights="none" pattern="*" />
<policy domain="filter" rights="none" pattern="*" />
<policy domain="coder" rights="none" pattern="*" />
<policy domain="coder" rights="read|write" pattern="{GIF,JPEG,PNG,WEBP}" />
-->
<policymap>
<!-- <policy domain="resource" name="temporary-path" value="/tmp"/> -->
<policy domain="resource" name="memory" value="256MiB"/>
<policy domain="resource" name="map" value="512MiB"/>
<policy domain="resource" name="width" value="16KP"/>
<policy domain="resource" name="height" value="16KP"/>
<!-- <policy domain="resource" name="list-length" value="128"/> -->
<policy domain="resource" name="area" value="128MP"/>
<policy domain="resource" name="disk" value="1GiB"/>
<!-- <policy domain="resource" name="file" value="768"/> -->
<!-- <policy domain="resource" name="thread" value="4"/> -->
<!-- <policy domain="resource" name="throttle" value="0"/> -->
<!-- <policy domain="resource" name="time" value="3600"/> -->
<!-- <policy domain="coder" rights="none" pattern="MVG" /> -->
<!-- <policy domain="module" rights="none" pattern="{PS,PDF,XPS}" /> -->
<!-- <policy domain="path" rights="none" pattern="@*" /> -->
<!-- <policy domain="cache" name="memory-map" value="anonymous"/> -->
<!-- <policy domain="cache" name="synchronize" value="True"/> -->
<!-- <policy domain="cache" name="shared-secret" value="passphrase" stealth="true"/>
<!-- <policy domain="system" name="max-memory-request" value="256MiB"/> -->
<!-- <policy domain="system" name="shred" value="2"/> -->
<!-- <policy domain="system" name="precision" value="6"/> -->
<!-- <policy domain="system" name="font" value="/path/to/font.ttf"/> -->
<!-- <policy domain="system" name="pixel-cache-memory" value="anonymous"/> -->
<!-- <policy domain="system" name="shred" value="2"/> -->
<!-- <policy domain="system" name="precision" value="6"/> -->
<!-- not needed due to the need to use explicitly by mvg: -->
<!-- <policy domain="delegate" rights="none" pattern="MVG" /> -->
<!-- use curl -->
<policy domain="delegate" rights="none" pattern="URL" />
<policy domain="delegate" rights="none" pattern="HTTPS" />
<policy domain="delegate" rights="none" pattern="HTTP" />
<!-- in order to avoid to get image with password text -->
<policy domain="path" rights="none" pattern="@*"/>
<!-- disable ghostscript format types -->
<policy domain="coder" rights="none" pattern="PS" />
<policy domain="coder" rights="none" pattern="PS2" />
<policy domain="coder" rights="none" pattern="PS3" />
<policy domain="coder" rights="none" pattern="EPS" />
<policy domain="coder" rights="read|write" pattern="PDF" />
<policy domain="coder" rights="none" pattern="XPS" />
</policymap>

28
docker/python/Dockerfile Normal file
View File

@ -0,0 +1,28 @@
FROM python:3.11-slim
ENV PYTHONUNBUFFERED=1
# Set working directory
WORKDIR /app
# Install system dependencies for WeasyPrint
RUN apt-get update && apt-get install -y \
python3-pip \
libpango-1.0-0 \
libharfbuzz0b \
libpangoft2-1.0-0 \
libharfbuzz-subset0 \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Install Python dependencies
RUN pip install --no-cache-dir Flask PyMuPDF weasyprint
# Copy application files
COPY ./src/scripts/pdf_manage.py /app/pdf_manage.py
# Expose the Flask port
EXPOSE 5000
# Run Flask server
CMD ["python", "pdf_manage.py"]

54
docker/roadrunner.yaml Normal file
View File

@ -0,0 +1,54 @@
version: '3'
rpc:
# RPC interface for internal communication
listen: tcp://127.0.0.1:6001
server:
# Command to start Laravel Octane server
command: "php artisan octane:start --server=roadrunner --host=0.0.0.0 --port=9001"
http:
# HTTP server configuration
address: 0.0.0.0:9001
pool:
# Worker pool configuration
num_workers: 8
max_jobs: 1000
allocate_timeout: 60s
destroy_timeout: 60s
static:
# Serve static files
dir: ./public
forbid: [ ".php", ".env", ".htaccess" ]
jobs:
num_pollers: 64
timeout: 60
pipeline_size: 100000
driver: redis
redis:
addr: laravel-redis:6379 # Redis host and port
stream: [ "fetch_tracking", "callback_retry", "default", "storage_management" ]
timeout: 10s # Fetch timeout
prefetch: 10
pool:
num_workers: 10
allocate_timeout: 60s
destroy_timeout: 60s
logs:
# Logging configuration
level: debug
mode: development
metrics:
# Metrics for monitoring
address: 0.0.0.0:2112
health:
# Health check endpoint
address: 0.0.0.0:2113

View File

@ -0,0 +1,15 @@
[supervisord]
nodaemon=true
[program:horizon]
process_name=%(program_name)s
command=php /var/www/html/artisan horizon
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
user=www-data
redirect_stderr=true
stdout_logfile=/var/www/html/storage/logs/horizon.log
stopwaitsecs=3600

16
docker/xdebug.ini Normal file
View File

@ -0,0 +1,16 @@
zend_extension=xdebug.so
xdebug.remote_enable=1
xdebug.mode=debug
xdebug.start_with_request=yes
xdebug.idekey=shipping
xdebug.client_host=host.docker.internal
xdebug.client_port=9003
xdebug.remote_autostart=1
;xdebug.remote_connect_back=1
xdebug.remote_handler = dbgp
xdebug.remote_mode = req
xdebug.log = /var/www/html/xdebug.log
xdebug.log_level = 10

View File

@ -12,6 +12,7 @@ DB_DATABASE=transcriptor
DB_USERNAME=t0is
DB_PASSWORD=Silenceisgolden555
APP_KEY=base64:ZbNIu92nsvQmghttxsgjENh6Aqk4xR+o6LU7Wt9mpy8=

View File

@ -23,15 +23,29 @@ class StatsController extends Controller
->selectRaw('AVG(TIMESTAMPDIFF(SECOND, transcription_start, transcription_finish)) as avg_duration')
->value('avg_duration');
// 2. Average VOD processing time (last 30 days, downloaded & processed = true)
$vodProcessingAverage = Video::where('data_downloaded', true)
->where('processed', true)
// 2. Average VOD processing time
$vodProcessingAverage = Video::join('transcriptions as t', 'videos.id', '=', 't.video_id')
->where('videos.processed', true)
->whereNotNull('t.transcription_finish')
->where('videos.created_at', '>=', $thirtyDaysAgo)
->selectRaw(
'AVG(TIMESTAMPDIFF(
SECOND,
videos.created_at,
t.transcription_finish
)) as avg_seconds'
)
->value('avg_seconds');
$vodDownloadAverage = Video::where('data_downloaded', true)
->whereNotNull('download_start')
->whereNotNull('download_end')
->where('created_at', '>=', $thirtyDaysAgo)
->whereNotNull('created_at')
->whereNotNull('updated_at')
->whereRaw('updated_at > "2025-03-31 23:59:59"')
->selectRaw('AVG(TIMESTAMPDIFF(SECOND, created_at, updated_at)) as avg_processing')
->value('avg_processing');
->selectRaw('AVG(TIMESTAMPDIFF(SECOND, download_start, download_end)) as avg_download')
->value('avg_download');
$averageExternalDate = DB::table('videos')
->where('data_downloaded', false)
@ -64,7 +78,9 @@ class StatsController extends Controller
// Return all the stats
return response()->json([
'transcription_duration_average' => round($transcriptionDurationAverage, 2),
'vod_processing_average' => round($vodDelayNow, 2),
'vod_delay_now' => round($vodDelayNow, 2),
'vod_download_average' => round($vodDownloadAverage, 2),
'vod_processing_average' => round($vodProcessingAverage, 2),
'clip_average_per_day' => round($averageClipsPerDay, 0),
'video_downloaded_true' => $videoDownloadStats->downloaded_true,
'video_downloaded_false' => $videoDownloadStats->downloaded_false,

Some files were not shown because too many files have changed in this diff Show More