22using System . Threading ;
33using UnityEngine ;
44using Cysharp . Threading . Tasks ;
5- using UnityEngine . Networking ;
5+ using NativeWebSocket ;
66
77namespace ProjectVG . Infrastructure . Network . WebSocket . Platforms
88{
99 /// <summary>
1010 /// WebGL 플랫폼용 WebSocket 구현체
11- /// UnityWebRequest.WebSocket을 사용합니다.
11+ /// NativeWebSocket 패키지를 사용합니다.
1212 /// </summary>
1313 public class WebGLWebSocket : INativeWebSocket
1414 {
15- public bool IsConnected { get ; private set ; }
16- public bool IsConnecting { get ; private set ; }
15+ public bool IsConnected => _webSocket ? . State == WebSocketState . Open ;
16+ public bool IsConnecting => _webSocket ? . State == WebSocketState . Connecting ;
1717
1818 public event Action OnConnected ;
1919 public event Action OnDisconnected ;
2020 public event Action < string > OnError ;
21- #pragma warning disable CS0067
2221 public event Action < string > OnMessageReceived ;
23- #pragma warning restore CS0067
2422
25- private UnityWebRequest _webRequest ;
23+ private NativeWebSocket . WebSocket _webSocket ;
2624 private CancellationTokenSource _cancellationTokenSource ;
2725 private bool _isDisposed = false ;
2826
@@ -38,42 +36,36 @@ public async UniTask<bool> ConnectAsync(string url, CancellationToken cancellati
3836 return IsConnected ;
3937 }
4038
41- IsConnecting = true ;
39+ if ( _isDisposed )
40+ {
41+ Debug . LogError ( "[WebGL WebSocket] Cannot connect: WebSocket is disposed" ) ;
42+ return false ;
43+ }
4244
4345 try
4446 {
45- var combinedCancellationToken = CancellationTokenSource . CreateLinkedTokenSource ( cancellationToken , _cancellationTokenSource . Token ) . Token ;
46-
47- // UnityWebRequest.WebSocket 사용
48- _webRequest = UnityWebRequest . Get ( url ) ;
49- _webRequest . SetRequestHeader ( "Upgrade" , "websocket" ) ;
50- _webRequest . SetRequestHeader ( "Connection" , "Upgrade" ) ;
51-
52- var operation = _webRequest . SendWebRequest ( ) ;
53- await operation . WithCancellation ( combinedCancellationToken ) ;
47+ var wsUrl = url . Replace ( "http://" , "ws://" ) . Replace ( "https://" , "wss://" ) ;
48+ Debug . Log ( $ "[WebGL WebSocket] 연결 시도: { wsUrl } ") ;
5449
55- if ( _webRequest . result == UnityWebRequest . Result . Success )
56- {
57- IsConnected = true ;
58- IsConnecting = false ;
59- OnConnected ? . Invoke ( ) ;
60-
61- // 메시지 수신 루프 시작
62- _ = ReceiveLoopAsync ( ) ;
63-
64- return true ;
65- }
66- else
67- {
68- var error = $ "WebGL WebSocket 연결 실패: { _webRequest . error } ";
69- Debug . LogError ( error ) ;
70- OnError ? . Invoke ( error ) ;
71- return false ;
72- }
50+ _webSocket = new NativeWebSocket . WebSocket ( wsUrl ) ;
51+
52+ _webSocket . OnOpen += OnNativeConnected ;
53+ _webSocket . OnMessage += OnNativeMessageReceived ;
54+ _webSocket . OnError += OnNativeError ;
55+ _webSocket . OnClose += OnNativeDisconnected ;
56+
57+ await _webSocket . Connect ( ) ;
58+
59+ Debug . Log ( "[WebGL WebSocket] 연결 성공" ) ;
60+ return true ;
61+ }
62+ catch ( OperationCanceledException )
63+ {
64+ Debug . Log ( "[WebGL WebSocket] 연결이 취소되었습니다." ) ;
65+ return false ;
7366 }
7467 catch ( Exception ex )
7568 {
76- IsConnecting = false ;
7769 var error = $ "WebGL WebSocket 연결 중 예외 발생: { ex . Message } ";
7870 Debug . LogError ( error ) ;
7971 OnError ? . Invoke ( error ) ;
@@ -83,88 +75,136 @@ public async UniTask<bool> ConnectAsync(string url, CancellationToken cancellati
8375
8476 public async UniTask DisconnectAsync ( )
8577 {
86- if ( ! IsConnected )
78+ if ( ! IsConnected && ! IsConnecting )
8779 {
8880 return ;
8981 }
9082
9183 try
9284 {
93- IsConnected = false ;
94- IsConnecting = false ;
95-
96- _webRequest ? . Abort ( ) ;
97- _webRequest ? . Dispose ( ) ;
98- _webRequest = null ;
99-
100- await UniTask . CompletedTask ; // 비동기 작업 시뮬레이션
85+ if ( _webSocket != null && _webSocket . State == WebSocketState . Open )
86+ {
87+ await _webSocket . Close ( ) ;
88+ }
10189
102- OnDisconnected ? . Invoke ( ) ;
90+ Debug . Log ( "[WebGL WebSocket] 연결 해제됨" ) ;
10391 }
10492 catch ( Exception ex )
10593 {
106- Debug . LogError ( $ "WebGL WebSocket 연결 해제 중 오류: { ex . Message } ") ;
94+ Debug . LogError ( $ "[ WebGL WebSocket] 연결 해제 중 오류: { ex . Message } ") ;
10795 }
10896 }
10997
11098 public async UniTask < bool > SendMessageAsync ( string message , CancellationToken cancellationToken = default )
11199 {
112100 if ( ! IsConnected )
113101 {
114- Debug . LogWarning ( "WebGL WebSocket이 연결되지 않았습니다." ) ;
102+ Debug . LogWarning ( "[WebGL WebSocket] 연결되지 않은 상태에서 메시지 전송 시도" ) ;
103+ return false ;
104+ }
105+
106+ if ( _isDisposed )
107+ {
108+ Debug . LogError ( "[WebGL WebSocket] WebSocket이 해제된 상태입니다." ) ;
115109 return false ;
116110 }
117111
118112 try
119113 {
120- // TODO : WebGL에서는 WebSocket 메시지 전송을 위한 별도 구현 필요
121- await UniTask . CompletedTask ;
122- return true ;
114+ if ( _webSocket != null && _webSocket . State == WebSocketState . Open )
115+ {
116+ await _webSocket . SendText ( message ) ;
117+ Debug . Log ( $ "[WebGL WebSocket] 메시지 전송 성공: { message . Substring ( 0 , Math . Min ( message . Length , 50 ) ) } ...") ;
118+ return true ;
119+ }
120+ else
121+ {
122+ Debug . LogWarning ( "[WebGL WebSocket] WebSocket이 연결되지 않았습니다." ) ;
123+ return false ;
124+ }
123125 }
124126 catch ( Exception ex )
125127 {
126- Debug . LogError ( $ "WebGL WebSocket 메시지 전송 실패: { ex . Message } ") ;
128+ Debug . LogError ( $ "[ WebGL WebSocket] 메시지 전송 실패: { ex . Message } ") ;
127129 return false ;
128130 }
129131 }
130132
131- private async UniTask ReceiveLoopAsync ( )
133+ private void OnNativeConnected ( )
132134 {
135+ if ( _isDisposed ) return ;
136+
137+ Debug . Log ( $ "[WebGL WebSocket] 연결 성공! Platform: { Application . platform } , IsWebGL: { Application . platform == RuntimePlatform . WebGLPlayer } ") ;
138+ OnConnected ? . Invoke ( ) ;
139+ }
140+
141+ private void OnNativeMessageReceived ( byte [ ] data )
142+ {
143+ if ( _isDisposed ) return ;
144+
133145 try
134146 {
135- while ( IsConnected && ! _isDisposed )
136- {
137- // TODO : WebGL에서는 WebSocket 메시지 수신을 위한 별도 구현 필요
138- await UniTask . Delay ( 100 ) ;
139- }
147+ var message = System . Text . Encoding . UTF8 . GetString ( data ) ;
148+ Debug . Log ( $ "[WebGL WebSocket] 메시지 수신! Platform: { Application . platform } " ) ;
149+ Debug . Log ( $ "[WebGL WebSocket] 데이터 크기: { data . Length } bytes" ) ;
150+ Debug . Log ( $ "[WebGL WebSocket] 메시지 내용: { message . Substring ( 0 , Math . Min ( message . Length , 200 ) ) } ..." ) ;
151+ OnMessageReceived ? . Invoke ( message ) ;
140152 }
141153 catch ( Exception ex )
142154 {
143- if ( ! _isDisposed )
144- {
145- Debug . LogError ( $ "WebGL WebSocket 수신 루프 오류: { ex . Message } ") ;
146- OnError ? . Invoke ( ex . Message ) ;
147- }
148- }
149- finally
150- {
151- IsConnected = false ;
152- if ( ! _isDisposed )
153- {
154- OnDisconnected ? . Invoke ( ) ;
155- }
155+ Debug . LogError ( $ "[WebGL WebSocket] 메시지 처리 중 오류: { ex . Message } ") ;
156156 }
157157 }
158158
159+ private void OnNativeError ( string error )
160+ {
161+ if ( _isDisposed ) return ;
162+
163+ Debug . LogError ( $ "[WebGL WebSocket] 오류 발생: { error } ") ;
164+ OnError ? . Invoke ( error ) ;
165+ }
166+
167+ private void OnNativeDisconnected ( WebSocketCloseCode closeCode )
168+ {
169+ if ( _isDisposed ) return ;
170+
171+ Debug . Log ( $ "[WebGL WebSocket] 연결 해제됨 - Code: { closeCode } ") ;
172+ OnDisconnected ? . Invoke ( ) ;
173+ }
174+
175+ public void DispatchMessageQueue ( )
176+ {
177+ #if ! UNITY_WEBGL || UNITY_EDITOR
178+ _webSocket ? . DispatchMessageQueue ( ) ;
179+ Debug . Log ( $ "[WebGL WebSocket] DispatchMessageQueue 호출됨 - Platform: { Application . platform } ") ;
180+ #else
181+ Debug . Log ( $ "[WebGL WebSocket] WebGL에서는 DispatchMessageQueue 생략 - Platform: { Application . platform } ") ;
182+ #endif
183+ }
184+
159185 public void Dispose ( )
160186 {
161187 if ( _isDisposed )
162188 return ;
163189
164190 _isDisposed = true ;
191+
192+ if ( _webSocket != null )
193+ {
194+ _webSocket . OnOpen -= OnNativeConnected ;
195+ _webSocket . OnMessage -= OnNativeMessageReceived ;
196+ _webSocket . OnError -= OnNativeError ;
197+ _webSocket . OnClose -= OnNativeDisconnected ;
198+
199+ if ( _webSocket . State == WebSocketState . Open )
200+ {
201+ _webSocket . Close ( ) ;
202+ }
203+ _webSocket = null ;
204+ }
205+
165206 _cancellationTokenSource ? . Cancel ( ) ;
166207 _cancellationTokenSource ? . Dispose ( ) ;
167- _webRequest ? . Dispose ( ) ;
168208 }
169209 }
170210}
0 commit comments