package main import ( "encoding/json" "flag" "fmt" "io" "log" "net/http" "os/exec" "time" ) var ( configPath string serverAddr string originalApp string ) func main() { flag.StringVar(&configPath, "config", "config.json", "path to config file") flag.StringVar(&serverAddr, "addr", ":9090", "address for config server") flag.StringVar(&originalApp, "app", "./override", "path to the original app") flag.Parse() http.HandleFunc("/api/config", handleConfig) http.HandleFunc("/api/restart", handleRestart) http.HandleFunc("/api/start", start) http.HandleFunc("/api/stop", stop) http.HandleFunc("/_ping", handlePing) http.Handle("/", http.FileServer(http.Dir("web"))) log.Printf("Config server starting on %s", serverAddr) log.Fatal(http.ListenAndServe(serverAddr, nil)) } func handleConfig(w http.ResponseWriter, r *http.Request) { if r.Method == http.MethodGet { config, err := LoadConfig(configPath) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") _, err = w.Write(config) if err != nil { return } } else if r.Method == http.MethodPost { var newConfig map[string]interface{} err := json.NewDecoder(r.Body).Decode(&newConfig) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } err = SaveConfig(configPath, newConfig) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) } else { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) } } func handleRestart(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } cmd := exec.Command(originalApp) err := cmd.Start() if err != nil { http.Error(w, "Failed to restart the application", http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) _, err = w.Write([]byte("Application restarted")) if err != nil { return } } func start(w http.ResponseWriter, r *http.Request) { cmd := exec.Command("override") err := cmd.Start() if err != nil { http.Error(w, "Failed to start override: "+err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) } func stop(w http.ResponseWriter, r *http.Request) { cmd := exec.Command("pkill", "override") err := cmd.Run() if err != nil { http.Error(w, "Failed to stop override: "+err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) } func handlePing(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } bindAddress := r.URL.Query().Get("bind") protocol := r.URL.Query().Get("protocol") if bindAddress == "" { http.Error(w, "bind address is required", http.StatusBadRequest) return } if protocol == "" { protocol = "http" // 默认使用http } url := fmt.Sprintf("%s://%s/_ping", protocol, bindAddress) client := &http.Client{ Timeout: 5 * time.Second, } resp, err := client.Get(url) if err != nil { w.WriteHeader(http.StatusServiceUnavailable) err := json.NewEncoder(w).Encode(map[string]string{ "msg": fmt.Sprintf("无法连接到服务器: %v", err), }) if err != nil { return } return } defer func(Body io.ReadCloser) { err := Body.Close() if err != nil { } }(resp.Body) if resp.StatusCode == http.StatusOK { w.WriteHeader(http.StatusOK) err := json.NewEncoder(w).Encode(map[string]interface{}{ "msg": "服务器已启动并正常运行", "data": map[string]interface{}{ "now": time.Now().Unix(), "ns1": "200 OK", }, }) if err != nil { return } } else { w.WriteHeader(http.StatusBadGateway) err := json.NewEncoder(w).Encode(map[string]string{ "msg": fmt.Sprintf("服务器响应异常: %s", resp.Status), }) if err != nil { return } } }