Upstream valeriansaliou/sonic state of the touched files before abd3d56935

This commit is contained in:
upstream committed 2026-10-10 12:42:09 +02:00
1 parent 73692bcfdb
commit 0f79d0dab8
11 files changed
+2450 -1

No files matched your search

+325
View File
@@ -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"
);
}
}