diff --git a/.gitignore b/.gitignore index f4cbc4f3..c4841e36 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,16 @@ -/target -/freedit.db* -/certs -/static/imgs -.rustc_info.json -.rustdoc_fingerprint.json -config.toml -/snapshots -/tantivy .DS_Store +.envrc +.tool-versions + +apps/server/freedit.db +apps/server/config.toml +apps/server/static/imgs +apps/server/snapshots +apps/server/tantivy +certs +target + +bun.lockb +node_modules +*.tsbuildinfo +yarn.lock diff --git a/.justfile b/.justfile new file mode 100644 index 00000000..8d325f2b --- /dev/null +++ b/.justfile @@ -0,0 +1,41 @@ +export PATH := "./node_modules/.bin:" + env_var('PATH') + +default: + @just --choose + +build: + #!/usr/bin/env -S parallel --shebang --ungroup --jobs {{ num_cpus() }} + just build-client + just build-server + +[working-directory: 'apps/client'] +build-client: + @bun tsc -b + bun vite build + +[working-directory: 'apps/server'] +build-server: + @cargo build -r + +clean-server: + @rm -fr apps/server/{config.toml,freedit.db,snapshots,static/imgs,tantivy,target} + +dev: + @just dev-client & just dev-server + +[working-directory: 'apps/client'] +dev-client: + @bun vite dev + +[working-directory: 'apps/server'] +dev-server: + @cargo run + +start: + @just start-server & just start-client + +start-server: + @./apps/server/target/release/freedit + +start-client: + @vite preview diff --git a/Cargo.lock b/Cargo.lock index 1be5b05c..8dec8c5b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -51,9 +51,9 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "ammonia" @@ -153,7 +153,7 @@ dependencies = [ "rustversion", "serde", "serde_urlencoded", - "sync_wrapper 1.0.2", + "sync_wrapper", "tokio", "tower", "tower-layer", @@ -176,7 +176,7 @@ dependencies = [ "mime", "pin-project-lite", "rustversion", - "sync_wrapper 1.0.2", + "sync_wrapper", "tower-layer", "tower-service", "tracing", @@ -352,9 +352,9 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "bytes" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" [[package]] name = "cached" @@ -412,9 +412,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.1" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" +checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d" dependencies = [ "jobserver", "libc", @@ -450,9 +450,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" dependencies = [ "num-traits", ] @@ -660,12 +660,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -697,15 +697,15 @@ checksum = "9afc2bd4d5a73106dd53d10d73d3401c2f32730ba2c0b93ddb888a8983680471" [[package]] name = "fastrand" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fdeflate" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07c6f4c64c1d33a3111c4466f7365ebdcc37c5bd1ea0d62aae2e3d722aacbedb" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" dependencies = [ "simd-adler32", ] @@ -782,7 +782,7 @@ dependencies = [ "stop-words", "syntect", "tantivy", - "thiserror 2.0.3", + "thiserror 2.0.6", "tikv-jemallocator", "tokio", "tower", @@ -1033,9 +1033,9 @@ checksum = "e9025058dae765dee5070ec375f591e2ba14638c63feff74f13805a72e523163" [[package]] name = "http" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" dependencies = [ "bytes", "fnv", @@ -1067,9 +1067,9 @@ dependencies = [ [[package]] name = "http-range-header" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08a397c49fec283e3d6211adbe480be95aae5f304cfb923e9970e08956d5168a" +checksum = "9171a2ea8a68358193d15dd5d70c1c10a2afc3e7e4c5bc92bc9f025cebd7359c" [[package]] name = "httparse" @@ -1323,9 +1323,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", "hashbrown 0.15.2", @@ -1360,9 +1360,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "540654e97a3f4470a492cd30ff187bc95d89557a903a2bbf112e2fae98104ef2" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "jieba-rs" @@ -1379,9 +1379,9 @@ dependencies = [ [[package]] name = "jiff" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d9d414fc817d3e3d62b2598616733f76c4cc74fbac96069674739b881295c8" +checksum = "db69f08d4fb10524cacdb074c10b296299d71274ddbc830a8ee65666867002e9" [[package]] name = "jobserver" @@ -1394,10 +1394,11 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.72" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -1421,9 +1422,9 @@ checksum = "0c2cdeb66e45e9f36bfad5bbdb4d2384e70936afbee843c6f6543f0c551ebb25" [[package]] name = "libc" -version = "0.2.164" +version = "0.2.168" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" +checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" [[package]] name = "libm" @@ -1586,11 +1587,10 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ - "hermit-abi", "libc", "wasi", "windows-sys 0.52.0", @@ -1598,9 +1598,9 @@ dependencies = [ [[package]] name = "mozjpeg" -version = "0.10.10" +version = "0.10.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "969e1dbc9af2f18ffe6ddba72bbe86506c7214ecb28670d98ecfba51cb9b8c6b" +checksum = "55571bce4f12d80ceb4296526e7614f796df72daaaac85f265ab732fa47b7bc9" dependencies = [ "arrayvec", "bytemuck", @@ -1777,7 +1777,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.7", + "redox_syscall 0.5.8", "smallvec", "windows-targets", ] @@ -1865,9 +1865,9 @@ checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "png" -version = "0.17.14" +version = "0.17.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52f9d46a34a05a6a57566bc2bfae066ef07585a6e3fa30fbbdff5936380623f0" +checksum = "b67582bd5b65bdff614270e2ea89a1cf15bef71245cc1e5f7ea126977144211d" dependencies = [ "bitflags 1.3.2", "crc32fast", @@ -1944,10 +1944,10 @@ dependencies = [ "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "rustls", "socket2", - "thiserror 2.0.3", + "thiserror 2.0.6", "tokio", "tracing", ] @@ -1962,11 +1962,11 @@ dependencies = [ "getrandom", "rand", "ring", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "rustls", "rustls-pki-types", "slab", - "thiserror 2.0.3", + "thiserror 2.0.6", "tinyvec", "tracing", "web-time", @@ -1974,9 +1974,9 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5a626c6807713b15cac82a6acaccd6043c9a5408c24baae07611fec3f243da" +checksum = "52cd4b1eff68bf27940dd39811292c49e007f4d0b4c357358dc9b0197be6b527" dependencies = [ "cfg_aliases", "libc", @@ -2066,9 +2066,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ "bitflags 2.6.0", ] @@ -2147,7 +2147,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "sync_wrapper 1.0.2", + "sync_wrapper", "tokio", "tokio-rustls", "tokio-socks", @@ -2217,7 +2217,7 @@ dependencies = [ "proc-macro2", "quote", "rinja_parser", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "syn", ] @@ -2264,28 +2264,28 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc-hash" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" +checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" [[package]] name = "rustix" -version = "0.38.41" +version = "0.38.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" +checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" dependencies = [ "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "rustls" -version = "0.23.18" +version = "0.23.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9cc1d47e243d655ace55ed38201c19ae02c148ae56412ab8750e8f0166ab7f" +checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" dependencies = [ "once_cell", "ring", @@ -2353,18 +2353,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.215" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.215" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", @@ -2485,9 +2485,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", "windows-sys 0.52.0", @@ -2560,21 +2560,15 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.89" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - [[package]] name = "sync_wrapper" version = "1.0.2" @@ -2791,11 +2785,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.3" +version = "2.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa" +checksum = "8fec2a1820ebd077e2b90c4df007bebf344cd394098a13c563957d0afc83ea47" dependencies = [ - "thiserror-impl 2.0.3", + "thiserror-impl 2.0.6", ] [[package]] @@ -2811,9 +2805,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.3" +version = "2.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568" +checksum = "d65750cab40f4ff1929fb1ba509e9914eb756131cef4210da8d5d700d26f6312" dependencies = [ "proc-macro2", "quote", @@ -2852,9 +2846,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.36" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ "deranged", "itoa", @@ -2873,9 +2867,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" dependencies = [ "num-conv", "time-core", @@ -2908,9 +2902,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.41.1" +version = "1.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" +checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" dependencies = [ "backtrace", "bytes", @@ -2935,12 +2929,11 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.0" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" dependencies = [ "rustls", - "rustls-pki-types", "tokio", ] @@ -2958,9 +2951,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.12" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" +checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" dependencies = [ "bytes", "futures-core", @@ -2971,14 +2964,14 @@ dependencies = [ [[package]] name = "tower" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", "futures-util", "pin-project-lite", - "sync_wrapper 0.1.2", + "sync_wrapper", "tokio", "tower-layer", "tower-service", @@ -3025,9 +3018,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "pin-project-lite", "tracing-core", @@ -3035,18 +3028,18 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", ] [[package]] name = "tracing-subscriber" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" dependencies = [ "matchers", "once_cell", @@ -3184,9 +3177,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" dependencies = [ "cfg-if", "once_cell", @@ -3195,13 +3188,12 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", "syn", @@ -3210,21 +3202,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.45" +version = "0.4.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" +checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2" dependencies = [ "cfg-if", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3232,9 +3225,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ "proc-macro2", "quote", @@ -3245,15 +3238,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.95" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" [[package]] name = "web-sys" -version = "0.3.72" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" +checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index 53b355b0..1fa1dfa5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,58 +1,10 @@ -[package] -name = "freedit" -version = "0.7.5" -edition = "2021" -license = "MIT License" - -[dependencies] -ammonia = "4.0.0" -atom_syndication = { version = "0.12", default-features = false } -axum = { version = "0.7.5", features = ["http1", "http2", "form", "query", "multipart", "tokio"], default-features = false } -axum-extra = { version = "0.9", features = ["typed-header"] } -axum_garde = { version = "0.20.0", default-features = false, features = ["form"] } -basic-toml = "*" -bincode = "2.0.0-rc.3" -cached = { version = "0.54.0", default-features = false, features = ["proc_macro", "ahash"] } -captcha = { git = "https://github.com/freedit-dev/captcha.git", default-features = false } -data-encoding = "*" -fast2s = "0.3" -garde = { version = "0.20.0", features = ["derive"] } -http = "1.1" -identicon = { git = "https://github.com/freedit-dev/identicon.git", default-features = false } -image = { version = "0.25.2", default-features = false, features = ["jpeg", "png", "gif"] } -img-parts = "0.3.0" -indexmap = "2" -jieba-rs = { git = "https://github.com/messense/jieba-rs.git", rev = "b39957e" } -jiff = { version = "0.1.13", default-features = false, features = ["std"] } -latex2mathml = "0.2.3" -mozjpeg = "0.10.10" -nanoid = "0.4.0" -pulldown-cmark = { version = "0.12.0", features = ["simd", "html"], default-features = false } -rand = "0.8" -regex = "1" -reqwest = { version = "0.12", default-features = false, features = ["rustls-tls", "socks"] } -ring = { version = "0.17", default-features = false } -rinja = { version = "0.3.4", default-features = false } -rinja_axum = { version = "0.3.4", default-features = false } -rss = { version = "2.0", default-features = false } -rust-stemmers = "1.2.0" -serde = { version = "1.0", features = ["derive"] } -sled = "0.34.7" -snailquote = "0.3.1" -stop-words = "0.8.0" -syntect = { version = "5", features = ["regex-fancy", "default-syntaxes", "default-themes", "html"], default-features = false } -tantivy = "0.22.0" -thiserror = "2" -tokio = { version = "1", features = ["macros", "rt-multi-thread"] } -tower = { version = "0.5.1", features = ["timeout"] } -tower-http = { version = "0.6.1", features = ["fs", "compression-zstd", "trace"] } -tracing = { version = "0.1", features = ["release_max_level_info", "max_level_info"], default-features = false } -tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt", "smallvec"], default-features = false } -unicode-segmentation = "1" -whichlang = "0.1.0" +[workspace] +members = ["apps/server"] +resolver = "2" -[target.'cfg(not(target_os = "windows"))'.dependencies] -tikv-jemallocator = "0.6" +[workspace.package] +edition = "2021" +license = "MIT" [profile.release] lto = "fat" diff --git a/README.md b/README.md index c6a69201..5b46e4cd 100644 --- a/README.md +++ b/README.md @@ -1,70 +1,10 @@ -# freedit +# PSE Freedit -[![CI](https://github.com/freedit-org/freedit/actions/workflows/ci.yml/badge.svg)](https://github.com/freedit-org/freedit/actions/workflows/ci.yml) -[![release](https://github.com/freedit-org/freedit/actions/workflows/release.yml/badge.svg)](https://github.com/freedit-org/freedit/releases) -[![Doc](https://img.shields.io/github/deployments/freedit-org/freedit/github-pages?label=doc)](https://freedit-org.github.io/freedit/freedit/index.html) +## Develop +### Requirements +- [bun](https://bun.sh/docs/installation) (JS runtime) +- [rust](https://www.rust-lang.org/tools/install) +- [just](https://just.systems) (tasks runner) -The safest and lightest forum, powered by rust. - -Demo: - -GitHub: - -## Support - -Help support the development and maintenance of freedit. Your contributions are greatly appreciated! - -- Monero (XMR): `45JB1KbCM54gw7zDY8LzkDXjEibDgTspyKBzM8VWi8mL1gY3wCyzHsCSRGRsXBwGgdC6HX1EtJFoNYXZELnDQW8S7DRG8tL` - -All donations go towards hosting costs and continued development of freedit. Thank you for your support! - -## Features - -* Easy to deploy: one binary to run, using embedded database [sled](https://github.com/spacejam/sled) -* No javascript at all, for safety maximization. ([Why javascript is evil](https://thehackernews.com/2022/05/tails-os-users-advised-not-to-use-tor.html)) -* e2ee private message -* Math and Code highlighting support without JavaScript -* Markdown support -* inn: Subgroup like Subreddits -* solo: Personal space like Twitter -* Online rss reader - -## Usage - -### From binary - -1. Download freedit binary from [releases](https://github.com/freedit-org/freedit/releases) -2. unzip freedit.zip -3. run `./freedit`, open browser to `addr`, - -### From source code - -Prerequisition: install [Rust](https://www.rust-lang.org/tools/install) - -```bash -git clone https://github.com/freedit-org/freedit -cd freedit && cargo build -r -./target/release/freedit -``` - -## Documentation - -* online doc: - -* generate local documentation: -```bash -cargo doc --no-deps --open -``` - -## Development - -```bash -git clone https://github.com/freedit-org/freedit -cd freedit && cargo run -``` - -## Credits - -* icon: -* CSS framework: -* Rust crates: [Cargo.toml](https://github.com/freedit-org/freedit/blob/main/Cargo.toml) \ No newline at end of file +Then start both server and client with `just dev`. +Or select any available scripts with `just`. diff --git a/apps/client/.gitignore b/apps/client/.gitignore new file mode 100644 index 00000000..a547bf36 --- /dev/null +++ b/apps/client/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/apps/client/README.md b/apps/client/README.md new file mode 100644 index 00000000..74872fd4 --- /dev/null +++ b/apps/client/README.md @@ -0,0 +1,50 @@ +# React + TypeScript + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh + +## Expanding the ESLint configuration + +If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: + +- Configure the top-level `parserOptions` property like this: + +```js +export default tseslint.config({ + languageOptions: { + // other options... + parserOptions: { + project: ['./tsconfig.node.json', './tsconfig.app.json'], + tsconfigRootDir: import.meta.dirname, + }, + }, +}) +``` + +- Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked` +- Optionally add `...tseslint.configs.stylisticTypeChecked` +- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config: + +```js +// eslint.config.js +import react from 'eslint-plugin-react' + +export default tseslint.config({ + // Set the react version + settings: { react: { version: '18.3' } }, + plugins: { + // Add the react plugin + react, + }, + rules: { + // other rules... + // Enable its recommended rules + ...react.configs.recommended.rules, + ...react.configs['jsx-runtime'].rules, + }, +}) +``` diff --git a/apps/client/eslint.config.js b/apps/client/eslint.config.js new file mode 100644 index 00000000..092408a9 --- /dev/null +++ b/apps/client/eslint.config.js @@ -0,0 +1,28 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import tseslint from 'typescript-eslint' + +export default tseslint.config( + { ignores: ['dist'] }, + { + extends: [js.configs.recommended, ...tseslint.configs.recommended], + files: ['**/*.{ts,tsx}'], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + }, + plugins: { + 'react-hooks': reactHooks, + 'react-refresh': reactRefresh, + }, + rules: { + ...reactHooks.configs.recommended.rules, + 'react-refresh/only-export-components': [ + 'warn', + { allowConstantExport: true }, + ], + }, + }, +) diff --git a/apps/client/index.html b/apps/client/index.html new file mode 100644 index 00000000..e4b78eae --- /dev/null +++ b/apps/client/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite + React + TS + + +
+ + + diff --git a/apps/client/package.json b/apps/client/package.json new file mode 100644 index 00000000..9102ca83 --- /dev/null +++ b/apps/client/package.json @@ -0,0 +1,20 @@ +{ + "name": "client", + "private": true, + "version": "0.0.0", + "type": "module", + "dependencies": { + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, + "devDependencies": { + "@tanstack/router-devtools": "^1.87.9", + "@tanstack/router-plugin": "^1.87.11", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "@vitejs/plugin-react-swc": "^3.5.0", + "globals": "^15.9.0", + "typescript": "^5.5.3", + "vite": "^5.4.1" + } +} diff --git a/apps/client/public/vite.svg b/apps/client/public/vite.svg new file mode 100644 index 00000000..e7b8dfb1 --- /dev/null +++ b/apps/client/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/client/src/App.css b/apps/client/src/App.css new file mode 100644 index 00000000..b9d355df --- /dev/null +++ b/apps/client/src/App.css @@ -0,0 +1,42 @@ +#root { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + +.logo { + height: 6em; + padding: 1.5em; + will-change: filter; + transition: filter 300ms; +} +.logo:hover { + filter: drop-shadow(0 0 2em #646cffaa); +} +.logo.react:hover { + filter: drop-shadow(0 0 2em #61dafbaa); +} + +@keyframes logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +@media (prefers-reduced-motion: no-preference) { + a:nth-of-type(2) .logo { + animation: logo-spin infinite 20s linear; + } +} + +.card { + padding: 2em; +} + +.read-the-docs { + color: #888; +} diff --git a/apps/client/src/App.tsx b/apps/client/src/App.tsx new file mode 100644 index 00000000..ea134720 --- /dev/null +++ b/apps/client/src/App.tsx @@ -0,0 +1,36 @@ +import reactLogo from './assets/react.svg' +import viteLogo from '/vite.svg' +import './App.css' +import { RouterProvider, createRouter } from '@tanstack/react-router' +import { routeTree } from './routeTree.gen' +const router = createRouter({ routeTree }) + +// Register the router instance for type safety +declare module '@tanstack/react-router' { + interface Register { + router: typeof router + } +} + + +function App() { + return ( + <> + +

Vite + React

+ +

+ Click on the Vite and React logos to learn more +

+ + ) +} + +export default App diff --git a/apps/client/src/assets/react.svg b/apps/client/src/assets/react.svg new file mode 100644 index 00000000..6c87de9b --- /dev/null +++ b/apps/client/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/client/src/index.css b/apps/client/src/index.css new file mode 100644 index 00000000..6119ad9a --- /dev/null +++ b/apps/client/src/index.css @@ -0,0 +1,68 @@ +:root { + font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} +a:hover { + color: #535bf2; +} + +body { + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 3.2em; + line-height: 1.1; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} +button:hover { + border-color: #646cff; +} +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + a:hover { + color: #747bff; + } + button { + background-color: #f9f9f9; + } +} diff --git a/apps/client/src/main.tsx b/apps/client/src/main.tsx new file mode 100644 index 00000000..6f4ac9bc --- /dev/null +++ b/apps/client/src/main.tsx @@ -0,0 +1,10 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import App from './App.tsx' +import './index.css' + +createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/apps/client/src/routeTree.gen.ts b/apps/client/src/routeTree.gen.ts new file mode 100644 index 00000000..d6919f5f --- /dev/null +++ b/apps/client/src/routeTree.gen.ts @@ -0,0 +1,116 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +import { createFileRoute } from '@tanstack/react-router' + +// Import Routes + +import { Route as rootRoute } from './routes/__root' + +// Create Virtual Routes + +const IndexLazyImport = createFileRoute('/')() +const InnIndexLazyImport = createFileRoute('/inn/')() + +// Create/Update Routes + +const IndexLazyRoute = IndexLazyImport.update({ + id: '/', + path: '/', + getParentRoute: () => rootRoute, +} as any).lazy(() => import('./routes/index.lazy').then((d) => d.Route)) + +const InnIndexLazyRoute = InnIndexLazyImport.update({ + id: '/inn/', + path: '/inn/', + getParentRoute: () => rootRoute, +} as any).lazy(() => import('./routes/inn.index.lazy').then((d) => d.Route)) + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/react-router' { + interface FileRoutesByPath { + '/': { + id: '/' + path: '/' + fullPath: '/' + preLoaderRoute: typeof IndexLazyImport + parentRoute: typeof rootRoute + } + '/inn/': { + id: '/inn/' + path: '/inn' + fullPath: '/inn' + preLoaderRoute: typeof InnIndexLazyImport + parentRoute: typeof rootRoute + } + } +} + +// Create and export the route tree + +export interface FileRoutesByFullPath { + '/': typeof IndexLazyRoute + '/inn': typeof InnIndexLazyRoute +} + +export interface FileRoutesByTo { + '/': typeof IndexLazyRoute + '/inn': typeof InnIndexLazyRoute +} + +export interface FileRoutesById { + __root__: typeof rootRoute + '/': typeof IndexLazyRoute + '/inn/': typeof InnIndexLazyRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: '/' | '/inn' + fileRoutesByTo: FileRoutesByTo + to: '/' | '/inn' + id: '__root__' | '/' | '/inn/' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren { + IndexLazyRoute: typeof IndexLazyRoute + InnIndexLazyRoute: typeof InnIndexLazyRoute +} + +const rootRouteChildren: RootRouteChildren = { + IndexLazyRoute: IndexLazyRoute, + InnIndexLazyRoute: InnIndexLazyRoute, +} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [ + "/", + "/inn/" + ] + }, + "/": { + "filePath": "index.lazy.tsx" + }, + "/inn/": { + "filePath": "inn.index.lazy.tsx" + } + } +} +ROUTE_MANIFEST_END */ diff --git a/apps/client/src/routes/__root.tsx b/apps/client/src/routes/__root.tsx new file mode 100644 index 00000000..5700ddd7 --- /dev/null +++ b/apps/client/src/routes/__root.tsx @@ -0,0 +1,20 @@ +import { createRootRoute, Link, Outlet } from '@tanstack/react-router' +import { TanStackRouterDevtools } from '@tanstack/router-devtools' + +export const Route = createRootRoute({ + component: () => ( + <> +
+ + Home + {' '} + + Inn + +
+
+ + + + ), +}) diff --git a/apps/client/src/routes/index.lazy.tsx b/apps/client/src/routes/index.lazy.tsx new file mode 100644 index 00000000..f8f08fe8 --- /dev/null +++ b/apps/client/src/routes/index.lazy.tsx @@ -0,0 +1,13 @@ +import { createLazyFileRoute } from '@tanstack/react-router' + +export const Route = createLazyFileRoute('/')({ + component: Index, +}) + +function Index() { + return ( +
+

Welcome Home!

+
+ ) +} diff --git a/apps/client/src/routes/inn.index.lazy.tsx b/apps/client/src/routes/inn.index.lazy.tsx new file mode 100644 index 00000000..fc1a7353 --- /dev/null +++ b/apps/client/src/routes/inn.index.lazy.tsx @@ -0,0 +1,28 @@ +import { createLazyFileRoute } from '@tanstack/react-router' +import { useEffect, useState } from "react"; + +export const Route = createLazyFileRoute('/inn/')({ + component: InnsList, +}) + +function InnsList() { + const [htmlContent, setHtmlContent] = useState(null); + +useEffect(() => { + // Fetch raw HTML from the API + fetch("http://localhost:3001/inn/0") + .then((response) => response.text()) + .then((html) => setHtmlContent(html)) + .catch((error) => console.error("Failed to fetch HTML:", error)); + }, []); + + if (!htmlContent) { + return

Loading...

; + } + + return ( +
+ ) +} diff --git a/apps/client/src/vite-env.d.ts b/apps/client/src/vite-env.d.ts new file mode 100644 index 00000000..11f02fe2 --- /dev/null +++ b/apps/client/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/apps/client/tsconfig.app.json b/apps/client/tsconfig.app.json new file mode 100644 index 00000000..f0a23505 --- /dev/null +++ b/apps/client/tsconfig.app.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"] +} diff --git a/apps/client/tsconfig.json b/apps/client/tsconfig.json new file mode 100644 index 00000000..1ffef600 --- /dev/null +++ b/apps/client/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/apps/client/tsconfig.node.json b/apps/client/tsconfig.node.json new file mode 100644 index 00000000..0d3d7144 --- /dev/null +++ b/apps/client/tsconfig.node.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": ["ES2023"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["vite.config.ts"] +} diff --git a/apps/client/vite.config.ts b/apps/client/vite.config.ts new file mode 100644 index 00000000..160a8e73 --- /dev/null +++ b/apps/client/vite.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react-swc' +import { TanStackRouterVite } from '@tanstack/router-plugin/vite' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [ + TanStackRouterVite(), + react()], +}) diff --git a/apps/server/.cargo/config.toml b/apps/server/.cargo/config.toml new file mode 100644 index 00000000..b6e2773a --- /dev/null +++ b/apps/server/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +target-dir = "../../apps/server/target" diff --git a/apps/server/Cargo.toml b/apps/server/Cargo.toml new file mode 100644 index 00000000..2e9457d5 --- /dev/null +++ b/apps/server/Cargo.toml @@ -0,0 +1,54 @@ +[package] +edition = "2021" +name = "freedit" +version = "0.7.5" + +[dependencies] +ammonia = "4.0.0" +atom_syndication = { version = "0.12", default-features = false } +axum = { version = "0.7.5", features = ["http1", "http2", "form", "query", "multipart", "tokio"], default-features = false } +axum-extra = { version = "0.9", features = ["typed-header"] } +axum_garde = { version = "0.20.0", default-features = false, features = ["form"] } +basic-toml = "*" +bincode = "2.0.0-rc.3" +cached = { version = "0.54.0", default-features = false, features = ["proc_macro", "ahash"] } +captcha = { git = "https://github.com/freedit-dev/captcha.git", default-features = false } +data-encoding = "*" +fast2s = "0.3" +garde = { version = "0.20.0", features = ["derive"] } +http = "1.1" +identicon = { git = "https://github.com/freedit-dev/identicon.git", default-features = false } +image = { version = "0.25.2", default-features = false, features = ["jpeg", "png", "gif"] } +img-parts = "0.3.0" +indexmap = "2" +jieba-rs = { git = "https://github.com/messense/jieba-rs.git", rev = "b39957e" } +jiff = { version = "0.1.13", default-features = false, features = ["std"] } +latex2mathml = "0.2.3" +mozjpeg = "0.10.10" +nanoid = "0.4.0" +pulldown-cmark = { version = "0.12.0", features = ["simd", "html"], default-features = false } +rand = "0.8" +regex = "1" +reqwest = { version = "0.12", default-features = false, features = ["rustls-tls", "socks"] } +ring = { version = "0.17", default-features = false } +rinja = { version = "0.3.4", default-features = false } +rinja_axum = { version = "0.3.4", default-features = false } +rss = { version = "2.0", default-features = false } +rust-stemmers = "1.2.0" +serde = { version = "1.0", features = ["derive"] } +sled = "0.34.7" +snailquote = "0.3.1" +stop-words = "0.8.0" +syntect = { version = "5", features = ["regex-fancy", "default-syntaxes", "default-themes", "html"], default-features = false } +tantivy = "0.22.0" +thiserror = "2" +tokio = { version = "1", features = ["macros", "rt-multi-thread"] } +tower = { version = "0.5.1", features = ["timeout"] } +tower-http = { version = "0.6.1", features = ["fs", "compression-zstd", "cors", "trace"] } +tracing = { version = "0.1", features = ["release_max_level_info", "max_level_info"], default-features = false } +tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt", "smallvec"], default-features = false } +unicode-segmentation = "1" +whichlang = "0.1.0" + +[target.'cfg(not(target_os = "windows"))'.dependencies] +tikv-jemallocator = "0.6" diff --git a/apps/server/README.md b/apps/server/README.md new file mode 100644 index 00000000..c6a69201 --- /dev/null +++ b/apps/server/README.md @@ -0,0 +1,70 @@ +# freedit + +[![CI](https://github.com/freedit-org/freedit/actions/workflows/ci.yml/badge.svg)](https://github.com/freedit-org/freedit/actions/workflows/ci.yml) +[![release](https://github.com/freedit-org/freedit/actions/workflows/release.yml/badge.svg)](https://github.com/freedit-org/freedit/releases) +[![Doc](https://img.shields.io/github/deployments/freedit-org/freedit/github-pages?label=doc)](https://freedit-org.github.io/freedit/freedit/index.html) + +The safest and lightest forum, powered by rust. + +Demo: + +GitHub: + +## Support + +Help support the development and maintenance of freedit. Your contributions are greatly appreciated! + +- Monero (XMR): `45JB1KbCM54gw7zDY8LzkDXjEibDgTspyKBzM8VWi8mL1gY3wCyzHsCSRGRsXBwGgdC6HX1EtJFoNYXZELnDQW8S7DRG8tL` + +All donations go towards hosting costs and continued development of freedit. Thank you for your support! + +## Features + +* Easy to deploy: one binary to run, using embedded database [sled](https://github.com/spacejam/sled) +* No javascript at all, for safety maximization. ([Why javascript is evil](https://thehackernews.com/2022/05/tails-os-users-advised-not-to-use-tor.html)) +* e2ee private message +* Math and Code highlighting support without JavaScript +* Markdown support +* inn: Subgroup like Subreddits +* solo: Personal space like Twitter +* Online rss reader + +## Usage + +### From binary + +1. Download freedit binary from [releases](https://github.com/freedit-org/freedit/releases) +2. unzip freedit.zip +3. run `./freedit`, open browser to `addr`, + +### From source code + +Prerequisition: install [Rust](https://www.rust-lang.org/tools/install) + +```bash +git clone https://github.com/freedit-org/freedit +cd freedit && cargo build -r +./target/release/freedit +``` + +## Documentation + +* online doc: + +* generate local documentation: +```bash +cargo doc --no-deps --open +``` + +## Development + +```bash +git clone https://github.com/freedit-org/freedit +cd freedit && cargo run +``` + +## Credits + +* icon: +* CSS framework: +* Rust crates: [Cargo.toml](https://github.com/freedit-org/freedit/blob/main/Cargo.toml) \ No newline at end of file diff --git a/build.rs b/apps/server/build.rs similarity index 100% rename from build.rs rename to apps/server/build.rs diff --git a/i18n/en.toml b/apps/server/i18n/en.toml similarity index 100% rename from i18n/en.toml rename to apps/server/i18n/en.toml diff --git a/i18n/fr.toml b/apps/server/i18n/fr.toml similarity index 100% rename from i18n/fr.toml rename to apps/server/i18n/fr.toml diff --git a/i18n/ja.toml b/apps/server/i18n/ja.toml similarity index 100% rename from i18n/ja.toml rename to apps/server/i18n/ja.toml diff --git a/i18n/zh_cn.toml b/apps/server/i18n/zh_cn.toml similarity index 100% rename from i18n/zh_cn.toml rename to apps/server/i18n/zh_cn.toml diff --git a/src/app_router.rs b/apps/server/src/app_router.rs similarity index 94% rename from src/app_router.rs rename to apps/server/src/app_router.rs index 40977d40..80f8378a 100644 --- a/src/app_router.rs +++ b/apps/server/src/app_router.rs @@ -26,10 +26,12 @@ use axum::{ error_handling::HandleErrorLayer, extract::DefaultBodyLimit, handler::Handler, http::StatusCode, routing::get, BoxError, Router, }; +use http::header::HeaderValue; use std::time::Duration; use tower::{timeout::TimeoutLayer, ServiceBuilder}; use tower_http::{ compression::CompressionLayer, + cors::{Any, CorsLayer}, services::ServeDir, trace::{DefaultMakeSpan, TraceLayer}, }; @@ -38,15 +40,19 @@ use tracing::Level; const UPLOAD_LIMIT: usize = 20 * 1024 * 1024; pub async fn router() -> Router { + let cors = CorsLayer::new() + .allow_origin(HeaderValue::from_static("http://localhost:5173")) + .allow_methods(Any) + .allow_headers(Any); + let middleware_stack = ServiceBuilder::new() .layer(HandleErrorLayer::new(|_: BoxError| async { StatusCode::REQUEST_TIMEOUT })) .layer(TimeoutLayer::new(Duration::from_secs(10))) .layer(CompressionLayer::new()) - .layer( - TraceLayer::new_for_http().make_span_with(DefaultMakeSpan::new().level(Level::INFO)), - ); + .layer(TraceLayer::new_for_http().make_span_with(DefaultMakeSpan::new().level(Level::INFO))) + .layer(cors); let router_db = Router::new() .route("/", get(home)) diff --git a/apps/server/src/config.rs b/apps/server/src/config.rs new file mode 100644 index 00000000..fed3a187 --- /dev/null +++ b/apps/server/src/config.rs @@ -0,0 +1,130 @@ +use serde::{Deserialize, Serialize}; +use std::env; +use std::fs::{self, read_to_string, File}; +use std::io::Write; +use std::path::{Path, PathBuf}; +use std::sync::LazyLock; +use tracing::{info, warn}; + +pub static CONFIG: LazyLock = LazyLock::new(Config::load_config); + +#[derive(Serialize, Deserialize)] +pub struct Config { + pub db: PathBuf, + pub snapshots_path: PathBuf, + pub addr: String, + pub rebuild_index: Option, + pub(crate) avatars_path: PathBuf, + pub(crate) inn_icons_path: PathBuf, + pub(crate) upload_path: PathBuf, + pub(crate) tantivy_path: PathBuf, + pub(crate) proxy: String, +} + +impl Config { + fn load_config() -> Config { + let exe_path = env::current_exe().expect("Failed to get current executable path"); + let exe_dir = exe_path + .parent() + .expect("Fialed to get executable directory") + .parent() + .expect("Failed to get target directory") + .parent() + .expect("Failed to get server directory"); + + let cfg_file = exe_dir.join( + env::args() + .nth(1) + .unwrap_or_else(|| "config.toml".to_owned()), + ); + let config = if let Ok(config_toml_content) = read_to_string(&cfg_file) { + let mut config: Config = + basic_toml::from_str(&config_toml_content).expect("Failed to parse config.toml"); + config.resolve_paths(&exe_dir); + config + } else { + warn!("Config file not found, using default config.toml"); + let mut config = Config::default(); + config.resolve_paths(&exe_dir); + let toml = basic_toml::to_string(&config).expect("Failed to serialize config.toml"); + let mut file = File::create(&cfg_file).expect("Failed to create config.toml file"); + file.write_all(toml.as_bytes()) + .expect("Failed to write to config.toml"); + info!("Wrote default config file at {}", &cfg_file.display()); + config + }; + + config.ensure_dirs(); + config + } + + fn resolve_paths(&mut self, base_dir: &Path) { + let path_fields: &mut [&mut PathBuf] = &mut [ + &mut self.db, + &mut self.snapshots_path, + &mut self.avatars_path, + &mut self.inn_icons_path, + &mut self.upload_path, + &mut self.tantivy_path, + ]; + + for p in path_fields.iter_mut() { + **p = resolve_path(base_dir, p.as_path()); + } + } + + fn ensure_dirs(&self) { + let path_fields = [ + &self.db, + &self.snapshots_path, + &self.avatars_path, + &self.inn_icons_path, + &self.upload_path, + &self.tantivy_path, + ]; + + for path in &path_fields { + check_path(path); + } + } +} + +impl Default for Config { + fn default() -> Self { + Config { + db: PathBuf::from("freedit.db"), + snapshots_path: PathBuf::from("snapshots"), + addr: "127.0.0.1:3001".into(), + rebuild_index: None, + avatars_path: PathBuf::from("static/imgs/avatars"), + inn_icons_path: PathBuf::from("static/imgs/inn_icons"), + upload_path: PathBuf::from("static/imgs/upload"), + tantivy_path: PathBuf::from("tantivy"), + proxy: "".into(), + } + } +} + +/// Resolve a PathBuf relative to base_dir if it's not absolute +fn resolve_path(base_dir: &Path, path: &Path) -> PathBuf { + if path.is_absolute() { + path.to_path_buf() + } else { + base_dir.join(path) + } +} + +/// Create new dir if the path doesn't exist. +fn check_path(path: &Path) { + if !path.exists() { + fs::create_dir_all(path).unwrap_or_else(|_| { + panic!( + "Failed to created necessary dir at {:?}", + path.canonicalize().unwrap_or_else(|_| path.to_path_buf()) + ) + }); + info!("Created dir: {:?}", path); + } else { + info!("Dir already exists {:?}", path); + } +} diff --git a/src/controller/admin.rs b/apps/server/src/controller/admin.rs similarity index 100% rename from src/controller/admin.rs rename to apps/server/src/controller/admin.rs diff --git a/src/controller/db_utils.rs b/apps/server/src/controller/db_utils.rs similarity index 100% rename from src/controller/db_utils.rs rename to apps/server/src/controller/db_utils.rs diff --git a/src/controller/feed.rs b/apps/server/src/controller/feed.rs similarity index 100% rename from src/controller/feed.rs rename to apps/server/src/controller/feed.rs diff --git a/src/controller/fmt.rs b/apps/server/src/controller/fmt.rs similarity index 100% rename from src/controller/fmt.rs rename to apps/server/src/controller/fmt.rs diff --git a/src/controller/inn.rs b/apps/server/src/controller/inn.rs similarity index 100% rename from src/controller/inn.rs rename to apps/server/src/controller/inn.rs diff --git a/src/controller/message.rs b/apps/server/src/controller/message.rs similarity index 100% rename from src/controller/message.rs rename to apps/server/src/controller/message.rs diff --git a/src/controller/meta_handler.rs b/apps/server/src/controller/meta_handler.rs similarity index 100% rename from src/controller/meta_handler.rs rename to apps/server/src/controller/meta_handler.rs diff --git a/src/controller/mod.rs b/apps/server/src/controller/mod.rs similarity index 100% rename from src/controller/mod.rs rename to apps/server/src/controller/mod.rs diff --git a/src/controller/notification.rs b/apps/server/src/controller/notification.rs similarity index 100% rename from src/controller/notification.rs rename to apps/server/src/controller/notification.rs diff --git a/src/controller/solo.rs b/apps/server/src/controller/solo.rs similarity index 100% rename from src/controller/solo.rs rename to apps/server/src/controller/solo.rs diff --git a/src/controller/tantivy.rs b/apps/server/src/controller/tantivy.rs similarity index 100% rename from src/controller/tantivy.rs rename to apps/server/src/controller/tantivy.rs diff --git a/src/controller/upload.rs b/apps/server/src/controller/upload.rs similarity index 97% rename from src/controller/upload.rs rename to apps/server/src/controller/upload.rs index 7255b922..0e773b2f 100644 --- a/src/controller/upload.rs +++ b/apps/server/src/controller/upload.rs @@ -53,14 +53,14 @@ pub(crate) async fn upload_pic_post( return Err(AppError::Unauthorized); } target = format!("/mod/{iid}"); - format!("{}/{}.png", &CONFIG.inn_icons_path, iid) + format!("{}/{}.png", &CONFIG.inn_icons_path.display(), iid) } else { return Err(AppError::NotFound); } } "user" => { target = "/user/setting".to_string(); - format!("{}/{}.png", &CONFIG.avatars_path, claim.uid) + format!("{}/{}.png", &CONFIG.avatars_path.display(), claim.uid) } _ => unreachable!(), }; @@ -177,7 +177,7 @@ pub(crate) async fn image_delete( if count == 0 { let img = String::from_utf8_lossy(&v1); - let path = format!("{}/{}", CONFIG.upload_path, img); + let path = format!("{}/{}", CONFIG.upload_path.display(), img); remove_file(path).await?; } } else { @@ -315,7 +315,7 @@ pub(crate) async fn upload_post( let digest = context.finish(); let sha1 = HEXLOWER.encode(digest.as_ref()); let fname = format!("{}.{}", &sha1[0..20], ext); - let location = format!("{}/{}", &CONFIG.upload_path, fname); + let location = format!("{}/{}", &CONFIG.upload_path.display(), fname); fs::write(location, &img_data).await.unwrap(); let img_id = incr_id(&DB, "imgs_count")?; diff --git a/src/controller/user.rs b/apps/server/src/controller/user.rs similarity index 99% rename from src/controller/user.rs rename to apps/server/src/controller/user.rs index a233920a..bf984e50 100644 --- a/src/controller/user.rs +++ b/apps/server/src/controller/user.rs @@ -987,7 +987,7 @@ pub(crate) async fn signup_post( let password_hash = generate_password_hash(&input.password); let uid = incr_id(&DB, "users_count")?; - let avatar = format!("{}/{}.png", &CONFIG.avatars_path, uid); + let avatar = format!("{}/{}.png", &CONFIG.avatars_path.display(), uid); Identicon::new(&generate_salt()).image().save(avatar)?; let created_at = Timestamp::now().as_second(); diff --git a/src/error.rs b/apps/server/src/error.rs similarity index 100% rename from src/error.rs rename to apps/server/src/error.rs diff --git a/src/lib.rs b/apps/server/src/lib.rs similarity index 97% rename from src/lib.rs rename to apps/server/src/lib.rs index 14559bff..cfc65bcc 100644 --- a/src/lib.rs +++ b/apps/server/src/lib.rs @@ -58,6 +58,6 @@ pub static DB: LazyLock = LazyLock::new(|| { let db_url = &CONFIG.db; let config = sled::Config::default().path(db_url); let db = config.open().unwrap(); - info!(%db_url); + info!("{}", db_url.display()); db }); diff --git a/src/main.rs b/apps/server/src/main.rs similarity index 92% rename from src/main.rs rename to apps/server/src/main.rs index 879d4a5c..fc14af93 100644 --- a/src/main.rs +++ b/apps/server/src/main.rs @@ -29,12 +29,7 @@ async fn main() -> Result<(), AppError> { #[cfg(not(debug_assertions))] tokio::spawn(async move { loop { - let snapshot_path = PathBuf::from("snapshots"); - // create snapshot dir if needed - if !snapshot_path.exists() { - fs::create_dir_all(&snapshot_path).unwrap(); - } - // create a snapshot + let snapshot_path = &CONFIG.snapshots_path; create_snapshot(&snapshot_path, &DB); // remove snapshots older than 48 hours if let Err(e) = prune_snapshots(&snapshot_path) { @@ -108,9 +103,9 @@ fn create_snapshot(snapshot_path: &PathBuf, db: &sled::Db) { info!(%checksum); let timestamp = SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_secs(); + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs(); // create a temporary directory for writing the snapshot // we don't do this in the system tmpdir because it may @@ -134,9 +129,9 @@ fn create_snapshot(snapshot_path: &PathBuf, db: &sled::Db) { fn prune_snapshots(snapshot_path: &PathBuf) -> Result<(), AppError> { let contents = fs::read_dir(snapshot_path)?; let now = SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_secs(); + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs(); for name in contents { let name = name?; diff --git a/static/css/bulma-list.css b/apps/server/static/css/bulma-list.css similarity index 100% rename from static/css/bulma-list.css rename to apps/server/static/css/bulma-list.css diff --git a/static/css/bulma.min.css b/apps/server/static/css/bulma.min.css similarity index 100% rename from static/css/bulma.min.css rename to apps/server/static/css/bulma.min.css diff --git a/static/css/main.css b/apps/server/static/css/main.css similarity index 100% rename from static/css/main.css rename to apps/server/static/css/main.css diff --git a/static/favicon.svg b/apps/server/static/favicon.svg similarity index 100% rename from static/favicon.svg rename to apps/server/static/favicon.svg diff --git a/static/js/encoding-helper.js b/apps/server/static/js/encoding-helper.js similarity index 100% rename from static/js/encoding-helper.js rename to apps/server/static/js/encoding-helper.js diff --git a/static/js/encryption-helper.js b/apps/server/static/js/encryption-helper.js similarity index 100% rename from static/js/encryption-helper.js rename to apps/server/static/js/encryption-helper.js diff --git a/static/robots.txt b/apps/server/static/robots.txt similarity index 100% rename from static/robots.txt rename to apps/server/static/robots.txt diff --git a/templates/admin.html b/apps/server/templates/admin.html similarity index 100% rename from templates/admin.html rename to apps/server/templates/admin.html diff --git a/templates/admin_gallery.html b/apps/server/templates/admin_gallery.html similarity index 100% rename from templates/admin_gallery.html rename to apps/server/templates/admin_gallery.html diff --git a/templates/admin_view.html b/apps/server/templates/admin_view.html similarity index 100% rename from templates/admin_view.html rename to apps/server/templates/admin_view.html diff --git a/templates/atom.xml b/apps/server/templates/atom.xml similarity index 100% rename from templates/atom.xml rename to apps/server/templates/atom.xml diff --git a/templates/error.html b/apps/server/templates/error.html similarity index 100% rename from templates/error.html rename to apps/server/templates/error.html diff --git a/templates/feed.html b/apps/server/templates/feed.html similarity index 100% rename from templates/feed.html rename to apps/server/templates/feed.html diff --git a/templates/feed_add.html b/apps/server/templates/feed_add.html similarity index 100% rename from templates/feed_add.html rename to apps/server/templates/feed_add.html diff --git a/templates/feed_read.html b/apps/server/templates/feed_read.html similarity index 100% rename from templates/feed_read.html rename to apps/server/templates/feed_read.html diff --git a/templates/gallery.html b/apps/server/templates/gallery.html similarity index 100% rename from templates/gallery.html rename to apps/server/templates/gallery.html diff --git a/templates/icons/feeds.svg b/apps/server/templates/icons/feeds.svg similarity index 100% rename from templates/icons/feeds.svg rename to apps/server/templates/icons/feeds.svg diff --git a/templates/icons/lock.svg b/apps/server/templates/icons/lock.svg similarity index 100% rename from templates/icons/lock.svg rename to apps/server/templates/icons/lock.svg diff --git a/templates/icons/lock_square.svg b/apps/server/templates/icons/lock_square.svg similarity index 100% rename from templates/icons/lock_square.svg rename to apps/server/templates/icons/lock_square.svg diff --git a/templates/icons/mail.svg b/apps/server/templates/icons/mail.svg similarity index 100% rename from templates/icons/mail.svg rename to apps/server/templates/icons/mail.svg diff --git a/templates/icons/notification.svg b/apps/server/templates/icons/notification.svg similarity index 100% rename from templates/icons/notification.svg rename to apps/server/templates/icons/notification.svg diff --git a/templates/icons/rss.svg b/apps/server/templates/icons/rss.svg similarity index 100% rename from templates/icons/rss.svg rename to apps/server/templates/icons/rss.svg diff --git a/templates/icons/setting.svg b/apps/server/templates/icons/setting.svg similarity index 100% rename from templates/icons/setting.svg rename to apps/server/templates/icons/setting.svg diff --git a/templates/icons/signout.svg b/apps/server/templates/icons/signout.svg similarity index 100% rename from templates/icons/signout.svg rename to apps/server/templates/icons/signout.svg diff --git a/templates/icons/star.svg b/apps/server/templates/icons/star.svg similarity index 100% rename from templates/icons/star.svg rename to apps/server/templates/icons/star.svg diff --git a/templates/icons/user-plus.svg b/apps/server/templates/icons/user-plus.svg similarity index 100% rename from templates/icons/user-plus.svg rename to apps/server/templates/icons/user-plus.svg diff --git a/templates/icons/user-xmark.svg b/apps/server/templates/icons/user-xmark.svg similarity index 100% rename from templates/icons/user-xmark.svg rename to apps/server/templates/icons/user-xmark.svg diff --git a/templates/inbox.html b/apps/server/templates/inbox.html similarity index 100% rename from templates/inbox.html rename to apps/server/templates/inbox.html diff --git a/templates/inn.html b/apps/server/templates/inn.html similarity index 100% rename from templates/inn.html rename to apps/server/templates/inn.html diff --git a/templates/inn_create.html b/apps/server/templates/inn_create.html similarity index 100% rename from templates/inn_create.html rename to apps/server/templates/inn_create.html diff --git a/templates/inn_edit.html b/apps/server/templates/inn_edit.html similarity index 100% rename from templates/inn_edit.html rename to apps/server/templates/inn_edit.html diff --git a/templates/inn_list.html b/apps/server/templates/inn_list.html similarity index 100% rename from templates/inn_list.html rename to apps/server/templates/inn_list.html diff --git a/templates/key.html b/apps/server/templates/key.html similarity index 100% rename from templates/key.html rename to apps/server/templates/key.html diff --git a/templates/layout.html b/apps/server/templates/layout.html similarity index 100% rename from templates/layout.html rename to apps/server/templates/layout.html diff --git a/templates/message.html b/apps/server/templates/message.html similarity index 100% rename from templates/message.html rename to apps/server/templates/message.html diff --git a/templates/notification.html b/apps/server/templates/notification.html similarity index 100% rename from templates/notification.html rename to apps/server/templates/notification.html diff --git a/templates/post.html b/apps/server/templates/post.html similarity index 100% rename from templates/post.html rename to apps/server/templates/post.html diff --git a/templates/post_create.html b/apps/server/templates/post_create.html similarity index 100% rename from templates/post_create.html rename to apps/server/templates/post_create.html diff --git a/templates/post_edit.html b/apps/server/templates/post_edit.html similarity index 100% rename from templates/post_edit.html rename to apps/server/templates/post_edit.html diff --git a/templates/preview.html b/apps/server/templates/preview.html similarity index 100% rename from templates/preview.html rename to apps/server/templates/preview.html diff --git a/templates/reset.html b/apps/server/templates/reset.html similarity index 100% rename from templates/reset.html rename to apps/server/templates/reset.html diff --git a/templates/search.html b/apps/server/templates/search.html similarity index 100% rename from templates/search.html rename to apps/server/templates/search.html diff --git a/templates/show_recovery.html b/apps/server/templates/show_recovery.html similarity index 100% rename from templates/show_recovery.html rename to apps/server/templates/show_recovery.html diff --git a/templates/signin.html b/apps/server/templates/signin.html similarity index 100% rename from templates/signin.html rename to apps/server/templates/signin.html diff --git a/templates/signup.html b/apps/server/templates/signup.html similarity index 100% rename from templates/signup.html rename to apps/server/templates/signup.html diff --git a/templates/solo.html b/apps/server/templates/solo.html similarity index 100% rename from templates/solo.html rename to apps/server/templates/solo.html diff --git a/templates/solo_list.html b/apps/server/templates/solo_list.html similarity index 100% rename from templates/solo_list.html rename to apps/server/templates/solo_list.html diff --git a/templates/tag.html b/apps/server/templates/tag.html similarity index 100% rename from templates/tag.html rename to apps/server/templates/tag.html diff --git a/templates/upload.html b/apps/server/templates/upload.html similarity index 100% rename from templates/upload.html rename to apps/server/templates/upload.html diff --git a/templates/user.html b/apps/server/templates/user.html similarity index 100% rename from templates/user.html rename to apps/server/templates/user.html diff --git a/templates/user_list.html b/apps/server/templates/user_list.html similarity index 100% rename from templates/user_list.html rename to apps/server/templates/user_list.html diff --git a/templates/user_setting.html b/apps/server/templates/user_setting.html similarity index 100% rename from templates/user_setting.html rename to apps/server/templates/user_setting.html diff --git a/typos.toml b/apps/server/typos.toml similarity index 100% rename from typos.toml rename to apps/server/typos.toml diff --git a/bunfig.toml b/bunfig.toml new file mode 100644 index 00000000..027d8652 --- /dev/null +++ b/bunfig.toml @@ -0,0 +1,2 @@ +[install.lockfile] +print = "yarn" # required for CI/CLI tools that don't support bun.lockb files diff --git a/package.json b/package.json new file mode 100644 index 00000000..d35e32af --- /dev/null +++ b/package.json @@ -0,0 +1,9 @@ +{ + "engines": { + "node": ">=20" + }, + "private": true, + "workspaces": [ + "apps/client" + ] +} diff --git a/src/config.rs b/src/config.rs deleted file mode 100644 index e4d9bd5a..00000000 --- a/src/config.rs +++ /dev/null @@ -1,72 +0,0 @@ -use serde::{Deserialize, Serialize}; -use std::fs::{self, read_to_string, File}; -use std::io::Write; -use std::path::Path; -use std::sync::LazyLock; -use tracing::{info, warn}; - -pub static CONFIG: LazyLock = LazyLock::new(Config::load_config); - -#[derive(Serialize, Deserialize)] -pub struct Config { - pub db: String, - pub addr: String, - pub rebuild_index: Option, - pub(crate) avatars_path: String, - pub(crate) inn_icons_path: String, - pub(crate) upload_path: String, - pub(crate) tantivy_path: String, - pub(crate) proxy: String, -} - -impl Config { - fn load_config() -> Config { - let cfg_file = std::env::args() - .nth(1) - .unwrap_or_else(|| "config.toml".to_owned()); - let config = if let Ok(config_toml_content) = read_to_string(cfg_file) { - let config: Config = basic_toml::from_str(&config_toml_content).unwrap(); - config - } else { - warn!("Config file not found, using default config.toml"); - let config = Config::default(); - let toml = basic_toml::to_string(&config).unwrap(); - let mut cfg_file = File::create("config.toml").unwrap(); - cfg_file.write_all(toml.as_bytes()).unwrap(); - config - }; - - check_path(&config.avatars_path); - check_path(&config.inn_icons_path); - check_path(&config.upload_path); - check_path(&config.tantivy_path); - - config - } -} - -impl Default for Config { - fn default() -> Self { - Config { - db: "freedit.db".into(), - addr: "127.0.0.1:3001".into(), - rebuild_index: None, - avatars_path: "static/imgs/avatars".into(), - inn_icons_path: "static/imgs/inn_icons".into(), - upload_path: "static/imgs/upload".into(), - tantivy_path: "tantivy".into(), - proxy: "".into(), - } - } -} - -/// Create new dir if the path doesn't exist. -fn check_path(path_str: &str) { - let path = Path::new(path_str); - if !path.exists() { - fs::create_dir_all(path).unwrap(); - info!("create path: {}", path_str); - } else { - info!("{path_str} is ok"); - } -}