lib.sh 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. #!/bin/bash
  2. # ===============================================
  3. # 1. 基础输出函数
  4. # ===============================================
  5. print_logo() {
  6. cat << "EOF"
  7. ___ ___ _
  8. / _ \ _ __ ___ __ __ _ _ / _ \ __ _ _ __ ___ | |
  9. / /_)/| '__| / _ \ \ \/ /| | | | / /_)/ / _` || '_ \ / _ \| |
  10. / ___/ | | | (_) | > < | |_| |/ ___/ | (_| || | | || __/| |
  11. \/ |_| \___/ /_/\_\ \__, |\/ \__,_||_| |_| \___||_|
  12. |___/
  13. EOF
  14. }
  15. print_message() {
  16. # 格式: 绿色中文 | 英文
  17. echo -e "\033[32m$2\033[0m | $1"
  18. }
  19. # ===============================================
  20. # 2. 环境检查函数
  21. # ===============================================
  22. # 检查软件是否安装
  23. check_available() {
  24. tools=$1
  25. if command -v "$tools" >/dev/null 2>&1; then
  26. print_message "$tools Installed!" "$tools 已安装!"
  27. else
  28. print_message "$tools did not installed!" "$tools 未安装!"
  29. fi
  30. }
  31. # 检查 Web 环境
  32. check_web_environment() {
  33. print_message "Checking web environment..." "正在检查 Web 环境..."
  34. check_available php
  35. check_available php-fpm
  36. check_available nginx
  37. check_available apache2
  38. check_available mysql
  39. check_available redis-cli
  40. }
  41. # ===============================================
  42. # 3. 依赖安装函数
  43. # ===============================================
  44. install_composer() {
  45. # 检查是否安装了 Composer
  46. if ! command -v composer &>/dev/null; then
  47. print_message "Composer not found, installing..." "未找到 Composer,正在安装..."
  48. EXPECTED_CHECKSUM="$(php -r 'copy("https://composer.github.io/installer.sig", "php://stdout");')"
  49. php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
  50. ACTUAL_CHECKSUM="$(php -r "echo hash_file('sha384', 'composer-setup.php');")"
  51. if [ "$EXPECTED_CHECKSUM" != "$ACTUAL_CHECKSUM" ]; then
  52. >&2 print_message "ERROR: Invalid installer checksum" "错误: 安装程序校验和无效"
  53. rm composer-setup.php
  54. exit 1
  55. fi
  56. php composer-setup.php --quiet
  57. rm composer-setup.php
  58. mv composer.phar /usr/local/bin/composer
  59. else
  60. print_message "Composer is already installed." "Composer 已安装。"
  61. # 导入 lib_o.sh 的 composer self-update 逻辑
  62. if [[ $(composer -n --version --no-ansi 2>/dev/null | cut -d" " -f3) < 2.2.0 ]]; then
  63. print_message "Updating Composer..." "正在更新 Composer..."
  64. composer self-update
  65. fi
  66. fi
  67. }
  68. # 安装 Node.js 和 NPM (新增函数)
  69. install_nodejs_npm() {
  70. if command -v node &>/dev/null && command -v npm &>/dev/null; then
  71. print_message "Node.js and npm are already installed." "Node.js 和 npm 已安装。"
  72. return 0
  73. fi
  74. print_message "Node.js or npm not found, attempting installation..." "未找到 Node.js 或 npm,正在尝试安装..."
  75. # Node.js LTS 版本
  76. NODE_VERSION=22
  77. if [[ -f /etc/debian_version ]]; then
  78. # Debian/Ubuntu (使用 NodeSource 仓库获取 LTS 版本)
  79. print_message "Using NodeSource repository for Debian/Ubuntu." "正在使用 NodeSource 仓库 (Debian/Ubuntu)。"
  80. curl -fsSL https://deb.nodesource.com/setup_$NODE_VERSION.x | sudo -E bash -
  81. sudo apt-get install -y nodejs
  82. elif [[ -f /etc/redhat-release ]]; then
  83. # RHEL/CentOS/Fedora
  84. print_message "Using NodeSource repository for RHEL/CentOS." "正在使用 NodeSource 仓库 (RHEL/CentOS)。"
  85. curl -fsSL https://rpm.nodesource.com/setup_$NODE_VERSION.x | sudo bash -
  86. sudo yum install -y nodejs
  87. elif [[ -f /etc/SuSE-release ]]; then
  88. # OpenSUSE/SLES
  89. print_message "Unsupported automatic Node.js installation for SUSE/OpenSUSE." "不支持 SUSE/OpenSUSE 的自动 Node.js 安装。"
  90. return 1
  91. elif [[ -f /etc/arch-release ]]; then
  92. # Arch Linux
  93. print_message "Installing Node.js via pacman for Arch Linux." "正在通过 pacman 安装 Node.js (Arch Linux)。"
  94. sudo pacman -S --noconfirm nodejs npm
  95. elif [[ -f /etc/alpine-release ]]; then
  96. # Alpine Linux
  97. print_message "Installing Node.js via apk for Alpine Linux." "正在通过 apk 安装 Node.js (Alpine Linux)。"
  98. sudo apk add nodejs npm
  99. else
  100. print_message "Unsupported Linux distribution. Please install Node.js/npm manually." "不支持的 Linux 发行版。请手动安装 Node.js/npm。"
  101. return 1
  102. fi
  103. if command -v node &>/dev/null && command -v npm &>/dev/null; then
  104. print_message "Node.js and npm installation completed!" "Node.js 和 npm 安装完成!"
  105. return 0
  106. else
  107. print_message "Node.js and npm installation failed! Please check system logs." "Node.js 和 npm 安装失败! 请检查系统日志。"
  108. return 1
  109. fi
  110. }
  111. # 安装 Supervisor
  112. install_supervisor() {
  113. # 判断系统
  114. if [[ -f /etc/debian_version ]]; then
  115. PM=apt-get
  116. elif [[ -f /etc/redhat-release ]]; then
  117. PM=yum
  118. elif [[ -f /etc/SuSE-release ]]; then
  119. PM=zypper
  120. elif [[ -f /etc/arch-release ]]; then
  121. PM=pacman
  122. elif [[ -f /etc/alpine-release ]]; then
  123. PM=apk
  124. else
  125. print_message "Unsupported Linux distribution. Please install supervisor manually." "不支持的 Linux 发行版。请手动安装 supervisor。"
  126. return 1
  127. fi
  128. if command -v supervisorctl >/dev/null; then
  129. print_message "Supervisor installed!" "Supervisor 已安装!"
  130. else
  131. print_message "Supervisor not found, installing..." "未找到 Supervisor,正在安装..."
  132. # 安装 Supervisor
  133. case $PM in
  134. apt-get)
  135. sudo apt-get update
  136. sudo apt-get install -y supervisor
  137. ;;
  138. yum)
  139. sudo yum install -y epel-release
  140. sudo yum install -y supervisor
  141. ;;
  142. zypper)
  143. sudo zypper install -y supervisor
  144. ;;
  145. apk)
  146. sudo apk add supervisor
  147. ;;
  148. pacman)
  149. sudo pacman -S supervisor
  150. ;;
  151. esac
  152. # 激活
  153. case $PM in
  154. yum)
  155. sudo service supervisord start
  156. sudo chkconfig supervisord on
  157. ;;
  158. *)
  159. # 适用于大多数使用 systemd 的系统
  160. sudo systemctl start supervisor.service
  161. sudo systemctl enable supervisor.service
  162. ;;
  163. esac
  164. if command -v supervisorctl >/dev/null; then
  165. print_message "Supervisor installation completed!" "Supervisor 安装完成!"
  166. else
  167. print_message "Supervisor installation failed! Please check logs." "Supervisor 安装失败! 请检查日志。"
  168. return 1
  169. fi
  170. fi
  171. return 0
  172. }
  173. # ===============================================
  174. # 4. 配置和权限函数
  175. # ===============================================
  176. set_permissions() {
  177. print_message "Setting Laravel directory permissions (www)..." "正在设置 Laravel 目录权限 (www)..."
  178. if [ ! -d "/home/www" ]; then
  179. mkdir -p /home/www
  180. chown www:www /home/www
  181. fi
  182. chmod -R 755 storage bootstrap/cache public/assets
  183. chown -R www:www storage bootstrap/cache public/assets
  184. }
  185. # ===============================================
  186. # 5. 服务配置函数
  187. # ===============================================
  188. set_schedule() {
  189. SCHEDULE_CMD="php $(pwd)/artisan schedule:run >> /dev/null 2>&1"
  190. # 尝试使用 www 用户的 crontab
  191. if command -v crontab >/dev/null && id -u www &>/dev/null; then
  192. USER_CRON="www"
  193. else
  194. # 如果 www 用户不存在,则使用当前用户
  195. USER_CRON=$(whoami)
  196. fi
  197. if crontab -u $USER_CRON -l 2>/dev/null | grep -q "$SCHEDULE_CMD"; then
  198. print_message "Schedule already exists in crontab for user $USER_CRON." "定时任务已存在于用户 $USER_CRON 的 crontab 中。"
  199. else
  200. # 添加定时任务
  201. (crontab -u $USER_CRON -l 2>/dev/null; echo "* * * * * $SCHEDULE_CMD") | crontab -u $USER_CRON -
  202. print_message "Schedule task added to crontab for user $USER_CRON." "定时任务已添加到用户 $USER_CRON 的 crontab。"
  203. fi
  204. }
  205. set_horizon() {
  206. # 创建 Horizon 配置文件 (用户使用 www 以匹配权限)
  207. if [ ! -f /etc/supervisor/conf.d/horizon.conf ]; then
  208. cat > /etc/supervisor/conf.d/horizon.conf <<EOF
  209. [program:horizon]
  210. process_name=%(program_name)s
  211. command=php $(pwd)/artisan horizon
  212. autostart=true
  213. autorestart=true
  214. user=www
  215. redirect_stderr=true
  216. stdout_logfile=$(pwd)/storage/logs/horizon.log
  217. stopwaitsecs=3600
  218. EOF
  219. # 重新加载 supervisor 配置
  220. supervisorctl reread
  221. supervisorctl update
  222. supervisorctl start horizon
  223. print_message "Horizon service configured and started." "Horizon 服务已配置并启动。"
  224. else
  225. # 优化:如果配置已存在,在更新后强制重启服务
  226. print_message "Horizon supervisor configuration already exists, attempting to restart service." "Horizon supervisor 配置已存在,尝试重启服务。"
  227. supervisorctl restart horizon
  228. fi
  229. }
  230. configure_reverb() {
  231. # 尝试加载 .env 文件,如果存在
  232. if [ -f ".env" ]; then
  233. # 从 .env 文件中获取 APP_URL 的值
  234. APP_URL=$(grep '^APP_URL=' .env | cut -d '=' -f2)
  235. fi
  236. # 检查 .env 文件中是否已存在 Reverb 配置
  237. if ! grep -q "REVERB_APP_KEY" .env || [ -z "$(grep "REVERB_APP_KEY=" .env | cut -d '=' -f2)" ]; then
  238. print_message "Adding Reverb configuration to .env file..." "正在向 .env 文件添加 Reverb 配置..."
  239. REVERB_APP_KEY=$(tr -dc 'a-zA-Z0-9' </dev/urandom | head -c 32)
  240. REVERB_APP_SECRET=$(tr -dc 'a-zA-Z0-9' </dev/urandom | head -c 32)
  241. REVERB_APP_ID=$(tr -dc '0-9' </dev/urandom | head -c 6)
  242. REVERB_SERVER_PATH=/broadcasting
  243. # 替换或添加 Reverb 配置到 .env 文件
  244. sed -i "/^BROADCAST_DRIVER=/d" .env
  245. sed -i "/^REVERB_APP_KEY=/d" .env
  246. sed -i "/^REVERB_APP_SECRET=/d" .env
  247. sed -i "/^REVERB_APP_ID=/d" .env
  248. sed -i "/^REVERB_SERVER_PATH=/d" .env
  249. sed -i "/^VITE_REVERB_APP_KEY=/d" .env
  250. sed -i "/^VITE_REVERB_HOST=/d" .env
  251. sed -i "/^VITE_REVERB_PORT=/d" .env
  252. echo "BROADCAST_DRIVER=reverb" >> .env
  253. echo "REVERB_APP_KEY=$REVERB_APP_KEY" >> .env
  254. echo "REVERB_APP_SECRET=$REVERB_APP_SECRET" >> .env
  255. echo "REVERB_APP_ID=$REVERB_APP_ID" >> .env
  256. echo "REVERB_SERVER_PATH=$REVERB_SERVER_PATH" >> .env
  257. echo "VITE_REVERB_APP_KEY=\"\${REVERB_APP_KEY}\"" >> .env
  258. echo "VITE_REVERB_HOST=\"\${REVERB_HOST}\"" >> .env
  259. echo "VITE_REVERB_PORT=\"\${REVERB_PORT}\"" >> .env
  260. print_message "Reverb configuration added to .env file." "Reverb 配置已添加到 .env 文件。"
  261. else
  262. print_message "Reverb configuration already exists in .env file." "Reverb 配置已存在于 .env 文件中。"
  263. fi
  264. # 创建 Reverb 服务的 supervisor 配置 (用户使用 www 以匹配权限)
  265. if [ ! -f "/etc/supervisor/conf.d/reverb.conf" ]; then
  266. cat > /etc/supervisor/conf.d/reverb.conf <<EOF
  267. [program:reverb]
  268. process_name=%(program_name)s
  269. command=php $(pwd)/artisan reverb:start
  270. autostart=true
  271. autorestart=true
  272. user=www
  273. redirect_stderr=true
  274. stdout_logfile=$(pwd)/storage/logs/reverb.log
  275. stopwaitsecs=3600
  276. EOF
  277. # 重新加载 supervisor 配置
  278. supervisorctl reread
  279. supervisorctl update
  280. supervisorctl start reverb
  281. print_message "Reverb supervisor configuration created and started." "Reverb supervisor 配置已创建并启动。"
  282. else
  283. print_message "Reverb supervisor configuration already exists, attempting to restart service." "Reverb supervisor 配置已存在,尝试重启服务。"
  284. supervisorctl restart reverb
  285. fi
  286. }
  287. build_frontend_assets() {
  288. # 检查 Node.js/npm 是否真的可用,以防安装失败
  289. if ! command -v node &>/dev/null || ! command -v npm &>/dev/null; then
  290. print_message "Cannot build frontend assets. Node.js/npm is not available." "无法构建前端资源。Node.js/npm 不可用。"
  291. return
  292. fi
  293. print_message "Installing frontend dependencies..." "安装前端依赖..."
  294. npm install
  295. print_message "Building frontend assets..." "构建前端资源..."
  296. npm run build
  297. }
  298. # ===============================================
  299. # 6. 清理函数
  300. # ===============================================
  301. update_old_queue() {
  302. # 检查旧的队列设置
  303. if crontab -l 2>/dev/null | grep -q "artisan queue:work"; then
  304. print_message "Removing old queue worker from crontab..." "正在从 crontab 中移除旧的队列工作者..."
  305. crontab -l | grep -v "artisan queue:work" | crontab -
  306. fi
  307. # 检查旧的队列设置
  308. if crontab -l 2>/dev/null | grep -q "queue.sh"; then
  309. print_message "Removing old queue.sh cron job..." "正在移除旧的 queue.sh 定时任务..."
  310. crontab -l | grep -v "queue.sh" | crontab -
  311. fi
  312. set_horizon
  313. }
  314. clean_files() {
  315. print_message "Cleaning up unnecessary files..." "正在清理不必要的文件..."
  316. rm -f .gitignore .styleci.yml
  317. rm -rf .htaccess 404.html index.html
  318. if [ -f .user.ini ]; then
  319. # 尝试移除文件锁
  320. if command -v chattr >/dev/null; then
  321. chattr -i .user.ini
  322. fi
  323. rm -f .user.ini
  324. print_message "Cleaned up unnecessary files" "不必要的文件已清理。"
  325. fi
  326. }