ceres: a small planet in a giant solar system
33
fork

Configure Feed

Select the types of activity you want to include in your feed.

wip for pref

+247 -14
+1
.gitignore
··· 1 1 /target 2 2 .env 3 + .ceres_data
+167
Cargo.lock
··· 357 357 checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 358 358 359 359 [[package]] 360 + name = "byteorder-lite" 361 + version = "0.1.0" 362 + source = "registry+https://github.com/rust-lang/crates.io-index" 363 + checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" 364 + 365 + [[package]] 360 366 name = "bytes" 361 367 version = "1.11.1" 362 368 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 364 370 dependencies = [ 365 371 "serde", 366 372 ] 373 + 374 + [[package]] 375 + name = "byteview" 376 + version = "0.10.1" 377 + source = "registry+https://github.com/rust-lang/crates.io-index" 378 + checksum = "1c53ba0f290bfc610084c05582d9c5d421662128fc69f4bf236707af6fd321b9" 367 379 368 380 [[package]] 369 381 name = "cbor4ii" ··· 392 404 "axum", 393 405 "dotenvy", 394 406 "env_logger", 407 + "fjall", 395 408 "jacquard", 396 409 "jacquard-api", 397 410 "jacquard-axum", ··· 507 520 "bytes", 508 521 "memchr", 509 522 ] 523 + 524 + [[package]] 525 + name = "compare" 526 + version = "0.0.6" 527 + source = "registry+https://github.com/rust-lang/crates.io-index" 528 + checksum = "ea0095f6103c2a8b44acd6fd15960c801dafebf02e21940360833e0673f48ba7" 510 529 511 530 [[package]] 512 531 name = "compression-codecs" ··· 603 622 source = "registry+https://github.com/rust-lang/crates.io-index" 604 623 checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" 605 624 dependencies = [ 625 + "crossbeam-utils", 626 + ] 627 + 628 + [[package]] 629 + name = "crossbeam-epoch" 630 + version = "0.9.18" 631 + source = "registry+https://github.com/rust-lang/crates.io-index" 632 + checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" 633 + dependencies = [ 634 + "crossbeam-utils", 635 + ] 636 + 637 + [[package]] 638 + name = "crossbeam-skiplist" 639 + version = "0.1.3" 640 + source = "registry+https://github.com/rust-lang/crates.io-index" 641 + checksum = "df29de440c58ca2cc6e587ec3d22347551a32435fbde9d2bff64e78a9ffa151b" 642 + dependencies = [ 643 + "crossbeam-epoch", 606 644 "crossbeam-utils", 607 645 ] 608 646 ··· 921 959 ] 922 960 923 961 [[package]] 962 + name = "enum_dispatch" 963 + version = "0.3.13" 964 + source = "registry+https://github.com/rust-lang/crates.io-index" 965 + checksum = "aa18ce2bc66555b3218614519ac839ddb759a7d6720732f979ef8d13be147ecd" 966 + dependencies = [ 967 + "once_cell", 968 + "proc-macro2", 969 + "quote", 970 + "syn", 971 + ] 972 + 973 + [[package]] 924 974 name = "env_filter" 925 975 version = "1.0.1" 926 976 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 999 1049 checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" 1000 1050 1001 1051 [[package]] 1052 + name = "fjall" 1053 + version = "3.1.4" 1054 + source = "registry+https://github.com/rust-lang/crates.io-index" 1055 + checksum = "b62b25b4d815ae178d7d9e4aa32ee59f072efd5431c736abede1e6ee13c8c453" 1056 + dependencies = [ 1057 + "byteorder-lite", 1058 + "byteview", 1059 + "dashmap", 1060 + "flume", 1061 + "log", 1062 + "lsm-tree", 1063 + "lz4_flex", 1064 + "tempfile", 1065 + "xxhash-rust", 1066 + ] 1067 + 1068 + [[package]] 1002 1069 name = "flate2" 1003 1070 version = "1.1.9" 1004 1071 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1017 1084 "borrow-or-share", 1018 1085 "ref-cast", 1019 1086 "serde", 1087 + ] 1088 + 1089 + [[package]] 1090 + name = "flume" 1091 + version = "0.12.0" 1092 + source = "registry+https://github.com/rust-lang/crates.io-index" 1093 + checksum = "5e139bc46ca777eb5efaf62df0ab8cc5fd400866427e56c68b22e414e53bd3be" 1094 + dependencies = [ 1095 + "spin 0.9.8", 1020 1096 ] 1021 1097 1022 1098 [[package]] ··· 1307 1383 "equivalent", 1308 1384 "foldhash", 1309 1385 ] 1386 + 1387 + [[package]] 1388 + name = "hashbrown" 1389 + version = "0.16.1" 1390 + source = "registry+https://github.com/rust-lang/crates.io-index" 1391 + checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" 1310 1392 1311 1393 [[package]] 1312 1394 name = "hashbrown" ··· 1697 1779 ] 1698 1780 1699 1781 [[package]] 1782 + name = "interval-heap" 1783 + version = "0.0.5" 1784 + source = "registry+https://github.com/rust-lang/crates.io-index" 1785 + checksum = "11274e5e8e89b8607cfedc2910b6626e998779b48a019151c7604d0adcb86ac6" 1786 + dependencies = [ 1787 + "compare", 1788 + ] 1789 + 1790 + [[package]] 1700 1791 name = "inventory" 1701 1792 version = "0.3.24" 1702 1793 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2173 2264 version = "0.1.2" 2174 2265 source = "registry+https://github.com/rust-lang/crates.io-index" 2175 2266 checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" 2267 + 2268 + [[package]] 2269 + name = "lsm-tree" 2270 + version = "3.1.4" 2271 + source = "registry+https://github.com/rust-lang/crates.io-index" 2272 + checksum = "e447ac67ff6aef4ec07fc19e507b219336cbba90a697c0dbeb1bf51b91536b67" 2273 + dependencies = [ 2274 + "byteorder-lite", 2275 + "byteview", 2276 + "crossbeam-skiplist", 2277 + "enum_dispatch", 2278 + "interval-heap", 2279 + "log", 2280 + "lz4_flex", 2281 + "quick_cache", 2282 + "rustc-hash", 2283 + "self_cell", 2284 + "sfa", 2285 + "tempfile", 2286 + "varint-rs", 2287 + "xxhash-rust", 2288 + ] 2289 + 2290 + [[package]] 2291 + name = "lz4_flex" 2292 + version = "0.13.0" 2293 + source = "registry+https://github.com/rust-lang/crates.io-index" 2294 + checksum = "db9a0d582c2874f68138a16ce1867e0ffde6c0bb0a0df85e1f36d04146db488a" 2295 + dependencies = [ 2296 + "twox-hash", 2297 + ] 2176 2298 2177 2299 [[package]] 2178 2300 name = "mac" ··· 2910 3032 checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" 2911 3033 2912 3034 [[package]] 3035 + name = "quick_cache" 3036 + version = "0.6.21" 3037 + source = "registry+https://github.com/rust-lang/crates.io-index" 3038 + checksum = "5a70b1b8b47e31d0498ecbc3c5470bb931399a8bfed1fd79d1717a61ce7f96e3" 3039 + dependencies = [ 3040 + "equivalent", 3041 + "hashbrown 0.16.1", 3042 + ] 3043 + 3044 + [[package]] 2913 3045 name = "quinn" 2914 3046 version = "0.11.9" 2915 3047 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3381 3513 ] 3382 3514 3383 3515 [[package]] 3516 + name = "self_cell" 3517 + version = "1.2.2" 3518 + source = "registry+https://github.com/rust-lang/crates.io-index" 3519 + checksum = "b12e76d157a900eb52e81bc6e9f3069344290341720e9178cde2407113ac8d89" 3520 + 3521 + [[package]] 3384 3522 name = "semver" 3385 3523 version = "1.0.28" 3386 3524 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3531 3669 ] 3532 3670 3533 3671 [[package]] 3672 + name = "sfa" 3673 + version = "1.0.0" 3674 + source = "registry+https://github.com/rust-lang/crates.io-index" 3675 + checksum = "a1296838937cab56cd6c4eeeb8718ec777383700c33f060e2869867bd01d1175" 3676 + dependencies = [ 3677 + "byteorder-lite", 3678 + "log", 3679 + "xxhash-rust", 3680 + ] 3681 + 3682 + [[package]] 3534 3683 name = "sha1_smol" 3535 3684 version = "1.0.1" 3536 3685 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4116 4265 ] 4117 4266 4118 4267 [[package]] 4268 + name = "twox-hash" 4269 + version = "2.1.2" 4270 + source = "registry+https://github.com/rust-lang/crates.io-index" 4271 + checksum = "9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c" 4272 + 4273 + [[package]] 4119 4274 name = "typenum" 4120 4275 version = "1.19.0" 4121 4276 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4200 4355 checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" 4201 4356 4202 4357 [[package]] 4358 + name = "varint-rs" 4359 + version = "2.2.0" 4360 + source = "registry+https://github.com/rust-lang/crates.io-index" 4361 + checksum = "8f54a172d0620933a27a4360d3db3e2ae0dd6cceae9730751a036bbf182c4b23" 4362 + 4363 + [[package]] 4203 4364 name = "vcpkg" 4204 4365 version = "0.2.15" 4205 4366 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 4775 4936 "mac", 4776 4937 "markup5ever", 4777 4938 ] 4939 + 4940 + [[package]] 4941 + name = "xxhash-rust" 4942 + version = "0.8.15" 4943 + source = "registry+https://github.com/rust-lang/crates.io-index" 4944 + checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" 4778 4945 4779 4946 [[package]] 4780 4947 name = "yansi"
+1
Cargo.toml
··· 8 8 axum = "0.8.9" 9 9 dotenvy = "0.15.7" 10 10 env_logger = "0.11.10" 11 + fjall = "3.1.4" 11 12 jacquard = "0.11.0" 12 13 jacquard-api = { version = "0.11.1", features = ["default", "app_bsky"] } 13 14 jacquard-axum = "0.11.0"
+55 -7
src/handlers/xrpc/app_bsky_actor.rs
··· 1 - use std::os::unix::prelude; 2 - 3 1 use crate::handlers::xrpc::XrpcErrorResponse; 4 2 use crate::state::AppState; 5 3 use axum::{ ··· 8 6 response::{IntoResponse, Response}, 9 7 }; 10 8 use jacquard::{ 9 + IntoStatic, 11 10 prelude::IdentityResolver, 12 11 types::{datetime::Datetime, did::Did, uri::UriValue}, 13 12 xrpc::XrpcEndpoint, ··· 16 15 PreferencesItem, ProfileViewDetailed, 17 16 get_preferences::{GetPreferencesOutput, GetPreferencesRequest}, 18 17 get_profile::{GetProfileOutput, GetProfileRequest}, 18 + put_preferences::PutPreferencesRequest, 19 19 }; 20 20 use jacquard_axum::{ExtractXrpc, IntoRouter, service_auth::ExtractOptionalServiceAuth}; 21 21 use log::info; ··· 101 101 Ok(profile.into()) 102 102 } 103 103 104 - pub async fn get_preferences() -> Result<Json<GetPreferencesOutput<'static>>, XrpcErrorResponse> { 105 - let preferences: Vec<PreferencesItem> = vec![]; 104 + fn pref_key(did: &Did<'_>) -> Vec<u8> { 105 + format!("preferences:{}", did.as_ref()).into_bytes() 106 + } 107 + 108 + pub async fn get_preferences( 109 + State(state): State<AppState>, 110 + ExtractOptionalServiceAuth(auth): ExtractOptionalServiceAuth, 111 + ) -> Result<Json<GetPreferencesOutput<'static>>, XrpcErrorResponse> { 112 + let auth = auth.ok_or_else(XrpcErrorResponse::auth_missing)?; 113 + let did = auth.did(); 114 + 115 + let stored = state.persistent_ks.get(pref_key(did)).map_err(|err| { 116 + log::error!("fjall get preferences: {err}"); 117 + XrpcErrorResponse::internal_server_error() 118 + })?; 106 119 107 - let preference_output = GetPreferencesOutput { 120 + let preferences: Vec<PreferencesItem<'static>> = match stored { 121 + Some(bytes) => serde_json::from_slice::<Vec<PreferencesItem<'_>>>(&bytes) 122 + .map_err(|err| { 123 + log::error!("deserialize preferences: {err}"); 124 + XrpcErrorResponse::internal_server_error() 125 + })? 126 + .into_static(), 127 + None => Vec::new(), 128 + }; 129 + 130 + Ok(Json(GetPreferencesOutput { 108 131 preferences, 109 132 extra_data: Default::default(), 110 - }; 133 + })) 134 + } 135 + 136 + pub async fn put_preferences( 137 + State(state): State<AppState>, 138 + ExtractOptionalServiceAuth(auth): ExtractOptionalServiceAuth, 139 + ExtractXrpc(req): ExtractXrpc<PutPreferencesRequest>, 140 + ) -> Result<Json<()>, XrpcErrorResponse> { 141 + let auth = auth.ok_or_else(XrpcErrorResponse::auth_missing)?; 142 + let did = auth.did(); 143 + 144 + let bytes = serde_json::to_vec(&req.preferences).map_err(|err| { 145 + log::error!("serialize preferences: {err}"); 146 + XrpcErrorResponse::internal_server_error() 147 + })?; 111 148 112 - Ok(preference_output.into()) 149 + state 150 + .persistent_ks 151 + .insert(pref_key(did), bytes) 152 + .map_err(|err| { 153 + log::error!("fjall insert preferences: {err}"); 154 + XrpcErrorResponse::internal_server_error() 155 + })?; 156 + 157 + Ok(Json(())) 113 158 } 114 159 115 160 pub fn routes() -> Router<AppState> { ··· 119 164 )) 120 165 .merge(GetPreferencesRequest::into_router::<_, AppState, _>( 121 166 get_preferences, 167 + )) 168 + .merge(PutPreferencesRequest::into_router::<_, AppState, _>( 169 + put_preferences, 122 170 )) 123 171 }
+20 -7
src/main.rs
··· 1 + use axum::body::Bytes; 1 2 use axum::{ 2 3 Json, Router, body, 3 4 extract::{Request, State}, ··· 5 6 response::{IntoResponse, Response}, 6 7 routing::get, 7 8 }; 8 - use axum::body::Bytes; 9 9 use env_logger::Env; 10 + use fjall::Database; 10 11 use handlers::{well_known::did_document, xrpc::app_bsky_actor}; 11 12 use jacquard::{identity::resolver::ResolverOptions, prelude::JacquardResolver, types::did::Did}; 12 13 use jacquard_axum::service_auth::ServiceAuthConfig; ··· 40 41 .expect("APP_VIEW_DOMAIN produced an invalid did:web"); 41 42 let service_auth = ServiceAuthConfig::new(service_did, resolver.clone()); 42 43 44 + //fjall db setup 45 + let data_directory = 46 + env::var("CERES_DATA_DIRECTORY").unwrap_or_else(|_| ".ceres_data".to_string()); 47 + let db = Database::builder(data_directory).open()?; 48 + let persistent_ks = db.keyspace("persistent", fjall::KeyspaceCreateOptions::default)?; 49 + let cache_ks = db.keyspace("cache", fjall::KeyspaceCreateOptions::default)?; 50 + 43 51 let state = AppState { 44 52 service_auth, 45 53 reqwest_client, 46 54 resolver, 47 55 forwarded_app_view: env::var("FORWARDED_APP_VIEW").ok(), 56 + database: db, 57 + persistent_ks, 58 + cache_ks, 48 59 }; 49 60 50 61 let app = Router::new() ··· 63 74 Ok(()) 64 75 } 65 76 66 - async fn log_request( 67 - State(state): State<AppState>, 68 - req: Request, 69 - ) -> Response { 77 + async fn log_request(State(state): State<AppState>, req: Request) -> Response { 70 78 let (parts, body) = req.into_parts(); 71 79 let method = parts.method.clone(); 72 80 let path = parts.uri.path().to_string(); 73 - let query = parts.uri.query().map(|q| format!("?{}", q)).unwrap_or_default(); 81 + let query = parts 82 + .uri 83 + .query() 84 + .map(|q| format!("?{}", q)) 85 + .unwrap_or_default(); 74 86 75 87 info!("{method} {path}{query}"); 76 88 ··· 111 123 112 124 if let Some(ref base_url) = state.forwarded_app_view { 113 125 let target_url = format!("{base_url}{path}{query}"); 114 - let proxy_res = state.reqwest_client 126 + let proxy_res = state 127 + .reqwest_client 115 128 .request(method, &target_url) 116 129 .body(bytes) 117 130 .send()
+3
src/state.rs
··· 7 7 pub reqwest_client: reqwest::Client, 8 8 pub resolver: JacquardResolver, 9 9 pub forwarded_app_view: Option<String>, 10 + pub database: fjall::Database, 11 + pub persistent_ks: fjall::Keyspace, 12 + pub cache_ks: fjall::Keyspace, 10 13 } 11 14 12 15 impl ServiceAuth for AppState {