Skip to content

Commit 80ba985

Browse files
committed
feat(group): add mutable selector and mutable urltest outbound groups
1 parent f05099d commit 80ba985

File tree

7 files changed

+888
-160
lines changed

7 files changed

+888
-160
lines changed

constant/proxy.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,7 @@ const (
88
)
99

1010
const (
11-
TypeFallback = "fallback"
11+
TypeFallback = "fallback"
12+
TypeMutableSelector = "mutableselector"
13+
TypeMutableURLTest = "mutableurltest"
1214
)

internal/sync/typed_map.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// Package sync provides a generic, type-safe wrapper around sync.Map
2+
// for concurrent access to maps with arbitrary key and value types.
3+
package sync
4+
5+
import (
6+
"iter"
7+
"sync"
8+
)
9+
10+
// TypedMap is a generic, type-safe concurrent map based on sync.Map.
11+
// It supports any comparable key type and any value type.
12+
type TypedMap[K comparable, V any] struct {
13+
data sync.Map
14+
}
15+
16+
func (m *TypedMap[K, V]) Clear() {
17+
m.data.Clear()
18+
}
19+
20+
func (m *TypedMap[K, V]) CompareAndDelete(key K, old V) (deleted bool) {
21+
return m.data.CompareAndDelete(key, old)
22+
}
23+
24+
func (m *TypedMap[K, V]) CompareAndSwap(key K, old V, new V) (swapped bool) {
25+
return m.data.CompareAndSwap(key, old, new)
26+
}
27+
28+
func (m *TypedMap[K, V]) Delete(key K) {
29+
m.data.Delete(key)
30+
}
31+
32+
func (m *TypedMap[K, V]) Load(key K) (value V, ok bool) {
33+
v, ok := m.data.Load(key)
34+
if !ok {
35+
return zero[V](), false
36+
}
37+
return v.(V), true
38+
}
39+
40+
func (m *TypedMap[K, V]) LoadAndDelete(key K) (value V, loaded bool) {
41+
v, loaded := m.data.LoadAndDelete(key)
42+
if !loaded {
43+
return zero[V](), false
44+
}
45+
return v.(V), true
46+
}
47+
48+
func (m *TypedMap[K, V]) LoadOrStore(key K, value V) (actual V, loaded bool) {
49+
v, loaded := m.data.LoadOrStore(key, value)
50+
if !loaded {
51+
return value, false
52+
}
53+
return v.(V), true
54+
}
55+
56+
func (m *TypedMap[K, V]) Iter() iter.Seq2[K, V] {
57+
return func(yield func(K, V) bool) {
58+
m.data.Range(func(key, value any) bool {
59+
return yield(key.(K), value.(V))
60+
})
61+
}
62+
}
63+
64+
func (m *TypedMap[K, V]) Store(key K, value V) {
65+
m.data.Store(key, value)
66+
}
67+
68+
func (m *TypedMap[K, V]) Swap(key K, value V) (previous V, loaded bool) {
69+
prev, loaded := m.data.Swap(key, value)
70+
return prev.(V), loaded
71+
}
72+
73+
func zero[V any]() V {
74+
var zero V
75+
return zero
76+
}

option/group.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,21 @@
11
package option
22

3+
import "github.com/sagernet/sing/common/json/badoption"
4+
35
type FallbackOutboundOptions struct {
46
// Primary and Fallback are the tags of the primary and fallback outbounds.
57
Primary string `json:"primary"`
68
Fallback string `json:"fallback"`
79
}
10+
11+
type MutableSelectorOutboundOptions struct {
12+
Outbounds []string `json:"outbounds"`
13+
}
14+
15+
type MutableURLTestOutboundOptions struct {
16+
Outbounds []string `json:"outbounds"`
17+
URL string `json:"url,omitempty"`
18+
Interval badoption.Duration `json:"interval,omitempty"`
19+
Tolerance uint16 `json:"tolerance,omitempty"`
20+
IdleTimeout badoption.Duration `json:"idle_timeout,omitempty"`
21+
}

0 commit comments

Comments
 (0)