diff --git a/adapter/adapter.go b/adapter/adapter.go index ffb5ced0..538ba271 100644 --- a/adapter/adapter.go +++ b/adapter/adapter.go @@ -4,16 +4,16 @@ import ( "context" "encoding/json" "fmt" - "github.com/Dreamacro/clash/common/queue" - "github.com/Dreamacro/clash/component/dialer" - C "github.com/Dreamacro/clash/constant" "net" "net/http" "net/netip" "net/url" "time" - "go.uber.org/atomic" + "github.com/Dreamacro/clash/common/atomic" + "github.com/Dreamacro/clash/common/queue" + "github.com/Dreamacro/clash/component/dialer" + C "github.com/Dreamacro/clash/constant" ) var UnifiedDelay = atomic.NewBool(false) diff --git a/adapter/outboundgroup/groupbase.go b/adapter/outboundgroup/groupbase.go index 0a421793..8e253e63 100644 --- a/adapter/outboundgroup/groupbase.go +++ b/adapter/outboundgroup/groupbase.go @@ -8,6 +8,7 @@ import ( "time" "github.com/Dreamacro/clash/adapter/outbound" + "github.com/Dreamacro/clash/common/atomic" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/constant/provider" types "github.com/Dreamacro/clash/constant/provider" @@ -15,7 +16,6 @@ import ( "github.com/Dreamacro/clash/tunnel" "github.com/dlclark/regexp2" - "go.uber.org/atomic" ) type GroupBase struct { diff --git a/adapter/provider/healthcheck.go b/adapter/provider/healthcheck.go index 9deb7b82..fa13e32e 100644 --- a/adapter/provider/healthcheck.go +++ b/adapter/provider/healthcheck.go @@ -4,13 +4,12 @@ import ( "context" "time" + "github.com/Dreamacro/clash/common/atomic" "github.com/Dreamacro/clash/common/batch" "github.com/Dreamacro/clash/common/singledo" "github.com/Dreamacro/clash/common/utils" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/log" - - "go.uber.org/atomic" ) const ( diff --git a/common/atomic/type.go b/common/atomic/type.go new file mode 100644 index 00000000..f1549235 --- /dev/null +++ b/common/atomic/type.go @@ -0,0 +1,205 @@ +package atomic + +import ( + "encoding/json" + "fmt" + "strconv" + "sync/atomic" +) + +type Bool struct { + atomic.Bool +} + +func NewBool(val bool) *Bool { + i := &Bool{} + i.Store(val) + return i +} + +func (i *Bool) MarshalJSON() ([]byte, error) { + return json.Marshal(i.Load()) +} + +func (i *Bool) UnmarshalJSON(b []byte) error { + var v bool + if err := json.Unmarshal(b, &v); err != nil { + return err + } + i.Store(v) + return nil +} + +func (i *Bool) String() string { + v := i.Load() + return strconv.FormatBool(v) +} + +type Pointer[T any] struct { + atomic.Pointer[T] +} + +func NewPointer[T any](v *T) *Pointer[T] { + var p Pointer[T] + if v != nil { + p.Store(v) + } + return &p +} + +func (p *Pointer[T]) MarshalJSON() ([]byte, error) { + return json.Marshal(p.Load()) +} + +func (p *Pointer[T]) UnmarshalJSON(b []byte) error { + var v *T + if err := json.Unmarshal(b, &v); err != nil { + return err + } + p.Store(v) + return nil +} + +func (p *Pointer[T]) String() string { + return fmt.Sprint(p.Load()) +} + +type Int32 struct { + atomic.Int32 +} + +func NewInt32(val int32) *Int32 { + i := &Int32{} + i.Store(val) + return i +} + +func (i *Int32) MarshalJSON() ([]byte, error) { + return json.Marshal(i.Load()) +} + +func (i *Int32) UnmarshalJSON(b []byte) error { + var v int32 + if err := json.Unmarshal(b, &v); err != nil { + return err + } + i.Store(v) + return nil +} + +func (i *Int32) String() string { + v := i.Load() + return strconv.FormatInt(int64(v), 10) +} + +type Int64 struct { + atomic.Int64 +} + +func NewInt64(val int64) *Int64 { + i := &Int64{} + i.Store(val) + return i +} + +func (i *Int64) MarshalJSON() ([]byte, error) { + return json.Marshal(i.Load()) +} + +func (i *Int64) UnmarshalJSON(b []byte) error { + var v int64 + if err := json.Unmarshal(b, &v); err != nil { + return err + } + i.Store(v) + return nil +} + +func (i *Int64) String() string { + v := i.Load() + return strconv.FormatInt(int64(v), 10) +} + +type Uint32 struct { + atomic.Uint32 +} + +func NewUint32(val uint32) *Uint32 { + i := &Uint32{} + i.Store(val) + return i +} + +func (i *Uint32) MarshalJSON() ([]byte, error) { + return json.Marshal(i.Load()) +} + +func (i *Uint32) UnmarshalJSON(b []byte) error { + var v uint32 + if err := json.Unmarshal(b, &v); err != nil { + return err + } + i.Store(v) + return nil +} + +func (i *Uint32) String() string { + v := i.Load() + return strconv.FormatUint(uint64(v), 10) +} + +type Uint64 struct { + atomic.Uint64 +} + +func NewUint64(val uint64) *Uint64 { + i := &Uint64{} + i.Store(val) + return i +} + +func (i *Uint64) MarshalJSON() ([]byte, error) { + return json.Marshal(i.Load()) +} + +func (i *Uint64) UnmarshalJSON(b []byte) error { + var v uint64 + if err := json.Unmarshal(b, &v); err != nil { + return err + } + i.Store(v) + return nil +} + +func (i *Uint64) String() string { + v := i.Load() + return strconv.FormatUint(uint64(v), 10) +} + +type Uintptr struct { + atomic.Uintptr +} + +func NewUintptr(val uintptr) *Uintptr { + i := &Uintptr{} + i.Store(val) + return i +} + +func (i *Uintptr) MarshalJSON() ([]byte, error) { + return json.Marshal(i.Load()) +} + +func (i *Uintptr) UnmarshalJSON(b []byte) error { + var v uintptr + if err := json.Unmarshal(b, &v); err != nil { + return err + } + i.Store(v) + return nil +} + +func (i *Uintptr) String() string { + v := i.Load() + return strconv.FormatUint(uint64(v), 10) +} diff --git a/common/atomic/value.go b/common/atomic/value.go new file mode 100644 index 00000000..ca0eb631 --- /dev/null +++ b/common/atomic/value.go @@ -0,0 +1,58 @@ +package atomic + +import ( + "encoding/json" + "sync/atomic" +) + +func DefaultValue[T any]() T { + var defaultValue T + return defaultValue +} + +type TypedValue[T any] struct { + value atomic.Value +} + +func (t *TypedValue[T]) Load() T { + value := t.value.Load() + if value == nil { + return DefaultValue[T]() + } + return value.(T) +} + +func (t *TypedValue[T]) Store(value T) { + t.value.Store(value) +} + +func (t *TypedValue[T]) Swap(new T) T { + old := t.value.Swap(new) + if old == nil { + return DefaultValue[T]() + } + return old.(T) +} + +func (t *TypedValue[T]) CompareAndSwap(old, new T) bool { + return t.value.CompareAndSwap(old, new) +} + +func (t *TypedValue[T]) MarshalJSON() ([]byte, error) { + return json.Marshal(t.Load()) +} + +func (t *TypedValue[T]) UnmarshalJSON(b []byte) error { + var v T + if err := json.Unmarshal(b, &v); err != nil { + return err + } + t.Store(v) + return nil +} + +func NewTypedValue[T any](t T) *TypedValue[T] { + v := &TypedValue[T]{} + v.Store(t) + return v +} diff --git a/common/observable/observable_test.go b/common/observable/observable_test.go index 5459e0e2..5a02273d 100644 --- a/common/observable/observable_test.go +++ b/common/observable/observable_test.go @@ -5,8 +5,9 @@ import ( "testing" "time" + "github.com/Dreamacro/clash/common/atomic" + "github.com/stretchr/testify/assert" - "go.uber.org/atomic" ) func iterator[T any](item []T) chan T { @@ -44,7 +45,7 @@ func TestObservable_MultiSubscribe(t *testing.T) { wg.Add(2) waitCh := func(ch <-chan int) { for range ch { - count.Inc() + count.Add(1) } wg.Done() } diff --git a/common/singledo/singledo_test.go b/common/singledo/singledo_test.go index 26e3d37d..9e114fb7 100644 --- a/common/singledo/singledo_test.go +++ b/common/singledo/singledo_test.go @@ -5,8 +5,9 @@ import ( "testing" "time" + "github.com/Dreamacro/clash/common/atomic" + "github.com/stretchr/testify/assert" - "go.uber.org/atomic" ) func TestBasic(t *testing.T) { @@ -26,7 +27,7 @@ func TestBasic(t *testing.T) { go func() { _, _, shard := single.Do(call) if shard { - shardCount.Inc() + shardCount.Add(1) } wg.Done() }() diff --git a/component/dialer/options.go b/component/dialer/options.go index 372a2e63..096c7a5c 100644 --- a/component/dialer/options.go +++ b/component/dialer/options.go @@ -4,14 +4,13 @@ import ( "context" "net" + "github.com/Dreamacro/clash/common/atomic" "github.com/Dreamacro/clash/component/resolver" - - "go.uber.org/atomic" ) var ( DefaultOptions []Option - DefaultInterface = atomic.NewString("") + DefaultInterface = atomic.NewTypedValue[string]("") DefaultRoutingMark = atomic.NewInt32(0) ) diff --git a/component/profile/profile.go b/component/profile/profile.go index e3d9e78c..aa6df2f7 100644 --- a/component/profile/profile.go +++ b/component/profile/profile.go @@ -1,7 +1,7 @@ package profile import ( - "go.uber.org/atomic" + "github.com/Dreamacro/clash/common/atomic" ) // StoreSelected is a global switch for storing selected proxy to cache diff --git a/dns/client.go b/dns/client.go index 637207f3..ba83412b 100644 --- a/dns/client.go +++ b/dns/client.go @@ -8,6 +8,7 @@ import ( "net/netip" "strings" + "github.com/Dreamacro/clash/common/atomic" "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/resolver" tlsC "github.com/Dreamacro/clash/component/tls" @@ -15,7 +16,6 @@ import ( D "github.com/miekg/dns" "github.com/zhangyunhao116/fastrand" - "go.uber.org/atomic" ) type client struct { @@ -23,7 +23,7 @@ type client struct { r *Resolver port string host string - iface *atomic.String + iface *atomic.TypedValue[string] proxyAdapter C.ProxyAdapter proxyName string addr string diff --git a/dns/dhcp.go b/dns/dhcp.go index 151e4421..a6c1df76 100644 --- a/dns/dhcp.go +++ b/dns/dhcp.go @@ -8,8 +8,7 @@ import ( "sync" "time" - "go.uber.org/atomic" - + "github.com/Dreamacro/clash/common/atomic" "github.com/Dreamacro/clash/component/dhcp" "github.com/Dreamacro/clash/component/iface" "github.com/Dreamacro/clash/component/resolver" @@ -86,7 +85,7 @@ func (d *dhcpClient) resolve(ctx context.Context) ([]dnsClient, error) { for _, item := range dns { nameserver = append(nameserver, NameServer{ Addr: net.JoinHostPort(item.String(), "53"), - Interface: atomic.NewString(d.ifaceName), + Interface: atomic.NewTypedValue(d.ifaceName), }) } diff --git a/dns/resolver.go b/dns/resolver.go index df8ed3d1..7e1b007d 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -7,8 +7,7 @@ import ( "strings" "time" - "go.uber.org/atomic" - + "github.com/Dreamacro/clash/common/atomic" "github.com/Dreamacro/clash/common/cache" "github.com/Dreamacro/clash/component/fakeip" "github.com/Dreamacro/clash/component/geodata/router" @@ -388,7 +387,7 @@ func (r *Resolver) Invalid() bool { type NameServer struct { Net string Addr string - Interface *atomic.String + Interface *atomic.TypedValue[string] ProxyAdapter C.ProxyAdapter ProxyName string Params map[string]string diff --git a/go.mod b/go.mod index ecc269df..1e3b7a1e 100644 --- a/go.mod +++ b/go.mod @@ -41,7 +41,6 @@ require ( github.com/xtls/go v0.0.0-20220914232946-0441cf4cf837 github.com/zhangyunhao116/fastrand v0.3.0 go.etcd.io/bbolt v1.3.6 - go.uber.org/atomic v1.10.0 go.uber.org/automaxprocs v1.5.2 golang.org/x/crypto v0.8.0 golang.org/x/exp v0.0.0-20230321023759-10a507213a29 @@ -103,5 +102,3 @@ require ( golang.org/x/tools v0.6.0 // indirect gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect ) - -replace go.uber.org/atomic v1.10.0 => github.com/metacubex/uber-atomic v0.0.0-20230202125923-feb10b770370 diff --git a/go.sum b/go.sum index a6a61afd..ec90cb29 100644 --- a/go.sum +++ b/go.sum @@ -102,8 +102,6 @@ github.com/metacubex/sing-tun v0.1.4-0.20230420054006-376d37578990 h1:VpC69WWsOy github.com/metacubex/sing-tun v0.1.4-0.20230420054006-376d37578990/go.mod h1:5CR2e0WQQiLSPd46Qaz3uhDRRik3QvvXiyMvlT3bXoc= github.com/metacubex/sing-wireguard v0.0.0-20230420053659-05c12d25b6eb h1:uoeOqHaQmNPev9RewQlff9Z55yuczEhRizcgDf4lSAw= github.com/metacubex/sing-wireguard v0.0.0-20230420053659-05c12d25b6eb/go.mod h1:Bsw2BvKMMMY0FhZPseDI50ZOalvoUPMKYyGpyqvIIqY= -github.com/metacubex/uber-atomic v0.0.0-20230202125923-feb10b770370 h1:UkViS4DCESAUEYgbIEQdD02hyMacFt6Dny+1MOJtNIo= -github.com/metacubex/uber-atomic v0.0.0-20230202125923-feb10b770370/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= github.com/miekg/dns v1.1.53 h1:ZBkuHr5dxHtB1caEOlZTLPo7D3L3TWckgUUs/RHfDxw= github.com/miekg/dns v1.1.53/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= github.com/mroth/weightedrand/v2 v2.0.0 h1:ADehnByWbliEDIazDAKFdBHoqgHSXAkgyKqM/9YsPoo= diff --git a/transport/gun/gun.go b/transport/gun/gun.go index 0e5d2321..36cf68f8 100644 --- a/transport/gun/gun.go +++ b/transport/gun/gun.go @@ -17,11 +17,11 @@ import ( "sync" "time" + "github.com/Dreamacro/clash/common/atomic" "github.com/Dreamacro/clash/common/buf" "github.com/Dreamacro/clash/common/pool" tlsC "github.com/Dreamacro/clash/component/tls" - "go.uber.org/atomic" "golang.org/x/net/http2" ) diff --git a/tunnel/statistic/manager.go b/tunnel/statistic/manager.go index 66e3857d..381ea7e6 100644 --- a/tunnel/statistic/manager.go +++ b/tunnel/statistic/manager.go @@ -5,8 +5,9 @@ import ( "sync" "time" + "github.com/Dreamacro/clash/common/atomic" + "github.com/shirou/gopsutil/v3/process" - "go.uber.org/atomic" ) var DefaultManager *Manager diff --git a/tunnel/statistic/tracker.go b/tunnel/statistic/tracker.go index 96376eb4..b9682c22 100644 --- a/tunnel/statistic/tracker.go +++ b/tunnel/statistic/tracker.go @@ -4,12 +4,12 @@ import ( "net" "time" + "github.com/Dreamacro/clash/common/atomic" "github.com/Dreamacro/clash/common/buf" "github.com/Dreamacro/clash/common/utils" C "github.com/Dreamacro/clash/constant" "github.com/gofrs/uuid/v5" - "go.uber.org/atomic" ) type tracker interface {