From 9436956e2a291a686a30ac721cd2c0fe1bb9c3e8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=A3=8E=E6=89=87=E6=BB=91=E7=BF=94=E7=BF=BC?=
 <Fangliding.fshxy@outlook.com>
Date: Fri, 13 Jun 2025 08:30:58 +0000
Subject: [PATCH] Add and use new TypedSyncMap

---
 common/utils/TypedSyncMap.go | 59 ++++++++++++++++++++++++++++++++++++
 proxy/freedom/freedom.go     |  9 +++---
 2 files changed, 64 insertions(+), 4 deletions(-)
 create mode 100644 common/utils/TypedSyncMap.go

diff --git a/common/utils/TypedSyncMap.go b/common/utils/TypedSyncMap.go
new file mode 100644
index 00000000..7512c0fb
--- /dev/null
+++ b/common/utils/TypedSyncMap.go
@@ -0,0 +1,59 @@
+package util
+
+import (
+	"sync"
+)
+
+// TypedSyncMap is a wrapper of sync.Map that provides type-safe for keys and values.
+// No need to use type assertions every time, so you can have more time to enjoy other things like GochiUsa
+type TypedSyncMap[K, V any] struct {
+	syncMap *sync.Map
+}
+
+func NewTypedSyncMap[K any, V any]() *TypedSyncMap[K, V] {
+	return &TypedSyncMap[K, V]{
+		syncMap: &sync.Map{},
+	}
+}
+
+func (m *TypedSyncMap[K, V]) Clear() {
+	m.syncMap.Clear()
+}
+
+func (m *TypedSyncMap[K, V]) CompareAndDelete(key K, old V) (deleted bool) {
+	return m.syncMap.CompareAndDelete(key, old)
+}
+
+func (m *TypedSyncMap[K, V]) CompareAndSwap(key K, old V, new V) (swapped bool) {
+	return m.syncMap.CompareAndSwap(key, old, new)
+}
+
+func (m *TypedSyncMap[K, V]) Delete(key K) {
+	m.syncMap.Delete(key)
+}
+
+func (m *TypedSyncMap[K, V]) Load(key K) (value V, ok bool) {
+	anyValue, ok := m.syncMap.Load(key)
+	return anyValue.(V), ok
+}
+
+func (m *TypedSyncMap[K, V]) LoadAndDelete(key K) (value V, loaded bool) {
+	anyValue, loaded := m.syncMap.LoadAndDelete(key)
+	return anyValue.(V), loaded
+}
+func (m *TypedSyncMap[K, V]) LoadOrStore(key K, value V) (actual V, loaded bool) {
+	anyActual, loaded := m.syncMap.LoadOrStore(key, value)
+	return anyActual.(V), loaded
+}
+func (m *TypedSyncMap[K, V]) Range(f func(key K, value V) bool) {
+	m.syncMap.Range(func(key, value any) bool {
+		return f(key.(K), value.(V))
+	})
+}
+func (m *TypedSyncMap[K, V]) Store(key K, value V) {
+	m.syncMap.Store(key, value)
+}
+func (m *TypedSyncMap[K, V]) Swap(key K, value V) (previous V, loaded bool) {
+	anyPrevious, loaded := m.syncMap.Swap(key, value)
+	return anyPrevious.(V), loaded
+}
\ No newline at end of file
diff --git a/proxy/freedom/freedom.go b/proxy/freedom/freedom.go
index 0399c3d1..e4f49d9d 100644
--- a/proxy/freedom/freedom.go
+++ b/proxy/freedom/freedom.go
@@ -27,6 +27,7 @@ import (
 	"github.com/xtls/xray-core/transport/internet"
 	"github.com/xtls/xray-core/transport/internet/stat"
 	"github.com/xtls/xray-core/transport/internet/tls"
+	"github.com/xtls/xray-core/common/utils"
 )
 
 var useSplice bool
@@ -343,7 +344,7 @@ func NewPacketWriter(conn net.Conn, h *Handler, ctx context.Context, UDPOverride
 			Handler:           h,
 			Context:           ctx,
 			UDPOverride:       UDPOverride,
-			resolvedUDPAddr:   resolvedUDPAddr,
+			resolvedUDPAddr:   util.NewTypedSyncMap[string, net.Address](),
 		}
 
 	}
@@ -361,7 +362,7 @@ type PacketWriter struct {
 	// But resolver will return a random one if the domain has many IPs
 	// Resulting in these packets being sent to many different IPs randomly
 	// So, cache and keep the resolve result
-	resolvedUDPAddr map[string]net.Address
+	resolvedUDPAddr *util.TypedSyncMap[string, net.Address]
 }
 
 func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
@@ -381,13 +382,13 @@ func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
 				b.UDP.Port = w.UDPOverride.Port
 			}
 			if w.Handler.config.hasStrategy() && b.UDP.Address.Family().IsDomain() {
-				if ip := w.resolvedUDPAddr[b.UDP.Address.Domain()]; ip != nil {
+				if ip, ok := w.resolvedUDPAddr.Load(b.UDP.Address.Domain()); ok {
 					b.UDP.Address = ip
 				} else {
 					ip := w.Handler.resolveIP(w.Context, b.UDP.Address.Domain(), nil)
 					if ip != nil {
 						b.UDP.Address = ip
-						w.resolvedUDPAddr[b.UDP.Address.Domain()] = ip
+						w.resolvedUDPAddr.Store(b.UDP.Address.Domain(), ip)
 					}
 				}
 			}