Xlinka / NeosPlus

NeosVR Plugin Extra Logix nodes and features
https://discord.gg/9QAaMtXwke
Other
29 stars 19 forks source link

UDP in logix #58

Open jeanahelver opened 1 year ago

jeanahelver commented 1 year ago

a node or component similar to websocket but for udp packets

Xlinka commented 1 year ago

any example or just any udp traffic such as just a generic udp client ?

Xlinka commented 10 months ago

since the artnet:// i made is a generic udp client with some filtering so if we reijig that will that be cool ?

Xlinka commented 10 months ago
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
using BaseX;
using FrooxEngine;

[Category("Network")]
public class UdpClient : Component
{
    public readonly Sync<Uri> URL;
    public readonly UserRef HandlingUser;
    public readonly Sync<string> AccessReason;
    public readonly Sync<float> ConnectRetryInterval;
    public readonly Sync<bool> IsConnected;

    private Uri _currentURL;
    private System.Net.Sockets.UdpClient _udpClient;

    public event Action<UdpClient> Connected;
    public event Action<UdpClient> Closed;
    public event Action<UdpClient, string> Error;
    public event Action<UdpClient, byte[]> PacketReceived;

    protected override void OnAwake()
    {
        base.OnAwake();
        ConnectRetryInterval.Value = 10f;
    }

    protected override void OnChanges()
    {
        Uri uri = (Enabled ? URL.Value : null);
        if (HandlingUser.Target != LocalUser)
        {
            uri = null;
        }
        if (uri != _currentURL)
        {
            _currentURL = uri;
            CloseCurrent();
            IsConnected.Value = false;
            if (_currentURL != null)
            {
                StartTask(async () =>
                {
                    await ConnectTo(_currentURL);
                });
            }
        }
    }

    private async Task ConnectTo(Uri target)
    {
        if (target.Scheme != "udp")
        {
            throw new ArgumentException("Invalid URL scheme. Expected 'udp://'.");
        }

        if (await Engine.Security.RequestAccessPermission(target.Host, target.Port, AccessReason.Value ?? "UDP Client") == HostAccessPermission.Allowed && target == _currentURL && !IsRemoved)
        {
            _udpClient = new System.Net.Sockets.UdpClient(target.Port);
            IsConnected.Value = true;
            Connected?.Invoke(this);
            StartTask(ReceiveLoop);
        }
    }

    private async Task ReceiveLoop()
    {
        IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
        while (IsConnected.Value)
        {
            UdpReceiveResult result = await _udpClient.ReceiveAsync();
            byte[] receivedData = result.Buffer;

            PacketReceived?.Invoke(this, receivedData);
        }
    }

    protected override void OnDispose()
    {
        CloseCurrent();
        base.OnDispose();
    }

    private void CloseCurrent()
    {
        if (_udpClient != null)
        {
            System.Net.Sockets.UdpClient udpClient = _udpClient;
            _udpClient = null;
            try
            {
                Closed?.Invoke(this);
            }
            catch (Exception ex)
            {
                UniLog.Error($"Exception in running Closed event on UdpClient:\n{ex}");
            }
            udpClient.Close();
        }
    }
}