Upstream valeriansaliou/sonic state of the touched files before abd3d56935
This commit is contained in:
1 parent
73692bcfdb
commit
0f79d0dab8
11 files changed
+2450
-1
No files matched your search
@@ -0,0 +1,325 @@
|
||||
// Sonic
|
||||
//
|
||||
// Fast, lightweight and schema-less search backend
|
||||
// Copyright: 2019, Valerian Saliou <valerian@valeriansaliou.name>
|
||||
// Copyright: 2026, Rémi Bardon <remi@remibardon.name>
|
||||
// License: Mozilla Public License v2.0 (MPL v2.0)
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::DEFAULT_CONFIG_FILE_PATHS;
|
||||
|
||||
pub fn defaults_toml() -> &'static str {
|
||||
r#"
|
||||
[server]
|
||||
log_level = "warn"
|
||||
|
||||
[channel]
|
||||
inet = "[::1]:1491"
|
||||
tcp_timeout = 300
|
||||
|
||||
[normalization]
|
||||
# TODO(major): Enable `"nfkc"` by default.
|
||||
unicode_normalization = "none"
|
||||
# TODO(major): Enable by default.
|
||||
diacritic_folding_enabled = false
|
||||
stemming_enabled = false
|
||||
|
||||
[tokenization]
|
||||
detect_special_patterns = true
|
||||
# TODO(major): Disable by default.
|
||||
compat_split_special_patterns = true
|
||||
|
||||
[stopwords]
|
||||
allow = []
|
||||
deny = []
|
||||
|
||||
[search]
|
||||
query_limit_default = 10
|
||||
query_limit_maximum = 100
|
||||
query_alternates_try = 4
|
||||
query_minimum_term_idf_default = 0.1
|
||||
query_minimum_term_idf_minimum_object_count = 100
|
||||
suggest_limit_default = 5
|
||||
suggest_limit_maximum = 20
|
||||
list_limit_default = 100
|
||||
list_limit_maximum = 500
|
||||
|
||||
[store.kv]
|
||||
path = "./data/store/kv/"
|
||||
retain_word_objects = 1000
|
||||
pool.inactive_after = 1800
|
||||
database.flush_after = 900
|
||||
database.compression_type = "zstd"
|
||||
database.parallelism = 2
|
||||
# database.write_buffer_size = 16384 # Default handled via serde
|
||||
database.write_ahead_log = true
|
||||
|
||||
[store.fst]
|
||||
path = "./data/store/fst/"
|
||||
pool.inactive_after = 300
|
||||
graph.consolidate_after = 180
|
||||
graph.max_size = 2048
|
||||
graph.max_words = 250000
|
||||
"#
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn parse(source: impl ::config::Source + Send + Sync + 'static) -> Self {
|
||||
// Read configuration.
|
||||
let raw_config: config::Config = config::Config::builder()
|
||||
// Start from defaults.
|
||||
.add_source(config::File::from_str(
|
||||
defaults_toml(),
|
||||
config::FileFormat::Toml,
|
||||
))
|
||||
// Merge static configuration (from file).
|
||||
.add_source(source)
|
||||
// Merge environment overrides.
|
||||
.add_source(
|
||||
config::Environment::with_prefix("SONIC")
|
||||
.separator("__")
|
||||
.prefix_separator("_"),
|
||||
)
|
||||
.build()
|
||||
.expect("error reading config");
|
||||
|
||||
// `#[serde(flatten)]` breaks type coercion from the `config` crate,
|
||||
// so we can’t have `crate::Config` define
|
||||
// `#[serde(flatten)] sonic: sonic::Config`. It’s a bit dirty but at
|
||||
// least we don’t have to manually add custom deserialization logic to
|
||||
// all non-string fields (in the core!).
|
||||
#[derive(serde::Deserialize)]
|
||||
pub struct ServerConfigTemp {
|
||||
pub channel: ChannelConfig,
|
||||
pub server: ServerConfig,
|
||||
}
|
||||
|
||||
// Parse configuration.
|
||||
let mut server_config = raw_config
|
||||
.clone()
|
||||
.try_deserialize::<ServerConfigTemp>()
|
||||
.expect("syntax error in config");
|
||||
let mut core_config = raw_config
|
||||
.try_deserialize::<sonic::Config>()
|
||||
.expect("syntax error in config");
|
||||
|
||||
back_compat::migrate_channel_search(&mut server_config.channel, &mut core_config);
|
||||
|
||||
// Validate configuration.
|
||||
core_config.validate();
|
||||
|
||||
Config {
|
||||
channel: server_config.channel,
|
||||
server: server_config.server,
|
||||
sonic: Arc::new(core_config),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_config(custom_path: Option<&str>) -> Config {
|
||||
if let Some(custom_path) = custom_path {
|
||||
// Abort if the user specified a config path that does not exist.
|
||||
if !std::path::Path::new(custom_path).exists() {
|
||||
panic!("Cannot find config file at {custom_path:?}");
|
||||
}
|
||||
|
||||
let path = std::path::absolute(custom_path).unwrap();
|
||||
tracing::debug!("reading config file: {path:?}");
|
||||
|
||||
Config::parse(config::File::from(path).format(config::FileFormat::Toml))
|
||||
} else {
|
||||
for path in DEFAULT_CONFIG_FILE_PATHS {
|
||||
let path = std::path::absolute(path).unwrap();
|
||||
tracing::debug!("looking for config file at {path:?}");
|
||||
|
||||
if path.exists() {
|
||||
tracing::debug!("reading config file: {path:?}");
|
||||
|
||||
return Config::parse(config::File::from(path).format(config::FileFormat::Toml));
|
||||
}
|
||||
}
|
||||
|
||||
tracing::debug!("no config file found in known locations, using defaults only");
|
||||
|
||||
Config::parse(config::File::from_str("", config::FileFormat::Toml))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Config {
|
||||
pub channel: ChannelConfig,
|
||||
|
||||
pub server: ServerConfig,
|
||||
|
||||
pub sonic: Arc<sonic::Config>,
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
#[derive(serde::Deserialize)]
|
||||
pub struct ChannelConfig {
|
||||
#[serde(deserialize_with = "sonic::util::serde::env_var::socket_addr")]
|
||||
pub inet: std::net::SocketAddr,
|
||||
|
||||
pub tcp_timeout: u64,
|
||||
|
||||
#[serde(default, deserialize_with = "sonic::util::serde::env_var::opt_str")]
|
||||
pub auth_password: Option<String>,
|
||||
|
||||
#[deprecated(since = "1.6.0", note = "Use `search` instead of `channel.search`")]
|
||||
#[serde(default)]
|
||||
pub search: Option<back_compat::ChannelSearchConfig>,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
pub struct ServerConfig {
|
||||
#[serde(deserialize_with = "sonic::util::serde::env_var::str")]
|
||||
pub log_level: String,
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
mod back_compat {
|
||||
#[deprecated(since = "1.6.0", note = "Use `search` instead of `channel.search`")]
|
||||
#[derive(serde::Deserialize)]
|
||||
pub struct ChannelSearchConfig {
|
||||
#[serde(default)]
|
||||
pub query_limit_default: Option<u16>,
|
||||
|
||||
#[serde(default)]
|
||||
pub query_limit_maximum: Option<u16>,
|
||||
|
||||
#[serde(default)]
|
||||
pub query_alternates_try: Option<usize>,
|
||||
|
||||
#[serde(default)]
|
||||
pub suggest_limit_default: Option<u16>,
|
||||
|
||||
#[serde(default)]
|
||||
pub suggest_limit_maximum: Option<u16>,
|
||||
|
||||
#[serde(default)]
|
||||
pub list_limit_default: Option<u16>,
|
||||
|
||||
#[serde(default)]
|
||||
pub list_limit_maximum: Option<u16>,
|
||||
}
|
||||
|
||||
// This is dirty, but AFAIK (@RemiBardon) the `config` crate doesn’t
|
||||
// provide a better API and hopefully we won’t have to do this again.
|
||||
pub fn migrate_channel_search(
|
||||
channel: &mut crate::config::ChannelConfig,
|
||||
sonic: &mut sonic::Config,
|
||||
) {
|
||||
if let Some(search) = channel.search.take() {
|
||||
tracing::warn!(
|
||||
"You’re still using the deprecated `channel.search` key. \
|
||||
Please use `search` instead. \
|
||||
For this run, we will override `search` with `channel.search`."
|
||||
);
|
||||
|
||||
let ChannelSearchConfig {
|
||||
query_limit_default,
|
||||
query_limit_maximum,
|
||||
query_alternates_try,
|
||||
suggest_limit_default,
|
||||
suggest_limit_maximum,
|
||||
list_limit_default,
|
||||
list_limit_maximum,
|
||||
} = search;
|
||||
|
||||
if let Some(query_limit_default) = query_limit_default {
|
||||
sonic.search.query_limit_default = query_limit_default;
|
||||
}
|
||||
if let Some(query_limit_maximum) = query_limit_maximum {
|
||||
sonic.search.query_limit_maximum = query_limit_maximum;
|
||||
}
|
||||
if let Some(query_alternates_try) = query_alternates_try {
|
||||
sonic.search.query_alternates_try = query_alternates_try;
|
||||
}
|
||||
if let Some(suggest_limit_default) = suggest_limit_default {
|
||||
sonic.search.suggest_limit_default = suggest_limit_default;
|
||||
}
|
||||
if let Some(suggest_limit_maximum) = suggest_limit_maximum {
|
||||
sonic.search.suggest_limit_maximum = suggest_limit_maximum;
|
||||
}
|
||||
if let Some(list_limit_default) = list_limit_default {
|
||||
sonic.search.list_limit_default = list_limit_default;
|
||||
}
|
||||
if let Some(list_limit_maximum) = list_limit_maximum {
|
||||
sonic.search.list_limit_maximum = list_limit_maximum;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn test_channel_search_migration() {
|
||||
let old_config_toml = r#"
|
||||
[channel]
|
||||
search.query_limit_default = 42
|
||||
search.query_alternates_try = 42
|
||||
search.query_minimum_term_idf_default = 42
|
||||
search.query_minimum_term_idf_minimum_object_count = 42
|
||||
search.suggest_limit_default = 42
|
||||
search.suggest_limit_maximum = 42
|
||||
search.list_limit_default = 42
|
||||
search.list_limit_maximum = 42
|
||||
"#;
|
||||
|
||||
let config = crate::Config::parse(config::File::from_str(
|
||||
old_config_toml,
|
||||
config::FileFormat::Toml,
|
||||
));
|
||||
|
||||
assert!(
|
||||
config.channel.search.is_none(),
|
||||
"`channel.search` not emptied"
|
||||
);
|
||||
assert_eq!(
|
||||
config.sonic.search.list_limit_default, 42,
|
||||
"should be overriden"
|
||||
);
|
||||
assert_ne!(
|
||||
config.sonic.search.query_limit_maximum, 42,
|
||||
"should not be overriden"
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[test]
|
||||
fn test_channel_search_migration_mixed() {
|
||||
let old_config_toml = r#"
|
||||
[channel.search]
|
||||
query_limit_default = 42
|
||||
# query_limit_maximum = 42
|
||||
query_alternates_try = 42
|
||||
query_minimum_term_idf_default = 42
|
||||
query_minimum_term_idf_minimum_object_count = 42
|
||||
suggest_limit_default = 42
|
||||
suggest_limit_maximum = 42
|
||||
list_limit_default = 42
|
||||
list_limit_maximum = 42
|
||||
|
||||
[search]
|
||||
query_limit_default = 8
|
||||
query_limit_maximum = 8
|
||||
"#;
|
||||
|
||||
let config = crate::Config::parse(config::File::from_str(
|
||||
old_config_toml,
|
||||
config::FileFormat::Toml,
|
||||
));
|
||||
|
||||
assert!(
|
||||
config.channel.search.is_none(),
|
||||
"`channel.search` not emptied"
|
||||
);
|
||||
assert_eq!(
|
||||
config.sonic.search.list_limit_default, 42,
|
||||
"should be overriden"
|
||||
);
|
||||
assert_eq!(
|
||||
config.sonic.search.query_limit_maximum, 8,
|
||||
"should not be overriden"
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user