Files
elmprodvpn/selective-vpn-api/app/transport_iface_orchestrator_lock.go

95 lines
1.9 KiB
Go

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
}