2using System.Collections.Generic;
4using System.Net.NetworkInformation;
5using System.Net.Sockets;
6using System.Reflection;
7using System.Security.Cryptography;
10using System.Threading.Tasks;
22using Windows.Networking;
23using Windows.Networking.Connectivity;
33 private static readonly Dictionary<Type, ObjectInfo> objectInfo =
new Dictionary<Type, ObjectInfo>();
34 private static Dictionary<Type, IProperty> propertyTypes =
null;
35 private static ObjectInfo rootObject;
37 private readonly LinkedList<ClusterUdpClient> outgoing =
new LinkedList<ClusterUdpClient>();
38 private readonly LinkedList<ClusterUdpClient> incoming =
new LinkedList<ClusterUdpClient>();
39 private readonly IPEndPoint destination;
40 internal readonly
byte[] key;
44 private readonly Random rnd =
new Random();
45 private readonly Dictionary<IPEndPoint, object> remoteStatus;
46 internal readonly Dictionary<string, LockInfo> lockedResources =
new Dictionary<string, LockInfo>();
47 private object localStatus;
48 private Timer aliveTimer;
49 internal bool shuttingDown =
false;
50 private readonly
bool internalScheduler;
51 private ManualResetEvent shutDown =
new ManualResetEvent(
false);
62 : this(MulticastAddress, Port, Encoding.UTF8.GetBytes(SharedSecret),
Sniffers)
76 ClusterUdpClient ClusterUdpClient;
79 if (MulticastAddress.AddressFamily != AddressFamily.InterNetwork)
80 throw new ArgumentException(
"Cluster communication must be done using IPv4.", nameof(MulticastAddress));
82 if (propertyTypes is
null)
85 rootObject = GetObjectInfo(typeof(
object));
88 this.aes = Aes.Create();
89 this.aes.BlockSize = 128;
90 this.aes.KeySize = 256;
91 this.aes.Mode = CipherMode.CBC;
92 this.aes.Padding = PaddingMode.None;
95 this.destination =
new IPEndPoint(MulticastAddress, Port);
97 this.localStatus =
null;
98 this.remoteStatus =
new Dictionary<IPEndPoint, object>();
99 this.currentStatus =
new Cache<string, object>(
int.MaxValue, TimeSpan.MaxValue, TimeSpan.FromSeconds(30),
true);
100 this.currentStatus.Removed += this.CurrentStatus_Removed;
105 this.internalScheduler =
false;
110 this.internalScheduler =
true;
114 foreach (HostName HostName
in NetworkInformation.GetHostNames())
116 if (HostName.IPInformation is
null)
119 foreach (ConnectionProfile Profile
in NetworkInformation.GetConnectionProfiles())
121 if (Profile.GetNetworkConnectivityLevel() == NetworkConnectivityLevel.None)
124 if (Profile.NetworkAdapter.NetworkAdapterId != HostName.IPInformation.NetworkAdapter.NetworkAdapterId)
127 if (!IPAddress.TryParse(HostName.CanonicalName, out IPAddress Address))
130 AddressFamily AddressFamily = Address.AddressFamily;
131 bool IsLoopback = IPAddress.IsLoopback(Address);
133 foreach (NetworkInterface Interface
in NetworkInterface.GetAllNetworkInterfaces())
135 if (Interface.OperationalStatus != OperationalStatus.Up)
138 switch (Interface.NetworkInterfaceType)
140 case NetworkInterfaceType.Loopback:
144 IPInterfaceProperties Properties = Interface.GetIPProperties();
146 foreach (UnicastIPAddressInformation UnicastAddress
in Properties.UnicastAddresses)
148 IPAddress Address = UnicastAddress.Address;
149 AddressFamily AddressFamily = Address.AddressFamily;
150 bool IsLoopback = Interface.NetworkInterfaceType == NetworkInterfaceType.Loopback;
152 if (Address.AddressFamily != MulticastAddress.AddressFamily)
161 Client =
new UdpClient(AddressFamily)
164 ExclusiveAddressUse =
true,
165 MulticastLoopback =
false,
166 EnableBroadcast =
true,
170 Client.Client.Bind(
new IPEndPoint(Address, 0));
174 Client.JoinMulticastGroup(MulticastAddress);
181 catch (NotSupportedException)
193 ClusterUdpClient =
new ClusterUdpClient(
this, Client, Address);
194 ClusterUdpClient.BeginReceive();
196 this.outgoing.AddLast(ClusterUdpClient);
202 Client =
new UdpClient(AddressFamily)
204 ExclusiveAddressUse =
false,
207 Client.Client.Bind(
new IPEndPoint(Address, Port));
209 catch (NotSupportedException)
221 ClusterUdpClient =
new ClusterUdpClient(
this, Client, Address);
222 ClusterUdpClient.BeginReceive();
224 this.incoming.AddLast(ClusterUdpClient);
231 Client =
new UdpClient(Port, MulticastAddress.AddressFamily)
233 MulticastLoopback =
false
236 Client.JoinMulticastGroup(MulticastAddress);
238 ClusterUdpClient =
new ClusterUdpClient(
this, Client,
null);
239 ClusterUdpClient.BeginReceive();
241 this.incoming.AddLast(ClusterUdpClient);
248 this.aliveTimer =
new Timer(this.SendAlive,
null, 0, 5000);
258 LinkedList<IPEndPoint> Result =
new LinkedList<IPEndPoint>();
260 foreach (ClusterUdpClient Client
in this.incoming)
261 Result.AddLast(Client.EndPoint);
270 [Obsolete(
"Use DisposeAsync")]
288 if (!this.shuttingDown)
290 LinkedList<string> ToRelease =
null;
292 lock (this.lockedResources)
294 foreach (LockInfo Info
in this.lockedResources.Values)
298 if (ToRelease is
null)
299 ToRelease =
new LinkedList<string>();
301 ToRelease.AddLast(Info.Resource);
305 this.lockedResources.Clear();
308 if (!(ToRelease is
null))
310 foreach (
string Resource
in ToRelease)
319 this.shuttingDown =
true;
322 this.shutDown?.WaitOne(2000);
323 this.shutDown?.Dispose();
324 this.shutDown =
null;
331 internal void Dispose2()
333 if (this.internalScheduler)
336 this.scheduler =
null;
338 this.aliveTimer?.Dispose();
339 this.aliveTimer =
null;
341 this.Clear(this.outgoing);
342 this.Clear(this.incoming);
345 this.currentStatus =
null;
349 if (Sniffer is IDisposable Disposable)
353 Disposable.Dispose();
362 this.shutDown?.Set();
365 private void Clear(LinkedList<ClusterUdpClient> Clients)
367 foreach (ClusterUdpClient Client
in Clients)
382 internal static ObjectInfo GetObjectInfo(Type T)
386 if (objectInfo.TryGetValue(T, out ObjectInfo Result))
390 List<PropertyReference> Properties =
new List<PropertyReference>();
392 foreach (PropertyInfo PI
in T.GetRuntimeProperties())
394 if (PI.GetMethod is
null || PI.SetMethod is
null)
397 Type PT = PI.PropertyType;
403 Properties.Add(
new PropertyReference()
411 return new ObjectInfo()
414 Properties = Properties.ToArray()
418 internal static IProperty GetProperty(Type PT)
422 Type ElementType = PT.GetElementType();
423 return new ArrayProperty(PT, ElementType, GetProperty(ElementType));
426 TypeInfo PTI = PT.GetTypeInfo();
430 else if (PTI.IsGenericType && PT.GetGenericTypeDefinition() == typeof(Nullable<>))
432 Type ElementType = PT.GenericTypeArguments[0];
433 IProperty Element = GetProperty(ElementType);
439 else if (!PTI.IsValueType)
445 private static void Init()
447 Dictionary<Type, IProperty> PropertyTypes =
new Dictionary<Type, IProperty>();
452 if (DefaultConstructor is
null)
462 if (PropertyTypes.ContainsKey(PT))
464 Log.
Error(
"Multiple classes available for property type " + PT.FullName +
".");
476 if (propertyTypes is
null)
477 Types.OnInvalidated += (Sender, e) => Init();
479 propertyTypes = PropertyTypes;
491 rootObject.Serialize(Output, Object);
506 return rootObject.Deserialize(Input, typeof(
object));
510 internal async
void DataReceived(
byte[] Data, IPEndPoint From)
514 if (Data.Length == 0)
526 object Object = rootObject.Deserialize(Input, typeof(
object));
529 await Message.MessageReceived(
this, From);
534 await this.
Error(
"Non-message object received in message: " + Object?.GetType()?.FullName);
539 string s = Id.ToString();
545 string Address =
new IPAddress(Input.
ReadBinary()).ToString();
548 if (this.IsEndpoint(this.outgoing, Address, Port) ||
549 this.IsEndpoint(this.incoming, Address, Port))
561 if (!this.currentStatus.
TryGetValue(s, out
object Obj) ||
564 Object = rootObject.Deserialize(Input, typeof(
object));
569 Ack = await Message.MessageReceived(
this, From);
580 this.currentStatus[s] = Ack;
584 await this.
Error(
"Non-message object received in message: " + Object?.GetType()?.FullName);
591 Output.
WriteByte(Ack ? (
byte)2 : (byte)3);
594 await this.Transmit(Output.
ToArray(), From);
604 Obj is MessageStatus MessageStatus)
606 lock (MessageStatus.Acknowledged)
608 MessageStatus.Acknowledged[From] = (
Command == 2);
613 if (MessageStatus.IsComplete(CurrentStatus))
615 this.currentStatus.
Remove(s);
616 this.scheduler.
Remove(MessageStatus.Timeout);
619 MessageStatus.Message, MessageStatus.GetResponses(CurrentStatus),
620 MessageStatus.State));
633 string Address =
new IPAddress(Input.
ReadBinary()).ToString();
636 if (this.IsEndpoint(this.outgoing, Address, Port) ||
637 this.IsEndpoint(this.incoming, Address, Port))
651 Object = rootObject.Deserialize(Input, typeof(
object));
656 Obj = await ClusterCommand.Execute(
this, From);
657 this.currentStatus[s] = Obj;
665 Obj =
new Exception(
"Non-command object received in command: " + Object?.GetType()?.FullName);
670 if (Obj is Exception ex)
683 rootObject.Serialize(Output, Obj);
686 await this.Transmit(Output.
ToArray(), From);
695 Obj is CommandStatusBase CommandStatus)
697 Object = rootObject.Deserialize(Input, typeof(
object));
699 CommandStatus.AddResponse(From, Object);
703 if (CommandStatus.IsComplete(CurrentStatus))
705 this.currentStatus.
Remove(s);
706 this.scheduler.
Remove(CommandStatus.Timeout);
708 await CommandStatus.RaiseResponseEvent(CurrentStatus);
718 Obj is CommandStatusBase CommandStatus2)
730 ex = (
Exception)Activator.CreateInstance(T, ExceptionMessage);
737 CommandStatus2.AddError(From, ex);
741 if (CommandStatus2.IsComplete(CurrentStatus))
743 this.currentStatus.
Remove(s);
744 this.scheduler.
Remove(CommandStatus2.Timeout);
746 await CommandStatus2.RaiseResponseEvent(CurrentStatus);
760 private bool IsEndpoint(LinkedList<ClusterUdpClient> Clients,
string Address,
int Port)
762 foreach (ClusterUdpClient Client
in Clients)
764 if (Client.IsEndpoint(Address, Port))
776 private async Task Transmit(
byte[] Message, IPEndPoint Destination)
780 foreach (ClusterUdpClient Client
in this.outgoing)
781 Client.BeginTransmit(Message, Destination);
795 rootObject.Serialize(Output, Message);
796 await this.Transmit(Output.
ToArray(),
this.destination);
802 if (this.shuttingDown)
818 EventHandlerAsync<ClusterMessageAckEventArgs> Callback,
object State)
821 Guid Id = Guid.NewGuid();
822 string s = Id.ToString();
823 MessageStatus Rec =
null;
830 rootObject.Serialize(Output, Message);
833 DateTime Now = DateTime.Now;
835 Rec =
new MessageStatus()
842 TimeLimit = Now.AddSeconds(30)
845 this.currentStatus[s] = Rec;
847 Rec.Timeout = this.scheduler.
Add(Now.AddSeconds(2),
this.ResendAcknowledgedMessage, Rec);
849 await this.Transmit(Bin, this.destination);
853 if (Rec.IsComplete(CurrentStatus))
855 this.currentStatus.
Remove(Rec.Id.ToString());
856 this.scheduler.
Remove(Rec.Timeout);
859 Rec.Message, Rec.GetResponses(CurrentStatus), Rec.State));
866 if (this.shuttingDown)
875 private async Task ResendAcknowledgedMessage(
object P)
877 MessageStatus Rec = (MessageStatus)P;
882 DateTime Now = DateTime.Now;
884 if (Rec.IsComplete(CurrentStatus) || Now >= Rec.TimeLimit)
886 this.currentStatus.
Remove(Rec.Id.ToString());
887 this.scheduler.
Remove(Rec.Timeout);
890 Rec.Message, Rec.GetResponses(CurrentStatus), Rec.State));
899 lock (Rec.Acknowledged)
903 foreach (IPEndPoint Endpoint
in Rec.Acknowledged.Keys)
905 Output.
WriteBinary(Endpoint.Address.GetAddressBytes());
910 Output.
WriteRaw(Rec.MessageBinary, 18, Rec.MessageBinary.Length - 18);
912 Rec.Timeout = this.scheduler.
Add(Now.AddSeconds(2),
this.ResendAcknowledgedMessage, Rec);
913 await this.Transmit(Output.
ToArray(),
this.destination);
929 TaskCompletionSource<EndpointAcknowledgement[]> Result =
new TaskCompletionSource<EndpointAcknowledgement[]>();
933 Result.TrySetResult(e.Responses);
934 return Task.CompletedTask;
937 return await Result.Task;
947 EventHandlerAsync<ClusterMessageAckEventArgs> Callback,
object State)
949 Guid MessageId = Guid.NewGuid();
953 MessageID = MessageId,
955 }, async (Sender, e) =>
959 MessageID = MessageId
960 }, async (sender2, e2) =>
973 TaskCompletionSource<EndpointAcknowledgement[]> Result =
new TaskCompletionSource<EndpointAcknowledgement[]>();
977 Result.TrySetResult(e.Responses);
978 return Task.CompletedTask;
981 return await Result.Task;
984 private async
void SendAlive(
object _)
992 this.localStatus = e.
Status;
996 Status = this.localStatus
1008 public event EventHandlerAsync<ClusterGetStatusEventArgs>
GetStatus =
null;
1025 lock (this.remoteStatus)
1030 foreach (KeyValuePair<IPEndPoint, object> P
in this.remoteStatus)
1048 lock (this.remoteStatus)
1050 New = !this.remoteStatus.ContainsKey(Endpoint);
1051 this.remoteStatus[Endpoint] = Status;
1069 lock (this.remoteStatus)
1071 Removed = this.remoteStatus.Remove(Endpoint);
1093 public event EventHandlerAsync<ClusterEndpointStatusEventArgs>
EndpointStatus =
null;
1095 internal void StatusReported(
object Status, IPEndPoint RemoteEndpoint)
1099 string s = RemoteEndpoint.ToString();
1102 this.currentStatus[s] = RemoteEndpoint;
1105 internal Task EndpointShutDown(IPEndPoint RemoteEndpoint)
1110 internal void AssuredTransport(Guid MessageId,
IClusterMessage Message)
1112 this.currentStatus[MessageId.ToString()] = Message;
1115 internal async Task<bool> AssuredDelivery(Guid MessageId,
ClusterEndpoint Endpoint, IPEndPoint RemoteEndpoint)
1117 string s = MessageId.ToString();
1119 if (this.currentStatus.
TryGetValue(s, out
object Obj))
1125 this.currentStatus[s] =
false;
1126 b = await Message.MessageReceived(Endpoint, RemoteEndpoint);
1127 this.currentStatus[s] = b;
1142 if (e.
Value is IPEndPoint RemoteEndpoint)
1144 else if (e.
Value is MessageStatus MessageStatus)
1148 this.scheduler.
Remove(MessageStatus.Timeout);
1151 MessageStatus.Message, MessageStatus.GetResponses(
this.GetRemoteStatuses()),
1152 MessageStatus.State));
1162 public Task
Ping(EventHandlerAsync<ClusterMessageAckEventArgs> Callback,
object State)
1172 TaskCompletionSource<EndpointAcknowledgement[]> Result =
new TaskCompletionSource<EndpointAcknowledgement[]>();
1174 await this.
Ping((Sender, e) =>
1176 Result.TrySetResult(e.Responses);
1177 return Task.CompletedTask;
1180 return await Result.Task;
1196 Guid Id = Guid.NewGuid();
1197 string s = Id.ToString();
1198 CommandStatus<ResponseType> Rec =
null;
1205 rootObject.Serialize(Output, Command);
1207 byte[] Bin = Output.
ToArray();
1208 DateTime Now = DateTime.Now;
1210 Rec =
new CommandStatus<ResponseType>()
1214 CommandBinary = Bin,
1215 TimeLimit = Now.AddSeconds(30),
1216 Callback = Callback,
1220 this.currentStatus[s] = Rec;
1222 Rec.Timeout = this.scheduler.
Add(Now.AddSeconds(2),
this.ResendCommand<ResponseType>, Rec);
1224 await this.Transmit(Bin, this.destination);
1228 if (Rec.IsComplete(CurrentStatus))
1230 this.currentStatus.
Remove(Rec.Id.ToString());
1231 this.scheduler.
Remove(Rec.Timeout);
1234 Rec.Command, Rec.GetResponses(CurrentStatus), Rec.State));
1241 if (this.shuttingDown)
1250 private async Task ResendCommand<ResponseType>(
object P)
1252 CommandStatus<ResponseType> Rec = (CommandStatus<ResponseType>)P;
1253 DateTime Now = DateTime.Now;
1259 if (Rec.IsComplete(CurrentStatus) || Now >= Rec.TimeLimit)
1261 this.currentStatus.
Remove(Rec.Id.ToString());
1262 this.scheduler.
Remove(Rec.Timeout);
1265 Rec.Command, Rec.GetResponses(CurrentStatus), Rec.State));
1274 lock (Rec.Responses)
1278 foreach (IPEndPoint Endpoint
in Rec.Responses.Keys)
1280 Output.
WriteBinary(Endpoint.Address.GetAddressBytes());
1285 Output.
WriteRaw(Rec.CommandBinary, 18, Rec.CommandBinary.Length - 18);
1287 Rec.Timeout = this.scheduler.
Add(Now.AddSeconds(2),
this.ResendCommand<ResponseType>, Rec);
1288 await this.Transmit(Output.
ToArray(),
this.destination);
1292 catch (Exception ex)
1308 TaskCompletionSource<EndpointResponse<ResponseType>[]> Result =
1309 new TaskCompletionSource<EndpointResponse<ResponseType>[]>();
1313 Result.TrySetResult(e.Responses);
1314 return Task.CompletedTask;
1317 return await Result.Task;
1328 return this.ExecuteCommand(
new Echo()
1331 }, Callback, State);
1338 public async Task<EndpointResponse<string>[]>
EchoAsync(
string Text)
1340 TaskCompletionSource<EndpointResponse<string>[]> Result =
new TaskCompletionSource<EndpointResponse<string>[]>();
1342 await this.
Echo(Text, (Sender, e) =>
1344 Result.TrySetResult(e.Responses);
1345 return Task.CompletedTask;
1348 return await Result.Task;
1358 return this.ExecuteCommand(
new Assemblies(), Callback, State);
1366 TaskCompletionSource<EndpointResponse<string[]>[]> Result =
new TaskCompletionSource<EndpointResponse<string[]>[]>();
1370 Result.TrySetResult(e.Responses);
1371 return Task.CompletedTask;
1374 return await Result.Task;
1384 public Task
Lock(
string ResourceName,
int TimeoutMilliseconds,
1385 EventHandlerAsync<ClusterResourceLockEventArgs> Callback,
object State)
1388 LockInfoRec InfoRec;
1390 lock (this.lockedResources)
1392 if (!this.lockedResources.TryGetValue(ResourceName, out Info))
1394 Info =
new LockInfo()
1396 Resource = ResourceName,
1400 this.lockedResources[ResourceName] = Info;
1403 Info.Queue.AddLast(InfoRec =
new LockInfoRec()
1406 Timeout = DateTime.Now.AddMilliseconds(TimeoutMilliseconds),
1407 Callback = Callback,
1413 return this.LockResult(
false,
null, InfoRec);
1415 return this.
Lock(Info, InfoRec);
1418 private Task
Lock(LockInfo Info, LockInfoRec InfoRec)
1422 Resource = Info.Resource
1425 IPEndPoint LockedBy =
null;
1429 if (Response.
ACK.HasValue && !Response.
ACK.Value)
1438 lock (this.lockedResources)
1443 Ok = LockedBy is
null;
1448 Info.Queue.Remove(InfoRec);
1450 else if (InfoRec.Timeout <= DateTime.Now)
1452 Info.Queue.Remove(InfoRec);
1454 if (!Info.Locked && Info.Queue.First is
null)
1455 this.lockedResources.Remove(Info.Resource);
1459 return this.LockResult(Ok, LockedBy, InfoRec);
1464 private async Task LockResult(
bool Ok, IPEndPoint LockedBy, LockInfoRec InfoRec)
1467 await this.Raise(InfoRec.Info.Resource,
true,
null, InfoRec);
1468 else if (DateTime.Now >= InfoRec.Timeout)
1469 await this.Raise(InfoRec.Info.Resource,
false, LockedBy, InfoRec);
1470 else if (!InfoRec.TimeoutScheduled)
1472 InfoRec.LockedBy = LockedBy;
1473 InfoRec.Timeout = this.scheduler.
Add(InfoRec.Timeout,
this.LockTimeout, InfoRec);
1474 InfoRec.TimeoutScheduled =
true;
1478 private Task LockTimeout(
object P)
1480 LockInfoRec InfoRec = (LockInfoRec)P;
1481 LockInfo Info = InfoRec.Info;
1483 InfoRec.TimeoutScheduled =
false;
1485 lock (this.lockedResources)
1487 Info.Queue.Remove(InfoRec);
1489 if (!Info.Locked && Info.Queue.First is
null)
1490 this.lockedResources.Remove(Info.Resource);
1493 return this.Raise(Info.Resource,
false, InfoRec.LockedBy, InfoRec);
1496 private async Task Raise(
string ResourceName,
bool LockSuccessful, IPEndPoint LockedBy,
1497 LockInfoRec InfoRec)
1501 if (InfoRec.TimeoutScheduled)
1503 this.scheduler.
Remove(InfoRec.Timeout);
1504 InfoRec.TimeoutScheduled =
false;
1507 LockInfo Info = InfoRec.Info;
1509 lock (this.lockedResources)
1511 Info.Queue.Remove(InfoRec);
1513 if (!Info.Locked && Info.Queue.First is
null)
1514 this.lockedResources.Remove(Info.Resource);
1518 LockSuccessful, LockedBy, InfoRec.State));
1520 catch (Exception ex)
1531 public async Task<ClusterResourceLockEventArgs>
LockAsync(
string ResourceName,
int TimeoutMilliseconds)
1533 TaskCompletionSource<ClusterResourceLockEventArgs> Result =
new TaskCompletionSource<ClusterResourceLockEventArgs>();
1535 await this.
Lock(ResourceName, TimeoutMilliseconds, (Sender, e) =>
1537 Result.TrySetResult(e);
1538 return Task.CompletedTask;
1541 return await Result.Task;
1552 LockInfoRec InfoRec;
1554 lock (this.lockedResources)
1556 if (!this.lockedResources.TryGetValue(ResourceName, out Info) || !Info.Locked)
1557 throw new ArgumentException(
"Resource not locked.", nameof(ResourceName));
1559 Info.Locked =
false;
1561 if (Info.Queue.First is
null)
1563 this.lockedResources.Remove(ResourceName);
1567 InfoRec = Info.Queue.First.Value;
1572 Resource = ResourceName
1575 if (!(InfoRec is
null))
1577 this.scheduler.
Add(DateTime.Now.AddMilliseconds(
this.rnd.Next(50) + 1), (P) =>
1579 this.Lock(Info, InfoRec);
1584 internal void Released(
string ResourceName)
1587 LockInfoRec InfoRec;
1589 lock (this.lockedResources)
1591 if (!this.lockedResources.TryGetValue(ResourceName, out Info) || Info.Locked)
1594 if (Info.Queue.First is
null)
1596 this.lockedResources.Remove(ResourceName);
1600 InfoRec = Info.Queue.First.Value;
1603 this.scheduler.
Add(DateTime.Now.AddMilliseconds(
this.rnd.Next(50) + 1), (P) =>
1605 this.Lock(Info, InfoRec);
Static class managing the application event log. Applications and services log events on this static ...
static void Exception(Exception Exception, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, params KeyValuePair< string, object >[] Tags)
Logs an exception. Event type will be determined by the severity of the exception.
static void Error(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs an error event.
static Exception UnnestException(Exception Exception)
Unnests an exception, to extract the relevant inner exception.
Event arguments for cluster endpoint events.
Represents one endpoint (or participant) in the network cluster.
async Task SendMessageAcknowledged(IClusterMessage Message, EventHandlerAsync< ClusterMessageAckEventArgs > Callback, object State)
Sends a message using acknowledged service. ("at least once")
async Task< EndpointAcknowledgement[]> SendMessageAssuredAsync(IClusterMessage Message)
Sends a message using assured service. ("exactly once")
async void Dispose()
IDisposable.Dispose
Task Lock(string ResourceName, int TimeoutMilliseconds, EventHandlerAsync< ClusterResourceLockEventArgs > Callback, object State)
Locks a singleton resource in the cluster.
Task Echo(string Text, EventHandlerAsync< ClusterResponseEventArgs< string > > Callback, object State)
Asks endpoints in the cluster to echo a text string back to the sender.
async Task ExecuteCommand< ResponseType >(IClusterCommand Command, EventHandlerAsync< ClusterResponseEventArgs< ResponseType > > Callback, object State)
Execute a command on the other members of the cluster, and waits for responses to be returned....
IEnumerable< IPEndPoint > Endpoints
IP endpoints listening on.
async Task< ClusterResourceLockEventArgs > LockAsync(string ResourceName, int TimeoutMilliseconds)
Locks a singleton resource in the cluster.
ClusterEndpoint(IPAddress MulticastAddress, int Port, string SharedSecret, params ISniffer[] Sniffers)
Represents one endpoint (or participant) in the network cluster.
EventHandlerAsync< ClusterGetStatusEventArgs > GetStatus
Event raised when current status is needed.
async Task< bool > RemoveRemoteStatus(IPEndPoint Endpoint)
Explicitly removes a remote cluster endpoint status object.
async Task DisposeAsync()
IDisposable.Dispose
object LocalStatus
Local status. For remote endpoint statuses, see GetRemoteStatuses
async Task Release(string ResourceName)
Releases a resource.
EndpointStatus[] GetRemoteStatuses()
Gets current remote statuses. For the current local status, see LocalStatus
EventHandlerAsync< ClusterEndpointEventArgs > EndpointOffline
Event raised when an endpoint goes offline.
object Deserialize(byte[] Data)
Deserializes an object.
EventHandlerAsync< ClusterEndpointStatusEventArgs > EndpointStatus
Event raised when status has been reported by an endpoint.
EventHandlerAsync< ClusterEndpointEventArgs > EndpointOnline
Event raised when a new endpoint is available in the cluster.
byte[] Serialize(object Object)
Serializes an object.
Task GetAssemblies(EventHandlerAsync< ClusterResponseEventArgs< string[]> > Callback, object State)
Asks endpoints in the cluster to return assemblies available in their runtime environment.
async void AddRemoteStatus(IPEndPoint Endpoint, object Status)
Explicitly adds a remote endpoint status object. In normal operation, calling this method is not nece...
async Task< EndpointResponse< string >[]> EchoAsync(string Text)
Asks endpoints in the cluster to echo a text string back to the sender.
EventHandlerAsync< ClusterMessageEventArgs > OnMessageReceived
Event raised when a cluster message has been received.
async Task< EndpointResponse< string[]>[]> GetAssembliesAsync()
Asks endpoints in the cluster to return assemblies available in their runtime environment.
ClusterEndpoint(IPAddress MulticastAddress, int Port, byte[] SharedSecret, params ISniffer[] Sniffers)
Represents one endpoint (or participant) in the network cluster.
Task Ping(EventHandlerAsync< ClusterMessageAckEventArgs > Callback, object State)
Sends an acknowledged ping message to the other servers in the cluster.
async Task< EndpointResponse< ResponseType >[]> ExecuteCommandAsync< ResponseType >(IClusterCommand Command)
Execute a command on the other members of the cluster, and waits for responses to be returned....
async Task SendMessageUnacknowledged(IClusterMessage Message)
Sends an unacknowledged message ("at most once")
async Task< EndpointAcknowledgement[]> SendMessageAcknowledgedAsync(IClusterMessage Message)
Sends a message using acknowledged service.
async Task SendMessageAssured(IClusterMessage Message, EventHandlerAsync< ClusterMessageAckEventArgs > Callback, object State)
Sends a message using assured service. ("exactly once")
async Task< EndpointAcknowledgement[]> PingAsync()
Sends an acknowledged ping message to the other servers in the cluster.
Event arguments for cluster endpoint status events.
Event arguments for cluster get status events.
object Status
Current status of service.
Event arguments for cluster message acknowledgement events.
Event arguments for cluster message events.
Event arguments for cluster resource lock events.
Event arguments for cluster message acknowledgement events.
Command to request available assembly names from cluster endpoints.
Command echoing incoming text string.
Contains information about one of the endpoints in the cluster.
bool? ACK
Acknowledgement response:
IPEndPoint Endpoint
Remote endpoint
Contains information about one of the endpoints in the cluster.
Alive message regularly sent on the network to inform members of the cluster of the status of the cur...
Delivers a message, as part of an assured message transfer
Message used to inform other members that the sending endpoint is trying to lock a resource....
Ping message that can be sent to test endpoints in cluster receive messages.
Message used to inform other members that the sending endpoint is releasing a locked resource.
Message sent when an endpoint is shut down, to let the other endpoints know the current endpoint is n...
Transports a message, as part of an assured message transfer
byte[] ReadBinary()
Reads binary data from the input.
ushort ReadUInt16()
Reads a 16-bit unsigned integer from the input.
ulong ReadVarUInt64()
Reads a variable-length unsigned integer from the input.
byte ReadByte()
Reads a byte from the input.
Guid ReadGuid()
Reads a Guid from the input.
string ReadString()
Reads a string from the input.
Abstract base class for properties
abstract Type PropertyType
Property Type
void WriteRaw(byte[] Binary)
Writes raw binary data to the output.
byte[] ToArray()
Returns the binary output.
void Dispose()
IDisposable.Dispose
void WriteVarUInt64(ulong Value)
Writes a variable-length unsigned integer to the output.
void WriteBinary(byte[] Value)
Writes binary data to the output.
void WriteGuid(Guid Value)
Writes a Guid to the output.
void WriteString(string Value)
Writes a string to the output.
void WriteByte(byte Value)
Writes a byte to the output.
void WriteUInt16(ushort Value)
Writes a 16-bit unsigned integer to the output.
Simple base class for classes implementing communication protocols.
Task TransmitBinary(byte[] Data)
Called when binary data has been transmitted.
Task Error(string Error)
Called to inform the viewer of an error state.
Task Exception(Exception Exception)
Called to inform the viewer of an exception state.
ISniffer[] Sniffers
Registered sniffers.
Task ReceiveBinary(byte[] Data)
Called when binary data has been received.
Implements an in-memory cache.
bool ContainsKey(KeyType Key)
Checks if a key is available in the cache.
void Dispose()
IDisposable.Dispose
bool Remove(KeyType Key)
Removes an item from the cache.
bool TryGetValue(KeyType Key, out ValueType Value)
Tries to get a value from the cache.
Event arguments for cache item removal events.
ValueType Value
Value of item that was removed.
RemovedReason Reason
Reason for removing the item.
Static class that dynamically manages types and interfaces available in the runtime environment.
static Type GetType(string FullName)
Gets a type, given its full name.
static bool TryGetModuleParameter(string Name, out object Value)
Tries to get a module parameter value.
static object[] NoParameters
Contains an empty array of parameter values.
static Type[] GetTypesImplementingInterface(string InterfaceFullName)
Gets all types implementing a given interface.
static ConstructorInfo GetDefaultConstructor(Type Type)
Gets the default constructor of a type, if one exists.
Class that can be used to schedule events in time. It uses a timer to execute tasks at the appointed ...
bool Remove(DateTime When)
Removes an event scheduled for a given point in time.
void Dispose()
IDisposable.Dispose
DateTime Add(DateTime When, ScheduledEventCallback Callback, object State)
Adds an event.
Contains methods for simple hash calculations.
static byte[] ComputeSHA256Hash(byte[] Data)
Computes the SHA-256 hash of a block of binary data.
Interface for cluster commands.
Interface for cluster messages.
Abstract base class for properties
Interface for sniffers. Sniffers can be added to ICommunicationLayer classes to eavesdrop on communic...
delegate Task EventHandlerAsync(object Sender, EventArgs e)
Asynchronous version of EventArgs.
RemovedReason
Reason for removing the item.