diff --git a/ArtNetSharp/ArtNetSharp.csproj b/ArtNetSharp/ArtNetSharp.csproj index ffd5ef6..7d9c985 100644 --- a/ArtNetSharp/ArtNetSharp.csproj +++ b/ArtNetSharp/ArtNetSharp.csproj @@ -2,7 +2,7 @@ netstandard2.0;net6.0;net7.0;net8.0 LICENSE - 0.0.28 + 0.0.29 https://github.com/DMXControl/ArtNetSharp $(RepositoryUrl) RDM; ArtNet; E1.20; E1.33; E1.37-1; E1.37-2; E1.37-7 diff --git a/ArtNetSharp/Communication/AbstractInstance.cs b/ArtNetSharp/Communication/AbstractInstance.cs index ae6922f..96a2e24 100644 --- a/ArtNetSharp/Communication/AbstractInstance.cs +++ b/ArtNetSharp/Communication/AbstractInstance.cs @@ -252,9 +252,9 @@ public void Dispose() public event EventHandler ResponderRDMMessageReceived; public event EventHandler ControllerRDMMessageReceived; - private static readonly SendPollThreadBag sendPollThreadBag = new SendPollThreadBag(); + internal static readonly SendPollThreadBag sendPollThreadBag = new SendPollThreadBag(); - private class SendPollThreadBag + internal class SendPollThreadBag { private readonly Thread sendPollThread; public EventHandler SendArtPollEvent; @@ -826,23 +826,6 @@ void add(RemoteClient rc) } } catch (Exception ex) { Logger.LogError(ex); } - - var timoutedClients = RemoteClients.Where(p => p.Timouted()); - if (timoutedClients.Count() != 0) - { - timoutedClients = timoutedClients.ToList(); - foreach (var rc in timoutedClients) - { - - if (remoteClients.TryRemove(rc.ID, out RemoteClient removed)) - remoteClientsTimeouted.TryAdd(removed.ID, removed); - if (removed != null) - { - Logger.LogInformation($"Timeout: {removed.ID} ({(DateTime.UtcNow - rc.LastSeen).TotalMilliseconds}ms)"); - Task.Run(() => RemoteClientTimedOut?.InvokeFailSafe(this, removed)); - } - } - } RemoteClients = remoteClients.Select(p => p.Value).ToList().AsReadOnly(); } private void processArtDMX(ArtDMX artDMX, IPv4Address sourceIp) @@ -1281,6 +1264,28 @@ private async void TimerSendPoll_Elapsed(object sender, EventArgs e) return; await triggerSendArtPoll(); + await Task.Delay(3000); + + var timoutedClients = remoteClients.Where(p => p.Value.Timouted()); + if (timoutedClients.Count() != 0) + { + timoutedClients = timoutedClients.ToList(); + foreach (var rc in timoutedClients) + { + + if (remoteClients.TryRemove(rc.Key, out RemoteClient removed)) + remoteClientsTimeouted.TryAdd(removed.ID, removed); + else + Logger.LogWarning($"Can't remove RemoteClient from ConcurrentDictionary"); + + if (removed != null) + { + Logger.LogInformation($"Timeout: {removed.ID} ({(DateTime.UtcNow - rc.Value.LastSeen).TotalMilliseconds}ms)"); + _ = Task.Run(() => RemoteClientTimedOut?.InvokeFailSafe(this, removed)); + } + } + } + RemoteClients = remoteClients.Select(p => p.Value).ToList().AsReadOnly(); } void IDisposable.Dispose() diff --git a/ArtNetSharp/Communication/RemoteClient.cs b/ArtNetSharp/Communication/RemoteClient.cs index c714b35..0bef00b 100644 --- a/ArtNetSharp/Communication/RemoteClient.cs +++ b/ArtNetSharp/Communication/RemoteClient.cs @@ -82,7 +82,7 @@ private set } internal bool Timouted() // Spec 1.4dd page 12, doubled to allow one lost reply (6s is allowad, for some delay i add 2500 ms) { - var now = DateTime.UtcNow.AddSeconds(-9.5); + var now = DateTime.UtcNow.AddSeconds(-3); return LastSeen <= now; } @@ -258,6 +258,7 @@ internal AbstractInstance Instance public RemoteClient(in ArtPollReply artPollReply) { + AbstractInstance.sendPollThreadBag.SendArtPollEvent += OnSendArtPoll; seen(); ID = getIDOf(artPollReply); MacAddress = artPollReply.MAC; @@ -266,6 +267,23 @@ public RemoteClient(in ArtPollReply artPollReply) processArtPollReply(artPollReply); seen(); } + private async void OnSendArtPoll(object sender, EventArgs e) + { + await Task.Delay(3000); + + var timoutedPorts = ports.Where(p => p.Value.Timouted()); + if (timoutedPorts.Count() != 0) + { + timoutedPorts = timoutedPorts.ToList(); + foreach (var port in timoutedPorts) + { + if (!ports.TryRemove(port.Key, out _)) + Logger.LogWarning($"Can't remove RemoteClientPort from ConcurrentDictionary"); + _ = Task.Run(() => PortTimedOut?.InvokeFailSafe(this, port)); + } + } + Ports = ports.Select(p => p.Value).ToList().AsReadOnly(); + } private void seen() { LastSeen = DateTime.UtcNow; @@ -288,6 +306,7 @@ public void processArtPollReply(ArtPollReply artPollReply) return; seen(); + List tasks = new List(); try { for (byte portIndex = 0; portIndex < artPollReply.Ports; portIndex++) @@ -300,7 +319,7 @@ public void processArtPollReply(ArtPollReply artPollReply) port = new RemoteClientPort(artPollReply, portIndex); if (ports.TryAdd(physicalPort, port)) { - Task.Run(() => PortDiscovered?.InvokeFailSafe(this, port)); + tasks.Add(Task.Run(() => PortDiscovered?.InvokeFailSafe(this, port))); port.RDMUIDReceived += Port_RDMUIDReceived; } } @@ -311,18 +330,6 @@ public void processArtPollReply(ArtPollReply artPollReply) Logger.LogError(ex); } seen(); - - var timoutedPorts = ports.Where(p => p.Value.Timouted()); - if (timoutedPorts.Count() != 0) - { - timoutedPorts = timoutedPorts.ToList(); - foreach (var port in timoutedPorts) - { - ports.TryRemove(port.Key, out _); - Task.Run(()=>PortTimedOut?.InvokeFailSafe(this, port)); - } - } - seen(); Ports = ports.Select(p => p.Value).ToList().AsReadOnly(); } public async Task processArtDataReply(ArtDataReply artDataReply) diff --git a/ArtNetSharp/Communication/RemoteClientPort.cs b/ArtNetSharp/Communication/RemoteClientPort.cs index 973d030..8c61c63 100644 --- a/ArtNetSharp/Communication/RemoteClientPort.cs +++ b/ArtNetSharp/Communication/RemoteClientPort.cs @@ -39,7 +39,7 @@ private void seen() } internal bool Timouted()// Spec 1.4dd page 12, doubled to allow one lost reply (6s is allowad, for some delay i add 1500 ms) { - var now = DateTime.UtcNow.AddSeconds(-7.5); + var now = DateTime.UtcNow.AddSeconds(-3); return LastSeen <= now; } public ArtPollReply ArtPollReply { get; private set; }