package app import ( "net/http" ) func handleTransportClientLifecycleAction(w http.ResponseWriter, r *http.Request, id, action string) { if r.Method != http.MethodPost { http.Error(w, "method not allowed", http.StatusMethodNotAllowed) return } lockIDs, ok := resolveTransportLifecycleLockIDs(id, action) if !ok { writeJSON(w, http.StatusNotFound, TransportClientLifecycleResponse{ OK: false, Message: "not found", Code: "TRANSPORT_CLIENT_NOT_FOUND", }) return } status := http.StatusOK resp := TransportClientLifecycleResponse{} withTransportIfaceLocks(lockIDs, func() { status, resp = executeTransportLifecycleActionWithPreflightLocked(id, action) }) writeJSON(w, status, resp) } func executeTransportLifecycleActionWithPreflightLocked(id, action string) (int, TransportClientLifecycleResponse) { if preStatus, preResp, handled := runTransportLifecyclePreflight(id, action); handled { return preStatus, preResp } return executeTransportLifecycleActionLocked(id, action) } func resolveTransportLifecycleLockIDsForSnapshot(items []TransportClient, ifaces transportInterfacesState, id, action string) ([]string, bool) { idx := findTransportClientIndex(items, id) if idx < 0 { return nil, false } targetBinding := resolveTransportIfaceBinding(items[idx], ifaces) lockIDs := []string{targetBinding.IfaceID} if action == "start" || action == "restart" { _, peers := matchTransportSingBoxPeersInSameNetnsForLock(items, idx, ifaces) for _, peer := range peers { lockIDs = append(lockIDs, peer.Binding.IfaceID) } } return lockIDs, true } func resolveTransportLifecycleLockIDs(id, action string) ([]string, bool) { transportMu.Lock() clientsState := loadTransportClientsState() idx := findTransportClientIndex(clientsState.Items, id) if idx < 0 { transportMu.Unlock() return nil, false } ifacesState := loadTransportInterfacesState() ifacesSnapshot := captureTransportInterfacesStateSnapshot(clientsState, ifacesState) transportMu.Unlock() normIfaces, changed := normalizeTransportInterfacesState(ifacesState, clientsState.Items) if changed { _ = saveTransportInterfacesIfSnapshotCurrent(ifacesSnapshot, normIfaces) } return resolveTransportLifecycleLockIDsForSnapshot(clientsState.Items, normIfaces, id, action) }