You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

config.rs 3.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. use std::collections::*;
  2. use std::convert::TryFrom;
  3. use std::default::Default;
  4. use std::io;
  5. use std::path::PathBuf;
  6. use futures::prelude::*;
  7. use futures::stream::TryStreamExt;
  8. use tokio::fs as tokiofs;
  9. use tokio::io::{AsyncRead, AsyncReadExt};
  10. use toml;
  11. use serde::Deserialize;
  12. use matrix_sdk::identifiers::RoomId;
  13. // FIXME Some of these error types are only used in the main module.
  14. #[derive(Debug)]
  15. pub enum Error {
  16. // TODO Reconcile these different parse errors.
  17. ParseFile(PathBuf),
  18. ParseToml(toml::de::Error),
  19. ParseIdentifier,
  20. Io(io::Error),
  21. }
  22. impl From<io::Error> for Error {
  23. fn from(f: io::Error) -> Self {
  24. Self::Io(f)
  25. }
  26. }
  27. impl From<toml::de::Error> for Error {
  28. fn from(f: toml::de::Error) -> Self {
  29. Self::ParseToml(f)
  30. }
  31. }
  32. #[derive(Default, Debug)]
  33. pub struct Config {
  34. pub accounts: HashMap<String, Account>,
  35. pub spool_dirs: Vec<SpoolDir>,
  36. }
  37. #[derive(Clone, Debug)]
  38. pub struct Account {
  39. pub homeserver: String,
  40. pub display: Option<String>,
  41. pub device_id: Option<String>,
  42. pub auth: Auth,
  43. }
  44. #[derive(Clone, Debug)]
  45. pub enum Auth {
  46. UsernamePass(String, String),
  47. }
  48. #[derive(Debug)]
  49. pub struct SpoolDir {
  50. pub path: PathBuf,
  51. pub send_delay_sec: u32,
  52. pub sender_acct_label: String,
  53. pub dest_room_id: RoomId,
  54. }
  55. #[derive(Clone, Debug, Deserialize)]
  56. pub struct ConfigFile {
  57. acct: Vec<ConfigAccount>,
  58. watch: Vec<ConfigWatch>,
  59. }
  60. #[derive(Clone, Debug, Deserialize)]
  61. pub struct ConfigAccount {
  62. label: String,
  63. homeserver: String,
  64. username: String,
  65. password: String,
  66. }
  67. #[derive(Clone, Debug, Deserialize)]
  68. pub struct ConfigWatch {
  69. sender: String,
  70. path: String,
  71. destroom: String,
  72. }
  73. pub async fn find_configs(search_dir: &PathBuf) -> Result<Vec<PathBuf>, Error> {
  74. let mut items: Vec<tokiofs::DirEntry> = Vec::new();
  75. let mut rd = tokiofs::read_dir(search_dir).await?;
  76. while let Some(dent) = rd.next_entry().await? {
  77. items.push(dent);
  78. }
  79. Ok(items
  80. .into_iter()
  81. .filter(|de| {
  82. de.file_name()
  83. .to_str()
  84. .map(|s| s.ends_with(".toml"))
  85. .unwrap_or(false)
  86. })
  87. .map(|e| e.path())
  88. .collect())
  89. }
  90. pub async fn parse_configs(paths: &Vec<PathBuf>) -> Result<Config, Error> {
  91. let mut conf = Config::default();
  92. for p in paths {
  93. println!("Reading config: {}", p.to_str().unwrap_or("[non-UTF-8]"));
  94. let val = match load_toml(p).await {
  95. Ok(t) => t,
  96. Err(_) => {
  97. println!("warning: error loading config, skipping: {:?}", p);
  98. continue;
  99. }
  100. };
  101. // Ingest the accounts.
  102. for a in val.acct {
  103. if conf.accounts.contains_key(&a.label) {
  104. eprintln!("warning: ignoring duplicate account entry for {}", a.label);
  105. continue;
  106. }
  107. let acct = Account {
  108. homeserver: a.homeserver,
  109. auth: Auth::UsernamePass(a.username, a.password),
  110. device_id: None,
  111. display: None,
  112. };
  113. conf.accounts.insert(a.label, acct);
  114. }
  115. // Ingest the watches.
  116. for s in val.watch {
  117. let sd = SpoolDir {
  118. path: PathBuf::from(s.path),
  119. send_delay_sec: 0,
  120. sender_acct_label: s.sender,
  121. dest_room_id: RoomId::try_from(s.destroom.as_str())
  122. .map_err(|_| Error::ParseIdentifier)?,
  123. };
  124. conf.spool_dirs.push(sd);
  125. }
  126. }
  127. Ok(conf)
  128. }
  129. async fn load_toml(path: &PathBuf) -> Result<ConfigFile, Error> {
  130. let mut buf = Vec::new();
  131. let mut f = tokiofs::File::open(path).await?;
  132. let _ = f.read_to_end(&mut buf).await?;
  133. toml::from_slice(&buf).map_err(|e| {
  134. eprintln!("warning: parsing file {:?}", e);
  135. Error::ParseFile(path.clone())
  136. })
  137. }