diff --git a/.circleci/config.yml b/.circleci/config.yml index e4bc7386..c7aae109 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -143,6 +143,7 @@ jobs: cache: <<#parameters.postgres>>postgres<><<^parameters.postgres>>sqlite<> - run_with_coverage: cmd: | + cargo run -p plume-cli --no-default-features --features=${FEATURES} -- migration run cmd="cargo test --all --exclude plume-front --exclude plume-macro --no-run --no-default-features --features=${FEATURES} -j" for i in 36 4 2 1 1; do $cmd $i && break diff --git a/CHANGELOG.md b/CHANGELOG.md index 11dbbeb3..c220aa80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - Allow `dir` attributes for LtoR text in RtoL document (#860) - More translation languages (#862) - Proxy support (#829) +- Riker a actor system library (#870) ### Changed @@ -16,6 +17,7 @@ - Use tracing crate (#868) - Update Rust version to nightly-2021-01-15 (#878) - Upgrade Tantivy to 0.13.3 and lindera-tantivy to 0.7.1 (#878) +- Run searcher on actor system (#870) ### Fixed diff --git a/Cargo.lock b/Cargo.lock index c38aa831..6a22928a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9,7 +9,7 @@ dependencies = [ "activitystreams-derive", "activitystreams-traits", "activitystreams-types", - "serde", + "serde 1.0.118", "serde_derive", "serde_json", ] @@ -32,7 +32,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "670ef03168e704b0cae242e7a5d8b40506772b339687e01a3496fc4afe2e8542" dependencies = [ "failure", - "serde", + "serde 1.0.118", "serde_json", ] @@ -46,7 +46,7 @@ dependencies = [ "activitystreams-traits", "chrono", "mime 0.3.16", - "serde", + "serde 1.0.118", "serde_derive", "serde_json", ] @@ -126,6 +126,9 @@ name = "ahash" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8fd72866655d1904d6b0997d0b07ba561047d070fbe29de039031c641b61217" +dependencies = [ + "const-random", +] [[package]] name = "aho-corasick" @@ -168,6 +171,12 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "arc-swap" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dabe5a181f83789739c194cbe5a897dde195078fac08568d09221fd6137a7ba8" + [[package]] name = "array_tool" version = "1.0.3" @@ -344,7 +353,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f30d3a39baa26f9651f17b375061f3233dde33424a8b72b0dbe93a68a0bc896d" dependencies = [ "byteorder 1.3.4", - "serde", + "serde 1.0.118", ] [[package]] @@ -516,8 +525,8 @@ checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" dependencies = [ "libc", "num-integer", - "num-traits", - "serde", + "num-traits 0.2.14", + "serde 1.0.118", "time", "winapi 0.3.9", ] @@ -555,6 +564,44 @@ dependencies = [ "memchr", ] +[[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", + "rust-ini", + "serde 1.0.118", + "serde-hjson", + "serde_json", + "toml 0.5.8", + "yaml-rust", +] + +[[package]] +name = "const-random" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f590d95d011aa80b063ffe3253422ed5aa462af4e9867d43ce8337562bac77c4" +dependencies = [ + "const-random-macro", + "proc-macro-hack 0.5.19", +] + +[[package]] +name = "const-random-macro" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "615f6e27d000a2bffbc7f2f6a8669179378fa27ee4d0a509e985dfc0a7defb40" +dependencies = [ + "getrandom 0.2.1", + "lazy_static", + "proc-macro-hack 0.5.19", + "tiny-keccak", +] + [[package]] name = "const_fn" version = "0.4.4" @@ -607,7 +654,7 @@ dependencies = [ "idna 0.1.5", "log 0.4.11", "publicsuffix", - "serde", + "serde 1.0.118", "serde_json", "time", "try_from", @@ -789,6 +836,17 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9" +[[package]] +name = "dashmap" +version = "3.11.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f260e2fc850179ef410018660006951c1b55b79e8087e87111a2c388994b9b5" +dependencies = [ + "ahash", + "cfg-if 0.1.10", + "num_cpus", +] + [[package]] name = "data-encoding" version = "2.1.2" @@ -1370,6 +1428,17 @@ dependencies = [ "wasi 0.9.0+wasi-snapshot-preview1", ] +[[package]] +name = "getrandom" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4060f4657be78b8e766215b02b18a2e862d83745545de804638e2b545e81aee6" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", +] + [[package]] name = "gettext" version = "0.3.0" @@ -1943,7 +2012,7 @@ dependencies = [ "log 0.4.11", "native-tls", "nom 4.2.3", - "serde", + "serde 1.0.118", "serde_derive", "serde_json", ] @@ -2010,7 +2079,7 @@ dependencies = [ "lindera-dictionary", "lindera-ipadic", "lindera-ipadic-builder", - "serde", + "serde 1.0.118", "serde_json", ] @@ -2023,7 +2092,7 @@ dependencies = [ "bincode", "byteorder 1.3.4", "encoding", - "serde", + "serde 1.0.118", "yada", ] @@ -2091,9 +2160,13 @@ dependencies = [ [[package]] name = "linked-hash-map" -version = "0.5.3" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a" +checksum = "6d262045c5b87c0861b3f004610afd0e2c851e2908d08b6c870cbb9d5f494ecd" +dependencies = [ + "serde 0.8.23", + "serde_test", +] [[package]] name = "lock_api" @@ -2152,7 +2225,7 @@ dependencies = [ "log 0.4.11", "phf", "phf_codegen", - "serde", + "serde 1.0.118", "serde_derive", "serde_json", "string_cache", @@ -2504,7 +2577,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" dependencies = [ "autocfg 1.0.1", - "num-traits", + "num-traits 0.2.14", ] [[package]] @@ -2515,7 +2588,16 @@ checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" dependencies = [ "autocfg 1.0.1", "num-integer", - "num-traits", + "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", ] [[package]] @@ -2826,7 +2908,7 @@ dependencies = [ "chrono", "indexmap", "line-wrap", - "serde", + "serde 1.0.118", "xml-rs", ] @@ -2854,6 +2936,7 @@ dependencies = [ "plume-api", "plume-common", "plume-models", + "riker", "rocket", "rocket_contrib", "rocket_csrf", @@ -2862,7 +2945,7 @@ dependencies = [ "rsass", "ructe", "scheduled-thread-pool", - "serde", + "serde 1.0.118", "serde_json", "shrinkwraprs 0.2.3", "tracing", @@ -2876,7 +2959,7 @@ dependencies = [ name = "plume-api" version = "0.6.1-dev" dependencies = [ - "serde", + "serde 1.0.118", "serde_derive", ] @@ -2909,7 +2992,7 @@ dependencies = [ "regex-syntax 0.6.21", "reqwest 0.9.24", "rocket", - "serde", + "serde 1.0.118", "serde_derive", "serde_json", "shrinkwraprs 0.3.0", @@ -2926,7 +3009,7 @@ dependencies = [ "gettext-macros", "gettext-utils", "lazy_static", - "serde", + "serde 1.0.118", "serde_json", "stdweb", "stdweb-internal-runtime", @@ -2961,15 +3044,17 @@ dependencies = [ "ldap3", "lindera-tantivy", "migrations_internals", + "once_cell", "openssl", "plume-api", "plume-common", "plume-macro", "reqwest 0.9.24", + "riker", "rocket", "rocket_i18n", "scheduled-thread-pool", - "serde", + "serde 1.0.118", "serde_derive", "serde_json", "shrinkwraprs 0.2.3", @@ -3220,7 +3305,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom", + "getrandom 0.1.15", "libc", "rand_chacha 0.2.2", "rand_core 0.5.1", @@ -3268,7 +3353,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom", + "getrandom 0.1.15", ] [[package]] @@ -3445,7 +3530,7 @@ dependencies = [ "mime 0.3.16", "mime_guess 2.0.3", "native-tls", - "serde", + "serde 1.0.118", "serde_json", "serde_urlencoded 0.5.5", "socks", @@ -3484,7 +3569,7 @@ dependencies = [ "native-tls", "percent-encoding 2.1.0", "pin-project-lite 0.2.0", - "serde", + "serde 1.0.118", "serde_urlencoded 0.7.0", "tokio 0.2.24", "tokio-tls", @@ -3495,6 +3580,38 @@ dependencies = [ "winreg 0.7.0", ] +[[package]] +name = "riker" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abff93ece5a5d3d7f2c54dfba7550657a644c9dc0a871c7ddf8c31381971c41b" +dependencies = [ + "chrono", + "config", + "dashmap", + "futures 0.3.8", + "num_cpus", + "pin-utils", + "rand 0.7.3", + "regex", + "riker-macros", + "slog", + "slog-scope", + "slog-stdlog", + "uuid 0.8.1", +] + +[[package]] +name = "riker-macros" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2a8e8f71c9e7980a596c39c7e3537ea8563054526e15712a610ac97a02dba15" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "syn 0.15.44", +] + [[package]] name = "ring" version = "0.13.5" @@ -3523,7 +3640,7 @@ dependencies = [ "rocket_http", "state", "time", - "toml", + "toml 0.4.10", "version_check 0.9.2", "yansi", ] @@ -3552,7 +3669,7 @@ dependencies = [ "log 0.4.11", "notify", "rocket", - "serde", + "serde 1.0.118", "serde_json", ] @@ -3564,7 +3681,7 @@ dependencies = [ "data-encoding", "ring", "rocket", - "serde", + "serde 1.0.118", "time", ] @@ -3623,7 +3740,7 @@ dependencies = [ "lazy_static", "nom 4.2.3", "num-rational", - "num-traits", + "num-traits 0.2.14", "rand 0.6.5", ] @@ -3640,13 +3757,19 @@ dependencies = [ "nom 5.1.2", ] +[[package]] +name = "rust-ini" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2" + [[package]] name = "rust-stemmers" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e46a2036019fdb888131db7a4c847a1063a7493f971ed94ea82c67eada63ca54" dependencies = [ - "serde", + "serde 1.0.118", "serde_derive", ] @@ -3749,6 +3872,12 @@ 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.118" @@ -3758,6 +3887,19 @@ 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", + "num-traits 0.1.43", + "regex", + "serde 0.8.23", +] + [[package]] name = "serde_derive" version = "1.0.118" @@ -3777,7 +3919,16 @@ checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a" dependencies = [ "itoa", "ryu", - "serde", + "serde 1.0.118", +] + +[[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", ] [[package]] @@ -3788,7 +3939,7 @@ checksum = "642dd69105886af2efd227f75a520ec9b44a820d65bc133a9131f7d229fd165a" dependencies = [ "dtoa", "itoa", - "serde", + "serde 1.0.118", "url 1.7.2", ] @@ -3801,7 +3952,7 @@ dependencies = [ "form_urlencoded", "itoa", "ryu", - "serde", + "serde 1.0.118", ] [[package]] @@ -3878,6 +4029,34 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" +[[package]] +name = "slog" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8347046d4ebd943127157b94d63abb990fcf729dc4e9978927fdf4ac3c998d06" + +[[package]] +name = "slog-scope" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c44c89dd8b0ae4537d1ae318353eaf7840b4869c536e31c41e963d1ea523ee6" +dependencies = [ + "arc-swap", + "lazy_static", + "slog", +] + +[[package]] +name = "slog-stdlog" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8228ab7302adbf4fcb37e66f3cda78003feb521e7fd9e3847ec117a7784d0f5a" +dependencies = [ + "log 0.4.11", + "slog", + "slog-scope", +] + [[package]] name = "smallvec" version = "0.6.13" @@ -3948,7 +4127,7 @@ checksum = "a68c0ce28cf7400ed022e18da3c4591e14e1df02c70e93573cc59921b3923aeb" dependencies = [ "discard", "rustc_version", - "serde", + "serde 1.0.118", "serde_json", "stdweb-derive", "stdweb-internal-macros", @@ -3964,7 +4143,7 @@ checksum = "0e21ebd9179de08f2300a65454268a17ea3de204627458588c84319c4def3930" dependencies = [ "proc-macro2 0.4.30", "quote 0.6.13", - "serde", + "serde 1.0.118", "serde_derive", "syn 0.15.44", ] @@ -3978,7 +4157,7 @@ dependencies = [ "base-x", "proc-macro2 0.4.30", "quote 0.6.13", - "serde", + "serde 1.0.118", "serde_derive", "serde_json", "sha1", @@ -4010,7 +4189,7 @@ dependencies = [ "new_debug_unreachable", "phf_shared", "precomputed-hash", - "serde", + "serde 1.0.118", "string_cache_codegen", "string_cache_shared", ] @@ -4154,7 +4333,7 @@ dependencies = [ "onig", "plist", "regex-syntax 0.6.21", - "serde", + "serde 1.0.118", "serde_derive", "serde_json", "walkdir", @@ -4194,7 +4373,7 @@ dependencies = [ "rayon", "regex", "rust-stemmers", - "serde", + "serde 1.0.118", "serde_json", "smallvec 1.5.1", "snap", @@ -4322,6 +4501,15 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tinyvec" version = "1.1.0" @@ -4605,7 +4793,16 @@ version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" dependencies = [ - "serde", + "serde 1.0.118", +] + +[[package]] +name = "toml" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +dependencies = [ + "serde 1.0.118", ] [[package]] @@ -4674,7 +4871,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb65ea441fbb84f9f6748fd496cf7f63ec9af5bca94dd86456978d055e8eb28b" dependencies = [ - "serde", + "serde 1.0.118", "tracing-core", ] @@ -4689,7 +4886,7 @@ dependencies = [ "lazy_static", "matchers", "regex", - "serde", + "serde 1.0.118", "serde_json", "sharded-slab", "smallvec 1.5.1", @@ -4875,7 +5072,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fde2f6a4bea1d6e007c4ad38c6839fa71cbb63b6dbf5b595aa38dc9b1093c11" dependencies = [ "rand 0.7.3", - "serde", + "serde 1.0.118", ] [[package]] @@ -4887,7 +5084,7 @@ dependencies = [ "idna 0.1.5", "lazy_static", "regex", - "serde", + "serde 1.0.118", "serde_derive", "serde_json", "url 1.7.2", @@ -4989,7 +5186,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3cd364751395ca0f68cafb17666eee36b63077fb5ecd972bbcd74c90c4bf736e" dependencies = [ "cfg-if 1.0.0", - "serde", + "serde 1.0.118", "serde_json", "wasm-bindgen-macro", ] @@ -5067,7 +5264,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec24b1b0700d4b466d280228ed0f62274eedeaa80206820f071fdc8ed787b664" dependencies = [ "reqwest 0.9.24", - "serde", + "serde 1.0.118", "serde_derive", ] diff --git a/Cargo.toml b/Cargo.toml index cf8d5ee2..85cebb03 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,6 +32,7 @@ validator_derive = "0.8" webfinger = "0.4.1" tracing = "0.1.22" tracing-subscriber = "0.2.15" +riker = "0.4.2" [[bin]] name = "plume" diff --git a/plume-models/Cargo.toml b/plume-models/Cargo.toml index 7b1ef7c5..ec97f278 100644 --- a/plume-models/Cargo.toml +++ b/plume-models/Cargo.toml @@ -33,6 +33,8 @@ diesel-derive-newtype = "0.1.2" glob = "0.3.0" lindera-tantivy = { version = "0.7.1", optional = true } tracing = "0.1.22" +riker = "0.4.2" +once_cell = "1.5.2" [dependencies.chrono] features = ["serde"] diff --git a/plume-models/src/blogs.rs b/plume-models/src/blogs.rs index 8df4a9dc..cfc0624b 100644 --- a/plume-models/src/blogs.rs +++ b/plume-models/src/blogs.rs @@ -1,6 +1,6 @@ use crate::{ ap_url, instance::*, medias::Media, posts::Post, safe_string::SafeString, schema::blogs, - search::Searcher, users::User, Connection, Error, PlumeRocket, Result, CONFIG, ITEMS_PER_PAGE, + users::User, Connection, Error, PlumeRocket, Result, CONFIG, ITEMS_PER_PAGE, }; use activitypub::{ actor::Group, @@ -317,9 +317,9 @@ impl Blog { .and_then(|c| c.url().ok()) } - pub fn delete(&self, conn: &Connection, searcher: &Searcher) -> Result<()> { + pub fn delete(&self, conn: &Connection) -> Result<()> { for post in Post::get_for_blog(conn, &self)? { - post.delete(conn, searcher)?; + post.delete(conn)?; } diesel::delete(self) .execute(conn) @@ -497,10 +497,8 @@ pub(crate) mod tests { use super::*; use crate::{ blog_authors::*, - config::CONFIG, instance::tests as instance_tests, medias::NewMedia, - search::tests::get_searcher, tests::{db, rockets}, users::tests as usersTests, Connection as Conn, @@ -767,9 +765,7 @@ pub(crate) mod tests { conn.test_transaction::<_, (), _>(|| { let (_, blogs) = fill_database(conn); - blogs[0] - .delete(conn, &get_searcher(&CONFIG.search_tokenizers)) - .unwrap(); + blogs[0].delete(conn).unwrap(); assert!(Blog::get(conn, blogs[0].id).is_err()); Ok(()) }) @@ -779,7 +775,6 @@ pub(crate) mod tests { fn delete_via_user() { let conn = &db(); conn.test_transaction::<_, (), _>(|| { - let searcher = get_searcher(&CONFIG.search_tokenizers); let (user, _) = fill_database(conn); let b1 = Blog::insert( @@ -836,10 +831,10 @@ pub(crate) mod tests { ) .unwrap(); - user[0].delete(conn, &searcher).unwrap(); + user[0].delete(conn).unwrap(); assert!(Blog::get(conn, blog[0].id).is_ok()); assert!(Blog::get(conn, blog[1].id).is_err()); - user[1].delete(conn, &searcher).unwrap(); + user[1].delete(conn).unwrap(); assert!(Blog::get(conn, blog[0].id).is_err()); Ok(()) }) @@ -886,7 +881,7 @@ pub(crate) mod tests { let _: Blog = blogs[0].save_changes(conn).unwrap(); let ap_repr = blogs[0].to_activity(conn).unwrap(); - blogs[0].delete(conn, &*r.searcher).unwrap(); + blogs[0].delete(conn).unwrap(); let blog = Blog::from_activity(&r, ap_repr).unwrap(); assert_eq!(blog.actor_id, blogs[0].actor_id); diff --git a/plume-models/src/inbox.rs b/plume-models/src/inbox.rs index 72acba2a..751eb550 100644 --- a/plume-models/src/inbox.rs +++ b/plume-models/src/inbox.rs @@ -97,7 +97,6 @@ pub(crate) mod tests { source: String::new(), cover_id: None, }, - &rockets.searcher, ) .unwrap(); diff --git a/plume-models/src/lib.rs b/plume-models/src/lib.rs index be7cf4b6..5a751877 100755 --- a/plume-models/src/lib.rs +++ b/plume-models/src/lib.rs @@ -17,7 +17,10 @@ extern crate serde_json; #[macro_use] extern crate tantivy; +use once_cell::sync::Lazy; use plume_common::activity_pub::inbox::InboxError; +use posts::PostEvent; +use riker::actors::{channel, ActorSystem, ChannelRef, SystemBuilder}; #[cfg(not(any(feature = "sqlite", feature = "postgres")))] compile_error!("Either feature \"sqlite\" or \"postgres\" must be enabled for this crate."); @@ -30,6 +33,16 @@ pub type Connection = diesel::SqliteConnection; #[cfg(all(not(feature = "sqlite"), feature = "postgres"))] pub type Connection = diesel::PgConnection; +pub(crate) static ACTOR_SYS: Lazy = Lazy::new(|| { + SystemBuilder::new() + .name("plume") + .create() + .expect("Failed to create actor system") +}); + +pub(crate) static POST_CHAN: Lazy> = + Lazy::new(|| channel("post_events", &*ACTOR_SYS).expect("Failed to create post channel")); + /// All the possible errors that can be encoutered in this crate #[derive(Debug)] pub enum Error { diff --git a/plume-models/src/posts.rs b/plume-models/src/posts.rs index 4e368f58..fbb03261 100644 --- a/plume-models/src/posts.rs +++ b/plume-models/src/posts.rs @@ -1,7 +1,7 @@ use crate::{ ap_url, blogs::Blog, instance::Instance, medias::Media, mentions::Mention, post_authors::*, - safe_string::SafeString, schema::posts, search::Searcher, tags::*, timeline::*, users::User, - Connection, Error, PlumeRocket, Result, CONFIG, + safe_string::SafeString, schema::posts, tags::*, timeline::*, users::User, Connection, Error, + PlumeRocket, PostEvent::*, Result, CONFIG, POST_CHAN, }; use activitypub::{ activity::{Create, Delete, Update}, @@ -19,11 +19,13 @@ use plume_common::{ }, utils::md_to_html, }; +use riker::actors::{Publish, Tell}; use std::collections::HashSet; +use std::sync::Arc; pub type LicensedArticle = CustomObject; -#[derive(Queryable, Identifiable, Clone, AsChangeset)] +#[derive(Queryable, Identifiable, Clone, AsChangeset, Debug)] #[changeset_options(treat_none_as_null = "true")] pub struct Post { pub id: i32, @@ -62,7 +64,7 @@ impl Post { find_by!(posts, find_by_ap_url, ap_url as &str); last!(posts); - pub fn insert(conn: &Connection, new: NewPost, searcher: &Searcher) -> Result { + pub fn insert(conn: &Connection, new: NewPost) -> Result { diesel::insert_into(posts::table) .values(new) .execute(conn)?; @@ -77,23 +79,29 @@ impl Post { let _: Post = post.save_changes(conn)?; } - searcher.add_document(conn, &post)?; + if post.published { + post.publish_published(); + } + Ok(post) } - pub fn update(&self, conn: &Connection, searcher: &Searcher) -> Result { + pub fn update(&self, conn: &Connection) -> Result { diesel::update(self).set(self).execute(conn)?; let post = Self::get(conn, self.id)?; - searcher.update_document(conn, &post)?; + // TODO: Call publish_published() when newly published + if post.published { + self.publish_updated(); + } Ok(post) } - pub fn delete(&self, conn: &Connection, searcher: &Searcher) -> Result<()> { + pub fn delete(&self, conn: &Connection) -> Result<()> { for m in Mention::list_for_post(&conn, self.id)? { m.delete(conn)?; } diesel::delete(self).execute(conn)?; - searcher.delete_document(self); + self.publish_deleted(); Ok(()) } @@ -545,6 +553,36 @@ impl Post { .set_to_link_vec(vec![Id::new(PUBLIC_VISIBILITY)])?; Ok(act) } + + fn publish_published(&self) { + POST_CHAN.tell( + Publish { + msg: PostPublished(Arc::new(self.clone())), + topic: "post.published".into(), + }, + None, + ) + } + + fn publish_updated(&self) { + POST_CHAN.tell( + Publish { + msg: PostUpdated(Arc::new(self.clone())), + topic: "post.updated".into(), + }, + None, + ) + } + + fn publish_deleted(&self) { + POST_CHAN.tell( + Publish { + msg: PostDeleted(Arc::new(self.clone())), + topic: "post.deleted".into(), + }, + None, + ) + } } impl FromId for Post { @@ -557,7 +595,6 @@ impl FromId for Post { fn from_activity(c: &PlumeRocket, article: LicensedArticle) -> Result { let conn = &*c.conn; - let searcher = &c.searcher; let license = article.custom_props.license_string().unwrap_or_default(); let article = article.object; @@ -605,7 +642,6 @@ impl FromId for Post { source: article.ap_object_props.source_object::()?.content, cover_id: cover, }, - searcher, )?; for author in authors { @@ -670,7 +706,7 @@ impl AsObject for Post { .into_iter() .any(|a| actor.id == a.id); if can_delete { - self.delete(&c.conn, &c.searcher).map(|_| ()) + self.delete(&c.conn).map(|_| ()) } else { Err(Error::Unauthorized) } @@ -727,7 +763,6 @@ impl AsObject for PostUpdate { fn activity(self, c: &PlumeRocket, actor: User, _id: &str) -> Result<()> { let conn = &*c.conn; - let searcher = &c.searcher; let mut post = Post::from_id(c, &self.ap_url, None, CONFIG.proxy()).map_err(|(_, e)| e)?; if !post.is_author(conn, actor.id)? { @@ -789,7 +824,7 @@ impl AsObject for PostUpdate { post.update_hashtags(conn, hashtags)?; } - post.update(conn, searcher)?; + post.update(conn)?; Ok(()) } } @@ -800,6 +835,25 @@ impl IntoId for Post { } } +#[derive(Clone, Debug)] +pub enum PostEvent { + PostPublished(Arc), + PostUpdated(Arc), + PostDeleted(Arc), +} + +impl From for Arc { + fn from(event: PostEvent) -> Self { + use PostEvent::*; + + match event { + PostPublished(post) => post, + PostUpdated(post) => post, + PostDeleted(post) => post, + } + } +} + #[cfg(test)] mod tests { use super::*; @@ -831,7 +885,6 @@ mod tests { source: "Hello".into(), cover_id: None, }, - &r.searcher, ) .unwrap(); PostAuthor::insert( @@ -843,7 +896,7 @@ mod tests { ) .unwrap(); let create = post.create_activity(conn).unwrap(); - post.delete(conn, &r.searcher).unwrap(); + post.delete(conn).unwrap(); match inbox(&r, serde_json::to_value(create).unwrap()).unwrap() { InboxResult::Post(p) => { diff --git a/plume-models/src/search/actor.rs b/plume-models/src/search/actor.rs new file mode 100644 index 00000000..a0b0d22e --- /dev/null +++ b/plume-models/src/search/actor.rs @@ -0,0 +1,207 @@ +use super::Searcher; +use crate::{db_conn::DbPool, posts::PostEvent, ACTOR_SYS, POST_CHAN}; +use riker::actors::{Actor, ActorFactoryArgs, ActorRefFactory, Context, Sender, Subscribe, Tell}; +use std::sync::Arc; +use std::thread::sleep; +use std::time::Duration; +use tracing::error; + +pub struct SearchActor { + searcher: Arc, + conn: DbPool, +} + +impl SearchActor { + pub fn init(searcher: Arc, conn: DbPool) { + ACTOR_SYS + .actor_of_args::("search", (searcher, conn)) + .expect("Failed to initialize searcher actor"); + } +} + +impl Actor for SearchActor { + type Msg = PostEvent; + + fn pre_start(&mut self, ctx: &Context) { + POST_CHAN.tell( + Subscribe { + actor: Box::new(ctx.myself()), + topic: "*".into(), + }, + None, + ) + } + + fn recv(&mut self, _ctx: &Context, msg: Self::Msg, _sender: Sender) { + use PostEvent::*; + + // Wait for transaction commited + sleep(Duration::from_millis(500)); + + match msg { + PostPublished(post) => { + let conn = self.conn.get(); + match conn { + Ok(conn) => { + self.searcher + .add_document(&conn, &post) + .unwrap_or_else(|e| error!("{:?}", e)); + } + _ => { + error!("Failed to get database connection"); + } + } + } + PostUpdated(post) => { + let conn = self.conn.get(); + match conn { + Ok(_) => { + self.searcher + .update_document(&conn.unwrap(), &post) + .unwrap_or_else(|e| error!("{:?}", e)); + } + _ => { + error!("Failed to get database connection"); + } + } + } + PostDeleted(post) => self.searcher.delete_document(&post), + } + } +} + +impl ActorFactoryArgs<(Arc, DbPool)> for SearchActor { + fn create_args((searcher, conn): (Arc, DbPool)) -> Self { + Self { searcher, conn } + } +} + +#[cfg(test)] +mod tests { + use crate::diesel::Connection; + use crate::diesel::RunQueryDsl; + use crate::{ + blog_authors::{BlogAuthor, NewBlogAuthor}, + blogs::{Blog, NewBlog}, + db_conn::{DbPool, PragmaForeignKey}, + instance::{Instance, NewInstance}, + post_authors::{NewPostAuthor, PostAuthor}, + posts::{NewPost, Post}, + safe_string::SafeString, + search::{actor::SearchActor, tests::get_searcher, Query}, + users::{NewUser, User}, + Connection as Conn, CONFIG, + }; + use diesel::r2d2::ConnectionManager; + use plume_common::utils::random_hex; + use std::str::FromStr; + use std::sync::Arc; + use std::thread::sleep; + use std::time::Duration; + + #[test] + fn post_updated() { + // Need to commit so that searcher on another thread retrieve records. + // So, build DbPool instead of using DB_POOL for testing. + let manager = ConnectionManager::::new(CONFIG.database_url.as_str()); + let db_pool = DbPool::builder() + .connection_customizer(Box::new(PragmaForeignKey)) + .build(manager) + .unwrap(); + + let searcher = Arc::new(get_searcher(&CONFIG.search_tokenizers)); + SearchActor::init(searcher.clone(), db_pool.clone()); + let conn = db_pool.clone().get().unwrap(); + + let title = random_hex()[..8].to_owned(); + let (instance, user, blog) = fill_database(&conn); + let author = &blog.list_authors(&conn).unwrap()[0]; + + let post = Post::insert( + &conn, + NewPost { + blog_id: blog.id, + slug: title.clone(), + title: title.clone(), + content: SafeString::new(""), + published: true, + license: "CC-BY-SA".to_owned(), + ap_url: "".to_owned(), + creation_date: None, + subtitle: "".to_owned(), + source: "".to_owned(), + cover_id: None, + }, + ) + .unwrap(); + PostAuthor::insert( + &conn, + NewPostAuthor { + post_id: post.id, + author_id: author.id, + }, + ) + .unwrap(); + let post_id = post.id; + + // Wait for searcher on another thread add document asynchronously + sleep(Duration::from_millis(700)); + searcher.commit(); + assert_eq!( + searcher.search_document(&conn, Query::from_str(&title).unwrap(), (0, 1))[0].id, + post_id + ); + // TODO: Make sure records are deleted even when assertion failed + post.delete(&conn).unwrap(); + blog.delete(&conn).unwrap(); + user.delete(&conn).unwrap(); + diesel::delete(&instance).execute(&conn).unwrap(); + } + + fn fill_database(conn: &Conn) -> (Instance, User, Blog) { + conn.transaction::<(Instance, User, Blog), diesel::result::Error, _>(|| { + let instance = Instance::insert( + conn, + NewInstance { + default_license: "CC-0-BY-SA".to_string(), + local: true, + long_description: SafeString::new("Good morning"), + long_description_html: "

Good morning

".to_string(), + short_description: SafeString::new("Hello"), + short_description_html: "

Hello

".to_string(), + name: random_hex().to_string(), + open_registrations: true, + public_domain: random_hex().to_string(), + }, + ) + .unwrap(); + let mut user = NewUser::default(); + user.instance_id = instance.id; + user.username = random_hex().to_string(); + user.ap_url = random_hex().to_string(); + user.inbox_url = random_hex().to_string(); + user.outbox_url = random_hex().to_string(); + user.followers_endpoint = random_hex().to_string(); + let user = User::insert(conn, user).unwrap(); + let mut blog = NewBlog::default(); + blog.instance_id = instance.id; + blog.actor_id = random_hex().to_string(); + blog.ap_url = random_hex().to_string(); + blog.inbox_url = random_hex().to_string(); + blog.outbox_url = random_hex().to_string(); + let blog = Blog::insert(conn, blog).unwrap(); + BlogAuthor::insert( + conn, + NewBlogAuthor { + blog_id: blog.id, + author_id: user.id, + is_owner: true, + }, + ) + .unwrap(); + + Ok((instance, user, blog)) + }) + .unwrap() + } +} diff --git a/plume-models/src/search/mod.rs b/plume-models/src/search/mod.rs index 83b9bf62..917f7778 100644 --- a/plume-models/src/search/mod.rs +++ b/plume-models/src/search/mod.rs @@ -1,3 +1,4 @@ +pub mod actor; mod query; mod searcher; mod tokenizer; @@ -7,12 +8,7 @@ pub use self::tokenizer::TokenizerKind; #[cfg(test)] pub(crate) mod tests { - use super::{Query, Searcher, TokenizerKind}; - use diesel::Connection; - use plume_common::utils::random_hex; - use std::env::temp_dir; - use std::str::FromStr; - + use super::{Query, Searcher}; use crate::{ blogs::tests::fill_database, config::SearchTokenizerConfig, @@ -22,6 +18,10 @@ pub(crate) mod tests { tests::db, CONFIG, }; + use diesel::Connection; + use plume_common::utils::random_hex; + use std::env::temp_dir; + use std::str::FromStr; pub(crate) fn get_searcher(tokenizers: &SearchTokenizerConfig) -> Searcher { let dir = temp_dir().join(&format!("plume-test-{}", random_hex())); @@ -144,7 +144,6 @@ pub(crate) mod tests { source: "".to_owned(), cover_id: None, }, - &searcher, ) .unwrap(); PostAuthor::insert( @@ -155,7 +154,7 @@ pub(crate) mod tests { }, ) .unwrap(); - + searcher.add_document(&conn, &post).unwrap(); searcher.commit(); assert_eq!( searcher.search_document(conn, Query::from_str(&title).unwrap(), (0, 1))[0].id, @@ -164,7 +163,8 @@ pub(crate) mod tests { let newtitle = random_hex()[..8].to_owned(); post.title = newtitle.clone(); - post.update(conn, &searcher).unwrap(); + post.update(conn).unwrap(); + searcher.update_document(conn, &post).unwrap(); searcher.commit(); assert_eq!( searcher.search_document(conn, Query::from_str(&newtitle).unwrap(), (0, 1))[0].id, @@ -174,7 +174,7 @@ pub(crate) mod tests { .search_document(conn, Query::from_str(&title).unwrap(), (0, 1)) .is_empty()); - post.delete(conn, &searcher).unwrap(); + searcher.delete_document(&post); searcher.commit(); assert!(searcher .search_document(conn, Query::from_str(&newtitle).unwrap(), (0, 1)) @@ -213,7 +213,6 @@ pub(crate) mod tests { source: "".to_owned(), cover_id: None, }, - &searcher, ) .unwrap(); diff --git a/plume-models/src/search/searcher.rs b/plume-models/src/search/searcher.rs index 34a45b0b..d4ebb642 100644 --- a/plume-models/src/search/searcher.rs +++ b/plume-models/src/search/searcher.rs @@ -1,15 +1,17 @@ use crate::{ config::SearchTokenizerConfig, instance::Instance, posts::Post, schema::posts, - search::query::PlumeQuery, tags::Tag, Connection, Result, + search::query::PlumeQuery, tags::Tag, Connection, Error, Result, }; -use chrono::Datelike; +use chrono::{Datelike, Utc}; use diesel::{ExpressionMethods, QueryDsl, RunQueryDsl}; use itertools::Itertools; +use std::fs; use std::{cmp, fs::create_dir_all, io, path::Path, sync::Mutex}; use tantivy::{ collector::TopDocs, directory::MmapDirectory, schema::*, Index, IndexReader, IndexWriter, ReloadPolicy, TantivyError, Term, }; +use tracing::warn; use whatlang::{detect as detect_lang, Lang}; #[derive(Debug)] @@ -67,6 +69,58 @@ impl Searcher { schema_builder.build() } + pub fn open_or_recreate(path: &dyn AsRef, tokenizers: &SearchTokenizerConfig) -> Self { + let mut open_searcher = Self::open(path, tokenizers); + if let Err(Error::Search(SearcherError::InvalidIndexDataError)) = open_searcher { + if Self::create(path, tokenizers).is_err() { + let backup_path = format!("{}.{}", path.as_ref().display(), Utc::now().timestamp()); + let backup_path = Path::new(&backup_path); + fs::rename(path, backup_path) + .expect("main: error on backing up search index directory for recreating"); + if Self::create(path, tokenizers).is_ok() { + if fs::remove_dir_all(backup_path).is_err() { + warn!( + "error on removing backup directory: {}. it remains", + backup_path.display() + ); + } + } else { + panic!("main: error on recreating search index in new index format. remove search index and run `plm search init` manually"); + } + } + open_searcher = Self::open(path, tokenizers); + } + match open_searcher { + Ok(s) => s, + Err(Error::Search(e)) => match e { + SearcherError::WriteLockAcquisitionError => panic!( + r#" +Your search index is locked. Plume can't start. To fix this issue +make sure no other Plume instance is started, and run: + + plm search unlock + +Then try to restart Plume. +"# + ), + SearcherError::IndexOpeningError => panic!( + r#" +Plume was unable to open the search index. If you created the index +before, make sure to run Plume in the same directory it was created in, or +to set SEARCH_INDEX accordingly. If you did not yet create the search +index, run this command: + + plm search init + +Then try to restart Plume +"# + ), + e => Err(e).unwrap(), + }, + _ => panic!("Unexpected error while opening search index"), + } + } + pub fn create(path: &dyn AsRef, tokenizers: &SearchTokenizerConfig) -> Result { let schema = Self::schema(); diff --git a/plume-models/src/timeline/mod.rs b/plume-models/src/timeline/mod.rs index 426c228b..ecfb2b52 100644 --- a/plume-models/src/timeline/mod.rs +++ b/plume-models/src/timeline/mod.rs @@ -408,7 +408,6 @@ mod tests { source: "you must say GNU/Linux, not Linux!!!".to_string(), cover_id: None, }, - &r.searcher, ) .unwrap(); assert!(gnu_tl.matches(r, &gnu_post, Kind::Original).unwrap()); @@ -428,7 +427,6 @@ mod tests { source: "so is Microsoft".to_string(), cover_id: None, }, - &r.searcher, ) .unwrap(); assert!(!gnu_tl.matches(r, &non_free_post, Kind::Original).unwrap()); @@ -481,7 +479,6 @@ mod tests { subtitle: "".to_string(), cover_id: None, }, - &r.searcher, ) .unwrap(); assert!(my_tl.matches(r, &post, Kind::Original).unwrap()); // matches because of "blog in fav_blogs" (and there is no cover) @@ -503,7 +500,6 @@ mod tests { subtitle: "".to_string(), cover_id: None, }, - &r.searcher, ) .unwrap(); assert!(!my_tl.matches(r, &post, Kind::Like(&users[1])).unwrap()); @@ -549,7 +545,6 @@ mod tests { source: "you must say GNU/Linux, not Linux!!!".to_string(), cover_id: None, }, - &r.searcher, ) .unwrap(); @@ -568,7 +563,6 @@ mod tests { source: "so is Microsoft".to_string(), cover_id: None, }, - &r.searcher, ) .unwrap(); @@ -608,7 +602,6 @@ mod tests { source: "you must say GNU/Linux, not Linux!!!".to_string(), cover_id: None, }, - &r.searcher, ) .unwrap(); gnu_post @@ -745,7 +738,6 @@ mod tests { source: "you must say GNU/Linux, not Linux!!!".to_string(), cover_id: None, }, - &r.searcher, ) .unwrap(); gnu_post.update_tags(conn, vec![Tag::build_activity("free".to_owned()).unwrap()]).unwrap(); @@ -779,7 +771,6 @@ mod tests { source: "you must say GNU/Linux, not Linux!!!".to_string(), cover_id: None, }, - &r.searcher, ) .unwrap(); diff --git a/plume-models/src/users.rs b/plume-models/src/users.rs index 753774f8..c4729acc 100644 --- a/plume-models/src/users.rs +++ b/plume-models/src/users.rs @@ -1,8 +1,8 @@ use crate::{ ap_url, blocklisted_emails::BlocklistedEmail, blogs::Blog, db_conn::DbConn, follows::Follow, instance::*, medias::Media, notifications::Notification, post_authors::PostAuthor, posts::Post, - safe_string::SafeString, schema::users, search::Searcher, timeline::Timeline, Connection, - Error, PlumeRocket, Result, CONFIG, ITEMS_PER_PAGE, + safe_string::SafeString, schema::users, timeline::Timeline, Connection, Error, PlumeRocket, + Result, CONFIG, ITEMS_PER_PAGE, }; use activitypub::{ activity::Delete, @@ -129,14 +129,14 @@ impl User { .map_err(Error::from) } - pub fn delete(&self, conn: &Connection, searcher: &Searcher) -> Result<()> { + pub fn delete(&self, conn: &Connection) -> Result<()> { use crate::schema::post_authors; for blog in Blog::find_for_author(conn, self)? .iter() .filter(|b| b.count_authors(conn).map(|c| c <= 1).unwrap_or(false)) { - blog.delete(conn, searcher)?; + blog.delete(conn)?; } // delete the posts if they is the only author let all_their_posts_ids: Vec = post_authors::table @@ -156,7 +156,7 @@ impl User { .unwrap_or(&0) > &0; if !has_other_authors { - Post::get(conn, post_id)?.delete(conn, searcher)?; + Post::get(conn, post_id)?.delete(conn)?; } } @@ -1037,7 +1037,7 @@ impl AsObject for User { fn activity(self, c: &PlumeRocket, actor: User, _id: &str) -> Result<()> { if self.id == actor.id { - self.delete(&c.conn, &c.searcher).map(|_| ()) + self.delete(&c.conn).map(|_| ()) } else { Err(Error::Unauthorized) } @@ -1130,9 +1130,7 @@ impl NewUser { pub(crate) mod tests { use super::*; use crate::{ - config::CONFIG, instance::{tests as instance_tests, Instance}, - search::tests::get_searcher, tests::{db, rockets}, Connection as Conn, }; @@ -1227,9 +1225,7 @@ pub(crate) mod tests { let inserted = fill_database(conn); assert!(User::get(conn, inserted[0].id).is_ok()); - inserted[0] - .delete(conn, &get_searcher(&CONFIG.search_tokenizers)) - .unwrap(); + inserted[0].delete(conn).unwrap(); assert!(User::get(conn, inserted[0].id).is_err()); Ok(()) }); @@ -1319,7 +1315,7 @@ pub(crate) mod tests { let users = fill_database(conn); let ap_repr = users[0].to_activity(conn).unwrap(); - users[0].delete(conn, &*r.searcher).unwrap(); + users[0].delete(conn).unwrap(); let user = User::from_activity(&r, ap_repr).unwrap(); assert_eq!(user.username, users[0].username); diff --git a/po/plume-front/cy.po b/po/plume-front/cy.po index 09f8c8e2..4c722366 100644 --- a/po/plume-front/cy.po +++ b/po/plume-front/cy.po @@ -10,12 +10,17 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=6; plural=(n == 0) ? 0 : ((n == 1) ? 1 : ((n == 2) ? 2 : ((n == 3) ? 3 : ((n == 6) ? 4 : 5))));\n" +"Plural-Forms: nplurals=6; plural=(n == 0) ? 0 : ((n == 1) ? 1 : ((n == 2) ? " +"2 : ((n == 3) ? 3 : ((n == 6) ? 4 : 5))));\n" "X-Generator: crowdin.com\n" "X-Crowdin-Project: plume\n" "X-Crowdin-Language: cy\n" "X-Crowdin-File: /master/po/plume-front/plume-front.pot\n" +# plume-front/src/editor.rs:189 +msgid "Do you want to load the local autosave last edited at {}?" +msgstr "" + # plume-front/src/editor.rs:114 msgid "Open the rich text editor" msgstr "" @@ -24,8 +29,8 @@ msgstr "" msgid "Title" msgstr "" -# plume-front/src/editor.rs:147 -msgid "Subtitle or summary" +# plume-front/src/editor.rs:319 +msgid "Subtitle, or summary" msgstr "" # plume-front/src/editor.rs:154 @@ -55,4 +60,3 @@ msgstr "" # plume-front/src/editor.rs:259 msgid "Publish" msgstr "" - diff --git a/po/plume-front/plume-front.pot b/po/plume-front/plume-front.pot index 28028a63..5a9d490d 100644 --- a/po/plume-front/plume-front.pot +++ b/po/plume-front/plume-front.pot @@ -12,46 +12,46 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" -# plume-front/src/editor.rs:189 +# plume-front/src/editor.rs:188 msgid "Do you want to load the local autosave last edited at {}?" msgstr "" -# plume-front/src/editor.rs:282 +# plume-front/src/editor.rs:281 msgid "Open the rich text editor" msgstr "" -# plume-front/src/editor.rs:315 +# plume-front/src/editor.rs:314 msgid "Title" msgstr "" -# plume-front/src/editor.rs:319 +# plume-front/src/editor.rs:318 msgid "Subtitle, or summary" msgstr "" -# plume-front/src/editor.rs:326 +# plume-front/src/editor.rs:325 msgid "Write your article here. Markdown is supported." msgstr "" -# plume-front/src/editor.rs:337 +# plume-front/src/editor.rs:336 msgid "Around {} characters left" msgstr "" -# plume-front/src/editor.rs:414 +# plume-front/src/editor.rs:413 msgid "Tags" msgstr "" -# plume-front/src/editor.rs:415 +# plume-front/src/editor.rs:414 msgid "License" msgstr "" -# plume-front/src/editor.rs:418 +# plume-front/src/editor.rs:417 msgid "Cover" msgstr "" -# plume-front/src/editor.rs:438 +# plume-front/src/editor.rs:437 msgid "This is a draft" msgstr "" -# plume-front/src/editor.rs:445 +# plume-front/src/editor.rs:444 msgid "Publish" msgstr "" diff --git a/po/plume/plume.pot b/po/plume/plume.pot index f5144446..8d82c5b3 100644 --- a/po/plume/plume.pot +++ b/po/plume/plume.pot @@ -72,27 +72,27 @@ msgstr "" msgid "Your blog was successfully created!" msgstr "" -# src/routes/blogs.rs:160 +# src/routes/blogs.rs:159 msgid "Your blog was deleted." msgstr "" -# src/routes/blogs.rs:168 +# src/routes/blogs.rs:167 msgid "You are not allowed to delete this blog." msgstr "" -# src/routes/blogs.rs:219 +# src/routes/blogs.rs:218 msgid "You are not allowed to edit this blog." msgstr "" -# src/routes/blogs.rs:275 +# src/routes/blogs.rs:274 msgid "You can't use this media as a blog icon." msgstr "" -# src/routes/blogs.rs:293 +# src/routes/blogs.rs:292 msgid "You can't use this media as a blog banner." msgstr "" -# src/routes/blogs.rs:327 +# src/routes/blogs.rs:326 msgid "Your blog information have been updated." msgstr "" @@ -104,39 +104,39 @@ msgstr "" msgid "Your comment has been deleted." msgstr "" -# src/routes/instance.rs:119 +# src/routes/instance.rs:118 msgid "Instance settings have been saved." msgstr "" -# src/routes/instance.rs:151 +# src/routes/instance.rs:150 msgid "{} has been unblocked." msgstr "" -# src/routes/instance.rs:153 +# src/routes/instance.rs:152 msgid "{} has been blocked." msgstr "" -# src/routes/instance.rs:202 +# src/routes/instance.rs:201 msgid "Blocks deleted" msgstr "" -# src/routes/instance.rs:217 +# src/routes/instance.rs:216 msgid "Email already blocked" msgstr "" -# src/routes/instance.rs:222 +# src/routes/instance.rs:221 msgid "Email Blocked" msgstr "" -# src/routes/instance.rs:313 +# src/routes/instance.rs:312 msgid "You can't change your own rights." msgstr "" -# src/routes/instance.rs:324 +# src/routes/instance.rs:323 msgid "You are not allowed to take this action." msgstr "" -# src/routes/instance.rs:361 +# src/routes/instance.rs:359 msgid "Done." msgstr "" @@ -188,31 +188,31 @@ msgstr "" msgid "You are not allowed to publish on this blog." msgstr "" -# src/routes/posts.rs:364 +# src/routes/posts.rs:363 msgid "Your article has been updated." msgstr "" -# src/routes/posts.rs:555 +# src/routes/posts.rs:553 msgid "Your article has been saved." msgstr "" -# src/routes/posts.rs:562 +# src/routes/posts.rs:560 msgid "New article" msgstr "" -# src/routes/posts.rs:599 +# src/routes/posts.rs:597 msgid "You are not allowed to delete this article." msgstr "" -# src/routes/posts.rs:624 +# src/routes/posts.rs:622 msgid "Your article has been deleted." msgstr "" -# src/routes/posts.rs:629 +# src/routes/posts.rs:627 msgid "It looks like the article you tried to delete doesn't exist. Maybe it is already gone?" msgstr "" -# src/routes/posts.rs:669 +# src/routes/posts.rs:667 msgid "Couldn't obtain enough information about your account. Please make sure your username is correct." msgstr "" diff --git a/src/api/posts.rs b/src/api/posts.rs index 284746ad..fca56108 100644 --- a/src/api/posts.rs +++ b/src/api/posts.rs @@ -105,7 +105,6 @@ pub fn create( rockets: PlumeRocket, ) -> Api { let conn = &*rockets.conn; - let search = &rockets.searcher; let worker = &rockets.worker; let author = User::get(conn, auth.0.user_id)?; @@ -155,7 +154,6 @@ pub fn create( source: payload.source.clone(), cover_id: payload.cover_id, }, - search, )?; PostAuthor::insert( @@ -232,7 +230,7 @@ pub fn delete(auth: Authorization, rockets: PlumeRocket, id: i32) - let author = User::get(&*rockets.conn, auth.0.user_id)?; if let Ok(post) = Post::get(&*rockets.conn, id) { if post.is_author(&*rockets.conn, author.id).unwrap_or(false) { - post.delete(&*rockets.conn, &rockets.searcher)?; + post.delete(&*rockets.conn)?; } } Ok(Json(())) diff --git a/src/main.rs b/src/main.rs index cc7561cd..60466437 100755 --- a/src/main.rs +++ b/src/main.rs @@ -10,20 +10,17 @@ extern crate serde_json; #[macro_use] extern crate validator_derive; -use chrono::Utc; use clap::App; use diesel::r2d2::ConnectionManager; use plume_models::{ db_conn::{DbPool, PragmaForeignKey}, instance::Instance, migrations::IMPORTED_MIGRATIONS, - search::{Searcher as UnmanagedSearcher, SearcherError}, - Connection, Error, CONFIG, + search::{actor::SearchActor, Searcher as UnmanagedSearcher}, + Connection, CONFIG, }; use rocket_csrf::CsrfFairingBuilder; use scheduled_thread_pool::ScheduledThreadPool; -use std::fs; -use std::path::Path; use std::process::exit; use std::sync::{Arc, Mutex}; use std::time::Duration; @@ -103,59 +100,11 @@ Then try to restart Plume. } let workpool = ScheduledThreadPool::with_name("worker {}", num_cpus::get()); // we want a fast exit here, so - let mut open_searcher = - UnmanagedSearcher::open(&CONFIG.search_index, &CONFIG.search_tokenizers); - if let Err(Error::Search(SearcherError::InvalidIndexDataError)) = open_searcher { - if UnmanagedSearcher::create(&CONFIG.search_index, &CONFIG.search_tokenizers).is_err() { - let current_path = Path::new(&CONFIG.search_index); - let backup_path = format!("{}.{}", ¤t_path.display(), Utc::now().timestamp()); - let backup_path = Path::new(&backup_path); - fs::rename(current_path, backup_path) - .expect("main: error on backing up search index directory for recreating"); - if UnmanagedSearcher::create(&CONFIG.search_index, &CONFIG.search_tokenizers).is_ok() { - if fs::remove_dir_all(backup_path).is_err() { - warn!( - "error on removing backup directory: {}. it remains", - backup_path.display() - ); - } - } else { - panic!("main: error on recreating search index in new index format. remove search index and run `plm search init` manually"); - } - } - open_searcher = UnmanagedSearcher::open(&CONFIG.search_index, &CONFIG.search_tokenizers); - } - #[allow(clippy::match_wild_err_arm)] - let searcher = match open_searcher { - Err(Error::Search(e)) => match e { - SearcherError::WriteLockAcquisitionError => panic!( - r#" -Your search index is locked. Plume can't start. To fix this issue -make sure no other Plume instance is started, and run: - - plm search unlock - -Then try to restart Plume. -"# - ), - SearcherError::IndexOpeningError => panic!( - r#" -Plume was unable to open the search index. If you created the index -before, make sure to run Plume in the same directory it was created in, or -to set SEARCH_INDEX accordingly. If you did not yet create the search -index, run this command: - - plm search init - -Then try to restart Plume -"# - ), - e => Err(e).unwrap(), - }, - Err(_) => panic!("Unexpected error while opening search index"), - Ok(s) => Arc::new(s), - }; - + let searcher = Arc::new(UnmanagedSearcher::open_or_recreate( + &CONFIG.search_index, + &CONFIG.search_tokenizers, + )); + SearchActor::init(searcher.clone(), dbpool.clone()); let commiter = searcher.clone(); workpool.execute_with_fixed_delay( Duration::from_secs(5), diff --git a/src/routes/blogs.rs b/src/routes/blogs.rs index 0c08c536..8696e82d 100644 --- a/src/routes/blogs.rs +++ b/src/routes/blogs.rs @@ -153,8 +153,7 @@ pub fn delete(name: String, rockets: PlumeRocket) -> RespondOrRedirect { .and_then(|u| u.is_author_in(&*conn, &blog).ok()) .unwrap_or(false) { - blog.delete(&conn, &rockets.searcher) - .expect("blog::expect: deletion error"); + blog.delete(&conn).expect("blog::expect: deletion error"); Flash::success( Redirect::to(uri!(super::instance::index)), i18n!(rockets.intl.catalog, "Your blog was deleted."), diff --git a/src/routes/instance.rs b/src/routes/instance.rs index 83bc46b6..bec1b092 100644 --- a/src/routes/instance.rs +++ b/src/routes/instance.rs @@ -21,7 +21,6 @@ use plume_models::{ instance::*, posts::Post, safe_string::SafeString, - search::Searcher, timeline::Timeline, users::{Role, User}, Connection, Error, PlumeRocket, CONFIG, @@ -331,7 +330,6 @@ pub fn edit_users( } let conn = &rockets.conn; - let searcher = &*rockets.searcher; let worker = &*rockets.worker; match form.action { UserActions::Admin => { @@ -351,7 +349,7 @@ pub fn edit_users( } UserActions::Ban => { for u in form.ids.clone() { - ban(u, conn, searcher, worker)?; + ban(u, conn, worker)?; } } } @@ -362,14 +360,9 @@ pub fn edit_users( )) } -fn ban( - id: i32, - conn: &Connection, - searcher: &Searcher, - worker: &ScheduledThreadPool, -) -> Result<(), ErrorPage> { +fn ban(id: i32, conn: &Connection, worker: &ScheduledThreadPool) -> Result<(), ErrorPage> { let u = User::get(&*conn, id)?; - u.delete(&*conn, searcher)?; + u.delete(&*conn)?; if Instance::get_local() .map(|i| u.instance_id == i.id) .unwrap_or(false) diff --git a/src/routes/posts.rs b/src/routes/posts.rs index b04fa4fc..f76100b1 100644 --- a/src/routes/posts.rs +++ b/src/routes/posts.rs @@ -298,8 +298,7 @@ pub fn update( post.source = form.content.clone(); post.license = form.license.clone(); post.cover_id = form.cover; - post.update(&*conn, &rockets.searcher) - .expect("post::update: update error"); + post.update(&*conn).expect("post::update: update error"); if post.published { post.update_mentions( @@ -481,7 +480,6 @@ pub fn create( source: form.content.clone(), cover_id: form.cover, }, - &rockets.searcher, ) .expect("post::create: post save error"); diff --git a/src/routes/user.rs b/src/routes/user.rs index f64fd42c..2a9f2080 100644 --- a/src/routes/user.rs +++ b/src/routes/user.rs @@ -421,7 +421,7 @@ pub fn delete( ) -> Result, ErrorPage> { let account = User::find_by_fqn(&rockets, &name)?; if user.id == account.id { - account.delete(&*rockets.conn, &rockets.searcher)?; + account.delete(&*rockets.conn)?; let target = User::one_by_instance(&*rockets.conn)?; let delete_act = account.delete_activity(&*rockets.conn)?;