Browse Source

Merge branch 'master' into federation

feature/settings-cleanup
Felix Ableitner 3 years ago
parent
commit
efa34f9903
  1. 15
      README.md
  2. 2
      ansible/VERSION
  3. 2
      ansible/templates/docker-compose.yml
  4. 2
      ansible/templates/nginx.conf
  5. 2
      docker/dev/docker-compose.yml
  6. 4
      docker/lemmy.hjson
  7. 8
      docker/prod/docker-compose.yml
  8. BIN
      docs/img/chat_screen.png
  9. BIN
      docs/img/main_screen.png
  10. BIN
      docs/img/rank_algorithm.png
  11. 2
      docs/src/about.md
  12. 2
      docs/src/about_ranking.md
  13. 7
      docs/src/administration_install_docker.md
  14. 4
      docs/src/contributing_federation_development.md
  15. 2
      docs/src/contributing_websocket_http_api.md
  16. 73
      install.sh
  17. 8
      server/Cargo.toml
  18. 113
      server/db-init.sh
  19. 4
      server/src/api/user.rs
  20. 109
      server/src/lib.rs
  21. 104
      server/src/main.rs
  22. 2
      server/src/routes/websocket.rs
  23. 2
      server/src/version.rs

15
README.md

@ -34,7 +34,7 @@
Front Page|Post
---|---
![main screen](https://i.imgur.com/kZSRcRu.png)|![chat screen](https://i.imgur.com/4XghNh6.png)
![main screen](https://raw.githubusercontent.com/LemmyNet/lemmy/master/docs/img/main_screen.png)|![chat screen](https://raw.githubusercontent.com/LemmyNet/lemmy/master/docs/img/chat_screen.png)
[Lemmy](https://github.com/LemmyNet/lemmy) is similar to sites like [Reddit](https://reddit.com), [Lobste.rs](https://lobste.rs), [Raddle](https://raddle.me), or [Hacker News](https://news.ycombinator.com/): you subscribe to forums you're interested in, post links and discussions, then vote, and comment on them. Behind the scenes, it is very different; anyone can easily run a server, and all these servers are federated (think email), and connected to the same universe, called the [Fediverse](https://en.wikipedia.org/wiki/Fediverse).
@ -44,7 +44,7 @@ The overall goal is to create an easily self-hostable, decentralized alternative
Each lemmy server can set its own moderation policy; appointing site-wide admins, and community moderators to keep out the trolls, and foster a healthy, non-toxic environment where all can feel comfortable contributing.
*Note: Federation is still in active development*
*Note: Federation is still in active development and the WebSocket, as well as, HTTP API are currently unstable*
### Why's it called Lemmy?
@ -125,16 +125,19 @@ Lemmy is free, open-source software, meaning no advertising, monetizing, or vent
- [Docker Development](https://dev.lemmy.ml/docs/contributing_docker_development.html)
- [Local Development](https://dev.lemmy.ml/docs/contributing_local_development.html)
### Translations
### Translations
If you want to help with translating, take a look at [Weblate](https://weblate.yerbamate.dev/projects/lemmy/).
## Contact
- [Mastodon](https://mastodon.social/@LemmyDev) - [![Mastodon Follow](https://img.shields.io/mastodon/follow/810572?domain=https%3A%2F%2Fmastodon.social&style=social)](https://mastodon.social/@LemmyDev)
- [Matrix](https://riot.im/app/#/room/#rust-reddit-fediverse:matrix.org) - [![Matrix](https://img.shields.io/matrix/rust-reddit-fediverse:matrix.org.svg?label=matrix-chat)](https://riot.im/app/#/room/#rust-reddit-fediverse:matrix.org)
- [Mastodon](https://mastodon.social/@LemmyDev)
- [Matrix](https://riot.im/app/#/room/#rust-reddit-fediverse:matrix.org)
## Code Mirrors
- [GitHub](https://github.com/LemmyNet/lemmy)
- [Gitea](https://yerbamate.dev/dessalines/lemmy)
- [Gitea](https://yerbamate.dev/LemmyNet/lemmy)
- [GitLab](https://gitlab.com/dessalines/lemmy)
## Credits

2
ansible/VERSION

@ -1 +1 @@
v0.6.51
v0.6.71

2
ansible/templates/docker-compose.yml

@ -26,7 +26,7 @@ services:
restart: always
pictshare:
image: shtripok/pictshare:latest
image: hascheksolutions/pictshare:latest
ports:
- "127.0.0.1:8537:80"
volumes:

2
ansible/templates/nginx.conf

@ -36,7 +36,7 @@ server {
# It might be nice to compress JSON, but leaving that out to protect against potential
# compression+encryption information leak attacks like BREACH.
gzip on;
gzip_types text/css application/javascript;
gzip_types text/css application/javascript image/svg+xml;
gzip_vary on;
# Only connect to this site via HTTPS for the two years

2
docker/dev/docker-compose.yml

@ -28,7 +28,7 @@ services:
- iframely
pictshare:
image: shtripok/pictshare:latest
image: hascheksolutions/pictshare:latest
ports:
- "127.0.0.1:8537:80"
volumes:

4
docker/lemmy.hjson

@ -23,9 +23,6 @@
jwt_secret: "changeme"
# The dir for the front end
front_end_dir: "/app/dist"
# whether to enable activitypub federation. this feature is in alpha, do not enable in production, as might
# cause problems like remote instances fetching and permanently storing bad data.
federation_enabled: false
# rate limits for various user actions, by user ip
rate_limit: {
# maximum number of messages created in interval
@ -60,6 +57,7 @@
# smtp_password: ""
# # address to send emails from, eg "[email protected]"
# smtp_from_address: ""
# use_tls: true
# }
}

8
docker/prod/docker-compose.yml

@ -1,4 +1,4 @@
version: '3.3'
version: '2.2'
services:
postgres:
@ -12,7 +12,7 @@ services:
restart: always
lemmy:
image: dessalines/lemmy:v0.6.51
image: dessalines/lemmy:v0.6.71
ports:
- "127.0.0.1:8536:8536"
restart: always
@ -26,12 +26,13 @@ services:
- iframely
pictshare:
image: shtripok/pictshare:latest
image: hascheksolutions/pictshare:latest
ports:
- "127.0.0.1:8537:80"
volumes:
- ./volumes/pictshare:/usr/share/nginx/html/data
restart: always
mem_limit: 100m
iframely:
image: dogbin/iframely:latest
@ -40,3 +41,4 @@ services:
volumes:
- ./iframely.config.local.js:/iframely/config.local.js:ro
restart: always
mem_limit: 100m

BIN
docs/img/chat_screen.png

After

Width: 1836  |  Height: 921  |  Size: 78 KiB

BIN
docs/img/main_screen.png

After

Width: 1839  |  Height: 921  |  Size: 92 KiB

BIN
docs/img/rank_algorithm.png

After

Width: 617  |  Height: 702  |  Size: 54 KiB

2
docs/src/about.md

@ -2,7 +2,7 @@
Front Page|Post
---|---
![main screen](https://i.imgur.com/kZSRcRu.png)|![chat screen](https://i.imgur.com/4XghNh6.png)
![main screen](https://raw.githubusercontent.com/LemmyNet/lemmy/master/docs/img/main_screen.png)|![chat screen](https://raw.githubusercontent.com/LemmyNet/lemmy/master/docs/img/chat_screen.png)
[Lemmy](https://github.com/LemmyNet/lemmy) is similar to sites like [Reddit](https://reddit.com), [Lobste.rs](https://lobste.rs), [Raddle](https://raddle.me), or [Hacker News](https://news.ycombinator.com/): you subscribe to forums you're interested in, post links and discussions, then vote, and comment on them. Behind the scenes, it is very different; anyone can easily run a server, and all these servers are federated (think email), and connected to the same universe, called the [Fediverse](https://en.wikipedia.org/wiki/Fediverse).

2
docs/src/about_ranking.md

@ -26,4 +26,4 @@ Gravity = Decay gravity, 1.8 is default
A plot of rank over 24 hours, of scores of 1, 5, 10, 100, 1000, with a scale factor of 10k.
![](https://i.imgur.com/w8oBLlL.png)
![](https://raw.githubusercontent.com/LemmyNet/lemmy/master/docs/img/rank_algorithm.png)

7
docs/src/administration_install_docker.md

@ -10,12 +10,13 @@ cd /lemmy
wget https://raw.githubusercontent.com/dessalines/lemmy/master/docker/prod/docker-compose.yml
wget https://raw.githubusercontent.com/dessalines/lemmy/master/docker/lemmy.hjson
wget https://raw.githubusercontent.com/dessalines/lemmy/master/docker/iframely.config.local.js
docker-compose up -d
```
After this, have a look at the [config file](administration_configuration.md) named `lemmy.hjson`, and adjust it, in particular the hostname.
After this, have a look at the [config file](administration_configuration.md) named `lemmy.hjson`, and adjust it, in particular the hostname, and possibly the db password. Then run:
`docker-compose up -d`
To make Lemmy available outside the server, you need to setup a reverse proxy, like Nginx. [A sample nginx config](/ansible/templates/nginx.conf), could be setup with:
To make Lemmy available outside the server, you need to setup a reverse proxy, like Nginx. [A sample nginx config](https://raw.githubusercontent.com/dessalines/lemmy/master/ansible/templates/nginx.conf), could be setup with:
```bash
wget https://raw.githubusercontent.com/dessalines/lemmy/master/ansible/templates/nginx.conf

4
docs/src/contributing_federation_development.md

@ -5,12 +5,12 @@
If you don't have a local clone of the Lemmy repo yet, just run the following command:
```bash
git clone https://yerbamate.dev/LemmyNet/lemmy.git -b federation
git clone https://github.com/LemmyNet/lemmy -b federation
```
If you already have the Lemmy repo cloned, you need to add a new remote:
```bash
git remote add federation https://yerbamate.dev/LemmyNet/lemmy.git
git remote add federation https://github.com/LemmyNet/lemmy
git checkout federation
git pull federation federation
```

2
docs/src/contributing_websocket_http_api.md

@ -1,6 +1,6 @@
# Lemmy API
*Note: this may lag behind the actual API endpoints [here](../server/src/api).*
*Note: this may lag behind the actual API endpoints [here](../server/src/api). The API should be considered unstable and may change any time.*
<!-- toc -->

73
install.sh

@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/sh
set -e
# Set the database variable to the default first.
@ -10,25 +10,55 @@ export LEMMY_DATABASE_URL=postgres://lemmy:[email protected]:5432/lemmy
export JWT_SECRET=changeme
export HOSTNAME=rrr
yes_no_prompt_invalid() {
echo "Invalid input. Please enter either \"y\" or \"n\"." 1>&2
}
ask_to_init_db() {
init_db_valid=0
init_db_final=0
while [ "$init_db_valid" == 0 ]
do
read -p "Initialize database (y/n)? " init_db
case "$init_db" in
[yY]* ) init_db_valid=1; init_db_final=1;;
[nN]* ) init_db_valid=1; init_db_final=0;;
* ) yes_no_prompt_invalid;;
esac
echo
done
if [ "$init_db_final" = 1 ]
then
source ./server/db-init.sh
read -n 1 -s -r -p "Press ANY KEY to continue execution of this script, press CTRL+C to quit..."
echo
fi
}
ask_to_auto_reload() {
auto_reload_valid=0
auto_reload_final=0
while [ "$auto_reload_valid" == 0 ]
do
echo "Automagically reload the project when source files are changed?"
echo "ONLY ENABLE THIS FOR DEVELOPMENT!"
read -p "(y/n) " auto_reload
case "$auto_reload" in
[yY]* ) auto_reload_valid=1; auto_reload_final=1;;
[nN]* ) auto_reload_valid=1; auto_reload_final=0;;
* ) yes_no_prompt_invalid;;
esac
echo
done
if [ "$auto_reload_final" = 1 ]
then
cd ui && yarn start
cd server && cargo watch -x run
fi
}
# Optionally initialize the database
init_db_valid=0
init_db_final=0
while [ "$init_db_valid" == 0 ]
do
read -p "Initialize database (y/n)? " init_db
case "${init_db,,}" in
y|yes ) init_db_valid=1; init_db_final=1;;
n|no ) init_db_valid=1; init_db_final=0;;
* ) echo "Invalid input" 1>&2;;
esac
echo
done
if [ "$init_db_final" = 1 ]
then
source ./server/db-init.sh
read -n 1 -s -r -p "Press ANY KEY to continue execution of this script, press CTRL+C to quit..."
echo
fi
ask_to_init_db
# Build the web client
cd ui
@ -39,6 +69,5 @@ yarn build
cd ../server
RUST_LOG=debug cargo run
# For live coding, where both the front and back end, automagically reload on any save, do:
# cd ui && yarn start
# cd server && cargo watch -x run
# For live coding, where both the front and back end, automagically reload on any save
ask_to_auto_reload

8
server/Cargo.toml

@ -1,7 +1,7 @@
[package]
name = "lemmy_server"
version = "0.0.1"
authors = ["Dessalines <[email protected].com>"]
authors = ["Dessalines <[email protected].com>"]
edition = "2018"
[dependencies]
@ -13,8 +13,8 @@ activitystreams-new = { git = "https://git.asonix.dog/asonix/activitystreams-ske
activitystreams-ext = { git = "https://git.asonix.dog/asonix/activitystreams-ext" }
bcrypt = "0.8.0"
chrono = { version = "0.4.7", features = ["serde"] }
failure = "0.1.8"
serde_json = { version = "1.0.48", features = ["preserve_order"]}
failure = "0.1.8"
serde = { version = "1.0.105", features = ["derive"] }
actix = "0.9.0"
actix-web = "2.0.0"
@ -29,8 +29,8 @@ strum_macros = "0.18.0"
jsonwebtoken = "7.0.1"
regex = "1.3.5"
lazy_static = "1.3.0"
lettre = "0.9.2"
lettre_email = "0.9.2"
lettre = "0.9.3"
lettre_email = "0.9.4"
sha2 = "0.8.1"
rss = "1.9.0"
htmlescape = "0.3.1"

113
server/db-init.sh

@ -1,43 +1,106 @@
#!/bin/bash
#!/bin/sh
# Default configurations
username=lemmy
dbname=lemmy
port=5432
password=""
password_confirm=""
password_valid=0
yes_no_prompt_invalid() {
echo "Invalid input. Please enter either \"y\" or \"n\"." 1>&2
}
while [ "$password_valid" == 0 ]
do
read -p "Enter database password: " -s password
echo
print_config() {
echo " database name: $dbname"
echo " username: $username"
echo " port: $port"
}
read -p "Verify database password: " -s password_confirm
echo
ask_for_db_config() {
echo "The default database configuration is:"
print_config
echo
# Start the loop from the top if either check fails
if [ -z "$password" ]
then
echo "Error: Password cannot be empty." 1>&2
default_config_final=0
default_config_valid=0
while [ "$default_config_valid" == 0 ]
do
read -p "Use this configuration (y/n)? " default_config
case "$default_config" in
[yY]* ) default_config_valid=1; default_config_final=1;;
[nN]* ) default_config_valid=1; default_config_final=0;;
* ) yes_no_prompt_invalid;;
esac
echo
continue
fi
if [ "$password" != "$password_confirm" ]
done
if [ "$default_config_final" == 0 ]
then
echo "Error: Passwords don't match." 1>&2
echo
continue
config_ok_final=0
while [ "$config_ok_final" == 0 ]
do
read -p "Database name: " dbname
read -p "Username: " username
read -p "Port: " port
#echo
#echo "The database configuration is:"
#print_config
#echo
config_ok_valid=0
while [ "$config_ok_valid" == 0 ]
do
read -p "Use this configuration (y/n)? " config_ok
case "$config_ok" in
[yY]* ) config_ok_valid=1; config_ok_final=1;;
[nN]* ) config_ok_valid=1; config_ok_final=0;;
* ) yes_no_prompt_invalid;;
esac
echo
done
done
fi
}
ask_for_password() {
password=""
password_confirm=""
password_valid=0
while [ "$password_valid" == 0 ]
do
read -p "Enter database password: " -s password
echo
read -p "Verify database password: " -s password_confirm
echo
echo
# Set the password_valid variable to break out of the loop
password_valid=1
done
# Start the loop from the top if either check fails
if [ -z "$password" ]
then
echo "Error: Password cannot be empty." 1>&2
echo
continue
fi
if [ "$password" != "$password_confirm" ]
then
echo "Error: Passwords don't match." 1>&2
echo
continue
fi
# Set the password_valid variable to break out of the loop
password_valid=1
done
}
ask_for_db_config
ask_for_password
psql -c "CREATE USER $username WITH PASSWORD '$password' SUPERUSER;" -U postgres
psql -c 'CREATE DATABASE $dbname WITH OWNER $username;' -U postgres
psql -c "CREATE DATABASE $dbname WITH OWNER $username;" -U postgres
export LEMMY_DATABASE_URL=postgres://$username:$password@localhost:$port/$dbname
echo $LEMMY_DATABASE_URL
echo "The database URL is $LEMMY_DATABASE_URL"

4
server/src/api/user.rs

@ -30,6 +30,7 @@ use crate::{
SortType,
},
generate_random_string,
is_valid_username,
naive_from_unix,
naive_now,
remove_slurs,
@ -314,6 +315,9 @@ impl Perform for Oper<Register> {
}
let user_keypair = generate_actor_keypair()?;
if !is_valid_username(&data.username) {
return Err(APIError::err("invalid_username").into());
}
// Register the new user
let user_form = UserForm {

109
server/src/lib.rs

@ -85,6 +85,20 @@ pub fn is_email_regex(test: &str) -> bool {
EMAIL_REGEX.is_match(test)
}
pub fn is_image_content_type(test: &str) -> Result<(), failure::Error> {
if isahc::get(test)?
.headers()
.get("Content-Type")
.ok_or_else(|| format_err!("No Content-Type header"))?
.to_str()?
.starts_with("image/")
{
Ok(())
} else {
Err(format_err!("Not an image type."))
}
}
pub fn remove_slurs(test: &str) -> String {
SLUR_REGEX.replace_all(test, "*removed*").to_string()
}
@ -178,6 +192,8 @@ pub struct PictshareResponse {
}
pub fn fetch_pictshare(image_url: &str) -> Result<PictshareResponse, failure::Error> {
is_image_content_type(image_url)?;
let fetch_url = format!(
"http://pictshare/api/geturl.php?url={}",
utf8_percent_encode(image_url, NON_ALPHANUMERIC)
@ -195,36 +211,46 @@ fn fetch_iframely_and_pictshare_data(
Option<String>,
Option<String>,
) {
// Fetch iframely data
let (iframely_title, iframely_description, iframely_thumbnail_url, iframely_html) = match url {
Some(url) => match fetch_iframely(&url) {
Ok(res) => (res.title, res.description, res.thumbnail_url, res.html),
Err(e) => {
error!("iframely err: {}", e);
(None, None, None, None)
}
},
match &url {
Some(url) => {
// Fetch iframely data
let (iframely_title, iframely_description, iframely_thumbnail_url, iframely_html) =
match fetch_iframely(url) {
Ok(res) => (res.title, res.description, res.thumbnail_url, res.html),
Err(e) => {
error!("iframely err: {}", e);
(None, None, None, None)
}
};
// Fetch pictshare thumbnail
let pictshare_thumbnail = match iframely_thumbnail_url {
Some(iframely_thumbnail_url) => match fetch_pictshare(&iframely_thumbnail_url) {
Ok(res) => Some(res.url),
Err(e) => {
error!("pictshare err: {}", e);
None
}
},
// Try to generate a small thumbnail if iframely is not supported
None => match fetch_pictshare(&url) {
Ok(res) => Some(res.url),
Err(e) => {
error!("pictshare err: {}", e);
None
}
},
};
(
iframely_title,
iframely_description,
iframely_html,
pictshare_thumbnail,
)
}
None => (None, None, None, None),
};
// Fetch pictshare thumbnail
let pictshare_thumbnail = match iframely_thumbnail_url {
Some(iframely_thumbnail_url) => match fetch_pictshare(&iframely_thumbnail_url) {
Ok(res) => Some(res.url),
Err(e) => {
error!("pictshare err: {}", e);
None
}
},
None => None,
};
(
iframely_title,
iframely_description,
iframely_html,
pictshare_thumbnail,
)
}
}
pub fn markdown_to_html(text: &str) -> String {
@ -268,10 +294,16 @@ pub fn scrape_text_for_mentions(text: &str) -> Vec<MentionData> {
out.into_iter().unique().collect()
}
pub fn is_valid_username(name: &str) -> bool {
VALID_USERNAME_REGEX.is_match(name)
}
#[cfg(test)]
mod tests {
use crate::{
is_email_regex,
is_image_content_type,
is_valid_username,
remove_slurs,
scrape_text_for_mentions,
slur_check,
@ -288,12 +320,30 @@ mod tests {
assert_eq!(mentions[1].domain, "lemmy_alpha:8540".to_string());
}
#[test]
fn test_image() {
assert!(is_image_content_type("https://1734811051.rsc.cdn77.org/data/images/full/365645/as-virus-kills-navajos-in-their-homes-tribal-women-provide-lifeline.jpg?w=600?w=650").is_ok());
assert!(is_image_content_type(
"https://twitter.com/BenjaminNorton/status/1259922424272957440?s=20"
)
.is_err());
}
#[test]
fn test_email() {
assert!(is_email_regex("[email protected]"));
assert!(!is_email_regex("nada_neutho"));
}
#[test]
fn test_valid_register_username() {
assert!(is_valid_username("Hello_98"));
assert!(is_valid_username("ten"));
assert!(!is_valid_username("Hello-98"));
assert!(!is_valid_username("a"));
assert!(!is_valid_username(""));
}
#[test]
fn test_slur_filter() {
let test =
@ -351,4 +401,5 @@ lazy_static! {
// TODO keep this old one, it didn't work with port well tho
// static ref WEBFINGER_USER_REGEX: Regex = Regex::new(r"@(?P<name>[\w.]+)@(?P<domain>[a-zA-Z0-9._-]+\.[a-zA-Z0-9_-]+)").unwrap();
static ref WEBFINGER_USER_REGEX: Regex = Regex::new(r"@(?P<name>[\w.]+)@(?P<domain>[a-zA-Z0-9._:-]+)").unwrap();
static ref VALID_USERNAME_REGEX: Regex = Regex::new(r"^[a-zA-Z0-9_]{3,20}$").unwrap();
}

104
server/src/main.rs

@ -1,14 +1,24 @@
extern crate lemmy_server;
#[macro_use]
extern crate diesel_migrations;
#[macro_use]
pub extern crate lazy_static;
use crate::lemmy_server::actix_web::dev::Service;
use actix::prelude::*;
use actix_web::*;
use actix_web::{
body::Body,
dev::{ServiceRequest, ServiceResponse},
http::{
header::{CACHE_CONTROL, CONTENT_TYPE},
HeaderValue,
},
*,
};
use diesel::{
r2d2::{ConnectionManager, Pool},
PgConnection,
};
use failure::Error;
use lemmy_server::{
db::code_migrations::run_advanced_migrations,
rate_limit::{rate_limiter::RateLimiter, RateLimit},
@ -16,13 +26,22 @@ use lemmy_server::{
settings::Settings,
websocket::server::*,
};
use std::sync::Arc;
use regex::Regex;
use std::{io, sync::Arc};
use tokio::sync::Mutex;
lazy_static! {
static ref CACHE_CONTROL_REGEX: Regex =
Regex::new("^((text|image)/.+|application/javascript)$").unwrap();
// static ref CACHE_CONTROL_VALUE: String = format!("public, max-age={}", 365 * 24 * 60 * 60);
// Test out 1 hour here, this is breaking some things
static ref CACHE_CONTROL_VALUE: String = format!("public, max-age={}", 60 * 60);
}
embed_migrations!();
#[actix_rt::main]
async fn main() -> Result<(), Error> {
async fn main() -> io::Result<()> {
env_logger::init();
let settings = Settings::get();
@ -52,33 +71,52 @@ async fn main() -> Result<(), Error> {
);
// Create Http server with websocket support
Ok(
HttpServer::new(move || {
let settings = Settings::get();
let rate_limiter = rate_limiter.clone();
App::new()
.wrap(middleware::Logger::default())
.data(pool.clone())
.data(server.clone())
// The routes
.configure(move |cfg| api::config(cfg, &rate_limiter))
.configure(federation::config)
.configure(feeds::config)
.configure(index::config)
.configure(nodeinfo::config)
.configure(webfinger::config)
// static files
.service(actix_files::Files::new(
"/static",
settings.front_end_dir.to_owned(),
))
.service(actix_files::Files::new(
"/docs",
settings.front_end_dir + "/documentation",
))
})
.bind((settings.bind, settings.port))?
.run()
.await?,
)
HttpServer::new(move || {
let settings = Settings::get();
let rate_limiter = rate_limiter.clone();
App::new()
.wrap_fn(add_cache_headers)
.wrap(middleware::Logger::default())
.data(pool.clone())
.data(server.clone())
// The routes
.configure(move |cfg| api::config(cfg, &rate_limiter))
.configure(federation::config)
.configure(feeds::config)
.configure(index::config)
.configure(nodeinfo::config)
.configure(webfinger::config)
// static files
.service(actix_files::Files::new(
"/static",
settings.front_end_dir.to_owned(),
))
.service(actix_files::Files::new(
"/docs",
settings.front_end_dir + "/documentation",
))
})
.bind((settings.bind, settings.port))?
.run()
.await
}
fn add_cache_headers<S>(
req: ServiceRequest,
srv: &mut S,
) -> impl Future<Output = Result<ServiceResponse, Error>>
where
S: Service<Request = ServiceRequest, Response = ServiceResponse<Body>, Error = Error>,
{
let fut = srv.call(req);
async move {
let mut res = fut.await?;
if let Some(content_type) = res.headers().get(CONTENT_TYPE) {
if CACHE_CONTROL_REGEX.is_match(content_type.to_str().unwrap()) {
let header_val = HeaderValue::from_static(&CACHE_CONTROL_VALUE);
res.headers_mut().insert(CACHE_CONTROL, header_val);
}
}
Ok(res)
}
}

2
server/src/routes/websocket.rs

@ -130,7 +130,7 @@ impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for WSSession {
}
actix::fut::ready(())
})
.wait(ctx);
.spawn(ctx);
}
ws::Message::Binary(_bin) => info!("Unexpected binary"),
ws::Message::Close(_) => {

2
server/src/version.rs

@ -1 +1 @@
pub const VERSION: &str = "v0.6.51";
pub const VERSION: &str = "v0.6.71";
Loading…
Cancel
Save