Browse Source

more docs

rate-limiting
Matthias Ahouansou 1 week ago
parent
commit
5b8289c67f
No known key found for this signature in database
  1. 28
      Cargo.lock
  2. 12
      Cargo.toml
  3. 40
      conduit-config/src/rate_limiting.rs
  4. 80
      conduit-macros/src/doc_generators.rs
  5. 2
      xtask/Cargo.toml
  6. 29
      xtask/src/generate_docs.rs

28
Cargo.lock generated

@ -507,6 +507,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071"
dependencies = [
"clap_builder",
"clap_derive",
]
[[package]]
@ -518,7 +519,18 @@ dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_derive"
version = "4.5.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7"
dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
"syn",
]
[[package]]
@ -853,7 +865,7 @@ version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a"
dependencies = [
"heck",
"heck 0.4.1",
"proc-macro2",
"quote",
"syn",
@ -1179,6 +1191,12 @@ version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "hermit-abi"
version = "0.3.9"
@ -3290,12 +3308,6 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "subslice"
version = "0.2.3"

12
Cargo.toml

@ -21,7 +21,17 @@ rust-version = "1.88.0"
[workspace.dependencies]
bytesize = "2"
clap = "4"
# Removing the `color` feature as it is not used in the admin room commands.
# `string` feature is added for some reason, not sure.
# Added `derive` feature to allow derive macros
clap = { version = "4", default-features = false, features = [
"derive",
"error-context",
"help",
"std",
"string",
"usage",
] }
conduit-config.path = "conduit-config"
conduit-macros.path = "conduit-macros"
reqwest = { version = "0.12", default-features = false }

40
conduit-config/src/rate_limiting.rs

@ -192,8 +192,12 @@ pub enum Restriction {
#[cfg(feature = "doc-generators")]
pub trait DocumentRestrictions: Sized {
fn variant_doc_comments() -> Vec<(Self, String)>;
fn container_doc_comment() -> String;
}
/// Applies for endpoints on the client-server API, which are used by clients, appservices, and
/// bots. Appservices can bypass rate-limiting though if `rate_limited` is set to `false` in their
/// registration file.
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(
feature = "doc-generators",
@ -201,26 +205,48 @@ pub trait DocumentRestrictions: Sized {
)]
#[serde(rename_all = "snake_case")]
pub enum ClientRestriction {
/// Endpoint for registering a new user account. May be called multiples times for a single
/// For registering a new user account. May be called multiples times for a single
/// registration if there are extra steps, e.g. providing a registration token.
Registration,
/// Endpoint used for logging into an existing account.
/// For logging into an existing account.
Login,
/// For checking whether a given registration token would allow the user to register an
/// account.
RegistrationTokenValidity,
/// For sending an event to a room.
///
/// Note that this is not used for state events, but for users who are unprivliged in a room,
/// the only state event they'll be able to send are ones to update their room profile.
SendEvent,
/// For joining a room.
Join,
/// For inviting a user to a room.
Invite,
/// For knocking on a room.
Knock,
/// For reporting a user, event, or room.
SendReport,
/// For adding an alias to a room.
CreateAlias,
/// For downloading a media file.
///
/// For rate-limiting based on the size of files downloaded, see the media rate-limiting
/// configuration.
MediaDownload,
/// For uploading a media file.
///
/// For rate-limiting based on the size of files uploaded, see the media rate-limiting
/// configuration.
MediaCreate,
}
/// Applies for endpoints on the federation API of this server, hence restricting how
/// many times other servers can use these endpoints on this server in a given timeframe.
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(
feature = "doc-generators",
@ -228,13 +254,19 @@ pub enum ClientRestriction {
)]
#[serde(rename_all = "snake_case")]
pub enum FederationRestriction {
/// For joining a room.
Join,
/// For knocking on a room.
Knock,
/// For inviting a local user to a room.
Invite,
// Transactions should be handled by a completely dedicated rate-limiter
Transaction,
/* /// For sending transactions of PDU/EDUs.
///
///
Transaction, */
/// For downloading media.
MediaDownload,
}

80
conduit-macros/src/doc_generators.rs

@ -1,15 +1,16 @@
use proc_macro2::TokenStream as TokenStream2;
use quote::{ToTokens, quote};
use syn::{Expr, Ident, ItemEnum, Lit, MetaNameValue, Variant, parse::Parse};
use syn::{Attribute, Expr, Ident, ItemEnum, Lit, MetaNameValue, Variant, parse::Parse};
pub(super) struct Restrictions {
ident: Ident,
doc_comment: String,
variants: Vec<Restriction>,
}
struct Restriction {
ident: Ident,
doc_comments: Vec<String>,
doc_comment: String,
}
impl Parse for Restrictions {
@ -17,50 +18,65 @@ impl Parse for Restrictions {
let ItemEnum {
ident,
variants,
// Might be useful later.
attrs: _,
attrs,
..
} = ItemEnum::parse(input)?;
let variants = variants
.into_iter()
.map(|Variant { attrs, ident, .. }| {
let doc_comments = attrs
.into_iter()
.filter_map(|attr| {
if let syn::Meta::NameValue(MetaNameValue { path, value, .. }) = attr.meta
&& path.is_ident("doc")
&& let Expr::Lit(lit) = value
&& let Lit::Str(string) = lit.lit
{
Some(string.value().trim().to_owned() + "\n")
} else {
None
}
})
.collect();
let doc_comment = attrs_to_doc_comment(attrs);
Ok(Restriction {
ident,
doc_comments,
})
Ok(Restriction { ident, doc_comment })
})
.collect::<syn::Result<Vec<_>>>()?;
Ok(Self { ident, variants })
let doc_comment = attrs_to_doc_comment(attrs);
Ok(Self {
ident,
variants,
doc_comment,
})
}
}
fn attrs_to_doc_comment(attrs: Vec<Attribute>) -> String {
attrs
.into_iter()
.filter_map(|attr| {
if let syn::Meta::NameValue(MetaNameValue { path, value, .. }) = attr.meta
&& path.is_ident("doc")
&& let Expr::Lit(lit) = value
&& let Lit::Str(string) = lit.lit
{
Some(string.value().trim().to_owned())
} else {
None
}
})
.collect::<Vec<_>>()
.join("\n")
}
/// Produces the following function on said restriction:
/// - `variant_doc_comments`, returning each variant and it's doc comment.
impl ToTokens for Restrictions {
fn to_tokens(&self, tokens: &mut TokenStream2) {
let Self { ident, variants } = self;
let Self {
ident,
variants,
doc_comment, /* , doc_comments */
} = self;
let output = quote! {
impl DocumentRestrictions for #ident {
fn variant_doc_comments() -> Vec<(Self, String)> {
vec![#((#variants)),*]
}
fn container_doc_comment() -> String {
#doc_comment.to_owned()
}
}
};
@ -70,19 +86,9 @@ impl ToTokens for Restrictions {
impl ToTokens for Restriction {
fn to_tokens(&self, tokens: &mut TokenStream2) {
let Self {
ident,
doc_comments,
} = self;
let doc_comment = doc_comments
.iter()
.map(|attr| attr.trim())
.collect::<Vec<_>>()
.join("\n");
let Self { ident, doc_comment } = self;
// `String::from` because despite `doc_comment` being a `String`, the macro still ends up
// with a `&str` somehow.
tokens.extend(quote!( (Self::#ident, String::from(#doc_comment) ) ))
// `clone` because `to_tokens` takes a reference to self.
tokens.extend(quote!( (Self::#ident, #doc_comment.to_owned() ) ))
}
}

2
xtask/Cargo.toml

@ -8,7 +8,7 @@ version = "0.11.0-alpha"
[dependencies]
# Processing commands
clap.workspace = true
clap = { workspace = true, features = ["color"] }
# Documentation generation for the configuration
conduit-config = { workspace = true, features = ["doc-generators"] }
serde.workspace = true

29
xtask/src/generate_docs.rs

@ -10,24 +10,25 @@ use conduit_config::rate_limiting::{
pub fn run() {
let mut markdown_text = String::new();
markdown_text.push_str("<!-- ANCHOR: client-restrictions -->\n");
for (restriction, comment) in ClientRestriction::variant_doc_comments() {
markdown_text.push_str(&format!(
"##### {}\n{}\n",
restriction_to_string(&restriction),
comment
));
macro_rules! push_restrictions {
($restriction_kind:ident) => {
markdown_text.push_str(&format!("{}\n", $restriction_kind::container_doc_comment()));
for (restriction, comment) in $restriction_kind::variant_doc_comments() {
markdown_text.push_str(&format!(
"##### `{}`\n{}\n",
restriction_to_string(&restriction),
comment
));
}
};
}
markdown_text.push_str("<!-- ANCHOR: client-restrictions -->\n");
push_restrictions!(ClientRestriction);
markdown_text.push_str("<!-- ANCHOR_END: client-restrictions -->\n");
markdown_text.push_str("<!-- ANCHOR: federation-restrictions -->\n");
for (restriction, comment) in FederationRestriction::variant_doc_comments() {
markdown_text.push_str(&format!(
"##### `{}`\n{}\n",
restriction_to_string(&restriction),
comment
));
}
push_restrictions!(FederationRestriction);
markdown_text.push_str("<!-- ANCHOR_END: federation-restrictions -->\n");
create_dir_all("./target/docs").unwrap();

Loading…
Cancel
Save