slop slop slop sahuuuurrr
0
fork

Configure Feed

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

log errors better

dawn 626e6362 cfb8f700

+1066 -527
+3
rust-toolchain.toml
··· 1 + [toolchain] 2 + channel = "stable" 3 + components = ["rust-analyzer", "rust-src", "rustfmt"]
+1063 -527
src/main.rs
··· 11 11 use jacquard_common::IntoStatic; 12 12 use jacquard_common::types::ident::AtIdentifier; 13 13 use serde::{Deserialize, Serialize}; 14 + use tracing; 14 15 use tracing_subscriber::EnvFilter; 15 16 16 17 #[derive(Clone)] ··· 346 347 ) -> Result<Response, StatusCode> { 347 348 // let hydrant = &app_state.hydrant; 348 349 let query_str = req.uri().query().unwrap_or(""); 349 - let Ok(params) = serde_urlencoded::from_str::<GetPostThreadParams>(query_str) else { 350 - return Err(StatusCode::BAD_REQUEST); 351 - }; 350 + let params = serde_urlencoded::from_str::<GetPostThreadParams>(query_str).map_err(|e| { 351 + tracing::error!("failed to parse query params: {e}"); 352 + StatusCode::BAD_REQUEST 353 + })?; 352 354 353 355 let viewer_did = get_auth_did(&req); 354 356 match get_thread_view_post( ··· 466 468 .and_then(|p| p.get("uri")) 467 469 .and_then(|u| u.as_str()) 468 470 { 469 - if let Ok(parent_thread) = Box::pin(get_thread_view_post( 471 + match Box::pin(get_thread_view_post( 470 472 app_state, 471 473 parent_uri, 472 474 0, ··· 475 477 )) 476 478 .await 477 479 { 478 - thread 479 - .as_object_mut() 480 - .unwrap() 481 - .insert("parent".to_string(), parent_thread); 480 + Ok(parent_thread) => { 481 + thread 482 + .as_object_mut() 483 + .unwrap() 484 + .insert("parent".to_string(), parent_thread); 485 + } 486 + Err(e) => { 487 + tracing::warn!("failed to fetch parent thread {parent_uri}: {e}"); 488 + } 482 489 } 483 490 } 484 491 } ··· 496 503 .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; 497 504 let mut replies = Vec::new(); 498 505 for bl in replies_page.backlinks { 499 - if let Ok(reply_thread) = Box::pin(get_thread_view_post( 506 + match Box::pin(get_thread_view_post( 500 507 app_state, 501 508 bl.uri.as_str(), 502 509 depth - 1, ··· 505 512 )) 506 513 .await 507 514 { 508 - replies.push(reply_thread); 515 + Ok(reply_thread) => { 516 + replies.push(reply_thread); 517 + } 518 + Err(e) => { 519 + tracing::warn!("failed to fetch reply thread {}: {e}", bl.uri); 520 + } 509 521 } 510 522 } 511 523 thread ··· 528 540 ) -> Result<Response, StatusCode> { 529 541 // let hydrant = &app_state.hydrant; 530 542 let query_str = req.uri().query().unwrap_or(""); 531 - let Ok(params) = serde_urlencoded::from_str::<GetProfileParams>(query_str) else { 532 - return Err(StatusCode::BAD_REQUEST); 533 - }; 543 + let params = serde_urlencoded::from_str::<GetProfileParams>(query_str).map_err(|e| { 544 + tracing::error!("failed to parse query params: {e}"); 545 + StatusCode::BAD_REQUEST 546 + })?; 534 547 535 - let Ok(ident) = AtIdentifier::new(&params.actor) else { 536 - return Err(StatusCode::BAD_REQUEST); 537 - }; 548 + let ident = AtIdentifier::new(&params.actor).map_err(|e| { 549 + tracing::error!("failed to parse actor identifier: {e}"); 550 + StatusCode::BAD_REQUEST 551 + })?; 538 552 539 - if let Ok(repo) = app_state.hydrant.repos.resolve(&ident).await { 540 - if let Ok(profile) = get_profile_internal(&app_state, repo.did.as_str(), None).await { 541 - return Ok(Json(profile).into_response()); 553 + match app_state.hydrant.repos.resolve(&ident).await { 554 + Ok(repo) => { 555 + match get_profile_internal(&app_state, repo.did.as_str(), None).await { 556 + Ok(profile) => return Ok(Json(profile).into_response()), 557 + Err(e) => { 558 + tracing::warn!("failed to get profile for {}: {e}", repo.did); 559 + } 560 + } 561 + } 562 + Err(e) => { 563 + tracing::error!("failed to resolve actor {}: {e}", params.actor); 542 564 } 543 565 } 544 566 ··· 715 737 ) -> Result<Response, StatusCode> { 716 738 // let hydrant = &app_state.hydrant; 717 739 let query_str = req.uri().query().unwrap_or(""); 718 - let Ok(params) = serde_urlencoded::from_str::<GetAuthorFeedParams>(query_str) else { 719 - return Err(StatusCode::BAD_REQUEST); 720 - }; 740 + let params = serde_urlencoded::from_str::<GetAuthorFeedParams>(query_str).map_err(|e| { 741 + tracing::error!("failed to parse query params: {e}"); 742 + StatusCode::BAD_REQUEST 743 + })?; 721 744 722 - let Ok(ident) = AtIdentifier::new(&params.actor) else { 723 - return Err(StatusCode::BAD_REQUEST); 724 - }; 745 + let ident = AtIdentifier::new(&params.actor).map_err(|e| { 746 + tracing::error!("failed to parse actor identifier: {e}"); 747 + StatusCode::BAD_REQUEST 748 + })?; 725 749 726 - let Ok(repo) = app_state.hydrant.repos.resolve(&ident).await else { 727 - return proxy_request(req).await; 750 + let repo = match app_state.hydrant.repos.resolve(&ident).await { 751 + Ok(repo) => repo, 752 + Err(e) => { 753 + tracing::error!("failed to resolve actor {}: {e}", params.actor); 754 + return proxy_request(req).await; 755 + } 728 756 }; 729 757 let did = repo.did.clone(); 730 758 731 759 let limit = params.limit.unwrap_or(50).min(100); 732 760 733 - let Ok(record_list) = repo 761 + let record_list = match repo 734 762 .list_records("app.bsky.feed.post", limit, true, params.cursor.as_deref()) 735 763 .await 736 - else { 737 - return proxy_request(req).await; 764 + { 765 + Ok(rl) => rl, 766 + Err(e) => { 767 + tracing::error!("failed to list records for {}: {e}", did); 768 + return proxy_request(req).await; 769 + } 738 770 }; 739 771 740 - let Ok(author_profile) = get_profile_internal(&app_state, did.as_str(), None).await else { 741 - return proxy_request(req).await; 772 + let author_profile = match get_profile_internal(&app_state, did.as_str(), None).await { 773 + Ok(p) => p, 774 + Err(e) => { 775 + tracing::error!("failed to get profile for {}: {e}", did); 776 + return proxy_request(req).await; 777 + } 742 778 }; 743 779 744 780 let mut feed = Vec::new(); ··· 784 820 ) -> Result<Response, StatusCode> { 785 821 // let hydrant = &app_state.hydrant; 786 822 let query_str = req.uri().query().unwrap_or(""); 787 - let Ok(params) = serde_urlencoded::from_str::<GetLikesParams>(query_str) else { 788 - return Err(StatusCode::BAD_REQUEST); 789 - }; 823 + let params = serde_urlencoded::from_str::<GetLikesParams>(query_str).map_err(|e| { 824 + tracing::error!("failed to parse query params: {e}"); 825 + StatusCode::BAD_REQUEST 826 + })?; 790 827 791 828 let limit = params.limit.unwrap_or(50).min(100); 792 829 ··· 797 834 .source("app.bsky.feed.like") 798 835 .limit(limit); 799 836 if let Some(cursor_str) = params.cursor { 800 - if let Ok(c) = data_encoding::BASE64URL_NOPAD.decode(cursor_str.as_bytes()) { 801 - fetch = fetch.cursor(c); 837 + match data_encoding::BASE64URL_NOPAD.decode(cursor_str.as_bytes()) { 838 + Ok(c) => { 839 + fetch = fetch.cursor(c); 840 + } 841 + Err(e) => { 842 + tracing::warn!("failed to decode cursor {cursor_str}: {e}"); 843 + } 802 844 } 803 845 } 804 846 805 - let Ok(backlinks_page) = fetch.run().await else { 806 - return proxy_request(req).await; 847 + let backlinks_page = match fetch.run().await { 848 + Ok(bp) => bp, 849 + Err(e) => { 850 + tracing::error!("failed to fetch backlinks for {}: {e}", params.uri); 851 + return proxy_request(req).await; 852 + } 807 853 }; 808 854 809 855 let mut likes = Vec::new(); 810 856 for bl in backlinks_page.backlinks { 811 - let Ok(uri) = jacquard_common::types::string::AtUri::new(bl.uri.as_str()) else { 812 - continue; 857 + let uri = match jacquard_common::types::string::AtUri::new(bl.uri.as_str()) { 858 + Ok(uri) => uri, 859 + Err(e) => { 860 + tracing::warn!("failed to parse uri {}: {e}", bl.uri); 861 + continue; 862 + } 813 863 }; 814 864 let author_ident = uri.authority(); 815 865 816 - let Ok(profile) = get_profile_internal(&app_state, author_ident.as_str(), None).await 817 - else { 818 - continue; 866 + let profile = match get_profile_internal(&app_state, author_ident.as_str(), None).await { 867 + Ok(p) => p, 868 + Err(e) => { 869 + tracing::warn!("failed to get profile for {author_ident}: {e}"); 870 + continue; 871 + } 819 872 }; 820 - let Ok(repo) = app_state.hydrant.repos.resolve(author_ident).await else { 821 - continue; 873 + let repo = match app_state.hydrant.repos.resolve(author_ident).await { 874 + Ok(repo) => repo, 875 + Err(e) => { 876 + tracing::warn!("failed to resolve actor {author_ident}: {e}"); 877 + continue; 878 + } 822 879 }; 823 880 let collection = uri.collection().unwrap().as_str(); 824 881 let rkey = uri.rkey().unwrap().0.as_str(); 825 882 826 - let Ok(Some(record)) = repo.get_record(collection, rkey).await else { 827 - continue; 883 + let record = match repo.get_record(collection, rkey).await { 884 + Ok(Some(record)) => record, 885 + Ok(None) => { 886 + tracing::warn!("record not found: {collection}/{rkey}"); 887 + continue; 888 + } 889 + Err(e) => { 890 + tracing::warn!("failed to get record {collection}/{rkey}: {e}"); 891 + continue; 892 + } 828 893 }; 829 894 let value = serde_json::to_value(record.value).unwrap_or(serde_json::json!({})); 830 895 let created_at = value ··· 858 923 ) -> Result<Response, StatusCode> { 859 924 // let hydrant = &app_state.hydrant; 860 925 let query_str = req.uri().query().unwrap_or(""); 861 - let Ok(params) = serde_urlencoded::from_str::<GetLikesParams>(query_str) else { 862 - return Err(StatusCode::BAD_REQUEST); 863 - }; 926 + let params = serde_urlencoded::from_str::<GetLikesParams>(query_str).map_err(|e| { 927 + tracing::error!("failed to parse query params: {e}"); 928 + StatusCode::BAD_REQUEST 929 + })?; 864 930 865 931 let limit = params.limit.unwrap_or(50).min(100); 866 932 ··· 871 937 .source("app.bsky.feed.repost") 872 938 .limit(limit); 873 939 if let Some(cursor_str) = params.cursor { 874 - if let Ok(c) = data_encoding::BASE64URL_NOPAD.decode(cursor_str.as_bytes()) { 875 - fetch = fetch.cursor(c); 940 + match data_encoding::BASE64URL_NOPAD.decode(cursor_str.as_bytes()) { 941 + Ok(c) => { 942 + fetch = fetch.cursor(c); 943 + } 944 + Err(e) => { 945 + tracing::warn!("failed to decode cursor {cursor_str}: {e}"); 946 + } 876 947 } 877 948 } 878 949 879 - let Ok(backlinks_page) = fetch.run().await else { 880 - return proxy_request(req).await; 950 + let backlinks_page = match fetch.run().await { 951 + Ok(bp) => bp, 952 + Err(e) => { 953 + tracing::error!("failed to fetch backlinks for {}: {e}", params.uri); 954 + return proxy_request(req).await; 955 + } 881 956 }; 882 957 883 958 let mut reposted_by = Vec::new(); 884 959 for bl in backlinks_page.backlinks { 885 - let Ok(uri) = jacquard_common::types::string::AtUri::new(bl.uri.as_str()) else { 886 - continue; 960 + let uri = match jacquard_common::types::string::AtUri::new(bl.uri.as_str()) { 961 + Ok(uri) => uri, 962 + Err(e) => { 963 + tracing::warn!("failed to parse uri {}: {e}", bl.uri); 964 + continue; 965 + } 887 966 }; 888 967 let author_ident = uri.authority(); 889 - let Ok(profile) = get_profile_internal(&app_state, author_ident.as_str(), None).await 890 - else { 891 - continue; 968 + let profile = match get_profile_internal(&app_state, author_ident.as_str(), None).await { 969 + Ok(p) => p, 970 + Err(e) => { 971 + tracing::warn!("failed to get profile for {author_ident}: {e}"); 972 + continue; 973 + } 892 974 }; 893 975 reposted_by.push(profile); 894 976 } ··· 938 1020 939 1021 let mut profiles = Vec::new(); 940 1022 for actor in actors { 941 - if let Ok(ident) = AtIdentifier::new(&actor) { 942 - if let Ok(repo) = app_state.hydrant.repos.resolve(&ident).await { 943 - if let Ok(profile) = get_profile_internal(&app_state, repo.did.as_str(), None).await 944 - { 945 - profiles.push(profile); 1023 + let ident = match AtIdentifier::new(&actor) { 1024 + Ok(ident) => ident, 1025 + Err(e) => { 1026 + tracing::warn!("failed to parse actor identifier {actor}: {e}"); 1027 + continue; 1028 + } 1029 + }; 1030 + match app_state.hydrant.repos.resolve(&ident).await { 1031 + Ok(repo) => { 1032 + match get_profile_internal(&app_state, repo.did.as_str(), None).await { 1033 + Ok(profile) => profiles.push(profile), 1034 + Err(e) => tracing::warn!("failed to get profile for {}: {e}", repo.did), 946 1035 } 947 1036 } 1037 + Err(e) => tracing::warn!("failed to resolve actor {actor}: {e}"), 948 1038 } 949 1039 } 950 1040 ··· 964 1054 965 1055 let mut posts = Vec::new(); 966 1056 for uri in uris { 967 - if let Ok(post) = get_post_view(&app_state, &uri, None).await { 968 - posts.push(post); 1057 + match get_post_view(&app_state, &uri, None).await { 1058 + Ok(post) => posts.push(post), 1059 + Err(e) => tracing::warn!("failed to get post view for {uri}: {e}"), 969 1060 } 970 1061 } 971 1062 ··· 987 1078 ) -> Result<Response, StatusCode> { 988 1079 // let hydrant = &app_state.hydrant; 989 1080 let query_str = req.uri().query().unwrap_or(""); 990 - let Ok(params) = serde_urlencoded::from_str::<GetFollowsParams>(query_str) else { 991 - return Err(StatusCode::BAD_REQUEST); 992 - }; 1081 + let params: GetFollowsParams = serde_urlencoded::from_str(query_str).map_err(|e| { 1082 + tracing::error!("failed to parse query params: {e}"); 1083 + StatusCode::BAD_REQUEST 1084 + })?; 993 1085 994 - let Ok(ident) = AtIdentifier::new(&params.actor) else { 995 - return Err(StatusCode::BAD_REQUEST); 996 - }; 997 - let Ok(repo) = app_state.hydrant.repos.resolve(&ident).await else { 998 - return proxy_request(req).await; 1086 + let ident = AtIdentifier::new(&params.actor).map_err(|e| { 1087 + tracing::error!("failed to parse actor identifier: {e}"); 1088 + StatusCode::BAD_REQUEST 1089 + })?; 1090 + let repo = match app_state.hydrant.repos.resolve(&ident).await { 1091 + Ok(repo) => repo, 1092 + Err(e) => { 1093 + tracing::error!("failed to resolve actor {}: {e}", params.actor); 1094 + return proxy_request(req).await; 1095 + } 999 1096 }; 1000 1097 1001 1098 let limit = params.limit.unwrap_or(50).min(100); 1002 - let Ok(record_list) = repo 1099 + let record_list = match repo 1003 1100 .list_records( 1004 1101 "app.bsky.graph.follow", 1005 1102 limit, ··· 1007 1104 params.cursor.as_deref(), 1008 1105 ) 1009 1106 .await 1010 - else { 1011 - return proxy_request(req).await; 1107 + { 1108 + Ok(rl) => rl, 1109 + Err(e) => { 1110 + tracing::error!("failed to list follows for {}: {e}", repo.did); 1111 + return proxy_request(req).await; 1112 + } 1012 1113 }; 1013 1114 1014 1115 let mut follows = Vec::new(); 1015 1116 for rec in record_list.records { 1016 1117 let value = serde_json::to_value(&rec.value).unwrap_or(serde_json::json!({})); 1017 1118 if let Some(subject_did) = value.get("subject").and_then(|s| s.as_str()) { 1018 - if let Ok(profile) = get_profile_internal(&app_state, subject_did, None).await { 1019 - follows.push(profile); 1119 + match get_profile_internal(&app_state, subject_did, None).await { 1120 + Ok(profile) => follows.push(profile), 1121 + Err(e) => tracing::warn!("failed to get profile for {subject_did}: {e}"), 1020 1122 } 1021 1123 } 1022 1124 } 1023 1125 1024 - let Ok(subject_profile) = get_profile_internal(&app_state, repo.did.as_str(), None).await 1025 - else { 1026 - return proxy_request(req).await; 1126 + let subject_profile = match get_profile_internal(&app_state, repo.did.as_str(), None).await { 1127 + Ok(p) => p, 1128 + Err(e) => { 1129 + tracing::error!("failed to get profile for {}: {e}", repo.did); 1130 + return proxy_request(req).await; 1131 + } 1027 1132 }; 1028 1133 1029 1134 Ok(Json(serde_json::json!({ ··· 1040 1145 ) -> Result<Response, StatusCode> { 1041 1146 // let hydrant = &app_state.hydrant; 1042 1147 let query_str = req.uri().query().unwrap_or(""); 1043 - let Ok(params) = serde_urlencoded::from_str::<GetFollowsParams>(query_str) else { 1044 - return Err(StatusCode::BAD_REQUEST); 1045 - }; 1148 + let params: GetFollowsParams = serde_urlencoded::from_str(query_str).map_err(|e| { 1149 + tracing::error!("failed to parse query params: {e}"); 1150 + StatusCode::BAD_REQUEST 1151 + })?; 1046 1152 1047 - let Ok(ident) = AtIdentifier::new(&params.actor) else { 1048 - return Err(StatusCode::BAD_REQUEST); 1049 - }; 1050 - let Ok(repo) = app_state.hydrant.repos.resolve(&ident).await else { 1051 - return proxy_request(req).await; 1153 + let ident = AtIdentifier::new(&params.actor).map_err(|e| { 1154 + tracing::error!("failed to parse actor identifier: {e}"); 1155 + StatusCode::BAD_REQUEST 1156 + })?; 1157 + let repo = match app_state.hydrant.repos.resolve(&ident).await { 1158 + Ok(repo) => repo, 1159 + Err(e) => { 1160 + tracing::error!("failed to resolve actor {}: {e}", params.actor); 1161 + return proxy_request(req).await; 1162 + } 1052 1163 }; 1053 1164 1054 1165 let limit = params.limit.unwrap_or(50).min(100); ··· 1059 1170 .source("app.bsky.graph.follow") 1060 1171 .limit(limit); 1061 1172 if let Some(cursor_str) = params.cursor { 1062 - if let Ok(c) = data_encoding::BASE64URL_NOPAD.decode(cursor_str.as_bytes()) { 1063 - fetch = fetch.cursor(c); 1173 + match data_encoding::BASE64URL_NOPAD.decode(cursor_str.as_bytes()) { 1174 + Ok(c) => fetch = fetch.cursor(c), 1175 + Err(e) => tracing::warn!("failed to decode cursor {cursor_str}: {e}"), 1064 1176 } 1065 1177 } 1066 1178 1067 - let Ok(backlinks_page) = fetch.run().await else { 1068 - return proxy_request(req).await; 1179 + let backlinks_page = match fetch.run().await { 1180 + Ok(bp) => bp, 1181 + Err(e) => { 1182 + tracing::error!("failed to fetch backlinks for {}: {e}", repo.did); 1183 + return proxy_request(req).await; 1184 + } 1069 1185 }; 1070 1186 1071 1187 let mut followers = Vec::new(); 1072 1188 for bl in backlinks_page.backlinks { 1073 - if let Ok(uri) = jacquard_common::types::string::AtUri::new(bl.uri.as_str()) { 1074 - let author_ident = uri.authority(); 1075 - if let Ok(profile) = get_profile_internal(&app_state, author_ident.as_str(), None).await 1076 - { 1077 - followers.push(profile); 1189 + match jacquard_common::types::string::AtUri::new(bl.uri.as_str()) { 1190 + Ok(uri) => { 1191 + let author_ident = uri.authority(); 1192 + match get_profile_internal(&app_state, author_ident.as_str(), None).await { 1193 + Ok(profile) => followers.push(profile), 1194 + Err(e) => tracing::warn!("failed to get profile for {author_ident}: {e}"), 1195 + } 1078 1196 } 1197 + Err(e) => tracing::warn!("failed to parse uri {}: {e}", bl.uri), 1079 1198 } 1080 1199 } 1081 1200 1082 - let Ok(subject_profile) = get_profile_internal(&app_state, repo.did.as_str(), None).await 1083 - else { 1084 - return proxy_request(req).await; 1201 + let subject_profile = match get_profile_internal(&app_state, repo.did.as_str(), None).await { 1202 + Ok(p) => p, 1203 + Err(e) => { 1204 + tracing::error!("failed to get profile for {}: {e}", repo.did); 1205 + return proxy_request(req).await; 1206 + } 1085 1207 }; 1086 1208 1087 1209 let cursor = backlinks_page ··· 1140 1262 let body_bytes = axum::body::to_bytes(req.into_body(), usize::MAX) 1141 1263 .await 1142 1264 .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; 1143 - let Ok(payload) = serde_json::from_slice::<CreateBookmarkReq>(&body_bytes) else { 1144 - return Err(StatusCode::BAD_REQUEST); 1145 - }; 1265 + let payload: CreateBookmarkReq = serde_json::from_slice(&body_bytes).map_err(|e| { 1266 + tracing::error!("failed to parse create bookmark request: {e}"); 1267 + StatusCode::BAD_REQUEST 1268 + })?; 1146 1269 1147 1270 let key = format!("bookmark:{}:{}", did, payload.uri); 1148 1271 app_state 1149 1272 .bookmarks 1150 1273 .insert(key.as_bytes(), payload.cid.as_bytes()) 1151 - .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; 1274 + .map_err(|e| { 1275 + tracing::error!("failed to insert bookmark: {e}"); 1276 + StatusCode::INTERNAL_SERVER_ERROR 1277 + })?; 1152 1278 1153 1279 Ok(Json(serde_json::json!({})).into_response()) 1154 1280 } ··· 1169 1295 let body_bytes = axum::body::to_bytes(req.into_body(), usize::MAX) 1170 1296 .await 1171 1297 .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; 1172 - let Ok(payload) = serde_json::from_slice::<DeleteBookmarkReq>(&body_bytes) else { 1173 - return Err(StatusCode::BAD_REQUEST); 1174 - }; 1298 + let payload: DeleteBookmarkReq = serde_json::from_slice(&body_bytes).map_err(|e| { 1299 + tracing::error!("failed to parse delete bookmark request: {e}"); 1300 + StatusCode::BAD_REQUEST 1301 + })?; 1175 1302 1176 1303 let key = format!("bookmark:{}:{}", did, payload.uri); 1177 1304 app_state 1178 1305 .bookmarks 1179 1306 .remove(key.as_bytes()) 1180 - .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; 1307 + .map_err(|e| { 1308 + tracing::error!("failed to remove bookmark: {e}"); 1309 + StatusCode::INTERNAL_SERVER_ERROR 1310 + })?; 1181 1311 1182 1312 Ok(Json(serde_json::json!({})).into_response()) 1183 1313 } ··· 1221 1351 let mut fetched_items = Vec::new(); 1222 1352 let mut next_cursor = None; 1223 1353 for item in iter { 1224 - let Ok((key, cid_bytes)) = item.into_inner() else { 1225 - continue; 1354 + let (key, cid_bytes) = match item.into_inner() { 1355 + Ok(inner) => inner, 1356 + Err(e) => { 1357 + tracing::warn!("failed to get item from bookmarks iterator: {e}"); 1358 + continue; 1359 + } 1226 1360 }; 1227 1361 if !key.starts_with(prefix.as_bytes()) { 1228 1362 break; ··· 1240 1374 let uri_str = &key_str[prefix.len()..]; 1241 1375 let cid_str = String::from_utf8_lossy(&cid_bytes); 1242 1376 1243 - if let Ok(uri) = jacquard_common::types::string::AtUri::new(uri_str) { 1244 - let author_ident = uri.authority(); 1245 - let collection = uri.collection().unwrap().as_str(); 1246 - let rkey = uri.rkey().unwrap().0.as_str(); 1377 + match jacquard_common::types::string::AtUri::new(uri_str) { 1378 + Ok(uri) => { 1379 + let author_ident = uri.authority(); 1380 + let collection = uri.collection().unwrap().as_str(); 1381 + let rkey = uri.rkey().unwrap().0.as_str(); 1247 1382 1248 - if let Ok(repo) = app_state.hydrant.repos.resolve(author_ident).await { 1249 - if let Ok(Some(record)) = repo.get_record(collection, rkey).await { 1250 - if let Ok(author_profile) = 1251 - get_profile_internal(&app_state, repo.did.as_str(), None).await 1252 - { 1253 - bookmarks.push(serde_json::json!({ 1254 - "uri": uri_str, 1255 - "cid": cid_str.to_string(), 1256 - "author": author_profile, 1257 - "record": record.value, 1258 - "replyCount": app_state.hydrant.backlinks.count(uri_str.to_string()).source("app.bsky.feed.post").run().await.unwrap_or(0), 1259 - "repostCount": app_state.hydrant.backlinks.count(uri_str.to_string()).source("app.bsky.feed.repost").run().await.unwrap_or(0), 1260 - "likeCount": app_state.hydrant.backlinks.count(uri_str.to_string()).source("app.bsky.feed.like").run().await.unwrap_or(0), 1261 - "indexedAt": chrono::Utc::now().to_rfc3339(), 1262 - })); 1383 + match app_state.hydrant.repos.resolve(author_ident).await { 1384 + Ok(repo) => { 1385 + match repo.get_record(collection, rkey).await { 1386 + Ok(Some(record)) => { 1387 + match get_profile_internal(&app_state, repo.did.as_str(), None).await 1388 + { 1389 + Ok(author_profile) => { 1390 + bookmarks.push(serde_json::json!({ 1391 + "uri": uri_str, 1392 + "cid": cid_str.to_string(), 1393 + "author": author_profile, 1394 + "record": record.value, 1395 + "replyCount": app_state.hydrant.backlinks.count(uri_str.to_string()).source("app.bsky.feed.post").run().await.unwrap_or(0), 1396 + "repostCount": app_state.hydrant.backlinks.count(uri_str.to_string()).source("app.bsky.feed.repost").run().await.unwrap_or(0), 1397 + "likeCount": app_state.hydrant.backlinks.count(uri_str.to_string()).source("app.bsky.feed.like").run().await.unwrap_or(0), 1398 + "indexedAt": chrono::Utc::now().to_rfc3339(), 1399 + })); 1400 + } 1401 + Err(e) => { 1402 + tracing::warn!("failed to get profile for {}: {e}", repo.did) 1403 + } 1404 + } 1405 + } 1406 + Ok(None) => tracing::warn!("bookmark record not found: {uri_str}"), 1407 + Err(e) => tracing::warn!("failed to get bookmark record {uri_str}: {e}"), 1408 + } 1263 1409 } 1410 + Err(e) => tracing::warn!("failed to resolve actor {author_ident}: {e}"), 1264 1411 } 1265 1412 } 1413 + Err(e) => tracing::warn!("failed to parse bookmark uri {uri_str}: {e}"), 1266 1414 } 1267 1415 1268 1416 if bookmarks.len() >= limit { ··· 1293 1441 1294 1442 let body_bytes = axum::body::to_bytes(req.into_body(), usize::MAX) 1295 1443 .await 1296 - .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; 1297 - let Ok(payload) = serde_json::from_slice::<CreateDraftReq>(&body_bytes) else { 1298 - return Err(StatusCode::BAD_REQUEST); 1299 - }; 1444 + .map_err(|e| { 1445 + tracing::error!("failed to read request body: {e}"); 1446 + StatusCode::INTERNAL_SERVER_ERROR 1447 + })?; 1448 + let payload = serde_json::from_slice::<CreateDraftReq>(&body_bytes).map_err(|e| { 1449 + tracing::error!("failed to deserialize create_draft request: {e}"); 1450 + StatusCode::BAD_REQUEST 1451 + })?; 1300 1452 1301 1453 let tid = jacquard_common::types::tid::Tid::now(1.try_into().unwrap()).to_string(); 1302 1454 let key = format!("draft:{}:{}", did, tid); ··· 1340 1492 1341 1493 let body_bytes = axum::body::to_bytes(req.into_body(), usize::MAX) 1342 1494 .await 1343 - .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; 1344 - let Ok(payload) = serde_json::from_slice::<UpdateDraftReq>(&body_bytes) else { 1345 - return Err(StatusCode::BAD_REQUEST); 1346 - }; 1495 + .map_err(|e| { 1496 + tracing::error!("failed to read request body: {e}"); 1497 + StatusCode::INTERNAL_SERVER_ERROR 1498 + })?; 1499 + let payload = serde_json::from_slice::<UpdateDraftReq>(&body_bytes).map_err(|e| { 1500 + tracing::error!("failed to deserialize update_draft request: {e}"); 1501 + StatusCode::BAD_REQUEST 1502 + })?; 1347 1503 1348 1504 let tid = payload.draft.id; 1349 1505 let key = format!("draft:{}:{}", did, tid); ··· 1351 1507 let existing = app_state 1352 1508 .drafts 1353 1509 .get(key.as_bytes()) 1354 - .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; 1510 + .map_err(|e| { 1511 + tracing::error!("failed to get draft from db: {e}"); 1512 + StatusCode::INTERNAL_SERVER_ERROR 1513 + })?; 1355 1514 if let Some(existing_bytes) = existing.as_deref() { 1356 - if let Ok(mut existing_obj) = serde_json::from_slice::<serde_json::Value>(&existing_bytes) { 1357 - let now = chrono::Utc::now().to_rfc3339(); 1358 - existing_obj["draft"] = payload.draft.draft; 1359 - existing_obj["updatedAt"] = serde_json::json!(now); 1515 + match serde_json::from_slice::<serde_json::Value>(&existing_bytes) { 1516 + Ok(mut existing_obj) => { 1517 + let now = chrono::Utc::now().to_rfc3339(); 1518 + existing_obj["draft"] = payload.draft.draft; 1519 + existing_obj["updatedAt"] = serde_json::json!(now); 1360 1520 1361 - let val = 1362 - serde_json::to_vec(&existing_obj).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; 1363 - app_state 1364 - .drafts 1365 - .insert(key.as_bytes(), val) 1366 - .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; 1521 + let val = serde_json::to_vec(&existing_obj).map_err(|e| { 1522 + tracing::error!("failed to serialize updated draft: {e}"); 1523 + StatusCode::INTERNAL_SERVER_ERROR 1524 + })?; 1525 + app_state.drafts.insert(key.as_bytes(), val).map_err(|e| { 1526 + tracing::error!("failed to insert updated draft to db: {e}"); 1527 + StatusCode::INTERNAL_SERVER_ERROR 1528 + })?; 1529 + } 1530 + Err(e) => { 1531 + tracing::error!("failed to parse existing draft from db: {e}"); 1532 + } 1367 1533 } 1368 1534 } 1369 1535 ··· 1385 1551 1386 1552 let body_bytes = axum::body::to_bytes(req.into_body(), usize::MAX) 1387 1553 .await 1388 - .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; 1389 - let Ok(payload) = serde_json::from_slice::<DeleteDraftReq>(&body_bytes) else { 1390 - return Err(StatusCode::BAD_REQUEST); 1391 - }; 1554 + .map_err(|e| { 1555 + tracing::error!("failed to read request body: {e}"); 1556 + StatusCode::INTERNAL_SERVER_ERROR 1557 + })?; 1558 + let payload = serde_json::from_slice::<DeleteDraftReq>(&body_bytes).map_err(|e| { 1559 + tracing::error!("failed to deserialize delete_draft request: {e}"); 1560 + StatusCode::BAD_REQUEST 1561 + })?; 1392 1562 1393 1563 let key = format!("draft:{}:{}", did, payload.id); 1394 - app_state 1395 - .drafts 1396 - .remove(key.as_bytes()) 1397 - .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; 1564 + app_state.drafts.remove(key.as_bytes()).map_err(|e| { 1565 + tracing::error!("failed to remove draft from db: {e}"); 1566 + StatusCode::INTERNAL_SERVER_ERROR 1567 + })?; 1398 1568 1399 1569 Ok(Json(serde_json::json!({})).into_response()) 1400 1570 } ··· 1438 1608 let mut next_cursor = None; 1439 1609 1440 1610 for item in iter { 1441 - let Ok((key, val_bytes)) = item.into_inner() else { 1442 - continue; 1611 + let (key, val_bytes) = match item.into_inner() { 1612 + Ok(v) => v, 1613 + Err(e) => { 1614 + tracing::error!("failed to get item from drafts iterator: {e}"); 1615 + continue; 1616 + } 1443 1617 }; 1444 1618 if !key.starts_with(prefix.as_bytes()) { 1445 1619 break; 1446 1620 } 1447 1621 1448 - if let Ok(obj) = serde_json::from_slice::<serde_json::Value>(&val_bytes) { 1449 - drafts.push(obj); 1622 + match serde_json::from_slice::<serde_json::Value>(&val_bytes) { 1623 + Ok(obj) => drafts.push(obj), 1624 + Err(e) => tracing::error!("failed to parse draft from db: {e}"), 1450 1625 } 1451 1626 1452 1627 if drafts.len() >= limit { ··· 1478 1653 ) -> Result<Response, StatusCode> { 1479 1654 // let hydrant = &app_state.hydrant; 1480 1655 let query_str = req.uri().query().unwrap_or(""); 1481 - let Ok(params) = serde_urlencoded::from_str::<GetTimelineParams>(query_str) else { 1482 - return Err(StatusCode::BAD_REQUEST); 1483 - }; 1656 + let params = serde_urlencoded::from_str::<GetTimelineParams>(query_str).map_err(|e| { 1657 + tracing::error!("failed to parse get_timeline query params: {e}"); 1658 + StatusCode::BAD_REQUEST 1659 + })?; 1484 1660 1485 1661 let Some(did_str) = get_auth_did(&req) else { 1486 1662 return Err(StatusCode::UNAUTHORIZED); 1487 1663 }; 1488 1664 1489 - let Ok(ident) = AtIdentifier::new(&did_str) else { 1490 - return Err(StatusCode::BAD_REQUEST); 1491 - }; 1492 - let Ok(repo) = app_state.hydrant.repos.resolve(&ident).await else { 1493 - return proxy_request(req).await; 1665 + let ident = AtIdentifier::new(&did_str).map_err(|e| { 1666 + tracing::error!("failed to create AtIdentifier from did_str {did_str}: {e}"); 1667 + StatusCode::BAD_REQUEST 1668 + })?; 1669 + let repo = match app_state.hydrant.repos.resolve(&ident).await { 1670 + Ok(r) => r, 1671 + Err(e) => { 1672 + tracing::error!("failed to resolve repo for {ident}: {e}"); 1673 + return proxy_request(req).await; 1674 + } 1494 1675 }; 1495 1676 1496 1677 // Get all follows of auth user ··· 1499 1680 1500 1681 let mut cursor = None; 1501 1682 loop { 1502 - let Ok(record_list) = repo 1683 + let record_list = match repo 1503 1684 .list_records("app.bsky.graph.follow", 100, true, cursor.as_deref()) 1504 1685 .await 1505 - else { 1506 - break; 1686 + { 1687 + Ok(rl) => rl, 1688 + Err(e) => { 1689 + tracing::error!("failed to list follows for {}: {e}", repo.did); 1690 + break; 1691 + } 1507 1692 }; 1508 1693 for rec in &record_list.records { 1509 1694 let value = serde_json::to_value(&rec.value).unwrap_or(serde_json::json!({})); 1510 1695 if let Some(subject_did) = value.get("subject").and_then(|s| s.as_str()) { 1511 - if let Ok(did) = jacquard_common::types::string::Did::new(subject_did) { 1512 - follows.insert(did.into_static()); 1696 + match jacquard_common::types::string::Did::new(subject_did) { 1697 + Ok(did) => { 1698 + follows.insert(did.into_static()); 1699 + } 1700 + Err(e) => { 1701 + tracing::error!("failed to parse subject DID {subject_did}: {e}"); 1702 + } 1513 1703 } 1514 1704 } 1515 1705 } ··· 1524 1714 let mut all_items = Vec::new(); 1525 1715 1526 1716 for did in follows { 1527 - if let Ok(followed_repo) = app_state.hydrant.repos.get(&did).info().await { 1528 - if let Some(info) = followed_repo { 1717 + match app_state.hydrant.repos.get(&did).info().await { 1718 + Ok(Some(info)) => { 1529 1719 if !info.tracked { 1530 1720 continue; 1531 1721 } 1532 - } else { 1722 + } 1723 + Ok(None) => continue, 1724 + Err(e) => { 1725 + tracing::error!("failed to get info for followed repo {did}: {e}"); 1533 1726 continue; 1534 1727 } 1535 - } else { 1536 - continue; 1537 1728 } 1538 1729 1539 1730 let followed_repo = app_state.hydrant.repos.get(&did); 1540 1731 1541 1732 // get posts 1542 - if let Ok(record_list) = followed_repo 1733 + match followed_repo 1543 1734 .list_records("app.bsky.feed.post", limit, true, None) 1544 1735 .await 1545 1736 { 1546 - for rec in record_list.records { 1547 - let rkey = rec.rkey.as_str().to_string(); 1548 - all_items.push(( 1549 - did.clone(), 1550 - "app.bsky.feed.post".to_string(), 1551 - rkey, 1552 - rec.value, 1553 - )); 1737 + Ok(record_list) => { 1738 + for rec in record_list.records { 1739 + let rkey = rec.rkey.as_str().to_string(); 1740 + all_items.push(( 1741 + did.clone(), 1742 + "app.bsky.feed.post".to_string(), 1743 + rkey, 1744 + rec.value, 1745 + )); 1746 + } 1747 + } 1748 + Err(e) => { 1749 + tracing::warn!("failed to list posts for {did}: {e}"); 1554 1750 } 1555 1751 } 1556 1752 1557 1753 // get reposts 1558 - if let Ok(record_list) = followed_repo 1754 + match followed_repo 1559 1755 .list_records("app.bsky.feed.repost", limit, true, None) 1560 1756 .await 1561 1757 { 1562 - for rec in record_list.records { 1563 - let rkey = rec.rkey.as_str().to_string(); 1564 - all_items.push(( 1565 - did.clone(), 1566 - "app.bsky.feed.repost".to_string(), 1567 - rkey, 1568 - rec.value, 1569 - )); 1758 + Ok(record_list) => { 1759 + for rec in record_list.records { 1760 + let rkey = rec.rkey.as_str().to_string(); 1761 + all_items.push(( 1762 + did.clone(), 1763 + "app.bsky.feed.repost".to_string(), 1764 + rkey, 1765 + rec.value, 1766 + )); 1767 + } 1768 + } 1769 + Err(e) => { 1770 + tracing::warn!("failed to list reposts for {did}: {e}"); 1570 1771 } 1571 1772 } 1572 1773 } ··· 1588 1789 let val_json = serde_json::to_value(&value).unwrap_or(serde_json::json!({})); 1589 1790 1590 1791 if col == "app.bsky.feed.post" { 1591 - if let Ok(post_view) = get_post_view(&app_state, &uri, None).await { 1592 - feed.push(serde_json::json!({ "post": post_view })); 1792 + match get_post_view(&app_state, &uri, None).await { 1793 + Ok(post_view) => feed.push(serde_json::json!({ "post": post_view })), 1794 + Err(e) => tracing::warn!("failed to get post view for {uri}: {e}"), 1593 1795 } 1594 1796 } else if col == "app.bsky.feed.repost" { 1595 1797 if let Some(subject_uri) = val_json ··· 1597 1799 .and_then(|s| s.get("uri")) 1598 1800 .and_then(|u| u.as_str()) 1599 1801 { 1600 - if let Ok(post_view) = get_post_view(&app_state, subject_uri, None).await { 1601 - if let Ok(reposter_profile) = 1602 - get_profile_internal(&app_state, did.as_str(), None).await 1603 - { 1604 - feed.push(serde_json::json!({ 1605 - "post": post_view, 1606 - "reason": { 1607 - "$type": "app.bsky.feed.defs#reasonRepost", 1608 - "by": reposter_profile, 1609 - "indexedAt": val_json.get("createdAt").and_then(|c| c.as_str()).map(|s| s.to_string()).unwrap_or_else(|| chrono::Utc::now().to_rfc3339()), 1802 + match get_post_view(&app_state, subject_uri, None).await { 1803 + Ok(post_view) => { 1804 + match get_profile_internal(&app_state, did.as_str(), None).await { 1805 + Ok(reposter_profile) => { 1806 + feed.push(serde_json::json!({ 1807 + "post": post_view, 1808 + "reason": { 1809 + "$type": "app.bsky.feed.defs#reasonRepost", 1810 + "by": reposter_profile, 1811 + "indexedAt": val_json.get("createdAt").and_then(|c| c.as_str()).map(|s| s.to_string()).unwrap_or_else(|| chrono::Utc::now().to_rfc3339()), 1812 + } 1813 + })); 1610 1814 } 1611 - })); 1815 + Err(e) => { 1816 + tracing::warn!("failed to get profile for reposter {did}: {e}"); 1817 + } 1818 + } 1819 + } 1820 + Err(e) => { 1821 + tracing::warn!("failed to get post view for reposted post {subject_uri}: {e}"); 1612 1822 } 1613 1823 } 1614 1824 } ··· 1639 1849 ) -> Result<Response, StatusCode> { 1640 1850 // let hydrant = &app_state.hydrant; 1641 1851 let query_str = req.uri().query().unwrap_or(""); 1642 - let Ok(params) = serde_urlencoded::from_str::<GetQuotesParams>(query_str) else { 1643 - return Err(StatusCode::BAD_REQUEST); 1644 - }; 1852 + let params = serde_urlencoded::from_str::<GetQuotesParams>(query_str).map_err(|e| { 1853 + tracing::error!("failed to parse get_quotes query params: {e}"); 1854 + StatusCode::BAD_REQUEST 1855 + })?; 1645 1856 1646 1857 let limit = params.limit.unwrap_or(50).min(100); 1647 1858 ··· 1652 1863 .source("app.bsky.feed.post") 1653 1864 .limit(limit * 3); 1654 1865 if let Some(cursor_str) = params.cursor { 1655 - if let Ok(c) = data_encoding::BASE64URL_NOPAD.decode(cursor_str.as_bytes()) { 1656 - fetch = fetch.cursor(c); 1866 + match data_encoding::BASE64URL_NOPAD.decode(cursor_str.as_bytes()) { 1867 + Ok(c) => { 1868 + fetch = fetch.cursor(c); 1869 + } 1870 + Err(e) => { 1871 + tracing::error!("failed to decode cursor {cursor_str}: {e}"); 1872 + } 1657 1873 } 1658 1874 } 1659 1875 1660 - let Ok(backlinks_page) = fetch.run().await else { 1661 - return proxy_request(req).await; 1876 + let backlinks_page = match fetch.run().await { 1877 + Ok(bp) => bp, 1878 + Err(e) => { 1879 + tracing::error!("failed to fetch backlinks for {}: {e}", params.uri); 1880 + return proxy_request(req).await; 1881 + } 1662 1882 }; 1663 1883 1664 1884 let mut posts = Vec::new(); ··· 1668 1888 break; 1669 1889 } 1670 1890 1671 - let Ok(uri) = jacquard_common::types::string::AtUri::new(bl.uri.as_str()) else { 1672 - continue; 1891 + let uri = match jacquard_common::types::string::AtUri::new(bl.uri.as_str()) { 1892 + Ok(u) => u, 1893 + Err(e) => { 1894 + tracing::error!("failed to parse backlink URI {}: {e}", bl.uri); 1895 + continue; 1896 + } 1673 1897 }; 1674 1898 let author_ident = uri.authority(); 1675 1899 let collection = uri.collection().unwrap().as_str(); 1676 1900 let rkey = uri.rkey().unwrap().0.as_str(); 1677 1901 1678 - let Ok(repo) = app_state.hydrant.repos.resolve(author_ident).await else { 1679 - continue; 1902 + let repo = match app_state.hydrant.repos.resolve(author_ident).await { 1903 + Ok(r) => r, 1904 + Err(e) => { 1905 + tracing::error!("failed to resolve repo for {author_ident}: {e}"); 1906 + continue; 1907 + } 1680 1908 }; 1681 - let Ok(Some(record)) = repo.get_record(collection, rkey).await else { 1682 - continue; 1909 + let record = match repo.get_record(collection, rkey).await { 1910 + Ok(Some(rec)) => rec, 1911 + Ok(None) => continue, 1912 + Err(e) => { 1913 + tracing::error!("failed to get record {collection}/{rkey} from repo {author_ident}: {e}"); 1914 + continue; 1915 + } 1683 1916 }; 1684 1917 let value = serde_json::to_value(&record.value).unwrap_or(serde_json::json!({})); 1685 1918 ··· 1704 1937 }); 1705 1938 1706 1939 if is_quote { 1707 - if let Ok(post_view) = get_post_view(&app_state, bl.uri.as_str(), None).await { 1708 - posts.push(post_view); 1709 - found += 1; 1940 + match get_post_view(&app_state, bl.uri.as_str(), None).await { 1941 + Ok(post_view) => { 1942 + posts.push(post_view); 1943 + found += 1; 1944 + } 1945 + Err(e) => { 1946 + tracing::warn!("failed to get post view for quoted post {}: {e}", bl.uri); 1947 + } 1710 1948 } 1711 1949 } 1712 1950 } ··· 1738 1976 ) -> Result<Response, StatusCode> { 1739 1977 // let hydrant = &app_state.hydrant; 1740 1978 let query_str = req.uri().query().unwrap_or(""); 1741 - let Ok(params) = serde_urlencoded::from_str::<GetActorLikesParams>(query_str) else { 1742 - return Err(StatusCode::BAD_REQUEST); 1743 - }; 1979 + let params = serde_urlencoded::from_str::<GetActorLikesParams>(query_str).map_err(|e| { 1980 + tracing::error!("failed to parse get_actor_likes query params: {e}"); 1981 + StatusCode::BAD_REQUEST 1982 + })?; 1744 1983 1745 - let Ok(ident) = AtIdentifier::new(&params.actor) else { 1746 - return Err(StatusCode::BAD_REQUEST); 1747 - }; 1748 - let Ok(repo) = app_state.hydrant.repos.resolve(&ident).await else { 1749 - return proxy_request(req).await; 1984 + let ident = AtIdentifier::new(&params.actor).map_err(|e| { 1985 + tracing::error!("failed to create AtIdentifier for actor {}: {e}", params.actor); 1986 + StatusCode::BAD_REQUEST 1987 + })?; 1988 + let repo = match app_state.hydrant.repos.resolve(&ident).await { 1989 + Ok(r) => r, 1990 + Err(e) => { 1991 + tracing::error!("failed to resolve repo for {ident}: {e}"); 1992 + return proxy_request(req).await; 1993 + } 1750 1994 }; 1751 1995 1752 1996 let limit = params.limit.unwrap_or(50).min(100); 1753 1997 1754 - let Ok(record_list) = repo 1998 + let record_list = match repo 1755 1999 .list_records("app.bsky.feed.like", limit, true, params.cursor.as_deref()) 1756 2000 .await 1757 - else { 1758 - return proxy_request(req).await; 2001 + { 2002 + Ok(rl) => rl, 2003 + Err(e) => { 2004 + tracing::error!("failed to list likes for {}: {e}", repo.did); 2005 + return proxy_request(req).await; 2006 + } 1759 2007 }; 1760 2008 1761 2009 let mut feed = Vec::new(); ··· 1766 2014 .and_then(|s| s.get("uri")) 1767 2015 .and_then(|u| u.as_str()) 1768 2016 { 1769 - if let Ok(post_view) = get_post_view(&app_state, subject_uri, None).await { 1770 - feed.push(serde_json::json!({ "post": post_view })); 2017 + match get_post_view(&app_state, subject_uri, None).await { 2018 + Ok(post_view) => feed.push(serde_json::json!({ "post": post_view })), 2019 + Err(e) => tracing::warn!("failed to get post view for liked post {subject_uri}: {e}"), 1771 2020 } 1772 2021 } 1773 2022 } ··· 1790 2039 ) -> Result<Response, StatusCode> { 1791 2040 // let hydrant = &app_state.hydrant; 1792 2041 let query_str = req.uri().query().unwrap_or(""); 1793 - let Ok(params) = serde_urlencoded::from_str::<GetRelationshipsParams>(query_str) else { 1794 - return Err(StatusCode::BAD_REQUEST); 1795 - }; 2042 + let params = serde_urlencoded::from_str::<GetRelationshipsParams>(query_str).map_err(|e| { 2043 + tracing::error!("failed to parse get_relationships query params: {e}"); 2044 + StatusCode::BAD_REQUEST 2045 + })?; 1796 2046 1797 2047 let others = extract_query_array(query_str, "others"); 1798 2048 if others.is_empty() { 1799 2049 return proxy_request(req).await; 1800 2050 } 1801 2051 1802 - let Ok(ident) = AtIdentifier::new(&params.actor) else { 1803 - return Err(StatusCode::BAD_REQUEST); 1804 - }; 1805 - let Ok(repo) = app_state.hydrant.repos.resolve(&ident).await else { 1806 - return proxy_request(req).await; 2052 + let ident = AtIdentifier::new(&params.actor).map_err(|e| { 2053 + tracing::error!("failed to create AtIdentifier for actor {}: {e}", params.actor); 2054 + StatusCode::BAD_REQUEST 2055 + })?; 2056 + let repo = match app_state.hydrant.repos.resolve(&ident).await { 2057 + Ok(r) => r, 2058 + Err(e) => { 2059 + tracing::error!("failed to resolve repo for {ident}: {e}"); 2060 + return proxy_request(req).await; 2061 + } 1807 2062 }; 1808 2063 let actor_did = repo.did.as_str().to_string(); 1809 2064 1810 2065 let mut relationships = Vec::new(); 1811 2066 for other in others { 1812 - let Ok(other_ident) = AtIdentifier::new(&other) else { 1813 - continue; 2067 + let other_ident = match AtIdentifier::new(&other) { 2068 + Ok(i) => i, 2069 + Err(e) => { 2070 + tracing::error!("failed to create AtIdentifier for other actor {other}: {e}"); 2071 + continue; 2072 + } 1814 2073 }; 1815 - let Ok(other_repo) = app_state.hydrant.repos.resolve(&other_ident).await else { 1816 - continue; 2074 + let other_repo = match app_state.hydrant.repos.resolve(&other_ident).await { 2075 + Ok(r) => r, 2076 + Err(e) => { 2077 + tracing::error!("failed to resolve repo for other actor {other_ident}: {e}"); 2078 + continue; 2079 + } 1817 2080 }; 1818 2081 let other_did = other_repo.did.as_str().to_string(); 1819 2082 ··· 1822 2085 1823 2086 let mut cursor = None; 1824 2087 loop { 1825 - if let Ok(rl) = repo 2088 + match repo 1826 2089 .list_records("app.bsky.graph.follow", 100, true, cursor.as_deref()) 1827 2090 .await 1828 2091 { 1829 - for rec in &rl.records { 1830 - let val = serde_json::to_value(&rec.value).unwrap_or(serde_json::json!({})); 1831 - if val.get("subject").and_then(|s| s.as_str()) == Some(&other_did) { 1832 - following = Some(format!( 1833 - "at://{}/app.bsky.graph.follow/{}", 1834 - actor_did, 1835 - rec.rkey.as_str() 1836 - )); 2092 + Ok(rl) => { 2093 + for rec in &rl.records { 2094 + let val = serde_json::to_value(&rec.value).unwrap_or(serde_json::json!({})); 2095 + if val.get("subject").and_then(|s| s.as_str()) == Some(&other_did) { 2096 + following = Some(format!( 2097 + "at://{}/app.bsky.graph.follow/{}", 2098 + actor_did, 2099 + rec.rkey.as_str() 2100 + )); 2101 + break; 2102 + } 2103 + } 2104 + if following.is_some() || rl.cursor.is_none() { 1837 2105 break; 1838 2106 } 2107 + cursor = rl.cursor.map(|c| c.to_string()); 1839 2108 } 1840 - if following.is_some() || rl.cursor.is_none() { 2109 + Err(e) => { 2110 + tracing::error!("failed to list follows for {actor_did}: {e}"); 1841 2111 break; 1842 2112 } 1843 - cursor = rl.cursor.map(|c| c.to_string()); 1844 - } else { 1845 - break; 1846 2113 } 1847 2114 } 1848 2115 1849 2116 let mut cursor = None; 1850 2117 loop { 1851 - if let Ok(rl) = other_repo 2118 + match other_repo 1852 2119 .list_records("app.bsky.graph.follow", 100, true, cursor.as_deref()) 1853 2120 .await 1854 2121 { 1855 - for rec in &rl.records { 1856 - let val = serde_json::to_value(&rec.value).unwrap_or(serde_json::json!({})); 1857 - if val.get("subject").and_then(|s| s.as_str()) == Some(&actor_did) { 1858 - followed_by = Some(format!( 1859 - "at://{}/app.bsky.graph.follow/{}", 1860 - other_did, 1861 - rec.rkey.as_str() 1862 - )); 2122 + Ok(rl) => { 2123 + for rec in &rl.records { 2124 + let val = serde_json::to_value(&rec.value).unwrap_or(serde_json::json!({})); 2125 + if val.get("subject").and_then(|s| s.as_str()) == Some(&actor_did) { 2126 + followed_by = Some(format!( 2127 + "at://{}/app.bsky.graph.follow/{}", 2128 + other_did, 2129 + rec.rkey.as_str() 2130 + )); 2131 + break; 2132 + } 2133 + } 2134 + if followed_by.is_some() || rl.cursor.is_none() { 1863 2135 break; 1864 2136 } 2137 + cursor = rl.cursor.map(|c| c.to_string()); 1865 2138 } 1866 - if followed_by.is_some() || rl.cursor.is_none() { 2139 + Err(e) => { 2140 + tracing::error!("failed to list follows for {other_did}: {e}"); 1867 2141 break; 1868 2142 } 1869 - cursor = rl.cursor.map(|c| c.to_string()); 1870 - } else { 1871 - break; 1872 2143 } 1873 2144 } 1874 2145 ··· 1893 2164 ) -> Result<Response, StatusCode> { 1894 2165 // let hydrant = &app_state.hydrant; 1895 2166 let query_str = req.uri().query().unwrap_or(""); 1896 - let Ok(params) = serde_urlencoded::from_str::<GetFollowsParams>(query_str) else { 1897 - return Err(StatusCode::BAD_REQUEST); 1898 - }; 2167 + let params = serde_urlencoded::from_str::<GetFollowsParams>(query_str).map_err(|e| { 2168 + tracing::error!("failed to parse get_known_followers query params: {e}"); 2169 + StatusCode::BAD_REQUEST 2170 + })?; 1899 2171 1900 2172 let Some(did_str) = get_auth_did(&req) else { 1901 2173 return Err(StatusCode::UNAUTHORIZED); 1902 2174 }; 1903 - let Ok(auth_ident) = AtIdentifier::new(&did_str) else { 1904 - return Err(StatusCode::BAD_REQUEST); 1905 - }; 1906 - let Ok(auth_repo) = app_state.hydrant.repos.resolve(&auth_ident).await else { 1907 - return proxy_request(req).await; 2175 + let auth_ident = AtIdentifier::new(&did_str).map_err(|e| { 2176 + tracing::error!("failed to create AtIdentifier for auth user {did_str}: {e}"); 2177 + StatusCode::BAD_REQUEST 2178 + })?; 2179 + let auth_repo = match app_state.hydrant.repos.resolve(&auth_ident).await { 2180 + Ok(r) => r, 2181 + Err(e) => { 2182 + tracing::error!("failed to resolve repo for auth user {auth_ident}: {e}"); 2183 + return proxy_request(req).await; 2184 + } 1908 2185 }; 1909 2186 1910 2187 let mut auth_follows = std::collections::HashSet::new(); 1911 2188 let mut cursor = None; 1912 2189 loop { 1913 - if let Ok(rl) = auth_repo 2190 + match auth_repo 1914 2191 .list_records("app.bsky.graph.follow", 100, true, cursor.as_deref()) 1915 2192 .await 1916 2193 { 1917 - for rec in &rl.records { 1918 - let val = serde_json::to_value(&rec.value).unwrap_or(serde_json::json!({})); 1919 - if let Some(subj) = val.get("subject").and_then(|s| s.as_str()) { 1920 - auth_follows.insert(subj.to_string()); 2194 + Ok(rl) => { 2195 + for rec in &rl.records { 2196 + let val = serde_json::to_value(&rec.value).unwrap_or(serde_json::json!({})); 2197 + if let Some(subj) = val.get("subject").and_then(|s| s.as_str()) { 2198 + auth_follows.insert(subj.to_string()); 2199 + } 1921 2200 } 2201 + if rl.cursor.is_none() { 2202 + break; 2203 + } 2204 + cursor = rl.cursor.map(|c| c.to_string()); 1922 2205 } 1923 - if rl.cursor.is_none() { 2206 + Err(e) => { 2207 + tracing::error!("failed to list follows for auth user {}: {e}", auth_repo.did); 1924 2208 break; 1925 2209 } 1926 - cursor = rl.cursor.map(|c| c.to_string()); 1927 - } else { 1928 - break; 1929 2210 } 1930 2211 } 1931 2212 1932 - let Ok(ident) = AtIdentifier::new(&params.actor) else { 1933 - return Err(StatusCode::BAD_REQUEST); 1934 - }; 1935 - let Ok(repo) = app_state.hydrant.repos.resolve(&ident).await else { 1936 - return proxy_request(req).await; 2213 + let ident = AtIdentifier::new(&params.actor).map_err(|e| { 2214 + tracing::error!("failed to create AtIdentifier for actor {}: {e}", params.actor); 2215 + StatusCode::BAD_REQUEST 2216 + })?; 2217 + let repo = match app_state.hydrant.repos.resolve(&ident).await { 2218 + Ok(r) => r, 2219 + Err(e) => { 2220 + tracing::error!("failed to resolve repo for {ident}: {e}"); 2221 + return proxy_request(req).await; 2222 + } 1937 2223 }; 1938 2224 1939 2225 let limit = params.limit.unwrap_or(50).min(100); ··· 1945 2231 .source("app.bsky.graph.follow") 1946 2232 .limit(limit * 3); 1947 2233 if let Some(cursor_str) = params.cursor { 1948 - if let Ok(c) = data_encoding::BASE64URL_NOPAD.decode(cursor_str.as_bytes()) { 1949 - fetch = fetch.cursor(c); 2234 + match data_encoding::BASE64URL_NOPAD.decode(cursor_str.as_bytes()) { 2235 + Ok(c) => { 2236 + fetch = fetch.cursor(c); 2237 + } 2238 + Err(e) => { 2239 + tracing::error!("failed to decode cursor {cursor_str}: {e}"); 2240 + } 1950 2241 } 1951 2242 } 1952 2243 1953 - let Ok(backlinks_page) = fetch.run().await else { 1954 - return proxy_request(req).await; 2244 + let backlinks_page = match fetch.run().await { 2245 + Ok(bp) => bp, 2246 + Err(e) => { 2247 + tracing::error!("failed to fetch backlinks for {}: {e}", repo.did); 2248 + return proxy_request(req).await; 2249 + } 1955 2250 }; 1956 2251 1957 2252 let mut followers = Vec::new(); ··· 1960 2255 if found >= limit { 1961 2256 break; 1962 2257 } 1963 - let Ok(uri) = jacquard_common::types::string::AtUri::new(bl.uri.as_str()) else { 1964 - continue; 2258 + let uri = match jacquard_common::types::string::AtUri::new(bl.uri.as_str()) { 2259 + Ok(u) => u, 2260 + Err(e) => { 2261 + tracing::error!("failed to parse backlink URI {}: {e}", bl.uri); 2262 + continue; 2263 + } 1965 2264 }; 1966 2265 let author_ident = uri.authority().as_str().to_string(); 1967 2266 1968 2267 if auth_follows.contains(&author_ident) { 1969 - if let Ok(profile) = get_profile_internal(&app_state, author_ident.as_str(), None).await 1970 - { 1971 - followers.push(profile); 1972 - found += 1; 2268 + match get_profile_internal(&app_state, author_ident.as_str(), None).await { 2269 + Ok(profile) => { 2270 + followers.push(profile); 2271 + found += 1; 2272 + } 2273 + Err(e) => { 2274 + tracing::warn!("failed to get profile for follower {author_ident}: {e}"); 2275 + } 1973 2276 } 1974 2277 } 1975 2278 } 1976 2279 1977 - let Ok(subject_profile) = get_profile_internal(&app_state, repo.did.as_str(), None).await 1978 - else { 1979 - return proxy_request(req).await; 2280 + let subject_profile = match get_profile_internal(&app_state, repo.did.as_str(), None).await { 2281 + Ok(p) => p, 2282 + Err(e) => { 2283 + tracing::error!("failed to get subject profile for {}: {e}", repo.did); 2284 + return proxy_request(req).await; 2285 + } 1980 2286 }; 1981 2287 1982 2288 let cursor = backlinks_page ··· 1997 2303 ) -> Result<Response, StatusCode> { 1998 2304 // let hydrant = &app_state.hydrant; 1999 2305 let query_str = req.uri().query().unwrap_or(""); 2000 - let Ok(params) = serde_urlencoded::from_str::<GetFollowsParams>(query_str) else { 2001 - return Err(StatusCode::BAD_REQUEST); 2002 - }; 2306 + let params = serde_urlencoded::from_str::<GetFollowsParams>(query_str).map_err(|e| { 2307 + tracing::error!("failed to parse get_blocks query params: {e}"); 2308 + StatusCode::BAD_REQUEST 2309 + })?; 2003 2310 2004 2311 let Some(did_str) = get_auth_did(&req) else { 2005 2312 return Err(StatusCode::UNAUTHORIZED); 2006 2313 }; 2007 - let Ok(ident) = AtIdentifier::new(&did_str) else { 2008 - return Err(StatusCode::BAD_REQUEST); 2009 - }; 2010 - let Ok(repo) = app_state.hydrant.repos.resolve(&ident).await else { 2011 - return proxy_request(req).await; 2314 + let ident = AtIdentifier::new(&did_str).map_err(|e| { 2315 + tracing::error!("failed to create AtIdentifier for did_str {did_str}: {e}"); 2316 + StatusCode::BAD_REQUEST 2317 + })?; 2318 + let repo = match app_state.hydrant.repos.resolve(&ident).await { 2319 + Ok(r) => r, 2320 + Err(e) => { 2321 + tracing::error!("failed to resolve repo for {ident}: {e}"); 2322 + return proxy_request(req).await; 2323 + } 2012 2324 }; 2013 2325 2014 2326 let limit = params.limit.unwrap_or(50).min(100); 2015 - let Ok(record_list) = repo 2327 + let record_list = match repo 2016 2328 .list_records( 2017 2329 "app.bsky.graph.block", 2018 2330 limit, ··· 2020 2332 params.cursor.as_deref(), 2021 2333 ) 2022 2334 .await 2023 - else { 2024 - return proxy_request(req).await; 2335 + { 2336 + Ok(rl) => rl, 2337 + Err(e) => { 2338 + tracing::error!("failed to list blocks for {}: {e}", repo.did); 2339 + return proxy_request(req).await; 2340 + } 2025 2341 }; 2026 2342 2027 2343 let mut blocks = Vec::new(); 2028 2344 for rec in record_list.records { 2029 2345 let value = serde_json::to_value(&rec.value).unwrap_or(serde_json::json!({})); 2030 2346 if let Some(subject_did) = value.get("subject").and_then(|s| s.as_str()) { 2031 - if let Ok(profile) = get_profile_internal(&app_state, subject_did, None).await { 2032 - blocks.push(profile); 2347 + match get_profile_internal(&app_state, subject_did, None).await { 2348 + Ok(profile) => blocks.push(profile), 2349 + Err(e) => tracing::warn!("failed to get profile for blocked actor {subject_did}: {e}"), 2033 2350 } 2034 2351 } 2035 2352 } ··· 2052 2369 #[serde(default)] 2053 2370 cursor: Option<String>, 2054 2371 } 2055 - let Ok(params) = serde_urlencoded::from_str::<GetListParams>(query_str) else { 2056 - return Err(StatusCode::BAD_REQUEST); 2057 - }; 2372 + let params = serde_urlencoded::from_str::<GetListParams>(query_str).map_err(|e| { 2373 + tracing::error!("failed to parse get_list query params: {e}"); 2374 + StatusCode::BAD_REQUEST 2375 + })?; 2058 2376 2059 - let Ok(uri) = jacquard_common::types::string::AtUri::new(&params.list) else { 2060 - return Err(StatusCode::BAD_REQUEST); 2061 - }; 2377 + let uri = jacquard_common::types::string::AtUri::new(&params.list).map_err(|e| { 2378 + tracing::error!("failed to parse list URI {}: {e}", params.list); 2379 + StatusCode::BAD_REQUEST 2380 + })?; 2062 2381 let author_ident = uri.authority(); 2063 2382 let rkey = uri 2064 2383 .rkey() 2065 - .ok_or(StatusCode::BAD_REQUEST)? 2384 + .ok_or_else(|| { 2385 + tracing::error!("missing rkey in list URI {}", params.list); 2386 + StatusCode::BAD_REQUEST 2387 + })? 2066 2388 .0 2067 2389 .as_str() 2068 2390 .to_string(); 2069 2391 2070 - let Ok(repo) = app_state.hydrant.repos.resolve(author_ident).await else { 2071 - return proxy_request(req).await; 2392 + let repo = match app_state.hydrant.repos.resolve(author_ident).await { 2393 + Ok(r) => r, 2394 + Err(e) => { 2395 + tracing::error!("failed to resolve repo for {author_ident}: {e}"); 2396 + return proxy_request(req).await; 2397 + } 2072 2398 }; 2073 2399 2074 - let Ok(Some(record)) = repo.get_record("app.bsky.graph.list", &rkey).await else { 2075 - return proxy_request(req).await; 2400 + let record = match repo.get_record("app.bsky.graph.list", &rkey).await { 2401 + Ok(Some(rec)) => rec, 2402 + Ok(None) => { 2403 + tracing::error!("list record not found: {author_ident}/app.bsky.graph.list/{rkey}"); 2404 + return proxy_request(req).await; 2405 + } 2406 + Err(e) => { 2407 + tracing::error!("failed to get list record {author_ident}/{rkey}: {e}"); 2408 + return proxy_request(req).await; 2409 + } 2076 2410 }; 2077 2411 2078 - let Ok(author_profile) = get_profile_internal(&app_state, repo.did.as_str(), None).await else { 2079 - return proxy_request(req).await; 2412 + let author_profile = match get_profile_internal(&app_state, repo.did.as_str(), None).await { 2413 + Ok(p) => p, 2414 + Err(e) => { 2415 + tracing::error!("failed to get author profile for {}: {e}", repo.did); 2416 + return proxy_request(req).await; 2417 + } 2080 2418 }; 2081 2419 2082 2420 let val_json = serde_json::to_value(&record.value).unwrap_or(serde_json::json!({})); ··· 2101 2439 .source("app.bsky.graph.listitem") 2102 2440 .limit(limit); 2103 2441 if let Some(cursor_str) = params.cursor { 2104 - if let Ok(c) = data_encoding::BASE64URL_NOPAD.decode(cursor_str.as_bytes()) { 2105 - fetch = fetch.cursor(c); 2442 + match data_encoding::BASE64URL_NOPAD.decode(cursor_str.as_bytes()) { 2443 + Ok(c) => { 2444 + fetch = fetch.cursor(c); 2445 + } 2446 + Err(e) => { 2447 + tracing::error!("failed to decode cursor {cursor_str}: {e}"); 2448 + } 2106 2449 } 2107 2450 } 2108 2451 2109 - let Ok(backlinks_page) = fetch.run().await else { 2110 - return proxy_request(req).await; 2452 + let backlinks_page = match fetch.run().await { 2453 + Ok(bp) => bp, 2454 + Err(e) => { 2455 + tracing::error!("failed to fetch backlinks for list {}: {e}", params.list); 2456 + return proxy_request(req).await; 2457 + } 2111 2458 }; 2112 2459 2113 2460 let mut items = Vec::new(); 2114 2461 for bl in backlinks_page.backlinks { 2115 - let Ok(item_uri) = jacquard_common::types::string::AtUri::new(bl.uri.as_str()) else { 2116 - continue; 2462 + let item_uri = match jacquard_common::types::string::AtUri::new(bl.uri.as_str()) { 2463 + Ok(u) => u, 2464 + Err(e) => { 2465 + tracing::error!("failed to parse listitem URI {}: {e}", bl.uri); 2466 + continue; 2467 + } 2117 2468 }; 2118 2469 let item_author = item_uri.authority(); 2119 2470 let item_rkey = item_uri.rkey().unwrap().0.as_str(); 2120 2471 2121 - let Ok(item_repo) = app_state.hydrant.repos.resolve(item_author).await else { 2122 - continue; 2472 + let item_repo = match app_state.hydrant.repos.resolve(item_author).await { 2473 + Ok(r) => r, 2474 + Err(e) => { 2475 + tracing::error!("failed to resolve repo for listitem author {item_author}: {e}"); 2476 + continue; 2477 + } 2123 2478 }; 2124 - let Ok(Some(item_rec)) = item_repo 2479 + let item_rec = match item_repo 2125 2480 .get_record("app.bsky.graph.listitem", item_rkey) 2126 2481 .await 2127 - else { 2128 - continue; 2482 + { 2483 + Ok(Some(rec)) => rec, 2484 + Ok(None) => continue, 2485 + Err(e) => { 2486 + tracing::error!("failed to get listitem record {item_author}/{item_rkey}: {e}"); 2487 + continue; 2488 + } 2129 2489 }; 2130 2490 let item_val = serde_json::to_value(&item_rec.value).unwrap_or(serde_json::json!({})); 2131 2491 2132 2492 if let Some(subject_did) = item_val.get("subject").and_then(|s| s.as_str()) { 2133 - if let Ok(subject_profile) = get_profile_internal(&app_state, subject_did, None).await { 2134 - items.push(serde_json::json!({ 2135 - "uri": bl.uri.as_str(), 2136 - "subject": subject_profile, 2137 - })); 2493 + match get_profile_internal(&app_state, subject_did, None).await { 2494 + Ok(subject_profile) => { 2495 + items.push(serde_json::json!({ 2496 + "uri": bl.uri.as_str(), 2497 + "subject": subject_profile, 2498 + })); 2499 + } 2500 + Err(e) => { 2501 + tracing::warn!("failed to get profile for listitem subject {subject_did}: {e}"); 2502 + } 2138 2503 } 2139 2504 } 2140 2505 } ··· 2153 2518 ) -> Result<Response, StatusCode> { 2154 2519 // let hydrant = &app_state.hydrant; 2155 2520 let query_str = req.uri().query().unwrap_or(""); 2156 - let Ok(params) = serde_urlencoded::from_str::<GetAuthorFeedParams>(query_str) else { 2157 - return Err(StatusCode::BAD_REQUEST); 2158 - }; 2521 + let params = serde_urlencoded::from_str::<GetAuthorFeedParams>(query_str).map_err(|e| { 2522 + tracing::error!("failed to parse get_lists query params: {e}"); 2523 + StatusCode::BAD_REQUEST 2524 + })?; 2159 2525 2160 - let Ok(ident) = AtIdentifier::new(&params.actor) else { 2161 - return Err(StatusCode::BAD_REQUEST); 2162 - }; 2163 - let Ok(repo) = app_state.hydrant.repos.resolve(&ident).await else { 2164 - return proxy_request(req).await; 2526 + let ident = AtIdentifier::new(&params.actor).map_err(|e| { 2527 + tracing::error!("failed to create AtIdentifier for actor {}: {e}", params.actor); 2528 + StatusCode::BAD_REQUEST 2529 + })?; 2530 + let repo = match app_state.hydrant.repos.resolve(&ident).await { 2531 + Ok(r) => r, 2532 + Err(e) => { 2533 + tracing::error!("failed to resolve repo for {ident}: {e}"); 2534 + return proxy_request(req).await; 2535 + } 2165 2536 }; 2166 2537 2167 - let Ok(author_profile) = get_profile_internal(&app_state, repo.did.as_str(), None).await else { 2168 - return proxy_request(req).await; 2538 + let author_profile = match get_profile_internal(&app_state, repo.did.as_str(), None).await { 2539 + Ok(p) => p, 2540 + Err(e) => { 2541 + tracing::error!("failed to get author profile for {}: {e}", repo.did); 2542 + return proxy_request(req).await; 2543 + } 2169 2544 }; 2170 2545 2171 2546 let limit = params.limit.unwrap_or(50).min(100); 2172 - let Ok(record_list) = repo 2547 + let record_list = match repo 2173 2548 .list_records("app.bsky.graph.list", limit, true, params.cursor.as_deref()) 2174 2549 .await 2175 - else { 2176 - return proxy_request(req).await; 2550 + { 2551 + Ok(rl) => rl, 2552 + Err(e) => { 2553 + tracing::error!("failed to list lists for {}: {e}", repo.did); 2554 + return proxy_request(req).await; 2555 + } 2177 2556 }; 2178 2557 2179 2558 let mut lists = Vec::new(); ··· 2204 2583 ) -> Result<Response, StatusCode> { 2205 2584 // let hydrant = &app_state.hydrant; 2206 2585 let query_str = req.uri().query().unwrap_or(""); 2207 - let Ok(params) = serde_urlencoded::from_str::<GetAuthorFeedParams>(query_str) else { 2208 - return Err(StatusCode::BAD_REQUEST); 2209 - }; 2586 + let params = serde_urlencoded::from_str::<GetAuthorFeedParams>(query_str).map_err(|e| { 2587 + tracing::error!("failed to parse get_lists_with_membership query params: {e}"); 2588 + StatusCode::BAD_REQUEST 2589 + })?; 2210 2590 2211 - let Ok(ident) = AtIdentifier::new(&params.actor) else { 2212 - return Err(StatusCode::BAD_REQUEST); 2213 - }; 2214 - let Ok(repo) = app_state.hydrant.repos.resolve(&ident).await else { 2215 - return proxy_request(req).await; 2591 + let ident = AtIdentifier::new(&params.actor).map_err(|e| { 2592 + tracing::error!("failed to create AtIdentifier for actor {}: {e}", params.actor); 2593 + StatusCode::BAD_REQUEST 2594 + })?; 2595 + let repo = match app_state.hydrant.repos.resolve(&ident).await { 2596 + Ok(r) => r, 2597 + Err(e) => { 2598 + tracing::error!("failed to resolve repo for {ident}: {e}"); 2599 + return proxy_request(req).await; 2600 + } 2216 2601 }; 2217 2602 2218 2603 // All lists created by actor 2219 - let Ok(record_list) = repo 2604 + let record_list = match repo 2220 2605 .list_records("app.bsky.graph.list", 100, true, None) 2221 2606 .await 2222 - else { 2223 - return proxy_request(req).await; 2607 + { 2608 + Ok(rl) => rl, 2609 + Err(e) => { 2610 + tracing::error!("failed to list lists for {}: {e}", repo.did); 2611 + return proxy_request(req).await; 2612 + } 2224 2613 }; 2225 2614 2226 2615 let mut lists: Vec<serde_json::Value> = Vec::new(); ··· 2247 2636 ) -> Result<Response, StatusCode> { 2248 2637 // let hydrant = &app_state.hydrant; 2249 2638 let query_str = req.uri().query().unwrap_or(""); 2250 - let Ok(params) = serde_urlencoded::from_str::<GetAuthorFeedParams>(query_str) else { 2251 - return Err(StatusCode::BAD_REQUEST); 2252 - }; 2639 + let params: GetAuthorFeedParams = serde_urlencoded::from_str(query_str).map_err(|e| { 2640 + tracing::error!("failed to parse get_actor_feeds query params: {e}"); 2641 + StatusCode::BAD_REQUEST 2642 + })?; 2253 2643 2254 - let Ok(ident) = AtIdentifier::new(&params.actor) else { 2255 - return Err(StatusCode::BAD_REQUEST); 2256 - }; 2257 - let Ok(repo) = app_state.hydrant.repos.resolve(&ident).await else { 2258 - return proxy_request(req).await; 2644 + let ident = AtIdentifier::new(&params.actor).map_err(|e| { 2645 + tracing::error!("failed to create AtIdentifier for actor {}: {e}", params.actor); 2646 + StatusCode::BAD_REQUEST 2647 + })?; 2648 + let repo = match app_state.hydrant.repos.resolve(&ident).await { 2649 + Ok(r) => r, 2650 + Err(e) => { 2651 + tracing::error!("failed to resolve repo for {ident}: {e}"); 2652 + return proxy_request(req).await; 2653 + } 2259 2654 }; 2260 2655 2261 - let Ok(author_profile) = get_profile_internal(&app_state, repo.did.as_str(), None).await else { 2262 - return proxy_request(req).await; 2656 + let author_profile = match get_profile_internal(&app_state, repo.did.as_str(), None).await { 2657 + Ok(p) => p, 2658 + Err(e) => { 2659 + tracing::error!("failed to get author profile for {}: {e}", repo.did); 2660 + return proxy_request(req).await; 2661 + } 2263 2662 }; 2264 2663 2265 2664 let limit = params.limit.unwrap_or(50).min(100); 2266 - let Ok(record_list) = repo 2665 + let record_list = match repo 2267 2666 .list_records( 2268 2667 "app.bsky.feed.generator", 2269 2668 limit, ··· 2271 2670 params.cursor.as_deref(), 2272 2671 ) 2273 2672 .await 2274 - else { 2275 - return proxy_request(req).await; 2673 + { 2674 + Ok(rl) => rl, 2675 + Err(e) => { 2676 + tracing::error!("failed to list feed generators for {}: {e}", repo.did); 2677 + return proxy_request(req).await; 2678 + } 2276 2679 }; 2277 2680 2278 2681 let mut feeds = Vec::new(); 2279 2682 for rec in record_list.records { 2280 2683 let val_json = serde_json::to_value(&rec.value).unwrap_or(serde_json::json!({})); 2684 + let uri = format!( 2685 + "at://{}/app.bsky.feed.generator/{}", 2686 + repo.did.as_str(), 2687 + rec.rkey.as_str() 2688 + ); 2281 2689 feeds.push(serde_json::json!({ 2282 - "uri": format!("at://{}/app.bsky.feed.generator/{}", repo.did.as_str(), rec.rkey.as_str()), 2690 + "uri": uri, 2283 2691 "cid": rec.cid.to_string(), 2284 2692 "did": val_json.get("did").and_then(|v| v.as_str()).unwrap_or(""), 2285 2693 "creator": author_profile.clone(), 2286 2694 "displayName": val_json.get("displayName").and_then(|v| v.as_str()).unwrap_or(""), 2287 2695 "description": val_json.get("description").and_then(|v| v.as_str()), 2288 2696 "avatar": val_json.get("avatar").and_then(|v| v.as_str()), 2289 - "likeCount": app_state.hydrant.backlinks.count(format!("at://{}/app.bsky.feed.generator/{}", repo.did.as_str(), rec.rkey.as_str())).source("app.bsky.feed.like").run().await.unwrap_or(0), 2697 + "likeCount": app_state.hydrant.backlinks.count(uri).source("app.bsky.feed.like").run().await.unwrap_or(0), 2290 2698 "indexedAt": chrono::Utc::now().to_rfc3339(), 2291 2699 })); 2292 2700 } ··· 2308 2716 struct GetFeedGeneratorParams { 2309 2717 feed: String, 2310 2718 } 2311 - let Ok(params) = serde_urlencoded::from_str::<GetFeedGeneratorParams>(query_str) else { 2312 - return Err(StatusCode::BAD_REQUEST); 2313 - }; 2719 + let params: GetFeedGeneratorParams = serde_urlencoded::from_str(query_str).map_err(|e| { 2720 + tracing::error!("failed to parse get_feed_generator query params: {e}"); 2721 + StatusCode::BAD_REQUEST 2722 + })?; 2314 2723 2315 - let Ok(uri) = jacquard_common::types::string::AtUri::new(&params.feed) else { 2316 - return Err(StatusCode::BAD_REQUEST); 2317 - }; 2724 + let uri = jacquard_common::types::string::AtUri::new(&params.feed).map_err(|e| { 2725 + tracing::error!("failed to parse feed uri {}: {e}", params.feed); 2726 + StatusCode::BAD_REQUEST 2727 + })?; 2318 2728 let author_ident = uri.authority(); 2319 2729 let rkey = uri 2320 2730 .rkey() 2321 - .ok_or(StatusCode::BAD_REQUEST)? 2731 + .ok_or_else(|| { 2732 + tracing::error!("missing rkey in feed uri {}", params.feed); 2733 + StatusCode::BAD_REQUEST 2734 + })? 2322 2735 .0 2323 2736 .as_str() 2324 2737 .to_string(); 2325 2738 2326 - let Ok(repo) = app_state.hydrant.repos.resolve(author_ident).await else { 2327 - return proxy_request(req).await; 2739 + let repo = match app_state.hydrant.repos.resolve(author_ident).await { 2740 + Ok(r) => r, 2741 + Err(e) => { 2742 + tracing::error!("failed to resolve repo for {author_ident}: {e}"); 2743 + return proxy_request(req).await; 2744 + } 2328 2745 }; 2329 2746 2330 - let Ok(Some(record)) = repo.get_record("app.bsky.feed.generator", &rkey).await else { 2331 - return proxy_request(req).await; 2747 + let record = match repo.get_record("app.bsky.feed.generator", &rkey).await { 2748 + Ok(Some(r)) => r, 2749 + Ok(None) => { 2750 + tracing::error!("feed generator record not found: {author_ident}/{rkey}"); 2751 + return proxy_request(req).await; 2752 + } 2753 + Err(e) => { 2754 + tracing::error!("failed to get feed generator record {author_ident}/{rkey}: {e}"); 2755 + return proxy_request(req).await; 2756 + } 2332 2757 }; 2333 2758 2334 - let Ok(author_profile) = get_profile_internal(&app_state, repo.did.as_str(), None).await else { 2335 - return proxy_request(req).await; 2759 + let author_profile = match get_profile_internal(&app_state, repo.did.as_str(), None).await { 2760 + Ok(p) => p, 2761 + Err(e) => { 2762 + tracing::error!("failed to get author profile for {}: {e}", repo.did); 2763 + return proxy_request(req).await; 2764 + } 2336 2765 }; 2337 2766 2338 2767 let val_json = serde_json::to_value(&record.value).unwrap_or(serde_json::json!({})); ··· 2370 2799 2371 2800 let mut views = Vec::new(); 2372 2801 for feed_uri in feeds { 2373 - let Ok(uri) = jacquard_common::types::string::AtUri::new(&feed_uri) else { 2374 - continue; 2802 + let uri = match jacquard_common::types::string::AtUri::new(&feed_uri) { 2803 + Ok(u) => u, 2804 + Err(e) => { 2805 + tracing::warn!("failed to parse feed uri {feed_uri}: {e}"); 2806 + continue; 2807 + } 2375 2808 }; 2376 2809 let author_ident = uri.authority(); 2377 2810 let rkey = uri.rkey().unwrap().0.as_str().to_string(); 2378 2811 2379 - if let Ok(repo) = app_state.hydrant.repos.resolve(author_ident).await { 2380 - if let Ok(Some(record)) = repo.get_record("app.bsky.feed.generator", &rkey).await { 2381 - if let Ok(author_profile) = 2382 - get_profile_internal(&app_state, repo.did.as_str(), None).await 2383 - { 2384 - let val_json = 2385 - serde_json::to_value(&record.value).unwrap_or(serde_json::json!({})); 2386 - views.push(serde_json::json!({ 2387 - "uri": feed_uri, 2388 - "cid": record.cid.to_string(), 2389 - "did": val_json.get("did").and_then(|v| v.as_str()).unwrap_or(""), 2390 - "creator": author_profile, 2391 - "displayName": val_json.get("displayName").and_then(|v| v.as_str()).unwrap_or(""), 2392 - "description": val_json.get("description").and_then(|v| v.as_str()), 2393 - "avatar": val_json.get("avatar").and_then(|v| v.as_str()), 2394 - "likeCount": app_state.hydrant.backlinks.count(feed_uri.clone()).source("app.bsky.feed.like").run().await.unwrap_or(0), 2395 - "indexedAt": chrono::Utc::now().to_rfc3339(), 2396 - })); 2812 + match app_state.hydrant.repos.resolve(author_ident).await { 2813 + Ok(repo) => { 2814 + match repo.get_record("app.bsky.feed.generator", &rkey).await { 2815 + Ok(Some(record)) => { 2816 + match get_profile_internal(&app_state, repo.did.as_str(), None).await { 2817 + Ok(author_profile) => { 2818 + let val_json = serde_json::to_value(&record.value) 2819 + .unwrap_or(serde_json::json!({})); 2820 + views.push(serde_json::json!({ 2821 + "uri": feed_uri, 2822 + "cid": record.cid.to_string(), 2823 + "did": val_json.get("did").and_then(|v| v.as_str()).unwrap_or(""), 2824 + "creator": author_profile, 2825 + "displayName": val_json.get("displayName").and_then(|v| v.as_str()).unwrap_or(""), 2826 + "description": val_json.get("description").and_then(|v| v.as_str()), 2827 + "avatar": val_json.get("avatar").and_then(|v| v.as_str()), 2828 + "likeCount": app_state.hydrant.backlinks.count(feed_uri.clone()).source("app.bsky.feed.like").run().await.unwrap_or(0), 2829 + "indexedAt": chrono::Utc::now().to_rfc3339(), 2830 + })); 2831 + } 2832 + Err(e) => { 2833 + tracing::warn!("failed to get author profile for {}: {e}", repo.did) 2834 + } 2835 + } 2836 + } 2837 + Ok(None) => tracing::warn!("feed generator record not found: {author_ident}/{rkey}"), 2838 + Err(e) => tracing::warn!( 2839 + "failed to get feed generator record {author_ident}/{rkey}: {e}" 2840 + ), 2397 2841 } 2398 2842 } 2843 + Err(e) => tracing::warn!("failed to resolve repo for {author_ident}: {e}"), 2399 2844 } 2400 2845 } 2401 2846 ··· 2418 2863 let body_bytes = axum::body::to_bytes(req.into_body(), usize::MAX) 2419 2864 .await 2420 2865 .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; 2421 - let Ok(payload) = serde_json::from_slice::<PutPreferencesReq>(&body_bytes) else { 2422 - return Err(StatusCode::BAD_REQUEST); 2423 - }; 2866 + let payload: PutPreferencesReq = serde_json::from_slice(&body_bytes).map_err(|e| { 2867 + tracing::error!("failed to parse put_preferences request: {e}"); 2868 + StatusCode::BAD_REQUEST 2869 + })?; 2424 2870 2425 2871 let key = format!("prefs:{}", did); 2426 2872 let val = ··· 2473 2919 let body_bytes = axum::body::to_bytes(req.into_body(), usize::MAX) 2474 2920 .await 2475 2921 .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; 2476 - let Ok(payload) = serde_json::from_slice::<MuteActorReq>(&body_bytes) else { 2477 - return Err(StatusCode::BAD_REQUEST); 2478 - }; 2922 + let payload: MuteActorReq = serde_json::from_slice(&body_bytes).map_err(|e| { 2923 + tracing::error!("failed to parse mute_actor/unmute_actor request: {e}"); 2924 + StatusCode::BAD_REQUEST 2925 + })?; 2479 2926 2480 - let Ok(ident) = AtIdentifier::new(&payload.actor) else { 2481 - return Err(StatusCode::BAD_REQUEST); 2482 - }; 2483 - let Ok(repo) = app_state.hydrant.repos.resolve(&ident).await else { 2484 - return Err(StatusCode::NOT_FOUND); 2927 + let ident = AtIdentifier::new(&payload.actor).map_err(|e| { 2928 + tracing::error!("failed to parse actor identifier {}: {e}", payload.actor); 2929 + StatusCode::BAD_REQUEST 2930 + })?; 2931 + let repo = match app_state.hydrant.repos.resolve(&ident).await { 2932 + Ok(r) => r, 2933 + Err(e) => { 2934 + tracing::error!("failed to resolve repo for {ident}: {e}"); 2935 + return Err(StatusCode::NOT_FOUND); 2936 + } 2485 2937 }; 2486 2938 2487 2939 let key = format!("mute:{}:{}", did, repo.did.as_str()); ··· 2505 2957 let body_bytes = axum::body::to_bytes(req.into_body(), usize::MAX) 2506 2958 .await 2507 2959 .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; 2508 - let Ok(payload) = serde_json::from_slice::<MuteActorReq>(&body_bytes) else { 2509 - return Err(StatusCode::BAD_REQUEST); 2510 - }; 2960 + let payload: MuteActorReq = serde_json::from_slice(&body_bytes).map_err(|e| { 2961 + tracing::error!("failed to parse mute_actor/unmute_actor request: {e}"); 2962 + StatusCode::BAD_REQUEST 2963 + })?; 2511 2964 2512 - let Ok(ident) = AtIdentifier::new(&payload.actor) else { 2513 - return Err(StatusCode::BAD_REQUEST); 2514 - }; 2515 - let Ok(repo) = app_state.hydrant.repos.resolve(&ident).await else { 2516 - return Err(StatusCode::NOT_FOUND); 2965 + let ident = AtIdentifier::new(&payload.actor).map_err(|e| { 2966 + tracing::error!("failed to parse actor identifier {}: {e}", payload.actor); 2967 + StatusCode::BAD_REQUEST 2968 + })?; 2969 + let repo = match app_state.hydrant.repos.resolve(&ident).await { 2970 + Ok(r) => r, 2971 + Err(e) => { 2972 + tracing::error!("failed to resolve repo for {ident}: {e}"); 2973 + return Err(StatusCode::NOT_FOUND); 2974 + } 2517 2975 }; 2518 2976 2519 2977 let key = format!("mute:{}:{}", did, repo.did.as_str()); ··· 2535 2993 }; 2536 2994 2537 2995 let query_str = req.uri().query().unwrap_or(""); 2538 - let Ok(params) = serde_urlencoded::from_str::<GetBookmarksParams>(query_str) else { 2539 - return Err(StatusCode::BAD_REQUEST); 2540 - }; 2996 + let params: GetBookmarksParams = serde_urlencoded::from_str(query_str).map_err(|e| { 2997 + tracing::error!("failed to parse get_mutes query params: {e}"); 2998 + StatusCode::BAD_REQUEST 2999 + })?; 2541 3000 2542 3001 let limit = params.limit.unwrap_or(50).min(100); 2543 3002 let prefix = format!("mute:{}:", did); ··· 2553 3012 2554 3013 let mut fetched_keys = Vec::new(); 2555 3014 for item in iter { 2556 - let Ok((key, _)) = item.into_inner() else { 2557 - continue; 3015 + let (key, _) = match item.into_inner() { 3016 + Ok(inner) => inner, 3017 + Err(e) => { 3018 + tracing::warn!("failed to get item from mutes iterator: {e}"); 3019 + continue; 3020 + } 2558 3021 }; 2559 3022 if !key.starts_with(prefix.as_bytes()) { 2560 3023 break; ··· 2570 3033 for key in fetched_keys { 2571 3034 let key_str = String::from_utf8_lossy(&key); 2572 3035 let muted_did = &key_str[prefix.len()..]; 2573 - if let Ok(profile) = get_profile_internal(&app_state, muted_did, None).await { 2574 - mutes.push(profile); 3036 + match get_profile_internal(&app_state, muted_did, None).await { 3037 + Ok(profile) => mutes.push(profile), 3038 + Err(e) => tracing::warn!("failed to get profile for muted actor {muted_did}: {e}"), 2575 3039 } 2576 3040 next_cursor = Some(key_str.to_string()); 2577 3041 } ··· 2607 3071 .and_then(|s| s.get("uri")) 2608 3072 .and_then(|u| u.as_str()) 2609 3073 { 2610 - if let Ok(u) = jacquard_common::types::string::AtUri::new(subj_uri) { 2611 - targets.push(( 2612 - u.authority().as_str().to_string(), 2613 - "like", 2614 - Some(subj_uri.to_string()), 2615 - )); 3074 + match jacquard_common::types::string::AtUri::new(subj_uri) { 3075 + Ok(u) => { 3076 + targets.push(( 3077 + u.authority().as_str().to_string(), 3078 + "like", 3079 + Some(subj_uri.to_string()), 3080 + )); 3081 + } 3082 + Err(e) => tracing::warn!("failed to parse notification like uri {subj_uri}: {e}"), 2616 3083 } 2617 3084 } 2618 3085 } ··· 2622 3089 .and_then(|s| s.get("uri")) 2623 3090 .and_then(|u| u.as_str()) 2624 3091 { 2625 - if let Ok(u) = jacquard_common::types::string::AtUri::new(subj_uri) { 2626 - targets.push(( 2627 - u.authority().as_str().to_string(), 2628 - "repost", 2629 - Some(subj_uri.to_string()), 2630 - )); 3092 + match jacquard_common::types::string::AtUri::new(subj_uri) { 3093 + Ok(u) => { 3094 + targets.push(( 3095 + u.authority().as_str().to_string(), 3096 + "repost", 3097 + Some(subj_uri.to_string()), 3098 + )); 3099 + } 3100 + Err(e) => tracing::warn!("failed to parse notification repost uri {subj_uri}: {e}"), 2631 3101 } 2632 3102 } 2633 3103 } ··· 2643 3113 .and_then(|p| p.get("uri")) 2644 3114 .and_then(|u| u.as_str()) 2645 3115 { 2646 - if let Ok(u) = jacquard_common::types::string::AtUri::new(parent_uri) { 2647 - targets.push(( 2648 - u.authority().as_str().to_string(), 2649 - "reply", 2650 - Some(parent_uri.to_string()), 2651 - )); 3116 + match jacquard_common::types::string::AtUri::new(parent_uri) { 3117 + Ok(u) => { 3118 + targets.push(( 3119 + u.authority().as_str().to_string(), 3120 + "reply", 3121 + Some(parent_uri.to_string()), 3122 + )); 3123 + } 3124 + Err(e) => tracing::warn!("failed to parse notification reply uri {parent_uri}: {e}"), 2652 3125 } 2653 3126 } 2654 3127 ··· 2691 3164 }; 2692 3165 2693 3166 if let Some(qu) = quote_uri { 2694 - if let Ok(u) = jacquard_common::types::string::AtUri::new(qu) { 2695 - targets.push(( 2696 - u.authority().as_str().to_string(), 2697 - "quote", 2698 - Some(qu.to_string()), 2699 - )); 3167 + match jacquard_common::types::string::AtUri::new(qu) { 3168 + Ok(u) => { 3169 + targets.push(( 3170 + u.authority().as_str().to_string(), 3171 + "quote", 3172 + Some(qu.to_string()), 3173 + )); 3174 + } 3175 + Err(e) => tracing::warn!("failed to parse notification quote uri {qu}: {e}"), 2700 3176 } 2701 3177 } 2702 3178 } ··· 2779 3255 // Collect all notification keys into a vector so we can iterate in reverse 2780 3256 let mut all_keys = Vec::new(); 2781 3257 for item in app_state.notifications.prefix(prefix.as_bytes()) { 2782 - if let Ok((k, v)) = item.into_inner() { 2783 - all_keys.push((k, v)); 3258 + match item.into_inner() { 3259 + Ok((k, v)) => { 3260 + all_keys.push((k, v)); 3261 + } 3262 + Err(e) => { 3263 + tracing::warn!("failed to get notification item: {e}"); 3264 + } 2784 3265 } 2785 3266 } 2786 3267 ··· 2807 3288 for (key, val_bytes) in all_keys.into_iter().take(limit) { 2808 3289 next_cursor = Some(String::from_utf8_lossy(&key).to_string()); 2809 3290 2810 - let Ok(val) = serde_json::from_slice::<serde_json::Value>(&val_bytes) else { 2811 - continue; 3291 + let val = match serde_json::from_slice::<serde_json::Value>(&val_bytes) { 3292 + Ok(v) => v, 3293 + Err(e) => { 3294 + tracing::warn!("failed to parse notification json: {e}"); 3295 + continue; 3296 + } 2812 3297 }; 2813 3298 2814 3299 let author_did = val.get("author_did").and_then(|a| a.as_str()).unwrap_or(""); ··· 2817 3302 let is_read = indexed_at <= last_seen.as_str(); 2818 3303 2819 3304 let mut notif = val.clone(); 2820 - if let Ok(author_profile) = get_profile_internal(&app_state, author_did, None).await { 2821 - notif["author"] = author_profile; 2822 - } else { 2823 - continue; 3305 + match get_profile_internal(&app_state, author_did, None).await { 3306 + Ok(author_profile) => { 3307 + notif["author"] = author_profile; 3308 + } 3309 + Err(e) => { 3310 + tracing::warn!("failed to get author profile for notification from {author_did}: {e}"); 3311 + continue; 3312 + } 2824 3313 } 2825 3314 2826 3315 notif["isRead"] = serde_json::json!(is_read); ··· 2858 3347 2859 3348 let mut count = 0; 2860 3349 for item in app_state.notifications.prefix(prefix.as_bytes()) { 2861 - let Ok((_key, val_bytes)) = item.into_inner() else { 2862 - continue; 3350 + let (_key, val_bytes) = match item.into_inner() { 3351 + Ok(inner) => inner, 3352 + Err(e) => { 3353 + tracing::warn!("failed to get notification item for count: {e}"); 3354 + continue; 3355 + } 2863 3356 }; 2864 - if let Ok(val) = serde_json::from_slice::<serde_json::Value>(&val_bytes) { 2865 - if let Some(indexed_at) = val.get("indexedAt").and_then(|a| a.as_str()) { 2866 - if indexed_at > last_seen.as_str() { 2867 - count += 1; 3357 + match serde_json::from_slice::<serde_json::Value>(&val_bytes) { 3358 + Ok(val) => { 3359 + if let Some(indexed_at) = val.get("indexedAt").and_then(|a| a.as_str()) { 3360 + if indexed_at > last_seen.as_str() { 3361 + count += 1; 3362 + } 2868 3363 } 2869 3364 } 3365 + Err(e) => tracing::warn!("failed to parse notification json for count: {e}"), 2870 3366 } 2871 3367 } 2872 3368 ··· 2892 3388 let body_bytes = axum::body::to_bytes(req.into_body(), usize::MAX) 2893 3389 .await 2894 3390 .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; 2895 - let Ok(payload) = serde_json::from_slice::<UpdateSeenReq>(&body_bytes) else { 2896 - return Err(StatusCode::BAD_REQUEST); 2897 - }; 3391 + let payload: UpdateSeenReq = serde_json::from_slice(&body_bytes).map_err(|e| { 3392 + tracing::error!("failed to parse update_seen request: {e}"); 3393 + StatusCode::BAD_REQUEST 3394 + })?; 2898 3395 2899 3396 let seen_key = format!("seen:{}", did); 2900 3397 app_state 2901 3398 .seen 2902 3399 .insert(seen_key.as_bytes(), payload.seenAt.as_bytes()) 2903 - .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; 3400 + .map_err(|e| { 3401 + tracing::error!("failed to insert seen: {e}"); 3402 + StatusCode::INTERNAL_SERVER_ERROR 3403 + })?; 2904 3404 2905 3405 Ok(Json(serde_json::json!({})).into_response()) 2906 3406 } ··· 2917 3417 async fn get_feed(State(app_state): State<AppState>, req: Request) -> Result<Response, StatusCode> { 2918 3418 // let hydrant = &app_state.hydrant; 2919 3419 let query_str = req.uri().query().unwrap_or(""); 2920 - let Ok(params) = serde_urlencoded::from_str::<GetFeedParams>(query_str) else { 2921 - return Err(StatusCode::BAD_REQUEST); 2922 - }; 3420 + let params: GetFeedParams = serde_urlencoded::from_str(query_str).map_err(|e| { 3421 + tracing::error!("failed to parse get_feed query params: {e}"); 3422 + StatusCode::BAD_REQUEST 3423 + })?; 2923 3424 2924 - let Ok(uri) = jacquard_common::types::string::AtUri::new(&params.feed) else { 2925 - return Err(StatusCode::BAD_REQUEST); 2926 - }; 3425 + let uri = jacquard_common::types::string::AtUri::new(&params.feed).map_err(|e| { 3426 + tracing::error!("failed to parse feed uri {}: {e}", params.feed); 3427 + StatusCode::BAD_REQUEST 3428 + })?; 2927 3429 let author_ident = uri.authority(); 2928 3430 let rkey = uri 2929 3431 .rkey() 2930 - .ok_or(StatusCode::BAD_REQUEST)? 3432 + .ok_or_else(|| { 3433 + tracing::error!("missing rkey in feed uri {}", params.feed); 3434 + StatusCode::BAD_REQUEST 3435 + })? 2931 3436 .0 2932 3437 .as_str() 2933 3438 .to_string(); 2934 3439 2935 - let Ok(repo) = app_state.hydrant.repos.resolve(author_ident).await else { 2936 - return proxy_request(req).await; 3440 + let repo = match app_state.hydrant.repos.resolve(author_ident).await { 3441 + Ok(r) => r, 3442 + Err(e) => { 3443 + tracing::error!("failed to resolve repo for {author_ident}: {e}"); 3444 + return proxy_request(req).await; 3445 + } 2937 3446 }; 2938 3447 2939 - let Ok(Some(record)) = repo.get_record("app.bsky.feed.generator", &rkey).await else { 2940 - return proxy_request(req).await; 3448 + let record = match repo.get_record("app.bsky.feed.generator", &rkey).await { 3449 + Ok(Some(r)) => r, 3450 + Ok(None) => { 3451 + tracing::error!("feed generator record not found: {author_ident}/{rkey}"); 3452 + return proxy_request(req).await; 3453 + } 3454 + Err(e) => { 3455 + tracing::error!("failed to get feed generator record {author_ident}/{rkey}: {e}"); 3456 + return proxy_request(req).await; 3457 + } 2941 3458 }; 2942 3459 2943 3460 let val_json = serde_json::to_value(&record.value).unwrap_or(serde_json::json!({})); 2944 3461 let Some(service_did) = val_json.get("did").and_then(|d| d.as_str()) else { 3462 + tracing::error!("missing did in feed generator record {author_ident}/{rkey}"); 2945 3463 return Err(StatusCode::BAD_REQUEST); 2946 3464 }; 2947 3465 2948 - let Ok(service_did_parsed) = jacquard_common::types::string::Did::new(service_did) else { 2949 - return Err(StatusCode::BAD_REQUEST); 2950 - }; 3466 + let service_did_parsed = jacquard_common::types::string::Did::new(service_did).map_err(|e| { 3467 + tracing::error!("failed to parse service did {service_did}: {e}"); 3468 + StatusCode::BAD_REQUEST 3469 + })?; 2951 3470 2952 - let Ok((doc_data, _)) = app_state 3471 + let (doc_data, _) = match app_state 2953 3472 .hydrant 2954 3473 .resolver() 2955 3474 .resolve_raw_doc(&service_did_parsed) 2956 3475 .await 2957 - else { 2958 - return proxy_request(req).await; 3476 + { 3477 + Ok(d) => d, 3478 + Err(e) => { 3479 + tracing::error!("failed to resolve service did {service_did}: {e}"); 3480 + return proxy_request(req).await; 3481 + } 2959 3482 }; 2960 3483 2961 3484 let doc_json = serde_json::to_value(&doc_data).unwrap_or(serde_json::json!({})); ··· 3013 3536 req_builder = req_builder.header("authorization", auth); 3014 3537 } 3015 3538 3016 - let Ok(res) = req_builder.send().await else { 3017 - return proxy_request(req).await; 3539 + let res = match req_builder.send().await { 3540 + Ok(r) => r, 3541 + Err(e) => { 3542 + tracing::error!("failed to send request to feed generator {skeleton_url}: {e}"); 3543 + return proxy_request(req).await; 3544 + } 3018 3545 }; 3019 3546 3020 - let Ok(skeleton) = res.json::<serde_json::Value>().await else { 3021 - return proxy_request(req).await; 3547 + let skeleton = match res.json::<serde_json::Value>().await { 3548 + Ok(s) => s, 3549 + Err(e) => { 3550 + tracing::error!("failed to parse feed skeleton json: {e}"); 3551 + return proxy_request(req).await; 3552 + } 3022 3553 }; 3023 3554 3024 3555 let mut hydrated_feed = Vec::new(); 3025 3556 if let Some(feed_items) = skeleton.get("feed").and_then(|f| f.as_array()) { 3026 3557 for item in feed_items { 3027 3558 if let Some(post_uri) = item.get("post").and_then(|p| p.as_str()) { 3028 - if let Ok(post_view) = get_post_view(&app_state, post_uri, None).await { 3029 - let mut feed_item = serde_json::json!({ 3030 - "post": post_view 3031 - }); 3032 - if let Some(reason) = item.get("reason") { 3033 - feed_item 3034 - .as_object_mut() 3035 - .unwrap() 3036 - .insert("reason".to_string(), reason.clone()); 3559 + match get_post_view(&app_state, post_uri, None).await { 3560 + Ok(post_view) => { 3561 + let mut feed_item = serde_json::json!({ 3562 + "post": post_view 3563 + }); 3564 + if let Some(reason) = item.get("reason") { 3565 + feed_item 3566 + .as_object_mut() 3567 + .unwrap() 3568 + .insert("reason".to_string(), reason.clone()); 3569 + } 3570 + hydrated_feed.push(feed_item); 3037 3571 } 3038 - hydrated_feed.push(feed_item); 3572 + Err(e) => { 3573 + tracing::warn!("failed to get post view for {post_uri} in feed: {e}"); 3574 + } 3039 3575 } 3040 3576 } 3041 3577 }