Skip to content

Commit 2613f12

Browse files
committed
Add better modes to control how statistics are returned (#635)
1 parent 6d3d703 commit 2613f12

File tree

5 files changed

+79
-55
lines changed

5 files changed

+79
-55
lines changed

config.example.toml

+9-8
Original file line numberDiff line numberDiff line change
@@ -103,19 +103,20 @@ description = "https://www.youtube.com/watch?v=6lnnPnr_0SU"
103103
# This is the maximum length of posts that can be posted on your instance
104104
# On Mastodon it's 500, on most other implementations it's freely configurable
105105
character-limit = 5000
106-
# Randomize the statistics of your server
107-
#
108-
# Kitsune will expose certain statistics about your server by default.
109-
# Set this value to `true` to serve randomized statistics instead.
110-
#
111-
# Why you'd want this can have many reasons, one of them being privacy reasons.
112-
# Perhaps you don't want to expose accurate information about your server publicly.
113-
randomize-statistics = false
114106
# Registrations open
115107
#
116108
# This signals to clients whether your registrations are currently open or not.
117109
# It will also hard-enforce the closed signups inside of Kitsune, returning an error when a signup is attempted.
118110
registrations-open = true
111+
# Statistics settings of your server
112+
#
113+
# Set to `regular` to just return actual statistics.
114+
# Set to `zero` to return all zeroes.
115+
# Set this value to `random` to serve randomized statistics instead.
116+
#
117+
# Why you'd want this can have many reasons, one of them being privacy reasons.
118+
# Perhaps you don't want to expose accurate information about your server publicly.
119+
statistics-mode = "regular"
119120

120121
# Federation filters
121122
#

crates/kitsune-config/src/instance.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,15 @@ pub enum FederationFilterConfiguration {
88
Deny { domains: Vec<SmolStr> },
99
}
1010

11+
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
12+
#[serde(rename_all = "kebab-case")]
13+
pub enum StatisticsMode {
14+
#[serde(alias = "dansup")]
15+
Random,
16+
Regular,
17+
Zero,
18+
}
19+
1120
#[derive(Clone, Debug, Deserialize, Serialize)]
1221
#[serde(rename_all = "kebab-case")]
1322
pub struct Configuration {
@@ -17,6 +26,6 @@ pub struct Configuration {
1726
pub webfinger_domain: Option<SmolStr>,
1827
pub character_limit: usize,
1928
pub federation_filter: FederationFilterConfiguration,
20-
pub randomize_statistics: bool,
2129
pub registrations_open: bool,
30+
pub statistics_mode: StatisticsMode,
2231
}
+49-39
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use diesel::{ExpressionMethods, QueryDsl};
22
use diesel_async::RunQueryDsl;
3+
use kitsune_config::instance::StatisticsMode;
34
use kitsune_db::{
45
schema::{accounts, posts, users},
56
with_connection, PgPool,
@@ -8,7 +9,7 @@ use kitsune_derive::kitsune_service;
89
use kitsune_error::{Error, Result};
910
use rand::seq::IteratorRandom;
1011
use smol_str::SmolStr;
11-
use std::ops::RangeInclusive;
12+
use std::{future::Future, ops::RangeInclusive};
1213

1314
const STATISTICS_RANGE: RangeInclusive<u64> = 24..=1312_1312;
1415

@@ -25,8 +26,20 @@ pub struct InstanceService {
2526
#[builder(setter(into))]
2627
description: SmolStr,
2728
character_limit: usize,
28-
randomize_statistics: bool,
2929
registrations_open: bool,
30+
statistics_mode: StatisticsMode,
31+
}
32+
33+
#[inline]
34+
async fn with_statistics_mode<F, E>(mode: StatisticsMode, fut: F) -> Result<u64, E>
35+
where
36+
F: Future<Output = Result<u64, E>>,
37+
{
38+
match mode {
39+
StatisticsMode::Random => Ok(random_statistic()),
40+
StatisticsMode::Regular => fut.await,
41+
StatisticsMode::Zero => Ok(0),
42+
}
3043
}
3144

3245
impl InstanceService {
@@ -46,37 +59,35 @@ impl InstanceService {
4659
}
4760

4861
pub async fn known_instances(&self) -> Result<u64> {
49-
if self.randomize_statistics {
50-
return Ok(random_statistic());
51-
}
52-
53-
with_connection!(self.db_pool, |db_conn| {
54-
accounts::table
55-
.filter(accounts::local.eq(false))
56-
.select(accounts::domain)
57-
.distinct()
58-
.count()
59-
.get_result::<i64>(db_conn)
60-
.await
61-
.map(|count| count as u64)
62+
with_statistics_mode(self.statistics_mode, async {
63+
with_connection!(self.db_pool, |db_conn| {
64+
accounts::table
65+
.filter(accounts::local.eq(false))
66+
.select(accounts::domain)
67+
.distinct()
68+
.count()
69+
.get_result::<i64>(db_conn)
70+
.await
71+
.map(|count| count as u64)
72+
})
73+
.map_err(Error::from)
6274
})
63-
.map_err(Error::from)
75+
.await
6476
}
6577

6678
pub async fn local_post_count(&self) -> Result<u64> {
67-
if self.randomize_statistics {
68-
return Ok(random_statistic());
69-
}
70-
71-
with_connection!(self.db_pool, |db_conn| {
72-
posts::table
73-
.filter(posts::is_local.eq(true))
74-
.count()
75-
.get_result::<i64>(db_conn)
76-
.await
77-
.map(|count| count as u64)
79+
with_statistics_mode(self.statistics_mode, async {
80+
with_connection!(self.db_pool, |db_conn| {
81+
posts::table
82+
.filter(posts::is_local.eq(true))
83+
.count()
84+
.get_result::<i64>(db_conn)
85+
.await
86+
.map(|count| count as u64)
87+
})
88+
.map_err(Error::from)
7889
})
79-
.map_err(Error::from)
90+
.await
8091
}
8192

8293
#[must_use]
@@ -85,17 +96,16 @@ impl InstanceService {
8596
}
8697

8798
pub async fn user_count(&self) -> Result<u64> {
88-
if self.randomize_statistics {
89-
return Ok(random_statistic());
90-
}
91-
92-
with_connection!(self.db_pool, |db_conn| {
93-
users::table
94-
.count()
95-
.get_result::<i64>(db_conn)
96-
.await
97-
.map(|count| count as u64)
99+
with_statistics_mode(self.statistics_mode, async {
100+
with_connection!(self.db_pool, |db_conn| {
101+
users::table
102+
.count()
103+
.get_result::<i64>(db_conn)
104+
.await
105+
.map(|count| count as u64)
106+
})
107+
.map_err(Error::from)
98108
})
99-
.map_err(Error::from)
109+
.await
100110
}
101111
}

kitsune/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,8 @@ pub async fn initialise_state(
126126
.db_pool(db_pool.clone())
127127
.description(config.instance.description.clone())
128128
.name(config.instance.name.clone())
129-
.randomize_statistics(config.instance.randomize_statistics)
130129
.registrations_open(config.instance.registrations_open)
130+
.statistics_mode(config.instance.statistics_mode)
131131
.build();
132132

133133
let mailing_service = MailingService::builder()

website/src/content/docs/configuration/instance.mdx

+10-6
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,19 @@ Similar to `name`, this setting adjusts the description on the landing page and
5656

5757
This setting sets the character limit specific to your instance.
5858

59-
## `randomize-statistics`
59+
## `statistics-mode`
6060

61-
Randomize the statistics of your server
61+
Control how statistics about your server are reported.
6262

63-
Kitsune will expose certain statistics about your server by default.
64-
Set this value to `true` to serve randomized statistics instead.
63+
Possible values:
6564

66-
Why you'd want this can have many reasons, one of them being privacy reasons.
67-
Perhaps you don't want to expose accurate information about your server publicly.
65+
- `regular`: Return accurate statistics read from the database
66+
- `zero`: Set all the statistics to zero
67+
- `random`: Set all the statistics to random values
68+
69+
The settings `zero` and `random` are great if you don't want crawlers to figure out how many people are on your instance.
70+
71+
<Aside type="caution">Booting your instance into `random` mode might upset techbros</Aside>
6872

6973
## `registrations-open`
7074

0 commit comments

Comments
 (0)