Download XrosClient.cs from LoveLogicAI/xros-shell: direct link, hf CLI and curl.
- Browser
- Download file 3.4 kB
-
https://huggingface.co/LoveLogicAI/xros-shell/resolve/main/XrosClient.cs
- Command line
-
hf download hf://LoveLogicAI/xros-shell/XrosClient.cs
-
curl -L -o XrosClient.cs https://huggingface.co/LoveLogicAI/xros-shell/resolve/main/XrosClient.cs
3.4 kB
| // XrosClient.cs — WebSocket client for the XROS spatial-shell backend. | |
| // | |
| // Connects to the Python backend (xros_server.py) and exposes a simple API: | |
| // SendCommand(text) -> run a spatial-shell command, get text output back | |
| // Send(msg) -> send an arbitrary JSON message | |
| // OnMessage -> event fired for every JSON message from the server | |
| // | |
| // Threading: the receive loop runs on a background task and pushes parsed | |
| // messages into a thread-safe queue; Update() drains it on the main thread so | |
| // Unity API calls (spawning GameObjects, updating UI) are always safe. | |
| // | |
| // Dependencies: Newtonsoft.Json (com.unity.nuget.newtonsoft-json in the | |
| // Package Manager). No other packages required. | |
| using System; | |
| using System.Collections.Concurrent; | |
| using System.Net.WebSockets; | |
| using System.Text; | |
| using System.Threading; | |
| using System.Threading.Tasks; | |
| using Newtonsoft.Json.Linq; | |
| using UnityEngine; | |
| public class XrosClient : MonoBehaviour | |
| { | |
| [] | |
| public string serverUrl = "ws://192.168.1.50:8765"; | |
| public event Action<JObject> OnMessage; | |
| private ClientWebSocket ws; | |
| private CancellationTokenSource cts; | |
| private readonly ConcurrentQueue<JObject> incoming = new ConcurrentQueue<JObject>(); | |
| public bool IsConnected => ws != null && ws.State == WebSocketState.Open; | |
| public async void Connect() | |
| { | |
| cts = new CancellationTokenSource(); | |
| ws = new ClientWebSocket(); | |
| try | |
| { | |
| await ws.ConnectAsync(new Uri(serverUrl), cts.Token); | |
| Debug.Log($"[XrosClient] connected to {serverUrl}"); | |
| _ = ReceiveLoop(); | |
| } | |
| catch (Exception e) | |
| { | |
| Debug.LogError($"[XrosClient] connect failed: {e.Message}"); | |
| } | |
| } | |
| public async void SendCommand(string text) | |
| { | |
| await Send(new JObject { ["op"] = "command", ["text"] = text }); | |
| } | |
| public async Task Send(JObject msg) | |
| { | |
| if (!IsConnected) { Debug.LogWarning("[XrosClient] not connected"); return; } | |
| var bytes = Encoding.UTF8.GetBytes(msg.ToString(Newtonsoft.Json.Formatting.None)); | |
| await ws.SendAsync(new ArraySegment<byte>(bytes), WebSocketMessageType.Text, true, cts.Token); | |
| } | |
| private async Task ReceiveLoop() | |
| { | |
| var buffer = new byte[8192]; | |
| var sb = new StringBuilder(); | |
| try | |
| { | |
| while (ws.State == WebSocketState.Open) | |
| { | |
| sb.Clear(); | |
| WebSocketReceiveResult result; | |
| do | |
| { | |
| result = await ws.ReceiveAsync(new ArraySegment<byte>(buffer), cts.Token); | |
| sb.Append(Encoding.UTF8.GetString(buffer, 0, result.Count)); | |
| } while (!result.EndOfMessage); | |
| if (result.MessageType == WebSocketMessageType.Text) | |
| { | |
| incoming.Enqueue(JObject.Parse(sb.ToString())); | |
| } | |
| } | |
| } | |
| catch (Exception e) | |
| { | |
| Debug.Log($"[XrosClient] receive loop ended: {e.Message}"); | |
| } | |
| } | |
| private void Update() | |
| { | |
| while (incoming.TryDequeue(out var msg)) | |
| { | |
| OnMessage?.Invoke(msg); | |
| } | |
| } | |
| private void OnDestroy() | |
| { | |
| cts?.Cancel(); | |
| ws?.Dispose(); | |
| } | |
| } | |