mirror of
https://github.com/cedar2025/Xboard.git
synced 2025-01-22 10:38:14 -05:00
Merge branch 'cedar2025:dev' into dev
This commit is contained in:
commit
e482b72430
@ -1,3 +1,7 @@
|
|||||||
unixsocket /run/redis-socket/redis.sock
|
unixsocket /run/redis-socket/redis.sock
|
||||||
unixsocketperm 777
|
unixsocketperm 777
|
||||||
port 0
|
port 0
|
||||||
|
|
||||||
|
save 900 1
|
||||||
|
save 300 10
|
||||||
|
save 60 10000
|
||||||
|
3
.github/workflows/docker-publish.yml
vendored
3
.github/workflows/docker-publish.yml
vendored
@ -10,6 +10,7 @@ on:
|
|||||||
branches: [ "dev" ]
|
branches: [ "dev" ]
|
||||||
# Publish semver tags as releases.
|
# Publish semver tags as releases.
|
||||||
tags: [ 'v*.*.*' ]
|
tags: [ 'v*.*.*' ]
|
||||||
|
workflow_dispatch: # Enable manual trigger
|
||||||
|
|
||||||
env:
|
env:
|
||||||
# Use docker.io for Docker Hub if empty
|
# Use docker.io for Docker Hub if empty
|
||||||
@ -60,7 +61,7 @@ jobs:
|
|||||||
uses: docker/metadata-action@v5.5.1
|
uses: docker/metadata-action@v5.5.1
|
||||||
with:
|
with:
|
||||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||||
|
|
||||||
- name: Get version
|
- name: Get version
|
||||||
id: get_version
|
id: get_version
|
||||||
run: echo "version=$(git describe --tags --always)" >> $GITHUB_OUTPUT
|
run: echo "version=$(git describe --tags --always)" >> $GITHUB_OUTPUT
|
||||||
|
@ -46,6 +46,9 @@ class XboardInstall extends Command
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$isDocker = env('docker', false);
|
$isDocker = env('docker', false);
|
||||||
|
$enableSqlite = env('enable_sqlite', false);
|
||||||
|
$enableRedis = env('enable_redis', false);
|
||||||
|
$adminAccount = env('admin_account', '');
|
||||||
$this->info("__ __ ____ _ ");
|
$this->info("__ __ ____ _ ");
|
||||||
$this->info("\ \ / /| __ ) ___ __ _ _ __ __| | ");
|
$this->info("\ \ / /| __ ) ___ __ _ _ __ __| | ");
|
||||||
$this->info(" \ \/ / | __ \ / _ \ / _` | '__/ _` | ");
|
$this->info(" \ \/ / | __ \ / _ \ / _` | '__/ _` | ");
|
||||||
@ -67,7 +70,7 @@ class XboardInstall extends Command
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 选择是否使用Sqlite
|
// 选择是否使用Sqlite
|
||||||
if (confirm(label: '是否启用Sqlite(无需额外安装)代替Mysql', default: false, yes: '启用', no: '不启用')) {
|
if ($enableSqlite || confirm(label: '是否启用Sqlite(无需额外安装)代替Mysql', default: false, yes: '启用', no: '不启用')) {
|
||||||
$sqliteFile = '.docker/.data/database.sqlite';
|
$sqliteFile = '.docker/.data/database.sqlite';
|
||||||
if (!file_exists(base_path($sqliteFile))) {
|
if (!file_exists(base_path($sqliteFile))) {
|
||||||
// 创建空文件
|
// 创建空文件
|
||||||
@ -142,7 +145,7 @@ class XboardInstall extends Command
|
|||||||
$isReidsValid = false;
|
$isReidsValid = false;
|
||||||
while (!$isReidsValid) {
|
while (!$isReidsValid) {
|
||||||
// 判断是否为Docker环境
|
// 判断是否为Docker环境
|
||||||
if ($isDocker == 'true' && (confirm(label: '是否启用Docker内置的Redis', default: true, yes: '启用', no: '不启用'))) {
|
if ($isDocker == 'true' && ($enableRedis || confirm(label: '是否启用Docker内置的Redis', default: true, yes: '启用', no: '不启用'))) {
|
||||||
$envConfig['REDIS_HOST'] = '/run/redis-socket/redis.sock';
|
$envConfig['REDIS_HOST'] = '/run/redis-socket/redis.sock';
|
||||||
$envConfig['REDIS_PORT'] = 0;
|
$envConfig['REDIS_PORT'] = 0;
|
||||||
$envConfig['REDIS_PASSWORD'] = null;
|
$envConfig['REDIS_PASSWORD'] = null;
|
||||||
@ -175,7 +178,7 @@ class XboardInstall extends Command
|
|||||||
abort(500, '复制环境文件失败,请检查目录权限');
|
abort(500, '复制环境文件失败,请检查目录权限');
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
$email = text(
|
$email = !empty($adminAccount) ? $adminAccount : text(
|
||||||
label: '请输入管理员账号',
|
label: '请输入管理员账号',
|
||||||
default: 'admin@demo.com',
|
default: 'admin@demo.com',
|
||||||
required: true,
|
required: true,
|
||||||
|
@ -73,7 +73,7 @@ class UserController extends Controller
|
|||||||
$res[$i]['plan_name'] = $plan[$k]['name'];
|
$res[$i]['plan_name'] = $plan[$k]['name'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$res[$i]['subscribe_url'] = Helper::getSubscribeUrl('/api/v1/client/subscribe?token=' . $res[$i]['token']);
|
$res[$i]['subscribe_url'] = Helper::getSubscribeUrl( $res[$i]['token']);
|
||||||
}
|
}
|
||||||
return response([
|
return response([
|
||||||
'data' => $res,
|
'data' => $res,
|
||||||
@ -162,7 +162,7 @@ class UserController extends Controller
|
|||||||
$transferEnable = $user['transfer_enable'] ? $user['transfer_enable'] / 1073741824 : 0;
|
$transferEnable = $user['transfer_enable'] ? $user['transfer_enable'] / 1073741824 : 0;
|
||||||
$notUseFlow = (($user['transfer_enable'] - ($user['u'] + $user['d'])) / 1073741824) ?? 0;
|
$notUseFlow = (($user['transfer_enable'] - ($user['u'] + $user['d'])) / 1073741824) ?? 0;
|
||||||
$planName = $user['plan_name'] ?? '无订阅';
|
$planName = $user['plan_name'] ?? '无订阅';
|
||||||
$subscribeUrl = Helper::getSubscribeUrl('/api/v1/client/subscribe?token=' . $user['token']);
|
$subscribeUrl = Helper::getSubscribeUrl($user['token']);
|
||||||
$data .= "{$user['email']},{$balance},{$commissionBalance},{$transferEnable},{$notUseFlow},{$expireDate},{$planName},{$subscribeUrl}\r\n";
|
$data .= "{$user['email']},{$balance},{$commissionBalance},{$transferEnable},{$notUseFlow},{$expireDate},{$planName},{$subscribeUrl}\r\n";
|
||||||
}
|
}
|
||||||
echo "\xEF\xBB\xBF" . $data;
|
echo "\xEF\xBB\xBF" . $data;
|
||||||
@ -240,7 +240,7 @@ class UserController extends Controller
|
|||||||
$expireDate = $user['expired_at'] === NULL ? '长期有效' : date('Y-m-d H:i:s', $user['expired_at']);
|
$expireDate = $user['expired_at'] === NULL ? '长期有效' : date('Y-m-d H:i:s', $user['expired_at']);
|
||||||
$createDate = date('Y-m-d H:i:s', $user['created_at']);
|
$createDate = date('Y-m-d H:i:s', $user['created_at']);
|
||||||
$password = $request->input('password') ?? $user['email'];
|
$password = $request->input('password') ?? $user['email'];
|
||||||
$subscribeUrl = Helper::getSubscribeUrl('/api/v1/client/subscribe?token=' . $user['token']);
|
$subscribeUrl = Helper::getSubscribeUrl($user['token']);
|
||||||
$data .= "{$user['email']},{$password},{$expireDate},{$user['uuid']},{$createDate},{$subscribeUrl}\r\n";
|
$data .= "{$user['email']},{$password},{$expireDate},{$user['uuid']},{$createDate},{$subscribeUrl}\r\n";
|
||||||
}
|
}
|
||||||
echo $data;
|
echo $data;
|
||||||
|
@ -24,6 +24,7 @@ class ClientController extends Controller
|
|||||||
'ClashX Meta' => '1.3.5',
|
'ClashX Meta' => '1.3.5',
|
||||||
'Hiddify' => '0.1.0',
|
'Hiddify' => '0.1.0',
|
||||||
'loon' => '637',
|
'loon' => '637',
|
||||||
|
'v2rayng' => '1.9.5',
|
||||||
'v2rayN' => '6.31',
|
'v2rayN' => '6.31',
|
||||||
'surge' => '2398'
|
'surge' => '2398'
|
||||||
];
|
];
|
||||||
|
@ -25,7 +25,7 @@ class KnowledgeController extends Controller
|
|||||||
if (!$userService->isAvailable($user)) {
|
if (!$userService->isAvailable($user)) {
|
||||||
$this->formatAccessData($knowledge['body']);
|
$this->formatAccessData($knowledge['body']);
|
||||||
}
|
}
|
||||||
$subscribeUrl = Helper::getSubscribeUrl("/api/v1/client/subscribe?token={$user['token']}");
|
$subscribeUrl = Helper::getSubscribeUrl($user['token']);
|
||||||
$knowledge['body'] = str_replace('{{siteName}}', admin_setting('app_name', 'XBoard'), $knowledge['body']);
|
$knowledge['body'] = str_replace('{{siteName}}', admin_setting('app_name', 'XBoard'), $knowledge['body']);
|
||||||
$knowledge['body'] = str_replace('{{subscribeUrl}}', $subscribeUrl, $knowledge['body']);
|
$knowledge['body'] = str_replace('{{subscribeUrl}}', $subscribeUrl, $knowledge['body']);
|
||||||
$knowledge['body'] = str_replace('{{urlEncodeSubscribeUrl}}', urlencode($subscribeUrl), $knowledge['body']);
|
$knowledge['body'] = str_replace('{{urlEncodeSubscribeUrl}}', urlencode($subscribeUrl), $knowledge['body']);
|
||||||
|
@ -140,7 +140,7 @@ class UserController extends Controller
|
|||||||
return $this->fail([400, __('Subscription plan does not exist')]);
|
return $this->fail([400, __('Subscription plan does not exist')]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$user['subscribe_url'] = Helper::getSubscribeUrl("/api/v1/client/subscribe?token={$user['token']}");
|
$user['subscribe_url'] = Helper::getSubscribeUrl($user['token']);
|
||||||
$userService = new UserService();
|
$userService = new UserService();
|
||||||
$user['reset_day'] = $userService->getResetDay($user);
|
$user['reset_day'] = $userService->getResetDay($user);
|
||||||
return $this->success($user);
|
return $this->success($user);
|
||||||
@ -157,7 +157,7 @@ class UserController extends Controller
|
|||||||
if (!$user->save()) {
|
if (!$user->save()) {
|
||||||
return $this->fail([400, __('Reset failed')]);
|
return $this->fail([400, __('Reset failed')]);
|
||||||
}
|
}
|
||||||
return $this->success(Helper::getSubscribeUrl('/api/v1/client/subscribe?token=' . $user->token));
|
return $this->success(Helper::getSubscribeUrl($user->token));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update(UserUpdate $request)
|
public function update(UserUpdate $request)
|
||||||
|
@ -12,7 +12,7 @@ class ClientRoute
|
|||||||
'middleware' => 'client'
|
'middleware' => 'client'
|
||||||
], function ($router) {
|
], function ($router) {
|
||||||
// Client
|
// Client
|
||||||
$router->get('/subscribe', 'V1\\Client\\ClientController@subscribe');
|
$router->get('/subscribe', 'V1\\Client\\ClientController@subscribe')->name('client.subscribe');
|
||||||
// App
|
// App
|
||||||
$router->get('/app/getConfig', 'V1\\Client\\AppController@getConfig');
|
$router->get('/app/getConfig', 'V1\\Client\\AppController@getConfig');
|
||||||
$router->get('/app/getVersion', 'V1\\Client\\AppController@getVersion');
|
$router->get('/app/getVersion', 'V1\\Client\\AppController@getVersion');
|
||||||
|
@ -27,7 +27,12 @@ class EPay
|
|||||||
'label' => 'KEY',
|
'label' => 'KEY',
|
||||||
'description' => '',
|
'description' => '',
|
||||||
'type' => 'input',
|
'type' => 'input',
|
||||||
]
|
],
|
||||||
|
'type' => [
|
||||||
|
'label' => 'TYPE',
|
||||||
|
'description' => 'alipay / qqpay / wxpay',
|
||||||
|
'type' => 'input',
|
||||||
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,6 +46,9 @@ class EPay
|
|||||||
'out_trade_no' => $order['trade_no'],
|
'out_trade_no' => $order['trade_no'],
|
||||||
'pid' => $this->config['pid']
|
'pid' => $this->config['pid']
|
||||||
];
|
];
|
||||||
|
if(optional($this->config)['type']){
|
||||||
|
$params['type'] = $this->config['type'];
|
||||||
|
}
|
||||||
ksort($params);
|
ksort($params);
|
||||||
reset($params);
|
reset($params);
|
||||||
$str = stripslashes(urldecode(http_build_query($params))) . $this->config['key'];
|
$str = stripslashes(urldecode(http_build_query($params))) . $this->config['key'];
|
||||||
|
@ -36,6 +36,9 @@ class General
|
|||||||
if ($item['type'] === 'trojan') {
|
if ($item['type'] === 'trojan') {
|
||||||
$uri .= self::buildTrojan($user['uuid'], $item);
|
$uri .= self::buildTrojan($user['uuid'], $item);
|
||||||
}
|
}
|
||||||
|
if ($item['type'] === 'hysteria') {
|
||||||
|
$uri .= self::buildHysteria($user['uuid'], $item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return base64_encode($uri);
|
return base64_encode($uri);
|
||||||
}
|
}
|
||||||
@ -170,4 +173,33 @@ class General
|
|||||||
return $uri;
|
return $uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function buildHysteria($password, $server)
|
||||||
|
{
|
||||||
|
$params = [];
|
||||||
|
// Return empty if version is not 2
|
||||||
|
if ($server['version'] !== 2) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($server['server_name']) {
|
||||||
|
$params['sni'] = $server['server_name'];
|
||||||
|
$params['security'] = 'tls';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($server['is_obfs']) {
|
||||||
|
$params['obfs'] = 'salamander';
|
||||||
|
$params['obfs-password'] = $server['server_key'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$params['insecure'] = $server['insecure'] ? 1 : 0;
|
||||||
|
|
||||||
|
$query = http_build_query($params);
|
||||||
|
$name = rawurlencode($server['name']);
|
||||||
|
|
||||||
|
$uri = "hysteria2://{$password}@{$server['host']}:{$server['port']}?{$query}#{$name}";
|
||||||
|
$uri .= "\r\n";
|
||||||
|
|
||||||
|
return $uri;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,9 @@ class Passwall
|
|||||||
if ($item['type'] === 'trojan') {
|
if ($item['type'] === 'trojan') {
|
||||||
$uri .= self::buildTrojan($user['uuid'], $item);
|
$uri .= self::buildTrojan($user['uuid'], $item);
|
||||||
}
|
}
|
||||||
|
if ($item['type'] === 'hysteria') {
|
||||||
|
$uri .= General::buildHysteria($user['uuid'], $item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return base64_encode($uri);
|
return base64_encode($uri);
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,9 @@ class SSRPlus
|
|||||||
if ($item['type'] === 'trojan') {
|
if ($item['type'] === 'trojan') {
|
||||||
$uri .= self::buildTrojan($user['uuid'], $item);
|
$uri .= self::buildTrojan($user['uuid'], $item);
|
||||||
}
|
}
|
||||||
|
if ($item['type'] === 'hysteria') {
|
||||||
|
$uri .= General::buildHysteria($user['uuid'], $item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return base64_encode($uri);
|
return base64_encode($uri);
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ class SingBox
|
|||||||
|
|
||||||
return response()
|
return response()
|
||||||
->json($this->config)
|
->json($this->config)
|
||||||
|
->header('profile-title', 'base64:'. base64_encode($appName))
|
||||||
->header('subscription-userinfo', "upload={$user['u']}; download={$user['d']}; total={$user['transfer_enable']}; expire={$user['expired_at']}")
|
->header('subscription-userinfo', "upload={$user['u']}; download={$user['d']}; total={$user['transfer_enable']}; expire={$user['expired_at']}")
|
||||||
->header('profile-update-interval', '24');
|
->header('profile-update-interval', '24');
|
||||||
}
|
}
|
||||||
@ -318,4 +319,4 @@ class SingBox
|
|||||||
|
|
||||||
return $array;
|
return $array;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ class Surfboard
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Subscription link
|
// Subscription link
|
||||||
$subsURL = Helper::getSubscribeUrl("/api/v1/client/subscribe?token={$user['token']}");
|
$subsURL = Helper::getSubscribeUrl($user['token']);
|
||||||
$subsDomain = request()->header('Host');
|
$subsDomain = request()->header('Host');
|
||||||
|
|
||||||
$config = str_replace('$subs_link', $subsURL, $config);
|
$config = str_replace('$subs_link', $subsURL, $config);
|
||||||
|
@ -71,9 +71,8 @@ class Surge
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Subscription link
|
// Subscription link
|
||||||
$subsURL = Helper::getSubscribeUrl("/api/v1/client/subscribe?token={$user['token']}");
|
|
||||||
$subsDomain = request()->header('Host');
|
$subsDomain = request()->header('Host');
|
||||||
$subsURL = 'https://' . $subsDomain . '/api/v1/client/subscribe?token=' . $user['token'];
|
$subsURL = Helper::getSubscribeUrl($user['token'], $subsDomain ? 'https://' . $subsDomain : null);
|
||||||
|
|
||||||
$config = str_replace('$subs_link', $subsURL, $config);
|
$config = str_replace('$subs_link', $subsURL, $config);
|
||||||
$config = str_replace('$subs_domain', $subsDomain, $config);
|
$config = str_replace('$subs_domain', $subsDomain, $config);
|
||||||
|
@ -37,7 +37,7 @@ class V2rayN
|
|||||||
$uri .= self::buildTrojan($user['uuid'], $item);
|
$uri .= self::buildTrojan($user['uuid'], $item);
|
||||||
}
|
}
|
||||||
if ($item['type'] === 'hysteria') {
|
if ($item['type'] === 'hysteria') {
|
||||||
$uri .= self::buildHysteria($user['uuid'], $item);
|
$uri .= General::buildHysteria($user['uuid'], $item);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -192,25 +192,5 @@ class V2rayN
|
|||||||
return $uri;
|
return $uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function buildHysteria($password, $server)
|
|
||||||
{
|
|
||||||
$name = rawurlencode($server['name']);
|
|
||||||
$params = [];
|
|
||||||
if ($server['server_name']) $params['sni'] = $server['server_name'];
|
|
||||||
$params['insecure'] = $server['insecure'] ? 1 : 0;
|
|
||||||
if($server['is_obfs']) {
|
|
||||||
$params['obfs'] = 'salamander';
|
|
||||||
$params['obfs-password'] = $server['server_key'];
|
|
||||||
}
|
|
||||||
$query = http_build_query($params);
|
|
||||||
if ($server['version'] == 2) {
|
|
||||||
$uri = "hysteria2://{$password}@{$server['host']}:{$server['port']}?{$query}#{$name}";
|
|
||||||
$uri .= "\r\n";
|
|
||||||
} else {
|
|
||||||
// V2rayN似乎不支持v1, 返回空
|
|
||||||
$uri = "";
|
|
||||||
}
|
|
||||||
return $uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,9 @@ class V2rayNG
|
|||||||
if ($item['type'] === 'vless') {
|
if ($item['type'] === 'vless') {
|
||||||
$uri .= self::buildVless($user['uuid'], $item);
|
$uri .= self::buildVless($user['uuid'], $item);
|
||||||
}
|
}
|
||||||
|
if ($item['type'] === 'hysteria') {
|
||||||
|
$uri .= General::buildHysteria($user['uuid'], $item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return base64_encode($uri);
|
return base64_encode($uri);
|
||||||
}
|
}
|
||||||
@ -190,5 +193,4 @@ class V2rayNG
|
|||||||
return $uri;
|
return $uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -314,9 +314,11 @@ class ServerService
|
|||||||
$servers[$k]['online'] = Cache::get(CacheKey::get("SERVER_{$serverType}_ONLINE_USER", $v['parent_id'] ?? $v['id'])) ?? 0;
|
$servers[$k]['online'] = Cache::get(CacheKey::get("SERVER_{$serverType}_ONLINE_USER", $v['parent_id'] ?? $v['id'])) ?? 0;
|
||||||
// 如果是子节点,先尝试从缓存中获取
|
// 如果是子节点,先尝试从缓存中获取
|
||||||
if($pid = $v['parent_id']){
|
if($pid = $v['parent_id']){
|
||||||
// 获取缓存
|
$cacheKey = CacheKey::get('MULTI_SERVER_' . $serverType . '_ONLINE_USER', $pid);
|
||||||
$onlineUsers = Cache::get(CacheKey::get('MULTI_SERVER_' . $serverType . '_ONLINE_USER', $pid)) ?? [];
|
$onlineUsers = Cache::get($cacheKey) ?? [];
|
||||||
$servers[$k]['online'] = (collect($onlineUsers)->whereIn('ip', $v['ips'])->sum('online_user')) . "|{$servers[$k]['online']}";
|
$onlineUserSum = collect($onlineUsers)->whereIn('ip', $v['ips'])->sum('online_user');
|
||||||
|
$online = ($onlineUserSum > 0 ? $onlineUserSum . "|" : "") . $servers[$k]['online'];
|
||||||
|
$servers[$k]['online'] = $online;
|
||||||
}
|
}
|
||||||
$servers[$k]['last_check_at'] = Cache::get(CacheKey::get("SERVER_{$serverType}_LAST_CHECK_AT", $v['parent_id'] ?? $v['id']));
|
$servers[$k]['last_check_at'] = Cache::get(CacheKey::get("SERVER_{$serverType}_LAST_CHECK_AT", $v['parent_id'] ?? $v['id']));
|
||||||
$servers[$k]['last_push_at'] = Cache::get(CacheKey::get("SERVER_{$serverType}_LAST_PUSH_AT", $v['parent_id'] ?? $v['id']));
|
$servers[$k]['last_push_at'] = Cache::get(CacheKey::get("SERVER_{$serverType}_LAST_PUSH_AT", $v['parent_id'] ?? $v['id']));
|
||||||
|
@ -108,13 +108,15 @@ class Helper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getSubscribeUrl($path)
|
public static function getSubscribeUrl(string $token, $subscribeUrl = null)
|
||||||
{
|
{
|
||||||
$subscribeUrls = explode(',', admin_setting('subscribe_url'));
|
$path = route('client.subscribe', ['token' => $token], false);
|
||||||
$subscribeUrl = $subscribeUrls[array_rand($subscribeUrls)];
|
if(!$subscribeUrl){
|
||||||
$subscribeUrl = self::replaceByPattern($subscribeUrl);
|
$subscribeUrls = explode(',', admin_setting('subscribe_url'));
|
||||||
if ($subscribeUrl) return $subscribeUrl . $path;
|
$subscribeUrl = \Arr::random($subscribeUrls);
|
||||||
return url($path);
|
$subscribeUrl = self::replaceByPattern($subscribeUrl);
|
||||||
|
}
|
||||||
|
return $subscribeUrl ? rtrim($subscribeUrl, '/') . $path : url($path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function randomPort($range) {
|
public static function randomPort($range) {
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^8.1",
|
"php": "^8.1",
|
||||||
"cedar2025/http-foundation": "6.4.x-dev",
|
|
||||||
"cweagans/composer-patches": "^1.7",
|
"cweagans/composer-patches": "^1.7",
|
||||||
"doctrine/dbal": "^3.7",
|
"doctrine/dbal": "^3.7",
|
||||||
"firebase/php-jwt": "^6.3",
|
"firebase/php-jwt": "^6.3",
|
||||||
|
@ -106,6 +106,8 @@ docker compose up -d
|
|||||||
|
|
||||||
🎉: 到这里,你已经可以通过域名访问你的站点了。
|
🎉: 到这里,你已经可以通过域名访问你的站点了。
|
||||||
|
|
||||||
|
⚠️: 请务必开启防火墙防止7001端口暴露到公网当中。
|
||||||
|
|
||||||
## 更新
|
## 更新
|
||||||
|
|
||||||
1. 通过 SSH 登录到服务器后,访问站点路径如:`/opt/1panel/apps/openresty/openresty/www/sites/xboard/index`,然后在站点目录中执行以下命令:
|
1. 通过 SSH 登录到服务器后,访问站点路径如:`/opt/1panel/apps/openresty/openresty/www/sites/xboard/index`,然后在站点目录中执行以下命令:
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
```
|
```
|
||||||
# 安装Docker
|
# 安装Docker
|
||||||
curl -sSL https://get.docker.com | bash
|
curl -sSL https://get.docker.com | bash
|
||||||
|
# Centos系统可能还需要执行下面命令来启动Docker
|
||||||
systemctl enable docker
|
systemctl enable docker
|
||||||
systemctl start docker
|
systemctl start docker
|
||||||
```
|
```
|
||||||
@ -79,7 +80,9 @@ location ^~ / {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
🎉: 到这里,你可以已经可以通过域名访问你的站点了
|
🎉: 到这里,你可以已经可以通过域名访问你的站点了
|
||||||
|
|
||||||
|
⚠️: 请务必开启防火墙防止7001端口暴露到公网当中。
|
||||||
|
|
||||||
### 更新
|
### 更新
|
||||||
1. 更新代码
|
1. 更新代码
|
||||||
|
@ -7,6 +7,9 @@
|
|||||||
1. 安装docker
|
1. 安装docker
|
||||||
```
|
```
|
||||||
curl -sSL https://get.docker.com | bash
|
curl -sSL https://get.docker.com | bash
|
||||||
|
```
|
||||||
|
Centos系统可能需要执行下面命令来启动Docker。
|
||||||
|
```
|
||||||
systemctl enable docker
|
systemctl enable docker
|
||||||
systemctl start docker
|
systemctl start docker
|
||||||
```
|
```
|
||||||
@ -18,6 +21,10 @@ cd Xboard
|
|||||||
3. 执行数据库安装命令
|
3. 执行数据库安装命令
|
||||||
> 选择 **启用sqlite** 和 **Docker内置的Redis**
|
> 选择 **启用sqlite** 和 **Docker内置的Redis**
|
||||||
```
|
```
|
||||||
|
docker compose run -it --rm -e enable_sqlite=true -e enable_redis=true -e admin_account=your_admin_email@example.com xboard php artisan xboard:install
|
||||||
|
```
|
||||||
|
> 或者根据自己的需要在运行时选择
|
||||||
|
```
|
||||||
docker compose run -it --rm xboard php artisan xboard:install
|
docker compose run -it --rm xboard php artisan xboard:install
|
||||||
```
|
```
|
||||||
> 执行这条命令之后,会返回你的后台地址和管理员账号密码(你需要记录下来)
|
> 执行这条命令之后,会返回你的后台地址和管理员账号密码(你需要记录下来)
|
||||||
@ -67,4 +74,4 @@ docker compose up -d
|
|||||||
```
|
```
|
||||||
|
|
||||||
### 注意
|
### 注意
|
||||||
启用webman后做的任何代码修改都需要重启生效
|
启用webman后做的任何代码修改都需要重启生效
|
||||||
|
Loading…
Reference in New Issue
Block a user