274 lines
7.8 KiB
C#
274 lines
7.8 KiB
C#
using UnityEngine;
|
|
using UnityEngine.Events;
|
|
using System;
|
|
using System.Collections;
|
|
using System.Text;
|
|
using System.Net.WebSockets;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
[System.Serializable]
|
|
public class StreamDockEvent : UnityEvent<string, object> { }
|
|
|
|
public class SimpleStreamDockCommunicator : MonoBehaviour
|
|
{
|
|
[Header("연결 설정")]
|
|
[SerializeField] private string serverUrl = "ws://localhost:15732";
|
|
[SerializeField] private bool autoConnect = true;
|
|
[SerializeField] private float reconnectInterval = 5f;
|
|
|
|
[Header("이벤트")]
|
|
public StreamDockEvent OnStreamDockMessageReceived;
|
|
public UnityEvent OnConnected;
|
|
public UnityEvent OnDisconnected;
|
|
|
|
// 내부 변수
|
|
private ClientWebSocket webSocket;
|
|
private CancellationTokenSource cancellationTokenSource;
|
|
private bool isConnecting = false;
|
|
private bool isConnected = false;
|
|
|
|
// 프로퍼티
|
|
public bool IsConnected => isConnected;
|
|
|
|
void Start()
|
|
{
|
|
if (autoConnect)
|
|
{
|
|
ConnectToStreamDock();
|
|
}
|
|
}
|
|
|
|
void OnDestroy()
|
|
{
|
|
DisconnectFromStreamDock();
|
|
}
|
|
|
|
/// <summary>
|
|
/// StreamDock에 연결
|
|
/// </summary>
|
|
public async void ConnectToStreamDock()
|
|
{
|
|
if (isConnecting || isConnected) return;
|
|
|
|
isConnecting = true;
|
|
|
|
try
|
|
{
|
|
webSocket = new ClientWebSocket();
|
|
cancellationTokenSource = new CancellationTokenSource();
|
|
|
|
Debug.Log($"StreamDock에 연결 중... {serverUrl}");
|
|
|
|
await webSocket.ConnectAsync(new Uri(serverUrl), cancellationTokenSource.Token);
|
|
|
|
isConnected = true;
|
|
isConnecting = false;
|
|
|
|
Debug.Log("StreamDock에 연결되었습니다!");
|
|
OnConnected?.Invoke();
|
|
|
|
// 메시지 수신 시작
|
|
_ = ReceiveMessages();
|
|
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.LogError($"StreamDock 연결 실패: {e.Message}");
|
|
isConnecting = false;
|
|
OnDisconnected?.Invoke();
|
|
|
|
// 재연결 시도
|
|
StartCoroutine(TryReconnect());
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// StreamDock 연결 해제
|
|
/// </summary>
|
|
public async void DisconnectFromStreamDock()
|
|
{
|
|
if (!isConnected) return;
|
|
|
|
try
|
|
{
|
|
cancellationTokenSource?.Cancel();
|
|
|
|
if (webSocket != null && webSocket.State == WebSocketState.Open)
|
|
{
|
|
await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Unity 종료", CancellationToken.None);
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.LogError($"연결 해제 중 오류: {e.Message}");
|
|
}
|
|
finally
|
|
{
|
|
isConnected = false;
|
|
webSocket?.Dispose();
|
|
webSocket = null;
|
|
OnDisconnected?.Invoke();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// StreamDock으로 메시지 전송
|
|
/// </summary>
|
|
public async void SendMessageToStreamDock(string eventType, object data = null)
|
|
{
|
|
if (!isConnected)
|
|
{
|
|
Debug.LogWarning("StreamDock에 연결되지 않았습니다.");
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
var message = new
|
|
{
|
|
type = eventType,
|
|
data = data,
|
|
timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
|
|
};
|
|
|
|
string jsonMessage = JsonUtility.ToJson(message);
|
|
byte[] buffer = Encoding.UTF8.GetBytes(jsonMessage);
|
|
|
|
await webSocket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, cancellationTokenSource.Token);
|
|
|
|
Debug.Log($"StreamDock으로 메시지 전송: {eventType}");
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.LogError($"메시지 전송 실패: {e.Message}");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 메시지 수신 처리
|
|
/// </summary>
|
|
private async Task ReceiveMessages()
|
|
{
|
|
var buffer = new byte[4096];
|
|
|
|
try
|
|
{
|
|
while (webSocket.State == WebSocketState.Open)
|
|
{
|
|
var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), cancellationTokenSource.Token);
|
|
|
|
if (result.MessageType == WebSocketMessageType.Text)
|
|
{
|
|
string message = Encoding.UTF8.GetString(buffer, 0, result.Count);
|
|
ProcessReceivedMessage(message);
|
|
}
|
|
else if (result.MessageType == WebSocketMessageType.Close)
|
|
{
|
|
Debug.Log("StreamDock에서 연결을 종료했습니다.");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.LogError($"메시지 수신 중 오류: {e.Message}");
|
|
}
|
|
finally
|
|
{
|
|
isConnected = false;
|
|
OnDisconnected?.Invoke();
|
|
StartCoroutine(TryReconnect());
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 수신된 메시지 처리
|
|
/// </summary>
|
|
private void ProcessReceivedMessage(string message)
|
|
{
|
|
try
|
|
{
|
|
//Debug.Log($"StreamDock에서 메시지 수신: {message}");
|
|
|
|
// JSON 파싱 (간단한 구조)
|
|
if (message.Contains("type"))
|
|
{
|
|
// UnityEvent 호출
|
|
OnStreamDockMessageReceived?.Invoke("streamdock_message", message);
|
|
|
|
// 특정 이벤트 타입 처리
|
|
if (message.Contains("streamdock_button_clicked"))
|
|
{
|
|
HandleButtonClick(message);
|
|
}
|
|
else if (message.Contains("dial_rotate"))
|
|
{
|
|
HandleDialRotate(message);
|
|
}
|
|
else if (message.Contains("dial_press"))
|
|
{
|
|
HandleDialPress(message);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.LogError($"메시지 처리 중 오류: {e.Message}");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 버튼 클릭 이벤트 처리
|
|
/// </summary>
|
|
private void HandleButtonClick(string message)
|
|
{
|
|
Debug.Log("StreamDock 버튼이 클릭되었습니다!");
|
|
OnStreamDockMessageReceived?.Invoke("button_clicked", message);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 다이얼 회전 이벤트 처리
|
|
/// </summary>
|
|
private void HandleDialRotate(string message)
|
|
{
|
|
Debug.Log("StreamDock 다이얼이 회전했습니다!");
|
|
OnStreamDockMessageReceived?.Invoke("dial_rotate", message);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 다이얼 누름 이벤트 처리
|
|
/// </summary>
|
|
private void HandleDialPress(string message)
|
|
{
|
|
Debug.Log("StreamDock 다이얼이 눌렸습니다!");
|
|
OnStreamDockMessageReceived?.Invoke("dial_press", message);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 재연결 시도
|
|
/// </summary>
|
|
private IEnumerator TryReconnect()
|
|
{
|
|
yield return new WaitForSeconds(reconnectInterval);
|
|
|
|
if (!isConnected && !isConnecting)
|
|
{
|
|
Debug.Log("StreamDock 재연결 시도...");
|
|
ConnectToStreamDock();
|
|
}
|
|
}
|
|
|
|
// 테스트용 메서드들
|
|
[ContextMenu("테스트 메시지 전송")]
|
|
public void SendTestMessage()
|
|
{
|
|
SendMessageToStreamDock("test_message", new { message = "Unity에서 테스트 메시지" });
|
|
}
|
|
|
|
[ContextMenu("커스텀 이벤트 전송")]
|
|
public void SendCustomEvent()
|
|
{
|
|
SendMessageToStreamDock("custom_event", new { action = "test_action", value = 123 });
|
|
}
|
|
} |