diff --git a/src/Bonsai.ZeroMQ/ConnectionId.cs b/src/Bonsai.ZeroMQ/ConnectionId.cs deleted file mode 100644 index 38c32f3..0000000 --- a/src/Bonsai.ZeroMQ/ConnectionId.cs +++ /dev/null @@ -1,78 +0,0 @@ -namespace Bonsai.ZeroMQ -{ - /// - /// Represents a connection identity for a ZeroMQ socket including the socket type, protocol and address. - /// - public class ConnectionId - { - /// - /// Gets or sets a value specifying the socket connection type (bind / connect). - /// - public SocketSettings.SocketConnection SocketConnection { get; set; } - /// - /// Gets or sets a value specifying the network protocol of the socket connection. - /// - public SocketSettings.SocketProtocol SocketProtocol {get; set;} - /// - /// Gets or sets a value specifying the host address of the socket connection. - /// - public string Host { get; set; } - /// - /// Gets or sets a value specifying the port of the socket connection. - /// - public string Port { get; set; } - - /// - /// Parameterlesss constructor of the class for serialization. - /// - public ConnectionId() - { - - } - - /// - /// Initializes a new instance of the class. - /// - /// The socket type (bind / connect). - /// The network protocol of the socket. - /// The socket host address. - /// The socket port. - public ConnectionId(SocketSettings.SocketConnection socketType, SocketSettings.SocketProtocol socketProtocol, string host, string port) - { - SocketConnection = socketType; - SocketProtocol = socketProtocol; - Host = host; - Port = port; - } - - /// - /// Initializes a new instance of the class from an address string. - /// - /// The address string in the form "{socketType}{socketProtocol}://{host}:{port}", e.g. "@tcp://localhost:5557". - public ConnectionId(string connectionString) - { - string port = connectionString.Split(':')[2]; - string host = connectionString.Split(':')[1].Split('/')[2]; - string protocol = connectionString.Split(':')[0].Remove(0, 1); - char type = connectionString[0]; - - Host = host; - Port = port; - SocketProtocol = SocketSettings.StringAsSocketProtocol(protocol); - SocketConnection = SocketSettings.CharAsSocketConnection(type); - } - - /// - public override string ToString() - { - if (SocketConnection == SocketSettings.SocketConnection.Bind) - { - return $"{SocketSettings.ConnectionString(SocketConnection)}{SocketSettings.ProtocolString(SocketProtocol)}://{Host}:{Port}"; - } - else - { - return $"{SocketSettings.ConnectionString(SocketConnection)}{SocketSettings.ProtocolString(SocketProtocol)}://{Host}:{Port}"; - } - } - } -} diff --git a/src/Bonsai.ZeroMQ/ConnectionIdConverter.cs b/src/Bonsai.ZeroMQ/ConnectionIdConverter.cs deleted file mode 100644 index 77b15a6..0000000 --- a/src/Bonsai.ZeroMQ/ConnectionIdConverter.cs +++ /dev/null @@ -1,99 +0,0 @@ -using System; -using System.Collections; -using System.ComponentModel; -using System.ComponentModel.Design.Serialization; -using System.Globalization; -using System.Reflection; - -namespace Bonsai.ZeroMQ -{ - internal class ConnectionIdConverter : TypeConverter - { - public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) - { - return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); - } - - public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) - { - return destinationType == typeof(InstanceDescriptor) || base.CanConvertTo(context, destinationType); - } - - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) - { - string connectionString = value as string; - if (connectionString != null) - { - return new ConnectionId(connectionString); - } - - return base.ConvertFrom(context, culture, value); - } - - public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) - { - object result = null; - ConnectionId connectionId = value as ConnectionId; - - if (connectionId != null) - { - if (destinationType == typeof(string)) - result = connectionId.ToString(); - else if (destinationType == typeof(InstanceDescriptor)) - { - ConstructorInfo constructorInfo; - - constructorInfo = typeof(ConnectionId).GetConstructor(new[] { typeof(SocketSettings.SocketConnection), typeof(string), typeof(string) }); - result = new InstanceDescriptor(constructorInfo, new object[] { connectionId.SocketConnection, connectionId.Host, connectionId.Port }); - } - } - - return result ?? base.ConvertTo(context, culture, value, destinationType); - } - - public override object CreateInstance(ITypeDescriptorContext context, IDictionary propertyValues) - { - return new ConnectionId( - (SocketSettings.SocketConnection)propertyValues["SocketConnection"], - (SocketSettings.SocketProtocol)propertyValues["SocketProtocol"], - (string)propertyValues["Host"], - (string)propertyValues["Port"]); - } - - public override bool GetPropertiesSupported(ITypeDescriptorContext context) - { - return true; - } - - public override bool GetCreateInstanceSupported(ITypeDescriptorContext context) - { - return true; - } - - public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) - { - return TypeDescriptor.GetProperties(value, attributes); - } - - class ConnectionPropertyDescriptor : SimplePropertyDescriptor - { - readonly PropertyDescriptor descriptor; - - public ConnectionPropertyDescriptor(string name, PropertyDescriptor descr, Attribute[] attributes) - : base(descr.ComponentType, name, descr.PropertyType, attributes) - { - descriptor = descr; - } - - public override object GetValue(object component) - { - return descriptor.GetValue(component); - } - - public override void SetValue(object component, object value) - { - descriptor.SetValue(component, value); - } - } - } -} \ No newline at end of file diff --git a/src/Bonsai.ZeroMQ/ConnectionStringConverter.cs b/src/Bonsai.ZeroMQ/ConnectionStringConverter.cs new file mode 100644 index 0000000..7a32bb0 --- /dev/null +++ b/src/Bonsai.ZeroMQ/ConnectionStringConverter.cs @@ -0,0 +1,188 @@ +using System; +using System.Collections; +using System.ComponentModel; + +namespace Bonsai.ZeroMQ +{ + internal class ConnectionStringConverter : StringConverter + { + const char BindPrefix = '@'; + const char ConnectPrefix = '>'; + const string ProtocolDelimiter = "://"; + + static char? GetDefaultAction(object value) + { + if (value is string connectionString && connectionString.Length > 0) + { + return connectionString[0]; + } + + return null; + } + + static string GetProtocol(object value) + { + if (value is string connectionString) + { + var trimString = connectionString.Trim(BindPrefix, ConnectPrefix); + var separatorIndex = trimString.IndexOf(ProtocolDelimiter); + if (separatorIndex >= 0) + { + return trimString.Substring(0, separatorIndex); + } + } + + return string.Empty; + } + + static string GetAddress(object value) + { + if (value is string connectionString) + { + var separatorIndex = connectionString.IndexOf(ProtocolDelimiter); + return separatorIndex >= 0 + ? connectionString.Substring(separatorIndex + ProtocolDelimiter.Length) + : connectionString; + } + + return string.Empty; + } + + static char? GetActionString(Action? value) + { + return value switch + { + Action.Connect => ConnectPrefix, + Action.Bind => BindPrefix, + _ => null + }; + } + + static string GetProtocolString(Protocol value) + { + return value switch + { + Protocol.InProc => "inproc", + Protocol.Tcp => "tcp", + Protocol.Ipc => "ipc", + Protocol.Pgm => "pgm", + Protocol.Epgm => "epgm", + _ => string.Empty + }; + } + + public override object CreateInstance(ITypeDescriptorContext context, IDictionary propertyValues) + { + var action = (Action?)propertyValues[nameof(Action)]; + var protocol = (Protocol)propertyValues[nameof(Protocol)]; + var address = propertyValues["Address"]; + return $"{GetActionString(action)}{GetProtocolString(protocol)}{ProtocolDelimiter}{address}"; + } + + public override bool GetCreateInstanceSupported(ITypeDescriptorContext context) + { + return true; + } + + public override bool GetPropertiesSupported(ITypeDescriptorContext context) + { + return true; + } + + public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) + { + return new PropertyDescriptorCollection(new PropertyDescriptor[] + { + new ActionDescriptor(), + new ProtocolDescriptor(), + new AddressDescriptor() + }).Sort(new[] { nameof(Action), nameof(Protocol) }); + } + + class ActionDescriptor : SimplePropertyDescriptor + { + public ActionDescriptor() + : base(typeof(string), nameof(Action), typeof(Action?)) + { + } + + public override Type PropertyType => typeof(string); + + public override TypeConverter Converter => TypeDescriptor.GetConverter(typeof(Action?)); + + public override object GetValue(object component) + { + return GetDefaultAction(component) switch + { + BindPrefix => Action.Bind, + ConnectPrefix => Action.Connect, + _ => null + }; + } + + public override void SetValue(object component, object value) + { + } + } + + class ProtocolDescriptor : SimplePropertyDescriptor + { + + public ProtocolDescriptor() + : base(typeof(string), nameof(Protocol), typeof(Protocol)) + { + } + + public override TypeConverter Converter => TypeDescriptor.GetConverter(typeof(Protocol)); + + public override object GetValue(object component) + { + return GetProtocol(component) switch + { + "inproc" => Protocol.InProc, + "tcp" => Protocol.Tcp, + "ipc" => Protocol.Ipc, + "pgm" => Protocol.Pgm, + "epgm" => Protocol.Epgm, + _ => throw new ArgumentException("Invalid protocol type string"), + }; + } + + public override void SetValue(object component, object value) + { + } + } + + class AddressDescriptor : SimplePropertyDescriptor + { + public AddressDescriptor() + : base(typeof(string), "Address", typeof(string)) + { + } + + public override object GetValue(object component) + { + return GetAddress(component); + } + + public override void SetValue(object component, object value) + { + } + } + + internal enum Action + { + Connect, + Bind + } + + internal enum Protocol + { + InProc, + Tcp, + Ipc, + Pgm, + Epgm + } + } +} diff --git a/src/Bonsai.ZeroMQ/Constants.cs b/src/Bonsai.ZeroMQ/Constants.cs new file mode 100644 index 0000000..60212ce --- /dev/null +++ b/src/Bonsai.ZeroMQ/Constants.cs @@ -0,0 +1,7 @@ +namespace Bonsai.ZeroMQ +{ + internal static class Constants + { + internal const string DefaultConnectionString = "tcp://localhost:5557"; + } +} diff --git a/src/Bonsai.ZeroMQ/Dealer.cs b/src/Bonsai.ZeroMQ/Dealer.cs index f843bf4..a2daeb3 100644 --- a/src/Bonsai.ZeroMQ/Dealer.cs +++ b/src/Bonsai.ZeroMQ/Dealer.cs @@ -14,10 +14,10 @@ namespace Bonsai.ZeroMQ public class Dealer : Source { /// - /// Gets or sets a value specifying the of the socket. + /// Gets or sets a value specifying the connection string of the socket. /// - [TypeConverter(typeof(ConnectionIdConverter))] - public ConnectionId ConnectionId { get; set; } = new ConnectionId(SocketSettings.SocketConnection.Connect, SocketSettings.SocketProtocol.TCP, "localhost", "5557"); + [TypeConverter(typeof(ConnectionStringConverter))] + public string ConnectionString { get; set; } = Constants.DefaultConnectionString; /// /// If no sequence is provided as source, creates a Dealer socket that acts only as a server listener. @@ -43,7 +43,7 @@ public IObservable Generate(IObservable message) { return Observable.Create((observer, cancellationToken) => { - var dealer = new DealerSocket(ConnectionId.ToString()); + var dealer = new DealerSocket(ConnectionString); cancellationToken.Register(() => { dealer.Dispose(); }); if (message != null) diff --git a/src/Bonsai.ZeroMQ/Publisher.cs b/src/Bonsai.ZeroMQ/Publisher.cs index 3889977..acb09a8 100644 --- a/src/Bonsai.ZeroMQ/Publisher.cs +++ b/src/Bonsai.ZeroMQ/Publisher.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using System.Reactive.Linq; using Bonsai.Osc; @@ -13,10 +13,10 @@ namespace Bonsai.ZeroMQ public class Publisher : Combinator { /// - /// Gets or sets a value specifying the of the socket. + /// Gets or sets a value specifying the connection string of the socket. /// - [TypeConverter(typeof(ConnectionIdConverter))] - public ConnectionId ConnectionId { get; set; } = new ConnectionId(SocketSettings.SocketConnection.Connect, SocketSettings.SocketProtocol.TCP, "localhost", "5557"); + [TypeConverter(typeof(ConnectionStringConverter))] + public string ConnectionString { get; set; } = Constants.DefaultConnectionString; /// /// Gets or sets a value specifying the topic of sent messages. @@ -24,7 +24,7 @@ public class Publisher : Combinator public string Topic { get; set; } /// - /// Creates a publisher socket with the specified + /// Creates a publisher socket with the specified /// /// /// A sequence to be sent by the socket. @@ -36,7 +36,7 @@ public override IObservable Process(IObservable source) { return Observable.Using(() => { - var pub = new PublisherSocket(ConnectionId.ToString()); + var pub = new PublisherSocket(ConnectionString); return pub; }, pub => source.Select(message => { diff --git a/src/Bonsai.ZeroMQ/Pull.cs b/src/Bonsai.ZeroMQ/Pull.cs index 9d8e72a..92d0ab8 100644 --- a/src/Bonsai.ZeroMQ/Pull.cs +++ b/src/Bonsai.ZeroMQ/Pull.cs @@ -13,13 +13,13 @@ namespace Bonsai.ZeroMQ public class Pull : Source { /// - /// Gets or sets a value specifying the of the socket. + /// Gets or sets a value specifying the connection string of the socket. /// - [TypeConverter(typeof(ConnectionIdConverter))] - public ConnectionId ConnectionId { get; set; } = new ConnectionId(SocketSettings.SocketConnection.Connect, SocketSettings.SocketProtocol.TCP, "localhost", "5557"); + [TypeConverter(typeof(ConnectionStringConverter))] + public string ConnectionString { get; set; } = Constants.DefaultConnectionString; /// - /// Creates a Pull socket with the specified . + /// Creates a Pull socket with the specified . /// /// /// A sequence of representing received messages from the Pull socket. @@ -28,7 +28,7 @@ public override IObservable Generate() { return Observable.Create((observer, cancellationToken) => { - var pull = new PullSocket(ConnectionId.ToString()); + var pull = new PullSocket(ConnectionString); return Task.Factory.StartNew(() => { diff --git a/src/Bonsai.ZeroMQ/Push.cs b/src/Bonsai.ZeroMQ/Push.cs index c3180e6..bd8760a 100644 --- a/src/Bonsai.ZeroMQ/Push.cs +++ b/src/Bonsai.ZeroMQ/Push.cs @@ -13,13 +13,13 @@ namespace Bonsai.ZeroMQ public class Push : Combinator { /// - /// Gets or sets a value specifying the of the socket. + /// Gets or sets a value specifying the connection string of the socket. /// - [TypeConverter(typeof(ConnectionIdConverter))] - public ConnectionId ConnectionId { get; set; } = new ConnectionId(SocketSettings.SocketConnection.Connect, SocketSettings.SocketProtocol.TCP, "localhost", "5557"); + [TypeConverter(typeof(ConnectionStringConverter))] + public string ConnectionString { get; set; } = Constants.DefaultConnectionString; /// - /// Creates a Push socket with the specified . + /// Creates a Push socket with the specified . /// /// /// A sequence to be sent by the socket. @@ -31,7 +31,7 @@ public override IObservable Process(IObservable source) { return Observable.Using(() => { - var push = new PushSocket(ConnectionId.ToString()); + var push = new PushSocket(ConnectionString); return push; }, push => source.Select(message => { diff --git a/src/Bonsai.ZeroMQ/Request.cs b/src/Bonsai.ZeroMQ/Request.cs index cb65b72..f988acd 100644 --- a/src/Bonsai.ZeroMQ/Request.cs +++ b/src/Bonsai.ZeroMQ/Request.cs @@ -13,13 +13,13 @@ namespace Bonsai.ZeroMQ public class Request : Combinator { /// - /// Gets or sets a value specifying the of the socket. + /// Gets or sets a value specifying the connection string of the socket. /// - [TypeConverter(typeof(ConnectionIdConverter))] - public ConnectionId ConnectionId { get; set; } = new ConnectionId(SocketSettings.SocketConnection.Connect, SocketSettings.SocketProtocol.TCP, "localhost", "5557"); + [TypeConverter(typeof(ConnectionStringConverter))] + public string ConnectionString { get; set; } = Constants.DefaultConnectionString; /// - /// Creates a request socket with the specified + /// Creates a request socket with the specified /// /// /// A sequence to be sent by the socket. @@ -31,7 +31,7 @@ public override IObservable Process(IObservable source) { return Observable.Using(() => { - var request = new RequestSocket(ConnectionId.ToString()); + var request = new RequestSocket(ConnectionString); return request; }, request => source.Select( @@ -49,4 +49,4 @@ public override IObservable Process(IObservable source) );; } } -} \ No newline at end of file +} diff --git a/src/Bonsai.ZeroMQ/Response.cs b/src/Bonsai.ZeroMQ/Response.cs index b488497..d009327 100644 --- a/src/Bonsai.ZeroMQ/Response.cs +++ b/src/Bonsai.ZeroMQ/Response.cs @@ -13,13 +13,14 @@ namespace Bonsai.ZeroMQ public class Response : Combinator { /// - /// Gets or sets a value specifying the of the socket. + /// Gets or sets a value specifying the connection string of the socket. /// - [TypeConverter(typeof(ConnectionIdConverter))] - public ConnectionId ConnectionId { get; set; } = new ConnectionId(SocketSettings.SocketConnection.Connect, SocketSettings.SocketProtocol.TCP, "localhost", "5557"); + [TypeConverter(typeof(ConnectionStringConverter))] + public string ConnectionString { get; set; } = Constants.DefaultConnectionString; /// - /// Creates a response socket with the specified . + /// + /// Creates a response socket with the specified . /// /// /// A sequence to be sent by the socket. @@ -31,7 +32,7 @@ public override IObservable Process(IObservable source) { return Observable.Using(() => { - var response = new ResponseSocket(ConnectionId.ToString()); + var response = new ResponseSocket(ConnectionString); return response; }, response => source.Select( @@ -50,4 +51,4 @@ public override IObservable Process(IObservable source) ); ; } } -} \ No newline at end of file +} diff --git a/src/Bonsai.ZeroMQ/Router.cs b/src/Bonsai.ZeroMQ/Router.cs index 2934384..599ae3d 100644 --- a/src/Bonsai.ZeroMQ/Router.cs +++ b/src/Bonsai.ZeroMQ/Router.cs @@ -14,10 +14,10 @@ namespace Bonsai.ZeroMQ public class Router : Source { /// - /// Gets or sets a value specifying the of the socket. + /// Gets or sets a value specifying the connection string of the socket. /// - [TypeConverter(typeof(ConnectionIdConverter))] - public ConnectionId ConnectionId { get; set; } = new ConnectionId(SocketSettings.SocketConnection.Bind, SocketSettings.SocketProtocol.TCP, "localhost", "5557"); + [TypeConverter(typeof(ConnectionStringConverter))] + public string ConnectionString { get; set; } = Constants.DefaultConnectionString; /// /// If no sequence is provided as source, creates a Router socket that acts only as a client listener. @@ -43,7 +43,7 @@ public IObservable Generate(IObservable> m { return Observable.Create((observer, cancellationToken) => { - var router = new RouterSocket(ConnectionId.ToString()); + var router = new RouterSocket(ConnectionString); cancellationToken.Register(() => { router.Dispose(); }); if (message != null) diff --git a/src/Bonsai.ZeroMQ/SocketSettings.cs b/src/Bonsai.ZeroMQ/SocketSettings.cs deleted file mode 100644 index cdb8935..0000000 --- a/src/Bonsai.ZeroMQ/SocketSettings.cs +++ /dev/null @@ -1,135 +0,0 @@ -using System; - -namespace Bonsai.ZeroMQ -{ - /// - /// Utility definitions and methods for defining socket settings. - /// - public static class SocketSettings - { - /// - /// Specifies a socket's connection type. - /// - public enum SocketConnection { - /// - /// Specifies a socket that will connect. - /// - Connect, - - /// - /// Specifies a socket that will bind. - /// - Bind - } - - /// - /// Specifies the network protocol to be used by a socket. - /// - public enum SocketProtocol { - /// - /// Specifies the socket will use Transmission Control protocol. - /// - TCP, - - /// - /// Specifies the socket will use the In-Process Transport protocol. - /// - InProc, - - /// - /// Specifies the socket will use the Pragmatic General Multicast protocol. - /// - PGM - } - - /// - /// Converts a character specifying the socket connection type to the appropriate . - /// - /// - /// The socket connection character. - /// - /// - /// A of the corresponding connection type. - /// - public static SocketConnection CharAsSocketConnection(char inputChar) - { - switch (inputChar) - { - case '@': - return SocketConnection.Bind; - case '>': - return SocketConnection.Connect; - default: - throw new ArgumentException("Invalid connection type char"); - } - } - - /// - /// Converts a string specifying the socket protocol to the appropriate . - /// - /// - /// The socket protocol string. - /// - /// - /// A of the corresponding protocol type. - /// - public static SocketProtocol StringAsSocketProtocol(string inputString) - { - switch (inputString) - { - case "tcp": - return SocketProtocol.TCP; - case "pgm": - return SocketProtocol.PGM; - case "inproc": - return SocketProtocol.InProc; - default: - throw new ArgumentException("Invalid protocol type string"); - } - } - - /// - /// Converts a to a representative string. - /// - /// - /// The type. - /// - /// - /// A string representing the socket connection type. - /// - public static string ConnectionString(SocketConnection connection) - { - switch (connection) - { - case SocketSettings.SocketConnection.Connect: - return ">"; - case SocketSettings.SocketConnection.Bind: - return "@"; - } - return ""; - } - - /// - /// Converts a to a representative string. - /// - /// - /// The type. - /// - /// - /// A string representing the socket protocol type. - /// - public static string ProtocolString(SocketProtocol protocol) - { - switch (protocol) - { - case SocketSettings.SocketProtocol.TCP: - return "tcp"; - case SocketSettings.SocketProtocol.InProc: - return "inproc"; - case SocketSettings.SocketProtocol.PGM: - return "pgm"; - } - return ""; - } - } -} diff --git a/src/Bonsai.ZeroMQ/Subscriber.cs b/src/Bonsai.ZeroMQ/Subscriber.cs index db68be0..8f5c7ef 100644 --- a/src/Bonsai.ZeroMQ/Subscriber.cs +++ b/src/Bonsai.ZeroMQ/Subscriber.cs @@ -13,10 +13,10 @@ namespace Bonsai.ZeroMQ public class Subscriber : Source { /// - /// Gets or sets a value specifying the of the socket. + /// Gets or sets a value specifying the connection string for the socket. /// - [TypeConverter(typeof(ConnectionIdConverter))] - public ConnectionId ConnectionId { get; set; } = new ConnectionId(SocketSettings.SocketConnection.Connect, SocketSettings.SocketProtocol.TCP, "localhost", "5557"); + [TypeConverter(typeof(ConnectionStringConverter))] + public string ConnectionString { get; set; } = Constants.DefaultConnectionString; /// /// Gets or sets a value specifying the topic that the socket will subscribe to. @@ -24,7 +24,7 @@ public class Subscriber : Source public string Topic { get; set; } /// - /// Creates a subscriber socket with the specified . + /// Creates a subscriber socket with the specified . /// /// /// A sequence of representing received messages from the subscriber socket. @@ -33,7 +33,7 @@ public override IObservable Generate() { return Observable.Create((observer, cancellationToken) => { - var sub = new SubscriberSocket(ConnectionId.ToString()); + var sub = new SubscriberSocket(ConnectionString); sub.Subscribe(Topic); return Task.Factory.StartNew(() =>