diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index c6b0a3cc..18db34bd 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -13,15 +13,7 @@ RUN apt-get update && \ \ # Update package information and install Nginx apt-get update && \ - apt-get install -y --no-install-recommends nginx && \ - \ - # Install the latest Node.js via NodeSource setup script - curl -fsSL https://deb.nodesource.com/setup_current.x | bash - && \ - apt-get update && \ - apt-get install -y nodejs && \ - \ - # Install pnpm globally using npm - npm install -g pnpm && \ + apt-get install -y --no-install-recommends nginx inotify-tools file && \ \ # Automatically retrieve the latest stable Go version and install it, # download the appropriate binary based on system architecture (amd64 or arm64) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 8f2f12df..27a99d31 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -10,7 +10,8 @@ "features": { "ghcr.io/devcontainers/features/common-utils:2": { "installOhMyZsh": true - } + }, + "ghcr.io/devcontainers/features/node:1": {} }, // Use 'forwardPorts' to make a list of ports inside the container available locally. @@ -27,7 +28,8 @@ "antfu.unocss", "github.copilot", "golang.go", - "vue.volar" + "vue.volar", + "ms-azuretools.vscode-docker" ] } }, diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml index 7300a3d7..63ab9b6e 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/docker-compose.yml @@ -1,15 +1,31 @@ services: nginx-ui: build: . + image: nginx-ui-dev + container_name: nginx-ui volumes: - ../..:/workspaces:cached - ./go-path:/root/go - - ./nginx:/etc/nginx + - ./data/nginx:/etc/nginx command: sleep infinity environment: - NGINX_UI_CERT_CA_DIR=https://pebble:14000/dir networks: nginxui: + nginx-ui-2: + image: nginx-ui-dev + container_name: nginx-ui-2 + volumes: + - ../..:/workspaces:cached + - ./data/nginx-ui-2/nginx:/etc/nginx + - ./data/nginx-ui-2/nginx-ui:/etc/nginx-ui + working_dir: /workspaces/nginx-ui + command: ./.devcontainer/node-supervisor.sh + depends_on: + - nginx-ui + networks: + nginxui: + pebble: image: ghcr.io/letsencrypt/pebble:latest volumes: diff --git a/.devcontainer/init-nginx.sh b/.devcontainer/init-nginx.sh new file mode 100755 index 00000000..87080779 --- /dev/null +++ b/.devcontainer/init-nginx.sh @@ -0,0 +1,6 @@ +# init nginx config dir +if [ "$(ls -A /etc/nginx)" = "" ]; then + echo "Initialing Nginx config dir" + cp -rp /etc/nginx.orig/* /etc/nginx/ + echo "Initialed Nginx config dir" +fi \ No newline at end of file diff --git a/.devcontainer/node-supervisor.sh b/.devcontainer/node-supervisor.sh new file mode 100755 index 00000000..fe918c9e --- /dev/null +++ b/.devcontainer/node-supervisor.sh @@ -0,0 +1,87 @@ +#!/bin/bash + +# Configurable variables +SOURCE_FILE=/workspaces/nginx-ui/tmp/main +TARGET_PATH=/usr/local/bin/nginx-ui +CONFIG_FILE=/etc/nginx-ui/app.ini + +# init nginx +./.devcontainer/init-nginx.sh + +LOG_PREFIX="[Supervisor]" + +# Debug initial state +echo "$LOG_PREFIX Starting supervisor with:" +echo "$LOG_PREFIX SOURCE_FILE: $SOURCE_FILE" +echo "$LOG_PREFIX TARGET_PATH: $TARGET_PATH" +echo "$LOG_PREFIX CONFIG_FILE: $CONFIG_FILE" + +# Wait for initial file creation +while [[ ! -f "$SOURCE_FILE" ]]; do + echo "$LOG_PREFIX Waiting for $SOURCE_FILE to be created..." + sleep 1 +done + +# Initial copy and start +echo "$LOG_PREFIX Initial file detected, starting service..." +cp -fv "$SOURCE_FILE" "$TARGET_PATH" +chmod +x "$TARGET_PATH" +pkill -x nginx-ui || echo "$LOG_PREFIX No existing process to kill" +nohup "$TARGET_PATH" -config "$CONFIG_FILE" > /proc/1/fd/1 2>&1 & + +# Use proper field separation for inotify output +inotifywait -m -e close_write,moved_to,create,delete \ + --format "%T|%w%f|%e" \ + --timefmt "%F-%H:%M:%S" \ + "$(dirname "$SOURCE_FILE")" | +while IFS='|' read -r TIME FILE EVENT; do + echo "$LOG_PREFIX [${TIME}] Event: ${EVENT} - ${FILE}" + + # Handle atomic save operations + if [[ "$FILE" =~ .*-tmp-umask$ ]] || [[ "$EVENT" == "DELETE" ]]; then + echo "$LOG_PREFIX Detected build intermediate file, checking main..." + sleep 0.3 # Allow atomic replace completion + + if [[ -f "$SOURCE_FILE" ]]; then + echo "$LOG_PREFIX Valid main file detected after build" + FILE="$SOURCE_FILE" + else + echo "$LOG_PREFIX Main file missing after build operation" + continue + fi + fi + + if [[ "$FILE" == "$SOURCE_FILE" ]]; then + # Stability checks + echo "$LOG_PREFIX File metadata:" + ls -l "$FILE" + file "$FILE" + + # Wait for file stability with retries + retries=5 + while ((retries-- > 0)); do + if file "$FILE" | grep -q "executable"; then + break + fi + echo "$LOG_PREFIX Waiting for valid executable (${retries} retries left)..." + sleep 1 + done + + if ((retries <= 0)); then + echo "$LOG_PREFIX ERROR: File validation failed after 5 retries" + continue + fi + + # Copy and restart service + echo "$LOG_PREFIX Updating service..." + cp -fv "$FILE" "$TARGET_PATH" + chmod +x "$TARGET_PATH" + + echo "$LOG_PREFIX Killing existing process..." + pkill -x nginx-ui || echo "$LOG_PREFIX No process to kill" + + echo "$LOG_PREFIX Starting new process..." + nohup "$TARGET_PATH" -config "$CONFIG_FILE" > /proc/1/fd/1 2>&1 & + echo "$LOG_PREFIX Restart complete. New PID: $(pgrep nginx-ui)" + fi +done diff --git a/.devcontainer/start.sh b/.devcontainer/start.sh index 21b723a5..aaee9690 100755 --- a/.devcontainer/start.sh +++ b/.devcontainer/start.sh @@ -9,11 +9,7 @@ if ! grep -q "zsh-autosuggestions" ~/.zshrc; then fi # init nginx config dir -if [ "$(ls -A /etc/nginx)" = "" ]; then - echo "Initialing Nginx config dir" - cp -rp /etc/nginx.orig/* /etc/nginx/ - echo "Initialed Nginx config dir" -fi +./.devcontainer/init-nginx.sh # install app dependencies echo "Installing app dependencies" diff --git a/.gitignore b/.gitignore index d56e89b3..e910352e 100644 --- a/.gitignore +++ b/.gitignore @@ -15,5 +15,5 @@ app/.status_hash .idea/deployment.xml .idea/webServers.xml .devcontainer/go-path -.devcontainer/nginx +.devcontainer/data .devcontainer/casdoor.pem diff --git a/api/cluster/environment.go b/api/cluster/environment.go index fe6a6be5..d63e9ed7 100644 --- a/api/cluster/environment.go +++ b/api/cluster/environment.go @@ -4,6 +4,10 @@ import ( "crypto/sha256" "encoding/hex" "encoding/json" + "io" + "net/http" + "time" + "github.com/0xJacky/Nginx-UI/api" "github.com/0xJacky/Nginx-UI/internal/analytic" "github.com/0xJacky/Nginx-UI/internal/cluster" @@ -14,9 +18,6 @@ import ( "github.com/spf13/cast" "github.com/uozi-tech/cosy" "gorm.io/gorm" - "io" - "net/http" - "time" ) func GetEnvironment(c *gin.Context) { @@ -151,23 +152,10 @@ func EditEnvironment(c *gin.Context) { } func DeleteEnvironment(c *gin.Context) { - id := cast.ToUint64(c.Param("id")) - envQuery := query.Environment - - env, err := envQuery.FirstByID(id) - if err != nil { - api.ErrHandler(c, err) - return - } - err = envQuery.DeleteByID(env.ID) - if err != nil { - api.ErrHandler(c, err) - return - } - - go analytic.RestartRetrieveNodesStatus() - - c.JSON(http.StatusNoContent, nil) + cosy.Core[model.Environment](c). + ExecutedHook(func(c *cosy.Ctx[model.Environment]) { + go analytic.RestartRetrieveNodesStatus() + }).Destroy() } func LoadEnvironmentFromSettings(c *gin.Context) { diff --git a/app/src/components/StdDesign/StdDataDisplay/StdCurd.vue b/app/src/components/StdDesign/StdDataDisplay/StdCurd.vue index 9d94eb85..3e8d1b81 100644 --- a/app/src/components/StdDesign/StdDataDisplay/StdCurd.vue +++ b/app/src/components/StdDesign/StdDataDisplay/StdCurd.vue @@ -181,7 +181,7 @@ function handleBatchUpdated() { v-if="!disableAdd && !inTrash" type="link" size="small" - @click="add" + @click="add()" > {{ $gettext('Add') }} diff --git a/app/src/version.json b/app/src/version.json index eea75a7c..b30487a6 100644 --- a/app/src/version.json +++ b/app/src/version.json @@ -1 +1 @@ -{"version":"2.0.0-rc.1","build_id":1,"total_build":375} \ No newline at end of file +{"version":"2.0.0-rc.1","build_id":7,"total_build":381} \ No newline at end of file diff --git a/app/src/views/environment/Environment.vue b/app/src/views/environment/Environment.vue index ac2a32b7..ad535c80 100644 --- a/app/src/views/environment/Environment.vue +++ b/app/src/views/environment/Environment.vue @@ -6,6 +6,7 @@ import BatchUpgrader from '@/views/environment/BatchUpgrader.vue' import envColumns from '@/views/environment/envColumns' import { message } from 'ant-design-vue' +const route = useRoute() const curd = ref() function loadFromSettings() { environment.load_from_settings().then(() => { @@ -20,6 +21,18 @@ const refUpgrader = ref() function batchUpgrade() { refUpgrader.value.open(selectedNodeIds, selectedNodes) } + +const inTrash = computed(() => { + return route.query.trash === 'true' +}) + +// const timer = setInterval(() => { +// curd.value.get_list() +// }, 10000) + +// onUnmounted(() => { +// clearInterval(timer) +// })