package app import ( "net/http" "strings" "time" ) func handleTransportSingBoxFeatures(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { http.Error(w, "method not allowed", http.StatusMethodNotAllowed) return } bin := "" for _, cand := range []string{"/usr/local/bin/sing-box", "/usr/bin/sing-box", "sing-box"} { if p, ok := findBinaryPath(cand); ok { bin = p break } } version := "" if bin != "" { stdout, _, code, _ := runCommandTimeout(2*time.Second, bin, "version") if code == 0 { for _, line := range strings.Split(stdout, "\n") { line = strings.TrimSpace(line) if line == "" { continue } version = line break } } } writeJSON(w, http.StatusOK, SingBoxFeaturesResponse{ OK: true, Message: "ok", Binary: bin, Version: version, ProfileModes: map[string]bool{ string(SingBoxProfileModeTyped): true, string(SingBoxProfileModeRaw): true, }, TypedProtocols: []string{"vless", "trojan", "shadowsocks", "wireguard", "hysteria2", "tuic"}, DNSFormats: map[string]bool{ "typed_servers": true, "typed_rules": true, "legacy_migration": true, "system_resolver": true, "rule_based_routing": true, }, ErrorCodes: []string{ singBoxProfileCodeNotFound, singBoxProfileCodeIDConflict, singBoxProfileCodeBadID, singBoxProfileCodeBadMode, singBoxProfileCodeBadBaseRevision, singBoxProfileCodeRevisionMismatch, singBoxProfileCodeSaveFailed, singBoxProfileCodeSecretsFailed, singBoxProfileCodeValidationFailed, singBoxProfileCodeRenderFailed, singBoxProfileCodeApplyFailed, singBoxProfileCodeRollbackFailed, singBoxProfileCodeHistoryMissing, singBoxProfileCodeNoClient, singBoxProfileCodeClientKind, singBoxProfileCodeRuntimeFailed, }, }) }