1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
// Buttplug Rust Source Code File - See https://buttplug.io for more info.

//

// Copyright 2016-2020 Nonpolynomial Labs LLC. All rights reserved.

//

// Licensed under the BSD 3-Clause license. See LICENSE file in the project root

// for full license information.


//! JSON Schema validator structure, used by the

//! [DeviceConfigurationManager][crate::device::configuration_manager::DeviceConfigurationManager] and

//! buttplug message de/serializers in both the client and server. Uses the

//! Valico library.


use crate::core::messages::serializer::ButtplugSerializerError;
use serde_json::Value;
use valico::json_schema;

pub struct JSONValidator {
  /// Valico's scope object, used for holding the schema.

  scope: json_schema::scope::Scope,
  /// Valico's id URL, used for accessing the schema.

  id: url::Url,
}

impl JSONValidator {
  /// Create a new validator.

  ///

  /// # Parameters

  ///

  /// - `schema`: JSON Schema that the validator should use.

  pub fn new(schema: &str) -> Self {
    let schema_json: Value = serde_json::from_str(schema).unwrap();
    let mut scope = json_schema::Scope::new();
    let id = scope.compile(schema_json, false).unwrap();
    Self { id, scope }
  }

  /// Validates a json string, based on the schema the validator was created

  /// with.

  ///

  /// # Parameters

  ///

  /// - `json_str`: JSON string to validate.

  pub fn validate(&self, json_str: &str) -> Result<(), ButtplugSerializerError> {
    let schema = self.scope.resolve(&self.id).unwrap();
    let check_value = serde_json::from_str(json_str)
      .map_err(|err| ButtplugSerializerError::JsonSerializerError(format!("{:?}", err)))?;
    let state = schema.validate(&check_value);
    if state.is_valid() {
      Ok(())
    } else {
      // Our errors need to be clonable, and validation state isn't. We can't do

      // much with it anyways, so just convert it to its display and hand that

      // back.

      Err(ButtplugSerializerError::JsonValidatorError(format!(
        "{:?}",
        state
      )))
    }
  }
}