Bug 1923689 - Implement basic configuration processing on SearchEngineSelector.
This implements processing the main parts of the search configuration JSON into the Rust structure using serde_json. Currently the processing applies to: * The identifier and base properties of the engine records. * The default engine records. As variant and environment handling is not yet implemented, the filter function will return all engines defined in the configuration.
This commit is contained in:
Родитель
a486b51698
Коммит
06a5d158b6
|
@ -3965,6 +3965,9 @@ name = "search"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"error-support",
|
||||
"parking_lot",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"uniffi",
|
||||
]
|
||||
|
|
|
@ -8,6 +8,9 @@ license = "MPL-2.0"
|
|||
|
||||
[dependencies]
|
||||
error-support = { path = "../support/error" }
|
||||
parking_lot = ">=0.11,<=0.12"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
thiserror = "1"
|
||||
uniffi = { workspace = true }
|
||||
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//! This module defines the structures that we use for serde_json to parse
|
||||
//! the search configuration.
|
||||
|
||||
use crate::{SearchEngineClassification, SearchUrlParam};
|
||||
use serde::Deserialize;
|
||||
|
||||
/// The list of possible submission methods for search engine urls.
|
||||
#[derive(Debug, uniffi::Enum, PartialEq, Deserialize, Clone, Default)]
|
||||
#[serde(rename_all = "UPPERCASE")]
|
||||
pub(crate) enum JSONEngineMethod {
|
||||
Post = 2,
|
||||
#[serde(other)]
|
||||
#[default]
|
||||
Get = 1,
|
||||
}
|
||||
|
||||
impl JSONEngineMethod {
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
JSONEngineMethod::Get => "GET",
|
||||
JSONEngineMethod::Post => "POST",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Defines an individual search engine URL. This is defined separately to
|
||||
/// `types::SearchEngineUrl` as various fields may be optional in the supplied
|
||||
/// configuration.
|
||||
#[derive(Debug, uniffi::Record, PartialEq, Deserialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct JSONEngineUrl {
|
||||
/// The PrePath and FilePath of the URL. May include variables for engines
|
||||
/// which have a variable FilePath, e.g. `{searchTerm}` for when a search
|
||||
/// term is within the path of the url.
|
||||
pub base: String,
|
||||
|
||||
/// The HTTP method to use to send the request (`GET` or `POST`).
|
||||
/// If the engine definition has not specified the method, it defaults to GET.
|
||||
pub method: Option<JSONEngineMethod>,
|
||||
|
||||
/// The parameters for this URL.
|
||||
pub params: Option<Vec<SearchUrlParam>>,
|
||||
|
||||
/// The name of the query parameter for the search term. Automatically
|
||||
/// appended to the end of the query. This may be skipped if `{searchTerm}`
|
||||
/// is included in the base.
|
||||
pub search_term_param_name: Option<String>,
|
||||
}
|
||||
|
||||
/// Reflects `types::SearchEngineUrls`, but using `EngineUrl`.
|
||||
#[derive(Debug, uniffi::Record, PartialEq, Deserialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct JSONEngineUrls {
|
||||
/// The URL to use for searches.
|
||||
pub search: JSONEngineUrl,
|
||||
|
||||
/// The URL to use for suggestions.
|
||||
pub suggestions: Option<JSONEngineUrl>,
|
||||
|
||||
/// The URL to use for trending suggestions.
|
||||
pub trending: Option<JSONEngineUrl>,
|
||||
}
|
||||
|
||||
/// Represents the engine base section of the configuration.
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct JSONEngineBase {
|
||||
/// A list of aliases for this engine.
|
||||
pub aliases: Option<Vec<String>>,
|
||||
|
||||
/// The character set this engine uses for queries. Defaults to 'UTF=8' if not set.
|
||||
pub charset: Option<String>,
|
||||
|
||||
/// The classification of search engine according to the main search types
|
||||
/// (e.g. general, shopping, travel, dictionary). Currently, only marking as
|
||||
/// a general search engine is supported.
|
||||
pub classification: SearchEngineClassification,
|
||||
|
||||
/// The user visible name for the search engine.
|
||||
pub name: String,
|
||||
|
||||
/// The partner code for the engine. This will be inserted into parameters
|
||||
/// which include `{partnerCode}`.
|
||||
pub partner_code: Option<String>,
|
||||
|
||||
/// The URLs associated with the search engine.
|
||||
pub urls: JSONEngineUrls,
|
||||
}
|
||||
|
||||
/// Represents an individual engine record in the configuration.
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct JSONEngineRecord {
|
||||
pub identifier: String,
|
||||
pub base: JSONEngineBase,
|
||||
}
|
||||
|
||||
/// Represents the default engines record.
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct JSONDefaultEnginesRecord {
|
||||
pub global_default: String,
|
||||
pub global_default_private: Option<String>,
|
||||
}
|
||||
|
||||
/// Represents the engine orders record.
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub(crate) struct JSONEngineOrdersRecord {
|
||||
// TODO: Implementation.
|
||||
}
|
||||
|
||||
/// Represents an individual record in the raw search configuration.
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
#[serde(tag = "recordType", rename_all = "camelCase")]
|
||||
pub(crate) enum JSONSearchConfigurationRecords {
|
||||
DefaultEngines(JSONDefaultEnginesRecord),
|
||||
Engine(Box<JSONEngineRecord>),
|
||||
EngineOrders(JSONEngineOrdersRecord),
|
||||
// Include some flexibilty if we choose to add new record types in future.
|
||||
// Current versions of the application receiving the configuration will
|
||||
// ignore the new record types.
|
||||
#[serde(other)]
|
||||
Unknown,
|
||||
}
|
||||
|
||||
/// Represents the search configuration as received from remote settings.
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub(crate) struct JSONSearchConfiguration {
|
||||
pub data: Vec<JSONSearchConfigurationRecords>,
|
||||
}
|
|
@ -11,8 +11,10 @@ use error_support::{ErrorHandling, GetErrorHandling};
|
|||
/// application.
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
#[error("NotImplemented")]
|
||||
NotImplemented,
|
||||
#[error("Search configuration not specified")]
|
||||
SearchConfigNotSpecified,
|
||||
#[error("JSON error: {0}")]
|
||||
Json(#[from] serde_json::Error),
|
||||
}
|
||||
|
||||
// #[non_exhaustive]
|
||||
|
|
|
@ -0,0 +1,204 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use crate::{
|
||||
error::Error, JSONEngineBase, JSONEngineRecord, JSONEngineUrl, JSONEngineUrls,
|
||||
JSONSearchConfigurationRecords, RefinedSearchConfig, SearchEngineDefinition, SearchEngineUrl,
|
||||
SearchEngineUrls, SearchUserEnvironment,
|
||||
};
|
||||
|
||||
impl From<JSONEngineUrl> for SearchEngineUrl {
|
||||
fn from(url: JSONEngineUrl) -> Self {
|
||||
Self {
|
||||
base: url.base,
|
||||
method: url.method.unwrap_or_default().as_str().to_string(),
|
||||
params: url.params.unwrap_or_default(),
|
||||
search_term_param_name: url.search_term_param_name,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<JSONEngineUrls> for SearchEngineUrls {
|
||||
fn from(urls: JSONEngineUrls) -> Self {
|
||||
Self {
|
||||
search: urls.search.into(),
|
||||
suggestions: None,
|
||||
trending: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SearchEngineDefinition {
|
||||
pub(crate) fn from_configuration_details(
|
||||
identifier: &str,
|
||||
base: JSONEngineBase,
|
||||
) -> SearchEngineDefinition {
|
||||
SearchEngineDefinition {
|
||||
aliases: base.aliases.unwrap_or_default(),
|
||||
charset: base.charset.unwrap_or_else(|| "UTF-8".to_string()),
|
||||
classification: base.classification,
|
||||
identifier: identifier.to_string(),
|
||||
name: base.name,
|
||||
order_hint: None,
|
||||
partner_code: base.partner_code.unwrap_or_default(),
|
||||
telemetry_suffix: None,
|
||||
urls: base.urls.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn filter_engine_configuration(
|
||||
user_environment: SearchUserEnvironment,
|
||||
configuration: Vec<JSONSearchConfigurationRecords>,
|
||||
) -> Result<RefinedSearchConfig, Error> {
|
||||
let mut engines = Vec::new();
|
||||
let mut default_engine_id: Option<String> = None;
|
||||
let mut default_private_engine_id: Option<String> = None;
|
||||
|
||||
for record in configuration {
|
||||
match record {
|
||||
JSONSearchConfigurationRecords::Engine(engine) => {
|
||||
let result = extract_engine_config(&user_environment, engine);
|
||||
engines.extend(result);
|
||||
}
|
||||
JSONSearchConfigurationRecords::DefaultEngines(default_engines) => {
|
||||
default_engine_id = Some(default_engines.global_default);
|
||||
default_private_engine_id.clone_from(&default_engines.global_default_private);
|
||||
}
|
||||
JSONSearchConfigurationRecords::EngineOrders(_engine_orders) => {
|
||||
// TODO: Implementation.
|
||||
}
|
||||
JSONSearchConfigurationRecords::Unknown => {
|
||||
// Prevents panics if a new record type is added in future.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(RefinedSearchConfig {
|
||||
engines,
|
||||
app_default_engine_id: default_engine_id.unwrap(),
|
||||
app_default_private_engine_id: default_private_engine_id,
|
||||
})
|
||||
}
|
||||
|
||||
fn extract_engine_config(
|
||||
_user_environment: &SearchUserEnvironment,
|
||||
record: Box<JSONEngineRecord>,
|
||||
) -> Option<SearchEngineDefinition> {
|
||||
// TODO: Variant handling.
|
||||
Some(SearchEngineDefinition::from_configuration_details(
|
||||
&record.identifier,
|
||||
record.base,
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::types::*;
|
||||
|
||||
#[test]
|
||||
fn test_from_configuration_details_fallsback_to_defaults() {
|
||||
let result = SearchEngineDefinition::from_configuration_details(
|
||||
"test",
|
||||
JSONEngineBase {
|
||||
aliases: None,
|
||||
charset: None,
|
||||
classification: SearchEngineClassification::General,
|
||||
name: "Test".to_string(),
|
||||
partner_code: None,
|
||||
urls: JSONEngineUrls {
|
||||
search: JSONEngineUrl {
|
||||
base: "https://example.com".to_string(),
|
||||
method: None,
|
||||
params: None,
|
||||
search_term_param_name: None,
|
||||
},
|
||||
suggestions: None,
|
||||
trending: None,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
result,
|
||||
SearchEngineDefinition {
|
||||
aliases: Vec::new(),
|
||||
charset: "UTF-8".to_string(),
|
||||
classification: SearchEngineClassification::General,
|
||||
identifier: "test".to_string(),
|
||||
partner_code: String::new(),
|
||||
name: "Test".to_string(),
|
||||
order_hint: None,
|
||||
telemetry_suffix: None,
|
||||
urls: SearchEngineUrls {
|
||||
search: SearchEngineUrl {
|
||||
base: "https://example.com".to_string(),
|
||||
method: "GET".to_string(),
|
||||
params: Vec::new(),
|
||||
search_term_param_name: None,
|
||||
},
|
||||
suggestions: None,
|
||||
trending: None
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_configuration_details_uses_values() {
|
||||
let result = SearchEngineDefinition::from_configuration_details(
|
||||
"test",
|
||||
JSONEngineBase {
|
||||
aliases: Some(vec!["foo".to_string(), "bar".to_string()]),
|
||||
charset: Some("ISO-8859-15".to_string()),
|
||||
classification: SearchEngineClassification::Unknown,
|
||||
name: "Test".to_string(),
|
||||
partner_code: Some("firefox".to_string()),
|
||||
urls: JSONEngineUrls {
|
||||
search: JSONEngineUrl {
|
||||
base: "https://example.com".to_string(),
|
||||
method: Some(crate::JSONEngineMethod::Post),
|
||||
params: Some(vec![SearchUrlParam {
|
||||
name: "param".to_string(),
|
||||
value: Some("test param".to_string()),
|
||||
experiment_config: None,
|
||||
}]),
|
||||
search_term_param_name: Some("baz".to_string()),
|
||||
},
|
||||
suggestions: None,
|
||||
trending: None,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
result,
|
||||
SearchEngineDefinition {
|
||||
aliases: vec!["foo".to_string(), "bar".to_string()],
|
||||
charset: "ISO-8859-15".to_string(),
|
||||
classification: SearchEngineClassification::Unknown,
|
||||
identifier: "test".to_string(),
|
||||
partner_code: "firefox".to_string(),
|
||||
name: "Test".to_string(),
|
||||
order_hint: None,
|
||||
telemetry_suffix: None,
|
||||
urls: SearchEngineUrls {
|
||||
search: SearchEngineUrl {
|
||||
base: "https://example.com".to_string(),
|
||||
method: "POST".to_string(),
|
||||
params: vec![SearchUrlParam {
|
||||
name: "param".to_string(),
|
||||
value: Some("test param".to_string()),
|
||||
experiment_config: None,
|
||||
}],
|
||||
search_term_param_name: Some("baz".to_string()),
|
||||
},
|
||||
suggestions: None,
|
||||
trending: None
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
|
@ -2,12 +2,15 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
mod configuration_types;
|
||||
mod error;
|
||||
mod filter;
|
||||
pub use error::SearchApiError;
|
||||
|
||||
pub mod selector;
|
||||
pub mod types;
|
||||
|
||||
pub(crate) use crate::configuration_types::*;
|
||||
pub use crate::types::*;
|
||||
pub use selector::SearchEngineSelector;
|
||||
pub type SearchApiResult<T> = std::result::Result<T, error::SearchApiError>;
|
||||
|
|
|
@ -2,20 +2,31 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use crate::{error::Error, RefinedSearchConfig, SearchApiResult, SearchUserEnvironment};
|
||||
use crate::filter::filter_engine_configuration;
|
||||
use crate::{
|
||||
error::Error, JSONSearchConfiguration, RefinedSearchConfig, SearchApiResult,
|
||||
SearchUserEnvironment,
|
||||
};
|
||||
use error_support::handle_error;
|
||||
use parking_lot::Mutex;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct SearchEngineSelectorInner {
|
||||
configuration: Option<JSONSearchConfiguration>,
|
||||
}
|
||||
|
||||
/// SearchEngineSelector parses the JSON configuration for
|
||||
/// search engines and returns the applicable engines depending
|
||||
/// on their region + locale.
|
||||
#[derive(Default, uniffi::Object)]
|
||||
pub struct SearchEngineSelector {}
|
||||
pub struct SearchEngineSelector(Mutex<SearchEngineSelectorInner>);
|
||||
|
||||
#[uniffi::export]
|
||||
impl SearchEngineSelector {
|
||||
#[uniffi::constructor]
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
Self(Mutex::default())
|
||||
}
|
||||
|
||||
/// Sets the search configuration from the given string. If the configuration
|
||||
|
@ -24,35 +35,158 @@ impl SearchEngineSelector {
|
|||
/// particularly during test runs where the same configuration may be used
|
||||
/// repeatedly.
|
||||
#[handle_error(Error)]
|
||||
pub fn set_search_config(&self, _configuration: String) -> SearchApiResult<()> {
|
||||
Err(Error::NotImplemented)
|
||||
pub fn set_search_config(self: Arc<Self>, configuration: String) -> SearchApiResult<()> {
|
||||
if configuration.is_empty() {
|
||||
return Err(Error::SearchConfigNotSpecified);
|
||||
}
|
||||
self.0.lock().configuration = serde_json::from_str(&configuration)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Clears the search configuration from memory if it is known that it is
|
||||
/// not required for a time, e.g. if the configuration will only be re-filtered
|
||||
/// after an app/environment update.
|
||||
pub fn clear_search_config(&self) {}
|
||||
pub fn clear_search_config(self: Arc<Self>) {}
|
||||
|
||||
/// Filters the search configuration with the user's given environment,
|
||||
/// and returns the set of engines and parameters that should be presented
|
||||
/// to the user.
|
||||
#[handle_error(Error)]
|
||||
pub fn filter_engine_configuration(
|
||||
&self,
|
||||
_user_environment: SearchUserEnvironment,
|
||||
self: Arc<Self>,
|
||||
user_environment: SearchUserEnvironment,
|
||||
) -> SearchApiResult<RefinedSearchConfig> {
|
||||
Err(Error::NotImplemented)
|
||||
let data = match &self.0.lock().configuration {
|
||||
None => return Err(Error::SearchConfigNotSpecified),
|
||||
Some(configuration) => configuration.data.clone(),
|
||||
};
|
||||
filter_engine_configuration(user_environment, data)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{SearchEngineSelector, SearchUserEnvironment};
|
||||
use super::*;
|
||||
use crate::types::*;
|
||||
use serde_json::json;
|
||||
|
||||
#[test]
|
||||
fn test_filter_engine_config_throws() {
|
||||
let selector = SearchEngineSelector::new();
|
||||
fn test_set_config_should_allow_basic_config() {
|
||||
let selector = Arc::new(SearchEngineSelector::new());
|
||||
|
||||
let config_result = Arc::clone(&selector).set_search_config(
|
||||
json!({
|
||||
"data": [
|
||||
{
|
||||
"recordType": "engine",
|
||||
"identifier": "test",
|
||||
"base": {
|
||||
"name": "Test",
|
||||
"classification": "general",
|
||||
"urls": {
|
||||
"search": {
|
||||
"base": "https://example.com",
|
||||
"method": "GET"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"recordType": "defaultEngines",
|
||||
"globalDefault": "test"
|
||||
}
|
||||
]
|
||||
})
|
||||
.to_string(),
|
||||
);
|
||||
assert!(
|
||||
config_result.is_ok(),
|
||||
"Should not have errored: `{config_result:?}`"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_set_config_should_allow_extra_fields() {
|
||||
let selector = Arc::new(SearchEngineSelector::new());
|
||||
|
||||
let config_result = Arc::clone(&selector).set_search_config(
|
||||
json!({
|
||||
"data": [
|
||||
{
|
||||
"recordType": "engine",
|
||||
"identifier": "test",
|
||||
"base": {
|
||||
"name": "Test",
|
||||
"classification": "general",
|
||||
"urls": {
|
||||
"search": {
|
||||
"base": "https://example.com",
|
||||
"method": "GET",
|
||||
"extraField1": true
|
||||
}
|
||||
},
|
||||
"extraField2": "123"
|
||||
},
|
||||
"extraField3": ["foo"]
|
||||
},
|
||||
{
|
||||
"recordType": "defaultEngines",
|
||||
"globalDefault": "test",
|
||||
"extraField4": {
|
||||
"subField1": true
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
.to_string(),
|
||||
);
|
||||
assert!(
|
||||
config_result.is_ok(),
|
||||
"Should not have errored: `{config_result:?}`"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_set_config_should_ignore_unknown_record_types() {
|
||||
let selector = Arc::new(SearchEngineSelector::new());
|
||||
|
||||
let config_result = Arc::clone(&selector).set_search_config(
|
||||
json!({
|
||||
"data": [
|
||||
{
|
||||
"recordType": "engine",
|
||||
"identifier": "test",
|
||||
"base": {
|
||||
"name": "Test",
|
||||
"classification": "general",
|
||||
"urls": {
|
||||
"search": {
|
||||
"base": "https://example.com",
|
||||
"method": "GET"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"recordType": "defaultEngines",
|
||||
"globalDefault": "test"
|
||||
},
|
||||
{
|
||||
"recordType": "unknown"
|
||||
}
|
||||
]
|
||||
})
|
||||
.to_string(),
|
||||
);
|
||||
assert!(
|
||||
config_result.is_ok(),
|
||||
"Should not have errored: `{config_result:?}`"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_filter_engine_configuration_throws_without_config() {
|
||||
let selector = Arc::new(SearchEngineSelector::new());
|
||||
|
||||
let result = selector.filter_engine_configuration(SearchUserEnvironment {
|
||||
locale: "fi".into(),
|
||||
|
@ -65,5 +199,122 @@ mod tests {
|
|||
});
|
||||
|
||||
assert!(result.is_err());
|
||||
assert!(result
|
||||
.unwrap_err()
|
||||
.to_string()
|
||||
.contains("Search configuration not specified"))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_filter_engine_configuration_returns_basic_engines() {
|
||||
let selector = Arc::new(SearchEngineSelector::new());
|
||||
|
||||
let config_result = Arc::clone(&selector).set_search_config(
|
||||
json!({
|
||||
"data": [
|
||||
{
|
||||
"recordType": "engine",
|
||||
"identifier": "test1",
|
||||
"base": {
|
||||
"name": "Test 1",
|
||||
"classification": "general",
|
||||
"urls": {
|
||||
"search": {
|
||||
"base": "https://example.com/1",
|
||||
"method": "GET",
|
||||
"searchTermParamName": "q"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"recordType": "engine",
|
||||
"identifier": "test2",
|
||||
"base": {
|
||||
"name": "Test 2",
|
||||
"classification": "general",
|
||||
"urls": {
|
||||
"search": {
|
||||
"base": "https://example.com/2",
|
||||
"method": "GET",
|
||||
"searchTermParamName": "search"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"recordType": "defaultEngines",
|
||||
"globalDefault": "test1",
|
||||
"globalDefaultPrivate": "test2"
|
||||
}
|
||||
]
|
||||
})
|
||||
.to_string(),
|
||||
);
|
||||
assert!(
|
||||
config_result.is_ok(),
|
||||
"Should not have errored: `{config_result:?}`"
|
||||
);
|
||||
|
||||
let result = selector.filter_engine_configuration(SearchUserEnvironment {
|
||||
locale: "fi".into(),
|
||||
region: "FR".into(),
|
||||
update_channel: SearchUpdateChannel::Default,
|
||||
distribution_id: String::new(),
|
||||
experiment: String::new(),
|
||||
app_name: SearchApplicationName::Firefox,
|
||||
version: String::new(),
|
||||
});
|
||||
|
||||
assert!(result.is_ok(), "Should not have errored: `{result:?}`");
|
||||
assert_eq!(
|
||||
result.unwrap(),
|
||||
RefinedSearchConfig {
|
||||
engines: vec!(
|
||||
SearchEngineDefinition {
|
||||
aliases: Vec::new(),
|
||||
charset: "UTF-8".to_string(),
|
||||
classification: SearchEngineClassification::General,
|
||||
identifier: "test1".to_string(),
|
||||
name: "Test 1".to_string(),
|
||||
order_hint: None,
|
||||
partner_code: String::new(),
|
||||
telemetry_suffix: None,
|
||||
urls: SearchEngineUrls {
|
||||
search: SearchEngineUrl {
|
||||
base: "https://example.com/1".to_string(),
|
||||
method: "GET".to_string(),
|
||||
params: Vec::new(),
|
||||
search_term_param_name: Some("q".to_string())
|
||||
},
|
||||
suggestions: None,
|
||||
trending: None
|
||||
}
|
||||
},
|
||||
SearchEngineDefinition {
|
||||
aliases: Vec::new(),
|
||||
charset: "UTF-8".to_string(),
|
||||
classification: SearchEngineClassification::General,
|
||||
identifier: "test2".to_string(),
|
||||
name: "Test 2".to_string(),
|
||||
order_hint: None,
|
||||
partner_code: String::new(),
|
||||
telemetry_suffix: None,
|
||||
urls: SearchEngineUrls {
|
||||
search: SearchEngineUrl {
|
||||
base: "https://example.com/2".to_string(),
|
||||
method: "GET".to_string(),
|
||||
params: Vec::new(),
|
||||
search_term_param_name: Some("search".to_string())
|
||||
},
|
||||
suggestions: None,
|
||||
trending: None
|
||||
}
|
||||
}
|
||||
),
|
||||
app_default_engine_id: "test1".to_string(),
|
||||
app_default_private_engine_id: Some("test2".to_string())
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//! This module defines the types that we export across the UNIFFI interface.
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
/// The list of possible application names that are currently supported.
|
||||
#[derive(Debug, uniffi::Enum)]
|
||||
pub enum SearchApplicationName {
|
||||
|
@ -79,7 +83,7 @@ pub struct SearchUserEnvironment {
|
|||
|
||||
/// Parameter definitions for search engine URLs. The name property is always
|
||||
/// specified, along with one of value, experiment_config or search_access_point.
|
||||
#[derive(Debug, uniffi::Record)]
|
||||
#[derive(Debug, uniffi::Record, PartialEq, Deserialize, Clone)]
|
||||
pub struct SearchUrlParam {
|
||||
/// The name of the parameter in the url.
|
||||
pub name: String,
|
||||
|
@ -94,7 +98,7 @@ pub struct SearchUrlParam {
|
|||
}
|
||||
|
||||
/// Defines an individual search engine URL.
|
||||
#[derive(Debug, uniffi::Record)]
|
||||
#[derive(Debug, uniffi::Record, PartialEq, Deserialize, Clone)]
|
||||
pub struct SearchEngineUrl {
|
||||
/// The PrePath and FilePath of the URL. May include variables for engines
|
||||
/// which have a variable FilePath, e.g. `{searchTerm}` for when a search
|
||||
|
@ -115,7 +119,7 @@ pub struct SearchEngineUrl {
|
|||
}
|
||||
|
||||
/// The URLs associated with the search engine.
|
||||
#[derive(Debug, uniffi::Record)]
|
||||
#[derive(Debug, uniffi::Record, PartialEq, Deserialize, Clone)]
|
||||
pub struct SearchEngineUrls {
|
||||
/// The URL to use for searches.
|
||||
pub search: SearchEngineUrl,
|
||||
|
@ -128,10 +132,12 @@ pub struct SearchEngineUrls {
|
|||
}
|
||||
|
||||
/// The list of acceptable classifications for a search engine.
|
||||
#[derive(Debug, uniffi::Enum)]
|
||||
#[derive(Debug, uniffi::Enum, PartialEq, Deserialize, Clone)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum SearchEngineClassification {
|
||||
Unknown = 1,
|
||||
General = 2,
|
||||
#[serde(other)]
|
||||
Unknown = 1,
|
||||
}
|
||||
|
||||
impl SearchEngineClassification {
|
||||
|
@ -144,11 +150,14 @@ impl SearchEngineClassification {
|
|||
}
|
||||
|
||||
/// A definition for an individual search engine to be presented to the user.
|
||||
#[derive(Debug, uniffi::Record)]
|
||||
#[derive(Debug, uniffi::Record, PartialEq)]
|
||||
pub struct SearchEngineDefinition {
|
||||
/// A list of aliases for this engine.
|
||||
pub aliases: Vec<String>,
|
||||
|
||||
/// The character set this engine uses for queries.
|
||||
pub charset: String,
|
||||
|
||||
/// The classification of search engine according to the main search types
|
||||
/// (e.g. general, shopping, travel, dictionary). Currently, only marking as
|
||||
/// a general search engine is supported.
|
||||
|
@ -165,8 +174,8 @@ pub struct SearchEngineDefinition {
|
|||
pub name: String,
|
||||
|
||||
/// The partner code for the engine. This will be inserted into parameters
|
||||
/// which include `{partnerCode}`.
|
||||
pub partner_code: Option<String>,
|
||||
/// which include `{partnerCode}`. May be the empty string.
|
||||
pub partner_code: String,
|
||||
|
||||
/// Optional suffix that is appended to the search engine identifier
|
||||
/// following a dash, i.e. `<identifier>-<suffix>`
|
||||
|
@ -185,7 +194,7 @@ pub struct SearchEngineDefinition {
|
|||
|
||||
/// Details of the search engines to display to the user, generated as a result
|
||||
/// of processing the search configuration.
|
||||
#[derive(Debug, uniffi::Record)]
|
||||
#[derive(Debug, uniffi::Record, PartialEq)]
|
||||
pub struct RefinedSearchConfig {
|
||||
/// A sorted list of engines. Clients may use the engine in the order that
|
||||
/// this list is specified, or they may implement their own order if they
|
||||
|
|
Загрузка…
Ссылка в новой задаче