166 lines
6.6 KiB
C#
166 lines
6.6 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Concurrent;
|
|
|
|
namespace RoboidControl {
|
|
|
|
/// <summary>
|
|
/// A participant is a device which manages things.
|
|
/// </summary>
|
|
/// It can communicate with other participant to synchronise the state of things.
|
|
/// This class is used to register the things the participant is managing.
|
|
/// It also maintains the communcation information to contact the participant.
|
|
/// It is used as a basis for the local participant, but also as a reference to remote participants.
|
|
public class Participant {
|
|
/// <summary>
|
|
/// Create a new participant with the given communcation info
|
|
/// </summary>
|
|
/// <param name="ipAddress">The IP address of the participant</param>
|
|
/// <param name="port">The UDP port of the participant</param>
|
|
public Participant(string ipAddress, int port) {
|
|
this.ipAddress = ipAddress;
|
|
this.port = port;
|
|
}
|
|
|
|
/// <summary>
|
|
/// The Ip Address of a participant. When the participant is local, this contains 0.0.0.0
|
|
/// </summary>
|
|
public string ipAddress = "0.0.0.0";
|
|
/// <summary>
|
|
/// The port number for UDP communication with the participant. This is 0 for isolated participants.
|
|
/// </summary>
|
|
public int port = 0;
|
|
|
|
/// <summary>
|
|
/// he network Id to identify the participant
|
|
/// </summary>
|
|
public byte networkId = 0;
|
|
|
|
/// <summary>
|
|
/// The things managed by this participant
|
|
/// </summary>
|
|
public readonly List<Thing> things = new();
|
|
|
|
/// <summary>
|
|
/// Get the thing with the given properties
|
|
/// </summary>
|
|
/// <param name="thingId">The ID of the thing</param>
|
|
/// <returns>The thing when it is found, null in other cases.</returns>
|
|
public Thing Get(byte thingId) {
|
|
Thing thing = things.Find(aThing => aThing.id == thingId);
|
|
//Thing thing = things.Find(aThing => Thing.IsThing(aThing, networkId, thingId));
|
|
// if (thing == null)
|
|
// Console.WriteLine($"Could not find thing {ipAddress}:{port}[{networkId}/{thingId}]");
|
|
return thing;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Add a new thing for this participant
|
|
/// </summary>
|
|
/// <param name="thing">The thing to add</param>
|
|
/// <param name="checkId">If true, the thing.id is regenerated if it is zero
|
|
public void Add(Thing thing, bool checkId = true) {
|
|
if (checkId && thing.id == 0) {
|
|
thing.id = (byte)(this.things.Count + 1);
|
|
this.things.Add(thing);
|
|
}
|
|
else {
|
|
Thing foundThing = Get(thing.id);
|
|
if (foundThing == null)
|
|
this.things.Add(thing);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Remove a thing for this participant
|
|
/// </summary>
|
|
/// <param name="thing">The thing to remove</param>
|
|
public void Remove(Thing thing) {
|
|
this.things.Remove(thing);
|
|
}
|
|
|
|
#region Update
|
|
|
|
/// <summary>
|
|
/// Update all things for this participant
|
|
/// </summary>
|
|
/// <param name="currentTimeMS">The current time in milliseconds (optional)</param>
|
|
public virtual void Update(ulong currentTimeMS = 0) {
|
|
int n = this.things.Count;
|
|
for (int ix = 0; ix < n; ix++) {
|
|
Thing thing = this.things[ix];
|
|
if (thing != null)
|
|
thing.Update(currentTimeMS, true);
|
|
}
|
|
}
|
|
|
|
public class UpdateEvent {
|
|
public int messageId; // see the communication messages
|
|
public Thing thing;
|
|
public Participant participant;
|
|
}
|
|
public ConcurrentQueue<UpdateEvent> updateQueue = new();
|
|
|
|
#endregion Update
|
|
|
|
/// <summary>
|
|
/// The collection of known participants.
|
|
/// </summary>
|
|
public readonly static List<Participant> participants = new();
|
|
|
|
/// <summary>
|
|
/// Retrieve a participant using ip address and port number
|
|
/// </summary>
|
|
/// <param name="ipAddress">The ip address of the participant</param>
|
|
/// <param name="port">The port number used to send messages to the participant</param>
|
|
/// <returns>The participant or null if it is not found.</returns>
|
|
public static Participant GetParticipant(string ipAddress, int port) {
|
|
//Console.WriteLine($"Get Participant {ipAddress}:{port}");
|
|
foreach (Participant participant in Participant.participants) {
|
|
if (participant.ipAddress == ipAddress && participant.port == port)
|
|
return participant;
|
|
}
|
|
return null;
|
|
}
|
|
/// <summary>
|
|
/// Retrieve a participant using a network ID
|
|
/// </summary>
|
|
/// <param name="networkId">The network ID of the participant</param>
|
|
/// <returns>The participant or null if it is not found.</returns>
|
|
public static Participant GetParticipant(int networkId) {
|
|
//Console.WriteLine($"Get Participant [networkId]");
|
|
foreach (Participant participant in Participant.participants) {
|
|
if (participant.networkId == networkId)
|
|
return participant;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Add a new participant to the collection of participants
|
|
/// </summary>
|
|
/// <param name="ipAddress">The IP address of the participant</param>
|
|
/// <param name="port">The port used to send messages to this participant</param>
|
|
/// <returns>The added participant</returns>
|
|
public static Participant AddParticipant(string ipAddress, int port) {
|
|
Console.WriteLine($"New Participant {ipAddress}:{port}");
|
|
Participant participant = new(ipAddress, port) {
|
|
networkId = (byte)(Participant.participants.Count + 1)
|
|
};
|
|
Participant.participants.Add(participant);
|
|
return participant;
|
|
}
|
|
/// <summary>
|
|
/// Add a new participant to the collection of participants
|
|
/// </summary>
|
|
/// <param name="participant">The participant to add</param>
|
|
/// <note>This function only adds the participant if it is not yet in the collection</note>
|
|
public static void AddParticipant(Participant participant) {
|
|
Participant foundParticipant = Participant.GetParticipant(participant.networkId);
|
|
if (foundParticipant == null)
|
|
Participant.participants.Add(participant);
|
|
}
|
|
|
|
}
|
|
|
|
} |