public XrcServer(CompositorBehavior behavior) { Listener = TcpListener.Create(31337); Listener.Start(); var broadcastTimer = new Timer { AutoReset = true, Interval = 100 }; var broadcastClient = new UdpClient { EnableBroadcast = true }; var ep = new IPEndPoint(IPAddress.Broadcast, 31337); var nameBytes = Encoding.UTF8.GetBytes("My XrCompositor"); var packet = new byte[6 + nameBytes.Length]; Array.Copy(BitConverter.GetBytes((ushort)31337), 0, packet, 0, 2); Array.Copy(BitConverter.GetBytes((uint)nameBytes.Length), 0, packet, 2, 4); Array.Copy(nameBytes, 0, packet, 6, nameBytes.Length); broadcastTimer.Elapsed += (_, __) => { if (!Alive) { broadcastTimer.Stop(); } else { broadcastClient.Send(packet, packet.Length, ep); } }; broadcastTimer.Start(); new Thread(() => { while (Alive) { if (Listener.Pending()) { Clients.Add(new XrcClient(Listener.AcceptSocket(), behavior)); } else { Thread.Sleep(50); } } }).Start(); }
public UnityCompositor(CompositorBehavior behavior) => Behavior = behavior;
public XrcClient(Socket socket, CompositorBehavior behavior) { Socket = socket; Behavior = behavior; var pingCount = 0; var pingTimer = new Timer { AutoReset = true, Interval = 5000 }; pingTimer.Elapsed += (_, __) => { lock (this) { if (pingCount >= 12 || !Alive) { // Client timed out Alive = false; pingTimer.Stop(); return; } pingCount++; Send(1); } }; pingTimer.Start(); new Thread(() => { var minibuf = new byte[128]; while (Alive) { try { var off = 0; while (off < 8) { off += socket.Receive(minibuf, off, 8 - off, SocketFlags.None); } var len = BitConverter.ToInt32(minibuf, 0); Debug.Assert(len >= 0); var opcode = BitConverter.ToUInt32(minibuf, 4); Behavior.Log($"Got message with opcode {opcode} and length {len}"); byte[] data = null; if (len > 128) { data = new byte[len]; } else if (len > 0) { data = minibuf; } if (data != null) { off = 0; while (off < len) { off += socket.Receive(data, off, len - off, SocketFlags.None); } } // Reset ping timer pingTimer.Stop(); pingTimer.Start(); switch (opcode) { case 1: // Ping Send(2); break; case 2: // Pong pingCount--; break; case 1001: { // Run script Behavior.Log("Attempting to run script..."); var code = Encoding.UTF8.GetString(data, 0, len); Behavior.Log($"Running script: {code.ToPrettyString()}"); Behavior.JobQueue.Enqueue(() => Behavior.RunScriptCode(code)); break; } case 1002: { // Load script var fnlen = BitConverter.ToInt32(data, 0); var fn = Encoding.UTF8.GetString(data, 4, fnlen); Behavior.JobQueue.Enqueue(() => { var path = Path.Combine(Application.persistentDataPath, fn); Behavior.Log($"Writing script to {path.ToPrettyString()}"); try { File.Delete(path); } catch (Exception) { } using (var fp = File.OpenWrite(path)) fp.Write(data, 4 + fnlen, len - 4 - fnlen); Behavior.LoadScript(path); }); break; } case 1004: // Request logs Behavior.LogMessage += (isError, message) => Send(2001, new[] { (byte)(isError ? 1 : 0) }.Concat(Encoding.UTF8.GetBytes(message)) .ToArray()); break; default: Behavior.Log($"Got message with unknown opcode {opcode} and length {len}"); break; } } catch (Exception e) { Alive = false; Behavior.Log(e.ToString()); break; } } }).Start(); }