package app import ( "sort" "sync" ) type transportIfaceOrchestrator struct { mu sync.Mutex locks map[string]*sync.Mutex } var transportIfaceRuntime = newTransportIfaceOrchestrator() func newTransportIfaceOrchestrator() *transportIfaceOrchestrator { return &transportIfaceOrchestrator{ locks: map[string]*sync.Mutex{}, } } func (o *transportIfaceOrchestrator) lockFor(ifaceID string) *sync.Mutex { key := normalizeTransportIfaceID(ifaceID) o.mu.Lock() defer o.mu.Unlock() if m, ok := o.locks[key]; ok { return m } m := &sync.Mutex{} o.locks[key] = m return m } func withTransportIfaceLock(ifaceID string, fn func()) { m := transportIfaceRuntime.lockFor(ifaceID) m.Lock() defer m.Unlock() fn() } func withTransportIfaceLocks(ifaceIDs []string, fn func()) { ids := normalizeTransportIfaceLockIDs(ifaceIDs) if len(ids) == 0 { fn() return } locks := make([]*sync.Mutex, 0, len(ids)) for _, ifaceID := range ids { locks = append(locks, transportIfaceRuntime.lockFor(ifaceID)) } for _, m := range locks { m.Lock() } defer func() { for i := len(locks) - 1; i >= 0; i-- { locks[i].Unlock() } }() fn() } func normalizeTransportIfaceLockIDs(ifaceIDs []string) []string { if len(ifaceIDs) == 0 { return nil } seen := map[string]struct{}{} out := make([]string, 0, len(ifaceIDs)) for _, raw := range ifaceIDs { id := normalizeTransportIfaceID(raw) if _, ok := seen[id]; ok { continue } seen[id] = struct{}{} out = append(out, id) } sort.Strings(out) return out } func resolveTransportClientIfaceID(clientID string) (string, bool) { id := sanitizeID(clientID) if id == "" { return "", false } transportMu.Lock() st := loadTransportClientsState() idx := findTransportClientIndex(st.Items, id) if idx < 0 { transportMu.Unlock() return "", false } ifaceID := normalizeTransportIfaceID(st.Items[idx].IfaceID) transportMu.Unlock() return ifaceID, true }