Ejemplo n.º 1
0
        /// <summary>
        /// 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 async void MessageReceivedHandler(object aSender, MessageReceivedEventArgs aArgs)
        {
            var msg = aArgs.Message;

            switch (msg)
            {
            case Log l:
                Log?.Invoke(this, new LogEventArgs(l));
                break;

            case DeviceAdded d:
                var dev = new ButtplugClientDevice(_bpLogManager, this, SendDeviceMessageAsync, d);
                _devices.Add(d.DeviceIndex, dev);
                DeviceAdded?.Invoke(this, new DeviceAddedEventArgs(dev));
                break;

            case DeviceRemoved d:
                if (!_devices.ContainsKey(d.DeviceIndex))
                {
                    ErrorReceived?.Invoke(this,
                                          new ButtplugExceptionEventArgs(
                                              new ButtplugDeviceException(_bpLogger,
                                                                          "Got device removed message for unknown device.",
                                                                          msg.Id)));
                    return;
                }

                var oldDev = _devices[d.DeviceIndex];
                _devices.Remove(d.DeviceIndex);
                DeviceRemoved?.Invoke(this, new DeviceRemovedEventArgs(oldDev));
                break;

            case ScanningFinished _:
                // The scanning finished event is self explanatory and doesn't require extra arguments.
                ScanningFinished?.Invoke(this, new EventArgs());
                break;

            case Error e:
                // This will both log the error and fire it from our ErrorReceived event handler.
                ErrorReceived?.Invoke(this, new ButtplugExceptionEventArgs(ButtplugException.FromError(_bpLogger, e)));

                if (e.ErrorCode == Error.ErrorClass.ERROR_PING)
                {
                    PingTimeout?.Invoke(this, EventArgs.Empty);
                    await DisconnectAsync().ConfigureAwait(false);
                }

                break;

            default:
                ErrorReceived?.Invoke(this,
                                      new ButtplugExceptionEventArgs(
                                          new ButtplugMessageException(_bpLogger,
                                                                       $"Got unhandled message: {msg}",
                                                                       msg.Id)));
                break;
            }
        }
        /// <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;
                }
            }
        }
Ejemplo n.º 3
0
        private void ScanningFinishedHandler(object aObj, EventArgs aEvent)
        {
            if (_sentFinished)
            {
                return;
            }

            var done = true;

            _managers.ForEach(aMgr => done &= !aMgr.IsScanning());
            if (!done)
            {
                return;
            }

            _sentFinished = true;
            ScanningFinished?.Invoke(this, new EventArgs());
        }
Ejemplo n.º 4
0
        private void ScanningFinishedHandler(object aObj, EventArgs aEvent)
        {
            // If we're in the middle of starting a scan, or we've already send ScanningFinished, bail
            if (_isStartingScan || _sentFinished)
            {
                return;
            }

            var done = true;

            _managers.ForEach(aMgr => done &= !aMgr.IsScanning());
            if (!done)
            {
                return;
            }

            _sentFinished = true;
            _isScanning   = false;
            ScanningFinished?.Invoke(this, new EventArgs());
        }
Ejemplo n.º 5
0
        public void SorterCallback(UIntPtr buf, int buf_length)
        {
            Span <byte> byteArray;

            unsafe
            {
                byteArray = new Span <byte>(buf.ToPointer(), buf_length);
            }
            var server_message = ButtplugFFIServerMessage.Parser.ParseFrom(byteArray.ToArray());

            if (server_message.Id > 0)
            {
                _messageSorter.CheckMessage(server_message);
            }
            else if (server_message.Message.MsgCase == ButtplugFFIServerMessage.Types.FFIMessage.MsgOneofCase.ServerMessage)
            {
                if (server_message.Message.ServerMessage.MsgCase == ServerMessage.MsgOneofCase.DeviceAdded)
                {
                    var device_added_message = server_message.Message.ServerMessage.DeviceAdded;
                    var device_handle        = ButtplugFFI.SendCreateDevice(_clientHandle, device_added_message.Index);
                    var attribute_dict       = new Dictionary <ServerMessage.Types.MessageAttributeType, ButtplugMessageAttributes>();
                    for (var i = 0; i < device_added_message.MessageAttributes.Count; ++i)
                    {
                        var attributes = device_added_message.MessageAttributes[i];
                        var device_message_attributes = new ButtplugMessageAttributes(attributes.FeatureCount, attributes.StepCount.ToArray(),
                                                                                      attributes.Endpoints.ToArray(), attributes.MaxDuration.ToArray(), null, null);
                        attribute_dict.Add(attributes.MessageType, device_message_attributes);
                    }
                    var device = new ButtplugClientDevice(_messageSorter, device_handle, device_added_message.Index, device_added_message.Name, attribute_dict);
                    _devices.Add(device_added_message.Index, device);
                    DeviceAdded.Invoke(this, new DeviceAddedEventArgs(device));
                }
                else if (server_message.Message.ServerMessage.MsgCase == ServerMessage.MsgOneofCase.DeviceRemoved)
                {
                    var device_removed_message = server_message.Message.ServerMessage.DeviceRemoved;
                    var device = _devices[device_removed_message.Index];
                    _devices.Remove(device_removed_message.Index);
                    DeviceRemoved.Invoke(this, new DeviceRemovedEventArgs(device));
                }
                else if (server_message.Message.ServerMessage.MsgCase == ServerMessage.MsgOneofCase.Disconnect)
                {
                    Connected = false;
                    ServerDisconnect?.Invoke(this, null);
                }
                else if (server_message.Message.ServerMessage.MsgCase == ServerMessage.MsgOneofCase.Error)
                {
                    var errorMsg = server_message.Message.ServerMessage.Error;
                    var error    = ButtplugException.FromError(errorMsg);
                    if (error is ButtplugPingException)
                    {
                        PingTimeout?.Invoke(this, null);
                    }
                    ErrorReceived?.Invoke(this, new ButtplugExceptionEventArgs(error));
                }
                else if (server_message.Message.ServerMessage.MsgCase == ServerMessage.MsgOneofCase.ScanningFinished)
                {
                    ScanningFinished?.Invoke(this, null);
                }
                else
                {
                    // We should probably do something here with unhandled events, but I'm not particularly sure what. I miss pattern matching. :(
                }
            }
            else
            {
                // We should probably do something here with unhandled events, but I'm not particularly sure what. I miss pattern matching. :(
            }
        }
Ejemplo n.º 6
0
        private async void wsReader(CancellationToken aToken)
        {
            var sb = new StringBuilder();

            while (_ws != null && _ws.State == WebSocketState.Open && !aToken.IsCancellationRequested)
            {
                try
                {
                    var buffer  = new byte[5];
                    var segment = new ArraySegment <byte>(buffer);
                    WebSocketReceiveResult result;
                    try
                    {
                        result = await _ws.ReceiveAsync(segment, aToken);
                    }
                    catch (OperationCanceledException)
                    {
                        // If the operation is cancelled, just continue so we fall out of the loop
                        continue;
                    }

                    var input = Encoding.UTF8.GetString(buffer, 0, result.Count);

                    sb.Append(input);
                    if (result.EndOfMessage)
                    {
                        var msgs = Deserialize(sb.ToString());
                        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.Invoke(() =>
                                {
                                    Log?.Invoke(this, new LogEventArgs(l));
                                });
                                break;

                            case DeviceAdded d:
                                var dev = new ButtplugClientDevice(d);
                                _devices.AddOrUpdate(d.DeviceIndex, dev, (idx, old) => dev);
                                _owningDispatcher.Invoke(() =>
                                {
                                    DeviceAdded?.Invoke(this, new DeviceEventArgs(dev, DeviceAction.ADDED));
                                });
                                break;

                            case DeviceRemoved d:
                                if (_devices.TryRemove(d.DeviceIndex, out ButtplugClientDevice oldDev))
                                {
                                    _owningDispatcher.Invoke(() =>
                                    {
                                        DeviceRemoved?.Invoke(this, new DeviceEventArgs(oldDev, DeviceAction.REMOVED));
                                    });
                                }

                                break;

                            case ScanningFinished sf:
                                _owningDispatcher.Invoke(() =>
                                {
                                    ScanningFinished?.Invoke(this, new ScanningFinishedEventArgs(sf));
                                });
                                break;

                            case Error e:
                                _owningDispatcher.Invoke(() =>
                                {
                                    ErrorReceived?.Invoke(this, new ErrorEventArgs(e));
                                });
                                break;
                            }
                        }

                        sb.Clear();
                    }
                }
                catch (WebSocketException)
                {
                    // Noop - WS probably closed on us during read
                }
            }
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="ScanningFinishedEventArgs"/> class.
 /// </summary>
 /// <param name="aMsg">A B******g ScanningFinished message.</param>
 public ScanningFinishedEventArgs(ScanningFinished aMsg)
 {
     Message = aMsg;
 }
Ejemplo n.º 8
0
        public async Task <TestSolution> GetTestSolutionAsync(Solution solution, string testSettings)
        {
            try
            {
                Interlocked.Increment(ref _sessionCount);
                ScanningStarted?.Invoke(this, EventArgs.Empty);

                var testSolution = new TestSolution(solution.Properties.Item("Name").Value as string, solution.FileName);

                var testAdapters     = new HashSet <ITestAdapter>();
                var testAdapterModes = new HashSet <TestAdapterMode>();
                var projects         = solution.GetProjects();
                foreach (Project project in projects)
                {
                    var assemblyName = project.GetAssemblyName();

                    if (assemblyName == null)
                    {
                        continue;
                    }

                    var isTestSource     = false;
                    var testAdapterNames = new List <string>();
                    foreach (var testAdapter in _testAdapterRepository.Adapters.Values)
                    {
                        if (testAdapter.IsTestSource(project))
                        {
                            testAdapters.Add(testAdapter);
                            testAdapterModes.Add(testAdapter.Mode);
                            testAdapterNames.Add(testAdapter.Name);
                            isTestSource = true;
                        }
                    }

                    if (isTestSource)
                    {
                        var outputFilePath = project.GetOutputDllPath();
                        var testProject    = new TestProject(testSolution, project.Name, outputFilePath, testAdapterNames.ToArray());

                        testSolution.TestAssemblies.Add(assemblyName);
                    }
                    else
                    {
                        testSolution.CodeAssemblies.Add(assemblyName);
                    }
                }

                if (testAdapterModes.Count == 1)
                {
                    _options.TestAdapterMode = testAdapterModes.First();
                }

                foreach (var testAdapter in testAdapters.ToArray())
                {
                    if (testAdapter.Mode != _options.TestAdapterMode)
                    {
                        testAdapters.Remove(testAdapter);
                    }
                }

                await Task.Run(() =>
                {
                    try
                    {
                        var testDiscoveryTasks = testAdapters
                                                 .Select(p => new TestDiscoveryTask()
                        {
                            TestAssemblyPaths = testSolution.Children
                                                .OfType <TestProject>()
                                                .Where(q => q.TestAdapters.Contains(p.Name))
                                                .Select(q => q.OutputFilePath)
                                                .ToArray(),
                            TestAdapterOptions = p
                                                 .GetLoadingOptions()
                                                 .Do(q => q.IsRedirectingAssemblies = _options.IsRedirectingFrameworkAssemblies)
                        })
                                                 .ToArray();

                        using (var discoveryProcess = DiscoveryProcess.Create(AdapterExtensions.GetTestPlatformAssemblyPaths(_options.TestAdapterMode)))
                        {
                            _editorContext.WriteToLog(Resources.TestDiscoveryStarted);
                            discoveryProcess.MessageReceived += (o, e) => _editorContext.WriteToLog(e.Value);
                            discoveryProcess.OutputReceived  += (o, e) => _editorContext.WriteToLog(e.Value);

                            var discoveryResults = discoveryProcess.DiscoverTests(testDiscoveryTasks, testSettings);

                            var testCasesByAssembly = discoveryResults
                                                      .Distinct(_testCaseEqualityComparer)
                                                      .GroupBy(p => p.Source)
                                                      .ToDictionary(p => p.Key, p => p.ToArray(), StringComparer.OrdinalIgnoreCase);

                            foreach (TestProject testProject in testSolution.Children.ToArray())
                            {
                                var testCases = testCasesByAssembly.TryGetValue(testProject.OutputFilePath);
                                if (testCases != null)
                                {
                                    LoadTests(testProject, testCases);
                                }

                                var isEmpty = !testProject
                                              .Flatten <TestItem>(p => p.Children, false)
                                              .Any(p => p.Kind == CodeItemKind.Method);
                                if (isEmpty)
                                {
                                    testProject.Remove();
                                }
                            }

                            _editorContext.WriteToLog(Resources.TestDiscoveryFinished);
                        }
                    }
                    catch (RemoteException exception) when(exception.RemoteReason != null)
                    {
                        _editorContext.WriteToLog(Resources.TestDiscoveryFailed);
                        _telemetryManager.UploadExceptionAsync(exception.RemoteReason);
                    }
                    catch (Exception exception)
                    {
                        _editorContext.WriteToLog(Resources.TestDiscoveryFailed);
                        _telemetryManager.UploadExceptionAsync(exception);
                    }
                });

                ScanningFinished?.Invoke(this, EventArgs.Empty);

                return(testSolution);
            }
            finally
            {
                Interlocked.Decrement(ref _sessionCount);
            }
        }
 protected void InvokeScanningFinished()
 {
     ScanningFinished?.Invoke(this, new EventArgs());
 }
Ejemplo n.º 10
0
        protected void SorterCallbackHandler(IntPtr buf, int buf_length)
        {
            // Process the data BEFORE we throw to the C# executor, otherwise
            // Rust will clean up the memory and we'll have nothing to read
            // from, meaning a null message at best and a crash at worst.
            Span <byte> byteArray;

            unsafe
            {
                byteArray = new Span <byte>(buf.ToPointer(), buf_length);
            }
            var server_message = ButtplugFFIServerMessage.Parser.ParseFrom(byteArray.ToArray());

            // Run the response in the context of the C# executor, not the Rust
            // thread. This means that if something goes wrong we at least
            // aren't blocking a rust executor thread.
            Task.Run(() =>
            {
                if (server_message.Id > 0)
                {
                    _messageSorter.CheckMessage(server_message);
                }
                else if (server_message.Message.MsgCase == ButtplugFFIServerMessage.Types.FFIMessage.MsgOneofCase.ServerMessage)
                {
                    if (server_message.Message.ServerMessage.MsgCase == ServerMessage.MsgOneofCase.DeviceAdded)
                    {
                        var device_added_message = server_message.Message.ServerMessage.DeviceAdded;
                        if (_devices.ContainsKey(device_added_message.Index))
                        {
                            ErrorReceived?.Invoke(this, new ButtplugExceptionEventArgs(new ButtplugDeviceException("A duplicate device index was received. This is most likely a bug, please file at https://github.com/buttplugio/b******g-rs-ffi")));
                            return;
                        }
                        var device_handle  = ButtplugFFI.SendCreateDevice(_clientHandle, device_added_message.Index);
                        var attribute_dict = new Dictionary <ServerMessage.Types.MessageAttributeType, ButtplugMessageAttributes>();
                        for (var i = 0; i < device_added_message.MessageAttributes.Count; ++i)
                        {
                            var attributes = device_added_message.MessageAttributes[i];
                            var device_message_attributes = new ButtplugMessageAttributes(attributes.FeatureCount, attributes.StepCount.ToArray(),
                                                                                          attributes.Endpoints.ToArray(), attributes.MaxDuration.ToArray(), null, null);
                            attribute_dict.Add(attributes.MessageType, device_message_attributes);
                        }
                        var device = new ButtplugClientDevice(_messageSorter, device_handle, device_added_message.Index, device_added_message.Name, attribute_dict, SorterCallbackDelegate, GCHandle.ToIntPtr(_indexHandle));
                        _devices.Add(device_added_message.Index, device);
                        DeviceAdded?.Invoke(this, new DeviceAddedEventArgs(device));
                    }
                    else if (server_message.Message.ServerMessage.MsgCase == ServerMessage.MsgOneofCase.DeviceRemoved)
                    {
                        var device_removed_message = server_message.Message.ServerMessage.DeviceRemoved;
                        if (!_devices.ContainsKey(device_removed_message.Index))
                        {
                            // Device was removed from our dict before we could remove it ourselves.
                            return;
                        }
                        try
                        {
                            var device = _devices[device_removed_message.Index];
                            _devices.Remove(device_removed_message.Index);
                            DeviceRemoved?.Invoke(this, new DeviceRemovedEventArgs(device));
                        }
                        catch (KeyNotFoundException)
                        {
                            ErrorReceived?.Invoke(this, new ButtplugExceptionEventArgs(new ButtplugDeviceException($"Cannot remove device index {device_removed_message.Index}, device not found.")));
                        }
                    }
                    else if (server_message.Message.ServerMessage.MsgCase == ServerMessage.MsgOneofCase.Disconnect)
                    {
                        Connected = false;
                        _devices.Clear();
                        ServerDisconnect?.Invoke(this, null);
                    }
                    else if (server_message.Message.ServerMessage.MsgCase == ServerMessage.MsgOneofCase.Error)
                    {
                        var errorMsg = server_message.Message.ServerMessage.Error;
                        var error    = ButtplugException.FromError(errorMsg);
                        if (error is ButtplugPingException)
                        {
                            PingTimeout?.Invoke(this, null);
                        }
                        ErrorReceived?.Invoke(this, new ButtplugExceptionEventArgs(error));
                    }
                    else if (server_message.Message.ServerMessage.MsgCase == ServerMessage.MsgOneofCase.ScanningFinished)
                    {
                        IsScanning = false;
                        ScanningFinished?.Invoke(this, null);
                    }
                    else
                    {
                        // We should probably do something here with unhandled events, but I'm not particularly sure what. I miss pattern matching. :(
                    }
                }
                else
                {
                    // We should probably do something here with unhandled events, but I'm not particularly sure what. I miss pattern matching. :(
                }
            });
        }
Ejemplo n.º 11
0
 public void OnScanningFinished(ResultModel args)
 {
     ScanningFinished?.Invoke(this, args);
 }