diff --git a/constant/status.go b/constant/status.go deleted file mode 100644 index 4a784bfa..00000000 --- a/constant/status.go +++ /dev/null @@ -1,9 +0,0 @@ -package constant - -type TunnelStatus uint8 - -const ( - TunnelSuspend TunnelStatus = iota - TunnelInner - TunnelRunning -) diff --git a/tunnel/status.go b/tunnel/status.go new file mode 100644 index 00000000..d81dd45e --- /dev/null +++ b/tunnel/status.go @@ -0,0 +1,92 @@ +package tunnel + +import ( + "encoding/json" + "errors" + "strings" + "sync/atomic" +) + +type TunnelStatus int + +// StatusMapping is a mapping for Status enum +var StatusMapping = map[string]TunnelStatus{ + Suspend.String(): Suspend, + Inner.String(): Inner, + Running.String(): Running, +} + +const ( + Suspend TunnelStatus = iota + Inner + Running +) + +// UnmarshalJSON unserialize Status +func (s *TunnelStatus) UnmarshalJSON(data []byte) error { + var tp string + json.Unmarshal(data, &tp) + status, exist := StatusMapping[strings.ToLower(tp)] + if !exist { + return errors.New("invalid mode") + } + *s = status + return nil +} + +// UnmarshalYAML unserialize Status with yaml +func (s *TunnelStatus) UnmarshalYAML(unmarshal func(any) error) error { + var tp string + unmarshal(&tp) + status, exist := StatusMapping[strings.ToLower(tp)] + if !exist { + return errors.New("invalid status") + } + *s = status + return nil +} + +// MarshalJSON serialize Status +func (s TunnelStatus) MarshalJSON() ([]byte, error) { + return json.Marshal(s.String()) +} + +// MarshalYAML serialize TunnelMode with yaml +func (s TunnelStatus) MarshalYAML() (any, error) { + return s.String(), nil +} + +func (s TunnelStatus) String() string { + switch s { + case Suspend: + return "suspend" + case Inner: + return "inner" + case Running: + return "running" + default: + return "Unknown" + } +} + +type AtomicStatus struct { + value atomic.Int32 +} + +func (a *AtomicStatus) Store(s TunnelStatus) { + a.value.Store(int32(s)) +} + +func (a *AtomicStatus) Load() TunnelStatus { + return TunnelStatus(a.value.Load()) +} + +func (a *AtomicStatus) String() string { + return a.Load().String() +} + +func newAtomicStatus(s TunnelStatus) *AtomicStatus { + a := &AtomicStatus{} + a.Store(s) + return a +} diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index 342cdd65..532c9e0e 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -12,7 +12,6 @@ import ( "time" "github.com/jpillora/backoff" - "go.uber.org/atomic" N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/component/nat" @@ -27,7 +26,7 @@ import ( ) var ( - status = atomic.NewInt32(int32(C.TunnelSuspend)) + status = newAtomicStatus(Suspend) tcpQueue = make(chan C.ConnContext, 200) udpQueue = make(chan C.PacketAdapter, 200) natTable = nat.New() @@ -52,18 +51,22 @@ var ( ) func OnSuspend() { - status.Store(int32(C.TunnelSuspend)) + status.Store(Suspend) for _, c := range statistic.DefaultManager.Snapshot().Connections { _ = c.Close() } } func OnInnerLoading() { - status.Store(int32(C.TunnelInner)) + status.Store(Inner) } func OnRunning() { - status.Store(int32(C.TunnelRunning)) + status.Store(Running) +} + +func Status() TunnelStatus { + return status.Load() } func SetFakeIPRange(p netip.Prefix) { @@ -176,8 +179,8 @@ func SetFindProcessMode(mode P.FindProcessMode) { } func isHandle(t C.Type) bool { - status := C.TunnelStatus(status.Load()) - return status == C.TunnelRunning || (status == C.TunnelInner && t == C.INNER) + status := status.Load() + return status == Running || (status == Inner && t == C.INNER) } // processUDP starts a loop to handle udp packet