···1515 USERS_DID: ${USERS_DID}
1616 TAP_URL: ${TAP_URL}
1717 DATABASE_URL: ${DATABASE_URL}
1818+ depends_on:
1919+ - tap
18201921 tap:
2022 container_name: tap
+3-3
readme.md
···1818 - [x] Run as part of a docker-compose file
1919 - [x] Configure to be in `Dynamically Configured` mode
2020 - [x] Configure the filters to be for `app.bsky.*` (maybe limit this just to be the ones needed)
2121-- [ ] - App start up configuration for user
2121+- [x] - App start up configuration for user
2222 - [x] Get users did from config
2323- - [ ] Fetch and store that users follows
2424- - [ ] For each user call the `/repos/add` endpoint on tap to add the follow to be tracked
2323+ - [x] Fetch and store that users follows
2424+ - [x] For each user call the `/repos/add` endpoint on tap to add the follow to be tracked
2525 - [x] Call `/repos/add` for the user of the appview
2626- [ ] - Handle the events for tracked users
2727 - [ ] Ignore anything other than the post lexicon types for the follows (work out what lexicon types need to be used for the user using the appview)
+59-4
src/tap.rs
···11use atproto_tap::{RecordAction, RecordEvent, TapClient, TapEvent, connect_to};
22-use axum::response::sse::Event;
32use serde::Deserialize;
33+use sqlx::Row;
44use tokio_stream::StreamExt;
5566#[derive(Deserialize)]
···1313 let client = TapClient::new(tap_url.as_str(), Some("password".to_string()));
14141515 // Add repositories to track
1616- client.add_repos(&[did.as_str()]).await?;
1616+ let res = client.add_repos(&[did.as_str()]).await;
1717+ match res {
1818+ Err(e) => {
1919+ println!("failed to add repo with tap: {e}");
2020+ }
2121+ Ok(()) => {
2222+ println!("added repo {did}");
2323+ }
2424+ }
17251826 Ok(())
1927}
20282929+pub async fn remove_repo(did: &String) {
3030+ let tap_url = std::env::var("TAP_URL").unwrap_or("localhost:2480".to_string());
3131+ let client = TapClient::new(tap_url.as_str(), Some("password".to_string()));
3232+3333+ let res = client.remove_repos(&[did.as_str()]).await;
3434+3535+ match res {
3636+ Err(e) => {
3737+ println!("failed to remove repo with tap: {e}");
3838+ }
3939+ Ok(()) => {
4040+ println!("removed repo {did}");
4141+ }
4242+ }
4343+}
4444+2145pub async fn run_tap(users_did: String, pool: &sqlx::SqlitePool) {
2246 let tap_url = std::env::var("TAP_URL").unwrap_or("localhost:2480".to_string());
2347 let mut stream = connect_to(tap_url.as_str());
···5680 RecordAction::Create => {
5781 let follow: FollowRecord = record.parse_record().unwrap();
5882 let result = sqlx::query("INSERT INTO follows (subject, rkey) VALUES ($1, $2)")
5959- .bind(follow.subject)
8383+ .bind(&follow.subject)
6084 .bind(record.rkey.to_string())
6185 .execute(pool)
6286 .await;
···6488 if result.is_err() {
6589 println!("Error inserting follow into the database: {result:?}");
6690 }
9191+9292+ // track the follow anyway
9393+ _ = add_repo(&follow.subject).await;
6794 }
6895 RecordAction::Delete => {
9696+ let follow_subject = get_follow_by_rkey(&record.rkey.to_string(), pool).await;
9797+ if follow_subject != "" {
9898+ _ = remove_repo(&follow_subject).await;
9999+ }
100100+69101 let result = sqlx::query("DELETE FROM follows WHERE rkey = $1")
70102 .bind(record.rkey.to_string())
71103 .execute(pool)
···79111 }
80112}
811138282-async fn handle_post_event(record: &RecordEvent, pool: &sqlx::SqlitePool) {
114114+async fn handle_post_event(record: &RecordEvent, _pool: &sqlx::SqlitePool) {
83115 match record.action {
84116 RecordAction::Create => {}
85117 RecordAction::Delete => {}
86118 RecordAction::Update => {}
87119 }
88120}
121121+122122+async fn get_follow_by_rkey(rkey: &String, pool: &sqlx::SqlitePool) -> String {
123123+ let result = sqlx::query("SELECT subject FROM follows where rkey = ? LIMIT 1")
124124+ .bind(rkey)
125125+ .fetch_one(pool)
126126+ .await;
127127+128128+ match result {
129129+ Ok(row) => {
130130+ if row.len() == 0 {
131131+ println!("did not find subject in follows with rkey: {rkey}");
132132+ return "".to_string();
133133+ }
134134+ let subject = row.get::<String, _>(0);
135135+136136+ return subject;
137137+ }
138138+ Err(e) => {
139139+ println!("error getting follow {e}");
140140+ return "".to_string();
141141+ }
142142+ }
143143+}