131 lines
3.7 KiB
Rust
131 lines
3.7 KiB
Rust
use std::{collections::HashMap, fmt, fs::File, io::BufReader};
|
|
|
|
use anyhow::Context;
|
|
use matrix_sdk::ruma::{OwnedRoomOrAliasId, OwnedUserId, RoomOrAliasId, UserId};
|
|
use serde::de;
|
|
|
|
#[derive(Deserialize)]
|
|
pub struct RepoConfig {
|
|
pub token: String,
|
|
#[serde(default)]
|
|
#[serde(deserialize_with = "deser_optional_room_or_alias_id")]
|
|
pub room: Option<OwnedRoomOrAliasId>,
|
|
}
|
|
|
|
#[derive(Deserialize)]
|
|
pub struct Config {
|
|
pub bind_address: Option<String>,
|
|
pub bind_port: Option<u16>,
|
|
pub url_prefix: Option<String>,
|
|
#[serde(deserialize_with = "deser_user_id")]
|
|
pub user_id: OwnedUserId,
|
|
pub password: String,
|
|
#[serde(default)]
|
|
#[serde(deserialize_with = "deser_optional_room_or_alias_id")]
|
|
pub default_room: Option<OwnedRoomOrAliasId>,
|
|
pub repo_configs: HashMap<String, RepoConfig>, // key is repo url without scheme; e.g.
|
|
// gitlab.xfce.org/xfce/xfdesktop
|
|
}
|
|
|
|
fn deser_user_id<'de, D>(deserializer: D) -> Result<OwnedUserId, D::Error>
|
|
where
|
|
D: de::Deserializer<'de>,
|
|
{
|
|
struct UserIdVisitor;
|
|
|
|
impl<'de> de::Visitor<'de> for UserIdVisitor {
|
|
type Value = OwnedUserId;
|
|
|
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
formatter.write_str("a matrix user ID")
|
|
}
|
|
|
|
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
|
where
|
|
E: de::Error,
|
|
{
|
|
UserId::parse(v).map_err(E::custom)
|
|
}
|
|
}
|
|
|
|
deserializer.deserialize_any(UserIdVisitor)
|
|
}
|
|
|
|
fn deser_room_or_alias_id<'de, D>(deserializer: D) -> Result<OwnedRoomOrAliasId, D::Error>
|
|
where
|
|
D: de::Deserializer<'de>,
|
|
{
|
|
struct RoomOrAliasIdVisitor;
|
|
|
|
impl<'de> de::Visitor<'de> for RoomOrAliasIdVisitor {
|
|
type Value = OwnedRoomOrAliasId;
|
|
|
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
formatter.write_str("a matrix room ID")
|
|
}
|
|
|
|
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
|
where
|
|
E: de::Error,
|
|
{
|
|
RoomOrAliasId::parse(v).map_err(E::custom)
|
|
}
|
|
}
|
|
|
|
deserializer.deserialize_any(RoomOrAliasIdVisitor)
|
|
}
|
|
|
|
fn deser_optional_room_or_alias_id<'de, D>(deserializer: D) -> Result<Option<OwnedRoomOrAliasId>, D::Error>
|
|
where
|
|
D: de::Deserializer<'de>,
|
|
{
|
|
struct OptionalRoomOrAliasIdVisitor;
|
|
|
|
impl<'de> de::Visitor<'de> for OptionalRoomOrAliasIdVisitor {
|
|
type Value = Option<OwnedRoomOrAliasId>;
|
|
|
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
formatter.write_str("null or matrix room ID")
|
|
}
|
|
|
|
fn visit_none<E>(self) -> Result<Self::Value, E>
|
|
where
|
|
E: de::Error,
|
|
{
|
|
Ok(None)
|
|
}
|
|
|
|
fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
|
where
|
|
D: serde::Deserializer<'de>,
|
|
{
|
|
Ok(Some(deser_room_or_alias_id(deserializer)?))
|
|
}
|
|
|
|
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
|
where
|
|
E: de::Error,
|
|
{
|
|
RoomOrAliasId::parse(v).map(Some).map_err(E::custom)
|
|
}
|
|
}
|
|
|
|
deserializer.deserialize_any(OptionalRoomOrAliasIdVisitor)
|
|
}
|
|
|
|
fn load_blocking(path: &String) -> anyhow::Result<Config> {
|
|
let f = File::open(path)?;
|
|
let r = BufReader::new(f);
|
|
let config: Config = serde_yaml::from_reader(r)?;
|
|
Ok(config)
|
|
}
|
|
|
|
pub async fn load<S: AsRef<str>>(path: S) -> anyhow::Result<Config> {
|
|
let p = String::from(path.as_ref());
|
|
let config = tokio::task::spawn_blocking(move || {
|
|
load_blocking(&p).with_context(|| format!("Failed to load config from {}", p))
|
|
})
|
|
.await??;
|
|
Ok(config)
|
|
}
|