Compare commits
8 commits
main
...
try_hjson_
Author | SHA1 | Date | |
---|---|---|---|
b4bbb06e13 | |||
59cce4a1f5 | |||
62c9be5b56 | |||
1bc7317b24 | |||
f83b5590c7 | |||
1a02ab3482 | |||
cddf9a6a85 | |||
f19c7a2e72 |
39 changed files with 681 additions and 379 deletions
|
@ -1,5 +1,5 @@
|
|||
tab_spaces = 2
|
||||
edition="2018"
|
||||
imports_layout="HorizontalVertical"
|
||||
merge_imports=true
|
||||
imports_granularity="Crate"
|
||||
reorder_imports=true
|
||||
|
|
188
Cargo.lock
generated
188
Cargo.lock
generated
|
@ -1,5 +1,7 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "activitystreams"
|
||||
version = "0.7.0-alpha.10"
|
||||
|
@ -8,7 +10,7 @@ checksum = "fe7ceed015dfca322d3bcec3653909c77557e7e57df72e98cb8806e2c93cc919"
|
|||
dependencies = [
|
||||
"chrono",
|
||||
"mime",
|
||||
"serde 1.0.123",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"url",
|
||||
|
@ -21,7 +23,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "bb8e19a0810cc25df3535061a08b7d8f8a734d309ea4411c57a9767e4a2ffa0e"
|
||||
dependencies = [
|
||||
"activitystreams",
|
||||
"serde 1.0.123",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
|
@ -128,7 +130,7 @@ dependencies = [
|
|||
"pin-project 1.0.4",
|
||||
"rand 0.7.3",
|
||||
"regex",
|
||||
"serde 1.0.123",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"sha-1 0.9.3",
|
||||
|
@ -156,7 +158,7 @@ dependencies = [
|
|||
"http",
|
||||
"log",
|
||||
"regex",
|
||||
"serde 1.0.123",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -300,7 +302,7 @@ dependencies = [
|
|||
"pin-project 1.0.4",
|
||||
"regex",
|
||||
"rustls",
|
||||
"serde 1.0.123",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"socket2",
|
||||
|
@ -389,12 +391,6 @@ version = "1.0.38"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
|
||||
|
||||
[[package]]
|
||||
name = "async-mutex"
|
||||
version = "1.4.0"
|
||||
|
@ -464,7 +460,7 @@ dependencies = [
|
|||
"percent-encoding",
|
||||
"rand 0.7.3",
|
||||
"rustls",
|
||||
"serde 1.0.123",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
]
|
||||
|
@ -494,7 +490,7 @@ dependencies = [
|
|||
"log",
|
||||
"num_cpus",
|
||||
"rand 0.7.3",
|
||||
"serde 1.0.123",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"tokio 0.2.25",
|
||||
|
@ -513,7 +509,7 @@ dependencies = [
|
|||
"async-trait",
|
||||
"chrono",
|
||||
"log",
|
||||
"serde 1.0.123",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"tokio 0.2.25",
|
||||
|
@ -733,8 +729,8 @@ checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
|
|||
dependencies = [
|
||||
"libc",
|
||||
"num-integer",
|
||||
"num-traits 0.2.14",
|
||||
"serde 1.0.123",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"time 0.1.44",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
@ -781,18 +777,6 @@ dependencies = [
|
|||
"xdg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "config"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19b076e143e1d9538dde65da30f8481c2a6c44040edb8e02b9bf1351edb92ce3"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"nom 5.1.2",
|
||||
"serde 1.0.123",
|
||||
"serde-hjson",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const_fn"
|
||||
version = "0.4.5"
|
||||
|
@ -995,6 +979,15 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deser-hjson"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d995b60ff81bc6af01a98f0bf5db70a7418a1ac8bd74ada633968f388139da5e"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diesel"
|
||||
version = "1.4.5"
|
||||
|
@ -1590,7 +1583,7 @@ dependencies = [
|
|||
"jpeg-decoder",
|
||||
"num-iter",
|
||||
"num-rational",
|
||||
"num-traits 0.2.14",
|
||||
"num-traits",
|
||||
"png",
|
||||
"scoped_threadpool",
|
||||
"tiff",
|
||||
|
@ -1684,7 +1677,7 @@ dependencies = [
|
|||
"base64 0.12.3",
|
||||
"pem",
|
||||
"ring",
|
||||
"serde 1.0.123",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"simple_asn1",
|
||||
]
|
||||
|
@ -1745,7 +1738,7 @@ dependencies = [
|
|||
"openssl",
|
||||
"rand 0.8.3",
|
||||
"reqwest",
|
||||
"serde 1.0.123",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"strum",
|
||||
|
@ -1792,7 +1785,7 @@ dependencies = [
|
|||
"percent-encoding",
|
||||
"rand 0.8.3",
|
||||
"reqwest",
|
||||
"serde 1.0.123",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"strum",
|
||||
|
@ -1816,7 +1809,7 @@ dependencies = [
|
|||
"lemmy_utils",
|
||||
"log",
|
||||
"regex",
|
||||
"serde 1.0.123",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"strum",
|
||||
|
@ -1831,7 +1824,7 @@ dependencies = [
|
|||
"chrono",
|
||||
"diesel",
|
||||
"log",
|
||||
"serde 1.0.123",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"url",
|
||||
]
|
||||
|
@ -1844,7 +1837,7 @@ dependencies = [
|
|||
"lemmy_db_queries",
|
||||
"lemmy_db_schema",
|
||||
"log",
|
||||
"serde 1.0.123",
|
||||
"serde",
|
||||
"url",
|
||||
]
|
||||
|
||||
|
@ -1855,7 +1848,7 @@ dependencies = [
|
|||
"diesel",
|
||||
"lemmy_db_queries",
|
||||
"lemmy_db_schema",
|
||||
"serde 1.0.123",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1865,7 +1858,7 @@ dependencies = [
|
|||
"diesel",
|
||||
"lemmy_db_queries",
|
||||
"lemmy_db_schema",
|
||||
"serde 1.0.123",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1889,7 +1882,7 @@ dependencies = [
|
|||
"lemmy_websocket",
|
||||
"log",
|
||||
"rss",
|
||||
"serde 1.0.123",
|
||||
"serde",
|
||||
"sha2",
|
||||
"strum",
|
||||
"url",
|
||||
|
@ -1925,7 +1918,7 @@ dependencies = [
|
|||
"log",
|
||||
"openssl",
|
||||
"reqwest",
|
||||
"serde 1.0.123",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"strum",
|
||||
"tokio 0.3.7",
|
||||
|
@ -1946,7 +1939,7 @@ dependencies = [
|
|||
"lemmy_db_views_moderator",
|
||||
"lemmy_utils",
|
||||
"log",
|
||||
"serde 1.0.123",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"url",
|
||||
]
|
||||
|
@ -1960,7 +1953,7 @@ dependencies = [
|
|||
"anyhow",
|
||||
"chrono",
|
||||
"comrak",
|
||||
"config",
|
||||
"deser-hjson",
|
||||
"diesel",
|
||||
"futures",
|
||||
"http",
|
||||
|
@ -1974,7 +1967,7 @@ dependencies = [
|
|||
"rand 0.8.3",
|
||||
"regex",
|
||||
"reqwest",
|
||||
"serde 1.0.123",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
|
@ -2001,7 +1994,7 @@ dependencies = [
|
|||
"log",
|
||||
"rand 0.8.3",
|
||||
"reqwest",
|
||||
"serde 1.0.123",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
|
@ -2020,46 +2013,23 @@ dependencies = [
|
|||
"idna",
|
||||
"mime",
|
||||
"native-tls",
|
||||
"nom 6.1.0",
|
||||
"nom",
|
||||
"once_cell",
|
||||
"quoted_printable",
|
||||
"r2d2",
|
||||
"rand 0.8.3",
|
||||
"regex",
|
||||
"serde 1.0.123",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lexical-core"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db65c6da02e61f55dae90a0ae427b2a5f6b3e8db09f58d10efab23af92592616"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bitflags",
|
||||
"cfg-if 0.1.10",
|
||||
"ryu",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1cca32fa0182e8c0989459524dc356b8f2b5c10f1b9eb521b7d182c03cf8c5ff"
|
||||
|
||||
[[package]]
|
||||
name = "linked-hash-map"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d262045c5b87c0861b3f004610afd0e2c851e2908d08b6c870cbb9d5f494ecd"
|
||||
dependencies = [
|
||||
"serde 0.8.23",
|
||||
"serde_test",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linked-hash-map"
|
||||
version = "0.5.4"
|
||||
|
@ -2102,7 +2072,7 @@ version = "0.1.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c"
|
||||
dependencies = [
|
||||
"linked-hash-map 0.5.4",
|
||||
"linked-hash-map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2271,17 +2241,6 @@ dependencies = [
|
|||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "5.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af"
|
||||
dependencies = [
|
||||
"lexical-core",
|
||||
"memchr",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "6.1.0"
|
||||
|
@ -2301,7 +2260,7 @@ checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304"
|
|||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits 0.2.14",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2311,7 +2270,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-traits 0.2.14",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2322,7 +2281,7 @@ checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59"
|
|||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits 0.2.14",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2333,16 +2292,7 @@ checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07"
|
|||
dependencies = [
|
||||
"autocfg",
|
||||
"num-integer",
|
||||
"num-traits 0.2.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.1.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
|
||||
dependencies = [
|
||||
"num-traits 0.2.14",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2838,7 +2788,7 @@ dependencies = [
|
|||
"native-tls",
|
||||
"percent-encoding",
|
||||
"pin-project-lite 0.2.4",
|
||||
"serde 1.0.123",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"tokio 0.2.25",
|
||||
|
@ -3008,12 +2958,6 @@ version = "0.7.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "0.8.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.123"
|
||||
|
@ -3023,19 +2967,6 @@ dependencies = [
|
|||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde-hjson"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a3a4e0ea8a88553209f6cc6cfe8724ecad22e1acf372793c27d995290fe74f8"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"linked-hash-map 0.3.0",
|
||||
"num-traits 0.1.43",
|
||||
"regex",
|
||||
"serde 0.8.23",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.123"
|
||||
|
@ -3056,16 +2987,7 @@ dependencies = [
|
|||
"indexmap",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde 1.0.123",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_test"
|
||||
version = "0.8.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "110b3dbdf8607ec493c22d5d947753282f3bae73c0f56d322af1e8c78e4c23d5"
|
||||
dependencies = [
|
||||
"serde 0.8.23",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3077,7 +2999,7 @@ dependencies = [
|
|||
"form_urlencoded",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde 1.0.123",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3147,7 +3069,7 @@ checksum = "692ca13de57ce0613a363c8c2f1de925adebc81b04c923ac60c5488bb44abe4b"
|
|||
dependencies = [
|
||||
"chrono",
|
||||
"num-bigint",
|
||||
"num-traits 0.2.14",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3188,12 +3110,6 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "stdweb"
|
||||
version = "0.4.20"
|
||||
|
@ -3216,7 +3132,7 @@ checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde 1.0.123",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"syn",
|
||||
]
|
||||
|
@ -3230,7 +3146,7 @@ dependencies = [
|
|||
"base-x",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde 1.0.123",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"sha1",
|
||||
|
@ -3666,7 +3582,7 @@ dependencies = [
|
|||
"idna",
|
||||
"matches",
|
||||
"percent-encoding",
|
||||
"serde 1.0.123",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3676,7 +3592,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
|
||||
dependencies = [
|
||||
"getrandom 0.2.2",
|
||||
"serde 1.0.123",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3720,7 +3636,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "55c0f7123de74f0dab9b7d00fd614e7b19349cd1e2f5252bbe9b1754b59433be"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"serde 1.0.123",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
|
|
@ -19,7 +19,13 @@ use lemmy_db_views_actor::{
|
|||
community_view::CommunityView,
|
||||
};
|
||||
use lemmy_structs::{blocking, comment::*, community::*, post::*, site::*, user::*, websocket::*};
|
||||
use lemmy_utils::{claims::Claims, settings::Settings, APIError, ConnectionId, LemmyError};
|
||||
use lemmy_utils::{
|
||||
claims::Claims,
|
||||
settings::structs::Settings,
|
||||
APIError,
|
||||
ConnectionId,
|
||||
LemmyError,
|
||||
};
|
||||
use lemmy_websocket::{serialize_websocket_message, LemmyContext, UserOperation};
|
||||
use serde::Deserialize;
|
||||
use std::process::Command;
|
||||
|
|
|
@ -48,7 +48,7 @@ use lemmy_db_views_moderator::{
|
|||
use lemmy_structs::{blocking, site::*, user::Register};
|
||||
use lemmy_utils::{
|
||||
location_info,
|
||||
settings::Settings,
|
||||
settings::structs::Settings,
|
||||
utils::{check_slurs, check_slurs_opt},
|
||||
version,
|
||||
APIError,
|
||||
|
@ -583,7 +583,9 @@ impl Perform for GetSiteConfig {
|
|||
// Only let admins read this
|
||||
is_admin(context.pool(), user.id).await?;
|
||||
|
||||
let config_hjson = Settings::read_config_file()?;
|
||||
// TODO: should make the response field optional?
|
||||
// or include env vars, but then we cant really save it
|
||||
let config_hjson = Settings::read_config_file().unwrap_or("".to_string());
|
||||
|
||||
Ok(GetSiteConfigResponse { config_hjson })
|
||||
}
|
||||
|
|
|
@ -71,7 +71,7 @@ use lemmy_utils::{
|
|||
claims::Claims,
|
||||
email::send_email,
|
||||
location_info,
|
||||
settings::Settings,
|
||||
settings::structs::Settings,
|
||||
utils::{
|
||||
check_slurs,
|
||||
generate_random_string,
|
||||
|
|
|
@ -31,7 +31,7 @@ use lemmy_db_schema::source::{comment::Comment, community::Community, post::Post
|
|||
use lemmy_structs::{blocking, WebFingerResponse};
|
||||
use lemmy_utils::{
|
||||
request::{retry, RecvError},
|
||||
settings::Settings,
|
||||
settings::structs::Settings,
|
||||
utils::{scrape_text_for_mentions, MentionData},
|
||||
LemmyError,
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use lemmy_utils::settings::Settings;
|
||||
use lemmy_utils::settings::structs::Settings;
|
||||
use url::{ParseError, Url};
|
||||
use uuid::Uuid;
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ use background_jobs::{
|
|||
use itertools::Itertools;
|
||||
use lemmy_db_queries::DbPool;
|
||||
use lemmy_db_schema::source::{community::Community, user::User_};
|
||||
use lemmy_utils::{location_info, settings::Settings, LemmyError};
|
||||
use lemmy_utils::{location_info, settings::structs::Settings, LemmyError};
|
||||
use lemmy_websocket::LemmyContext;
|
||||
use log::{debug, warn};
|
||||
use reqwest::Client;
|
||||
|
|
|
@ -35,14 +35,14 @@ use lemmy_db_schema::source::{
|
|||
use lemmy_db_views::{comment_view::CommentView, post_view::PostView};
|
||||
use lemmy_db_views_actor::{community_view::CommunityView, user_view::UserViewSafe};
|
||||
use lemmy_structs::{blocking, site::SearchResponse};
|
||||
use lemmy_utils::{settings::Settings, LemmyError};
|
||||
use lemmy_utils::{settings::structs::Settings, LemmyError};
|
||||
use lemmy_websocket::LemmyContext;
|
||||
use log::debug;
|
||||
use url::Url;
|
||||
|
||||
/// The types of ActivityPub objects that can be fetched directly by searching for their ID.
|
||||
#[serde(untagged)]
|
||||
#[derive(serde::Deserialize, Debug)]
|
||||
#[serde(untagged)]
|
||||
enum SearchAcceptedObjects {
|
||||
Person(Box<PersonExt>),
|
||||
Group(Box<GroupExt>),
|
||||
|
|
|
@ -4,7 +4,7 @@ use http::StatusCode;
|
|||
use lemmy_db_queries::source::activity::Activity_;
|
||||
use lemmy_db_schema::source::activity::Activity;
|
||||
use lemmy_structs::blocking;
|
||||
use lemmy_utils::{settings::Settings, LemmyError};
|
||||
use lemmy_utils::{settings::structs::Settings, LemmyError};
|
||||
use lemmy_websocket::LemmyContext;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ use lemmy_db_queries::{
|
|||
};
|
||||
use lemmy_db_schema::source::{activity::Activity, community::Community, user::User_};
|
||||
use lemmy_structs::blocking;
|
||||
use lemmy_utils::{location_info, settings::Settings, LemmyError};
|
||||
use lemmy_utils::{location_info, settings::structs::Settings, LemmyError};
|
||||
use lemmy_websocket::LemmyContext;
|
||||
use serde::Serialize;
|
||||
use std::fmt::Debug;
|
||||
|
|
|
@ -34,7 +34,7 @@ use lemmy_db_schema::source::{
|
|||
user::User_,
|
||||
};
|
||||
use lemmy_structs::blocking;
|
||||
use lemmy_utils::{location_info, settings::Settings, LemmyError};
|
||||
use lemmy_utils::{location_info, settings::structs::Settings, LemmyError};
|
||||
use lemmy_websocket::LemmyContext;
|
||||
use serde::Serialize;
|
||||
use std::net::IpAddr;
|
||||
|
|
|
@ -15,7 +15,12 @@ use diesel::result::Error::NotFound;
|
|||
use lemmy_db_queries::{ApubObject, Crud, DbPool};
|
||||
use lemmy_db_schema::source::community::Community;
|
||||
use lemmy_structs::blocking;
|
||||
use lemmy_utils::{location_info, settings::Settings, utils::convert_datetime, LemmyError};
|
||||
use lemmy_utils::{
|
||||
location_info,
|
||||
settings::structs::Settings,
|
||||
utils::convert_datetime,
|
||||
LemmyError,
|
||||
};
|
||||
use lemmy_websocket::LemmyContext;
|
||||
use url::Url;
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ use lemmy_db_schema::{
|
|||
use lemmy_structs::blocking;
|
||||
use lemmy_utils::{
|
||||
location_info,
|
||||
settings::Settings,
|
||||
settings::structs::Settings,
|
||||
utils::{check_slurs, check_slurs_opt, convert_datetime},
|
||||
LemmyError,
|
||||
};
|
||||
|
|
|
@ -16,7 +16,7 @@ use crate::{
|
|||
};
|
||||
use actix_web::*;
|
||||
use http_signature_normalization_actix::digest::middleware::VerifyDigest;
|
||||
use lemmy_utils::settings::Settings;
|
||||
use lemmy_utils::settings::structs::Settings;
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
static APUB_JSON_CONTENT_TYPE_LONG: &str =
|
||||
|
|
|
@ -7,7 +7,7 @@ use lemmy_db_schema::{
|
|||
source::user::{UserForm, UserSafeSettings, User_},
|
||||
Url,
|
||||
};
|
||||
use lemmy_utils::settings::Settings;
|
||||
use lemmy_utils::settings::structs::Settings;
|
||||
|
||||
mod safe_type {
|
||||
use crate::ToSafe;
|
||||
|
|
|
@ -15,7 +15,12 @@ use lemmy_db_views::{
|
|||
};
|
||||
use lemmy_db_views_actor::user_mention_view::{UserMentionQueryBuilder, UserMentionView};
|
||||
use lemmy_structs::blocking;
|
||||
use lemmy_utils::{claims::Claims, settings::Settings, utils::markdown_to_html, LemmyError};
|
||||
use lemmy_utils::{
|
||||
claims::Claims,
|
||||
settings::structs::Settings,
|
||||
utils::markdown_to_html,
|
||||
LemmyError,
|
||||
};
|
||||
use lemmy_websocket::LemmyContext;
|
||||
use rss::{
|
||||
extension::dublincore::DublinCoreExtensionBuilder,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use actix::clock::Duration;
|
||||
use actix_web::{body::BodyStream, http::StatusCode, *};
|
||||
use awc::Client;
|
||||
use lemmy_utils::{claims::Claims, rate_limit::RateLimit, settings::Settings};
|
||||
use lemmy_utils::{claims::Claims, rate_limit::RateLimit, settings::structs::Settings};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimit) {
|
||||
|
|
|
@ -2,7 +2,7 @@ use actix_web::{body::Body, error::ErrorBadRequest, *};
|
|||
use anyhow::anyhow;
|
||||
use lemmy_db_views::site_view::SiteView;
|
||||
use lemmy_structs::blocking;
|
||||
use lemmy_utils::{settings::Settings, version, LemmyError};
|
||||
use lemmy_utils::{settings::structs::Settings, version, LemmyError};
|
||||
use lemmy_websocket::LemmyContext;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use url::Url;
|
||||
|
|
|
@ -4,7 +4,7 @@ use lemmy_db_queries::source::{community::Community_, user::User};
|
|||
use lemmy_db_schema::source::{community::Community, user::User_};
|
||||
use lemmy_structs::{blocking, WebFingerLink, WebFingerResponse};
|
||||
use lemmy_utils::{
|
||||
settings::Settings,
|
||||
settings::structs::Settings,
|
||||
LemmyError,
|
||||
WEBFINGER_COMMUNITY_REGEX,
|
||||
WEBFINGER_USER_REGEX,
|
||||
|
|
|
@ -13,7 +13,7 @@ use lemmy_db_schema::source::{
|
|||
user::User_,
|
||||
user_mention::{UserMention, UserMentionForm},
|
||||
};
|
||||
use lemmy_utils::{email::send_email, settings::Settings, utils::MentionData, LemmyError};
|
||||
use lemmy_utils::{email::send_email, settings::structs::Settings, utils::MentionData, LemmyError};
|
||||
use log::error;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use url::Url;
|
||||
|
|
|
@ -9,7 +9,6 @@ path = "src/lib.rs"
|
|||
|
||||
[dependencies]
|
||||
regex = "1.4.3"
|
||||
config = { version = "0.10.1", default-features = false, features = ["hjson"] }
|
||||
chrono = { version = "0.4.19", features = ["serde"] }
|
||||
lettre = "0.10.0-alpha.5"
|
||||
log = "0.4.14"
|
||||
|
@ -34,3 +33,4 @@ futures = "0.3.12"
|
|||
diesel = "1.4.5"
|
||||
http = "0.2.3"
|
||||
jsonwebtoken = "7.2.0"
|
||||
deser-hjson = "0.1.12"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::settings::Settings;
|
||||
use crate::settings::structs::Settings;
|
||||
use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, TokenData, Validation};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::settings::Settings;
|
||||
use crate::settings::structs::Settings;
|
||||
use lettre::{
|
||||
message::{header, Mailbox, MultiPart, SinglePart},
|
||||
transport::smtp::{
|
||||
|
|
|
@ -14,7 +14,7 @@ mod test;
|
|||
pub mod utils;
|
||||
pub mod version;
|
||||
|
||||
use crate::settings::Settings;
|
||||
use crate::settings::structs::Settings;
|
||||
use http::StatusCode;
|
||||
use regex::Regex;
|
||||
use thiserror::Error;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
settings::{RateLimitConfig, Settings},
|
||||
settings::structs::{RateLimitConfig, Settings},
|
||||
utils::get_ip,
|
||||
LemmyError,
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{settings::Settings, LemmyError};
|
||||
use crate::{settings::structs::Settings, LemmyError};
|
||||
use anyhow::anyhow;
|
||||
use log::error;
|
||||
use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
|
||||
|
|
|
@ -1,210 +0,0 @@
|
|||
use crate::location_info;
|
||||
use anyhow::Context;
|
||||
use config::{Config, ConfigError, Environment, File};
|
||||
use serde::Deserialize;
|
||||
use std::{env, fs, io::Error, net::IpAddr, sync::RwLock};
|
||||
|
||||
static CONFIG_FILE_DEFAULTS: &str = "config/defaults.hjson";
|
||||
static CONFIG_FILE: &str = "config/config.hjson";
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct Settings {
|
||||
pub setup: Option<Setup>,
|
||||
pub database: DatabaseConfig,
|
||||
pub hostname: String,
|
||||
pub bind: IpAddr,
|
||||
pub port: u16,
|
||||
pub tls_enabled: bool,
|
||||
pub jwt_secret: String,
|
||||
pub pictrs_url: String,
|
||||
pub iframely_url: String,
|
||||
pub rate_limit: RateLimitConfig,
|
||||
pub email: Option<EmailConfig>,
|
||||
pub federation: FederationConfig,
|
||||
pub captcha: CaptchaConfig,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct Setup {
|
||||
pub admin_username: String,
|
||||
pub admin_password: String,
|
||||
pub admin_email: Option<String>,
|
||||
pub site_name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct RateLimitConfig {
|
||||
pub message: i32,
|
||||
pub message_per_second: i32,
|
||||
pub post: i32,
|
||||
pub post_per_second: i32,
|
||||
pub register: i32,
|
||||
pub register_per_second: i32,
|
||||
pub image: i32,
|
||||
pub image_per_second: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct EmailConfig {
|
||||
pub smtp_server: String,
|
||||
pub smtp_login: Option<String>,
|
||||
pub smtp_password: Option<String>,
|
||||
pub smtp_from_address: String,
|
||||
pub use_tls: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct CaptchaConfig {
|
||||
pub enabled: bool,
|
||||
pub difficulty: String, // easy, medium, or hard
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct DatabaseConfig {
|
||||
pub user: String,
|
||||
pub password: String,
|
||||
pub host: String,
|
||||
pub port: i32,
|
||||
pub database: String,
|
||||
pub pool_size: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct FederationConfig {
|
||||
pub enabled: bool,
|
||||
pub allowed_instances: String,
|
||||
pub blocked_instances: String,
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref SETTINGS: RwLock<Settings> = RwLock::new(match Settings::init() {
|
||||
Ok(c) => c,
|
||||
Err(e) => panic!("{}", e),
|
||||
});
|
||||
}
|
||||
|
||||
impl Settings {
|
||||
/// Reads config from the files and environment.
|
||||
/// First, defaults are loaded from CONFIG_FILE_DEFAULTS, then these values can be overwritten
|
||||
/// from CONFIG_FILE (optional). Finally, values from the environment (with prefix LEMMY) are
|
||||
/// added to the config.
|
||||
///
|
||||
/// Note: The env var `LEMMY_DATABASE_URL` is parsed in
|
||||
/// `lemmy_db_queries/src/lib.rs::get_database_url_from_env()`
|
||||
fn init() -> Result<Self, ConfigError> {
|
||||
let mut s = Config::new();
|
||||
|
||||
s.merge(File::with_name(&Self::get_config_defaults_location()))?;
|
||||
|
||||
s.merge(File::with_name(&Self::get_config_location()).required(false))?;
|
||||
|
||||
// Add in settings from the environment (with a prefix of LEMMY)
|
||||
// Eg.. `LEMMY_DEBUG=1 ./target/app` would set the `debug` key
|
||||
// Note: we need to use double underscore here, because otherwise variables containing
|
||||
// underscore cant be set from environmnet.
|
||||
// https://github.com/mehcode/config-rs/issues/73
|
||||
s.merge(Environment::with_prefix("LEMMY").separator("__"))?;
|
||||
|
||||
s.try_into()
|
||||
}
|
||||
|
||||
/// Returns the config as a struct.
|
||||
pub fn get() -> Self {
|
||||
SETTINGS.read().unwrap().to_owned()
|
||||
}
|
||||
|
||||
pub fn get_database_url(&self) -> String {
|
||||
format!(
|
||||
"postgres://{}:{}@{}:{}/{}",
|
||||
self.database.user,
|
||||
self.database.password,
|
||||
self.database.host,
|
||||
self.database.port,
|
||||
self.database.database
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_config_defaults_location() -> String {
|
||||
env::var("LEMMY_CONFIG_DEFAULTS_LOCATION").unwrap_or_else(|_| CONFIG_FILE_DEFAULTS.to_string())
|
||||
}
|
||||
|
||||
pub fn get_config_location() -> String {
|
||||
env::var("LEMMY_CONFIG_LOCATION").unwrap_or_else(|_| CONFIG_FILE.to_string())
|
||||
}
|
||||
|
||||
pub fn read_config_file() -> Result<String, Error> {
|
||||
fs::read_to_string(Self::get_config_location())
|
||||
}
|
||||
|
||||
pub fn get_allowed_instances(&self) -> Vec<String> {
|
||||
let mut allowed_instances: Vec<String> = self
|
||||
.federation
|
||||
.allowed_instances
|
||||
.split(',')
|
||||
.map(|d| d.trim().to_string())
|
||||
.collect();
|
||||
|
||||
// The defaults.hjson config always returns a [""]
|
||||
allowed_instances.retain(|d| !d.eq(""));
|
||||
|
||||
allowed_instances
|
||||
}
|
||||
|
||||
pub fn get_blocked_instances(&self) -> Vec<String> {
|
||||
let mut blocked_instances: Vec<String> = self
|
||||
.federation
|
||||
.blocked_instances
|
||||
.split(',')
|
||||
.map(|d| d.trim().to_string())
|
||||
.collect();
|
||||
|
||||
// The defaults.hjson config always returns a [""]
|
||||
blocked_instances.retain(|d| !d.eq(""));
|
||||
|
||||
blocked_instances
|
||||
}
|
||||
|
||||
/// Returns either "http" or "https", depending on tls_enabled setting
|
||||
pub fn get_protocol_string(&self) -> &'static str {
|
||||
if self.tls_enabled {
|
||||
"https"
|
||||
} else {
|
||||
"http"
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns something like `http://localhost` or `https://lemmy.ml`,
|
||||
/// with the correct protocol and hostname.
|
||||
pub fn get_protocol_and_hostname(&self) -> String {
|
||||
format!("{}://{}", self.get_protocol_string(), self.hostname)
|
||||
}
|
||||
|
||||
/// When running the federation test setup in `api_tests/` or `docker/federation`, the `hostname`
|
||||
/// variable will be like `lemmy-alpha:8541`. This method removes the port and returns
|
||||
/// `lemmy-alpha` instead. It has no effect in production.
|
||||
pub fn get_hostname_without_port(&self) -> Result<String, anyhow::Error> {
|
||||
Ok(
|
||||
self
|
||||
.hostname
|
||||
.split(':')
|
||||
.collect::<Vec<&str>>()
|
||||
.first()
|
||||
.context(location_info!())?
|
||||
.to_string(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn save_config_file(data: &str) -> Result<String, Error> {
|
||||
fs::write(CONFIG_FILE, data)?;
|
||||
|
||||
// Reload the new settings
|
||||
// From https://stackoverflow.com/questions/29654927/how-do-i-assign-a-string-to-a-mutable-static-variable/47181804#47181804
|
||||
let mut new_settings = SETTINGS.write().unwrap();
|
||||
*new_settings = match Settings::init() {
|
||||
Ok(c) => c,
|
||||
Err(e) => panic!("{}", e),
|
||||
};
|
||||
|
||||
Self::read_config_file()
|
||||
}
|
||||
}
|
70
crates/utils/src/settings/defaults.rs
Normal file
70
crates/utils/src/settings/defaults.rs
Normal file
|
@ -0,0 +1,70 @@
|
|||
use crate::settings::structs::*;
|
||||
use std::net::{IpAddr, Ipv4Addr};
|
||||
|
||||
impl Default for Settings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
database: DatabaseConfig::default(),
|
||||
rate_limit: RateLimitConfig::default(),
|
||||
federation: FederationConfig::default(),
|
||||
captcha: CaptchaConfig::default(),
|
||||
email: None,
|
||||
setup: None,
|
||||
// TODO: not sure how to handle this, its mandatory but not provided by defaults
|
||||
hostname: "hostname_not_set".into(),
|
||||
bind: IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)),
|
||||
port: 8536,
|
||||
tls_enabled: true,
|
||||
jwt_secret: "changeme".into(),
|
||||
pictrs_url: "http://pictrs:8080".into(),
|
||||
iframely_url: "http://iframely".into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for RateLimitConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
message: 180,
|
||||
message_per_second: 60,
|
||||
post: 6,
|
||||
post_per_second: 600,
|
||||
register: 3,
|
||||
register_per_second: 3600,
|
||||
image: 6,
|
||||
image_per_second: 3600,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for CaptchaConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
enabled: true,
|
||||
difficulty: "medium".into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for DatabaseConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
user: "lemmy".into(),
|
||||
password: "password".into(),
|
||||
host: "localhost".into(),
|
||||
port: 5432,
|
||||
database: "lemmy".into(),
|
||||
pool_size: 5,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FederationConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
enabled: false,
|
||||
allowed_instances: "".into(),
|
||||
blocked_instances: "".into(),
|
||||
}
|
||||
}
|
||||
}
|
73
crates/utils/src/settings/environment.rs
Normal file
73
crates/utils/src/settings/environment.rs
Normal file
|
@ -0,0 +1,73 @@
|
|||
use crate::settings::structs_opt::{
|
||||
CaptchaConfigOpt,
|
||||
DatabaseConfigOpt,
|
||||
EmailConfigOpt,
|
||||
FederationConfigOpt,
|
||||
RateLimitConfigOpt,
|
||||
SettingsOpt,
|
||||
SetupOpt,
|
||||
};
|
||||
use std::{env, str::FromStr};
|
||||
|
||||
pub(in crate::settings) fn parse_from_env() -> SettingsOpt {
|
||||
SettingsOpt {
|
||||
hostname: env_var("HOSTNAME"),
|
||||
bind: env_var("BIND"),
|
||||
port: env_var("PORT"),
|
||||
tls_enabled: env_var("TLS_ENABLED"),
|
||||
jwt_secret: env_var("JWT_SECRET"),
|
||||
pictrs_url: env_var("PICTRS_URL"),
|
||||
iframely_url: env_var("IFRAMELY_URL"),
|
||||
rate_limit: Some(RateLimitConfigOpt {
|
||||
message: env_var("RATE_LIMIT__MESSAGE"),
|
||||
message_per_second: env_var("RATE_LIMIT__MESSAGE_PER_SECOND"),
|
||||
post: env_var("RATE_LIMIT__POST"),
|
||||
post_per_second: env_var("RATE_LIMIT__POST_PER_SECOND"),
|
||||
register: env_var("RATE_LIMIT__REGISTER"),
|
||||
register_per_second: env_var("RATE_LIMIT__REGISTER_PER_SECOND"),
|
||||
image: env_var("RATE_LIMIT__IMAGE"),
|
||||
image_per_second: env_var("RATE_LIMIT__IMAGE_PER_SECOND"),
|
||||
}),
|
||||
email: Some(EmailConfigOpt {
|
||||
smtp_server: env_var("EMAIL__SMTP_SERVER"),
|
||||
smtp_login: Some(env_var("EMAIL__SMTP_LOGIN")),
|
||||
smtp_password: Some(env_var("EMAIL__SMTP_PASSWORD")),
|
||||
smtp_from_address: env_var("EMAIL__SMTP_FROM_ADDRESS"),
|
||||
use_tls: env_var("EMAIL__USE_TLS"),
|
||||
}),
|
||||
federation: Some(FederationConfigOpt {
|
||||
enabled: env_var("FEDERATION__ENABLED"),
|
||||
allowed_instances: env_var("FEDERATION__ALLOWED_INSTANCES"),
|
||||
blocked_instances: env_var("FEDERATION__BLOCKED_INSTANCES"),
|
||||
}),
|
||||
captcha: Some(CaptchaConfigOpt {
|
||||
enabled: env_var("CAPTCHA__ENABLED"),
|
||||
difficulty: env_var("CAPTCHA__DIFFICULTY"),
|
||||
}),
|
||||
setup: Some(SetupOpt {
|
||||
admin_username: env_var("SETUP__ADMIN_USERNAME"),
|
||||
admin_password: env_var("SETUP__ADMIN_PASSWORD"),
|
||||
admin_email: Some(env_var("SETUP__ADMIN_EMAIL")),
|
||||
site_name: env_var("SETUP__SITE_NAME"),
|
||||
}),
|
||||
database: Some(DatabaseConfigOpt {
|
||||
user: env_var("DATABASE__USER"),
|
||||
password: env_var("DATABASE__PASSWORD"),
|
||||
host: env_var("DATABASE__HOST"),
|
||||
port: env_var("DATABASE__PORT"),
|
||||
database: env_var("DATABASE__DATABASE"),
|
||||
pool_size: env_var("DATABASE__POOL_SIZE"),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn env_var<T>(name: &str) -> Option<T>
|
||||
where
|
||||
T: FromStr,
|
||||
<T as FromStr>::Err: std::fmt::Debug,
|
||||
{
|
||||
// TODO: probably remove the unwrap
|
||||
env::var(format!("LEMMY_{}", name))
|
||||
.ok()
|
||||
.map(|v| T::from_str(&v).unwrap())
|
||||
}
|
141
crates/utils/src/settings/merge.rs
Normal file
141
crates/utils/src/settings/merge.rs
Normal file
|
@ -0,0 +1,141 @@
|
|||
use crate::settings::{structs::*, structs_opt::*};
|
||||
|
||||
pub(in crate::settings) trait Merge<T> {
|
||||
fn merge(self, opt: T) -> Self;
|
||||
}
|
||||
|
||||
impl Merge<SettingsOpt> for Settings {
|
||||
fn merge(self, opt: SettingsOpt) -> Self {
|
||||
Settings {
|
||||
setup: merge_structs(self.setup, opt.setup),
|
||||
database: merge_structs(self.database, opt.database),
|
||||
hostname: opt.hostname.unwrap_or(self.hostname),
|
||||
bind: opt.bind.unwrap_or(self.bind),
|
||||
port: opt.port.unwrap_or(self.port),
|
||||
tls_enabled: opt.tls_enabled.unwrap_or(self.tls_enabled),
|
||||
jwt_secret: opt.jwt_secret.unwrap_or(self.jwt_secret),
|
||||
pictrs_url: opt.pictrs_url.unwrap_or(self.pictrs_url),
|
||||
iframely_url: opt.iframely_url.unwrap_or(self.iframely_url),
|
||||
rate_limit: merge_structs(self.rate_limit, opt.rate_limit),
|
||||
email: merge_structs(self.email, opt.email),
|
||||
federation: merge_structs(self.federation, opt.federation),
|
||||
captcha: merge_structs(self.captcha, opt.captcha),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Merge<RateLimitConfigOpt> for RateLimitConfig {
|
||||
fn merge(self, opt: RateLimitConfigOpt) -> Self {
|
||||
RateLimitConfig {
|
||||
message: opt.message.unwrap_or(self.message),
|
||||
message_per_second: opt.message_per_second.unwrap_or(self.message_per_second),
|
||||
post: opt.post.unwrap_or(self.post),
|
||||
post_per_second: opt.post_per_second.unwrap_or(self.post_per_second),
|
||||
register: opt.register.unwrap_or(self.register),
|
||||
register_per_second: opt.register_per_second.unwrap_or(self.register_per_second),
|
||||
image: opt.image.unwrap_or(self.image),
|
||||
image_per_second: opt.image_per_second.unwrap_or(self.image_per_second),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Merge<SetupOpt> for Option<Setup> {
|
||||
fn merge(self, opt: SetupOpt) -> Self {
|
||||
if let Some(setup) = self {
|
||||
Some(Setup {
|
||||
admin_username: opt.admin_username.unwrap_or(setup.admin_username),
|
||||
admin_password: opt.admin_password.unwrap_or(setup.admin_password),
|
||||
admin_email: opt.admin_email.unwrap_or(setup.admin_email),
|
||||
site_name: opt.site_name.unwrap_or(setup.site_name),
|
||||
})
|
||||
} else if let (Some(admin_username), Some(admin_password), Some(site_name)) =
|
||||
(opt.admin_username, opt.admin_password, opt.site_name)
|
||||
{
|
||||
Some(Setup {
|
||||
admin_username,
|
||||
admin_password,
|
||||
admin_email: opt.admin_email.flatten(),
|
||||
site_name,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Merge<EmailConfigOpt> for Option<EmailConfig> {
|
||||
fn merge(self, opt: EmailConfigOpt) -> Self {
|
||||
if let Some(email_config) = self {
|
||||
Some(EmailConfig {
|
||||
smtp_server: opt.smtp_server.unwrap_or(email_config.smtp_server),
|
||||
smtp_login: opt.smtp_login.unwrap_or(email_config.smtp_login),
|
||||
smtp_password: opt.smtp_password.unwrap_or(email_config.smtp_password),
|
||||
smtp_from_address: opt
|
||||
.smtp_from_address
|
||||
.unwrap_or(email_config.smtp_from_address),
|
||||
use_tls: opt.use_tls.unwrap_or(email_config.use_tls),
|
||||
})
|
||||
} else if let (Some(smtp_server), Some(smtp_from_address), Some(use_tls)) =
|
||||
(opt.smtp_server, opt.smtp_from_address, opt.use_tls)
|
||||
{
|
||||
Some(EmailConfig {
|
||||
smtp_server,
|
||||
smtp_login: opt
|
||||
.smtp_login
|
||||
.or(self.clone().map(|s| s.smtp_login))
|
||||
.flatten(),
|
||||
smtp_password: opt
|
||||
.smtp_password
|
||||
.or(self.map(|s| s.smtp_password))
|
||||
.flatten(),
|
||||
smtp_from_address,
|
||||
use_tls,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Merge<DatabaseConfigOpt> for DatabaseConfig {
|
||||
fn merge(self, opt: DatabaseConfigOpt) -> Self {
|
||||
DatabaseConfig {
|
||||
user: opt.user.unwrap_or(self.user),
|
||||
password: opt.password.unwrap_or(self.password),
|
||||
host: opt.host.unwrap_or(self.host),
|
||||
port: opt.port.unwrap_or(self.port),
|
||||
database: opt.database.unwrap_or(self.database),
|
||||
pool_size: opt.pool_size.unwrap_or(self.pool_size),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Merge<FederationConfigOpt> for FederationConfig {
|
||||
fn merge(self, opt: FederationConfigOpt) -> Self {
|
||||
FederationConfig {
|
||||
enabled: opt.enabled.unwrap_or(self.enabled),
|
||||
allowed_instances: opt.allowed_instances.unwrap_or(self.allowed_instances),
|
||||
blocked_instances: opt.blocked_instances.unwrap_or(self.blocked_instances),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Merge<CaptchaConfigOpt> for CaptchaConfig {
|
||||
fn merge(self, opt: CaptchaConfigOpt) -> Self {
|
||||
CaptchaConfig {
|
||||
enabled: opt.enabled.unwrap_or(self.enabled),
|
||||
difficulty: opt.difficulty.unwrap_or(self.difficulty),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn merge_structs<T, U>(lhs: T, rhs: Option<U>) -> T
|
||||
where
|
||||
T: Merge<U> + std::clone::Clone,
|
||||
{
|
||||
if let Some(x) = rhs {
|
||||
lhs.merge(x)
|
||||
} else {
|
||||
lhs.to_owned()
|
||||
}
|
||||
}
|
151
crates/utils/src/settings/mod.rs
Normal file
151
crates/utils/src/settings/mod.rs
Normal file
|
@ -0,0 +1,151 @@
|
|||
use crate::{
|
||||
location_info,
|
||||
settings::{
|
||||
environment::parse_from_env,
|
||||
merge::Merge,
|
||||
structs::Settings,
|
||||
structs_opt::SettingsOpt,
|
||||
},
|
||||
LemmyError,
|
||||
};
|
||||
use anyhow::{anyhow, Context};
|
||||
use deser_hjson::from_str;
|
||||
use std::{env, fs, sync::RwLock};
|
||||
|
||||
pub mod defaults;
|
||||
mod environment;
|
||||
mod merge;
|
||||
pub mod structs;
|
||||
mod structs_opt;
|
||||
|
||||
static CONFIG_FILE: &str = "config/config.hjson";
|
||||
|
||||
lazy_static! {
|
||||
static ref SETTINGS: RwLock<Settings> = RwLock::new(match Settings::init() {
|
||||
Ok(c) => c,
|
||||
Err(e) => panic!("{}", e),
|
||||
});
|
||||
}
|
||||
|
||||
impl Settings {
|
||||
/// Reads config from the files and environment.
|
||||
/// First, defaults are loaded from CONFIG_FILE_DEFAULTS, then these values can be overwritten
|
||||
/// from CONFIG_FILE (optional). Finally, values from the environment (with prefix LEMMY) are
|
||||
/// added to the config.
|
||||
///
|
||||
/// Note: The env var `LEMMY_DATABASE_URL` is parsed in
|
||||
/// `lemmy_db_queries/src/lib.rs::get_database_url_from_env()`
|
||||
fn init() -> Result<Self, LemmyError> {
|
||||
let mut config = Settings::default();
|
||||
|
||||
// Read the config file
|
||||
if let Some(config_file) = &Self::read_config_file() {
|
||||
config = config.merge(from_str::<SettingsOpt>(config_file)?);
|
||||
}
|
||||
|
||||
// Read env vars
|
||||
config = config.merge(parse_from_env());
|
||||
|
||||
if config.hostname == Settings::default().hostname {
|
||||
return Err(anyhow!("Hostname variable is not set!").into());
|
||||
}
|
||||
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
/// Returns the config as a struct.
|
||||
pub fn get() -> Self {
|
||||
SETTINGS.read().unwrap().to_owned()
|
||||
}
|
||||
|
||||
pub fn get_database_url(&self) -> String {
|
||||
let conf = self.database.to_owned();
|
||||
format!(
|
||||
"postgres://{}:{}@{}:{}/{}",
|
||||
conf.user, conf.password, conf.host, conf.port, conf.database,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_config_location() -> String {
|
||||
env::var("LEMMY_CONFIG_LOCATION").unwrap_or_else(|_| CONFIG_FILE.to_string())
|
||||
}
|
||||
|
||||
pub fn read_config_file() -> Option<String> {
|
||||
fs::read_to_string(Self::get_config_location()).ok()
|
||||
}
|
||||
|
||||
pub fn get_allowed_instances(&self) -> Vec<String> {
|
||||
let mut allowed_instances: Vec<String> = self
|
||||
.federation
|
||||
.to_owned()
|
||||
.allowed_instances
|
||||
.split(',')
|
||||
.map(|d| d.trim().to_string())
|
||||
.collect();
|
||||
|
||||
allowed_instances.retain(|d| !d.eq(""));
|
||||
allowed_instances
|
||||
}
|
||||
|
||||
pub fn get_blocked_instances(&self) -> Vec<String> {
|
||||
let mut blocked_instances: Vec<String> = self
|
||||
.federation
|
||||
.to_owned()
|
||||
.blocked_instances
|
||||
.split(',')
|
||||
.map(|d| d.trim().to_string())
|
||||
.collect();
|
||||
|
||||
blocked_instances.retain(|d| !d.eq(""));
|
||||
blocked_instances
|
||||
}
|
||||
|
||||
/// Returns either "http" or "https", depending on tls_enabled setting
|
||||
pub fn get_protocol_string(&self) -> &'static str {
|
||||
if self.tls_enabled {
|
||||
"https"
|
||||
} else {
|
||||
"http"
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns something like `http://localhost` or `https://lemmy.ml`,
|
||||
/// with the correct protocol and hostname.
|
||||
pub fn get_protocol_and_hostname(&self) -> String {
|
||||
format!(
|
||||
"{}://{}",
|
||||
self.get_protocol_string(),
|
||||
self.hostname.to_owned()
|
||||
)
|
||||
}
|
||||
|
||||
/// When running the federation test setup in `api_tests/` or `docker/federation`, the `hostname`
|
||||
/// variable will be like `lemmy-alpha:8541`. This method removes the port and returns
|
||||
/// `lemmy-alpha` instead. It has no effect in production.
|
||||
pub fn get_hostname_without_port(&self) -> Result<String, anyhow::Error> {
|
||||
Ok(
|
||||
self
|
||||
.hostname
|
||||
.to_owned()
|
||||
.split(':')
|
||||
.collect::<Vec<&str>>()
|
||||
.first()
|
||||
.context(location_info!())?
|
||||
.to_string(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn save_config_file(data: &str) -> Result<String, LemmyError> {
|
||||
fs::write(CONFIG_FILE, data)?;
|
||||
|
||||
// Reload the new settings
|
||||
// From https://stackoverflow.com/questions/29654927/how-do-i-assign-a-string-to-a-mutable-static-variable/47181804#47181804
|
||||
let mut new_settings = SETTINGS.write().unwrap();
|
||||
*new_settings = match Settings::init() {
|
||||
Ok(c) => c,
|
||||
Err(e) => panic!("{}", e),
|
||||
};
|
||||
|
||||
Self::read_config_file().ok_or(anyhow!("Failed to read config").into())
|
||||
}
|
||||
}
|
72
crates/utils/src/settings/structs.rs
Normal file
72
crates/utils/src/settings/structs.rs
Normal file
|
@ -0,0 +1,72 @@
|
|||
use serde::Deserialize;
|
||||
use std::net::IpAddr;
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct Settings {
|
||||
pub setup: Option<Setup>,
|
||||
pub database: DatabaseConfig,
|
||||
pub hostname: String,
|
||||
pub bind: IpAddr,
|
||||
pub port: u16,
|
||||
pub tls_enabled: bool,
|
||||
pub jwt_secret: String,
|
||||
pub pictrs_url: String,
|
||||
pub iframely_url: String,
|
||||
pub rate_limit: RateLimitConfig,
|
||||
pub email: Option<EmailConfig>,
|
||||
pub federation: FederationConfig,
|
||||
pub captcha: CaptchaConfig,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct Setup {
|
||||
pub admin_username: String,
|
||||
pub admin_password: String,
|
||||
pub admin_email: Option<String>,
|
||||
pub site_name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct RateLimitConfig {
|
||||
pub message: i32,
|
||||
pub message_per_second: i32,
|
||||
pub post: i32,
|
||||
pub post_per_second: i32,
|
||||
pub register: i32,
|
||||
pub register_per_second: i32,
|
||||
pub image: i32,
|
||||
pub image_per_second: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct EmailConfig {
|
||||
pub smtp_server: String,
|
||||
pub smtp_login: Option<String>,
|
||||
pub smtp_password: Option<String>,
|
||||
pub smtp_from_address: String,
|
||||
pub use_tls: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct CaptchaConfig {
|
||||
pub enabled: bool,
|
||||
// TODO: use enum for this
|
||||
pub difficulty: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct DatabaseConfig {
|
||||
pub user: String,
|
||||
pub password: String,
|
||||
pub host: String,
|
||||
pub port: i32,
|
||||
pub database: String,
|
||||
pub pool_size: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct FederationConfig {
|
||||
pub enabled: bool,
|
||||
pub allowed_instances: String,
|
||||
pub blocked_instances: String,
|
||||
}
|
71
crates/utils/src/settings/structs_opt.rs
Normal file
71
crates/utils/src/settings/structs_opt.rs
Normal file
|
@ -0,0 +1,71 @@
|
|||
use serde::Deserialize;
|
||||
use std::net::IpAddr;
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct SettingsOpt {
|
||||
pub setup: Option<SetupOpt>,
|
||||
pub database: Option<DatabaseConfigOpt>,
|
||||
pub hostname: Option<String>,
|
||||
pub bind: Option<IpAddr>,
|
||||
pub port: Option<u16>,
|
||||
pub tls_enabled: Option<bool>,
|
||||
pub jwt_secret: Option<String>,
|
||||
pub pictrs_url: Option<String>,
|
||||
pub iframely_url: Option<String>,
|
||||
pub rate_limit: Option<RateLimitConfigOpt>,
|
||||
pub email: Option<EmailConfigOpt>,
|
||||
pub federation: Option<FederationConfigOpt>,
|
||||
pub captcha: Option<CaptchaConfigOpt>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct SetupOpt {
|
||||
pub admin_username: Option<String>,
|
||||
pub admin_password: Option<String>,
|
||||
pub admin_email: Option<Option<String>>,
|
||||
pub site_name: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct RateLimitConfigOpt {
|
||||
pub message: Option<i32>,
|
||||
pub message_per_second: Option<i32>,
|
||||
pub post: Option<i32>,
|
||||
pub post_per_second: Option<i32>,
|
||||
pub register: Option<i32>,
|
||||
pub register_per_second: Option<i32>,
|
||||
pub image: Option<i32>,
|
||||
pub image_per_second: Option<i32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct EmailConfigOpt {
|
||||
pub smtp_server: Option<String>,
|
||||
pub smtp_login: Option<Option<String>>,
|
||||
pub smtp_password: Option<Option<String>>,
|
||||
pub smtp_from_address: Option<String>,
|
||||
pub use_tls: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct CaptchaConfigOpt {
|
||||
pub enabled: Option<bool>,
|
||||
pub difficulty: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct DatabaseConfigOpt {
|
||||
pub user: Option<String>,
|
||||
pub password: Option<String>,
|
||||
pub host: Option<String>,
|
||||
pub port: Option<i32>,
|
||||
pub database: Option<String>,
|
||||
pub pool_size: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
pub struct FederationConfigOpt {
|
||||
pub enabled: Option<bool>,
|
||||
pub allowed_instances: Option<String>,
|
||||
pub blocked_instances: Option<String>,
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{settings::Settings, APIError};
|
||||
use crate::{settings::structs::Settings, APIError};
|
||||
use actix_web::dev::ConnectionInfo;
|
||||
use chrono::{DateTime, FixedOffset, NaiveDateTime};
|
||||
use itertools::Itertools;
|
||||
|
|
|
@ -28,7 +28,7 @@ services:
|
|||
lemmy-ui:
|
||||
image: dessalines/lemmy-ui:0.9.7
|
||||
ports:
|
||||
- "1235:1234"
|
||||
- "127.0.0.1:1235:1234"
|
||||
restart: always
|
||||
environment:
|
||||
- LEMMY_INTERNAL_HOST=lemmy:8536
|
||||
|
|
|
@ -24,7 +24,7 @@ use lemmy_db_schema::{
|
|||
user::{UserForm, User_},
|
||||
},
|
||||
};
|
||||
use lemmy_utils::{apub::generate_actor_keypair, settings::Settings, LemmyError};
|
||||
use lemmy_utils::{apub::generate_actor_keypair, settings::structs::Settings, LemmyError};
|
||||
use log::info;
|
||||
|
||||
pub fn run_advanced_migrations(conn: &PgConnection) -> Result<(), LemmyError> {
|
||||
|
|
|
@ -15,7 +15,7 @@ use lemmy_server::{code_migrations::run_advanced_migrations, scheduled_tasks};
|
|||
use lemmy_structs::blocking;
|
||||
use lemmy_utils::{
|
||||
rate_limit::{rate_limiter::RateLimiter, RateLimit},
|
||||
settings::Settings,
|
||||
settings::structs::Settings,
|
||||
LemmyError,
|
||||
};
|
||||
use lemmy_websocket::{chat_server::ChatServer, LemmyContext};
|
||||
|
|
|
@ -39,7 +39,7 @@ use lemmy_server::code_migrations::run_advanced_migrations;
|
|||
use lemmy_utils::{
|
||||
apub::generate_actor_keypair,
|
||||
rate_limit::{rate_limiter::RateLimiter, RateLimit},
|
||||
settings::Settings,
|
||||
settings::structs::Settings,
|
||||
};
|
||||
use lemmy_websocket::{chat_server::ChatServer, LemmyContext};
|
||||
use reqwest::Client;
|
||||
|
|
Loading…
Reference in a new issue