A personal app view to see Bsky posts of your followers (for when their app view goes down)
17
fork

Configure Feed

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

refactor to split store code into its own file

Signed-off-by: Will Andrews <did:plc:dadhhalkfcq3gucaq25hjqon>

+10 -108
+1
src/main.rs
··· 1 1 mod server; 2 + mod store; 2 3 mod tap; 3 4 use sqlx::migrate::MigrateDatabase; 4 5
+9 -108
src/tap.rs
··· 1 1 use ::chrono::{DateTime, Utc}; 2 2 use atproto_tap::{RecordAction, RecordEvent, TapClient, TapEvent, connect_to}; 3 3 use serde::Deserialize; 4 - use sqlx::{FromRow, Row, types::chrono}; 5 4 use tokio_stream::StreamExt; 5 + 6 + use crate::store; 6 7 7 8 #[derive(Deserialize)] 8 9 struct FollowRecord { ··· 97 98 _ = add_repo(&follow.subject).await; 98 99 } 99 100 RecordAction::Delete => { 100 - let follow_subject = get_follow_by_rkey(&record.rkey.to_string(), pool).await; 101 + let follow_subject = store::get_follow_by_rkey(&record.rkey.to_string(), pool).await; 101 102 if follow_subject != "" { 102 103 _ = remove_repo(&follow_subject).await; 103 104 } ··· 122 123 Some(x) => x.to_string(), 123 124 None => "".to_string(), 124 125 }; 125 - let mut post = PostRecord { 126 + let mut post = store::PostRecord { 126 127 created: Utc::now(), 127 128 indexed: Utc::now(), 128 129 author: record.did.clone().to_string(), ··· 142 143 } 143 144 } 144 145 145 - insert_post(post, pool).await; 146 + store::insert_post(post, pool).await; 146 147 } 147 148 RecordAction::Delete => { 148 - delete_post(record.rkey.to_string(), pool).await; 149 + store::delete_post(record.rkey.to_string(), pool).await; 149 150 } 150 151 RecordAction::Update => {} 151 152 } ··· 165 166 None => "".to_string(), 166 167 }; 167 168 168 - let mut repost = RepostRecord { 169 + let mut repost = store::RepostRecord { 169 170 created: Utc::now(), 170 171 indexed: Utc::now(), 171 172 author: record.did.clone().to_string(), ··· 184 185 } 185 186 } 186 187 187 - insert_repost(repost, pool).await; 188 + store::insert_repost(repost, pool).await; 188 189 } 189 190 RecordAction::Delete => { 190 - delete_repost(record.rkey.to_string(), pool).await; 191 + store::delete_repost(record.rkey.to_string(), pool).await; 191 192 } 192 193 RecordAction::Update => {} 193 194 } 194 195 } 195 196 196 - async fn get_follow_by_rkey(rkey: &String, pool: &sqlx::SqlitePool) -> String { 197 - let result = sqlx::query("SELECT subject FROM follows where rkey = ? LIMIT 1") 198 - .bind(rkey) 199 - .fetch_one(pool) 200 - .await; 201 - 202 - match result { 203 - Ok(row) => { 204 - if row.len() == 0 { 205 - println!("did not find subject in follows with rkey: {rkey}"); 206 - return "".to_string(); 207 - } 208 - let subject = row.get::<String, _>(0); 209 - 210 - return subject; 211 - } 212 - Err(e) => { 213 - println!("error getting follow {e}"); 214 - return "".to_string(); 215 - } 216 - } 217 - } 218 197 #[derive(Debug, Deserialize)] 219 198 struct TapPost { 220 199 #[serde(rename = "createdAt")] ··· 226 205 struct Subject { 227 206 uri: String, 228 207 } 229 - 230 - #[derive(Debug, FromRow)] 231 - struct PostRecord { 232 - created: chrono::DateTime<chrono::Utc>, 233 - indexed: chrono::DateTime<chrono::Utc>, 234 - author: String, 235 - rkey: String, 236 - cid: String, 237 - // TODO: other fields like reply to etc 238 - } 239 - 240 - #[derive(Debug, FromRow)] 241 - struct RepostRecord { 242 - created: chrono::DateTime<chrono::Utc>, 243 - indexed: chrono::DateTime<chrono::Utc>, 244 - author: String, 245 - rkey: String, 246 - subject: String, 247 - cid: String, 248 - // TODO: other fields like reply to etc 249 - } 250 - 251 - async fn insert_post(post: PostRecord, pool: &sqlx::SqlitePool) { 252 - let result = sqlx::query( 253 - "INSERT INTO posts (created, indexed, author, rkey, cid) VALUES ($1, $2, $3, $4, $5)", 254 - ) 255 - .bind(post.created) 256 - .bind(post.indexed) 257 - .bind(post.author) 258 - .bind(post.rkey) 259 - .bind(post.cid) 260 - .execute(pool) 261 - .await; 262 - 263 - if result.is_err() { 264 - println!("Error inserting post into the database: {result:?}"); 265 - } 266 - } 267 - 268 - async fn insert_repost(repost: RepostRecord, pool: &sqlx::SqlitePool) { 269 - let result = sqlx::query( 270 - "INSERT INTO reposts (created, indexed, author, rkey, subject, cid) VALUES ($1, $2, $3, $4, $5, $6)", 271 - ) 272 - .bind(repost.created) 273 - .bind(repost.indexed) 274 - .bind(repost.author) 275 - .bind(repost.rkey) 276 - .bind(repost.subject) 277 - .bind(repost.cid) 278 - .execute(pool) 279 - .await; 280 - 281 - if result.is_err() { 282 - println!("Error inserting repost into the database: {result:?}"); 283 - } 284 - } 285 - 286 - async fn delete_post(rkey: String, pool: &sqlx::SqlitePool) { 287 - let result = sqlx::query("DELETE FROM posts WHERE rkey = $1") 288 - .bind(rkey) 289 - .execute(pool) 290 - .await; 291 - 292 - if result.is_err() { 293 - println!("Error deleting post from the database: {result:?}"); 294 - } 295 - } 296 - 297 - async fn delete_repost(rkey: String, pool: &sqlx::SqlitePool) { 298 - let result = sqlx::query("DELETE FROM reposts WHERE rkey = $1") 299 - .bind(rkey) 300 - .execute(pool) 301 - .await; 302 - 303 - if result.is_err() { 304 - println!("Error deleting repost from the database: {result:?}"); 305 - } 306 - }