您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. //#![allow(unused)]
  2. #![allow(incomplete_features)]
  3. #![feature(impl_trait_in_bindings)]
  4. #![feature(async_closure)]
  5. use std::collections::*;
  6. use std::path::PathBuf;
  7. use clap::Clap;
  8. use tokio::runtime;
  9. use tokio::sync::mpsc;
  10. mod config;
  11. mod sender;
  12. mod spool;
  13. use crate::config::*;
  14. #[derive(Clap)]
  15. #[clap(version = "0.1")]
  16. struct Opts {
  17. #[clap(
  18. name = "config",
  19. short = "c",
  20. help = "Read this config file by itself, parsed before -C"
  21. )]
  22. conf: Option<PathBuf>,
  23. #[clap(
  24. name = "configdir",
  25. short = "C",
  26. help = "Read all config files in this directory"
  27. )]
  28. conf_dir: Option<PathBuf>,
  29. #[clap(
  30. name = "triggerpath",
  31. short = "r",
  32. help = "Delete this file to trigger a config reload [NYI]"
  33. )]
  34. reload_trigger: Option<PathBuf>,
  35. }
  36. fn main() {
  37. let opts = Opts::parse();
  38. if opts.reload_trigger.is_some() {
  39. eprintln!("[init] warning: reload trigger file specified, but this option is not supported yet, ignoring...");
  40. }
  41. let mut rt = make_runtime();
  42. // Figure out which files we want to configure.
  43. let mut confs = Vec::new();
  44. if let Some(main) = opts.conf {
  45. confs.push(main.clone());
  46. }
  47. if let Some(dir) = opts.conf_dir {
  48. match rt.block_on(find_configs(&dir)) {
  49. Ok(paths) => confs.extend(paths),
  50. Err(e) => {
  51. eprintln!("[init] error reading configuration: {:?}", e);
  52. return;
  53. }
  54. }
  55. }
  56. // Sanity check.
  57. if confs.len() == 0 {
  58. println!("[init] no configuration declared, exiting...");
  59. return;
  60. }
  61. // Process configuration.
  62. // TODO Remove all these cases of `block_on` except for a final toplevel task.
  63. let config = match rt.block_on(parse_configs(&confs)) {
  64. Ok(c) => c,
  65. Err(e) => {
  66. eprintln!("[init] error parsing configuration: {:?}", e);
  67. return; // maybe
  68. }
  69. };
  70. let mut clients = HashMap::new();
  71. let mut sender_futs = Vec::new();
  72. // Init each account and put outgoing channels into a table for later reference.
  73. for cc in config.accounts.iter() {
  74. match rt.block_on(sender::create_and_auth_client(cc.1.clone())) {
  75. Ok(c) => {
  76. let (send, recv) = mpsc::channel(2); // FIXME configurable
  77. clients.insert(cc.0.clone(), send);
  78. sender_futs.push(sender::submit_messages(c, recv));
  79. }
  80. Err(e) => {
  81. eprintln!("[init] error: client setup failed: {:?}", e);
  82. return; // maybe
  83. }
  84. }
  85. }
  86. // This is where the real stuff actually happens.
  87. match rt.block_on(spool::start_spoolers(config, clients)) {
  88. Ok(_) => {}
  89. Err(e) => println!("fatal error: {:?}", e),
  90. }
  91. // just wait I guess?
  92. rt.block_on(futures::future::join_all(sender_futs.into_iter()));
  93. }
  94. fn make_runtime() -> runtime::Runtime {
  95. runtime::Builder::new()
  96. .max_threads(1)
  97. .enable_all()
  98. .basic_scheduler()
  99. .build()
  100. .expect("init runtime")
  101. }