private void DeviceAddedHandler(object aObj, DeviceAddedEventArgs aEvent) { // If we get to 4 billion devices connected, this may be a problem. var deviceIndex = (uint)Interlocked.Increment(ref _deviceIndexCounter); // Devices can be turned off by the time they get to this point, at which point they end up null. Make sure the device isn't null. if (aEvent.Device == null) { return; } var duplicates = from x in _devices.Values where x.Identifier == aEvent.Device.Identifier select x; if (duplicates.Any()) { _bpLogger.Trace($"Already have device {aEvent.Device.Name} in Devices list"); return; } _bpLogger.Debug($"Adding Device {aEvent.Device.Name} at index {deviceIndex}"); _devices.Add(deviceIndex, aEvent.Device); aEvent.Device.DeviceRemoved += DeviceRemovedHandler; var msg = new DeviceAdded(deviceIndex, aEvent.Device.Name, GetAllowedMessageTypesAsStrings(aEvent.Device).ToArray()); DeviceMessageReceived?.Invoke(this, new MessageReceivedEventArgs(msg)); }
public async Task <IButtplugDevice> CreateDeviceAsync([NotNull] BluetoothLEDevice aDevice) { // GetGattServicesForUuidAsync is 15063 only var services = await aDevice.GetGattServicesAsync(BluetoothCacheMode.Cached); foreach (var s in services.Services) { _bpLogger.Trace("Found service UUID: " + s.Uuid); } var srvResult = await aDevice.GetGattServicesForUuidAsync(_deviceInfo.Services[0], BluetoothCacheMode.Cached); if (srvResult.Status != GattCommunicationStatus.Success || !srvResult.Services.Any()) { _bpLogger.Trace("Cannot find service for device"); return(null); } var service = srvResult.Services.First(); var chrResult = await service.GetCharacteristicsAsync(); if (chrResult.Status != GattCommunicationStatus.Success) { return(null); } var chrs = from x in chrResult.Characteristics where _deviceInfo.Characteristics.Contains(x.Uuid) select x; var gattCharacteristics = chrs as GattCharacteristic[] ?? chrs.ToArray(); if (!gattCharacteristics.Any()) { return(null); } // TODO This assumes we're always planning on having the UUIDs sorted in the Info classes, which is probably not true. var bleInterface = new UWPBluetoothDeviceInterface(_buttplugLogManager, aDevice, gattCharacteristics.OrderBy((aChr) => aChr.Uuid).ToArray()); var device = _deviceInfo.CreateDevice(_buttplugLogManager, bleInterface); if (await device.Initialize() is Ok) { return(device); } // If initialization fails, don't actually send the message back. Just return null, we'll have the info in the logs. return(null); }
public UWPBluetoothDeviceFactory([NotNull] IButtplugLogManager aLogManager, [NotNull] IBluetoothDeviceInfo aInfo) { _buttplugLogManager = aLogManager; _bpLogger = _buttplugLogManager.GetLogger(GetType()); _bpLogger.Trace($"Creating {GetType().Name}"); _deviceInfo = aInfo; }
public HidDeviceFactory(IButtplugLogManager aLogManager, IHidDeviceInfo aInfo) { _buttplugLogManager = aLogManager; _bpLogger = _buttplugLogManager.GetLogger(GetType()); _bpLogger.Trace($"Creating {GetType().Name}"); _deviceInfo = aInfo; }
public async Task <ButtplugMessage> SendMessage([NotNull] ButtplugMessage aMsg) { _bpLogger.Trace($"Got Message {aMsg.Id} of type {aMsg.GetType().Name} to send"); var id = aMsg.Id; if (id == 0) { return(_bpLogger.LogWarnMsg(id, Error.ErrorClass.ERROR_MSG, "Message Id 0 is reserved for outgoing system messages. Please use another Id.")); } if (aMsg is IButtplugMessageOutgoingOnly) { return(_bpLogger.LogWarnMsg(id, Error.ErrorClass.ERROR_MSG, $"Message of type {aMsg.GetType().Name} cannot be sent to server")); } if (_pingTimedOut) { return(_bpLogger.LogErrorMsg(id, Error.ErrorClass.ERROR_PING, "Ping timed out.")); } // If we get a message that's not RequestServerInfo first, return an error. if (!_receivedRequestServerInfo && !(aMsg is RequestServerInfo)) { return(_bpLogger.LogErrorMsg(id, Error.ErrorClass.ERROR_INIT, "RequestServerInfo must be first message received by server!")); } switch (aMsg) { case RequestLog m: _bpLogger.Debug("Got RequestLog Message"); BpLogManager.Level = m.LogLevel; return(new Ok(id)); case Ping _: // Start the timer _pingTimer?.Change((int)_maxPingTime, (int)_maxPingTime); return(new Ok(id)); case RequestServerInfo rsi: _bpLogger.Debug("Got RequestServerInfo Message"); _receivedRequestServerInfo = true; _clientMessageVersion = rsi.MessageVersion; // Start the timer _pingTimer?.Change((int)_maxPingTime, (int)_maxPingTime); ClientConnected?.Invoke(this, new MessageReceivedEventArgs(rsi)); return(new ServerInfo(_serverName, 1, _maxPingTime, id)); case Test m: return(new Test(m.TestString, id)); } return(await _deviceManager.SendMessage(aMsg)); }
public ButtplugWSClient(string aClientName) { _clientName = aClientName; _bpLogManager = new ButtplugLogManager(); _bpLogger = _bpLogManager.GetLogger(GetType()); _parser = new ButtplugJsonMessageParser(_bpLogManager); _bpLogger.Trace("Finished setting up ButtplugClient"); _owningDispatcher = Dispatcher.CurrentDispatcher; _tokenSource = new CancellationTokenSource(); }
public async Task <ButtplugMessage> SendMessage([NotNull] ButtplugMessage aMsg) { _bpLogger.Trace($"Got Message {aMsg.Id} of type {aMsg.GetType().Name} to send"); var id = aMsg.Id; if (id == 0) { return(_bpLogger.LogWarnMsg(id, Error.ErrorClass.ERROR_MSG, "Message Id 0 is reserved for outgoing system messages. Please use another Id.")); } if (aMsg is IButtplugMessageOutgoingOnly) { return(_bpLogger.LogWarnMsg(id, Error.ErrorClass.ERROR_MSG, $"Message of type {aMsg.GetType().Name} cannot be sent to server")); } if (_pingTimedOut) { return(_bpLogger.LogErrorMsg(id, Error.ErrorClass.ERROR_PING, "Ping timed out.")); } // If we get a message that's not RequestServerInfo first, return an error. if (!_receivedRequestServerInfo && !(aMsg is RequestServerInfo)) { return(_bpLogger.LogErrorMsg(id, Error.ErrorClass.ERROR_INIT, "RequestServerInfo must be first message received by server!")); } switch (aMsg) { case RequestLog m: _bpLogManager.Level = m.LogLevel; return(new Ok(id)); case Ping _: if (_pingTimer != null) { _pingTimer.Stop(); _pingTimer.Start(); } return(new Ok(id)); case RequestServerInfo _: _receivedRequestServerInfo = true; _pingTimer?.Start(); return(new ServerInfo(_serverName, 1, _maxPingTime, id)); case Test m: return(new Test(m.TestString, id)); } return(await _deviceManager.SendMessage(aMsg)); }
public DeviceManager(IButtplugLogManager aLogManager) { _bpLogManager = aLogManager; _bpLogger = _bpLogManager.GetLogger(GetType()); _bpLogger.Trace("Setting up DeviceManager"); _sentFinished = true; _devices = new Dictionary <uint, IButtplugDevice>(); _deviceIndexCounter = 0; _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 bool MayBeDevice(string advertName, List <Guid> advertGUIDs) { if (_deviceInfo.NamePrefixes.Any()) { foreach (var deviceInfoNamePrefix in _deviceInfo.NamePrefixes) { if (advertName.IndexOf(deviceInfoNamePrefix) != 0) { continue; } _bpLogger.Debug($"Found {advertName} via NamePrefix {deviceInfoNamePrefix}"); return(true); } } if ((_deviceInfo.Names.Any() && !_deviceInfo.Names.Contains(advertName)) || !_deviceInfo.Names.Any()) { _bpLogger.Trace($"Dropping query for {advertName}."); return(false); } if (_deviceInfo.Names.Any() && !advertGUIDs.Any()) { _bpLogger.Debug("Found " + advertName + " for " + _deviceInfo.GetType()); return(true); } _bpLogger.Trace("Found " + advertName + " for " + _deviceInfo.GetType() + " with services " + advertGUIDs); foreach (var s in _deviceInfo.Services) { _bpLogger.Trace("Expecting " + s); } foreach (var s in advertGUIDs) { _bpLogger.Trace("Got " + s); } // Intersect doesn't intersect until the enumerator is called var sv = _deviceInfo.Services.Intersect(advertGUIDs); foreach (var s in sv) { _bpLogger.Trace("Matched " + s); return(true); } return(false); }
public async Task <ButtplugMessage> SendMessageAsync(ButtplugMessage aMsg, CancellationToken aToken = default(CancellationToken)) { ButtplugUtils.ArgumentNotNull(aMsg, nameof(aMsg)); var id = aMsg.Id; switch (aMsg) { case StartScanning _: _bpLogger.Debug("Got StartScanning Message"); try { await StartScanning(); } catch (ButtplugDeviceException aEx) { // Catch and rethrow here, adding the message Id onto the exception throw new ButtplugDeviceException(_bpLogger, aEx.Message, id); } return(new Ok(id)); case StopScanning _: _bpLogger.Debug("Got StopScanning Message"); StopScanning(); return(new Ok(id)); case StopAllDevices _: _bpLogger.Debug("Got StopAllDevices Message"); var isOk = true; var errorMsg = string.Empty; foreach (var d in Devices.ToList()) { if (!d.Value.Connected) { continue; } try { await d.Value.ParseMessageAsync(new StopDeviceCmd(d.Key, aMsg.Id), aToken).ConfigureAwait(false); } catch (ButtplugDeviceException e) { isOk = false; errorMsg += $"{e.Message}; "; } } if (isOk) { return(new Ok(aMsg.Id)); } throw new ButtplugDeviceException(_bpLogger, errorMsg, aMsg.Id); case RequestDeviceList _: _bpLogger.Debug("Got RequestDeviceList Message"); var msgDevices = Devices.Where(aDevice => aDevice.Value.Connected) .Select(aDevice => new DeviceMessageInfo( aDevice.Key, aDevice.Value.Name, GetAllowedMessageTypesAsDictionary(aDevice.Value, SpecVersion))).ToList(); return(new DeviceList(msgDevices.ToArray(), id)); // If it's a device message, it's most likely not ours. case ButtplugDeviceMessage m: _bpLogger.Trace($"Sending {aMsg.GetType().Name} to device index {m.DeviceIndex}"); if (!Devices.ContainsKey(m.DeviceIndex)) { throw new ButtplugDeviceException(_bpLogger, $"Dropping message for unknown device index {m.DeviceIndex}", id); } return(await Devices[m.DeviceIndex].ParseMessageAsync(m, aToken).ConfigureAwait(false)); } throw new ButtplugMessageException(_bpLogger, $"Message type {aMsg.GetType().Name} unhandled by this server.", id); }
public async Task <ButtplugMessage> SendMessage(ButtplugMessage aMsg) { var id = aMsg.Id; switch (aMsg) { case StartScanning _: _bpLogger.Debug("Got StartScanning Message"); StartScanning(); return(new Ok(id)); case StopScanning _: _bpLogger.Debug("Got StopScanning Message"); StopScanning(); return(new Ok(id)); case StopAllDevices _: _bpLogger.Debug("Got StopAllDevices Message"); var isOk = true; var errorMsg = string.Empty; foreach (var d in _devices.ToList()) { if (!d.Value.IsConnected) { continue; } var r = await d.Value.ParseMessage(new StopDeviceCmd(d.Key, aMsg.Id)); if (r is Ok) { continue; } isOk = false; errorMsg += $"{(r as Error).ErrorMessage}; "; } if (isOk) { return(new Ok(aMsg.Id)); } return(new Error(errorMsg, Error.ErrorClass.ERROR_DEVICE, aMsg.Id)); case RequestDeviceList _: _bpLogger.Debug("Got RequestDeviceList Message"); var msgDevices = _devices.Where(aDevice => aDevice.Value.IsConnected) .Select(aDevice => new DeviceMessageInfo(aDevice.Key, aDevice.Value.Name, GetAllowedMessageTypesAsStrings(aDevice.Value).ToArray())).ToList(); return(new DeviceList(msgDevices.ToArray(), id)); // If it's a device message, it's most likely not ours. case ButtplugDeviceMessage m: _bpLogger.Trace($"Sending {aMsg.GetType().Name} to device index {m.DeviceIndex}"); if (_devices.ContainsKey(m.DeviceIndex)) { return(await _devices[m.DeviceIndex].ParseMessage(m)); } return(_bpLogger.LogErrorMsg(id, Error.ErrorClass.ERROR_DEVICE, $"Dropping message for unknown device index {m.DeviceIndex}")); } return(_bpLogger.LogErrorMsg(id, Error.ErrorClass.ERROR_MSG, $"Message type {aMsg.GetType().Name} unhandled by this server.")); }
public async Task <ButtplugMessage> SendMessageAsync([NotNull] ButtplugMessage aMsg, CancellationToken aToken = default(CancellationToken)) { var combinedToken = CancellationTokenSource.CreateLinkedTokenSource(_internalToken.Token, aToken); _bpLogger.Trace($"Got Message {aMsg.Id} of type {aMsg.GetType().Name} to send"); var id = aMsg.Id; ButtplugUtils.ArgumentNotNull(aMsg, nameof(aMsg)); if (id == ButtplugConsts.SystemMsgId) { throw new ButtplugMessageException(_bpLogger, "Message Id 0 is reserved for outgoing system messages. Please use another Id.", id); } if (aMsg is IButtplugMessageOutgoingOnly) { throw new ButtplugMessageException(_bpLogger, $"Message of type {aMsg.GetType().Name} cannot be sent to server", id); } if (_pingTimedOut) { throw new ButtplugPingException(_bpLogger, "Ping timed out.", id); } // If we get a message that's not RequestServerInfo first, return an error. if (!_receivedRequestServerInfo && !(aMsg is RequestServerInfo)) { throw new ButtplugHandshakeException(_bpLogger, "RequestServerInfo must be first message received by server!", id); } _bpLogger.Debug($"Got {aMsg.Name} message."); switch (aMsg) { case RequestLog m: BpLogManager.Level = m.LogLevel; return(new Ok(id)); case Ping _: // Start the timer _pingTimer?.Change((int)_maxPingTime, (int)_maxPingTime); return(new Ok(id)); case RequestServerInfo rsi: if (_receivedRequestServerInfo) { throw new ButtplugHandshakeException(_bpLogger, "Already received RequestServerInfo, cannot be sent twice.", id); } _receivedRequestServerInfo = true; _clientSpecVersion = rsi.MessageVersion; _deviceManager.SpecVersion = _clientSpecVersion; // Start the timer _pingTimer?.Change((int)_maxPingTime, (int)_maxPingTime); _clientName = rsi.ClientName; ClientConnected?.Invoke(this, EventArgs.Empty); return(new ServerInfo(_serverName, ButtplugConsts.CurrentSpecVersion, _maxPingTime, id)); case Core.Messages.Test m: return(new Core.Messages.Test(m.TestString, id)); } return(await _deviceManager.SendMessageAsync(aMsg, combinedToken.Token).ConfigureAwait(false)); }
public ButtplugMessage[] Deserialize(string aJsonMsg) { _bpLogger?.Trace($"Got JSON Message: {aJsonMsg}"); var res = new List <ButtplugMessage>(); JsonData json = JsonMapper.ToObject(aJsonMsg); for (var i = 0; i < json.Count; ++i) { foreach (var key in json[i].Keys) { if (json[i][key].Keys.Contains("Id")) { _bpLogger?.Trace($"Got BP {key} Message: {json[i][key].ToJson()}"); switch (key) { case "Ok": res.Add(JsonUtility.FromJson <Ok>(json[i][key].ToJson())); break; case "Test": res.Add(JsonUtility.FromJson <Test>(json[i][key].ToJson())); break; case "Error": res.Add(JsonUtility.FromJson <Error>(json[i][key].ToJson())); break; case "DeviceList": var dList = JsonUtility.FromJson <DeviceList>(json[i][key].ToJson()); List <DeviceMessageInfo> devs = new List <DeviceMessageInfo>(); if (json[i][key].ContainsKey("Devices") && json[i][key]["Devices"].IsArray) { foreach (JsonData dev in json[i][key]["Devices"]) { var dInfo = JsonUtility.FromJson <DeviceMessageInfo>(dev.ToJson()); dInfo.DeviceMessages = new Dictionary <string, MessageAttributes>(); if (dev.ContainsKey("DeviceMessages")) { foreach (var key2 in dev["DeviceMessages"].Keys) { var attr = new MessageAttributes(); if (dev["DeviceMessages"][key2].ContainsKey("FeatureCount")) { attr.FeatureCount = Convert.ToUInt32(dev["DeviceMessages"][key2]["FeatureCount"].IsInt); } dInfo.DeviceMessages.Add(key2, attr); } } devs.Add(dInfo); } dList.Devices = devs.ToArray(); } res.Add(dList); _bpLogger.Trace("Converted back: " + JsonMapper.ToJson(res.Last())); break; case "DeviceAdded": var dAdded = JsonUtility.FromJson <DeviceAdded>(json[i][key].ToJson()); dAdded.DeviceMessages = new Dictionary <string, MessageAttributes>(); if (json[i][key].ContainsKey("DeviceMessages")) { foreach (var key2 in json[i][key]["DeviceMessages"].Keys) { var attr = new MessageAttributes(); if (json[i][key]["DeviceMessages"][key2].ContainsKey("FeatureCount")) { attr.FeatureCount = (uint)json[i][key]["DeviceMessages"][key2]["FeatureCount"]; } dAdded.DeviceMessages.Add(key2, attr); } } res.Add(dAdded); _bpLogger.Trace("Converted back: " + JsonMapper.ToJson(res.Last())); break; case "DeviceRemoved": res.Add(JsonUtility.FromJson <DeviceRemoved>(json[i][key].ToJson())); break; case "ScanningFinished": res.Add(JsonUtility.FromJson <ScanningFinished>(json[i][key].ToJson())); break; case "Log": res.Add(JsonUtility.FromJson <Log>(json[i][key].ToJson())); break; case "ServerInfo": res.Add(JsonUtility.FromJson <ServerInfo>(json[i][key].ToJson())); break; default: _bpLogger?.Trace($"Don't know how to handle: {key}"); break; } } } } return(res.ToArray()); }
public IEnumerable <ButtplugMessage> Deserialize(string aJsonMsg) { _bpLogger.Trace($"Got JSON Message: {aJsonMsg}"); var textReader = new StringReader(aJsonMsg); // While we aren't receiving from a stream here, we may get multiple JSON arrays // depending on how we received messages. var reader = new JsonTextReader(textReader) { CloseInput = false, SupportMultipleContent = true, }; // Aggregate all messages in the string we received. Note that we may have received // multiple strings, which may have multiple arrays. If any message in the array is // invalid, we dump the message list and just throw. This is considered a catastrophic // event and the system should probably just shut down anyways. var msgList = new List <ButtplugMessage>(); while (true) { try { if (!reader.Read()) { break; } } catch (JsonReaderException e) { throw new ButtplugMessageException(_bpLogger, $"Not valid JSON: {aJsonMsg} - {e.Message}"); } JArray msgArray; try { msgArray = JArray.Load(reader); } catch (JsonReaderException e) { throw new ButtplugMessageException(_bpLogger, $"Not valid JSON: {aJsonMsg} - {e.Message}"); } var errors = _schema.Validate(msgArray); if (errors.Any()) { throw new ButtplugMessageException(_bpLogger, "Message does not conform to schema: " + string.Join(", ", errors.Select(aErr => aErr?.ToString()).ToArray())); } foreach (var jsonObj in msgArray.Children <JObject>()) { var msgName = jsonObj.Properties().First().Name; // Only way we should get here is if the schema includes a class that we don't // have a matching C# class for. if (!_messageTypes.ContainsKey(msgName)) { throw new ButtplugMessageException(_bpLogger, $"{msgName} is not a valid message class"); } // This specifically could fail due to object conversion. msgList.Add(DeserializeAs(jsonObj, _messageTypes[msgName])); } } return(msgList); }
protected DeviceSubtypeManager([NotNull] IButtplugLogManager aLogManager) { LogManager = aLogManager; BpLogger = aLogManager.GetLogger(GetType()); BpLogger.Trace($"Setting up Device Manager {GetType().Name}"); }
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()); } }
public ButtplugMessage[] Deserialize(string aJsonMsg) { _bpLogger?.Trace($"Got JSON Message: {aJsonMsg}"); var res = new List <ButtplugMessage>(); JArray msgArray; try { msgArray = JArray.Parse(aJsonMsg); } catch (JsonReaderException e) { var err = new Error($"Not valid JSON: {aJsonMsg} - {e.Message}", ErrorClass.ERROR_MSG, ButtplugConsts.SystemMsgId); _bpLogger?.LogErrorMsg(err); res.Add(err); return(res.ToArray()); } var errors = _schema.Validate(msgArray); if (errors.Any()) { var err = new Error("Message does not conform to schema: " + string.Join(", ", errors.Select(aErr => aErr.ToString()).ToArray()), ErrorClass.ERROR_MSG, ButtplugConsts.SystemMsgId); _bpLogger?.LogErrorMsg(err); res.Add(err); return(res.ToArray()); } if (!msgArray.Any()) { var err = new Error("No messages in array", ErrorClass.ERROR_MSG, ButtplugConsts.SystemMsgId); _bpLogger?.LogErrorMsg(err); res.Add(err); return(res.ToArray()); } // JSON input is an array of messages. // We currently only handle the first one. foreach (var o in msgArray.Children <JObject>()) { if (!o.Properties().Any()) { var err = new Error("No message name available", ErrorClass.ERROR_MSG, ButtplugConsts.SystemMsgId); _bpLogger?.LogErrorMsg(err); res.Add(err); continue; } var msgName = o.Properties().First().Name; if (!_messageTypes.Any() || !_messageTypes.ContainsKey(msgName)) { var err = new Error($"{msgName} is not a valid message class", ErrorClass.ERROR_MSG, ButtplugConsts.SystemMsgId); _bpLogger?.LogErrorMsg(err); res.Add(err); continue; } // This specifically could fail due to object conversion. res.Add(DeserializeAs(o, _messageTypes[msgName], msgName, aJsonMsg)); } return(res.ToArray()); }
public ButtplugMessage[] Deserialize(string aJsonMsg) { _bpLogger.Trace($"Got JSON Message: {aJsonMsg}"); var res = new List <ButtplugMessage>(); JArray msgArray; try { msgArray = JArray.Parse(aJsonMsg); } catch (JsonReaderException e) { res.Add(_bpLogger.LogErrorMsg(ButtplugConsts.SystemMsgId, ErrorClass.ERROR_MSG, $"Not valid JSON: {aJsonMsg} - {e.Message}")); return(res.ToArray()); } var errors = _schema.Validate(msgArray); if (errors.Any()) { res.Add(_bpLogger.LogErrorMsg(ButtplugConsts.SystemMsgId, ErrorClass.ERROR_MSG, "Message does not conform to schema: " + string.Join(", ", errors.Select(aErr => aErr.ToString()).ToArray()))); return(res.ToArray()); } if (!msgArray.Any()) { res.Add(_bpLogger.LogErrorMsg(ButtplugConsts.SystemMsgId, ErrorClass.ERROR_MSG, "No messages in array")); return(res.ToArray()); } // JSON input is an array of messages. // We currently only handle the first one. foreach (var o in msgArray.Children <JObject>()) { if (!o.Properties().Any()) { res.Add(_bpLogger.LogErrorMsg(ButtplugConsts.SystemMsgId, ErrorClass.ERROR_MSG, "No message name available")); continue; } var msgName = o.Properties().First().Name; if (!_messageTypes.Keys.Any() || !_messageTypes.Keys.Contains(msgName)) { res.Add(_bpLogger.LogErrorMsg(ButtplugConsts.SystemMsgId, ErrorClass.ERROR_MSG, $"{msgName} is not a valid message class")); continue; } var s = new JsonSerializer { MissingMemberHandling = MissingMemberHandling.Error }; // This specifically could fail due to object conversion. try { var r = o[msgName].Value <JObject>(); res.Add((ButtplugMessage)r.ToObject(_messageTypes[msgName], s)); _bpLogger.Trace($"Message successfully parsed as {msgName} type"); } catch (InvalidCastException e) { res.Add(_bpLogger.LogErrorMsg(ButtplugConsts.SystemMsgId, ErrorClass.ERROR_MSG, $"Could not create message for JSON {aJsonMsg}: {e.Message}")); } catch (JsonSerializationException e) { res.Add(_bpLogger.LogErrorMsg(ButtplugConsts.SystemMsgId, ErrorClass.ERROR_MSG, $"Could not create message for JSON {aJsonMsg}: {e.Message}")); } } return(res.ToArray()); }