/// <summary> /// Websocket Message Received event handler. Either tries to match incoming messages as /// replies to messages we've sent, or fires an event related to an incoming event, like /// device additions/removals, log messages, etc. /// </summary> /// <param name="aSender">Object sending the open event, unused.</param> /// <param name="aArgs">Event parameters, including the data received.</param> private void MessageReceivedHandler(object aSender, WebSocket4Net.MessageReceivedEventArgs aArgs) { var msgs = Deserialize(aArgs.Message); foreach (var msg in msgs) { if (msg.Id > 0 && _waitingMsgs.TryRemove(msg.Id, out TaskCompletionSource <ButtplugMessage> queued)) { queued.TrySetResult(msg); continue; } switch (msg) { case Log l: _owningDispatcher.Send(_ => { Log?.Invoke(this, new LogEventArgs(l)); }, null); break; case DeviceAdded d: var dev = new ButtplugClientDevice(d); _devices.AddOrUpdate(d.DeviceIndex, dev, (idx, old) => dev); _owningDispatcher.Send(_ => { DeviceAdded?.Invoke(this, new DeviceEventArgs(dev, DeviceEventArgs.DeviceAction.ADDED)); }, null); break; case DeviceRemoved d: if (_devices.TryRemove(d.DeviceIndex, out ButtplugClientDevice oldDev)) { _owningDispatcher.Send(_ => { DeviceRemoved?.Invoke(this, new DeviceEventArgs(oldDev, DeviceEventArgs.DeviceAction.REMOVED)); }, null); } break; case ScanningFinished sf: _owningDispatcher.Send(_ => { ScanningFinished?.Invoke(this, new ScanningFinishedEventArgs(sf)); }, null); break; case Error e: _owningDispatcher.Send(_ => { ErrorReceived?.Invoke(this, new ErrorEventArgs(e)); }, null); break; } } }
/// <summary> /// Sends a DeviceMessage (e.g. <see cref="VibrateCmd"/> or <see cref="LinearCmd"/>). Handles /// constructing some parts of the message for the user. /// </summary> /// <param name="aDevice">The device to be controlled by the message.</param> /// <param name="aDeviceMsg">The device message (Id and DeviceIndex will be overriden).</param> /// <returns> /// <see cref="Ok"/> message on success, <see cref="Error"/> message with error info otherwise. /// </returns> public Task <ButtplugMessage> SendDeviceMessage(ButtplugClientDevice aDevice, ButtplugDeviceMessage aDeviceMsg) { if (!_devices.TryGetValue(aDevice.Index, out ButtplugClientDevice dev)) { var t = new Task <ButtplugMessage>(() => new Error("Device not available.", Error.ErrorClass.ERROR_DEVICE, ButtplugConsts.SystemMsgId)); t.Start(TaskScheduler.Default); return(t); } if (!dev.AllowedMessages.ContainsKey(aDeviceMsg.GetType().Name)) { var t = new Task <ButtplugMessage>(() => new Error("Device does not accept message type: " + aDeviceMsg.GetType().Name, Error.ErrorClass.ERROR_DEVICE, ButtplugConsts.SystemMsgId)); t.Start(TaskScheduler.Default); return(t); } aDeviceMsg.DeviceIndex = aDevice.Index; return(SendMessage(aDeviceMsg)); }
public void Connect(Uri aURL, bool aIgnoreSSLErrors = false) { if (_ws != null && (_ws.State == WebSocketState.Connecting || _ws.State == WebSocketState.Open)) { throw new InvalidOperationException("Already connected!"); } _bpLogger.Trace("Opening connection"); _ws = new WebSocket(aURL.ToString()); _waitingMsgs.Clear(); _devices.Clear(); _counter = 1; _connectedOrFailed = new TaskCompletionSource <bool>(); _disconnected = new TaskCompletionSource <bool>(); _ws.Opened += OpenedHandler; _ws.Closed += ClosedHandler; _ws.Error += ErrorHandler; if (aIgnoreSSLErrors) { _ws.Security.AllowNameMismatchCertificate = true; _ws.Security.AllowUnstrustedCertificate = true; _ws.Security.AllowCertificateChainErrors = true; } _ws.Open(); _connecting = true; _connectedOrFailed.Task.Wait(); _connecting = false; if (_ws.State != WebSocketState.Open) { throw new Exception("Connection failed!"); } _bpLogger.Trace("Connected"); _ws.MessageReceived += MessageReceivedHandler; var res = SendMessage(new RequestServerInfo(_clientName)).Result; switch (res) { case ServerInfo si: if (si.MaxPingTime > 0) { _pingTimer = new Timer(OnPingTimer, null, 0, Convert.ToInt32(Math.Round(((double)si.MaxPingTime) / 2, 0))); } if (si.MessageVersion < 1) { throw new Exception("B******g Server's schema version (" + si.MessageVersion + ") is less than the client's (" + 1 + "). A newer server is required."); } // Get full device list and populate internal list var resp = SendMessage(new RequestDeviceList()).Result; if ((resp as DeviceList)?.Devices == null) { if (resp is Error) { _owningDispatcher.Send(_ => { ErrorReceived?.Invoke(this, new ErrorEventArgs(resp as Error)); }, null); } return; } foreach (var d in (resp as DeviceList).Devices) { if (_devices.ContainsKey(d.DeviceIndex)) { continue; } var device = new ButtplugClientDevice(d); if (_devices.TryAdd(d.DeviceIndex, device)) { _owningDispatcher.Send(_ => { DeviceAdded?.Invoke(this, new DeviceEventArgs(device, DeviceEventArgs.DeviceAction.ADDED)); }, null); } } break; case Error e: throw new Exception(e.ErrorMessage); default: throw new Exception("Unexpecte message returned: " + res.GetType()); } }
/// <summary> /// Initializes a new instance of the <see cref="DeviceEventArgs"/> class. /// </summary> /// <param name="aDevice">The B******g Device.</param> /// <param name="aAction">The action of the event.</param> public DeviceEventArgs(ButtplugClientDevice aDevice, DeviceAction aAction) { Device = aDevice; Action = aAction; }