]> Untitled Git - lemmy.git/commitdiff
Generate config docs from code (#1786)
authorNutomic <me@nutomic.com>
Fri, 8 Oct 2021 15:07:24 +0000 (15:07 +0000)
committerGitHub <noreply@github.com>
Fri, 8 Oct 2021 15:07:24 +0000 (11:07 -0400)
* Generate config docs from code

* update library

* move settings comments from config.hjson to code

* updte doku to 0.10

* update doku

Cargo.lock
Cargo.toml
config/config.hjson
crates/utils/Cargo.toml
crates/utils/src/settings/mod.rs
crates/utils/src/settings/structs.rs
src/main.rs

index 6c5adba317061baa7de6101c50b6190a9d77e5de..8dff7b2714d5b2b4b3c5fc8df48ba180a0c41ecc 100644 (file)
@@ -1000,6 +1000,28 @@ version = "1.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "31ad93652f40969dead8d4bf897a41e9462095152eb21c56e5830537e41179dd"
 
+[[package]]
+name = "doku"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b44778199365a299b026bf1c16d80579adaeba3c484244e1561f3a93de43451a"
+dependencies = [
+ "doku-derive",
+ "serde",
+]
+
+[[package]]
+name = "doku-derive"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "949dc0bf36de2fe276d42c79ff81cf4326c45b98b091c0edec75e857b5775626"
+dependencies = [
+ "darling 0.13.0",
+ "proc-macro2 1.0.29",
+ "quote 1.0.10",
+ "syn 1.0.80",
+]
+
 [[package]]
 name = "either"
 version = "1.6.1"
@@ -1924,6 +1946,7 @@ dependencies = [
  "clokwerk",
  "diesel",
  "diesel_migrations",
+ "doku",
  "env_logger",
  "http-signature-normalization-actix",
  "lemmy_api",
@@ -1960,6 +1983,7 @@ dependencies = [
  "comrak",
  "deser-hjson",
  "diesel",
+ "doku",
  "futures",
  "http",
  "itertools",
index 199c732eeba6ddc59755270427ebe7320fa42712..8fe071a832f36f285ae525fe69aa709329829487 100644 (file)
@@ -64,6 +64,7 @@ activitystreams = "0.7.0-alpha.11"
 actix-rt = { version = "2.2.0", default-features = false }
 serde_json = { version = "1.0.68", features = ["preserve_order"] }
 clokwerk = "0.3.5"
+doku = "0.10.1"
 
 [dev-dependencies.cargo-husky]
 version = "1.5.0"
index 11b64b2048362510d5ac711e207bbd587b97809b..252fca25044f07c0075e52174f23c88f3d37d2ce 100644 (file)
@@ -1,95 +1,5 @@
+# See the documentation for available config fields and descriptions:
+# https://join-lemmy.org/docs/en/administration/configuration.html
 {
-#  # optional: parameters for automatic configuration of new instance (only used at first start)
-#  setup: {
-#    # username for the admin user
-#    admin_username: ""
-#    # password for the admin user
-#    admin_password: ""
-#    # optional: email for the admin user (can be omitted and set later through the website)
-#    admin_email: ""
-#    # name of the site (can be changed later)
-#    site_name: ""
-#  }
-  # settings related to the postgresql database
-  database: {
-    # username to connect to postgres
-    user: "lemmy"
-    # password to connect to postgres
-    password: "password"
-    # host where postgres is running
-    host: "localhost"
-    # port where postgres can be accessed
-    port: 5432
-    # name of the postgres database for lemmy
-    database: "lemmy"
-    # maximum number of active sql connections
-    pool_size: 5
-  }
-  # the domain name of your instance (eg "lemmy.ml")
   hostname: lemmy-alpha
-  # address where lemmy should listen for incoming requests
-  bind: "0.0.0.0"
-  # port where lemmy should listen for incoming requests
-  port: 8536
-  # whether tls is required for activitypub. only disable this for debugging, never for producion.
-  tls_enabled: true
-  # address where pictrs is available
-  pictrs_url: "http://pictrs:8080"
-  # maximum length of local community and user names
-  actor_name_max_length: 20
-  # rate limits for various user actions, by user ip
-  rate_limit: {
-    # maximum number of messages created in interval
-    message: 180
-    # interval length for message limit
-    message_per_second: 60
-    # maximum number of posts created in interval
-    post: 6
-    # interval length for post limit
-    post_per_second: 600
-    # maximum number of registrations in interval
-    register: 3
-    # interval length for registration limit
-    register_per_second: 3600
-    # maximum number of image uploads in interval
-    image: 6
-    # interval length for image uploads
-    image_per_second: 3600
-  }
-  # settings related to activitypub federation
-  federation: {
-    # whether to enable activitypub federation.
-    enabled: false
-    # Allows and blocks are described here:
-    # https://join-lemmy.org/docs/en/federation/administration.html#instance-allowlist-and-blocklist
-    #
-    # list of instances with which federation is allowed
-    # allowed_instances: ["instance1.tld","instance2.tld"]
-    # instances which we never federate anything with (but previously federated objects are unaffected)
-    # blocked_instances: []
-    # If true, only federate with instances on the allowlist and block everything else. If false,
-    # use allowlist only for remote communities, and posts/comments in local communities.
-    # strict_allowlist: true
-  }
-  captcha: {
-    enabled: true
-    difficulty: medium # Can be easy, medium, or hard
-  }
-#  # email sending configuration
-#  email: {
-#    # hostname and port of the smtp server
-#    smtp_server: ""
-#    # login name for smtp server
-#    smtp_login: ""
-#    # password to login to the smtp server
-#    smtp_password: ""
-#    # address to send emails from, eg "noreply@your-instance.com"
-#    smtp_from_address: ""
-#    # whether or not smtp connections should use tls
-#    use_tls: true
-#  }
-  # additional_slurs:
-  #  '''
-  #  (\bThis\b)|(\bis\b)|(\bsample\b)
-  #  '''
 }
index f8e7804acabc4e84c556cab612d2b451db8a3ea3..9671b885ce5b058a9c610963c87a005604b6bc34 100644 (file)
@@ -39,3 +39,4 @@ deser-hjson = "1.0.2"
 smart-default = "0.6.0"
 webpage = { version = "1.3.0", default-features = false, features = ["serde"] }
 jsonwebtoken = "7.2.0"
+doku = "0.10.1"
index 7e320701db80a3fc54a1fe8b8056b86702c5d876..6678b91f5d99776ae98ec29393d5ad96abcf19d9 100644 (file)
@@ -11,6 +11,16 @@ static DEFAULT_CONFIG_FILE: &str = "config/config.hjson";
 lazy_static! {
   static ref SETTINGS: RwLock<Settings> =
     RwLock::new(Settings::init().expect("Failed to load settings file"));
+  static ref WEBFINGER_COMMUNITY_REGEX: Regex = Regex::new(&format!(
+    "^group:([a-z0-9_]{{3,}})@{}$",
+    Settings::get().hostname
+  ))
+  .expect("compile webfinger regex");
+  static ref WEBFINGER_USER_REGEX: Regex = Regex::new(&format!(
+    "^acct:([a-z0-9_]{{3,}})@{}$",
+    Settings::get().hostname
+  ))
+  .expect("compile webfinger regex");
 }
 
 impl Settings {
@@ -21,22 +31,12 @@ impl Settings {
   /// Warning: Only call this once.
   pub fn init() -> Result<Self, LemmyError> {
     // Read the config file
-    let mut config = from_str::<Settings>(&Self::read_config_file()?)?;
+    let config = from_str::<Settings>(&Self::read_config_file()?)?;
 
     if config.hostname == "unset" {
       return Err(anyhow!("Hostname variable is not set!").into());
     }
 
-    // Initialize the regexes
-    config.webfinger_community_regex = Some(
-      Regex::new(&format!("^group:([a-z0-9_]{{3,}})@{}$", config.hostname))
-        .expect("compile webfinger regex"),
-    );
-    config.webfinger_username_regex = Some(
-      Regex::new(&format!("^acct:([a-z0-9_]{{3,}})@{}$", config.hostname))
-        .expect("compile webfinger regex"),
-    );
-
     Ok(config)
   }
 
@@ -106,17 +106,11 @@ impl Settings {
   }
 
   pub fn webfinger_community_regex(&self) -> Regex {
-    self
-      .webfinger_community_regex
-      .to_owned()
-      .expect("compile webfinger regex")
+    WEBFINGER_COMMUNITY_REGEX.to_owned()
   }
 
   pub fn webfinger_username_regex(&self) -> Regex {
-    self
-      .webfinger_username_regex
-      .to_owned()
-      .expect("compile webfinger regex")
+    WEBFINGER_USER_REGEX.to_owned()
   }
 
   pub fn slur_regex(&self) -> Regex {
index 29334934863d085d2df5c076b2db4e94510a4918..4ec17906ba6d348605b2d866e33fdd2bd24336e3 100644 (file)
-use regex::Regex;
-use serde::Deserialize;
+use doku::Document;
+use serde::{Deserialize, Serialize};
 use std::net::{IpAddr, Ipv4Addr};
 
-#[derive(Debug, Deserialize, Clone, SmartDefault)]
+#[derive(Debug, Deserialize, Serialize, Clone, SmartDefault, Document)]
 #[serde(default)]
 pub struct Settings {
+  /// settings related to the postgresql database
   #[serde(default)]
   pub database: DatabaseConfig,
   #[default(Some(RateLimitConfig::default()))]
+  /// rate limits for various user actions, by user ip
   pub rate_limit: Option<RateLimitConfig>,
+  /// Settings related to activitypub federation
   #[default(FederationConfig::default())]
   pub federation: FederationConfig,
   #[default(CaptchaConfig::default())]
   pub captcha: CaptchaConfig,
+  /// Email sending configuration. All options except login/password are mandatory
   #[default(None)]
   pub email: Option<EmailConfig>,
+  /// Parameters for automatic configuration of new instance (only used at first start)
   #[default(None)]
   pub setup: Option<SetupConfig>,
+  /// the domain name of your instance (mandatory)
   #[default("unset")]
+  #[doku(example = "example.com")]
   pub hostname: String,
+  /// Address where lemmy should listen for incoming requests
   #[default(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)))]
+  #[doku(as = "String")]
   pub bind: IpAddr,
+  /// Port where lemmy should listen for incoming requests
   #[default(8536)]
   pub port: u16,
+  /// Whether the site is available over TLS. Needs to be true for federation to work.
   #[default(true)]
   pub tls_enabled: bool,
+  /// Address where pictrs is available (for image hosting)
   #[default(None)]
+  #[doku(example = "http://localhost:8080")]
   pub pictrs_url: Option<String>,
+  /// Regex for slurs which are prohibited. Example: `(\bThis\b)|(\bis\b)|(\bsample\b)`
   #[default(None)]
   pub additional_slurs: Option<String>,
+  /// Maximum length of local community and user names
   #[default(20)]
   pub actor_name_max_length: usize,
-  #[default(None)]
-  #[serde(skip)]
-  pub webfinger_community_regex: Option<Regex>,
-  #[default(None)]
-  #[serde(skip)]
-  pub webfinger_username_regex: Option<Regex>,
 }
 
-#[derive(Debug, Deserialize, Clone, SmartDefault)]
+#[derive(Debug, Deserialize, Serialize, Clone, SmartDefault, Document)]
 #[serde(default)]
 pub struct CaptchaConfig {
+  /// Whether captcha is required for signup
   #[default(false)]
   pub enabled: bool,
+  /// Can be easy, medium, or hard
   #[default("medium")]
   pub difficulty: String,
 }
 
-#[derive(Debug, Deserialize, Clone, SmartDefault)]
+#[derive(Debug, Deserialize, Serialize, Clone, SmartDefault, Document)]
 #[serde(default)]
 pub struct DatabaseConfig {
+  /// Username to connect to postgres
   #[default("lemmy")]
   pub(super) user: String,
+  /// Password to connect to postgres
   #[default("password")]
   pub password: String,
   #[default("localhost")]
+  /// Host where postgres is running
   pub host: String,
+  /// Port where postgres can be accessed
   #[default(5432)]
   pub(super) port: i32,
+  /// Name of the postgres database for lemmy
   #[default("lemmy")]
   pub(super) database: String,
+  /// Maximum number of active sql connections
   #[default(5)]
   pub pool_size: u32,
 }
 
-#[derive(Debug, Deserialize, Clone)]
+#[derive(Debug, Deserialize, Serialize, Clone, Document)]
 pub struct EmailConfig {
+  /// Hostname and port of the smtp server
+  #[doku(example = "localhost:25")]
   pub smtp_server: String,
+  /// Login name for smtp server
   pub smtp_login: Option<String>,
+  /// Password to login to the smtp server
   pub smtp_password: Option<String>,
+  #[doku(example = "noreply@example.com")]
+  /// Address to send emails from, eg "noreply@your-instance.com"
   pub smtp_from_address: String,
+  /// Whether or not smtp connections should use tls
   pub use_tls: bool,
 }
 
-#[derive(Debug, Deserialize, Clone, SmartDefault)]
+#[derive(Debug, Deserialize, Serialize, Clone, SmartDefault, Document)]
 #[serde(default)]
 pub struct FederationConfig {
+  /// Whether to enable activitypub federation.
   #[default(false)]
   pub enabled: bool,
+  /// Allows and blocks are described here:
+  /// https://join-lemmy.org/docs/en/federation/administration.html///instance-allowlist-and-blocklist
+  ///
+  /// list of instances with which federation is allowed
   #[default(None)]
+  #[doku(example = "instance1.tld")]
+  #[doku(example = "instance2.tld")]
   pub allowed_instances: Option<Vec<String>>,
+  /// Instances which we never federate anything with (but previously federated objects are unaffected)
   #[default(None)]
   pub blocked_instances: Option<Vec<String>>,
+  /// If true, only federate with instances on the allowlist and block everything else. If false,
+  /// use allowlist only for remote communities, and posts/comments in local communities
+  /// (meaning remote communities will show content from arbitrary instances).
   #[default(true)]
   pub strict_allowlist: bool,
 }
 
-#[derive(Debug, Deserialize, Clone, SmartDefault)]
+#[derive(Debug, Deserialize, Serialize, Clone, SmartDefault, Document)]
 #[serde(default)]
 pub struct RateLimitConfig {
+  /// Maximum number of messages created in interval
   #[default(180)]
   pub message: i32,
+  /// Interval length for message limit, in seconds
   #[default(60)]
   pub message_per_second: i32,
+  /// Maximum number of posts created in interval
   #[default(6)]
   pub post: i32,
+  /// Interval length for post limit, in seconds
   #[default(600)]
   pub post_per_second: i32,
+  /// Maximum number of registrations in interval
   #[default(3)]
   pub register: i32,
+  /// Interval length for registration limit, in seconds
   #[default(3600)]
   pub register_per_second: i32,
+  /// Maximum number of image uploads in interval
   #[default(6)]
   pub image: i32,
+  /// Interval length for image uploads, in seconds
   #[default(3600)]
   pub image_per_second: i32,
 }
 
-#[derive(Debug, Deserialize, Clone, SmartDefault)]
+#[derive(Debug, Deserialize, Serialize, Clone, SmartDefault, Document)]
 pub struct SetupConfig {
+  /// Username for the admin user
+  #[doku(example = "admin")]
   pub admin_username: String,
+  /// Password for the admin user
+  #[doku(example = "my_passwd")]
   pub admin_password: String,
+  /// Name of the site (can be changed later)
+  #[doku(example = "My Lemmy Instance")]
   pub site_name: String,
+  /// Email for the admin user (optional, can be omitted and set later through the website)
   #[default(None)]
   pub admin_email: Option<String>,
   #[default(None)]
index 7d49e32ba096a32cf592228b6661100e0db93154..483b174153e8a9c0e81011dd94c933145f34d845 100644 (file)
@@ -7,6 +7,7 @@ use diesel::{
   r2d2::{ConnectionManager, Pool},
   PgConnection,
 };
+use doku::json::{AutoComments, Formatting};
 use lemmy_api::match_websocket_operation;
 use lemmy_api_common::blocking;
 use lemmy_api_crud::match_websocket_operation_crud;
@@ -23,13 +24,23 @@ use lemmy_utils::{
 };
 use lemmy_websocket::{chat_server::ChatServer, LemmyContext};
 use reqwest::Client;
-use std::{sync::Arc, thread};
+use std::{env, sync::Arc, thread};
 use tokio::sync::Mutex;
 
 embed_migrations!();
 
 #[actix_web::main]
 async fn main() -> Result<(), LemmyError> {
+  let args: Vec<String> = env::args().collect();
+  if args.len() == 2 && args[1] == "--print-config-docs" {
+    let fmt = Formatting {
+      auto_comments: AutoComments::none(),
+      ..Default::default()
+    };
+    println!("{}", doku::to_json_fmt_val(&fmt, &Settings::default()));
+    return Ok(());
+  }
+
   env_logger::init();
   let settings = Settings::init().expect("Couldn't initialize settings.");