瀏覽代碼

feat(devcontainer): multi node

Jacky 2 月之前
父節點
當前提交
b090564a34

+ 1 - 9
.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)

+ 4 - 2
.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"
       ]
     }
   },

+ 17 - 1
.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:

+ 6 - 0
.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

+ 87 - 0
.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

+ 1 - 5
.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"

+ 1 - 1
.gitignore

@@ -15,5 +15,5 @@ app/.status_hash
 .idea/deployment.xml
 .idea/webServers.xml
 .devcontainer/go-path
-.devcontainer/nginx
+.devcontainer/data
 .devcontainer/casdoor.pem

+ 8 - 20
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) {

+ 1 - 1
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') }}
           </AButton>

+ 1 - 1
app/src/version.json

@@ -1 +1 @@
-{"version":"2.0.0-rc.1","build_id":1,"total_build":375}
+{"version":"2.0.0-rc.1","build_id":7,"total_build":381}

+ 14 - 1
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)
+// })
 </script>
 
 <template>
@@ -43,7 +56,7 @@ function batchUpgrade() {
 
     <BatchUpgrader ref="refUpgrader" />
 
-    <FooterToolBar>
+    <FooterToolBar v-if="!inTrash">
       <ATooltip
         :title="$gettext('Please select at least one node to upgrade')"
         placement="topLeft"

+ 4 - 4
app/src/views/environment/envColumns.tsx

@@ -26,12 +26,12 @@ const columns: Column[] = [{
       placeholder: () => 'https://10.0.0.1:9000',
     },
   },
-  width: 300,
+  width: 260,
 }, {
   title: () => $gettext('Version'),
   dataIndex: 'version',
   pithy: true,
-  width: 150,
+  width: 120,
 }, {
   title: () => 'NodeSecret',
   dataIndex: 'token',
@@ -65,7 +65,7 @@ const columns: Column[] = [{
   },
   sorter: true,
   pithy: true,
-  width: 200,
+  width: 120,
 }, {
   title: () => $gettext('Enabled'),
   dataIndex: 'enabled',
@@ -85,7 +85,7 @@ const columns: Column[] = [{
   },
   sorter: true,
   pithy: true,
-  width: 150,
+  width: 120,
 }, {
   title: () => $gettext('Updated at'),
   dataIndex: 'updated_at',

+ 4 - 3
main.go

@@ -1,22 +1,23 @@
 package main
 
 import (
+	"errors"
 	"flag"
 	"fmt"
+	"net/http"
+	"time"
+
 	"github.com/0xJacky/Nginx-UI/internal/kernel"
 	"github.com/0xJacky/Nginx-UI/model"
 	"github.com/0xJacky/Nginx-UI/router"
 	"github.com/0xJacky/Nginx-UI/settings"
 	"github.com/gin-gonic/gin"
 	"github.com/jpillora/overseer"
-	"errors"
 	"github.com/uozi-tech/cosy"
 	cKernel "github.com/uozi-tech/cosy/kernel"
 	"github.com/uozi-tech/cosy/logger"
 	cRouter "github.com/uozi-tech/cosy/router"
 	cSettings "github.com/uozi-tech/cosy/settings"
-	"net/http"
-	"time"
 )
 
 func Program(confPath string) func(state overseer.State) {

+ 1 - 1
model/environment.go

@@ -10,7 +10,7 @@ type Environment struct {
 	Name    string `json:"name"`
 	URL     string `json:"url"`
 	Token   string `json:"token"`
-	Enabled bool   `json:"enabled" gorm:"default:true"`
+	Enabled bool   `json:"enabled" gorm:"default:false"`
 }
 
 func (e *Environment) GetUrl(uri string) (decodedUri string, err error) {