chore: add all in one mode
Some checks are pending
Docker Build and Publish / build (push) Waiting to run

This commit is contained in:
xboard 2025-01-10 11:04:12 +08:00
parent cf10a45d2d
commit 9cd3859def
12 changed files with 104 additions and 502 deletions

View File

@ -0,0 +1,64 @@
[supervisord]
nodaemon=true
user=root
logfile=/dev/stdout
logfile_maxbytes=0
pidfil=/www/storage/logs/supervisor/supervisord.pid
loglevel=info
[program:octane]
process_name=%(program_name)s_%(process_num)02d
command=php /www/artisan octane:start --host=0.0.0.0 --port=7001
autostart=%(ENV_ENABLE_WEB)s
autorestart=true
user=www
redirect_stderr=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stdout_logfile_backups=0
numprocs=1
stopwaitsecs=10
stopsignal=QUIT
stopasgroup=true
killasgroup=true
priority=100
[program:horizon]
process_name=%(program_name)s_%(process_num)02d
command=php /www/artisan horizon
autostart=%(ENV_ENABLE_HORIZON)s
autorestart=true
user=www
redirect_stderr=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stdout_logfile_backups=0
numprocs=1
stopwaitsecs=3
stopsignal=SIGINT
stopasgroup=true
killasgroup=true
priority=200
[program:redis]
process_name=%(program_name)s_%(process_num)02d
command=redis-server --dir /data
--dbfilename dump.rdb
--save 900 1
--save 300 10
--save 60 10000
--unixsocket /data/redis.sock
--unixsocketperm 777
autostart=%(ENV_ENABLE_REDIS)s
autorestart=true
user=redis
redirect_stderr=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stdout_logfile_backups=0
numprocs=1
stopwaitsecs=3
stopsignal=TERM
stopasgroup=true
killasgroup=true
priority=300

View File

@ -1,23 +1,25 @@
FROM phpswoole/swoole:php8.1-alpine
COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/
RUN install-php-extensions pcntl bcmath \
&& apk --no-cache add shadow sqlite mysql-client git patch \
&& addgroup -S -g 1000 www && adduser -S -G www -u 1000 www
#复制项目文件以及配置文件
&& apk --no-cache add shadow sqlite mysql-client git patch supervisor redis \
&& addgroup -S -g 1000 www && adduser -S -G www -u 1000 www \
&& (getent group redis || addgroup -S redis) \
&& (getent passwd redis || adduser -S -G redis -H -h /data redis)
WORKDIR /www
COPY .docker /
COPY . /www
COPY .docker/supervisor/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
RUN composer install --optimize-autoloader --no-cache --no-dev \
&& php artisan storage:link \
&& chown -R www:www /www \
&& chmod -R 775 /www
CMD php artisan octane:start \
--server="swoole" \
--host=0.0.0.0 \
--port=${OCTANE_PORT:-7001} \
--workers=${OCTANE_WORKERS:-auto} \
--task-workers=${OCTANE_TASK_WORKERS:-auto} \
--max-requests=${OCTANE_MAX_REQUESTS:-500}
&& chmod -R 775 /www \
&& mkdir -p /data \
&& chown redis:redis /data
ENV ENABLE_WEB=false \
ENABLE_HORIZON=false \
ENABLE_REDIS=false
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]

View File

@ -31,14 +31,13 @@ Xboard New是基于Xboard二次开发重写后台管理并优化系统架构
git clone -b compose-new --depth 1 https://github.com/cedar2025/Xboard && \
cd Xboard && \
docker compose run -it --rm \
-e enable_sqlite=true \
-e enable_redis=true \
-e admin_account=admin@demo.com \
-e ENABLE_SQLITE=true \
-e ENABLE_REDIS=true \
-e ADMIN_ACCOUNT=admin@demo.com \
web php artisan xboard:install && \
docker compose up -d
# 安装完成后访问 http://服务器IP:7001
```
安装完成后访问 http://服务器IP:7001
> 提示:安装过程中会显示管理员账号密码,请务必保存。

View File

@ -45,10 +45,10 @@ class XboardInstall extends Command
public function handle()
{
try {
$isDocker = env('docker', false);
$enableSqlite = env('enable_sqlite', false);
$enableRedis = env('enable_redis', false);
$adminAccount = env('admin_account', '');
$isDocker = file_exists('/.dockerenv');
$enableSqlite = env('ENABLE_SQLITE', false);
$enableRedis = env('ENABLE_REDIS', false);
$adminAccount = env('ADMIN_ACCOUNT', '');
$this->info("__ __ ____ _ ");
$this->info("\ \ / /| __ ) ___ __ _ _ __ __| | ");
$this->info(" \ \/ / | __ \ / _ \ / _` | '__/ _` | ");
@ -146,7 +146,7 @@ class XboardInstall extends Command
while (!$isReidsValid) {
// 判断是否为Docker环境
if ($isDocker == 'true' && ($enableRedis || confirm(label: '是否启用Docker内置的Redis', default: true, yes: '启用', no: '不启用'))) {
$envConfig['REDIS_HOST'] = '/run/redis-socket/redis.sock';
$envConfig['REDIS_HOST'] = '/data/redis.sock';
$envConfig['REDIS_PORT'] = 0;
$envConfig['REDIS_PASSWORD'] = null;
} else {
@ -171,6 +171,7 @@ class XboardInstall extends Command
// 连接失败,输出错误消息
$this->error("redis连接失败" . $e->getMessage());
$this->info("请重新输入REDIS配置");
sleep(1);
}
}

View File

@ -1,26 +0,0 @@
#!/usr/bin/env bash
WORK_DIR=$1
if [ ! -n "${WORK_DIR}" ] ;then
WORK_DIR="."
fi
echo "Restarting LaravelS..."
./bin/laravels restart -d -i
echo "Starting fswatch..."
LOCKING=0
fswatch -e ".*" -i "\\.php$" -r ${WORK_DIR} | while read file
do
if [[ ! ${file} =~ .php$ ]] ;then
continue
fi
if [ ${LOCKING} -eq 1 ] ;then
echo "Reloading, skipped."
continue
fi
echo "File ${file} has been modified."
LOCKING=1
./bin/laravels reload
LOCKING=0
done
exit 0

View File

@ -1,28 +0,0 @@
#!/usr/bin/env bash
WORK_DIR=$1
if [ ! -n "${WORK_DIR}" ] ;then
WORK_DIR="."
fi
echo "Restarting LaravelS..."
./bin/laravels restart -d -i
echo "Starting inotifywait..."
LOCKING=0
inotifywait --event modify --event create --event move --event delete -mrq ${WORK_DIR} | while read file
do
if [[ ! ${file} =~ .php$ ]] ;then
continue
fi
if [ ${LOCKING} -eq 1 ] ;then
echo "Reloading, skipped."
continue
fi
echo "File ${file} has been modified."
LOCKING=1
./bin/laravels reload
LOCKING=0
done
exit 0

View File

@ -1,168 +0,0 @@
#!/usr/bin/env php
<?php
/**
* This autoloader is only used to pull laravel-s.
* Class Psr4Autoloader
*/
class Psr4Autoloader
{
/**
* An associative array where the key is a namespace prefix and the value
* is an array of base directories for classes in that namespace.
*
* @var array
*/
protected $prefixes = [];
/**
* Register loader with SPL autoloader stack.
*
* @return void
*/
public function register()
{
spl_autoload_register([$this, 'loadClass']);
}
/**
* Adds a base directory for a namespace prefix.
*
* @param string $prefix The namespace prefix.
* @param string $base_dir A base directory for class files in the
* namespace.
* @param bool $prepend If true, prepend the base directory to the stack
* instead of appending it; this causes it to be searched first rather
* than last.
* @return void
*/
public function addNamespace($prefix, $base_dir, $prepend = false)
{
// normalize namespace prefix
$prefix = trim($prefix, '\\') . '\\';
// normalize the base directory with a trailing separator
$base_dir = rtrim($base_dir, DIRECTORY_SEPARATOR) . '/';
// initialize the namespace prefix array
if (isset($this->prefixes[$prefix]) === false) {
$this->prefixes[$prefix] = [];
}
// retain the base directory for the namespace prefix
if ($prepend) {
array_unshift($this->prefixes[$prefix], $base_dir);
} else {
$this->prefixes[$prefix][] = $base_dir;
}
}
/**
* Loads the class file for a given class name.
*
* @param string $class The fully-qualified class name.
* @return mixed The mapped file name on success, or boolean false on
* failure.
*/
public function loadClass($class)
{
// the current namespace prefix
$prefix = $class;
// work backwards through the namespace names of the fully-qualified
// class name to find a mapped file name
while (false !== $pos = strrpos($prefix, '\\')) {
// retain the trailing namespace separator in the prefix
$prefix = substr($class, 0, $pos + 1);
// the rest is the relative class name
$relative_class = substr($class, $pos + 1);
// try to load a mapped file for the prefix and relative class
$mapped_file = $this->loadMappedFile($prefix, $relative_class);
if ($mapped_file) {
return $mapped_file;
}
// remove the trailing namespace separator for the next iteration
// of strrpos()
$prefix = rtrim($prefix, '\\');
}
// never found a mapped file
return false;
}
/**
* Load the mapped file for a namespace prefix and relative class.
*
* @param string $prefix The namespace prefix.
* @param string $relative_class The relative class name.
* @return mixed Boolean false if no mapped file can be loaded, or the
* name of the mapped file that was loaded.
*/
protected function loadMappedFile($prefix, $relative_class)
{
// are there any base directories for this namespace prefix?
if (isset($this->prefixes[$prefix]) === false) {
return false;
}
// look through base directories for this namespace prefix
foreach ($this->prefixes[$prefix] as $base_dir) {
// replace the namespace prefix with the base directory,
// replace namespace separators with directory separators
// in the relative class name, append with .php
$file = $base_dir
. str_replace('\\', '/', $relative_class)
. '.php';
// if the mapped file exists, require it
if ($this->requireFile($file)) {
// yes, we're done
return $file;
}
}
// never found it
return false;
}
/**
* If a file exists, require it from the file system.
*
* @param string $file The file to require.
* @return bool True if the file exists, false if not.
*/
public function requireFile($file)
{
if (file_exists($file)) {
require $file;
return true;
}
return false;
}
}
$basePath = dirname(__DIR__) . '/';
$loader = new Psr4Autoloader();
$loader->register();
// Register laravel-s
$loader->addNamespace('Hhxsv5\LaravelS', $basePath . '/vendor/hhxsv5/laravel-s/src');
// Register laravel-s dependencies
// To fix issue #364 https://github.com/hhxsv5/laravel-s/issues/364
$loader->addNamespace('Symfony\Polyfill\Php80', $basePath . '/vendor/symfony/polyfill-php80');
$loader->requireFile($basePath . '/vendor/symfony/polyfill-php80/bootstrap.php');
$loader->addNamespace('Symfony\Component\Console', $basePath . '/vendor/symfony/console');
$loader->addNamespace('Symfony\Contracts\Service', $basePath . '/vendor/symfony/service-contracts');
$loader->addNamespace('Symfony\Contracts', $basePath . '/vendor/symfony/contracts');
$command = new Hhxsv5\LaravelS\Console\Portal($basePath);
$input = new Symfony\Component\Console\Input\ArgvInput();
$output = new Symfony\Component\Console\Output\ConsoleOutput();
$code = $command->run($input, $output);
exit($code);

View File

@ -2,19 +2,19 @@ services:
web:
image: ghcr.io/cedar2025/xboard:new
volumes:
- ./.docker/.data/redis/:/run/redis-socket
- ./.docker/.data/redis/:/data/
- ./:/www/
environment:
- docker=true
depends_on:
- redis
network_mode: host
command: php artisan octane:start --server="swoole" --port=7001 --host=0.0.0.0
command: php artisan octane:start --port=7001 --host=0.0.0.0
restart: on-failure
horizon:
image: ghcr.io/cedar2025/xboard:new
volumes:
- ./.docker/.data/redis/:/run/redis-socket
- ./.docker/.data/redis/:/data/
- ./:/www/
restart: on-failure
network_mode: host

View File

@ -36,7 +36,7 @@ return [
|
*/
'server' => env('OCTANE_SERVER', 'roadrunner'),
'server' => env('OCTANE_SERVER', 'swoole'),
/*
|--------------------------------------------------------------------------

View File

@ -1,137 +0,0 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| HTTP server configurations.
|--------------------------------------------------------------------------
|
| @see https://www.swoole.co.uk/docs/modules/swoole-server/configuration
|
*/
'server' => [
'host' => env('SWOOLE_HTTP_HOST', '0.0.0.0'),
'port' => env('SWOOLE_HTTP_PORT', '1215'),
'public_path' => base_path('public'),
// Determine if to use swoole to respond request for static files
'handle_static_files' => env('SWOOLE_HANDLE_STATIC', true),
'access_log' => env('SWOOLE_HTTP_ACCESS_LOG', false),
// You must add --enable-openssl while compiling Swoole
// Put `SWOOLE_SOCK_TCP | SWOOLE_SSL` if you want to enable SSL
'socket_type' => SWOOLE_SOCK_TCP,
'process_type' => SWOOLE_PROCESS,
'options' => [
'pid_file' => env('SWOOLE_HTTP_PID_FILE', base_path('storage/logs/swoole_http.pid')),
'log_file' => env('SWOOLE_HTTP_LOG_FILE', base_path('storage/logs/swoole_http.log')),
'daemonize' => env('SWOOLE_HTTP_DAEMONIZE', false),
// Normally this value should be 1~4 times larger according to your cpu cores.
'reactor_num' => env('SWOOLE_HTTP_REACTOR_NUM', swoole_cpu_num()),
'worker_num' => env('SWOOLE_HTTP_WORKER_NUM', swoole_cpu_num()),
'task_worker_num' => env('SWOOLE_HTTP_TASK_WORKER_NUM', swoole_cpu_num()),
// The data to receive can't be larger than buffer_output_size.
'package_max_length' => 20 * 1024 * 1024,
// The data to send can't be larger than buffer_output_size.
'buffer_output_size' => 10 * 1024 * 1024,
// Max buffer size for socket connections
'socket_buffer_size' => 128 * 1024 * 1024,
// Worker will restart after processing this number of requests
'max_request' => 3000,
// Enable coroutine send
'send_yield' => true,
// You must add --enable-openssl while compiling Swoole
'ssl_cert_file' => null,
'ssl_key_file' => null,
],
],
/*
|--------------------------------------------------------------------------
| Enable to turn on websocket server.
|--------------------------------------------------------------------------
*/
'websocket' => [
'enabled' => env('SWOOLE_HTTP_WEBSOCKET', false),
],
/*
|--------------------------------------------------------------------------
| Hot reload configuration
|--------------------------------------------------------------------------
*/
'hot_reload' => [
'enabled' => env('SWOOLE_HOT_RELOAD_ENABLE', false),
'recursively' => env('SWOOLE_HOT_RELOAD_RECURSIVELY', true),
'directory' => env('SWOOLE_HOT_RELOAD_DIRECTORY', base_path()),
'log' => env('SWOOLE_HOT_RELOAD_LOG', true),
'filter' => env('SWOOLE_HOT_RELOAD_FILTER', '.php'),
],
/*
|--------------------------------------------------------------------------
| Console output will be transferred to response content if enabled.
|--------------------------------------------------------------------------
*/
'ob_output' => env('SWOOLE_OB_OUTPUT', true),
/*
|--------------------------------------------------------------------------
| Pre-resolved instances here will be resolved when sandbox created.
|--------------------------------------------------------------------------
*/
'pre_resolved' => [
'view', 'files', 'session', 'session.store', 'routes',
'db', 'db.factory', 'cache', 'cache.store', 'config', 'cookie',
'encrypter', 'hash', 'router', 'translator', 'url', 'log',
],
/*
|--------------------------------------------------------------------------
| Instances here will be cleared on every request.
|--------------------------------------------------------------------------
*/
'instances' => [
'auth',
],
/*
|--------------------------------------------------------------------------
| Providers here will be registered on every request.
|--------------------------------------------------------------------------
*/
'providers' => [
Illuminate\Pagination\PaginationServiceProvider::class,
],
/*
|--------------------------------------------------------------------------
| Resetters for sandbox app.
|--------------------------------------------------------------------------
*/
'resetters' => [
SwooleTW\Http\Server\Resetters\ResetConfig::class,
SwooleTW\Http\Server\Resetters\ResetSession::class,
SwooleTW\Http\Server\Resetters\ResetCookie::class,
SwooleTW\Http\Server\Resetters\ClearInstances::class,
SwooleTW\Http\Server\Resetters\BindRequest::class,
SwooleTW\Http\Server\Resetters\RebindKernelContainer::class,
SwooleTW\Http\Server\Resetters\RebindRouterContainer::class,
SwooleTW\Http\Server\Resetters\RebindViewContainer::class,
SwooleTW\Http\Server\Resetters\ResetProviders::class,
],
/*
|--------------------------------------------------------------------------
| Define your swoole tables here.
|
| @see https://www.swoole.co.uk/docs/modules/swoole-table
|--------------------------------------------------------------------------
*/
'tables' => [
// 'table_name' => [
// 'size' => 1024,
// 'columns' => [
// ['name' => 'column_name', 'type' => Table::TYPE_STRING, 'size' => 1024],
// ]
// ],
],
];

View File

@ -1,107 +0,0 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Websocket handler for onOpen and onClose callback
| Replace this handler if you want to customize your websocket handler
|--------------------------------------------------------------------------
*/
'handler' => SwooleTW\Http\Websocket\SocketIO\WebsocketHandler::class,
/*
|--------------------------------------------------------------------------
| Default frame parser
| Replace it if you want to customize your websocket payload
|--------------------------------------------------------------------------
*/
'parser' => SwooleTW\Http\Websocket\SocketIO\SocketIOParser::class,
/*
|--------------------------------------------------------------------------
| Websocket route file path
|--------------------------------------------------------------------------
*/
'route_file' => base_path('routes/websocket.php'),
/*
|--------------------------------------------------------------------------
| Default middleware for on connect request
|--------------------------------------------------------------------------
*/
'middleware' => [
// SwooleTW\Http\Websocket\Middleware\DecryptCookies::class,
// SwooleTW\Http\Websocket\Middleware\StartSession::class,
// SwooleTW\Http\Websocket\Middleware\Authenticate::class,
],
/*
|--------------------------------------------------------------------------
| Websocket handler for customized onHandShake callback
|--------------------------------------------------------------------------
*/
'handshake' => [
'enabled' => false,
'handler' => SwooleTW\Http\Websocket\HandShakeHandler::class,
],
/*
|--------------------------------------------------------------------------
| Default websocket driver
|--------------------------------------------------------------------------
*/
'default' => 'table',
/*
|--------------------------------------------------------------------------
| Websocket client's heartbeat interval (ms)
|--------------------------------------------------------------------------
*/
'ping_interval' => 25000,
/*
|--------------------------------------------------------------------------
| Websocket client's heartbeat interval timeout (ms)
|--------------------------------------------------------------------------
*/
'ping_timeout' => 60000,
/*
|--------------------------------------------------------------------------
| Room drivers mapping
|--------------------------------------------------------------------------
*/
'drivers' => [
'table' => SwooleTW\Http\Websocket\Rooms\TableRoom::class,
'redis' => SwooleTW\Http\Websocket\Rooms\RedisRoom::class,
],
/*
|--------------------------------------------------------------------------
| Room drivers settings
|--------------------------------------------------------------------------
*/
'settings' => [
'table' => [
'room_rows' => 4096,
'room_size' => 2048,
'client_rows' => 8192,
'client_size' => 2048,
],
'redis' => [
'server' => [
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', 6379),
'database' => 0,
'persistent' => true,
],
'options' => [
//
],
'prefix' => 'swoole:',
],
],
];

View File

@ -21,16 +21,18 @@ git clone -b compose-new --depth 1 https://github.com/cedar2025/Xboard
cd Xboard
```
2. 安装数据库:
```bash
# 快速安装(推荐新手使用)
docker compose run -it --rm \
-e enable_sqlite=true \
-e enable_redis=true \
-e admin_account=admin@demo.com \
web php artisan xboard:install
2. 安装数据库:
# 自定义配置安装(高级用户)
- 快速安装(推荐新手使用)
```bash
docker compose run -it --rm \
-e ENABLE_SQLITE=true \
-e ENABLE_REDIS=true \
-e ADMIN_ACCOUNT=admin@demo.com \
web php artisan xboard:install && \
```
- 自定义配置安装(高级用户)
```bash
docker compose run -it --rm web php artisan xboard:install
```
> 安装完成后请保存返回的后台地址和管理员账号密码