cache local instance (#572)

* cache local instance

fix #564

* don't use local instance cache for plm

* use instance cache for plm, but initialize it

* cargo fmt
This commit is contained in:
fdb-hiroshima 2019-05-10 22:59:34 +02:00 committed by Baptiste Gelez
parent 5b50f90d2b
commit 773fbfe7c8
20 changed files with 123 additions and 88 deletions

View File

@ -6,7 +6,7 @@ extern crate rpassword;
use clap::App; use clap::App;
use diesel::Connection; use diesel::Connection;
use plume_models::{Connection as Conn, CONFIG}; use plume_models::{instance::Instance, Connection as Conn, CONFIG};
use std::io::{self, prelude::*}; use std::io::{self, prelude::*};
mod instance; mod instance;
@ -27,6 +27,7 @@ fn main() {
dotenv::dotenv().ok(); dotenv::dotenv().ok();
let conn = Conn::establish(CONFIG.database_url.as_str()); let conn = Conn::establish(CONFIG.database_url.as_str());
let _ = conn.as_ref().map(|conn| Instance::cache_local(conn));
match matches.subcommand() { match matches.subcommand() {
("instance", Some(args)) => { ("instance", Some(args)) => {

View File

@ -129,7 +129,7 @@ fn reset_password<'a>(args: &ArgMatches<'a>, conn: &Connection) {
let user = User::find_by_name( let user = User::find_by_name(
conn, conn,
&username, &username,
Instance::get_local(conn) Instance::get_local()
.expect("Failed to get local instance") .expect("Failed to get local instance")
.id, .id,
) )

View File

@ -172,7 +172,7 @@ impl Blog {
let mut icon = Image::default(); let mut icon = Image::default();
icon.object_props.set_url_string( icon.object_props.set_url_string(
self.icon_id self.icon_id
.and_then(|id| Media::get(conn, id).and_then(|m| m.url(conn)).ok()) .and_then(|id| Media::get(conn, id).and_then(|m| m.url()).ok())
.unwrap_or_default(), .unwrap_or_default(),
)?; )?;
icon.object_props.set_attributed_to_link( icon.object_props.set_attributed_to_link(
@ -189,7 +189,7 @@ impl Blog {
let mut banner = Image::default(); let mut banner = Image::default();
banner.object_props.set_url_string( banner.object_props.set_url_string(
self.banner_id self.banner_id
.and_then(|id| Media::get(conn, id).and_then(|m| m.url(conn)).ok()) .and_then(|id| Media::get(conn, id).and_then(|m| m.url()).ok())
.unwrap_or_default(), .unwrap_or_default(),
)?; )?;
banner.object_props.set_attributed_to_link( banner.object_props.set_attributed_to_link(
@ -271,14 +271,14 @@ impl Blog {
pub fn icon_url(&self, conn: &Connection) -> String { pub fn icon_url(&self, conn: &Connection) -> String {
self.icon_id self.icon_id
.and_then(|id| Media::get(conn, id).and_then(|m| m.url(conn)).ok()) .and_then(|id| Media::get(conn, id).and_then(|m| m.url()).ok())
.unwrap_or_else(|| "/static/default-avatar.png".to_string()) .unwrap_or_else(|| "/static/default-avatar.png".to_string())
} }
pub fn banner_url(&self, conn: &Connection) -> Option<String> { pub fn banner_url(&self, conn: &Connection) -> Option<String> {
self.banner_id self.banner_id
.and_then(|i| Media::get(conn, i).ok()) .and_then(|i| Media::get(conn, i).ok())
.and_then(|c| c.url(conn).ok()) .and_then(|c| c.url().ok())
} }
pub fn delete(&self, conn: &Connection, searcher: &Searcher) -> Result<()> { pub fn delete(&self, conn: &Connection, searcher: &Searcher) -> Result<()> {
@ -407,7 +407,9 @@ impl AsActor<&PlumeRocket> for Blog {
} }
fn is_local(&self) -> bool { fn is_local(&self) -> bool {
self.instance_id == 1 // TODO: this is not always true Instance::get_local()
.map(|i| self.instance_id == i.id)
.unwrap_or(false)
} }
} }
@ -474,7 +476,7 @@ pub(crate) mod tests {
"BlogName".to_owned(), "BlogName".to_owned(),
"Blog name".to_owned(), "Blog name".to_owned(),
"This is a small blog".to_owned(), "This is a small blog".to_owned(),
Instance::get_local(conn).unwrap().id, Instance::get_local().unwrap().id,
) )
.unwrap(), .unwrap(),
) )
@ -485,7 +487,7 @@ pub(crate) mod tests {
"MyBlog".to_owned(), "MyBlog".to_owned(),
"My blog".to_owned(), "My blog".to_owned(),
"Welcome to my blog".to_owned(), "Welcome to my blog".to_owned(),
Instance::get_local(conn).unwrap().id, Instance::get_local().unwrap().id,
) )
.unwrap(), .unwrap(),
) )
@ -496,7 +498,7 @@ pub(crate) mod tests {
"WhyILikePlume".to_owned(), "WhyILikePlume".to_owned(),
"Why I like Plume".to_owned(), "Why I like Plume".to_owned(),
"In this blog I will explay you why I like Plume so much".to_owned(), "In this blog I will explay you why I like Plume so much".to_owned(),
Instance::get_local(conn).unwrap().id, Instance::get_local().unwrap().id,
) )
.unwrap(), .unwrap(),
) )
@ -556,7 +558,7 @@ pub(crate) mod tests {
"SomeName".to_owned(), "SomeName".to_owned(),
"Some name".to_owned(), "Some name".to_owned(),
"This is some blog".to_owned(), "This is some blog".to_owned(),
Instance::get_local(conn).unwrap().id, Instance::get_local().unwrap().id,
) )
.unwrap(), .unwrap(),
) )
@ -564,7 +566,7 @@ pub(crate) mod tests {
assert_eq!( assert_eq!(
blog.get_instance(conn).unwrap().id, blog.get_instance(conn).unwrap().id,
Instance::get_local(conn).unwrap().id Instance::get_local().unwrap().id
); );
// TODO add tests for remote instance // TODO add tests for remote instance
@ -584,7 +586,7 @@ pub(crate) mod tests {
"SomeName".to_owned(), "SomeName".to_owned(),
"Some name".to_owned(), "Some name".to_owned(),
"This is some blog".to_owned(), "This is some blog".to_owned(),
Instance::get_local(conn).unwrap().id, Instance::get_local().unwrap().id,
) )
.unwrap(), .unwrap(),
) )
@ -595,7 +597,7 @@ pub(crate) mod tests {
"Blog".to_owned(), "Blog".to_owned(),
"Blog".to_owned(), "Blog".to_owned(),
"I've named my blog Blog".to_owned(), "I've named my blog Blog".to_owned(),
Instance::get_local(conn).unwrap().id, Instance::get_local().unwrap().id,
) )
.unwrap(), .unwrap(),
) )
@ -687,7 +689,7 @@ pub(crate) mod tests {
"SomeName".to_owned(), "SomeName".to_owned(),
"Some name".to_owned(), "Some name".to_owned(),
"This is some blog".to_owned(), "This is some blog".to_owned(),
Instance::get_local(conn).unwrap().id, Instance::get_local().unwrap().id,
) )
.unwrap(), .unwrap(),
) )
@ -711,7 +713,7 @@ pub(crate) mod tests {
"SomeName".to_owned(), "SomeName".to_owned(),
"Some name".to_owned(), "Some name".to_owned(),
"This is some blog".to_owned(), "This is some blog".to_owned(),
Instance::get_local(conn).unwrap().id, Instance::get_local().unwrap().id,
) )
.unwrap(), .unwrap(),
) )
@ -749,7 +751,7 @@ pub(crate) mod tests {
"SomeName".to_owned(), "SomeName".to_owned(),
"Some name".to_owned(), "Some name".to_owned(),
"This is some blog".to_owned(), "This is some blog".to_owned(),
Instance::get_local(conn).unwrap().id, Instance::get_local().unwrap().id,
) )
.unwrap(), .unwrap(),
) )
@ -760,7 +762,7 @@ pub(crate) mod tests {
"Blog".to_owned(), "Blog".to_owned(),
"Blog".to_owned(), "Blog".to_owned(),
"I've named my blog Blog".to_owned(), "I've named my blog Blog".to_owned(),
Instance::get_local(conn).unwrap().id, Instance::get_local().unwrap().id,
) )
.unwrap(), .unwrap(),
) )

View File

@ -79,7 +79,7 @@ impl Comment {
pub fn count_local(conn: &Connection) -> Result<i64> { pub fn count_local(conn: &Connection) -> Result<i64> {
use schema::users; use schema::users;
let local_authors = users::table let local_authors = users::table
.filter(users::instance_id.eq(Instance::get_local(conn)?.id)) .filter(users::instance_id.eq(Instance::get_local()?.id))
.select(users::id); .select(users::id);
comments::table comments::table
.filter(comments::author_id.eq_any(local_authors)) .filter(comments::author_id.eq_any(local_authors))
@ -107,7 +107,7 @@ impl Comment {
let author = User::get(&c.conn, self.author_id)?; let author = User::get(&c.conn, self.author_id)?;
let (html, mentions, _hashtags) = utils::md_to_html( let (html, mentions, _hashtags) = utils::md_to_html(
self.content.get().as_ref(), self.content.get().as_ref(),
Some(&Instance::get_local(&c.conn)?.public_domain), Some(&Instance::get_local()?.public_domain),
true, true,
Some(Media::get_media_processor(&c.conn, vec![&author])), Some(Media::get_media_processor(&c.conn, vec![&author])),
); );

View File

@ -1,6 +1,7 @@
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use diesel::{self, ExpressionMethods, QueryDsl, RunQueryDsl}; use diesel::{self, ExpressionMethods, QueryDsl, RunQueryDsl};
use std::iter::Iterator; use std::iter::Iterator;
use std::sync::RwLock;
use ap_url; use ap_url;
use medias::Media; use medias::Media;
@ -40,8 +41,24 @@ pub struct NewInstance {
pub short_description_html: String, pub short_description_html: String,
} }
lazy_static! {
static ref LOCAL_INSTANCE: RwLock<Option<Instance>> = RwLock::new(None);
}
impl Instance { impl Instance {
pub fn get_local(conn: &Connection) -> Result<Instance> { pub fn set_local(self) {
LOCAL_INSTANCE.write().unwrap().replace(self);
}
pub fn get_local() -> Result<Instance> {
LOCAL_INSTANCE
.read()
.unwrap()
.clone()
.ok_or(Error::NotFound)
}
pub fn get_local_uncached(conn: &Connection) -> Result<Instance> {
instances::table instances::table
.filter(instances::local.eq(true)) .filter(instances::local.eq(true))
.limit(1) .limit(1)
@ -51,6 +68,10 @@ impl Instance {
.ok_or(Error::NotFound) .ok_or(Error::NotFound)
} }
pub fn cache_local(conn: &Connection) {
*LOCAL_INSTANCE.write().unwrap() = Instance::get_local_uncached(conn).ok();
}
pub fn get_remotes(conn: &Connection) -> Result<Vec<Instance>> { pub fn get_remotes(conn: &Connection) -> Result<Vec<Instance>> {
instances::table instances::table
.filter(instances::local.eq(false)) .filter(instances::local.eq(false))
@ -141,7 +162,7 @@ impl Instance {
false, false,
Some(Media::get_media_processor(conn, vec![])), Some(Media::get_media_processor(conn, vec![])),
); );
diesel::update(self) let res = diesel::update(self)
.set(( .set((
instances::name.eq(name), instances::name.eq(name),
instances::open_registrations.eq(open_registrations), instances::open_registrations.eq(open_registrations),
@ -152,7 +173,11 @@ impl Instance {
)) ))
.execute(conn) .execute(conn)
.map(|_| ()) .map(|_| ())
.map_err(Error::from) .map_err(Error::from);
if self.local {
Instance::cache_local(conn);
}
res
} }
pub fn count(conn: &Connection) -> Result<i64> { pub fn count(conn: &Connection) -> Result<i64> {
@ -171,7 +196,7 @@ pub(crate) mod tests {
use Connection as Conn; use Connection as Conn;
pub(crate) fn fill_database(conn: &Conn) -> Vec<(NewInstance, Instance)> { pub(crate) fn fill_database(conn: &Conn) -> Vec<(NewInstance, Instance)> {
vec![ let res = vec![
NewInstance { NewInstance {
default_license: "WTFPL".to_string(), default_license: "WTFPL".to_string(),
local: true, local: true,
@ -225,7 +250,9 @@ pub(crate) mod tests {
.unwrap_or_else(|_| Instance::insert(conn, inst).unwrap()), .unwrap_or_else(|_| Instance::insert(conn, inst).unwrap()),
) )
}) })
.collect() .collect();
Instance::cache_local(conn);
res
} }
#[test] #[test]
@ -237,7 +264,7 @@ pub(crate) mod tests {
.map(|(inserted, _)| inserted) .map(|(inserted, _)| inserted)
.find(|inst| inst.local) .find(|inst| inst.local)
.unwrap(); .unwrap();
let res = Instance::get_local(conn).unwrap(); let res = Instance::get_local().unwrap();
part_eq!( part_eq!(
res, res,

View File

@ -104,8 +104,8 @@ impl Media {
} }
} }
pub fn html(&self, conn: &Connection) -> Result<SafeString> { pub fn html(&self) -> Result<SafeString> {
let url = self.url(conn)?; let url = self.url()?;
Ok(match self.category() { Ok(match self.category() {
MediaCategory::Image => SafeString::trusted(&format!( MediaCategory::Image => SafeString::trusted(&format!(
r#"<img src="{}" alt="{}" title="{}">"#, r#"<img src="{}" alt="{}" title="{}">"#,
@ -126,23 +126,23 @@ impl Media {
}) })
} }
pub fn markdown(&self, conn: &Connection) -> Result<SafeString> { pub fn markdown(&self) -> Result<SafeString> {
Ok(match self.category() { Ok(match self.category() {
MediaCategory::Image => { MediaCategory::Image => {
SafeString::new(&format!("![{}]({})", escape(&self.alt_text), self.id)) SafeString::new(&format!("![{}]({})", escape(&self.alt_text), self.id))
} }
MediaCategory::Audio | MediaCategory::Video => self.html(conn)?, MediaCategory::Audio | MediaCategory::Video => self.html()?,
MediaCategory::Unknown => SafeString::new(""), MediaCategory::Unknown => SafeString::new(""),
}) })
} }
pub fn url(&self, conn: &Connection) -> Result<String> { pub fn url(&self) -> Result<String> {
if self.is_remote { if self.is_remote {
Ok(self.remote_url.clone().unwrap_or_default()) Ok(self.remote_url.clone().unwrap_or_default())
} else { } else {
Ok(ap_url(&format!( Ok(ap_url(&format!(
"{}/{}", "{}/{}",
Instance::get_local(conn)?.public_domain, Instance::get_local()?.public_domain,
self.file_path self.file_path
))) )))
} }
@ -237,7 +237,7 @@ impl Media {
let media = Media::get(conn, id).ok()?; let media = Media::get(conn, id).ok()?;
// if owner is user or check is disabled // if owner is user or check is disabled
if uid.contains(&media.owner_id) || uid.is_empty() { if uid.contains(&media.owner_id) || uid.is_empty() {
Some((media.url(conn).ok()?, media.content_warning)) Some((media.url().ok()?, media.content_warning))
} else { } else {
None None
} }

View File

@ -141,7 +141,7 @@ impl Post {
use schema::post_authors; use schema::post_authors;
use schema::users; use schema::users;
let local_authors = users::table let local_authors = users::table
.filter(users::instance_id.eq(Instance::get_local(conn)?.id)) .filter(users::instance_id.eq(Instance::get_local()?.id))
.select(users::id); .select(users::id);
let local_posts_id = post_authors::table let local_posts_id = post_authors::table
.filter(post_authors::author_id.eq_any(local_authors)) .filter(post_authors::author_id.eq_any(local_authors))
@ -384,7 +384,7 @@ impl Post {
.collect::<Vec<serde_json::Value>>(); .collect::<Vec<serde_json::Value>>();
let mut tags_json = Tag::for_post(conn, self.id)? let mut tags_json = Tag::for_post(conn, self.id)?
.into_iter() .into_iter()
.map(|t| json!(t.to_activity(conn).ok())) .map(|t| json!(t.to_activity().ok()))
.collect::<Vec<serde_json::Value>>(); .collect::<Vec<serde_json::Value>>();
mentions_json.append(&mut tags_json); mentions_json.append(&mut tags_json);
@ -419,7 +419,7 @@ impl Post {
if let Some(media_id) = self.cover_id { if let Some(media_id) = self.cover_id {
let media = Media::get(conn, media_id)?; let media = Media::get(conn, media_id)?;
let mut cover = Image::default(); let mut cover = Image::default();
cover.object_props.set_url_string(media.url(conn)?)?; cover.object_props.set_url_string(media.url()?)?;
if media.sensitive { if media.sensitive {
cover cover
.object_props .object_props
@ -603,7 +603,7 @@ impl Post {
pub fn cover_url(&self, conn: &Connection) -> Option<String> { pub fn cover_url(&self, conn: &Connection) -> Option<String> {
self.cover_id self.cover_id
.and_then(|i| Media::get(conn, i).ok()) .and_then(|i| Media::get(conn, i).ok())
.and_then(|c| c.url(conn).ok()) .and_then(|c| c.url().ok())
} }
pub fn build_delete(&self, conn: &Connection) -> Result<Delete> { pub fn build_delete(&self, conn: &Connection) -> Result<Delete> {

View File

@ -27,11 +27,11 @@ impl Tag {
find_by!(tags, find_by_name, tag as &str); find_by!(tags, find_by_name, tag as &str);
list_by!(tags, for_post, post_id as i32); list_by!(tags, for_post, post_id as i32);
pub fn to_activity(&self, conn: &Connection) -> Result<Hashtag> { pub fn to_activity(&self) -> Result<Hashtag> {
let mut ht = Hashtag::default(); let mut ht = Hashtag::default();
ht.set_href_string(ap_url(&format!( ht.set_href_string(ap_url(&format!(
"{}/tag/{}", "{}/tag/{}",
Instance::get_local(conn)?.public_domain, Instance::get_local()?.public_domain,
self.tag self.tag
)))?; )))?;
ht.set_name_string(self.tag.clone())?; ht.set_name_string(self.tag.clone())?;
@ -54,11 +54,11 @@ impl Tag {
) )
} }
pub fn build_activity(conn: &Connection, tag: String) -> Result<Hashtag> { pub fn build_activity(tag: String) -> Result<Hashtag> {
let mut ht = Hashtag::default(); let mut ht = Hashtag::default();
ht.set_href_string(ap_url(&format!( ht.set_href_string(ap_url(&format!(
"{}/tag/{}", "{}/tag/{}",
Instance::get_local(conn)?.public_domain, Instance::get_local()?.public_domain,
tag tag
)))?; )))?;
ht.set_name_string(tag)?; ht.set_name_string(tag)?;

View File

@ -228,7 +228,7 @@ impl User {
pub fn count_local(conn: &Connection) -> Result<i64> { pub fn count_local(conn: &Connection) -> Result<i64> {
users::table users::table
.filter(users::instance_id.eq(Instance::get_local(conn)?.id)) .filter(users::instance_id.eq(Instance::get_local()?.id))
.count() .count()
.get_result(conn) .get_result(conn)
.map_err(Error::from) .map_err(Error::from)
@ -353,7 +353,7 @@ impl User {
pub fn get_local_page(conn: &Connection, (min, max): (i32, i32)) -> Result<Vec<User>> { pub fn get_local_page(conn: &Connection, (min, max): (i32, i32)) -> Result<Vec<User>> {
users::table users::table
.filter(users::instance_id.eq(Instance::get_local(conn)?.id)) .filter(users::instance_id.eq(Instance::get_local()?.id))
.order(users::username.asc()) .order(users::username.asc())
.offset(min.into()) .offset(min.into())
.limit((max - min).into()) .limit((max - min).into())
@ -634,7 +634,7 @@ impl User {
let mut avatar = Image::default(); let mut avatar = Image::default();
avatar.object_props.set_url_string( avatar.object_props.set_url_string(
self.avatar_id self.avatar_id
.and_then(|id| Media::get(conn, id).and_then(|m| m.url(conn)).ok()) .and_then(|id| Media::get(conn, id).and_then(|m| m.url()).ok())
.unwrap_or_default(), .unwrap_or_default(),
)?; )?;
actor.object_props.set_icon_object(avatar)?; actor.object_props.set_icon_object(avatar)?;
@ -667,7 +667,7 @@ impl User {
pub fn avatar_url(&self, conn: &Connection) -> String { pub fn avatar_url(&self, conn: &Connection) -> String {
self.avatar_id self.avatar_id
.and_then(|id| Media::get(conn, id).and_then(|m| m.url(conn)).ok()) .and_then(|id| Media::get(conn, id).and_then(|m| m.url()).ok())
.unwrap_or_else(|| "/static/default-avatar.png".to_string()) .unwrap_or_else(|| "/static/default-avatar.png".to_string())
} }
@ -861,7 +861,9 @@ impl AsActor<&PlumeRocket> for User {
} }
fn is_local(&self) -> bool { fn is_local(&self) -> bool {
self.instance_id == 1 Instance::get_local()
.map(|i| self.instance_id == i.id)
.unwrap_or(false)
} }
} }
@ -934,7 +936,7 @@ impl NewUser {
summary_html: SafeString::new(&utils::md_to_html(&summary, None, false, None).0), summary_html: SafeString::new(&utils::md_to_html(&summary, None, false, None).0),
email: Some(email), email: Some(email),
hashed_password: Some(password), hashed_password: Some(password),
instance_id: Instance::get_local(conn)?.id, instance_id: Instance::get_local()?.id,
ap_url: String::new(), ap_url: String::new(),
public_key: String::from_utf8(pub_key).or(Err(Error::Signature))?, public_key: String::from_utf8(pub_key).or(Err(Error::Signature))?,
private_key: Some(String::from_utf8(priv_key).or(Err(Error::Signature))?), private_key: Some(String::from_utf8(priv_key).or(Err(Error::Signature))?),
@ -1007,7 +1009,7 @@ pub(crate) mod tests {
assert_eq!( assert_eq!(
test_user.id, test_user.id,
User::find_by_name(conn, "test", Instance::get_local(conn).unwrap().id) User::find_by_name(conn, "test", Instance::get_local().unwrap().id)
.unwrap() .unwrap()
.id .id
); );
@ -1025,7 +1027,7 @@ pub(crate) mod tests {
conn, conn,
&format!( &format!(
"https://{}/@/{}/", "https://{}/@/{}/",
Instance::get_local(conn).unwrap().public_domain, Instance::get_local().unwrap().public_domain,
"test" "test"
) )
) )
@ -1056,7 +1058,7 @@ pub(crate) mod tests {
let conn = &db(); let conn = &db();
conn.test_transaction::<_, (), _>(|| { conn.test_transaction::<_, (), _>(|| {
let inserted = fill_database(conn); let inserted = fill_database(conn);
let local_inst = Instance::get_local(conn).unwrap(); let local_inst = Instance::get_local().unwrap();
let mut i = 0; let mut i = 0;
while local_inst.has_admin(conn).unwrap() { while local_inst.has_admin(conn).unwrap() {
assert!(i < 100); //prevent from looping indefinitelly assert!(i < 100); //prevent from looping indefinitelly

View File

@ -114,7 +114,7 @@ pub fn create(
NaiveDateTime::parse_from_str(format!("{} 00:00:00", d).as_ref(), "%Y-%m-%d %H:%M:%S").ok() NaiveDateTime::parse_from_str(format!("{} 00:00:00", d).as_ref(), "%Y-%m-%d %H:%M:%S").ok()
}); });
let domain = &Instance::get_local(conn)?.public_domain; let domain = &Instance::get_local()?.public_domain;
let (content, mentions, hashtags) = md_to_html( let (content, mentions, hashtags) = md_to_html(
&payload.source, &payload.source,
Some(domain), Some(domain),
@ -144,7 +144,7 @@ pub fn create(
content: SafeString::new(content.as_ref()), content: SafeString::new(content.as_ref()),
published: payload.published.unwrap_or(true), published: payload.published.unwrap_or(true),
license: payload.license.clone().unwrap_or_else(|| { license: payload.license.clone().unwrap_or_else(|| {
Instance::get_local(conn) Instance::get_local()
.map(|i| i.default_license) .map(|i| i.default_license)
.unwrap_or_else(|_| String::from("CC-BY-SA")) .unwrap_or_else(|_| String::from("CC-BY-SA"))
}), }),

View File

@ -41,6 +41,7 @@ extern crate webfinger;
use diesel::r2d2::ConnectionManager; use diesel::r2d2::ConnectionManager;
use plume_models::{ use plume_models::{
db_conn::{DbPool, PragmaForeignKey}, db_conn::{DbPool, PragmaForeignKey},
instance::Instance,
migrations::IMPORTED_MIGRATIONS, migrations::IMPORTED_MIGRATIONS,
search::{Searcher as UnmanagedSearcher, SearcherError}, search::{Searcher as UnmanagedSearcher, SearcherError},
Connection, Error, CONFIG, Connection, Error, CONFIG,
@ -73,10 +74,12 @@ fn init_pool() -> Option<DbPool> {
dotenv::dotenv().ok(); dotenv::dotenv().ok();
let manager = ConnectionManager::<Connection>::new(CONFIG.database_url.as_str()); let manager = ConnectionManager::<Connection>::new(CONFIG.database_url.as_str());
DbPool::builder() let pool = DbPool::builder()
.connection_customizer(Box::new(PragmaForeignKey)) .connection_customizer(Box::new(PragmaForeignKey))
.build(manager) .build(manager)
.ok() .ok()?;
Instance::cache_local(&pool.get().unwrap());
Some(pool)
} }
fn main() { fn main() {

View File

@ -118,7 +118,7 @@ pub fn create(
slug.clone(), slug.clone(),
form.title.to_string(), form.title.to_string(),
String::from(""), String::from(""),
Instance::get_local(&*conn) Instance::get_local()
.expect("blog::create: instance error") .expect("blog::create: instance error")
.id, .id,
) )
@ -348,7 +348,7 @@ pub fn atom_feed(name: String, rockets: PlumeRocket) -> Option<Content<String>>
let conn = &*rockets.conn; let conn = &*rockets.conn;
let feed = FeedBuilder::default() let feed = FeedBuilder::default()
.title(blog.title.clone()) .title(blog.title.clone())
.id(Instance::get_local(&*conn) .id(Instance::get_local()
.ok()? .ok()?
.compute_box("~", &name, "atom.xml")) .compute_box("~", &name, "atom.xml"))
.entries( .entries(

View File

@ -43,7 +43,7 @@ pub fn create(
let (html, mentions, _hashtags) = utils::md_to_html( let (html, mentions, _hashtags) = utils::md_to_html(
form.content.as_ref(), form.content.as_ref(),
Some( Some(
&Instance::get_local(&conn) &Instance::get_local()
.expect("comments::create: local instance error") .expect("comments::create: local instance error")
.public_domain, .public_domain,
), ),

View File

@ -19,7 +19,7 @@ use template_utils::{IntoContext, Ructe};
#[get("/")] #[get("/")]
pub fn index(rockets: PlumeRocket) -> Result<Ructe, ErrorPage> { pub fn index(rockets: PlumeRocket) -> Result<Ructe, ErrorPage> {
let conn = &*rockets.conn; let conn = &*rockets.conn;
let inst = Instance::get_local(conn)?; let inst = Instance::get_local()?;
let federated = Post::get_recents_page(conn, Page::default().limits())?; let federated = Post::get_recents_page(conn, Page::default().limits())?;
let local = Post::get_instance_page(conn, inst.id, Page::default().limits())?; let local = Post::get_instance_page(conn, inst.id, Page::default().limits())?;
let user_feed = rockets.user.clone().and_then(|user| { let user_feed = rockets.user.clone().and_then(|user| {
@ -43,7 +43,7 @@ pub fn index(rockets: PlumeRocket) -> Result<Ructe, ErrorPage> {
#[get("/local?<page>")] #[get("/local?<page>")]
pub fn local(page: Option<Page>, rockets: PlumeRocket) -> Result<Ructe, ErrorPage> { pub fn local(page: Option<Page>, rockets: PlumeRocket) -> Result<Ructe, ErrorPage> {
let page = page.unwrap_or_default(); let page = page.unwrap_or_default();
let instance = Instance::get_local(&*rockets.conn)?; let instance = Instance::get_local()?;
let articles = Post::get_instance_page(&*rockets.conn, instance.id, page.limits())?; let articles = Post::get_instance_page(&*rockets.conn, instance.id, page.limits())?;
Ok(render!(instance::local( Ok(render!(instance::local(
&rockets.to_context(), &rockets.to_context(),
@ -83,7 +83,7 @@ pub fn federated(page: Option<Page>, rockets: PlumeRocket) -> Result<Ructe, Erro
#[get("/admin")] #[get("/admin")]
pub fn admin(_admin: Admin, rockets: PlumeRocket) -> Result<Ructe, ErrorPage> { pub fn admin(_admin: Admin, rockets: PlumeRocket) -> Result<Ructe, ErrorPage> {
let local_inst = Instance::get_local(&*rockets.conn)?; let local_inst = Instance::get_local()?;
Ok(render!(instance::admin( Ok(render!(instance::admin(
&rockets.to_context(), &rockets.to_context(),
local_inst.clone(), local_inst.clone(),
@ -119,7 +119,7 @@ pub fn update_settings(
form.validate() form.validate()
.and_then(|_| { .and_then(|_| {
let instance = let instance =
Instance::get_local(conn).expect("instance::update_settings: local instance error"); Instance::get_local().expect("instance::update_settings: local instance error");
instance instance
.update( .update(
conn, conn,
@ -136,7 +136,7 @@ pub fn update_settings(
}) })
.or_else(|e| { .or_else(|e| {
let local_inst = let local_inst =
Instance::get_local(conn).expect("instance::update_settings: local instance error"); Instance::get_local().expect("instance::update_settings: local instance error");
Err(render!(instance::admin( Err(render!(instance::admin(
&rockets.to_context(), &rockets.to_context(),
local_inst, local_inst,
@ -156,7 +156,7 @@ pub fn admin_instances(
let instances = Instance::page(&*rockets.conn, page.limits())?; let instances = Instance::page(&*rockets.conn, page.limits())?;
Ok(render!(instance::list( Ok(render!(instance::list(
&rockets.to_context(), &rockets.to_context(),
Instance::get_local(&*rockets.conn)?, Instance::get_local()?,
instances, instances,
page.0, page.0,
Page::total(Instance::count(&*rockets.conn)? as i32) Page::total(Instance::count(&*rockets.conn)? as i32)
@ -204,7 +204,7 @@ pub fn ban(_admin: Admin, id: i32, rockets: PlumeRocket) -> Result<Flash<Redirec
let u = User::get(&*rockets.conn, id)?; let u = User::get(&*rockets.conn, id)?;
u.delete(&*rockets.conn, &rockets.searcher)?; u.delete(&*rockets.conn, &rockets.searcher)?;
if Instance::get_local(&*rockets.conn) if Instance::get_local()
.map(|i| u.instance_id == i.id) .map(|i| u.instance_id == i.id)
.unwrap_or(false) .unwrap_or(false)
{ {
@ -267,7 +267,7 @@ pub fn nodeinfo(conn: DbConn, version: String) -> Result<Json<serde_json::Value>
return Err(ErrorPage::from(Error::NotFound)); return Err(ErrorPage::from(Error::NotFound));
} }
let local_inst = Instance::get_local(&*conn)?; let local_inst = Instance::get_local()?;
let mut doc = json!({ let mut doc = json!({
"version": version, "version": version,
"software": { "software": {
@ -305,8 +305,8 @@ pub fn about(rockets: PlumeRocket) -> Result<Ructe, ErrorPage> {
let conn = &*rockets.conn; let conn = &*rockets.conn;
Ok(render!(instance::about( Ok(render!(instance::about(
&rockets.to_context(), &rockets.to_context(),
Instance::get_local(conn)?, Instance::get_local()?,
Instance::get_local(conn)?.main_admin(conn)?, Instance::get_local()?.main_admin(conn)?,
User::count_local(conn)?, User::count_local(conn)?,
Post::count_local(conn)?, Post::count_local(conn)?,
Instance::count(conn)? - 1 Instance::count(conn)? - 1
@ -314,8 +314,8 @@ pub fn about(rockets: PlumeRocket) -> Result<Ructe, ErrorPage> {
} }
#[get("/manifest.json")] #[get("/manifest.json")]
pub fn web_manifest(conn: DbConn) -> Result<Json<serde_json::Value>, ErrorPage> { pub fn web_manifest() -> Result<Json<serde_json::Value>, ErrorPage> {
let instance = Instance::get_local(&*conn)?; let instance = Instance::get_local()?;
Ok(Json(json!({ Ok(Json(json!({
"name": &instance.name, "name": &instance.name,
"description": &instance.short_description, "description": &instance.short_description,

View File

@ -147,7 +147,7 @@ pub fn new(blog: String, cl: ContentLen, rockets: PlumeRocket) -> Result<Ructe,
b, b,
false, false,
&NewPostForm { &NewPostForm {
license: Instance::get_local(&*conn)?.default_license, license: Instance::get_local()?.default_license,
..NewPostForm::default() ..NewPostForm::default()
}, },
true, true,
@ -263,7 +263,7 @@ pub fn update(
let (content, mentions, hashtags) = utils::md_to_html( let (content, mentions, hashtags) = utils::md_to_html(
form.content.to_string().as_ref(), form.content.to_string().as_ref(),
Some( Some(
&Instance::get_local(&conn) &Instance::get_local()
.expect("posts::update: Error getting local instance") .expect("posts::update: Error getting local instance")
.public_domain, .public_domain,
), ),
@ -314,7 +314,7 @@ pub fn update(
.filter(|t| !t.is_empty()) .filter(|t| !t.is_empty())
.collect::<HashSet<_>>() .collect::<HashSet<_>>()
.into_iter() .into_iter()
.filter_map(|t| Tag::build_activity(&conn, t).ok()) .filter_map(|t| Tag::build_activity(t).ok())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
post.update_tags(&conn, tags) post.update_tags(&conn, tags)
.expect("post::update: tags error"); .expect("post::update: tags error");
@ -324,7 +324,7 @@ pub fn update(
.map(|h| h.to_camel_case()) .map(|h| h.to_camel_case())
.collect::<HashSet<_>>() .collect::<HashSet<_>>()
.into_iter() .into_iter()
.filter_map(|t| Tag::build_activity(&conn, t).ok()) .filter_map(|t| Tag::build_activity(t).ok())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
post.update_hashtags(&conn, hashtags) post.update_hashtags(&conn, hashtags)
.expect("post::update: hashtags error"); .expect("post::update: hashtags error");
@ -435,7 +435,7 @@ pub fn create(
let (content, mentions, hashtags) = utils::md_to_html( let (content, mentions, hashtags) = utils::md_to_html(
form.content.to_string().as_ref(), form.content.to_string().as_ref(),
Some( Some(
&Instance::get_local(&conn) &Instance::get_local()
.expect("post::create: local instance error") .expect("post::create: local instance error")
.public_domain, .public_domain,
), ),

View File

@ -109,7 +109,7 @@ pub fn details(
.clone() .clone()
.and_then(|x| x.is_following(&*conn, user.id).ok()) .and_then(|x| x.is_following(&*conn, user.id).ok())
.unwrap_or(false), .unwrap_or(false),
user.instance_id != Instance::get_local(&*conn)?.id, user.instance_id != Instance::get_local()?.id,
user.get_instance(&*conn)?.public_domain, user.get_instance(&*conn)?.public_domain,
recents, recents,
reshares reshares
@ -278,7 +278,7 @@ pub fn followers(
.clone() .clone()
.and_then(|x| x.is_following(&*conn, user.id).ok()) .and_then(|x| x.is_following(&*conn, user.id).ok())
.unwrap_or(false), .unwrap_or(false),
user.instance_id != Instance::get_local(&*conn)?.id, user.instance_id != Instance::get_local()?.id,
user.get_instance(&*conn)?.public_domain, user.get_instance(&*conn)?.public_domain,
user.get_followers_page(&*conn, page.limits())?, user.get_followers_page(&*conn, page.limits())?,
page.0, page.0,
@ -305,7 +305,7 @@ pub fn followed(
.clone() .clone()
.and_then(|x| x.is_following(conn, user.id).ok()) .and_then(|x| x.is_following(conn, user.id).ok())
.unwrap_or(false), .unwrap_or(false),
user.instance_id != Instance::get_local(conn)?.id, user.instance_id != Instance::get_local()?.id,
user.get_instance(conn)?.public_domain, user.get_instance(conn)?.public_domain,
user.get_followed_page(conn, page.limits())?, user.get_followed_page(conn, page.limits())?,
page.0, page.0,
@ -327,7 +327,7 @@ pub fn activity_details(
pub fn new(rockets: PlumeRocket) -> Result<Ructe, ErrorPage> { pub fn new(rockets: PlumeRocket) -> Result<Ructe, ErrorPage> {
Ok(render!(users::new( Ok(render!(users::new(
&rockets.to_context(), &rockets.to_context(),
Instance::get_local(&*rockets.conn)?.open_registrations, Instance::get_local()?.open_registrations,
&NewUserForm::default(), &NewUserForm::default(),
ValidationErrors::default() ValidationErrors::default()
))) )))
@ -494,7 +494,7 @@ pub fn create(
rockets: PlumeRocket, rockets: PlumeRocket,
) -> Result<Flash<Redirect>, Ructe> { ) -> Result<Flash<Redirect>, Ructe> {
let conn = &*rockets.conn; let conn = &*rockets.conn;
if !Instance::get_local(conn) if !Instance::get_local()
.map(|i| i.open_registrations) .map(|i| i.open_registrations)
.unwrap_or(true) .unwrap_or(true)
{ {
@ -533,7 +533,7 @@ pub fn create(
.map_err(|err| { .map_err(|err| {
render!(users::new( render!(users::new(
&rockets.to_context(), &rockets.to_context(),
Instance::get_local(conn) Instance::get_local()
.map(|i| i.open_registrations) .map(|i| i.open_registrations)
.unwrap_or(true), .unwrap_or(true),
&form, &form,
@ -590,7 +590,7 @@ pub fn atom_feed(name: String, rockets: PlumeRocket) -> Option<Content<String>>
let author = User::find_by_fqn(&rockets, &name).ok()?; let author = User::find_by_fqn(&rockets, &name).ok()?;
let feed = FeedBuilder::default() let feed = FeedBuilder::default()
.title(author.display_name.clone()) .title(author.display_name.clone())
.id(Instance::get_local(conn) .id(Instance::get_local()
.unwrap() .unwrap()
.compute_box("@", &name, "atom.xml")) .compute_box("@", &name, "atom.xml"))
.entries( .entries(

View File

@ -13,7 +13,7 @@
<meta content="120" property="og:image:width" /> <meta content="120" property="og:image:width" />
<meta content="120" property="og:image:height" /> <meta content="120" property="og:image:height" />
<meta content="summary" property="twitter:card" /> <meta content="summary" property="twitter:card" />
<meta content="'@Instance::get_local(ctx.0).unwrap().name" property="og:site_name" /> <meta content="'@Instance::get_local().unwrap().name" property="og:site_name" />
<meta content="@blog.ap_url" property="og:url" /> <meta content="@blog.ap_url" property="og:url" />
<meta content="@blog.fqn" property="profile:username" /> <meta content="@blog.fqn" property="profile:username" />
<meta content="@blog.title" property="og:title" /> <meta content="@blog.title" property="og:title" />
@ -21,7 +21,7 @@
<meta content="@blog.summary_html" property="og:description" /> <meta content="@blog.summary_html" property="og:description" />
<meta content="@blog.icon_url(ctx.0)" property="og:image" /> <meta content="@blog.icon_url(ctx.0)" property="og:image" />
<link href='@Instance::get_local(ctx.0).unwrap().compute_box("~", &blog.fqn, "atom.xml")' rel='alternate' type='application/atom+xml'> <link href='@Instance::get_local().unwrap().compute_box("~", &blog.fqn, "atom.xml")' rel='alternate' type='application/atom+xml'>
<link href='@blog.ap_url' rel='alternate' type='application/activity+json'> <link href='@blog.ap_url' rel='alternate' type='application/activity+json'>
}, { }, {
<a href="@uri!(blogs::details: name = &blog.fqn, page = _)">@blog.title</a> <a href="@uri!(blogs::details: name = &blog.fqn, page = _)">@blog.title</a>

View File

@ -14,7 +14,7 @@
<section> <section>
<figure class="media"> <figure class="media">
@Html(media.html(ctx.0).unwrap_or_else(|_| SafeString::new(""))) @Html(media.html().unwrap_or_else(|_| SafeString::new("")))
<figcaption>@media.alt_text</figcaption> <figcaption>@media.alt_text</figcaption>
</figure> </figure>
<div> <div>
@ -22,7 +22,7 @@
@i18n!(ctx.1, "Markdown syntax") @i18n!(ctx.1, "Markdown syntax")
<small>@i18n!(ctx.1, "Copy it into your articles, to insert this media:")</small> <small>@i18n!(ctx.1, "Copy it into your articles, to insert this media:")</small>
</p> </p>
<code>@media.markdown(ctx.0).unwrap_or_else(|_| SafeString::new(""))</code> <code>@media.markdown().unwrap_or_else(|_| SafeString::new(""))</code>
</div> </div>
<div> <div>
@if media.category() == MediaCategory::Image { @if media.category() == MediaCategory::Image {

View File

@ -20,7 +20,7 @@
<div class="card"> <div class="card">
<div class="cover media-preview @media.category().to_string()" <div class="cover media-preview @media.category().to_string()"
@if media.category() == MediaCategory::Image { @if media.category() == MediaCategory::Image {
style="background-image: url('@media.url(ctx.0).unwrap_or_default()')" style="background-image: url('@media.url().unwrap_or_default()')"
} }
></div> ></div>
<main> <main>

View File

@ -12,7 +12,7 @@
<meta content="120" property="og:image:width" /> <meta content="120" property="og:image:width" />
<meta content="120" property="og:image:height" /> <meta content="120" property="og:image:height" />
<meta content="summary" property="twitter:card" /> <meta content="summary" property="twitter:card" />
<meta content="'@Instance::get_local(ctx.0).unwrap().name" property="og:site_name" /> <meta content="'@Instance::get_local().unwrap().name" property="og:site_name" />
<meta content="@user.ap_url" property="og:url" /> <meta content="@user.ap_url" property="og:url" />
<meta content="@user.display_name" property="profile:username" /> <meta content="@user.display_name" property="profile:username" />
<meta content="@user.display_name's Blog" property="og:title" /> <meta content="@user.display_name's Blog" property="og:title" />
@ -20,7 +20,7 @@
<meta content="@user.summary_html" property="og:description" /> <meta content="@user.summary_html" property="og:description" />
<meta content="@user.avatar_url(ctx.0)" property="og:image" /> <meta content="@user.avatar_url(ctx.0)" property="og:image" />
<link href='@Instance::get_local(ctx.0).unwrap().compute_box("@", &user.fqn, "atom.xml")' rel='alternate' type='application/atom+xml'> <link href='@Instance::get_local().unwrap().compute_box("@", &user.fqn, "atom.xml")' rel='alternate' type='application/atom+xml'>
<link href='@user.ap_url' rel='alternate' type='application/activity+json'> <link href='@user.ap_url' rel='alternate' type='application/activity+json'>
}, {}, { }, {}, {
@:header(ctx, &user, follows, is_remote, remote_url) @:header(ctx, &user, follows, is_remote, remote_url)