public ButtplugServer(ButtplugServerOptions aOptions) { ButtplugUtils.ArgumentNotNull(aOptions, nameof(aOptions)); _clientName = null; _serverName = aOptions.ServerName; _maxPingTime = aOptions.MaxPingTime; _pingTimedOut = false; if (_maxPingTime != 0) { // Create a new timer that wont fire any events just yet _pingTimer = new Timer(PingTimeoutHandler, null, Timeout.Infinite, Timeout.Infinite); } BpLogManager = new ButtplugLogManager(); _bpLogger = BpLogManager.GetLogger(GetType()); _bpLogger.Debug("Setting up ButtplugServer"); _parser = new ButtplugJsonMessageParser(BpLogManager); _deviceManager = aOptions.DeviceManager ?? new DeviceManager(BpLogManager, aOptions.SubtypeManagerSearchPaths); _bpLogger.Info("Finished setting up ButtplugServer"); _deviceManager.DeviceMessageReceived += DeviceMessageReceivedHandler; _deviceManager.ScanningFinished += ScanningFinishedHandler; if (!DeviceConfigurationManager.HasManager) { DeviceConfigurationManager.LoadBaseConfigurationFromResource(); } }
/// <summary> /// Initializes a new instance of the <see cref="ButtplugClientDevice"/> class, using /// discrete parameters. /// </summary> /// <param name="aIndex">The device index.</param> /// <param name="aName">The device name.</param> /// <param name="aMessages">The device allowed message list, with corresponding attributes.</param> public ButtplugClientDevice(IButtplugLogManager aLogManager, ButtplugClient aOwningClient, Func <ButtplugClientDevice, ButtplugDeviceMessage, CancellationToken, Task> aSendClosure, uint aIndex, string aName, Dictionary <string, MessageAttributes> aMessages) { ButtplugUtils.ArgumentNotNull(aLogManager, nameof(aLogManager)); ButtplugUtils.ArgumentNotNull(aOwningClient, nameof(aOwningClient)); ButtplugUtils.ArgumentNotNull(aSendClosure, nameof(aSendClosure)); _bpLogger = aLogManager.GetLogger(GetType()); _owningClient = aOwningClient; _sendClosure = aSendClosure; Index = aIndex; Name = aName; AllowedMessages = new Dictionary <Type, MessageAttributes>(); foreach (var msg in aMessages) { var msgType = ButtplugUtils.GetMessageType(msg.Key); if (msgType == null) { throw new ButtplugDeviceException($"Message type {msg.Key} does not exist."); } AllowedMessages[msgType] = msg.Value; } }
public async Task StartServerAsync([NotNull] Func <ButtplugServer> aFactory, uint aMaxConnections = 1, int aPort = 12345, bool aLocalOnly = true, string aCertPath = null, string aKeyPath = null) { _cancellation = new CancellationTokenSource(); _serverFactory = aFactory; _maxConnections = aMaxConnections; _logManager = new ButtplugLogManager(); _logger = _logManager.GetLogger(GetType()); var endpoint = new IPEndPoint(aLocalOnly ? IPAddress.Loopback : IPAddress.Any, aPort); var options = new WebSocketListenerOptions(); options.Standards.RegisterRfc6455(); if (aCertPath != null && aKeyPath != null) { var cert = CertUtils.LoadPEMCert(aCertPath, aKeyPath); options.ConnectionExtensions.RegisterSecureConnection(cert); } _server = new WebSocketListener(endpoint, options); await _server.StartAsync().ConfigureAwait(false); _websocketTask = Task.Run(() => AcceptWebSocketClientsAsync(_server, _cancellation.Token)); }
public HidDeviceFactory(IButtplugLogManager aLogManager, IHidDeviceInfo aInfo) { _buttplugLogManager = aLogManager; _bpLogger = _buttplugLogManager.GetLogger(GetType()); _bpLogger.Trace($"Creating {GetType().Name}"); _deviceInfo = aInfo; }
/// <summary> /// Initializes a new instance of the <see cref="ButtplugJsonMessageParser"/> class. /// </summary> /// <param name="aLogManager">Log manager</param> public ButtplugJsonMessageParser(IButtplugLogManager aLogManager = null) { _bpLogger = aLogManager.GetLogger(GetType()); _bpLogger?.Info($"Setting up {GetType().Name}"); IEnumerable <Type> allTypes; // Some classes in the library may not load on certain platforms due to missing symbols. // If this is the case, we should still find messages even though an exception was thrown. try { allTypes = Assembly.GetAssembly(typeof(ButtplugMessage)).GetTypes(); } catch (ReflectionTypeLoadException e) { allTypes = e.Types; } var messageClasses = allTypes.Where(t => t != null && t.IsClass && t.Namespace == "Buttplug4Net35.Messages" && typeof(ButtplugMessage).IsAssignableFrom(t)); var enumerable = messageClasses as Type[] ?? messageClasses.ToArray(); _bpLogger?.Debug($"Message type count: {enumerable.Length}"); _messageTypes = new Dictionary <string, Type>(); enumerable.ToList().ForEach(aMessageType => { _bpLogger?.Debug($"- {aMessageType.Name}"); _messageTypes.Add(aMessageType.Name, aMessageType); }); }
public UWPBluetoothDeviceFactory([NotNull] IButtplugLogManager aLogManager, [NotNull] IBluetoothDeviceInfo aInfo) { _buttplugLogManager = aLogManager; _bpLogger = _buttplugLogManager.GetLogger(GetType()); _bpLogger.Trace($"Creating {GetType().Name}"); _deviceInfo = aInfo; }
/// <summary> /// Initializes a new instance of the <see cref="ButtplugJsonMessageParser"/> class. /// </summary> /// <param name="aLogManager">Log manager, passed from the parser owner.</param> public ButtplugJsonMessageParser([NotNull] IButtplugLogManager aLogManager) { // Set up logging. if (aLogManager == null) { throw new ArgumentNullException(nameof(aLogManager)); } _bpLogger = aLogManager.GetLogger(GetType()); _bpLogger?.Info($"Setting up {GetType().Name}"); _serializer = new JsonSerializer { MissingMemberHandling = MissingMemberHandling.Error }; _messageTypes = new Dictionary <string, Type>(); foreach (var aMessageType in ButtplugUtils.GetAllMessageTypes()) { _bpLogger?.Debug($"- {aMessageType.Name}"); _messageTypes.Add(aMessageType.Name, aMessageType); } // If we can't find any message types in our assembly, the system is basically useless. if (!_messageTypes.Any()) { throw new ButtplugMessageException(_bpLogger, "No message types available."); } // Load the schema for validation. Schema file is an embedded resource in the library. var jsonSchemaString = ButtplugUtils.GetStringFromFileResource("B******g.b******g-schema.json"); _schema = JsonSchema.FromJsonAsync(jsonSchemaString)?.GetAwaiter().GetResult() ?? throw new InvalidOperationException(); }
public KiirooPlatformEmulator() { _log = new ButtplugLogManager().GetLogger(GetType()); _httpListener = new HttpListener(); _httpListener.Prefixes.Add("http://localhost:6969/"); _stop = false; _isRunning = false; }
public UWPBluetoothDeviceInterface( [NotNull] IButtplugLogManager aLogManager, [NotNull] IBluetoothDeviceInfo aInfo, [NotNull] BluetoothLEDevice aDevice, [NotNull] GattCharacteristic[] aChars) { _bpLogger = aLogManager.GetLogger(GetType()); _bleDevice = aDevice; if (aInfo.Characteristics.Count > 0) { foreach (var item in aInfo.Characteristics) { var c = (from x in aChars where x.Uuid == item.Value select x).ToArray(); if (c.Length != 1) { var err = $"Cannot find characteristic ${item.Value} for device {Name}"; _bpLogger.Error(err); throw new Exception(err); } if (_indexedChars == null) { _indexedChars = new Dictionary <uint, GattCharacteristic>(); } _indexedChars.Add(item.Key, c[0]); } } else { foreach (var c in aChars) { if (c.CharacteristicProperties.HasFlag(GattCharacteristicProperties.Read) || c.CharacteristicProperties.HasFlag(GattCharacteristicProperties.Notify) || c.CharacteristicProperties.HasFlag(GattCharacteristicProperties.Indicate)) { _rxChar = c; } else if (c.CharacteristicProperties.HasFlag(GattCharacteristicProperties.WriteWithoutResponse) || c.CharacteristicProperties.HasFlag(GattCharacteristicProperties.Write)) { _txChar = c; } } } if (_rxChar == null && _txChar == null && _indexedChars == null) { var err = $"No characteristics to connect to for device {Name}"; _bpLogger.Error(err); throw new Exception(err); } _bleDevice.ConnectionStatusChanged += ConnectionStatusChangedHandler; }
/// <summary> /// Initializes a new instance of the <see cref="ButtplugDevice"/> class. /// </summary> /// <param name="aLogManager">The log manager</param> /// <param name="aName">The device name</param> /// <param name="aIdentifier">The device identifier</param> protected ButtplugDevice([NotNull] IButtplugLogManager aLogManager, [NotNull] string aName, [NotNull] string aIdentifier) { BpLogger = aLogManager.GetLogger(GetType()); MsgFuncs = new Dictionary <Type, ButtplugDeviceWrapper>(); Name = aName; Identifier = aIdentifier; }
/// <summary> /// Initializes a new instance of the <see cref="ButtplugJsonMessageParser"/> class. /// </summary> /// <param name="aLogManager">Log manager</param> public ButtplugJsonMessageParser(IButtplugLogManager aLogManager = null) { _bpLogger = aLogManager.GetLogger(GetType()); _bpLogger?.Info($"Setting up {GetType().Name}"); _serializer = new JsonSerializer { MissingMemberHandling = MissingMemberHandling.Error }; IEnumerable <Type> allTypes; // Some classes in the library may not load on certain platforms due to missing symbols. // If this is the case, we should still find messages even though an exception was thrown. try { allTypes = Assembly.GetAssembly(typeof(ButtplugMessage)).GetTypes(); } catch (ReflectionTypeLoadException e) { allTypes = e.Types; } var messageClasses = allTypes.Where(t => t != null && t.IsClass && t.Namespace == "B******g.Core.Messages" && typeof(ButtplugMessage).IsAssignableFrom(t)); var enumerable = messageClasses as Type[] ?? messageClasses.ToArray(); _bpLogger?.Debug($"Message type count: {enumerable.Length}"); _messageTypes = new Dictionary <string, Type>(); enumerable.ToList().ForEach(aMessageType => { _bpLogger?.Debug($"- {aMessageType.Name}"); _messageTypes.Add(aMessageType.Name, aMessageType); }); // Load the schema for validation var assembly = Assembly.GetExecutingAssembly(); const string resourceName = "B******g.Core.b******g-schema.json"; Stream stream = null; try { stream = assembly.GetManifestResourceStream(resourceName); using (var reader = new StreamReader(stream)) { stream = null; var result = reader.ReadToEnd(); _schema = JsonSchema4.FromJsonAsync(result).GetAwaiter().GetResult(); } } catch (Exception e) { _bpLogger.LogException(e); throw e; } finally { stream?.Dispose(); } }
public UWPBluetoothDeviceInterface( [NotNull] IButtplugLogManager aLogManager, [NotNull] BluetoothLEDevice aDevice, [NotNull] GattCharacteristic[] aCharacteristics) { _bpLogger = aLogManager.GetLogger(GetType()); _bleDevice = aDevice; _gattCharacteristics = aCharacteristics; _bleDevice.ConnectionStatusChanged += ConnectionStatusChangedHandler; }
public ButtplugWSClient(string aClientName) { _clientName = aClientName; _bpLogManager = new ButtplugLogManager(); _bpLogger = _bpLogManager.GetLogger(GetType()); _parser = new ButtplugJsonMessageParser(_bpLogManager); _bpLogger.Info("Finished setting up ButtplugClient"); _owningDispatcher = Dispatcher.CurrentDispatcher; _tokenSource = new CancellationTokenSource(); }
/// <summary> /// Initializes a new instance of the <see cref="ButtplugDevice"/> class. /// </summary> /// <param name="aLogManager">The log manager.</param> /// <param name="aDevice">The device implementation (Bluetooth, USB, etc).</param> /// <param name="aProtocol">The device protocol (Lovense, Launch, etc).</param> public ButtplugDevice([NotNull] IButtplugLogManager aLogManager, [NotNull] IButtplugDeviceProtocol aProtocol, [NotNull] IButtplugDeviceImpl aDevice) { // Protocol can be null if activator construction from type constructor fails ButtplugUtils.ArgumentNotNull(aProtocol, nameof(aProtocol)); _protocol = aProtocol; _device = aDevice; BpLogger = aLogManager.GetLogger(GetType()); _device.DeviceRemoved += OnDeviceRemoved; }
public VibHubDevice(string deviceId, uint aDeviceNum, VibHubManager aManager, IButtplugLogManager aLogManager) { Identifier = deviceId; _deviceNumber = aDeviceNum; _manager = aManager; _bpLogger = aLogManager.GetLogger(GetType()); _msgTypes.Add(typeof(StopDeviceCmd), new MessageAttributes()); _msgTypes.Add(typeof(SingleMotorVibrateCmd), new MessageAttributes()); _msgTypes.Add(typeof(VibrateCmd), new MessageAttributes(4)); }
public void StartServer([NotNull] Func <ButtplugServer> aFactory, string aPipeName = "ButtplugPipe") { _cancellation = new CancellationTokenSource(); _serverFactory = aFactory; _logManager = new ButtplugLogManager(); _logger = _logManager.GetLogger(GetType()); _acceptTask = new Task(async() => { await ConnectionAccepter(aPipeName, _cancellation.Token).ConfigureAwait(false); }, _cancellation.Token, TaskCreationOptions.LongRunning); _acceptTask.Start(); }
public DeviceManager(IButtplugLogManager aLogManager) { _bpLogManager = aLogManager; _bpLogger = _bpLogManager.GetLogger(GetType()); _bpLogger.Info("Setting up DeviceManager"); _sentFinished = true; _devices = new Dictionary <uint, IButtplugDevice>(); _deviceIndexCounter = 0; _managers = new List <IDeviceSubtypeManager>(); }
/// <summary> /// Initializes a new instance of the <see cref="ButtplugWSClient"/> class. /// </summary> /// <param name="aClientName">The name of the client (used by the server for UI and permissions).</param> public ButtplugWSClient(string aClientName) { _clientName = aClientName; IButtplugLogManager bpLogManager = new ButtplugLogManager(); _bpLogger = bpLogManager.GetLogger(GetType()); _parser = new ButtplugJsonMessageParser(bpLogManager); _bpLogger.Info("Finished setting up ButtplugClient"); _owningDispatcher = SynchronizationContext.Current ?? new SynchronizationContext(); _tokenSource = new CancellationTokenSource(); _counter = 0; }
public ButtplugWebsocketServerSession(IButtplugLogManager aLogManager, ButtplugServer aServer, WebSocket aSocket, CancellationTokenSource aExternalCancelSource) { _logger = aLogManager.GetLogger(GetType()); _internalCancelSource = new CancellationTokenSource(); _linkedCancelSource = CancellationTokenSource.CreateLinkedTokenSource(aExternalCancelSource.Token, _internalCancelSource.Token); _ws = aSocket; _server = aServer; _server.MessageReceived += ReceiveMessageFromServerHandler; _server.ClientConnected += ClientConnectedHandler; _server.PingTimeout += PingTimeoutHandler; }
public ServerControl(Func <ButtplugServer> aFactory) { InitializeComponent(); _logManager = new ButtplugLogManager(); _log = _logManager.GetLogger(GetType()); _ws = new ButtplugWebsocketServer(); _bpFactory = aFactory; _config = new ButtplugConfig("B******g"); _connUrls = new ConnUrlList(); _port = 12345; // Usually, if we throw errors then connect, it's not actually an error. If we don't // connect after a second of throwing an exception, pop the toaster, but not before then. _toastTimer = new Timer { Interval = 1000, AutoReset = false, Enabled = false, }; _toastTimer.Elapsed += PopToaster; if (uint.TryParse(_config.GetValue("b******g.server.port", "12345"), out uint pres)) { _port = pres; } _secure = true; if (bool.TryParse(_config.GetValue("b******g.server.secure", "true"), out bool sres)) { _secure = sres; } _loopback = true; if (bool.TryParse(_config.GetValue("b******g.server.loopbackOnly", "true"), out bool lres)) { _loopback = lres; } _hostname = _config.GetValue("b******g.server.hostname", "localhost"); PortTextBox.Text = _port.ToString(); SecureCheckBox.IsChecked = _secure; LoopbackCheckBox.IsChecked = _loopback; ConnectionUrl.ItemsSource = _connUrls; _ws.OnException += WebSocketExceptionHandler; _ws.ConnectionAccepted += WebSocketConnectionAccepted; _ws.ConnectionUpdated += WebSocketConnectionAccepted; _ws.ConnectionClosed += WebSocketConnectionClosed; _log.OnLogException += ExceptionLogged; }
/// <summary> /// Initializes a new instance of the <see cref="ButtplugClient"/> class. /// </summary> /// <param name="aClientName">The name of the client (used by the server for UI and permissions).</param> /// <param name="aConnector">Connector for the client.</param> public ButtplugClient([NotNull] string aClientName, [NotNull] IButtplugClientConnector aConnector) { ButtplugUtils.ArgumentNotNull(aConnector, nameof(aConnector)); Name = aClientName; _connector = aConnector; _connector.Disconnected += (aObj, aEventArgs) => { ServerDisconnect?.Invoke(aObj, aEventArgs); }; _connector.InvalidMessageReceived += ConnectorErrorHandler; _bpLogManager = new ButtplugLogManager(); _connector.LogManager = _bpLogManager; _bpLogger = _bpLogManager.GetLogger(GetType()); _bpLogger.Info("Finished setting up ButtplugClient"); }
/// <summary> /// Initializes a new instance of the <see cref="ButtplugJsonMessageParser"/> class. /// </summary> /// <param name="aLogManager">Log manager, passed from the parser owner.</param> public ButtplugJsonMessageParser([NotNull] IButtplugLogManager aLogManager) { // Set up logging. if (aLogManager == null) { throw new ArgumentNullException(nameof(aLogManager)); } _bpLogger = aLogManager.GetLogger(GetType()); _bpLogger?.Info($"Setting up {GetType().Name}"); _serializer = new JsonSerializer { MissingMemberHandling = MissingMemberHandling.Error }; _messageTypes = new Dictionary <string, Type>(); foreach (var aMessageType in ButtplugUtils.GetAllMessageTypes()) { _bpLogger?.Debug($"- {aMessageType.Name}"); _messageTypes.Add(aMessageType.Name, aMessageType); } // If we can't find any message types in our assembly, the system is basically useless. if (!_messageTypes.Any()) { throw new ButtplugMessageException(_bpLogger, "No message types available."); } // Load the schema for validation. Schema file is an embedded resource in the library. var assembly = Assembly.GetExecutingAssembly(); const string resourceName = "B******g.b******g-schema.json"; var stream = assembly.GetManifestResourceStream(resourceName); try { using (var reader = new StreamReader(stream ?? throw new InvalidOperationException())) { stream = null; var result = reader.ReadToEnd(); _schema = JsonSchema4.FromJsonAsync(result)?.GetAwaiter().GetResult() ?? throw new InvalidOperationException(); } } finally { // Always make sure we dispose of the resource stream, even if we throw. All // exceptions should be rethrown though. stream?.Dispose(); } }
public DeviceManager(IButtplugLogManager aLogManager, List <string> aSearchDirs = null) { ButtplugUtils.ArgumentNotNull(aLogManager, nameof(aLogManager)); _bpLogManager = aLogManager; _bpLogger = _bpLogManager.GetLogger(GetType()); _bpLogger.Info("Setting up DeviceManager"); _sentFinished = true; Devices = new Dictionary <uint, IButtplugDevice>(); DeviceIds = new Dictionary <string, uint>(); _deviceIndexCounter = 0; _isScanning = false; _managerSearchDirs = aSearchDirs ?? new List <string> { Directory.GetCurrentDirectory() }; _managers = new List <IDeviceSubtypeManager>(); }
public ButtplugService([NotNull] string aServerName, uint aMaxPingTime) { _serverName = aServerName; _maxPingTime = aMaxPingTime; _pingTimedOut = false; if (aMaxPingTime != 0) { _pingTimer = new Timer(_maxPingTime); _pingTimer.Elapsed += PingTimeoutHandler; } _bpLogManager = new ButtplugLogManager(); _bpLogger = _bpLogManager.GetLogger(GetType()); _bpLogger.Trace("Setting up ButtplugService"); _parser = new ButtplugJsonMessageParser(_bpLogManager); _deviceManager = new DeviceManager(_bpLogManager); _bpLogger.Trace("Finished setting up ButtplugService"); _deviceManager.DeviceMessageReceived += DeviceMessageReceivedHandler; _deviceManager.ScanningFinished += ScanningFinishedHandler; _bpLogManager.LogMessageReceived += LogMessageReceivedHandler; }
public ButtplugServer([NotNull] string aServerName, uint aMaxPingTime, DeviceManager aDeviceManager = null) { _serverName = aServerName; _maxPingTime = aMaxPingTime; _pingTimedOut = false; if (aMaxPingTime != 0) { // Create a new timer that wont fire any events just yet _pingTimer = new Timer(PingTimeoutHandler, null, Timeout.Infinite, Timeout.Infinite); } BpLogManager = new ButtplugLogManager(); _bpLogger = BpLogManager.GetLogger(GetType()); _bpLogger.Debug("Setting up ButtplugServer"); _parser = new ButtplugJsonMessageParser(BpLogManager); _deviceManager = aDeviceManager ?? new DeviceManager(BpLogManager); _bpLogger.Info("Finished setting up ButtplugServer"); _deviceManager.DeviceMessageReceived += DeviceMessageReceivedHandler; _deviceManager.ScanningFinished += ScanningFinishedHandler; BpLogManager.LogMessageReceived += LogMessageReceivedHandler; }
public void CheckMessage(ButtplugMessage aMsg, IButtplugLog aLog = null) { // We'll never match a system message, those are server -> client only. if (aMsg.Id == 0) { throw new ButtplugMessageException(aLog, "Cannot sort message with System ID", aMsg.Id); } // If we haven't gotten a system message and we're not currently waiting for the message // id, throw. if (!_waitingMsgs.TryRemove(aMsg.Id, out var queued)) { throw new ButtplugMessageException(aLog, "Message with non-matching ID received.", aMsg.Id); } if (aMsg is Error errMsg) { queued.SetException(ButtplugException.FromError(errMsg)); return; } queued.SetResult(aMsg); }
public void StartServer([NotNull] IButtplugServerFactory aFactory, int aPort = 12345, bool aLoopBack = true, bool aSecure = false, string aHostname = "localhost") { _cancellation = new CancellationTokenSource(); _factory = aFactory; _logManager = new ButtplugLogManager(); _logger = _logManager.GetLogger(this.GetType()); var endpoint = new IPEndPoint(aLoopBack ? IPAddress.Loopback : IPAddress.Any, aPort); _server = new WebSocketListener(endpoint); var rfc6455 = new vtortola.WebSockets.Rfc6455.WebSocketFactoryRfc6455(_server); _server.Standards.RegisterStandard(rfc6455); if (aSecure) { var cert = CertUtils.GetCert("B******g", aHostname); _server.ConnectionExtensions.RegisterExtension(new WebSocketSecureConnectionExtension(cert)); } _server.Start(); Task.Run(() => AcceptWebSocketClientsAsync(_server, _cancellation.Token)); }
/// <inheritdoc /> /// <summary> /// Creates a ButtplugException. /// </summary> /// <param name="aLogger">Logger to log exception error message through (gives type context for the message).</param> /// <param name="aMessage">Exception message.</param> /// <param name="aClass">Exception class, based on B******g Error Message Classes. (https://b******g-spec.docs.b******g.io/status.html#error)</param> /// <param name="aId">Message ID for the resulting B******g Error Message.</param> /// <param name="aInner">Optional inner exception.</param> public ButtplugException([NotNull] IButtplugLog aLogger, string aMessage, Error.ErrorClass aClass = Error.ErrorClass.ERROR_UNKNOWN, uint aId = ButtplugConsts.SystemMsgId, Exception aInner = null) : this(aMessage, aClass, aId, aInner) { ButtplugUtils.ArgumentNotNull(aLogger, nameof(aLogger)); aLogger.Error(aMessage); }
public static ButtplugException FromError(IButtplugLog aLogger, Error aMsg) { ButtplugUtils.ArgumentNotNull(aLogger, nameof(aLogger)); aLogger.Error(aMsg.ErrorMessage); return(FromError(aMsg)); }
/// <inheritdoc cref="ButtplugException" /> /// <summary> /// Initializes a new instance of the <see cref="ButtplugClientConnectorException"/> class. /// </summary> /// <param name="aLogger">Logger to log exception error message through (gives type context for the message).</param> /// <param name="aMessage">Exception message.</param> /// <param name="aClass">Exception class, based on B******g Error Message Classes. See https://b******g-spec.docs.b******g.io/status.html#error for more info.</param> /// <param name="aId">Message ID for the resulting B******g Error Message.</param> /// <param name="aInner">Optional inner exception.</param> public ButtplugClientConnectorException(IButtplugLog aLogger, string aMessage, Exception aInner = null) : base(aLogger, aMessage, Error.ErrorClass.ERROR_UNKNOWN, ButtplugConsts.SystemMsgId, aInner) { }